agentopology 0.5.2 → 0.7.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 +5 -5
- package/dist/__tests__/e2e/compile.test.d.ts +12 -0
- package/dist/__tests__/e2e/compile.test.d.ts.map +1 -0
- package/dist/__tests__/e2e/compile.test.js +219 -0
- package/dist/__tests__/e2e/compile.test.js.map +1 -0
- package/dist/__tests__/e2e/roundtrip.test.d.ts +16 -0
- package/dist/__tests__/e2e/roundtrip.test.d.ts.map +1 -0
- package/dist/__tests__/e2e/roundtrip.test.js +178 -0
- package/dist/__tests__/e2e/roundtrip.test.js.map +1 -0
- package/dist/__tests__/e2e/scaffold-owns.test.d.ts +10 -0
- package/dist/__tests__/e2e/scaffold-owns.test.d.ts.map +1 -0
- package/dist/__tests__/e2e/scaffold-owns.test.js +163 -0
- package/dist/__tests__/e2e/scaffold-owns.test.js.map +1 -0
- package/dist/__tests__/e2e/sync-cycle.test.d.ts +10 -0
- package/dist/__tests__/e2e/sync-cycle.test.d.ts.map +1 -0
- package/dist/__tests__/e2e/sync-cycle.test.js +49 -0
- package/dist/__tests__/e2e/sync-cycle.test.js.map +1 -0
- package/dist/__tests__/global-setup.d.ts +7 -0
- package/dist/__tests__/global-setup.d.ts.map +1 -0
- package/dist/__tests__/global-setup.js +16 -0
- package/dist/__tests__/global-setup.js.map +1 -0
- package/dist/__tests__/live/claude-code.live.test.d.ts +20 -0
- package/dist/__tests__/live/claude-code.live.test.d.ts.map +1 -0
- package/dist/__tests__/live/claude-code.live.test.js +198 -0
- package/dist/__tests__/live/claude-code.live.test.js.map +1 -0
- package/dist/__tests__/live/zz-debug.test.d.ts +2 -0
- package/dist/__tests__/live/zz-debug.test.d.ts.map +1 -0
- package/dist/__tests__/live/zz-debug.test.js +4 -0
- package/dist/__tests__/live/zz-debug.test.js.map +1 -0
- package/dist/__tests__/open-findings.test.d.ts +10 -0
- package/dist/__tests__/open-findings.test.d.ts.map +1 -0
- package/dist/__tests__/open-findings.test.js +15 -0
- package/dist/__tests__/open-findings.test.js.map +1 -0
- package/dist/__tests__/spec-testing-sync.test.d.ts +10 -0
- package/dist/__tests__/spec-testing-sync.test.d.ts.map +1 -0
- package/dist/__tests__/spec-testing-sync.test.js +57 -0
- package/dist/__tests__/spec-testing-sync.test.js.map +1 -0
- package/dist/bindings/__tests__/bindings.test.js +19 -19
- package/dist/bindings/__tests__/bindings.test.js.map +1 -1
- package/dist/bindings/__tests__/claude-code-hybrid.test.js +5 -5
- package/dist/bindings/__tests__/claude-code-hybrid.test.js.map +1 -1
- package/dist/bindings/__tests__/hook-command.test.d.ts +9 -0
- package/dist/bindings/__tests__/hook-command.test.d.ts.map +1 -0
- package/dist/bindings/__tests__/hook-command.test.js +88 -0
- package/dist/bindings/__tests__/hook-command.test.js.map +1 -0
- package/dist/bindings/__tests__/hybrid-e2e.test.js +1 -1
- package/dist/bindings/__tests__/hybrid-e2e.test.js.map +1 -1
- package/dist/bindings/__tests__/mod-plugin.test.d.ts +9 -0
- package/dist/bindings/__tests__/mod-plugin.test.d.ts.map +1 -0
- package/dist/bindings/__tests__/mod-plugin.test.js +164 -0
- package/dist/bindings/__tests__/mod-plugin.test.js.map +1 -0
- package/dist/bindings/claude-code.d.ts +50 -1
- package/dist/bindings/claude-code.d.ts.map +1 -1
- package/dist/bindings/claude-code.js +636 -231
- package/dist/bindings/claude-code.js.map +1 -1
- package/dist/bindings/index.d.ts +7 -0
- package/dist/bindings/index.d.ts.map +1 -1
- package/dist/bindings/index.js +26 -7
- package/dist/bindings/index.js.map +1 -1
- package/dist/bindings/lib/prompt-fence.d.ts +22 -0
- package/dist/bindings/lib/prompt-fence.d.ts.map +1 -0
- package/dist/bindings/lib/prompt-fence.js +29 -0
- package/dist/bindings/lib/prompt-fence.js.map +1 -0
- package/dist/bindings/types.d.ts +6 -0
- package/dist/bindings/types.d.ts.map +1 -1
- package/dist/bindings/types.js.map +1 -1
- package/dist/cli/__tests__/cli.test.d.ts +1 -1
- package/dist/cli/__tests__/cli.test.js +1 -1
- package/dist/cli/index.js +124 -76
- package/dist/cli/index.js.map +1 -1
- package/dist/docs/content.d.ts.map +1 -1
- package/dist/docs/content.js +39 -3
- package/dist/docs/content.js.map +1 -1
- package/dist/docs/teach.d.ts.map +1 -1
- package/dist/docs/teach.js +46 -0
- package/dist/docs/teach.js.map +1 -1
- package/dist/import/__tests__/import.test.js +21 -9
- package/dist/import/__tests__/import.test.js.map +1 -1
- package/dist/import/claude-code.d.ts.map +1 -1
- package/dist/import/claude-code.js +128 -44
- package/dist/import/claude-code.js.map +1 -1
- package/dist/import/serializer.d.ts.map +1 -1
- package/dist/import/serializer.js +10 -0
- package/dist/import/serializer.js.map +1 -1
- package/dist/parser/__tests__/mod-hooks.test.d.ts +10 -0
- package/dist/parser/__tests__/mod-hooks.test.d.ts.map +1 -0
- package/dist/parser/__tests__/mod-hooks.test.js +136 -0
- package/dist/parser/__tests__/mod-hooks.test.js.map +1 -0
- package/dist/parser/ast.d.ts +29 -2
- 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 +102 -25
- package/dist/parser/index.js.map +1 -1
- package/dist/parser/paths.d.ts +15 -0
- package/dist/parser/paths.d.ts.map +1 -0
- package/dist/parser/paths.js +34 -0
- package/dist/parser/paths.js.map +1 -0
- package/dist/parser/run.d.ts +45 -0
- package/dist/parser/run.d.ts.map +1 -0
- package/dist/parser/run.js +91 -0
- package/dist/parser/run.js.map +1 -0
- package/dist/parser/validator.d.ts +12 -0
- package/dist/parser/validator.d.ts.map +1 -1
- package/dist/parser/validator.js +268 -2
- package/dist/parser/validator.js.map +1 -1
- package/dist/scaffold/__tests__/safety.test.d.ts +11 -0
- package/dist/scaffold/__tests__/safety.test.d.ts.map +1 -0
- package/dist/scaffold/__tests__/safety.test.js +184 -0
- package/dist/scaffold/__tests__/safety.test.js.map +1 -0
- package/dist/scaffold/__tests__/scaffold.test.js +2 -1
- package/dist/scaffold/__tests__/scaffold.test.js.map +1 -1
- package/dist/scaffold/__tests__/settings-merge.test.js +40 -9
- package/dist/scaffold/__tests__/settings-merge.test.js.map +1 -1
- package/dist/scaffold/diff.d.ts +17 -0
- package/dist/scaffold/diff.d.ts.map +1 -0
- package/dist/scaffold/diff.js +66 -0
- package/dist/scaffold/diff.js.map +1 -0
- package/dist/scaffold/incremental.d.ts +49 -13
- package/dist/scaffold/incremental.d.ts.map +1 -1
- package/dist/scaffold/incremental.js +235 -95
- package/dist/scaffold/incremental.js.map +1 -1
- package/dist/scaffold/manifest.d.ts +8 -1
- package/dist/scaffold/manifest.d.ts.map +1 -1
- package/dist/scaffold/manifest.js +32 -8
- package/dist/scaffold/manifest.js.map +1 -1
- package/dist/scaffold/merge.d.ts +15 -4
- package/dist/scaffold/merge.d.ts.map +1 -1
- package/dist/scaffold/merge.js +123 -18
- package/dist/scaffold/merge.js.map +1 -1
- package/dist/scaffold/types.d.ts +17 -0
- package/dist/scaffold/types.d.ts.map +1 -1
- package/dist/sync/index.d.ts +1 -0
- package/dist/sync/index.d.ts.map +1 -1
- package/dist/sync/index.js +40 -2
- package/dist/sync/index.js.map +1 -1
- package/package.json +1 -1
- package/spec/grammar.md +24 -5
- package/spec/testing.md +85 -0
- package/spec/validation.md +8 -2
package/README.md
CHANGED
|
@@ -96,7 +96,7 @@ who works, when they work, and what they know when they work. One file, two ways
|
|
|
96
96
|
┌────────────┐
|
|
97
97
|
┌──────────────┐ │ Parser & │ scaffold ──▶ Platform configs
|
|
98
98
|
│ .at file │─▶│ Validator │──┤ ├── .claude/agents/
|
|
99
|
-
│ (you write) │ │
|
|
99
|
+
│ (you write) │ │ 99 rules │ │ ├── <topology>.workflow.js
|
|
100
100
|
└──────────────┘ └────────────┘ │ ├── .codex/ .cursor/rules/
|
|
101
101
|
│ ├── .openclaw/ .github/agents/
|
|
102
102
|
│ └── .kiro/ …
|
|
@@ -234,7 +234,7 @@ In Claude Code, type `/agentopology` — or just ask naturally:
|
|
|
234
234
|
Say **"I want a code review team with an analyzer, security scanner, and reviewer"** — the skill:
|
|
235
235
|
|
|
236
236
|
1. Generates the `.at` file with the right syntax
|
|
237
|
-
2. Validates it against
|
|
237
|
+
2. Validates it against 99 rules
|
|
238
238
|
3. Scaffolds it to Claude Code, OpenClaw, Cursor, or any target
|
|
239
239
|
|
|
240
240
|
**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.
|
|
@@ -566,7 +566,7 @@ import { parse, validate, bindings } from "agentopology";
|
|
|
566
566
|
// Parse
|
|
567
567
|
const ast = parse(atSource);
|
|
568
568
|
|
|
569
|
-
// Validate (
|
|
569
|
+
// Validate (99 built-in rules, V1-V99)
|
|
570
570
|
const issues = validate(ast);
|
|
571
571
|
|
|
572
572
|
// Scaffold — generate platform files
|
|
@@ -624,7 +624,7 @@ You can `agentopology visualize` it into an interactive graph. You can hand it t
|
|
|
624
624
|
| **Switch platforms** | Rewrite everything | Change `--target` |
|
|
625
625
|
| **Add an agent** | Update 5-12 files across 3 tools | Add 4 lines to `.at` file |
|
|
626
626
|
| **See the architecture** | Read YAML, JSON, TOML, Markdown across 6 dirs | One `.at` file. Or `visualize` it. |
|
|
627
|
-
| **Validate** | Hope for the best |
|
|
627
|
+
| **Validate** | Hope for the best | 99 built-in rules catch errors before deploy |
|
|
628
628
|
| **Onboard someone** | "Read these 15 files and figure it out" | "Read this `.at` file" |
|
|
629
629
|
| **Version control** | Diff 47 generated files | Diff one `.at` file |
|
|
630
630
|
| **Move to a new tool** | Start over | `--target new-tool` |
|
|
@@ -646,7 +646,7 @@ You can `agentopology visualize` it into an interactive graph. You can hand it t
|
|
|
646
646
|
## CLI Reference
|
|
647
647
|
|
|
648
648
|
```
|
|
649
|
-
agentopology validate <file> Validate an .at file (
|
|
649
|
+
agentopology validate <file> Validate an .at file (99 rules)
|
|
650
650
|
agentopology plan <file> Resolve for interpreted execution — no files written
|
|
651
651
|
agentopology scaffold <file> --target <t> Generate platform configs
|
|
652
652
|
agentopology sync <file> --target <t> --dir <d> Sync platform files back to .at
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End to end: what scaffold writes, Claude Code reads as meant.
|
|
3
|
+
*
|
|
4
|
+
* Phase 3 of the compile audit. Each test is a construct that used to compile
|
|
5
|
+
* to config Claude Code skipped (an agent without a description, a url server
|
|
6
|
+
* without type), misread (`yes` as a boolean, a regex matcher breaking YAML)
|
|
7
|
+
* or never fired (a hook on AgentStop, a prompt hook sent as a command). The
|
|
8
|
+
* fixture (fixtures/compile.at) holds them all; the live suite starts real
|
|
9
|
+
* Claude Code on it too.
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=compile.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compile.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/e2e/compile.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End to end: what scaffold writes, Claude Code reads as meant.
|
|
3
|
+
*
|
|
4
|
+
* Phase 3 of the compile audit. Each test is a construct that used to compile
|
|
5
|
+
* to config Claude Code skipped (an agent without a description, a url server
|
|
6
|
+
* without type), misread (`yes` as a boolean, a regex matcher breaking YAML)
|
|
7
|
+
* or never fired (a hook on AgentStop, a prompt hook sent as a command). The
|
|
8
|
+
* fixture (fixtures/compile.at) holds them all; the live suite starts real
|
|
9
|
+
* Claude Code on it too.
|
|
10
|
+
*/
|
|
11
|
+
import { describe, it, expect } from "vitest";
|
|
12
|
+
import * as fs from "node:fs";
|
|
13
|
+
import { resolve, dirname } from "node:path";
|
|
14
|
+
import { fileURLToPath } from "node:url";
|
|
15
|
+
import { parse } from "../../parser/index.js";
|
|
16
|
+
import { validate } from "../../parser/validator.js";
|
|
17
|
+
import { scriptNameFromRun, runParts } from "../../parser/run.js";
|
|
18
|
+
import { claudeCodeBinding } from "../../bindings/claude-code.js";
|
|
19
|
+
import { STUB_MARKER } from "../../bindings/lib/stub.js";
|
|
20
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
21
|
+
const ast = parse(fs.readFileSync(resolve(here, "fixtures/compile.at"), "utf-8"));
|
|
22
|
+
const files = new Map(claudeCodeBinding.scaffold(ast).map((f) => [f.path, f]));
|
|
23
|
+
const read = (p) => {
|
|
24
|
+
const f = files.get(p);
|
|
25
|
+
if (!f)
|
|
26
|
+
throw new Error(`not generated: ${p}`);
|
|
27
|
+
return f.content;
|
|
28
|
+
};
|
|
29
|
+
const settings = JSON.parse(read(".claude/settings.json"));
|
|
30
|
+
const drafter = read(".claude/agents/drafter/AGENT.md");
|
|
31
|
+
const auditor = read(".claude/agents/auditor/AGENT.md");
|
|
32
|
+
describe("the fixture itself", () => {
|
|
33
|
+
it("validates with no errors", () => {
|
|
34
|
+
expect(validate(ast).filter((r) => r.level === "error")).toEqual([]);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
describe("hooks fire on events Claude Code has, in the form it reads", () => {
|
|
38
|
+
it("[N5] a prompt hook is a prompt handler, in settings and in an agent's frontmatter", () => {
|
|
39
|
+
expect(settings.hooks.Stop[0].hooks[0]).toEqual({
|
|
40
|
+
type: "prompt",
|
|
41
|
+
prompt: "Check the session ended with a summary: reply ok true or false.",
|
|
42
|
+
});
|
|
43
|
+
expect(drafter).toContain('- type: "prompt"\n prompt: "Did the draft cite a source? Answer ok: false if not."');
|
|
44
|
+
// and no shell stub is planned for a prompt
|
|
45
|
+
expect([...files.keys()].filter((p) => /judge|review/.test(p))).toEqual([]);
|
|
46
|
+
});
|
|
47
|
+
it("[N6] universal events map to Claude Code's (AgentStop is SubagentStop; Stop inside an agent)", () => {
|
|
48
|
+
expect(settings.hooks.AgentStop).toBeUndefined();
|
|
49
|
+
expect(settings.hooks.SubagentStop.map((e) => e.matcher)).toContain("drafter");
|
|
50
|
+
expect(drafter).not.toContain("AgentStop");
|
|
51
|
+
expect(drafter).toMatch(/^ {2}Stop:$/m);
|
|
52
|
+
});
|
|
53
|
+
it("[N9] a regex matcher stays a valid YAML string in an agent's frontmatter", () => {
|
|
54
|
+
// `\.` inside a YAML double-quoted string is an invalid escape: the whole
|
|
55
|
+
// frontmatter failed to parse and Claude Code dropped the agent.
|
|
56
|
+
expect(drafter).toContain(String.raw `- matcher: "Edit|Write\\.md$"`);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
describe("agents register as written", () => {
|
|
60
|
+
it("[N10] a manual agent keeps its description (Claude Code skips an agent without one) and says it runs on request", () => {
|
|
61
|
+
expect(auditor).toMatch(/^description: Audits a draft on request\. Use only when the user asks for this agent by name/m);
|
|
62
|
+
});
|
|
63
|
+
it("[N8] permissions confirm and bypass compile to real permissionMode values", () => {
|
|
64
|
+
expect(drafter).not.toContain("permissionMode");
|
|
65
|
+
expect(auditor).toContain("permissionMode: bypassPermissions");
|
|
66
|
+
});
|
|
67
|
+
it("[N17] a scalar YAML would read as another type is quoted", () => {
|
|
68
|
+
expect(drafter).toContain('description: "yes"');
|
|
69
|
+
expect(drafter).toMatch(/^model: sonnet$/m);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
describe("MCP and permissions", () => {
|
|
73
|
+
it("[N4] a url server gets type: http, so Claude Code does not skip it", () => {
|
|
74
|
+
const mcp = JSON.parse(read(".mcp.json"));
|
|
75
|
+
expect(mcp.mcpServers.search).toEqual({ url: "https://search.example.com/mcp", type: "http" });
|
|
76
|
+
});
|
|
77
|
+
it("[N7] MCP names convert whole-server, wildcard and dotted forms, in tools and in permissions", () => {
|
|
78
|
+
expect(drafter).toContain('tools: "Read, mcp__notes, mcp__search__*, mcp__search__find.all"');
|
|
79
|
+
expect(settings.permissions.allow).toEqual(["Read", "mcp__search"]);
|
|
80
|
+
expect(settings.permissions.deny).toEqual(["mcp__notes__delete"]);
|
|
81
|
+
});
|
|
82
|
+
it("[N14] settings ask rules are emitted", () => {
|
|
83
|
+
expect(settings.permissions.ask).toEqual(["Bash(git push:*)"]);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
describe("a run: line is a command with arguments", () => {
|
|
87
|
+
it("[C3] the script is the word after the interpreter, never an argument", () => {
|
|
88
|
+
const run = "python3 docs/tools/check.py check-dir docs/show/SLUG --out OUT/frames-critic.json";
|
|
89
|
+
expect(runParts(run)).toEqual({
|
|
90
|
+
interpreter: "python3",
|
|
91
|
+
script: "docs/tools/check.py",
|
|
92
|
+
args: ["check-dir", "docs/show/SLUG", "--out", "OUT/frames-critic.json"],
|
|
93
|
+
});
|
|
94
|
+
expect(scriptNameFromRun(run)).toBe("check.py");
|
|
95
|
+
const planned = [...files.keys()];
|
|
96
|
+
expect(planned.filter((p) => /SLUG|frames-critic/.test(p))).toEqual([]);
|
|
97
|
+
// the gate runs the real script, from the project root, arguments kept
|
|
98
|
+
expect(read(".claude/skills/compile/scripts/gate-copy-check.sh")).toContain('python3 "$CLAUDE_PROJECT_DIR/docs/tools/check.py" check-dir docs/show/SLUG --out OUT/frames-critic.json');
|
|
99
|
+
// a stub fills the gap only until the user's script exists
|
|
100
|
+
expect(files.get("docs/tools/check.py")?.createOnly).toBe(true);
|
|
101
|
+
});
|
|
102
|
+
it("[N19] scaffold output is byte-stable: no date in any generated file", () => {
|
|
103
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
104
|
+
expect([...files.values()].filter((f) => f.content.includes(today)).map((f) => f.path)).toEqual([]);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
describe("gates and human steps are enforced before the agent they guard", () => {
|
|
108
|
+
const script = read(".claude/skills/compile/scripts/before-agent.sh");
|
|
109
|
+
it("[C4] a gate after an action runs before its next agent launches (PreToolUse on the Agent tool)", () => {
|
|
110
|
+
expect(settings.hooks.PreToolUse).toContainEqual({
|
|
111
|
+
matcher: "Agent|Task",
|
|
112
|
+
hooks: [{ type: "command", command: 'bash "$CLAUDE_PROJECT_DIR/.claude/skills/compile/scripts/before-agent.sh"' }],
|
|
113
|
+
});
|
|
114
|
+
expect(script).toMatch(/drafter\)\n[\s\S]*bash "\$DIR\/gate-brief-check\.sh" >&2 \|\| exit 2/);
|
|
115
|
+
// not also a SubagentStop hook on a node Claude Code never registers
|
|
116
|
+
const matchers = settings.hooks.SubagentStop.map((e) => e.matcher);
|
|
117
|
+
expect(matchers).not.toContain("intake");
|
|
118
|
+
});
|
|
119
|
+
it("[H1] a human node is an approval step: Claude Code asks before launching the next agent; no AGENT.md", () => {
|
|
120
|
+
expect([...files.keys()]).not.toContain(".claude/agents/approve/AGENT.md");
|
|
121
|
+
expect(script).toContain(`ask 'Approval step "approve": The editor approves the brief before drafting'`);
|
|
122
|
+
expect(script).toContain(`permissionDecision: "ask"`);
|
|
123
|
+
expect(read(".claude/skills/compile/SKILL.md")).toMatch(/## Approval steps[\s\S]*### Approve\nThe editor approves/);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
describe("the topology's context does not compete with the project's own", () => {
|
|
127
|
+
it("[C2] context goes to .claude/rules/<topology>.md, never a CLAUDE.md", () => {
|
|
128
|
+
expect([...files.keys()].filter((p) => /(^|\/)CLAUDE\.md$/.test(p))).toEqual([]);
|
|
129
|
+
expect(read(".claude/rules/compile.md")).toMatch(/^# Compile\n/);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
describe("a skill's instructions reach the model", () => {
|
|
133
|
+
it("[N12] prompt: path tells Claude to read and follow the file; a prompt block is the body", () => {
|
|
134
|
+
const brief = read(".claude/skills/brief/SKILL.md");
|
|
135
|
+
expect(brief).not.toContain("See:");
|
|
136
|
+
expect(brief).toContain("Read `prompts/brief.md` before anything else and follow it");
|
|
137
|
+
expect(read(".claude/skills/tone/SKILL.md")).toMatch(/## Instructions\n\n### Tone\nShort sentences\. No jargon\./);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
describe("actions, tools and schedules run what they declare", () => {
|
|
141
|
+
it("[A3] an action's commands are emitted whatever its kind; one without commands is a marked stub that fails", () => {
|
|
142
|
+
expect(read(".claude/skills/compile/scripts/action-fetch.sh")).toContain("curl -fsS https://feeds.example.com/brief -o brief.json");
|
|
143
|
+
const digest = read(".claude/skills/compile/scripts/action-digest.sh");
|
|
144
|
+
expect(digest).toContain(STUB_MARKER);
|
|
145
|
+
expect(digest).toMatch(/exit 1\n$/);
|
|
146
|
+
// an inline action is done in conversation: not a stub
|
|
147
|
+
expect(read(".claude/skills/compile/scripts/action-intake.sh")).not.toContain(STUB_MARKER);
|
|
148
|
+
});
|
|
149
|
+
it("[A3b] a tool's stub goes where its script: points, never a copy beside it", () => {
|
|
150
|
+
expect(files.get("tools/render.py")?.createOnly).toBe(true);
|
|
151
|
+
expect(files.has(".claude/skills/compile/scripts/render.py")).toBe(false);
|
|
152
|
+
expect(read(".claude/skills/compile/scripts/count.sh")).toContain(STUB_MARKER);
|
|
153
|
+
});
|
|
154
|
+
it("[B4] schedules run headless from the project root, call the real action path, and every: becomes cron", () => {
|
|
155
|
+
const nightly = read("scripts/schedule-nightly.sh");
|
|
156
|
+
expect(nightly).toContain('cd "$(dirname "$0")/.."');
|
|
157
|
+
expect(nightly).toContain('claude -p "Run your scheduled task (nightly)." --agent drafter');
|
|
158
|
+
expect(read("scripts/schedule-weekly-digest.sh")).toContain("bash .claude/skills/compile/scripts/action-digest.sh");
|
|
159
|
+
const cron = read("crontab.fragment");
|
|
160
|
+
expect(cron).toContain("*/15 * * * * bash scripts/schedule-nightly.sh");
|
|
161
|
+
expect(cron).toContain("0 0 * * 0 bash scripts/schedule-weekly-digest.sh");
|
|
162
|
+
// 7 minutes has no cron form: left commented, and scaffold warns
|
|
163
|
+
expect(cron).toContain("# every: 7m bash scripts/schedule-odd.sh");
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
describe("nothing written in the .at is dropped without a message", () => {
|
|
167
|
+
it("[N21] a gate (or hook, tool, job) outside its container block is a V98 error, not silently ignored", () => {
|
|
168
|
+
const src = fs.readFileSync(resolve(here, "fixtures/compile.at"), "utf-8").replace(" flow {", ' gate stray {\n after: drafter\n run: "scripts/stray.sh"\n }\n\n job lost {\n cron: "0 * * * *"\n agent: drafter\n }\n\n flow {');
|
|
169
|
+
const v98 = validate(parse(src)).filter((r) => r.rule === "V98");
|
|
170
|
+
expect(v98.map((r) => r.message)).toEqual([
|
|
171
|
+
'"gate stray" is outside a "gates { }" block, so it is ignored — move it inside "gates { ... }"',
|
|
172
|
+
'"job lost" is outside a "schedule { }" block, so it is ignored — move it inside "schedule { ... }"',
|
|
173
|
+
]);
|
|
174
|
+
expect(v98.every((r) => r.level === "error")).toBe(true);
|
|
175
|
+
});
|
|
176
|
+
it("[N21] no shipped example trips V98", () => {
|
|
177
|
+
const dir = resolve(here, "../../../examples");
|
|
178
|
+
const hits = fs.readdirSync(dir).filter((f) => f.endsWith(".at"))
|
|
179
|
+
.filter((f) => validate(parse(fs.readFileSync(resolve(dir, f), "utf-8"))).some((r) => r.rule === "V98"));
|
|
180
|
+
expect(hits).toEqual([]);
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
describe("references resolve", () => {
|
|
184
|
+
it("[N18] an undeclared skill, MCP server or skill agent is a V99 warning", () => {
|
|
185
|
+
const src = fs.readFileSync(resolve(here, "fixtures/compile.at"), "utf-8")
|
|
186
|
+
.replace(' permissions: bypass\n', ' permissions: bypass\n skills: [tone, toen]\n mcp-servers: [search, serch]\n')
|
|
187
|
+
.replace(' description: "Write a brief"\n', ' description: "Write a brief"\n agent: draftr\n');
|
|
188
|
+
const v99 = validate(parse(src)).filter((r) => r.rule === "V99");
|
|
189
|
+
expect(v99.map((r) => r.message.split(",")[0])).toEqual([
|
|
190
|
+
'Agent "auditor" uses skill "toen"',
|
|
191
|
+
'Agent "auditor" uses MCP server "serch"',
|
|
192
|
+
'Skill "brief" runs in agent "draftr"',
|
|
193
|
+
]);
|
|
194
|
+
expect(v99.every((r) => r.level === "warning")).toBe(true);
|
|
195
|
+
// declared names and built-in agents pass
|
|
196
|
+
expect(validate(ast).filter((r) => r.rule === "V99")).toEqual([]);
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
describe("model ids are checked for the target", () => {
|
|
200
|
+
it("[N16] a model Claude Code does not have is omitted with a warning; aliases and claude-* ids pass", () => {
|
|
201
|
+
const src = fs.readFileSync(resolve(here, "fixtures/compile.at"), "utf-8")
|
|
202
|
+
.replace(" agent auditor {\n model: sonnet", " agent auditor {\n model: gpt-4o")
|
|
203
|
+
.replace(" agent drafter {\n model: sonnet", " agent drafter {\n model: claude-opus-5-5");
|
|
204
|
+
const warnings = [];
|
|
205
|
+
const warn = console.warn;
|
|
206
|
+
console.warn = (...a) => void warnings.push(a.join(" "));
|
|
207
|
+
let out;
|
|
208
|
+
try {
|
|
209
|
+
out = new Map(claudeCodeBinding.scaffold(parse(src)).map((f) => [f.path, f.content]));
|
|
210
|
+
}
|
|
211
|
+
finally {
|
|
212
|
+
console.warn = warn;
|
|
213
|
+
}
|
|
214
|
+
expect(out.get(".claude/agents/auditor/AGENT.md")).not.toMatch(/^model:/m);
|
|
215
|
+
expect(warnings.some((w) => w.includes('model "gpt-4o" is not a Claude Code model'))).toBe(true);
|
|
216
|
+
expect(out.get(".claude/agents/drafter/AGENT.md")).toMatch(/^model: claude-opus-5-5$/m);
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
//# sourceMappingURL=compile.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compile.test.js","sourceRoot":"","sources":["../../../src/__tests__/e2e/compile.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End to end: a system built by hand comes into .at without losing anything.
|
|
3
|
+
*
|
|
4
|
+
* The rule (Nadav, 2026-10-29): AgentTopology gives the structure; bringing a
|
|
5
|
+
* hand-built system into it must never delete its internals. Before this,
|
|
6
|
+
* import then scaffold on this repo's own .claude left 0 of 72 files
|
|
7
|
+
* identical, 37 missing and the rest cut down (a 404-line SKILL.md came back
|
|
8
|
+
* as 9 lines), and the imported .at had 22 validation errors.
|
|
9
|
+
*
|
|
10
|
+
* The fixture (fixtures/handbuilt) holds what was lost: a flat and a folder
|
|
11
|
+
* agent, frontmatter the language has no field for, a comma-string tools
|
|
12
|
+
* list, a skill with scripts and references, a command, real permissions and
|
|
13
|
+
* a hand-written hook.
|
|
14
|
+
*/
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=roundtrip.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"roundtrip.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/e2e/roundtrip.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG"}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End to end: a system built by hand comes into .at without losing anything.
|
|
3
|
+
*
|
|
4
|
+
* The rule (Nadav, 2026-10-29): AgentTopology gives the structure; bringing a
|
|
5
|
+
* hand-built system into it must never delete its internals. Before this,
|
|
6
|
+
* import then scaffold on this repo's own .claude left 0 of 72 files
|
|
7
|
+
* identical, 37 missing and the rest cut down (a 404-line SKILL.md came back
|
|
8
|
+
* as 9 lines), and the imported .at had 22 validation errors.
|
|
9
|
+
*
|
|
10
|
+
* The fixture (fixtures/handbuilt) holds what was lost: a flat and a folder
|
|
11
|
+
* agent, frontmatter the language has no field for, a comma-string tools
|
|
12
|
+
* list, a skill with scripts and references, a command, real permissions and
|
|
13
|
+
* a hand-written hook.
|
|
14
|
+
*/
|
|
15
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
16
|
+
import { execFileSync } from "node:child_process";
|
|
17
|
+
import { createHash } from "node:crypto";
|
|
18
|
+
import * as fs from "node:fs";
|
|
19
|
+
import * as os from "node:os";
|
|
20
|
+
import { resolve, dirname, join, relative } from "node:path";
|
|
21
|
+
import { fileURLToPath } from "node:url";
|
|
22
|
+
import { parse } from "../../parser/index.js";
|
|
23
|
+
import { validate } from "../../parser/validator.js";
|
|
24
|
+
import { claudeCodeBinding } from "../../bindings/claude-code.js";
|
|
25
|
+
import { deepMergeSettingsJson } from "../../scaffold/merge.js";
|
|
26
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
27
|
+
const root = resolve(here, "../../..");
|
|
28
|
+
const CLI = resolve(root, "dist/cli/index.js");
|
|
29
|
+
const HANDBUILT = resolve(here, "fixtures/handbuilt");
|
|
30
|
+
function cli(args) {
|
|
31
|
+
try {
|
|
32
|
+
const out = execFileSync(process.execPath, [CLI, ...args], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
|
|
33
|
+
return { out, code: 0 };
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
const e = err;
|
|
37
|
+
return { out: `${e.stdout ?? ""}${e.stderr ?? ""}`, code: e.status ?? 1 };
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/** path -> sha1 of every file under dir. */
|
|
41
|
+
function snapshot(dir) {
|
|
42
|
+
const out = new Map();
|
|
43
|
+
const walk = (d) => {
|
|
44
|
+
for (const e of fs.readdirSync(d, { withFileTypes: true })) {
|
|
45
|
+
const p = join(d, e.name);
|
|
46
|
+
if (e.isDirectory())
|
|
47
|
+
walk(p);
|
|
48
|
+
else
|
|
49
|
+
out.set(relative(dir, p), createHash("sha1").update(fs.readFileSync(p)).digest("hex"));
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
walk(dir);
|
|
53
|
+
return out;
|
|
54
|
+
}
|
|
55
|
+
let tmp;
|
|
56
|
+
let project;
|
|
57
|
+
let at;
|
|
58
|
+
beforeEach(() => {
|
|
59
|
+
tmp = fs.mkdtempSync(join(os.tmpdir(), "at-roundtrip-"));
|
|
60
|
+
project = join(tmp, "project");
|
|
61
|
+
fs.cpSync(HANDBUILT, project, { recursive: true });
|
|
62
|
+
at = join(tmp, "handbuilt.at");
|
|
63
|
+
expect(cli(["import", "--target", "claude-code", "--dir", project, "--name", "handbuilt", "--output", tmp]).code).toBe(0);
|
|
64
|
+
});
|
|
65
|
+
afterEach(() => {
|
|
66
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
67
|
+
});
|
|
68
|
+
describe("import then scaffold loses nothing (e2e)", () => {
|
|
69
|
+
it("[R3] the imported .at validates with no errors", () => {
|
|
70
|
+
const errors = validate(parse(fs.readFileSync(at, "utf-8"))).filter((r) => r.level === "error");
|
|
71
|
+
expect(errors.map((e) => `[${e.rule}] ${e.message}`)).toEqual([]);
|
|
72
|
+
});
|
|
73
|
+
it("[R1] every hand-built file is still there after scaffolding the import back", () => {
|
|
74
|
+
const before = snapshot(project);
|
|
75
|
+
expect(cli(["scaffold", at, "--target", "claude-code", "--output", project]).code).toBe(0);
|
|
76
|
+
const after = snapshot(project);
|
|
77
|
+
const missing = [...before.keys()].filter((p) => !after.has(p));
|
|
78
|
+
expect(missing).toEqual([]);
|
|
79
|
+
});
|
|
80
|
+
it("[R2] every hand-built file is byte-identical, settings.json included", () => {
|
|
81
|
+
const before = snapshot(project);
|
|
82
|
+
cli(["scaffold", at, "--target", "claude-code", "--output", project]);
|
|
83
|
+
const after = snapshot(project);
|
|
84
|
+
const changed = [...before].filter(([p, h]) => after.get(p) !== h).map(([p]) => p);
|
|
85
|
+
expect(changed).toEqual([]);
|
|
86
|
+
});
|
|
87
|
+
it("[A4] even --force leaves every hand-written file byte-identical", () => {
|
|
88
|
+
// Two layers protect a hand-built file: scaffold keeps files it did not
|
|
89
|
+
// create (G1), and file: means the binding never generates them at all.
|
|
90
|
+
// --force removes the first layer, so this proves the second on its own.
|
|
91
|
+
const before = snapshot(project);
|
|
92
|
+
expect(cli(["scaffold", at, "--target", "claude-code", "--output", project, "--force"]).code).toBe(0);
|
|
93
|
+
const after = snapshot(project);
|
|
94
|
+
const changed = [...before].filter(([p, h]) => after.get(p) !== h).map(([p]) => p);
|
|
95
|
+
expect(changed).toEqual([]);
|
|
96
|
+
});
|
|
97
|
+
it("[G12] a second scaffold of the import changes nothing", () => {
|
|
98
|
+
cli(["scaffold", at, "--target", "claude-code", "--output", project]);
|
|
99
|
+
expect(cli(["scaffold", at, "--target", "claude-code", "--output", project]).out).toMatch(/ 0 created, 0 updated/);
|
|
100
|
+
});
|
|
101
|
+
it("[R4] import keeps what the language has no field for, and the real permissions", () => {
|
|
102
|
+
const ast = parse(fs.readFileSync(at, "utf-8"));
|
|
103
|
+
const reviewer = ast.nodes.find((n) => n.id === "reviewer");
|
|
104
|
+
expect(reviewer.file).toBe(".claude/agents/reviewer.md");
|
|
105
|
+
expect(reviewer.extensions?.["claude-code"]).toMatchObject({
|
|
106
|
+
effort: "high",
|
|
107
|
+
color: "purple",
|
|
108
|
+
});
|
|
109
|
+
expect(reviewer.tools).toEqual(["Read", "Grep", "Glob"]);
|
|
110
|
+
expect(ast.settings.allow).toContain("Read");
|
|
111
|
+
expect(ast.settings.ask).toEqual(["Bash(git push:*)"]);
|
|
112
|
+
});
|
|
113
|
+
it("[A4] skills, commands and agents found on disk are marked file: and never generated", () => {
|
|
114
|
+
const ast = parse(fs.readFileSync(at, "utf-8"));
|
|
115
|
+
expect(ast.skills.find((s) => s.id === "story")?.file).toBe(".claude/skills/story/SKILL.md");
|
|
116
|
+
expect(ast.triggers.find((t) => t.name === "ship")?.file).toBe(".claude/commands/ship.md");
|
|
117
|
+
const paths = claudeCodeBinding.scaffold(ast).map((f) => f.path);
|
|
118
|
+
expect(paths.filter((p) => p.startsWith(".claude/skills/story/"))).toEqual([]);
|
|
119
|
+
expect(paths).not.toContain(".claude/commands/ship.md");
|
|
120
|
+
expect(paths).not.toContain(".claude/agents/reviewer/AGENT.md");
|
|
121
|
+
expect(paths).not.toContain(".claude/agents/writer/AGENT.md");
|
|
122
|
+
});
|
|
123
|
+
it("[G13] an agent's extensions never leak into project-wide settings", () => {
|
|
124
|
+
cli(["scaffold", at, "--target", "claude-code", "--output", project]);
|
|
125
|
+
const settings = JSON.parse(fs.readFileSync(join(project, ".claude/settings.json"), "utf-8"));
|
|
126
|
+
expect(settings.effort).toBeUndefined();
|
|
127
|
+
expect(settings.color).toBeUndefined();
|
|
128
|
+
});
|
|
129
|
+
it("[G14] an imported hook and its compiled form are one hook, not two", () => {
|
|
130
|
+
const existing = JSON.stringify({
|
|
131
|
+
hooks: { PreToolUse: [{ matcher: "Bash", hooks: [{ type: "command", command: "bash .claude/hooks/guard.sh" }] }] },
|
|
132
|
+
});
|
|
133
|
+
const generated = JSON.stringify({
|
|
134
|
+
hooks: { PreToolUse: [{ matcher: "Bash", hooks: [{ type: "command", command: 'bash "$CLAUDE_PROJECT_DIR/.claude/hooks/guard.sh"' }] }] },
|
|
135
|
+
});
|
|
136
|
+
const merged = JSON.parse(deepMergeSettingsJson(existing, generated));
|
|
137
|
+
expect(merged.hooks.PreToolUse).toHaveLength(1);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
describe("an on-demand agent needs no flow path", () => {
|
|
141
|
+
it("[G17] V11 skips a reader or writer with invocation: manual", () => {
|
|
142
|
+
const src = fs.readFileSync(at, "utf-8")
|
|
143
|
+
.replace("agent reviewer {", 'agent reviewer {\n reads: ["drafts/"]')
|
|
144
|
+
.replace("agent writer {", 'agent writer {\n writes: ["drafts/"]');
|
|
145
|
+
expect(validate(parse(src)).filter((r) => r.rule === "V11")).toEqual([]);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
describe("file: is checked, and scaffold's two overrides are separate", () => {
|
|
149
|
+
it("[G15] V97 refuses a file: outside the project", () => {
|
|
150
|
+
const src = fs.readFileSync(at, "utf-8").replace("file: .claude/agents/reviewer.md", 'file: "../elsewhere/reviewer.md"');
|
|
151
|
+
const errors = validate(parse(src)).filter((r) => r.rule === "V97");
|
|
152
|
+
expect(errors).toHaveLength(1);
|
|
153
|
+
});
|
|
154
|
+
it("[F3] --allow-invalid compiles despite errors; --force alone does not", () => {
|
|
155
|
+
fs.writeFileSync(at, fs.readFileSync(at, "utf-8").replace("file: .claude/agents/reviewer.md", 'file: "../x.md"'));
|
|
156
|
+
const forced = cli(["scaffold", at, "--target", "claude-code", "--output", project, "--force"]);
|
|
157
|
+
expect(forced.code).toBe(1);
|
|
158
|
+
expect(forced.out).toContain("Nothing was written");
|
|
159
|
+
const allowed = cli(["scaffold", at, "--target", "claude-code", "--output", project, "--allow-invalid"]);
|
|
160
|
+
expect(allowed.code).toBe(0);
|
|
161
|
+
// --allow-invalid does not overwrite what scaffold did not create.
|
|
162
|
+
expect(fs.readFileSync(join(project, ".claude/hooks/guard.sh"), "utf-8")).toContain("Blocks a push");
|
|
163
|
+
});
|
|
164
|
+
it("[C5] a hook's own script is never overwritten, even with --force, and not reported as a conflict", () => {
|
|
165
|
+
const { out } = cli(["scaffold", at, "--target", "claude-code", "--output", project, "--force"]);
|
|
166
|
+
expect(fs.readFileSync(join(project, ".claude/hooks/guard.sh"), "utf-8")).toContain("Blocks a push");
|
|
167
|
+
expect(out).not.toContain("guard.sh (exists");
|
|
168
|
+
const manifest = JSON.parse(fs.readFileSync(join(project, ".claude/.scaffold-manifest.json"), "utf-8"));
|
|
169
|
+
expect(manifest.files[".claude/hooks/guard.sh"]).toBeUndefined();
|
|
170
|
+
});
|
|
171
|
+
it("[G16] scaffold names a hand-written file the project lacks", () => {
|
|
172
|
+
fs.rmSync(join(project, ".claude/commands/ship.md"));
|
|
173
|
+
const { out } = cli(["scaffold", at, "--target", "claude-code", "--output", project, "--dry-run"]);
|
|
174
|
+
expect(out).toContain(".claude/commands/ship.md");
|
|
175
|
+
expect(out).toMatch(/hand-written file\(s\) named by file: are not in/);
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
//# sourceMappingURL=roundtrip.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"roundtrip.test.js","sourceRoot":"","sources":["../../../src/__tests__/e2e/roundtrip.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End to end: scaffold only changes what it owns.
|
|
3
|
+
*
|
|
4
|
+
* Each test runs the built CLI as a user would, against a temporary project
|
|
5
|
+
* that holds the hazards a real harness hit on 2026-10-28. Test names carry
|
|
6
|
+
* the guarantee id from spec/testing.md; spec-testing-sync.test.ts fails if a
|
|
7
|
+
* guarantee there has no test here or elsewhere.
|
|
8
|
+
*/
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=scaffold-owns.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scaffold-owns.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/e2e/scaffold-owns.test.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
|