agentopology 0.2.5 → 0.4.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 (162) hide show
  1. package/README.md +121 -7
  2. package/dist/analyzer/__tests__/analyzer.test.js +36 -9
  3. package/dist/analyzer/__tests__/analyzer.test.js.map +1 -1
  4. package/dist/analyzer/__tests__/observability-gap.test.js +40 -10
  5. package/dist/analyzer/__tests__/observability-gap.test.js.map +1 -1
  6. package/dist/analyzer/index.d.ts +2 -1
  7. package/dist/analyzer/index.d.ts.map +1 -1
  8. package/dist/analyzer/index.js +1 -1
  9. package/dist/analyzer/index.js.map +1 -1
  10. package/dist/bindings/__tests__/bindings.test.js +20 -5
  11. package/dist/bindings/__tests__/bindings.test.js.map +1 -1
  12. package/dist/bindings/__tests__/claude-workflow.test.js +12 -3
  13. package/dist/bindings/__tests__/claude-workflow.test.js.map +1 -1
  14. package/dist/bindings/__tests__/defaults-agreement.test.d.ts +16 -0
  15. package/dist/bindings/__tests__/defaults-agreement.test.d.ts.map +1 -0
  16. package/dist/bindings/__tests__/defaults-agreement.test.js +80 -0
  17. package/dist/bindings/__tests__/defaults-agreement.test.js.map +1 -0
  18. package/dist/bindings/__tests__/observability.test.js +8 -2
  19. package/dist/bindings/__tests__/observability.test.js.map +1 -1
  20. package/dist/bindings/__tests__/stub-generation.test.js +8 -2
  21. package/dist/bindings/__tests__/stub-generation.test.js.map +1 -1
  22. package/dist/bindings/claude-code.d.ts.map +1 -1
  23. package/dist/bindings/claude-code.js +102 -3
  24. package/dist/bindings/claude-code.js.map +1 -1
  25. package/dist/bindings/claude-workflow.d.ts.map +1 -1
  26. package/dist/bindings/claude-workflow.js +2 -1
  27. package/dist/bindings/claude-workflow.js.map +1 -1
  28. package/dist/bindings/codex.d.ts.map +1 -1
  29. package/dist/bindings/codex.js +6 -2
  30. package/dist/bindings/codex.js.map +1 -1
  31. package/dist/bindings/gemini-cli.d.ts.map +1 -1
  32. package/dist/bindings/gemini-cli.js +2 -1
  33. package/dist/bindings/gemini-cli.js.map +1 -1
  34. package/dist/bindings/kiro.d.ts.map +1 -1
  35. package/dist/bindings/kiro.js +2 -1
  36. package/dist/bindings/kiro.js.map +1 -1
  37. package/dist/bindings/openclaw.d.ts.map +1 -1
  38. package/dist/bindings/openclaw.js +2 -1
  39. package/dist/bindings/openclaw.js.map +1 -1
  40. package/dist/cli/__tests__/cli.test.d.ts +12 -0
  41. package/dist/cli/__tests__/cli.test.d.ts.map +1 -0
  42. package/dist/cli/__tests__/cli.test.js +171 -0
  43. package/dist/cli/__tests__/cli.test.js.map +1 -0
  44. package/dist/cli/index.d.ts +1 -0
  45. package/dist/cli/index.d.ts.map +1 -1
  46. package/dist/cli/index.js +344 -5
  47. package/dist/cli/index.js.map +1 -1
  48. package/dist/docs/content.d.ts.map +1 -1
  49. package/dist/docs/content.js +112 -0
  50. package/dist/docs/content.js.map +1 -1
  51. package/dist/exporters/ascii.d.ts +13 -0
  52. package/dist/exporters/ascii.d.ts.map +1 -0
  53. package/dist/exporters/ascii.js +26 -0
  54. package/dist/exporters/ascii.js.map +1 -0
  55. package/dist/exporters/brief.d.ts +14 -0
  56. package/dist/exporters/brief.d.ts.map +1 -0
  57. package/dist/exporters/brief.js +37 -0
  58. package/dist/exporters/brief.js.map +1 -0
  59. package/dist/exporters/index.d.ts +2 -0
  60. package/dist/exporters/index.d.ts.map +1 -1
  61. package/dist/exporters/index.js +6 -0
  62. package/dist/exporters/index.js.map +1 -1
  63. package/dist/exporters/markdown.d.ts.map +1 -1
  64. package/dist/exporters/markdown.js +2 -1
  65. package/dist/exporters/markdown.js.map +1 -1
  66. package/dist/exporters/mermaid.d.ts.map +1 -1
  67. package/dist/exporters/mermaid.js +2 -1
  68. package/dist/exporters/mermaid.js.map +1 -1
  69. package/dist/import/__tests__/import.test.js +8 -2
  70. package/dist/import/__tests__/import.test.js.map +1 -1
  71. package/dist/parser/__tests__/parser.test.js +1553 -207
  72. package/dist/parser/__tests__/parser.test.js.map +1 -1
  73. package/dist/parser/__tests__/spec-sync.test.d.ts +10 -0
  74. package/dist/parser/__tests__/spec-sync.test.d.ts.map +1 -0
  75. package/dist/parser/__tests__/spec-sync.test.js +60 -0
  76. package/dist/parser/__tests__/spec-sync.test.js.map +1 -0
  77. package/dist/parser/ast.d.ts +39 -0
  78. package/dist/parser/ast.d.ts.map +1 -1
  79. package/dist/parser/index.d.ts +50 -6
  80. package/dist/parser/index.d.ts.map +1 -1
  81. package/dist/parser/index.js +241 -30
  82. package/dist/parser/index.js.map +1 -1
  83. package/dist/parser/validator.d.ts +7 -1
  84. package/dist/parser/validator.d.ts.map +1 -1
  85. package/dist/parser/validator.js +143 -5
  86. package/dist/parser/validator.js.map +1 -1
  87. package/dist/plan/__tests__/brief.test.d.ts +2 -0
  88. package/dist/plan/__tests__/brief.test.d.ts.map +1 -0
  89. package/dist/plan/__tests__/brief.test.js +442 -0
  90. package/dist/plan/__tests__/brief.test.js.map +1 -0
  91. package/dist/plan/brief.d.ts +207 -0
  92. package/dist/plan/brief.d.ts.map +1 -0
  93. package/dist/plan/brief.js +342 -0
  94. package/dist/plan/brief.js.map +1 -0
  95. package/dist/plan/render.d.ts +20 -0
  96. package/dist/plan/render.d.ts.map +1 -0
  97. package/dist/plan/render.js +425 -0
  98. package/dist/plan/render.js.map +1 -0
  99. package/dist/render/__tests__/ascii.test.d.ts +2 -0
  100. package/dist/render/__tests__/ascii.test.d.ts.map +1 -0
  101. package/dist/render/__tests__/ascii.test.js +171 -0
  102. package/dist/render/__tests__/ascii.test.js.map +1 -0
  103. package/dist/render/ascii.d.ts +23 -0
  104. package/dist/render/ascii.d.ts.map +1 -0
  105. package/dist/render/ascii.js +178 -0
  106. package/dist/render/ascii.js.map +1 -0
  107. package/dist/resolve/__tests__/defaults.test.d.ts +2 -0
  108. package/dist/resolve/__tests__/defaults.test.d.ts.map +1 -0
  109. package/dist/resolve/__tests__/defaults.test.js +109 -0
  110. package/dist/resolve/__tests__/defaults.test.js.map +1 -0
  111. package/dist/resolve/__tests__/order.test.d.ts +2 -0
  112. package/dist/resolve/__tests__/order.test.d.ts.map +1 -0
  113. package/dist/resolve/__tests__/order.test.js +238 -0
  114. package/dist/resolve/__tests__/order.test.js.map +1 -0
  115. package/dist/resolve/__tests__/phase.test.d.ts +12 -0
  116. package/dist/resolve/__tests__/phase.test.d.ts.map +1 -0
  117. package/dist/resolve/__tests__/phase.test.js +81 -0
  118. package/dist/resolve/__tests__/phase.test.js.map +1 -0
  119. package/dist/resolve/defaults.d.ts +51 -0
  120. package/dist/resolve/defaults.d.ts.map +1 -0
  121. package/dist/resolve/defaults.js +109 -0
  122. package/dist/resolve/defaults.js.map +1 -0
  123. package/dist/resolve/order.d.ts +73 -0
  124. package/dist/resolve/order.d.ts.map +1 -0
  125. package/dist/resolve/order.js +208 -0
  126. package/dist/resolve/order.js.map +1 -0
  127. package/dist/resolve/phase.d.ts +57 -0
  128. package/dist/resolve/phase.d.ts.map +1 -0
  129. package/dist/resolve/phase.js +60 -0
  130. package/dist/resolve/phase.js.map +1 -0
  131. package/dist/scaffold/__tests__/scaffold.test.js +8 -2
  132. package/dist/scaffold/__tests__/scaffold.test.js.map +1 -1
  133. package/dist/scaffold/__tests__/settings-merge.test.js +95 -0
  134. package/dist/scaffold/__tests__/settings-merge.test.js.map +1 -1
  135. package/dist/scaffold/incremental.d.ts.map +1 -1
  136. package/dist/scaffold/incremental.js +13 -2
  137. package/dist/scaffold/incremental.js.map +1 -1
  138. package/dist/visualizer/__tests__/brain.test.d.ts +2 -0
  139. package/dist/visualizer/__tests__/brain.test.d.ts.map +1 -0
  140. package/dist/visualizer/__tests__/brain.test.js +138 -0
  141. package/dist/visualizer/__tests__/brain.test.js.map +1 -0
  142. package/dist/visualizer/__tests__/topology-brain-link.test.d.ts +2 -0
  143. package/dist/visualizer/__tests__/topology-brain-link.test.d.ts.map +1 -0
  144. package/dist/visualizer/__tests__/topology-brain-link.test.js +56 -0
  145. package/dist/visualizer/__tests__/topology-brain-link.test.js.map +1 -0
  146. package/dist/visualizer/brain.d.ts +97 -0
  147. package/dist/visualizer/brain.d.ts.map +1 -0
  148. package/dist/visualizer/brain.js +473 -0
  149. package/dist/visualizer/brain.js.map +1 -0
  150. package/dist/visualizer/index.d.ts +19 -1
  151. package/dist/visualizer/index.d.ts.map +1 -1
  152. package/dist/visualizer/index.js +26 -11
  153. package/dist/visualizer/index.js.map +1 -1
  154. package/examples/code-review.at +32 -4
  155. package/examples/company-brain-team.at +241 -0
  156. package/examples/company-brain.at +104 -0
  157. package/examples/data-processing.at +33 -4
  158. package/examples/logos/gmail.svg +1 -0
  159. package/examples/logos/slack.svg +1 -0
  160. package/package.json +1 -1
  161. package/spec/grammar.md +55 -3
  162. package/spec/validation.md +103 -35
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Terminal renderer — the human-facing view of a topology.
3
+ *
4
+ * Nothing like this existed in the package. The nearest prior art was
5
+ * `exporters/markdown.ts` `renderFlow()`, a flat edge list with no layout.
6
+ * This ranks by resolved execution order (`../resolve/order`), so what you read
7
+ * is the order the host agent will actually enact — including gates spliced at
8
+ * the position their `after` / `before` names, rather than at Kahn's depth 0.
9
+ *
10
+ * Pure: returns a string, prints nothing, applies no colour. The CLI adds
11
+ * colour; keeping this pure is what makes it testable, which the CLI is not.
12
+ *
13
+ * @module
14
+ */
15
+ import type { TopologyAST } from "../parser/ast.js";
16
+ /**
17
+ * Render a topology as a terminal flow graph plus a roles table.
18
+ *
19
+ * @param ast - A parsed topology.
20
+ * @returns A plain string. No ANSI codes, no trailing newline.
21
+ */
22
+ export declare function renderAscii(ast: TopologyAST): string;
23
+ //# sourceMappingURL=ascii.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ascii.d.ts","sourceRoot":"","sources":["../../src/render/ascii.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAyC,MAAM,kBAAkB,CAAC;AAoK3F;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,CAKpD"}
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Terminal renderer — the human-facing view of a topology.
3
+ *
4
+ * Nothing like this existed in the package. The nearest prior art was
5
+ * `exporters/markdown.ts` `renderFlow()`, a flat edge list with no layout.
6
+ * This ranks by resolved execution order (`../resolve/order`), so what you read
7
+ * is the order the host agent will actually enact — including gates spliced at
8
+ * the position their `after` / `before` names, rather than at Kahn's depth 0.
9
+ *
10
+ * Pure: returns a string, prints nothing, applies no colour. The CLI adds
11
+ * colour; keeping this pure is what makes it testable, which the CLI is not.
12
+ *
13
+ * @module
14
+ */
15
+ import { resolveOrder } from "../resolve/order.js";
16
+ /** Glyph per node kind. Mirrors the shape vocabulary in `exporters/mermaid.ts`. */
17
+ const GLYPH = {
18
+ spawn: "▸",
19
+ action: "▪",
20
+ gate: "◆",
21
+ human: "☰",
22
+ group: "▤",
23
+ };
24
+ /**
25
+ * Edge annotation string. Same field order and spelling as
26
+ * `exporters/markdown.ts` `edgeLabel`, so an edge is never described two
27
+ * different ways across two outputs.
28
+ */
29
+ function edgeLabel(edge) {
30
+ const parts = [];
31
+ if (edge.isError)
32
+ parts.push(edge.errorType ? `error(${edge.errorType})` : "error");
33
+ if (edge.condition)
34
+ parts.push(`when ${edge.condition}`);
35
+ if (edge.maxIterations)
36
+ parts.push(`max ${edge.maxIterations}`);
37
+ if (edge.race)
38
+ parts.push("race");
39
+ if (edge.tolerance != null)
40
+ parts.push(`tolerance: ${edge.tolerance}`);
41
+ if (edge.wait)
42
+ parts.push(`wait ${edge.wait}`);
43
+ if (edge.weight != null)
44
+ parts.push(`weight ${edge.weight}`);
45
+ if (edge.reflection)
46
+ parts.push("reflection");
47
+ return parts.join(", ");
48
+ }
49
+ /** Right-pad to a column width, without truncating content that overflows. */
50
+ function pad(s, w) {
51
+ return s.length >= w ? s : s + " ".repeat(w - s.length);
52
+ }
53
+ function stepAnnotation(step, byId) {
54
+ if (step.kind === "gate") {
55
+ const g = byId.get(step.ids[0]);
56
+ const bits = ["gate"];
57
+ if (g?.behavior)
58
+ bits.push(g.behavior);
59
+ else
60
+ bits.push("blocking");
61
+ if (g?.onFail)
62
+ bits.push(`on-fail: ${g.onFail}`);
63
+ return bits.join(" · ");
64
+ }
65
+ if (step.kind === "spawn") {
66
+ const models = step.ids
67
+ .map((id) => byId.get(id)?.model)
68
+ .filter((m) => !!m);
69
+ const uniq = [...new Set(models)];
70
+ const label = step.ids.length === 1
71
+ ? "agent"
72
+ : step.exclusive
73
+ ? `branch ×${step.ids.length}, exactly one runs`
74
+ : `agent ×${step.ids.length}, parallel`;
75
+ return uniq.length ? `${label} · ${uniq.join(", ")}` : label;
76
+ }
77
+ return step.kind;
78
+ }
79
+ function renderSpine(ast) {
80
+ const byId = new Map(ast.nodes.map((n) => [n.id, n]));
81
+ const { steps, loops, unreachable, orchestrator } = resolveOrder(ast);
82
+ const out = [];
83
+ // Nodes with no edge at all are not a parallel step — they are declared and
84
+ // never wired in. Kahn ranks them all at depth 0, so they used to render as
85
+ // one big "agent ×N, parallel" line that read like real concurrent work.
86
+ const wired = new Set(ast.edges.flatMap((e) => [e.from, e.to]));
87
+ const orphans = ast.nodes
88
+ .filter((n) => n.type !== "orchestrator" && !wired.has(n.id))
89
+ .map((n) => n.id);
90
+ const orphanSet = new Set(orphans);
91
+ const spineSteps = steps
92
+ .map((s) => ({ ...s, ids: s.ids.filter((id) => !orphanSet.has(id)) }))
93
+ .filter((s) => s.ids.length > 0)
94
+ // Renumber: dropping an unwired step must not leave a gap in the column.
95
+ .map((s, i) => ({ ...s, index: i + 1 }));
96
+ if (spineSteps.length === 0) {
97
+ out.push(" (no flow declared)");
98
+ if (orphans.length) {
99
+ out.push("");
100
+ out.push(` declared but not in the flow: ${orphans.join(", ")}`);
101
+ }
102
+ return out;
103
+ }
104
+ // Width of the widest node column, so annotations line up.
105
+ // `∥` is concurrency. An exclusive branch is not concurrent — exactly one of
106
+ // its ids runs — so it gets a different separator and a different glyph.
107
+ const bodies = spineSteps.map((s) => s.ids.join(s.exclusive ? " | " : " ∥ "));
108
+ const width = Math.max(...bodies.map((b) => b.length), 20);
109
+ // Pad the step number to the widest index, not a fixed 2 — at step 100 the
110
+ // column shifted and the whole spine lost alignment.
111
+ const numWidth = String(spineSteps.length).length;
112
+ spineSteps.forEach((step, i) => {
113
+ const glyph = step.exclusive ? "⑂" : (GLYPH[step.kind] ?? "▸");
114
+ const num = String(step.index).padStart(numWidth, " ");
115
+ out.push(` ${num} ${glyph} ${pad(bodies[i], width)} ${stepAnnotation(step, byId)}`);
116
+ if (step.exclusive && step.branchOn) {
117
+ for (const b of step.branchOn) {
118
+ out.push(` ${" ".repeat(numWidth)} ├─ ${b.id} when ${b.condition}`);
119
+ }
120
+ }
121
+ if (i < spineSteps.length - 1)
122
+ out.push(` ${" ".repeat(numWidth)} │`);
123
+ });
124
+ if (loops.length) {
125
+ out.push("");
126
+ for (const l of loops) {
127
+ const edge = ast.edges.find((e) => e.from === l.from && e.to === l.to);
128
+ const label = edge ? edgeLabel(edge) : "";
129
+ out.push(` ↩ ${l.from} → ${l.to}${label ? ` ${label}` : ""}`);
130
+ }
131
+ }
132
+ if (orphans.length) {
133
+ out.push("");
134
+ out.push(` ⚠ declared but not in the flow: ${orphans.join(", ")}`);
135
+ }
136
+ if (unreachable.length) {
137
+ out.push("");
138
+ out.push(` ⚠ unreachable from the entry point: ${unreachable.join(", ")}`);
139
+ }
140
+ if (orchestrator) {
141
+ out.push("");
142
+ out.push(` orchestrator "${orchestrator}" is the host agent — it is not a step.`);
143
+ }
144
+ return out;
145
+ }
146
+ function renderRoles(ast) {
147
+ const agents = ast.nodes.filter((n) => n.type === "agent");
148
+ if (!agents.length)
149
+ return [];
150
+ const rows = agents.map((a) => ({
151
+ id: a.id,
152
+ model: a.model ?? "—",
153
+ reads: a.reads?.length ? String(a.reads.length) : "—",
154
+ writes: a.writes?.length ? String(a.writes.length) : "—",
155
+ role: a.role ?? a.description ?? "—",
156
+ }));
157
+ const wId = Math.max(4, ...rows.map((r) => r.id.length));
158
+ const wModel = Math.max(5, ...rows.map((r) => r.model.length));
159
+ const out = ["", " Roles", ""];
160
+ out.push(` ${pad("id", wId)} ${pad("model", wModel)} in out role`);
161
+ out.push(` ${"─".repeat(wId)} ${"─".repeat(wModel)} ── ─── ${"─".repeat(28)}`);
162
+ for (const r of rows) {
163
+ out.push(` ${pad(r.id, wId)} ${pad(r.model, wModel)} ${pad(r.reads, 2)} ${pad(r.writes, 3)} ${r.role}`);
164
+ }
165
+ return out;
166
+ }
167
+ /**
168
+ * Render a topology as a terminal flow graph plus a roles table.
169
+ *
170
+ * @param ast - A parsed topology.
171
+ * @returns A plain string. No ANSI codes, no trailing newline.
172
+ */
173
+ export function renderAscii(ast) {
174
+ const header = `${ast.topology.name} v${ast.topology.version ?? "0.0.0"}`;
175
+ const patterns = ast.topology.patterns?.length ? ` · ${ast.topology.patterns.join(", ")}` : "";
176
+ return [` ${header}${patterns}`, "", ...renderSpine(ast), ...renderRoles(ast)].join("\n");
177
+ }
178
+ //# sourceMappingURL=ascii.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ascii.js","sourceRoot":"","sources":["../../src/render/ascii.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=defaults.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults.test.d.ts","sourceRoot":"","sources":["../../../src/resolve/__tests__/defaults.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,109 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { readFileSync } from "node:fs";
3
+ import { resolve, dirname } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { parse } from "../../parser/index.js";
6
+ import { resolveDefaults } from "../defaults.js";
7
+ const example = (name) => readFileSync(resolve(dirname(fileURLToPath(import.meta.url)), "../../../examples", name), "utf8");
8
+ const MINIMAL = `topology t : [pipeline] {
9
+ meta {
10
+ version: "1.0.0"
11
+ description: "x"
12
+ }
13
+ agent worker {
14
+ model: sonnet
15
+ description: "w"
16
+ }
17
+ action intake {
18
+ kind: inline
19
+ description: "in"
20
+ }
21
+ flow { intake -> worker }
22
+ }`;
23
+ describe("resolveDefaults", () => {
24
+ it("fills agent.permissions with the SPEC default, not a binding's", () => {
25
+ // The bindings disagree: codex.ts uses "supervised", openclaw.ts uses
26
+ // "auto". spec/grammar.md:1717 says "autonomous". The spec wins here.
27
+ const { ast } = resolveDefaults(parse(MINIMAL));
28
+ const worker = ast.nodes.find((n) => n.id === "worker");
29
+ expect(worker.permissions).toBe("autonomous");
30
+ });
31
+ it("fills concrete agent defaults and leaves 'none' fields undefined", () => {
32
+ const { ast } = resolveDefaults(parse(MINIMAL));
33
+ const worker = ast.nodes.find((n) => n.id === "worker");
34
+ expect(worker.reads).toEqual([]);
35
+ expect(worker.writes).toEqual([]);
36
+ expect(worker.outputs).toEqual({});
37
+ expect(worker.retry).toBe(0);
38
+ expect(worker.background).toBe(false);
39
+ expect(worker.behavior).toBe("blocking");
40
+ // Rows whose spec default is "-- (none)" must stay absent — absence IS
41
+ // their meaning, and inventing a value would change behaviour.
42
+ expect(worker.phase).toBeUndefined();
43
+ expect(worker.prompt).toBeUndefined();
44
+ expect(worker.tools).toBeUndefined();
45
+ expect(worker.isolation).toBeUndefined();
46
+ expect(worker.maxTurns).toBeUndefined();
47
+ });
48
+ it("never overwrites an authored value", () => {
49
+ // NB: fields must be newline-separated. parseFields is line-based, so two
50
+ // fields on one line make the first key swallow the rest of the line.
51
+ const src = MINIMAL.replace('agent worker {\n model: sonnet\n description: "w"\n }', [
52
+ "agent worker {",
53
+ " model: sonnet",
54
+ ' description: "w"',
55
+ " permissions: supervised",
56
+ " retry: 3",
57
+ " }",
58
+ ].join("\n"));
59
+ const { ast, applied } = resolveDefaults(parse(src));
60
+ const worker = ast.nodes.find((n) => n.id === "worker");
61
+ expect(worker.permissions).toBe("supervised");
62
+ expect(worker.retry).toBe(3);
63
+ expect(applied.find((a) => a.node === "worker" && a.field === "permissions")).toBeUndefined();
64
+ expect(applied.find((a) => a.node === "worker" && a.field === "retry")).toBeUndefined();
65
+ });
66
+ it("does not mutate the input AST", () => {
67
+ const original = parse(MINIMAL);
68
+ const before = original.nodes.find((n) => n.id === "worker");
69
+ expect(before.permissions).toBeUndefined();
70
+ resolveDefaults(original);
71
+ expect(before.permissions).toBeUndefined();
72
+ });
73
+ it("reports every field it filled, so a brief can name them", () => {
74
+ const { applied } = resolveDefaults(parse(MINIMAL));
75
+ const workerFields = applied.filter((a) => a.node === "worker").map((a) => a.field);
76
+ expect(workerFields).toContain("permissions");
77
+ expect(workerFields).toContain("mcp-servers");
78
+ // grammar-name spelling, not the AST camelCase key
79
+ expect(workerFields).not.toContain("mcpServers");
80
+ });
81
+ it("resolves gate defaults from the spec", () => {
82
+ const { ast } = resolveDefaults(parse(example("simple-pipeline.at")));
83
+ const gate = ast.nodes.find((n) => n.type === "gate");
84
+ expect(gate.onFail).toBeDefined();
85
+ expect(gate.behavior).toBeDefined();
86
+ expect(gate.retry).toBeDefined();
87
+ });
88
+ it("leaves a real example's authored values intact", () => {
89
+ const raw = parse(example("code-review.at"));
90
+ const { ast } = resolveDefaults(raw);
91
+ const analyzer = ast.nodes.find((n) => n.id === "analyzer");
92
+ expect(analyzer.permissions).toBe("supervised"); // authored
93
+ expect(analyzer.tools).toEqual(["Read", "Grep", "Glob"]); // authored
94
+ expect(analyzer.memory).toEqual([]); // filled
95
+ });
96
+ it("does not hand the caller a reference to the defaults table", () => {
97
+ // Regression: `applied[].value` aliased the module-level table, so mutating
98
+ // a reported value poisoned the default for every later topology in the
99
+ // process.
100
+ const first = resolveDefaults(parse(MINIMAL));
101
+ const reads = first.applied.find((a) => a.field === "reads");
102
+ reads.value.push("POISON");
103
+ const second = resolveDefaults(parse(MINIMAL));
104
+ const worker = second.ast.nodes.find((n) => n.id === "worker");
105
+ expect(worker.reads).toEqual([]);
106
+ expect(second.applied.find((a) => a.field === "reads").value).toEqual([]);
107
+ });
108
+ });
109
+ //# sourceMappingURL=defaults.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults.test.js","sourceRoot":"","sources":["../../../src/resolve/__tests__/defaults.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=order.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"order.test.d.ts","sourceRoot":"","sources":["../../../src/resolve/__tests__/order.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,238 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { readFileSync } from "node:fs";
3
+ import { resolve, dirname } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { parse } from "../../parser/index.js";
6
+ import { computeLayers } from "../../analyzer/index.js";
7
+ import { resolveOrder } from "../order.js";
8
+ const example = (name) => readFileSync(resolve(dirname(fileURLToPath(import.meta.url)), "../../../examples", name), "utf8");
9
+ describe("resolveOrder", () => {
10
+ it("does NOT leave gates at depth 0 the way raw computeLayers does", () => {
11
+ // Regression for the whole reason this module exists. Gates bind by
12
+ // after:/before:, never by edges, so their in-degree is 0 and Kahn ranks
13
+ // them as sources. Measured: `human-approval` lands in layer 0 next to the
14
+ // entry action, which would run a post-review gate before any review.
15
+ const ast = parse(example("code-review.at"));
16
+ const allIds = new Set(ast.nodes.map((n) => n.id));
17
+ const raw = computeLayers(ast.edges, allIds);
18
+ expect(raw[0].nodes).toContain("human-approval");
19
+ const { steps } = resolveOrder(ast);
20
+ const gateStep = steps.find((s) => s.kind === "gate");
21
+ const reviewerStep = steps.find((s) => s.ids.includes("reviewer"));
22
+ expect(gateStep.index).toBeGreaterThan(reviewerStep.index);
23
+ });
24
+ it("splices a gate immediately after its `after` anchor", () => {
25
+ const ast = parse(example("simple-pipeline.at"));
26
+ const { steps } = resolveOrder(ast);
27
+ const writer = steps.find((s) => s.ids.includes("writer"));
28
+ const gate = steps.find((s) => s.ids.includes("quality-check"));
29
+ expect(gate.index).toBe(writer.index + 1);
30
+ expect(gate.depth).toBeNull();
31
+ });
32
+ it("groups a parallel layer into one step", () => {
33
+ const { steps } = resolveOrder(parse(example("code-review.at")));
34
+ const fanout = steps.find((s) => s.ids.length > 1);
35
+ expect(fanout.kind).toBe("spawn");
36
+ expect(fanout.ids.sort()).toEqual(["analyzer", "security-scanner"]);
37
+ });
38
+ it("never mixes node kinds in one step", () => {
39
+ for (const f of ["code-review.at", "simple-pipeline.at", "data-processing.at"]) {
40
+ const ast = parse(example(f));
41
+ const byType = new Map(ast.nodes.map((n) => [n.id, n.type]));
42
+ for (const step of resolveOrder(ast).steps) {
43
+ const types = new Set(step.ids.map((id) => byType.get(id)));
44
+ expect(types.size, `${f} step ${step.index}`).toBe(1);
45
+ }
46
+ }
47
+ });
48
+ it("excludes the orchestrator from steps and names it as the host", () => {
49
+ const { steps, orchestrator } = resolveOrder(parse(example("simple-pipeline.at")));
50
+ expect(orchestrator).toBe("orchestrator");
51
+ expect(steps.some((s) => s.ids.includes("orchestrator"))).toBe(false);
52
+ });
53
+ it("reports every loop with its traversal budget", () => {
54
+ const { loops } = resolveOrder(parse(example("simple-pipeline.at")));
55
+ const revise = loops.find((l) => l.from === "reviewer" && l.to === "writer");
56
+ expect(revise.budget).toBe(2);
57
+ expect(revise.condition).toContain("revise");
58
+ });
59
+ it("numbers steps contiguously from 1", () => {
60
+ const { steps } = resolveOrder(parse(example("code-review.at")));
61
+ expect(steps.map((s) => s.index)).toEqual(steps.map((_, i) => i + 1));
62
+ });
63
+ it("places a gate anchored to nothing resolvable last, rather than dropping it", () => {
64
+ const src = `topology t : [pipeline] {
65
+ meta {
66
+ version: "1.0.0"
67
+ description: "x"
68
+ }
69
+ agent a {
70
+ model: sonnet
71
+ description: "a"
72
+ }
73
+ action intake {
74
+ kind: inline
75
+ description: "in"
76
+ }
77
+ gates {
78
+ gate orphan {
79
+ after: nowhere
80
+ run: "true"
81
+ }
82
+ }
83
+ flow { intake -> a }
84
+ }`;
85
+ const { steps } = resolveOrder(parse(src));
86
+ expect(steps[steps.length - 1].ids).toEqual(["orphan"]);
87
+ });
88
+ const BRANCH = `topology t : [pipeline] {
89
+ meta {
90
+ version: "1.0.0"
91
+ description: "one decision, two exclusive outcomes"
92
+ }
93
+ agent judge {
94
+ model: opus
95
+ description: "j"
96
+ outputs: {
97
+ verdict: pass | fail
98
+ }
99
+ }
100
+ agent onpass {
101
+ model: sonnet
102
+ description: "p"
103
+ }
104
+ agent onfail {
105
+ model: sonnet
106
+ description: "f"
107
+ }
108
+ action i {
109
+ kind: inline
110
+ description: "in"
111
+ }
112
+ flow { i -> judge
113
+ judge -> onpass [when judge.verdict == pass]
114
+ judge -> onfail [when judge.verdict == fail] }
115
+ }`;
116
+ it("marks mutually exclusive branches as exclusive, not parallel", () => {
117
+ // Regression: two conditional outcomes of ONE decision sat at the same
118
+ // depth, so they were reported as a parallel fan-out. The brief then marked
119
+ // them mutually blind and told the host to dispatch BOTH in one message —
120
+ // running every branch of a decision instead of taking one.
121
+ const step = resolveOrder(parse(BRANCH)).steps.find((s) => s.ids.length > 1);
122
+ expect(step.exclusive).toBe(true);
123
+ expect(step.branchOn?.map((b) => b.id).sort()).toEqual(["onfail", "onpass"]);
124
+ for (const b of step.branchOn)
125
+ expect(b.condition).toContain("judge.verdict");
126
+ });
127
+ it("does not mark a genuine parallel fan-out exclusive", () => {
128
+ const step = resolveOrder(parse(example("code-review.at"))).steps.find((s) => s.ids.length > 1);
129
+ expect(step.exclusive).toBe(false);
130
+ });
131
+ it("does not report a forward edge carrying [max N] as a loop", () => {
132
+ // A forward edge may legitimately carry a bound. Treating any [max N] as a
133
+ // back-edge reported straight-line flows as cycles.
134
+ const src = `topology t : [pipeline] {
135
+ meta {
136
+ version: "1.0.0"
137
+ description: "x"
138
+ }
139
+ agent a {
140
+ model: sonnet
141
+ description: "a"
142
+ }
143
+ agent b {
144
+ model: sonnet
145
+ description: "b"
146
+ }
147
+ action i {
148
+ kind: inline
149
+ description: "in"
150
+ }
151
+ flow { i -> a
152
+ a -> b [max 3] }
153
+ }`;
154
+ expect(resolveOrder(parse(src)).loops).toEqual([]);
155
+ });
156
+ it("still reports a real back-edge as a loop, with its budget", () => {
157
+ const { loops } = resolveOrder(parse(example("simple-pipeline.at")));
158
+ expect(loops.length).toBeGreaterThan(0);
159
+ expect(loops.find((l) => l.from === "reviewer" && l.to === "writer").budget).toBe(2);
160
+ });
161
+ it("keeps two gates on the same anchor in declaration order", () => {
162
+ // Regression: each gate spliced at the same index and pushed its
163
+ // predecessor down, so they ran in REVERSE declaration order.
164
+ const src = `topology t : [pipeline] {
165
+ meta {
166
+ version: "1.0.0"
167
+ description: "x"
168
+ }
169
+ agent a {
170
+ model: sonnet
171
+ description: "a"
172
+ }
173
+ agent b {
174
+ model: sonnet
175
+ description: "b"
176
+ }
177
+ action i {
178
+ kind: inline
179
+ description: "in"
180
+ }
181
+ gates {
182
+ gate first {
183
+ after: a
184
+ run: "true"
185
+ }
186
+ gate second {
187
+ after: a
188
+ run: "true"
189
+ }
190
+ }
191
+ flow { i -> a -> b }
192
+ }`;
193
+ const gateSteps = resolveOrder(parse(src))
194
+ .steps.filter((s) => s.kind === "gate")
195
+ .map((s) => s.ids[0]);
196
+ expect(gateSteps).toEqual(["first", "second"]);
197
+ });
198
+ it("places a gate anchored to another gate after it, whatever the declaration order", () => {
199
+ // Regression: gates spliced in declaration order, so a gate whose anchor
200
+ // was declared LATER found nothing, fell through to "runs last", and
201
+ // silently skipped past the step it was meant to guard.
202
+ const src = `topology t : [pipeline] {
203
+ meta {
204
+ version: "1.0.0"
205
+ description: "x"
206
+ }
207
+ agent a {
208
+ model: sonnet
209
+ description: "a"
210
+ }
211
+ agent b {
212
+ model: sonnet
213
+ description: "b"
214
+ }
215
+ action i {
216
+ kind: inline
217
+ description: "in"
218
+ }
219
+ gates {
220
+ gate second {
221
+ after: first
222
+ run: "true"
223
+ }
224
+ gate first {
225
+ after: a
226
+ run: "true"
227
+ }
228
+ }
229
+ flow { i -> a -> b }
230
+ }`;
231
+ const steps = resolveOrder(parse(src)).steps;
232
+ const idx = (id) => steps.findIndex((s) => s.ids.includes(id));
233
+ expect(idx("first")).toBeGreaterThan(idx("a"));
234
+ expect(idx("second")).toBe(idx("first") + 1);
235
+ expect(idx("second")).toBeLessThan(idx("b"));
236
+ });
237
+ });
238
+ //# sourceMappingURL=order.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"order.test.js","sourceRoot":"","sources":["../../../src/resolve/__tests__/order.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * An unphased agent must sort the same way on every target.
3
+ *
4
+ * Regression: six consumers each picked their own sentinel — MAX_SAFE_INTEGER
5
+ * in claude-code and claude-workflow, 999 in gemini-cli, 0 in openclaw, kiro,
6
+ * mermaid and the markdown exporter. So the same topology put an unphased
7
+ * agent LAST on three targets and FIRST on three others. That is exactly the
8
+ * failure "write once, deploy to any platform" exists to prevent, and nothing
9
+ * compared them.
10
+ */
11
+ export {};
12
+ //# sourceMappingURL=phase.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"phase.test.d.ts","sourceRoot":"","sources":["../../../src/resolve/__tests__/phase.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}