vigiles 5.1.0 → 6.0.0
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/README.md +59 -18
- package/dist/adapters/claude-code/adapter.js +1 -0
- package/dist/adapters/claude-code/agent-runtime.d.ts +45 -6
- package/dist/adapters/claude-code/agent-runtime.js +94 -8
- package/dist/adapters/claude-code/dialect.d.ts +34 -0
- package/dist/adapters/claude-code/dialect.js +51 -19
- package/dist/adapters/claude-code/effect-region.d.ts +9 -0
- package/dist/adapters/claude-code/effect-region.js +45 -0
- package/dist/adapters/claude-code/layout.js +3 -0
- package/dist/adapters/claude-code/skill-runtime.d.ts +25 -0
- package/dist/adapters/claude-code/skill-runtime.js +40 -0
- package/dist/adapters/claude-code/typed-spec.d.ts +58 -0
- package/dist/adapters/claude-code/typed-spec.js +55 -0
- package/dist/adapters/codex/adapter.js +3 -0
- package/dist/adapters/codex/layout.js +3 -0
- package/dist/adapters/opencode/adapter.js +1 -0
- package/dist/adapters/opencode/layout.js +3 -0
- package/dist/check.d.ts +8 -0
- package/dist/check.js +27 -3
- package/dist/claude-code.d.ts +1 -0
- package/dist/claude-code.js +8 -1
- package/dist/cli.js +469 -88
- package/dist/core/adapter.d.ts +10 -0
- package/dist/core/bash-effects.d.ts +41 -0
- package/dist/core/bash-effects.js +405 -0
- package/dist/core/compile.d.ts +3 -1
- package/dist/core/compile.js +176 -39
- package/dist/core/dialect.d.ts +10 -0
- package/dist/core/effects.d.ts +172 -0
- package/dist/core/effects.js +245 -0
- package/dist/core/generate-harness.d.ts +187 -0
- package/dist/core/generate-harness.js +337 -0
- package/dist/core/layout.d.ts +6 -0
- package/dist/core/mcp-tool.d.ts +1 -1
- package/dist/core/orphans.js +21 -0
- package/dist/core/spec.d.ts +432 -11
- package/dist/core/spec.js +166 -3
- package/dist/core/tool-contract.d.ts +1 -1
- package/dist/core/types.d.ts +6 -6
- package/dist/core/validate.js +4 -4
- package/dist/harness-test.d.ts +7 -0
- package/dist/harness-test.js +19 -7
- package/dist/leaderboard.d.ts +2 -0
- package/dist/leaderboard.js +2 -0
- package/dist/optimize.d.ts +74 -0
- package/dist/optimize.js +94 -0
- package/dist/scaffold-test.d.ts +58 -0
- package/dist/scaffold-test.js +263 -0
- package/dist/scan.d.ts +40 -0
- package/dist/scan.js +91 -43
- package/dist/score-explainer.d.ts +69 -0
- package/dist/score-explainer.js +169 -0
- package/dist/test-coverage.d.ts +7 -0
- package/dist/test-coverage.js +39 -24
- package/package.json +2 -1
- package/skills/{migrate-to-spec → adopt-spec}/SKILL.md +4 -4
- package/skills/edit-spec/SKILL.md +1 -1
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed Claude Code authoring surface — the compile-time half of the purity
|
|
3
|
+
* contract, bound to the Claude Code tool vocabulary.
|
|
4
|
+
*
|
|
5
|
+
* The core `agent()` / `skill()` builders (`vigiles/spec`) are generic over a
|
|
6
|
+
* tool `ToolVocabulary` that DEFAULTS to fully-open (`string` at every purity
|
|
7
|
+
* level), so they accept any tools — backwards-compatible, harness-agnostic.
|
|
8
|
+
* This module re-binds them to the CONCRETE Claude Code vocabulary derived from
|
|
9
|
+
* `claudeCodeDialect`, so authoring a spec with an invalid `purity`×`tools`
|
|
10
|
+
* combination is a `tsc` error at EDIT TIME, before any vigiles command runs:
|
|
11
|
+
*
|
|
12
|
+
* import { agent } from "vigiles/claude-code";
|
|
13
|
+
*
|
|
14
|
+
* agent({ purity: "pure", tools: ["Read", "Bash"] });
|
|
15
|
+
* // ^^^^^^ tsc error — Bash side-effecting
|
|
16
|
+
*
|
|
17
|
+
* agent({ purity: "bounded", tools: ["Read", "Bash", "Write"] }); // OK
|
|
18
|
+
* agent({ purity: "bounded", tools: ["mcp__x__y"] });
|
|
19
|
+
* // ^^^^^^^^^^^ tsc error — MCP not decidable
|
|
20
|
+
*
|
|
21
|
+
* agent({ tools: ["anything", "mcp__x__y"] }); // no purity → open, OK
|
|
22
|
+
*
|
|
23
|
+
* This is a STRICT ADDITION to the runtime/compile checks: `purityViolations`
|
|
24
|
+
* (`vigiles compile`) and `decidePurityGate` (the PreToolUse gate) are unchanged
|
|
25
|
+
* and remain the universal backstop. In particular the command-level decision a
|
|
26
|
+
* `bounded` unit makes for `Bash` (read-only command allowed, mutating denied)
|
|
27
|
+
* is the RUNTIME gate's job — the type only admits the `Bash` TOOL at `bounded`.
|
|
28
|
+
*
|
|
29
|
+
* The CC literal tool names live ONLY in this adapter (and the dialect it reads
|
|
30
|
+
* from), never in core — the hexagonal boundary that keeps the domain
|
|
31
|
+
* harness-agnostic.
|
|
32
|
+
*/
|
|
33
|
+
import { type AgentSpec, type AgentSpecInput, type SkillSpec, type SkillSpecInput, type AuthoredPurity, type ToolVocabulary } from "../../core/spec.js";
|
|
34
|
+
import type { ClaudeCodeReadOnlyTool, ClaudeCodeBoundedTool } from "./dialect.js";
|
|
35
|
+
/**
|
|
36
|
+
* The Claude Code tool vocabulary, split by the purity floor that admits each
|
|
37
|
+
* tool (mirrors the runtime ladder in `core/effects.ts`):
|
|
38
|
+
* - `readOnly`: tools a `pure` unit may declare (Read/Grep/Glob/LS).
|
|
39
|
+
* - `bounded`: read-only ∪ Write/Edit/MultiEdit/NotebookEdit ∪ `Bash`.
|
|
40
|
+
*/
|
|
41
|
+
export interface ClaudeCodeToolVocabulary extends ToolVocabulary {
|
|
42
|
+
readonly readOnly: ClaudeCodeReadOnlyTool;
|
|
43
|
+
readonly bounded: ClaudeCodeBoundedTool;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Define a Claude Code subagent with the purity floor enforced AT COMPILE TIME
|
|
47
|
+
* against the Claude Code tool catalog. Identical to the core `agent()` at
|
|
48
|
+
* runtime (it IS the core builder); the only difference is the typed `tools`
|
|
49
|
+
* constraint. `P` is inferred from the literal `purity` field.
|
|
50
|
+
*/
|
|
51
|
+
export declare function agent<const P extends AuthoredPurity | undefined = undefined>(spec: AgentSpecInput<P, ClaudeCodeToolVocabulary>): AgentSpec;
|
|
52
|
+
/**
|
|
53
|
+
* Define a Claude Code skill with the purity floor enforced AT COMPILE TIME
|
|
54
|
+
* against the Claude Code tool catalog. Identical to the core `skill()` at
|
|
55
|
+
* runtime; the typed `tools` constraint is the only difference.
|
|
56
|
+
*/
|
|
57
|
+
export declare function skill<const P extends AuthoredPurity | undefined = undefined>(spec: SkillSpecInput<P, ClaudeCodeToolVocabulary>): SkillSpec;
|
|
58
|
+
//# sourceMappingURL=typed-spec.d.ts.map
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.agent = agent;
|
|
4
|
+
exports.skill = skill;
|
|
5
|
+
/**
|
|
6
|
+
* Typed Claude Code authoring surface — the compile-time half of the purity
|
|
7
|
+
* contract, bound to the Claude Code tool vocabulary.
|
|
8
|
+
*
|
|
9
|
+
* The core `agent()` / `skill()` builders (`vigiles/spec`) are generic over a
|
|
10
|
+
* tool `ToolVocabulary` that DEFAULTS to fully-open (`string` at every purity
|
|
11
|
+
* level), so they accept any tools — backwards-compatible, harness-agnostic.
|
|
12
|
+
* This module re-binds them to the CONCRETE Claude Code vocabulary derived from
|
|
13
|
+
* `claudeCodeDialect`, so authoring a spec with an invalid `purity`×`tools`
|
|
14
|
+
* combination is a `tsc` error at EDIT TIME, before any vigiles command runs:
|
|
15
|
+
*
|
|
16
|
+
* import { agent } from "vigiles/claude-code";
|
|
17
|
+
*
|
|
18
|
+
* agent({ purity: "pure", tools: ["Read", "Bash"] });
|
|
19
|
+
* // ^^^^^^ tsc error — Bash side-effecting
|
|
20
|
+
*
|
|
21
|
+
* agent({ purity: "bounded", tools: ["Read", "Bash", "Write"] }); // OK
|
|
22
|
+
* agent({ purity: "bounded", tools: ["mcp__x__y"] });
|
|
23
|
+
* // ^^^^^^^^^^^ tsc error — MCP not decidable
|
|
24
|
+
*
|
|
25
|
+
* agent({ tools: ["anything", "mcp__x__y"] }); // no purity → open, OK
|
|
26
|
+
*
|
|
27
|
+
* This is a STRICT ADDITION to the runtime/compile checks: `purityViolations`
|
|
28
|
+
* (`vigiles compile`) and `decidePurityGate` (the PreToolUse gate) are unchanged
|
|
29
|
+
* and remain the universal backstop. In particular the command-level decision a
|
|
30
|
+
* `bounded` unit makes for `Bash` (read-only command allowed, mutating denied)
|
|
31
|
+
* is the RUNTIME gate's job — the type only admits the `Bash` TOOL at `bounded`.
|
|
32
|
+
*
|
|
33
|
+
* The CC literal tool names live ONLY in this adapter (and the dialect it reads
|
|
34
|
+
* from), never in core — the hexagonal boundary that keeps the domain
|
|
35
|
+
* harness-agnostic.
|
|
36
|
+
*/
|
|
37
|
+
const spec_js_1 = require("../../core/spec.js");
|
|
38
|
+
/**
|
|
39
|
+
* Define a Claude Code subagent with the purity floor enforced AT COMPILE TIME
|
|
40
|
+
* against the Claude Code tool catalog. Identical to the core `agent()` at
|
|
41
|
+
* runtime (it IS the core builder); the only difference is the typed `tools`
|
|
42
|
+
* constraint. `P` is inferred from the literal `purity` field.
|
|
43
|
+
*/
|
|
44
|
+
function agent(spec) {
|
|
45
|
+
return (0, spec_js_1.agent)(spec);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Define a Claude Code skill with the purity floor enforced AT COMPILE TIME
|
|
49
|
+
* against the Claude Code tool catalog. Identical to the core `skill()` at
|
|
50
|
+
* runtime; the typed `tools` constraint is the only difference.
|
|
51
|
+
*/
|
|
52
|
+
function skill(spec) {
|
|
53
|
+
return (0, spec_js_1.skill)(spec);
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=typed-spec.js.map
|
|
@@ -29,6 +29,9 @@ exports.codexAdapter = {
|
|
|
29
29
|
referenceVerification: true,
|
|
30
30
|
harnessTesting: true,
|
|
31
31
|
shellHooks: true,
|
|
32
|
+
// Codex `[agents]` is a concurrency table, not a subagent tool-contract file
|
|
33
|
+
// — the subagent-surface rules report n/a here (a deliberate non-goal).
|
|
34
|
+
subagents: false,
|
|
32
35
|
},
|
|
33
36
|
dialect: dialect_js_1.codexDialect,
|
|
34
37
|
layout: layout_js_1.codexLayout,
|
|
@@ -9,6 +9,9 @@ exports.codexLayout = {
|
|
|
9
9
|
settingsFormat: "toml",
|
|
10
10
|
instructionFile: "AGENTS.md",
|
|
11
11
|
surfaceDirs: ["skills", "prompts"],
|
|
12
|
+
skillDir: "skills",
|
|
13
|
+
agentDir: "", // Codex `[agents]` is a TOML concurrency table, not a subagent dir
|
|
14
|
+
commandDir: "prompts",
|
|
12
15
|
materializeRoot: ".codex",
|
|
13
16
|
pluginRootToken: "${PLUGIN_ROOT}",
|
|
14
17
|
mcpConfigFile: ".mcp.json",
|
|
@@ -16,6 +16,9 @@ exports.opencodeLayout = {
|
|
|
16
16
|
// `.opencode/` segment. (Contrast Claude Code: root-level `skills/` surfaces
|
|
17
17
|
// relocated under `.claude`.)
|
|
18
18
|
surfaceDirs: [".opencode/agent", ".opencode/command"],
|
|
19
|
+
skillDir: ".opencode/skill",
|
|
20
|
+
agentDir: ".opencode/agent",
|
|
21
|
+
commandDir: ".opencode/command",
|
|
19
22
|
materializeRoot: "",
|
|
20
23
|
pluginRootToken: "${OPENCODE_PLUGIN_ROOT}",
|
|
21
24
|
mcpConfigFile: "opencode.json",
|
package/dist/check.d.ts
CHANGED
|
@@ -104,6 +104,14 @@ export declare function turns(opts: {
|
|
|
104
104
|
}): Check<Trace>;
|
|
105
105
|
/** The agent wrote (or left) a file at this path in the work dir. */
|
|
106
106
|
export declare function wrote(path: string): Check<Trace>;
|
|
107
|
+
/**
|
|
108
|
+
* The agent did NOT leave a file at this path — the **side-effect boundary**
|
|
109
|
+
* negative: a skill that declares it writes only `out.txt` should leave nothing
|
|
110
|
+
* at `secrets.env`. The symmetric sibling of `wrote()`; pairs with
|
|
111
|
+
* `notTool(...)` to assert a unit stayed inside its declared write surface
|
|
112
|
+
* deterministically (no model judge).
|
|
113
|
+
*/
|
|
114
|
+
export declare function didNotWrite(path: string): Check<Trace>;
|
|
107
115
|
/** The named subagent (`Task` `subagent_type`) ran and passed every nested check. */
|
|
108
116
|
export declare function subagent(name: string, checks: readonly Check<Trace>[]): Check<Trace>;
|
|
109
117
|
/** The hook blocked the event (exit 2 / deny / block). */
|
package/dist/check.js
CHANGED
|
@@ -11,6 +11,7 @@ exports.hookFired = hookFired;
|
|
|
11
11
|
exports.received = received;
|
|
12
12
|
exports.turns = turns;
|
|
13
13
|
exports.wrote = wrote;
|
|
14
|
+
exports.didNotWrite = didNotWrite;
|
|
14
15
|
exports.subagent = subagent;
|
|
15
16
|
exports.blocked = blocked;
|
|
16
17
|
exports.allowed = allowed;
|
|
@@ -236,16 +237,34 @@ function wrote(path) {
|
|
|
236
237
|
toJSON: () => ({ kind: "wrote", path }),
|
|
237
238
|
};
|
|
238
239
|
}
|
|
240
|
+
/**
|
|
241
|
+
* The agent did NOT leave a file at this path — the **side-effect boundary**
|
|
242
|
+
* negative: a skill that declares it writes only `out.txt` should leave nothing
|
|
243
|
+
* at `secrets.env`. The symmetric sibling of `wrote()`; pairs with
|
|
244
|
+
* `notTool(...)` to assert a unit stayed inside its declared write surface
|
|
245
|
+
* deterministically (no model judge).
|
|
246
|
+
*/
|
|
247
|
+
function didNotWrite(path) {
|
|
248
|
+
return {
|
|
249
|
+
kind: "didNotWrite",
|
|
250
|
+
eval: (t) => t.file(path) === null
|
|
251
|
+
? ok(`file "${path}" was not created`)
|
|
252
|
+
: no(`expected the agent NOT to create "${path}", but it exists`),
|
|
253
|
+
toJSON: () => ({ kind: "didNotWrite", path }),
|
|
254
|
+
};
|
|
255
|
+
}
|
|
239
256
|
// ---------------------------------------------------------------------------
|
|
240
257
|
// Subagent — a `Task` run as a nested trace. Run checks over what the SUBAGENT
|
|
241
258
|
// did, not just that `Task` fired. Composes the whole vocabulary recursively.
|
|
242
259
|
// ---------------------------------------------------------------------------
|
|
243
|
-
/** Wrap a subagent's tool calls as a minimal `Trace` so checks
|
|
260
|
+
/** Wrap a subagent's tool calls + returned text as a minimal `Trace` so checks
|
|
261
|
+
* (incl. `output()` over the sub's RETURN — where a result() vigiles:ok/err block
|
|
262
|
+
* lands) run over it. */
|
|
244
263
|
function subTrace(sub) {
|
|
245
264
|
return {
|
|
246
265
|
toolCalls: sub.toolCalls,
|
|
247
266
|
hooks: [],
|
|
248
|
-
output:
|
|
267
|
+
output: sub.output,
|
|
249
268
|
modelRequests: [],
|
|
250
269
|
turns: 0,
|
|
251
270
|
subagents: [],
|
|
@@ -258,7 +277,12 @@ function subagent(name, checks) {
|
|
|
258
277
|
kind: "subagent",
|
|
259
278
|
eval: (t) => {
|
|
260
279
|
const subs = t.subagents ?? [];
|
|
261
|
-
|
|
280
|
+
// A `--plugin-dir` agent's `subagent_type` is namespaced `plugin:agent`
|
|
281
|
+
// (e.g. "reviewer-spec:code-reviewer"), but callers pass the bare agent name
|
|
282
|
+
// — so match the full id OR its last `:`-segment. Non-namespaced (harness
|
|
283
|
+
// mock) names match exactly as before.
|
|
284
|
+
const bare = (n) => n.includes(":") ? n.slice(n.lastIndexOf(":") + 1) : n;
|
|
285
|
+
const sub = subs.find((s) => s.name === name || bare(s.name) === name);
|
|
262
286
|
if (!sub) {
|
|
263
287
|
return no(`expected subagent "${name}" to run; subagents that ran: ${subs.length > 0 ? `[${subs.map((s) => s.name).join(", ")}]` : "none"}`);
|
|
264
288
|
}
|
package/dist/claude-code.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export * from "./adapters/claude-code/plugin-loader.js";
|
|
|
9
9
|
export * from "./mock-model.js";
|
|
10
10
|
export { claudeCodeDriver, buildClaudeArgs, parseClaudeRun, claudeAvailable, } from "./harness-test.js";
|
|
11
11
|
export * from "./adapters/claude-code/dialect.js";
|
|
12
|
+
export { agent, skill, type ClaudeCodeToolVocabulary, } from "./adapters/claude-code/typed-spec.js";
|
|
12
13
|
export * from "./adapters/claude-code/layout.js";
|
|
13
14
|
export * from "./adapters/claude-code/runtime.js";
|
|
14
15
|
export * from "./adapters/claude-code/hook-protocol.js";
|
package/dist/claude-code.js
CHANGED
|
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.claudeAvailable = exports.parseClaudeRun = exports.buildClaudeArgs = exports.claudeCodeDriver = void 0;
|
|
17
|
+
exports.skill = exports.agent = exports.claudeAvailable = exports.parseClaudeRun = exports.buildClaudeArgs = exports.claudeCodeDriver = void 0;
|
|
18
18
|
/**
|
|
19
19
|
* `vigiles/claude-code` — the Claude Code-specific harness pieces a *different*
|
|
20
20
|
* harness would swap out: the plugin/repo loader (reads real Claude Code plugin
|
|
@@ -35,6 +35,13 @@ Object.defineProperty(exports, "buildClaudeArgs", { enumerable: true, get: funct
|
|
|
35
35
|
Object.defineProperty(exports, "parseClaudeRun", { enumerable: true, get: function () { return harness_test_js_1.parseClaudeRun; } });
|
|
36
36
|
Object.defineProperty(exports, "claudeAvailable", { enumerable: true, get: function () { return harness_test_js_1.claudeAvailable; } });
|
|
37
37
|
__exportStar(require("./adapters/claude-code/dialect.js"), exports);
|
|
38
|
+
// The typed Claude Code authoring surface: `agent` / `skill` with the `purity`
|
|
39
|
+
// floor enforced AT COMPILE TIME against the CC tool catalog (a `tsc` error for
|
|
40
|
+
// e.g. `purity: "pure"` + `"Bash"`). A strict addition to the runtime/compile
|
|
41
|
+
// purity checks; the bare core `agent()`/`skill()` (`vigiles/spec`) stay open.
|
|
42
|
+
var typed_spec_js_1 = require("./adapters/claude-code/typed-spec.js");
|
|
43
|
+
Object.defineProperty(exports, "agent", { enumerable: true, get: function () { return typed_spec_js_1.agent; } });
|
|
44
|
+
Object.defineProperty(exports, "skill", { enumerable: true, get: function () { return typed_spec_js_1.skill; } });
|
|
38
45
|
__exportStar(require("./adapters/claude-code/layout.js"), exports);
|
|
39
46
|
__exportStar(require("./adapters/claude-code/runtime.js"), exports);
|
|
40
47
|
__exportStar(require("./adapters/claude-code/hook-protocol.js"), exports);
|