@chimix/agentscan 1.3.0 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +384 -0
- package/README.md +369 -171
- package/dist/cli.js +11164 -9974
- package/package.json +5 -3
package/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,390 @@ and [v0.4.0](https://github.com/SimaAlexandru99/agentscan/releases/tag/v0.4.0).
|
|
|
11
11
|
(the published package version). A separate 1.0.1 npm tag would need an
|
|
12
12
|
intermediate commit that this train does not cut.
|
|
13
13
|
|
|
14
|
+
## Unreleased
|
|
15
|
+
|
|
16
|
+
## 2.3.1 — 2026-11-14
|
|
17
|
+
|
|
18
|
+
- Codex: `[hooks.state]`, the per-hook trust record Codex writes into
|
|
19
|
+
`config.toml`, is no longer read as a hook group (it raised
|
|
20
|
+
`config.unreadable` on every machine that had trusted a hook).
|
|
21
|
+
|
|
22
|
+
## 2.3.0 — 2026-11-14
|
|
23
|
+
|
|
24
|
+
Six more agents, each from a capture of its official docs read on
|
|
25
|
+
2026-11-14 (`docs/spec/`). Anything a capture lists as unverified never
|
|
26
|
+
raises an error. **163 checks**, **694 tests**.
|
|
27
|
+
|
|
28
|
+
- **Claude Desktop:** `claude_desktop_config.json` MCP servers under
|
|
29
|
+
`--global` (macOS, Windows `%APPDATA%\Claude`, Linux); unknown top-level keys
|
|
30
|
+
are ignored. Installed extension manifests
|
|
31
|
+
(`Claude Extensions/<id>/manifest.json`):
|
|
32
|
+
`claude-desktop.extension.missing-field` (warning; `dxt_version` is accepted).
|
|
33
|
+
- **Amp:** `amp.mcpServers` in the nearest `.amp/settings.json` and, under
|
|
34
|
+
`--global`, `~/.config/amp/settings.json`; `~/.config/amp/skills` and
|
|
35
|
+
`~/.config/agents/skills` as Agent Skills.
|
|
36
|
+
- **Zed:** `context_servers` in `.zed/settings.json` and the user settings
|
|
37
|
+
(JSONC). Extension-provided servers and the `{path, args}` command form are
|
|
38
|
+
launchable.
|
|
39
|
+
- **Qwen Code:** `.qwen/settings.json` MCP (`command` / `url` / `httpUrl`) and
|
|
40
|
+
hooks (23 events, `command` / `http` / `prompt`), `.qwen/skills`.
|
|
41
|
+
- **Goose:** `config.yaml` extensions under `--global`; `sse` is flagged
|
|
42
|
+
because Goose does not support it.
|
|
43
|
+
- **Factory Droid:** `.factory/mcp.json`, unwrapped `.factory/hooks.json` (user
|
|
44
|
+
`settings.json` fallback), `.factory/skills`, and custom droids
|
|
45
|
+
(`factory.droid.invalid-name`, `factory.droid.empty-body`).
|
|
46
|
+
|
|
47
|
+
## 2.2.0 — 2026-11-14
|
|
48
|
+
|
|
49
|
+
Aligned with the vendor docs re-read on 2026-11-14: all 46 drifted spec
|
|
50
|
+
captures were re-read, and `spec:check` is clean. **144 checks**,
|
|
51
|
+
**673 tests**.
|
|
52
|
+
|
|
53
|
+
- New `codex.agent.missing-field` (error): a Codex custom agent file
|
|
54
|
+
(`.codex/agents/*.toml`, and `$CODEX_HOME/agents` under `--global`) must
|
|
55
|
+
define string `name`, `description` and `developer_instructions`.
|
|
56
|
+
- Codex skills come from `.agents/skills` (repo walk and `~/.agents/skills`),
|
|
57
|
+
as the Codex skills page documents. `.codex/skills` is no longer scanned.
|
|
58
|
+
- Copilot CLI project MCP: `.github/mcp.json` is read as `copilot-json`.
|
|
59
|
+
- `--global` reads `~/.cursor/skills`; Cline also reads `.clinerules/skills`.
|
|
60
|
+
- Antigravity skills: `name` is optional and defaults to the folder name.
|
|
61
|
+
- Command Code agents accept `permissionMode` `accept-edits` and `yolo`.
|
|
62
|
+
- Claude: an `agent` hook on `PermissionRequest` is incompatible; a skill
|
|
63
|
+
without `description` falls back to the first non-empty line.
|
|
64
|
+
- Kiro accepts the CLI V3 `AgentSpawn` / `agentSpawn` spellings.
|
|
65
|
+
- `windsurf.hook.unknown-event` is a warning: the Cascade event table left the
|
|
66
|
+
live docs (only `post_setup_worktree` is still quoted).
|
|
67
|
+
|
|
68
|
+
## 2.1.0 — 2026-11-14
|
|
69
|
+
|
|
70
|
+
Fewer false findings when the scan root is a home directory or `--global` is
|
|
71
|
+
on, from an audit of four machines (692 findings on one home, about 440 of
|
|
72
|
+
them false or noise). **143 checks**, **656 tests**. No rule id was added or
|
|
73
|
+
removed.
|
|
74
|
+
|
|
75
|
+
- `check --global` with no project in the working directory scans the
|
|
76
|
+
documented global locations instead of exiting 2.
|
|
77
|
+
- `claude.agent.duplicate-name`: `~/.claude/agents` is read once when the scan
|
|
78
|
+
root is home, so one file is no longer reported as its own duplicate.
|
|
79
|
+
- `claude.hook.missing-script`: a quoted script operand such as
|
|
80
|
+
`"${CLAUDE_PLUGIN_ROOT}/scripts/x"` is unquoted before it is resolved.
|
|
81
|
+
- `config.unreadable`: `EACCES` and `EPERM` are an `info` permission note, once
|
|
82
|
+
per path, and podman storage under `~/.local/share/containers` is skipped.
|
|
83
|
+
- `skill.locked-not-installed`: a `skills-lock.json` entry resolves beside the
|
|
84
|
+
lock's own directory, so a lock inside a worktree or dot-directory finds its
|
|
85
|
+
skills.
|
|
86
|
+
- `skill.broken-reference`: a reference into a sibling skill named earlier in
|
|
87
|
+
the same sentence resolves there, also across a line wrap; under `--global`
|
|
88
|
+
a Claude skill's reference also resolves against the repo that owns its
|
|
89
|
+
`.claude/skills`.
|
|
90
|
+
- `claude.agent.invalid-name` follows the current sub-agents page: an error
|
|
91
|
+
only for an empty name, a name over 256 characters, or one containing `:`.
|
|
92
|
+
Digits, capitals and spaces are accepted.
|
|
93
|
+
- `copilot.hook.unknown-event`: a PascalCase twin of a documented camelCase
|
|
94
|
+
event (for example `Notification`) is a `warning` that names the documented
|
|
95
|
+
spelling.
|
|
96
|
+
- `windsurf.rule.missing-trigger` is `info`. Under `--global`, plugin caches,
|
|
97
|
+
marketplaces, backups and installed-plugin copies are skipped for Windsurf
|
|
98
|
+
rules, `budget.*` and `scan.truncated`.
|
|
99
|
+
|
|
100
|
+
## 2.0.0 — 2026-11-12
|
|
101
|
+
|
|
102
|
+
Breaking for configs that still name the 0.7 rule ids or the old threshold
|
|
103
|
+
keys. `ignoreRules`, `ignoreFindings`, and `explain` accept only the printed
|
|
104
|
+
ids (`claude.hook.missing-script`, not `hook.missing-script`).
|
|
105
|
+
`thresholds.skillDescriptionBytes` and `thresholds.skills` are rejected; the
|
|
106
|
+
listing budget is `thresholds.skillListingChars`. **143 checks**, **647 tests**.
|
|
107
|
+
|
|
108
|
+
- Kiro agents: `.kiro/agents/**/*.json` and `*.md` on the ancestor walk, and
|
|
109
|
+
`~/.kiro/agents/` under `--global`. The name is the path relative to that
|
|
110
|
+
directory, without the extension. A nearer workspace file shadows a farther
|
|
111
|
+
workspace file and a global file with the same name. No field is required.
|
|
112
|
+
No new rule id. A `.json` and a `.md` with the same stem in one directory
|
|
113
|
+
are both kept.
|
|
114
|
+
- Antigravity rules and skills. Workspace `GEMINI.md` and `.agents/GEMINI.md`,
|
|
115
|
+
one level of `.agents/rules/*.md` and legacy `.agent/rules/*.md`, and
|
|
116
|
+
`.agents/rules.json` as shape only (`inherits` and `entries` paths are not
|
|
117
|
+
opened). `--global` adds `~/.gemini/AGENTS.md`, `~/.gemini/GEMINI.md`,
|
|
118
|
+
`~/.gemini/config/AGENTS.md`, `~/.gemini/config/GEMINI.md`,
|
|
119
|
+
`~/.gemini/config/rules/*.md`, and `~/.gemini/config/skills/`. Workspace
|
|
120
|
+
`AGENTS.md` stays the portable policy file, so the 24,000-byte check does
|
|
121
|
+
not apply to it. The byte check counts the raw file, before
|
|
122
|
+
`@[label](path)` expansion. The 20,000-token aggregate is not checked.
|
|
123
|
+
Plugin rules and plugin skills stay unread, as do
|
|
124
|
+
`~/.gemini/antigravity-cli/skills/`, `~/.gemini/skills/`, and
|
|
125
|
+
`~/.gemini/antigravity/skills/`. Global skills use the Agent Skills
|
|
126
|
+
contract. New: `antigravity.rule.missing-trigger`,
|
|
127
|
+
`antigravity.rule.invalid-trigger`,
|
|
128
|
+
`antigravity.rule.missing-description`, `antigravity.rule.missing-globs`,
|
|
129
|
+
`antigravity.rule.too-large`.
|
|
130
|
+
- Antigravity hooks: `.agents/hooks.json` on the ancestor walk, and
|
|
131
|
+
`~/.gemini/config/hooks.json` under `--global`. The file maps hook names to
|
|
132
|
+
definitions. Direct handlers and matcher groups are both valid. `enabled:
|
|
133
|
+
false` skips a definition. `type` defaults to `command`. Six events.
|
|
134
|
+
Plugin hooks stay unread. New: `antigravity.hook.unknown-event`,
|
|
135
|
+
`antigravity.hook.missing-script`, `antigravity.hook.invalid-group`,
|
|
136
|
+
`antigravity.hook.command-without-command`,
|
|
137
|
+
`antigravity.hook.unknown-handler-type`.
|
|
138
|
+
- Codex hooks: project `.codex/hooks.json` and inline `[hooks]` in
|
|
139
|
+
`.codex/config.toml`, plus the same two files under `$CODEX_HOME` or
|
|
140
|
+
`~/.codex` with `--global`. Both files in a layer are inventoried. Fourteen
|
|
141
|
+
events. `command` and `mcp_tool` run; `prompt` and `agent` are parsed but
|
|
142
|
+
skipped; `SessionEnd` does not run `mcp_tool`. SessionEnd and Interrupt
|
|
143
|
+
timeouts must be 1–3 seconds. Other events are not timeout-checked.
|
|
144
|
+
Plugins, `requirements.toml`, and the trust gate stay unread. New:
|
|
145
|
+
`codex.hook.unknown-event`, `codex.hook.missing-script`,
|
|
146
|
+
`codex.hook.invalid-group`, `codex.hook.command-without-command`,
|
|
147
|
+
`codex.hook.mcp-tool-without-server-or-tool`,
|
|
148
|
+
`codex.hook.unknown-handler-type`, `codex.hook.incompatible-handler`,
|
|
149
|
+
`codex.hook.timeout-out-of-bounds`.
|
|
150
|
+
- Cursor user MCP under `--global`: `~/.cursor/mcp.json` uses the same
|
|
151
|
+
`cursor-json` profile as the project file. A missing `version` is not a
|
|
152
|
+
finding.
|
|
153
|
+
- Kiro hook triggers `SessionEnd`, `PreCompact`, and `PostCompact`, quoted
|
|
154
|
+
on the types page (2026-11-12). `PreTaskExec` and `PostTaskExec` stay:
|
|
155
|
+
that table still lists Pre/Post Task Execution and does not quote a
|
|
156
|
+
replacement token.
|
|
157
|
+
- `CLAUDE_CONFIG_DIR` also relocates `~/.claude.json` to
|
|
158
|
+
`$CLAUDE_CONFIG_DIR/.claude.json` under `--global`. Unset, the file stays
|
|
159
|
+
`~/.claude.json`.
|
|
160
|
+
- Devin CLI, beside the legacy Windsurf contract: `.devin/hooks.v1.json`
|
|
161
|
+
and `"hooks"` in `.devin/config.json` / `config.local.json` (user
|
|
162
|
+
`~/.config/devin/config.json` under `--global`); MCP
|
|
163
|
+
`.devin/mcp_config.json`, `.devin/mcp_config.local.json`, and a
|
|
164
|
+
`mcpServers` key still sitting in those config files. Launch is `command`
|
|
165
|
+
or `url` (`sse` is a valid transport, not a check). Skills:
|
|
166
|
+
`.devin/skills` and `--global` `~/.config/devin/skills`. New:
|
|
167
|
+
`devin.hook.unknown-event`, `devin.hook.missing-script`,
|
|
168
|
+
`devin.hook.invalid-group`, `devin.hook.command-without-command`,
|
|
169
|
+
`devin.hook.prompt-without-prompt`, `devin.hook.unknown-handler-type`,
|
|
170
|
+
`devin.mcp.no-launch`. `.windsurf/hooks.json` and
|
|
171
|
+
`~/.codeium/windsurf/mcp_config.json` stay the Cascade contract.
|
|
172
|
+
`.claude/settings.json` stays Claude.
|
|
173
|
+
- Antigravity MCP: `url` is an alias of `serverUrl`. `httpUrl` alone is
|
|
174
|
+
still `antigravity.mcp.no-launch`.
|
|
175
|
+
- Copilot portable user MCP under `--global`: `$COPILOT_HOME/mcp-config.json`
|
|
176
|
+
or `~/.copilot/mcp-config.json` (`mcpServers`, `command` or `url`),
|
|
177
|
+
reported as `vscode.mcp.no-launch`. `.vscode/mcp.json` stays the `servers`
|
|
178
|
+
file. Legacy Local hooks stay the eight PascalCase command-only events;
|
|
179
|
+
`version: 1` stays Copilot.
|
|
180
|
+
|
|
181
|
+
- Kiro hooks (`.kiro/hooks/*.json`, `--global` `~/.kiro/hooks/`) on their
|
|
182
|
+
own profile: 13 PascalCase triggers, `command` /
|
|
183
|
+
`agent` actions, array-of-hooks files. New: `kiro.hook.unknown-event`,
|
|
184
|
+
`kiro.hook.missing-script`, `kiro.hook.command-without-command`,
|
|
185
|
+
`kiro.hook.prompt-without-prompt`, `kiro.hook.unknown-handler-type`,
|
|
186
|
+
`kiro.hook.invalid-group`. Agents are inventoried on their own walk
|
|
187
|
+
(above). Skills: `.kiro/skills` as Agent Skills.
|
|
188
|
+
- Cline / Roo / Kilo / Junie skill directories (`.cline/skills`,
|
|
189
|
+
`.roo/skills`, `.kilo/skills`, `.junie/skills`, plus `--global` home
|
|
190
|
+
copies). Junie does not require `description` and does not require
|
|
191
|
+
`name` to match the folder. Cline hooks and Cline agents stay unread.
|
|
192
|
+
- VS Code `.github/agents/*.agent.md` frontmatter hooks parse as
|
|
193
|
+
vscode-native. Marketplace plugin `hooks.json` stays unread.
|
|
194
|
+
- `--global` Cursor `~/.cursor/hooks.json`, Gemini
|
|
195
|
+
`~/.gemini/settings.json` (hooks and MCP together), and Antigravity
|
|
196
|
+
`~/.gemini/config/mcp_config.json`. Credential siblings are never
|
|
197
|
+
opened. Copilot-consumed `.claude/settings.json` stays Claude.
|
|
198
|
+
- Spec provenance: VS Code hooks-reference, geminicli.com (GitHub MCP
|
|
199
|
+
page kept for the underscore warning), both OpenCode MCP URLs.
|
|
200
|
+
|
|
201
|
+
- Claude user `~/.claude/settings.json` hooks under `--global` /
|
|
202
|
+
`includeGlobal`. Same Claude schema as project settings;
|
|
203
|
+
`${CLAUDE_PROJECT_DIR}` resolves against the scanned project. Same-event
|
|
204
|
+
user and project hooks coexist. Managed policy and marketplace plugins
|
|
205
|
+
stay unread.
|
|
206
|
+
- Claude user `~/.claude.json` MCP under `--global` / `includeGlobal`:
|
|
207
|
+
top-level `mcpServers` (user) and matching
|
|
208
|
+
`projects.<scanned-path>.mcpServers` (local). Absent keys are not
|
|
209
|
+
`config.unreadable`. Same-name project, user, and local servers are
|
|
210
|
+
all inventoried. Other projects' local servers stay unread.
|
|
211
|
+
- Claude `--global` user agents, `CLAUDE.md`, rules, and commands
|
|
212
|
+
(`$CLAUDE_CONFIG_DIR` or `~/.claude`). `CLAUDE_CONFIG_DIR` relocates
|
|
213
|
+
that directory; `~/.claude.json` stays in the home directory.
|
|
214
|
+
- Project `.claude/commands/*.md` inventoried as Claude slash commands;
|
|
215
|
+
frontmatter hooks use the skill source. In-tree plugin `skills/`,
|
|
216
|
+
root `SKILL.md`, `agents/` (no frontmatter hooks), `commands/`, and
|
|
217
|
+
`.mcp.json` (`claude-json`). Marketplace plugins stay unread.
|
|
218
|
+
- Gemini CLI hooks: the `hooks` object in project `.gemini/settings.json`,
|
|
219
|
+
the same file the MCP scan already opens. Nested `{ matcher?, sequential?,
|
|
220
|
+
hooks: [...] }` groups, required `type` whose only documented value is
|
|
221
|
+
`command`, and `$GEMINI_PROJECT_DIR` script resolution. Eleven events
|
|
222
|
+
(`SessionStart`, `SessionEnd`, `BeforeAgent`, `AfterAgent`, `BeforeModel`,
|
|
223
|
+
`AfterModel`, `BeforeToolSelection`, `BeforeTool`, `AfterTool`,
|
|
224
|
+
`PreCompress`, `Notification`) on their own profile — Claude's names are
|
|
225
|
+
never accepted here, and Gemini's are never validated against Claude's.
|
|
226
|
+
New: `gemini.hook.unknown-event`, `gemini.hook.missing-script`,
|
|
227
|
+
`gemini.hook.invalid-group`, `gemini.hook.command-without-command`,
|
|
228
|
+
`gemini.hook.unknown-handler-type`. User `~/.gemini/settings.json` is
|
|
229
|
+
opened under `--global` together with that file's MCP servers.
|
|
230
|
+
`/etc/gemini-cli/settings.json` and extension hooks stay unread.
|
|
231
|
+
- Cursor hooks: project `.cursor/hooks.json`. Flat arrays, not Claude groups;
|
|
232
|
+
`command` required on every entry, `type` optional and defaulting to
|
|
233
|
+
`command` (`command` / `prompt`), scripts resolved against the project root
|
|
234
|
+
as the page documents. Twenty-one camelCase events across agent, Tab, and
|
|
235
|
+
app-lifecycle families. New: `cursor.hook.unknown-event`,
|
|
236
|
+
`cursor.hook.missing-script`, `cursor.hook.command-without-command`,
|
|
237
|
+
`cursor.hook.unknown-handler-type`. User `~/.cursor/hooks.json` is opened
|
|
238
|
+
under `--global`. MDM paths and dashboard-synced team hooks stay unread.
|
|
239
|
+
- `spec:check` now diffs the Gemini, Cursor, and Kiro event sets against
|
|
240
|
+
their live pages, and those pages are tracked by content hash.
|
|
241
|
+
- Every finding now says where its rule comes from. `StructuralCheck` gains a
|
|
242
|
+
required `source`: either `{ kind: "spec", url, capture }` naming the vendor
|
|
243
|
+
page and the `docs/spec` file holding the verbatim quote, or
|
|
244
|
+
`{ kind: "derived", detail }` stating plainly that no vendor page asserts it.
|
|
245
|
+
Required, so a new rule that cannot say where it came from does not compile.
|
|
246
|
+
`make()` copies it, with `provenance` and `lastVerified`, onto every finding.
|
|
247
|
+
- Default report: one dim line per rule group —
|
|
248
|
+
`spec-required · cursor.com/docs/hooks · read 2026-09-03`, or
|
|
249
|
+
`internal-consistency · no vendor page · agentscan inference`.
|
|
250
|
+
- `explain`: adds `provenance:`, the full `source:` URL, and `capture:`.
|
|
251
|
+
- `--json`: three new keys per finding (`provenance`, `source`,
|
|
252
|
+
`lastVerified`). Additive; no key renamed or removed.
|
|
253
|
+
- `--output prompt`: a `Source:` bullet, so a fixing agent can read the page
|
|
254
|
+
before editing the config the rule is about.
|
|
255
|
+
- `agentscan rules` gains provenance and source columns and a `--json` flag
|
|
256
|
+
(it previously accepted no flags at all).
|
|
257
|
+
- All 28 pages cited by a rule are already in `SPEC_SURFACES`, so every source
|
|
258
|
+
a user sees is re-fetched and hash-compared by `bun run spec:check`. A test
|
|
259
|
+
enforces it, along with: every capture file exists, the capture names the
|
|
260
|
+
rule, `lastVerified` matches the capture's `**Read:**` date, and a
|
|
261
|
+
`spec-required` rule may not claim it has no source.
|
|
262
|
+
- `bun run readme:rules` generates the README rule table from the registry;
|
|
263
|
+
a test fails the build when it drifts. This recovers the three
|
|
264
|
+
`windsurf.hook.*` rows the hand-maintained table had been missing since #13,
|
|
265
|
+
and the check count is now asserted against the registry in the three README
|
|
266
|
+
places it is written by hand. `site/lib/site.ts` deliberately stays at the
|
|
267
|
+
published release's count; the test only forbids the site advertising more
|
|
268
|
+
checks than the registry holds.
|
|
269
|
+
|
|
270
|
+
### Removed
|
|
271
|
+
|
|
272
|
+
- `ignoreRules`, `ignoreFindings`, and `explain` no longer accept 0.7 rule
|
|
273
|
+
ids (`hook.missing-script`, `skill.missing-frontmatter`, and the rest of
|
|
274
|
+
that set). Use the id the finding prints (`claude.hook.missing-script`).
|
|
275
|
+
- `thresholds.skillDescriptionBytes` and `thresholds.skills` are rejected.
|
|
276
|
+
The listing budget key is `thresholds.skillListingChars`.
|
|
277
|
+
- The README "Catches" column is the registry description. `bun run
|
|
278
|
+
readme:rules` no longer keeps a second, hand-written sentence.
|
|
279
|
+
|
|
280
|
+
### Changed
|
|
281
|
+
|
|
282
|
+
- An explicit `--config <path>` that does not exist now exits 2 with
|
|
283
|
+
`config file not found: <path>` instead of silently scanning with defaults.
|
|
284
|
+
A missing implicit `.agentscanrc.json` still means defaults. A config that
|
|
285
|
+
parses as JSON but breaks the schema exits 2 with
|
|
286
|
+
`Invalid config at <path>: <key>: <problem>` instead of a raw zod dump.
|
|
287
|
+
|
|
288
|
+
### Fixed
|
|
289
|
+
|
|
290
|
+
- 54 rules recorded a `lastVerified` older than the `**Read:**` date of the
|
|
291
|
+
capture they rest on: the 2026-09-03 re-read of those pages never reached the
|
|
292
|
+
registry. Synced, with a test that keeps the two in step.
|
|
293
|
+
- Three `tests/unit/codex-mcp.test.ts` cases failed on any machine with
|
|
294
|
+
`CODEX_HOME` exported: they mock `os.homedir()`, but `codexHomeDir()`
|
|
295
|
+
correctly prefers the env override. A `tests/helpers/env.ts` preload clears
|
|
296
|
+
`CODEX_HOME`, `GROK_HOME`, `CLAUDE_CONFIG_DIR`, and `COPILOT_HOME` for the
|
|
297
|
+
whole suite; the tests that need one still set and restore it themselves.
|
|
298
|
+
|
|
299
|
+
## 1.4.0 — 2026-09-02
|
|
300
|
+
|
|
301
|
+
Closes two coverage gaps left after the 2026-09-02 re-verification, then
|
|
302
|
+
ships everything that sat in Unreleased: the seven false-positive
|
|
303
|
+
corrections, plan 038 content hashes and verbatim fixtures, and #13
|
|
304
|
+
Windsurf Cascade hooks / skills. **103 checks**, **532 tests**.
|
|
305
|
+
|
|
306
|
+
### Added
|
|
307
|
+
|
|
308
|
+
- Copilot CLI inline `hooks` in `.github/copilot/settings.json` and
|
|
309
|
+
`.github/copilot/settings.local.json` (always `copilot-cli`, source
|
|
310
|
+
`copilot-settings`). User `$COPILOT_HOME/settings.json` or
|
|
311
|
+
`~/.copilot/settings.json` under `--global`. Same-event hooks from
|
|
312
|
+
settings and `.github/hooks` coexist. `$COPILOT_HOME` is honored for
|
|
313
|
+
user hook files too. `.claude/settings.json` stays on the Claude
|
|
314
|
+
profile. Policy and plugin hook files stay unread.
|
|
315
|
+
- `mcp.literal-credential` (security, warning): secret-named string values
|
|
316
|
+
under MCP `headers`, `http_headers`, or `auth` that are not
|
|
317
|
+
interpolation. Field paths only; values never echoed. Grok `{{var}}`,
|
|
318
|
+
Gemini `%VAR%`, and the existing `${VAR}` / `${env:}` / `${input:}`
|
|
319
|
+
forms are interpolation. Token-shaped literals still fire
|
|
320
|
+
`security.hardcoded-secret` first.
|
|
321
|
+
|
|
322
|
+
- `bun run spec:check` hashes the prose of every source page in
|
|
323
|
+
`scripts/spec-surfaces.ts` (35 unique URLs) and compares against
|
|
324
|
+
`scripts/spec-hashes.json`; a changed page is reported as drift with the
|
|
325
|
+
recorded date and URL. `bun run spec:record` rewrites the baseline after a
|
|
326
|
+
human has re-read the page. Page text is never stored. GitHub blob URLs are
|
|
327
|
+
fetched as raw files. Offline tests cover normalisation, hashing, and the
|
|
328
|
+
baseline file's shape.
|
|
329
|
+
- Conformance fixtures carry the vendors' own examples verbatim: Claude
|
|
330
|
+
`type: "http"` / `"streamable-http"` MCP entries and the five documented
|
|
331
|
+
hook handler examples (command exec form, http, mcp_tool, prompt, agent);
|
|
332
|
+
Copilot CLI `exec`, `http`, `prompt`, and the PascalCase lifecycle names;
|
|
333
|
+
Gemini `httpUrl`, SSE `url`, and `%VAR_NAME%` env; the Command Code agents
|
|
334
|
+
page's full frontmatter example; the Agent Skills optional-fields example
|
|
335
|
+
with its referenced files; the VS Code OS-override example with its scripts.
|
|
336
|
+
With the pre-fix checks these fixtures fail on `claude-json`,
|
|
337
|
+
`copilot-hooks`, and `gemini-json`.
|
|
338
|
+
- The conformance test pins a minimum fact count per fixture, so a discovery
|
|
339
|
+
regression that silently drops a file cannot keep a fixture green.
|
|
340
|
+
|
|
341
|
+
### Fixed
|
|
342
|
+
|
|
343
|
+
- `commandcode.mcp.invalid-transport` no longer fires on `"type":
|
|
344
|
+
"streamable-http"` in a shared `.mcp.json` — Claude Code documents it as an
|
|
345
|
+
alias for `http`. It also no longer fires on `sse` in Command Code-only
|
|
346
|
+
files, which the Command Code MCP page names as a transport it connects to
|
|
347
|
+
(skip, not a claim of support).
|
|
348
|
+
- `agent-skills.skill.invalid-name` accepts lowercase letters from any script
|
|
349
|
+
(`résumé-builder`), matching the spec's "unicode lowercase alphanumeric" and
|
|
350
|
+
the `skills-ref` reference validator. Uppercase, underscores, spaces, and
|
|
351
|
+
hyphen placement are still rejected.
|
|
352
|
+
- `copilot.hook.command-without-command` accepts the documented `exec` (+
|
|
353
|
+
`args`) form as a complete command handler; `exec` paths are existence-
|
|
354
|
+
checked like any other launch.
|
|
355
|
+
- `copilot.hook.unknown-event` accepts the PascalCase spellings the Copilot
|
|
356
|
+
reference documents for Copilot-only events in `version: 1` files:
|
|
357
|
+
`SessionEnd`, `PostToolUseFailure`, `ErrorOccurred`, `PermissionRequest`.
|
|
358
|
+
Native VS Code files still reject them.
|
|
359
|
+
- `mcp.literal-env` treats Gemini CLI's documented Windows `%VAR_NAME%` form as
|
|
360
|
+
interpolation, not a literal secret.
|
|
361
|
+
- `commandcode.agent.invalid-permission-mode` accepts `inherit`, the value the
|
|
362
|
+
agents page lists as the field's default.
|
|
363
|
+
|
|
364
|
+
### Changed
|
|
365
|
+
|
|
366
|
+
- All `docs/spec/*.md` captures whose source page was re-read carry
|
|
367
|
+
`**Read:** 2026-09-02`; `scripts/spec-surfaces.ts` and the registry's
|
|
368
|
+
`lastVerified` match. Six discovery-only surfaces that were not re-opened
|
|
369
|
+
keep their earlier date.
|
|
370
|
+
- `bun run spec:check` now also diffs the Copilot PascalCase aliases against
|
|
371
|
+
the live page, and exits 1 when any source page's content hash has moved.
|
|
372
|
+
- New captured lines: Claude hook `args` exec form and `${CLAUDE_PLUGIN_DATA}`;
|
|
373
|
+
Claude sub-agent skip list; VS Code agent-scoped and plugin hook locations;
|
|
374
|
+
Command Code `reasoningEffort` (documented, invalid values fall back and
|
|
375
|
+
load — no check); Antigravity "legacy fields like `url` or `httpUrl` are not
|
|
376
|
+
supported"; Continue `uses:` cited from the config reference.
|
|
377
|
+
|
|
378
|
+
### From #13 — true findings and Windsurf Cascade hooks / skills
|
|
379
|
+
|
|
380
|
+
- `.agentscan-root` now stops walk-up, so a dirty `/tmp/.git` cannot become the
|
|
381
|
+
scan root for fixtures or nested checkouts.
|
|
382
|
+
- Fenced `SKILL.md` examples: a bundled path on the second line of a code
|
|
383
|
+
fence is not `skill.broken-reference`.
|
|
384
|
+
- Unclosed YAML `---` is `config.unreadable`, not `*.skill.missing-frontmatter`.
|
|
385
|
+
- Invalid Windsurf rule YAML is not `windsurf.rule.missing-trigger`.
|
|
386
|
+
- `node .` / `"."` is not a missing hook script or MCP command.
|
|
387
|
+
- Skill-directory symlinks that leave the scan root are not inventoried.
|
|
388
|
+
- `--global` copy names Copilot hooks and Windsurf user files; Action
|
|
389
|
+
`bun-version` defaults to `1.4.0` (CI pin).
|
|
390
|
+
- Windsurf Cascade hooks: `.windsurf/hooks.json` and `--global`
|
|
391
|
+
`~/.codeium/windsurf/hooks.json`. 12 snake_case events; `command` /
|
|
392
|
+
`powershell`; `windsurf.hook.unknown-event`, `missing-script`,
|
|
393
|
+
`command-without-command`.
|
|
394
|
+
- Windsurf Cascade skills: `.windsurf/skills` and `--global`
|
|
395
|
+
`~/.codeium/windsurf/skills`. Agent Skills contract (page cites
|
|
396
|
+
agentskills.io). System skill dirs unread.
|
|
397
|
+
|
|
14
398
|
## 1.3.0 — 2026-08-31
|
|
15
399
|
|
|
16
400
|
Native Windsurf / Cascade coverage against 2026-08-31 official docs.
|