Skip to content

fix(version): sync plugin manifests with package.json on version bump - #110

Open
grlee wants to merge 1 commit into
ramarivera:mainfrom
grlee:fix/sync-version-on-bump
Open

fix(version): sync plugin manifests with package.json on version bump#110
grlee wants to merge 1 commit into
ramarivera:mainfrom
grlee:fix/sync-version-on-bump

Conversation

@grlee

@grlee grlee commented Apr 25, 2026

Copy link
Copy Markdown
Contributor

Problem

The plugin manifests have been frozen at 0.3.0 across four releases:

File main HEAD
package.json 0.5.2
.claude-plugin/plugin.json 0.3.0
.claude-plugin/marketplace.json (metadata + plugins[0]) 0.3.0
server/index.ts MCP server version literal "0.3.0"

Each chore: bump version to X commit (#93, #97, #100, #102) only touched package.json. As a result:

  • Marketplace clients reading .claude-plugin/marketplace.json see version 0.3.0.
  • The MCP server registers itself with the SDK (new McpServer({ ..., version })) as 0.3.0 regardless of installed version.
  • Anyone debugging "what version of claude-buddy do I have?" gets a misleading answer.

Fix

  • New scripts/sync-version.ts makes package.json the single source of truth and writes the manifest files to match. Supports --check for CI drift detection (non-zero exit on mismatch).
  • New "version" lifecycle script in package.jsonbun pm version <bump> (or npm version <bump>) now runs the sync and git adds the manifest files into the auto-generated version commit. No follow-up commit needed.
  • server/index.ts now imports version from package.json instead of a hardcoded literal, using the standard JSON import attribute syntax.
  • Catches up the manifest files to the current 0.5.2.

Verification

  • bun run typecheck passes (the with { type: "json" } import resolves cleanly).
  • bun test passes — 246/246 tests, no failures.
  • bun run sync-version --check exits 0 after this PR (drift resolved).
  • Re-running bun run sync-version is idempotent — reports "all version fields already at 0.5.2" and does not modify any file.
  • Smoke test: bun -e 'import pkg from "./package.json" with { type: "json" }; console.log(pkg.version)' prints 0.5.2.

Known minor side-effect

scripts/sync-version.ts uses JSON.stringify to write the manifest files. On the first future drift event (i.e. the next bun pm version <bump>), the existing em-dash escapes in the description fields will be re-encoded as raw characters. This is a one-time cosmetic round-trip; both forms are semantically identical JSON. Not addressed in this PR to keep the diff scoped to the version-sync fix, but happy to add normalization beforehand if you'd prefer the first sync commit to be purely version-only.

Future-proofing

CI could add bun run sync-version --check as a guard so this regression cannot recur. Happy to add in a follow-up if desired.

The plugin manifests (.claude-plugin/plugin.json, .claude-plugin/marketplace.json)
and the MCP server's hardcoded version string have all been frozen at 0.3.0 across
the 0.4.0, 0.5.0, 0.5.1, and 0.5.2 releases because only package.json was bumped.

Marketplace clients reading the manifest see 0.3.0, and the MCP server registers
itself with the SDK as 0.3.0 regardless of the installed version.

This change:
- Adds scripts/sync-version.ts to make package.json the single source of truth.
  Reads package.json and writes plugin.json + marketplace.json to match.
  Supports --check for CI drift detection (non-zero exit on mismatch).
- Wires it into the npm/bun "version" lifecycle in package.json so future
  `bun pm version <bump>` (or `npm version <bump>`) syncs all three files into
  the same auto-generated version commit. No follow-up commit needed.
- Replaces the hardcoded "0.3.0" in server/index.ts with an import from
  package.json using the standard JSON import attribute syntax.
- Catches up the manifest files to the current 0.5.2.

Signed-off-by: George Lee <grlee@users.noreply.github.com>
@grlee
grlee force-pushed the fix/sync-version-on-bump branch from 9b562b3 to ddb36c0 Compare June 10, 2026 11:54
@ramarivera

Copy link
Copy Markdown
Owner

Hey @grlee — triaging the queue post-rename. Good news: this is not superseded — current main still has no version-sync mechanism, so the idea stands. It does need a refresh though: main is now at 0.6.0, the plugin was renamed claude-buddy → coding-buddy, and npm trusted publishing landed (#132/#133), so the manifest contents your script touches have changed. A rebase updating the hardcoded bits should make this land smoothly.

🤖 Created with the help of AI (Claude Fable 5).

ramarivera added a commit that referenced this pull request Jul 28, 2026
package.json has been the only version field that moves. The plugin
manifests sat three minors behind at 0.8.0, and the version the MCP server
advertises to clients was further back still at 0.6.0 — so anything reading
the marketplace entry or the server handshake saw a release that shipped
weeks ago.

Numbers only. The recurrence is what actually needs fixing, and #110 (from
@grlee) already does it properly with a sync-version script wired into the
npm version lifecycle plus a --check mode for CI. This does not touch that
work.


Claude-Session: https://claude.ai/code/session_01H2GXsqpMvUhxBSNabSqZdk

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
ramarivera added a commit that referenced this pull request Jul 28, 2026
* feat(version): keep every version field in sync with package.json

package.json was the only version that moved. The plugin manifests fell three
minors behind and the MCP handshake fell further still, which #173 corrected by
hand — this stops it recurring.

- scripts/sync-version.ts rewrites drifted manifest fields, or reports them and
  exits 1 under --check.
- CI runs --check, so drift cannot land.
- The npm `version` lifecycle runs the fixer and git-adds .claude-plugin, so a
  bump updates the manifests in the same commit.
- server/index.ts imports pkg.version instead of a literal, which is better than
  syncing it — a test asserts no hardcoded semver returns to that call.

Design and the original implementation are from #110 by @grlee. That PR now
conflicts with main and lives on a fork, so it could not be rebased; this
reimplements it and #110 should be closed in its favour.

Verified both directions: injecting 0.1.0 into plugin.json makes --check exit 1
with an exact report, and the fixer restores the file byte-identically.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H2GXsqpMvUhxBSNabSqZdk

* fix(version): typecheck scripts, handle absent metadata, scope the source assertion

Review round 1 (Copilot, Devin):

- tsconfig `include` did not cover scripts/, so sync-version.ts was never
  typechecked despite CI now running it. Added scripts/**/*.ts, and set
  resolveJsonModule explicitly since server/index.ts now imports package.json.
  Verified with --listFilesOnly that both the script and package.json are in
  the program.
- The marketplace metadata.version setter was guarded by `if (doc.metadata)`,
  so an absent metadata block would be reported as drift the fixer could never
  resolve. It now creates the block. Verified by deleting the field: --check
  reports it, the fixer restores it.
- The "no hardcoded semver" assertion scanned all of server/index.ts. Scoped to
  the new McpServer(...) options object so an unrelated literal cannot fail it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H2GXsqpMvUhxBSNabSqZdk

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
@ramarivera

Copy link
Copy Markdown
Owner

Thanks for this @grlee — the diagnosis and the design were both right, and the drift had gotten worse since you filed: the plugin manifests were at 0.8.0 and the MCP handshake in server/index.ts was at 0.6.0 while the package shipped 0.9.3.

This PR now conflicts with main and lives on a fork, so I could not rebase it. I have landed the same approach in #174scripts/sync-version.ts with a --check mode, the npm version lifecycle hook, and server/index.ts importing pkg.version instead of a literal — plus a CI step running --check so drift cannot land again, and tests. Your PR is credited in the commit message and the PR body.

Two review findings on top of the original: the metadata.version setter needed to create an absent metadata block (otherwise --check could report drift the fixer would never repair), and scripts/** had to be added to the tsconfig include or the script CI depends on would never be typechecked.

Closing this in favour of #174 is up to @ramarivera. Either way — this was the right call and it is now shipped.

🤖 Created with the help of AI (Claude Opus 5).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants