agent-relay 4.0.0 → 4.0.2

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 (140) hide show
  1. package/README.md +5 -5
  2. package/bin/agent-relay-broker-darwin-arm64 +0 -0
  3. package/bin/agent-relay-broker-darwin-x64 +0 -0
  4. package/bin/agent-relay-broker-linux-arm64 +0 -0
  5. package/bin/agent-relay-broker-linux-x64 +0 -0
  6. package/dist/index.cjs +1980 -1024
  7. package/dist/src/cli/commands/core.d.ts.map +1 -1
  8. package/dist/src/cli/commands/core.js +4 -3
  9. package/dist/src/cli/commands/core.js.map +1 -1
  10. package/dist/src/cli/commands/on/relayfile-binary.d.ts +2 -0
  11. package/dist/src/cli/commands/on/relayfile-binary.d.ts.map +1 -0
  12. package/dist/src/cli/commands/on/relayfile-binary.js +208 -0
  13. package/dist/src/cli/commands/on/relayfile-binary.js.map +1 -0
  14. package/dist/src/cli/commands/on/start.d.ts.map +1 -1
  15. package/dist/src/cli/commands/on/start.js +62 -26
  16. package/dist/src/cli/commands/on/start.js.map +1 -1
  17. package/dist/src/cli/commands/on/workspace.d.ts.map +1 -1
  18. package/dist/src/cli/commands/on/workspace.js +4 -0
  19. package/dist/src/cli/commands/on/workspace.js.map +1 -1
  20. package/dist/src/cli/commands/on.js +1 -1
  21. package/dist/src/cli/commands/on.js.map +1 -1
  22. package/dist/src/cli/lib/broker-lifecycle.d.ts.map +1 -1
  23. package/dist/src/cli/lib/broker-lifecycle.js +15 -8
  24. package/dist/src/cli/lib/broker-lifecycle.js.map +1 -1
  25. package/dist/src/cli/lib/client-factory.d.ts +2 -2
  26. package/dist/src/cli/lib/client-factory.d.ts.map +1 -1
  27. package/dist/src/cli/lib/client-factory.js.map +1 -1
  28. package/dist/src/cost/pricing.d.ts +18 -0
  29. package/dist/src/cost/pricing.d.ts.map +1 -0
  30. package/dist/src/cost/pricing.js +111 -0
  31. package/dist/src/cost/pricing.js.map +1 -0
  32. package/dist/src/cost/tracker.d.ts +13 -0
  33. package/dist/src/cost/tracker.d.ts.map +1 -0
  34. package/dist/src/cost/tracker.js +152 -0
  35. package/dist/src/cost/tracker.js.map +1 -0
  36. package/dist/src/cost/types.d.ts +23 -0
  37. package/dist/src/cost/types.d.ts.map +1 -0
  38. package/dist/src/cost/types.js +2 -0
  39. package/dist/src/cost/types.js.map +1 -0
  40. package/package.json +10 -10
  41. package/packages/acp-bridge/package.json +2 -2
  42. package/packages/brand/package.json +1 -1
  43. package/packages/cloud/package.json +3 -3
  44. package/packages/config/package.json +1 -1
  45. package/packages/hooks/package.json +4 -4
  46. package/packages/memory/package.json +2 -2
  47. package/packages/openclaw/package.json +2 -2
  48. package/packages/policy/package.json +2 -2
  49. package/packages/sdk/dist/broker-path.d.ts +3 -2
  50. package/packages/sdk/dist/broker-path.d.ts.map +1 -1
  51. package/packages/sdk/dist/broker-path.js +119 -32
  52. package/packages/sdk/dist/broker-path.js.map +1 -1
  53. package/packages/sdk/dist/client.d.ts +12 -2
  54. package/packages/sdk/dist/client.d.ts.map +1 -1
  55. package/packages/sdk/dist/client.js +20 -1
  56. package/packages/sdk/dist/client.js.map +1 -1
  57. package/packages/sdk/dist/index.d.ts +1 -1
  58. package/packages/sdk/dist/index.d.ts.map +1 -1
  59. package/packages/sdk/dist/index.js.map +1 -1
  60. package/packages/sdk/dist/relay.d.ts +2 -1
  61. package/packages/sdk/dist/relay.d.ts.map +1 -1
  62. package/packages/sdk/dist/relay.js +1 -1
  63. package/packages/sdk/dist/relay.js.map +1 -1
  64. package/packages/sdk/dist/workflows/__tests__/channel-messenger.test.d.ts +2 -0
  65. package/packages/sdk/dist/workflows/__tests__/channel-messenger.test.d.ts.map +1 -0
  66. package/packages/sdk/dist/workflows/__tests__/channel-messenger.test.js +117 -0
  67. package/packages/sdk/dist/workflows/__tests__/channel-messenger.test.js.map +1 -0
  68. package/packages/sdk/dist/workflows/__tests__/run-summary-table.test.js +4 -3
  69. package/packages/sdk/dist/workflows/__tests__/run-summary-table.test.js.map +1 -1
  70. package/packages/sdk/dist/workflows/__tests__/step-executor.test.d.ts +2 -0
  71. package/packages/sdk/dist/workflows/__tests__/step-executor.test.d.ts.map +1 -0
  72. package/packages/sdk/dist/workflows/__tests__/step-executor.test.js +378 -0
  73. package/packages/sdk/dist/workflows/__tests__/step-executor.test.js.map +1 -0
  74. package/packages/sdk/dist/workflows/__tests__/template-resolver.test.d.ts +2 -0
  75. package/packages/sdk/dist/workflows/__tests__/template-resolver.test.d.ts.map +1 -0
  76. package/packages/sdk/dist/workflows/__tests__/template-resolver.test.js +145 -0
  77. package/packages/sdk/dist/workflows/__tests__/template-resolver.test.js.map +1 -0
  78. package/packages/sdk/dist/workflows/__tests__/verification.test.d.ts +2 -0
  79. package/packages/sdk/dist/workflows/__tests__/verification.test.d.ts.map +1 -0
  80. package/packages/sdk/dist/workflows/__tests__/verification.test.js +170 -0
  81. package/packages/sdk/dist/workflows/__tests__/verification.test.js.map +1 -0
  82. package/packages/sdk/dist/workflows/builder.d.ts +3 -2
  83. package/packages/sdk/dist/workflows/builder.d.ts.map +1 -1
  84. package/packages/sdk/dist/workflows/builder.js +1 -3
  85. package/packages/sdk/dist/workflows/builder.js.map +1 -1
  86. package/packages/sdk/dist/workflows/channel-messenger.d.ts +28 -0
  87. package/packages/sdk/dist/workflows/channel-messenger.d.ts.map +1 -0
  88. package/packages/sdk/dist/workflows/channel-messenger.js +255 -0
  89. package/packages/sdk/dist/workflows/channel-messenger.js.map +1 -0
  90. package/packages/sdk/dist/workflows/index.d.ts +7 -0
  91. package/packages/sdk/dist/workflows/index.d.ts.map +1 -1
  92. package/packages/sdk/dist/workflows/index.js +7 -0
  93. package/packages/sdk/dist/workflows/index.js.map +1 -1
  94. package/packages/sdk/dist/workflows/process-spawner.d.ts +35 -0
  95. package/packages/sdk/dist/workflows/process-spawner.d.ts.map +1 -0
  96. package/packages/sdk/dist/workflows/process-spawner.js +141 -0
  97. package/packages/sdk/dist/workflows/process-spawner.js.map +1 -0
  98. package/packages/sdk/dist/workflows/run.d.ts +2 -1
  99. package/packages/sdk/dist/workflows/run.d.ts.map +1 -1
  100. package/packages/sdk/dist/workflows/run.js.map +1 -1
  101. package/packages/sdk/dist/workflows/runner.d.ts +6 -6
  102. package/packages/sdk/dist/workflows/runner.d.ts.map +1 -1
  103. package/packages/sdk/dist/workflows/runner.js +443 -719
  104. package/packages/sdk/dist/workflows/runner.js.map +1 -1
  105. package/packages/sdk/dist/workflows/step-executor.d.ts +95 -0
  106. package/packages/sdk/dist/workflows/step-executor.d.ts.map +1 -0
  107. package/packages/sdk/dist/workflows/step-executor.js +393 -0
  108. package/packages/sdk/dist/workflows/step-executor.js.map +1 -0
  109. package/packages/sdk/dist/workflows/template-resolver.d.ts +33 -0
  110. package/packages/sdk/dist/workflows/template-resolver.d.ts.map +1 -0
  111. package/packages/sdk/dist/workflows/template-resolver.js +144 -0
  112. package/packages/sdk/dist/workflows/template-resolver.js.map +1 -0
  113. package/packages/sdk/dist/workflows/verification.d.ts +33 -0
  114. package/packages/sdk/dist/workflows/verification.d.ts.map +1 -0
  115. package/packages/sdk/dist/workflows/verification.js +122 -0
  116. package/packages/sdk/dist/workflows/verification.js.map +1 -0
  117. package/packages/sdk/package.json +2 -2
  118. package/packages/sdk/src/broker-path.ts +136 -30
  119. package/packages/sdk/src/client.ts +37 -3
  120. package/packages/sdk/src/index.ts +1 -0
  121. package/packages/sdk/src/relay.ts +6 -2
  122. package/packages/sdk/src/workflows/__tests__/channel-messenger.test.ts +137 -0
  123. package/packages/sdk/src/workflows/__tests__/run-summary-table.test.ts +4 -3
  124. package/packages/sdk/src/workflows/__tests__/step-executor.test.ts +444 -0
  125. package/packages/sdk/src/workflows/__tests__/template-resolver.test.ts +162 -0
  126. package/packages/sdk/src/workflows/__tests__/verification.test.ts +229 -0
  127. package/packages/sdk/src/workflows/builder.ts +6 -6
  128. package/packages/sdk/src/workflows/channel-messenger.ts +314 -0
  129. package/packages/sdk/src/workflows/index.ts +12 -0
  130. package/packages/sdk/src/workflows/process-spawner.ts +201 -0
  131. package/packages/sdk/src/workflows/run.ts +2 -1
  132. package/packages/sdk/src/workflows/runner.ts +636 -951
  133. package/packages/sdk/src/workflows/step-executor.ts +579 -0
  134. package/packages/sdk/src/workflows/template-resolver.ts +180 -0
  135. package/packages/sdk/src/workflows/verification.ts +184 -0
  136. package/packages/sdk-py/pyproject.toml +1 -1
  137. package/packages/telemetry/package.json +1 -1
  138. package/packages/trajectory/package.json +2 -2
  139. package/packages/user-directory/package.json +2 -2
  140. package/packages/utils/package.json +2 -2
