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: 5 additions & 0 deletions .changeset/cursor-hooks-manifest-validation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"agent-bundle": patch
---

Validate the Cursor hooks document that `.cursor-plugin/plugin.json` `hooks` names instead of always reading `hooks/hooks.json`, so `agent-bundle doctor` (`AB7319`/`AB7320`) and `validateCursorPlugin` (`AB6027`) no longer reject a unified `plugin` bundle whose Cursor manifest points at `hooks/hooks-cursor.json` beside the Claude-format `hooks/hooks.json`. A declared hooks file that is missing or leaves the plugin root is now an `AB6027` error, an inline `hooks` object is validated in place, and Doctor's `AB7322` registration proof applies the same folder-discovery fallback. (#442)
6 changes: 3 additions & 3 deletions docs/diagnostics.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ even when no error diagnostic was reported.
| Code | Severity | Trigger | Recovery |
| --- | --- | --- | --- |
| `AB6026` | info | Every Cursor host-validation report states that Cursor publishes no plugin-validate devtools verb and names the vendored schema pin used for local validation. | Review the pinned Cursor schema provenance before changing the local validator contract. |
| `AB6027` | error | A required generated Cursor document is missing or a present plugin, marketplace, MCP, or hooks document is unreadable, invalid JSON, or rejected by its pinned schema. | Repair the generated Cursor JSON document so it satisfies the vendored pinned schema, then rebuild. |
| `AB6027` | error | A required generated Cursor document is missing or a present plugin, marketplace, MCP, or hooks document is unreadable, invalid JSON, or rejected by its pinned schema. The hooks document is the one `.cursor-plugin/plugin.json` `hooks` names — a plugin-root-relative file (`hooks/hooks.json` for the `cursor` target, `hooks/hooks-cursor.json` for the unified `plugin` target, reported under that path) or an inline object (`.cursor-plugin/plugin.json#/hooks`) — falling back to `hooks/hooks.json` folder discovery only when the field is absent; a declared file that is missing or resolves outside the plugin root is an error, and any other `hooks/hooks.json` beside a named document is not read. | Repair the generated Cursor JSON document so it satisfies the vendored pinned schema, then rebuild. |
| `AB6028` | error | Generated bytes violate pinned Cursor loader evidence: manifest-candidate precedence selects a fallback manifest, a symlink resolves outside the bundle, or `CURSOR_PLUGIN_ROOT` appears outside loader-substituted fields. | Repair the generated Cursor layout, token locations, or symlinks to match the pinned loader evidence, then rebuild. |
| `AB6029` | info / warning | The Cursor Agent version probe is unavailable (`ENOENT`, info) or cannot complete successfully (warning). Local pinned-schema validation still runs. | Install Cursor Agent or repair `cursor-agent --version` when local CLI version evidence is required, then rerun artifact validation. |

Expand Down Expand Up @@ -696,7 +696,7 @@ host CLI, repair a bundle, or perform a live protocol exchange.
| Code | Severity | Trigger | Recovery |
| --- | --- | --- | --- |
| `AB7319` | error | A host tree resolved from `doctor --from` violates its pinned document schemas or process-free loader rules. The message retains the originating build-validator code and detail. | Rebuild that host bundle from valid source bytes, then rerun Doctor. |
| `AB7320` | error / info | Error when a `.cursor-plugin/plugin.json` install violates Cursor's pinned document schemas or token-location rules, when a root `plugin.json` install that declares an Agent Plugins `$schema` violates the pinned Agent Plugins 1.0.0 contract (`AB6035`–`AB6037`, retained in the message), or when any local plugin contains a symlink that escapes `~/.cursor/plugins/local`; the inventory entry is reported as `corrupt`. Info naming the contract applied to an Agent Plugins install, or stating that a `.claude-plugin/plugin.json` (or schema-less root `plugin.json`) install has no Cursor-side pinned static document contract; loader-recognized entries remain `installed`. | Reinstall an invalid Cursor plugin, rebuild an invalid portable bundle, or repair an escaping symlink. For other manifest flavors, use that ecosystem's validator when static document proof is required. |
| `AB7320` | error / info | Error when a `.cursor-plugin/plugin.json` install violates Cursor's pinned document schemas or token-location rules (the hooks document checked is the one the manifest `hooks` field names, so a unified `plugin` bundle's Claude-format `hooks/hooks.json` beside its `hooks/hooks-cursor.json` is not a finding), when a root `plugin.json` install that declares an Agent Plugins `$schema` violates the pinned Agent Plugins 1.0.0 contract (`AB6035`–`AB6037`, retained in the message), or when any local plugin contains a symlink that escapes `~/.cursor/plugins/local`; the inventory entry is reported as `corrupt`. Info naming the contract applied to an Agent Plugins install, or stating that a `.claude-plugin/plugin.json` (or schema-less root `plugin.json`) install has no Cursor-side pinned static document contract; loader-recognized entries remain `installed`. | Reinstall an invalid Cursor plugin, rebuild an invalid portable bundle, or repair an escaping symlink. For other manifest flavors, use that ecosystem's validator when static document proof is required. |

