fix(plugin): point Claude plugin.json at hooks/hooks.json so Cursor wrappers are not loaded - #450
Conversation
Claude Code was discovering hooks/hooks-cursor.json beside the shared hooks.json and invoking Cursor wrappers that expect camelCase hook_event_name values.
🦋 Changeset detectedLatest commit: 27e8f4a The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
commit: |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b69f3b7042
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| "agent-bundle": patch | ||
| --- | ||
|
|
||
| Point the unified `plugin` bundle's `.claude-plugin/plugin.json` `hooks` field at `./hooks/hooks.json` so Claude Code loads the Claude/Codex document instead of also discovering `hooks/hooks-cursor.json` and invoking Cursor wrappers that expect camelCase `hook_event_name` values (`preToolUse` / `postToolUse`). |
There was a problem hiding this comment.
Append the PR reference to the changeset summary
The new changeset summary ends without the required (#PR) suffix. When this changeset is consumed into the changelog, the release note will lack the repository-mandated PR traceability; append the applicable PR reference before merging.
AGENTS.md reference: AGENTS.md:L57-L58
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Done in d9bc62a (chore(changeset): reference #450): the summary now ends with (#450).
…document, not on pretty-printed spacing The on-disk .claude-plugin/plugin.json is compact JSON, so the substring '"hooks": "./hooks/hooks.json"' never matched. Parse and toMatchObject.
|
@codex review |
|
Codex Review: Didn't find any major issues. Nice work! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
… duplicate; pin every Claude hook_event_name (#470) * fix(claude): drop the manifest hooks pointer and pin every Claude hook_event_name Claude Code loads `hooks/hooks.json` on its own; `manifest.hooks` is only for additional documents. The `claude` target has named `./hooks/hooks.json` there since b256d44 and #450 added the same pointer to the unified `plugin` bundle. Claude Code 2.1.259 records a `hook-load-failed` plugin error for it: "Duplicate hooks file detected: ./hooks/hooks.json resolves to already-loaded file ... The standard hooks/hooks.json is loaded automatically, so manifest.hooks should only reference additional hook files" (reproduced with an isolated CLAUDE_CONFIG_DIR against a built Claude pack). #450's stated root cause does not hold: Claude Code never scans `hooks/` for other documents, so `hooks/hooks-cursor.json` is invisible to it. The live "native hook_event_name must equal postToolUse" errors came from the Claude wrapper path (`event-route-tool-after.mjs`, per the session transcript) during a rebuild/reinstall window of a directory marketplace, whose `${CLAUDE_PLUGIN_ROOT}` is the build output itself; only a Cursor-built wrapper bakes that camelCase constant. - claude.ts / plugin.ts: emit no `hooks` field on `.claude-plugin/plugin.json`. - tests/claude-hook-event-name.test.ts: for every supported Claude event route, the planned wrapper bakes the pinned PascalCase name, the hooks document is keyed by it, and a real Claude envelope passes validateNativeEventEnvelope; the live PostToolUse:Bash envelope is accepted by the Claude wrapper and rejected with the exact observed message only under a Cursor-baked validation; the unified bundle keeps `.mjs`/`.cursor.mjs` spellings apart; no Claude manifest pointer. - docs (en+zh hooks.mdx, installation.mdx) state the loader behavior. * chore(changeset): reference #470 --------- Co-authored-by: Ubuntu <zack@ubuntu-main.local>
Summary
pluginbundles emit bothhooks/hooks.json(Claude/Codex, PascalCasePreToolUse/PostToolUse) andhooks/hooks-cursor.json(Cursor, camelCasepreToolUse/postToolUse)..claude-plugin/plugin.jsonomittedhooks, so Claude Code could discover the Cursor document and invoke.cursor.mjswrappers. That producednative hook_event_name must equal postToolUseon every ClaudePostToolUse../hooks/hooks.json. Tests pin both host spellings.Test plan
rstestpackages/agent-bundle/tests/plugin-claude-hook-manifest.test.tspluginartifact's.claude-plugin/plugin.jsoncontains"hooks": "./hooks/hooks.json"