@@ -0,0 +1,378 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { StepExecutor } from '../step-executor.js';
3
+ import { createProcessSpawner } from '../process-spawner.js';
4
+ // ── Helpers ──────────────────────────────────────────────────────────────────
5
+ function makeStep(overrides = {}) {
6
+ return {
7
+ name: 'step-1',
8
+ type: 'deterministic',
9
+ command: 'echo hello',
10
+ ...overrides,
11
+ };
12
+ }
13
+ function makeAgent(overrides = {}) {
14
+ return {
15
+ name: 'worker-1',
16
+ cli: 'claude',
17
+ role: 'specialist',
18
+ ...overrides,
19
+ };
20
+ }
21
+ function mockSpawner(overrides = {}) {
22
+ return {
23
+ spawnShell: vi.fn(async () => ({ output: 'hello\n', exitCode: 0 })),
24
+ spawnAgent: vi.fn(async () => ({ output: 'done', exitCode: 0 })),
25
+ spawnInteractive: vi.fn(async () => ({ output: 'completed', exitCode: 0 })),
26
+ buildCommand: vi.fn(() => ({ bin: 'claude', args: ['--task', 'x'] })),
27
+ ...overrides,
28
+ };
29
+ }
30
+ function makeDeps(overrides = {}) {
31
+ return {
32
+ cwd: '/tmp/test-project',
33
+ runId: 'run-001',
34
+ postToChannel: vi.fn(),
35
+ persistStepRow: vi.fn(),
36
+ persistStepOutput: vi.fn(),
37
+ resolveTemplate: vi.fn((s) => s),
38
+ getStepOutput: vi.fn(() => ''),
39
+ checkAborted: vi.fn(),
40
+ waitIfPaused: vi.fn(async () => { }),
41
+ log: vi.fn(),
42
+ processSpawner: mockSpawner(),
43
+ ...overrides,
44
+ };
45
+ }
46
+ function createExecutor(overrides = {}) {
47
+ return new StepExecutor(makeDeps(overrides));
48
+ }
49
+ // ── 1. Deterministic step execution ──────────────────────────────────────────
50
+ describe('StepExecutor — deterministic steps', () => {
51
+ it('runs a shell command and captures stdout', async () => {
52
+ const executor = createExecutor();
53
+ const step = makeStep({ command: 'echo hello' });
54
+ const result = await executor.executeOne(step, new Map());
55
+ expect(result.status).toBe('completed');
56
+ expect(result.output).toContain('hello');
57
+ expect(result.exitCode).toBe(0);
58
+ });
59
+ it('marks step failed on non-zero exit code', async () => {
60
+ const executor = createExecutor({
61
+ processSpawner: mockSpawner({
62
+ spawnShell: vi.fn(async () => ({ output: 'err', exitCode: 1 })),
63
+ }),
64
+ });
65
+ const step = makeStep({ command: 'false' });
66
+ const result = await executor.executeOne(step, new Map());
67
+ expect(result.status).toBe('failed');
68
+ expect(result.exitCode).toBe(1);
69
+ });
70
+ it('succeeds with non-zero exit when failOnError is false', async () => {
71
+ const executor = createExecutor({
72
+ processSpawner: mockSpawner({
73
+ spawnShell: vi.fn(async () => ({ output: 'warn', exitCode: 1 })),
74
+ }),
75
+ });
76
+ const step = makeStep({ command: 'maybe-fail', failOnError: false });
77
+ const result = await executor.executeOne(step, new Map());
78
+ expect(result.status).toBe('completed');
79
+ });
80
+ });
81
+ // ── 2. Non-interactive agent step ────────────────────────────────────────────
82
+ describe('StepExecutor — non-interactive agent steps', () => {
83
+ it('spawns a codex worker and captures output', async () => {
84
+ const spawner = mockSpawner();
85
+ const executor = createExecutor({ processSpawner: spawner });
86
+ const agent = makeAgent({ cli: 'codex', name: 'codex-worker', interactive: false });
87
+ const step = makeStep({ name: 'codex-step', type: 'agent', agent: 'codex-worker', task: 'Fix the bug', command: undefined });
88
+ const agentMap = new Map([['codex-worker', agent]]);
89
+ const result = await executor.executeOne(step, agentMap);
90
+ expect(spawner.spawnAgent).toHaveBeenCalledWith(agent, 'Fix the bug', expect.objectContaining({ cwd: '/tmp/test-project' }));
91
+ expect(result.status).toBe('completed');
92
+ });
93
+ it('fails when agent is not found in agentMap', async () => {
94
+ const executor = createExecutor();
95
+ const step = makeStep({ name: 'orphan', type: 'agent', agent: 'missing-agent', task: 'Do stuff', command: undefined });
96
+ const result = await executor.executeOne(step, new Map());
97
+ expect(result.status).toBe('failed');
98
+ expect(result.error).toContain('not found');
99
+ });
100
+ });
101
+ // ── 3. Interactive agent step ────────────────────────────────────────────────
102
+ describe('StepExecutor — interactive agent steps', () => {
103
+ it('spawns a claude lead via spawnInteractive', async () => {
104
+ const spawner = mockSpawner();
105
+ const executor = createExecutor({ processSpawner: spawner });
106
+ const agent = makeAgent({ cli: 'claude', name: 'lead-agent' });
107
+ const step = makeStep({ name: 'lead-step', type: 'agent', agent: 'lead-agent', task: 'Coordinate work', command: undefined });
108
+ const agentMap = new Map([['lead-agent', agent]]);
109
+ const result = await executor.executeOne(step, agentMap);
110
+ expect(spawner.spawnInteractive).toHaveBeenCalled();
111
+ expect(result.status).toBe('completed');
112
+ });
113
+ });
114
+ // ── 4. Step timeout handling ─────────────────────────────────────────────────
115
+ describe('StepExecutor — timeout handling', () => {
116
+ it('passes timeoutMs through to process spawner', async () => {
117
+ const spawner = mockSpawner();
118
+ const executor = createExecutor({ processSpawner: spawner });
119
+ const step = makeStep({ command: 'sleep 60', timeoutMs: 5000 });
120
+ await executor.executeOne(step, new Map());
121
+ expect(spawner.spawnShell).toHaveBeenCalledWith('sleep 60', expect.objectContaining({ timeoutMs: 5000 }));
122
+ });
123
+ it('fails step when spawn rejects due to timeout', async () => {
124
+ const executor = createExecutor({
125
+ processSpawner: mockSpawner({
126
+ spawnShell: vi.fn(async () => { throw new Error('Process timed out'); }),
127
+ }),
128
+ });
129
+ const step = makeStep({ command: 'sleep 60', timeoutMs: 100 });
130
+ const result = await executor.executeOne(step, new Map());
131
+ expect(result.status).toBe('failed');
132
+ expect(result.error).toContain('timed out');
133
+ });
134
+ });
135
+ // ── 5. Step dependency resolution (dependsOn) ────────────────────────────────
136
+ describe('StepExecutor — dependency resolution', () => {
137
+ it('returns only steps whose deps are all completed', () => {
138
+ const executor = createExecutor();
139
+ const steps = [
140
+ makeStep({ name: 'a' }),
141
+ makeStep({ name: 'b', dependsOn: ['a'] }),
142
+ makeStep({ name: 'c', dependsOn: ['a', 'b'] }),
143
+ ];
144
+ const statuses = new Map([
145
+ ['a', 'completed'],
146
+ ['b', 'pending'],
147
+ ['c', 'pending'],
148
+ ]);
149
+ const ready = executor.findReady(steps, statuses);
150
+ expect(ready.map((s) => s.name)).toEqual(['b']);
151
+ });
152
+ it('treats skipped deps as satisfied', () => {
153
+ const executor = createExecutor();
154
+ const steps = [
155
+ makeStep({ name: 'a' }),
156
+ makeStep({ name: 'b', dependsOn: ['a'] }),
157
+ ];
158
+ const statuses = new Map([
159
+ ['a', 'skipped'],
160
+ ['b', 'pending'],
161
+ ]);
162
+ const ready = executor.findReady(steps, statuses);
163
+ expect(ready.map((s) => s.name)).toEqual(['b']);
164
+ });
165
+ it('returns steps with no deps when all are pending', () => {
166
+ const executor = createExecutor();
167
+ const steps = [
168
+ makeStep({ name: 'a' }),
169
+ makeStep({ name: 'b', dependsOn: ['a'] }),
170
+ ];
171
+ const statuses = new Map([
172
+ ['a', 'pending'],
173
+ ['b', 'pending'],
174
+ ]);
175
+ const ready = executor.findReady(steps, statuses);
176
+ expect(ready.map((s) => s.name)).toEqual(['a']);
177
+ });
178
+ it('returns nothing when all deps are failed', () => {
179
+ const executor = createExecutor();
180
+ const steps = [
181
+ makeStep({ name: 'a' }),
182
+ makeStep({ name: 'b', dependsOn: ['a'] }),
183
+ ];
184
+ const statuses = new Map([
185
+ ['a', 'failed'],
186
+ ['b', 'pending'],
187
+ ]);
188
+ const ready = executor.findReady(steps, statuses);
189
+ expect(ready.map((s) => s.name)).toEqual([]);
190
+ });
191
+ });
192
+ // ── 6. Step output capture and storage ───────────────────────────────────────
193
+ describe('StepExecutor — output capture', () => {
194
+ it('persists step output after successful completion', async () => {
195
+ const deps = makeDeps();
196
+ const executor = new StepExecutor(deps);
197
+ const step = makeStep({ command: 'echo result-data' });
198
+ await executor.executeOne(step, new Map());
199
+ expect(deps.persistStepOutput).toHaveBeenCalledWith('run-001', 'step-1', expect.stringContaining('hello'));
200
+ });
201
+ it('persists step row status on completion', async () => {
202
+ const deps = makeDeps();
203
+ const executor = new StepExecutor(deps);
204
+ const step = makeStep({ command: 'echo ok' });
205
+ await executor.executeOne(step, new Map());
206
+ expect(deps.persistStepRow).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({ status: 'completed' }));
207
+ });
208
+ it('captures output on failure', async () => {
209
+ const deps = makeDeps({
210
+ processSpawner: mockSpawner({
211
+ spawnShell: vi.fn(async () => ({ output: 'error: not found', exitCode: 1 })),
212
+ }),
213
+ });
214
+ const executor = new StepExecutor(deps);
215
+ const step = makeStep({ command: 'bad-command' });
216
+ const result = await executor.executeOne(step, new Map());
217
+ expect(result.output).toContain('error: not found');
218
+ });
219
+ it('suppresses output when captureOutput is false', async () => {
220
+ const executor = createExecutor();
221
+ const step = makeStep({ command: 'echo secret', captureOutput: false });
222
+ const result = await executor.executeOne(step, new Map());
223
+ expect(result.output).toContain('Command completed');
224
+ expect(result.output).not.toContain('hello');
225
+ });
226
+ });
227
+ // ── 7. Step retry on failure ─────────────────────────────────────────────────
228
+ describe('StepExecutor — retry logic', () => {
229
+ // Note: monitorStep retries on thrown errors (spawn failures), not on non-zero exit codes.
230
+ // Non-zero exit codes are handled by toCompletionResult and produce immediate failure.
231
+ it('retries when spawn throws an error', async () => {
232
+ let attempt = 0;
233
+ const executor = createExecutor({
234
+ processSpawner: mockSpawner({
235
+ spawnShell: vi.fn(async () => {
236
+ attempt++;
237
+ if (attempt < 3)
238
+ throw new Error('connection refused');
239
+ return { output: 'ok', exitCode: 0 };
240
+ }),
241
+ }),
242
+ });
243
+ const step = makeStep({ command: 'flaky', retries: 3 });
244
+ const result = await executor.executeOne(step, new Map());
245
+ expect(result.status).toBe('completed');
246
+ expect(result.retries).toBe(2);
247
+ });
248
+ it('fails after exhausting retries on thrown errors', async () => {
249
+ const executor = createExecutor({
250
+ processSpawner: mockSpawner({
251
+ spawnShell: vi.fn(async () => { throw new Error('always fails'); }),
252
+ }),
253
+ });
254
+ const step = makeStep({ command: 'always-fail', retries: 2 });
255
+ const result = await executor.executeOne(step, new Map());
256
+ expect(result.status).toBe('failed');
257
+ expect(result.retries).toBe(2);
258
+ expect(result.error).toContain('always fails');
259
+ });
260
+ it('does not retry on non-zero exit code (immediate failure)', async () => {
261
+ const spawnShell = vi.fn(async () => ({ output: 'fail', exitCode: 1 }));
262
+ const executor = createExecutor({
263
+ processSpawner: mockSpawner({ spawnShell }),
264
+ });
265
+ const step = makeStep({ command: 'bad', retries: 3 });
266
+ const result = await executor.executeOne(step, new Map());
267
+ expect(result.status).toBe('failed');
268
+ // Called only once — no retries for clean non-zero exits
269
+ expect(spawnShell).toHaveBeenCalledTimes(1);
270
+ });
271
+ it('calls onStepRetried callback on each retry', async () => {
272
+ const onStepRetried = vi.fn();
273
+ let attempt = 0;
274
+ const executor = createExecutor({
275
+ onStepRetried,
276
+ processSpawner: mockSpawner({
277
+ spawnShell: vi.fn(async () => {
278
+ attempt++;
279
+ if (attempt < 2)
280
+ throw new Error('transient');
281
+ return { output: 'ok', exitCode: 0 };
282
+ }),
283
+ }),
284
+ });
285
+ const step = makeStep({ command: 'flaky', retries: 2 });
286
+ await executor.executeOne(step, new Map());
287
+ expect(onStepRetried).toHaveBeenCalledTimes(1);
288
+ });
289
+ });
290
+ // ── 8. Process spawner — command building ────────────────────────────────────
291
+ describe('ProcessSpawner — buildCommand', () => {
292
+ it('builds claude CLI command', () => {
293
+ const spawner = createProcessSpawner({ cwd: '/tmp' });
294
+ const agent = makeAgent({ cli: 'claude', name: 'claude-worker' });
295
+ const cmd = spawner.buildCommand(agent, 'Do the task');
296
+ expect(cmd.bin).toBe('claude');
297
+ expect(cmd.args).toContain('Do the task');
298
+ });
299
+ it('builds codex CLI command', () => {
300
+ const spawner = createProcessSpawner({ cwd: '/tmp' });
301
+ const agent = makeAgent({ cli: 'codex', name: 'codex-worker' });
302
+ const cmd = spawner.buildCommand(agent, 'Fix bug');
303
+ expect(cmd.bin).toBe('codex');
304
+ expect(cmd.args).toContain('Fix bug');
305
+ });
306
+ it('builds aider CLI command', () => {
307
+ const spawner = createProcessSpawner({ cwd: '/tmp' });
308
+ const agent = makeAgent({ cli: 'aider', name: 'aider-worker' });
309
+ const cmd = spawner.buildCommand(agent, 'Refactor');
310
+ expect(cmd.bin).toBe('aider');
311
+ expect(cmd.args).toContain('Refactor');
312
+ });
313
+ it('builds gemini CLI command', () => {
314
+ const spawner = createProcessSpawner({ cwd: '/tmp' });
315
+ const agent = makeAgent({ cli: 'gemini', name: 'gemini-worker' });
316
+ const cmd = spawner.buildCommand(agent, 'Analyze');
317
+ expect(cmd.bin).toBe('gemini');
318
+ expect(cmd.args).toContain('Analyze');
319
+ });
320
+ });
321
+ // ── 9. executeAll — DAG orchestration ────────────────────────────────────────
322
+ describe('StepExecutor — executeAll', () => {
323
+ it('executes steps in dependency order', async () => {
324
+ const order = [];
325
+ const executor = createExecutor({
326
+ processSpawner: mockSpawner({
327
+ spawnShell: vi.fn(async () => {
328
+ return { output: 'ok', exitCode: 0 };
329
+ }),
330
+ }),
331
+ onStepStarted: vi.fn((step) => { order.push(step.name); }),
332
+ });
333
+ const steps = [
334
+ makeStep({ name: 'a', command: 'echo a' }),
335
+ makeStep({ name: 'b', command: 'echo b', dependsOn: ['a'] }),
336
+ ];
337
+ const results = await executor.executeAll(steps, new Map());
338
+ expect(results.size).toBe(2);
339
+ expect(order).toEqual(['a', 'b']);
340
+ expect(results.get('a')?.status).toBe('completed');
341
+ expect(results.get('b')?.status).toBe('completed');
342
+ });
343
+ it('skips downstream steps on fail-fast', async () => {
344
+ const executor = createExecutor({
345
+ processSpawner: mockSpawner({
346
+ spawnShell: vi.fn(async () => ({ output: 'err', exitCode: 1 })),
347
+ }),
348
+ markDownstreamSkipped: vi.fn(),
349
+ });
350
+ const steps = [
351
+ makeStep({ name: 'a', command: 'fail' }),
352
+ makeStep({ name: 'b', command: 'echo b', dependsOn: ['a'] }),
353
+ ];
354
+ await expect(executor.executeAll(steps, new Map(), { strategy: 'fail-fast' })).rejects.toThrow('Step "a" failed');
355
+ });
356
+ it('continues past failures with continue strategy', async () => {
357
+ let callCount = 0;
358
+ const executor = createExecutor({
359
+ processSpawner: mockSpawner({
360
+ spawnShell: vi.fn(async () => {
361
+ callCount++;
362
+ if (callCount === 1)
363
+ return { output: 'err', exitCode: 1 };
364
+ return { output: 'ok', exitCode: 0 };
365
+ }),
366
+ }),
367
+ markDownstreamSkipped: vi.fn(),
368
+ });
369
+ const steps = [
370
+ makeStep({ name: 'a', command: 'fail' }),
371
+ makeStep({ name: 'c', command: 'echo c' }), // no dependency on a
372
+ ];
373
+ const results = await executor.executeAll(steps, new Map(), { strategy: 'continue' });
374
+ expect(results.get('a')?.status).toBe('failed');
375
+ expect(results.get('c')?.status).toBe('completed');
376
+ });
377
+ });
378
+ //# sourceMappingURL=step-executor.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step-executor.test.js","sourceRoot":"","sources":["../../../src/workflows/__tests__/step-executor.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=template-resolver.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-resolver.test.d.ts","sourceRoot":"","sources":["../../../src/workflows/__tests__/template-resolver.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,145 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ // Import from the module that will be extracted from runner.ts
3
+ import { resolveStepOutputRef, resolveTemplate, TemplateResolver } from '../template-resolver.js';
4
+ describe('TemplateResolver', () => {
5
+ const resolver = new TemplateResolver();
6
+ describe('resolveTemplate', () => {
7
+ it('replaces non-step placeholders and preserves deferred step outputs', () => {
8
+ const result = resolveTemplate('Deploy {{env}} after {{steps.plan.output}}', { env: 'prod' });
9
+ expect(result).toBe('Deploy prod after {{steps.plan.output}}');
10
+ });
11
+ it('throws on unresolved placeholders', () => {
12
+ expect(() => resolveTemplate('Deploy {{missing}}', {})).toThrow('Unresolved variable: {{missing}}');
13
+ });
14
+ });
15
+ describe('resolveStepOutputRef', () => {
16
+ it('resolves a completed step output by reference', () => {
17
+ const stepOutputs = new Map([['plan', 'Build a REST API']]);
18
+ expect(resolveStepOutputRef('steps.plan.output', stepOutputs)).toBe('Build a REST API');
19
+ });
20
+ it('accepts references wrapped in template braces', () => {
21
+ const stepOutputs = new Map([['code', 'Created 3 files']]);
22
+ expect(resolveStepOutputRef('{{steps.code.output}}', stepOutputs)).toBe('Created 3 files');
23
+ });
24
+ });
25
+ describe('resolveVariables', () => {
26
+ it('replaces simple {{var}} placeholders in agent tasks', () => {
27
+ const config = {
28
+ version: '1',
29
+ name: 'test',
30
+ swarm: { mode: 'coordinate' },
31
+ agents: [{ name: 'a1', cli: 'claude', task: 'Deploy {{env}} to {{region}}' }],
32
+ };
33
+ const result = resolver.resolveVariables(config, { env: 'staging', region: 'us-east-1' });
34
+ expect(result.agents[0].task).toBe('Deploy staging to us-east-1');
35
+ });
36
+ it('replaces variables in workflow step tasks and commands', () => {
37
+ const config = {
38
+ version: '1',
39
+ name: 'test',
40
+ swarm: { mode: 'coordinate' },
41
+ agents: [],
42
+ workflows: [
43
+ {
44
+ name: 'wf1',
45
+ steps: [
46
+ { name: 's1', task: 'Build {{project}}', agent: 'a1' },
47
+ { name: 's2', command: 'deploy --env={{env}}' },
48
+ ],
49
+ },
50
+ ],
51
+ };
52
+ const result = resolver.resolveVariables(config, { project: 'relay', env: 'prod' });
53
+ expect(result.workflows[0].steps[0].task).toBe('Build relay');
54
+ expect(result.workflows[0].steps[1].command).toBe('deploy --env=prod');
55
+ });
56
+ it('replaces variables in step params', () => {
57
+ const config = {
58
+ version: '1',
59
+ name: 'test',
60
+ swarm: { mode: 'coordinate' },
61
+ agents: [],
62
+ workflows: [
63
+ {
64
+ name: 'wf1',
65
+ steps: [{ name: 's1', agent: 'a1', params: { url: '{{base_url}}/api', count: 42 } }],
66
+ },
67
+ ],
68
+ };
69
+ const result = resolver.resolveVariables(config, { base_url: 'https://example.com' });
70
+ expect(result.workflows[0].steps[0].params.url).toBe('https://example.com/api');
71
+ // Non-string params are left untouched
72
+ expect(result.workflows[0].steps[0].params.count).toBe(42);
73
+ });
74
+ it('preserves {{steps.X.output}} placeholders for later resolution', () => {
75
+ const config = {
76
+ version: '1',
77
+ name: 'test',
78
+ swarm: { mode: 'coordinate' },
79
+ agents: [{ name: 'a1', cli: 'claude', task: 'Use {{steps.plan.output}} for {{env}}' }],
80
+ };
81
+ const result = resolver.resolveVariables(config, { env: 'prod' });
82
+ expect(result.agents[0].task).toBe('Use {{steps.plan.output}} for prod');
83
+ });
84
+ it('throws on unresolved non-step variables', () => {
85
+ const config = {
86
+ version: '1',
87
+ name: 'test',
88
+ swarm: { mode: 'coordinate' },
89
+ agents: [{ name: 'a1', cli: 'claude', task: 'Deploy to {{missing_var}}' }],
90
+ };
91
+ expect(() => resolver.resolveVariables(config, {})).toThrow('Unresolved variable: {{missing_var}}');
92
+ });
93
+ it('does not mutate the original config', () => {
94
+ const config = {
95
+ version: '1',
96
+ name: 'test',
97
+ swarm: { mode: 'coordinate' },
98
+ agents: [{ name: 'a1', cli: 'claude', task: 'Deploy {{env}}' }],
99
+ };
100
+ resolver.resolveVariables(config, { env: 'staging' });
101
+ expect(config.agents[0].task).toBe('Deploy {{env}}');
102
+ });
103
+ });
104
+ describe('resolveDotPath', () => {
105
+ it('resolves nested dot-path variables', () => {
106
+ const config = {
107
+ version: '1',
108
+ name: 'test',
109
+ swarm: { mode: 'coordinate' },
110
+ agents: [{ name: 'a1', cli: 'claude', task: 'Region: {{aws.region}}' }],
111
+ };
112
+ const vars = { aws: { region: 'us-west-2' } };
113
+ const result = resolver.resolveVariables(config, vars);
114
+ expect(result.agents[0].task).toBe('Region: us-west-2');
115
+ });
116
+ it('throws for undefined nested paths', () => {
117
+ const config = {
118
+ version: '1',
119
+ name: 'test',
120
+ swarm: { mode: 'coordinate' },
121
+ agents: [{ name: 'a1', cli: 'claude', task: '{{a.b.c}}' }],
122
+ };
123
+ expect(() => resolver.resolveVariables(config, { a: { b: {} } })).toThrow('Unresolved variable: {{a.b.c}}');
124
+ });
125
+ });
126
+ describe('interpolateStepTask', () => {
127
+ it('resolves step output references from completed steps', () => {
128
+ const template = 'Review: {{steps.plan.output}} and {{steps.code.output}}';
129
+ const context = {
130
+ steps: {
131
+ plan: { output: 'Build a REST API' },
132
+ code: { output: 'Created 3 files' },
133
+ },
134
+ };
135
+ const result = resolver.interpolateStepTask(template, context);
136
+ expect(result).toBe('Review: Build a REST API and Created 3 files');
137
+ });
138
+ it('leaves unresolved step references intact', () => {
139
+ const template = 'Use {{steps.future.output}} later';
140
+ const result = resolver.interpolateStepTask(template, { steps: {} });
141
+ expect(result).toBe('Use {{steps.future.output}} later');
142
+ });
143
+ });
144
+ });
145
+ //# sourceMappingURL=template-resolver.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-resolver.test.js","sourceRoot":"","sources":["../../../src/workflows/__tests__/template-resolver.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=verification.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verification.test.d.ts","sourceRoot":"","sources":["../../../src/workflows/__tests__/verification.test.ts"],"names":[],"mappings":""}