@rallycry/conveyor-agent 10.13.72 → 11.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{boot-ZNL7X5LQ.js → boot-PKQ2I66D.js} +49 -2
- package/dist/{chunk-WMMBAKPE.js → chunk-GL2DIQEQ.js} +121 -8
- package/dist/{chunk-2L5THOWD.js → chunk-JQVAWRVL.js} +2 -2
- package/dist/{chunk-LSZ2KLJY.js → chunk-N4WSUTGV.js} +40 -3
- package/dist/{chunk-2SN32LM6.js → chunk-PEEGCZAR.js} +2055 -1035
- package/dist/cli.js +257 -100
- package/dist/index.d.ts +170 -3
- package/dist/index.js +3 -3
- package/dist/{serve-boot-4N3FRXVQ.js → serve-boot-YPAUKENG.js} +3 -3
- package/package.json +5 -4
- package/skills/conveyor-build/SKILL.md +262 -0
- package/skills/conveyor-build/references/pack-path.md +224 -0
- package/skills/conveyor-build/references/task-path.md +67 -0
- package/skills/conveyor-consensus/SKILL.md +99 -0
- package/skills/conveyor-consensus/references/doc-template.html +204 -0
- package/skills/conveyor-local-loop/SKILL.md +258 -0
- package/skills/conveyor-meeting-review/SKILL.md +72 -0
- package/skills/conveyor-plan/SKILL.md +177 -0
- package/skills/conveyor-plan/references/plan-format.md +134 -0
- package/skills/conveyor-review/SKILL.md +161 -0
- package/skills/conveyor-start/SKILL.md +106 -0
- package/skills/conveyor-triage/SKILL.md +174 -0
- package/skills/conveyor-workflows/SKILL.md +195 -0
- package/skills/conveyor-workflows/references/mcp-setup.md +43 -0
package/dist/cli.js
CHANGED
|
@@ -7,10 +7,11 @@ import {
|
|
|
7
7
|
WorkspaceCommandSupervisor,
|
|
8
8
|
startWorkspaceCommandsAfterConnect,
|
|
9
9
|
stopWorkspaceCommands
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-JQVAWRVL.js";
|
|
11
11
|
import {
|
|
12
12
|
DEFAULT_SONNET_MODEL,
|
|
13
13
|
PtyHarness,
|
|
14
|
+
RUNNER_MODES,
|
|
14
15
|
SessionRunner,
|
|
15
16
|
buildProjectTools,
|
|
16
17
|
buildRateLimitEvents,
|
|
@@ -18,6 +19,7 @@ import {
|
|
|
18
19
|
buildUnmeasurableEvent,
|
|
19
20
|
claudeJsonPath,
|
|
20
21
|
isPermissionDeniedError,
|
|
22
|
+
parsePackExecution,
|
|
21
23
|
parseUsageGauges,
|
|
22
24
|
resolvePlaywrightMcpServer,
|
|
23
25
|
resolveSessionStart,
|
|
@@ -25,7 +27,7 @@ import {
|
|
|
25
27
|
resolveTuiKindFromEnv,
|
|
26
28
|
runUsageProbe,
|
|
27
29
|
sampleKeyUsage
|
|
28
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-PEEGCZAR.js";
|
|
29
31
|
import "./chunk-XORJ6SII.js";
|
|
30
32
|
import {
|
|
31
33
|
AgentConnection,
|
|
@@ -37,8 +39,8 @@ import {
|
|
|
37
39
|
createServiceLogger,
|
|
38
40
|
fetchBootstrap,
|
|
39
41
|
loadConveyorConfig
|
|
40
|
-
} from "./chunk-
|
|
41
|
-
import "./chunk-
|
|
42
|
+
} from "./chunk-N4WSUTGV.js";
|
|
43
|
+
import "./chunk-GL2DIQEQ.js";
|
|
42
44
|
import "./chunk-IA45XHOA.js";
|
|
43
45
|
import "./chunk-EXQ6AHOY.js";
|
|
44
46
|
import "./chunk-KMB3BU4S.js";
|
|
@@ -57,22 +59,22 @@ import { fileURLToPath } from "url";
|
|
|
57
59
|
|
|
58
60
|
// src/utils/session-identity.ts
|
|
59
61
|
async function checkSessionTaskIdentity(params) {
|
|
60
|
-
const { sessionId, taskId, fetchSessionTaskId, logger:
|
|
62
|
+
const { sessionId, taskId, fetchSessionTaskId, logger: logger7 } = params;
|
|
61
63
|
if (!sessionId || sessionId === taskId) return "skipped";
|
|
62
64
|
let sessionTaskId;
|
|
63
65
|
try {
|
|
64
66
|
sessionTaskId = await fetchSessionTaskId(sessionId);
|
|
65
67
|
} catch (err) {
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
+
const message2 = err instanceof Error ? err.message : String(err);
|
|
69
|
+
logger7.warn("Could not verify session/task identity \u2014 continuing (defense-in-depth only)", {
|
|
68
70
|
sessionId,
|
|
69
71
|
taskId,
|
|
70
|
-
error:
|
|
72
|
+
error: message2
|
|
71
73
|
});
|
|
72
74
|
return "error";
|
|
73
75
|
}
|
|
74
76
|
if (sessionTaskId !== taskId) {
|
|
75
|
-
|
|
77
|
+
logger7.warn(
|
|
76
78
|
"!!! CONVEYOR_SESSION_ID is bound to a different task than CONVEYOR_TASK_ID \u2014 server-side guards should still block mutations, but this indicates a misconfiguration or replayed token.",
|
|
77
79
|
{ sessionId, envTaskId: taskId, sessionTaskId }
|
|
78
80
|
);
|
|
@@ -188,10 +190,10 @@ var ProjectSessionRunner = class {
|
|
|
188
190
|
await this.waitUntilStopped();
|
|
189
191
|
this._finalState = "finished";
|
|
190
192
|
} catch (error) {
|
|
191
|
-
const
|
|
192
|
-
process.stderr.write(`[conveyor-agent] Project runner failed: ${
|
|
193
|
+
const message2 = error instanceof Error ? error.message : String(error);
|
|
194
|
+
process.stderr.write(`[conveyor-agent] Project runner failed: ${message2}
|
|
193
195
|
`);
|
|
194
|
-
this.connection.sendEvent({ type: "error", message });
|
|
196
|
+
this.connection.sendEvent({ type: "error", message: message2 });
|
|
195
197
|
this._finalState = "error";
|
|
196
198
|
} finally {
|
|
197
199
|
this.shutdown();
|
|
@@ -463,10 +465,10 @@ var AdhocSessionRunner = class {
|
|
|
463
465
|
await this.runInteractiveTui();
|
|
464
466
|
this._finalState = "finished";
|
|
465
467
|
} catch (error) {
|
|
466
|
-
const
|
|
467
|
-
process.stderr.write(`[conveyor-agent] Ad-hoc runner failed: ${
|
|
468
|
+
const message2 = error instanceof Error ? error.message : String(error);
|
|
469
|
+
process.stderr.write(`[conveyor-agent] Ad-hoc runner failed: ${message2}
|
|
468
470
|
`);
|
|
469
|
-
this.connection.sendEvent({ type: "error", message });
|
|
471
|
+
this.connection.sendEvent({ type: "error", message: message2 });
|
|
470
472
|
this._finalState = "error";
|
|
471
473
|
} finally {
|
|
472
474
|
await this.shutdown();
|
|
@@ -620,6 +622,10 @@ var ReviewChildSupervisor = class {
|
|
|
620
622
|
spawnFn;
|
|
621
623
|
child = null;
|
|
622
624
|
childSessionId = null;
|
|
625
|
+
/** The review session this supervisor currently hosts, if any. */
|
|
626
|
+
get activeSessionId() {
|
|
627
|
+
return this.childSessionId;
|
|
628
|
+
}
|
|
623
629
|
/** Spawn (or replace) the review child for a `session:spawnReview` push. */
|
|
624
630
|
async spawn(data) {
|
|
625
631
|
logger2.info("Spawning same-pod review child", {
|
|
@@ -653,10 +659,10 @@ var ReviewChildSupervisor = class {
|
|
|
653
659
|
this.childSessionId = data.sessionId;
|
|
654
660
|
const spawnedAt = Date.now();
|
|
655
661
|
let reported = false;
|
|
656
|
-
const reportOnce = (
|
|
662
|
+
const reportOnce = (message2) => {
|
|
657
663
|
if (reported) return;
|
|
658
664
|
reported = true;
|
|
659
|
-
this.connection.reportReviewSpawnFailure(data.sessionId,
|
|
665
|
+
this.connection.reportReviewSpawnFailure(data.sessionId, message2);
|
|
660
666
|
};
|
|
661
667
|
child.stdout?.on("data", (chunk) => {
|
|
662
668
|
process.stdout.write(`[review-child] ${chunk.toString()}`);
|
|
@@ -776,6 +782,10 @@ var SessionChildSupervisor = class {
|
|
|
776
782
|
get size() {
|
|
777
783
|
return this.children.size;
|
|
778
784
|
}
|
|
785
|
+
/** Sessions this supervisor currently hosts. Drives the shutdown deferral. */
|
|
786
|
+
get activeSessionIds() {
|
|
787
|
+
return [...this.children.keys()];
|
|
788
|
+
}
|
|
779
789
|
/** Spawn a TUI/shell child for a `session:spawnTui` push. Additive per session. */
|
|
780
790
|
async spawn(data) {
|
|
781
791
|
logger3.info("Spawning same-pod session child", {
|
|
@@ -806,10 +816,10 @@ var SessionChildSupervisor = class {
|
|
|
806
816
|
this.children.set(data.sessionId, child);
|
|
807
817
|
const spawnedAt = Date.now();
|
|
808
818
|
let reported = false;
|
|
809
|
-
const reportOnce = (
|
|
819
|
+
const reportOnce = (message2) => {
|
|
810
820
|
if (reported) return;
|
|
811
821
|
reported = true;
|
|
812
|
-
this.connection.reportSessionSpawnFailure(data.sessionId,
|
|
822
|
+
this.connection.reportSessionSpawnFailure(data.sessionId, message2);
|
|
813
823
|
};
|
|
814
824
|
const prefix = `[${data.mode}-child]`;
|
|
815
825
|
child.stdout?.on("data", (chunk) => {
|
|
@@ -936,10 +946,10 @@ var ShellSessionRunner = class {
|
|
|
936
946
|
await this.runShell();
|
|
937
947
|
this._finalState = "finished";
|
|
938
948
|
} catch (error) {
|
|
939
|
-
const
|
|
940
|
-
process.stderr.write(`[conveyor-agent] Shell runner failed: ${
|
|
949
|
+
const message2 = error instanceof Error ? error.message : String(error);
|
|
950
|
+
process.stderr.write(`[conveyor-agent] Shell runner failed: ${message2}
|
|
941
951
|
`);
|
|
942
|
-
this.connection.sendEvent({ type: "error", message });
|
|
952
|
+
this.connection.sendEvent({ type: "error", message: message2 });
|
|
943
953
|
this._finalState = "error";
|
|
944
954
|
} finally {
|
|
945
955
|
this.shutdown();
|
|
@@ -1033,14 +1043,158 @@ function createSpawnedChildRunner(inputs) {
|
|
|
1033
1043
|
);
|
|
1034
1044
|
}
|
|
1035
1045
|
|
|
1046
|
+
// src/runner/builder-child.ts
|
|
1047
|
+
import { spawn as nodeSpawn3 } from "child_process";
|
|
1048
|
+
var logger5 = createServiceLogger("BuilderChild");
|
|
1049
|
+
function buildBuilderChildEnv(baseEnv, data) {
|
|
1050
|
+
const env = { ...baseEnv };
|
|
1051
|
+
env.CONVEYOR_TASK_TOKEN = data.sessionJwt;
|
|
1052
|
+
env.CONVEYOR_SESSION_ID = data.sessionId;
|
|
1053
|
+
env.CONVEYOR_MODE = data.mode ?? "task";
|
|
1054
|
+
env.CONVEYOR_WORKBENCH_TOKEN ??= baseEnv.POD_BOOTSTRAP_TOKEN;
|
|
1055
|
+
delete env.POD_BOOTSTRAP_TOKEN;
|
|
1056
|
+
delete env.CONVEYOR_BOOTSTRAP_TOKEN;
|
|
1057
|
+
delete env.CONVEYOR_START_COMMAND;
|
|
1058
|
+
delete env.CONVEYOR_GIT_READY;
|
|
1059
|
+
delete env.CONVEYOR_GIT_READY_MARKER;
|
|
1060
|
+
delete env.CONVEYOR_AGENT_MODE;
|
|
1061
|
+
delete env.CONVEYOR_IS_AUTO;
|
|
1062
|
+
return env;
|
|
1063
|
+
}
|
|
1064
|
+
var BuilderChildSupervisor = class {
|
|
1065
|
+
constructor(connection, workspaceDir, spawnFn = nodeSpawn3) {
|
|
1066
|
+
this.connection = connection;
|
|
1067
|
+
this.workspaceDir = workspaceDir;
|
|
1068
|
+
this.spawnFn = spawnFn;
|
|
1069
|
+
}
|
|
1070
|
+
connection;
|
|
1071
|
+
workspaceDir;
|
|
1072
|
+
spawnFn;
|
|
1073
|
+
child = null;
|
|
1074
|
+
childSessionId = null;
|
|
1075
|
+
/** The build session this supervisor currently hosts, if any. */
|
|
1076
|
+
get activeSessionId() {
|
|
1077
|
+
return this.childSessionId;
|
|
1078
|
+
}
|
|
1079
|
+
/** Spawn (or replace) the builder child for a `session:spawnBuilder` push. */
|
|
1080
|
+
async spawn(data) {
|
|
1081
|
+
if (this.childSessionId === data.sessionId && this.child && this.child.exitCode === null) {
|
|
1082
|
+
logger5.info("Builder child already running for this session; ignoring re-push", {
|
|
1083
|
+
buildSessionId: data.sessionId
|
|
1084
|
+
});
|
|
1085
|
+
return;
|
|
1086
|
+
}
|
|
1087
|
+
logger5.info("Spawning same-pod builder child", {
|
|
1088
|
+
buildSessionId: data.sessionId,
|
|
1089
|
+
branch: data.branch ?? void 0,
|
|
1090
|
+
agentName: data.agentName ?? void 0
|
|
1091
|
+
});
|
|
1092
|
+
await this.stopCurrent("superseded by new builder spawn");
|
|
1093
|
+
const cliPath = process.argv[1];
|
|
1094
|
+
if (!cliPath) {
|
|
1095
|
+
this.connection.reportBuilderSpawnFailure(data.sessionId, "cannot resolve CLI entry path");
|
|
1096
|
+
return;
|
|
1097
|
+
}
|
|
1098
|
+
let child;
|
|
1099
|
+
try {
|
|
1100
|
+
child = this.spawnFn(process.execPath, [cliPath], {
|
|
1101
|
+
cwd: this.workspaceDir,
|
|
1102
|
+
env: buildBuilderChildEnv(process.env, data),
|
|
1103
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
1104
|
+
});
|
|
1105
|
+
} catch (err) {
|
|
1106
|
+
this.connection.reportBuilderSpawnFailure(
|
|
1107
|
+
data.sessionId,
|
|
1108
|
+
err instanceof Error ? err.message : String(err)
|
|
1109
|
+
);
|
|
1110
|
+
return;
|
|
1111
|
+
}
|
|
1112
|
+
this.child = child;
|
|
1113
|
+
this.childSessionId = data.sessionId;
|
|
1114
|
+
this.watchForEarlyExit(child, data.sessionId);
|
|
1115
|
+
}
|
|
1116
|
+
/**
|
|
1117
|
+
* A non-zero exit inside the grace window is a spawn failure, not a finished
|
|
1118
|
+
* build — the child never got far enough to connect. Reporting it lets the
|
|
1119
|
+
* server End the orphaned session and fall back to a cold boot instead of
|
|
1120
|
+
* leaving the card parked with a Builder tab that never appears.
|
|
1121
|
+
*/
|
|
1122
|
+
watchForEarlyExit(child, sessionId) {
|
|
1123
|
+
const spawnedAt = Date.now();
|
|
1124
|
+
child.on("exit", (code) => {
|
|
1125
|
+
if (this.childSessionId === sessionId) {
|
|
1126
|
+
this.child = null;
|
|
1127
|
+
this.childSessionId = null;
|
|
1128
|
+
}
|
|
1129
|
+
const early = Date.now() - spawnedAt < SPAWN_FAILURE_GRACE_MS;
|
|
1130
|
+
if (early && code !== 0) {
|
|
1131
|
+
logger5.warn("Builder child exited inside the spawn grace window", { sessionId, code });
|
|
1132
|
+
this.connection.reportBuilderSpawnFailure(sessionId, `child exited with code ${code}`);
|
|
1133
|
+
}
|
|
1134
|
+
});
|
|
1135
|
+
}
|
|
1136
|
+
/** SIGTERM the current child, escalating to SIGKILL after KILL_WAIT_MS. */
|
|
1137
|
+
async stopCurrent(reason) {
|
|
1138
|
+
const child = this.child;
|
|
1139
|
+
if (!child || child.exitCode !== null) {
|
|
1140
|
+
this.child = null;
|
|
1141
|
+
this.childSessionId = null;
|
|
1142
|
+
return;
|
|
1143
|
+
}
|
|
1144
|
+
logger5.info("Stopping builder child", { reason, buildSessionId: this.childSessionId });
|
|
1145
|
+
child.kill("SIGTERM");
|
|
1146
|
+
await new Promise((resolve) => {
|
|
1147
|
+
const timer = setTimeout(() => {
|
|
1148
|
+
if (child.exitCode === null) child.kill("SIGKILL");
|
|
1149
|
+
resolve();
|
|
1150
|
+
}, KILL_WAIT_MS);
|
|
1151
|
+
child.once("exit", () => {
|
|
1152
|
+
clearTimeout(timer);
|
|
1153
|
+
resolve();
|
|
1154
|
+
});
|
|
1155
|
+
});
|
|
1156
|
+
this.child = null;
|
|
1157
|
+
this.childSessionId = null;
|
|
1158
|
+
}
|
|
1159
|
+
};
|
|
1160
|
+
|
|
1036
1161
|
// src/runner/host-modes.ts
|
|
1037
1162
|
function hostsSpawnedChildren(mode) {
|
|
1038
|
-
return mode === "task" || mode === "pack";
|
|
1163
|
+
return mode === "task" || mode === "plan" || mode === "pack";
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
// src/runner/wire-spawn-children.ts
|
|
1167
|
+
var message = (err) => err instanceof Error ? err.message : String(err);
|
|
1168
|
+
function wireSpawnChildren(mode, connection, supervisors, logger7) {
|
|
1169
|
+
if (hostsSpawnedChildren(mode)) {
|
|
1170
|
+
connection.onSpawnReview((data) => {
|
|
1171
|
+
void supervisors.review.spawn(data).catch((err) => {
|
|
1172
|
+
logger7.error("Review child spawn threw", { error: message(err) });
|
|
1173
|
+
connection.reportReviewSpawnFailure(data.sessionId, message(err));
|
|
1174
|
+
});
|
|
1175
|
+
});
|
|
1176
|
+
}
|
|
1177
|
+
if (mode === "plan") {
|
|
1178
|
+
connection.onSpawnBuilder((data) => {
|
|
1179
|
+
void supervisors.builder.spawn(data).catch((err) => {
|
|
1180
|
+
logger7.error("Builder child spawn threw", { error: message(err) });
|
|
1181
|
+
connection.reportBuilderSpawnFailure(data.sessionId, message(err));
|
|
1182
|
+
});
|
|
1183
|
+
});
|
|
1184
|
+
}
|
|
1185
|
+
if (hostsSpawnedChildren(mode)) {
|
|
1186
|
+
connection.onSpawnTui((data) => {
|
|
1187
|
+
void supervisors.session.spawn(data).catch((err) => {
|
|
1188
|
+
logger7.error("Session child spawn threw", { error: message(err) });
|
|
1189
|
+
connection.reportSessionSpawnFailure(data.sessionId, message(err));
|
|
1190
|
+
});
|
|
1191
|
+
});
|
|
1192
|
+
}
|
|
1039
1193
|
}
|
|
1040
1194
|
|
|
1041
1195
|
// src/cli.ts
|
|
1042
1196
|
if (process.argv[2] === "boot") {
|
|
1043
|
-
const { runBoot } = await import("./boot-
|
|
1197
|
+
const { runBoot } = await import("./boot-PKQ2I66D.js");
|
|
1044
1198
|
process.exit(await runBoot(process.argv.slice(3)));
|
|
1045
1199
|
}
|
|
1046
1200
|
if (isLegacyEntrypointLaunch(process.env)) {
|
|
@@ -1055,7 +1209,7 @@ if (process.argv.includes("--version")) {
|
|
|
1055
1209
|
process.stdout.write(pkg.version + "\n");
|
|
1056
1210
|
process.exit(0);
|
|
1057
1211
|
}
|
|
1058
|
-
var
|
|
1212
|
+
var logger6 = createServiceLogger("CLI");
|
|
1059
1213
|
var exitContext = {};
|
|
1060
1214
|
var exitLogged = false;
|
|
1061
1215
|
var shuttingDown = false;
|
|
@@ -1070,12 +1224,12 @@ function logAgentExit(reason, opts) {
|
|
|
1070
1224
|
uptimeSec: process.uptime(),
|
|
1071
1225
|
identity: exitContext
|
|
1072
1226
|
});
|
|
1073
|
-
|
|
1227
|
+
logger6[exitLogLevel(reason)]("agent_exit", payload);
|
|
1074
1228
|
}
|
|
1075
1229
|
async function bootstrapFromCodespace(apiUrl, instanceName) {
|
|
1076
1230
|
const bootstrapToken = process.env.CONVEYOR_BOOTSTRAP_TOKEN;
|
|
1077
1231
|
const apiUrlFromEnv = Boolean(process.env.CONVEYOR_API_URL);
|
|
1078
|
-
|
|
1232
|
+
logger6.info("Bootstrapping from codespace", {
|
|
1079
1233
|
codespace: instanceName,
|
|
1080
1234
|
apiUrl,
|
|
1081
1235
|
apiUrlFromEnv,
|
|
@@ -1087,7 +1241,7 @@ async function bootstrapFromCodespace(apiUrl, instanceName) {
|
|
|
1087
1241
|
bootstrapToken
|
|
1088
1242
|
});
|
|
1089
1243
|
if (!result.ok) {
|
|
1090
|
-
|
|
1244
|
+
logger6.error("Bootstrap failed after retries", {
|
|
1091
1245
|
reason: result.reason,
|
|
1092
1246
|
attempts: result.attempts,
|
|
1093
1247
|
status: result.status,
|
|
@@ -1100,20 +1254,20 @@ async function bootstrapFromCodespace(apiUrl, instanceName) {
|
|
|
1100
1254
|
process.exit(1);
|
|
1101
1255
|
}
|
|
1102
1256
|
applyBootstrapToEnv(result.config);
|
|
1103
|
-
|
|
1257
|
+
logger6.info("Bootstrap complete", {
|
|
1104
1258
|
taskId: result.config.taskId,
|
|
1105
1259
|
attempts: result.attempts
|
|
1106
1260
|
});
|
|
1107
1261
|
}
|
|
1108
1262
|
function isExpectedAbortError(error) {
|
|
1109
|
-
const
|
|
1110
|
-
const hasAbortMessage = /operation aborted/i.test(
|
|
1263
|
+
const message2 = error.message || "";
|
|
1264
|
+
const hasAbortMessage = /operation aborted/i.test(message2) || /abort/i.test(message2);
|
|
1111
1265
|
const hasAbortCode = !("code" in error) || error.code === void 0 || error.code === "ABORT_ERR";
|
|
1112
1266
|
return hasAbortMessage && hasAbortCode;
|
|
1113
1267
|
}
|
|
1114
1268
|
function exitOnPermissionDenial(err) {
|
|
1115
1269
|
if (!isPermissionDeniedError(err)) return false;
|
|
1116
|
-
|
|
1270
|
+
logger6.error("Not authorized for this project \u2014 parking instead of crash-looping", {
|
|
1117
1271
|
error: err.message
|
|
1118
1272
|
});
|
|
1119
1273
|
logAgentExit("unauthorized", { exitCode: 0 });
|
|
@@ -1122,22 +1276,22 @@ function exitOnPermissionDenial(err) {
|
|
|
1122
1276
|
process.on("uncaughtException", (err) => {
|
|
1123
1277
|
if (err.code === "EPIPE") return;
|
|
1124
1278
|
if (shuttingDown && isExpectedAbortError(err)) {
|
|
1125
|
-
|
|
1279
|
+
logger6.info("Ignored expected abort after shutdown", { error: err.message, code: err.code });
|
|
1126
1280
|
return;
|
|
1127
1281
|
}
|
|
1128
1282
|
if (exitOnPermissionDenial(err)) return;
|
|
1129
|
-
|
|
1283
|
+
logger6.error("Uncaught exception", { error: err.message, code: err.code });
|
|
1130
1284
|
logAgentExit("uncaught_exception", { exitCode: 1 });
|
|
1131
1285
|
process.exit(1);
|
|
1132
1286
|
});
|
|
1133
1287
|
process.on("unhandledRejection", (reason) => {
|
|
1134
1288
|
const err = reason instanceof Error ? reason : new Error(String(reason));
|
|
1135
1289
|
if (shuttingDown && isExpectedAbortError(err)) {
|
|
1136
|
-
|
|
1290
|
+
logger6.info("Ignored expected abort rejection after shutdown", { error: err.message });
|
|
1137
1291
|
return;
|
|
1138
1292
|
}
|
|
1139
1293
|
if (exitOnPermissionDenial(err)) return;
|
|
1140
|
-
|
|
1294
|
+
logger6.error("Unhandled rejection", { error: err.message });
|
|
1141
1295
|
logAgentExit("unhandled_rejection", { exitCode: 1 });
|
|
1142
1296
|
process.exit(1);
|
|
1143
1297
|
});
|
|
@@ -1148,7 +1302,7 @@ if (process.env.CONVEYOR_MODE === "workbench") {
|
|
|
1148
1302
|
const port = Number(process.env.CONVEYOR_WORKBENCH_PORT) || DEFAULT_WORKBENCH_PORT;
|
|
1149
1303
|
const token = process.env.CONVEYOR_WORKBENCH_TOKEN ?? process.env.POD_BOOTSTRAP_TOKEN ?? "";
|
|
1150
1304
|
if (!token) {
|
|
1151
|
-
|
|
1305
|
+
logger6.error("workbench mode requires POD_BOOTSTRAP_TOKEN (or CONVEYOR_WORKBENCH_TOKEN)");
|
|
1152
1306
|
process.exit(1);
|
|
1153
1307
|
}
|
|
1154
1308
|
const pkgDir = dirname(fileURLToPath(import.meta.url));
|
|
@@ -1158,12 +1312,12 @@ if (process.env.CONVEYOR_MODE === "workbench") {
|
|
|
1158
1312
|
token,
|
|
1159
1313
|
version: pkg.version ?? "unknown",
|
|
1160
1314
|
oomWatchdog: oomWatchdogOptionsFromEnv({
|
|
1161
|
-
info: (m) =>
|
|
1162
|
-
warn: (m) =>
|
|
1163
|
-
error: (m) =>
|
|
1315
|
+
info: (m) => logger6.info(m),
|
|
1316
|
+
warn: (m) => logger6.warn(m),
|
|
1317
|
+
error: (m) => logger6.error(m)
|
|
1164
1318
|
})
|
|
1165
1319
|
});
|
|
1166
|
-
|
|
1320
|
+
logger6.info(`Workbench launcher listening on 127.0.0.1:${handle.port}`);
|
|
1167
1321
|
process.on("SIGTERM", () => process.exit(0));
|
|
1168
1322
|
await new Promise(() => {
|
|
1169
1323
|
});
|
|
@@ -1173,7 +1327,7 @@ var conveyorApiUrl = process.env.CONVEYOR_API_URL || DEFAULT_CONVEYOR_API_URL;
|
|
|
1173
1327
|
var INSTANCE_NAME = process.env.CODESPACE_NAME || process.env.CLAUDESPACE_NAME;
|
|
1174
1328
|
if (INSTANCE_NAME && !process.env.CONVEYOR_TASK_TOKEN) {
|
|
1175
1329
|
if (!conveyorApiUrl) {
|
|
1176
|
-
|
|
1330
|
+
logger6.error("Could not resolve CONVEYOR_API_URL for codespace bootstrap");
|
|
1177
1331
|
process.exit(1);
|
|
1178
1332
|
}
|
|
1179
1333
|
await bootstrapFromCodespace(conveyorApiUrl, INSTANCE_NAME);
|
|
@@ -1191,7 +1345,7 @@ exitContext.runnerMode = CONVEYOR_MODE;
|
|
|
1191
1345
|
exitContext.sessionId = process.env.CONVEYOR_SESSION_ID ?? CONVEYOR_TASK_ID;
|
|
1192
1346
|
var projectIdentity = resolveProjectRunnerIdentity(process.env);
|
|
1193
1347
|
if (!CONVEYOR_TASK_ID && projectIdentity && CONVEYOR_MODE === "adhoc") {
|
|
1194
|
-
|
|
1348
|
+
logger6.info("Starting ad-hoc agent", { projectId: projectIdentity.projectId });
|
|
1195
1349
|
const adhocRunner = new AdhocSessionRunner(
|
|
1196
1350
|
{
|
|
1197
1351
|
connection: {
|
|
@@ -1210,7 +1364,7 @@ if (!CONVEYOR_TASK_ID && projectIdentity && CONVEYOR_MODE === "adhoc") {
|
|
|
1210
1364
|
},
|
|
1211
1365
|
{
|
|
1212
1366
|
onEvent: (event) => {
|
|
1213
|
-
|
|
1367
|
+
logger6.info("Ad-hoc runner event", { eventType: event.type });
|
|
1214
1368
|
}
|
|
1215
1369
|
}
|
|
1216
1370
|
);
|
|
@@ -1234,7 +1388,7 @@ if (!CONVEYOR_TASK_ID && projectIdentity && CONVEYOR_MODE === "adhoc") {
|
|
|
1234
1388
|
process.exit(adhocError ? 1 : 0);
|
|
1235
1389
|
}
|
|
1236
1390
|
if (!CONVEYOR_TASK_ID && projectIdentity) {
|
|
1237
|
-
|
|
1391
|
+
logger6.info("Starting project agent", { projectId: projectIdentity.projectId });
|
|
1238
1392
|
const projectRunner = new ProjectSessionRunner(
|
|
1239
1393
|
{
|
|
1240
1394
|
connection: {
|
|
@@ -1249,7 +1403,7 @@ if (!CONVEYOR_TASK_ID && projectIdentity) {
|
|
|
1249
1403
|
},
|
|
1250
1404
|
{
|
|
1251
1405
|
onEvent: (event) => {
|
|
1252
|
-
|
|
1406
|
+
logger6.info("Project runner event", { eventType: event.type });
|
|
1253
1407
|
}
|
|
1254
1408
|
}
|
|
1255
1409
|
);
|
|
@@ -1273,29 +1427,26 @@ if (!CONVEYOR_TASK_ID && projectIdentity) {
|
|
|
1273
1427
|
process.exit(projectError ? 1 : 0);
|
|
1274
1428
|
}
|
|
1275
1429
|
if (!CONVEYOR_TASK_TOKEN || !CONVEYOR_TASK_ID) {
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1430
|
+
logger6.error("Missing required environment variables");
|
|
1431
|
+
logger6.error(" CONVEYOR_TASK_TOKEN - JWT token for task authentication");
|
|
1432
|
+
logger6.error(" CONVEYOR_TASK_ID - ID of the task to execute");
|
|
1433
|
+
logger6.error("");
|
|
1434
|
+
logger6.error("CONVEYOR_API_URL is provided via codespace secret or bootstrap.");
|
|
1435
|
+
logger6.error("");
|
|
1436
|
+
logger6.error("Optional:");
|
|
1437
|
+
logger6.error(" CONVEYOR_MODE - Runner mode: 'task' (default), 'pack', or 'pm'");
|
|
1438
|
+
logger6.error(" CONVEYOR_WORKSPACE - Working directory (defaults to cwd)");
|
|
1439
|
+
logger6.error(
|
|
1286
1440
|
" Project pods instead require CONVEYOR_PROJECT_ID + CONVEYOR_SESSION_ID + CONVEYOR_MODE=pm"
|
|
1287
1441
|
);
|
|
1288
1442
|
process.exit(1);
|
|
1289
1443
|
}
|
|
1290
|
-
if (CONVEYOR_MODE
|
|
1291
|
-
|
|
1292
|
-
mode: CONVEYOR_MODE,
|
|
1293
|
-
expected: ["task", "pm", "code-review", "adhoc", "pack", "shell", "serving"]
|
|
1294
|
-
});
|
|
1444
|
+
if (!RUNNER_MODES.includes(CONVEYOR_MODE)) {
|
|
1445
|
+
logger6.error("Invalid CONVEYOR_MODE", { mode: CONVEYOR_MODE, expected: RUNNER_MODES });
|
|
1295
1446
|
process.exit(1);
|
|
1296
1447
|
}
|
|
1297
1448
|
if (CONVEYOR_MODE === "serving") {
|
|
1298
|
-
const { runServingSession } = await import("./serve-boot-
|
|
1449
|
+
const { runServingSession } = await import("./serve-boot-YPAUKENG.js");
|
|
1299
1450
|
exitContext.runnerMode = "serving";
|
|
1300
1451
|
exitContext.sessionId = process.env.CONVEYOR_SESSION_ID ?? exitContext.sessionId;
|
|
1301
1452
|
const outcome = await runServingSession({
|
|
@@ -1315,7 +1466,7 @@ if (CONVEYOR_MODE === "serving") {
|
|
|
1315
1466
|
if (CONVEYOR_MODE === "shell" || CONVEYOR_MODE === "adhoc") {
|
|
1316
1467
|
const spawnedSessionId = process.env.CONVEYOR_SESSION_ID;
|
|
1317
1468
|
if (!spawnedSessionId) {
|
|
1318
|
-
|
|
1469
|
+
logger6.error("Spawned child requires CONVEYOR_SESSION_ID", { mode: CONVEYOR_MODE });
|
|
1319
1470
|
process.exit(1);
|
|
1320
1471
|
}
|
|
1321
1472
|
exitContext.sessionId = spawnedSessionId;
|
|
@@ -1328,7 +1479,7 @@ if (CONVEYOR_MODE === "shell" || CONVEYOR_MODE === "adhoc") {
|
|
|
1328
1479
|
workspaceDir: CONVEYOR_WORKSPACE,
|
|
1329
1480
|
projectId: process.env.CONVEYOR_PROJECT_ID ?? ""
|
|
1330
1481
|
});
|
|
1331
|
-
|
|
1482
|
+
logger6.info("Starting spawned session child", {
|
|
1332
1483
|
mode: CONVEYOR_MODE,
|
|
1333
1484
|
sessionId: spawnedSessionId
|
|
1334
1485
|
});
|
|
@@ -1348,7 +1499,7 @@ if (CONVEYOR_MODE === "shell" || CONVEYOR_MODE === "adhoc") {
|
|
|
1348
1499
|
});
|
|
1349
1500
|
process.exit(childError ? 1 : 0);
|
|
1350
1501
|
}
|
|
1351
|
-
|
|
1502
|
+
logger6.info("Starting agent", { mode: CONVEYOR_MODE });
|
|
1352
1503
|
var lifecycleOverrides = process.env.CLAUDESPACE_NAME ? { idleTimeoutMs: 60 * 60 * 1e3 } : { gitFlushIntervalMs: 0 };
|
|
1353
1504
|
var runner = new SessionRunner(
|
|
1354
1505
|
{
|
|
@@ -1361,6 +1512,10 @@ var runner = new SessionRunner(
|
|
|
1361
1512
|
runnerMode: CONVEYOR_MODE
|
|
1362
1513
|
},
|
|
1363
1514
|
runnerMode: CONVEYOR_MODE,
|
|
1515
|
+
// Only read when the mode is "pack". Parsed rather than cast so an unset or
|
|
1516
|
+
// malformed value falls back to single-pod instead of selecting a third,
|
|
1517
|
+
// non-existent behavior.
|
|
1518
|
+
packExecution: parsePackExecution(process.env.CONVEYOR_PACK_EXECUTION),
|
|
1364
1519
|
isAuto: CONVEYOR_IS_AUTO,
|
|
1365
1520
|
workspaceDir: CONVEYOR_WORKSPACE,
|
|
1366
1521
|
agentMode: CONVEYOR_AGENT_MODE,
|
|
@@ -1368,29 +1523,51 @@ var runner = new SessionRunner(
|
|
|
1368
1523
|
},
|
|
1369
1524
|
{
|
|
1370
1525
|
onStatusChange: (status) => {
|
|
1371
|
-
|
|
1526
|
+
logger6.info("Status changed", { status });
|
|
1372
1527
|
},
|
|
1373
1528
|
onEvent: (event) => {
|
|
1374
1529
|
const detail = event.message ?? event.content ?? event.summary ?? "";
|
|
1375
1530
|
if (detail) {
|
|
1376
|
-
|
|
1531
|
+
logger6.info(detail, { eventType: event.type });
|
|
1377
1532
|
}
|
|
1378
1533
|
}
|
|
1379
1534
|
}
|
|
1380
1535
|
);
|
|
1381
1536
|
var reviewChildren = new ReviewChildSupervisor(runner.connection, CONVEYOR_WORKSPACE);
|
|
1382
1537
|
var sessionChildren = new SessionChildSupervisor(runner.connection, CONVEYOR_WORKSPACE);
|
|
1538
|
+
var builderChildren = new BuilderChildSupervisor(runner.connection, CONVEYOR_WORKSPACE);
|
|
1539
|
+
runner.setLiveChildSources([
|
|
1540
|
+
{
|
|
1541
|
+
kind: "builder",
|
|
1542
|
+
activeSessionIds: () => {
|
|
1543
|
+
const id = builderChildren.activeSessionId;
|
|
1544
|
+
return id ? [id] : [];
|
|
1545
|
+
}
|
|
1546
|
+
},
|
|
1547
|
+
{
|
|
1548
|
+
kind: "review",
|
|
1549
|
+
activeSessionIds: () => {
|
|
1550
|
+
const id = reviewChildren.activeSessionId;
|
|
1551
|
+
return id ? [id] : [];
|
|
1552
|
+
}
|
|
1553
|
+
},
|
|
1554
|
+
{ kind: "tui", activeSessionIds: () => sessionChildren.activeSessionIds }
|
|
1555
|
+
]);
|
|
1383
1556
|
var shutdownSignal;
|
|
1384
1557
|
var workspaceCommandSupervisor = null;
|
|
1385
1558
|
var shutdownCompletion = null;
|
|
1386
1559
|
var shutdownAgent = (signal) => {
|
|
1387
1560
|
shuttingDown = true;
|
|
1388
|
-
|
|
1561
|
+
logger6.info(`Received ${signal}, flushing git and stopping agent`);
|
|
1389
1562
|
const commandShutdown = stopWorkspaceCommands(workspaceCommandSupervisor);
|
|
1390
1563
|
shutdownSignal = signal;
|
|
1391
1564
|
shutdownCompletion ??= (async () => {
|
|
1392
1565
|
try {
|
|
1393
|
-
await Promise.all([
|
|
1566
|
+
await Promise.all([
|
|
1567
|
+
reviewChildren.stopAll(),
|
|
1568
|
+
sessionChildren.stopAll(),
|
|
1569
|
+
builderChildren.stopCurrent("agent shutdown")
|
|
1570
|
+
]);
|
|
1394
1571
|
} catch {
|
|
1395
1572
|
}
|
|
1396
1573
|
try {
|
|
@@ -1402,8 +1579,8 @@ var shutdownAgent = (signal) => {
|
|
|
1402
1579
|
})();
|
|
1403
1580
|
void shutdownCompletion;
|
|
1404
1581
|
setTimeout(() => {
|
|
1405
|
-
|
|
1406
|
-
|
|
1582
|
+
logger6.warn(`Forcing exit after ${signal} timeout`);
|
|
1583
|
+
logger6.warn(
|
|
1407
1584
|
"agent_exit",
|
|
1408
1585
|
buildAgentExitLog({
|
|
1409
1586
|
reason: "force_timeout",
|
|
@@ -1429,7 +1606,7 @@ workspaceCommandSupervisor = await startWorkspaceCommandsAfterConnect({
|
|
|
1429
1606
|
})
|
|
1430
1607
|
});
|
|
1431
1608
|
if (!workspaceCommandSupervisor) {
|
|
1432
|
-
|
|
1609
|
+
logger6.info("Agent stopped before workspace commands were started");
|
|
1433
1610
|
if (shutdownCompletion) await shutdownCompletion;
|
|
1434
1611
|
logAgentExit(shutdownSignal ? "signal" : "clean", {
|
|
1435
1612
|
exitCode: 0,
|
|
@@ -1449,34 +1626,14 @@ void checkSessionTaskIdentity({
|
|
|
1449
1626
|
});
|
|
1450
1627
|
return ctx.id;
|
|
1451
1628
|
},
|
|
1452
|
-
logger:
|
|
1629
|
+
logger: logger6
|
|
1453
1630
|
});
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
runner.connection.reportReviewSpawnFailure(
|
|
1461
|
-
data.sessionId,
|
|
1462
|
-
err instanceof Error ? err.message : String(err)
|
|
1463
|
-
);
|
|
1464
|
-
});
|
|
1465
|
-
});
|
|
1466
|
-
}
|
|
1467
|
-
if (hostsSpawnedChildren(CONVEYOR_MODE)) {
|
|
1468
|
-
runner.connection.onSpawnTui((data) => {
|
|
1469
|
-
void sessionChildren.spawn(data).catch((err) => {
|
|
1470
|
-
logger5.error("Session child spawn threw", {
|
|
1471
|
-
error: err instanceof Error ? err.message : String(err)
|
|
1472
|
-
});
|
|
1473
|
-
runner.connection.reportSessionSpawnFailure(
|
|
1474
|
-
data.sessionId,
|
|
1475
|
-
err instanceof Error ? err.message : String(err)
|
|
1476
|
-
);
|
|
1477
|
-
});
|
|
1478
|
-
});
|
|
1479
|
-
}
|
|
1631
|
+
wireSpawnChildren(
|
|
1632
|
+
CONVEYOR_MODE,
|
|
1633
|
+
runner.connection,
|
|
1634
|
+
{ review: reviewChildren, builder: builderChildren, session: sessionChildren },
|
|
1635
|
+
logger6
|
|
1636
|
+
);
|
|
1480
1637
|
runner.run().then(async () => {
|
|
1481
1638
|
await stopWorkspaceCommands(workspaceCommandSupervisor);
|
|
1482
1639
|
const errored = runner.finalState === "error";
|
|
@@ -1490,7 +1647,7 @@ runner.run().then(async () => {
|
|
|
1490
1647
|
}).catch(async (error) => {
|
|
1491
1648
|
await stopWorkspaceCommands(workspaceCommandSupervisor);
|
|
1492
1649
|
const msg = error instanceof Error ? error.message : String(error);
|
|
1493
|
-
|
|
1650
|
+
logger6.error("Agent runner failed", { error: msg });
|
|
1494
1651
|
logAgentExit("error", { exitCode: 1, finalState: runner.finalState ?? void 0 });
|
|
1495
1652
|
process.exit(1);
|
|
1496
1653
|
});
|