agent-relay 3.1.19 → 3.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -1
- package/bin/agent-relay-broker-darwin-arm64 +0 -0
- package/bin/agent-relay-broker-darwin-x64 +0 -0
- package/bin/agent-relay-broker-linux-arm64 +0 -0
- package/bin/agent-relay-broker-linux-x64 +0 -0
- package/dist/index.cjs +435 -190
- package/dist/src/cli/bootstrap.js +0 -15
- package/dist/src/cli/bootstrap.js.map +1 -1
- package/dist/src/cli/commands/agent-management.d.ts +1 -0
- package/dist/src/cli/commands/agent-management.d.ts.map +1 -1
- package/dist/src/cli/commands/agent-management.js +235 -16
- package/dist/src/cli/commands/agent-management.js.map +1 -1
- package/dist/src/cli/commands/core.js +1 -1
- package/dist/src/cli/commands/core.js.map +1 -1
- package/dist/src/cli/index.d.ts.map +1 -1
- package/dist/src/cli/index.js +13 -1
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/cli/lib/broker-lifecycle.d.ts.map +1 -1
- package/dist/src/cli/lib/broker-lifecycle.js +3 -5
- package/dist/src/cli/lib/broker-lifecycle.js.map +1 -1
- package/dist/src/cli/lib/connect-daytona.js +2 -2
- package/dist/src/cli/lib/connect-daytona.js.map +1 -1
- package/install.sh +9 -3
- package/package.json +13 -13
- package/packages/acp-bridge/package.json +2 -2
- package/packages/config/package.json +1 -1
- package/packages/hooks/package.json +4 -4
- package/packages/memory/package.json +2 -2
- package/packages/openclaw/dist/cli.js +79 -2
- package/packages/openclaw/dist/cli.js.map +1 -1
- package/packages/openclaw/dist/config.d.ts +28 -1
- package/packages/openclaw/dist/config.d.ts.map +1 -1
- package/packages/openclaw/dist/config.js +145 -0
- package/packages/openclaw/dist/config.js.map +1 -1
- package/packages/openclaw/dist/index.d.ts +2 -2
- package/packages/openclaw/dist/index.d.ts.map +1 -1
- package/packages/openclaw/dist/index.js +1 -1
- package/packages/openclaw/dist/index.js.map +1 -1
- package/packages/openclaw/dist/setup.d.ts.map +1 -1
- package/packages/openclaw/dist/setup.js +24 -1
- package/packages/openclaw/dist/setup.js.map +1 -1
- package/packages/openclaw/dist/types.d.ts +23 -0
- package/packages/openclaw/dist/types.d.ts.map +1 -1
- package/packages/openclaw/package.json +2 -2
- package/packages/openclaw/skill/SKILL.md +46 -0
- package/packages/openclaw/src/cli.ts +90 -2
- package/packages/openclaw/src/config.ts +165 -1
- package/packages/openclaw/src/index.ts +7 -1
- package/packages/openclaw/src/setup.ts +26 -1
- package/packages/openclaw/src/types.ts +25 -0
- package/packages/policy/package.json +2 -2
- package/packages/sdk/dist/__tests__/integration.test.js +35 -0
- package/packages/sdk/dist/__tests__/integration.test.js.map +1 -1
- package/packages/sdk/dist/client.d.ts +9 -0
- package/packages/sdk/dist/client.d.ts.map +1 -1
- package/packages/sdk/dist/client.js +33 -22
- package/packages/sdk/dist/client.js.map +1 -1
- package/packages/sdk/dist/protocol.d.ts +1 -0
- package/packages/sdk/dist/protocol.d.ts.map +1 -1
- package/packages/sdk/dist/relay.d.ts +8 -0
- package/packages/sdk/dist/relay.d.ts.map +1 -1
- package/packages/sdk/dist/relay.js +50 -5
- package/packages/sdk/dist/relay.js.map +1 -1
- package/packages/sdk/dist/workflows/cli.js +2 -0
- package/packages/sdk/dist/workflows/cli.js.map +1 -1
- package/packages/sdk/dist/workflows/runner.d.ts +11 -0
- package/packages/sdk/dist/workflows/runner.d.ts.map +1 -1
- package/packages/sdk/dist/workflows/runner.js +350 -167
- package/packages/sdk/dist/workflows/runner.js.map +1 -1
- package/packages/sdk/dist/workflows/trajectory.d.ts +6 -1
- package/packages/sdk/dist/workflows/trajectory.d.ts.map +1 -1
- package/packages/sdk/dist/workflows/trajectory.js +16 -2
- package/packages/sdk/dist/workflows/trajectory.js.map +1 -1
- package/packages/sdk/package.json +2 -2
- package/packages/sdk/src/__tests__/integration.test.ts +49 -0
- package/packages/sdk/src/__tests__/orchestration-upgrades.test.ts +50 -1
- package/packages/sdk/src/client.ts +44 -21
- package/packages/sdk/src/protocol.ts +1 -1
- package/packages/sdk/src/relay.ts +70 -5
- package/packages/sdk/src/workflows/cli.ts +2 -0
- package/packages/sdk/src/workflows/runner.ts +414 -185
- package/packages/sdk/src/workflows/trajectory.ts +22 -2
- package/packages/sdk-py/pyproject.toml +1 -1
- package/packages/sdk-py/src/agent_relay/client.py +18 -1
- package/packages/sdk-py/src/agent_relay/relay.py +4 -0
- package/packages/sdk-py/src/agent_relay/types.py +4 -0
- package/packages/telemetry/package.json +1 -1
- package/packages/trajectory/package.json +2 -2
- package/packages/user-directory/package.json +2 -2
- package/packages/utils/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -9102,7 +9102,8 @@ var AgentRelayClient = class _AgentRelayClient {
|
|
|
9102
9102
|
agent,
|
|
9103
9103
|
...input.task != null ? { initial_task: input.task } : {},
|
|
9104
9104
|
...input.idleThresholdSecs != null ? { idle_threshold_secs: input.idleThresholdSecs } : {},
|
|
9105
|
-
...input.continueFrom != null ? { continue_from: input.continueFrom } : {}
|
|
9105
|
+
...input.continueFrom != null ? { continue_from: input.continueFrom } : {},
|
|
9106
|
+
...input.skipRelayPrompt != null ? { skip_relay_prompt: input.skipRelayPrompt } : {}
|
|
9106
9107
|
});
|
|
9107
9108
|
return result;
|
|
9108
9109
|
}
|
|
@@ -9117,7 +9118,8 @@ var AgentRelayClient = class _AgentRelayClient {
|
|
|
9117
9118
|
};
|
|
9118
9119
|
const result = await this.requestOk("spawn_agent", {
|
|
9119
9120
|
agent,
|
|
9120
|
-
...input.task != null ? { initial_task: input.task } : {}
|
|
9121
|
+
...input.task != null ? { initial_task: input.task } : {},
|
|
9122
|
+
...input.skipRelayPrompt != null ? { skip_relay_prompt: input.skipRelayPrompt } : {}
|
|
9121
9123
|
});
|
|
9122
9124
|
return result;
|
|
9123
9125
|
}
|
|
@@ -9132,7 +9134,8 @@ var AgentRelayClient = class _AgentRelayClient {
|
|
|
9132
9134
|
provider: input.provider,
|
|
9133
9135
|
args: input.args,
|
|
9134
9136
|
channels: input.channels,
|
|
9135
|
-
task: input.task
|
|
9137
|
+
task: input.task,
|
|
9138
|
+
skipRelayPrompt: input.skipRelayPrompt
|
|
9136
9139
|
});
|
|
9137
9140
|
}
|
|
9138
9141
|
return this.spawnPty({
|
|
@@ -9148,7 +9151,8 @@ var AgentRelayClient = class _AgentRelayClient {
|
|
|
9148
9151
|
shadowMode: input.shadowMode,
|
|
9149
9152
|
idleThresholdSecs: input.idleThresholdSecs,
|
|
9150
9153
|
restartPolicy: input.restartPolicy,
|
|
9151
|
-
continueFrom: input.continueFrom
|
|
9154
|
+
continueFrom: input.continueFrom,
|
|
9155
|
+
skipRelayPrompt: input.skipRelayPrompt
|
|
9152
9156
|
});
|
|
9153
9157
|
}
|
|
9154
9158
|
async spawnClaude(input) {
|
|
@@ -9214,25 +9218,35 @@ var AgentRelayClient = class _AgentRelayClient {
|
|
|
9214
9218
|
if (!this.child) {
|
|
9215
9219
|
return;
|
|
9216
9220
|
}
|
|
9217
|
-
|
|
9218
|
-
|
|
9219
|
-
} catch {
|
|
9220
|
-
}
|
|
9221
|
+
void this.requestOk("shutdown", {}).catch(() => {
|
|
9222
|
+
});
|
|
9221
9223
|
const child = this.child;
|
|
9222
9224
|
const wait = this.exitPromise ?? Promise.resolve();
|
|
9223
|
-
const
|
|
9224
|
-
|
|
9225
|
-
|
|
9226
|
-
|
|
9227
|
-
|
|
9228
|
-
|
|
9229
|
-
|
|
9230
|
-
|
|
9231
|
-
|
|
9232
|
-
|
|
9233
|
-
|
|
9234
|
-
|
|
9225
|
+
const waitForExit = async (timeoutMs) => {
|
|
9226
|
+
let timer;
|
|
9227
|
+
const result = await Promise.race([
|
|
9228
|
+
wait.then(() => true),
|
|
9229
|
+
new Promise((resolve3) => {
|
|
9230
|
+
timer = setTimeout(() => resolve3(false), timeoutMs);
|
|
9231
|
+
})
|
|
9232
|
+
]);
|
|
9233
|
+
if (timer !== void 0)
|
|
9234
|
+
clearTimeout(timer);
|
|
9235
|
+
return result;
|
|
9236
|
+
};
|
|
9237
|
+
if (await waitForExit(this.options.shutdownTimeoutMs)) {
|
|
9238
|
+
return;
|
|
9239
|
+
}
|
|
9240
|
+
if (child.exitCode === null && child.signalCode === null) {
|
|
9241
|
+
child.kill("SIGTERM");
|
|
9235
9242
|
}
|
|
9243
|
+
if (await waitForExit(1e3)) {
|
|
9244
|
+
return;
|
|
9245
|
+
}
|
|
9246
|
+
if (child.exitCode === null && child.signalCode === null) {
|
|
9247
|
+
child.kill("SIGKILL");
|
|
9248
|
+
}
|
|
9249
|
+
await waitForExit(1e3);
|
|
9236
9250
|
}
|
|
9237
9251
|
async waitForExit() {
|
|
9238
9252
|
if (!this.child) {
|
|
@@ -9250,8 +9264,7 @@ var AgentRelayClient = class _AgentRelayClient {
|
|
|
9250
9264
|
"init",
|
|
9251
9265
|
"--name",
|
|
9252
9266
|
this.options.brokerName,
|
|
9253
|
-
"--channels",
|
|
9254
|
-
this.options.channels.join(","),
|
|
9267
|
+
...this.options.channels.length > 0 ? ["--channels", this.options.channels.join(",")] : [],
|
|
9255
9268
|
...this.options.binaryArgs
|
|
9256
9269
|
];
|
|
9257
9270
|
const env = { ...this.options.env };
|
|
@@ -9262,7 +9275,7 @@ var AgentRelayClient = class _AgentRelayClient {
|
|
|
9262
9275
|
env.PATH = `${binDir}${import_node_path.default.delimiter}${currentPath}`;
|
|
9263
9276
|
}
|
|
9264
9277
|
}
|
|
9265
|
-
console.
|
|
9278
|
+
console.error(`[broker] Starting: ${resolvedBinary} ${args.join(" ")}`);
|
|
9266
9279
|
const child = (0, import_node_child_process.spawn)(resolvedBinary, args, {
|
|
9267
9280
|
cwd: this.options.cwd,
|
|
9268
9281
|
env,
|
|
@@ -9298,7 +9311,7 @@ var AgentRelayClient = class _AgentRelayClient {
|
|
|
9298
9311
|
});
|
|
9299
9312
|
});
|
|
9300
9313
|
const helloAck = await this.requestHello();
|
|
9301
|
-
console.
|
|
9314
|
+
console.error("[broker] Broker ready (hello handshake complete)");
|
|
9302
9315
|
if (helloAck.workspace_key) {
|
|
9303
9316
|
this.workspaceKey = helloAck.workspace_key;
|
|
9304
9317
|
}
|
|
@@ -45196,7 +45209,7 @@ var AgentRelay = class {
|
|
|
45196
45209
|
this.clientOptions = {
|
|
45197
45210
|
binaryPath: options.binaryPath,
|
|
45198
45211
|
binaryArgs: options.binaryArgs,
|
|
45199
|
-
brokerName: options.brokerName,
|
|
45212
|
+
brokerName: options.brokerName ?? options.workspaceName,
|
|
45200
45213
|
channels: this.defaultChannels,
|
|
45201
45214
|
cwd: options.cwd,
|
|
45202
45215
|
env: options.env,
|
|
@@ -45255,7 +45268,8 @@ var AgentRelay = class {
|
|
|
45255
45268
|
shadowOf: input.shadowOf,
|
|
45256
45269
|
shadowMode: input.shadowMode,
|
|
45257
45270
|
idleThresholdSecs: input.idleThresholdSecs,
|
|
45258
|
-
restartPolicy: input.restartPolicy
|
|
45271
|
+
restartPolicy: input.restartPolicy,
|
|
45272
|
+
skipRelayPrompt: input.skipRelayPrompt
|
|
45259
45273
|
});
|
|
45260
45274
|
} catch (error95) {
|
|
45261
45275
|
await this.invokeLifecycleHook(input.onError, {
|
|
@@ -45288,6 +45302,7 @@ var AgentRelay = class {
|
|
|
45288
45302
|
shadowMode: options?.shadowMode,
|
|
45289
45303
|
idleThresholdSecs: options?.idleThresholdSecs,
|
|
45290
45304
|
restartPolicy: options?.restartPolicy,
|
|
45305
|
+
skipRelayPrompt: options?.skipRelayPrompt,
|
|
45291
45306
|
onStart: options?.onStart,
|
|
45292
45307
|
onSuccess: options?.onSuccess,
|
|
45293
45308
|
onError: options?.onError
|
|
@@ -45597,10 +45612,21 @@ var AgentRelay = class {
|
|
|
45597
45612
|
this.unsubEvent();
|
|
45598
45613
|
this.unsubEvent = void 0;
|
|
45599
45614
|
}
|
|
45600
|
-
|
|
45601
|
-
|
|
45602
|
-
|
|
45615
|
+
let client = this.client;
|
|
45616
|
+
if (!client && this.startPromise) {
|
|
45617
|
+
try {
|
|
45618
|
+
client = await this.startPromise;
|
|
45619
|
+
} catch {
|
|
45620
|
+
client = void 0;
|
|
45621
|
+
}
|
|
45622
|
+
}
|
|
45623
|
+
if (client) {
|
|
45624
|
+
await client.shutdown();
|
|
45625
|
+
if (this.client === client) {
|
|
45626
|
+
this.client = void 0;
|
|
45627
|
+
}
|
|
45603
45628
|
}
|
|
45629
|
+
this.startPromise = void 0;
|
|
45604
45630
|
this.knownAgents.clear();
|
|
45605
45631
|
this.readyAgents.clear();
|
|
45606
45632
|
this.messageReadyAgents.clear();
|
|
@@ -45672,8 +45698,10 @@ var AgentRelay = class {
|
|
|
45672
45698
|
* 4. Auto-create a fresh workspace via the Relaycast REST API
|
|
45673
45699
|
*/
|
|
45674
45700
|
async ensureRelaycastApiKey() {
|
|
45675
|
-
if (this.relayApiKey)
|
|
45701
|
+
if (this.relayApiKey) {
|
|
45702
|
+
this.wireRelaycastBaseUrl();
|
|
45676
45703
|
return;
|
|
45704
|
+
}
|
|
45677
45705
|
const envKey = this.clientOptions.env?.RELAY_API_KEY ?? process.env.RELAY_API_KEY;
|
|
45678
45706
|
if (envKey) {
|
|
45679
45707
|
this.relayApiKey = envKey;
|
|
@@ -45682,11 +45710,19 @@ var AgentRelay = class {
|
|
|
45682
45710
|
} else if (!this.clientOptions.env.RELAY_API_KEY) {
|
|
45683
45711
|
this.clientOptions.env.RELAY_API_KEY = envKey;
|
|
45684
45712
|
}
|
|
45713
|
+
this.wireRelaycastBaseUrl();
|
|
45685
45714
|
return;
|
|
45686
45715
|
}
|
|
45687
45716
|
if (!this.clientOptions.env) {
|
|
45688
45717
|
this.clientOptions.env = { ...process.env };
|
|
45689
45718
|
}
|
|
45719
|
+
this.wireRelaycastBaseUrl();
|
|
45720
|
+
}
|
|
45721
|
+
/** Inject relaycastBaseUrl into broker env. Explicit option wins over inherited env. */
|
|
45722
|
+
wireRelaycastBaseUrl() {
|
|
45723
|
+
if (this.relaycastBaseUrl && this.clientOptions.env) {
|
|
45724
|
+
this.clientOptions.env.RELAYCAST_BASE_URL = this.relaycastBaseUrl;
|
|
45725
|
+
}
|
|
45690
45726
|
}
|
|
45691
45727
|
async ensureStarted() {
|
|
45692
45728
|
if (this.client)
|
|
@@ -45849,12 +45885,31 @@ var AgentRelay = class {
|
|
|
45849
45885
|
name,
|
|
45850
45886
|
reason: releaseOptions.reason
|
|
45851
45887
|
};
|
|
45888
|
+
if (!relay.knownAgents.has(name)) {
|
|
45889
|
+
await relay.invokeLifecycleHook(releaseOptions.onStart, releaseContext, `release("${name}") onStart`);
|
|
45890
|
+
await relay.invokeLifecycleHook(releaseOptions.onSuccess, releaseContext, `release("${name}") onSuccess`);
|
|
45891
|
+
return;
|
|
45892
|
+
}
|
|
45852
45893
|
const client = await relay.ensureStarted();
|
|
45853
45894
|
await relay.invokeLifecycleHook(releaseOptions.onStart, releaseContext, `release("${name}") onStart`);
|
|
45854
45895
|
try {
|
|
45855
45896
|
await client.release(name, releaseOptions.reason);
|
|
45856
45897
|
await relay.invokeLifecycleHook(releaseOptions.onSuccess, releaseContext, `release("${name}") onSuccess`);
|
|
45857
45898
|
} catch (error95) {
|
|
45899
|
+
if (error95 instanceof AgentRelayProtocolError && error95.code === "agent_not_found") {
|
|
45900
|
+
relay.exitedAgents.add(name);
|
|
45901
|
+
relay.readyAgents.delete(name);
|
|
45902
|
+
relay.messageReadyAgents.delete(name);
|
|
45903
|
+
relay.idleAgents.delete(name);
|
|
45904
|
+
relay.knownAgents.delete(name);
|
|
45905
|
+
relay.outputListeners.delete(name);
|
|
45906
|
+
relay.exitResolvers.get(name)?.resolve("released");
|
|
45907
|
+
relay.exitResolvers.delete(name);
|
|
45908
|
+
relay.idleResolvers.get(name)?.resolve("exited");
|
|
45909
|
+
relay.idleResolvers.delete(name);
|
|
45910
|
+
await relay.invokeLifecycleHook(releaseOptions.onSuccess, releaseContext, `release("${name}") onSuccess`);
|
|
45911
|
+
return;
|
|
45912
|
+
}
|
|
45858
45913
|
await relay.invokeLifecycleHook(releaseOptions.onError, {
|
|
45859
45914
|
...releaseContext,
|
|
45860
45915
|
error: error95
|
|
@@ -45996,6 +46051,7 @@ var AgentRelay = class {
|
|
|
45996
46051
|
task,
|
|
45997
46052
|
model: options?.model,
|
|
45998
46053
|
cwd: options?.cwd,
|
|
46054
|
+
skipRelayPrompt: options?.skipRelayPrompt,
|
|
45999
46055
|
onStart: options?.onStart,
|
|
46000
46056
|
onSuccess: options?.onSuccess,
|
|
46001
46057
|
onError: options?.onError
|
|
@@ -46017,7 +46073,8 @@ var AgentRelay = class {
|
|
|
46017
46073
|
transport: "headless",
|
|
46018
46074
|
args,
|
|
46019
46075
|
channels,
|
|
46020
|
-
task
|
|
46076
|
+
task,
|
|
46077
|
+
skipRelayPrompt: options?.skipRelayPrompt
|
|
46021
46078
|
});
|
|
46022
46079
|
} catch (error95) {
|
|
46023
46080
|
await this.invokeLifecycleHook(options?.onError, {
|
|
@@ -47242,7 +47299,7 @@ var WorkflowTrajectory = class {
|
|
|
47242
47299
|
id,
|
|
47243
47300
|
version: 1,
|
|
47244
47301
|
task: {
|
|
47245
|
-
title:
|
|
47302
|
+
title: workflowName,
|
|
47246
47303
|
source: { system: "workflow-runner", id: this.runId }
|
|
47247
47304
|
},
|
|
47248
47305
|
status: "active",
|
|
@@ -47296,6 +47353,8 @@ var WorkflowTrajectory = class {
|
|
|
47296
47353
|
if (participants?.reviewer) {
|
|
47297
47354
|
await this.registerAgent(participants.reviewer, "reviewer");
|
|
47298
47355
|
}
|
|
47356
|
+
this.closeCurrentChapter();
|
|
47357
|
+
this.openChapter(`Execution: ${step.name}`, agent);
|
|
47299
47358
|
const intent = step.task ? step.task.trim().split(/\n|\.(?=\s)/)[0].trim().slice(0, 120) : `${step.type ?? "deterministic"} step`;
|
|
47300
47359
|
this.addEvent("note", `"${step.name}": ${intent}`, void 0, { agent });
|
|
47301
47360
|
await this.flush();
|
|
@@ -47449,12 +47508,24 @@ var WorkflowTrajectory = class {
|
|
|
47449
47508
|
await this.moveToCompleted();
|
|
47450
47509
|
}
|
|
47451
47510
|
/** Abandon the trajectory. */
|
|
47452
|
-
async abandon(reason) {
|
|
47511
|
+
async abandon(reason, meta5) {
|
|
47453
47512
|
if (!this.enabled || !this.trajectory)
|
|
47454
47513
|
return;
|
|
47514
|
+
const elapsed = Date.now() - this.startTime;
|
|
47515
|
+
const elapsedStr = elapsed > 6e4 ? `${Math.round(elapsed / 6e4)} minutes` : `${Math.round(elapsed / 1e3)} seconds`;
|
|
47516
|
+
const summary = meta5?.summary ?? `Workflow abandoned: ${reason}`;
|
|
47517
|
+
this.openRetrospective();
|
|
47518
|
+
this.addEvent("reflection", `${summary} (abandoned after ${elapsedStr})`, "high");
|
|
47455
47519
|
this.addEvent("error", `Workflow abandoned: ${reason}`, "high");
|
|
47456
47520
|
this.trajectory.status = "abandoned";
|
|
47457
47521
|
this.trajectory.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
47522
|
+
this.trajectory.retrospective = {
|
|
47523
|
+
summary,
|
|
47524
|
+
approach: `${this.swarmPattern} workflow (${this.trajectory.agents.filter((a) => a.role !== "workflow-runner").length} agents)`,
|
|
47525
|
+
confidence: meta5?.confidence ?? 0,
|
|
47526
|
+
learnings: meta5?.learnings,
|
|
47527
|
+
challenges: meta5?.challenges
|
|
47528
|
+
};
|
|
47458
47529
|
this.closeCurrentChapter();
|
|
47459
47530
|
await this.flush();
|
|
47460
47531
|
await this.moveToCompleted();
|
|
@@ -47613,6 +47684,16 @@ var WorkflowTrajectory = class {
|
|
|
47613
47684
|
};
|
|
47614
47685
|
|
|
47615
47686
|
// packages/sdk/dist/workflows/runner.js
|
|
47687
|
+
var SpawnExitError = class extends Error {
|
|
47688
|
+
exitCode;
|
|
47689
|
+
exitSignal;
|
|
47690
|
+
constructor(message, exitCode, exitSignal) {
|
|
47691
|
+
super(message);
|
|
47692
|
+
this.name = "SpawnExitError";
|
|
47693
|
+
this.exitCode = exitCode;
|
|
47694
|
+
this.exitSignal = exitSignal ?? void 0;
|
|
47695
|
+
}
|
|
47696
|
+
};
|
|
47616
47697
|
var _resolvedCursorCli;
|
|
47617
47698
|
function resolveCursorCli() {
|
|
47618
47699
|
if (_resolvedCursorCli !== void 0)
|
|
@@ -47656,6 +47737,8 @@ var WorkflowRunner = class _WorkflowRunner {
|
|
|
47656
47737
|
activeAgentHandles = /* @__PURE__ */ new Map();
|
|
47657
47738
|
// PTY-based output capture: accumulate terminal output per-agent
|
|
47658
47739
|
ptyOutputBuffers = /* @__PURE__ */ new Map();
|
|
47740
|
+
/** Snapshot of PTY output from the most recent failed attempt, keyed by step name. */
|
|
47741
|
+
lastFailedStepOutput = /* @__PURE__ */ new Map();
|
|
47659
47742
|
ptyListeners = /* @__PURE__ */ new Map();
|
|
47660
47743
|
ptyLogStreams = /* @__PURE__ */ new Map();
|
|
47661
47744
|
/** Path to workers.json so `agents:kill` can find workflow-spawned agents */
|
|
@@ -48383,7 +48466,10 @@ ${err.suggestion}`);
|
|
|
48383
48466
|
// ── Execution ───────────────────────────────────────────────────────────
|
|
48384
48467
|
/** Execute a named workflow from a validated config. */
|
|
48385
48468
|
async execute(config3, workflowName, vars) {
|
|
48469
|
+
this.abortController = new AbortController();
|
|
48470
|
+
this.paused = false;
|
|
48386
48471
|
const resolved = vars ? this.resolveVariables(config3, vars) : config3;
|
|
48472
|
+
this.validateConfig(resolved);
|
|
48387
48473
|
const pathResult = this.resolvePathDefinitions(resolved.paths, this.cwd);
|
|
48388
48474
|
if (pathResult.errors.length > 0) {
|
|
48389
48475
|
throw new Error(`Path validation failed:
|
|
@@ -48446,6 +48532,8 @@ ${err.suggestion}`);
|
|
|
48446
48532
|
}
|
|
48447
48533
|
/** Resume a previously paused or partially completed run. */
|
|
48448
48534
|
async resume(runId, vars) {
|
|
48535
|
+
this.abortController = new AbortController();
|
|
48536
|
+
this.paused = false;
|
|
48449
48537
|
const run = await this.db.getRun(runId);
|
|
48450
48538
|
if (!run) {
|
|
48451
48539
|
throw new Error(`Run "${runId}" not found`);
|
|
@@ -48492,8 +48580,6 @@ ${err.suggestion}`);
|
|
|
48492
48580
|
async runWorkflowCore(input) {
|
|
48493
48581
|
const { run, workflow: workflow2, config: config3, stepStates, isResume } = input;
|
|
48494
48582
|
const runId = run.id;
|
|
48495
|
-
this.abortController = new AbortController();
|
|
48496
|
-
this.paused = false;
|
|
48497
48583
|
this.currentConfig = config3;
|
|
48498
48584
|
this.currentRunId = runId;
|
|
48499
48585
|
this.runStartTime = Date.now();
|
|
@@ -48517,14 +48603,18 @@ ${err.suggestion}`);
|
|
|
48517
48603
|
config3.swarm.channel = channel;
|
|
48518
48604
|
await this.db.updateRun(runId, { config: config3 });
|
|
48519
48605
|
}
|
|
48520
|
-
|
|
48521
|
-
|
|
48522
|
-
|
|
48523
|
-
|
|
48524
|
-
|
|
48525
|
-
this.
|
|
48526
|
-
this.log(
|
|
48527
|
-
this.
|
|
48606
|
+
const relaycastDisabled = this.relayOptions.env?.AGENT_RELAY_WORKFLOW_DISABLE_RELAYCAST === "1";
|
|
48607
|
+
const requiresBroker = !this.executor && workflow2.steps.some((step) => step.type !== "deterministic" && step.type !== "worktree");
|
|
48608
|
+
if (requiresBroker) {
|
|
48609
|
+
if (!relaycastDisabled) {
|
|
48610
|
+
this.log("Resolving Relaycast API key...");
|
|
48611
|
+
await this.ensureRelaycastApiKey(channel);
|
|
48612
|
+
this.log("API key resolved");
|
|
48613
|
+
if (this.relayApiKeyAutoCreated && this.relayApiKey) {
|
|
48614
|
+
this.log(`Workspace created \u2014 follow this run in Relaycast:`);
|
|
48615
|
+
this.log(` Observer: https://agentrelay.dev/observer?key=${this.relayApiKey}`);
|
|
48616
|
+
this.log(` Channel: ${channel}`);
|
|
48617
|
+
}
|
|
48528
48618
|
}
|
|
48529
48619
|
this.log("Starting broker...");
|
|
48530
48620
|
const brokerBaseName = import_node_path8.default.basename(this.cwd) || "workflow";
|
|
@@ -48532,7 +48622,7 @@ ${err.suggestion}`);
|
|
|
48532
48622
|
this.relay = new AgentRelay({
|
|
48533
48623
|
...this.relayOptions,
|
|
48534
48624
|
brokerName,
|
|
48535
|
-
channels: [channel],
|
|
48625
|
+
channels: relaycastDisabled ? [] : [channel],
|
|
48536
48626
|
env: this.getRelayEnv(),
|
|
48537
48627
|
// Workflows spawn agents across multiple waves; each spawn requires a PTY +
|
|
48538
48628
|
// Relaycast registration. 60s is too tight when the broker is saturated with
|
|
@@ -48580,6 +48670,18 @@ ${err.suggestion}`);
|
|
|
48580
48670
|
}
|
|
48581
48671
|
};
|
|
48582
48672
|
this.relay.onMessageReceived = (msg) => {
|
|
48673
|
+
this.emit({
|
|
48674
|
+
type: "broker:event",
|
|
48675
|
+
runId,
|
|
48676
|
+
event: {
|
|
48677
|
+
kind: "relay_inbound",
|
|
48678
|
+
event_id: msg.eventId,
|
|
48679
|
+
from: msg.from,
|
|
48680
|
+
target: msg.to,
|
|
48681
|
+
body: msg.text,
|
|
48682
|
+
thread_id: msg.threadId
|
|
48683
|
+
}
|
|
48684
|
+
});
|
|
48583
48685
|
const body = msg.text.length > 120 ? msg.text.slice(0, 117) + "..." : msg.text;
|
|
48584
48686
|
const fromShort = msg.from.replace(/-[a-f0-9]{6,}$/, "");
|
|
48585
48687
|
const toShort = msg.to.replace(/-[a-f0-9]{6,}$/, "");
|
|
@@ -48590,18 +48692,59 @@ ${err.suggestion}`);
|
|
|
48590
48692
|
}
|
|
48591
48693
|
};
|
|
48592
48694
|
this.relay.onAgentSpawned = (agent) => {
|
|
48695
|
+
this.emit({
|
|
48696
|
+
type: "broker:event",
|
|
48697
|
+
runId,
|
|
48698
|
+
event: {
|
|
48699
|
+
kind: "agent_spawned",
|
|
48700
|
+
name: agent.name,
|
|
48701
|
+
runtime: agent.runtime
|
|
48702
|
+
}
|
|
48703
|
+
});
|
|
48593
48704
|
if (!this.activeAgentHandles.has(agent.name)) {
|
|
48594
48705
|
this.log(`[spawned] ${agent.name} (${agent.runtime})`);
|
|
48595
48706
|
}
|
|
48596
48707
|
};
|
|
48708
|
+
this.relay.onAgentReleased = (agent) => {
|
|
48709
|
+
this.emit({
|
|
48710
|
+
type: "broker:event",
|
|
48711
|
+
runId,
|
|
48712
|
+
event: {
|
|
48713
|
+
kind: "agent_released",
|
|
48714
|
+
name: agent.name
|
|
48715
|
+
}
|
|
48716
|
+
});
|
|
48717
|
+
};
|
|
48597
48718
|
this.relay.onAgentExited = (agent) => {
|
|
48719
|
+
this.emit({
|
|
48720
|
+
type: "broker:event",
|
|
48721
|
+
runId,
|
|
48722
|
+
event: {
|
|
48723
|
+
kind: "agent_exited",
|
|
48724
|
+
name: agent.name,
|
|
48725
|
+
code: agent.exitCode,
|
|
48726
|
+
signal: agent.exitSignal
|
|
48727
|
+
}
|
|
48728
|
+
});
|
|
48598
48729
|
this.lastActivity.delete(agent.name);
|
|
48599
48730
|
this.lastIdleLog.delete(agent.name);
|
|
48600
48731
|
if (!this.activeAgentHandles.has(agent.name)) {
|
|
48601
48732
|
this.log(`[exited] ${agent.name} (code: ${agent.exitCode ?? "?"})`);
|
|
48602
48733
|
}
|
|
48603
48734
|
};
|
|
48735
|
+
this.relay.onDeliveryUpdate = (event) => {
|
|
48736
|
+
this.emit({ type: "broker:event", runId, event });
|
|
48737
|
+
};
|
|
48604
48738
|
this.relay.onAgentIdle = ({ name, idleSecs }) => {
|
|
48739
|
+
this.emit({
|
|
48740
|
+
type: "broker:event",
|
|
48741
|
+
runId,
|
|
48742
|
+
event: {
|
|
48743
|
+
kind: "agent_idle",
|
|
48744
|
+
name,
|
|
48745
|
+
idle_secs: idleSecs
|
|
48746
|
+
}
|
|
48747
|
+
});
|
|
48605
48748
|
const bucket = Math.floor(idleSecs / 30) * 30;
|
|
48606
48749
|
if (bucket >= 30 && this.lastIdleLog.get(name) !== bucket) {
|
|
48607
48750
|
this.lastIdleLog.set(name, bucket);
|
|
@@ -48614,17 +48757,19 @@ ${err.suggestion}`);
|
|
|
48614
48757
|
this.unsubBrokerStderr = this.relay.onBrokerStderr((line) => {
|
|
48615
48758
|
console.log(`[broker] ${line}`);
|
|
48616
48759
|
});
|
|
48617
|
-
|
|
48618
|
-
|
|
48619
|
-
|
|
48620
|
-
|
|
48621
|
-
|
|
48622
|
-
|
|
48623
|
-
|
|
48624
|
-
|
|
48625
|
-
|
|
48626
|
-
|
|
48627
|
-
|
|
48760
|
+
if (!relaycastDisabled) {
|
|
48761
|
+
this.log(`Creating channel: ${channel}...`);
|
|
48762
|
+
if (isResume) {
|
|
48763
|
+
await this.createAndJoinRelaycastChannel(channel);
|
|
48764
|
+
} else {
|
|
48765
|
+
await this.createAndJoinRelaycastChannel(channel, workflow2.description);
|
|
48766
|
+
}
|
|
48767
|
+
this.log("Channel ready");
|
|
48768
|
+
if (isResume) {
|
|
48769
|
+
this.postToChannel(`Workflow **${workflow2.name}** resumed \u2014 ${pendingCount} pending steps`);
|
|
48770
|
+
} else {
|
|
48771
|
+
this.postToChannel(`Workflow **${workflow2.name}** started \u2014 ${workflow2.steps.length} steps, pattern: ${config3.swarm.pattern}`);
|
|
48772
|
+
}
|
|
48628
48773
|
}
|
|
48629
48774
|
}
|
|
48630
48775
|
const agentMap = /* @__PURE__ */ new Map();
|
|
@@ -48636,7 +48781,9 @@ ${err.suggestion}`);
|
|
|
48636
48781
|
}
|
|
48637
48782
|
this.log(`Executing ${workflow2.steps.length} steps (pattern: ${config3.swarm.pattern})`);
|
|
48638
48783
|
await this.executeSteps(workflow2, stepStates, agentMap, config3.errorHandling, runId);
|
|
48639
|
-
const
|
|
48784
|
+
const errorStrategy = config3.errorHandling?.strategy ?? workflow2.onError ?? "fail-fast";
|
|
48785
|
+
const continueOnError = errorStrategy === "continue" || errorStrategy === "skip";
|
|
48786
|
+
const allCompleted = [...stepStates.values()].every((s) => s.row.status === "completed" || s.row.status === "skipped" || continueOnError && s.row.status === "failed");
|
|
48640
48787
|
if (allCompleted) {
|
|
48641
48788
|
this.log("Workflow completed successfully");
|
|
48642
48789
|
await this.updateRunStatus(runId, "completed");
|
|
@@ -48656,24 +48803,52 @@ ${err.suggestion}`);
|
|
|
48656
48803
|
await this.updateRunStatus(runId, "failed", errorMsg);
|
|
48657
48804
|
this.emit({ type: "run:failed", runId, error: errorMsg });
|
|
48658
48805
|
const outcomes = this.collectOutcomes(stepStates, workflow2.steps);
|
|
48806
|
+
const summary = this.trajectory.buildRunSummary(outcomes);
|
|
48807
|
+
const confidence = this.trajectory.computeConfidence(outcomes);
|
|
48808
|
+
const learnings = this.trajectory.extractLearnings(outcomes);
|
|
48809
|
+
const challenges = this.trajectory.extractChallenges(outcomes);
|
|
48659
48810
|
this.postFailureReport(workflow2.name, outcomes, errorMsg);
|
|
48660
48811
|
this.logRunSummary(workflow2.name, outcomes, runId);
|
|
48661
|
-
await this.trajectory.abandon(errorMsg
|
|
48812
|
+
await this.trajectory.abandon(errorMsg, {
|
|
48813
|
+
summary,
|
|
48814
|
+
confidence,
|
|
48815
|
+
learnings,
|
|
48816
|
+
challenges
|
|
48817
|
+
});
|
|
48662
48818
|
}
|
|
48663
48819
|
} catch (err) {
|
|
48664
48820
|
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
48665
48821
|
const status = !isResume && this.abortController?.signal.aborted ? "cancelled" : "failed";
|
|
48666
48822
|
await this.updateRunStatus(runId, status, errorMsg);
|
|
48667
48823
|
if (status === "cancelled") {
|
|
48824
|
+
for (const [stepName, state] of stepStates) {
|
|
48825
|
+
if (state.row.status === "pending" || state.row.status === "running") {
|
|
48826
|
+
state.row.status = "failed";
|
|
48827
|
+
state.row.error = "Cancelled";
|
|
48828
|
+
await this.db.updateStep(state.row.id, {
|
|
48829
|
+
status: "failed",
|
|
48830
|
+
error: "Cancelled",
|
|
48831
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
48832
|
+
});
|
|
48833
|
+
this.emit({ type: "step:failed", runId, stepName, error: "Cancelled" });
|
|
48834
|
+
}
|
|
48835
|
+
}
|
|
48668
48836
|
this.emit({ type: "run:cancelled", runId });
|
|
48669
48837
|
this.postToChannel(`Workflow **${workflow2.name}** cancelled`);
|
|
48670
48838
|
await this.trajectory.abandon("Cancelled by user");
|
|
48671
48839
|
} else {
|
|
48672
48840
|
this.emit({ type: "run:failed", runId, error: errorMsg });
|
|
48673
48841
|
this.postToChannel(`Workflow failed: ${errorMsg}`);
|
|
48674
|
-
|
|
48842
|
+
const outcomes = this.collectOutcomes(stepStates, workflow2.steps);
|
|
48843
|
+
await this.trajectory.abandon(errorMsg, {
|
|
48844
|
+
summary: this.trajectory.buildRunSummary(outcomes),
|
|
48845
|
+
confidence: this.trajectory.computeConfidence(outcomes),
|
|
48846
|
+
learnings: this.trajectory.extractLearnings(outcomes),
|
|
48847
|
+
challenges: this.trajectory.extractChallenges(outcomes)
|
|
48848
|
+
});
|
|
48675
48849
|
}
|
|
48676
48850
|
} finally {
|
|
48851
|
+
this.lastFailedStepOutput.clear();
|
|
48677
48852
|
for (const stream of this.ptyLogStreams.values())
|
|
48678
48853
|
stream.end();
|
|
48679
48854
|
this.ptyLogStreams.clear();
|
|
@@ -48684,9 +48859,11 @@ ${err.suggestion}`);
|
|
|
48684
48859
|
if (this.relay) {
|
|
48685
48860
|
this.relay.onMessageReceived = null;
|
|
48686
48861
|
this.relay.onAgentSpawned = null;
|
|
48862
|
+
this.relay.onAgentReleased = null;
|
|
48687
48863
|
this.relay.onAgentExited = null;
|
|
48688
48864
|
this.relay.onAgentIdle = null;
|
|
48689
48865
|
this.relay.onWorkerOutput = null;
|
|
48866
|
+
this.relay.onDeliveryUpdate = null;
|
|
48690
48867
|
}
|
|
48691
48868
|
this.lastIdleLog.clear();
|
|
48692
48869
|
this.lastActivity.clear();
|
|
@@ -48907,7 +49084,7 @@ ${trimmedOutput.slice(0, 200)}`);
|
|
|
48907
49084
|
}
|
|
48908
49085
|
async executeStep(step, stepStates, agentMap, errorHandling, runId) {
|
|
48909
49086
|
if (this.isDeterministicStep(step)) {
|
|
48910
|
-
return this.executeDeterministicStep(step, stepStates, runId);
|
|
49087
|
+
return this.executeDeterministicStep(step, stepStates, runId, errorHandling);
|
|
48911
49088
|
}
|
|
48912
49089
|
if (this.isWorktreeStep(step)) {
|
|
48913
49090
|
return this.executeWorktreeStep(step, stepStates, runId);
|
|
@@ -48918,131 +49095,154 @@ ${trimmedOutput.slice(0, 200)}`);
|
|
|
48918
49095
|
* Execute a deterministic step (shell command).
|
|
48919
49096
|
* Fast, reliable, $0 LLM cost.
|
|
48920
49097
|
*/
|
|
48921
|
-
async executeDeterministicStep(step, stepStates, runId) {
|
|
49098
|
+
async executeDeterministicStep(step, stepStates, runId, errorHandling) {
|
|
48922
49099
|
const state = stepStates.get(step.name);
|
|
48923
49100
|
if (!state)
|
|
48924
49101
|
throw new Error(`Step state not found: ${step.name}`);
|
|
48925
|
-
|
|
48926
|
-
|
|
48927
|
-
|
|
48928
|
-
|
|
48929
|
-
|
|
48930
|
-
|
|
48931
|
-
|
|
48932
|
-
|
|
48933
|
-
|
|
48934
|
-
this.postToChannel(`**[${step.name}]** Started (deterministic)`);
|
|
48935
|
-
const stepOutputContext = this.buildStepOutputContext(stepStates, runId);
|
|
48936
|
-
let resolvedCommand = this.interpolateStepTask(step.command ?? "", stepOutputContext);
|
|
48937
|
-
resolvedCommand = resolvedCommand.replace(/\{\{([\w][\w.\-]*)\}\}/g, (_match, key) => {
|
|
48938
|
-
if (key.startsWith("steps."))
|
|
48939
|
-
return _match;
|
|
48940
|
-
const value = this.resolveDotPath(key, stepOutputContext);
|
|
48941
|
-
return value !== void 0 ? String(value) : _match;
|
|
48942
|
-
});
|
|
48943
|
-
const stepCwd = this.resolveStepWorkdir(step) ?? this.cwd;
|
|
48944
|
-
try {
|
|
48945
|
-
if (this.executor?.executeDeterministicStep) {
|
|
48946
|
-
const result = await this.executor.executeDeterministicStep(step, resolvedCommand, stepCwd);
|
|
48947
|
-
const failOnError = step.failOnError !== false;
|
|
48948
|
-
if (failOnError && result.exitCode !== 0) {
|
|
48949
|
-
throw new Error(`Command failed with exit code ${result.exitCode}: ${result.output.slice(0, 500)}`);
|
|
48950
|
-
}
|
|
48951
|
-
const output2 = step.captureOutput !== false ? result.output : `Command completed (exit code ${result.exitCode})`;
|
|
48952
|
-
state.row.status = "completed";
|
|
48953
|
-
state.row.output = output2;
|
|
48954
|
-
state.row.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
49102
|
+
const maxRetries = step.retries ?? errorHandling?.maxRetries ?? 0;
|
|
49103
|
+
const retryDelay = errorHandling?.retryDelayMs ?? 1e3;
|
|
49104
|
+
let lastError;
|
|
49105
|
+
for (let attempt = 0; attempt <= maxRetries; attempt += 1) {
|
|
49106
|
+
this.checkAborted();
|
|
49107
|
+
if (attempt > 0) {
|
|
49108
|
+
this.emit({ type: "step:retrying", runId, stepName: step.name, attempt });
|
|
49109
|
+
this.postToChannel(`**[${step.name}]** Retrying (attempt ${attempt + 1}/${maxRetries + 1})`);
|
|
49110
|
+
state.row.retryCount = attempt;
|
|
48955
49111
|
await this.db.updateStep(state.row.id, {
|
|
48956
|
-
|
|
48957
|
-
output: output2,
|
|
48958
|
-
completedAt: state.row.completedAt,
|
|
49112
|
+
retryCount: attempt,
|
|
48959
49113
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
48960
49114
|
});
|
|
48961
|
-
await this.
|
|
48962
|
-
this.emit({ type: "step:completed", runId, stepName: step.name, output: output2 });
|
|
48963
|
-
return;
|
|
49115
|
+
await this.delay(retryDelay);
|
|
48964
49116
|
}
|
|
48965
|
-
|
|
48966
|
-
|
|
48967
|
-
|
|
48968
|
-
|
|
48969
|
-
|
|
48970
|
-
|
|
48971
|
-
|
|
48972
|
-
|
|
48973
|
-
|
|
48974
|
-
|
|
48975
|
-
|
|
48976
|
-
|
|
48977
|
-
|
|
48978
|
-
|
|
48979
|
-
|
|
48980
|
-
|
|
48981
|
-
|
|
48982
|
-
|
|
48983
|
-
|
|
48984
|
-
if (
|
|
48985
|
-
|
|
48986
|
-
|
|
48987
|
-
|
|
48988
|
-
|
|
48989
|
-
}, step.timeoutMs);
|
|
48990
|
-
}
|
|
48991
|
-
child.stdout?.on("data", (chunk) => {
|
|
48992
|
-
stdoutChunks.push(chunk.toString());
|
|
48993
|
-
});
|
|
48994
|
-
child.stderr?.on("data", (chunk) => {
|
|
48995
|
-
stderrChunks.push(chunk.toString());
|
|
48996
|
-
});
|
|
48997
|
-
child.on("close", (code) => {
|
|
48998
|
-
if (timer)
|
|
48999
|
-
clearTimeout(timer);
|
|
49000
|
-
if (abortHandler && abortSignal) {
|
|
49001
|
-
abortSignal.removeEventListener("abort", abortHandler);
|
|
49117
|
+
state.row.status = "running";
|
|
49118
|
+
state.row.startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
49119
|
+
await this.db.updateStep(state.row.id, {
|
|
49120
|
+
status: "running",
|
|
49121
|
+
startedAt: state.row.startedAt,
|
|
49122
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
49123
|
+
});
|
|
49124
|
+
this.emit({ type: "step:started", runId, stepName: step.name });
|
|
49125
|
+
this.postToChannel(`**[${step.name}]** Started (deterministic)`);
|
|
49126
|
+
const stepOutputContext = this.buildStepOutputContext(stepStates, runId);
|
|
49127
|
+
let resolvedCommand = this.interpolateStepTask(step.command ?? "", stepOutputContext);
|
|
49128
|
+
resolvedCommand = resolvedCommand.replace(/\{\{([\w][\w.\-]*)\}\}/g, (_match, key) => {
|
|
49129
|
+
if (key.startsWith("steps."))
|
|
49130
|
+
return _match;
|
|
49131
|
+
const value = this.resolveDotPath(key, stepOutputContext);
|
|
49132
|
+
return value !== void 0 ? String(value) : _match;
|
|
49133
|
+
});
|
|
49134
|
+
const stepCwd = this.resolveStepWorkdir(step) ?? this.cwd;
|
|
49135
|
+
try {
|
|
49136
|
+
if (this.executor?.executeDeterministicStep) {
|
|
49137
|
+
const result = await this.executor.executeDeterministicStep(step, resolvedCommand, stepCwd);
|
|
49138
|
+
const failOnError = step.failOnError !== false;
|
|
49139
|
+
if (failOnError && result.exitCode !== 0) {
|
|
49140
|
+
throw new Error(`Command failed with exit code ${result.exitCode}: ${result.output.slice(0, 500)}`);
|
|
49002
49141
|
}
|
|
49003
|
-
|
|
49004
|
-
|
|
49005
|
-
|
|
49142
|
+
const output2 = step.captureOutput !== false ? result.output : `Command completed (exit code ${result.exitCode})`;
|
|
49143
|
+
if (step.verification) {
|
|
49144
|
+
this.runVerification(step.verification, output2, step.name);
|
|
49006
49145
|
}
|
|
49007
|
-
|
|
49008
|
-
|
|
49009
|
-
|
|
49146
|
+
state.row.status = "completed";
|
|
49147
|
+
state.row.output = output2;
|
|
49148
|
+
state.row.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
49149
|
+
await this.db.updateStep(state.row.id, {
|
|
49150
|
+
status: "completed",
|
|
49151
|
+
output: output2,
|
|
49152
|
+
completedAt: state.row.completedAt,
|
|
49153
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
49154
|
+
});
|
|
49155
|
+
await this.persistStepOutput(runId, step.name, output2);
|
|
49156
|
+
this.emit({ type: "step:completed", runId, stepName: step.name, output: output2 });
|
|
49157
|
+
return;
|
|
49158
|
+
}
|
|
49159
|
+
const output = await new Promise((resolve3, reject) => {
|
|
49160
|
+
const child = (0, import_node_child_process3.spawn)("sh", ["-c", resolvedCommand], {
|
|
49161
|
+
stdio: "pipe",
|
|
49162
|
+
cwd: stepCwd,
|
|
49163
|
+
env: { ...process.env }
|
|
49164
|
+
});
|
|
49165
|
+
const stdoutChunks = [];
|
|
49166
|
+
const stderrChunks = [];
|
|
49167
|
+
const abortSignal = this.abortController?.signal;
|
|
49168
|
+
let abortHandler;
|
|
49169
|
+
if (abortSignal && !abortSignal.aborted) {
|
|
49170
|
+
abortHandler = () => {
|
|
49171
|
+
child.kill("SIGTERM");
|
|
49172
|
+
setTimeout(() => child.kill("SIGKILL"), 5e3);
|
|
49173
|
+
};
|
|
49174
|
+
abortSignal.addEventListener("abort", abortHandler, { once: true });
|
|
49010
49175
|
}
|
|
49011
|
-
|
|
49012
|
-
|
|
49013
|
-
|
|
49014
|
-
|
|
49015
|
-
|
|
49016
|
-
|
|
49176
|
+
let timedOut = false;
|
|
49177
|
+
let timer;
|
|
49178
|
+
if (step.timeoutMs) {
|
|
49179
|
+
timer = setTimeout(() => {
|
|
49180
|
+
timedOut = true;
|
|
49181
|
+
child.kill("SIGTERM");
|
|
49182
|
+
setTimeout(() => child.kill("SIGKILL"), 5e3);
|
|
49183
|
+
}, step.timeoutMs);
|
|
49017
49184
|
}
|
|
49018
|
-
|
|
49185
|
+
child.stdout?.on("data", (chunk) => {
|
|
49186
|
+
stdoutChunks.push(chunk.toString());
|
|
49187
|
+
});
|
|
49188
|
+
child.stderr?.on("data", (chunk) => {
|
|
49189
|
+
stderrChunks.push(chunk.toString());
|
|
49190
|
+
});
|
|
49191
|
+
child.on("close", (code) => {
|
|
49192
|
+
if (timer)
|
|
49193
|
+
clearTimeout(timer);
|
|
49194
|
+
if (abortHandler && abortSignal) {
|
|
49195
|
+
abortSignal.removeEventListener("abort", abortHandler);
|
|
49196
|
+
}
|
|
49197
|
+
if (abortSignal?.aborted) {
|
|
49198
|
+
reject(new Error(`Step "${step.name}" aborted`));
|
|
49199
|
+
return;
|
|
49200
|
+
}
|
|
49201
|
+
if (timedOut) {
|
|
49202
|
+
reject(new Error(`Step "${step.name}" timed out (no step timeout set, check global swarm.timeoutMs)`));
|
|
49203
|
+
return;
|
|
49204
|
+
}
|
|
49205
|
+
const stdout = stdoutChunks.join("");
|
|
49206
|
+
const stderr = stderrChunks.join("");
|
|
49207
|
+
const failOnError = step.failOnError !== false;
|
|
49208
|
+
if (failOnError && code !== 0 && code !== null) {
|
|
49209
|
+
reject(new Error(`Command failed with exit code ${code}${stderr ? `: ${stderr.slice(0, 500)}` : ""}`));
|
|
49210
|
+
return;
|
|
49211
|
+
}
|
|
49212
|
+
resolve3(step.captureOutput !== false ? stdout : `Command completed (exit code ${code ?? 0})`);
|
|
49213
|
+
});
|
|
49214
|
+
child.on("error", (err) => {
|
|
49215
|
+
if (timer)
|
|
49216
|
+
clearTimeout(timer);
|
|
49217
|
+
if (abortHandler && abortSignal) {
|
|
49218
|
+
abortSignal.removeEventListener("abort", abortHandler);
|
|
49219
|
+
}
|
|
49220
|
+
reject(new Error(`Failed to execute command: ${err.message}`));
|
|
49221
|
+
});
|
|
49019
49222
|
});
|
|
49020
|
-
|
|
49021
|
-
|
|
49022
|
-
|
|
49023
|
-
|
|
49024
|
-
|
|
49025
|
-
|
|
49026
|
-
|
|
49223
|
+
if (step.verification) {
|
|
49224
|
+
this.runVerification(step.verification, output, step.name);
|
|
49225
|
+
}
|
|
49226
|
+
state.row.status = "completed";
|
|
49227
|
+
state.row.output = output;
|
|
49228
|
+
state.row.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
49229
|
+
await this.db.updateStep(state.row.id, {
|
|
49230
|
+
status: "completed",
|
|
49231
|
+
output,
|
|
49232
|
+
completedAt: state.row.completedAt,
|
|
49233
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
49027
49234
|
});
|
|
49028
|
-
|
|
49029
|
-
|
|
49030
|
-
|
|
49031
|
-
|
|
49032
|
-
|
|
49033
|
-
|
|
49034
|
-
output,
|
|
49035
|
-
completedAt: state.row.completedAt,
|
|
49036
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
49037
|
-
});
|
|
49038
|
-
await this.persistStepOutput(runId, step.name, output);
|
|
49039
|
-
this.emit({ type: "step:completed", runId, stepName: step.name, output });
|
|
49040
|
-
} catch (err) {
|
|
49041
|
-
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
49042
|
-
this.postToChannel(`**[${step.name}]** Failed: ${errorMsg}`);
|
|
49043
|
-
await this.markStepFailed(state, errorMsg, runId);
|
|
49044
|
-
throw new Error(`Step "${step.name}" failed: ${errorMsg}`);
|
|
49235
|
+
await this.persistStepOutput(runId, step.name, output);
|
|
49236
|
+
this.emit({ type: "step:completed", runId, stepName: step.name, output });
|
|
49237
|
+
return;
|
|
49238
|
+
} catch (err) {
|
|
49239
|
+
lastError = err instanceof Error ? err.message : String(err);
|
|
49240
|
+
}
|
|
49045
49241
|
}
|
|
49242
|
+
const errorMsg = lastError ?? "Unknown error";
|
|
49243
|
+
this.postToChannel(`**[${step.name}]** Failed: ${errorMsg}`);
|
|
49244
|
+
await this.markStepFailed(state, errorMsg, runId);
|
|
49245
|
+
throw new Error(`Step "${step.name}" failed: ${errorMsg}`);
|
|
49046
49246
|
}
|
|
49047
49247
|
/**
|
|
49048
49248
|
* Execute a worktree step (git worktree setup).
|
|
@@ -49211,8 +49411,12 @@ ${trimmedOutput.slice(0, 200)}`);
|
|
|
49211
49411
|
const retryDelay = errorHandling?.retryDelayMs ?? 1e3;
|
|
49212
49412
|
const timeoutMs = step.timeoutMs ?? ownerDef.constraints?.timeoutMs ?? specialistDef.constraints?.timeoutMs ?? this.currentConfig?.swarm?.timeoutMs;
|
|
49213
49413
|
let lastError;
|
|
49414
|
+
let lastExitCode;
|
|
49415
|
+
let lastExitSignal;
|
|
49214
49416
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
49215
49417
|
this.checkAborted();
|
|
49418
|
+
lastExitCode = void 0;
|
|
49419
|
+
lastExitSignal = void 0;
|
|
49216
49420
|
if (attempt > 0) {
|
|
49217
49421
|
this.emit({ type: "step:retrying", runId, stepName: step.name, attempt });
|
|
49218
49422
|
this.postToChannel(`**[${step.name}]** Retrying (attempt ${attempt + 1}/${maxRetries + 1})`);
|
|
@@ -49252,6 +49456,15 @@ ${trimmedOutput.slice(0, 200)}`);
|
|
|
49252
49456
|
});
|
|
49253
49457
|
const stepOutputContext = this.buildStepOutputContext(stepStates, runId);
|
|
49254
49458
|
let resolvedTask = this.interpolateStepTask(step.task ?? "", stepOutputContext);
|
|
49459
|
+
if (attempt > 0 && lastError) {
|
|
49460
|
+
const priorOutput = (this.lastFailedStepOutput.get(step.name) ?? "").slice(-2e3);
|
|
49461
|
+
resolvedTask = `[RETRY \u2014 Attempt ${attempt + 1}/${maxRetries + 1}]
|
|
49462
|
+
Previous attempt failed: ${lastError}
|
|
49463
|
+
` + (priorOutput ? `Previous output (last 2000 chars):
|
|
49464
|
+
${priorOutput}
|
|
49465
|
+
` : "") + `---
|
|
49466
|
+
${resolvedTask}`;
|
|
49467
|
+
}
|
|
49255
49468
|
if (specialistDef.interactive !== false || ownerDef.interactive !== false) {
|
|
49256
49469
|
const nonInteractiveInfo = this.buildNonInteractiveAwareness(agentMap, stepStates);
|
|
49257
49470
|
if (nonInteractiveInfo) {
|
|
@@ -49282,7 +49495,10 @@ ${trimmedOutput.slice(0, 200)}`);
|
|
|
49282
49495
|
this.log(`[${step.name}] Spawning owner "${effectiveOwner.name}" (cli: ${effectiveOwner.cli})${step.workdir ? ` [workdir: ${step.workdir}]` : ""}`);
|
|
49283
49496
|
const resolvedStep = { ...step, task: ownerTask };
|
|
49284
49497
|
const ownerStartTime = Date.now();
|
|
49285
|
-
const
|
|
49498
|
+
const spawnResult = this.executor ? await this.executor.executeAgentStep(resolvedStep, effectiveOwner, ownerTask, timeoutMs) : await this.spawnAndWait(effectiveOwner, resolvedStep, timeoutMs);
|
|
49499
|
+
const output = typeof spawnResult === "string" ? spawnResult : spawnResult.output;
|
|
49500
|
+
lastExitCode = typeof spawnResult === "string" ? void 0 : spawnResult.exitCode;
|
|
49501
|
+
lastExitSignal = typeof spawnResult === "string" ? void 0 : spawnResult.exitSignal;
|
|
49286
49502
|
ownerElapsed = Date.now() - ownerStartTime;
|
|
49287
49503
|
this.log(`[${step.name}] Owner "${effectiveOwner.name}" exited`);
|
|
49288
49504
|
if (usesOwnerFlow) {
|
|
@@ -49292,7 +49508,7 @@ ${trimmedOutput.slice(0, 200)}`);
|
|
|
49292
49508
|
ownerOutput = output;
|
|
49293
49509
|
}
|
|
49294
49510
|
if (step.verification) {
|
|
49295
|
-
this.runVerification(step.verification, specialistOutput, step.name, resolvedTask);
|
|
49511
|
+
this.runVerification(step.verification, specialistOutput, step.name, effectiveOwner.interactive === false ? void 0 : resolvedTask);
|
|
49296
49512
|
}
|
|
49297
49513
|
let combinedOutput = specialistOutput;
|
|
49298
49514
|
if (usesOwnerFlow && reviewDef) {
|
|
@@ -49310,11 +49526,15 @@ ${trimmedOutput.slice(0, 200)}`);
|
|
|
49310
49526
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
49311
49527
|
});
|
|
49312
49528
|
await this.persistStepOutput(runId, step.name, combinedOutput);
|
|
49313
|
-
this.emit({ type: "step:completed", runId, stepName: step.name, output: combinedOutput });
|
|
49529
|
+
this.emit({ type: "step:completed", runId, stepName: step.name, output: combinedOutput, exitCode: lastExitCode, exitSignal: lastExitSignal });
|
|
49314
49530
|
await this.trajectory?.stepCompleted(step, combinedOutput, attempt + 1);
|
|
49315
49531
|
return;
|
|
49316
49532
|
} catch (err) {
|
|
49317
49533
|
lastError = err instanceof Error ? err.message : String(err);
|
|
49534
|
+
if (err instanceof SpawnExitError) {
|
|
49535
|
+
lastExitCode = err.exitCode;
|
|
49536
|
+
lastExitSignal = err.exitSignal;
|
|
49537
|
+
}
|
|
49318
49538
|
const ownerTimedOut = usesDedicatedOwner ? /\bowner timed out\b/i.test(lastError) : /\btimed out\b/i.test(lastError) && !lastError.includes(`${step.name}-review`);
|
|
49319
49539
|
if (ownerTimedOut) {
|
|
49320
49540
|
this.emit({ type: "step:owner-timeout", runId, stepName: step.name, ownerName: ownerDef.name });
|
|
@@ -49329,7 +49549,10 @@ ${trimmedOutput.slice(0, 200)}`);
|
|
|
49329
49549
|
verificationValue
|
|
49330
49550
|
});
|
|
49331
49551
|
this.postToChannel(`**[${step.name}]** Failed: ${lastError ?? "Unknown error"}`);
|
|
49332
|
-
await this.markStepFailed(state, lastError ?? "Unknown error", runId
|
|
49552
|
+
await this.markStepFailed(state, lastError ?? "Unknown error", runId, {
|
|
49553
|
+
exitCode: lastExitCode,
|
|
49554
|
+
exitSignal: lastExitSignal
|
|
49555
|
+
});
|
|
49333
49556
|
throw new Error(`Step "${step.name}" failed after ${maxRetries} retries: ${lastError ?? "Unknown error"}`);
|
|
49334
49557
|
}
|
|
49335
49558
|
injectStepOwnerContract(step, resolvedTask, ownerDef, specialistDef) {
|
|
@@ -49447,10 +49670,10 @@ Output exactly: STEP_COMPLETE:${step.name}`;
|
|
|
49447
49670
|
throw error95;
|
|
49448
49671
|
});
|
|
49449
49672
|
const workerSettled = workerPromise.catch(() => void 0);
|
|
49450
|
-
workerPromise.then((
|
|
49673
|
+
workerPromise.then((result) => {
|
|
49451
49674
|
workerReleased = true;
|
|
49452
49675
|
this.postToChannel(`**[${step.name}]** Worker \`${workerRuntimeName}\` exited`);
|
|
49453
|
-
if (step.verification?.type === "output_contains" && output.includes(step.verification.value)) {
|
|
49676
|
+
if (step.verification?.type === "output_contains" && result.output.includes(step.verification.value)) {
|
|
49454
49677
|
this.postToChannel(`**[${step.name}]** Verification gate observed: output contains ${JSON.stringify(step.verification.value)}`);
|
|
49455
49678
|
}
|
|
49456
49679
|
}).catch((error95) => {
|
|
@@ -49468,7 +49691,7 @@ Output exactly: STEP_COMPLETE:${step.name}`;
|
|
|
49468
49691
|
this.log(`[${step.name}] Spawning owner "${supervised.owner.name}" (cli: ${supervised.owner.cli})`);
|
|
49469
49692
|
const ownerStartTime = Date.now();
|
|
49470
49693
|
try {
|
|
49471
|
-
const
|
|
49694
|
+
const ownerResultObj = await this.spawnAndWait(supervised.owner, ownerStep, timeoutMs, {
|
|
49472
49695
|
agentNameSuffix: "owner",
|
|
49473
49696
|
onSpawned: ({ actualName }) => {
|
|
49474
49697
|
this.supervisedRuntimeAgents.set(actualName, {
|
|
@@ -49482,9 +49705,10 @@ Output exactly: STEP_COMPLETE:${step.name}`;
|
|
|
49482
49705
|
}
|
|
49483
49706
|
});
|
|
49484
49707
|
const ownerElapsed = Date.now() - ownerStartTime;
|
|
49708
|
+
const ownerOutput = ownerResultObj.output;
|
|
49485
49709
|
this.log(`[${step.name}] Owner "${supervised.owner.name}" exited`);
|
|
49486
49710
|
this.assertOwnerCompletionMarker(step, ownerOutput, supervisorTask);
|
|
49487
|
-
const specialistOutput = await workerPromise;
|
|
49711
|
+
const specialistOutput = (await workerPromise).output;
|
|
49488
49712
|
return { specialistOutput, ownerOutput, ownerElapsed };
|
|
49489
49713
|
} catch (error95) {
|
|
49490
49714
|
const message = error95 instanceof Error ? error95.message : String(error95);
|
|
@@ -49682,7 +49906,7 @@ Then output /exit.`;
|
|
|
49682
49906
|
})();
|
|
49683
49907
|
};
|
|
49684
49908
|
try {
|
|
49685
|
-
|
|
49909
|
+
await this.spawnAndWait(reviewerDef, reviewStep, safetyTimeoutMs, {
|
|
49686
49910
|
onSpawned: ({ agent }) => {
|
|
49687
49911
|
reviewerHandle = agent;
|
|
49688
49912
|
},
|
|
@@ -49862,7 +50086,7 @@ DO NOT:
|
|
|
49862
50086
|
const stdoutChunks = [];
|
|
49863
50087
|
const stderrChunks = [];
|
|
49864
50088
|
try {
|
|
49865
|
-
const output = await new Promise((resolve3, reject) => {
|
|
50089
|
+
const { stdout: output, exitCode, exitSignal } = await new Promise((resolve3, reject) => {
|
|
49866
50090
|
const child = (0, import_node_child_process3.spawn)(cmd, args, {
|
|
49867
50091
|
stdio: ["ignore", "pipe", "pipe"],
|
|
49868
50092
|
cwd: this.resolveAgentCwd(agentDef),
|
|
@@ -49908,7 +50132,7 @@ DO NOT:
|
|
|
49908
50132
|
setTimeout(() => child.kill("SIGKILL"), 5e3);
|
|
49909
50133
|
}, timeoutMs);
|
|
49910
50134
|
}
|
|
49911
|
-
child.on("close", (code) => {
|
|
50135
|
+
child.on("close", (code, signal) => {
|
|
49912
50136
|
clearInterval(heartbeat);
|
|
49913
50137
|
if (timer)
|
|
49914
50138
|
clearTimeout(timer);
|
|
@@ -49926,10 +50150,14 @@ DO NOT:
|
|
|
49926
50150
|
}
|
|
49927
50151
|
if (code !== 0 && code !== null) {
|
|
49928
50152
|
const stderr = stderrChunks.join("");
|
|
49929
|
-
reject(new
|
|
50153
|
+
reject(new SpawnExitError(`Step "${step.name}" exited with code ${code}${stderr ? `: ${stderr.slice(0, 500)}` : ""}`, code, signal));
|
|
49930
50154
|
return;
|
|
49931
50155
|
}
|
|
49932
|
-
resolve3(
|
|
50156
|
+
resolve3({
|
|
50157
|
+
stdout,
|
|
50158
|
+
exitCode: code ?? void 0,
|
|
50159
|
+
exitSignal: signal ?? void 0
|
|
50160
|
+
});
|
|
49933
50161
|
});
|
|
49934
50162
|
child.on("error", (err) => {
|
|
49935
50163
|
clearInterval(heartbeat);
|
|
@@ -49941,8 +50169,10 @@ DO NOT:
|
|
|
49941
50169
|
reject(new Error(`Failed to spawn ${cmd}: ${err.message}`));
|
|
49942
50170
|
});
|
|
49943
50171
|
});
|
|
49944
|
-
return output;
|
|
50172
|
+
return { output, exitCode, exitSignal };
|
|
49945
50173
|
} finally {
|
|
50174
|
+
const combinedOutput = stdoutChunks.join("") + stderrChunks.join("");
|
|
50175
|
+
this.lastFailedStepOutput.set(step.name, combinedOutput);
|
|
49946
50176
|
stopHeartbeat?.();
|
|
49947
50177
|
logStream.end();
|
|
49948
50178
|
this.unregisterWorker(agentName);
|
|
@@ -50062,8 +50292,12 @@ DO NOT:
|
|
|
50062
50292
|
throw new Error(`Step "${step.name}" timed out after ${timeoutMs ?? "unknown"}ms`);
|
|
50063
50293
|
}
|
|
50064
50294
|
}
|
|
50295
|
+
if (exitResult === "force-released") {
|
|
50296
|
+
throw new Error(`Step "${step.name}" failed \u2014 agent was force-released after exhausting idle nudges without completing`);
|
|
50297
|
+
}
|
|
50065
50298
|
} finally {
|
|
50066
50299
|
ptyChunks = this.ptyOutputBuffers.get(agentName) ?? [];
|
|
50300
|
+
this.lastFailedStepOutput.set(step.name, ptyChunks.join(""));
|
|
50067
50301
|
stopHeartbeat?.();
|
|
50068
50302
|
this.activeAgentHandles.delete(agentName);
|
|
50069
50303
|
this.ptyOutputBuffers.delete(agentName);
|
|
@@ -50081,9 +50315,13 @@ DO NOT:
|
|
|
50081
50315
|
output = ptyChunks.join("");
|
|
50082
50316
|
} else {
|
|
50083
50317
|
const summaryPath = import_node_path8.default.join(this.summaryDir, `${step.name}.md`);
|
|
50084
|
-
output = (0, import_node_fs4.existsSync)(summaryPath) ? await (0, import_promises3.readFile)(summaryPath, "utf-8") : exitResult === "timeout" ? "Agent completed (released after idle timeout)" : exitResult === "released" ? "Agent completed (
|
|
50318
|
+
output = (0, import_node_fs4.existsSync)(summaryPath) ? await (0, import_promises3.readFile)(summaryPath, "utf-8") : exitResult === "timeout" ? "Agent completed (released after idle timeout)" : exitResult === "released" ? "Agent completed (idle \u2014 treated as done)" : `Agent exited (${exitResult})`;
|
|
50085
50319
|
}
|
|
50086
|
-
return
|
|
50320
|
+
return {
|
|
50321
|
+
output,
|
|
50322
|
+
exitCode: agent?.exitCode,
|
|
50323
|
+
exitSignal: agent?.exitSignal
|
|
50324
|
+
};
|
|
50087
50325
|
}
|
|
50088
50326
|
// ── Idle nudging ────────────────────────────────────────────────────────
|
|
50089
50327
|
/** Patterns where a hub agent coordinates spoke agents. */
|
|
@@ -50142,7 +50380,7 @@ DO NOT:
|
|
|
50142
50380
|
if (exitResult !== "timeout") {
|
|
50143
50381
|
return exitResult;
|
|
50144
50382
|
}
|
|
50145
|
-
if (
|
|
50383
|
+
if (timeoutMs !== void 0 && Date.now() - startTime >= timeoutMs) {
|
|
50146
50384
|
return "timeout";
|
|
50147
50385
|
}
|
|
50148
50386
|
if (nudgeCount < maxNudges) {
|
|
@@ -50155,7 +50393,7 @@ DO NOT:
|
|
|
50155
50393
|
this.postToChannel(`**[${step.name}]** Agent \`${agent.name}\` still idle after ${nudgeCount} nudge(s) \u2014 force-releasing`);
|
|
50156
50394
|
this.emit({ type: "step:force-released", runId: this.currentRunId ?? "", stepName: step.name });
|
|
50157
50395
|
await agent.release();
|
|
50158
|
-
return "released";
|
|
50396
|
+
return "force-released";
|
|
50159
50397
|
}
|
|
50160
50398
|
}
|
|
50161
50399
|
/**
|
|
@@ -50250,7 +50488,7 @@ DO NOT:
|
|
|
50250
50488
|
}
|
|
50251
50489
|
await this.db.updateRun(runId, patch);
|
|
50252
50490
|
}
|
|
50253
|
-
async markStepFailed(state, error95, runId) {
|
|
50491
|
+
async markStepFailed(state, error95, runId, exitInfo) {
|
|
50254
50492
|
state.row.status = "failed";
|
|
50255
50493
|
state.row.error = error95;
|
|
50256
50494
|
state.row.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -50260,7 +50498,14 @@ DO NOT:
|
|
|
50260
50498
|
completedAt: state.row.completedAt,
|
|
50261
50499
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
50262
50500
|
});
|
|
50263
|
-
this.emit({
|
|
50501
|
+
this.emit({
|
|
50502
|
+
type: "step:failed",
|
|
50503
|
+
runId,
|
|
50504
|
+
stepName: state.row.stepName,
|
|
50505
|
+
error: error95,
|
|
50506
|
+
exitCode: exitInfo?.exitCode,
|
|
50507
|
+
exitSignal: exitInfo?.exitSignal
|
|
50508
|
+
});
|
|
50264
50509
|
}
|
|
50265
50510
|
async markDownstreamSkipped(failedStepName, allSteps, stepStates, runId) {
|
|
50266
50511
|
const queue = [failedStepName];
|