@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.
Files changed (4) hide show
  1. package/CHANGELOG.md +384 -0
  2. package/README.md +369 -171
  3. package/dist/cli.js +11164 -9974
  4. 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.