agentopology 0.9.1 → 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.
Files changed (178) hide show
  1. package/README.md +17 -19
  2. package/dist/__tests__/e2e/action-guard.test.d.ts +13 -0
  3. package/dist/__tests__/e2e/action-guard.test.d.ts.map +1 -0
  4. package/dist/__tests__/e2e/action-guard.test.js +299 -0
  5. package/dist/__tests__/e2e/action-guard.test.js.map +1 -0
  6. package/dist/__tests__/e2e/compile.test.js +1 -1
  7. package/dist/__tests__/e2e/compile.test.js.map +1 -1
  8. package/dist/__tests__/e2e/conformance.test.d.ts +13 -0
  9. package/dist/__tests__/e2e/conformance.test.d.ts.map +1 -0
  10. package/dist/__tests__/e2e/conformance.test.js +109 -0
  11. package/dist/__tests__/e2e/conformance.test.js.map +1 -0
  12. package/dist/__tests__/e2e/contract-drift.test.d.ts +11 -0
  13. package/dist/__tests__/e2e/contract-drift.test.d.ts.map +1 -0
  14. package/dist/__tests__/e2e/contract-drift.test.js +142 -0
  15. package/dist/__tests__/e2e/contract-drift.test.js.map +1 -0
  16. package/dist/__tests__/e2e/fail-closed.test.d.ts +11 -0
  17. package/dist/__tests__/e2e/fail-closed.test.d.ts.map +1 -0
  18. package/dist/__tests__/e2e/fail-closed.test.js +111 -0
  19. package/dist/__tests__/e2e/fail-closed.test.js.map +1 -0
  20. package/dist/__tests__/e2e/guard-check.test.d.ts +9 -0
  21. package/dist/__tests__/e2e/guard-check.test.d.ts.map +1 -0
  22. package/dist/__tests__/e2e/guard-check.test.js +316 -0
  23. package/dist/__tests__/e2e/guard-check.test.js.map +1 -0
  24. package/dist/__tests__/e2e/guard-target.test.d.ts +11 -0
  25. package/dist/__tests__/e2e/guard-target.test.d.ts.map +1 -0
  26. package/dist/__tests__/e2e/guard-target.test.js +198 -0
  27. package/dist/__tests__/e2e/guard-target.test.js.map +1 -0
  28. package/dist/__tests__/e2e/inventory.test.d.ts +18 -0
  29. package/dist/__tests__/e2e/inventory.test.d.ts.map +1 -0
  30. package/dist/__tests__/e2e/inventory.test.js +187 -0
  31. package/dist/__tests__/e2e/inventory.test.js.map +1 -0
  32. package/dist/__tests__/e2e/matcher.test.d.ts +14 -0
  33. package/dist/__tests__/e2e/matcher.test.d.ts.map +1 -0
  34. package/dist/__tests__/e2e/matcher.test.js +145 -0
  35. package/dist/__tests__/e2e/matcher.test.js.map +1 -0
  36. package/dist/__tests__/e2e/step-check.test.d.ts +9 -0
  37. package/dist/__tests__/e2e/step-check.test.d.ts.map +1 -0
  38. package/dist/__tests__/e2e/step-check.test.js +158 -0
  39. package/dist/__tests__/e2e/step-check.test.js.map +1 -0
  40. package/dist/__tests__/e2e/strength.test.d.ts +17 -0
  41. package/dist/__tests__/e2e/strength.test.d.ts.map +1 -0
  42. package/dist/__tests__/e2e/strength.test.js +130 -0
  43. package/dist/__tests__/e2e/strength.test.js.map +1 -0
  44. package/dist/__tests__/e2e/verified-on.test.d.ts +2 -0
  45. package/dist/__tests__/e2e/verified-on.test.d.ts.map +1 -0
  46. package/dist/__tests__/e2e/verified-on.test.js +57 -0
  47. package/dist/__tests__/e2e/verified-on.test.js.map +1 -0
  48. package/dist/__tests__/open-findings.test.js +1 -0
  49. package/dist/__tests__/open-findings.test.js.map +1 -1
  50. package/dist/bindings/__tests__/bindings.test.js +6 -686
  51. package/dist/bindings/__tests__/bindings.test.js.map +1 -1
  52. package/dist/bindings/__tests__/defaults-agreement.test.js +0 -12
  53. package/dist/bindings/__tests__/defaults-agreement.test.js.map +1 -1
  54. package/dist/bindings/__tests__/hook-command.test.js +2 -2
  55. package/dist/bindings/__tests__/hook-command.test.js.map +1 -1
  56. package/dist/bindings/__tests__/mod-plugin.test.js +2 -2
  57. package/dist/bindings/__tests__/mod-plugin.test.js.map +1 -1
  58. package/dist/bindings/claude-code.d.ts +45 -1
  59. package/dist/bindings/claude-code.d.ts.map +1 -1
  60. package/dist/bindings/claude-code.js +191 -19
  61. package/dist/bindings/claude-code.js.map +1 -1
  62. package/dist/bindings/index.d.ts +5 -5
  63. package/dist/bindings/index.d.ts.map +1 -1
  64. package/dist/bindings/index.js +9 -16
  65. package/dist/bindings/index.js.map +1 -1
  66. package/dist/bindings/lib/stub.d.ts +15 -1
  67. package/dist/bindings/lib/stub.d.ts.map +1 -1
  68. package/dist/bindings/lib/stub.js +27 -2
  69. package/dist/bindings/lib/stub.js.map +1 -1
  70. package/dist/bindings/types.d.ts +6 -1
  71. package/dist/bindings/types.d.ts.map +1 -1
  72. package/dist/cli/__tests__/cli.test.js +25 -0
  73. package/dist/cli/__tests__/cli.test.js.map +1 -1
  74. package/dist/cli/index.js +222 -8
  75. package/dist/cli/index.js.map +1 -1
  76. package/dist/conformance/claude-code.d.ts +99 -0
  77. package/dist/conformance/claude-code.d.ts.map +1 -0
  78. package/dist/conformance/claude-code.js +242 -0
  79. package/dist/conformance/claude-code.js.map +1 -0
  80. package/dist/conformance/extract.d.ts +70 -0
  81. package/dist/conformance/extract.d.ts.map +1 -0
  82. package/dist/conformance/extract.js +185 -0
  83. package/dist/conformance/extract.js.map +1 -0
  84. package/dist/docs/content.d.ts.map +1 -1
  85. package/dist/docs/content.js +57 -32
  86. package/dist/docs/content.js.map +1 -1
  87. package/dist/guard/check.d.ts +53 -0
  88. package/dist/guard/check.d.ts.map +1 -0
  89. package/dist/guard/check.js +366 -0
  90. package/dist/guard/check.js.map +1 -0
  91. package/dist/guard/target.d.ts +45 -0
  92. package/dist/guard/target.d.ts.map +1 -0
  93. package/dist/guard/target.js +168 -0
  94. package/dist/guard/target.js.map +1 -0
  95. package/dist/import/__tests__/import.test.js +0 -554
  96. package/dist/import/__tests__/import.test.js.map +1 -1
  97. package/dist/import/index.d.ts +0 -1
  98. package/dist/import/index.d.ts.map +1 -1
  99. package/dist/import/index.js +1 -7
  100. package/dist/import/index.js.map +1 -1
  101. package/dist/import/serializer.d.ts.map +1 -1
  102. package/dist/import/serializer.js +41 -0
  103. package/dist/import/serializer.js.map +1 -1
  104. package/dist/index.d.ts +0 -4
  105. package/dist/index.d.ts.map +1 -1
  106. package/dist/index.js +0 -4
  107. package/dist/index.js.map +1 -1
  108. package/dist/inventory/index.d.ts +65 -0
  109. package/dist/inventory/index.d.ts.map +1 -0
  110. package/dist/inventory/index.js +272 -0
  111. package/dist/inventory/index.js.map +1 -0
  112. package/dist/parser/ast.d.ts +46 -0
  113. package/dist/parser/ast.d.ts.map +1 -1
  114. package/dist/parser/ast.js.map +1 -1
  115. package/dist/parser/index.d.ts +6 -1
  116. package/dist/parser/index.d.ts.map +1 -1
  117. package/dist/parser/index.js +66 -4
  118. package/dist/parser/index.js.map +1 -1
  119. package/dist/parser/known-fields.d.ts +3 -0
  120. package/dist/parser/known-fields.d.ts.map +1 -1
  121. package/dist/parser/known-fields.js +5 -3
  122. package/dist/parser/known-fields.js.map +1 -1
  123. package/dist/parser/ledger.d.ts +36 -0
  124. package/dist/parser/ledger.d.ts.map +1 -0
  125. package/dist/parser/ledger.js +72 -0
  126. package/dist/parser/ledger.js.map +1 -0
  127. package/dist/parser/run.d.ts +6 -0
  128. package/dist/parser/run.d.ts.map +1 -1
  129. package/dist/parser/run.js +10 -0
  130. package/dist/parser/run.js.map +1 -1
  131. package/dist/parser/validator.d.ts.map +1 -1
  132. package/dist/parser/validator.js +255 -1
  133. package/dist/parser/validator.js.map +1 -1
  134. package/dist/scaffold/manifest.d.ts.map +1 -1
  135. package/dist/scaffold/manifest.js +0 -8
  136. package/dist/scaffold/manifest.js.map +1 -1
  137. package/dist/scaffold/merge.d.ts.map +1 -1
  138. package/dist/scaffold/merge.js +1 -3
  139. package/dist/scaffold/merge.js.map +1 -1
  140. package/dist/step/check.d.ts +56 -0
  141. package/dist/step/check.d.ts.map +1 -0
  142. package/dist/step/check.js +125 -0
  143. package/dist/step/check.js.map +1 -0
  144. package/dist/sync/index.d.ts +0 -2
  145. package/dist/sync/index.d.ts.map +1 -1
  146. package/dist/sync/index.js +0 -109
  147. package/dist/sync/index.js.map +1 -1
  148. package/package.json +3 -1
  149. package/spec/claude-code/README.md +19 -0
  150. package/spec/claude-code/hooks-contract.2.1.295.json +143 -0
  151. package/spec/claude-code/hooks-contract.json +142 -0
  152. package/spec/grammar.md +45 -7
  153. package/spec/testing.md +16 -0
  154. package/spec/validation.md +11 -2
  155. package/dist/__tests__/live/zz-debug.test.d.ts +0 -2
  156. package/dist/__tests__/live/zz-debug.test.d.ts.map +0 -1
  157. package/dist/__tests__/live/zz-debug.test.js +0 -4
  158. package/dist/__tests__/live/zz-debug.test.js.map +0 -1
  159. package/dist/bindings/copilot-cli.d.ts +0 -20
  160. package/dist/bindings/copilot-cli.d.ts.map +0 -1
  161. package/dist/bindings/copilot-cli.js +0 -1516
  162. package/dist/bindings/copilot-cli.js.map +0 -1
  163. package/dist/bindings/gemini-cli.d.ts +0 -18
  164. package/dist/bindings/gemini-cli.d.ts.map +0 -1
  165. package/dist/bindings/gemini-cli.js +0 -1318
  166. package/dist/bindings/gemini-cli.js.map +0 -1
  167. package/dist/bindings/kiro.d.ts +0 -17
  168. package/dist/bindings/kiro.d.ts.map +0 -1
  169. package/dist/bindings/kiro.js +0 -1615
  170. package/dist/bindings/kiro.js.map +0 -1
  171. package/dist/bindings/openclaw.d.ts +0 -18
  172. package/dist/bindings/openclaw.d.ts.map +0 -1
  173. package/dist/bindings/openclaw.js +0 -1947
  174. package/dist/bindings/openclaw.js.map +0 -1
  175. package/dist/import/openclaw.d.ts +0 -70
  176. package/dist/import/openclaw.d.ts.map +0 -1
  177. package/dist/import/openclaw.js +0 -1060
  178. package/dist/import/openclaw.js.map +0 -1
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Conformance v0: the claude-code binding's generated hooks, run against
3
+ * Claude Code's hook contract (src/conformance/claude-code.ts, checked against
4
+ * the docs for Claude Code 2.1.319).
5
+ *
6
+ * For every example and fixture: the settings.json hooks and each agent's
7
+ * frontmatter hooks are checked statically, then every command hook is run
8
+ * the way Claude Code runs it (a shell, the session's current directory,
9
+ * CLAUDE_PROJECT_DIR set, the event's JSON on stdin). The working directory is
10
+ * a subfolder on purpose: hooks run where Claude is, not at the project root.
11
+ */
12
+ import { describe, it, expect, beforeAll, afterAll } from "vitest";
13
+ import { spawnSync } from "node:child_process";
14
+ import * as fs from "node:fs";
15
+ import * as os from "node:os";
16
+ import { resolve, dirname, join } from "node:path";
17
+ import { fileURLToPath } from "node:url";
18
+ import { parse } from "../../parser/index.js";
19
+ import { claudeCodeBinding } from "../../bindings/claude-code.js";
20
+ import { checkHooks, checkStdout, payloadFor, unanchoredScript, VERIFIED_ON, HOOK_EVENTS } from "../../conformance/claude-code.js";
21
+ const here = dirname(fileURLToPath(import.meta.url));
22
+ const repo = resolve(here, "../../..");
23
+ const CORPUS = [
24
+ ...fs.readdirSync(join(repo, "examples")).filter((f) => f.endsWith(".at")).map((f) => join(repo, "examples", f)),
25
+ join(here, "fixtures/compile.at"),
26
+ join(here, "fixtures/hazards.at"),
27
+ join(repo, "kitchen-sink.at"),
28
+ ];
29
+ const hasJq = spawnSync("/bin/sh", ["-c", "command -v jq"]).status === 0;
30
+ /** Command hooks from settings.json and from agent frontmatter. */
31
+ function commandHooks(files) {
32
+ const out = [];
33
+ const settings = files.find((f) => f.path === ".claude/settings.json");
34
+ for (const [event, entries] of Object.entries((settings ? JSON.parse(settings.content).hooks : {}) ?? {})) {
35
+ for (const e of entries) {
36
+ for (const h of e.hooks)
37
+ if (h.type === "command" && h.command)
38
+ out.push({ event, matcher: e.matcher, command: h.command, where: "settings.json" });
39
+ }
40
+ }
41
+ for (const f of files.filter((x) => x.path.startsWith(".claude/agents/") && x.path.endsWith(".md"))) {
42
+ const front = f.content.split(/\n---\n/)[0];
43
+ let event = "";
44
+ for (const line of front.split("\n")) {
45
+ const ev = /^ {2}([A-Za-z]+):\s*$/.exec(line);
46
+ if (ev)
47
+ event = ev[1];
48
+ const cmd = /^\s+(?:- )?command: (".*")\s*$/.exec(line);
49
+ if (cmd && event)
50
+ out.push({ event: event === "Stop" ? "SubagentStop" : event, command: JSON.parse(cmd[1]), where: f.path });
51
+ }
52
+ }
53
+ return out;
54
+ }
55
+ it(`[N28] [CF0] the contract names the Claude Code version it was checked on (${VERIFIED_ON})`, () => {
56
+ expect(VERIFIED_ON).toMatch(/^\d+\.\d+\.\d+$/);
57
+ expect(HOOK_EVENTS.size).toBe(33);
58
+ });
59
+ it("[N28] [CF0] a relative script path is caught; an anchored or absolute one is not", () => {
60
+ expect(unanchoredScript("bash .claude/skills/t/scripts/x.sh")).toBe(".claude/skills/t/scripts/x.sh");
61
+ expect(unanchoredScript('bash "$CLAUDE_PROJECT_DIR/.claude/skills/t/scripts/x.sh"')).toBeNull();
62
+ expect(unanchoredScript("python3 /opt/check.py --strict")).toBeNull();
63
+ expect(unanchoredScript("echo hi")).toBeNull();
64
+ });
65
+ for (const file of CORPUS) {
66
+ const name = file.replace(repo + "/", "");
67
+ describe(`conformance: ${name}`, () => {
68
+ const files = claudeCodeBinding.scaffold(parse(fs.readFileSync(file, "utf8")));
69
+ const settings = files.find((f) => f.path === ".claude/settings.json");
70
+ const hooks = commandHooks(files);
71
+ let root;
72
+ let sub;
73
+ beforeAll(() => {
74
+ root = fs.mkdtempSync(join(os.tmpdir(), "at-conformance-"));
75
+ for (const f of files) {
76
+ const p = join(root, f.path);
77
+ fs.mkdirSync(dirname(p), { recursive: true });
78
+ fs.writeFileSync(p, f.content);
79
+ if (f.executable)
80
+ fs.chmodSync(p, 0o755);
81
+ }
82
+ sub = join(root, "src/deep");
83
+ fs.mkdirSync(sub, { recursive: true });
84
+ });
85
+ afterAll(() => fs.rmSync(root, { recursive: true, force: true }));
86
+ it("[N28] [CF1] settings.json hooks match the contract (events, matchers, handler fields, onFailure, anchored paths)", () => {
87
+ expect(checkHooks(settings ? JSON.parse(settings.content).hooks ?? {} : {})).toEqual([]);
88
+ });
89
+ it("[N28] [CF1] agent frontmatter command hooks name their scripts by an anchored path", () => {
90
+ const loose = hooks.filter((h) => h.where !== "settings.json").map((h) => unanchoredScript(h.command)).filter(Boolean);
91
+ expect(loose).toEqual([]);
92
+ });
93
+ it.skipIf(!hasJq)("[N28] [CF2] every command hook runs from a subfolder: found, exits 0 or 2, and its stdout is valid for its event", () => {
94
+ const results = hooks.map((h) => {
95
+ const r = spawnSync("/bin/sh", ["-c", h.command], {
96
+ cwd: sub,
97
+ input: JSON.stringify(payloadFor(h.event, sub, h.matcher)),
98
+ env: { ...process.env, CLAUDE_PROJECT_DIR: root },
99
+ encoding: "utf8",
100
+ timeout: 20_000,
101
+ });
102
+ const bad = r.status !== 0 && r.status !== 2 ? `exit ${r.status}: ${r.stderr.trim().split("\n").pop()}` : r.status === 0 ? checkStdout(h.event, r.stdout) : null;
103
+ return bad ? `${h.event} ${h.matcher ?? ""} ${h.command} → ${bad}` : null;
104
+ });
105
+ expect(results.filter(Boolean)).toEqual([]);
106
+ });
107
+ });
108
+ }
109
+ //# sourceMappingURL=conformance.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conformance.test.js","sourceRoot":"","sources":["../../../src/__tests__/e2e/conformance.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
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
+ export {};
11
+ //# sourceMappingURL=contract-drift.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract-drift.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/e2e/contract-drift.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
@@ -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,11 @@
1
+ /**
2
+ * Generated gates fail closed (N27).
3
+ *
4
+ * Claude Code blocks only on exit 2. Measured on 0.9.1 (2026-11-09): with
5
+ * CLAUDE_PROJECT_DIR unset before-agent.sh exited 1, with jq missing 127, and
6
+ * a gate script nobody had written exited 0. In all three the agent launched
7
+ * with its gate and its approval step skipped. Each case below runs the
8
+ * generated scripts the way Claude Code does, with stdin and an environment.
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=fail-closed.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fail-closed.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/e2e/fail-closed.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Generated gates fail closed (N27).
3
+ *
4
+ * Claude Code blocks only on exit 2. Measured on 0.9.1 (2026-11-09): with
5
+ * CLAUDE_PROJECT_DIR unset before-agent.sh exited 1, with jq missing 127, and
6
+ * a gate script nobody had written exited 0. In all three the agent launched
7
+ * with its gate and its approval step skipped. Each case below runs the
8
+ * generated scripts the way Claude Code does, with stdin and an environment.
9
+ */
10
+ import { describe, it, expect, beforeAll, afterAll } from "vitest";
11
+ import { spawnSync } from "node:child_process";
12
+ import * as fs from "node:fs";
13
+ import * as os from "node:os";
14
+ import { resolve, dirname, join } from "node:path";
15
+ import { fileURLToPath } from "node:url";
16
+ import { parse } from "../../parser/index.js";
17
+ import { claudeCodeBinding } from "../../bindings/claude-code.js";
18
+ const here = dirname(fileURLToPath(import.meta.url));
19
+ const ast = parse(fs.readFileSync(resolve(here, "fixtures/compile.at"), "utf-8"));
20
+ const LAUNCH_DRAFTER = JSON.stringify({ tool_name: "Agent", tool_input: { subagent_type: "drafter" } });
21
+ let root;
22
+ /**
23
+ * Every case runs under /bin/bash (3.2 on macOS, whose EXIT trap sees status 0
24
+ * after an unset variable) and under the bash on PATH, which Claude Code's
25
+ * `bash "..."` command uses.
26
+ */
27
+ const pathBash = spawnSync("/bin/bash", ["-c", "command -v bash"], { encoding: "utf8" }).stdout.trim();
28
+ const SHELLS = [...new Set(["/bin/bash", pathBash].filter(Boolean))];
29
+ let BASH = "/bin/bash";
30
+ const scripts = () => join(root, ".claude/skills/compile/scripts");
31
+ function run(script, opts = {}) {
32
+ const env = {};
33
+ for (const [k, v] of Object.entries({ ...process.env, CLAUDE_PROJECT_DIR: root, ...opts.env })) {
34
+ if (v !== undefined)
35
+ env[k] = v;
36
+ }
37
+ const r = spawnSync(BASH, [join(scripts(), script)], { input: opts.stdin ?? LAUNCH_DRAFTER, env, cwd: root, encoding: "utf8" });
38
+ return { code: r.status, out: r.stdout, err: r.stderr };
39
+ }
40
+ /** A PATH holding only bash and the basics, so a named command is missing. */
41
+ function pathWithout(...missing) {
42
+ const bin = join(root, "bin-" + missing.join("-"));
43
+ fs.mkdirSync(bin, { recursive: true });
44
+ for (const c of ["bash", "env", "cat", "jq", "python3", "date", "echo"]) {
45
+ if (missing.includes(c))
46
+ continue;
47
+ const which = spawnSync("/bin/bash", ["-c", `command -v ${c}`], { encoding: "utf8" }).stdout.trim();
48
+ if (which.startsWith("/") && !fs.existsSync(join(bin, c)))
49
+ fs.symlinkSync(which, join(bin, c));
50
+ }
51
+ return bin;
52
+ }
53
+ const hasJq = spawnSync("/bin/bash", ["-c", "command -v jq"]).status === 0;
54
+ beforeAll(() => {
55
+ root = fs.mkdtempSync(join(os.tmpdir(), "at-fail-closed-"));
56
+ for (const f of claudeCodeBinding.scaffold(ast)) {
57
+ const p = join(root, f.path);
58
+ fs.mkdirSync(dirname(p), { recursive: true });
59
+ fs.writeFileSync(p, f.content);
60
+ if (f.executable)
61
+ fs.chmodSync(p, 0o755);
62
+ }
63
+ });
64
+ afterAll(() => fs.rmSync(root, { recursive: true, force: true }));
65
+ for (const shell of SHELLS)
66
+ describe(`a generated gate blocks when it cannot run (${shell})`, () => {
67
+ beforeAll(() => { BASH = shell; });
68
+ it("[N27] before-agent.sh blocks (exit 2) when CLAUDE_PROJECT_DIR is unset", () => {
69
+ const r = run("before-agent.sh", { env: { CLAUDE_PROJECT_DIR: undefined } });
70
+ expect(r.code).toBe(2);
71
+ expect(r.err).toContain("blocked");
72
+ });
73
+ it("[N27] before-agent.sh blocks (exit 2) when jq is missing", () => {
74
+ const r = run("before-agent.sh", { env: { PATH: pathWithout("jq") } });
75
+ expect(r.code).toBe(2);
76
+ });
77
+ it("[N27] a gate script nobody has written fails, so the launch is blocked", () => {
78
+ const stub = fs.readFileSync(join(scripts(), "brief-check.sh"), "utf8");
79
+ expect(stub).toContain("AGENTOPOLOGY_STUB");
80
+ expect(run("brief-check.sh").code).toBe(2);
81
+ expect(run("before-agent.sh").code).toBe(2);
82
+ });
83
+ it("[N27] a SubagentStop gate wrapper blocks (exit 2) when its check's interpreter is missing", () => {
84
+ const r = run("gate-copy-check.sh", { env: { PATH: pathWithout("python3") }, stdin: "{}" });
85
+ expect(r.code).toBe(2);
86
+ });
87
+ it.skipIf(!hasJq)("[N27] a written gate that passes still lets the launch through to its approval step", () => {
88
+ const stub = join(scripts(), "brief-check.sh");
89
+ const saved = fs.readFileSync(stub, "utf8");
90
+ fs.writeFileSync(stub, "#!/usr/bin/env bash\nexit 0\n");
91
+ try {
92
+ const r = run("before-agent.sh");
93
+ expect(r.code).toBe(0);
94
+ expect(JSON.parse(r.out).hookSpecificOutput.permissionDecision).toBe("ask");
95
+ }
96
+ finally {
97
+ fs.writeFileSync(stub, saved);
98
+ }
99
+ });
100
+ it.skipIf(!hasJq)("[N27] an agent with no gate launches untouched", () => {
101
+ const r = run("before-agent.sh", { stdin: JSON.stringify({ tool_input: { subagent_type: "critic" } }) });
102
+ expect(r.code).toBe(0);
103
+ expect(r.out).toBe("");
104
+ });
105
+ it("[N27] the guard's settings entry asks Claude Code to block when the hook itself fails", () => {
106
+ const settings = JSON.parse(claudeCodeBinding.scaffold(ast).find((f) => f.path === ".claude/settings.json").content);
107
+ const guard = settings.hooks.PreToolUse.find((e) => e.matcher === "Agent|Task");
108
+ expect(guard.hooks[0].onFailure).toBe("block");
109
+ });
110
+ });
111
+ //# sourceMappingURL=fail-closed.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fail-closed.test.js","sourceRoot":"","sources":["../../../src/__tests__/e2e/fail-closed.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"}