@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.
@@ -1,13 +1,31 @@
1
1
  import {
2
2
  LoopLagMonitor
3
3
  } from "./chunk-7TQO4ZF4.js";
4
-
5
- // src/utils/sleep.ts
6
- function sleep(ms) {
7
- return new Promise((resolve) => {
8
- setTimeout(resolve, ms);
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 || process.env.CLAUDESPACE_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 rm3 } from "fs/promises";
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-tar.ts
1587
- import { execFile as execFile2 } from "child_process";
1614
+ // src/runner/work-preservation/snapshot-transfer.ts
1615
+ import { randomUUID } from "crypto";
1588
1616
  import { createReadStream, createWriteStream } from "fs";
1589
- import { mkdtemp, rm, stat, writeFile } from "fs/promises";
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 as pipeline2 } from "stream/promises";
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(createReadStream2(tarResult.tarPath));
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 = path2.join(tmpdir2(), `conveyor-snapshot-restore-${randomUUID()}.tar.gz`);
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 pipeline2(
1651
+ await pipeline(
1798
1652
  Readable.fromWeb(res.body),
1799
- createWriteStream2(tmpTar)
1653
+ createWriteStream(tmpTar)
1800
1654
  );
1801
1655
  return tmpTar;
1802
1656
  } catch {
1803
- await rm2(tmpTar, { force: true }).catch(() => {
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 buildSnapshotTar(cwd);
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 extractSnapshotTar(cwd, tmpTar);
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 rm3(tmpTar, { force: true }).catch(() => {
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 rm5 } from "fs/promises";
3406
- import { tmpdir as tmpdir3 } from "os";
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(path4, onEvent, onRawRecord) {
3689
- this.path = path4;
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 isRecord3(value) {
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" && isRecord3(input)) {
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 (!isRecord3(message)) return [];
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 (!isRecord3(raw)) continue;
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) => isRecord3(b) && b.type === "text").map((b) => typeof b.text === "string" ? b.text : "").filter((t) => t.length > 0).join("\n");
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 (!isRecord3(raw) || raw.type !== "tool_result") continue;
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 (!isRecord3(message)) return [];
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) => isRecord3(b) && b.type === "tool_result");
3802
+ const hasToolResult = content.some((b) => isRecord2(b) && b.type === "tool_result");
4042
3803
  if (hasToolResult) return mapToolResults(content);
4043
- text = content.filter((b) => isRecord3(b) && b.type === "text").map((b) => typeof b.text === "string" ? b.text : "").filter((t) => t.length > 0).join("\n");
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 (!isRecord3(raw)) return [];
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 as writeFile2, chmod } from "fs/promises";
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 ?? join(homedir(), ".claude");
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 join(claudeConfigHome(), "projects", projectSlug(cwd), `${sessionId}.jsonl`);
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 = join(dir, "hook-helper.cjs");
4248
- const settingsPath = join(dir, "settings.json");
4008
+ const helperPath = join2(dir, "hook-helper.cjs");
4009
+ const settingsPath = join2(dir, "settings.json");
4249
4010
  await mkdir(dir, { recursive: true });
4250
- await writeFile2(helperPath, HOOK_HELPER_SOURCE, "utf8");
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 writeFile2(settingsPath, JSON.stringify(settings, null, 2), "utf8");
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 writeFile3 } from "fs/promises";
4366
- import { join as join2 } from "path";
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 = join2(tempDir, "mcp-config.json");
4558
- await writeFile3(mcpConfigPath, JSON.stringify({ mcpServers: config }, null, 2), "utf8");
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 rm4, writeFile as writeFile4 } from "fs/promises";
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 join3 } from "path";
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 join3(claudeConfigHome(), ".credentials.json");
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(path4) {
4445
+ async function readRaw(path3) {
4685
4446
  try {
4686
- return await readFile(path4, "utf8");
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(path4, mode) {
4473
+ function fsWriteIo(path3, mode) {
4713
4474
  return {
4714
- write: (contents) => writeFile4(path4, contents, mode === void 0 ? "utf8" : { encoding: "utf8", mode }),
4715
- read: () => readRaw(path4)
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 path4 = claudeCredentialsPath();
4486
+ const path3 = claudeCredentialsPath();
4726
4487
  const plan = planCredentialsWrite({
4727
4488
  isCloud,
4728
4489
  token,
4729
- existingRaw: await readRaw(path4),
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(path4, 384), plan.contents);
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 ${path4} \u2014 TUI may land on the login picker
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(path4, 384).catch(() => {
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 path4 = claudeJsonPath();
4771
- const cleaned = planApprovedApiKeyCleanup(await readRaw(path4), oauthToken);
4531
+ const path3 = claudeJsonPath();
4532
+ const cleaned = planApprovedApiKeyCleanup(await readRaw(path3), oauthToken);
4772
4533
  if (cleaned === null) return;
4773
- const verified = await writeWithReadBackRetry(fsWriteIo(path4), cleaned);
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 ${path4} \u2014 CLI may still see the poisoned entry
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 ? join3(configDir, ".claude.json") : join3(homedir2(), ".claude.json");
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 join3(claudeConfigHome(), "conveyor-oauth-account.json");
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 path4 = claudeJsonPath();
4913
- const existingRaw = await readRaw(path4);
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(path4), contents);
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(path4);
4689
+ const verify = await readRaw(path3);
4929
4690
  process.stderr.write(
4930
- `[conveyor-agent] claude onboarding seed read-back MISMATCH at ${path4} after retries: wrote ${contents.length}B, read ${verify?.length ?? 0}B \u2014 CLI may see stale config and park at a startup dialog
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 path4 = claudeCredentialsPath();
4944
- const existing = parseClaudeAiOauth(await readRaw(path4));
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 rm4(path4, { force: true });
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(join4(tmpdir3(), "conveyor-pty-"));
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(join4(tmpdir3(), "conveyor-pty-"));
5294
- const socketPath = join4(this.tempDir, "hook.sock");
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 rm5(this.tempDir, { recursive: true, force: true });
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 spawn2 = await loadPtySpawn();
5468
- const pty = spawn2(spec.file, spec.args, {
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 join5 } from "path";
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 join5(homedir3(), ".claude-local");
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(join5(configHome, "projects", projectSlug(cwd)), { recursive: true });
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(join5(fallback, "projects", projectSlug(cwd)), { recursive: true });
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
- let mtimeMs;
6269
- try {
6270
- const st = await stat3(filePath);
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 readFile2(filePath, "utf-8");
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
- let mtimeMs;
6291
- try {
6292
- const st = await stat3(folderPath);
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 readdir(folderPath);
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 readFile3, stat as stat4 } from "fs/promises";
7962
- import { basename, extname, isAbsolute, join as join6 } from "path";
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: path4, title }) => {
7762
+ async ({ path: path3, title }) => {
7980
7763
  try {
7981
- const filePath = isAbsolute(path4) ? path4 : join6(config.workspaceDir, path4);
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 stat4(filePath).catch(() => null);
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 readFile3(filePath);
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 join7 } from "path";
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(path4) {
8535
+ function isExecutable(path3) {
8753
8536
  try {
8754
- if (!statSync(path4).isFile()) return false;
8755
- accessSync(path4, constants.X_OK);
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 = join7(dir, binary);
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 list2 = outputsByTool.get(entry.tool) ?? [];
9100
- list2.push(entry.output);
9101
- outputsByTool.set(entry.tool, list2);
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 list2 = outputsByTool.get(call.tool);
9105
- if (list2 && list2.length > 0) {
9106
- call.output = list2.shift();
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(path4) {
9414
+ function repairTornSessionFile(path3) {
9632
9415
  try {
9633
- if (!existsSync2(path4)) return false;
9634
- const content = readFileSync(path4, "utf8");
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(path4, Buffer.byteLength(content.slice(0, keepEnd), "utf8"));
9436
+ truncateSync(path3, Buffer.byteLength(content.slice(0, keepEnd), "utf8"));
9654
9437
  logger2.warn("Repaired torn transcript before resume", {
9655
- path: path4,
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 join8 } from "path";
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(join8(here, rel), "utf-8"));
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 spawn2 = deps.spawn;
10689
- if (!spawn2) {
10471
+ let spawn = deps.spawn;
10472
+ if (!spawn) {
10690
10473
  try {
10691
- spawn2 = await loadPtySpawn();
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 = spawn2(binary, [], {
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 stat5 } from "fs/promises";
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(path4) {
10568
+ async function fileExists(path3) {
10786
10569
  try {
10787
- await access(path4);
10788
- const s = await stat5(path4);
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 readFile4 } from "fs/promises";
10852
- import { execFile as execFile3 } from "child_process";
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 path4 of procPaths) {
10686
+ for (const path3 of procPaths) {
10904
10687
  try {
10905
- const content = await readFile4(path4, "utf8");
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
- execFile3("netstat", ["-an", "-p", "tcp"], { timeout: 5e3 }, (err, stdout) => {
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 execFile4 } from "child_process";
11089
- import { promisify as promisify3 } from "util";
11090
- var execFileAsync3 = promisify3(execFile4);
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 execFileAsync3("git", ["fetch", "origin", branch], { cwd: workDir, timeout: 6e4 });
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 execFileAsync3("git", ["pull", "--ff-only", "origin", branch], {
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 path3 from "path";
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(path3.join(runDir(), `${key}.pid`), "utf8").trim();
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 { readFile as readFile5 } from "fs/promises";
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 readFile5(join9(workspaceDir, DEVCONTAINER_PATH), "utf-8");
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 as execSync2 } from "child_process";
11879
+ import { execSync } from "child_process";
12212
11880
  function unshallowRepo(workspaceDir) {
12213
11881
  try {
12214
- execSync2("git fetch --unshallow", {
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-PXQJ4NVO.js.map
11937
+ //# sourceMappingURL=chunk-DJPSNHVJ.js.map