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.
Files changed (168) 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/conformance.test.d.ts +13 -0
  7. package/dist/__tests__/e2e/conformance.test.d.ts.map +1 -0
  8. package/dist/__tests__/e2e/conformance.test.js +109 -0
  9. package/dist/__tests__/e2e/conformance.test.js.map +1 -0
  10. package/dist/__tests__/e2e/contract-drift.test.d.ts +11 -0
  11. package/dist/__tests__/e2e/contract-drift.test.d.ts.map +1 -0
  12. package/dist/__tests__/e2e/contract-drift.test.js +142 -0
  13. package/dist/__tests__/e2e/contract-drift.test.js.map +1 -0
  14. package/dist/__tests__/e2e/guard-check.test.d.ts +9 -0
  15. package/dist/__tests__/e2e/guard-check.test.d.ts.map +1 -0
  16. package/dist/__tests__/e2e/guard-check.test.js +316 -0
  17. package/dist/__tests__/e2e/guard-check.test.js.map +1 -0
  18. package/dist/__tests__/e2e/guard-target.test.d.ts +11 -0
  19. package/dist/__tests__/e2e/guard-target.test.d.ts.map +1 -0
  20. package/dist/__tests__/e2e/guard-target.test.js +198 -0
  21. package/dist/__tests__/e2e/guard-target.test.js.map +1 -0
  22. package/dist/__tests__/e2e/inventory.test.d.ts +18 -0
  23. package/dist/__tests__/e2e/inventory.test.d.ts.map +1 -0
  24. package/dist/__tests__/e2e/inventory.test.js +187 -0
  25. package/dist/__tests__/e2e/inventory.test.js.map +1 -0
  26. package/dist/__tests__/e2e/matcher.test.d.ts +14 -0
  27. package/dist/__tests__/e2e/matcher.test.d.ts.map +1 -0
  28. package/dist/__tests__/e2e/matcher.test.js +145 -0
  29. package/dist/__tests__/e2e/matcher.test.js.map +1 -0
  30. package/dist/__tests__/e2e/step-check.test.d.ts +9 -0
  31. package/dist/__tests__/e2e/step-check.test.d.ts.map +1 -0
  32. package/dist/__tests__/e2e/step-check.test.js +158 -0
  33. package/dist/__tests__/e2e/step-check.test.js.map +1 -0
  34. package/dist/__tests__/e2e/strength.test.d.ts +17 -0
  35. package/dist/__tests__/e2e/strength.test.d.ts.map +1 -0
  36. package/dist/__tests__/e2e/strength.test.js +130 -0
  37. package/dist/__tests__/e2e/strength.test.js.map +1 -0
  38. package/dist/__tests__/e2e/verified-on.test.d.ts +2 -0
  39. package/dist/__tests__/e2e/verified-on.test.d.ts.map +1 -0
  40. package/dist/__tests__/e2e/verified-on.test.js +57 -0
  41. package/dist/__tests__/e2e/verified-on.test.js.map +1 -0
  42. package/dist/__tests__/open-findings.test.js +1 -0
  43. package/dist/__tests__/open-findings.test.js.map +1 -1
  44. package/dist/bindings/__tests__/bindings.test.js +6 -686
  45. package/dist/bindings/__tests__/bindings.test.js.map +1 -1
  46. package/dist/bindings/__tests__/defaults-agreement.test.js +0 -12
  47. package/dist/bindings/__tests__/defaults-agreement.test.js.map +1 -1
  48. package/dist/bindings/__tests__/hook-command.test.js +2 -2
  49. package/dist/bindings/__tests__/hook-command.test.js.map +1 -1
  50. package/dist/bindings/__tests__/mod-plugin.test.js +2 -2
  51. package/dist/bindings/__tests__/mod-plugin.test.js.map +1 -1
  52. package/dist/bindings/claude-code.d.ts +45 -1
  53. package/dist/bindings/claude-code.d.ts.map +1 -1
  54. package/dist/bindings/claude-code.js +181 -15
  55. package/dist/bindings/claude-code.js.map +1 -1
  56. package/dist/bindings/index.d.ts +5 -5
  57. package/dist/bindings/index.d.ts.map +1 -1
  58. package/dist/bindings/index.js +9 -16
  59. package/dist/bindings/index.js.map +1 -1
  60. package/dist/bindings/types.d.ts +6 -1
  61. package/dist/bindings/types.d.ts.map +1 -1
  62. package/dist/cli/__tests__/cli.test.js +25 -0
  63. package/dist/cli/__tests__/cli.test.js.map +1 -1
  64. package/dist/cli/index.js +222 -8
  65. package/dist/cli/index.js.map +1 -1
  66. package/dist/conformance/claude-code.d.ts +99 -0
  67. package/dist/conformance/claude-code.d.ts.map +1 -0
  68. package/dist/conformance/claude-code.js +242 -0
  69. package/dist/conformance/claude-code.js.map +1 -0
  70. package/dist/conformance/extract.d.ts +70 -0
  71. package/dist/conformance/extract.d.ts.map +1 -0
  72. package/dist/conformance/extract.js +185 -0
  73. package/dist/conformance/extract.js.map +1 -0
  74. package/dist/docs/content.d.ts.map +1 -1
  75. package/dist/docs/content.js +57 -32
  76. package/dist/docs/content.js.map +1 -1
  77. package/dist/guard/check.d.ts +53 -0
  78. package/dist/guard/check.d.ts.map +1 -0
  79. package/dist/guard/check.js +366 -0
  80. package/dist/guard/check.js.map +1 -0
  81. package/dist/guard/target.d.ts +45 -0
  82. package/dist/guard/target.d.ts.map +1 -0
  83. package/dist/guard/target.js +168 -0
  84. package/dist/guard/target.js.map +1 -0
  85. package/dist/import/__tests__/import.test.js +0 -554
  86. package/dist/import/__tests__/import.test.js.map +1 -1
  87. package/dist/import/index.d.ts +0 -1
  88. package/dist/import/index.d.ts.map +1 -1
  89. package/dist/import/index.js +1 -7
  90. package/dist/import/index.js.map +1 -1
  91. package/dist/import/serializer.d.ts.map +1 -1
  92. package/dist/import/serializer.js +41 -0
  93. package/dist/import/serializer.js.map +1 -1
  94. package/dist/index.d.ts +0 -4
  95. package/dist/index.d.ts.map +1 -1
  96. package/dist/index.js +0 -4
  97. package/dist/index.js.map +1 -1
  98. package/dist/inventory/index.d.ts +65 -0
  99. package/dist/inventory/index.d.ts.map +1 -0
  100. package/dist/inventory/index.js +272 -0
  101. package/dist/inventory/index.js.map +1 -0
  102. package/dist/parser/ast.d.ts +46 -0
  103. package/dist/parser/ast.d.ts.map +1 -1
  104. package/dist/parser/ast.js.map +1 -1
  105. package/dist/parser/index.d.ts +6 -1
  106. package/dist/parser/index.d.ts.map +1 -1
  107. package/dist/parser/index.js +66 -4
  108. package/dist/parser/index.js.map +1 -1
  109. package/dist/parser/known-fields.d.ts +3 -0
  110. package/dist/parser/known-fields.d.ts.map +1 -1
  111. package/dist/parser/known-fields.js +5 -3
  112. package/dist/parser/known-fields.js.map +1 -1
  113. package/dist/parser/ledger.d.ts +36 -0
  114. package/dist/parser/ledger.d.ts.map +1 -0
  115. package/dist/parser/ledger.js +72 -0
  116. package/dist/parser/ledger.js.map +1 -0
  117. package/dist/parser/run.d.ts +6 -0
  118. package/dist/parser/run.d.ts.map +1 -1
  119. package/dist/parser/run.js +10 -0
  120. package/dist/parser/run.js.map +1 -1
  121. package/dist/parser/validator.d.ts.map +1 -1
  122. package/dist/parser/validator.js +255 -1
  123. package/dist/parser/validator.js.map +1 -1
  124. package/dist/scaffold/manifest.d.ts.map +1 -1
  125. package/dist/scaffold/manifest.js +0 -8
  126. package/dist/scaffold/manifest.js.map +1 -1
  127. package/dist/scaffold/merge.d.ts.map +1 -1
  128. package/dist/scaffold/merge.js +1 -3
  129. package/dist/scaffold/merge.js.map +1 -1
  130. package/dist/step/check.d.ts +56 -0
  131. package/dist/step/check.d.ts.map +1 -0
  132. package/dist/step/check.js +125 -0
  133. package/dist/step/check.js.map +1 -0
  134. package/dist/sync/index.d.ts +0 -2
  135. package/dist/sync/index.d.ts.map +1 -1
  136. package/dist/sync/index.js +0 -109
  137. package/dist/sync/index.js.map +1 -1
  138. package/package.json +3 -1
  139. package/spec/claude-code/README.md +19 -0
  140. package/spec/claude-code/hooks-contract.2.1.295.json +143 -0
  141. package/spec/claude-code/hooks-contract.json +142 -0
  142. package/spec/grammar.md +45 -7
  143. package/spec/testing.md +15 -0
  144. package/spec/validation.md +11 -2
  145. package/dist/__tests__/live/zz-debug.test.d.ts +0 -2
  146. package/dist/__tests__/live/zz-debug.test.d.ts.map +0 -1
  147. package/dist/__tests__/live/zz-debug.test.js +0 -4
  148. package/dist/__tests__/live/zz-debug.test.js.map +0 -1
  149. package/dist/bindings/copilot-cli.d.ts +0 -20
  150. package/dist/bindings/copilot-cli.d.ts.map +0 -1
  151. package/dist/bindings/copilot-cli.js +0 -1516
  152. package/dist/bindings/copilot-cli.js.map +0 -1
  153. package/dist/bindings/gemini-cli.d.ts +0 -18
  154. package/dist/bindings/gemini-cli.d.ts.map +0 -1
  155. package/dist/bindings/gemini-cli.js +0 -1318
  156. package/dist/bindings/gemini-cli.js.map +0 -1
  157. package/dist/bindings/kiro.d.ts +0 -17
  158. package/dist/bindings/kiro.d.ts.map +0 -1
  159. package/dist/bindings/kiro.js +0 -1615
  160. package/dist/bindings/kiro.js.map +0 -1
  161. package/dist/bindings/openclaw.d.ts +0 -18
  162. package/dist/bindings/openclaw.d.ts.map +0 -1
  163. package/dist/bindings/openclaw.js +0 -1947
  164. package/dist/bindings/openclaw.js.map +0 -1
  165. package/dist/import/openclaw.d.ts +0 -70
  166. package/dist/import/openclaw.d.ts.map +0 -1
  167. package/dist/import/openclaw.js +0 -1060
  168. package/dist/import/openclaw.js.map +0 -1
