@rallycry/conveyor-agent 11.0.2 → 11.0.4
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/chunk-7P6QZHXZ.js +76 -0
- package/dist/{chunk-QETNCXIR.js → chunk-HYPX6FEX.js} +410 -163
- package/dist/{chunk-JQVAWRVL.js → chunk-URYBO32C.js} +40 -6
- package/dist/cli.js +25 -17
- package/dist/gate-cli.d.ts +1 -0
- package/dist/gate-cli.js +85 -0
- package/dist/index.d.ts +83 -11
- package/dist/index.js +9 -8
- package/dist/{serve-boot-YPAUKENG.js → serve-boot-B4BIZMNB.js} +3 -3
- package/package.json +3 -2
- package/skills/conveyor-build/SKILL.md +10 -0
- package/dist/{boot-PKQ2I66D.js → boot-SWUVT5B4.js} +5 -5
- package/dist/{chunk-N4WSUTGV.js → chunk-SLUBOIYE.js} +6 -6
|
@@ -5,21 +5,21 @@ import {
|
|
|
5
5
|
readWorkspaceBytes,
|
|
6
6
|
statWorkspacePath,
|
|
7
7
|
workspacePathExists
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-SLUBOIYE.js";
|
|
9
9
|
import {
|
|
10
10
|
reportBootMilestone
|
|
11
11
|
} from "./chunk-GL2DIQEQ.js";
|
|
12
|
+
import {
|
|
13
|
+
runSetupCommand,
|
|
14
|
+
runStartCommand,
|
|
15
|
+
terminateProcessGroup
|
|
16
|
+
} from "./chunk-W4LZ7R6Z.js";
|
|
12
17
|
import {
|
|
13
18
|
getWorkbenchClient
|
|
14
19
|
} from "./chunk-EXQ6AHOY.js";
|
|
15
20
|
import {
|
|
16
21
|
workbenchEnabled
|
|
17
22
|
} from "./chunk-KMB3BU4S.js";
|
|
18
|
-
import {
|
|
19
|
-
runSetupCommand,
|
|
20
|
-
runStartCommand,
|
|
21
|
-
terminateProcessGroup
|
|
22
|
-
} from "./chunk-W4LZ7R6Z.js";
|
|
23
23
|
|
|
24
24
|
// src/setup/db-schema-sync.ts
|
|
25
25
|
import { basename, dirname, join } from "path";
|
|
@@ -226,6 +226,30 @@ async function runDepsSync(options) {
|
|
|
226
226
|
}
|
|
227
227
|
}
|
|
228
228
|
|
|
229
|
+
// src/setup/turbo-cache-diagnostic.ts
|
|
230
|
+
import { join as join3 } from "path";
|
|
231
|
+
var TURBO_CACHE_ENV_VARS = [
|
|
232
|
+
"TURBO_API",
|
|
233
|
+
"TURBO_TOKEN",
|
|
234
|
+
"TURBO_TEAM",
|
|
235
|
+
"TURBO_REMOTE_CACHE_SIGNATURE_KEY"
|
|
236
|
+
];
|
|
237
|
+
function describeTurboCacheEnv(env) {
|
|
238
|
+
const missing = TURBO_CACHE_ENV_VARS.filter((name) => !env[name]?.trim());
|
|
239
|
+
if (missing.length === 0) return "[turbo-cache] remote cache: configured";
|
|
240
|
+
return `[turbo-cache] remote cache: absent (missing ${missing.join(", ")}) \u2014 gates run turbo-cold; set the TURBO_* project secrets to restore remote cache hits`;
|
|
241
|
+
}
|
|
242
|
+
async function reportTurboCacheEnv(options) {
|
|
243
|
+
const pathExists = options.pathExists ?? workspacePathExists;
|
|
244
|
+
try {
|
|
245
|
+
if (!await pathExists(join3(options.workspaceDir, "turbo.json"))) return;
|
|
246
|
+
} catch {
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
options.onOutput("stdout", `${describeTurboCacheEnv(options.env)}
|
|
250
|
+
`);
|
|
251
|
+
}
|
|
252
|
+
|
|
229
253
|
// src/setup/sidecars.ts
|
|
230
254
|
import net from "net";
|
|
231
255
|
var POSTGRES_TIMEOUT_MS = 12e4;
|
|
@@ -409,6 +433,7 @@ var WorkspaceCommandSupervisor = class {
|
|
|
409
433
|
runStartCommandFn;
|
|
410
434
|
syncDbSchemaFn;
|
|
411
435
|
syncDepsFn;
|
|
436
|
+
reportTurboCacheFn;
|
|
412
437
|
loadForwardPortsFn;
|
|
413
438
|
writeOutput;
|
|
414
439
|
terminateStartCommand;
|
|
@@ -461,6 +486,11 @@ var WorkspaceCommandSupervisor = class {
|
|
|
461
486
|
onOutput: opts.onOutput,
|
|
462
487
|
signal: opts.signal
|
|
463
488
|
}));
|
|
489
|
+
this.reportTurboCacheFn = options.reportTurboCache ?? ((opts) => reportTurboCacheEnv({
|
|
490
|
+
workspaceDir: this.workspaceDir,
|
|
491
|
+
env: this.env,
|
|
492
|
+
onOutput: opts.onOutput
|
|
493
|
+
}));
|
|
464
494
|
this.loadForwardPortsFn = options.loadForwardPorts ?? loadForwardPorts;
|
|
465
495
|
this.writeOutput = options.writeOutput ?? defaultWriteOutput;
|
|
466
496
|
this.terminateStartCommand = options.terminateStartCommand ?? terminateProcessGroup;
|
|
@@ -521,6 +551,10 @@ var WorkspaceCommandSupervisor = class {
|
|
|
521
551
|
this.reportBootMilestoneFn("sidecars_ready");
|
|
522
552
|
await this.loopReady;
|
|
523
553
|
if (this.stopped) return;
|
|
554
|
+
await this.reportTurboCacheFn({
|
|
555
|
+
onOutput: (stream, data) => this.forwardSetupOutput(stream, data)
|
|
556
|
+
});
|
|
557
|
+
if (this.stopped) return;
|
|
524
558
|
await this.syncDeps();
|
|
525
559
|
if (this.stopped) return;
|
|
526
560
|
await this.syncDbSchema();
|
package/dist/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
WorkspaceCommandSupervisor,
|
|
8
8
|
startWorkspaceCommandsAfterConnect,
|
|
9
9
|
stopWorkspaceCommands
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-URYBO32C.js";
|
|
11
11
|
import {
|
|
12
12
|
DEFAULT_SONNET_MODEL,
|
|
13
13
|
PtyHarness,
|
|
@@ -27,8 +27,13 @@ import {
|
|
|
27
27
|
resolveTuiKindFromEnv,
|
|
28
28
|
runUsageProbe,
|
|
29
29
|
sampleKeyUsage
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-HYPX6FEX.js";
|
|
31
31
|
import "./chunk-XORJ6SII.js";
|
|
32
|
+
import {
|
|
33
|
+
inheritedEnv,
|
|
34
|
+
resolvePtySpawn,
|
|
35
|
+
sessionTempBase
|
|
36
|
+
} from "./chunk-3F4ZZKCA.js";
|
|
32
37
|
import {
|
|
33
38
|
AgentConnection,
|
|
34
39
|
CodespacePortVisibility,
|
|
@@ -39,17 +44,13 @@ import {
|
|
|
39
44
|
createServiceLogger,
|
|
40
45
|
fetchBootstrap,
|
|
41
46
|
loadConveyorConfig
|
|
42
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-SLUBOIYE.js";
|
|
43
48
|
import "./chunk-GL2DIQEQ.js";
|
|
49
|
+
import "./chunk-W4LZ7R6Z.js";
|
|
50
|
+
import "./chunk-7P6QZHXZ.js";
|
|
44
51
|
import "./chunk-IA45XHOA.js";
|
|
45
52
|
import "./chunk-EXQ6AHOY.js";
|
|
46
53
|
import "./chunk-KMB3BU4S.js";
|
|
47
|
-
import {
|
|
48
|
-
inheritedEnv,
|
|
49
|
-
resolvePtySpawn,
|
|
50
|
-
sessionTempBase
|
|
51
|
-
} from "./chunk-3F4ZZKCA.js";
|
|
52
|
-
import "./chunk-W4LZ7R6Z.js";
|
|
53
54
|
import "./chunk-6Q6LQBWO.js";
|
|
54
55
|
|
|
55
56
|
// src/cli.ts
|
|
@@ -237,7 +238,10 @@ var ProjectSessionRunner = class {
|
|
|
237
238
|
async sampleAndReportKeyUsage() {
|
|
238
239
|
if (this.stopped) return;
|
|
239
240
|
const codingAgentKeyId = process.env.CONVEYOR_CODING_AGENT_KEY_ID;
|
|
240
|
-
const { samples, unmeasurable } = await sampleKeyUsage(
|
|
241
|
+
const { samples, unmeasurable } = await sampleKeyUsage(
|
|
242
|
+
process.env.CLAUDE_CODE_OAUTH_TOKEN,
|
|
243
|
+
() => runUsageProbe({ cwd: this.config.workspaceDir })
|
|
244
|
+
);
|
|
241
245
|
if (unmeasurable) {
|
|
242
246
|
this.connection.sendEvent(buildUnmeasurableEvent(unmeasurable.reason, codingAgentKeyId));
|
|
243
247
|
return;
|
|
@@ -281,7 +285,7 @@ function gaugesToSamples(stdout) {
|
|
|
281
285
|
}
|
|
282
286
|
return samples;
|
|
283
287
|
}
|
|
284
|
-
async function isolatedProbe(token, now) {
|
|
288
|
+
async function isolatedProbe(token, now, cwd) {
|
|
285
289
|
let dir = null;
|
|
286
290
|
try {
|
|
287
291
|
dir = await mkdtemp(join(sessionTempBase(), "conveyor-usage-"));
|
|
@@ -291,7 +295,7 @@ async function isolatedProbe(token, now) {
|
|
|
291
295
|
});
|
|
292
296
|
await copyFile(claudeJsonPath(), join(dir, ".claude.json")).catch(() => {
|
|
293
297
|
});
|
|
294
|
-
return await runUsageProbe({ env: { ...process.env, CLAUDE_CONFIG_DIR: dir } });
|
|
298
|
+
return await runUsageProbe({ cwd, env: { ...process.env, CLAUDE_CONFIG_DIR: dir } });
|
|
295
299
|
} catch (error) {
|
|
296
300
|
logger.info("isolated usage probe failed", {
|
|
297
301
|
error: error instanceof Error ? error.message : String(error)
|
|
@@ -304,7 +308,7 @@ async function isolatedProbe(token, now) {
|
|
|
304
308
|
}
|
|
305
309
|
async function probeKeysUsage(keys, deps = {}) {
|
|
306
310
|
const now = deps.now ?? Date.now;
|
|
307
|
-
const probeOne = deps.probeOne ?? ((token) => isolatedProbe(token, now()));
|
|
311
|
+
const probeOne = deps.probeOne ?? ((token) => isolatedProbe(token, now(), deps.cwd));
|
|
308
312
|
const results = [];
|
|
309
313
|
for (const key of keys) {
|
|
310
314
|
if (!key.oauthToken) continue;
|
|
@@ -558,7 +562,7 @@ var AdhocSessionRunner = class {
|
|
|
558
562
|
await this.sampleAndReportOwnKey();
|
|
559
563
|
return;
|
|
560
564
|
}
|
|
561
|
-
const probed = await probeKeysUsage(keys);
|
|
565
|
+
const probed = await probeKeysUsage(keys, { cwd: this.config.workspaceDir });
|
|
562
566
|
for (const { codingAgentKeyId, samples } of probed) {
|
|
563
567
|
for (const event of buildRateLimitEvents(samples, codingAgentKeyId)) {
|
|
564
568
|
this.connection.sendEvent(event);
|
|
@@ -569,7 +573,10 @@ var AdhocSessionRunner = class {
|
|
|
569
573
|
async sampleAndReportOwnKey() {
|
|
570
574
|
if (this.stopped) return;
|
|
571
575
|
const codingAgentKeyId = process.env.CONVEYOR_CODING_AGENT_KEY_ID;
|
|
572
|
-
const { samples, unmeasurable } = await sampleKeyUsage(
|
|
576
|
+
const { samples, unmeasurable } = await sampleKeyUsage(
|
|
577
|
+
process.env.CLAUDE_CODE_OAUTH_TOKEN,
|
|
578
|
+
() => runUsageProbe({ cwd: this.config.workspaceDir })
|
|
579
|
+
);
|
|
573
580
|
if (unmeasurable) {
|
|
574
581
|
this.connection.sendEvent(buildUnmeasurableEvent(unmeasurable.reason, codingAgentKeyId));
|
|
575
582
|
return;
|
|
@@ -1194,7 +1201,7 @@ function wireSpawnChildren(mode, connection, supervisors, logger7) {
|
|
|
1194
1201
|
|
|
1195
1202
|
// src/cli.ts
|
|
1196
1203
|
if (process.argv[2] === "boot") {
|
|
1197
|
-
const { runBoot } = await import("./boot-
|
|
1204
|
+
const { runBoot } = await import("./boot-SWUVT5B4.js");
|
|
1198
1205
|
process.exit(await runBoot(process.argv.slice(3)));
|
|
1199
1206
|
}
|
|
1200
1207
|
if (isLegacyEntrypointLaunch(process.env)) {
|
|
@@ -1398,6 +1405,7 @@ if (!CONVEYOR_TASK_ID && projectIdentity) {
|
|
|
1398
1405
|
runnerMode: "pm"
|
|
1399
1406
|
},
|
|
1400
1407
|
projectId: projectIdentity.projectId,
|
|
1408
|
+
workspaceDir: CONVEYOR_WORKSPACE,
|
|
1401
1409
|
// Same extended idle window claudespace task pods get.
|
|
1402
1410
|
...process.env.CLAUDESPACE_NAME ? { lifecycle: { idleTimeoutMs: 60 * 60 * 1e3 } } : {}
|
|
1403
1411
|
},
|
|
@@ -1446,7 +1454,7 @@ if (!RUNNER_MODES.includes(CONVEYOR_MODE)) {
|
|
|
1446
1454
|
process.exit(1);
|
|
1447
1455
|
}
|
|
1448
1456
|
if (CONVEYOR_MODE === "serving") {
|
|
1449
|
-
const { runServingSession } = await import("./serve-boot-
|
|
1457
|
+
const { runServingSession } = await import("./serve-boot-B4BIZMNB.js");
|
|
1450
1458
|
exitContext.runnerMode = "serving";
|
|
1451
1459
|
exitContext.sessionId = process.env.CONVEYOR_SESSION_ID ?? exitContext.sessionId;
|
|
1452
1460
|
const outcome = await runServingSession({
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/gate-cli.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
gatesDir
|
|
4
|
+
} from "./chunk-7P6QZHXZ.js";
|
|
5
|
+
|
|
6
|
+
// src/runner/gate-wrapper.ts
|
|
7
|
+
import { mkdirSync, rmSync, writeFileSync } from "fs";
|
|
8
|
+
import { constants as osConstants } from "os";
|
|
9
|
+
import path from "path";
|
|
10
|
+
import { spawn } from "child_process";
|
|
11
|
+
var LABEL_RE = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
12
|
+
function parseGateArgs(argv) {
|
|
13
|
+
const usage = "usage: conveyor-gate <label> -- <cmd> [args\u2026]";
|
|
14
|
+
const [label, separator, command, ...args] = argv;
|
|
15
|
+
if (!label || separator !== "--" || !command) throw new Error(usage);
|
|
16
|
+
if (!LABEL_RE.test(label)) {
|
|
17
|
+
throw new Error(`invalid gate label '${label}' \u2014 use letters, digits, '.', '_', '-'`);
|
|
18
|
+
}
|
|
19
|
+
return { label, command, args };
|
|
20
|
+
}
|
|
21
|
+
function exitCodeFor(code, signal) {
|
|
22
|
+
if (code !== null) return code;
|
|
23
|
+
if (signal) {
|
|
24
|
+
const num = osConstants.signals[signal];
|
|
25
|
+
if (typeof num === "number") return 128 + num;
|
|
26
|
+
}
|
|
27
|
+
return 1;
|
|
28
|
+
}
|
|
29
|
+
var FORWARDED_SIGNALS = ["SIGTERM", "SIGINT", "SIGHUP"];
|
|
30
|
+
function runGate(argv, options = {}) {
|
|
31
|
+
const log = options.log ?? ((message) => process.stderr.write(message));
|
|
32
|
+
const { label, command, args } = parseGateArgs(argv);
|
|
33
|
+
const dir = gatesDir();
|
|
34
|
+
mkdirSync(dir, { recursive: true });
|
|
35
|
+
const pidFile = path.join(dir, `${label}.pid`);
|
|
36
|
+
const exitFile = path.join(dir, `${label}.exit`);
|
|
37
|
+
rmSync(exitFile, { force: true });
|
|
38
|
+
return new Promise((resolve) => {
|
|
39
|
+
const child = spawn(command, args, { stdio: "inherit" });
|
|
40
|
+
const forward = (signal) => {
|
|
41
|
+
child.kill(signal);
|
|
42
|
+
};
|
|
43
|
+
const listeners = FORWARDED_SIGNALS.map((signal) => {
|
|
44
|
+
const listener = () => forward(signal);
|
|
45
|
+
process.on(signal, listener);
|
|
46
|
+
return { signal, listener };
|
|
47
|
+
});
|
|
48
|
+
const finish = (code) => {
|
|
49
|
+
for (const { signal, listener } of listeners) process.removeListener(signal, listener);
|
|
50
|
+
try {
|
|
51
|
+
writeFileSync(exitFile, `${JSON.stringify({ code, finishedAtMs: Date.now() })}
|
|
52
|
+
`);
|
|
53
|
+
} catch (error) {
|
|
54
|
+
log(`[conveyor-gate] failed to write ${exitFile}: ${String(error)}
|
|
55
|
+
`);
|
|
56
|
+
}
|
|
57
|
+
rmSync(pidFile, { force: true });
|
|
58
|
+
resolve(code);
|
|
59
|
+
};
|
|
60
|
+
child.once("error", (error) => {
|
|
61
|
+
log(`[conveyor-gate] failed to run ${command}: ${error.message}
|
|
62
|
+
`);
|
|
63
|
+
finish(127);
|
|
64
|
+
});
|
|
65
|
+
child.once("exit", (code, signal) => finish(exitCodeFor(code, signal)));
|
|
66
|
+
if (child.pid !== void 0) {
|
|
67
|
+
try {
|
|
68
|
+
writeFileSync(pidFile, `${child.pid}
|
|
69
|
+
`);
|
|
70
|
+
} catch (error) {
|
|
71
|
+
log(`[conveyor-gate] failed to write ${pidFile}: ${String(error)}
|
|
72
|
+
`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// src/gate-cli.ts
|
|
79
|
+
try {
|
|
80
|
+
process.exitCode = await runGate(process.argv.slice(2));
|
|
81
|
+
} catch (error) {
|
|
82
|
+
process.stderr.write(`conveyor-gate: ${error instanceof Error ? error.message : String(error)}
|
|
83
|
+
`);
|
|
84
|
+
process.exitCode = 2;
|
|
85
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -758,6 +758,53 @@ declare class SessionRunner {
|
|
|
758
758
|
* live build costs work.
|
|
759
759
|
*/
|
|
760
760
|
private deferShutdownForLiveChild;
|
|
761
|
+
/** Epoch ms of the first idle-shutdown deferral for background work in the
|
|
762
|
+
* current idle episode; null when nothing has deferred. Reset when a turn
|
|
763
|
+
* runs, so each idle episode gets its own bounded hold. */
|
|
764
|
+
private backgroundDeferStartedAt;
|
|
765
|
+
/**
|
|
766
|
+
* Suppress an idle shutdown while backgrounded work (`run_in_background`
|
|
767
|
+
* launches tracked by `BackgroundWorkTracker`) or a live gate process
|
|
768
|
+
* (`isHeavyGateActive` — singleton pidfiles plus the `conveyor-gate`
|
|
769
|
+
* contract dir) is still running. Without this the 30-minute idle timeout
|
|
770
|
+
* stopped the runner mid-gate: `shutdown()` cleared the tracker, heartbeats
|
|
771
|
+
* stopped, the activity clock expired, and the reconciler slept the pod and
|
|
772
|
+
* reverted the card to Open.
|
|
773
|
+
*
|
|
774
|
+
* Bounded: deferrals past the first one cap at `BACKGROUND_WORK_MAX_MS`, so
|
|
775
|
+
* a wedged gate process cannot pin a pod forever. Only the IDLE timeout is
|
|
776
|
+
* deferred — post-`completed` dormancy keeps today's behavior, and a parked
|
|
777
|
+
* prefill (`waiting_for_input`) contributes nothing here, so those cards
|
|
778
|
+
* still sleep on the ordinary window.
|
|
779
|
+
*/
|
|
780
|
+
private deferShutdownForBackgroundWork;
|
|
781
|
+
/** When orphan evidence (tracked work pending, no live gate process) began
|
|
782
|
+
* holding continuously; null while the evidence is absent. */
|
|
783
|
+
private orphanGraceStartedAt;
|
|
784
|
+
/** One-shot latch: at most one watchdog wake per idle episode. Reset when a
|
|
785
|
+
* turn runs. */
|
|
786
|
+
private backgroundWakeFiredThisIdle;
|
|
787
|
+
/** When the current idle episode began — an exit sentinel older than this
|
|
788
|
+
* appeared while a turn could still have consumed it, so it never wakes. */
|
|
789
|
+
private idleEpisodeStartedAt;
|
|
790
|
+
/**
|
|
791
|
+
* Wake a parked agent whose background work finished — or died — without a
|
|
792
|
+
* consumed completion callback. Completion normally arrives as the CLI's
|
|
793
|
+
* `<task-notification>` transcript record; when that record is lost (SDK
|
|
794
|
+
* harness, torn transcript, a gate killed out from under the CLI) the
|
|
795
|
+
* tracker entry silently expires and the agent waits forever.
|
|
796
|
+
*
|
|
797
|
+
* This is NOT the removed auto-mode stuck-nudge: it fires only on positive
|
|
798
|
+
* evidence of orphaned background work — a tracked launch with no live gate
|
|
799
|
+
* process continuously past `ORPHAN_WAKE_GRACE_MS`, or an unconsumed
|
|
800
|
+
* `gates/<label>.exit` sentinel that appeared this idle episode — never on
|
|
801
|
+
* "the agent seems stuck". A `completed` agent is never woken (the
|
|
802
|
+
* completion guard holds), and a live pid always suppresses the wake.
|
|
803
|
+
*/
|
|
804
|
+
private maybeWakeForOrphanedBackgroundWork;
|
|
805
|
+
/** Orphan evidence that has held past the grace, or null. Maintains the
|
|
806
|
+
* grace clock for the tracked-work condition as a side effect. */
|
|
807
|
+
private findOrphanEvidence;
|
|
761
808
|
get sessionId(): string;
|
|
762
809
|
get isStopped(): boolean;
|
|
763
810
|
/** Wire the boot supervisor handle post-construction — cli.ts constructs it
|
|
@@ -802,18 +849,41 @@ declare class SessionRunner {
|
|
|
802
849
|
/** Returns true if an initial query was executed, false otherwise. */
|
|
803
850
|
private executeInitialMode;
|
|
804
851
|
/**
|
|
805
|
-
* The mid-turn
|
|
806
|
-
*
|
|
807
|
-
* `--resume`" — assumes a human or a follow-up is
|
|
808
|
-
*
|
|
809
|
-
*
|
|
852
|
+
* The mid-turn watchdog aborts a turn that produced no events for 30 minutes
|
|
853
|
+
* (or one whose config-home mount died). Its documented recovery — "the next
|
|
854
|
+
* message respawns with `--resume`" — assumes a human or a follow-up is
|
|
855
|
+
* coming. A KICKOFF turn has neither by construction: it is the turn that
|
|
856
|
+
* starts the conversation, so there is no next message, and the runner goes
|
|
857
|
+
* idle with the card parked until a human notices.
|
|
858
|
+
*
|
|
859
|
+
* Observed live 2026-08-28 (card cmtd78iql): a spawned builder child's
|
|
860
|
+
* kickoff turn produced nothing for 30 minutes, was aborted, and the child
|
|
861
|
+
* then heartbeated idle for another 43 minutes until a human typed
|
|
862
|
+
* "@[agent:builder] continue".
|
|
863
|
+
*
|
|
864
|
+
* So any submit-delivery INITIAL query killed by the watchdog is re-run once
|
|
865
|
+
* against the (durable, on-disk) resumed session. Bounded to a single retry:
|
|
866
|
+
* a second wedge is a real failure that should surface as a parked card
|
|
867
|
+
* rather than loop the pod.
|
|
868
|
+
*
|
|
869
|
+
* Nothing recovers a card from there automatically, and that is the honest
|
|
870
|
+
* state of it. The server's session sweep does NOT catch this shape: its
|
|
871
|
+
* predicate is `agentRunningAt` still null, and a turn that started and then
|
|
872
|
+
* wedged has already stamped it. The sweep covers a builder that never took a
|
|
873
|
+
* turn at all; this retry covers one whose first turn stalled. Twice-wedged
|
|
874
|
+
* needs a human, and a card left that way keeps its Builder tab and its
|
|
875
|
+
* heartbeat, so it is visible rather than silently gone.
|
|
876
|
+
*
|
|
877
|
+
* Skipped when a pending message already exists, because the core loop
|
|
878
|
+
* delivers that instead, which is the path the watchdog's original recovery
|
|
879
|
+
* assumed.
|
|
880
|
+
*
|
|
881
|
+
* A mount-death abort retries too, and must: the repair for a dead config
|
|
882
|
+
* home is the respawn that follows the abort, so a kickoff with nothing
|
|
883
|
+
* behind it would otherwise never get one.
|
|
810
884
|
*
|
|
811
|
-
*
|
|
812
|
-
*
|
|
813
|
-
* Bounded to a single retry: a second wedge is a real failure that should
|
|
814
|
-
* surface as a parked card rather than loop the pod. Skipped when a pending
|
|
815
|
-
* message already exists — the core loop delivers that instead, which is the
|
|
816
|
-
* path the watchdog's original recovery assumed.
|
|
885
|
+
* NOT for follow-up turns — there "the conversation resumes on the next
|
|
886
|
+
* message" is exactly right.
|
|
817
887
|
*/
|
|
818
888
|
private requeueWedgedInitialQuery;
|
|
819
889
|
/**
|
|
@@ -957,6 +1027,8 @@ declare class SessionRunner {
|
|
|
957
1027
|
private _finalState;
|
|
958
1028
|
/** The final status after run() completes. Use to determine exit code. */
|
|
959
1029
|
get finalState(): AgentRunnerStatus | null;
|
|
1030
|
+
/** Does a transcript already exist for this session's lineage? */
|
|
1031
|
+
private resolvesToTranscriptResume;
|
|
960
1032
|
private buildTaskContextSnapshot;
|
|
961
1033
|
private buildInitializationContext;
|
|
962
1034
|
private logInitialization;
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SessionRunner,
|
|
3
3
|
unshallowRepo
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-HYPX6FEX.js";
|
|
5
5
|
import "./chunk-XORJ6SII.js";
|
|
6
|
+
import "./chunk-3F4ZZKCA.js";
|
|
6
7
|
import {
|
|
7
8
|
AgentConnection,
|
|
8
9
|
GIT_TIMEOUT_MS,
|
|
@@ -16,8 +17,14 @@ import {
|
|
|
16
17
|
stageAndCommit,
|
|
17
18
|
updateRemoteToken,
|
|
18
19
|
workspacePathExists
|
|
19
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-SLUBOIYE.js";
|
|
20
21
|
import "./chunk-GL2DIQEQ.js";
|
|
22
|
+
import {
|
|
23
|
+
runAuthTokenCommand,
|
|
24
|
+
runSetupCommand,
|
|
25
|
+
runStartCommand
|
|
26
|
+
} from "./chunk-W4LZ7R6Z.js";
|
|
27
|
+
import "./chunk-7P6QZHXZ.js";
|
|
21
28
|
import "./chunk-IA45XHOA.js";
|
|
22
29
|
import {
|
|
23
30
|
getWorkbenchClient
|
|
@@ -25,12 +32,6 @@ import {
|
|
|
25
32
|
import {
|
|
26
33
|
workbenchEnabled
|
|
27
34
|
} from "./chunk-KMB3BU4S.js";
|
|
28
|
-
import "./chunk-3F4ZZKCA.js";
|
|
29
|
-
import {
|
|
30
|
-
runAuthTokenCommand,
|
|
31
|
-
runSetupCommand,
|
|
32
|
-
runStartCommand
|
|
33
|
-
} from "./chunk-W4LZ7R6Z.js";
|
|
34
35
|
import "./chunk-6Q6LQBWO.js";
|
|
35
36
|
|
|
36
37
|
// src/runner/worktree.ts
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
WorkspaceCommandSupervisor
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-URYBO32C.js";
|
|
4
4
|
import {
|
|
5
5
|
AgentConnection,
|
|
6
6
|
CodespacePortVisibility,
|
|
@@ -11,12 +11,12 @@ import {
|
|
|
11
11
|
createServiceLogger,
|
|
12
12
|
ensureOnTaskBranch,
|
|
13
13
|
loadConveyorConfig
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-SLUBOIYE.js";
|
|
15
15
|
import "./chunk-GL2DIQEQ.js";
|
|
16
|
+
import "./chunk-W4LZ7R6Z.js";
|
|
16
17
|
import "./chunk-IA45XHOA.js";
|
|
17
18
|
import "./chunk-EXQ6AHOY.js";
|
|
18
19
|
import "./chunk-KMB3BU4S.js";
|
|
19
|
-
import "./chunk-W4LZ7R6Z.js";
|
|
20
20
|
import "./chunk-6Q6LQBWO.js";
|
|
21
21
|
|
|
22
22
|
// src/runner/serve-session-runner.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rallycry/conveyor-agent",
|
|
3
|
-
"version": "11.0.
|
|
3
|
+
"version": "11.0.4",
|
|
4
4
|
"description": "Conveyor Agent Runner v10 - PTY harness for the task chat (SDK harness for audit/project-chat). Agent-as-User architecture with BaseService patterns. Works locally too.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
],
|
|
12
12
|
"license": "MIT",
|
|
13
13
|
"bin": {
|
|
14
|
-
"conveyor-agent": "dist/cli.js"
|
|
14
|
+
"conveyor-agent": "dist/cli.js",
|
|
15
|
+
"conveyor-gate": "dist/gate-cli.js"
|
|
15
16
|
},
|
|
16
17
|
"files": [
|
|
17
18
|
"dist",
|
|
@@ -149,6 +149,16 @@ and never silence a failure with a filter, a `.skip`, or a "known flake" note:
|
|
|
149
149
|
either your diff broke it, or the test is broken or environment-dependent and
|
|
150
150
|
you fix the test.
|
|
151
151
|
|
|
152
|
+
**Long gates in a pod: background them the sanctioned way.** Launch a long
|
|
153
|
+
gate with the harness's `run_in_background` Bash option and end the turn — the
|
|
154
|
+
runner tracks the launch, holds pod liveness while a gate process is alive,
|
|
155
|
+
and wakes you when it finishes (or if its completion callback is lost). In a
|
|
156
|
+
repo without Conveyor's `scripts/singleton.sh`, wrap the command in the
|
|
157
|
+
shipped `conveyor-gate` bin — `conveyor-gate <label> -- <cmd…>` — which writes
|
|
158
|
+
the same pid/exit contract under `$CONVEYOR_RUN_DIR/gates/` so the runner can
|
|
159
|
+
see it. Hand-rolled backgrounding (`nohup`, `&`, `disown`) is invisible to the
|
|
160
|
+
runner: the pod can sleep mid-run and nothing will wake you.
|
|
161
|
+
|
|
152
162
|
**A UI-visible change needs visual proof before the PR**, in both environments:
|
|
153
163
|
capture a screenshot (static) or a short recording (interaction) with the host
|
|
154
164
|
repo's own tooling and attach it with `mcp__conveyor__upload_attachment`, then
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
startWorkbenchServer
|
|
3
|
+
} from "./chunk-UBDSLM44.js";
|
|
1
4
|
import {
|
|
2
5
|
TOMBSTONE_MESSAGE,
|
|
3
6
|
isLegacyEntrypointLaunch
|
|
@@ -5,6 +8,7 @@ import {
|
|
|
5
8
|
import {
|
|
6
9
|
readAgentVersion
|
|
7
10
|
} from "./chunk-XORJ6SII.js";
|
|
11
|
+
import "./chunk-3F4ZZKCA.js";
|
|
8
12
|
import {
|
|
9
13
|
GitPrepJob,
|
|
10
14
|
defaultGit,
|
|
@@ -12,14 +16,10 @@ import {
|
|
|
12
16
|
redactToken,
|
|
13
17
|
reportBootMilestone
|
|
14
18
|
} from "./chunk-GL2DIQEQ.js";
|
|
19
|
+
import "./chunk-W4LZ7R6Z.js";
|
|
15
20
|
import {
|
|
16
21
|
workbenchPort
|
|
17
22
|
} from "./chunk-KMB3BU4S.js";
|
|
18
|
-
import {
|
|
19
|
-
startWorkbenchServer
|
|
20
|
-
} from "./chunk-UBDSLM44.js";
|
|
21
|
-
import "./chunk-3F4ZZKCA.js";
|
|
22
|
-
import "./chunk-W4LZ7R6Z.js";
|
|
23
23
|
import {
|
|
24
24
|
DEFAULT_WORKBENCH_PORT
|
|
25
25
|
} from "./chunk-6Q6LQBWO.js";
|
|
@@ -4,6 +4,12 @@ import {
|
|
|
4
4
|
FETCH_TIMEOUT_MS,
|
|
5
5
|
GIT_PREP_MAX_RETRIES
|
|
6
6
|
} from "./chunk-GL2DIQEQ.js";
|
|
7
|
+
import {
|
|
8
|
+
gitCredentialHelper,
|
|
9
|
+
sleep,
|
|
10
|
+
syncGithubTokenFiles,
|
|
11
|
+
writeGitCredential
|
|
12
|
+
} from "./chunk-W4LZ7R6Z.js";
|
|
7
13
|
import {
|
|
8
14
|
buildConveyorSocketOptions,
|
|
9
15
|
callWithAck,
|
|
@@ -18,12 +24,6 @@ import {
|
|
|
18
24
|
import {
|
|
19
25
|
workbenchEnabled
|
|
20
26
|
} from "./chunk-KMB3BU4S.js";
|
|
21
|
-
import {
|
|
22
|
-
gitCredentialHelper,
|
|
23
|
-
sleep,
|
|
24
|
-
syncGithubTokenFiles,
|
|
25
|
-
writeGitCredential
|
|
26
|
-
} from "./chunk-W4LZ7R6Z.js";
|
|
27
27
|
|
|
28
28
|
// src/setup/bootstrap.ts
|
|
29
29
|
var BOOTSTRAP_TIMEOUT_MS = 3e4;
|