You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: .archcore/plugin/cli-integration-tests.rule.md
+4-3Lines changed: 4 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -16,7 +16,7 @@ Any change to plugin code that invokes the `archcore` CLI MUST be accompanied by
16
16
In particular:
17
17
18
18
1. Every shell-out from a `bin/*` script to the CLI (`archcore <subcmd> [args...]`) MUST be covered by a unit test that asserts the invoked subcommand via the `MOCK_ARCHCORE_LOG` mechanism (see `mock_archcore_logging` in `test/helpers/common.bash`).
19
-
2. Every `args` array in `.mcp.json`, `.codex.mcp.json`, and `cursor.mcp.json`, and every subcommand in any new `hooks/*.json`-referenced script, MUST name only canonical subcommands. The canonical surface as of plugin v0.4.0 is `config | doctor | help | hooks | init | mcp | status | update`.
19
+
2. Every `args` array in `.mcp.json`, `.codex.mcp.json`, and `docs/cursor.mcp.example.json`, and every subcommand in any new `hooks/*.json`-referenced script, MUST name only canonical subcommands. The canonical surface as of plugin v0.4.0 is `config | doctor | help | hooks | init | mcp | status | update`. Note that `docs/cursor.mcp.example.json` may also include `--project <path>` after `mcp` — this is a flag, not a subcommand, and is locked by `test/structure/cursor-plugin.bats`.
20
20
3. Every prescriptive `` `archcore <subcmd>` `` reference in `README.md` MUST be guarded by `test/structure/readme-cli-references.bats`. Internal `.archcore/` design docs are intentionally excluded from this guard — they hold historical spec text that may legitimately reference renamed commands.
21
21
4. Skill or agent prose that instructs the agent to run `archcore <subcmd>` as a shell command MUST be reviewed against the canonical CLI surface; prefer routing CLI work through MCP tools (`mcp__archcore__*`) rather than shell-outs, so the agent stays inside the validated path.
22
22
@@ -104,15 +104,16 @@ assert_output ""
104
104
The rule is enforced by these tests, which ship in the plugin:
105
105
106
106
-**`test/structure/readme-cli-references.bats`** — every code-quoted `` `archcore <subcmd>` `` in `README.md` must name a canonical subcommand. The allowlist is hardcoded in the test file and tracks the CLI's `archcore --help` surface.
107
+
-**`test/structure/cursor-plugin.bats`** — locks the contents of `docs/cursor.mcp.example.json`: command is `archcore`, args contain `mcp` followed by `--project ${workspaceFolder}`, no `cwd` field, and no legacy `cursor.mcp.json` at the plugin root.
107
108
-**`test/unit/validate-archcore.bats`** — invocation-log assertions using `MOCK_ARCHCORE_LOG` for `validate-archcore`. The two relevant tests are `validate-archcore calls archcore doctor (not validate)` and `validate-archcore invokes only allowlisted subcommands`.
108
-
-**`test/unit/session-start.bats`** — covers the missing-CLI fallback (the hook must exit 0 and emit install guidance, not block the session) and verifies `session-start invokes only the 'hooks' subcommand`.
109
+
-**`test/unit/session-start.bats`** — covers the missing-CLI fallback (the hook must exit 0 and emit install guidance, not block the session), verifies `session-start invokes only the 'hooks' subcommand`, and asserts the plugin-install-dir guard (silent exit when sibling `.cursor-plugin/`, `.claude-plugin/`, or `.codex-plugin/` manifests are present).
109
110
110
111
When the canonical CLI surface changes upstream (new subcommand added, renamed, or removed), update `ARCHCORE_SUBCOMMANDS` in `readme-cli-references.bats` and the equivalent constant in any unit test that asserts on it. Any new subcommand the plugin starts invoking from a bin/ script gets its own invocation-log assertion before merge.
111
112
112
113
A change that does not satisfy this rule is rejected in code review. The rule applies to:
113
114
114
115
- Any script under `bin/` that calls `archcore`
115
-
-`args` arrays in `.mcp.json`, `.codex.mcp.json`, `cursor.mcp.json`
116
+
-`args` arrays in `.mcp.json`, `.codex.mcp.json`, `docs/cursor.mcp.example.json`
116
117
- Any new hook config (`hooks/*.json`) referencing a CLI-invoking script
117
118
- README and other user-facing prescriptive docs naming `` `archcore <subcmd>` `` invocations
118
119
- Skill or agent prompt text that instructs the agent to run an `archcore` shell command
Copy file name to clipboardExpand all lines: .archcore/plugin/component-registry.doc.md
+11-8Lines changed: 11 additions & 8 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -112,14 +112,16 @@ Hook 6 (`check-precision`) is the Phase 1 implementation of the Precision Initia
112
112
113
113
Historical note: a prior revision had a `PostToolUse` entry with matcher `Write|Edit` invoking `validate-archcore`. It was removed because PreToolUse already blocks all Write/Edit to `.archcore/*.md` (PostToolUse fires only on success), so the matcher was dead weight forking a shell on every Write/Edit anywhere in the repo. See `hooks-validation-system.spec.md` for the rationale. Structure tests guard against its re-introduction.
114
114
115
+
`bin/session-start` carries a plugin-install-dir guard (see `cursor-mcp-architecture.adr.md`): when cwd contains a sibling `.cursor-plugin/`, `.claude-plugin/`, or `.codex-plugin/` manifest, the hook exits silently. This prevents the hook from emitting the plugin's bundled `.archcore/` (if any future regression reintroduces it) as the user's knowledge base.
116
+
115
117
### Bin Scripts
116
118
117
119
The `bin/` tree contains hook scripts and the shared stdin-normalization library. The plugin **does not bundle the Archcore CLI binary or any launcher wrapper** — it invokes `archcore` directly from PATH. Users install the CLI globally via the official installer at https://docs.archcore.ai/cli/install/. See `remove-bundled-launcher-global-cli.idea.md` for the rationale.
|`bin/session-start`| SessionStart | Sources the normalizer; if `archcore` is not on PATH, prints an install message pointing at https://docs.archcore.ai/cli/install/ and exits 0. Otherwise detects missing `.archcore/` and emits init guidance (instructs the agent to call `mcp__archcore__init_project`), or invokes `archcore hooks <host> session-start` directly, then calls `bin/check-staleness`. Always exits 0. |
124
+
|`bin/session-start`| SessionStart | Sources the normalizer; if `archcore` is not on PATH, prints an install message pointing at https://docs.archcore.ai/cli/install/ and exits 0. Refuses to run when cwd contains a sibling plugin manifest (see `cursor-mcp-architecture.adr.md` — Layer 3 defense). Otherwise detects missing `.archcore/` and emits init guidance (instructs the agent to call `mcp__archcore__init_project`), or invokes `archcore hooks <host> session-start` directly, then calls `bin/check-staleness`. Always exits 0. |
123
125
|`bin/check-archcore-write`| PreToolUse | Blocks direct Write/Edit to `.archcore/**/*.md` with exit 2 + stderr message redirecting to MCP tools. Allows `.archcore/settings.json` and `.archcore/.sync-state.json`. Allows all paths outside `.archcore/`. |
124
126
|`bin/check-code-alignment`| PreToolUse | Injects relevant `.archcore/` context for source-file Write/Edit. Greps `.archcore/**/*.md` for documents referencing the edit path (directory prefixes, longest-first). Ranks by specificity → type priority (rule > cpat > adr > spec > guide). Emits top-3 via `hookSpecificOutput.additionalContext` (Claude Code/Codex/Copilot) or `additional_context` (Cursor). Never blocks; always exits 0. Honors `ARCHCORE_DISABLE_INJECTION=1` escape hatch and `.archcore/settings.json → codeAlignment.sourceRoots` override. |
125
127
|`bin/validate-archcore`| PostToolUse | Runs `archcore doctor` directly (timeout 2s) after MCP document operations (by tool_name prefix). The subcommand invocation is locked by `test/structure/readme-cli-references.bats` against the canonical CLI surface and a `MOCK_ARCHCORE_LOG`-backed assertion in `test/unit/validate-archcore.bats`. The legacy Write/Edit branch in the script is retained as defensive code but is never reached from the current hooks config. Outputs JSON `hookSpecificOutput` when issues found, empty otherwise. Silently exits 0 if the CLI is unavailable. Always exits 0. |
@@ -131,12 +133,13 @@ The `bin/` tree contains hook scripts and the shared stdin-normalization library
| Unit tests |`test/unit/`|112| Test each bin script: stdin parsing, host detection, exit codes, output format, edge cases. Includes `check-staleness.bats` (24h rate limit, corrupt-stamp recovery) and `check-code-alignment.bats` (source-root filter, specificity ranking, top-3 cap, settings override, Cursor JSON shape, non-blocking safety). `session-start.bats` covers the missing-CLI fallback path now that the launcher is gone. |
135
-
| Structure tests |`test/structure/`| 100 | Validate JSON configs, skill frontmatter, agent frontmatter, hook references, script permissions, rules. `hooks.bats` includes anti-regression invariants: no Write/Edit matcher on PostToolUse, no postToolUse event on Cursor, exact event-set invariants per host. `codex-plugin.bats` enforces Codex manifest, marketplace schema, hooks shape, MCP wiring (`command: "archcore"` on PATH), TOML agents, and parity between `commands/*.md` wrappers and `skills/<name>/SKILL.md`. `readme-cli-references.bats` validates every `archcore <subcmd>` reference in README against the canonical surface (`config doctor help hooks init mcp status update`). |
136
+
| Unit tests |`test/unit/`|115| Test each bin script: stdin parsing, host detection, exit codes, output format, edge cases. Includes `check-staleness.bats` (24h rate limit, corrupt-stamp recovery), `check-code-alignment.bats` (source-root filter, specificity ranking, top-3 cap, settings override, Cursor JSON shape, non-blocking safety), and `session-start.bats`(covers the missing-CLI fallback path and the plugin-install-dir guard for cursor/claude/codex sibling manifests). |
137
+
| Structure tests | `test/structure/` | 105 | Validate JSON configs, skill frontmatter, agent frontmatter, hook references, script permissions, rules. `hooks.bats` includes anti-regression invariants: no Write/Edit matcher on PostToolUse, no postToolUse event on Cursor, exact event-set invariants per host. `cursor-plugin.bats` locks `docs/cursor.mcp.example.json` shape (command, `--project ${workspaceFolder}` in args, no `cwd` field, no legacy `cursor.mcp.json` at root). `no-bundled-archcore-refs.bats` ensures no distributable file references concrete paths under `.archcore/<category>/<slug>.<type>.md` (which would only be plugin-internal docs). `codex-plugin.bats` enforces Codex manifest, marketplace schema, hooks shape, MCP wiring (`command: "archcore"` on PATH), TOML agents, and parity between `commands/*.md` wrappers and `skills/<name>/SKILL.md`. `readme-cli-references.bats` validates every `archcore <subcmd>` reference in README against the canonical surface (`config doctor help hooks init mcp status update`). |
136
138
| Fixtures |`test/fixtures/stdin/`| 12 files | Mock stdin JSON for Claude Code, Cursor, Copilot, Codex CLI, and malformed inputs |
| CI |`.github/workflows/test.yml`| — | GitHub Actions on push/PR to `dev`: macOS + Linux matrix, bats + shellcheck |
142
+
| Release |`.github/workflows/release.yml`| — | GitHub Actions on tag push: strips dev-only artifacts, force-pushes the clean tree to `main`. See `docs/release.md` for the blocklist. |
140
143
141
144
Run `make verify` for full check. Run `make test` for tests only. See `plugin-testing.guide.md` for details.
142
145
@@ -159,7 +162,7 @@ The `command` resolves through PATH — users must have the Archcore CLI install
159
162
160
163
Codex CLI uses `.codex-plugin/plugin.json` to point at plugin-root `.codex.mcp.json`, which uses the same shape — `command: "archcore"`, `args: ["mcp"]`. No `cwd` indirection, no `env_vars` allowlist gymnastics: with the launcher gone, Codex's plugin-cache rebase of `cwd: "."` is no longer needed.
161
164
162
-
Cursor users still register MCP externally via Cursor's MCP settings or a project `mcp.json`. The bundled `cursor.mcp.json` template adds `cwd: "${workspaceFolder}"` to scope the MCP to the active project — required because Cursor does not auto-inject a project CWD into plugin-spawned processes.
165
+
Cursor is the exception. The plugin **does not** ship a plugin-MCP for Cursor — no `mcp.json` at the plugin root and no `mcpServers` field in `.cursor-plugin/plugin.json`. Cursor 2.5+ would auto-detect a plugin-root `mcp.json` and register it under "Plugin MCP Servers," but it spawns plugin-MCPs with cwd = plugin install directory, and its MCP stdio schema has no `cwd` field to redirect to the workspace ([forum #74861](https://forum.cursor.com/t/allow-workspacefolder-in-mcp-project-configration/74861), [forum #99215](https://forum.cursor.com/t/how-get-the-correct-current-work-directory-in-mcp-server/99215)). Shipping a plugin-MCP would cause the server to serve the plugin install dir instead of the user's workspace. Cursor users instead copy `docs/cursor.mcp.example.json` into `~/.cursor/mcp.json` (user-scoped) or `.cursor/mcp.json` (project-scoped); the template passes `--project ${workspaceFolder}` in `args` to make the workspace explicit. Full rationale and three-layer defense in `cursor-mcp-architecture.adr.md`.
163
166
164
167
Rationale: see `remove-bundled-launcher-global-cli.idea.md`. The previous bundled launcher (download-on-first-use, checksum-verified, cached per host) is removed; CLI lifecycle now decouples cleanly from plugin releases.
165
168
@@ -168,14 +171,14 @@ Rationale: see `remove-bundled-launcher-global-cli.idea.md`. The previous bundle
|`cursor.mcp.json`| Cursor | Reference MCP config for users to copy into `~/.cursor/mcp.json` or `.cursor/mcp.json` (Cursor does not auto-register plugin MCP)|
181
+
|`docs/cursor.mcp.example.json`| Cursor | Reference MCP config for users to copy into `~/.cursor/mcp.json` or `.cursor/mcp.json`. Lives under `docs/` (not the plugin root) so it cannot trigger Cursor's plugin-MCP auto-detection. Passes `--project ${workspaceFolder}` in `args`.|
179
182
|`hooks/hooks.json`| Claude Code | Hook event config (PascalCase) |
0 commit comments