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.
- package/dist/adapter-conformance.js +17 -0
- package/dist/adapters/claude-code/dialect.d.ts +19 -13
- package/dist/adapters/claude-code/dialect.js +40 -62
- package/dist/adapters/claude-code/vocabulary.d.ts +133 -0
- package/dist/adapters/claude-code/vocabulary.js +208 -0
- package/dist/core/compile.js +6 -1
- package/dist/core/dialect.d.ts +27 -0
- package/dist/core/hook-events.d.ts +32 -15
- package/dist/core/hook-events.js +23 -29
- package/dist/core/hook-program.js +12 -4
- package/dist/core/rule-meta.js +2 -2
- package/dist/core/tool-contract.d.ts +69 -30
- package/dist/core/tool-contract.js +59 -57
- package/dist/core/vocabulary-consistency.d.ts +35 -0
- package/dist/core/vocabulary-consistency.js +81 -0
- package/dist/core/vocabulary.d.ts +138 -0
- package/dist/core/vocabulary.js +262 -0
- package/dist/scan-core.d.ts +8 -1
- package/dist/scan-core.js +64 -6
- package/dist/scan-files.js +4 -1
- package/dist/scan.d.ts +24 -0
- package/dist/scan.js +8 -1
- package/package.json +1 -1
|
@@ -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
|
-
*
|
|
15
|
-
*
|
|
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", "
|
|
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
|
|
20
|
-
*
|
|
21
|
-
*
|
|
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", "
|
|
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/
|
|
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
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
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" | "
|
|
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
|
-
*
|
|
8
|
-
*
|
|
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
|
-
|
|
12
|
-
|
|
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
|
|
30
|
-
*
|
|
31
|
-
*
|
|
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
|
|
53
|
-
//
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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
|
|
69
|
-
//
|
|
70
|
-
//
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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,
|
|
109
|
-
//
|
|
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
|
package/dist/core/compile.js
CHANGED
|
@@ -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
|
-
|
|
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
|
}));
|
package/dist/core/dialect.d.ts
CHANGED
|
@@ -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
|