@rallycry/conveyor-agent 10.7.3 → 10.7.5
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-UOHROQ6A.js → chunk-CWTQXS34.js} +282 -120
- package/dist/chunk-CWTQXS34.js.map +1 -0
- package/dist/cli.js +376 -130
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +11 -4
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-UOHROQ6A.js.map +0 -1
|
@@ -1540,52 +1540,6 @@ async function backupOtherBranches(cwd, currentBranch) {
|
|
|
1540
1540
|
return count;
|
|
1541
1541
|
}
|
|
1542
1542
|
|
|
1543
|
-
// src/setup/git-ready.ts
|
|
1544
|
-
import { access, stat } from "fs/promises";
|
|
1545
|
-
var DEFAULT_FAILED_PATH = "/workspaces/.conveyor-git-failed";
|
|
1546
|
-
var DEFAULT_TIMEOUT_MS = 6e5;
|
|
1547
|
-
var DEFAULT_POLL_MS = 200;
|
|
1548
|
-
async function fileExists(path4) {
|
|
1549
|
-
try {
|
|
1550
|
-
await access(path4);
|
|
1551
|
-
const s = await stat(path4);
|
|
1552
|
-
return s.isFile();
|
|
1553
|
-
} catch {
|
|
1554
|
-
return false;
|
|
1555
|
-
}
|
|
1556
|
-
}
|
|
1557
|
-
function awaitGitReady(opts = {}) {
|
|
1558
|
-
const markerPath = opts.markerPath ?? process.env.CONVEYOR_GIT_READY_MARKER;
|
|
1559
|
-
if (!markerPath) {
|
|
1560
|
-
return Promise.resolve("not-gated");
|
|
1561
|
-
}
|
|
1562
|
-
const failedPath = opts.failedPath ?? process.env.CONVEYOR_GIT_FAILED_MARKER ?? DEFAULT_FAILED_PATH;
|
|
1563
|
-
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
1564
|
-
const pollMs = opts.pollMs ?? DEFAULT_POLL_MS;
|
|
1565
|
-
opts.onLog?.(`waiting for workspace git (marker=${markerPath})`);
|
|
1566
|
-
return pollForMarkers(markerPath, failedPath, timeoutMs, pollMs, opts.onLog);
|
|
1567
|
-
}
|
|
1568
|
-
async function pollForMarkers(markerPath, failedPath, timeoutMs, pollMs, onLog) {
|
|
1569
|
-
const deadline = Date.now() + timeoutMs;
|
|
1570
|
-
for (; ; ) {
|
|
1571
|
-
if (await fileExists(markerPath)) {
|
|
1572
|
-
onLog?.("workspace git ready");
|
|
1573
|
-
return "ready";
|
|
1574
|
-
}
|
|
1575
|
-
if (await fileExists(failedPath)) {
|
|
1576
|
-
onLog?.("workspace git preparation failed (marker present)");
|
|
1577
|
-
return "failed";
|
|
1578
|
-
}
|
|
1579
|
-
if (Date.now() >= deadline) {
|
|
1580
|
-
onLog?.(`workspace git not ready after ${timeoutMs}ms \u2014 giving up`);
|
|
1581
|
-
return "timeout";
|
|
1582
|
-
}
|
|
1583
|
-
await new Promise((resolve) => {
|
|
1584
|
-
setTimeout(resolve, pollMs);
|
|
1585
|
-
});
|
|
1586
|
-
}
|
|
1587
|
-
}
|
|
1588
|
-
|
|
1589
1543
|
// src/runner/work-preservation/index.ts
|
|
1590
1544
|
import { rm as rm3 } from "fs/promises";
|
|
1591
1545
|
|
|
@@ -1599,7 +1553,7 @@ function selectRestoreSource(probe) {
|
|
|
1599
1553
|
// src/runner/work-preservation/snapshot-tar.ts
|
|
1600
1554
|
import { execFile as execFile2 } from "child_process";
|
|
1601
1555
|
import { createReadStream, createWriteStream } from "fs";
|
|
1602
|
-
import { mkdtemp, rm, stat
|
|
1556
|
+
import { mkdtemp, rm, stat, writeFile } from "fs/promises";
|
|
1603
1557
|
import { tmpdir } from "os";
|
|
1604
1558
|
import path from "path";
|
|
1605
1559
|
import { pipeline } from "stream/promises";
|
|
@@ -1691,7 +1645,7 @@ async function buildSnapshotTar(cwd) {
|
|
|
1691
1645
|
const tarPath = path.join(staging, "snapshot.tar.gz");
|
|
1692
1646
|
await pipeline(createReadStream(rawTarPath), createGzip(), createWriteStream(tarPath));
|
|
1693
1647
|
await rm(rawTarPath, { force: true });
|
|
1694
|
-
const { size } = await
|
|
1648
|
+
const { size } = await stat(tarPath);
|
|
1695
1649
|
return {
|
|
1696
1650
|
tarPath,
|
|
1697
1651
|
sizeBytes: size,
|
|
@@ -4389,7 +4343,7 @@ async function removeConveyorCredentials(env = process.env) {
|
|
|
4389
4343
|
}
|
|
4390
4344
|
|
|
4391
4345
|
// src/harness/pty/pty-support.ts
|
|
4392
|
-
import { stat as
|
|
4346
|
+
import { stat as stat2 } from "fs/promises";
|
|
4393
4347
|
var MAX_DIAGNOSTIC_OUTPUT = 4e3;
|
|
4394
4348
|
var MAX_BETWEEN_TURN_BUFFER = 500;
|
|
4395
4349
|
var SUBMIT_SETTLE_MS = 300;
|
|
@@ -4449,9 +4403,9 @@ function extractSpawn(mod) {
|
|
|
4449
4403
|
}
|
|
4450
4404
|
async function loadPtySpawn() {
|
|
4451
4405
|
const mod = await import("node-pty");
|
|
4452
|
-
const
|
|
4453
|
-
if (!
|
|
4454
|
-
return
|
|
4406
|
+
const spawn2 = extractSpawn(mod);
|
|
4407
|
+
if (!spawn2) throw new Error("node-pty: spawn export not found");
|
|
4408
|
+
return spawn2;
|
|
4455
4409
|
}
|
|
4456
4410
|
function inheritedEnv(socketPath) {
|
|
4457
4411
|
const env = {};
|
|
@@ -4488,7 +4442,7 @@ function sleep3(ms) {
|
|
|
4488
4442
|
}
|
|
4489
4443
|
async function transcriptSize(path4) {
|
|
4490
4444
|
try {
|
|
4491
|
-
return (await
|
|
4445
|
+
return (await stat2(path4)).size;
|
|
4492
4446
|
} catch {
|
|
4493
4447
|
return 0;
|
|
4494
4448
|
}
|
|
@@ -4953,8 +4907,8 @@ var PtySession = class {
|
|
|
4953
4907
|
// server doesn't load).
|
|
4954
4908
|
...this.mcpConfigPath ? { mcpConfigPath: this.mcpConfigPath } : {}
|
|
4955
4909
|
});
|
|
4956
|
-
const
|
|
4957
|
-
const pty =
|
|
4910
|
+
const spawn2 = await loadPtySpawn();
|
|
4911
|
+
const pty = spawn2(spec.file, spec.args, {
|
|
4958
4912
|
name: "xterm-color",
|
|
4959
4913
|
cols: this.cols,
|
|
4960
4914
|
rows: this.rows,
|
|
@@ -5606,7 +5560,7 @@ function formatIncidents(incidents) {
|
|
|
5606
5560
|
}
|
|
5607
5561
|
|
|
5608
5562
|
// src/execution/tag-context-resolver.ts
|
|
5609
|
-
import { readFile as readFile2, readdir, stat as
|
|
5563
|
+
import { readFile as readFile2, readdir, stat as stat3 } from "fs/promises";
|
|
5610
5564
|
var TYPE_PRIORITY = { rule: 0, file: 1, folder: 2, doc: 3 };
|
|
5611
5565
|
var SUMMARY_SCAN_CHARS = 4e3;
|
|
5612
5566
|
var SUMMARY_MAX_CHARS = 160;
|
|
@@ -5680,7 +5634,7 @@ async function readFileSummary(filePath) {
|
|
|
5680
5634
|
if (isBinaryPath(filePath)) return null;
|
|
5681
5635
|
let mtimeMs;
|
|
5682
5636
|
try {
|
|
5683
|
-
const st = await
|
|
5637
|
+
const st = await stat3(filePath);
|
|
5684
5638
|
mtimeMs = st.mtimeMs;
|
|
5685
5639
|
} catch {
|
|
5686
5640
|
return null;
|
|
@@ -5702,7 +5656,7 @@ async function readFolderListing(folderPath) {
|
|
|
5702
5656
|
try {
|
|
5703
5657
|
let mtimeMs;
|
|
5704
5658
|
try {
|
|
5705
|
-
const st = await
|
|
5659
|
+
const st = await stat3(folderPath);
|
|
5706
5660
|
mtimeMs = st.mtimeMs;
|
|
5707
5661
|
} catch {
|
|
5708
5662
|
return null;
|
|
@@ -7306,7 +7260,7 @@ function buildMutationTools(connection, config) {
|
|
|
7306
7260
|
}
|
|
7307
7261
|
|
|
7308
7262
|
// src/tools/attachment-tools.ts
|
|
7309
|
-
import { readFile as readFile3, stat as
|
|
7263
|
+
import { readFile as readFile3, stat as stat4 } from "fs/promises";
|
|
7310
7264
|
import { basename, extname, isAbsolute, join as join5 } from "path";
|
|
7311
7265
|
import { z as z7 } from "zod";
|
|
7312
7266
|
var IMAGE_MIME_BY_EXT = {
|
|
@@ -7333,7 +7287,7 @@ function buildUploadAttachmentTool(connection, config) {
|
|
|
7333
7287
|
`Unsupported file type "${extname(filePath) || "(none)"}". Supported: ${Object.keys(IMAGE_MIME_BY_EXT).join(", ")}`
|
|
7334
7288
|
);
|
|
7335
7289
|
}
|
|
7336
|
-
const info = await
|
|
7290
|
+
const info = await stat4(filePath).catch(() => null);
|
|
7337
7291
|
if (!info?.isFile()) {
|
|
7338
7292
|
return textResult(`File not found: ${filePath}`);
|
|
7339
7293
|
}
|
|
@@ -9650,10 +9604,21 @@ function readAgentVersion() {
|
|
|
9650
9604
|
return null;
|
|
9651
9605
|
}
|
|
9652
9606
|
|
|
9607
|
+
// src/execution/usage-sampler.ts
|
|
9608
|
+
import { existsSync as existsSync3 } from "fs";
|
|
9609
|
+
|
|
9653
9610
|
// src/usage/parse-usage.ts
|
|
9611
|
+
var ESC = "\\u001b";
|
|
9612
|
+
var ANSI_CSI2 = new RegExp(`${ESC}\\[[0-9;?]*[ -/]*[@-~]`, "g");
|
|
9613
|
+
var ANSI_OSC = new RegExp(`${ESC}\\][^\\u0007${ESC}]*(?:\\u0007|${ESC}\\\\)`, "g");
|
|
9614
|
+
var BAR_GLYPHS = /[─-▟]/g;
|
|
9615
|
+
function normalizeUsageText(stdout) {
|
|
9616
|
+
return stdout.replace(ANSI_CSI2, "").replace(ANSI_OSC, "").replace(BAR_GLYPHS, " ").replace(/\r/g, "");
|
|
9617
|
+
}
|
|
9654
9618
|
function parseUsageGauges(stdout) {
|
|
9655
|
-
const
|
|
9656
|
-
const
|
|
9619
|
+
const text = normalizeUsageText(stdout);
|
|
9620
|
+
const session = text.match(/Current session[^%\n]*?(\d+(?:\.\d+)?)\s*%(?:\s*used)?/i);
|
|
9621
|
+
const weekly = [...text.matchAll(/Current week[^%\n]*?(\d+(?:\.\d+)?)\s*%(?:\s*used)?/gi)];
|
|
9657
9622
|
return {
|
|
9658
9623
|
sessionUsage: session ? Number(session[1]) / 100 : null,
|
|
9659
9624
|
weeklyUsage: weekly.length ? Math.max(...weekly.map((m) => Number(m[1]))) / 100 : null
|
|
@@ -9661,54 +9626,116 @@ function parseUsageGauges(stdout) {
|
|
|
9661
9626
|
}
|
|
9662
9627
|
|
|
9663
9628
|
// src/usage/run-probe.ts
|
|
9664
|
-
|
|
9665
|
-
var
|
|
9629
|
+
var PROBE_TIMEOUT_MS = 3e4;
|
|
9630
|
+
var FIRST_SEND_MS = 5e3;
|
|
9631
|
+
var RESEND_INTERVAL_MS = 4e3;
|
|
9632
|
+
var MAX_SENDS = 5;
|
|
9633
|
+
var RENDER_SETTLE_MS = 900;
|
|
9666
9634
|
function buildProbeEnv(env = process.env) {
|
|
9667
|
-
const
|
|
9668
|
-
|
|
9669
|
-
|
|
9670
|
-
|
|
9635
|
+
const clean = {};
|
|
9636
|
+
for (const [key, value] of Object.entries(env)) {
|
|
9637
|
+
if (typeof value === "string") clean[key] = value;
|
|
9638
|
+
}
|
|
9639
|
+
delete clean.CLAUDE_CODE_OAUTH_TOKEN;
|
|
9640
|
+
delete clean.ANTHROPIC_API_KEY;
|
|
9641
|
+
return clean;
|
|
9642
|
+
}
|
|
9643
|
+
function panelRendering(buf) {
|
|
9644
|
+
return /Current session/i.test(buf) && /%/.test(buf);
|
|
9645
|
+
}
|
|
9646
|
+
var UsageProbeRun = class {
|
|
9647
|
+
constructor(resolve, timing) {
|
|
9648
|
+
this.resolve = resolve;
|
|
9649
|
+
this.timing = timing;
|
|
9650
|
+
}
|
|
9651
|
+
resolve;
|
|
9652
|
+
timing;
|
|
9653
|
+
buf = "";
|
|
9654
|
+
settled = false;
|
|
9655
|
+
sends = 0;
|
|
9656
|
+
child = null;
|
|
9657
|
+
hardTimer = null;
|
|
9658
|
+
resendTimer = null;
|
|
9659
|
+
settleTimer = null;
|
|
9660
|
+
start(child, timeoutMs) {
|
|
9661
|
+
this.child = child;
|
|
9662
|
+
child.onData((data) => this.onData(data));
|
|
9663
|
+
child.onExit(() => this.finishBestEffort());
|
|
9664
|
+
this.hardTimer = setTimeout(() => this.finishBestEffort(), timeoutMs);
|
|
9665
|
+
this.hardTimer.unref?.();
|
|
9666
|
+
const first = setTimeout(() => this.trySend(), this.timing.firstSendMs);
|
|
9667
|
+
first.unref?.();
|
|
9668
|
+
this.resendTimer = setInterval(() => this.trySend(), this.timing.resendIntervalMs);
|
|
9669
|
+
this.resendTimer.unref?.();
|
|
9670
|
+
}
|
|
9671
|
+
trySend() {
|
|
9672
|
+
if (this.settled || this.sends >= MAX_SENDS) return;
|
|
9673
|
+
this.sends += 1;
|
|
9674
|
+
try {
|
|
9675
|
+
this.child?.write("/usage\r");
|
|
9676
|
+
} catch {
|
|
9677
|
+
}
|
|
9678
|
+
}
|
|
9679
|
+
onData(chunk) {
|
|
9680
|
+
this.buf += chunk;
|
|
9681
|
+
if (this.settleTimer || !panelRendering(this.buf)) return;
|
|
9682
|
+
this.settleTimer = setTimeout(() => this.finish(this.buf), this.timing.settleMs);
|
|
9683
|
+
}
|
|
9684
|
+
finishBestEffort() {
|
|
9685
|
+
this.finish(panelRendering(this.buf) ? this.buf : "");
|
|
9686
|
+
}
|
|
9687
|
+
finish(out) {
|
|
9688
|
+
if (this.settled) return;
|
|
9689
|
+
this.settled = true;
|
|
9690
|
+
if (this.hardTimer) clearTimeout(this.hardTimer);
|
|
9691
|
+
if (this.resendTimer) clearInterval(this.resendTimer);
|
|
9692
|
+
if (this.settleTimer) clearTimeout(this.settleTimer);
|
|
9693
|
+
try {
|
|
9694
|
+
this.child?.kill();
|
|
9695
|
+
} catch {
|
|
9696
|
+
}
|
|
9697
|
+
this.resolve(out);
|
|
9698
|
+
}
|
|
9699
|
+
};
|
|
9700
|
+
async function runUsageProbe(deps = {}) {
|
|
9701
|
+
let spawn2 = deps.spawn;
|
|
9702
|
+
if (!spawn2) {
|
|
9703
|
+
try {
|
|
9704
|
+
spawn2 = await loadPtySpawn();
|
|
9705
|
+
} catch {
|
|
9706
|
+
return "";
|
|
9707
|
+
}
|
|
9708
|
+
}
|
|
9709
|
+
const binary = deps.binary ?? resolveClaudeBinary();
|
|
9710
|
+
const cwd = deps.cwd ?? process.cwd();
|
|
9711
|
+
const timeoutMs = deps.timeoutMs ?? PROBE_TIMEOUT_MS;
|
|
9712
|
+
const timing = {
|
|
9713
|
+
firstSendMs: deps.firstSendMs ?? FIRST_SEND_MS,
|
|
9714
|
+
resendIntervalMs: deps.resendIntervalMs ?? RESEND_INTERVAL_MS,
|
|
9715
|
+
settleMs: deps.settleMs ?? RENDER_SETTLE_MS
|
|
9716
|
+
};
|
|
9671
9717
|
return new Promise((resolve) => {
|
|
9672
|
-
let stdout = "";
|
|
9673
|
-
let settled = false;
|
|
9674
|
-
const finish = (out) => {
|
|
9675
|
-
if (settled) return;
|
|
9676
|
-
settled = true;
|
|
9677
|
-
resolve(out);
|
|
9678
|
-
};
|
|
9679
9718
|
let child;
|
|
9680
9719
|
try {
|
|
9681
|
-
child =
|
|
9720
|
+
child = spawn2(binary, [], {
|
|
9721
|
+
name: "xterm-256color",
|
|
9722
|
+
cols: 120,
|
|
9723
|
+
rows: 45,
|
|
9724
|
+
cwd,
|
|
9725
|
+
env: buildProbeEnv()
|
|
9726
|
+
});
|
|
9682
9727
|
} catch {
|
|
9683
|
-
|
|
9728
|
+
resolve("");
|
|
9684
9729
|
return;
|
|
9685
9730
|
}
|
|
9686
|
-
|
|
9687
|
-
try {
|
|
9688
|
-
child.kill("SIGKILL");
|
|
9689
|
-
} catch {
|
|
9690
|
-
}
|
|
9691
|
-
finish("");
|
|
9692
|
-
}, PROBE_TIMEOUT_MS);
|
|
9693
|
-
timer.unref?.();
|
|
9694
|
-
child.stdout?.on("data", (d) => {
|
|
9695
|
-
stdout += d.toString();
|
|
9696
|
-
});
|
|
9697
|
-
child.on("error", () => {
|
|
9698
|
-
clearTimeout(timer);
|
|
9699
|
-
finish("");
|
|
9700
|
-
});
|
|
9701
|
-
child.on("close", (code) => {
|
|
9702
|
-
clearTimeout(timer);
|
|
9703
|
-
finish(code === 0 ? stdout : "");
|
|
9704
|
-
});
|
|
9731
|
+
new UsageProbeRun(resolve, timing).start(child, timeoutMs);
|
|
9705
9732
|
});
|
|
9706
9733
|
}
|
|
9707
9734
|
|
|
9708
9735
|
// src/execution/usage-sampler.ts
|
|
9709
9736
|
var logger4 = createServiceLogger("usage-sampler");
|
|
9710
|
-
async function sampleKeyUsage(token, probe = runUsageProbe) {
|
|
9711
|
-
if (!token) return [];
|
|
9737
|
+
async function sampleKeyUsage(token, probe = () => runUsageProbe(), hasSubscriptionCredentials = () => existsSync3(claudeCredentialsPath())) {
|
|
9738
|
+
if (!token && !hasSubscriptionCredentials()) return [];
|
|
9712
9739
|
try {
|
|
9713
9740
|
const stdout = await probe();
|
|
9714
9741
|
const { sessionUsage, weeklyUsage } = parseUsageGauges(stdout);
|
|
@@ -9734,6 +9761,76 @@ async function sampleKeyUsage(token, probe = runUsageProbe) {
|
|
|
9734
9761
|
}
|
|
9735
9762
|
}
|
|
9736
9763
|
|
|
9764
|
+
// src/setup/git-ready.ts
|
|
9765
|
+
import { access, stat as stat5 } from "fs/promises";
|
|
9766
|
+
var DEFAULT_FAILED_PATH = "/workspaces/.conveyor-git-failed";
|
|
9767
|
+
var DEFAULT_TIMEOUT_MS = 6e5;
|
|
9768
|
+
var DEFAULT_POLL_MS = 200;
|
|
9769
|
+
async function fileExists(path4) {
|
|
9770
|
+
try {
|
|
9771
|
+
await access(path4);
|
|
9772
|
+
const s = await stat5(path4);
|
|
9773
|
+
return s.isFile();
|
|
9774
|
+
} catch {
|
|
9775
|
+
return false;
|
|
9776
|
+
}
|
|
9777
|
+
}
|
|
9778
|
+
function awaitGitReady(opts = {}) {
|
|
9779
|
+
if (opts.signal?.aborted) return Promise.reject(abortError());
|
|
9780
|
+
const markerPath = opts.markerPath ?? process.env.CONVEYOR_GIT_READY_MARKER;
|
|
9781
|
+
if (!markerPath) {
|
|
9782
|
+
return Promise.resolve("not-gated");
|
|
9783
|
+
}
|
|
9784
|
+
const failedPath = opts.failedPath ?? process.env.CONVEYOR_GIT_FAILED_MARKER ?? DEFAULT_FAILED_PATH;
|
|
9785
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
9786
|
+
const pollMs = opts.pollMs ?? DEFAULT_POLL_MS;
|
|
9787
|
+
opts.onLog?.(`waiting for workspace git (marker=${markerPath})`);
|
|
9788
|
+
return pollForMarkers(markerPath, failedPath, timeoutMs, pollMs, opts.onLog, opts.signal);
|
|
9789
|
+
}
|
|
9790
|
+
function abortError() {
|
|
9791
|
+
const error = new Error("Operation aborted");
|
|
9792
|
+
error.name = "AbortError";
|
|
9793
|
+
return error;
|
|
9794
|
+
}
|
|
9795
|
+
function abortableDelay(ms, signal) {
|
|
9796
|
+
if (!signal) {
|
|
9797
|
+
return new Promise((resolve) => {
|
|
9798
|
+
setTimeout(resolve, ms);
|
|
9799
|
+
});
|
|
9800
|
+
}
|
|
9801
|
+
if (signal.aborted) return Promise.reject(abortError());
|
|
9802
|
+
return new Promise((resolve, reject) => {
|
|
9803
|
+
const timer = setTimeout(() => {
|
|
9804
|
+
signal.removeEventListener("abort", onAbort);
|
|
9805
|
+
resolve();
|
|
9806
|
+
}, ms);
|
|
9807
|
+
const onAbort = () => {
|
|
9808
|
+
clearTimeout(timer);
|
|
9809
|
+
reject(abortError());
|
|
9810
|
+
};
|
|
9811
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
9812
|
+
});
|
|
9813
|
+
}
|
|
9814
|
+
async function pollForMarkers(markerPath, failedPath, timeoutMs, pollMs, onLog, signal) {
|
|
9815
|
+
const deadline = Date.now() + timeoutMs;
|
|
9816
|
+
for (; ; ) {
|
|
9817
|
+
if (signal?.aborted) throw abortError();
|
|
9818
|
+
if (await fileExists(markerPath)) {
|
|
9819
|
+
onLog?.("workspace git ready");
|
|
9820
|
+
return "ready";
|
|
9821
|
+
}
|
|
9822
|
+
if (await fileExists(failedPath)) {
|
|
9823
|
+
onLog?.("workspace git preparation failed (marker present)");
|
|
9824
|
+
return "failed";
|
|
9825
|
+
}
|
|
9826
|
+
if (Date.now() >= deadline) {
|
|
9827
|
+
onLog?.(`workspace git not ready after ${timeoutMs}ms \u2014 giving up`);
|
|
9828
|
+
return "timeout";
|
|
9829
|
+
}
|
|
9830
|
+
await abortableDelay(pollMs, signal);
|
|
9831
|
+
}
|
|
9832
|
+
}
|
|
9833
|
+
|
|
9737
9834
|
// src/runner/port-discovery.ts
|
|
9738
9835
|
import { readFile as readFile4 } from "fs/promises";
|
|
9739
9836
|
import { execFile as execFile3 } from "child_process";
|
|
@@ -9847,6 +9944,7 @@ var PortDiscovery = class {
|
|
|
9847
9944
|
timer = null;
|
|
9848
9945
|
ticking = false;
|
|
9849
9946
|
disabled = false;
|
|
9947
|
+
stopped = false;
|
|
9850
9948
|
/** Set when the confirmed set changed (or a report failed) — cleared only
|
|
9851
9949
|
* after a successful report, so transient RPC failures retry next tick. */
|
|
9852
9950
|
reportPending = false;
|
|
@@ -9864,8 +9962,9 @@ var PortDiscovery = class {
|
|
|
9864
9962
|
}
|
|
9865
9963
|
/** Take the baseline scan and start polling. Safe to call once. */
|
|
9866
9964
|
async start() {
|
|
9867
|
-
if (this.timer || this.disabled) return;
|
|
9965
|
+
if (this.timer || this.disabled || this.stopped) return;
|
|
9868
9966
|
const baseline = await this.scanSafe();
|
|
9967
|
+
if (this.stopped) return;
|
|
9869
9968
|
if (baseline === null) {
|
|
9870
9969
|
this.disabled = true;
|
|
9871
9970
|
this.log("Port discovery disabled: no listening-socket source available");
|
|
@@ -9876,6 +9975,7 @@ var PortDiscovery = class {
|
|
|
9876
9975
|
this.timer.unref?.();
|
|
9877
9976
|
}
|
|
9878
9977
|
stop() {
|
|
9978
|
+
this.stopped = true;
|
|
9879
9979
|
if (this.timer) {
|
|
9880
9980
|
clearInterval(this.timer);
|
|
9881
9981
|
this.timer = null;
|
|
@@ -10071,13 +10171,16 @@ var SessionRunner = class _SessionRunner {
|
|
|
10071
10171
|
/** Max consecutive gate-deferred ticks (~2 min each) before flushing anyway. */
|
|
10072
10172
|
static MAX_GATE_SKIPS = 10;
|
|
10073
10173
|
/** Runtime preview-port poller (v3 dynamic port discovery). */
|
|
10074
|
-
portDiscovery
|
|
10174
|
+
portDiscovery;
|
|
10075
10175
|
/** Main event-loop lag measurement, shared with the heartbeat worker. */
|
|
10076
10176
|
loopLag = new LoopLagMonitor();
|
|
10077
|
-
constructor(config, callbacks) {
|
|
10177
|
+
constructor(config, callbacks, deps = {}) {
|
|
10078
10178
|
this.config = config;
|
|
10079
10179
|
this.callbacks = callbacks;
|
|
10080
10180
|
this.connection = new AgentConnection(config.connection);
|
|
10181
|
+
this.portDiscovery = deps.portDiscovery ?? new PortDiscovery({
|
|
10182
|
+
report: (ports) => this.connection.reportDiscoveredPorts(ports)
|
|
10183
|
+
});
|
|
10081
10184
|
const initialMode = config.agentMode ?? (config.runnerMode === "pm" ? config.isAuto ? "auto" : "discovery" : "building");
|
|
10082
10185
|
this.mode = new ModeController(initialMode, config.runnerMode, config.isAuto);
|
|
10083
10186
|
const lifecycleConfig = { ...DEFAULT_LIFECYCLE_CONFIG, ...config.lifecycle };
|
|
@@ -10142,16 +10245,18 @@ var SessionRunner = class _SessionRunner {
|
|
|
10142
10245
|
this.pendingMessages.push({ content: msg.content, userId: msg.userId });
|
|
10143
10246
|
}
|
|
10144
10247
|
}
|
|
10145
|
-
this.
|
|
10146
|
-
|
|
10147
|
-
|
|
10148
|
-
|
|
10149
|
-
}
|
|
10248
|
+
if (this.stopped) return false;
|
|
10249
|
+
try {
|
|
10250
|
+
await this.portDiscovery.start();
|
|
10251
|
+
} catch {
|
|
10252
|
+
}
|
|
10253
|
+
if (this.stopped) return false;
|
|
10150
10254
|
const agentVersion = readAgentVersion();
|
|
10151
10255
|
if (agentVersion) {
|
|
10152
10256
|
this.connection.call("notifyAgentVersion", { sessionId: this.sessionId, agentVersion }).catch(() => {
|
|
10153
10257
|
});
|
|
10154
10258
|
}
|
|
10259
|
+
return true;
|
|
10155
10260
|
}
|
|
10156
10261
|
/**
|
|
10157
10262
|
* Run the main agent lifecycle: fetch context, resolve mode, execute, loop.
|
|
@@ -10267,7 +10372,7 @@ var SessionRunner = class _SessionRunner {
|
|
|
10267
10372
|
}
|
|
10268
10373
|
/** Convenience wrapper: connect() then run(). */
|
|
10269
10374
|
async start() {
|
|
10270
|
-
await this.connect();
|
|
10375
|
+
if (!await this.connect()) return;
|
|
10271
10376
|
await this.run();
|
|
10272
10377
|
}
|
|
10273
10378
|
// ── Core loop ──────────────────────────────────────────────────────
|
|
@@ -10661,7 +10766,7 @@ var SessionRunner = class _SessionRunner {
|
|
|
10661
10766
|
this.queryBridge?.stop();
|
|
10662
10767
|
void this.queryBridge?.dispose().catch(() => {
|
|
10663
10768
|
});
|
|
10664
|
-
this.portDiscovery
|
|
10769
|
+
this.portDiscovery.stop();
|
|
10665
10770
|
this.loopLag.stop();
|
|
10666
10771
|
this.lifecycle.destroy();
|
|
10667
10772
|
this.connection.disconnect();
|
|
@@ -10873,7 +10978,7 @@ var SessionRunner = class _SessionRunner {
|
|
|
10873
10978
|
process.stderr.write(`[conveyor-agent] Shutdown: reason=${finalState}
|
|
10874
10979
|
`);
|
|
10875
10980
|
this.connection.sendEvent({ type: "shutdown", reason: finalState });
|
|
10876
|
-
this.portDiscovery
|
|
10981
|
+
this.portDiscovery.stop();
|
|
10877
10982
|
this.loopLag.stop();
|
|
10878
10983
|
this.lifecycle.destroy();
|
|
10879
10984
|
try {
|
|
@@ -10971,29 +11076,84 @@ function loadConveyorConfig() {
|
|
|
10971
11076
|
}
|
|
10972
11077
|
|
|
10973
11078
|
// src/setup/commands.ts
|
|
10974
|
-
import { spawn
|
|
10975
|
-
|
|
11079
|
+
import { spawn, execSync } from "child_process";
|
|
11080
|
+
var PROCESS_TERMINATION_GRACE_MS = 5e3;
|
|
11081
|
+
function abortError2() {
|
|
11082
|
+
const error = new Error("Operation aborted");
|
|
11083
|
+
error.name = "AbortError";
|
|
11084
|
+
return error;
|
|
11085
|
+
}
|
|
11086
|
+
function signalProcessGroup(child, signal) {
|
|
11087
|
+
try {
|
|
11088
|
+
if (child.pid) process.kill(-child.pid, signal);
|
|
11089
|
+
else child.kill(signal);
|
|
11090
|
+
} catch {
|
|
11091
|
+
try {
|
|
11092
|
+
child.kill(signal);
|
|
11093
|
+
} catch {
|
|
11094
|
+
}
|
|
11095
|
+
}
|
|
11096
|
+
}
|
|
11097
|
+
function terminateProcessGroup(child, graceMs = PROCESS_TERMINATION_GRACE_MS) {
|
|
11098
|
+
if (child.exitCode !== null) return Promise.resolve();
|
|
11099
|
+
return new Promise((resolve) => {
|
|
11100
|
+
let settled = false;
|
|
11101
|
+
const finish = () => {
|
|
11102
|
+
if (settled) return;
|
|
11103
|
+
settled = true;
|
|
11104
|
+
clearTimeout(timer);
|
|
11105
|
+
child.removeListener("exit", finish);
|
|
11106
|
+
resolve();
|
|
11107
|
+
};
|
|
11108
|
+
const timer = setTimeout(() => {
|
|
11109
|
+
signalProcessGroup(child, "SIGKILL");
|
|
11110
|
+
finish();
|
|
11111
|
+
}, graceMs);
|
|
11112
|
+
timer.unref();
|
|
11113
|
+
child.once("exit", finish);
|
|
11114
|
+
signalProcessGroup(child, "SIGTERM");
|
|
11115
|
+
});
|
|
11116
|
+
}
|
|
11117
|
+
function runSetupCommand(cmd, cwd, onOutput, signal) {
|
|
11118
|
+
if (signal?.aborted) return Promise.reject(abortError2());
|
|
10976
11119
|
return new Promise((resolve, reject) => {
|
|
10977
|
-
const child =
|
|
11120
|
+
const child = spawn("sh", ["-c", cmd], {
|
|
10978
11121
|
cwd,
|
|
10979
11122
|
stdio: ["ignore", "pipe", "pipe"],
|
|
11123
|
+
detached: true,
|
|
10980
11124
|
env: { ...process.env }
|
|
10981
11125
|
});
|
|
11126
|
+
let settled = false;
|
|
11127
|
+
let aborting = false;
|
|
11128
|
+
const cleanup = () => signal?.removeEventListener("abort", onAbort);
|
|
11129
|
+
const settle = (error) => {
|
|
11130
|
+
if (settled) return;
|
|
11131
|
+
settled = true;
|
|
11132
|
+
cleanup();
|
|
11133
|
+
if (error) reject(error);
|
|
11134
|
+
else resolve();
|
|
11135
|
+
};
|
|
11136
|
+
const onAbort = () => {
|
|
11137
|
+
if (settled || aborting) return;
|
|
11138
|
+
aborting = true;
|
|
11139
|
+
void terminateProcessGroup(child).then(() => settle(abortError2()));
|
|
11140
|
+
};
|
|
11141
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
11142
|
+
if (signal?.aborted) onAbort();
|
|
10982
11143
|
child.stdout.on("data", (chunk) => {
|
|
11144
|
+
if (aborting || signal?.aborted) return;
|
|
10983
11145
|
onOutput("stdout", chunk.toString());
|
|
10984
11146
|
});
|
|
10985
11147
|
child.stderr.on("data", (chunk) => {
|
|
11148
|
+
if (aborting || signal?.aborted) return;
|
|
10986
11149
|
onOutput("stderr", chunk.toString());
|
|
10987
11150
|
});
|
|
10988
11151
|
child.on("close", (code) => {
|
|
10989
|
-
if (
|
|
10990
|
-
|
|
10991
|
-
} else {
|
|
10992
|
-
reject(new Error(`Setup command exited with code ${code}`));
|
|
10993
|
-
}
|
|
11152
|
+
if (aborting) return;
|
|
11153
|
+
settle(code === 0 ? void 0 : new Error(`Setup command exited with code ${code}`));
|
|
10994
11154
|
});
|
|
10995
11155
|
child.on("error", (err) => {
|
|
10996
|
-
|
|
11156
|
+
if (!aborting) settle(err);
|
|
10997
11157
|
});
|
|
10998
11158
|
});
|
|
10999
11159
|
}
|
|
@@ -11013,7 +11173,7 @@ function runAuthTokenCommand(cmd, userEmail, cwd) {
|
|
|
11013
11173
|
}
|
|
11014
11174
|
}
|
|
11015
11175
|
function runStartCommand(cmd, cwd, onOutput) {
|
|
11016
|
-
const child =
|
|
11176
|
+
const child = spawn("sh", ["-c", cmd], {
|
|
11017
11177
|
cwd,
|
|
11018
11178
|
stdio: ["ignore", "pipe", "pipe"],
|
|
11019
11179
|
detached: true,
|
|
@@ -11070,6 +11230,7 @@ export {
|
|
|
11070
11230
|
resolveSessionStart,
|
|
11071
11231
|
sampleKeyUsage,
|
|
11072
11232
|
awaitGitReady,
|
|
11233
|
+
PortDiscovery,
|
|
11073
11234
|
uploadSnapshotToGcs,
|
|
11074
11235
|
captureSnapshot,
|
|
11075
11236
|
startPeriodic,
|
|
@@ -11080,9 +11241,10 @@ export {
|
|
|
11080
11241
|
loadForwardPorts,
|
|
11081
11242
|
buildSessionPreviewPorts,
|
|
11082
11243
|
loadConveyorConfig,
|
|
11244
|
+
terminateProcessGroup,
|
|
11083
11245
|
runSetupCommand,
|
|
11084
11246
|
runAuthTokenCommand,
|
|
11085
11247
|
runStartCommand,
|
|
11086
11248
|
unshallowRepo
|
|
11087
11249
|
};
|
|
11088
|
-
//# sourceMappingURL=chunk-
|
|
11250
|
+
//# sourceMappingURL=chunk-CWTQXS34.js.map
|