agentopology 0.9.2 → 0.10.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 +17 -19
- package/dist/__tests__/e2e/action-guard.test.d.ts +13 -0
- package/dist/__tests__/e2e/action-guard.test.d.ts.map +1 -0
- package/dist/__tests__/e2e/action-guard.test.js +299 -0
- package/dist/__tests__/e2e/action-guard.test.js.map +1 -0
- package/dist/__tests__/e2e/conformance.test.d.ts +13 -0
- package/dist/__tests__/e2e/conformance.test.d.ts.map +1 -0
- package/dist/__tests__/e2e/conformance.test.js +109 -0
- package/dist/__tests__/e2e/conformance.test.js.map +1 -0
- package/dist/__tests__/e2e/contract-drift.test.d.ts +11 -0
- package/dist/__tests__/e2e/contract-drift.test.d.ts.map +1 -0
- package/dist/__tests__/e2e/contract-drift.test.js +142 -0
- package/dist/__tests__/e2e/contract-drift.test.js.map +1 -0
- package/dist/__tests__/e2e/guard-check.test.d.ts +9 -0
- package/dist/__tests__/e2e/guard-check.test.d.ts.map +1 -0
- package/dist/__tests__/e2e/guard-check.test.js +316 -0
- package/dist/__tests__/e2e/guard-check.test.js.map +1 -0
- package/dist/__tests__/e2e/guard-target.test.d.ts +11 -0
- package/dist/__tests__/e2e/guard-target.test.d.ts.map +1 -0
- package/dist/__tests__/e2e/guard-target.test.js +198 -0
- package/dist/__tests__/e2e/guard-target.test.js.map +1 -0
- package/dist/__tests__/e2e/inventory.test.d.ts +18 -0
- package/dist/__tests__/e2e/inventory.test.d.ts.map +1 -0
- package/dist/__tests__/e2e/inventory.test.js +187 -0
- package/dist/__tests__/e2e/inventory.test.js.map +1 -0
- package/dist/__tests__/e2e/matcher.test.d.ts +14 -0
- package/dist/__tests__/e2e/matcher.test.d.ts.map +1 -0
- package/dist/__tests__/e2e/matcher.test.js +145 -0
- package/dist/__tests__/e2e/matcher.test.js.map +1 -0
- package/dist/__tests__/e2e/step-check.test.d.ts +9 -0
- package/dist/__tests__/e2e/step-check.test.d.ts.map +1 -0
- package/dist/__tests__/e2e/step-check.test.js +158 -0
- package/dist/__tests__/e2e/step-check.test.js.map +1 -0
- package/dist/__tests__/e2e/strength.test.d.ts +17 -0
- package/dist/__tests__/e2e/strength.test.d.ts.map +1 -0
- package/dist/__tests__/e2e/strength.test.js +130 -0
- package/dist/__tests__/e2e/strength.test.js.map +1 -0
- package/dist/__tests__/e2e/verified-on.test.d.ts +2 -0
- package/dist/__tests__/e2e/verified-on.test.d.ts.map +1 -0
- package/dist/__tests__/e2e/verified-on.test.js +57 -0
- package/dist/__tests__/e2e/verified-on.test.js.map +1 -0
- package/dist/__tests__/open-findings.test.js +1 -0
- package/dist/__tests__/open-findings.test.js.map +1 -1
- package/dist/bindings/__tests__/bindings.test.js +6 -686
- package/dist/bindings/__tests__/bindings.test.js.map +1 -1
- package/dist/bindings/__tests__/defaults-agreement.test.js +0 -12
- package/dist/bindings/__tests__/defaults-agreement.test.js.map +1 -1
- package/dist/bindings/__tests__/hook-command.test.js +2 -2
- package/dist/bindings/__tests__/hook-command.test.js.map +1 -1
- package/dist/bindings/__tests__/mod-plugin.test.js +2 -2
- package/dist/bindings/__tests__/mod-plugin.test.js.map +1 -1
- package/dist/bindings/claude-code.d.ts +45 -1
- package/dist/bindings/claude-code.d.ts.map +1 -1
- package/dist/bindings/claude-code.js +181 -15
- package/dist/bindings/claude-code.js.map +1 -1
- package/dist/bindings/index.d.ts +5 -5
- package/dist/bindings/index.d.ts.map +1 -1
- package/dist/bindings/index.js +9 -16
- package/dist/bindings/index.js.map +1 -1
- package/dist/bindings/types.d.ts +6 -1
- package/dist/bindings/types.d.ts.map +1 -1
- package/dist/cli/__tests__/cli.test.js +25 -0
- package/dist/cli/__tests__/cli.test.js.map +1 -1
- package/dist/cli/index.js +222 -8
- package/dist/cli/index.js.map +1 -1
- package/dist/conformance/claude-code.d.ts +99 -0
- package/dist/conformance/claude-code.d.ts.map +1 -0
- package/dist/conformance/claude-code.js +242 -0
- package/dist/conformance/claude-code.js.map +1 -0
- package/dist/conformance/extract.d.ts +70 -0
- package/dist/conformance/extract.d.ts.map +1 -0
- package/dist/conformance/extract.js +185 -0
- package/dist/conformance/extract.js.map +1 -0
- package/dist/docs/content.d.ts.map +1 -1
- package/dist/docs/content.js +57 -32
- package/dist/docs/content.js.map +1 -1
- package/dist/guard/check.d.ts +53 -0
- package/dist/guard/check.d.ts.map +1 -0
- package/dist/guard/check.js +366 -0
- package/dist/guard/check.js.map +1 -0
- package/dist/guard/target.d.ts +45 -0
- package/dist/guard/target.d.ts.map +1 -0
- package/dist/guard/target.js +168 -0
- package/dist/guard/target.js.map +1 -0
- package/dist/import/__tests__/import.test.js +0 -554
- package/dist/import/__tests__/import.test.js.map +1 -1
- package/dist/import/index.d.ts +0 -1
- package/dist/import/index.d.ts.map +1 -1
- package/dist/import/index.js +1 -7
- package/dist/import/index.js.map +1 -1
- package/dist/import/serializer.d.ts.map +1 -1
- package/dist/import/serializer.js +41 -0
- package/dist/import/serializer.js.map +1 -1
- package/dist/index.d.ts +0 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -4
- package/dist/index.js.map +1 -1
- package/dist/inventory/index.d.ts +65 -0
- package/dist/inventory/index.d.ts.map +1 -0
- package/dist/inventory/index.js +272 -0
- package/dist/inventory/index.js.map +1 -0
- package/dist/parser/ast.d.ts +46 -0
- package/dist/parser/ast.d.ts.map +1 -1
- package/dist/parser/ast.js.map +1 -1
- package/dist/parser/index.d.ts +6 -1
- package/dist/parser/index.d.ts.map +1 -1
- package/dist/parser/index.js +66 -4
- package/dist/parser/index.js.map +1 -1
- package/dist/parser/known-fields.d.ts +3 -0
- package/dist/parser/known-fields.d.ts.map +1 -1
- package/dist/parser/known-fields.js +5 -3
- package/dist/parser/known-fields.js.map +1 -1
- package/dist/parser/ledger.d.ts +36 -0
- package/dist/parser/ledger.d.ts.map +1 -0
- package/dist/parser/ledger.js +72 -0
- package/dist/parser/ledger.js.map +1 -0
- package/dist/parser/run.d.ts +6 -0
- package/dist/parser/run.d.ts.map +1 -1
- package/dist/parser/run.js +10 -0
- package/dist/parser/run.js.map +1 -1
- package/dist/parser/validator.d.ts.map +1 -1
- package/dist/parser/validator.js +255 -1
- package/dist/parser/validator.js.map +1 -1
- package/dist/scaffold/manifest.d.ts.map +1 -1
- package/dist/scaffold/manifest.js +0 -8
- package/dist/scaffold/manifest.js.map +1 -1
- package/dist/scaffold/merge.d.ts.map +1 -1
- package/dist/scaffold/merge.js +1 -3
- package/dist/scaffold/merge.js.map +1 -1
- package/dist/step/check.d.ts +56 -0
- package/dist/step/check.d.ts.map +1 -0
- package/dist/step/check.js +125 -0
- package/dist/step/check.js.map +1 -0
- package/dist/sync/index.d.ts +0 -2
- package/dist/sync/index.d.ts.map +1 -1
- package/dist/sync/index.js +0 -109
- package/dist/sync/index.js.map +1 -1
- package/package.json +3 -1
- package/spec/claude-code/README.md +19 -0
- package/spec/claude-code/hooks-contract.2.1.295.json +143 -0
- package/spec/claude-code/hooks-contract.json +142 -0
- package/spec/grammar.md +45 -7
- package/spec/testing.md +15 -0
- package/spec/validation.md +11 -2
- package/dist/__tests__/live/zz-debug.test.d.ts +0 -2
- package/dist/__tests__/live/zz-debug.test.d.ts.map +0 -1
- package/dist/__tests__/live/zz-debug.test.js +0 -4
- package/dist/__tests__/live/zz-debug.test.js.map +0 -1
- package/dist/bindings/copilot-cli.d.ts +0 -20
- package/dist/bindings/copilot-cli.d.ts.map +0 -1
- package/dist/bindings/copilot-cli.js +0 -1516
- package/dist/bindings/copilot-cli.js.map +0 -1
- package/dist/bindings/gemini-cli.d.ts +0 -18
- package/dist/bindings/gemini-cli.d.ts.map +0 -1
- package/dist/bindings/gemini-cli.js +0 -1318
- package/dist/bindings/gemini-cli.js.map +0 -1
- package/dist/bindings/kiro.d.ts +0 -17
- package/dist/bindings/kiro.d.ts.map +0 -1
- package/dist/bindings/kiro.js +0 -1615
- package/dist/bindings/kiro.js.map +0 -1
- package/dist/bindings/openclaw.d.ts +0 -18
- package/dist/bindings/openclaw.d.ts.map +0 -1
- package/dist/bindings/openclaw.js +0 -1947
- package/dist/bindings/openclaw.js.map +0 -1
- package/dist/import/openclaw.d.ts +0 -70
- package/dist/import/openclaw.d.ts.map +0 -1
- package/dist/import/openclaw.js +0 -1060
- package/dist/import/openclaw.js.map +0 -1
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code's hook contract as a committed snapshot (N37).
|
|
3
|
+
*
|
|
4
|
+
* spec/claude-code/hooks-contract.json is extracted from the hooks reference
|
|
5
|
+
* page by scripts/claude-code-drift.mjs; the minimum version's contract
|
|
6
|
+
* (hooks-contract.2.1.295.json) is derived from it by dropping what requires a
|
|
7
|
+
* newer version. These tests are offline: they hold the code to the snapshot,
|
|
8
|
+
* and the script holds the snapshot to the live page.
|
|
9
|
+
*/
|
|
10
|
+
import { describe, it, expect } from "vitest";
|
|
11
|
+
import * as fs from "node:fs";
|
|
12
|
+
import { resolve, dirname, join } from "node:path";
|
|
13
|
+
import { fileURLToPath } from "node:url";
|
|
14
|
+
import { parse } from "../../parser/index.js";
|
|
15
|
+
import { claudeCodeBinding } from "../../bindings/claude-code.js";
|
|
16
|
+
import { HOOK_EVENTS, NO_MATCHER_EVENTS, HANDLER_REQUIRED, ON_FAILURE_TYPES, VERIFIED_ON, MINIMUM_VERSION, } from "../../conformance/claude-code.js";
|
|
17
|
+
import { extractHookContract, contractAt, diffContracts, hasDrift, renderDiff } from "../../conformance/extract.js";
|
|
18
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
19
|
+
const repo = resolve(here, "../../..");
|
|
20
|
+
const read = (p) => JSON.parse(fs.readFileSync(join(repo, p), "utf8"));
|
|
21
|
+
const current = read("spec/claude-code/hooks-contract.json");
|
|
22
|
+
const minimum = read(`spec/claude-code/hooks-contract.${MINIMUM_VERSION}.json`);
|
|
23
|
+
const fieldsOf = (c, type) => ({ ...c.fields.common, ...c.fields[type === "agent" ? "prompt" : type] });
|
|
24
|
+
describe("the code agrees with the snapshot", () => {
|
|
25
|
+
it("[N37] [SD1] the event list, the no-matcher events, the handler types and onFailure match the snapshot", () => {
|
|
26
|
+
expect([...HOOK_EVENTS].sort()).toEqual([...current.events].sort());
|
|
27
|
+
expect([...NO_MATCHER_EVENTS].sort()).toEqual(current.noMatcherEvents);
|
|
28
|
+
expect(Object.keys(HANDLER_REQUIRED).sort()).toEqual([...current.handlerTypes].sort());
|
|
29
|
+
for (const type of current.handlerTypes) {
|
|
30
|
+
const required = Object.entries(fieldsOf(current, type)).filter(([n, f]) => f.required && n !== "type").map(([n]) => n);
|
|
31
|
+
expect([...HANDLER_REQUIRED[type]].sort(), type).toEqual(required.sort());
|
|
32
|
+
}
|
|
33
|
+
const withOnFailure = current.handlerTypes.filter((t) => "onFailure" in fieldsOf(current, t));
|
|
34
|
+
expect([...ON_FAILURE_TYPES].sort()).toEqual(withOnFailure.sort());
|
|
35
|
+
});
|
|
36
|
+
it("[N37] [SD2] the snapshot is of the verified version; the minimum's is derived from it at MINIMUM_VERSION", () => {
|
|
37
|
+
expect(current.claudeCode).toBe(VERIFIED_ON);
|
|
38
|
+
expect(minimum).toEqual(contractAt(current, MINIMUM_VERSION));
|
|
39
|
+
expect(minimum).toMatchObject({ derived: true, claudeCode: MINIMUM_VERSION });
|
|
40
|
+
});
|
|
41
|
+
it("[N37] [SD3] everything the binding writes exists at the minimum version: every event, every handler field", () => {
|
|
42
|
+
const files = [
|
|
43
|
+
...fs.readdirSync(join(repo, "examples")).filter((f) => f.endsWith(".at")).map((f) => join(repo, "examples", f)),
|
|
44
|
+
...["compile.at", "hazards.at"].map((f) => join(here, "fixtures", f)),
|
|
45
|
+
join(repo, "kitchen-sink.at"),
|
|
46
|
+
];
|
|
47
|
+
const problems = [];
|
|
48
|
+
for (const file of files) {
|
|
49
|
+
const out = claudeCodeBinding.scaffold(parse(fs.readFileSync(file, "utf8")));
|
|
50
|
+
const settings = out.find((f) => f.path === ".claude/settings.json");
|
|
51
|
+
if (!settings)
|
|
52
|
+
continue;
|
|
53
|
+
for (const [event, entries] of Object.entries(JSON.parse(settings.content).hooks ?? {})) {
|
|
54
|
+
if (!minimum.events.includes(event))
|
|
55
|
+
problems.push(`${file}: event ${event}`);
|
|
56
|
+
for (const entry of entries) {
|
|
57
|
+
for (const h of entry.hooks ?? []) {
|
|
58
|
+
const allowed = fieldsOf(minimum, h.type);
|
|
59
|
+
for (const key of Object.keys(h))
|
|
60
|
+
if (!(key in allowed))
|
|
61
|
+
problems.push(`${file}: ${event} ${h.type}.${key}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
expect(problems).toEqual([]);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
const PAGE = `# Hooks reference
|
|
70
|
+
|
|
71
|
+
### Matcher patterns
|
|
72
|
+
|
|
73
|
+
| Matcher value | Evaluated as | Example |
|
|
74
|
+
| :- | :- | :- |
|
|
75
|
+
| \`"*"\` | Match all | every |
|
|
76
|
+
| Only letters | Exact string | \`Bash\` |
|
|
77
|
+
|
|
78
|
+
| Event | What the matcher filters | Example matcher values |
|
|
79
|
+
| :- | :- | :- |
|
|
80
|
+
| \`PreToolUse\` | tool name | \`Bash\` |
|
|
81
|
+
| \`Stop\`, \`Ping\` | no matcher support | always fires |
|
|
82
|
+
|
|
83
|
+
#### Common fields
|
|
84
|
+
|
|
85
|
+
| Field | Required | Description |
|
|
86
|
+
| :- | :- | :- |
|
|
87
|
+
| \`type\` | yes | \`"command"\` or \`"http"\` |
|
|
88
|
+
| \`timeout\` | no | Seconds |
|
|
89
|
+
|
|
90
|
+
#### Command hook fields
|
|
91
|
+
|
|
92
|
+
| Field | Required | Description |
|
|
93
|
+
| :- | :- | :- |
|
|
94
|
+
| \`command\` | yes | Shell command |
|
|
95
|
+
| \`onFailure\` | no | Block or continue. Requires Claude Code v2.1.295 or later |
|
|
96
|
+
|
|
97
|
+
## Hook events
|
|
98
|
+
|
|
99
|
+
### PreToolUse
|
|
100
|
+
|
|
101
|
+
\`\`\`bash
|
|
102
|
+
#!/bin/bash
|
|
103
|
+
# a comment in an example, not a heading
|
|
104
|
+
\`\`\`
|
|
105
|
+
|
|
106
|
+
### Ping
|
|
107
|
+
|
|
108
|
+
Ping requires Claude Code v2.1.400 or later.
|
|
109
|
+
|
|
110
|
+
### Stop
|
|
111
|
+
|
|
112
|
+
## Debug hooks
|
|
113
|
+
`;
|
|
114
|
+
const meta = { source: "test", fetched: "2026-11-10", claudeCode: "2.1.319" };
|
|
115
|
+
describe("the extractor and the diff", () => {
|
|
116
|
+
it("[N37] [SD4] events, their versions, the no-matcher events, handler fields; a # comment in a code block is not a heading", () => {
|
|
117
|
+
const c = extractHookContract(PAGE, meta);
|
|
118
|
+
expect(c.events).toEqual(["PreToolUse", "Ping", "Stop"]);
|
|
119
|
+
expect(c.eventRequires).toEqual({ Ping: "2.1.400" });
|
|
120
|
+
expect(c.noMatcherEvents).toEqual(["Ping", "Stop"]);
|
|
121
|
+
expect(c.handlerTypes).toEqual(["command", "http"]);
|
|
122
|
+
expect(c.fields.command).toEqual({ command: { required: true }, onFailure: { required: false, requires: "2.1.295" } });
|
|
123
|
+
expect(c.matcherRules).toHaveLength(2);
|
|
124
|
+
});
|
|
125
|
+
it("[N37] [SD5] the contract at an older version drops what needs a newer one", () => {
|
|
126
|
+
const c = extractHookContract(PAGE, meta);
|
|
127
|
+
expect(contractAt(c, "2.1.300").events).toEqual(["PreToolUse", "Stop"]);
|
|
128
|
+
expect(Object.keys(contractAt(c, "2.1.290").fields.command)).toEqual(["command"]);
|
|
129
|
+
});
|
|
130
|
+
it("[N37] [SD6] a diff names what moved, and the same page has none", () => {
|
|
131
|
+
const before = extractHookContract(PAGE, meta);
|
|
132
|
+
expect(hasDrift(diffContracts(before, before))).toBe(false);
|
|
133
|
+
expect(renderDiff(diffContracts(before, before))).toEqual(["no drift"]);
|
|
134
|
+
const page = PAGE.replace("### Stop", "### Stop\n\n### Wake").replace("v2.1.295", "v2.1.300").replace("| `timeout` | no | Seconds |\n", "");
|
|
135
|
+
const d = diffContracts(before, extractHookContract(page, meta));
|
|
136
|
+
expect(d.eventsAdded).toEqual(["Wake"]);
|
|
137
|
+
expect(d.fieldsRemoved).toEqual(["common.timeout"]);
|
|
138
|
+
expect(d.changed).toEqual(["command.onFailure: requires 2.1.295 → 2.1.300"]);
|
|
139
|
+
expect(hasDrift(d)).toBe(true);
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
//# sourceMappingURL=contract-drift.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract-drift.test.js","sourceRoot":"","sources":["../../../src/__tests__/e2e/contract-drift.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `agentopology guard <file> --check` (GC): which gates, approval steps and
|
|
3
|
+
* permission rules a project actually enforces today. It reads; it never
|
|
4
|
+
* writes. Built on compile.at: brief-check (a gate before an agent, run by
|
|
5
|
+
* before-agent.sh), copy-check (a gate after an agent, a SubagentStop hook),
|
|
6
|
+
* approve (a human step before drafter), and settings ask and deny rules.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=guard-check.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guard-check.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/e2e/guard-check.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `agentopology guard <file> --check` (GC): which gates, approval steps and
|
|
3
|
+
* permission rules a project actually enforces today. It reads; it never
|
|
4
|
+
* writes. Built on compile.at: brief-check (a gate before an agent, run by
|
|
5
|
+
* before-agent.sh), copy-check (a gate after an agent, a SubagentStop hook),
|
|
6
|
+
* approve (a human step before drafter), and settings ask and deny rules.
|
|
7
|
+
*/
|
|
8
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
9
|
+
import { spawnSync } from "node:child_process";
|
|
10
|
+
import * as fs from "node:fs";
|
|
11
|
+
import * as os from "node:os";
|
|
12
|
+
import { resolve, dirname, join } from "node:path";
|
|
13
|
+
import { fileURLToPath } from "node:url";
|
|
14
|
+
import { parse } from "../../parser/index.js";
|
|
15
|
+
import { claudeCodeBinding } from "../../bindings/claude-code.js";
|
|
16
|
+
import { checkGuards } from "../../guard/check.js";
|
|
17
|
+
import { validate } from "../../parser/validator.js";
|
|
18
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
19
|
+
const FIXTURE = resolve(here, "fixtures/compile.at");
|
|
20
|
+
const CLI = resolve(here, "../../../dist/cli/index.js");
|
|
21
|
+
const ast = parse(fs.readFileSync(FIXTURE, "utf-8"));
|
|
22
|
+
const SCRIPTS = ".claude/skills/compile/scripts";
|
|
23
|
+
let root;
|
|
24
|
+
const at = (p) => join(root, p);
|
|
25
|
+
const settings = () => JSON.parse(fs.readFileSync(at(".claude/settings.json"), "utf8"));
|
|
26
|
+
const writeSettings = (s) => fs.writeFileSync(at(".claude/settings.json"), JSON.stringify(s, null, 2));
|
|
27
|
+
const item = (id) => checkGuards(ast, root).items.find((i) => i.id === id);
|
|
28
|
+
beforeEach(() => {
|
|
29
|
+
root = fs.mkdtempSync(join(os.tmpdir(), "at-guard-check-"));
|
|
30
|
+
for (const f of claudeCodeBinding.scaffold(ast)) {
|
|
31
|
+
fs.mkdirSync(dirname(at(f.path)), { recursive: true });
|
|
32
|
+
fs.writeFileSync(at(f.path), f.content);
|
|
33
|
+
}
|
|
34
|
+
// copy-check runs the user's own python script; give it one.
|
|
35
|
+
fs.mkdirSync(at("docs/tools"), { recursive: true });
|
|
36
|
+
fs.writeFileSync(at("docs/tools/check.py"), "print('ok')\n");
|
|
37
|
+
});
|
|
38
|
+
afterEach(() => fs.rmSync(root, { recursive: true, force: true }));
|
|
39
|
+
describe("guard --check on a freshly scaffolded project", () => {
|
|
40
|
+
it("[N31] [GC1] a gate after an agent refuses by its SubagentStop hook", () => {
|
|
41
|
+
const g = item("copy-check");
|
|
42
|
+
expect(g).toMatchObject({ kind: "gate", strength: "refuse", by: "hook" });
|
|
43
|
+
expect(g.where).toContain("SubagentStop");
|
|
44
|
+
expect(g.where).toContain("drafter");
|
|
45
|
+
});
|
|
46
|
+
it("[N31] [GC1] a gate before an agent refuses by the before-agent guard; its unwritten script is reported as blocking every run", () => {
|
|
47
|
+
const g = item("brief-check");
|
|
48
|
+
expect(g).toMatchObject({ kind: "gate", strength: "refuse", by: "hook" });
|
|
49
|
+
expect(g.where).toContain("PreToolUse");
|
|
50
|
+
expect(g.notes.join(" ")).toMatch(/stub.*blocks every run/);
|
|
51
|
+
});
|
|
52
|
+
it("[N31] [GC1] a human step before an agent refuses by asking in the session, and says -p denies it", () => {
|
|
53
|
+
const h = item("approve");
|
|
54
|
+
expect(h).toMatchObject({ kind: "human", strength: "refuse", by: "hook" });
|
|
55
|
+
expect(h.notes.join(" ")).toMatch(/-p/);
|
|
56
|
+
});
|
|
57
|
+
it("[N31] [GC1] deny and ask rules refuse by settings", () => {
|
|
58
|
+
expect(item("deny mcp__notes__delete")).toMatchObject({ kind: "permission", strength: "refuse", by: "settings" });
|
|
59
|
+
expect(item("ask Bash(git push:*)")).toMatchObject({ kind: "permission", strength: "refuse", by: "settings" });
|
|
60
|
+
});
|
|
61
|
+
it("[N31] [GC1] the summary counts steps that refuse: k of m (v10's enforcement number)", () => {
|
|
62
|
+
const r = checkGuards(ast, root);
|
|
63
|
+
expect(r.enforcement).toEqual({ refuse: 3, of: 3 });
|
|
64
|
+
expect(r.missing).toBe(0);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
describe("guard --check reports what has gone missing", () => {
|
|
68
|
+
it("[N31] [GC2] the SubagentStop entry removed from settings.json: the gate enforces nothing", () => {
|
|
69
|
+
const s = settings();
|
|
70
|
+
s.hooks.SubagentStop = s.hooks.SubagentStop.filter((e) => e.matcher !== "drafter");
|
|
71
|
+
writeSettings(s);
|
|
72
|
+
const g = item("copy-check");
|
|
73
|
+
expect(g.strength).toBe("none");
|
|
74
|
+
expect(g.notes.join(" ")).toContain("settings.json");
|
|
75
|
+
expect(checkGuards(ast, root).enforcement).toEqual({ refuse: 2, of: 3 });
|
|
76
|
+
});
|
|
77
|
+
it("[N31] [GC2] a hook entry whose command is relative fails open off the project root", () => {
|
|
78
|
+
const s = settings();
|
|
79
|
+
for (const e of s.hooks.SubagentStop)
|
|
80
|
+
for (const h of e.hooks)
|
|
81
|
+
if (h.command)
|
|
82
|
+
h.command = h.command.replace(/"\$CLAUDE_PROJECT_DIR\/(.*)"/, "$1");
|
|
83
|
+
writeSettings(s);
|
|
84
|
+
const g = item("copy-check");
|
|
85
|
+
expect(g.strength).toBe("none");
|
|
86
|
+
expect(g.notes.join(" ")).toMatch(/relative/);
|
|
87
|
+
});
|
|
88
|
+
it("[N31] [GC2] the before-agent guard without onFailure: block is reported as failing open if the hook can't start", () => {
|
|
89
|
+
const s = settings();
|
|
90
|
+
for (const e of s.hooks.PreToolUse)
|
|
91
|
+
for (const h of e.hooks)
|
|
92
|
+
delete h.onFailure;
|
|
93
|
+
writeSettings(s);
|
|
94
|
+
expect(item("brief-check").strength).toBe("refuse");
|
|
95
|
+
expect(item("brief-check").notes.join(" ")).toMatch(/onFailure/);
|
|
96
|
+
});
|
|
97
|
+
it("[N31] [GC2] the gate wrapper script deleted: none", () => {
|
|
98
|
+
fs.rmSync(at(`${SCRIPTS}/gate-copy-check.sh`));
|
|
99
|
+
expect(item("copy-check").strength).toBe("none");
|
|
100
|
+
});
|
|
101
|
+
it("[N31] [GC2] before-agent.sh edited so it no longer runs the gate: none", () => {
|
|
102
|
+
const p = at(`${SCRIPTS}/before-agent.sh`);
|
|
103
|
+
fs.writeFileSync(p, fs.readFileSync(p, "utf8").replace(/.*gate-brief-check\.sh.*\n/, ""));
|
|
104
|
+
expect(item("brief-check").strength).toBe("none");
|
|
105
|
+
});
|
|
106
|
+
it("[N31] [GC2] the user's check script missing: the gate still refuses, and every run is blocked", () => {
|
|
107
|
+
fs.rmSync(at("docs/tools/check.py"));
|
|
108
|
+
const g = item("copy-check");
|
|
109
|
+
expect(g.strength).toBe("refuse");
|
|
110
|
+
expect(g.notes.join(" ")).toMatch(/missing.*blocks every run/);
|
|
111
|
+
});
|
|
112
|
+
it("[N31] [GC2] a deny rule removed from settings.json: none", () => {
|
|
113
|
+
const s = settings();
|
|
114
|
+
s.permissions.deny = [];
|
|
115
|
+
writeSettings(s);
|
|
116
|
+
expect(item("deny mcp__notes__delete").strength).toBe("none");
|
|
117
|
+
});
|
|
118
|
+
it("[N31] [GC2] a hand-built hook it cannot tie to a step is listed, not silently counted", () => {
|
|
119
|
+
expect(checkGuards(ast, root).unattributed).toEqual([]);
|
|
120
|
+
const s = settings();
|
|
121
|
+
s.hooks.PreToolUse.push({ matcher: "Bash", hooks: [{ type: "command", command: 'python3 "$CLAUDE_PROJECT_DIR/harness/lock/hook.py"' }] });
|
|
122
|
+
writeSettings(s);
|
|
123
|
+
const r = checkGuards(ast, root);
|
|
124
|
+
expect(r.unattributed).toEqual(['PreToolUse Bash: python3 "$CLAUDE_PROJECT_DIR/harness/lock/hook.py"']);
|
|
125
|
+
expect(r.enforcement).toEqual({ refuse: 3, of: 3 });
|
|
126
|
+
});
|
|
127
|
+
it("[N31] [GC2] no .claude/settings.json at all: every hook and rule is none", () => {
|
|
128
|
+
fs.rmSync(at(".claude/settings.json"));
|
|
129
|
+
const r = checkGuards(ast, root);
|
|
130
|
+
expect(r.enforcement.refuse).toBe(0);
|
|
131
|
+
expect(r.items.filter((i) => i.strength === "none").length).toBe(r.items.length);
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
describe("guard --check from the CLI", () => {
|
|
135
|
+
const cli = (...args) => spawnSync(process.execPath, [CLI, ...args], { cwd: root, encoding: "utf8" });
|
|
136
|
+
it("[N31] [GC3] prints one line per item and the enforcement count, writes nothing, exits 0 when nothing is missing", () => {
|
|
137
|
+
const before = spawnSync("find", [root, "-type", "f"], { encoding: "utf8" }).stdout;
|
|
138
|
+
const r = cli("guard", FIXTURE, "--check", "--dir", root);
|
|
139
|
+
expect(r.status).toBe(0);
|
|
140
|
+
expect(r.stdout).toMatch(/gate copy-check\s+refuse\s+by: hook/);
|
|
141
|
+
expect(r.stdout).toMatch(/enforcement: 3 of 3 steps refuse/);
|
|
142
|
+
expect(r.stdout).toMatch(/Claude Code \d+\.\d+\.\d+/);
|
|
143
|
+
expect(spawnSync("find", [root, "-type", "f"], { encoding: "utf8" }).stdout).toBe(before);
|
|
144
|
+
});
|
|
145
|
+
it("[N31] [GC3] exits 1 when something the binding generates is missing on disk", () => {
|
|
146
|
+
fs.rmSync(at(`${SCRIPTS}/gate-copy-check.sh`));
|
|
147
|
+
const r = cli("guard", FIXTURE, "--check", "--dir", root);
|
|
148
|
+
expect(r.status).toBe(1);
|
|
149
|
+
expect(r.stdout).toMatch(/gate copy-check\s+none/);
|
|
150
|
+
});
|
|
151
|
+
it("[N31] [GC3] guard without --check says only the read-only mode exists yet", () => {
|
|
152
|
+
const r = cli("guard", FIXTURE, "--dir", root);
|
|
153
|
+
expect(r.status).toBe(1);
|
|
154
|
+
expect(r.stderr).toMatch(/--check/);
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
/**
|
|
158
|
+
* Citations (N33). A hand-built guard can be credited when the file cites it:
|
|
159
|
+
* a gate with `by: code` and `at: "path:line"` is checked on disk (the file,
|
|
160
|
+
* the line, and the `match:` text within 5 lines), and a gate whose edge says
|
|
161
|
+
* `[guard: lock-bash]` is credited with that hook when the hook is in
|
|
162
|
+
* settings.json and declares its strength. A broken citation is `none` and
|
|
163
|
+
* exits 1; a strength the file writes down as `none` is reported, not failed.
|
|
164
|
+
*/
|
|
165
|
+
// release and voice carry no commands: the binding compiles no hook for a gate
|
|
166
|
+
// before them, so only the cited guard can credit it. (With commands, such a
|
|
167
|
+
// gate is guarded by before-action.sh: see action-guard.test.ts.)
|
|
168
|
+
const CITED = `topology cited : [pipeline] {
|
|
169
|
+
meta {
|
|
170
|
+
version: "1.0.0"
|
|
171
|
+
description: "Citation probe"
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
orchestrator {
|
|
175
|
+
model: sonnet
|
|
176
|
+
handles: [release, voice]
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
agent writer {
|
|
180
|
+
model: sonnet
|
|
181
|
+
description: "Writes the post"
|
|
182
|
+
prompt {
|
|
183
|
+
Write the post.
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
human owner-yes {
|
|
188
|
+
description: "The owner approves the post"
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
action release {
|
|
192
|
+
kind: external
|
|
193
|
+
description: "Posts it"
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
action voice {
|
|
197
|
+
kind: external
|
|
198
|
+
description: "Records the voice-over"
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
hooks {
|
|
202
|
+
hook lock-bash {
|
|
203
|
+
on: PreToolUse
|
|
204
|
+
matcher: "Bash"
|
|
205
|
+
run: "python3 harness/lock/hook.py"
|
|
206
|
+
strength: refuse
|
|
207
|
+
bypass: "AT_UNLOCK"
|
|
208
|
+
}
|
|
209
|
+
hook note-bash {
|
|
210
|
+
on: PostToolUse
|
|
211
|
+
matcher: "Bash"
|
|
212
|
+
run: "python3 harness/lock/note.py"
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
gates {
|
|
217
|
+
gate lock-release {
|
|
218
|
+
after: owner-yes
|
|
219
|
+
before: release
|
|
220
|
+
run: "scripts/lock.sh"
|
|
221
|
+
on-fail: halt
|
|
222
|
+
}
|
|
223
|
+
gate lock-voice {
|
|
224
|
+
after: owner-yes
|
|
225
|
+
before: voice
|
|
226
|
+
run: "scripts/lock-voice.sh"
|
|
227
|
+
on-fail: halt
|
|
228
|
+
}
|
|
229
|
+
gate doctrine {
|
|
230
|
+
after: owner-yes
|
|
231
|
+
before: voice
|
|
232
|
+
strength: refuse
|
|
233
|
+
by: code
|
|
234
|
+
at: "tools/px.py:5"
|
|
235
|
+
match: "PX_ALLOW_NO_DOCTRINE"
|
|
236
|
+
bypass: "PX_ALLOW_NO_DOCTRINE"
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
flow {
|
|
241
|
+
writer -> owner-yes
|
|
242
|
+
owner-yes -> release [guard: lock-bash]
|
|
243
|
+
owner-yes -> voice [guard: note-bash]
|
|
244
|
+
writer -> voice [strength: none]
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
`;
|
|
248
|
+
describe("guard --check credits what the file cites", () => {
|
|
249
|
+
const cast = parse(CITED);
|
|
250
|
+
let proj;
|
|
251
|
+
const put = (p, text) => { fs.mkdirSync(dirname(join(proj, p)), { recursive: true }); fs.writeFileSync(join(proj, p), text); };
|
|
252
|
+
const lines = (n, at, text) => Array.from({ length: n }, (_, i) => (i + 1 === at ? text : `line ${i + 1}`)).join("\n") + "\n";
|
|
253
|
+
const handBuilt = (hooks) => put(".claude/settings.json", JSON.stringify({ hooks }, null, 2));
|
|
254
|
+
const LOCK = { PreToolUse: [{ matcher: "Bash", hooks: [{ type: "command", command: '/usr/bin/python3 "$CLAUDE_PROJECT_DIR/harness/lock/hook.py"' }] }] };
|
|
255
|
+
const find = (id) => checkGuards(cast, proj).items.find((i) => i.id === id);
|
|
256
|
+
beforeEach(() => {
|
|
257
|
+
proj = fs.mkdtempSync(join(os.tmpdir(), "at-guard-cite-"));
|
|
258
|
+
put("tools/px.py", lines(20, 7, 'if os.environ.get("PX_ALLOW_NO_DOCTRINE"): return'));
|
|
259
|
+
handBuilt(LOCK);
|
|
260
|
+
});
|
|
261
|
+
afterEach(() => fs.rmSync(proj, { recursive: true, force: true }));
|
|
262
|
+
it("[N33] the file parses and validates clean", () => {
|
|
263
|
+
expect(validate(cast).filter((r) => r.level === "error")).toEqual([]);
|
|
264
|
+
});
|
|
265
|
+
it("[N33] a by: code citation whose match text is within 5 lines: refuse by code, cited not proven, bypass named", () => {
|
|
266
|
+
const g = find("doctrine");
|
|
267
|
+
expect(g).toMatchObject({ kind: "gate", strength: "refuse", by: "code" });
|
|
268
|
+
expect(g.where).toContain("tools/px.py:5");
|
|
269
|
+
expect(g.notes.join(" ")).toMatch(/cited, not proven/);
|
|
270
|
+
expect(g.notes.join(" ")).toMatch(/bypass.*PX_ALLOW_NO_DOCTRINE/);
|
|
271
|
+
});
|
|
272
|
+
it("[N33] the match text moved away from the cited line: none, and exit-worthy", () => {
|
|
273
|
+
put("tools/px.py", lines(20, 15, 'if os.environ.get("PX_ALLOW_NO_DOCTRINE"): return'));
|
|
274
|
+
const g = find("doctrine");
|
|
275
|
+
expect(g.strength).toBe("none");
|
|
276
|
+
expect(g.notes.join(" ")).toMatch(/PX_ALLOW_NO_DOCTRINE.*not within 5 lines of line 5/);
|
|
277
|
+
expect(checkGuards(cast, proj).missing).toBeGreaterThan(0);
|
|
278
|
+
});
|
|
279
|
+
it("[N33] the cited file missing, or the line past its end: none", () => {
|
|
280
|
+
fs.rmSync(join(proj, "tools/px.py"));
|
|
281
|
+
expect(find("doctrine").notes.join(" ")).toMatch(/tools\/px\.py is missing/);
|
|
282
|
+
put("tools/px.py", lines(3, 2, "PX_ALLOW_NO_DOCTRINE"));
|
|
283
|
+
expect(find("doctrine").strength).toBe("none");
|
|
284
|
+
expect(find("doctrine").notes.join(" ")).toMatch(/has 3 lines/);
|
|
285
|
+
});
|
|
286
|
+
it("[N33] a gate with no hook of its own is credited by the guard its edge cites, when that hook is in settings.json", () => {
|
|
287
|
+
const g = find("lock-release");
|
|
288
|
+
expect(g).toMatchObject({ strength: "refuse", by: "hook" });
|
|
289
|
+
expect(g.where).toContain("lock-bash");
|
|
290
|
+
expect(g.notes.join(" ")).toMatch(/bypass.*AT_UNLOCK/);
|
|
291
|
+
expect(checkGuards(cast, proj).unattributed).toEqual([]);
|
|
292
|
+
});
|
|
293
|
+
it("[N33] the cited hook missing from settings.json: the gate stays hope, and says why", () => {
|
|
294
|
+
handBuilt({});
|
|
295
|
+
const g = find("lock-release");
|
|
296
|
+
expect(g.strength).toBe("hope");
|
|
297
|
+
expect(g.notes.join(" ")).toMatch(/lock-bash.*not in .claude\/settings.json/);
|
|
298
|
+
});
|
|
299
|
+
it("[N33] a cited hook that declares no strength is not credited", () => {
|
|
300
|
+
handBuilt({ ...LOCK, PostToolUse: [{ matcher: "Bash", hooks: [{ type: "command", command: 'python3 "$CLAUDE_PROJECT_DIR/harness/lock/note.py"' }] }] });
|
|
301
|
+
const g = find("lock-voice");
|
|
302
|
+
expect(g.strength).toBe("hope");
|
|
303
|
+
expect(g.notes.join(" ")).toMatch(/note-bash declares no strength/);
|
|
304
|
+
});
|
|
305
|
+
it("[N33] an edge whose strength is written down as none is reported as declared, and is not a failure", () => {
|
|
306
|
+
const e = find("writer -> voice");
|
|
307
|
+
expect(e).toMatchObject({ kind: "edge", strength: "none", by: "prose" });
|
|
308
|
+
expect(e.notes.join(" ")).toMatch(/declared/);
|
|
309
|
+
put("tools/px.py", lines(20, 7, 'if os.environ.get("PX_ALLOW_NO_DOCTRINE"): return'));
|
|
310
|
+
expect(checkGuards(cast, proj).missing).toBe(0);
|
|
311
|
+
});
|
|
312
|
+
it("[N33] the count reads the credit: 2 of 4 steps refuse (doctrine by code, lock-release by its cited hook)", () => {
|
|
313
|
+
expect(checkGuards(cast, proj).enforcement).toEqual({ refuse: 2, of: 4 });
|
|
314
|
+
});
|
|
315
|
+
});
|
|
316
|
+
//# sourceMappingURL=guard-check.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guard-check.test.js","sourceRoot":"","sources":["../../../src/__tests__/e2e/guard-check.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* [N41] `guard <file> --target claude-code` writes only the guard part of what
|
|
3
|
+
* scaffold would write, into a project that was built by hand: the hook
|
|
4
|
+
* scripts settings.json runs, the gate wrappers and check scripts they call,
|
|
5
|
+
* and the `hooks` and `permissions` keys of settings.json, merged. It never
|
|
6
|
+
* writes an agent, skill, command, rule, .mcp.json or CLAUDE.md, never
|
|
7
|
+
* overwrites a script the user edited or a check that is no longer a stub,
|
|
8
|
+
* and a rerun changes nothing.
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=guard-target.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guard-target.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/e2e/guard-target.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|