@rallycry/conveyor-agent 10.2.1 → 10.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-YGLTLUGA.js → chunk-53ZLFIAI.js} +64 -13
- package/dist/chunk-53ZLFIAI.js.map +1 -0
- package/dist/cli.js +233 -45
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +24 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-YGLTLUGA.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -13,10 +13,11 @@ import {
|
|
|
13
13
|
fetchBootstrap,
|
|
14
14
|
loadConveyorConfig,
|
|
15
15
|
loadForwardPorts,
|
|
16
|
+
resolveSessionStart,
|
|
16
17
|
runSetupCommand,
|
|
17
18
|
runStartCommand,
|
|
18
19
|
sampleKeyUsage
|
|
19
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-53ZLFIAI.js";
|
|
20
21
|
|
|
21
22
|
// src/cli.ts
|
|
22
23
|
import { readFileSync } from "fs";
|
|
@@ -144,14 +145,14 @@ async function waitForSidecars(opts = {}) {
|
|
|
144
145
|
|
|
145
146
|
// src/utils/session-identity.ts
|
|
146
147
|
async function checkSessionTaskIdentity(params) {
|
|
147
|
-
const { sessionId, taskId, fetchSessionTaskId, logger:
|
|
148
|
+
const { sessionId, taskId, fetchSessionTaskId, logger: logger3 } = params;
|
|
148
149
|
if (!sessionId || sessionId === taskId) return "skipped";
|
|
149
150
|
let sessionTaskId;
|
|
150
151
|
try {
|
|
151
152
|
sessionTaskId = await fetchSessionTaskId(sessionId);
|
|
152
153
|
} catch (err) {
|
|
153
154
|
const message = err instanceof Error ? err.message : String(err);
|
|
154
|
-
|
|
155
|
+
logger3.warn("Could not verify session/task identity \u2014 continuing (defense-in-depth only)", {
|
|
155
156
|
sessionId,
|
|
156
157
|
taskId,
|
|
157
158
|
error: message
|
|
@@ -159,7 +160,7 @@ async function checkSessionTaskIdentity(params) {
|
|
|
159
160
|
return "error";
|
|
160
161
|
}
|
|
161
162
|
if (sessionTaskId !== taskId) {
|
|
162
|
-
|
|
163
|
+
logger3.warn(
|
|
163
164
|
"!!! 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.",
|
|
164
165
|
{ sessionId, envTaskId: taskId, sessionTaskId }
|
|
165
166
|
);
|
|
@@ -172,11 +173,14 @@ async function checkSessionTaskIdentity(params) {
|
|
|
172
173
|
function resolveProjectRunnerIdentity(env) {
|
|
173
174
|
if (env.CONVEYOR_TASK_ID) return null;
|
|
174
175
|
if (!env.CONVEYOR_TASK_TOKEN) return null;
|
|
175
|
-
if (!env.CONVEYOR_PROJECT_ID || !env.CONVEYOR_SESSION_ID)
|
|
176
|
+
if (!env.CONVEYOR_PROJECT_ID || !env.CONVEYOR_SESSION_ID || !env.CONVEYOR_WORKSPACE_ID) {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
176
179
|
if (env.CONVEYOR_MODE !== "pm" && env.CONVEYOR_MODE !== "adhoc") return null;
|
|
177
180
|
return {
|
|
178
181
|
projectId: env.CONVEYOR_PROJECT_ID,
|
|
179
182
|
sessionId: env.CONVEYOR_SESSION_ID,
|
|
183
|
+
workspaceId: env.CONVEYOR_WORKSPACE_ID,
|
|
180
184
|
taskToken: env.CONVEYOR_TASK_TOKEN
|
|
181
185
|
};
|
|
182
186
|
}
|
|
@@ -322,7 +326,7 @@ function buildAdhocPtyBridge(connection) {
|
|
|
322
326
|
onResize: (handler) => connection.onPtyResize(handler)
|
|
323
327
|
};
|
|
324
328
|
}
|
|
325
|
-
function buildAdhocQueryOptions(workspaceDir, model, abortController) {
|
|
329
|
+
function buildAdhocQueryOptions(workspaceDir, model, abortController, session) {
|
|
326
330
|
return {
|
|
327
331
|
model,
|
|
328
332
|
systemPrompt: { type: "preset", preset: "claude_code", append: ADHOC_SYSTEM_NOTE },
|
|
@@ -336,7 +340,9 @@ function buildAdhocQueryOptions(workspaceDir, model, abortController) {
|
|
|
336
340
|
settingSources: ["user", "project"],
|
|
337
341
|
// Empty box, unsubmitted: the human types the first prompt themselves.
|
|
338
342
|
promptDelivery: "prefill",
|
|
339
|
-
abortController
|
|
343
|
+
abortController,
|
|
344
|
+
...session?.sessionId ? { sessionId: session.sessionId } : {},
|
|
345
|
+
...session?.resume ? { resume: session.resume } : {}
|
|
340
346
|
};
|
|
341
347
|
}
|
|
342
348
|
var AdhocSessionRunner = class {
|
|
@@ -414,7 +420,13 @@ var AdhocSessionRunner = class {
|
|
|
414
420
|
*/
|
|
415
421
|
async runInteractiveTui() {
|
|
416
422
|
const model = this.config.model ?? process.env.CONVEYOR_ADHOC_MODEL ?? DEFAULT_SONNET_MODEL;
|
|
417
|
-
const
|
|
423
|
+
const session = resolveSessionStart(this.config.workspaceId, this.config.workspaceDir);
|
|
424
|
+
const options = buildAdhocQueryOptions(
|
|
425
|
+
this.config.workspaceDir,
|
|
426
|
+
model,
|
|
427
|
+
this.abortController,
|
|
428
|
+
session
|
|
429
|
+
);
|
|
418
430
|
try {
|
|
419
431
|
for await (const _event of this.harness.executeQuery({ prompt: "", options })) {
|
|
420
432
|
if (this.stopped) break;
|
|
@@ -456,6 +468,163 @@ var AdhocSessionRunner = class {
|
|
|
456
468
|
}
|
|
457
469
|
};
|
|
458
470
|
|
|
471
|
+
// src/runner/review-child.ts
|
|
472
|
+
import { spawn as nodeSpawn, execFile } from "child_process";
|
|
473
|
+
import { promisify } from "util";
|
|
474
|
+
var execFileAsync = promisify(execFile);
|
|
475
|
+
var logger = createServiceLogger("ReviewChild");
|
|
476
|
+
var SPAWN_FAILURE_GRACE_MS = 15e3;
|
|
477
|
+
var KILL_WAIT_MS = 5e3;
|
|
478
|
+
function buildReviewChildEnv(baseEnv, data) {
|
|
479
|
+
const env = { ...baseEnv };
|
|
480
|
+
env.CONVEYOR_TASK_TOKEN = data.sessionJwt;
|
|
481
|
+
env.CONVEYOR_SESSION_ID = data.sessionId;
|
|
482
|
+
env.CONVEYOR_MODE = "code-review";
|
|
483
|
+
delete env.POD_BOOTSTRAP_TOKEN;
|
|
484
|
+
delete env.CONVEYOR_BOOTSTRAP_TOKEN;
|
|
485
|
+
delete env.CONVEYOR_SETUP_COMMAND;
|
|
486
|
+
delete env.CONVEYOR_START_COMMAND;
|
|
487
|
+
delete env.CONVEYOR_AGENT_MODE;
|
|
488
|
+
delete env.CONVEYOR_IS_AUTO;
|
|
489
|
+
return env;
|
|
490
|
+
}
|
|
491
|
+
var ReviewChildSupervisor = class {
|
|
492
|
+
constructor(connection, workspaceDir, spawnFn = nodeSpawn) {
|
|
493
|
+
this.connection = connection;
|
|
494
|
+
this.workspaceDir = workspaceDir;
|
|
495
|
+
this.spawnFn = spawnFn;
|
|
496
|
+
}
|
|
497
|
+
connection;
|
|
498
|
+
workspaceDir;
|
|
499
|
+
spawnFn;
|
|
500
|
+
child = null;
|
|
501
|
+
childSessionId = null;
|
|
502
|
+
/** Spawn (or replace) the review child for a `session:spawnReview` push. */
|
|
503
|
+
async spawn(data) {
|
|
504
|
+
logger.info("Spawning same-pod review child", {
|
|
505
|
+
reviewSessionId: data.sessionId,
|
|
506
|
+
branch: data.branch ?? void 0,
|
|
507
|
+
prNumber: data.prNumber ?? void 0
|
|
508
|
+
});
|
|
509
|
+
await this.stopCurrent("superseded by new review spawn");
|
|
510
|
+
await this.refreshCheckout(data.branch ?? null);
|
|
511
|
+
const env = buildReviewChildEnv(process.env, data);
|
|
512
|
+
const cliPath = process.argv[1];
|
|
513
|
+
if (!cliPath) {
|
|
514
|
+
this.connection.reportReviewSpawnFailure(data.sessionId, "cannot resolve CLI entry path");
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
let child;
|
|
518
|
+
try {
|
|
519
|
+
child = this.spawnFn(process.execPath, [cliPath], {
|
|
520
|
+
cwd: this.workspaceDir,
|
|
521
|
+
env,
|
|
522
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
523
|
+
});
|
|
524
|
+
} catch (err) {
|
|
525
|
+
this.connection.reportReviewSpawnFailure(
|
|
526
|
+
data.sessionId,
|
|
527
|
+
err instanceof Error ? err.message : String(err)
|
|
528
|
+
);
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
this.child = child;
|
|
532
|
+
this.childSessionId = data.sessionId;
|
|
533
|
+
const spawnedAt = Date.now();
|
|
534
|
+
let reported = false;
|
|
535
|
+
const reportOnce = (message) => {
|
|
536
|
+
if (reported) return;
|
|
537
|
+
reported = true;
|
|
538
|
+
this.connection.reportReviewSpawnFailure(data.sessionId, message);
|
|
539
|
+
};
|
|
540
|
+
child.stdout?.on("data", (chunk) => {
|
|
541
|
+
process.stdout.write(`[review-child] ${chunk.toString()}`);
|
|
542
|
+
});
|
|
543
|
+
child.stderr?.on("data", (chunk) => {
|
|
544
|
+
process.stderr.write(`[review-child] ${chunk.toString()}`);
|
|
545
|
+
});
|
|
546
|
+
child.on("error", (err) => {
|
|
547
|
+
logger.error("Review child spawn error", { error: err.message });
|
|
548
|
+
if (this.child === child) {
|
|
549
|
+
this.child = null;
|
|
550
|
+
this.childSessionId = null;
|
|
551
|
+
}
|
|
552
|
+
reportOnce(err.message);
|
|
553
|
+
});
|
|
554
|
+
child.on("exit", (code, signal) => {
|
|
555
|
+
const wasCurrent = this.child === child;
|
|
556
|
+
if (wasCurrent) {
|
|
557
|
+
this.child = null;
|
|
558
|
+
this.childSessionId = null;
|
|
559
|
+
}
|
|
560
|
+
logger.info("Review child exited", { code, signal, reviewSessionId: data.sessionId });
|
|
561
|
+
const withinGrace = Date.now() - spawnedAt < SPAWN_FAILURE_GRACE_MS;
|
|
562
|
+
if (wasCurrent && withinGrace && code !== null && code !== 0) {
|
|
563
|
+
reportOnce(`review child exited with code ${code} within startup grace`);
|
|
564
|
+
}
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
/** Stop any live child (parent shutdown / supersede). Best-effort. */
|
|
568
|
+
async stopAll() {
|
|
569
|
+
await this.stopCurrent("parent shutting down");
|
|
570
|
+
}
|
|
571
|
+
async stopCurrent(reason) {
|
|
572
|
+
const child = this.child;
|
|
573
|
+
if (!child || child.exitCode !== null || child.killed) {
|
|
574
|
+
this.child = null;
|
|
575
|
+
this.childSessionId = null;
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
logger.info("Stopping review child", { reason, reviewSessionId: this.childSessionId });
|
|
579
|
+
this.child = null;
|
|
580
|
+
this.childSessionId = null;
|
|
581
|
+
await new Promise((resolve) => {
|
|
582
|
+
const timer = setTimeout(() => {
|
|
583
|
+
try {
|
|
584
|
+
child.kill("SIGKILL");
|
|
585
|
+
} catch {
|
|
586
|
+
}
|
|
587
|
+
resolve();
|
|
588
|
+
}, KILL_WAIT_MS);
|
|
589
|
+
timer.unref();
|
|
590
|
+
child.once("exit", () => {
|
|
591
|
+
clearTimeout(timer);
|
|
592
|
+
resolve();
|
|
593
|
+
});
|
|
594
|
+
try {
|
|
595
|
+
child.kill("SIGTERM");
|
|
596
|
+
} catch {
|
|
597
|
+
clearTimeout(timer);
|
|
598
|
+
resolve();
|
|
599
|
+
}
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* Best-effort branch freshen before the review reads the tree: fetch the PR
|
|
604
|
+
* branch and fast-forward only (never clobber local work — the builder's
|
|
605
|
+
* checkout is the source of truth on conflict). Failures are logged and
|
|
606
|
+
* skipped; the reviewer still reads the diff via the GitHub API.
|
|
607
|
+
*/
|
|
608
|
+
async refreshCheckout(branch) {
|
|
609
|
+
if (!branch) return;
|
|
610
|
+
try {
|
|
611
|
+
await execFileAsync("git", ["fetch", "origin", branch], {
|
|
612
|
+
cwd: this.workspaceDir,
|
|
613
|
+
timeout: 6e4
|
|
614
|
+
});
|
|
615
|
+
await execFileAsync("git", ["merge", "--ff-only", `origin/${branch}`], {
|
|
616
|
+
cwd: this.workspaceDir,
|
|
617
|
+
timeout: 3e4
|
|
618
|
+
});
|
|
619
|
+
} catch (err) {
|
|
620
|
+
logger.warn("Review checkout freshen skipped", {
|
|
621
|
+
branch,
|
|
622
|
+
error: err instanceof Error ? err.message : String(err)
|
|
623
|
+
});
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
};
|
|
627
|
+
|
|
459
628
|
// src/cli.ts
|
|
460
629
|
if (process.argv.includes("--version")) {
|
|
461
630
|
const __dirname = dirname2(fileURLToPath(import.meta.url));
|
|
@@ -464,11 +633,11 @@ if (process.argv.includes("--version")) {
|
|
|
464
633
|
process.stdout.write(pkg.version + "\n");
|
|
465
634
|
process.exit(0);
|
|
466
635
|
}
|
|
467
|
-
var
|
|
636
|
+
var logger2 = createServiceLogger("CLI");
|
|
468
637
|
async function bootstrapFromCodespace(apiUrl, instanceName) {
|
|
469
638
|
const bootstrapToken = process.env.CONVEYOR_BOOTSTRAP_TOKEN;
|
|
470
639
|
const apiUrlFromEnv = Boolean(process.env.CONVEYOR_API_URL);
|
|
471
|
-
|
|
640
|
+
logger2.info("Bootstrapping from codespace", {
|
|
472
641
|
codespace: instanceName,
|
|
473
642
|
apiUrl,
|
|
474
643
|
apiUrlFromEnv,
|
|
@@ -480,7 +649,7 @@ async function bootstrapFromCodespace(apiUrl, instanceName) {
|
|
|
480
649
|
bootstrapToken
|
|
481
650
|
});
|
|
482
651
|
if (!result.ok) {
|
|
483
|
-
|
|
652
|
+
logger2.error("Bootstrap failed after retries", {
|
|
484
653
|
reason: result.reason,
|
|
485
654
|
attempts: result.attempts,
|
|
486
655
|
status: result.status,
|
|
@@ -493,7 +662,7 @@ async function bootstrapFromCodespace(apiUrl, instanceName) {
|
|
|
493
662
|
process.exit(1);
|
|
494
663
|
}
|
|
495
664
|
applyBootstrapToEnv(result.config);
|
|
496
|
-
|
|
665
|
+
logger2.info("Bootstrap complete", {
|
|
497
666
|
taskId: result.config.taskId,
|
|
498
667
|
attempts: result.attempts
|
|
499
668
|
});
|
|
@@ -507,19 +676,19 @@ function isExpectedAbortError(error) {
|
|
|
507
676
|
process.on("uncaughtException", (err) => {
|
|
508
677
|
if (err.code === "EPIPE") return;
|
|
509
678
|
if (isExpectedAbortError(err)) {
|
|
510
|
-
|
|
679
|
+
logger2.info("Ignored expected abort after shutdown", { error: err.message, code: err.code });
|
|
511
680
|
return;
|
|
512
681
|
}
|
|
513
|
-
|
|
682
|
+
logger2.error("Uncaught exception", { error: err.message, code: err.code });
|
|
514
683
|
process.exit(1);
|
|
515
684
|
});
|
|
516
685
|
process.on("unhandledRejection", (reason) => {
|
|
517
686
|
const err = reason instanceof Error ? reason : new Error(String(reason));
|
|
518
687
|
if (isExpectedAbortError(err)) {
|
|
519
|
-
|
|
688
|
+
logger2.info("Ignored expected abort rejection after shutdown", { error: err.message });
|
|
520
689
|
return;
|
|
521
690
|
}
|
|
522
|
-
|
|
691
|
+
logger2.error("Unhandled rejection", { error: err.message });
|
|
523
692
|
process.exit(1);
|
|
524
693
|
});
|
|
525
694
|
var DEFAULT_CONVEYOR_API_URL = "https://api.conveyor.rallycryapp.com";
|
|
@@ -527,7 +696,7 @@ var conveyorApiUrl = process.env.CONVEYOR_API_URL || DEFAULT_CONVEYOR_API_URL;
|
|
|
527
696
|
var INSTANCE_NAME = process.env.CODESPACE_NAME || process.env.CLAUDESPACE_NAME;
|
|
528
697
|
if (INSTANCE_NAME && !process.env.CONVEYOR_TASK_TOKEN) {
|
|
529
698
|
if (!conveyorApiUrl) {
|
|
530
|
-
|
|
699
|
+
logger2.error("Could not resolve CONVEYOR_API_URL for codespace bootstrap");
|
|
531
700
|
process.exit(1);
|
|
532
701
|
}
|
|
533
702
|
await bootstrapFromCodespace(conveyorApiUrl, INSTANCE_NAME);
|
|
@@ -541,7 +710,7 @@ var CONVEYOR_AGENT_MODE = process.env.CONVEYOR_AGENT_MODE || void 0;
|
|
|
541
710
|
var CONVEYOR_IS_AUTO = CONVEYOR_AGENT_MODE ? CONVEYOR_AGENT_MODE === "auto" : process.env.CONVEYOR_IS_AUTO === "true";
|
|
542
711
|
var projectIdentity = resolveProjectRunnerIdentity(process.env);
|
|
543
712
|
if (!CONVEYOR_TASK_ID && projectIdentity && CONVEYOR_MODE === "adhoc") {
|
|
544
|
-
|
|
713
|
+
logger2.info("Starting ad-hoc agent", { projectId: projectIdentity.projectId });
|
|
545
714
|
const adhocRunner = new AdhocSessionRunner(
|
|
546
715
|
{
|
|
547
716
|
connection: {
|
|
@@ -551,12 +720,13 @@ if (!CONVEYOR_TASK_ID && projectIdentity && CONVEYOR_MODE === "adhoc") {
|
|
|
551
720
|
runnerMode: "adhoc"
|
|
552
721
|
},
|
|
553
722
|
projectId: projectIdentity.projectId,
|
|
723
|
+
workspaceId: projectIdentity.workspaceId,
|
|
554
724
|
workspaceDir: CONVEYOR_WORKSPACE,
|
|
555
725
|
...process.env.CLAUDESPACE_NAME ? { lifecycle: { idleTimeoutMs: 60 * 60 * 1e3 } } : {}
|
|
556
726
|
},
|
|
557
727
|
{
|
|
558
728
|
onEvent: (event) => {
|
|
559
|
-
|
|
729
|
+
logger2.info("Ad-hoc runner event", { eventType: event.type });
|
|
560
730
|
}
|
|
561
731
|
}
|
|
562
732
|
);
|
|
@@ -566,7 +736,7 @@ if (!CONVEYOR_TASK_ID && projectIdentity && CONVEYOR_MODE === "adhoc") {
|
|
|
566
736
|
process.exit(adhocRunner.finalState === "error" ? 1 : 0);
|
|
567
737
|
}
|
|
568
738
|
if (!CONVEYOR_TASK_ID && projectIdentity) {
|
|
569
|
-
|
|
739
|
+
logger2.info("Starting project agent", { projectId: projectIdentity.projectId });
|
|
570
740
|
const projectRunner = new ProjectSessionRunner(
|
|
571
741
|
{
|
|
572
742
|
connection: {
|
|
@@ -581,7 +751,7 @@ if (!CONVEYOR_TASK_ID && projectIdentity) {
|
|
|
581
751
|
},
|
|
582
752
|
{
|
|
583
753
|
onEvent: (event) => {
|
|
584
|
-
|
|
754
|
+
logger2.info("Project runner event", { eventType: event.type });
|
|
585
755
|
}
|
|
586
756
|
}
|
|
587
757
|
);
|
|
@@ -591,28 +761,28 @@ if (!CONVEYOR_TASK_ID && projectIdentity) {
|
|
|
591
761
|
process.exit(projectRunner.finalState === "error" ? 1 : 0);
|
|
592
762
|
}
|
|
593
763
|
if (!CONVEYOR_TASK_TOKEN || !CONVEYOR_TASK_ID) {
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
764
|
+
logger2.error("Missing required environment variables");
|
|
765
|
+
logger2.error(" CONVEYOR_TASK_TOKEN - JWT token for task authentication");
|
|
766
|
+
logger2.error(" CONVEYOR_TASK_ID - ID of the task to execute");
|
|
767
|
+
logger2.error("");
|
|
768
|
+
logger2.error("CONVEYOR_API_URL is provided via codespace secret or bootstrap.");
|
|
769
|
+
logger2.error("");
|
|
770
|
+
logger2.error("Optional:");
|
|
771
|
+
logger2.error(" CONVEYOR_MODE - Runner mode: 'task' (default) or 'pm'");
|
|
772
|
+
logger2.error(" CONVEYOR_WORKSPACE - Working directory (defaults to cwd)");
|
|
773
|
+
logger2.error(
|
|
604
774
|
" Project pods instead require CONVEYOR_PROJECT_ID + CONVEYOR_SESSION_ID + CONVEYOR_MODE=pm"
|
|
605
775
|
);
|
|
606
776
|
process.exit(1);
|
|
607
777
|
}
|
|
608
778
|
if (CONVEYOR_MODE !== "task" && CONVEYOR_MODE !== "pm" && CONVEYOR_MODE !== "code-review" && CONVEYOR_MODE !== "adhoc") {
|
|
609
|
-
|
|
779
|
+
logger2.error("Invalid CONVEYOR_MODE", {
|
|
610
780
|
mode: CONVEYOR_MODE,
|
|
611
781
|
expected: ["task", "pm", "code-review", "adhoc"]
|
|
612
782
|
});
|
|
613
783
|
process.exit(1);
|
|
614
784
|
}
|
|
615
|
-
|
|
785
|
+
logger2.info("Starting agent", { mode: CONVEYOR_MODE });
|
|
616
786
|
var lifecycleOverrides = process.env.CLAUDESPACE_NAME ? { idleTimeoutMs: 60 * 60 * 1e3 } : { gitFlushIntervalMs: 0 };
|
|
617
787
|
var runner = new SessionRunner(
|
|
618
788
|
{
|
|
@@ -632,19 +802,24 @@ var runner = new SessionRunner(
|
|
|
632
802
|
},
|
|
633
803
|
{
|
|
634
804
|
onStatusChange: (status) => {
|
|
635
|
-
|
|
805
|
+
logger2.info("Status changed", { status });
|
|
636
806
|
},
|
|
637
807
|
onEvent: (event) => {
|
|
638
808
|
const detail = event.message ?? event.content ?? event.summary ?? "";
|
|
639
809
|
if (detail) {
|
|
640
|
-
|
|
810
|
+
logger2.info(detail, { eventType: event.type });
|
|
641
811
|
}
|
|
642
812
|
}
|
|
643
813
|
}
|
|
644
814
|
);
|
|
815
|
+
var reviewChildren = new ReviewChildSupervisor(runner.connection, CONVEYOR_WORKSPACE);
|
|
645
816
|
var shutdownAgent = (signal) => {
|
|
646
|
-
|
|
817
|
+
logger2.info(`Received ${signal}, flushing git and stopping agent`);
|
|
647
818
|
void (async () => {
|
|
819
|
+
try {
|
|
820
|
+
await reviewChildren.stopAll();
|
|
821
|
+
} catch {
|
|
822
|
+
}
|
|
648
823
|
try {
|
|
649
824
|
await runner.flushGitOnShutdown();
|
|
650
825
|
} finally {
|
|
@@ -652,7 +827,7 @@ var shutdownAgent = (signal) => {
|
|
|
652
827
|
}
|
|
653
828
|
})();
|
|
654
829
|
setTimeout(() => {
|
|
655
|
-
|
|
830
|
+
logger2.warn(`Forcing exit after ${signal} timeout`);
|
|
656
831
|
process.exit(1);
|
|
657
832
|
}, 45e3).unref();
|
|
658
833
|
};
|
|
@@ -680,7 +855,7 @@ var stopStartCommandChild = () => {
|
|
|
680
855
|
}
|
|
681
856
|
};
|
|
682
857
|
var launchStartCommand = (command) => {
|
|
683
|
-
|
|
858
|
+
logger2.info("Running start command", { command });
|
|
684
859
|
runner.connection.sendEvent({ type: "start_command_started" });
|
|
685
860
|
const child = runStartCommand(command, CONVEYOR_WORKSPACE, (stream, data) => {
|
|
686
861
|
runner.connection.sendEvent({ type: "start_command_output", stream, data });
|
|
@@ -690,7 +865,7 @@ var launchStartCommand = (command) => {
|
|
|
690
865
|
child.on("exit", (code, signal) => {
|
|
691
866
|
if (startCommandChild === child) startCommandChild = null;
|
|
692
867
|
if (expectedStartCommandStops.has(child)) return;
|
|
693
|
-
|
|
868
|
+
logger2.info("Start command exited", { code, signal });
|
|
694
869
|
runner.connection.sendEvent({
|
|
695
870
|
type: "start_command_exited",
|
|
696
871
|
code,
|
|
@@ -706,7 +881,7 @@ var launchStartCommand = (command) => {
|
|
|
706
881
|
});
|
|
707
882
|
child.on("error", (err) => {
|
|
708
883
|
if (startCommandChild === child) startCommandChild = null;
|
|
709
|
-
|
|
884
|
+
logger2.error("Start command error", { error: err.message });
|
|
710
885
|
runner.connection.sendEvent({ type: "start_command_error", message: err.message });
|
|
711
886
|
});
|
|
712
887
|
};
|
|
@@ -722,8 +897,21 @@ void checkSessionTaskIdentity({
|
|
|
722
897
|
const ctx = await runner.connection.call("getTaskContext", { sessionId });
|
|
723
898
|
return ctx.id;
|
|
724
899
|
},
|
|
725
|
-
logger
|
|
900
|
+
logger: logger2
|
|
726
901
|
});
|
|
902
|
+
if (CONVEYOR_MODE === "task") {
|
|
903
|
+
runner.connection.onSpawnReview((data) => {
|
|
904
|
+
void reviewChildren.spawn(data).catch((err) => {
|
|
905
|
+
logger2.error("Review child spawn threw", {
|
|
906
|
+
error: err instanceof Error ? err.message : String(err)
|
|
907
|
+
});
|
|
908
|
+
runner.connection.reportReviewSpawnFailure(
|
|
909
|
+
data.sessionId,
|
|
910
|
+
err instanceof Error ? err.message : String(err)
|
|
911
|
+
);
|
|
912
|
+
});
|
|
913
|
+
});
|
|
914
|
+
}
|
|
727
915
|
var conveyorConfig = loadConveyorConfig();
|
|
728
916
|
runner.connection.onRunStartCommand(() => {
|
|
729
917
|
if (!conveyorConfig?.startCommand) return;
|
|
@@ -754,15 +942,15 @@ if (conveyorConfig) {
|
|
|
754
942
|
startLazy: false
|
|
755
943
|
});
|
|
756
944
|
if (conveyorConfig.setupCommand) {
|
|
757
|
-
|
|
945
|
+
logger2.info("Running setup command (background)", {
|
|
758
946
|
command: conveyorConfig.setupCommand
|
|
759
947
|
});
|
|
760
948
|
try {
|
|
761
949
|
await runSetupCommand(conveyorConfig.setupCommand, CONVEYOR_WORKSPACE, logSetupOutput);
|
|
762
|
-
|
|
950
|
+
logger2.info("Setup command completed");
|
|
763
951
|
} catch (error) {
|
|
764
952
|
const msg = error instanceof Error ? error.message : "Setup command failed";
|
|
765
|
-
|
|
953
|
+
logger2.error("Setup command failed", { error: msg });
|
|
766
954
|
runner.connection.sendEvent({ type: "setup_error", message: msg });
|
|
767
955
|
}
|
|
768
956
|
}
|
|
@@ -785,7 +973,7 @@ runner.run().then(() => {
|
|
|
785
973
|
process.exit(runner.finalState === "error" ? 1 : 0);
|
|
786
974
|
}).catch((error) => {
|
|
787
975
|
const msg = error instanceof Error ? error.message : String(error);
|
|
788
|
-
|
|
976
|
+
logger2.error("Agent runner failed", { error: msg });
|
|
789
977
|
process.exit(1);
|
|
790
978
|
});
|
|
791
979
|
//# sourceMappingURL=cli.js.map
|