## Install replacement and Doctor install comparison (`AB7005`, `AB7307`–`AB7309`, `AB7321`)

Expand Down Expand Up @@ -807,7 +807,7 @@ that registration statically and never writes `~/.cursor/hooks.json`.

| Code | Severity | Meaning | Recovery |
| --- | --- | --- | --- |
| `AB7322` | info / error | Info: an installed `.cursor-plugin/plugin.json` plugin registers plugin-scoped hooks (events and command count listed) and the script each command executes — `${CURSOR_PLUGIN_ROOT}/…` or any relative path, including an interpreter's entry operand — exists under the plugin root (`hooks.state = registered`). Error: the declared hooks file is missing (`missing`), is not a regular file or not a `{ version, hooks: { <event>: [{ command }] } }` document, or an executed script is absent (`stale`). Documents and scripts are probed with `stat` before any read, so a FIFO cannot stall Doctor. | Reinstall the plugin from a bundle whose emitted hooks document and scripts are intact. |
| `AB7322` | info / error | Info: an installed `.cursor-plugin/plugin.json` plugin registers plugin-scoped hooks (from the document its manifest `hooks` field names, or from `hooks/hooks.json` folder discovery when the field is absent; events and command count listed) and the script each command executes — `${CURSOR_PLUGIN_ROOT}/…` or any relative path, including an interpreter's entry operand — exists under the plugin root (`hooks.state = registered`). Error: the declared hooks file is missing (`missing`), is not a regular file or not a `{ version, hooks: { <event>: [{ command }] } }` document, or an executed script is absent (`stale`). Documents and scripts are probed with `stat` before any read, so a FIFO cannot stall Doctor. | Reinstall the plugin from a bundle whose emitted hooks document and scripts are intact. |
| `AB7323` | warning | `~/.cursor/hooks.json` registers a command whose executed file (after leading `NAME=value` assignments, `env`, and interpreter options) points into an installed plugin directory — compared on path-component boundaries, case-folded on Windows — so Cursor would deliver that hook twice; or the file is not a valid hooks document. | Remove the plugin-pointing entries or repair the file; manifest registration alone is sufficient. |
| `AB7324` | info / warning / error | A staged marketplace repository under `~/.cursor/agent-bundle/marketplaces/<name>` (from `install cursor --mode marketplace`) is imported by Cursor (matching plugin under `~/.cursor/plugins/cache`; info, `registered`), still awaiting the Customize "Add Plugins from Local Repository" step (warning, `unregistered`), or incomplete (error, `corrupt`: manifests missing or failing the pinned schemas, no resolvable Git HEAD, HEAD naming a commit object that does not exist, or a working tree that differs from committed HEAD — verified read-only through `git cat-file -e` / `git --no-optional-locks status` when `git` is available). | Complete the Customize import, use `--mode local`, or remove the staged directory and rerun the installer. |

Expand Down
Loading
Loading