package/README.md CHANGED
@@ -12,7 +12,7 @@
12
12
  </p>
13
13
 
14
14
  <p align="center">
15
- <strong>Claude Code</strong> · <strong>Claude Workflow</strong> · <strong>OpenClaw</strong> · <strong>Codex</strong> · <strong>Cursor</strong> · <strong>Gemini CLI</strong> · <strong>Copilot</strong> · <strong>Kiro</strong>
15
+ <strong>Claude Code</strong> · experimental: Claude Workflow · Codex · Cursor
16
16
  </p>
17
17
 
18
18
  <p align="center">
@@ -61,7 +61,6 @@ topology code-review : [pipeline] {
61
61
  ```bash
62
62
  agentopology scaffold my-team.at --target claude-code # → .claude/agents/
63
63
  agentopology scaffold my-team.at --target claude-workflow # → my-team.workflow.js (+ SEAM/README/LOSSY-REPORT)
64
- agentopology scaffold my-team.at --target openclaw # → .openclaw/soul.md
65
64
  agentopology scaffold my-team.at --target codex # → .codex/
66
65
  agentopology scaffold my-team.at --target cursor # → .cursor/rules/
67
66
  ```
@@ -96,10 +95,9 @@ who works, when they work, and what they know when they work. One file, two ways
96
95
  ┌────────────┐
97
96
  ┌──────────────┐ │ Parser & │ scaffold ──▶ Platform configs
98
97
  │ .at file │─▶│ Validator │──┤ ├── .claude/agents/
99
- │ (you write) │ │ 103 rules │ │ ├── <topology>.workflow.js
98
+ │ (you write) │ │ 112 rules │ │ ├── <topology>.workflow.js
100
99
  └──────────────┘ └────────────┘ │ ├── .codex/ .cursor/rules/
101
- │ ├── .openclaw/ .github/agents/
102
- │ └── .kiro/ …
100
+ │ └── …
103
101
  │
104
102
  └── plan ──────▶ Execution brief
105
103
  │
@@ -234,8 +232,8 @@ In Claude Code, type `/agentopology` — or just ask naturally:
234
232
  Say **"I want a code review team with an analyzer, security scanner, and reviewer"** — the skill:
235
233
 
236
234
  1. Generates the `.at` file with the right syntax
237
- 2. Validates it against 103 rules
238
- 3. Scaffolds it to Claude Code, OpenClaw, Cursor, or any target
235
+ 2. Validates it against 112 rules
236
+ 3. Scaffolds it to Claude Code (or an experimental target: Codex, Cursor)
239
237
 
240
238
  **Full agent team in under 2 minutes.** No docs to read. No syntax to memorize. You describe what you want, the skill handles the rest.
241
239
 
@@ -249,7 +247,7 @@ You have a working `.at` file and want to make it better? Just tell the skill wh
249
247
  - **"Add a hook that formats code after every write"** — generates the hook block with the right lifecycle event
250
248
  - **"Add an MCP server for GitHub"** — adds the server config with environment variables
251
249
  - **"Add a quality gate between the builder and reviewer"** — inserts a gate with halt-on-fail
252
- - **"Switch the target to OpenClaw"** — re-scaffolds the entire topology for a different platform
250
+ - **"Switch the target to Codex"** — re-scaffolds the entire topology for an experimental target
253
251
 
254
252
  The workflow is always the same: **describe the change → the skill updates the `.at` file → validates → re-scaffolds.** You never touch config files manually.
255
253
 
@@ -323,15 +321,11 @@ This defines three agents, their tools and memory, a quality gate, and a flow wi
323
321
  | Target | Command | What It Generates |
324
322
  |--------|---------|-------------------|
325
323
  | **Claude Code** | `--target claude-code` | `.claude/agents/`, `.claude/skills/`, `.mcp.json`, `.claude/settings.json` (the event-driven host) |
326
- | **Claude Workflow** | `--target claude-workflow` | `<topology>.workflow.js` (deterministic fan-out rung) + `-SEAM.md`, `-README.md`, `-LOSSY-REPORT.md` |
327
- | **OpenClaw** | `--target openclaw` | `.openclaw/soul.md`, `.openclaw/skills/`, `.openclaw/config.json` |
328
- | **Codex** | `--target codex` | `.codex/config.toml`, `AGENTS.md` |
329
- | **Cursor** | `--target cursor` | `.cursor/rules/*.mdc`, `.cursor/mcp.json`, `.cursor/hooks.json` |
330
- | **Gemini CLI** | `--target gemini-cli` | `.gemini/`, `AGENTS.md` |
331
- | **Copilot** | `--target copilot-cli` | `.github/agents/*.agent.md`, `.github/copilot-instructions.md` |
332
- | **Kiro** | `--target kiro` | `.kiro/agents/*.json`, `.kiro/steering/` |
324
+ | **Claude Workflow** (experimental) | `--target claude-workflow` | `<topology>.workflow.js` (deterministic fan-out rung) + `-SEAM.md`, `-README.md`, `-LOSSY-REPORT.md` |
325
+ | **Codex** (experimental) | `--target codex` | `.codex/config.toml`, `AGENTS.md` |
326
+ | **Cursor** (experimental) | `--target cursor` | `.cursor/rules/*.mdc`, `.cursor/mcp.json`, `.cursor/hooks.json` |
333
327
 
334
- Every binding is ground-truth validated against real-world configs from production repos.
328
+ Claude Code is the supported target. The experimental ones are kept, not verified the way claude-code is. `gemini-cli`, `copilot-cli`, `openclaw` and `kiro` were removed in 0.10.0 (use 0.9.x for them).
335
329
 
336
330
  ---
337
331
 
@@ -566,7 +560,7 @@ import { parse, validate, bindings } from "agentopology";
566
560
  // Parse
567
561
  const ast = parse(atSource);
568
562
 
569
- // Validate (103 built-in rules, V1-V103)
563
+ // Validate (112 built-in rules, V1-V112)
570
564
  const issues = validate(ast);
571
565
 
572
566
  // Scaffold — generate platform files
@@ -624,7 +618,7 @@ You can `agentopology visualize` it into an interactive graph. You can hand it t
624
618
  | **Switch platforms** | Rewrite everything | Change `--target` |
625
619
  | **Add an agent** | Update 5-12 files across 3 tools | Add 4 lines to `.at` file |
626
620
  | **See the architecture** | Read YAML, JSON, TOML, Markdown across 6 dirs | One `.at` file. Or `visualize` it. |
627
- | **Validate** | Hope for the best | 103 built-in rules catch errors before deploy |
621
+ | **Validate** | Hope for the best | 112 built-in rules catch errors before deploy |
628
622
  | **Onboard someone** | "Read these 15 files and figure it out" | "Read this `.at` file" |
629
623
  | **Version control** | Diff 47 generated files | Diff one `.at` file |
630
624
  | **Move to a new tool** | Start over | `--target new-tool` |
@@ -646,7 +640,7 @@ You can `agentopology visualize` it into an interactive graph. You can hand it t
646
640
  ## CLI Reference
647
641
 
648
642
  ```
649
- agentopology validate <file> Validate an .at file (103 rules)
643
+ agentopology validate <file> Validate an .at file (112 rules)
650
644
  agentopology plan <file> Resolve for interpreted execution — no files written
651
645
  agentopology scaffold <file> --target <t> Generate platform configs
652
646
  agentopology sync <file> --target <t> --dir <d> Sync platform files back to .at
@@ -655,6 +649,10 @@ agentopology visualize <file> Interactive topology graph (+ cross-li
655
649
  agentopology visualize-brain <folder> Render a brain vault as an Obsidian-style graph (no Obsidian)
656
650
  agentopology export <file> --format <fmt> Export as markdown, mermaid, json, ascii, or brief
657
651
  agentopology info <file> Topology analysis and suggestions
652
+ agentopology guard <file> --check [--dir <d>] What the project enforces today: refuse / none / hope per gate
653
+ agentopology guard <file> --target claude-code [--dir <d>] [--dry-run] Write only the guards (hook scripts, gates, checks, settings hooks and permissions) into a hand-built project
654
+ agentopology inventory [<dir>] What is live in the project, as JSON (writes nothing)
655
+ agentopology validate <file> --inventory <dir> Coverage: live things the .at accounts for; unmapped, missing
658
656
  agentopology targets List supported platforms
659
657
  agentopology docs [topic] Language reference (43 topics)
660
658
  ```
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Guards for script steps (N38). A gate whose `before:` is an action (a script
3
+ * step) used to compile to nothing: V25 said "invoke it from your playbook" and
4
+ * a session ran the step whether or not the gate held. Now one generated
5
+ * script, before-action.sh, refuses the step's Bash command (exit 2) until the
6
+ * ledger shows the gate's `after:` step finished ok for the same unit.
7
+ *
8
+ * The tests scaffold a small topology into a temp dir and run the generated
9
+ * script the way Claude Code runs a hook: a shell, a subfolder as the current
10
+ * directory, CLAUDE_PROJECT_DIR set, the event's JSON on stdin.
11
+ */
12
+ export {};
13
+ //# sourceMappingURL=action-guard.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action-guard.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/e2e/action-guard.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}
@@ -0,0 +1,299 @@
1
+ /**
2
+ * Guards for script steps (N38). A gate whose `before:` is an action (a script
3
+ * step) used to compile to nothing: V25 said "invoke it from your playbook" and
4
+ * a session ran the step whether or not the gate held. Now one generated
5
+ * script, before-action.sh, refuses the step's Bash command (exit 2) until the
6
+ * ledger shows the gate's `after:` step finished ok for the same unit.
7
+ *
8
+ * The tests scaffold a small topology into a temp dir and run the generated
9
+ * script the way Claude Code runs a hook: a shell, a subfolder as the current
10
+ * directory, CLAUDE_PROJECT_DIR set, the event's JSON on stdin.
11
+ */
12
+ import { describe, it, expect, beforeEach, afterEach } 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 { dirname, join } from "node:path";
17
+ import { parse } from "../../parser/index.js";
18
+ import { validate } from "../../parser/validator.js";
19
+ import { serializeAST as serialize } from "../../import/serializer.js";
20
+ import { claudeCodeBinding } from "../../bindings/claude-code.js";
21
+ import { checkGuards } from "../../guard/check.js";
22
+ const hasJq = spawnSync("/bin/sh", ["-c", "command -v jq"]).status === 0;
23
+ const topology = (extra = "", gate = `after: render\n before: publish\n ledger: trace`) => `topology ship : [pipeline] {
24
+ meta { version: "1.0.0" description: "Render then publish" }
25
+ orchestrator { model: sonnet handles: [render, publish] }
26
+ action render {
27
+ kind: external
28
+ commands: ["./tool render"]
29
+ }
30
+ action publish {
31
+ kind: external
32
+ commands: ["./tool publish", "./tool republish"]
33
+ unit-from: "./tool (?:re)?publish (\\S+)"
34
+ }
35
+ records {
36
+ record trace { path: "logs/{unit}/trace.jsonl" }
37
+ }
38
+ gates {
39
+ gate publish-ready {
40
+ ${gate}
41
+ on-fail: halt
42
+ }
43
+ }
44
+ flow { render -> publish }
45
+ ${extra}}
46
+ `;
47
+ let root;
48
+ const at = (p) => join(root, p);
49
+ const SCRIPT = ".claude/skills/ship/scripts/before-action.sh";
50
+ function scaffold(src) {
51
+ const ast = parse(src);
52
+ for (const f of claudeCodeBinding.scaffold(ast)) {
53
+ fs.mkdirSync(dirname(at(f.path)), { recursive: true });
54
+ fs.writeFileSync(at(f.path), f.content);
55
+ if (f.executable)
56
+ fs.chmodSync(at(f.path), 0o755);
57
+ }
58
+ fs.mkdirSync(at("src/deep"), { recursive: true });
59
+ return ast;
60
+ }
61
+ function hook(stdin, command = `bash "$CLAUDE_PROJECT_DIR/${SCRIPT}"`) {
62
+ return spawnSync("/bin/sh", ["-c", command], {
63
+ cwd: at("src/deep"),
64
+ input: stdin,
65
+ env: { ...process.env, CLAUDE_PROJECT_DIR: root },
66
+ encoding: "utf8",
67
+ timeout: 20_000,
68
+ });
69
+ }
70
+ const bash = (command) => JSON.stringify({ hook_event_name: "PreToolUse", tool_name: "Bash", tool_input: { command } });
71
+ const ledger = (unit, lines) => {
72
+ fs.mkdirSync(at(`logs/${unit}`), { recursive: true });
73
+ fs.writeFileSync(at(`logs/${unit}/trace.jsonl`), lines.map((l) => JSON.stringify(l)).join("\n") + "\n");
74
+ };
75
+ const rec = (step, ok, unit) => ({ step, ...(unit ? { unit } : {}), ok, at: "2026-01-01T00:00:00Z" });
76
+ beforeEach(() => { root = fs.mkdtempSync(join(os.tmpdir(), "at-action-guard-")); });
77
+ afterEach(() => fs.rmSync(root, { recursive: true, force: true }));
78
+ describe.skipIf(!hasJq)("[N38] before-action.sh refuses a script step until the ledger shows its gate held", () => {
79
+ beforeEach(() => { scaffold(topology()); });
80
+ it("[N38] AG1 is wired as a PreToolUse Bash entry with onFailure block, naming the script by $CLAUDE_PROJECT_DIR", () => {
81
+ const settings = JSON.parse(fs.readFileSync(at(".claude/settings.json"), "utf8"));
82
+ expect(settings.hooks.PreToolUse).toContainEqual({
83
+ matcher: "Bash",
84
+ hooks: [{ type: "command", command: `bash "$CLAUDE_PROJECT_DIR/${SCRIPT}"`, onFailure: "block" }],
85
+ });
86
+ });
87
+ it("[N38] AG2 no ledger record for the step: exit 2, stderr names the gate, step, unit and ledger path", () => {
88
+ const r = hook(bash("./tool publish ep42"));
89
+ expect(r.status).toBe(2);
90
+ expect(r.stderr).toContain("publish-ready");
91
+ expect(r.stderr).toContain("render");
92
+ expect(r.stderr).toContain("ep42");
93
+ expect(r.stderr).toContain("logs/ep42/trace.jsonl");
94
+ });
95
+ it("[N38] AG3 an ok record for the same unit: exit 0", () => {
96
+ ledger("ep42", [rec("render", true, "ep42")]);
97
+ expect(hook(bash("./tool publish ep42")).status).toBe(0);
98
+ expect(hook(bash("./tool republish ep42")).status).toBe(0);
99
+ });
100
+ it("[N38] AG4 an ok record for another unit does not open this unit's gate", () => {
101
+ ledger("ep41", [rec("render", true, "ep41")]);
102
+ ledger("ep42", [rec("render", true, "ep41")]);
103
+ expect(hook(bash("./tool publish ep42")).status).toBe(2);
104
+ });
105
+ it("[N38] AG5 the LAST record decides: ok:false after an earlier ok is a deny", () => {
106
+ ledger("ep42", [rec("render", true, "ep42"), rec("render", false, "ep42")]);
107
+ expect(hook(bash("./tool publish ep42")).status).toBe(2);
108
+ });
109
+ it("[N38] AG5 a later ok after an earlier failure opens the gate", () => {
110
+ ledger("ep42", [rec("render", false, "ep42"), rec("render", true, "ep42")]);
111
+ expect(hook(bash("./tool publish ep42")).status).toBe(0);
112
+ });
113
+ it("[N38] AG6 a command that matches no guarded action: exit 0", () => {
114
+ expect(hook(bash("ls -la")).status).toBe(0);
115
+ expect(hook(bash("./tool render ep42")).status).toBe(0);
116
+ expect(hook(bash("./tool publishing ep42")).status).toBe(0);
117
+ });
118
+ it("[N38] AG7 a missing ledger file is a deny", () => {
119
+ expect(fs.existsSync(at("logs"))).toBe(false);
120
+ expect(hook(bash("./tool publish ep42")).status).toBe(2);
121
+ });
122
+ it("[N38] AG8 bad JSON on stdin: exit 2", () => {
123
+ expect(hook("not json {").status).toBe(2);
124
+ expect(hook("").status).toBe(2);
125
+ });
126
+ it("[N38] AG9 leading VAR=value assignments are stripped before matching", () => {
127
+ expect(hook(bash("DEBUG=1 TOKEN='a b' ./tool publish ep42")).status).toBe(2);
128
+ ledger("ep42", [rec("render", true, "ep42")]);
129
+ expect(hook(bash("DEBUG=1 TOKEN='a b' ./tool publish ep42")).status).toBe(0);
130
+ });
131
+ it("[N38] AG10 a unit that would climb out of the project is a deny, not a path", () => {
132
+ const r = hook(bash("./tool publish ../../etc"));
133
+ expect(r.status).toBe(2);
134
+ });
135
+ it("[N38] AG11 fails closed when CLAUDE_PROJECT_DIR is unset", () => {
136
+ const r = spawnSync("/bin/sh", ["-c", `bash ${at(SCRIPT)}`], {
137
+ input: bash("ls"), env: { PATH: process.env.PATH }, encoding: "utf8",
138
+ });
139
+ expect(r.status).toBe(2);
140
+ });
141
+ it("[N38] AG12 a gate with run: also runs its wrapper, and a failing check denies", () => {
142
+ scaffold(topology("", `after: render\n before: publish\n ledger: trace\n run: "scripts/check.sh"`));
143
+ ledger("ep42", [rec("render", true, "ep42")]);
144
+ // the scaffolded wrapper is a stub that blocks until it is written
145
+ expect(hook(bash("./tool publish ep42")).status).toBe(2);
146
+ fs.writeFileSync(at(".claude/skills/ship/scripts/check.sh"), "#!/usr/bin/env bash\nexit 0\n", { mode: 0o755 });
147
+ expect(hook(bash("./tool publish ep42")).status).toBe(0);
148
+ fs.writeFileSync(at(".claude/skills/ship/scripts/check.sh"), "#!/usr/bin/env bash\nexit 1\n", { mode: 0o755 });
149
+ expect(hook(bash("./tool publish ep42")).status).toBe(2);
150
+ });
151
+ });
152
+ describe("[N38] the language: records, ledger and unit-from", () => {
153
+ it("[N38] AG13 parse and serialize round-trip", () => {
154
+ const ast = parse(topology());
155
+ expect(ast.records).toEqual([{ id: "trace", path: "logs/{unit}/trace.jsonl" }]);
156
+ const publish = ast.nodes.find((n) => n.id === "publish");
157
+ expect(publish.unitFrom).toBe("./tool (?:re)?publish (\\S+)");
158
+ const gate = ast.nodes.find((n) => n.id === "publish-ready");
159
+ expect(gate.ledger).toBe("trace");
160
+ const again = parse(serialize(ast));
161
+ expect(again.records).toEqual(ast.records);
162
+ expect(again.nodes.find((n) => n.id === "publish").unitFrom).toBe(publish.unitFrom);
163
+ expect(again.nodes.find((n) => n.id === "publish-ready").ledger).toBe("trace");
164
+ });
165
+ it("[N38] AG14 V102 accepts the new names and still refuses unknown ones", () => {
166
+ const rules = (src) => validate(parse(src)).filter((r) => r.rule === "V102");
167
+ expect(rules(topology())).toEqual([]);
168
+ expect(rules(topology().replace("ledger: trace", "ledgr: trace")).length).toBe(1);
169
+ });
170
+ });
171
+ describe("[N38] validation", () => {
172
+ const findings = (src, rule) => validate(parse(src)).filter((r) => r.rule === rule);
173
+ it("[N38] AG15 V25 no longer warns for a bounce-back gate before an action with commands, and still does for one without", () => {
174
+ const bounce = (src) => src.replace("on-fail: halt", "on-fail: bounce-back");
175
+ expect(findings(bounce(topology()), "V25")).toEqual([]);
176
+ const noCommands = bounce(topology()).replace(/(action publish \{\n kind: external\n) commands: \[[^\]]*\]\n/, "$1");
177
+ expect(findings(noCommands, "V25").length).toBe(1);
178
+ });
179
+ it("[N38] AG16 V110 warns when a gate before an action has neither ledger nor run:", () => {
180
+ const src = topology().replace("records {\n record trace { path: \"logs/{unit}/trace.jsonl\" }\n }\n", "").replace(" ledger: trace\n", "");
181
+ const hits = findings(src, "V110");
182
+ expect(hits.length).toBe(1);
183
+ expect(hits[0].level).toBe("warning");
184
+ expect(hits[0].node).toBe("publish-ready");
185
+ expect(findings(topology(), "V110")).toEqual([]);
186
+ });
187
+ it("[N38] AG17 V110 does not fire when the single record is the default ledger", () => {
188
+ expect(findings(topology().replace(" ledger: trace\n", ""), "V110")).toEqual([]);
189
+ });
190
+ it("[N38] AG18 V111 errors on a unit-from that is not a regex or has no capture group", () => {
191
+ const bad = findings(topology().replace(/unit-from: ".*"/, 'unit-from: "./tool (publish"'), "V111");
192
+ expect(bad.length).toBe(1);
193
+ expect(bad[0].level).toBe("error");
194
+ const none = findings(topology().replace(/unit-from: ".*"/, 'unit-from: "./tool publish \\\\S+"'), "V111");
195
+ expect(none.length).toBe(1);
196
+ expect(none[0].message).toMatch(/capture group/);
197
+ expect(findings(topology(), "V111")).toEqual([]);
198
+ });
199
+ it("[N38] AG19 V112 errors on a ledger that names no record", () => {
200
+ const hits = findings(topology().replace("ledger: trace", "ledger: nope"), "V112");
201
+ expect(hits.length).toBe(1);
202
+ expect(hits[0].level).toBe("error");
203
+ expect(hits[0].message).toContain("nope");
204
+ });
205
+ it("[N38] AG19 V112 errors on an unsafe record path, and allows {unit}", () => {
206
+ expect(findings(topology().replace("logs/{unit}/trace.jsonl", "../{unit}/trace.jsonl"), "V112").length).toBe(1);
207
+ expect(findings(topology().replace("logs/{unit}/trace.jsonl", "/abs/trace.jsonl"), "V112").length).toBe(1);
208
+ expect(findings(topology(), "V112")).toEqual([]);
209
+ });
210
+ it("[N38] AG19 V112 errors when a gate needs a ledger, names none, and several records exist", () => {
211
+ const two = topology().replace(" }\n gates", ' record audit { path: "logs/audit.jsonl" }\n }\n gates').replace(" ledger: trace\n", "");
212
+ const hits = findings(two, "V112");
213
+ expect(hits.length).toBe(1);
214
+ expect(hits[0].message).toMatch(/more than one record|which/);
215
+ });
216
+ });
217
+ describe.skipIf(!hasJq)("[N38] guard --check", () => {
218
+ it("[N38] AG20 reports refuse by hook when the Bash entry and the script's line are on disk, with the scope note", () => {
219
+ const ast = scaffold(topology());
220
+ const g = checkGuards(ast, root).items.find((i) => i.id === "publish-ready");
221
+ expect(g).toMatchObject({ kind: "gate", strength: "refuse", by: "hook" });
222
+ expect(g.notes.join(" ")).toContain("refuses in Claude Code sessions only; a step run outside Claude is covered by step check (by: code)");
223
+ });
224
+ it("[N38] AG20 reports none when the settings entry is gone", () => {
225
+ const ast = scaffold(topology());
226
+ const s = JSON.parse(fs.readFileSync(at(".claude/settings.json"), "utf8"));
227
+ delete s.hooks;
228
+ fs.writeFileSync(at(".claude/settings.json"), JSON.stringify(s));
229
+ const g = checkGuards(ast, root).items.find((i) => i.id === "publish-ready");
230
+ expect(g.strength).toBe("none");
231
+ });
232
+ it("[N38] AG20 reports none when the script has no line for the gate", () => {
233
+ const ast = scaffold(topology());
234
+ fs.writeFileSync(at(SCRIPT), "#!/usr/bin/env bash\nexit 0\n");
235
+ expect(checkGuards(ast, root).items.find((i) => i.id === "publish-ready").strength).toBe("none");
236
+ });
237
+ });
238
+ describe.skipIf(!hasJq)("[N42] before-action.sh sees a step inside a chained command", () => {
239
+ beforeEach(() => { scaffold(topology()); });
240
+ it("[N42] AG21 a step after cd, ;, ||, | or on a later line is refused while its gate is unmet", () => {
241
+ for (const c of [
242
+ "cd sub && ./tool publish ep1",
243
+ "true; ./tool publish ep1",
244
+ "make x || ./tool publish ep1",
245
+ "./tool lint | ./tool publish ep1",
246
+ "echo hi\n./tool publish ep1",
247
+ "(cd sub && ./tool publish ep1)",
248
+ "cd sub && DEBUG=1 time ./tool publish ep1",
249
+ "{ ./tool publish ep1; }",
250
+ "./tool lint & ./tool publish ep1",
251
+ ]) {
252
+ const r = hook(bash(c));
253
+ expect(r.status, c).toBe(2);
254
+ expect(r.stderr, c).toContain("publish-ready");
255
+ }
256
+ });
257
+ it("[N42] AG22 with an ok record the chained step runs, and the unit is read from the right segment", () => {
258
+ ledger("ep1", [rec("render", true, "ep1")]);
259
+ expect(hook(bash("cd sub && ./tool publish ep1")).status).toBe(0);
260
+ const r = hook(bash("cd sub && ./tool publish ep2"));
261
+ expect(r.status).toBe(2);
262
+ expect(r.stderr).toContain("ep2");
263
+ });
264
+ it("[N42] AG23 a command word that is not at a segment start is not a step", () => {
265
+ expect(hook(bash("echo ./tool publish ep1")).status).toBe(0);
266
+ expect(hook(bash("cd sub && echo ./tool publish ep1")).status).toBe(0);
267
+ });
268
+ it("[N42] AG24 two guarded steps in one command need both gates", () => {
269
+ const two = topology().replace(" records {", ' action archive {\n kind: external\n commands: ["./tool archive"]\n unit-from: "./tool archive (\\S+)"\n }\n records {').replace(" }\n flow", " gate archive-ready {\n after: publish\n before: archive\n ledger: trace\n on-fail: halt\n }\n }\n flow");
270
+ scaffold(two);
271
+ const cmd = "./tool publish ep1 && ./tool archive ep1";
272
+ ledger("ep1", [rec("render", true, "ep1")]);
273
+ const r = hook(bash(cmd));
274
+ expect(r.status).toBe(2);
275
+ expect(r.stderr).toContain("archive-ready");
276
+ ledger("ep1", [rec("publish", true, "ep1")]);
277
+ const r2 = hook(bash(cmd));
278
+ expect(r2.status).toBe(2);
279
+ expect(r2.stderr).toContain("publish-ready");
280
+ ledger("ep1", [rec("render", true, "ep1"), rec("publish", true, "ep1")]);
281
+ const ok = hook(bash(cmd));
282
+ expect(ok.stderr).toBe("");
283
+ expect(ok.status).toBe(0);
284
+ });
285
+ it("[N42] AG26 a check script that reads stdin does not swallow the later segments", () => {
286
+ const two = topology().replace(" gate publish-ready {", ' gate render-ready {\n before: render\n run: "scripts/check.sh"\n on-fail: halt\n }\n gate publish-ready {');
287
+ scaffold(two);
288
+ fs.writeFileSync(at(".claude/skills/ship/scripts/check.sh"), "#!/usr/bin/env bash\ncat >/dev/null\nexit 0\n", { mode: 0o755 });
289
+ const r = hook(bash("./tool render && ./tool publish ep1"));
290
+ expect(r.status).toBe(2);
291
+ expect(r.stderr).toContain("publish-ready");
292
+ });
293
+ it("[N42] AG25 guard --check notes that an indirect run is not seen", () => {
294
+ const ast = scaffold(topology());
295
+ const g = checkGuards(ast, root).items.find((i) => i.id === "publish-ready");
296
+ expect(g.notes.join(" ")).toContain("a command that runs the step indirectly (bash -c, eval, a script that calls it) is not seen");
297
+ });
298
+ });
299
+ //# sourceMappingURL=action-guard.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"action-guard.test.js","sourceRoot":"","sources":["../../../src/__tests__/e2e/action-guard.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
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
+ export {};
13
+ //# sourceMappingURL=conformance.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conformance.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/e2e/conformance.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}
@@ -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"}