Release 1.2.2 — the plugin's MCP server resolves against the plugin root - #871
Conversation
`.mcp.json` named `./dist/commitlore.mjs` and set `"cwd": "."`, and both of
those resolve against the *session's* working directory rather than the
plugin's install directory. The plugin MCP server therefore died at launch
with MODULE_NOT_FOUND in every session whose cwd was not a built commitlore
checkout. Capture is MCP-only, so those sessions committed no records, and the
only visible symptom was one line about a cached connection failure. The one
cwd where the defect cannot appear is this repository, which is where every
existing check ran.
The entry point is now `${CLAUDE_PLUGIN_ROOT:-.}/dist/commitlore.mjs` and there
is no `cwd` — the form ADR-0026 and the F14 ticket already documented. The
default is what keeps this repository's own registration working when a host
loads it as an ordinary project file, where nothing sets that variable.
Readers of a registration now expand `${VAR}` and `${VAR:-default}` the way a
host expands them before it spawns. Without that, doctor's unattended-initiator
probe launched the literal `${...}` as a path and reported a working
registration unhealthy — a report that sends an operator to repair the one
thing that is not broken. An unset placeholder with no default is left as
written: a host refuses that registration outright, and expanding it to nothing
would turn the refusal into a plausible-looking path whose failure names a file
nobody wrote.
The manifest checks now launch from a directory that is not a checkout, and one
of them drives the server to an MCP initialize — the launch the old
configuration could not complete and the old check never attempted.
Closes #870
Claude-Session: https://claude.ai/code/session_01USc9G3aJ1s8pnhWy5K5hLr
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Version fields, install pins and the changelog entry for 1.2.2. The release carries one fix: the plugin's MCP server resolved its entry point against the session's working directory, so it died at launch with MODULE_NOT_FOUND in every session that was not a built commitlore checkout (#870). Capture is MCP-only, so those sessions recorded nothing. The install pins move; the field-report paragraph in each README keeps saying v1.2.1, because that is the version the run it describes was made on and a measurement does not follow the version number. `dist/` is deliberately not in this branch. `canonical-merge.yml` rebuilds the bundle from the merged tree and refuses a pull request that touches it, so the committed bundle matches the source it lands with. Claude-Session: https://claude.ai/code/session_01USc9G3aJ1s8pnhWy5K5hLr Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
CommitLore — record lintTrailers: clean — 2 commits in Active constraints for the paths this PR touchesLimits (234)
Ruled out (380)
Truncated: 364 lines omitted — the comment hit GitHub's 65000 character limit. Trailer violations fail this check. Active constraints are informational — they are what the repository already decided, not a verdict on this PR. |
|
What is failing
Why the fix is not in this branch
So this is #720's shape: source only, from a host that cannot run the canonical builder. I checked whether a plain local build would do instead of assuming it would not. Against What clears it
So that dispatch is a maintainer step. I have not re-run the failed jobs: the failure is deterministic and understood, not a flake, and a re-run would report the same thing. What is green
Locally: I will keep watching this pull request until it is merged or closed. Generated by Claude Code |
Closes #870.
The defect
.mcp.jsonnamed the entry point as./dist/commitlore.mjsand set"cwd": ".", and both of those resolve against the session's working directory rather than the plugin's install directory. So node was asked for<session-cwd>/dist/commitlore.mjs, which does not exist, and the plugin's MCP server exited in under 60ms withMODULE_NOT_FOUND.Capture is MCP-only, so a session with the plugin installed committed no records at all, and the only visible symptom was one line saying a connection failure had been cached. The
0.8.0and1.2.0plugin caches are identical in this respect — no release ever shipped a working one.The fix
{ "mcpServers": { "commitlore": { "command": "node", "args": ["${CLAUDE_PLUGIN_ROOT:-.}/dist/commitlore.mjs", "mcp"] } } }This is the form ADR-0026 and
docs/tickets/F14-distribution.mdalready documented while the file said otherwise.The
:-.default is load-bearing rather than decoration: this repository's.mcp.jsonis also an ordinary project file here, loaded by a host that sets no plugin root, and without the fallback the dogfooding install would break in exchange for fixing the plugin.A second defect the first one exposed
.mcp.jsonis a launch instruction for a host, and hosts expand${VAR}and${VAR:-default}before they spawn anything — the readers insrc/core/mcp-registration.tsreturned the raw text. Doctor's unattended-initiator probe would therefore have launched a literal${...}as a path and reported this repository's own registration unhealthy, sending an operator to repair the one thing that is not broken.registeredMcpLaunchnow expands both forms. An unset placeholder with no default is left as written on purpose: a host refuses that registration outright, and expanding it to nothing would turn the refusal into a plausible-looking path whose failure names a file nobody wrote.Why nothing caught it
A checkout is the one cwd where a session-relative path is also the plugin's path, and that is where the suite, the release gate and the maintainers all work. So:
test/manifest.test.tsnow launches from a directory that is not a checkout, asserts the entry point is bound to${CLAUDE_PLUGIN_ROOT, asserts nocwd, and drives the server to an MCPinitializerather than stopping at "something resolved" — the same distinction A machine with both installs silently runs the older one: PATH wins over CLAUDE_PLUGIN_ROOT #483 forced on the plugin entry point two releases ago.test/doctor.test.tscovers both branches of the expansion rule: a${VAR:-<wrapper>}registration probes healthy, and an unset placeholder with no default stays literal and warns.test/codex-plugin.test.tsanddocs/COMPATIBILITY.mdfollow the manifest.Reverting
.mcp.jsonfails the new manifest checks and passes the old one.Release 1.2.2
Version fields moved in
package.json,package-lock.json(both root declarations),.claude-plugin/plugin.json,.codex-plugin/plugin.jsonandserver.json; install pins moved in four READMEs,install.shandinstall.ps1;CHANGELOG.mdhas the entry.The "field report" paragraph in each README still says v1.2.1 — that is the version the run it describes was made on, and a measurement does not follow the version number.
Verified locally
node scripts/check-release-version.mjs v1.2.2— consistent across all seven sourcesnpx tsc -p tsconfig.json --noEmitbash spec/verify.sh— 32 fixtures + protocol example sync + vocab tablenode scripts/check-readme-numbers.mjsnpx vitest run test/manifest.test.ts test/codex-plugin.test.ts test/compatibility-matrix.test.ts test/doctor.test.ts— 160 passedNot verified
Codex reads the same
.mcp.json, declared by.codex-plugin/plugin.json, and whether Codex performs the same placeholder expansion was not measured — no Codex install was available. What is measured is that the Claude Code plugin path now launches from a foreign cwd and answersinitialize. If Codex does not expand, its launch is no worse than the relative path it had before; that is a claim about the shape of the change, not a test result.No cross-provider review was run on this change.
dist/is deliberately absentcanonical-merge.ymlrefuses a pull request that touchesdist/orinstaller/canonical-artifact.json, and rebuilds the bundle from the merged tree so the committed bundle matches the source it lands with. This branch is source-only.🤖 Generated with Claude Code
https://claude.ai/code/session_01USc9G3aJ1s8pnhWy5K5hLr
Generated by Claude Code