@rallycry/conveyor-agent 10.13.9 → 10.13.11
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-2K6RRTQC.js +451 -0
- package/dist/chunk-2K6RRTQC.js.map +1 -0
- package/dist/chunk-4VUQ2NPF.js +25 -0
- package/dist/chunk-4VUQ2NPF.js.map +1 -0
- package/dist/{chunk-PXQJ4NVO.js → chunk-DJPSNHVJ.js} +229 -567
- package/dist/chunk-DJPSNHVJ.js.map +1 -0
- package/dist/chunk-IE7EOKMD.js +55 -0
- package/dist/chunk-IE7EOKMD.js.map +1 -0
- package/dist/chunk-YRC57EYG.js +413 -0
- package/dist/chunk-YRC57EYG.js.map +1 -0
- package/dist/cli.js +53 -9
- package/dist/cli.js.map +1 -1
- package/dist/client-ICIWKSK2.js +17 -0
- package/dist/client-ICIWKSK2.js.map +1 -0
- package/dist/index.js +24 -8
- package/dist/index.js.map +1 -1
- package/dist/mode-6RL3SVMV.js +13 -0
- package/dist/mode-6RL3SVMV.js.map +1 -0
- package/dist/protocol-QJRHTTMQ.js +15 -0
- package/dist/protocol-QJRHTTMQ.js.map +1 -0
- package/dist/server-UGE67KIZ.js +313 -0
- package/dist/server-UGE67KIZ.js.map +1 -0
- package/package.json +1 -1
- package/runtime/entrypoint.sh +100 -16
- package/dist/chunk-PXQJ4NVO.js.map +0 -1
|
@@ -1,13 +1,31 @@
|
|
|
1
1
|
import {
|
|
2
2
|
LoopLagMonitor
|
|
3
3
|
} from "./chunk-7TQO4ZF4.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
import {
|
|
5
|
+
getWorkbenchClient
|
|
6
|
+
} from "./chunk-YRC57EYG.js";
|
|
7
|
+
import {
|
|
8
|
+
workbenchEnabled
|
|
9
|
+
} from "./chunk-4VUQ2NPF.js";
|
|
10
|
+
import {
|
|
11
|
+
MAX_BETWEEN_TURN_BUFFER,
|
|
12
|
+
MAX_DIAGNOSTIC_OUTPUT,
|
|
13
|
+
buildPromptBytes,
|
|
14
|
+
buildSnapshotTar,
|
|
15
|
+
extractSnapshotTar,
|
|
16
|
+
inheritedEnv,
|
|
17
|
+
loadPtySpawn,
|
|
18
|
+
parseUserQuestions,
|
|
19
|
+
renderPromptContentText,
|
|
20
|
+
resolvePlanDialogTiming,
|
|
21
|
+
resolvePtySpawn,
|
|
22
|
+
resolveSubmitNudgeTiming,
|
|
23
|
+
resolveSubmitSettleMs,
|
|
24
|
+
sessionTempBase,
|
|
25
|
+
sleep,
|
|
26
|
+
transcriptSize,
|
|
27
|
+
turnOptionsFrom
|
|
28
|
+
} from "./chunk-2K6RRTQC.js";
|
|
11
29
|
|
|
12
30
|
// src/setup/bootstrap.ts
|
|
13
31
|
var BOOTSTRAP_TIMEOUT_MS = 3e4;
|
|
@@ -1031,7 +1049,7 @@ ${q.question}${q.options.length ? "\n" + q.options.map((o) => `- ${o.label}: ${o
|
|
|
1031
1049
|
refreshFromBootstrap() {
|
|
1032
1050
|
const none = Promise.resolve({ refreshedClaude: false, refreshedTaskToken: false });
|
|
1033
1051
|
const podBootstrapToken = process.env.POD_BOOTSTRAP_TOKEN;
|
|
1034
|
-
const codespaceName = process.env.CODESPACE_NAME
|
|
1052
|
+
const codespaceName = process.env.CODESPACE_NAME;
|
|
1035
1053
|
const apiUrl = this.config.apiUrl;
|
|
1036
1054
|
if (!apiUrl || !podBootstrapToken && !codespaceName) {
|
|
1037
1055
|
return none;
|
|
@@ -1193,6 +1211,14 @@ var GIT_TIMEOUT_MS = 6e4;
|
|
|
1193
1211
|
var GIT_SLOW_TIMEOUT_MS = 12e4;
|
|
1194
1212
|
var GIT_MAX_BUFFER = 16 * 1024 * 1024;
|
|
1195
1213
|
async function git(cwd, args, timeoutMs = GIT_TIMEOUT_MS) {
|
|
1214
|
+
if (workbenchEnabled()) {
|
|
1215
|
+
const { stdout: stdout2 } = await getWorkbenchClient().execFile("git", args, {
|
|
1216
|
+
cwd,
|
|
1217
|
+
timeout: timeoutMs,
|
|
1218
|
+
maxBuffer: GIT_MAX_BUFFER
|
|
1219
|
+
});
|
|
1220
|
+
return stdout2.trim();
|
|
1221
|
+
}
|
|
1196
1222
|
const { stdout } = await execFileAsync("git", args, {
|
|
1197
1223
|
cwd,
|
|
1198
1224
|
timeout: timeoutMs,
|
|
@@ -1574,7 +1600,9 @@ async function backupOtherBranches(cwd, currentBranch) {
|
|
|
1574
1600
|
}
|
|
1575
1601
|
|
|
1576
1602
|
// src/runner/work-preservation/index.ts
|
|
1577
|
-
import { rm as
|
|
1603
|
+
import { mkdtemp, rm as rm2 } from "fs/promises";
|
|
1604
|
+
import { tmpdir as tmpdir2 } from "os";
|
|
1605
|
+
import { join } from "path";
|
|
1578
1606
|
|
|
1579
1607
|
// src/runner/work-preservation/restore-precedence.ts
|
|
1580
1608
|
function selectRestoreSource(probe) {
|
|
@@ -1583,193 +1611,19 @@ function selectRestoreSource(probe) {
|
|
|
1583
1611
|
return "clean";
|
|
1584
1612
|
}
|
|
1585
1613
|
|
|
1586
|
-
// src/runner/work-preservation/snapshot-
|
|
1587
|
-
import {
|
|
1614
|
+
// src/runner/work-preservation/snapshot-transfer.ts
|
|
1615
|
+
import { randomUUID } from "crypto";
|
|
1588
1616
|
import { createReadStream, createWriteStream } from "fs";
|
|
1589
|
-
import {
|
|
1617
|
+
import { rm } from "fs/promises";
|
|
1590
1618
|
import { tmpdir } from "os";
|
|
1591
1619
|
import path from "path";
|
|
1592
|
-
import { pipeline } from "stream/promises";
|
|
1593
|
-
import { promisify as promisify2 } from "util";
|
|
1594
|
-
import { createGzip } from "zlib";
|
|
1595
|
-
import * as tar from "tar";
|
|
1596
|
-
|
|
1597
|
-
// src/runner/work-preservation/snapshot-artifact.ts
|
|
1598
|
-
function planSnapshotFiles(git2) {
|
|
1599
|
-
const include = git2.trackedAndUntracked();
|
|
1600
|
-
const includeSet = new Set(include);
|
|
1601
|
-
const deletions = [...new Set(git2.deletedSinceHead())].filter((path4) => !includeSet.has(path4));
|
|
1602
|
-
return { include, deletions };
|
|
1603
|
-
}
|
|
1604
|
-
|
|
1605
|
-
// src/runner/work-preservation/snapshot-tar.ts
|
|
1606
|
-
var SNAPSHOT_MANIFEST_NAME = ".conveyor-snapshot-manifest.json";
|
|
1607
|
-
var LEGACY_PG_DUMP_FILENAME = ".conveyor-pgdump.sql";
|
|
1608
|
-
var STATUS_MAX_BUFFER = 64 * 1024 * 1024;
|
|
1609
|
-
function parseStatusPorcelainZ(raw) {
|
|
1610
|
-
const includes = [];
|
|
1611
|
-
const deletions = [];
|
|
1612
|
-
const tokens = raw.split("\0");
|
|
1613
|
-
for (let i = 0; i < tokens.length; i++) {
|
|
1614
|
-
const token = tokens[i];
|
|
1615
|
-
if (!token || token.length < 4) continue;
|
|
1616
|
-
const x = token[0];
|
|
1617
|
-
const y = token[1];
|
|
1618
|
-
const filePath = token.slice(3);
|
|
1619
|
-
if (x === "R" || x === "C") {
|
|
1620
|
-
const origPath = tokens[++i];
|
|
1621
|
-
if (x === "R" && origPath) deletions.push(origPath);
|
|
1622
|
-
}
|
|
1623
|
-
if (x === "!") continue;
|
|
1624
|
-
const missingFromWorktree = y === "D" || x === "D" && y === " ";
|
|
1625
|
-
if (missingFromWorktree) deletions.push(filePath);
|
|
1626
|
-
else includes.push(filePath);
|
|
1627
|
-
}
|
|
1628
|
-
return { includes, deletions };
|
|
1629
|
-
}
|
|
1630
|
-
var execFileAsync2 = promisify2(execFile2);
|
|
1631
|
-
var GIT_TIMEOUT_MS2 = 12e4;
|
|
1632
|
-
async function realGitSurface(cwd) {
|
|
1633
|
-
const { stdout } = await execFileAsync2("git", ["status", "--porcelain=v1", "-z", "-uall"], {
|
|
1634
|
-
cwd,
|
|
1635
|
-
timeout: GIT_TIMEOUT_MS2,
|
|
1636
|
-
maxBuffer: STATUS_MAX_BUFFER
|
|
1637
|
-
});
|
|
1638
|
-
const cached = parseStatusPorcelainZ(stdout.toString());
|
|
1639
|
-
return {
|
|
1640
|
-
trackedAndUntracked: () => cached.includes,
|
|
1641
|
-
deletedSinceHead: () => cached.deletions
|
|
1642
|
-
};
|
|
1643
|
-
}
|
|
1644
|
-
async function gitHead(cwd) {
|
|
1645
|
-
try {
|
|
1646
|
-
const { stdout } = await execFileAsync2("git", ["rev-parse", "HEAD"], {
|
|
1647
|
-
cwd,
|
|
1648
|
-
timeout: GIT_TIMEOUT_MS2
|
|
1649
|
-
});
|
|
1650
|
-
return stdout.toString().trim() || null;
|
|
1651
|
-
} catch {
|
|
1652
|
-
return null;
|
|
1653
|
-
}
|
|
1654
|
-
}
|
|
1655
|
-
async function buildSnapshotTar(cwd) {
|
|
1656
|
-
const staging = await mkdtemp(path.join(tmpdir(), "conveyor-snapshot-"));
|
|
1657
|
-
const cleanup = async () => {
|
|
1658
|
-
await rm(staging, { recursive: true, force: true }).catch(() => {
|
|
1659
|
-
});
|
|
1660
|
-
};
|
|
1661
|
-
try {
|
|
1662
|
-
const plan = planSnapshotFiles(await realGitSurface(cwd));
|
|
1663
|
-
const head = await gitHead(cwd);
|
|
1664
|
-
if (!head) throw new Error("cannot snapshot a repo without a resolvable HEAD");
|
|
1665
|
-
const capturedAt = Date.now();
|
|
1666
|
-
const manifest = {
|
|
1667
|
-
head,
|
|
1668
|
-
deletions: plan.deletions,
|
|
1669
|
-
capturedAt
|
|
1670
|
-
};
|
|
1671
|
-
await writeFile(path.join(staging, SNAPSHOT_MANIFEST_NAME), JSON.stringify(manifest), "utf8");
|
|
1672
|
-
const stagedEntries = [SNAPSHOT_MANIFEST_NAME];
|
|
1673
|
-
const rawTarPath = path.join(staging, "snapshot.tar");
|
|
1674
|
-
await tar.create({ cwd: staging, file: rawTarPath, portable: true }, stagedEntries);
|
|
1675
|
-
if (plan.include.length > 0) {
|
|
1676
|
-
await tar.replace({ file: rawTarPath, cwd, portable: true }, plan.include);
|
|
1677
|
-
}
|
|
1678
|
-
const tarPath = path.join(staging, "snapshot.tar.gz");
|
|
1679
|
-
await pipeline(createReadStream(rawTarPath), createGzip(), createWriteStream(tarPath));
|
|
1680
|
-
await rm(rawTarPath, { force: true });
|
|
1681
|
-
const { size } = await stat(tarPath);
|
|
1682
|
-
return {
|
|
1683
|
-
tarPath,
|
|
1684
|
-
sizeBytes: size,
|
|
1685
|
-
fileCount: plan.include.length,
|
|
1686
|
-
deletionCount: plan.deletions.length,
|
|
1687
|
-
capturedAt,
|
|
1688
|
-
cleanup
|
|
1689
|
-
};
|
|
1690
|
-
} catch (err) {
|
|
1691
|
-
await cleanup();
|
|
1692
|
-
throw err;
|
|
1693
|
-
}
|
|
1694
|
-
}
|
|
1695
|
-
function isWithinWorkspace(cwd, rel) {
|
|
1696
|
-
if (!rel || path.isAbsolute(rel)) return false;
|
|
1697
|
-
const root = path.resolve(cwd);
|
|
1698
|
-
const abs = path.resolve(root, rel);
|
|
1699
|
-
return abs !== root && abs.startsWith(root + path.sep);
|
|
1700
|
-
}
|
|
1701
|
-
async function readSnapshotArchive(tarPath) {
|
|
1702
|
-
let manifestRaw = null;
|
|
1703
|
-
try {
|
|
1704
|
-
await tar.list({
|
|
1705
|
-
file: tarPath,
|
|
1706
|
-
onReadEntry: (entry) => {
|
|
1707
|
-
if (entry.path === SNAPSHOT_MANIFEST_NAME) {
|
|
1708
|
-
const chunks = [];
|
|
1709
|
-
entry.on("data", (chunk) => chunks.push(chunk));
|
|
1710
|
-
entry.on("end", () => {
|
|
1711
|
-
manifestRaw = Buffer.concat(chunks);
|
|
1712
|
-
});
|
|
1713
|
-
}
|
|
1714
|
-
}
|
|
1715
|
-
});
|
|
1716
|
-
} catch {
|
|
1717
|
-
return null;
|
|
1718
|
-
}
|
|
1719
|
-
if (!manifestRaw) return null;
|
|
1720
|
-
try {
|
|
1721
|
-
const parsed = JSON.parse(manifestRaw.toString("utf8"));
|
|
1722
|
-
if (typeof parsed.head !== "string" || !parsed.head) return null;
|
|
1723
|
-
return {
|
|
1724
|
-
head: parsed.head,
|
|
1725
|
-
deletions: Array.isArray(parsed.deletions) ? parsed.deletions : [],
|
|
1726
|
-
capturedAt: typeof parsed.capturedAt === "number" ? parsed.capturedAt : 0
|
|
1727
|
-
};
|
|
1728
|
-
} catch {
|
|
1729
|
-
return null;
|
|
1730
|
-
}
|
|
1731
|
-
}
|
|
1732
|
-
async function extractSnapshotTar(cwd, tarPath) {
|
|
1733
|
-
const manifest = await readSnapshotArchive(tarPath);
|
|
1734
|
-
if (!manifest) return { status: "invalid" };
|
|
1735
|
-
const currentHead = await gitHead(cwd);
|
|
1736
|
-
if (manifest.head !== currentHead) {
|
|
1737
|
-
return { status: "stale-head", snapshotHead: manifest.head, currentHead };
|
|
1738
|
-
}
|
|
1739
|
-
let filesExtracted = 0;
|
|
1740
|
-
await tar.extract({
|
|
1741
|
-
file: tarPath,
|
|
1742
|
-
cwd,
|
|
1743
|
-
filter: (entryPath) => {
|
|
1744
|
-
if (entryPath === SNAPSHOT_MANIFEST_NAME || entryPath === LEGACY_PG_DUMP_FILENAME) {
|
|
1745
|
-
return false;
|
|
1746
|
-
}
|
|
1747
|
-
filesExtracted++;
|
|
1748
|
-
return true;
|
|
1749
|
-
}
|
|
1750
|
-
});
|
|
1751
|
-
let deletionsApplied = 0;
|
|
1752
|
-
for (const rel of manifest.deletions) {
|
|
1753
|
-
if (typeof rel !== "string" || !isWithinWorkspace(cwd, rel)) continue;
|
|
1754
|
-
await rm(path.resolve(cwd, rel), { recursive: true, force: true });
|
|
1755
|
-
deletionsApplied++;
|
|
1756
|
-
}
|
|
1757
|
-
return { status: "extracted", filesExtracted, deletionsApplied };
|
|
1758
|
-
}
|
|
1759
|
-
|
|
1760
|
-
// src/runner/work-preservation/snapshot-transfer.ts
|
|
1761
|
-
import { randomUUID } from "crypto";
|
|
1762
|
-
import { createReadStream as createReadStream2, createWriteStream as createWriteStream2 } from "fs";
|
|
1763
|
-
import { rm as rm2 } from "fs/promises";
|
|
1764
|
-
import { tmpdir as tmpdir2 } from "os";
|
|
1765
|
-
import path2 from "path";
|
|
1766
1620
|
import { Readable } from "stream";
|
|
1767
|
-
import { pipeline
|
|
1621
|
+
import { pipeline } from "stream/promises";
|
|
1768
1622
|
var SNAPSHOT_HTTP_TIMEOUT_MS = 6e4;
|
|
1769
1623
|
var SNAPSHOT_CAPTURED_AT_HEADER = "x-snapshot-captured-at";
|
|
1770
1624
|
async function putSnapshotToGcs(url, tarResult) {
|
|
1771
1625
|
try {
|
|
1772
|
-
const body = Readable.toWeb(
|
|
1626
|
+
const body = Readable.toWeb(createReadStream(tarResult.tarPath));
|
|
1773
1627
|
const res = await fetch(url, {
|
|
1774
1628
|
method: "PUT",
|
|
1775
1629
|
headers: {
|
|
@@ -1787,26 +1641,51 @@ async function putSnapshotToGcs(url, tarResult) {
|
|
|
1787
1641
|
}
|
|
1788
1642
|
}
|
|
1789
1643
|
async function downloadSnapshotToTemp(url) {
|
|
1790
|
-
const tmpTar =
|
|
1644
|
+
const tmpTar = path.join(tmpdir(), `conveyor-snapshot-restore-${randomUUID()}.tar.gz`);
|
|
1791
1645
|
try {
|
|
1792
1646
|
const res = await fetch(url, {
|
|
1793
1647
|
method: "GET",
|
|
1794
1648
|
signal: AbortSignal.timeout(SNAPSHOT_HTTP_TIMEOUT_MS)
|
|
1795
1649
|
});
|
|
1796
1650
|
if (!res.ok || !res.body) return null;
|
|
1797
|
-
await
|
|
1651
|
+
await pipeline(
|
|
1798
1652
|
Readable.fromWeb(res.body),
|
|
1799
|
-
|
|
1653
|
+
createWriteStream(tmpTar)
|
|
1800
1654
|
);
|
|
1801
1655
|
return tmpTar;
|
|
1802
1656
|
} catch {
|
|
1803
|
-
await
|
|
1657
|
+
await rm(tmpTar, { force: true }).catch(() => {
|
|
1804
1658
|
});
|
|
1805
1659
|
return null;
|
|
1806
1660
|
}
|
|
1807
1661
|
}
|
|
1808
1662
|
|
|
1809
1663
|
// src/runner/work-preservation/index.ts
|
|
1664
|
+
async function captureSnapshotTar(cwd) {
|
|
1665
|
+
if (!workbenchEnabled()) return buildSnapshotTar(cwd);
|
|
1666
|
+
const staging = await mkdtemp(join(tmpdir2(), "conveyor-snapshot-remote-"));
|
|
1667
|
+
const cleanup = async () => {
|
|
1668
|
+
await rm2(staging, { recursive: true, force: true }).catch(() => {
|
|
1669
|
+
});
|
|
1670
|
+
};
|
|
1671
|
+
try {
|
|
1672
|
+
const meta = await getWorkbenchClient().buildSnapshot(cwd, join(staging, "snapshot.tar.gz"));
|
|
1673
|
+
return {
|
|
1674
|
+
tarPath: meta.tarPath,
|
|
1675
|
+
sizeBytes: meta.sizeBytes,
|
|
1676
|
+
fileCount: meta.fileCount,
|
|
1677
|
+
deletionCount: meta.deletionCount,
|
|
1678
|
+
capturedAt: meta.capturedAt,
|
|
1679
|
+
cleanup
|
|
1680
|
+
};
|
|
1681
|
+
} catch (err) {
|
|
1682
|
+
await cleanup();
|
|
1683
|
+
throw err;
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
function applySnapshotTar(cwd, tarPath) {
|
|
1687
|
+
return workbenchEnabled() ? getWorkbenchClient().extractSnapshot(cwd, tarPath) : extractSnapshotTar(cwd, tarPath);
|
|
1688
|
+
}
|
|
1810
1689
|
var periodicTimer = null;
|
|
1811
1690
|
var inFlightCapture = null;
|
|
1812
1691
|
var inFlightGcsUpload = null;
|
|
@@ -1819,7 +1698,7 @@ var EMPTY_GCS_RESULT = {
|
|
|
1819
1698
|
async function doUploadSnapshotToGcs(cwd, uploadUrl, opts) {
|
|
1820
1699
|
let tarResult;
|
|
1821
1700
|
try {
|
|
1822
|
-
tarResult = await
|
|
1701
|
+
tarResult = await captureSnapshotTar(cwd);
|
|
1823
1702
|
} catch {
|
|
1824
1703
|
return EMPTY_GCS_RESULT;
|
|
1825
1704
|
}
|
|
@@ -1902,7 +1781,7 @@ async function restoreOnBoot(bundle, cwd) {
|
|
|
1902
1781
|
const tmpTar = await downloadSnapshotToTemp(bundle.snapshotUrl);
|
|
1903
1782
|
if (tmpTar) {
|
|
1904
1783
|
try {
|
|
1905
|
-
const result = await
|
|
1784
|
+
const result = await applySnapshotTar(cwd, tmpTar);
|
|
1906
1785
|
if (result.status === "extracted") {
|
|
1907
1786
|
gcsAvailable = true;
|
|
1908
1787
|
gcsFileCount = result.filesExtracted;
|
|
@@ -1910,7 +1789,7 @@ async function restoreOnBoot(bundle, cwd) {
|
|
|
1910
1789
|
} catch {
|
|
1911
1790
|
gcsAvailable = false;
|
|
1912
1791
|
} finally {
|
|
1913
|
-
await
|
|
1792
|
+
await rm2(tmpTar, { force: true }).catch(() => {
|
|
1914
1793
|
});
|
|
1915
1794
|
}
|
|
1916
1795
|
}
|
|
@@ -2636,6 +2515,9 @@ var GetProjectSummaryRequestSchema = z4.object({
|
|
|
2636
2515
|
var GetProjectOnboardingStatusRequestSchema = z4.object({
|
|
2637
2516
|
projectId: z4.string()
|
|
2638
2517
|
});
|
|
2518
|
+
var GetProjectOnboardingStepRequestSchema = z4.object({
|
|
2519
|
+
projectId: z4.string()
|
|
2520
|
+
});
|
|
2639
2521
|
var GetProjectConnectUrlsRequestSchema = z4.object({
|
|
2640
2522
|
projectId: z4.string()
|
|
2641
2523
|
});
|
|
@@ -3402,9 +3284,8 @@ var ClaudeCodeHarness = class {
|
|
|
3402
3284
|
|
|
3403
3285
|
// src/harness/pty/session.ts
|
|
3404
3286
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
3405
|
-
import { mkdtemp as mkdtemp2, mkdir as mkdir3, rm as
|
|
3406
|
-
import {
|
|
3407
|
-
import { join as join4, dirname } from "path";
|
|
3287
|
+
import { mkdtemp as mkdtemp2, mkdir as mkdir3, rm as rm4 } from "fs/promises";
|
|
3288
|
+
import { join as join5, dirname } from "path";
|
|
3408
3289
|
|
|
3409
3290
|
// src/harness/pty/event-queue.ts
|
|
3410
3291
|
var AsyncEventQueue = class {
|
|
@@ -3685,8 +3566,8 @@ function mapTranscriptRecord(raw) {
|
|
|
3685
3566
|
// src/harness/pty/jsonl-tailer.ts
|
|
3686
3567
|
var POLL_INTERVAL_MS = 25;
|
|
3687
3568
|
var JsonlTailer = class {
|
|
3688
|
-
constructor(
|
|
3689
|
-
this.path =
|
|
3569
|
+
constructor(path3, onEvent, onRawRecord) {
|
|
3570
|
+
this.path = path3;
|
|
3690
3571
|
this.onEvent = onEvent;
|
|
3691
3572
|
this.onRawRecord = onRawRecord;
|
|
3692
3573
|
}
|
|
@@ -3800,131 +3681,11 @@ function matchUsageLimitBanner(text, now = Date.now()) {
|
|
|
3800
3681
|
};
|
|
3801
3682
|
}
|
|
3802
3683
|
|
|
3803
|
-
// src/harness/pty/pty-support.ts
|
|
3804
|
-
import { stat as stat2 } from "fs/promises";
|
|
3805
|
-
var MAX_DIAGNOSTIC_OUTPUT = 4e3;
|
|
3806
|
-
var MAX_BETWEEN_TURN_BUFFER = 500;
|
|
3807
|
-
var SUBMIT_SETTLE_MS = 300;
|
|
3808
|
-
var SUBMIT_NUDGE_INTERVAL_MS = 2e3;
|
|
3809
|
-
var SUBMIT_NUDGE_MAX_PRESSES = 5;
|
|
3810
|
-
var SUBMIT_NUDGE_SLOW_INTERVAL_MS = 5e3;
|
|
3811
|
-
var SUBMIT_NUDGE_WINDOW_MS = 9e4;
|
|
3812
|
-
var PLAN_DIALOG_FIRST_PRESS_MS = 700;
|
|
3813
|
-
var PLAN_DIALOG_INTERVAL_MS = 1500;
|
|
3814
|
-
var PLAN_DIALOG_SLOW_INTERVAL_MS = 5e3;
|
|
3815
|
-
var PLAN_DIALOG_FAST_WINDOW_MS = 1e4;
|
|
3816
|
-
var PLAN_DIALOG_WINDOW_MS = 9e4;
|
|
3817
|
-
function envMs(name, fallback) {
|
|
3818
|
-
const raw = Number(process.env[name]);
|
|
3819
|
-
return Number.isFinite(raw) && raw > 0 ? raw : fallback;
|
|
3820
|
-
}
|
|
3821
|
-
function resolveSubmitSettleMs() {
|
|
3822
|
-
return envMs("CONVEYOR_PTY_SUBMIT_SETTLE_MS", SUBMIT_SETTLE_MS);
|
|
3823
|
-
}
|
|
3824
|
-
function resolveSubmitNudgeTiming() {
|
|
3825
|
-
return {
|
|
3826
|
-
intervalMs: envMs("CONVEYOR_PTY_NUDGE_INTERVAL_MS", SUBMIT_NUDGE_INTERVAL_MS),
|
|
3827
|
-
slowIntervalMs: envMs("CONVEYOR_PTY_NUDGE_SLOW_INTERVAL_MS", SUBMIT_NUDGE_SLOW_INTERVAL_MS),
|
|
3828
|
-
maxPresses: SUBMIT_NUDGE_MAX_PRESSES,
|
|
3829
|
-
windowMs: envMs("CONVEYOR_PTY_NUDGE_WINDOW_MS", SUBMIT_NUDGE_WINDOW_MS)
|
|
3830
|
-
};
|
|
3831
|
-
}
|
|
3832
|
-
function resolvePlanDialogTiming() {
|
|
3833
|
-
return {
|
|
3834
|
-
firstPressMs: envMs("CONVEYOR_PTY_PLAN_DIALOG_FIRST_PRESS_MS", PLAN_DIALOG_FIRST_PRESS_MS),
|
|
3835
|
-
intervalMs: envMs("CONVEYOR_PTY_PLAN_DIALOG_INTERVAL_MS", PLAN_DIALOG_INTERVAL_MS),
|
|
3836
|
-
slowIntervalMs: envMs(
|
|
3837
|
-
"CONVEYOR_PTY_PLAN_DIALOG_SLOW_INTERVAL_MS",
|
|
3838
|
-
PLAN_DIALOG_SLOW_INTERVAL_MS
|
|
3839
|
-
),
|
|
3840
|
-
fastWindowMs: envMs("CONVEYOR_PTY_PLAN_DIALOG_FAST_WINDOW_MS", PLAN_DIALOG_FAST_WINDOW_MS),
|
|
3841
|
-
windowMs: envMs("CONVEYOR_PTY_PLAN_DIALOG_WINDOW_MS", PLAN_DIALOG_WINDOW_MS)
|
|
3842
|
-
};
|
|
3843
|
-
}
|
|
3844
|
-
function turnOptionsFrom(options) {
|
|
3845
|
-
return {
|
|
3846
|
-
canUseTool: options.canUseTool,
|
|
3847
|
-
promptDelivery: options.promptDelivery,
|
|
3848
|
-
planDialogAutoAccept: options.planDialogAutoAccept,
|
|
3849
|
-
abortController: options.abortController
|
|
3850
|
-
};
|
|
3851
|
-
}
|
|
3852
|
-
function isRecord2(value) {
|
|
3853
|
-
return typeof value === "object" && value !== null;
|
|
3854
|
-
}
|
|
3855
|
-
function extractSpawn(mod) {
|
|
3856
|
-
if (!isRecord2(mod)) return null;
|
|
3857
|
-
if (typeof mod.spawn === "function") return mod.spawn;
|
|
3858
|
-
const def = mod.default;
|
|
3859
|
-
if (isRecord2(def) && typeof def.spawn === "function") return def.spawn;
|
|
3860
|
-
return null;
|
|
3861
|
-
}
|
|
3862
|
-
async function loadPtySpawn() {
|
|
3863
|
-
const mod = await import("node-pty");
|
|
3864
|
-
const spawn2 = extractSpawn(mod);
|
|
3865
|
-
if (!spawn2) throw new Error("node-pty: spawn export not found");
|
|
3866
|
-
return spawn2;
|
|
3867
|
-
}
|
|
3868
|
-
function inheritedEnv(socketPath) {
|
|
3869
|
-
const env = {};
|
|
3870
|
-
for (const [key, value] of Object.entries(process.env)) {
|
|
3871
|
-
if (typeof value === "string") env[key] = value;
|
|
3872
|
-
}
|
|
3873
|
-
if (env.CLAUDE_CODE_OAUTH_TOKEN) {
|
|
3874
|
-
delete env.ANTHROPIC_API_KEY;
|
|
3875
|
-
}
|
|
3876
|
-
if (socketPath) {
|
|
3877
|
-
env.CONVEYOR_HOOK_SOCKET = socketPath;
|
|
3878
|
-
}
|
|
3879
|
-
env.MCP_TIMEOUT ??= "60000";
|
|
3880
|
-
env.MCP_TOOL_TIMEOUT ??= "180000";
|
|
3881
|
-
return env;
|
|
3882
|
-
}
|
|
3883
|
-
function buildPromptBytes(text) {
|
|
3884
|
-
return `\x1B[200~${text}\x1B[201~`;
|
|
3885
|
-
}
|
|
3886
|
-
function renderPromptContentText(content) {
|
|
3887
|
-
return content.map((block) => {
|
|
3888
|
-
const b = block;
|
|
3889
|
-
if (b?.type === "text" && typeof b.text === "string") return b.text;
|
|
3890
|
-
if (b?.type === "image") {
|
|
3891
|
-
return `[Image attachment \u2014 use list_task_files / get_attachment to view]`;
|
|
3892
|
-
}
|
|
3893
|
-
return JSON.stringify(block);
|
|
3894
|
-
}).join("\n\n");
|
|
3895
|
-
}
|
|
3896
|
-
async function transcriptSize(path4) {
|
|
3897
|
-
try {
|
|
3898
|
-
return (await stat2(path4)).size;
|
|
3899
|
-
} catch {
|
|
3900
|
-
return 0;
|
|
3901
|
-
}
|
|
3902
|
-
}
|
|
3903
|
-
function parseUserQuestions(input) {
|
|
3904
|
-
if (!Array.isArray(input.questions)) return [];
|
|
3905
|
-
const questions = [];
|
|
3906
|
-
for (const entry of input.questions) {
|
|
3907
|
-
if (!isRecord2(entry)) continue;
|
|
3908
|
-
if (typeof entry.question !== "string") continue;
|
|
3909
|
-
const options = Array.isArray(entry.options) ? entry.options.filter(isRecord2).filter((o) => typeof o.label === "string").map((o) => ({
|
|
3910
|
-
label: o.label,
|
|
3911
|
-
description: typeof o.description === "string" ? o.description : ""
|
|
3912
|
-
})) : [];
|
|
3913
|
-
questions.push({
|
|
3914
|
-
question: entry.question,
|
|
3915
|
-
header: typeof entry.header === "string" ? entry.header : "",
|
|
3916
|
-
options,
|
|
3917
|
-
...typeof entry.multiSelect === "boolean" ? { multiSelect: entry.multiSelect } : {}
|
|
3918
|
-
});
|
|
3919
|
-
}
|
|
3920
|
-
return questions;
|
|
3921
|
-
}
|
|
3922
|
-
|
|
3923
3684
|
// src/harness/pty/chat-record-mapper.ts
|
|
3924
3685
|
var TEXT_MAX = 16e3;
|
|
3925
3686
|
var TOOL_INPUT_MAX = 1900;
|
|
3926
3687
|
var TOOL_OUTPUT_MAX = 1900;
|
|
3927
|
-
function
|
|
3688
|
+
function isRecord2(value) {
|
|
3928
3689
|
return typeof value === "object" && value !== null;
|
|
3929
3690
|
}
|
|
3930
3691
|
function isUnknownArray2(value) {
|
|
@@ -3955,7 +3716,7 @@ function compactQuestionsJson(questions) {
|
|
|
3955
3716
|
return bare.slice(0, TOOL_INPUT_MAX);
|
|
3956
3717
|
}
|
|
3957
3718
|
function compactToolInput(name, input) {
|
|
3958
|
-
if (name === "AskUserQuestion" &&
|
|
3719
|
+
if (name === "AskUserQuestion" && isRecord2(input)) {
|
|
3959
3720
|
const questions = parseUserQuestions(input);
|
|
3960
3721
|
if (questions.length > 0) return compactQuestionsJson(questions);
|
|
3961
3722
|
}
|
|
@@ -3980,11 +3741,11 @@ function mapSystem2(record) {
|
|
|
3980
3741
|
}
|
|
3981
3742
|
function mapAssistant2(record) {
|
|
3982
3743
|
const message = record.message;
|
|
3983
|
-
if (!
|
|
3744
|
+
if (!isRecord2(message)) return [];
|
|
3984
3745
|
const content = isUnknownArray2(message.content) ? message.content : [];
|
|
3985
3746
|
const events = [];
|
|
3986
3747
|
for (const raw of content) {
|
|
3987
|
-
if (!
|
|
3748
|
+
if (!isRecord2(raw)) continue;
|
|
3988
3749
|
if (raw.type === "text") {
|
|
3989
3750
|
const text = stringField2(raw, "text");
|
|
3990
3751
|
if (text && text.length > 0) {
|
|
@@ -4011,14 +3772,14 @@ function toolResultText(block) {
|
|
|
4011
3772
|
const content = block.content;
|
|
4012
3773
|
if (typeof content === "string") return content;
|
|
4013
3774
|
if (isUnknownArray2(content)) {
|
|
4014
|
-
return content.filter((b) =>
|
|
3775
|
+
return content.filter((b) => isRecord2(b) && b.type === "text").map((b) => typeof b.text === "string" ? b.text : "").filter((t) => t.length > 0).join("\n");
|
|
4015
3776
|
}
|
|
4016
3777
|
return "";
|
|
4017
3778
|
}
|
|
4018
3779
|
function mapToolResults(content) {
|
|
4019
3780
|
const events = [];
|
|
4020
3781
|
for (const raw of content) {
|
|
4021
|
-
if (!
|
|
3782
|
+
if (!isRecord2(raw) || raw.type !== "tool_result") continue;
|
|
4022
3783
|
const event = {
|
|
4023
3784
|
kind: "tool_result",
|
|
4024
3785
|
output: truncate(toolResultText(raw), TOOL_OUTPUT_MAX),
|
|
@@ -4032,15 +3793,15 @@ function mapToolResults(content) {
|
|
|
4032
3793
|
}
|
|
4033
3794
|
function mapUser(record) {
|
|
4034
3795
|
const message = record.message;
|
|
4035
|
-
if (!
|
|
3796
|
+
if (!isRecord2(message)) return [];
|
|
4036
3797
|
const content = message.content;
|
|
4037
3798
|
let text;
|
|
4038
3799
|
if (typeof content === "string") {
|
|
4039
3800
|
text = content;
|
|
4040
3801
|
} else if (isUnknownArray2(content)) {
|
|
4041
|
-
const hasToolResult = content.some((b) =>
|
|
3802
|
+
const hasToolResult = content.some((b) => isRecord2(b) && b.type === "tool_result");
|
|
4042
3803
|
if (hasToolResult) return mapToolResults(content);
|
|
4043
|
-
text = content.filter((b) =>
|
|
3804
|
+
text = content.filter((b) => isRecord2(b) && b.type === "text").map((b) => typeof b.text === "string" ? b.text : "").filter((t) => t.length > 0).join("\n");
|
|
4044
3805
|
} else {
|
|
4045
3806
|
return [];
|
|
4046
3807
|
}
|
|
@@ -4049,7 +3810,7 @@ function mapUser(record) {
|
|
|
4049
3810
|
return [{ kind: "user_text", text: truncate(trimmed, TEXT_MAX) }];
|
|
4050
3811
|
}
|
|
4051
3812
|
function mapChatRecords(raw) {
|
|
4052
|
-
if (!
|
|
3813
|
+
if (!isRecord2(raw)) return [];
|
|
4053
3814
|
if (raw.isSidechain === true || raw.isMeta === true) return [];
|
|
4054
3815
|
switch (raw.type) {
|
|
4055
3816
|
case "system":
|
|
@@ -4066,17 +3827,17 @@ function mapChatRecords(raw) {
|
|
|
4066
3827
|
}
|
|
4067
3828
|
|
|
4068
3829
|
// src/harness/pty/settings.ts
|
|
4069
|
-
import { mkdir, writeFile
|
|
3830
|
+
import { mkdir, writeFile, chmod } from "fs/promises";
|
|
4070
3831
|
import { homedir } from "os";
|
|
4071
|
-
import { join } from "path";
|
|
3832
|
+
import { join as join2 } from "path";
|
|
4072
3833
|
function claudeConfigHome() {
|
|
4073
|
-
return process.env.CLAUDE_CONFIG_DIR ??
|
|
3834
|
+
return process.env.CLAUDE_CONFIG_DIR ?? join2(homedir(), ".claude");
|
|
4074
3835
|
}
|
|
4075
3836
|
function projectSlug(cwd) {
|
|
4076
3837
|
return cwd.replace(/\//g, "-");
|
|
4077
3838
|
}
|
|
4078
3839
|
function sessionTranscriptPath(cwd, sessionId) {
|
|
4079
|
-
return
|
|
3840
|
+
return join2(claudeConfigHome(), "projects", projectSlug(cwd), `${sessionId}.jsonl`);
|
|
4080
3841
|
}
|
|
4081
3842
|
var ALLOW_RULES = [
|
|
4082
3843
|
"Bash",
|
|
@@ -4244,10 +4005,10 @@ function preToolUse(payload) {
|
|
|
4244
4005
|
}
|
|
4245
4006
|
`;
|
|
4246
4007
|
async function writeHookSettings(dir) {
|
|
4247
|
-
const helperPath =
|
|
4248
|
-
const settingsPath =
|
|
4008
|
+
const helperPath = join2(dir, "hook-helper.cjs");
|
|
4009
|
+
const settingsPath = join2(dir, "settings.json");
|
|
4249
4010
|
await mkdir(dir, { recursive: true });
|
|
4250
|
-
await
|
|
4011
|
+
await writeFile(helperPath, HOOK_HELPER_SOURCE, "utf8");
|
|
4251
4012
|
await chmod(helperPath, 493);
|
|
4252
4013
|
const settings = {
|
|
4253
4014
|
// Pre-accept Claude Code's "Bypass Permissions mode" disclaimer. Build-capable
|
|
@@ -4303,7 +4064,7 @@ async function writeHookSettings(dir) {
|
|
|
4303
4064
|
]
|
|
4304
4065
|
}
|
|
4305
4066
|
};
|
|
4306
|
-
await
|
|
4067
|
+
await writeFile(settingsPath, JSON.stringify(settings, null, 2), "utf8");
|
|
4307
4068
|
return { settingsPath, helperPath };
|
|
4308
4069
|
}
|
|
4309
4070
|
|
|
@@ -4362,8 +4123,8 @@ var PtyOutputCoalescer = class {
|
|
|
4362
4123
|
// src/harness/pty/tool-server.ts
|
|
4363
4124
|
import { createServer as createServer2 } from "http";
|
|
4364
4125
|
import { z as z6 } from "zod";
|
|
4365
|
-
import { writeFile as
|
|
4366
|
-
import { join as
|
|
4126
|
+
import { writeFile as writeFile2 } from "fs/promises";
|
|
4127
|
+
import { join as join3 } from "path";
|
|
4367
4128
|
import { randomBytes } from "crypto";
|
|
4368
4129
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4369
4130
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
@@ -4554,8 +4315,8 @@ async function startToolServers(mcpServers, tempDir) {
|
|
|
4554
4315
|
config[name] = { type: "http", url, headers: { Authorization: `Bearer ${token}` } };
|
|
4555
4316
|
}
|
|
4556
4317
|
if (Object.keys(config).length === 0) return { servers, mcpConfigPath: null };
|
|
4557
|
-
const mcpConfigPath =
|
|
4558
|
-
await
|
|
4318
|
+
const mcpConfigPath = join3(tempDir, "mcp-config.json");
|
|
4319
|
+
await writeFile2(mcpConfigPath, JSON.stringify({ mcpServers: config }, null, 2), "utf8");
|
|
4559
4320
|
return { servers, mcpConfigPath };
|
|
4560
4321
|
}
|
|
4561
4322
|
|
|
@@ -4630,13 +4391,13 @@ ${tail}`);
|
|
|
4630
4391
|
}
|
|
4631
4392
|
|
|
4632
4393
|
// src/harness/pty/credentials.ts
|
|
4633
|
-
import { chmod as chmod2, mkdir as mkdir2, readFile, rm as
|
|
4394
|
+
import { chmod as chmod2, mkdir as mkdir2, readFile, rm as rm3, writeFile as writeFile3 } from "fs/promises";
|
|
4634
4395
|
import { homedir as homedir2 } from "os";
|
|
4635
|
-
import { join as
|
|
4396
|
+
import { join as join4 } from "path";
|
|
4636
4397
|
var SYNTH_TOKEN_TTL_MS = 365 * 24 * 60 * 60 * 1e3;
|
|
4637
4398
|
var REFRESH_SKEW_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
4638
4399
|
function claudeCredentialsPath() {
|
|
4639
|
-
return
|
|
4400
|
+
return join4(claudeConfigHome(), ".credentials.json");
|
|
4640
4401
|
}
|
|
4641
4402
|
function isConveyorCloudEnv(env = process.env) {
|
|
4642
4403
|
return Boolean(env.CLAUDESPACE_NAME || env.CODESPACE_NAME || env.CODESPACES);
|
|
@@ -4681,9 +4442,9 @@ function planCredentialsWrite(input) {
|
|
|
4681
4442
|
if (fresh) return { action: "skip", reason: "current" };
|
|
4682
4443
|
return { action: "write", contents };
|
|
4683
4444
|
}
|
|
4684
|
-
async function readRaw(
|
|
4445
|
+
async function readRaw(path3) {
|
|
4685
4446
|
try {
|
|
4686
|
-
return await readFile(
|
|
4447
|
+
return await readFile(path3, "utf8");
|
|
4687
4448
|
} catch {
|
|
4688
4449
|
return null;
|
|
4689
4450
|
}
|
|
@@ -4709,10 +4470,10 @@ async function writeWithReadBackRetry(io2, contents, delaysMs = READ_BACK_DELAYS
|
|
|
4709
4470
|
await sleep2(delaysMs[attempt]);
|
|
4710
4471
|
}
|
|
4711
4472
|
}
|
|
4712
|
-
function fsWriteIo(
|
|
4473
|
+
function fsWriteIo(path3, mode) {
|
|
4713
4474
|
return {
|
|
4714
|
-
write: (contents) =>
|
|
4715
|
-
read: () => readRaw(
|
|
4475
|
+
write: (contents) => writeFile3(path3, contents, mode === void 0 ? "utf8" : { encoding: "utf8", mode }),
|
|
4476
|
+
read: () => readRaw(path3)
|
|
4716
4477
|
};
|
|
4717
4478
|
}
|
|
4718
4479
|
async function ensureClaudeCredentials(env = process.env) {
|
|
@@ -4722,23 +4483,23 @@ async function ensureClaudeCredentials(env = process.env) {
|
|
|
4722
4483
|
await sanitizeApprovedApiKeys(token);
|
|
4723
4484
|
}
|
|
4724
4485
|
try {
|
|
4725
|
-
const
|
|
4486
|
+
const path3 = claudeCredentialsPath();
|
|
4726
4487
|
const plan = planCredentialsWrite({
|
|
4727
4488
|
isCloud,
|
|
4728
4489
|
token,
|
|
4729
|
-
existingRaw: await readRaw(
|
|
4490
|
+
existingRaw: await readRaw(path3),
|
|
4730
4491
|
now: Date.now()
|
|
4731
4492
|
});
|
|
4732
4493
|
if (plan.action === "skip") return;
|
|
4733
4494
|
await mkdir2(claudeConfigHome(), { recursive: true });
|
|
4734
|
-
const verified = await writeWithReadBackRetry(fsWriteIo(
|
|
4495
|
+
const verified = await writeWithReadBackRetry(fsWriteIo(path3, 384), plan.contents);
|
|
4735
4496
|
if (!verified) {
|
|
4736
4497
|
process.stderr.write(
|
|
4737
|
-
`[conveyor-agent] claude credentials read-back still stale after retries at ${
|
|
4498
|
+
`[conveyor-agent] claude credentials read-back still stale after retries at ${path3} \u2014 TUI may land on the login picker
|
|
4738
4499
|
`
|
|
4739
4500
|
);
|
|
4740
4501
|
}
|
|
4741
|
-
await chmod2(
|
|
4502
|
+
await chmod2(path3, 384).catch(() => {
|
|
4742
4503
|
});
|
|
4743
4504
|
} catch (err) {
|
|
4744
4505
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -4767,12 +4528,12 @@ function planApprovedApiKeyCleanup(existingRaw, oauthToken) {
|
|
|
4767
4528
|
}
|
|
4768
4529
|
async function sanitizeApprovedApiKeys(oauthToken) {
|
|
4769
4530
|
try {
|
|
4770
|
-
const
|
|
4771
|
-
const cleaned = planApprovedApiKeyCleanup(await readRaw(
|
|
4531
|
+
const path3 = claudeJsonPath();
|
|
4532
|
+
const cleaned = planApprovedApiKeyCleanup(await readRaw(path3), oauthToken);
|
|
4772
4533
|
if (cleaned === null) return;
|
|
4773
|
-
const verified = await writeWithReadBackRetry(fsWriteIo(
|
|
4534
|
+
const verified = await writeWithReadBackRetry(fsWriteIo(path3), cleaned);
|
|
4774
4535
|
process.stderr.write(
|
|
4775
|
-
verified ? "[conveyor-agent] removed poisoned customApiKeyResponses.approved entry from .claude.json\n" : `[conveyor-agent] approved-key sanitize read-back still stale after retries at ${
|
|
4536
|
+
verified ? "[conveyor-agent] removed poisoned customApiKeyResponses.approved entry from .claude.json\n" : `[conveyor-agent] approved-key sanitize read-back still stale after retries at ${path3} \u2014 CLI may still see the poisoned entry
|
|
4776
4537
|
`
|
|
4777
4538
|
);
|
|
4778
4539
|
} catch (err) {
|
|
@@ -4783,7 +4544,7 @@ async function sanitizeApprovedApiKeys(oauthToken) {
|
|
|
4783
4544
|
}
|
|
4784
4545
|
function claudeJsonPath() {
|
|
4785
4546
|
const configDir = process.env.CLAUDE_CONFIG_DIR;
|
|
4786
|
-
return configDir ?
|
|
4547
|
+
return configDir ? join4(configDir, ".claude.json") : join4(homedir2(), ".claude.json");
|
|
4787
4548
|
}
|
|
4788
4549
|
function asRecord(value) {
|
|
4789
4550
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
|
|
@@ -4876,7 +4637,7 @@ function planClaudeJsonSeed(existingRaw, trustCwd, oauthIdentity) {
|
|
|
4876
4637
|
return changed ? JSON.stringify(config) : null;
|
|
4877
4638
|
}
|
|
4878
4639
|
function conveyorOauthMarkerPath() {
|
|
4879
|
-
return
|
|
4640
|
+
return join4(claudeConfigHome(), "conveyor-oauth-account.json");
|
|
4880
4641
|
}
|
|
4881
4642
|
function parseOauthIdentity(raw) {
|
|
4882
4643
|
if (!raw || raw.trim() === "") return null;
|
|
@@ -4909,8 +4670,8 @@ async function persistOauthIdentityMarker(configIdentity, markerIdentity) {
|
|
|
4909
4670
|
async function ensureClaudeOnboarding(env = process.env, trustCwd) {
|
|
4910
4671
|
try {
|
|
4911
4672
|
if (!isConveyorCloudEnv(env)) return;
|
|
4912
|
-
const
|
|
4913
|
-
const existingRaw = await readRaw(
|
|
4673
|
+
const path3 = claudeJsonPath();
|
|
4674
|
+
const existingRaw = await readRaw(path3);
|
|
4914
4675
|
const markerIdentity = parseOauthIdentity(await readRaw(conveyorOauthMarkerPath()));
|
|
4915
4676
|
await persistOauthIdentityMarker(
|
|
4916
4677
|
extractOauthIdentity(parseClaudeJson(existingRaw)),
|
|
@@ -4918,16 +4679,16 @@ async function ensureClaudeOnboarding(env = process.env, trustCwd) {
|
|
|
4918
4679
|
);
|
|
4919
4680
|
const contents = planClaudeJsonSeed(existingRaw, trustCwd, markerIdentity);
|
|
4920
4681
|
if (contents === null) return;
|
|
4921
|
-
const verified = await writeWithReadBackRetry(fsWriteIo(
|
|
4682
|
+
const verified = await writeWithReadBackRetry(fsWriteIo(path3), contents);
|
|
4922
4683
|
if (verified) {
|
|
4923
4684
|
process.stderr.write(
|
|
4924
4685
|
`[conveyor-agent] claude onboarding seeded${trustCwd ? ` (trust: ${trustCwd})` : ""}
|
|
4925
4686
|
`
|
|
4926
4687
|
);
|
|
4927
4688
|
} else {
|
|
4928
|
-
const verify = await readRaw(
|
|
4689
|
+
const verify = await readRaw(path3);
|
|
4929
4690
|
process.stderr.write(
|
|
4930
|
-
`[conveyor-agent] claude onboarding seed read-back MISMATCH at ${
|
|
4691
|
+
`[conveyor-agent] claude onboarding seed read-back MISMATCH at ${path3} after retries: wrote ${contents.length}B, read ${verify?.length ?? 0}B \u2014 CLI may see stale config and park at a startup dialog
|
|
4931
4692
|
`
|
|
4932
4693
|
);
|
|
4933
4694
|
}
|
|
@@ -4940,12 +4701,12 @@ async function ensureClaudeOnboarding(env = process.env, trustCwd) {
|
|
|
4940
4701
|
async function removeConveyorCredentials(env = process.env) {
|
|
4941
4702
|
try {
|
|
4942
4703
|
if (!isConveyorCloudEnv(env)) return;
|
|
4943
|
-
const
|
|
4944
|
-
const existing = parseClaudeAiOauth(await readRaw(
|
|
4704
|
+
const path3 = claudeCredentialsPath();
|
|
4705
|
+
const existing = parseClaudeAiOauth(await readRaw(path3));
|
|
4945
4706
|
if (existing && typeof existing.refreshToken === "string" && existing.refreshToken.length > 0) {
|
|
4946
4707
|
return;
|
|
4947
4708
|
}
|
|
4948
|
-
await
|
|
4709
|
+
await rm3(path3, { force: true });
|
|
4949
4710
|
} catch (err) {
|
|
4950
4711
|
const message = err instanceof Error ? err.message : String(err);
|
|
4951
4712
|
process.stderr.write(`[conveyor-agent] claude credentials removal failed: ${message}
|
|
@@ -5253,7 +5014,7 @@ var PtySession = class {
|
|
|
5253
5014
|
const { settingsPath, socketPath } = await this.startStructuredEventSources(sessionId);
|
|
5254
5015
|
await this.spawn(settingsPath, socketPath);
|
|
5255
5016
|
} else {
|
|
5256
|
-
this.tempDir = await mkdtemp2(
|
|
5017
|
+
this.tempDir = await mkdtemp2(join5(sessionTempBase(), "conveyor-pty-"));
|
|
5257
5018
|
await this.spawn();
|
|
5258
5019
|
this.pushEvent({
|
|
5259
5020
|
type: "system",
|
|
@@ -5290,8 +5051,8 @@ var PtySession = class {
|
|
|
5290
5051
|
* paths spawn() must wire into the child's argv/env.
|
|
5291
5052
|
*/
|
|
5292
5053
|
async startStructuredEventSources(sessionId) {
|
|
5293
|
-
this.tempDir = await mkdtemp2(
|
|
5294
|
-
const socketPath =
|
|
5054
|
+
this.tempDir = await mkdtemp2(join5(sessionTempBase(), "conveyor-pty-"));
|
|
5055
|
+
const socketPath = join5(this.tempDir, "hook.sock");
|
|
5295
5056
|
this.socket = new HookSocketServer(
|
|
5296
5057
|
socketPath,
|
|
5297
5058
|
(progress) => this.handleProgress(progress),
|
|
@@ -5435,7 +5196,7 @@ var PtySession = class {
|
|
|
5435
5196
|
this.activeQueue?.close();
|
|
5436
5197
|
this.activeQueue = null;
|
|
5437
5198
|
if (this.tempDir) {
|
|
5438
|
-
await
|
|
5199
|
+
await rm4(this.tempDir, { recursive: true, force: true });
|
|
5439
5200
|
this.tempDir = "";
|
|
5440
5201
|
}
|
|
5441
5202
|
}
|
|
@@ -5464,8 +5225,8 @@ var PtySession = class {
|
|
|
5464
5225
|
// server doesn't load).
|
|
5465
5226
|
...this.mcpConfigPath ? { mcpConfigPath: this.mcpConfigPath } : {}
|
|
5466
5227
|
});
|
|
5467
|
-
const
|
|
5468
|
-
const pty =
|
|
5228
|
+
const spawn = await resolvePtySpawn();
|
|
5229
|
+
const pty = spawn(spec.file, spec.args, {
|
|
5469
5230
|
name: "xterm-color",
|
|
5470
5231
|
cols: this.cols,
|
|
5471
5232
|
rows: this.rows,
|
|
@@ -5711,7 +5472,7 @@ var PtySession = class {
|
|
|
5711
5472
|
// src/harness/pty/config-home-health.ts
|
|
5712
5473
|
import { mkdir as mkdir4 } from "fs/promises";
|
|
5713
5474
|
import { homedir as homedir3 } from "os";
|
|
5714
|
-
import { join as
|
|
5475
|
+
import { join as join6 } from "path";
|
|
5715
5476
|
var MOUNT_DISCONNECT_CODES = /* @__PURE__ */ new Set(["ENOTCONN", "EIO", "ESTALE", "ENXIO"]);
|
|
5716
5477
|
var MOUNT_DISCONNECT_MESSAGES = [
|
|
5717
5478
|
"socket is not connected",
|
|
@@ -5727,12 +5488,12 @@ function isMountDisconnectError(err) {
|
|
|
5727
5488
|
return MOUNT_DISCONNECT_MESSAGES.some((needle) => lower.includes(needle));
|
|
5728
5489
|
}
|
|
5729
5490
|
function podLocalConfigHome() {
|
|
5730
|
-
return
|
|
5491
|
+
return join6(homedir3(), ".claude-local");
|
|
5731
5492
|
}
|
|
5732
5493
|
async function ensureUsableClaudeConfigHome(cwd, log) {
|
|
5733
5494
|
const configHome = claudeConfigHome();
|
|
5734
5495
|
try {
|
|
5735
|
-
await mkdir4(
|
|
5496
|
+
await mkdir4(join6(configHome, "projects", projectSlug(cwd)), { recursive: true });
|
|
5736
5497
|
return { configHome, fellBack: false };
|
|
5737
5498
|
} catch (err) {
|
|
5738
5499
|
if (!isMountDisconnectError(err)) throw err;
|
|
@@ -5746,7 +5507,7 @@ async function ensureUsableClaudeConfigHome(cwd, log) {
|
|
|
5746
5507
|
}
|
|
5747
5508
|
);
|
|
5748
5509
|
process.env.CLAUDE_CONFIG_DIR = fallback;
|
|
5749
|
-
await mkdir4(
|
|
5510
|
+
await mkdir4(join6(fallback, "projects", projectSlug(cwd)), { recursive: true });
|
|
5750
5511
|
return { configHome: fallback, fellBack: true };
|
|
5751
5512
|
}
|
|
5752
5513
|
}
|
|
@@ -6192,8 +5953,38 @@ function formatIncidents(incidents) {
|
|
|
6192
5953
|
return parts;
|
|
6193
5954
|
}
|
|
6194
5955
|
|
|
5956
|
+
// src/workbench/fs.ts
|
|
5957
|
+
import { readFile as localReadFile, readdir as localReaddir, stat as localStat } from "fs/promises";
|
|
5958
|
+
async function readWorkspaceFile(path3) {
|
|
5959
|
+
if (workbenchEnabled()) {
|
|
5960
|
+
return (await getWorkbenchClient().readFile(path3)).toString("utf8");
|
|
5961
|
+
}
|
|
5962
|
+
return localReadFile(path3, "utf-8");
|
|
5963
|
+
}
|
|
5964
|
+
function readWorkspaceDir(path3) {
|
|
5965
|
+
if (workbenchEnabled()) return getWorkbenchClient().readdir(path3);
|
|
5966
|
+
return localReaddir(path3);
|
|
5967
|
+
}
|
|
5968
|
+
async function statWorkspacePath(path3) {
|
|
5969
|
+
if (workbenchEnabled()) return getWorkbenchClient().stat(path3);
|
|
5970
|
+
try {
|
|
5971
|
+
const s = await localStat(path3);
|
|
5972
|
+
return {
|
|
5973
|
+
exists: true,
|
|
5974
|
+
isFile: s.isFile(),
|
|
5975
|
+
isDirectory: s.isDirectory(),
|
|
5976
|
+
size: s.size,
|
|
5977
|
+
mtimeMs: s.mtimeMs
|
|
5978
|
+
};
|
|
5979
|
+
} catch {
|
|
5980
|
+
return { exists: false, isFile: false, isDirectory: false, size: 0, mtimeMs: 0 };
|
|
5981
|
+
}
|
|
5982
|
+
}
|
|
5983
|
+
async function workspacePathExists(path3) {
|
|
5984
|
+
return (await statWorkspacePath(path3)).exists;
|
|
5985
|
+
}
|
|
5986
|
+
|
|
6195
5987
|
// src/execution/tag-context-resolver.ts
|
|
6196
|
-
import { readFile as readFile2, readdir, stat as stat3 } from "fs/promises";
|
|
6197
5988
|
var TYPE_PRIORITY = { rule: 0, file: 1, folder: 2, doc: 3 };
|
|
6198
5989
|
var SUMMARY_SCAN_CHARS = 4e3;
|
|
6199
5990
|
var SUMMARY_MAX_CHARS = 160;
|
|
@@ -6265,18 +6056,14 @@ function truncateSummary(text) {
|
|
|
6265
6056
|
async function readFileSummary(filePath) {
|
|
6266
6057
|
try {
|
|
6267
6058
|
if (isBinaryPath(filePath)) return null;
|
|
6268
|
-
|
|
6269
|
-
|
|
6270
|
-
|
|
6271
|
-
mtimeMs = st.mtimeMs;
|
|
6272
|
-
} catch {
|
|
6273
|
-
return null;
|
|
6274
|
-
}
|
|
6059
|
+
const st = await statWorkspacePath(filePath);
|
|
6060
|
+
if (!st.exists) return null;
|
|
6061
|
+
const mtimeMs = st.mtimeMs;
|
|
6275
6062
|
const cached = fileSummaryCache.get(filePath);
|
|
6276
6063
|
if (cached && cached.mtimeMs === mtimeMs) {
|
|
6277
6064
|
return cached.summary;
|
|
6278
6065
|
}
|
|
6279
|
-
const raw = await
|
|
6066
|
+
const raw = await readWorkspaceFile(filePath);
|
|
6280
6067
|
fileReadCount++;
|
|
6281
6068
|
const summary = deriveSummary(raw.slice(0, SUMMARY_SCAN_CHARS));
|
|
6282
6069
|
fileSummaryCache.set(filePath, { mtimeMs, summary });
|
|
@@ -6287,18 +6074,14 @@ async function readFileSummary(filePath) {
|
|
|
6287
6074
|
}
|
|
6288
6075
|
async function readFolderListing(folderPath) {
|
|
6289
6076
|
try {
|
|
6290
|
-
|
|
6291
|
-
|
|
6292
|
-
|
|
6293
|
-
mtimeMs = st.mtimeMs;
|
|
6294
|
-
} catch {
|
|
6295
|
-
return null;
|
|
6296
|
-
}
|
|
6077
|
+
const st = await statWorkspacePath(folderPath);
|
|
6078
|
+
if (!st.exists) return null;
|
|
6079
|
+
const mtimeMs = st.mtimeMs;
|
|
6297
6080
|
const cached = folderListingCache.get(folderPath);
|
|
6298
6081
|
if (cached && cached.mtimeMs === mtimeMs) {
|
|
6299
6082
|
return cached.listing;
|
|
6300
6083
|
}
|
|
6301
|
-
const entries = await
|
|
6084
|
+
const entries = await readWorkspaceDir(folderPath);
|
|
6302
6085
|
folderReadCount++;
|
|
6303
6086
|
const listing = `Files: ${entries.join(", ")}`;
|
|
6304
6087
|
folderListingCache.set(folderPath, { mtimeMs, listing });
|
|
@@ -7958,8 +7741,8 @@ function buildMutationTools(connection, config) {
|
|
|
7958
7741
|
}
|
|
7959
7742
|
|
|
7960
7743
|
// src/tools/attachment-tools.ts
|
|
7961
|
-
import { readFile as
|
|
7962
|
-
import { basename, extname, isAbsolute, join as
|
|
7744
|
+
import { readFile as readFile2, stat } from "fs/promises";
|
|
7745
|
+
import { basename, extname, isAbsolute, join as join7 } from "path";
|
|
7963
7746
|
import { z as z10 } from "zod";
|
|
7964
7747
|
var IMAGE_MIME_BY_EXT = {
|
|
7965
7748
|
".png": "image/png",
|
|
@@ -7976,16 +7759,16 @@ function buildUploadAttachmentTool(connection, config) {
|
|
|
7976
7759
|
path: z10.string().describe("Path to the image file \u2014 absolute, or relative to the workspace root"),
|
|
7977
7760
|
title: z10.string().optional().describe("Short caption posted with the image (defaults to the file name)")
|
|
7978
7761
|
},
|
|
7979
|
-
async ({ path:
|
|
7762
|
+
async ({ path: path3, title }) => {
|
|
7980
7763
|
try {
|
|
7981
|
-
const filePath = isAbsolute(
|
|
7764
|
+
const filePath = isAbsolute(path3) ? path3 : join7(config.workspaceDir, path3);
|
|
7982
7765
|
const mimeType = IMAGE_MIME_BY_EXT[extname(filePath).toLowerCase()];
|
|
7983
7766
|
if (!mimeType) {
|
|
7984
7767
|
return textResult(
|
|
7985
7768
|
`Unsupported file type "${extname(filePath) || "(none)"}". Supported: ${Object.keys(IMAGE_MIME_BY_EXT).join(", ")}`
|
|
7986
7769
|
);
|
|
7987
7770
|
}
|
|
7988
|
-
const info = await
|
|
7771
|
+
const info = await stat(filePath).catch(() => null);
|
|
7989
7772
|
if (!info?.isFile()) {
|
|
7990
7773
|
return textResult(`File not found: ${filePath}`);
|
|
7991
7774
|
}
|
|
@@ -8001,7 +7784,7 @@ function buildUploadAttachmentTool(connection, config) {
|
|
|
8001
7784
|
mimeType,
|
|
8002
7785
|
fileSize: info.size
|
|
8003
7786
|
});
|
|
8004
|
-
const body = await
|
|
7787
|
+
const body = await readFile2(filePath);
|
|
8005
7788
|
const res = await fetch(uploadUrl, {
|
|
8006
7789
|
method: "PUT",
|
|
8007
7790
|
headers: { "Content-Type": mimeType },
|
|
@@ -8740,7 +8523,7 @@ function createConveyorMcpServer(harness, connection, config, context, agentMode
|
|
|
8740
8523
|
|
|
8741
8524
|
// src/harness/pty/adapters/types.ts
|
|
8742
8525
|
import { accessSync, constants, statSync } from "fs";
|
|
8743
|
-
import { join as
|
|
8526
|
+
import { join as join8 } from "path";
|
|
8744
8527
|
var TuiUnavailableError = class extends Error {
|
|
8745
8528
|
constructor(tui, message) {
|
|
8746
8529
|
super(message);
|
|
@@ -8749,10 +8532,10 @@ var TuiUnavailableError = class extends Error {
|
|
|
8749
8532
|
}
|
|
8750
8533
|
tui;
|
|
8751
8534
|
};
|
|
8752
|
-
function isExecutable(
|
|
8535
|
+
function isExecutable(path3) {
|
|
8753
8536
|
try {
|
|
8754
|
-
if (!statSync(
|
|
8755
|
-
accessSync(
|
|
8537
|
+
if (!statSync(path3).isFile()) return false;
|
|
8538
|
+
accessSync(path3, constants.X_OK);
|
|
8756
8539
|
return true;
|
|
8757
8540
|
} catch {
|
|
8758
8541
|
return false;
|
|
@@ -8764,7 +8547,7 @@ function findOnPath(binary, env = process.env) {
|
|
|
8764
8547
|
}
|
|
8765
8548
|
for (const dir of (env.PATH ?? "").split(":")) {
|
|
8766
8549
|
if (!dir) continue;
|
|
8767
|
-
const candidate =
|
|
8550
|
+
const candidate = join8(dir, binary);
|
|
8768
8551
|
if (isExecutable(candidate)) return candidate;
|
|
8769
8552
|
}
|
|
8770
8553
|
return null;
|
|
@@ -9096,14 +8879,14 @@ function flushPendingToolCalls(host, turnToolCalls) {
|
|
|
9096
8879
|
}
|
|
9097
8880
|
const outputsByTool = /* @__PURE__ */ new Map();
|
|
9098
8881
|
for (const entry of host.pendingToolOutputs) {
|
|
9099
|
-
const
|
|
9100
|
-
|
|
9101
|
-
outputsByTool.set(entry.tool,
|
|
8882
|
+
const list = outputsByTool.get(entry.tool) ?? [];
|
|
8883
|
+
list.push(entry.output);
|
|
8884
|
+
outputsByTool.set(entry.tool, list);
|
|
9102
8885
|
}
|
|
9103
8886
|
for (const call of turnToolCalls) {
|
|
9104
|
-
const
|
|
9105
|
-
if (
|
|
9106
|
-
call.output =
|
|
8887
|
+
const list = outputsByTool.get(call.tool);
|
|
8888
|
+
if (list && list.length > 0) {
|
|
8889
|
+
call.output = list.shift();
|
|
9107
8890
|
}
|
|
9108
8891
|
}
|
|
9109
8892
|
host.connection.sendEvent({ type: "turn_end", toolCalls: [...turnToolCalls] });
|
|
@@ -9628,10 +9411,10 @@ function resolveSessionStart(lineageKey, cwd) {
|
|
|
9628
9411
|
}
|
|
9629
9412
|
return { sessionId: sessionUuid };
|
|
9630
9413
|
}
|
|
9631
|
-
function repairTornSessionFile(
|
|
9414
|
+
function repairTornSessionFile(path3) {
|
|
9632
9415
|
try {
|
|
9633
|
-
if (!existsSync2(
|
|
9634
|
-
const content = readFileSync(
|
|
9416
|
+
if (!existsSync2(path3)) return false;
|
|
9417
|
+
const content = readFileSync(path3, "utf8");
|
|
9635
9418
|
if (content.length === 0) return false;
|
|
9636
9419
|
let keepEnd = content.length;
|
|
9637
9420
|
if (!content.endsWith("\n")) {
|
|
@@ -9650,9 +9433,9 @@ function repairTornSessionFile(path4) {
|
|
|
9650
9433
|
keepEnd = prevNewline + 1;
|
|
9651
9434
|
}
|
|
9652
9435
|
if (keepEnd === content.length) return false;
|
|
9653
|
-
truncateSync(
|
|
9436
|
+
truncateSync(path3, Buffer.byteLength(content.slice(0, keepEnd), "utf8"));
|
|
9654
9437
|
logger2.warn("Repaired torn transcript before resume", {
|
|
9655
|
-
path:
|
|
9438
|
+
path: path3,
|
|
9656
9439
|
trimmedBytes: content.length - keepEnd
|
|
9657
9440
|
});
|
|
9658
9441
|
return true;
|
|
@@ -10450,7 +10233,7 @@ var QueryBridge = class {
|
|
|
10450
10233
|
|
|
10451
10234
|
// src/runner/session-runner-helpers.ts
|
|
10452
10235
|
import { readFileSync as readFileSync2 } from "fs";
|
|
10453
|
-
import { dirname as dirname2, join as
|
|
10236
|
+
import { dirname as dirname2, join as join9 } from "path";
|
|
10454
10237
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
10455
10238
|
function mapChatHistory(messages) {
|
|
10456
10239
|
if (!messages) return [];
|
|
@@ -10479,7 +10262,7 @@ function readAgentVersion() {
|
|
|
10479
10262
|
const here = dirname2(fileURLToPath2(import.meta.url));
|
|
10480
10263
|
for (const rel of ["../package.json", "../../package.json"]) {
|
|
10481
10264
|
try {
|
|
10482
|
-
const pkg = JSON.parse(readFileSync2(
|
|
10265
|
+
const pkg = JSON.parse(readFileSync2(join9(here, rel), "utf-8"));
|
|
10483
10266
|
if (pkg.version) return pkg.version;
|
|
10484
10267
|
} catch {
|
|
10485
10268
|
}
|
|
@@ -10685,10 +10468,10 @@ var UsageProbeRun = class {
|
|
|
10685
10468
|
}
|
|
10686
10469
|
};
|
|
10687
10470
|
async function runUsageProbe(deps = {}) {
|
|
10688
|
-
let
|
|
10689
|
-
if (!
|
|
10471
|
+
let spawn = deps.spawn;
|
|
10472
|
+
if (!spawn) {
|
|
10690
10473
|
try {
|
|
10691
|
-
|
|
10474
|
+
spawn = await loadPtySpawn();
|
|
10692
10475
|
} catch {
|
|
10693
10476
|
return "";
|
|
10694
10477
|
}
|
|
@@ -10704,7 +10487,7 @@ async function runUsageProbe(deps = {}) {
|
|
|
10704
10487
|
return new Promise((resolve) => {
|
|
10705
10488
|
let child;
|
|
10706
10489
|
try {
|
|
10707
|
-
child =
|
|
10490
|
+
child = spawn(binary, [], {
|
|
10708
10491
|
name: "xterm-256color",
|
|
10709
10492
|
cols: 120,
|
|
10710
10493
|
rows: 45,
|
|
@@ -10778,14 +10561,14 @@ async function sampleKeyUsage(token, probe = () => runUsageProbe(), hasSubscript
|
|
|
10778
10561
|
}
|
|
10779
10562
|
|
|
10780
10563
|
// src/setup/git-ready.ts
|
|
10781
|
-
import { access, stat as
|
|
10564
|
+
import { access, stat as stat2 } from "fs/promises";
|
|
10782
10565
|
var DEFAULT_FAILED_PATH = "/workspaces/.conveyor-git-failed";
|
|
10783
10566
|
var DEFAULT_TIMEOUT_MS = 6e5;
|
|
10784
10567
|
var DEFAULT_POLL_MS = 200;
|
|
10785
|
-
async function fileExists(
|
|
10568
|
+
async function fileExists(path3) {
|
|
10786
10569
|
try {
|
|
10787
|
-
await access(
|
|
10788
|
-
const s = await
|
|
10570
|
+
await access(path3);
|
|
10571
|
+
const s = await stat2(path3);
|
|
10789
10572
|
return s.isFile();
|
|
10790
10573
|
} catch {
|
|
10791
10574
|
return false;
|
|
@@ -10848,8 +10631,8 @@ async function pollForMarkers(markerPath, failedPath, timeoutMs, pollMs, onLog,
|
|
|
10848
10631
|
}
|
|
10849
10632
|
|
|
10850
10633
|
// src/runner/port-discovery.ts
|
|
10851
|
-
import { readFile as
|
|
10852
|
-
import { execFile as
|
|
10634
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
10635
|
+
import { execFile as execFile2 } from "child_process";
|
|
10853
10636
|
var PROC_TCP_LISTEN_STATE = "0A";
|
|
10854
10637
|
function isLoopbackHexAddress(hex) {
|
|
10855
10638
|
const addr = hex.toUpperCase();
|
|
@@ -10900,9 +10683,9 @@ var DEFAULT_PROC_PATHS = ["/proc/net/tcp", "/proc/net/tcp6"];
|
|
|
10900
10683
|
async function readProcListeningPorts(procPaths = DEFAULT_PROC_PATHS) {
|
|
10901
10684
|
const sockets = [];
|
|
10902
10685
|
let readable = false;
|
|
10903
|
-
for (const
|
|
10686
|
+
for (const path3 of procPaths) {
|
|
10904
10687
|
try {
|
|
10905
|
-
const content = await
|
|
10688
|
+
const content = await readFile3(path3, "utf8");
|
|
10906
10689
|
readable = true;
|
|
10907
10690
|
sockets.push(...parseProcNetTcpListeners(content));
|
|
10908
10691
|
} catch {
|
|
@@ -10912,7 +10695,7 @@ async function readProcListeningPorts(procPaths = DEFAULT_PROC_PATHS) {
|
|
|
10912
10695
|
}
|
|
10913
10696
|
async function readNetstatListeningPorts() {
|
|
10914
10697
|
const output = await new Promise((resolve) => {
|
|
10915
|
-
|
|
10698
|
+
execFile2("netstat", ["-an", "-p", "tcp"], { timeout: 5e3 }, (err, stdout) => {
|
|
10916
10699
|
resolve(err ? null : stdout);
|
|
10917
10700
|
});
|
|
10918
10701
|
});
|
|
@@ -11085,9 +10868,9 @@ var PortDiscovery = class {
|
|
|
11085
10868
|
};
|
|
11086
10869
|
|
|
11087
10870
|
// src/runner/parent-pull-handler.ts
|
|
11088
|
-
import { execFile as
|
|
11089
|
-
import { promisify as
|
|
11090
|
-
var
|
|
10871
|
+
import { execFile as execFile3 } from "child_process";
|
|
10872
|
+
import { promisify as promisify2 } from "util";
|
|
10873
|
+
var execFileAsync2 = promisify2(execFile3);
|
|
11091
10874
|
async function handlePullBranch(workDir, branch) {
|
|
11092
10875
|
if (!branch) return;
|
|
11093
10876
|
const current = await getCurrentBranch(workDir);
|
|
@@ -11106,14 +10889,14 @@ async function handlePullBranch(workDir, branch) {
|
|
|
11106
10889
|
return;
|
|
11107
10890
|
}
|
|
11108
10891
|
try {
|
|
11109
|
-
await
|
|
10892
|
+
await execFileAsync2("git", ["fetch", "origin", branch], { cwd: workDir, timeout: 6e4 });
|
|
11110
10893
|
} catch {
|
|
11111
10894
|
process.stderr.write(`[conveyor-agent] pull_branch: fetch failed for ${branch}
|
|
11112
10895
|
`);
|
|
11113
10896
|
return;
|
|
11114
10897
|
}
|
|
11115
10898
|
try {
|
|
11116
|
-
await
|
|
10899
|
+
await execFileAsync2("git", ["pull", "--ff-only", "origin", branch], {
|
|
11117
10900
|
cwd: workDir,
|
|
11118
10901
|
timeout: 6e4
|
|
11119
10902
|
});
|
|
@@ -11129,7 +10912,7 @@ async function handlePullBranch(workDir, branch) {
|
|
|
11129
10912
|
|
|
11130
10913
|
// src/runner/heavy-gate.ts
|
|
11131
10914
|
import { readFileSync as readFileSync3 } from "fs";
|
|
11132
|
-
import
|
|
10915
|
+
import path2 from "path";
|
|
11133
10916
|
var GATE_KEYS = ["heavy", "test", "typecheck", "build"];
|
|
11134
10917
|
function runDir() {
|
|
11135
10918
|
return process.env.CONVEYOR_RUN_DIR ?? "/tmp/conveyor-run";
|
|
@@ -11145,7 +10928,7 @@ function pidAlive(pid) {
|
|
|
11145
10928
|
function isHeavyGateActive() {
|
|
11146
10929
|
for (const key of GATE_KEYS) {
|
|
11147
10930
|
try {
|
|
11148
|
-
const raw = readFileSync3(
|
|
10931
|
+
const raw = readFileSync3(path2.join(runDir(), `${key}.pid`), "utf8").trim();
|
|
11149
10932
|
const pid = Number.parseInt(raw, 10);
|
|
11150
10933
|
if (Number.isInteger(pid) && pid > 0 && pidAlive(pid)) return true;
|
|
11151
10934
|
} catch {
|
|
@@ -12046,13 +11829,12 @@ var SessionRunner = class _SessionRunner {
|
|
|
12046
11829
|
};
|
|
12047
11830
|
|
|
12048
11831
|
// src/setup/config.ts
|
|
12049
|
-
import {
|
|
12050
|
-
import { join as join9 } from "path";
|
|
11832
|
+
import { join as join10 } from "path";
|
|
12051
11833
|
var DEVCONTAINER_PATH = ".devcontainer/conveyor/devcontainer.json";
|
|
12052
11834
|
var DEVCONTAINER_PORT_DENY_LIST = /* @__PURE__ */ new Set([5432, 6379, 9200]);
|
|
12053
11835
|
async function loadForwardPorts(workspaceDir) {
|
|
12054
11836
|
try {
|
|
12055
|
-
const raw = await
|
|
11837
|
+
const raw = await readWorkspaceFile(join10(workspaceDir, DEVCONTAINER_PATH));
|
|
12056
11838
|
const parsed = JSON.parse(raw);
|
|
12057
11839
|
const ports = (parsed.forwardPorts ?? []).filter(
|
|
12058
11840
|
(p) => typeof p === "number" && !DEVCONTAINER_PORT_DENY_LIST.has(p)
|
|
@@ -12093,125 +11875,11 @@ function loadConveyorConfig() {
|
|
|
12093
11875
|
return null;
|
|
12094
11876
|
}
|
|
12095
11877
|
|
|
12096
|
-
// src/setup/commands.ts
|
|
12097
|
-
import { spawn, execSync } from "child_process";
|
|
12098
|
-
var PROCESS_TERMINATION_GRACE_MS = 5e3;
|
|
12099
|
-
function abortError2() {
|
|
12100
|
-
const error = new Error("Operation aborted");
|
|
12101
|
-
error.name = "AbortError";
|
|
12102
|
-
return error;
|
|
12103
|
-
}
|
|
12104
|
-
function signalProcessGroup(child, signal) {
|
|
12105
|
-
try {
|
|
12106
|
-
if (child.pid) process.kill(-child.pid, signal);
|
|
12107
|
-
else child.kill(signal);
|
|
12108
|
-
} catch {
|
|
12109
|
-
try {
|
|
12110
|
-
child.kill(signal);
|
|
12111
|
-
} catch {
|
|
12112
|
-
}
|
|
12113
|
-
}
|
|
12114
|
-
}
|
|
12115
|
-
function terminateProcessGroup(child, graceMs = PROCESS_TERMINATION_GRACE_MS) {
|
|
12116
|
-
if (child.exitCode !== null) return Promise.resolve();
|
|
12117
|
-
return new Promise((resolve) => {
|
|
12118
|
-
let settled = false;
|
|
12119
|
-
const finish = () => {
|
|
12120
|
-
if (settled) return;
|
|
12121
|
-
settled = true;
|
|
12122
|
-
clearTimeout(timer);
|
|
12123
|
-
child.removeListener("exit", finish);
|
|
12124
|
-
resolve();
|
|
12125
|
-
};
|
|
12126
|
-
const timer = setTimeout(() => {
|
|
12127
|
-
signalProcessGroup(child, "SIGKILL");
|
|
12128
|
-
finish();
|
|
12129
|
-
}, graceMs);
|
|
12130
|
-
timer.unref();
|
|
12131
|
-
child.once("exit", finish);
|
|
12132
|
-
signalProcessGroup(child, "SIGTERM");
|
|
12133
|
-
});
|
|
12134
|
-
}
|
|
12135
|
-
function runSetupCommand(cmd, cwd, onOutput, signal) {
|
|
12136
|
-
if (signal?.aborted) return Promise.reject(abortError2());
|
|
12137
|
-
return new Promise((resolve, reject) => {
|
|
12138
|
-
const child = spawn("sh", ["-c", cmd], {
|
|
12139
|
-
cwd,
|
|
12140
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
12141
|
-
detached: true,
|
|
12142
|
-
env: { ...process.env }
|
|
12143
|
-
});
|
|
12144
|
-
let settled = false;
|
|
12145
|
-
let aborting = false;
|
|
12146
|
-
const cleanup = () => signal?.removeEventListener("abort", onAbort);
|
|
12147
|
-
const settle = (error) => {
|
|
12148
|
-
if (settled) return;
|
|
12149
|
-
settled = true;
|
|
12150
|
-
cleanup();
|
|
12151
|
-
if (error) reject(error);
|
|
12152
|
-
else resolve();
|
|
12153
|
-
};
|
|
12154
|
-
const onAbort = () => {
|
|
12155
|
-
if (settled || aborting) return;
|
|
12156
|
-
aborting = true;
|
|
12157
|
-
void terminateProcessGroup(child).then(() => settle(abortError2()));
|
|
12158
|
-
};
|
|
12159
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
12160
|
-
if (signal?.aborted) onAbort();
|
|
12161
|
-
child.stdout.on("data", (chunk) => {
|
|
12162
|
-
if (aborting || signal?.aborted) return;
|
|
12163
|
-
onOutput("stdout", chunk.toString());
|
|
12164
|
-
});
|
|
12165
|
-
child.stderr.on("data", (chunk) => {
|
|
12166
|
-
if (aborting || signal?.aborted) return;
|
|
12167
|
-
onOutput("stderr", chunk.toString());
|
|
12168
|
-
});
|
|
12169
|
-
child.on("close", (code) => {
|
|
12170
|
-
if (aborting) return;
|
|
12171
|
-
settle(code === 0 ? void 0 : new Error(`Setup command exited with code ${code}`));
|
|
12172
|
-
});
|
|
12173
|
-
child.on("error", (err) => {
|
|
12174
|
-
if (!aborting) settle(err);
|
|
12175
|
-
});
|
|
12176
|
-
});
|
|
12177
|
-
}
|
|
12178
|
-
var AUTH_TOKEN_TIMEOUT_MS = 3e4;
|
|
12179
|
-
function runAuthTokenCommand(cmd, userEmail, cwd) {
|
|
12180
|
-
try {
|
|
12181
|
-
const output = execSync(`${cmd} ${JSON.stringify(userEmail)}`, {
|
|
12182
|
-
cwd,
|
|
12183
|
-
timeout: AUTH_TOKEN_TIMEOUT_MS,
|
|
12184
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
12185
|
-
env: { ...process.env }
|
|
12186
|
-
});
|
|
12187
|
-
const token = output.toString().trim();
|
|
12188
|
-
return token || null;
|
|
12189
|
-
} catch {
|
|
12190
|
-
return null;
|
|
12191
|
-
}
|
|
12192
|
-
}
|
|
12193
|
-
function runStartCommand(cmd, cwd, onOutput) {
|
|
12194
|
-
const child = spawn("sh", ["-c", cmd], {
|
|
12195
|
-
cwd,
|
|
12196
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
12197
|
-
detached: true,
|
|
12198
|
-
env: { ...process.env }
|
|
12199
|
-
});
|
|
12200
|
-
child.stdout.on("data", (chunk) => {
|
|
12201
|
-
onOutput("stdout", chunk.toString());
|
|
12202
|
-
});
|
|
12203
|
-
child.stderr.on("data", (chunk) => {
|
|
12204
|
-
onOutput("stderr", chunk.toString());
|
|
12205
|
-
});
|
|
12206
|
-
child.unref();
|
|
12207
|
-
return child;
|
|
12208
|
-
}
|
|
12209
|
-
|
|
12210
11878
|
// src/setup/codespace.ts
|
|
12211
|
-
import { execSync
|
|
11879
|
+
import { execSync } from "child_process";
|
|
12212
11880
|
function unshallowRepo(workspaceDir) {
|
|
12213
11881
|
try {
|
|
12214
|
-
|
|
11882
|
+
execSync("git fetch --unshallow", {
|
|
12215
11883
|
cwd: workspaceDir,
|
|
12216
11884
|
timeout: 6e4,
|
|
12217
11885
|
stdio: "ignore"
|
|
@@ -12229,15 +11897,13 @@ export {
|
|
|
12229
11897
|
DEFAULT_LIFECYCLE_CONFIG,
|
|
12230
11898
|
Lifecycle,
|
|
12231
11899
|
defineTool,
|
|
12232
|
-
loadPtySpawn,
|
|
12233
|
-
inheritedEnv,
|
|
12234
|
-
buildPromptBytes,
|
|
12235
11900
|
cleanTerminalOutput,
|
|
12236
11901
|
buildSynthesizedCredentials,
|
|
12237
11902
|
claudeJsonPath,
|
|
12238
11903
|
ClaudeTuiAdapter,
|
|
12239
11904
|
createServiceLogger,
|
|
12240
11905
|
PtyHarness,
|
|
11906
|
+
workspacePathExists,
|
|
12241
11907
|
textResult,
|
|
12242
11908
|
GIT_TIMEOUT_MS,
|
|
12243
11909
|
hasUncommittedChanges,
|
|
@@ -12266,10 +11932,6 @@ export {
|
|
|
12266
11932
|
loadForwardPorts,
|
|
12267
11933
|
buildSessionPreviewPorts,
|
|
12268
11934
|
loadConveyorConfig,
|
|
12269
|
-
terminateProcessGroup,
|
|
12270
|
-
runSetupCommand,
|
|
12271
|
-
runAuthTokenCommand,
|
|
12272
|
-
runStartCommand,
|
|
12273
11935
|
unshallowRepo
|
|
12274
11936
|
};
|
|
12275
|
-
//# sourceMappingURL=chunk-
|
|
11937
|
+
//# sourceMappingURL=chunk-DJPSNHVJ.js.map
|