vigiles 16.1.2 → 16.1.3

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.
@@ -18,6 +18,7 @@ const node_path_1 = require("node:path");
18
18
  const compile_js_1 = require("./core/compile.js");
19
19
  const spec_js_1 = require("./core/spec.js");
20
20
  const plugin_loader_js_1 = require("./plugin-loader.js");
21
+ const vocabulary_consistency_js_1 = require("./core/vocabulary-consistency.js");
21
22
  /** Check an adapter against the port contracts; returns the (possibly empty) failure list. */
22
23
  function checkAdapterConformance(adapter) {
23
24
  const failures = [];
@@ -33,6 +34,22 @@ function checkAdapterConformance(adapter) {
33
34
  need(refVerification, "capabilities.referenceVerification must be true (every adapter does pillar 1)");
34
35
  // --- Pillar 1 (always required): dialect + layout ---
35
36
  need(adapter.dialect.builtinAgentTools.length > 0, "dialect has no builtinAgentTools");
37
+ // The dialect's several name lists describe ONE vocabulary from different
38
+ // angles, and nothing used to check they agreed — which is how `Agent` came to
39
+ // sit in `neverAvailableTools` while its own alias `Task` sat in the built-in
40
+ // catalog, undetected, for every consumer of the adapter. Cheap, total, and it
41
+ // runs for every adapter including third-party ones.
42
+ for (const problem of (0, vocabulary_consistency_js_1.dialectVocabularyProblems)(adapter.dialect))
43
+ need(false, `dialect self-contradiction: ${problem}`);
44
+ // When a dialect ships the richer vocabulary AND the flat lists, the flat ones
45
+ // must be exactly its projections — else the two drift apart again, one level
46
+ // down.
47
+ if (adapter.dialect.subagentToolVocabulary !== undefined)
48
+ for (const problem of (0, vocabulary_consistency_js_1.vocabularyProjectionProblems)(adapter.dialect.subagentToolVocabulary, adapter.dialect.builtinAgentTools, adapter.dialect.neverAvailableTools))
49
+ need(false, `subagentToolVocabulary: ${problem}`);
50
+ if (adapter.dialect.hookEventVocabulary !== undefined)
51
+ for (const problem of (0, vocabulary_consistency_js_1.vocabularyProjectionProblems)(adapter.dialect.hookEventVocabulary, adapter.dialect.hookEvents, []))
52
+ need(false, `hookEventVocabulary: ${problem}`);
36
53
  need(adapter.dialect.instructionTargets.length > 0, "dialect has no instructionTargets");
37
54
  need(adapter.layout.instructionFile.length > 0, "layout.instructionFile is empty");
38
55
  need(adapter.layout.manifestPath.length > 0, "layout.manifestPath is empty");
@@ -11,16 +11,23 @@ import type { HarnessDialect } from "../../core/dialect.js";
11
11
  /**
12
12
  * The Claude Code built-in subagent tool catalog as a `const` tuple, so a typed
13
13
  * authoring surface can derive a LITERAL union (`ClaudeCodeBuiltinTool`) from it.
14
- * `claudeCodeDialect.builtinAgentTools` references this same array — one source
15
- * of truth for the runtime catalog AND the compile-time tool vocabulary.
14
+ *
15
+ * DERIVED, not authored: it is exactly the vocabulary's declarable terms — the
16
+ * ones the platform provides outright plus the ones it withholds only under a
17
+ * condition. Both halves are legitimate to write in a `tools:` line, which is
18
+ * why `Agent` belongs here and used to sit in `neverAvailableTools` instead.
19
+ * Because this is a projection rather than a second hand-kept list, the two can
20
+ * no longer disagree; `vocabularyProjectionProblems` asserts it in the
21
+ * conformance kit rather than leaving it to care.
16
22
  */
17
- export declare const claudeCodeBuiltinAgentTools: readonly ["Read", "Write", "Edit", "MultiEdit", "Bash", "BashOutput", "KillBash", "Grep", "Glob", "LS", "WebSearch", "WebFetch", "NotebookEdit", "TodoWrite", "Task", "Skill"];
23
+ export declare const claudeCodeBuiltinAgentTools: readonly ["Read", "Grep", "Glob", "Bash", "PowerShell", "Edit", "Write", "NotebookEdit", "WebFetch", "WebSearch", "TodoWrite", "Skill", "ToolSearch", "EnterWorktree", "ExitWorktree", "Monitor", "TaskStop", "SendMessage", "Artifact", "Agent", "Task", "ExitPlanMode", "ListAgents", "LSP", "ShareOnboardingGuide", "CronCreate", "CronDelete", "CronList", "TaskCreate", "TaskGet", "TaskList", "TaskUpdate"];
18
24
  /**
19
- * The Claude Code side-effecting tools as a `const` tuple (the complement of
20
- * read-only within `builtinAgentTools`). `claudeCodeDialect.sideEffectingTools`
21
- * references this; the typed vocabulary derives the read-only / bounded splits.
25
+ * The Claude Code side-effecting tools (the complement of read-only within
26
+ * `builtinAgentTools`). Authored in `vocabulary.ts` beside the catalog it
27
+ * partitions, because a name added to the catalog without a decision here would
28
+ * silently be classified read-only.
22
29
  */
23
- export declare const claudeCodeSideEffectingTools: readonly ["Bash", "BashOutput", "KillBash", "Edit", "MultiEdit", "Write", "NotebookEdit", "WebFetch", "WebSearch", "Skill", "Task", "TodoWrite"];
30
+ export declare const claudeCodeSideEffectingTools: readonly ["Bash", "PowerShell", "Edit", "Write", "NotebookEdit", "WebFetch", "WebSearch", "Skill", "TodoWrite", "Monitor", "SendMessage", "Artifact", "EnterWorktree", "ExitWorktree", "TaskStop", "Agent", "Task", "TaskCreate", "TaskUpdate", "CronCreate", "CronDelete", "ShareOnboardingGuide"];
24
31
  export declare const claudeCodeDialect: HarnessDialect;
25
32
  /** Every Claude Code built-in subagent tool (literal union). */
26
33
  export type ClaudeCodeBuiltinTool = (typeof claudeCodeBuiltinAgentTools)[number];
@@ -33,15 +40,14 @@ export type ClaudeCodeSideEffectingTool = (typeof claudeCodeSideEffectingTools)[
33
40
  export type ClaudeCodeReadOnlyTool = Exclude<ClaudeCodeBuiltinTool, ClaudeCodeSideEffectingTool>;
34
41
  /**
35
42
  * Tools a `bounded` CC unit may declare: read-only ∪ the decidable
36
- * side-effecting tools (Write/Edit/MultiEdit/NotebookEdit) ∪ `Bash` (its
43
+ * side-effecting tools (Write/Edit/NotebookEdit) ∪ `Bash`/`PowerShell` (whose
37
44
  * command is decided at RUNTIME by the gate). Bars MCP / unknown / wildcard —
38
45
  * those are simply not in the built-in union, so listing one is a `tsc` error.
39
46
  *
40
- * NOTE: `BashOutput`/`KillBash` are read-only-ish helpers tied to a running
41
- * Bash; `Bash` is the admitting tool, so they're included via the read-only
42
- * exclusion path only if read-only — here they stay side-effecting, hence the
43
- * explicit add of the bounded-decidable set plus `Bash`.
47
+ * `MultiEdit` was listed here until 2026-08-17. It is not a Claude Code tool —
48
+ * it appears zero times across the vendor's documentation so it is gone along
49
+ * with `BashOutput`, `KillBash` and `LS`.
44
50
  */
45
- export type ClaudeCodeBoundedTool = ClaudeCodeReadOnlyTool | "Write" | "Edit" | "MultiEdit" | "NotebookEdit" | "Bash";
51
+ export type ClaudeCodeBoundedTool = ClaudeCodeReadOnlyTool | "Write" | "Edit" | "NotebookEdit" | "Bash" | "PowerShell";
46
52
  export type { HarnessDialect } from "../../core/dialect.js";
47
53
  //# sourceMappingURL=dialect.d.ts.map
@@ -1,84 +1,55 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.claudeCodeDialect = exports.claudeCodeSideEffectingTools = exports.claudeCodeBuiltinAgentTools = void 0;
4
+ const vocabulary_js_1 = require("./vocabulary.js");
4
5
  /**
5
6
  * The Claude Code built-in subagent tool catalog as a `const` tuple, so a typed
6
7
  * authoring surface can derive a LITERAL union (`ClaudeCodeBuiltinTool`) from it.
7
- * `claudeCodeDialect.builtinAgentTools` references this same array — one source
8
- * of truth for the runtime catalog AND the compile-time tool vocabulary.
8
+ *
9
+ * DERIVED, not authored: it is exactly the vocabulary's declarable terms — the
10
+ * ones the platform provides outright plus the ones it withholds only under a
11
+ * condition. Both halves are legitimate to write in a `tools:` line, which is
12
+ * why `Agent` belongs here and used to sit in `neverAvailableTools` instead.
13
+ * Because this is a projection rather than a second hand-kept list, the two can
14
+ * no longer disagree; `vocabularyProjectionProblems` asserts it in the
15
+ * conformance kit rather than leaving it to care.
9
16
  */
10
17
  exports.claudeCodeBuiltinAgentTools = [
11
- "Read",
12
- "Write",
13
- "Edit",
14
- "MultiEdit",
15
- "Bash",
16
- "BashOutput",
17
- "KillBash",
18
- "Grep",
19
- "Glob",
20
- "LS",
21
- "WebSearch",
22
- "WebFetch",
23
- "NotebookEdit",
24
- "TodoWrite",
25
- "Task",
26
- "Skill",
18
+ ...vocabulary_js_1.claudeCodeAvailableAgentTools,
19
+ ...vocabulary_js_1.claudeCodeConditionalAgentToolNames,
27
20
  ];
28
21
  /**
29
- * The Claude Code side-effecting tools as a `const` tuple (the complement of
30
- * read-only within `builtinAgentTools`). `claudeCodeDialect.sideEffectingTools`
31
- * references this; the typed vocabulary derives the read-only / bounded splits.
22
+ * The Claude Code side-effecting tools (the complement of read-only within
23
+ * `builtinAgentTools`). Authored in `vocabulary.ts` beside the catalog it
24
+ * partitions, because a name added to the catalog without a decision here would
25
+ * silently be classified read-only.
32
26
  */
33
- exports.claudeCodeSideEffectingTools = [
34
- "Bash",
35
- "BashOutput",
36
- "KillBash",
37
- "Edit",
38
- "MultiEdit",
39
- "Write",
40
- "NotebookEdit",
41
- "WebFetch",
42
- "WebSearch",
43
- "Skill",
44
- "Task",
45
- "TodoWrite",
46
- ];
27
+ exports.claudeCodeSideEffectingTools = vocabulary_js_1.claudeCodeSideEffectingAgentTools;
47
28
  exports.claudeCodeDialect = {
48
29
  name: "claude-code",
49
30
  // The tool contract a subagent may declare — the rails it runs on. Anything
50
31
  // else must be an MCP tool, else it's a typo / nonexistent tool.
51
32
  builtinAgentTools: exports.claudeCodeBuiltinAgentTools,
52
- // Tools the platform never exposes to a subagent, whatever the list says — so
53
- // a subagent listing one is a guaranteed-dead reference only a compiler catches.
54
- neverAvailableTools: [
55
- "Agent",
56
- "AskUserQuestion",
57
- "EnterPlanMode",
58
- "ExitPlanMode",
59
- "ScheduleWakeup",
60
- "WaitForMcpServers",
61
- ],
33
+ // Tools the platform removes UNCONDITIONALLY, whatever the list says — so a
34
+ // subagent listing one is a guaranteed-dead reference only a compiler catches.
35
+ // Derived from the vocabulary's `withheld` terms. `Agent` and `ExitPlanMode`
36
+ // are deliberately absent: the vendor removes both only under a stated
37
+ // condition (depth limit / `permissionMode: plan`), so they are `conditional`
38
+ // and reported as a note. Listing them here is what told delegating subagents
39
+ // to delete the tool they exist to use.
40
+ neverAvailableTools: vocabulary_js_1.claudeCodeWithheldAgentTools,
62
41
  mcpToolPattern: /^mcp__[a-z0-9_-]+__[a-z0-9_-]+$/i,
63
42
  // Claude Code's own built-in MCP server: the IDE integration provides
64
43
  // `mcp__ide__getDiagnostics` / `mcp__ide__executeCode` at runtime without any
65
44
  // plugin declaring it, so a contract that lists those must NOT be flagged as
66
45
  // referencing an undeclared server (the mcp-tool-resolves allowlist).
67
46
  knownMcpServers: ["ide"],
68
- // The real Claude Code hook events. (Was wrong: PreSession/PostSession don't
69
- // exist; SessionStart/SessionEnd/Stop/SubagentStop/UserPromptSubmit/PreCompact
70
- // were missing verified against the events real plugins register.)
71
- hookEvents: [
72
- "PreToolUse",
73
- "PostToolUse",
74
- "UserPromptSubmit",
75
- "Notification",
76
- "Stop",
77
- "SubagentStop",
78
- "PreCompact",
79
- "SessionStart",
80
- "SessionEnd",
81
- ],
47
+ // The real Claude Code hook events all 31 the vendor documents, derived from
48
+ // `claudeCodeHookEventNames`. This list held 9 until 2026-08-17; `Setup` was
49
+ // reported as "never fires" and the other 21 absentees drew nothing at all,
50
+ // because whether an unknown name was accused or ignored came down to its edit
51
+ // distance from the 9 we had. See `vocabulary.ts` for the capture.
52
+ hookEvents: vocabulary_js_1.claudeCodeHookEventNames,
82
53
  // Events where a block decision is silently ignored ENTIRELY — no veto AND no
83
54
  // model feedback (exit 2 there writes stderr only to the user). These are the
84
55
  // ONLY events hook-block-ineffective flags as wrong-event. PostToolUse is NOT
@@ -105,10 +76,17 @@ exports.claudeCodeDialect = {
105
76
  // disable-model-invocation, argument-hint, …).
106
77
  skillFrontmatter: "claude-code",
107
78
  // Tools that produce side effects in Claude Code. The complement — the
108
- // read-only tools — are: Read, Grep, Glob, LS, ToolSearch (and LSP/Agent
109
- // which are not in the subagent catalog). Bash is side-effecting because
110
- // `cat` and `rm -rf` are the same tool at the tool-name level — the
79
+ // read-only tools — are: Read, Grep, Glob, ToolSearch, LSP, ListAgents,
80
+ // TaskGet, TaskList, CronList. Bash (and PowerShell) are side-effecting
81
+ // because `cat` and `rm -rf` are the same tool at the tool-name level — the
111
82
  // sandbox is the only closure for subprocess effects.
112
83
  sideEffectingTools: exports.claudeCodeSideEffectingTools,
84
+ // The richer catalogs the flat lists above project from — status per term,
85
+ // with the vendor capture they were read from. An unknown name resolves
86
+ // against these to an `unrecognised` ADVISORY that names vigiles as the
87
+ // possibly-stale party, instead of the silence-or-accusation coin flip that
88
+ // edit distance used to decide.
89
+ hookEventVocabulary: vocabulary_js_1.claudeCodeHookEventVocabulary,
90
+ subagentToolVocabulary: vocabulary_js_1.claudeCodeSubagentToolVocabulary,
113
91
  };
114
92
  //# sourceMappingURL=dialect.js.map
@@ -0,0 +1,133 @@
1
+ /**
2
+ * The Claude Code vocabularies — hook events and subagent tools — re-derived
3
+ * from the vendor's own documentation on 2026-08-17 against Claude Code 2.1.233
4
+ * (`claude --version` on the capture box).
5
+ *
6
+ * Every entry below came from a STRUCTURAL read of the docs, not a prose grep:
7
+ * the hook events are the 31 `<h3>` subsections of the `## Hook events` section
8
+ * of https://code.claude.com/docs/en/hooks (2,589,700 bytes as fetched), in
9
+ * document order; the tool statuses are the two filter lists in the
10
+ * "Available tools" section of https://code.claude.com/docs/en/sub-agents
11
+ * (1,126,213 bytes as fetched). The `condition` strings are the vendor's own
12
+ * wording, trimmed.
13
+ *
14
+ * This file is the ONE authored place for both catalogs. `dialect.ts` builds
15
+ * `builtinAgentTools` / `neverAvailableTools` / `sideEffectingTools` and the
16
+ * literal tool unions from the tuples below, so the state that produced the
17
+ * `Agent`/`Task` inversion — two hand-kept lists disagreeing with each other —
18
+ * has nowhere left to live.
19
+ *
20
+ * WHAT THIS CORRECTS, and how badly it was wrong (measured; the mechanism is
21
+ * documented in `core/vocabulary.ts`):
22
+ *
23
+ * - HOOK EVENTS: the old catalog held 9 of 31. It was NOT "current except for
24
+ * `Setup`" — 22 documented events were missing, and 21 of those went unsaid
25
+ * only because they sit more than 2 edit distance from a name we held.
26
+ * `Setup` was the one that happened to land within 2 of `Stop`, so it alone
27
+ * drew an accusation, and the fix it suggested — rewire a one-shot setup hook
28
+ * onto every turn's Stop — would have broken the repo it was aimed at.
29
+ * - `Agent` WAS BACKWARDS. The old dialect listed `Agent` as never-available
30
+ * and `Task` as a built-in. The vendor renamed it the other way round:
31
+ *
32
+ * > In version 2.1.63, the Task tool was renamed to Agent. Existing
33
+ * > `Task(...)` references in settings and agent definitions still work
34
+ * > as aliases.
35
+ *
36
+ * and ships `tools: Agent(worker, researcher), Read, Bash` as a worked
37
+ * example. vigiles rejected the current name, accepted the deprecated one,
38
+ * and told orchestrator subagents to delete the one tool they exist to use.
39
+ * - FOUR NAMES WE HELD DO NOT EXIST. `MultiEdit`, `BashOutput`, `KillBash` and
40
+ * `LS` appear ZERO times across all six vendor doc pages fetched (hooks,
41
+ * sub-agents, tools-reference, settings, iam, tool-use). They are historical.
42
+ * They are gone from this catalog, so listing one now draws an
43
+ * `unrecognised` advisory instead of silent approval.
44
+ * - THE EVIDENCE WAS ALREADY IN THE REPO. `dialect-drift.ts`'s
45
+ * `ACKNOWLEDGED_TOOL_INPUT_TYPES` has carried `Agent`, `TaskOutput` and
46
+ * `Workflow` — read from the vendor's own `sdk-tools.d.ts` — since 2.1.187,
47
+ * under a note asserting they are "NOT subagent-grantable". Nothing ever
48
+ * compared that list against this one, so the drift alarm watched the
49
+ * platform move while our two catalogs contradicted both it and each other.
50
+ *
51
+ * WHY `conditional` IS NOT A DEFECT. The vendor is explicit that a subagent's
52
+ * tool set is not a property of the name:
53
+ *
54
+ * > Claude Code removes every other built-in tool from a background subagent,
55
+ * > whether inherited or listed in the `tools` field, so the same definition
56
+ * > can resolve to different tools in the foreground and the background.
57
+ *
58
+ * and, of the catalog as a whole:
59
+ *
60
+ * > Your exact tool set depends on your provider, platform, and settings.
61
+ *
62
+ * Availability is therefore a function of foreground/background, spawn depth,
63
+ * `permissionMode`, model, provider and settings — none of which vigiles can
64
+ * read off a `tools:` line. `conditional` records the condition and reports it
65
+ * as a note. Evaluating those conditions (two of them are decidable from
66
+ * frontmatter we already parse — `ExitPlanMode` against the agent's own
67
+ * `permissionMode`, and background-vs-foreground) is real follow-on work and is
68
+ * deliberately NOT done here.
69
+ *
70
+ * KNOWN GAP, recorded rather than smoothed: `TodoWrite` is named by the vendor
71
+ * among the built-ins a background subagent keeps, so it is `available` — but
72
+ * `tools-reference` also says that from 2.1.233 `TodoWrite`, `TaskCreate`,
73
+ * `TaskGet`, `TaskUpdate` and `TaskList` are withheld on Opus 4.8 / Sonnet 5 /
74
+ * Fable 5 / Mythos 5 and later unless opted in. That is a MODEL axis on top of
75
+ * the two filter axes. The four `Task*` tools are `conditional` for the
76
+ * background reason anyway and their condition says so; `TodoWrite` stays
77
+ * `available` because the vendor names it in the kept-list verbatim. One
78
+ * condition string cannot express three independent axes, and adding a field to
79
+ * hold a case we still could not evaluate would be worse than saying so here.
80
+ */
81
+ import type { HarnessVocabulary } from "../../core/vocabulary.js";
82
+ /**
83
+ * The Claude Code hook events — the 31 `###` subsections under `## Hook events`
84
+ * at https://code.claude.com/docs/en/hooks, in document order.
85
+ *
86
+ * `Setup` is the third. It is a real event with its own `Setup input` and
87
+ * `Setup decision control` subsections; the old catalog's absence of it is what
88
+ * produced the two-letter grade inversion this file exists to fix.
89
+ */
90
+ export declare const claudeCodeHookEventNames: readonly ["SessionStart", "Setup", "InstructionsLoaded", "UserPromptSubmit", "UserPromptExpansion", "MessageDisplay", "PreToolUse", "PermissionRequest", "PostToolUse", "PostToolUseFailure", "PostToolBatch", "PermissionDenied", "Notification", "SubagentStart", "SubagentStop", "TaskCreated", "TaskCompleted", "Stop", "StopFailure", "TeammateIdle", "ConfigChange", "CwdChanged", "DirectoryAdded", "FileChanged", "WorktreeCreate", "WorktreeRemove", "PreCompact", "PostCompact", "SessionEnd", "Elicitation", "ElicitationResult"];
91
+ /**
92
+ * The 19 built-ins the vendor names as the set a BACKGROUND subagent keeps —
93
+ * the default case, and the only tool set vigiles can assume without reading
94
+ * conditions it cannot see.
95
+ */
96
+ export declare const claudeCodeAvailableAgentTools: readonly ["Read", "Grep", "Glob", "Bash", "PowerShell", "Edit", "Write", "NotebookEdit", "WebFetch", "WebSearch", "TodoWrite", "Skill", "ToolSearch", "EnterWorktree", "ExitWorktree", "Monitor", "TaskStop", "SendMessage", "Artifact"];
97
+ /**
98
+ * The 7 unconditional entries of the vendor's first filter — "removes these
99
+ * tools, even when listed in the `tools` field", with no qualifier attached.
100
+ * Listing one is a genuine dead reference, and the only tool verdict that
101
+ * still enters the grade.
102
+ */
103
+ export declare const claudeCodeWithheldAgentTools: readonly ["AskUserQuestion", "EndConversation", "EnterPlanMode", "ScheduleWakeup", "TaskOutput", "WaitForMcpServers", "Workflow"];
104
+ /**
105
+ * Tools the platform removes only under a stated condition — the qualified
106
+ * entries of the first filter, plus the built-ins that survive in the
107
+ * foreground but not in the background. Declaring one is legitimate, so none
108
+ * of these is scored; the condition is reported and vigiles stops there.
109
+ */
110
+ export declare const claudeCodeConditionalAgentToolNames: readonly ["Agent", "Task", "ExitPlanMode", "ListAgents", "LSP", "ShareOnboardingGuide", "CronCreate", "CronDelete", "CronList", "TaskCreate", "TaskGet", "TaskList", "TaskUpdate"];
111
+ /**
112
+ * The side-effecting subset of everything a subagent may declare (the
113
+ * complement is read-only). Two rules decided the additions here, both from the
114
+ * vendor's own tool descriptions rather than from the tool's name:
115
+ *
116
+ * - `Monitor` "writes a small script, runs it in the background" and can open
117
+ * a WebSocket — execution plus network, so it is side-effecting despite
118
+ * reading like an observer.
119
+ * - `LSP`, `ToolSearch`, `ListAgents`, `TaskGet`, `TaskList` and `CronList`
120
+ * only report state, so they stay read-only.
121
+ *
122
+ * This matters beyond tidiness: `classifyToolEffect` treats "in the built-in
123
+ * catalog and NOT here" as read-only, so a name added to the catalog without a
124
+ * decision here would silently be declared harmless — and a spawning tool
125
+ * misfiled as read-only would let a subagent pass the lethal-trifecta check it
126
+ * should fail.
127
+ */
128
+ export declare const claudeCodeSideEffectingAgentTools: readonly ["Bash", "PowerShell", "Edit", "Write", "NotebookEdit", "WebFetch", "WebSearch", "Skill", "TodoWrite", "Monitor", "SendMessage", "Artifact", "EnterWorktree", "ExitWorktree", "TaskStop", "Agent", "Task", "TaskCreate", "TaskUpdate", "CronCreate", "CronDelete", "ShareOnboardingGuide"];
129
+ /** The hook-event vocabulary — every documented event, all currently available. */
130
+ export declare const claudeCodeHookEventVocabulary: HarnessVocabulary;
131
+ /** The subagent-tool vocabulary — available / withheld / conditional. */
132
+ export declare const claudeCodeSubagentToolVocabulary: HarnessVocabulary;
133
+ //# sourceMappingURL=vocabulary.d.ts.map
@@ -0,0 +1,208 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.claudeCodeSubagentToolVocabulary = exports.claudeCodeHookEventVocabulary = exports.claudeCodeSideEffectingAgentTools = exports.claudeCodeConditionalAgentToolNames = exports.claudeCodeWithheldAgentTools = exports.claudeCodeAvailableAgentTools = exports.claudeCodeHookEventNames = void 0;
4
+ /** The vendor artifact + version both catalogs below were captured from. */
5
+ const CAPTURE = "code.claude.com/docs (claude-code 2.1.233, read 2026-08-17)";
6
+ /**
7
+ * The Claude Code hook events — the 31 `###` subsections under `## Hook events`
8
+ * at https://code.claude.com/docs/en/hooks, in document order.
9
+ *
10
+ * `Setup` is the third. It is a real event with its own `Setup input` and
11
+ * `Setup decision control` subsections; the old catalog's absence of it is what
12
+ * produced the two-letter grade inversion this file exists to fix.
13
+ */
14
+ exports.claudeCodeHookEventNames = [
15
+ "SessionStart",
16
+ "Setup",
17
+ "InstructionsLoaded",
18
+ "UserPromptSubmit",
19
+ "UserPromptExpansion",
20
+ "MessageDisplay",
21
+ "PreToolUse",
22
+ "PermissionRequest",
23
+ "PostToolUse",
24
+ "PostToolUseFailure",
25
+ "PostToolBatch",
26
+ "PermissionDenied",
27
+ "Notification",
28
+ "SubagentStart",
29
+ "SubagentStop",
30
+ "TaskCreated",
31
+ "TaskCompleted",
32
+ "Stop",
33
+ "StopFailure",
34
+ "TeammateIdle",
35
+ "ConfigChange",
36
+ "CwdChanged",
37
+ "DirectoryAdded",
38
+ "FileChanged",
39
+ "WorktreeCreate",
40
+ "WorktreeRemove",
41
+ "PreCompact",
42
+ "PostCompact",
43
+ "SessionEnd",
44
+ "Elicitation",
45
+ "ElicitationResult",
46
+ ];
47
+ /**
48
+ * The 19 built-ins the vendor names as the set a BACKGROUND subagent keeps —
49
+ * the default case, and the only tool set vigiles can assume without reading
50
+ * conditions it cannot see.
51
+ */
52
+ exports.claudeCodeAvailableAgentTools = [
53
+ "Read",
54
+ "Grep",
55
+ "Glob",
56
+ "Bash",
57
+ "PowerShell",
58
+ "Edit",
59
+ "Write",
60
+ "NotebookEdit",
61
+ "WebFetch",
62
+ "WebSearch",
63
+ "TodoWrite",
64
+ "Skill",
65
+ "ToolSearch",
66
+ "EnterWorktree",
67
+ "ExitWorktree",
68
+ "Monitor",
69
+ "TaskStop",
70
+ "SendMessage",
71
+ "Artifact",
72
+ ];
73
+ /**
74
+ * The 7 unconditional entries of the vendor's first filter — "removes these
75
+ * tools, even when listed in the `tools` field", with no qualifier attached.
76
+ * Listing one is a genuine dead reference, and the only tool verdict that
77
+ * still enters the grade.
78
+ */
79
+ exports.claudeCodeWithheldAgentTools = [
80
+ "AskUserQuestion",
81
+ "EndConversation",
82
+ "EnterPlanMode",
83
+ "ScheduleWakeup",
84
+ "TaskOutput",
85
+ "WaitForMcpServers",
86
+ "Workflow",
87
+ ];
88
+ /** Vendor conditions quoted once, so the term table below stays readable. */
89
+ const DEPTH_LIMIT = "only when the subagent is at the depth limit; in a fork the tool stays " +
90
+ "listed but returns an error instead of spawning";
91
+ const BACKGROUND = "from a background subagent (the default) — a foreground subagent or a fork " +
92
+ "keeps it";
93
+ const BACKGROUND_AND_MODEL = `${BACKGROUND}; also withheld from Opus 4.8 / Sonnet 5 / Fable 5 / Mythos 5 ` +
94
+ "and later unless CLAUDE_CODE_ENABLE_TODO_TOOLS=1";
95
+ /**
96
+ * Tools the platform removes only under a stated condition — the qualified
97
+ * entries of the first filter, plus the built-ins that survive in the
98
+ * foreground but not in the background. Declaring one is legitimate, so none
99
+ * of these is scored; the condition is reported and vigiles stops there.
100
+ */
101
+ exports.claudeCodeConditionalAgentToolNames = [
102
+ "Agent",
103
+ // The rename runs the OTHER WAY from what vigiles used to encode: `Task` is
104
+ // the old name and still works as an alias, `Agent` is the current one.
105
+ "Task",
106
+ "ExitPlanMode",
107
+ "ListAgents",
108
+ "LSP",
109
+ "ShareOnboardingGuide",
110
+ "CronCreate",
111
+ "CronDelete",
112
+ "CronList",
113
+ "TaskCreate",
114
+ "TaskGet",
115
+ "TaskList",
116
+ "TaskUpdate",
117
+ ];
118
+ /**
119
+ * The vendor's qualifier for each conditional tool.
120
+ *
121
+ * Typed as a `Record` over the name tuple ON PURPOSE: a conditional tool with no
122
+ * stated condition cannot be reported as conditional (the condition IS the
123
+ * report), so adding a name above without a line here is a `tsc` error rather
124
+ * than a runtime surprise. The equivalent runtime check in
125
+ * `vocabularyProjectionProblems` stays for adapters that build a vocabulary
126
+ * dynamically, but for this one the gap is unrepresentable.
127
+ */
128
+ const CONDITIONS = {
129
+ Agent: DEPTH_LIMIT,
130
+ Task: DEPTH_LIMIT,
131
+ ExitPlanMode: "unless the subagent's permissionMode is plan",
132
+ ListAgents: "from a background subagent; a foreground subagent inherits it only in " +
133
+ "sessions where cross-session messaging is enabled",
134
+ LSP: BACKGROUND,
135
+ ShareOnboardingGuide: BACKGROUND,
136
+ CronCreate: BACKGROUND,
137
+ CronDelete: BACKGROUND,
138
+ CronList: BACKGROUND,
139
+ TaskCreate: BACKGROUND_AND_MODEL,
140
+ TaskGet: BACKGROUND_AND_MODEL,
141
+ TaskList: BACKGROUND_AND_MODEL,
142
+ TaskUpdate: BACKGROUND_AND_MODEL,
143
+ };
144
+ /** Still-honoured deprecated spellings, pointing at the current name. */
145
+ const ALIASES = { Task: "Agent" };
146
+ /**
147
+ * The side-effecting subset of everything a subagent may declare (the
148
+ * complement is read-only). Two rules decided the additions here, both from the
149
+ * vendor's own tool descriptions rather than from the tool's name:
150
+ *
151
+ * - `Monitor` "writes a small script, runs it in the background" and can open
152
+ * a WebSocket — execution plus network, so it is side-effecting despite
153
+ * reading like an observer.
154
+ * - `LSP`, `ToolSearch`, `ListAgents`, `TaskGet`, `TaskList` and `CronList`
155
+ * only report state, so they stay read-only.
156
+ *
157
+ * This matters beyond tidiness: `classifyToolEffect` treats "in the built-in
158
+ * catalog and NOT here" as read-only, so a name added to the catalog without a
159
+ * decision here would silently be declared harmless — and a spawning tool
160
+ * misfiled as read-only would let a subagent pass the lethal-trifecta check it
161
+ * should fail.
162
+ */
163
+ exports.claudeCodeSideEffectingAgentTools = [
164
+ "Bash",
165
+ "PowerShell",
166
+ "Edit",
167
+ "Write",
168
+ "NotebookEdit",
169
+ "WebFetch",
170
+ "WebSearch",
171
+ "Skill",
172
+ "TodoWrite",
173
+ "Monitor",
174
+ "SendMessage",
175
+ "Artifact",
176
+ "EnterWorktree",
177
+ "ExitWorktree",
178
+ "TaskStop",
179
+ "Agent",
180
+ "Task",
181
+ "TaskCreate",
182
+ "TaskUpdate",
183
+ "CronCreate",
184
+ "CronDelete",
185
+ "ShareOnboardingGuide",
186
+ ];
187
+ /** The hook-event vocabulary — every documented event, all currently available. */
188
+ exports.claudeCodeHookEventVocabulary = {
189
+ kind: "claude-code hook event",
190
+ capturedFrom: `${CAPTURE} § hooks / Hook events`,
191
+ terms: exports.claudeCodeHookEventNames.map((name) => ({ name, status: "available" })),
192
+ };
193
+ /** The subagent-tool vocabulary — available / withheld / conditional. */
194
+ exports.claudeCodeSubagentToolVocabulary = {
195
+ kind: "claude-code subagent tool",
196
+ capturedFrom: `${CAPTURE} § sub-agents / Available tools`,
197
+ terms: [
198
+ ...exports.claudeCodeAvailableAgentTools.map((name) => ({ name, status: "available" })),
199
+ ...exports.claudeCodeWithheldAgentTools.map((name) => ({ name, status: "withheld" })),
200
+ ...exports.claudeCodeConditionalAgentToolNames.map((name) => ({
201
+ name,
202
+ status: "conditional",
203
+ condition: CONDITIONS[name],
204
+ ...(ALIASES[name] !== undefined ? { aliasOf: ALIASES[name] } : {}),
205
+ })),
206
+ ],
207
+ };
208
+ //# sourceMappingURL=vocabulary.js.map
@@ -827,7 +827,12 @@ function compileSkill(spec, options = {}) {
827
827
  * detection lives in the shared `verifyToolContract` detector (one-detector-no-
828
828
  * drift: compile + scan + the subagent-tool-contract lint rule call the same code). */
829
829
  function validateAgentTools(tools, dialect) {
830
- return (0, tool_contract_js_1.verifyToolContract)(tools, dialect).map((issue) => ({
830
+ // `authoringIssues` drops the `conditional` verdicts: `Agent`, `ExitPlanMode`
831
+ // and the foreground-only built-ins are REAL tools, legitimate to declare, and
832
+ // erroring on them is what made `tools: Agent, Read, Bash` — a worked example
833
+ // in the vendor's own docs — fail to compile. Everything else stays an error,
834
+ // because authoring your own spec is a closed world.
835
+ return (0, tool_contract_js_1.authoringIssues)((0, tool_contract_js_1.verifyToolContract)(tools, dialect)).map((issue) => ({
831
836
  type: "unknown-tool",
832
837
  message: issue.message,
833
838
  }));
@@ -22,6 +22,7 @@
22
22
  * Which SKILL.md frontmatter keys a harness understands — see
23
23
  * `HarnessDialect.skillFrontmatter`.
24
24
  */
25
+ import type { HarnessVocabulary } from "./vocabulary.js";
25
26
  export type SkillFrontmatterProfile = "claude-code" | "minimal";
26
27
  export interface HarnessDialect {
27
28
  /** Stable identifier, e.g. "claude-code". */
@@ -83,5 +84,31 @@ export interface HarnessDialect {
83
84
  * Optional (additive, non-breaking) — absent ⇒ no tool is known-side-effecting.
84
85
  */
85
86
  readonly sideEffectingTools?: readonly string[];
87
+ /**
88
+ * The hook-event catalog as a {@link HarnessVocabulary} — a status and a
89
+ * recorded vendor capture per term, rather than bare membership in
90
+ * `hookEvents`. When present it is what `verifyHookEvents` classifies against,
91
+ * so a name the catalog doesn't hold produces an `unrecognised` ADVISORY
92
+ * (naming vigiles's capture as the possibly-stale party) instead of the old
93
+ * behaviour, where an unknown name drew an accusation or silence depending on
94
+ * its edit distance to the list.
95
+ *
96
+ * Optional (additive, non-breaking). Absent ⇒ one is synthesised from
97
+ * `hookEvents` via `vocabularyFromLists`, so a legacy adapter keeps working
98
+ * and its unknowns become advisories rather than silence.
99
+ */
100
+ readonly hookEventVocabulary?: HarnessVocabulary;
101
+ /**
102
+ * The subagent-tool catalog as a {@link HarnessVocabulary}. Same contract as
103
+ * `hookEventVocabulary`; absent ⇒ synthesised from `builtinAgentTools`
104
+ * (available) + `neverAvailableTools` (withheld).
105
+ *
106
+ * The third status is why this exists: the vendor removes `Agent` only at the
107
+ * spawn depth limit and `ExitPlanMode` only outside plan mode, and removes
108
+ * most built-ins from a background subagent but not a foreground one — so
109
+ * "available to a subagent" is not a property of the name, and a two-way
110
+ * split had to encode one of those conditions as an unconditional fact.
111
+ */
112
+ readonly subagentToolVocabulary?: HarnessVocabulary;
86
113
  }
87
114
  //# sourceMappingURL=dialect.d.ts.map