@relayflows/core 0.0.1 → 1.0.1
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/dist/agent-handle.d.ts +27 -0
- package/dist/agent-handle.d.ts.map +1 -0
- package/dist/agent-handle.js +32 -0
- package/dist/agent-handle.js.map +1 -0
- package/dist/api-executor.d.ts +16 -0
- package/dist/api-executor.d.ts.map +1 -0
- package/dist/api-executor.js +94 -0
- package/dist/api-executor.js.map +1 -0
- package/dist/barrier.d.ts +72 -0
- package/dist/barrier.d.ts.map +1 -0
- package/dist/barrier.js +162 -0
- package/dist/barrier.js.map +1 -0
- package/dist/budget-tracker.d.ts +75 -0
- package/dist/budget-tracker.d.ts.map +1 -0
- package/dist/budget-tracker.js +184 -0
- package/dist/budget-tracker.js.map +1 -0
- package/dist/builder.d.ts +229 -0
- package/dist/builder.d.ts.map +1 -0
- package/dist/builder.js +430 -0
- package/dist/builder.js.map +1 -0
- package/dist/builtin-templates/bug-fix.yaml +139 -0
- package/dist/builtin-templates/code-review.yaml +137 -0
- package/dist/builtin-templates/competitive.yaml +107 -0
- package/dist/builtin-templates/documentation.yaml +128 -0
- package/dist/builtin-templates/feature-dev.yaml +146 -0
- package/dist/builtin-templates/refactor.yaml +145 -0
- package/dist/builtin-templates/review-loop.yaml +227 -0
- package/dist/builtin-templates/security-audit.yaml +139 -0
- package/dist/channel-messenger.d.ts +28 -0
- package/dist/channel-messenger.d.ts.map +1 -0
- package/dist/channel-messenger.js +275 -0
- package/dist/channel-messenger.js.map +1 -0
- package/dist/cli-registry.d.ts +77 -0
- package/dist/cli-registry.d.ts.map +1 -0
- package/dist/cli-registry.js +268 -0
- package/dist/cli-registry.js.map +1 -0
- package/dist/cli-session-collector.d.ts +39 -0
- package/dist/cli-session-collector.d.ts.map +1 -0
- package/dist/cli-session-collector.js +23 -0
- package/dist/cli-session-collector.js.map +1 -0
- package/dist/cli.d.ts +11 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +395 -0
- package/dist/cli.js.map +1 -0
- package/dist/cloud-runner.d.ts +15 -0
- package/dist/cloud-runner.d.ts.map +1 -0
- package/dist/cloud-runner.js +41 -0
- package/dist/cloud-runner.js.map +1 -0
- package/dist/cloud-schedules.d.ts +3 -0
- package/dist/cloud-schedules.d.ts.map +1 -0
- package/dist/cloud-schedules.js +2 -0
- package/dist/cloud-schedules.js.map +1 -0
- package/dist/collectors/claude.d.ts +6 -0
- package/dist/collectors/claude.d.ts.map +1 -0
- package/dist/collectors/claude.js +330 -0
- package/dist/collectors/claude.js.map +1 -0
- package/dist/collectors/codex.d.ts +18 -0
- package/dist/collectors/codex.d.ts.map +1 -0
- package/dist/collectors/codex.js +265 -0
- package/dist/collectors/codex.js.map +1 -0
- package/dist/collectors/opencode.d.ts +6 -0
- package/dist/collectors/opencode.d.ts.map +1 -0
- package/dist/collectors/opencode.js +204 -0
- package/dist/collectors/opencode.js.map +1 -0
- package/dist/coordinator.d.ts +73 -0
- package/dist/coordinator.d.ts.map +1 -0
- package/dist/coordinator.js +647 -0
- package/dist/coordinator.js.map +1 -0
- package/dist/custom-steps.d.ts +73 -0
- package/dist/custom-steps.d.ts.map +1 -0
- package/dist/custom-steps.js +321 -0
- package/dist/custom-steps.js.map +1 -0
- package/dist/default-logger.d.ts +9 -0
- package/dist/default-logger.d.ts.map +1 -0
- package/dist/default-logger.js +104 -0
- package/dist/default-logger.js.map +1 -0
- package/dist/dry-run-format.d.ts +6 -0
- package/dist/dry-run-format.d.ts.map +1 -0
- package/dist/dry-run-format.js +79 -0
- package/dist/dry-run-format.js.map +1 -0
- package/dist/file-db.d.ts +85 -0
- package/dist/file-db.d.ts.map +1 -0
- package/dist/file-db.js +215 -0
- package/dist/file-db.js.map +1 -0
- package/dist/index.d.ts +37 -1
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -3
- package/dist/index.js.map +1 -0
- package/dist/integrations/browser.d.ts +99 -0
- package/dist/integrations/browser.d.ts.map +1 -0
- package/dist/integrations/browser.js +419 -0
- package/dist/integrations/browser.js.map +1 -0
- package/dist/integrations/github.d.ts +79 -0
- package/dist/integrations/github.d.ts.map +1 -0
- package/dist/integrations/github.js +459 -0
- package/dist/integrations/github.js.map +1 -0
- package/dist/integrations/slack.d.ts +80 -0
- package/dist/integrations/slack.d.ts.map +1 -0
- package/dist/integrations/slack.js +355 -0
- package/dist/integrations/slack.js.map +1 -0
- package/dist/listr-renderer.d.ts +26 -0
- package/dist/listr-renderer.d.ts.map +1 -0
- package/dist/listr-renderer.js +230 -0
- package/dist/listr-renderer.js.map +1 -0
- package/dist/memory-db.d.ts +17 -0
- package/dist/memory-db.d.ts.map +1 -0
- package/dist/memory-db.js +33 -0
- package/dist/memory-db.js.map +1 -0
- package/dist/process-backend-executor.d.ts +18 -0
- package/dist/process-backend-executor.d.ts.map +1 -0
- package/dist/process-backend-executor.js +74 -0
- package/dist/process-backend-executor.js.map +1 -0
- package/dist/process-spawner.d.ts +35 -0
- package/dist/process-spawner.d.ts.map +1 -0
- package/dist/process-spawner.js +173 -0
- package/dist/process-spawner.js.map +1 -0
- package/dist/provisioner.d.ts +64 -0
- package/dist/provisioner.d.ts.map +1 -0
- package/dist/provisioner.js +269 -0
- package/dist/provisioner.js.map +1 -0
- package/dist/proxy-env.d.ts +52 -0
- package/dist/proxy-env.d.ts.map +1 -0
- package/dist/proxy-env.js +92 -0
- package/dist/proxy-env.js.map +1 -0
- package/dist/run-script.d.ts +82 -0
- package/dist/run-script.d.ts.map +1 -0
- package/dist/run-script.js +527 -0
- package/dist/run-script.js.map +1 -0
- package/dist/run-summary-table.d.ts +5 -0
- package/dist/run-summary-table.d.ts.map +1 -0
- package/dist/run-summary-table.js +132 -0
- package/dist/run-summary-table.js.map +1 -0
- package/dist/run.d.ts +45 -0
- package/dist/run.d.ts.map +1 -0
- package/dist/run.js +37 -0
- package/dist/run.js.map +1 -0
- package/dist/runner.d.ts +528 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +6269 -0
- package/dist/runner.js.map +1 -0
- package/dist/schema.d.ts +275 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +27 -0
- package/dist/schema.js.map +1 -0
- package/dist/schema.json +940 -0
- package/dist/sibling-links.d.ts +100 -0
- package/dist/sibling-links.d.ts.map +1 -0
- package/dist/sibling-links.js +205 -0
- package/dist/sibling-links.js.map +1 -0
- package/dist/state.d.ts +77 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +140 -0
- package/dist/state.js.map +1 -0
- package/dist/step-executor.d.ts +95 -0
- package/dist/step-executor.d.ts.map +1 -0
- package/dist/step-executor.js +393 -0
- package/dist/step-executor.js.map +1 -0
- package/dist/template-resolver.d.ts +33 -0
- package/dist/template-resolver.d.ts.map +1 -0
- package/dist/template-resolver.js +144 -0
- package/dist/template-resolver.js.map +1 -0
- package/dist/templates.d.ts +47 -0
- package/dist/templates.d.ts.map +1 -0
- package/dist/templates.js +405 -0
- package/dist/templates.js.map +1 -0
- package/dist/trajectory.d.ts +87 -0
- package/dist/trajectory.d.ts.map +1 -0
- package/dist/trajectory.js +412 -0
- package/dist/trajectory.js.map +1 -0
- package/dist/types.d.ts +471 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +37 -0
- package/dist/types.js.map +1 -0
- package/dist/validator.d.ts +11 -0
- package/dist/validator.d.ts.map +1 -0
- package/dist/validator.js +186 -0
- package/dist/validator.js.map +1 -0
- package/dist/verification.d.ts +53 -0
- package/dist/verification.d.ts.map +1 -0
- package/dist/verification.js +238 -0
- package/dist/verification.js.map +1 -0
- package/package.json +12 -8
package/dist/builder.js
ADDED
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { stringify as stringifyYaml } from 'yaml';
|
|
3
|
+
import { JsonFileWorkflowDb } from './file-db.js';
|
|
4
|
+
import { WorkflowRunner } from './runner.js';
|
|
5
|
+
import { formatDryRunReport } from './dry-run-format.js';
|
|
6
|
+
import { createDefaultEventLogger } from './default-logger.js';
|
|
7
|
+
import { runInCloud } from './cloud-runner.js';
|
|
8
|
+
// ── WorkflowBuilder ─────────────────────────────────────────────────────────
|
|
9
|
+
/**
|
|
10
|
+
* Fluent builder for constructing workflow configurations programmatically.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { workflow } from "@relayflows/core";
|
|
15
|
+
*
|
|
16
|
+
* const result = await workflow("my-workflow")
|
|
17
|
+
* .pattern("dag")
|
|
18
|
+
* .agent("worker", { cli: "claude", role: "Backend engineer" })
|
|
19
|
+
* .step("build", { agent: "worker", task: "Build the project" })
|
|
20
|
+
* .step("test", { agent: "worker", task: "Run tests", dependsOn: ["build"] })
|
|
21
|
+
* .run();
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export class WorkflowBuilder {
|
|
25
|
+
_name;
|
|
26
|
+
_description;
|
|
27
|
+
_pattern = 'dag';
|
|
28
|
+
_maxConcurrency;
|
|
29
|
+
_timeoutMs;
|
|
30
|
+
_channel;
|
|
31
|
+
_idleNudge;
|
|
32
|
+
_paths;
|
|
33
|
+
_agents = [];
|
|
34
|
+
_steps = [];
|
|
35
|
+
_errorHandling;
|
|
36
|
+
_coordination;
|
|
37
|
+
_state;
|
|
38
|
+
_trajectories;
|
|
39
|
+
_startFrom;
|
|
40
|
+
_previousRunId;
|
|
41
|
+
constructor(name) {
|
|
42
|
+
this._name = name;
|
|
43
|
+
}
|
|
44
|
+
/** Set workflow description. */
|
|
45
|
+
description(desc) {
|
|
46
|
+
this._description = desc;
|
|
47
|
+
return this;
|
|
48
|
+
}
|
|
49
|
+
/** Set swarm pattern (default: "dag"). */
|
|
50
|
+
pattern(p) {
|
|
51
|
+
this._pattern = p;
|
|
52
|
+
return this;
|
|
53
|
+
}
|
|
54
|
+
/** Set maximum concurrent agents. */
|
|
55
|
+
maxConcurrency(n) {
|
|
56
|
+
this._maxConcurrency = n;
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
59
|
+
/** Set global timeout in milliseconds. */
|
|
60
|
+
timeout(ms) {
|
|
61
|
+
this._timeoutMs = ms;
|
|
62
|
+
return this;
|
|
63
|
+
}
|
|
64
|
+
/** Set the relay channel for agent communication. */
|
|
65
|
+
channel(ch) {
|
|
66
|
+
const CHANNEL_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
67
|
+
if (!CHANNEL_RE.test(ch)) {
|
|
68
|
+
throw new Error(`Invalid channel name "${ch}". Channel names must be lowercase alphanumeric and hyphens, starting with a letter or number. ` +
|
|
69
|
+
`Fix: use .toLowerCase().replace(/[^a-z0-9-]/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '')`);
|
|
70
|
+
}
|
|
71
|
+
this._channel = ch;
|
|
72
|
+
return this;
|
|
73
|
+
}
|
|
74
|
+
/** Configure idle agent detection and nudging for interactive agents. */
|
|
75
|
+
idleNudge(config) {
|
|
76
|
+
this._idleNudge = config;
|
|
77
|
+
return this;
|
|
78
|
+
}
|
|
79
|
+
/** Set workflow coordination settings (barriers, voting threshold, consensus strategy). */
|
|
80
|
+
coordination(config) {
|
|
81
|
+
this._coordination = config;
|
|
82
|
+
return this;
|
|
83
|
+
}
|
|
84
|
+
/** Configure shared workflow state backend settings. */
|
|
85
|
+
state(config) {
|
|
86
|
+
this._state = config;
|
|
87
|
+
return this;
|
|
88
|
+
}
|
|
89
|
+
/** Configure trajectory recording, or pass `false` to disable it. */
|
|
90
|
+
trajectories(config) {
|
|
91
|
+
this._trajectories = config;
|
|
92
|
+
return this;
|
|
93
|
+
}
|
|
94
|
+
/** Start execution from a specific step, skipping all predecessor steps. */
|
|
95
|
+
startFrom(stepName) {
|
|
96
|
+
this._startFrom = stepName;
|
|
97
|
+
return this;
|
|
98
|
+
}
|
|
99
|
+
/** Set the previous run ID whose cached step outputs should be used with startFrom. */
|
|
100
|
+
previousRunId(id) {
|
|
101
|
+
this._previousRunId = id;
|
|
102
|
+
return this;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Declare named paths to additional directories the workflow needs.
|
|
106
|
+
*
|
|
107
|
+
* For multi-repo cloud workflows (relay#774, cloud#302), each entry is
|
|
108
|
+
* tarballed by the CLI at submit time and mounted at
|
|
109
|
+
* `/home/daytona/workspace/{name}/` in the sandbox. Locally, the runner
|
|
110
|
+
* resolves `path` relative to the workflow file's parent directory and
|
|
111
|
+
* agents reference each entry by its declared `name`.
|
|
112
|
+
*
|
|
113
|
+
* Calling this is a no-op for the runtime — the runner doesn't need
|
|
114
|
+
* `paths` to execute steps. The CLI and the cloud bootstrap consume
|
|
115
|
+
* it. Declaring via the builder keeps single-source-of-truth for tools
|
|
116
|
+
* that walk the built config (e.g. dashboards, dry-run reports).
|
|
117
|
+
*/
|
|
118
|
+
paths(paths) {
|
|
119
|
+
if (!Array.isArray(paths)) {
|
|
120
|
+
throw new Error('.paths() expects an array of PathDefinition objects');
|
|
121
|
+
}
|
|
122
|
+
const seen = new Set();
|
|
123
|
+
for (const p of paths) {
|
|
124
|
+
if (!p || typeof p.name !== 'string' || typeof p.path !== 'string') {
|
|
125
|
+
throw new Error('.paths() entries must each have string `name` and `path` fields');
|
|
126
|
+
}
|
|
127
|
+
if (seen.has(p.name)) {
|
|
128
|
+
throw new Error(`.paths() got duplicate entry name "${p.name}"`);
|
|
129
|
+
}
|
|
130
|
+
seen.add(p.name);
|
|
131
|
+
}
|
|
132
|
+
this._paths = paths.map((p) => ({ ...p }));
|
|
133
|
+
return this;
|
|
134
|
+
}
|
|
135
|
+
/** Add an agent definition. */
|
|
136
|
+
agent(name, options) {
|
|
137
|
+
const def = {
|
|
138
|
+
name,
|
|
139
|
+
cli: options.cli,
|
|
140
|
+
};
|
|
141
|
+
if (options.role !== undefined)
|
|
142
|
+
def.role = options.role;
|
|
143
|
+
if (options.task !== undefined)
|
|
144
|
+
def.task = options.task;
|
|
145
|
+
if (options.channels !== undefined)
|
|
146
|
+
def.channels = options.channels;
|
|
147
|
+
if (options.preset !== undefined)
|
|
148
|
+
def.preset = options.preset;
|
|
149
|
+
if (options.interactive !== undefined)
|
|
150
|
+
def.interactive = options.interactive;
|
|
151
|
+
if (options.skills !== undefined)
|
|
152
|
+
def.skills = options.skills;
|
|
153
|
+
if (options.model !== undefined ||
|
|
154
|
+
options.maxTokens !== undefined ||
|
|
155
|
+
options.timeoutMs !== undefined ||
|
|
156
|
+
options.retries !== undefined ||
|
|
157
|
+
options.idleThresholdSecs !== undefined) {
|
|
158
|
+
def.constraints = {};
|
|
159
|
+
if (options.model !== undefined)
|
|
160
|
+
def.constraints.model = options.model;
|
|
161
|
+
if (options.maxTokens !== undefined)
|
|
162
|
+
def.constraints.maxTokens = options.maxTokens;
|
|
163
|
+
if (options.timeoutMs !== undefined)
|
|
164
|
+
def.constraints.timeoutMs = options.timeoutMs;
|
|
165
|
+
if (options.retries !== undefined)
|
|
166
|
+
def.constraints.retries = options.retries;
|
|
167
|
+
if (options.idleThresholdSecs !== undefined)
|
|
168
|
+
def.constraints.idleThresholdSecs = options.idleThresholdSecs;
|
|
169
|
+
}
|
|
170
|
+
this._agents.push(def);
|
|
171
|
+
return this;
|
|
172
|
+
}
|
|
173
|
+
/** Add a workflow step (agent or deterministic). */
|
|
174
|
+
step(name, options) {
|
|
175
|
+
const step = { name };
|
|
176
|
+
if ('type' in options && options.type === 'deterministic') {
|
|
177
|
+
if (!options.command) {
|
|
178
|
+
throw new Error('deterministic steps must have a command');
|
|
179
|
+
}
|
|
180
|
+
if ('agent' in options || 'task' in options) {
|
|
181
|
+
throw new Error('deterministic steps must not have agent or task');
|
|
182
|
+
}
|
|
183
|
+
step.type = 'deterministic';
|
|
184
|
+
step.command = options.command;
|
|
185
|
+
if (options.cwd !== undefined)
|
|
186
|
+
step.cwd = options.cwd;
|
|
187
|
+
if (options.captureOutput !== undefined)
|
|
188
|
+
step.captureOutput = options.captureOutput;
|
|
189
|
+
if (options.failOnError !== undefined)
|
|
190
|
+
step.failOnError = options.failOnError;
|
|
191
|
+
if (options.dependsOn !== undefined)
|
|
192
|
+
step.dependsOn = options.dependsOn;
|
|
193
|
+
if (options.verification !== undefined)
|
|
194
|
+
step.verification = options.verification;
|
|
195
|
+
if (options.timeoutMs !== undefined)
|
|
196
|
+
step.timeoutMs = options.timeoutMs;
|
|
197
|
+
}
|
|
198
|
+
else if ('type' in options && options.type === 'worktree') {
|
|
199
|
+
if ('agent' in options || 'task' in options) {
|
|
200
|
+
throw new Error('worktree steps must not have agent or task');
|
|
201
|
+
}
|
|
202
|
+
step.type = 'worktree';
|
|
203
|
+
step.branch = options.branch;
|
|
204
|
+
if (options.baseBranch !== undefined)
|
|
205
|
+
step.baseBranch = options.baseBranch;
|
|
206
|
+
if (options.path !== undefined)
|
|
207
|
+
step.path = options.path;
|
|
208
|
+
if (options.createBranch !== undefined)
|
|
209
|
+
step.createBranch = options.createBranch;
|
|
210
|
+
if (options.dependsOn !== undefined)
|
|
211
|
+
step.dependsOn = options.dependsOn;
|
|
212
|
+
if (options.timeoutMs !== undefined)
|
|
213
|
+
step.timeoutMs = options.timeoutMs;
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
// Agent step
|
|
217
|
+
const agentOpts = options;
|
|
218
|
+
if (!agentOpts.agent || !agentOpts.task) {
|
|
219
|
+
throw new Error('Agent steps must have both agent and task');
|
|
220
|
+
}
|
|
221
|
+
step.agent = agentOpts.agent;
|
|
222
|
+
step.task = agentOpts.task;
|
|
223
|
+
if (agentOpts.cwd !== undefined)
|
|
224
|
+
step.cwd = agentOpts.cwd;
|
|
225
|
+
if (agentOpts.dependsOn !== undefined)
|
|
226
|
+
step.dependsOn = agentOpts.dependsOn;
|
|
227
|
+
if (agentOpts.verification !== undefined)
|
|
228
|
+
step.verification = agentOpts.verification;
|
|
229
|
+
if (agentOpts.timeoutMs !== undefined)
|
|
230
|
+
step.timeoutMs = agentOpts.timeoutMs;
|
|
231
|
+
if (agentOpts.retries !== undefined)
|
|
232
|
+
step.retries = agentOpts.retries;
|
|
233
|
+
}
|
|
234
|
+
this._steps.push(step);
|
|
235
|
+
return this;
|
|
236
|
+
}
|
|
237
|
+
/** Set error handling strategy. */
|
|
238
|
+
onError(strategy, options) {
|
|
239
|
+
this._errorHandling = { strategy };
|
|
240
|
+
if (options?.maxRetries !== undefined)
|
|
241
|
+
this._errorHandling.maxRetries = options.maxRetries;
|
|
242
|
+
if (options?.retryDelayMs !== undefined)
|
|
243
|
+
this._errorHandling.retryDelayMs = options.retryDelayMs;
|
|
244
|
+
if (options?.notifyChannel !== undefined)
|
|
245
|
+
this._errorHandling.notifyChannel = options.notifyChannel;
|
|
246
|
+
if (options?.repairAgent !== undefined)
|
|
247
|
+
this._errorHandling.repairAgent = options.repairAgent;
|
|
248
|
+
if (options?.repairRetries !== undefined)
|
|
249
|
+
this._errorHandling.repairRetries = options.repairRetries;
|
|
250
|
+
return this;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Opt into the product reliability contract: repairable workflow failures get
|
|
254
|
+
* routed through an agent and retried before the workflow is allowed to fail.
|
|
255
|
+
*/
|
|
256
|
+
repairable(options = {}) {
|
|
257
|
+
return this.onError('retry', {
|
|
258
|
+
maxRetries: options.maxRetries ?? options.repairRetries ?? 2,
|
|
259
|
+
retryDelayMs: options.retryDelayMs ?? 1000,
|
|
260
|
+
notifyChannel: options.notifyChannel,
|
|
261
|
+
repairAgent: options.repairAgent,
|
|
262
|
+
repairRetries: options.repairRetries ?? options.maxRetries ?? 2,
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
/** Alias for `.repairable()` for workflow authors who think in product terms. */
|
|
266
|
+
reliable(options = {}) {
|
|
267
|
+
return this.repairable(options);
|
|
268
|
+
}
|
|
269
|
+
validateBuilderState() {
|
|
270
|
+
const hasAgentSteps = this._steps.some((s) => s.type !== 'deterministic' && s.type !== 'worktree');
|
|
271
|
+
if (hasAgentSteps && this._agents.length === 0) {
|
|
272
|
+
throw new Error('Workflow must have at least one agent when using agent steps');
|
|
273
|
+
}
|
|
274
|
+
if (this._steps.length === 0) {
|
|
275
|
+
throw new Error('Workflow must have at least one step');
|
|
276
|
+
}
|
|
277
|
+
const agentNames = new Set(this._agents.map((agent) => agent.name));
|
|
278
|
+
for (const step of this._steps) {
|
|
279
|
+
const diagnosticAgent = step.verification?.diagnosticAgent;
|
|
280
|
+
if (!diagnosticAgent)
|
|
281
|
+
continue;
|
|
282
|
+
if (!agentNames.has(diagnosticAgent)) {
|
|
283
|
+
throw new Error(`Step "${step.name}" references unknown diagnosticAgent "${diagnosticAgent}"`);
|
|
284
|
+
}
|
|
285
|
+
if (step.retries === undefined || step.retries === 0) {
|
|
286
|
+
console.warn(`Step "${step.name}": diagnosticAgent configured but no retries — diagnostic will never run`);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
/** Build and return the RelayYamlConfig object. */
|
|
291
|
+
toConfig() {
|
|
292
|
+
this.validateBuilderState();
|
|
293
|
+
const wfDef = {
|
|
294
|
+
name: `${this._name}-workflow`,
|
|
295
|
+
steps: [...this._steps],
|
|
296
|
+
};
|
|
297
|
+
const config = {
|
|
298
|
+
version: '1.0',
|
|
299
|
+
name: this._name,
|
|
300
|
+
swarm: {
|
|
301
|
+
pattern: this._pattern,
|
|
302
|
+
},
|
|
303
|
+
agents: [...this._agents],
|
|
304
|
+
workflows: [wfDef],
|
|
305
|
+
};
|
|
306
|
+
if (this._description !== undefined)
|
|
307
|
+
config.description = this._description;
|
|
308
|
+
if (this._paths !== undefined && this._paths.length > 0) {
|
|
309
|
+
config.paths = this._paths.map((p) => ({ ...p }));
|
|
310
|
+
}
|
|
311
|
+
if (this._maxConcurrency !== undefined)
|
|
312
|
+
config.swarm.maxConcurrency = this._maxConcurrency;
|
|
313
|
+
if (this._timeoutMs !== undefined)
|
|
314
|
+
config.swarm.timeoutMs = this._timeoutMs;
|
|
315
|
+
if (this._channel !== undefined)
|
|
316
|
+
config.swarm.channel = this._channel;
|
|
317
|
+
if (this._idleNudge !== undefined)
|
|
318
|
+
config.swarm.idleNudge = this._idleNudge;
|
|
319
|
+
config.errorHandling = this._errorHandling ?? {
|
|
320
|
+
strategy: 'retry',
|
|
321
|
+
maxRetries: 2,
|
|
322
|
+
retryDelayMs: 1000,
|
|
323
|
+
repairRetries: 2,
|
|
324
|
+
};
|
|
325
|
+
if (this._coordination !== undefined)
|
|
326
|
+
config.coordination = this._coordination;
|
|
327
|
+
if (this._state !== undefined)
|
|
328
|
+
config.state = this._state;
|
|
329
|
+
if (this._trajectories !== undefined)
|
|
330
|
+
config.trajectories = this._trajectories;
|
|
331
|
+
return config;
|
|
332
|
+
}
|
|
333
|
+
/** Serialize the config to a YAML string. */
|
|
334
|
+
toYaml() {
|
|
335
|
+
return stringifyYaml(this.toConfig());
|
|
336
|
+
}
|
|
337
|
+
async run(options = {}) {
|
|
338
|
+
const config = this.toConfig();
|
|
339
|
+
const runnerCwd = options.cwd ?? process.cwd();
|
|
340
|
+
const dbPath = path.join(runnerCwd, '.agent-relay', 'workflow-runs.jsonl');
|
|
341
|
+
const db = new JsonFileWorkflowDb(dbPath);
|
|
342
|
+
const runner = new WorkflowRunner({
|
|
343
|
+
cwd: options.cwd,
|
|
344
|
+
relay: options.relay,
|
|
345
|
+
executor: options.executor,
|
|
346
|
+
envSecrets: options.envSecrets,
|
|
347
|
+
db,
|
|
348
|
+
});
|
|
349
|
+
// Auto-detect DRY_RUN env var so existing scripts get dry-run for free
|
|
350
|
+
const isDryRun = options.dryRun ?? !!process.env.DRY_RUN;
|
|
351
|
+
if (isDryRun) {
|
|
352
|
+
const report = runner.dryRun(config, options.workflow, options.vars);
|
|
353
|
+
console.log(formatDryRunReport(report));
|
|
354
|
+
return report;
|
|
355
|
+
}
|
|
356
|
+
// Cloud execution path — submit to remote API and poll for completion
|
|
357
|
+
if (options.cloud) {
|
|
358
|
+
const cloudApiUrl = options.cloudApiUrl ?? process.env.CLOUD_API_URL;
|
|
359
|
+
const cloudApiToken = options.cloudApiToken ?? process.env.CLOUD_API_TOKEN;
|
|
360
|
+
if (!cloudApiUrl)
|
|
361
|
+
throw new Error('cloud: true requires cloudApiUrl or CLOUD_API_URL env var');
|
|
362
|
+
if (!cloudApiToken)
|
|
363
|
+
throw new Error('cloud: true requires cloudApiToken or CLOUD_API_TOKEN env var');
|
|
364
|
+
return runInCloud(config, {
|
|
365
|
+
cloudApiUrl,
|
|
366
|
+
cloudApiToken,
|
|
367
|
+
envSecrets: options.envSecrets,
|
|
368
|
+
pollIntervalMs: options.cloudPollIntervalMs,
|
|
369
|
+
timeoutMs: this._timeoutMs,
|
|
370
|
+
onStatusChange: options.onCloudStatusChange,
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
// Wire up default console logger unless explicitly disabled
|
|
374
|
+
// renderer: "listr" owns the terminal — skip console logger to avoid garbled output
|
|
375
|
+
// renderer: false implies no output at all
|
|
376
|
+
const logLevel = options.renderer === 'listr' || options.renderer === false ? false : (options.logLevel ?? 'normal');
|
|
377
|
+
if (logLevel !== false) {
|
|
378
|
+
runner.on(createDefaultEventLogger(logLevel));
|
|
379
|
+
}
|
|
380
|
+
// Wire up user-provided event handler (additive — does not replace the default logger)
|
|
381
|
+
if (options.onEvent) {
|
|
382
|
+
runner.on(options.onEvent);
|
|
383
|
+
}
|
|
384
|
+
// Auto-detect RESUME_RUN_ID env var for resuming failed runs
|
|
385
|
+
const resumeRunId = process.env.RESUME_RUN_ID;
|
|
386
|
+
const startFrom = this._startFrom ?? options.startFrom ?? process.env.START_FROM;
|
|
387
|
+
const previousRunId = this._previousRunId ?? options.previousRunId ?? process.env.PREVIOUS_RUN_ID;
|
|
388
|
+
const executeOptions = startFrom
|
|
389
|
+
? { startFrom, previousRunId }
|
|
390
|
+
: undefined;
|
|
391
|
+
// If listr renderer requested, wire it up and run concurrently
|
|
392
|
+
// Must be set up BEFORE the resume check so resume runs also get event output
|
|
393
|
+
if (options.renderer === 'listr') {
|
|
394
|
+
const { createWorkflowRenderer } = await import('./listr-renderer.js');
|
|
395
|
+
const renderer = createWorkflowRenderer();
|
|
396
|
+
runner.on(renderer.onEvent);
|
|
397
|
+
const runPromise = resumeRunId
|
|
398
|
+
? runner.resume(resumeRunId, options.vars, config)
|
|
399
|
+
: runner.execute(config, options.workflow, options.vars, executeOptions);
|
|
400
|
+
try {
|
|
401
|
+
const [result] = await Promise.all([runPromise, renderer.start()]);
|
|
402
|
+
return result;
|
|
403
|
+
}
|
|
404
|
+
finally {
|
|
405
|
+
renderer.unmount();
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
if (resumeRunId) {
|
|
409
|
+
return runner.resume(resumeRunId, options.vars, config);
|
|
410
|
+
}
|
|
411
|
+
return runner.execute(config, options.workflow, options.vars, executeOptions);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
// ── Entry point ─────────────────────────────────────────────────────────────
|
|
415
|
+
/**
|
|
416
|
+
* Create a new workflow builder.
|
|
417
|
+
*
|
|
418
|
+
* @example
|
|
419
|
+
* ```typescript
|
|
420
|
+
* const result = await workflow("my-task")
|
|
421
|
+
* .pattern("fan-out")
|
|
422
|
+
* .agent("worker", { cli: "claude" })
|
|
423
|
+
* .step("do-work", { agent: "worker", task: "Build the feature" })
|
|
424
|
+
* .run();
|
|
425
|
+
* ```
|
|
426
|
+
*/
|
|
427
|
+
export function workflow(name) {
|
|
428
|
+
return new WorkflowBuilder(name);
|
|
429
|
+
}
|
|
430
|
+
//# sourceMappingURL=builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builder.js","sourceRoot":"","sources":["../src/builder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
version: '1.0'
|
|
2
|
+
name: bug-fix
|
|
3
|
+
description: 'Blueprint-style bug investigation and remediation with validation gates.'
|
|
4
|
+
swarm:
|
|
5
|
+
pattern: hub-spoke
|
|
6
|
+
maxConcurrency: 2
|
|
7
|
+
timeoutMs: 2700000
|
|
8
|
+
channel: swarm-bug-fix
|
|
9
|
+
idleNudge:
|
|
10
|
+
nudgeAfterMs: 120000
|
|
11
|
+
escalateAfterMs: 120000
|
|
12
|
+
maxNudges: 1
|
|
13
|
+
agents:
|
|
14
|
+
- name: lead
|
|
15
|
+
cli: claude
|
|
16
|
+
role: 'Coordinates debugging and release decisions'
|
|
17
|
+
permissions: { access: full }
|
|
18
|
+
- name: investigator
|
|
19
|
+
cli: codex
|
|
20
|
+
role: 'Reproduces and scopes the defect'
|
|
21
|
+
permissions: { access: readonly }
|
|
22
|
+
interactive: false
|
|
23
|
+
- name: fixer
|
|
24
|
+
cli: codex
|
|
25
|
+
role: 'Implements and tests the fix'
|
|
26
|
+
permissions: { access: readwrite }
|
|
27
|
+
interactive: false
|
|
28
|
+
- name: verifier
|
|
29
|
+
cli: claude
|
|
30
|
+
role: 'Validates risk, regressions, and completion'
|
|
31
|
+
permissions: { access: readonly }
|
|
32
|
+
workflows:
|
|
33
|
+
- name: bug-remediation
|
|
34
|
+
description: 'Investigate root cause, patch safely, and verify no regressions.'
|
|
35
|
+
onError: retry
|
|
36
|
+
preflight:
|
|
37
|
+
- command: git status --porcelain
|
|
38
|
+
failIf: non-empty
|
|
39
|
+
description: 'Ensure working directory is clean'
|
|
40
|
+
- command: npm test 2>/dev/null || echo "baseline"
|
|
41
|
+
description: 'Capture baseline test state'
|
|
42
|
+
steps:
|
|
43
|
+
# Agent: Investigate root cause
|
|
44
|
+
- name: investigate
|
|
45
|
+
type: agent
|
|
46
|
+
agent: investigator
|
|
47
|
+
task: |
|
|
48
|
+
Reproduce the issue, identify root cause, and provide a fix strategy:
|
|
49
|
+
{{task}}
|
|
50
|
+
verification:
|
|
51
|
+
type: output_contains
|
|
52
|
+
value: ROOT_CAUSE_IDENTIFIED
|
|
53
|
+
|
|
54
|
+
# Deterministic: Create fix branch
|
|
55
|
+
- name: create-branch
|
|
56
|
+
type: deterministic
|
|
57
|
+
dependsOn: [investigate]
|
|
58
|
+
command: git checkout -b fix/{{branch-name}}
|
|
59
|
+
|
|
60
|
+
# Agent: Implement the fix
|
|
61
|
+
- name: patch
|
|
62
|
+
type: agent
|
|
63
|
+
agent: fixer
|
|
64
|
+
dependsOn: [create-branch]
|
|
65
|
+
task: |
|
|
66
|
+
Implement the fix based on the investigation report:
|
|
67
|
+
{{steps.investigate.output}}
|
|
68
|
+
retries: 2
|
|
69
|
+
verification:
|
|
70
|
+
type: output_contains
|
|
71
|
+
value: PATCH_APPLIED
|
|
72
|
+
|
|
73
|
+
# Deterministic: Run tests
|
|
74
|
+
- name: test
|
|
75
|
+
type: deterministic
|
|
76
|
+
dependsOn: [patch]
|
|
77
|
+
command: npm test
|
|
78
|
+
|
|
79
|
+
# Agent: Fix test failures if any (with iteration limit)
|
|
80
|
+
- name: fix-if-broken
|
|
81
|
+
type: agent
|
|
82
|
+
agent: fixer
|
|
83
|
+
dependsOn: [test]
|
|
84
|
+
task: |
|
|
85
|
+
Review test results. If tests failed, fix them. If all passed, output TESTS_PASSED.
|
|
86
|
+
Test output: {{steps.test.output}}
|
|
87
|
+
maxIterations: 2
|
|
88
|
+
verification:
|
|
89
|
+
type: output_contains
|
|
90
|
+
value: TESTS_PASSED
|
|
91
|
+
|
|
92
|
+
# Deterministic: Commit
|
|
93
|
+
- name: commit
|
|
94
|
+
type: deterministic
|
|
95
|
+
dependsOn: [fix-if-broken]
|
|
96
|
+
command: 'git add -A && git commit -m "fix: {{steps.investigate.output | first-line}}"'
|
|
97
|
+
|
|
98
|
+
# Agent: Verify no regressions
|
|
99
|
+
- name: regression-check
|
|
100
|
+
type: agent
|
|
101
|
+
agent: verifier
|
|
102
|
+
dependsOn: [commit]
|
|
103
|
+
task: |
|
|
104
|
+
Validate the patch for correctness and regression risk:
|
|
105
|
+
{{steps.patch.output}}
|
|
106
|
+
verification:
|
|
107
|
+
type: output_contains
|
|
108
|
+
value: VERIFICATION_COMPLETE
|
|
109
|
+
|
|
110
|
+
# Deterministic: Push to remote
|
|
111
|
+
- name: push
|
|
112
|
+
type: deterministic
|
|
113
|
+
dependsOn: [regression-check]
|
|
114
|
+
command: git push origin fix/{{branch-name}}
|
|
115
|
+
|
|
116
|
+
# Agent: Closeout
|
|
117
|
+
- name: closeout
|
|
118
|
+
type: agent
|
|
119
|
+
agent: lead
|
|
120
|
+
dependsOn: [push]
|
|
121
|
+
task: |
|
|
122
|
+
Prepare final incident summary, residual risk, and deployment notes.
|
|
123
|
+
verification:
|
|
124
|
+
type: output_contains
|
|
125
|
+
value: DONE
|
|
126
|
+
coordination:
|
|
127
|
+
barriers:
|
|
128
|
+
- name: fix-ready
|
|
129
|
+
waitFor: [investigate, patch, regression-check]
|
|
130
|
+
timeoutMs: 600000
|
|
131
|
+
state:
|
|
132
|
+
backend: memory
|
|
133
|
+
ttlMs: 43200000
|
|
134
|
+
namespace: bug-fix
|
|
135
|
+
errorHandling:
|
|
136
|
+
strategy: retry
|
|
137
|
+
maxRetries: 3
|
|
138
|
+
retryDelayMs: 3000
|
|
139
|
+
notifyChannel: swarm-bug-fix
|