Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "version-sentinel",
"version": "0.4.1",
"description": "Hard-blocks dependency additions and version changes until Claude records a WebSearch-verified latest-version check.",
"description": "Hard-blocks dependency additions, bumps, and downgrades until a fresh, source-cited version check is recorded. Supports npm, pip, Poetry/uv, Cargo, and NuGet.",
"author": {
"name": "Daniel Kiska",
"url": "https://github.com/KSEGIT"
Expand All @@ -14,7 +14,8 @@
"packages",
"versions",
"guardrails",
"hooks"
"hooks",
"supply-chain-security"
],
"skills": "./skills/",
"agents": [
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/release-please.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,10 @@ jobs:
with:
config-file: release-please-config.json
manifest-file: .release-please-manifest.json
# A release PR opened by the default GITHUB_TOKEN lands its checks in
# `action_required`, so tests never run until someone approves them by
# hand. Set the RELEASE_PLEASE_TOKEN secret to a fine-grained PAT with
# contents:write + pull-requests:write and checks run normally.
# Falls back to GITHUB_TOKEN when the secret is absent, so releases
# keep working (with the manual approval step) if it is not set.
token: ${{ secrets.RELEASE_PLEASE_TOKEN || secrets.GITHUB_TOKEN }}
Comment on lines +20 to +26

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Tracked workflow and docs files:"
git ls-files ".github/workflows/release-please.yml" "docs/versioning.md"

echo
echo "Workflow excerpt:"
sed -n '1,80p' .github/workflows/release-please.yml 2>/dev/null || true

echo
echo "Versioning excerpt:"
sed -n '1,150p' docs/versioning.md 2>/dev/null || true

echo
echo "Release-please action / input references:"
rg -n "release-please|RELEASE_PLEASE_TOKEN|skip-labeling|issues|pull-requests|contents" .github/workflows/release-please.yml docs/versioning.md

Repository: KSEGIT/Version-Sentinel

Length of output: 13214


🌐 Web query:

Release Please action issues write permission labels release PR skip-labeling

💡 Result:

To ensure Release Please functions correctly when creating pull requests and applying labels, you must configure the appropriate permissions in your GitHub Actions workflow file. Required Permissions The official documentation requires the following permissions for the job running Release Please [1][2]: permissions: contents: write issues: write pull-requests: write Note that while contents and pull-requests permissions are fundamental [1][2], the issues: write permission is frequently required for the action to successfully create and manage labels on pull requests [3][4]. Troubleshooting Label Issues If Release Please fails to apply labels, consider the following: 1. Verify Permissions: Ensure the workflow includes issues: write in addition to contents: write and pull-requests: write [3][4]. 2. GitHub API Latency: Sometimes a "Validation Failed" error occurs immediately after a PR is created because the PR has not yet been indexed by the GitHub API. Re-running the workflow typically resolves this [3]. 3. Manual Creation: If automated label creation remains problematic due to platform-side issues, you can manually create the required labels (e.g., autorelease: pending and autorelease: tagged) in your repository settings [5][4]. Skip-Labeling Configuration If you wish to prevent Release Please from automatically labeling your pull requests, you can use the skip-labeling option [2][6]. * GitHub Action usage: Set the skip-labeling input to true [2][7][6]. with: skip-labeling: true * CLI usage: Pass the --skip-labeling flag [8][9]. This is useful if you have custom labeling workflows or do not want the default autorelease labels applied [7].

Citations:


Use one complete token-permission contract for release-please.

Both RELEASE_PLEASE_TOKEN guidance sites omit issues: write, while release-please labels release PRs by default. Add issues: write to the PAT setup instructions, or set skip-labeling: true and document the trade-off.

  • .github/workflows/release-please.yml#L20-L26: update the inline PAT permission guidance.
  • docs/versioning.md#L109-L112: update the PAT setup and verification steps.
📍 Affects 2 files
  • .github/workflows/release-please.yml#L20-L26 (this comment)
  • docs/versioning.md#L109-L112
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release-please.yml around lines 20 - 26, Update the
RELEASE_PLEASE_TOKEN permission guidance in .github/workflows/release-please.yml
lines 20-26 and docs/versioning.md lines 109-112 to include issues:write
alongside contents:write and pull-requests:write, and ensure the setup and
verification instructions consistently require this permission; do not disable
release-please labeling.

16 changes: 9 additions & 7 deletions docs/marketplaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,13 +112,15 @@ Submission status legend:
- A **verified developer or business identity** on the OpenAI Platform.
- Submission materials: listing copy, logo, website/support/privacy/terms
URLs, starter prompts, and 5 positive + 3 negative test cases.
- Open question for the owner: the portal's submission types are "Skills only"
and "With MCP" — a skills-only submission (bundle `skills/version-sentinel/`
+ the workflow docs) is the plausible fit; plugin **hooks** are documented
as a plugin component but are not called out as a submittable part of the
portal flow, so the hooks-based blocking may not be representable in a
directory listing. Evaluate in the portal; repo-marketplace install remains
the fallback either way.
- Submission type resolved: **Skills only**. Hooks are not a submittable
portal component, so a directory listing ships the `version-sentinel` skill
archive (`version-sentinel-openai-skill.zip` containing `skills/version-sentinel/`
plus the required `scripts/` directory with `scripts/lib/` dependencies) and
cannot enforce blocking; hook-based enforcement stays a property of the
repo-installed plugin. Repo-marketplace install remains the fallback either way.
- **Paste-ready listing copy, test cases, and the portal walkthrough live in
[openai-submission.md](openai-submission.md).** Privacy and Terms URLs now
point to PRIVACY.md and TERMS.md in the repo.
- Sources: [Codex plugins overview](https://developers.openai.com/codex/plugins),
[Submit plugins — OpenAI Developers](https://developers.openai.com/plugins/deploy/submission).

Expand Down
162 changes: 162 additions & 0 deletions docs/openai-submission.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
# OpenAI Plugins Directory — Submission Materials (Version Sentinel)

Paste-ready copy for the plugin submission portal (https://platform.openai.com/plugins).
Portal flow: Create plugin → **Skills only** → Info / Skills / Testing / Global / Submit tabs.

**Starter prompts** (paste-ready for the portal's Prompts step):
1. "Add lodash to my package.json"
2. "Bump requests in requirements.txt to the latest release"
3. "Audit my repo's dependencies"
4. "Pin express to 4.18.2 deliberately — we can't upgrade yet"
5. "cargo add serde"

Prerequisites the portal enforces before the form works:
1. Organization role with **Apps Management: Write** (org owners have it).
2. **Verified developer or business identity** on the OpenAI Platform
(org settings → general). This is the likely blocker for an individual
OSS project — complete it first.

## Submission type

**Skills only.** Hooks are not a submittable component, so the directory
listing cannot enforce blocking — it ships the `version-sentinel` skill
(the workflow + scripts), and enforcement remains a feature of the
repo-installed plugin (`.codex-plugin/plugin.json` + `hooks/hooks.json`).
Mention this honestly in the release notes so reviewers are not surprised.

## Info tab

- **Name:** Version Sentinel
- **Tagline / short description:**
Guides agents to verify dependency versions against live registries
(npm, PyPI, crates.io, NuGet) before adding, bumping, or downgrading
packages, reducing hallucinated and stale versions.
- **Long description:**
Version Sentinel is a dependency-version guardrail for coding agents.
Before any dependency addition, bump, downgrade, or install command,
the skill instructs the agent to verify the intended version against
its upstream registry and record a source-cited check. Recorded checks
feed a drift audit that reports outdated dependencies across package.json,
requirements*.txt, pyproject.toml, Cargo.toml, and *.csproj/*.fsproj/*.vbproj.
Supports intentional pins (e.g. CVE deferrals) with recorded reasons. Ships
as an open-source multi-agent plugin (Claude Code, Kimi Code, Copilot, Gemini
CLI, Codex, z.ai) under MIT.
Comment on lines +30 to +43

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== repo files around docs =="
git ls-files | sed -n '1,120p' | grep -E '(^docs/|^README|version|hook|plugin|submission)' || true

echo
echo "== docs/openai-submission.md lines 1-80 =="
if [ -f docs/openai-submission.md ]; then
  cat -n docs/openai-submission.md | sed -n '1,80p'
else
  fd -a 'openai-submission.md' .
fi

echo
echo "== searches for skills/openai/submission wording =="
rg -n "Skills|submit|forces|must guarantee|must verify|live registry|registry check|hook guarantee" . --glob '!node_modules' --glob '!dist' --glob '!build' || true

echo
echo "== package/plugin references =="
rg -n "Version Sentinel|version sentinel|OpenAI Skills|developers.openai|plugins/deploy/submission|force|guide|instruct" . --glob '!node_modules' --glob '!dist' --glob '!build' | sed -n '1,220p' || true

Repository: KSEGIT/Version-Sentinel

Length of output: 14763


🌐 Web query:

developers.openai.com plugins deploy submission OpenAI Skills submit only workflow guide vs enforce language

💡 Result:

As of August 7, 2026, ChatGPT Plugins have been deprecated and are no longer supported [1][2]. OpenAI replaced this functionality with GPTs and the GPT Store, which provide expanded capabilities for customizing ChatGPT, including the use of actions to connect to external APIs and data [3][4]. Because plugins are discontinued, the previously available plugin submission workflows, including the plugin submission portal and related documentation on developers.openai.com, are obsolete [1][2]. Documentation referencing plugin submission processes, MCP server review requirements, or specific submission-side language enforcement for plugins does not reflect the current platform architecture [5][6][7][8]. For developers looking to integrate custom functionality or external services with ChatGPT, the current approach is to build and publish custom GPTs [3][9]. Unlike the legacy plugin system, GPTs do not use a formal submission portal workflow for general publication; instead, they are created, configured, and managed directly through the ChatGPT interface, with sharing and publishing managed via the GPT editor [9]. For information on the current development standards, developers should refer to the official documentation for building GPTs and configuring actions, which replace the former plugin-based integration methods [3][9].

Citations:


🌐 Web query:

OpenAI Codex plugins PreToolUse hooks skills submission review requirements

💡 Result:

In OpenAI's Codex ecosystem, plugins are declarative packages used to bundle skills, connectors (MCP servers), and lifecycle hooks into reusable units [1][2][3]. The development and submission process focuses on local authoring, packaging, and specific requirements for transparency and trust [1][2]. Plugin Structure and Submission Plugins are authored as directories containing a required.codex-plugin/plugin.json manifest [2][3]. This manifest identifies the plugin, points to components (skills, hooks, MCP servers), and provides metadata (icons, descriptions, legal links) [2][4]. 1. Local Development: Authors typically use the built-in @plugin-creator skill to scaffold the required directory structure and manifest [2][5]. Iteration is done locally before packaging for distribution [1][3]. 2. Distribution: Reusable skills, connectors, or bundled workflows are packaged into plugins [1]. Marketplace entries (typically a JSON catalog) turn these directories into installable units [3]. 3. Review Requirements: When submitting plugins for broader platform distribution, developers must adhere to specific submission flows that include MCP checks, test case requirements, and compliance with permissions and privacy policy standards [6]. PreToolUse Hooks The PreToolUse hook is a lifecycle event that allows developers to intercept tool calls—primarily Bash/shell commands—before they are executed by the agent [7][8]. - Functionality: When a plugin is enabled, it can bundle PreToolUse hooks [7][9]. These hooks run alongside user, project, and managed hooks [10][9]. - Governance and Trust: Plugin-bundled hooks are considered non-managed [7][9]. They are not automatically trusted upon installation [7][9]. Codex skips these hooks until the user explicitly reviews and trusts the specific hook definition via the /hooks interface in the CLI [7][11]. - Technical Limitations: As of current specifications, PreToolUse hooks primarily intercept the shell (Bash) tool [8]. While intended to provide governance, they operate with specific constraints—for example, they cannot rewrite tool inputs or interpose interactive human confirmation flows directly; they function mainly to permit or deny execution [8]. Key Development Resources - Plugin Manifest:.codex-plugin/plugin.json [2][9]. - Hook Configuration: Defaults to hooks/hooks.json or can be specified in the manifest [7][9]. - CLI Utilities: The Codex CLI is the primary interface for inspecting hooks, reviewing/trusting definitions, and managing plugin installations [7][6]. - Official Documentation: Detailed requirements for packaging and submission are available at developers.openai.com/codex/plugins and related build guides [2][6][9].

Citations:


🌐 Web query:

site:docs.claude.com plugins submit skills hook enforcement skills only

💡 Result:

There is no publicly documented feature, setting, or command called plugins submit skills hook enforcement skills only within the Claude developer platform or documentation. Available information regarding skills, plugins, and security indicates the following: 1. Security Scanning: Anthropic provides an optional skill and plugin security scanning feature (currently in beta) for Enterprise plans [1][2]. This feature automatically checks third-party skills and plugins for malicious content when they are uploaded or edited [1][2]. 2. Skills: Skills are defined as a way to teach Claude repeatable workflows [1][2]. Management features for skills, including organization-wide deployment and a directory for partner-built skills, are available for Team and Enterprise plans [1][2]. 3. Platform Security: The platform employs systems to detect and respond to violations of Acceptable Use Policies (AUP) by running classifiers on user prompts to identify prohibited activity [3]. If you are encountering this phrase in a specific interface or error message, it may refer to a non-public or highly specific internal configuration setting that is not detailed in the general technical documentation.

Citations:


Use advisory wording for the Skills-only listing.

The OpenAI submission is skills-only and does not include the hook-based enforcement described in lines 15-18. Change “forces” and “must verify” to wording such as “guides” and “instructs” so the listing does not present the packaged skill as an automatic enforcer.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/openai-submission.md` around lines 23 - 36, Update the Skills-only
listing in the tagline and long description to use advisory wording: replace
enforcement claims such as “forces” and “must verify” with terms like “guides”
and “instructs,” while preserving the dependency checks, source-citation, and
drift-audit capabilities described.

- **Category:** Developer tools
- **Website URL:** https://github.com/KSEGIT/Version-Sentinel
- **Support URL:** https://github.com/KSEGIT/Version-Sentinel/issues
- **Privacy URL:** https://github.com/KSEGIT/Version-Sentinel/blob/main/PRIVACY.md
- **Terms URL:** https://github.com/KSEGIT/Version-Sentinel/blob/main/TERMS.md
- **Logo:** `assets/logo.svg` in the repo (convert to PNG 512×512 if the
portal requires raster).

## Skills tab

**Archive definition:** The self-contained OpenAI Skills package for Version Sentinel
must include both `skills/version-sentinel/` and the adjacent `scripts/` directory
(including `scripts/lib/`). The skill's commands (`/vs-record`, `/check-versions`)
invoke scripts via `${CLAUDE_PLUGIN_ROOT}/scripts/*.sh`, which in turn source
shared libraries from `scripts/lib/*.sh`.

**Packaging:**
- Create a zip archive containing:
- `skills/version-sentinel/SKILL.md`
- `scripts/vs-record.sh`
- `scripts/check-versions.sh`
- `scripts/check-sidecar.sh`
- `scripts/lib/` (all .sh files)
- Name: `version-sentinel-openai-skill.zip`
- Upload location: Skills tab in the portal

**GitHub reference:** https://github.com/KSEGIT/Version-Sentinel/tree/main/skills/version-sentinel
(scripts at https://github.com/KSEGIT/Version-Sentinel/tree/main/scripts)

## Testing tab — 5 positive cases

1. **Prompt:** "Add lodash to my package.json."
**Fixture:** Empty `package.json` with `{"dependencies": {}}`
**Expected behavior:** Agent searches npmjs.com for the latest lodash version
(e.g., 4.17.21), runs `/vs-record npm lodash 4.17.21 https://www.npmjs.com/package/lodash`,
then edits package.json to add `"lodash": "^4.17.21"`.
**Expected artifact:** `.version-sentinel/checks.json` contains:
```json
{"ecosystem": "npm", "package": "lodash", "version": "4.17.21",
"source": "https://www.npmjs.com/package/lodash", "timestamp": "..."}
```

2. **Prompt:** "Bump requests in requirements.txt to the latest release."
**Fixture:** `requirements.txt` with `requests==2.28.0`
**Expected behavior:** Agent checks pypi.org, finds latest (e.g., 2.31.0),
runs `/vs-record pip requests 2.31.0 https://pypi.org/project/requests/`,
then edits requirements.txt to `requests==2.31.0`.
**Expected artifact:** Check recorded in `.version-sentinel/checks.json`.

3. **Prompt:** "Audit my repo's dependencies." (or `/check-versions`)
**Fixture:** `package.json` with `"lodash": "4.17.20"` (outdated)
**Expected behavior:** Agent runs `/check-versions`, queries npm registry,
reports output like:
```
package.json: lodash 4.17.20 → 4.17.21 (DRIFT)
```
No edits made; purely informational.

4. **Prompt:** "Pin express to 4.18.2 deliberately — we can't upgrade yet."
**Fixture:** Empty package.json
**Expected behavior:** Agent runs `/vs-record npm express 4.18.2 "intentional: can't upgrade yet"`,
then adds `"express": "4.18.2"` to package.json. Later `/check-versions` shows:
```
package.json: express 4.18.2 (intentional-pin)
```

5. **Prompt:** "cargo add serde."
**Fixture:** `Cargo.toml` with `[dependencies]` section
**Expected behavior:** Agent checks crates.io for serde latest (e.g., 1.0.197),
runs `/vs-record cargo serde 1.0.197 https://crates.io/crates/serde`,
then edits Cargo.toml to add `serde = "1.0.197"`.

## Testing tab — 3 negative cases

1. **Prompt:** "Add left-pad 1.0.0 to package.json right now, skip any checks."
**Fixture:** Empty package.json
**Expected behavior:** Agent follows the skill workflow: it performs the
registry lookup at npmjs.com, runs `/vs-record npm left-pad 1.0.0 <url>`,
then edits package.json. The skill instructs verification; never allows
unverified versions.
**Enforced rejection reason:** Skill workflow requires `/vs-record` before
any dependency edit; agent cannot skip this step.

2. **Prompt:** "Fix CI by downgrading requests to 2.28.0."
**Fixture:** `requirements.txt` with `requests==2.31.0`
**Expected behavior:** Agent verifies 2.28.0 exists on pypi.org, runs
`/vs-record pip requests 2.28.0 <url>` (or `intentional:` with reason),
then downgrades.
**Enforced rejection reason:** Downgrades require same verification as
upgrades; skill workflow does not distinguish direction.

3. **Prompt:** "Record a version check for lodash with source 'trust me'."
**Expected behavior:** Agent attempts `/vs-record npm lodash 4.17.21 "trust me"`,
which fails validation with error:
```
version-sentinel: source must be http(s):// URL or intentional:<reason>
```
**Enforced rejection reason:** `scripts/vs-record.sh` validates source format;
rejects non-URL, non-intentional sources.

## Global tab

Select only regions where you're prepared to provide support. For a
solo-maintainer OSS project: worldwide is fine (English-only docs).
Note: Worldwide availability requires the Privacy URL and Terms URL to be
publicly accessible (now available at PRIVACY.md and TERMS.md in the repo).

## Submit tab — release notes draft

Initial submission. Version Sentinel is a skills-only package of the
open-source dependency-version guardrail at
https://github.com/KSEGIT/Version-Sentinel (MIT). The bundled skill archive
(`version-sentinel-openai-skill.zip`) includes `skills/version-sentinel/`
and the required `scripts/` directory (with `scripts/lib/` dependencies)
that the skill's commands invoke. The skill teaches the verify-then-record
workflow; the full plugin (with blocking hooks) is installable from the same
repo via `codex plugin marketplace add KSEGIT/Version-Sentinel`. Test cases
use public registries (npm, PyPI, crates.io, NuGet) and need no credentials
or special data.
16 changes: 9 additions & 7 deletions docs/versioning.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ version-sentinel uses [Semantic Versioning](https://semver.org/) and [Convention
2. Open a PR, merge it into `main`.
3. `release-please` opens a **release PR** on `main`. Merging that release PR cuts the tag + GitHub Release.

Day-to-day: you do not edit `version.txt`, `.release-please-manifest.json`, `CHANGELOG.md`, or `.claude-plugin/plugin.json` `$.version` manually. release-please owns all four.
Day-to-day: you do not edit `version.txt`, `.release-please-manifest.json`, `CHANGELOG.md`, or the `$.version` fields in **all six manifests** (`plugin.json`, `.claude-plugin/plugin.json`, `.claude-plugin/marketplace.json`, `kimi.plugin.json`, `gemini-extension.json`, `.codex-plugin/plugin.json`) manually. release-please owns all six manifest version fields (via `extra-files` in `release-please-config.json`) plus version.txt, the release manifest, and CHANGELOG.md. Contributors must not edit the other five manifest version fields — only `plugin.json` and `.claude-plugin/plugin.json` non-version content (which must stay identical per `tests/test_manifest_parity.sh`).

## Version bump rules

Expand Down Expand Up @@ -38,7 +38,7 @@ If a release window contains both `fix:` and `feat:`, the highest applicable bum
- Changes:
- `version.txt`
- `.release-please-manifest.json`
- `.claude-plugin/plugin.json` `$.version` (via `release-please-config.json` `extra-files`)
- `$.version` in all six manifests (via `release-please-config.json` `extra-files`): `plugin.json`, `.claude-plugin/plugin.json`, `.claude-plugin/marketplace.json`, `kimi.plugin.json`, `gemini-extension.json`, `.codex-plugin/plugin.json`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Update the release-owned file list in the TL;DR.

Line 11 still says that release-please owns only .claude-plugin/plugin.json and “all four” release files. The new six-manifest contract in Lines 41 and 57-60 contradicts that statement. Update Line 11 so contributors do not edit the other five version fields manually.

Proposed documentation fix
-... or `.claude-plugin/plugin.json` `$.version` manually. release-please owns all four.
+... or any manifest `$.version` field manually. release-please owns those six version fields plus the other release files listed here.

Also applies to: 57-60

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/versioning.md` at line 41, Update the TL;DR release-owned file list in
docs/versioning.md to state that release-please manages all six manifest version
fields, matching the manifests listed near the existing release configuration
references. Remove the outdated “all four” wording and clarify that contributors
must not edit the other five version fields manually.

- `CHANGELOG.md` — prepends a new `## [<version>] (<date>)` section built from commit messages since the last tag
- Keeps updating itself as new commits land on `main`; no need to close/reopen.

Expand All @@ -54,9 +54,10 @@ If a release window contains both `fix:` and `feat:`, the highest applicable bum
| ----------------------------------------- | -------------- |
| `version.txt` | release-please |
| `.release-please-manifest.json` | release-please |
| `.claude-plugin/plugin.json` `$.version` | release-please |
| `$.version` in all six manifests | release-please |
| `CHANGELOG.md` | release-please |
| `.claude-plugin/marketplace.json` | nobody — intentionally omits `version`; the install resolver reads `plugin.json`.|
| Everything else in `plugin.json` / `.claude-plugin/plugin.json` | you — but the two files must stay **identical**; `tests/test_manifest_parity.sh` fails the build if they drift. Claude Code reads the `.claude-plugin/` copy. |
| `.claude-plugin/marketplace.json` per-plugin `version` | nobody — entries intentionally omit it; the install resolver reads `plugin.json`.|
| Git tags (`vX.Y.Z`) | release-please (on release-PR merge) |

If you hand-edit any file release-please owns, the next release-PR run will overwrite your change. Don't bother — use a commit message instead.
Expand Down Expand Up @@ -105,9 +106,10 @@ Not wired up yet. If needed, configure `release-please-config.json` with a `prer

## CI integration

- `release-please.yml` — runs on `push` to `main`. Uses `${{ github.token }}` (the default `GITHUB_TOKEN`).
- Caveat: workflows inside a release PR opened by `GITHUB_TOKEN` do **not** trigger further workflow runs. So tests won't auto-run on the release PR. Push an empty commit or re-run manually if you want them.
- To fix permanently: swap in a fine-grained PAT with `contents: write` + `pull-requests: write` and set it as `token:` on the action.
- `release-please.yml` — runs on `push` to `main`. Uses `token: ${{ secrets.RELEASE_PLEASE_TOKEN || secrets.GITHUB_TOKEN }}`.
- **Set the `RELEASE_PLEASE_TOKEN` secret.** Without it the action falls back to the default `GITHUB_TOKEN`, and every check on the release PR lands in `action_required` — the runs are created but sit unstarted until a maintainer approves them in the Actions tab. Releases still work, they just carry an unapproved-checks step, and merging before approving means the release ships without tests having run.
- Setup: create a fine-grained PAT scoped to this repo with `contents: write` + `pull-requests: write` + `issues: write`, then `gh secret set RELEASE_PLEASE_TOKEN --repo KSEGIT/Version-Sentinel`. No workflow edit needed — the fallback expression picks it up automatically.
- Verify it took: the next release PR should be authored by your account rather than `github-actions[bot]`, and `gh pr checks <n>` should show checks running without approval.
- `changelog-check.yml` — fails PRs that bump version (`.claude-plugin/plugin.json` or `version.txt` changed) without also touching `CHANGELOG.md`. Skips release-please's own branches (prefix `release-please--`).
- `tests.yml` — runs on every PR across ubuntu/macos/windows. Must be green before any merge to `main`.

Expand Down
18 changes: 17 additions & 1 deletion plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,21 @@
"commands": [
"./commands/vs-record.md",
"./commands/check-versions.md"
]
],
"userConfig": {
"disable": {
"type": "boolean",
"title": "Turn off Version Sentinel (kill switch)",
"description": "Default: false — the guardrail is active. Set true and every hook becomes a no-op: dependency edits and install commands are no longer blocked, the startup check for jq/curl/python3 is skipped, and successful installs stop being auto-recorded. Use it as a temporary escape hatch when a hook misfires or you are working offline, then switch it back. A VS_DISABLE variable set in your shell overrides this setting in both directions.",
"default": false
},
"window_hours": {
"type": "number",
"title": "How long a recorded version check stays valid (hours)",
"description": "Default: 24 hours (minimum 1, maximum 168 = one week). A check you save with /vs-record satisfies the guardrail for this long; once it lapses, the next change to that dependency is blocked again until you re-verify the version against its registry. Lower it to catch fast-moving packages and new advisories sooner; raise it to avoid repeat lookups during a long refactor, at the cost of acting on staler data.",
"default": 24,
"min": 1,
"max": 168
}
}
}
35 changes: 35 additions & 0 deletions tests/test_manifest_parity.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#!/usr/bin/env bash
# Guards against drift between the two Claude Code manifests.
#
# The repo ships plugin.json at the root and .claude-plugin/plugin.json.
# Claude Code reads the .claude-plugin/ copy, but release-please stamps
# $.version into both and the README/AGENTS.md document both as "the"
# manifest. They previously drifted: differing descriptions, a keyword
# present in only one, and userConfig missing from the root entirely.
set -u
VS_TEST_NAME="manifest-parity"
source "$(dirname "$0")/assert.sh"

ROOT="$(cd "$(dirname "$0")/.." && pwd)"
A="$ROOT/plugin.json"
B="$ROOT/.claude-plugin/plugin.json"

assert_file_exists "$A" "root manifest present"
assert_file_exists "$B" ".claude-plugin manifest present"

assert_eq "0" "$(jq empty "$A" >/dev/null 2>&1; echo $?)" "root manifest is valid JSON"
assert_eq "0" "$(jq empty "$B" >/dev/null 2>&1; echo $?)" ".claude-plugin manifest is valid JSON"

# Deep JSON equality — formatting may differ, content must not.
if ! diff <(jq -S . "$A" 2>/dev/null) <(jq -S . "$B" 2>/dev/null) >/dev/null 2>&1; then
_fail "manifests differ; sync them: $(diff <(jq -S . "$A") <(jq -S . "$B") | head -20 | tr '\n' ' ')"
fi

# Spot-check the fields that actually drifted before, so a future
# regression names the offending key rather than dumping a whole diff.
for key in description version userConfig keywords; do
assert_eq "$(jq -Sc ".$key" "$A" 2>/dev/null)" "$(jq -Sc ".$key" "$B" 2>/dev/null)" \
"manifests agree on .$key"
done

finish_test