codeam-cli 2.74.7 → 2.74.9

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.
Files changed (3) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/index.js +286 -283
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -3211,11 +3211,11 @@ function quiet(fn) {
3211
3211
  log.debug(TAG, "ignored sync error", err);
3212
3212
  }
3213
3213
  }
3214
- function rmIfExistsQuiet(path95) {
3214
+ function rmIfExistsQuiet(path96) {
3215
3215
  try {
3216
- fs2.rmSync(path95, { force: true });
3216
+ fs2.rmSync(path96, { force: true });
3217
3217
  } catch (err) {
3218
- log.debug(TAG, `rmIfExists failed for ${path95}`, err);
3218
+ log.debug(TAG, `rmIfExists failed for ${path96}`, err);
3219
3219
  }
3220
3220
  }
3221
3221
  function killQuiet(target, signal = "SIGTERM") {
@@ -3386,7 +3386,7 @@ var { getConfig, ensurePluginId, addSession, removeSession, setActiveSession, ge
3386
3386
  // src/commands/pair-auto.ts
3387
3387
  var fs66 = __toESM(require("fs"));
3388
3388
  var os55 = __toESM(require("os"));
3389
- var path72 = __toESM(require("path"));
3389
+ var path73 = __toESM(require("path"));
3390
3390
  var import_crypto4 = require("crypto");
3391
3391
 
3392
3392
  // src/services/telemetry.service.ts
@@ -3422,8 +3422,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
3422
3422
  return decodedFile;
3423
3423
  };
3424
3424
  }
3425
- function normalizeWindowsPath(path95) {
3426
- return path95.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
3425
+ function normalizeWindowsPath(path96) {
3426
+ return path96.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
3427
3427
  }
3428
3428
 
3429
3429
  // ../../node_modules/@posthog/core/dist/featureFlagUtils.mjs
@@ -5903,9 +5903,9 @@ async function addSourceContext(frames) {
5903
5903
  LRU_FILE_CONTENTS_CACHE.reduce();
5904
5904
  return frames;
5905
5905
  }
5906
- function getContextLinesFromFile(path95, ranges, output) {
5906
+ function getContextLinesFromFile(path96, ranges, output) {
5907
5907
  return new Promise((resolve11) => {
5908
- const stream = (0, import_node_fs.createReadStream)(path95);
5908
+ const stream = (0, import_node_fs.createReadStream)(path96);
5909
5909
  const lineReaded = (0, import_node_readline.createInterface)({
5910
5910
  input: stream
5911
5911
  });
@@ -5920,7 +5920,7 @@ function getContextLinesFromFile(path95, ranges, output) {
5920
5920
  let rangeStart = range[0];
5921
5921
  let rangeEnd = range[1];
5922
5922
  function onStreamError() {
5923
- LRU_FILE_CONTENTS_FS_READ_FAILED.set(path95, 1);
5923
+ LRU_FILE_CONTENTS_FS_READ_FAILED.set(path96, 1);
5924
5924
  lineReaded.close();
5925
5925
  lineReaded.removeAllListeners();
5926
5926
  destroyStreamAndResolve();
@@ -5981,8 +5981,8 @@ function clearLineContext(frame) {
5981
5981
  delete frame.context_line;
5982
5982
  delete frame.post_context;
5983
5983
  }
5984
- function shouldSkipContextLinesForFile(path95) {
5985
- return path95.startsWith("node:") || path95.endsWith(".min.js") || path95.endsWith(".min.cjs") || path95.endsWith(".min.mjs") || path95.startsWith("data:");
5984
+ function shouldSkipContextLinesForFile(path96) {
5985
+ return path96.startsWith("node:") || path96.endsWith(".min.js") || path96.endsWith(".min.cjs") || path96.endsWith(".min.mjs") || path96.startsWith("data:");
5986
5986
  }
5987
5987
  function shouldSkipContextLinesForFrame(frame) {
5988
5988
  if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
@@ -8136,7 +8136,7 @@ function readAnonId() {
8136
8136
  }
8137
8137
  function superProperties() {
8138
8138
  return {
8139
- cliVersion: true ? "2.74.7" : "0.0.0-dev",
8139
+ cliVersion: true ? "2.74.9" : "0.0.0-dev",
8140
8140
  nodeVersion: process.version,
8141
8141
  platform: process.platform,
8142
8142
  arch: process.arch,
@@ -8378,7 +8378,7 @@ var http = __toESM(require("http"));
8378
8378
  // package.json
8379
8379
  var package_default = {
8380
8380
  name: "codeam-cli",
8381
- version: "2.74.7",
8381
+ version: "2.74.9",
8382
8382
  description: "Workflow-continuity bridge for AI coding agents. Wrap Claude Code or Codex in a PTY and supervise, approve, and redirect the session from any device \u2014 async. The terminal companion for CodeAgent Mobile.",
8383
8383
  type: "commonjs",
8384
8384
  main: "dist/index.js",
@@ -9971,7 +9971,7 @@ var CommandRelayService = class _CommandRelayService {
9971
9971
  // fresh + clear the "CLI update available" banner after a self-update
9972
9972
  // (a codespace that reinstalls @latest reconnects via heartbeat, not
9973
9973
  // pair/reconnect). Older backends ignore the extra field.
9974
- ..."2.74.7" ? { ideVersion: "2.74.7" } : {}
9974
+ ..."2.74.9" ? { ideVersion: "2.74.9" } : {}
9975
9975
  }).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
9976
9976
  }
9977
9977
  /**
@@ -11380,7 +11380,7 @@ function closeAllTerminals() {
11380
11380
  // src/commands/start/handlers.ts
11381
11381
  var fs65 = __toESM(require("fs"));
11382
11382
  var os54 = __toESM(require("os"));
11383
- var path71 = __toESM(require("path"));
11383
+ var path72 = __toESM(require("path"));
11384
11384
  var import_crypto3 = require("crypto");
11385
11385
  var import_child_process28 = require("child_process");
11386
11386
 
@@ -17588,8 +17588,8 @@ function pickLine(obj) {
17588
17588
  function toHunk(raw, groupSeverity) {
17589
17589
  if (!raw || typeof raw !== "object") return null;
17590
17590
  const o = raw;
17591
- const path95 = asString(pick(o, ["file_path", "filePath", "file", "path", "filename", "fileName"])) ?? asString(pick(o, ["location"])?.path);
17592
- if (!path95) return null;
17591
+ const path96 = asString(pick(o, ["file_path", "filePath", "file", "path", "filename", "fileName"])) ?? asString(pick(o, ["location"])?.path);
17592
+ if (!path96) return null;
17593
17593
  const message = asString(
17594
17594
  pick(o, [
17595
17595
  "comment",
@@ -17606,7 +17606,7 @@ function toHunk(raw, groupSeverity) {
17606
17606
  const severity = normSeverity(pick(o, ["severity", "level", "priority", "impact"])) ?? normSeverity(groupSeverity);
17607
17607
  const locObj = pick(o, ["location"]) ?? o;
17608
17608
  return {
17609
- path: path95.trim(),
17609
+ path: path96.trim(),
17610
17610
  line: pickLine(o) ?? pickLine(locObj),
17611
17611
  severity,
17612
17612
  message: (title && message ? `${title}: ${message}` : title || message).trim() || "(no message)"
@@ -17689,10 +17689,10 @@ function parsePlain(stdout) {
17689
17689
  for (const line of stdout.split(/\r?\n/)) {
17690
17690
  const m = line.match(HUNK_LINE_RE);
17691
17691
  if (!m) continue;
17692
- const [, path95, lineNo, sevToken, message] = m;
17693
- if (!path95 || !lineNo || !message) continue;
17692
+ const [, path96, lineNo, sevToken, message] = m;
17693
+ if (!path96 || !lineNo || !message) continue;
17694
17694
  hunks.push({
17695
- path: path95.trim(),
17695
+ path: path96.trim(),
17696
17696
  line: Number(lineNo),
17697
17697
  severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
17698
17698
  message: message.trim().replace(/^[*-]\s+/, "")
@@ -22272,7 +22272,7 @@ async function autoUpgradeBeforeCriticalCommand() {
22272
22272
  if (process.env.NODE_ENV === "test") return;
22273
22273
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
22274
22274
  if (process.env.CI) return;
22275
- const current2 = true ? "2.74.7" : null;
22275
+ const current2 = true ? "2.74.9" : null;
22276
22276
  if (!current2) return;
22277
22277
  const cache = readCache();
22278
22278
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -22289,7 +22289,7 @@ function checkForUpdates() {
22289
22289
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
22290
22290
  if (process.env.CI) return;
22291
22291
  if (!process.stdout.isTTY) return;
22292
- const current2 = true ? "2.74.7" : null;
22292
+ const current2 = true ? "2.74.9" : null;
22293
22293
  if (!current2) return;
22294
22294
  const cache = readCache();
22295
22295
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -22312,7 +22312,7 @@ var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
22312
22312
  var SELF_UPDATE_LS_TIMEOUT_MS = 15e3;
22313
22313
  var SUDO_PREFLIGHT_TIMEOUT_MS = 5e3;
22314
22314
  function currentCliVersion() {
22315
- return true ? "2.74.7" : null;
22315
+ return true ? "2.74.9" : null;
22316
22316
  }
22317
22317
  async function installedVersion(deps) {
22318
22318
  const ls = await deps.run(
@@ -23279,7 +23279,9 @@ var HostAgentSupervisor = class {
23279
23279
  );
23280
23280
  return;
23281
23281
  }
23282
- if (!await this.fleetBoxImageStale(containerName)) {
23282
+ const stale = await this.fleetBoxImageStale(containerName);
23283
+ if (stale === null) return;
23284
+ if (!stale) {
23283
23285
  log.info("host-agent", `fleet_migrate_box_image: ${containerName} already current`);
23284
23286
  return;
23285
23287
  }
@@ -23362,7 +23364,7 @@ var HostAgentSupervisor = class {
23362
23364
  * current registry `:latest` (a stale runtime), or the container is gone.
23363
23365
  * Pulls `:latest` first so the comparison is against the freshest image.
23364
23366
  * Best-effort + fail-SAFE: a local-image override (int test / operator) or any
23365
- * pull/inspect error returns false → the caller falls back to a plain
23367
+ * pull/inspect error returns false (null for a failed pull, logged) → the caller falls back to a plain
23366
23368
  * `docker start`, so a transient docker hiccup can never wedge a wake.
23367
23369
  */
23368
23370
  async fleetBoxImageStale(containerName) {
@@ -23372,8 +23374,16 @@ var HostAgentSupervisor = class {
23372
23374
  if (cur.code !== 0) {
23373
23375
  return isMissingContainerError(cur.stderr);
23374
23376
  }
23375
- const pull = await this.docker.run(["pull", image], { timeoutMs: DOCKER_RUN_TIMEOUT_MS });
23376
- if (pull.code !== 0) return false;
23377
+ const pull = await this.docker.run(["pull", image], {
23378
+ timeoutMs: DOCKER_RUN_WITH_PULL_TIMEOUT_MS
23379
+ });
23380
+ if (pull.code !== 0) {
23381
+ log.warn(
23382
+ "host-agent",
23383
+ `fleet image pull failed (code=${pull.code}) \u2014 cannot tell whether ${containerName} is stale, leaving it: ` + pull.stderr.trim().slice(-300)
23384
+ );
23385
+ return null;
23386
+ }
23377
23387
  const latest = await this.docker.run(["inspect", "--format", "{{.Id}}", image]);
23378
23388
  if (latest.code !== 0) return false;
23379
23389
  return cur.stdout.trim() !== "" && cur.stdout.trim() !== latest.stdout.trim();
@@ -24279,17 +24289,17 @@ async function defaultFetchJson(url2) {
24279
24289
  async function readUsageReport(deps = {}) {
24280
24290
  const port = deps.port ?? HEADROOM_PROXY_PORT;
24281
24291
  const base = `http://127.0.0.1:${port}`;
24282
- const get3 = deps.fetchJson ?? ((path95) => defaultFetchJson(`${base}${path95}`));
24292
+ const get4 = deps.fetchJson ?? ((path96) => defaultFetchJson(`${base}${path96}`));
24283
24293
  let history;
24284
24294
  try {
24285
- history = await get3("/stats-history");
24295
+ history = await get4("/stats-history");
24286
24296
  } catch (err) {
24287
24297
  log.info("headroomUsage", `stats-history unavailable: ${err.message}`);
24288
24298
  return null;
24289
24299
  }
24290
24300
  let proxyVersion;
24291
24301
  try {
24292
- const health = await get3("/health");
24302
+ const health = await get4("/health");
24293
24303
  if (health && typeof health.version === "string") proxyVersion = health.version;
24294
24304
  } catch {
24295
24305
  }
@@ -24949,6 +24959,51 @@ function quoteIfNeeded(value) {
24949
24959
  return value;
24950
24960
  }
24951
24961
 
24962
+ // src/services/preview/expo.ts
24963
+ var http6 = __toESM(require("http"));
24964
+ var path60 = __toESM(require("path"));
24965
+ var EXPO_PACKAGER_PROXY_URL_ENV = "EXPO_PACKAGER_PROXY_URL";
24966
+ function stripExpoTunnelFlag(args2) {
24967
+ return args2.filter((a) => a !== "--tunnel" && !a.startsWith("--tunnel="));
24968
+ }
24969
+ function ensureExpoPortArg(command2, args2, port) {
24970
+ const hasPort = args2.some((a) => a === "--port" || a.startsWith("--port="));
24971
+ if (hasPort) return [...args2];
24972
+ const out2 = [...args2];
24973
+ if (path60.basename(command2) === "npm" && !out2.includes("--")) out2.push("--");
24974
+ out2.push("--port", String(port));
24975
+ return out2;
24976
+ }
24977
+ function expoSpawnArgs(command2, args2, port) {
24978
+ return ensureExpoPortArg(command2, stripExpoTunnelFlag(args2), port);
24979
+ }
24980
+ function expoGoDeepLink(publicUrl) {
24981
+ return `exps://${new URL(publicUrl).host}`;
24982
+ }
24983
+ function isExpoManifestServed(port, host2 = "127.0.0.1") {
24984
+ return new Promise((resolve11) => {
24985
+ const req = http6.get(
24986
+ { host: host2, port, path: "/", headers: { "expo-platform": "ios" }, timeout: 1500 },
24987
+ (res) => {
24988
+ const ok = res.statusCode !== void 0 && res.statusCode >= 200 && res.statusCode < 300;
24989
+ res.resume();
24990
+ resolve11(ok);
24991
+ }
24992
+ );
24993
+ req.once("timeout", () => req.destroy());
24994
+ req.once("error", () => resolve11(false));
24995
+ });
24996
+ }
24997
+ async function waitForExpoManifest(port, opts) {
24998
+ const interval = opts.intervalMs ?? 500;
24999
+ const deadline = Date.now() + opts.timeoutMs;
25000
+ for (; ; ) {
25001
+ if (await isExpoManifestServed(port)) return true;
25002
+ if (Date.now() >= deadline) return false;
25003
+ await new Promise((r) => setTimeout(r, interval));
25004
+ }
25005
+ }
25006
+
24952
25007
  // src/services/preview/parser.ts
24953
25008
  var REQUIRED_FIELDS2 = [
24954
25009
  "framework",
@@ -25037,21 +25092,6 @@ function parseCloudflaredUrl(stderr) {
25037
25092
  const match = stderr.match(CLOUDFLARED_URL_RE);
25038
25093
  return match ? match[0] : null;
25039
25094
  }
25040
- var EXPO_DEEP_LINK_RE = /exp:\/\/[^\s"'`)]+\.exp\.(?:direct|host)(?::\d+)?/;
25041
- var EXPO_DEBUG_TUNNEL_RE = /Tunnel URL:\s*(https?:\/\/([^\s"'`)]+\.exp\.(?:direct|host)))/;
25042
- function parseExpoUrl(output) {
25043
- const direct = output.match(EXPO_DEEP_LINK_RE);
25044
- if (direct) return direct[0];
25045
- const dbg = output.match(EXPO_DEBUG_TUNNEL_RE);
25046
- if (dbg) return `exp://${dbg[2]}`;
25047
- return null;
25048
- }
25049
- var EXPO_TUNNEL_DEBUG_CHANNEL = "expo:start:server:ngrok";
25050
- function expoTunnelDebugEnv(existing) {
25051
- const cur = (existing ?? "").split(",").map((s) => s.trim()).filter(Boolean);
25052
- if (!cur.includes(EXPO_TUNNEL_DEBUG_CHANNEL)) cur.push(EXPO_TUNNEL_DEBUG_CHANNEL);
25053
- return { DEBUG: cur.join(",") };
25054
- }
25055
25095
  var RAW_EXCERPT_LIMIT = 1e3;
25056
25096
  function describeDetectionFailure(raw) {
25057
25097
  const text = raw?.trim() ?? "";
@@ -25535,25 +25575,6 @@ async function ensureYarnInstalled(deps) {
25535
25575
  if (!res.ok) return res;
25536
25576
  return await deps.hasYarn() ? { ok: true, code: 0 } : { ok: false, code: res.code };
25537
25577
  }
25538
- function isExpoTunnelCommand(command2, args2) {
25539
- const flat = [import_path8.default.basename(command2), ...args2];
25540
- return flat.includes("expo") && flat.includes("--tunnel");
25541
- }
25542
- var EXPO_NGROK_SPEC = "@expo/ngrok@^4.1.0";
25543
- async function ensureExpoTunnelDeps(deps) {
25544
- if (await deps.hasNgrok()) return { ok: true, code: 0, installed: false };
25545
- const res = await deps.installNgrok();
25546
- if (!res.ok) return { ...res, installed: false };
25547
- return await deps.hasNgrok() ? { ok: true, code: 0, installed: true } : { ok: false, code: res.code, installed: false };
25548
- }
25549
- function ngrokResolvesFrom(cwd) {
25550
- try {
25551
- require.resolve("@expo/ngrok/package.json", { paths: [cwd] });
25552
- return true;
25553
- } catch {
25554
- return false;
25555
- }
25556
- }
25557
25578
  function isJsInstallCommand(cmd, args2) {
25558
25579
  const known = ["npm", "pnpm", "yarn", "bun"];
25559
25580
  if (!known.includes(cmd)) return false;
@@ -25602,7 +25623,7 @@ async function awaitTunnelRegistered(candidate, hostname3, deadlineMs) {
25602
25623
  }
25603
25624
 
25604
25625
  // src/services/preview/adopt-port.ts
25605
- var http6 = __toESM(require("http"));
25626
+ var http7 = __toESM(require("http"));
25606
25627
  var DIRECTORY_LISTING_RE = /<title>\s*(?:Directory listing for|Index of)/i;
25607
25628
  var PROBE_TIMEOUT_MS = 2e3;
25608
25629
  var PROBE_BODY_LIMIT = 4 * 1024;
@@ -25617,7 +25638,7 @@ function verdictFor(res) {
25617
25638
  return { adopt: true };
25618
25639
  }
25619
25640
  var probePort = (port) => new Promise((resolve11) => {
25620
- const req = http6.get(
25641
+ const req = http7.get(
25621
25642
  { host: "127.0.0.1", port, path: "/", timeout: PROBE_TIMEOUT_MS },
25622
25643
  (res) => {
25623
25644
  let body = "";
@@ -25699,18 +25720,18 @@ function activePreviewSessionIds() {
25699
25720
  // src/services/preview/start-orchestrator.ts
25700
25721
  var import_child_process23 = require("child_process");
25701
25722
  var fs59 = __toESM(require("fs"));
25702
- var path64 = __toESM(require("path"));
25723
+ var path65 = __toESM(require("path"));
25703
25724
  var import_which2 = __toESM(require("which"));
25704
25725
 
25705
25726
  // src/services/project-env/index.ts
25706
25727
  var import_fs6 = require("fs");
25707
- var path63 = __toESM(require("path"));
25728
+ var path64 = __toESM(require("path"));
25708
25729
 
25709
25730
  // src/beads/project-key.ts
25710
25731
  var import_child_process22 = require("child_process");
25711
25732
  var crypto2 = __toESM(require("crypto"));
25712
25733
  var fs57 = __toESM(require("fs"));
25713
- var path62 = __toESM(require("path"));
25734
+ var path63 = __toESM(require("path"));
25714
25735
  function normalizeOrigin(raw) {
25715
25736
  const trimmed = raw.trim();
25716
25737
  if (!trimmed) return null;
@@ -25736,17 +25757,17 @@ function normalizeOrigin(raw) {
25736
25757
  return `${host2}/${pathPart}`;
25737
25758
  }
25738
25759
  function findRepoRoot(cwd) {
25739
- let dir = path62.resolve(cwd);
25760
+ let dir = path63.resolve(cwd);
25740
25761
  const seen = /* @__PURE__ */ new Set();
25741
25762
  for (let i = 0; i < 256; i++) {
25742
25763
  if (seen.has(dir)) return null;
25743
25764
  seen.add(dir);
25744
25765
  try {
25745
- const stat3 = fs57.statSync(path62.join(dir, ".git"), { throwIfNoEntry: false });
25766
+ const stat3 = fs57.statSync(path63.join(dir, ".git"), { throwIfNoEntry: false });
25746
25767
  if (stat3 && (stat3.isDirectory() || stat3.isFile())) return dir;
25747
25768
  } catch {
25748
25769
  }
25749
- const parent = path62.dirname(dir);
25770
+ const parent = path63.dirname(dir);
25750
25771
  if (parent === dir) return null;
25751
25772
  dir = parent;
25752
25773
  }
@@ -25786,7 +25807,7 @@ function deriveProjectIdentity(cwd = process.cwd()) {
25786
25807
  } catch {
25787
25808
  }
25788
25809
  const hash = crypto2.createHash("sha256").update(real).digest("hex");
25789
- return { projectKey: `path:${hash}`, projectLabel: path62.basename(real) || "project" };
25810
+ return { projectKey: `path:${hash}`, projectLabel: path63.basename(real) || "project" };
25790
25811
  }
25791
25812
 
25792
25813
  // src/services/project-env/index.ts
@@ -25799,7 +25820,7 @@ async function readIfExists(p2) {
25799
25820
  }
25800
25821
  async function syncProjectEnvUp(cwd, ctx) {
25801
25822
  if (!ctx.pluginAuthToken) return;
25802
- const content = await readIfExists(path63.join(cwd, ".env"));
25823
+ const content = await readIfExists(path64.join(cwd, ".env"));
25803
25824
  if (content == null) return;
25804
25825
  try {
25805
25826
  const { projectKey, projectLabel } = deriveProjectIdentity(cwd);
@@ -25821,7 +25842,7 @@ async function syncProjectEnvUp(cwd, ctx) {
25821
25842
  }
25822
25843
  async function restoreProjectEnvIfMissing(cwd, ctx) {
25823
25844
  if (!ctx.pluginAuthToken) return false;
25824
- const envPath = path63.join(cwd, ".env");
25845
+ const envPath = path64.join(cwd, ".env");
25825
25846
  if (await readIfExists(envPath) != null) return false;
25826
25847
  try {
25827
25848
  const { projectKey, projectLabel } = deriveProjectIdentity(cwd);
@@ -25832,7 +25853,7 @@ async function restoreProjectEnvIfMissing(cwd, ctx) {
25832
25853
  projectKey
25833
25854
  });
25834
25855
  if (!stored) return false;
25835
- const tmp = path63.join(cwd, ".env.codeam-restore.tmp");
25856
+ const tmp = path64.join(cwd, ".env.codeam-restore.tmp");
25836
25857
  await import_fs6.promises.writeFile(tmp, stored.content, { encoding: "utf8", mode: 384 });
25837
25858
  await import_fs6.promises.rename(tmp, envPath);
25838
25859
  log.info("project-env", `restored .env (${stored.keyCount} vars) for ${projectLabel}`);
@@ -25864,7 +25885,7 @@ async function resolveNamedTunnel(ctx, fetchTunnel) {
25864
25885
  }
25865
25886
 
25866
25887
  // src/services/preview/inspector-proxy.ts
25867
- var http7 = __toESM(require("http"));
25888
+ var http8 = __toESM(require("http"));
25868
25889
  var net4 = __toESM(require("net"));
25869
25890
  var INJECTION_SCAN_BUDGET_BYTES = 64 * 1024;
25870
25891
  var INJECTION_ANCHORS = ["</head>", "<body>", "</body>"];
@@ -25890,7 +25911,7 @@ function injectAt(html, script) {
25890
25911
  async function startInspectorProxy(opts) {
25891
25912
  const targetHost = opts.targetHost ?? "127.0.0.1";
25892
25913
  const upgraded = /* @__PURE__ */ new Set();
25893
- const server = http7.createServer((req, res) => {
25914
+ const server = http8.createServer((req, res) => {
25894
25915
  const one = (v) => Array.isArray(v) ? v[0] : v;
25895
25916
  const inject = isNavigation({
25896
25917
  accept: one(req.headers.accept),
@@ -25899,7 +25920,7 @@ async function startInspectorProxy(opts) {
25899
25920
  });
25900
25921
  const headers = { ...req.headers };
25901
25922
  if (inject) delete headers["accept-encoding"];
25902
- const upstream = http7.request(
25923
+ const upstream = http8.request(
25903
25924
  { host: targetHost, port: opts.targetPort, method: req.method, path: req.url, headers },
25904
25925
  (originRes) => {
25905
25926
  const outHeaders = { ...originRes.headers };
@@ -26412,7 +26433,7 @@ function normalizeDetectionForSpawn(detection, cwd) {
26412
26433
  if (args2.length === 0) return detection;
26413
26434
  const binName = args2[0];
26414
26435
  if (binName.startsWith("-")) return detection;
26415
- const binPath = path64.join(cwd, "node_modules", ".bin", binName);
26436
+ const binPath = path65.join(cwd, "node_modules", ".bin", binName);
26416
26437
  if (!fs59.existsSync(binPath)) return detection;
26417
26438
  return {
26418
26439
  ...detection,
@@ -26445,10 +26466,38 @@ async function runPreviewStart(args2) {
26445
26466
  });
26446
26467
  ctx.emitProgress("ENV_DETECTED", `${detection.framework}`);
26447
26468
  if (!await provisionDeps(ctx)) return;
26469
+ if (detection.framework === "Expo") {
26470
+ await runExpoBringUp(ctx);
26471
+ return;
26472
+ }
26448
26473
  const dev = await startDevServer(ctx);
26449
26474
  if (!dev) return;
26450
26475
  const tun = await establishTunnel(ctx, dev);
26451
26476
  if (!tun) return;
26477
+ announceReady(ctx, dev, tun);
26478
+ }
26479
+ async function runExpoBringUp(ctx) {
26480
+ const { detection, emit: emit2, emitProgress } = ctx;
26481
+ emitProgress("TUNNEL_STARTING", `cloudflared quick tunnel \u2192 Expo :${detection.port}`);
26482
+ const pub = await bringUpPublicUrl(ctx, detection.port);
26483
+ if (!pub.ok) {
26484
+ emit2(USER_EVENTS.PREVIEW_ERROR, { stage: "tunnel", message: pub.message });
26485
+ return;
26486
+ }
26487
+ const dev = await startDevServer(ctx, { [EXPO_PACKAGER_PROXY_URL_ENV]: pub.url });
26488
+ if (!dev) {
26489
+ killQuiet(pub.tunnel);
26490
+ return;
26491
+ }
26492
+ announceReady(ctx, dev, {
26493
+ url: expoGoDeepLink(pub.url),
26494
+ tunnel: pub.tunnel,
26495
+ // No inspector: a DOM inspector means nothing against a native app.
26496
+ inspector: null
26497
+ });
26498
+ }
26499
+ function announceReady(ctx, dev, tun) {
26500
+ const { sessionId, detection, emit: emit2 } = ctx;
26452
26501
  ctx.emitProgress("TUNNEL_READY", tun.url);
26453
26502
  registerPreview(sessionId, {
26454
26503
  sessionId,
@@ -26479,7 +26528,6 @@ async function provisionDeps(ctx) {
26479
26528
  pluginAuthToken: ctx.projectEnvAuth.pluginAuthToken
26480
26529
  });
26481
26530
  }
26482
- const needsExpoNgrok = isExpoTunnelCommand(detection.command, detection.args ?? []);
26483
26531
  const missingDeps = detectMissingNodeDeps(cwd);
26484
26532
  let preflightRan = false;
26485
26533
  if (missingDeps) {
@@ -26533,32 +26581,6 @@ async function provisionDeps(ctx) {
26533
26581
  }
26534
26582
  preflightRan = true;
26535
26583
  }
26536
- if (needsExpoNgrok) {
26537
- const ensured = await ensureExpoTunnelDeps({
26538
- hasNgrok: async () => ngrokResolvesFrom(cwd),
26539
- installNgrok: async () => {
26540
- emitProgress(
26541
- "SETUP_RUN",
26542
- `npm install --no-save ${EXPO_NGROK_SPEC} (Expo tunnel needs ngrok; not found)`
26543
- );
26544
- const r = await runSetupCommand(
26545
- "npm",
26546
- ["install", "--no-save", "--no-audit", "--no-fund", EXPO_NGROK_SPEC],
26547
- cwd,
26548
- detection.env,
26549
- { timeoutMs: INSTALL_TIMEOUT_MS2 }
26550
- );
26551
- return { ok: r.status === "ok", code: r.code };
26552
- }
26553
- });
26554
- if (!ensured.ok) {
26555
- emit2(USER_EVENTS.PREVIEW_ERROR, {
26556
- stage: "spawn",
26557
- message: `Expo's tunnel needs @expo/ngrok and installing it automatically failed (npm install --no-save ${EXPO_NGROK_SPEC}, exit ${ensured.code}). Install it in the project and try the preview again.`
26558
- });
26559
- return false;
26560
- }
26561
- }
26562
26584
  const normalizedSetup = (detection.setup_commands ?? []).map((entry) => {
26563
26585
  if (typeof entry === "string") {
26564
26586
  const parts = entry.trim().split(/\s+/).filter(Boolean);
@@ -26594,7 +26616,7 @@ async function provisionDeps(ctx) {
26594
26616
  }
26595
26617
  return true;
26596
26618
  }
26597
- async function startDevServer(ctx) {
26619
+ async function startDevServer(ctx, extraEnv = {}) {
26598
26620
  const { sessionId, detection, cwd, emit: emit2, emitProgress } = ctx;
26599
26621
  if (await isPortListening(detection.port)) {
26600
26622
  const raceExisting = activePreviews.get(sessionId);
@@ -26646,7 +26668,7 @@ async function startDevServer(ctx) {
26646
26668
  if (verdict.adopt) {
26647
26669
  log.info("preview", `adopting the dev server already serving on port ${detection.port}`);
26648
26670
  emitProgress("READY_DETECTED", `adopted the server already on port ${detection.port}`);
26649
- return { devServer: null, expoUrlRef: { current: null } };
26671
+ return { devServer: null };
26650
26672
  }
26651
26673
  emit2(USER_EVENTS.PREVIEW_ERROR, {
26652
26674
  stage: "spawn",
@@ -26656,13 +26678,16 @@ async function startDevServer(ctx) {
26656
26678
  }
26657
26679
  }
26658
26680
  await applyPreviewHostAllow(cwd);
26659
- const spawnable = normalizeDetectionForSpawn(detection, cwd);
26660
- emitProgress("BOOT_SEQUENCE", `${spawnable.command} ${spawnable.args.join(" ")}`);
26661
26681
  const isExpo = detection.framework === "Expo";
26662
- const expoDebugEnv = isExpo && isExpoTunnelCommand(detection.command, detection.args ?? []) ? expoTunnelDebugEnv(spawnable.env?.DEBUG ?? process.env.DEBUG) : {};
26682
+ const normalized = normalizeDetectionForSpawn(detection, cwd);
26683
+ const spawnable = isExpo ? {
26684
+ ...normalized,
26685
+ args: expoSpawnArgs(normalized.command, normalized.args, detection.port)
26686
+ } : normalized;
26687
+ emitProgress("BOOT_SEQUENCE", `${spawnable.command} ${spawnable.args.join(" ")}`);
26663
26688
  const devServer = (0, import_child_process23.spawn)(spawnable.command, spawnable.args, {
26664
26689
  cwd,
26665
- env: { ...process.env, ...spawnable.env ?? {}, ...expoDebugEnv },
26690
+ env: { ...process.env, ...spawnable.env ?? {}, ...extraEnv },
26666
26691
  stdio: ["ignore", "pipe", "pipe"],
26667
26692
  // POSIX: lead a new process group so teardown can SIGTERM the whole
26668
26693
  // tree. Dev servers fork worker children that bind the port; killing
@@ -26674,22 +26699,19 @@ async function startDevServer(ctx) {
26674
26699
  });
26675
26700
  emitProgress("BIND_PORT", String(detection.port));
26676
26701
  emitProgress("WAITING_FOR_READY", detection.ready_pattern);
26677
- const expoUrlRef = { current: null };
26678
26702
  let outputTail = "";
26679
26703
  const readyRe = isExpo ? new RegExp(
26680
- `(?:${compileReadyPattern(detection.ready_pattern).source})|exp:\\/\\/[^\\s]+\\.exp\\.(?:direct|host)|Tunnel URL:`,
26704
+ `(?:${compileReadyPattern(detection.ready_pattern).source})|Waiting on http:\\/\\/localhost:${detection.port}|Logs for your project will appear below`,
26681
26705
  "i"
26682
26706
  ) : compileReadyPattern(detection.ready_pattern);
26683
26707
  const isNextJs = /next/i.test(detection.framework);
26708
+ const portProbe = isExpo ? () => waitForExpoManifest(detection.port, { timeoutMs: 1e3, intervalMs: 250 }) : isNextJs ? () => waitForPortListening(detection.port, { timeoutMs: 1e3, intervalMs: 250 }) : void 0;
26684
26709
  const outcome = await waitForDevServerReady(devServer, readyRe, {
26685
26710
  timeoutMs: 12e4,
26686
26711
  onChunk: (s) => {
26687
26712
  outputTail = (outputTail + s).slice(-16e3);
26688
- if (!expoUrlRef.current && isExpo) {
26689
- expoUrlRef.current = parseExpoUrl(outputTail);
26690
- }
26691
26713
  },
26692
- portProbe: isNextJs ? () => waitForPortListening(detection.port, { timeoutMs: 1e3, intervalMs: 250 }) : void 0
26714
+ portProbe
26693
26715
  });
26694
26716
  if (outcome.kind === "exited") {
26695
26717
  killProcessTree(devServer, "SIGTERM");
@@ -26710,48 +26732,31 @@ async function startDevServer(ctx) {
26710
26732
  return null;
26711
26733
  }
26712
26734
  emitProgress("READY_DETECTED", `port ${detection.port}`);
26713
- return { devServer, expoUrlRef };
26735
+ return { devServer };
26714
26736
  }
26715
26737
  var MAX_TUNNEL_ATTEMPTS = 3;
26716
26738
  async function establishTunnel(ctx, dev) {
26717
26739
  const { detection, emit: emit2, emitProgress } = ctx;
26718
26740
  const { devServer } = dev;
26719
- emitProgress(
26720
- "TUNNEL_STARTING",
26721
- detection.framework === "Expo" ? "Expo (self-tunnelled)" : "cloudflared quick tunnel"
26722
- );
26723
- if (detection.framework === "Expo") {
26724
- if (!dev.expoUrlRef.current) {
26725
- const expoDeadline = Date.now() + 15e3;
26726
- while (!dev.expoUrlRef.current && Date.now() < expoDeadline) {
26727
- await new Promise((r) => setTimeout(r, 250));
26728
- }
26729
- }
26730
- const expoUrl = dev.expoUrlRef.current;
26731
- if (!expoUrl) {
26732
- if (devServer) killProcessTree(devServer, "SIGTERM");
26733
- emit2(USER_EVENTS.PREVIEW_ERROR, {
26734
- stage: "tunnel",
26735
- message: "Expo did not report a tunnel URL."
26736
- });
26737
- return null;
26738
- }
26739
- return { url: expoUrl, tunnel: null, inspector: null };
26740
- }
26741
+ emitProgress("TUNNEL_STARTING", "cloudflared quick tunnel");
26741
26742
  const inspection = await bringUpInspector(detection.port, {
26742
26743
  log: (m) => log.info("preview", m)
26743
26744
  });
26744
- const tunnelPort = inspection.port;
26745
+ const pub = await bringUpPublicUrl(ctx, inspection.port);
26746
+ if (!pub.ok) {
26747
+ if (devServer) killProcessTree(devServer, "SIGTERM");
26748
+ emit2(USER_EVENTS.PREVIEW_ERROR, { stage: "tunnel", message: pub.message });
26749
+ return null;
26750
+ }
26751
+ return { url: pub.url, tunnel: pub.tunnel, inspector: inspection.proxy };
26752
+ }
26753
+ async function bringUpPublicUrl(ctx, tunnelPort) {
26754
+ const { emitProgress } = ctx;
26745
26755
  let bin;
26746
26756
  try {
26747
26757
  bin = await resolveCloudflared();
26748
26758
  } catch (e) {
26749
- if (devServer) killProcessTree(devServer, "SIGTERM");
26750
- emit2(USER_EVENTS.PREVIEW_ERROR, {
26751
- stage: "tunnel",
26752
- message: e.message
26753
- });
26754
- return null;
26759
+ return { ok: false, message: e.message };
26755
26760
  }
26756
26761
  let tunnel = null;
26757
26762
  let parsedUrl = null;
@@ -26817,22 +26822,20 @@ async function establishTunnel(ctx, dev) {
26817
26822
  killQuiet(candidate);
26818
26823
  }
26819
26824
  }
26820
- if (!parsedUrl) {
26821
- if (devServer) killProcessTree(devServer, "SIGTERM");
26822
- emit2(USER_EVENTS.PREVIEW_ERROR, {
26823
- stage: "tunnel",
26825
+ if (!parsedUrl || !tunnel) {
26826
+ return {
26827
+ ok: false,
26824
26828
  message: `Tunnel did not become reachable after ${MAX_TUNNEL_ATTEMPTS} attempts (${lastTunnelErr}). Cloudflare Quick Tunnels occasionally fail to register \u2014 please retry.`
26825
- });
26826
- return null;
26829
+ };
26827
26830
  }
26828
- return { url: parsedUrl, tunnel, inspector: inspection.proxy };
26831
+ return { ok: true, url: parsedUrl, tunnel };
26829
26832
  }
26830
26833
 
26831
26834
  // src/beads/bd-adapter.ts
26832
26835
  var import_child_process24 = require("child_process");
26833
26836
  var fs60 = __toESM(require("fs"));
26834
26837
  var os48 = __toESM(require("os"));
26835
- var path65 = __toESM(require("path"));
26838
+ var path66 = __toESM(require("path"));
26836
26839
  var BD_PACKAGE = "@beads/bd";
26837
26840
  function resolveBundledBdBinary() {
26838
26841
  return _resolveSeam.resolveBundled();
@@ -26844,9 +26847,9 @@ function _defaultResolveBundled() {
26844
26847
  } catch {
26845
26848
  return null;
26846
26849
  }
26847
- const binDir = path65.join(path65.dirname(pkgJsonPath), "bin");
26850
+ const binDir = path66.join(path66.dirname(pkgJsonPath), "bin");
26848
26851
  const binaryName = process.platform === "win32" ? "bd.exe" : "bd";
26849
- const binaryPath = path65.join(binDir, binaryName);
26852
+ const binaryPath = path66.join(binDir, binaryName);
26850
26853
  try {
26851
26854
  fs60.accessSync(binaryPath, fs60.constants.F_OK);
26852
26855
  return binaryPath;
@@ -26858,11 +26861,11 @@ function resolveBdOnPath() {
26858
26861
  return _resolveSeam.resolveOnPath();
26859
26862
  }
26860
26863
  function _defaultResolveOnPath() {
26861
- const dirs = (process.env.PATH ?? "").split(path65.delimiter).filter(Boolean);
26864
+ const dirs = (process.env.PATH ?? "").split(path66.delimiter).filter(Boolean);
26862
26865
  const candidates = process.platform === "win32" ? ["bd.exe", "bd.cmd", "bd"] : ["bd"];
26863
26866
  for (const dir of dirs) {
26864
26867
  for (const candidate of candidates) {
26865
- const full = path65.join(dir, candidate);
26868
+ const full = path66.join(dir, candidate);
26866
26869
  try {
26867
26870
  fs60.accessSync(full, fs60.constants.F_OK);
26868
26871
  return full;
@@ -27043,7 +27046,7 @@ function coerceIssue(row, projectKey) {
27043
27046
  var import_child_process27 = require("child_process");
27044
27047
  var fs62 = __toESM(require("fs"));
27045
27048
  var os50 = __toESM(require("os"));
27046
- var path67 = __toESM(require("path"));
27049
+ var path68 = __toESM(require("path"));
27047
27050
 
27048
27051
  // src/beads/install-bd.ts
27049
27052
  var import_child_process25 = require("child_process");
@@ -27110,7 +27113,7 @@ async function installBd(platform3 = process.platform) {
27110
27113
  var import_child_process26 = require("child_process");
27111
27114
  var fs61 = __toESM(require("fs"));
27112
27115
  var os49 = __toESM(require("os"));
27113
- var path66 = __toESM(require("path"));
27116
+ var path67 = __toESM(require("path"));
27114
27117
  var DOLT_INSTALL_SH_URL = "https://github.com/dolthub/dolt/releases/latest/download/install.sh";
27115
27118
  var DOLT_MSI_URL = "https://github.com/dolthub/dolt/releases/latest/download/dolt-windows-amd64.msi";
27116
27119
  function resolveDoltInstallStrategy(platform3) {
@@ -27217,7 +27220,7 @@ function doltBinaryNames(platform3) {
27217
27220
  return platform3 === "win32" ? ["dolt.exe", "dolt.cmd", "dolt"] : ["dolt"];
27218
27221
  }
27219
27222
  function knownDoltDirs(platform3) {
27220
- const P3 = platform3 === "win32" ? path66.win32 : path66.posix;
27223
+ const P3 = platform3 === "win32" ? path67.win32 : path67.posix;
27221
27224
  const home = _doltPathSeam.homedir();
27222
27225
  if (platform3 === "win32") {
27223
27226
  return [
@@ -27233,7 +27236,7 @@ function knownDoltDirs(platform3) {
27233
27236
  ].filter(Boolean);
27234
27237
  }
27235
27238
  function ensureDoltResolvable(platform3 = process.platform) {
27236
- const P3 = platform3 === "win32" ? path66.win32 : path66.posix;
27239
+ const P3 = platform3 === "win32" ? path67.win32 : path67.posix;
27237
27240
  const delim = platform3 === "win32" ? ";" : ":";
27238
27241
  const names = doltBinaryNames(platform3);
27239
27242
  const pathDirs = _doltPathSeam.getPath().split(delim).filter(Boolean);
@@ -27441,9 +27444,9 @@ var _linkSeam = {
27441
27444
  * which `linkBdOntoPath` creates if missing.
27442
27445
  */
27443
27446
  cliBinDir: () => {
27444
- const pathDirs = (process.env.PATH ?? "").split(path67.delimiter).filter(Boolean);
27447
+ const pathDirs = (process.env.PATH ?? "").split(path68.delimiter).filter(Boolean);
27445
27448
  const home = _linkSeam.homedir();
27446
- const localBin = home ? path67.join(home, ".local", "bin") : null;
27449
+ const localBin = home ? path68.join(home, ".local", "bin") : null;
27447
27450
  if (localBin) {
27448
27451
  try {
27449
27452
  _linkSeam.ensureDir(localBin);
@@ -27453,16 +27456,16 @@ var _linkSeam = {
27453
27456
  const candidates = [];
27454
27457
  if (localBin) candidates.push(localBin);
27455
27458
  try {
27456
- candidates.push(path67.dirname(process.execPath));
27459
+ candidates.push(path68.dirname(process.execPath));
27457
27460
  } catch {
27458
27461
  }
27459
27462
  candidates.push("/usr/local/bin");
27460
27463
  const entry = process.argv[1];
27461
27464
  if (entry) {
27462
27465
  try {
27463
- candidates.push(path67.dirname(fs62.realpathSync(entry)));
27466
+ candidates.push(path68.dirname(fs62.realpathSync(entry)));
27464
27467
  } catch {
27465
- candidates.push(path67.dirname(entry));
27468
+ candidates.push(path68.dirname(entry));
27466
27469
  }
27467
27470
  }
27468
27471
  const onPathWritable = candidates.find(
@@ -27487,7 +27490,7 @@ function linkBdOntoPath(binaryPath) {
27487
27490
  const binDir = _linkSeam.cliBinDir();
27488
27491
  if (!binDir) return;
27489
27492
  _linkSeam.ensureDir(binDir);
27490
- const linkPath = path67.join(binDir, "bd");
27493
+ const linkPath = path68.join(binDir, "bd");
27491
27494
  if (linkPath === binaryPath) return;
27492
27495
  const current2 = _linkSeam.readlink(linkPath);
27493
27496
  if (current2 === binaryPath) return;
@@ -27682,7 +27685,7 @@ function dedupeRecipes(agents) {
27682
27685
 
27683
27686
  // src/beads/watcher.ts
27684
27687
  var crypto4 = __toESM(require("crypto"));
27685
- var path68 = __toESM(require("path"));
27688
+ var path69 = __toESM(require("path"));
27686
27689
  var API_BASE6 = resolveApiBaseUrl();
27687
27690
  var DEBOUNCE_MS2 = 400;
27688
27691
  var ZERO_SUMMARY = {
@@ -27706,7 +27709,7 @@ var BeadsWatcher = class {
27706
27709
  constructor(opts) {
27707
27710
  this.opts = opts;
27708
27711
  this.bd = opts.adapter ?? new BdAdapter({ cwd: opts.cwd, beadsDir: opts.beadsDir });
27709
- this.feedPath = opts.feedPath ?? path68.join(opts.cwd ?? process.cwd(), ".beads", "last-touched");
27712
+ this.feedPath = opts.feedPath ?? path69.join(opts.cwd ?? process.cwd(), ".beads", "last-touched");
27710
27713
  this.apiBase = opts.apiBaseUrl ?? API_BASE6;
27711
27714
  }
27712
27715
  opts;
@@ -28205,7 +28208,7 @@ function cleanupAttachmentTempFiles() {
28205
28208
  function saveFilesTemp(files) {
28206
28209
  return files.filter(({ base64 }) => base64 && base64.length > 0).map(({ filename, base64 }) => {
28207
28210
  const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
28208
- const tmpPath = path71.join(os54.tmpdir(), `codeam-${(0, import_crypto3.randomUUID)()}-${safeName}`);
28211
+ const tmpPath = path72.join(os54.tmpdir(), `codeam-${(0, import_crypto3.randomUUID)()}-${safeName}`);
28209
28212
  fs65.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
28210
28213
  pendingAttachmentFiles.add(tmpPath);
28211
28214
  return tmpPath;
@@ -28441,7 +28444,7 @@ var listFiles = async (ctx, cmd, parsed) => {
28441
28444
  await ctx.relay.sendResult(cmd.id, "completed", result);
28442
28445
  };
28443
28446
  var envReadH = async (ctx, cmd) => {
28444
- const envPath = path71.join(process.cwd(), ".env");
28447
+ const envPath = path72.join(process.cwd(), ".env");
28445
28448
  await restoreProjectEnvIfMissing(process.cwd(), ctx);
28446
28449
  try {
28447
28450
  const raw = await fs65.promises.readFile(envPath, "utf8");
@@ -28473,7 +28476,7 @@ var envParseH = async (ctx, cmd, parsed) => {
28473
28476
  const existing = /* @__PURE__ */ new Map();
28474
28477
  if (!replace) {
28475
28478
  try {
28476
- const raw = await fs65.promises.readFile(path71.join(process.cwd(), ".env"), "utf8");
28479
+ const raw = await fs65.promises.readFile(path72.join(process.cwd(), ".env"), "utf8");
28477
28480
  for (const v of parseDotenv(raw)) existing.set(v.key, v.value);
28478
28481
  } catch {
28479
28482
  }
@@ -28513,8 +28516,8 @@ var envWriteH = async (ctx, cmd, parsed) => {
28513
28516
  }
28514
28517
  seen.add(v.key);
28515
28518
  }
28516
- const envPath = path71.join(process.cwd(), ".env");
28517
- const tmpPath = path71.join(process.cwd(), ".env.codeam.tmp");
28519
+ const envPath = path72.join(process.cwd(), ".env");
28520
+ const tmpPath = path72.join(process.cwd(), ".env.codeam.tmp");
28518
28521
  try {
28519
28522
  await fs65.promises.writeFile(tmpPath, serializeDotenv(vars), "utf8");
28520
28523
  await fs65.promises.rename(tmpPath, envPath);
@@ -29051,7 +29054,7 @@ function buildNpmInstallInvocation(opts) {
29051
29054
  const execPath = opts?.execPath ?? process.execPath;
29052
29055
  const exists2 = opts?.existsSync ?? fs65.existsSync;
29053
29056
  const platform3 = opts?.platform ?? process.platform;
29054
- const p2 = platform3 === "win32" ? path71.win32 : path71.posix;
29057
+ const p2 = platform3 === "win32" ? path72.win32 : path72.posix;
29055
29058
  const normalized = entryScript.split(/[\\/]/).join("/");
29056
29059
  const marker = "/lib/node_modules/codeam-cli/";
29057
29060
  const markerIdx = normalized.indexOf(marker);
@@ -29073,7 +29076,7 @@ function isPermissionError(stderr) {
29073
29076
  function resolveGlobalNodeModulesDir(opts) {
29074
29077
  const entryScript = opts?.entryScript ?? process.argv[1] ?? "";
29075
29078
  const platform3 = opts?.platform ?? process.platform;
29076
- const p2 = platform3 === "win32" ? path71.win32 : path71.posix;
29079
+ const p2 = platform3 === "win32" ? path72.win32 : path72.posix;
29077
29080
  const marker = "/lib/node_modules/codeam-cli/";
29078
29081
  const markerIdx = entryScript.split(/[\\/]/).join("/").indexOf(marker);
29079
29082
  if (markerIdx <= 0) return null;
@@ -29095,7 +29098,7 @@ function sweepStaleCliStagingDirs(nodeModulesDir, now = Date.now(), deps) {
29095
29098
  }
29096
29099
  for (const name of entries) {
29097
29100
  if (!/^\.codeam-cli-/.test(name)) continue;
29098
- const full = path71.join(nodeModulesDir, name);
29101
+ const full = path72.join(nodeModulesDir, name);
29099
29102
  try {
29100
29103
  const st3 = statSync17(full);
29101
29104
  if (now - st3.mtimeMs < STALE_STAGING_AGE_MS) continue;
@@ -30060,11 +30063,11 @@ function resolveTokenValue(args2) {
30060
30063
  }
30061
30064
  const fileFlag = args2.find((a) => a.startsWith("--token-file="));
30062
30065
  if (fileFlag) {
30063
- const path95 = fileFlag.slice("--token-file=".length);
30066
+ const path96 = fileFlag.slice("--token-file=".length);
30064
30067
  try {
30065
- const content = fs66.readFileSync(path95, "utf8").trim();
30066
- if (content.length === 0) fail(`--token-file ${path95} is empty`);
30067
- rmIfExistsQuiet(path95);
30068
+ const content = fs66.readFileSync(path96, "utf8").trim();
30069
+ if (content.length === 0) fail(`--token-file ${path96} is empty`);
30070
+ rmIfExistsQuiet(path96);
30068
30071
  return content;
30069
30072
  } catch (err) {
30070
30073
  fail(`Could not read --token-file: ${err.message}`);
@@ -30156,12 +30159,12 @@ async function claim(token, pluginId, pluginSecretHash) {
30156
30159
  }
30157
30160
  }
30158
30161
  function pairAutoLockPath() {
30159
- return path72.join(os55.homedir(), ".codeam", "pair-auto.lock");
30162
+ return path73.join(os55.homedir(), ".codeam", "pair-auto.lock");
30160
30163
  }
30161
30164
  var procRoot = "/proc";
30162
30165
  function readProcFile(rel) {
30163
30166
  try {
30164
- return fs66.readFileSync(path72.join(procRoot, rel), "utf8");
30167
+ return fs66.readFileSync(path73.join(procRoot, rel), "utf8");
30165
30168
  } catch {
30166
30169
  return void 0;
30167
30170
  }
@@ -30237,12 +30240,12 @@ function releaseOwnLock(lockPath) {
30237
30240
  }
30238
30241
  function daemonLockPath(sessionId) {
30239
30242
  const safe = sessionId.replace(/[^a-zA-Z0-9_-]/g, "_");
30240
- return path72.join(os55.homedir(), ".codeam", `daemon-${safe}.lock`);
30243
+ return path73.join(os55.homedir(), ".codeam", `daemon-${safe}.lock`);
30241
30244
  }
30242
30245
  function acquireDaemonLock(sessionId) {
30243
30246
  const lockPath = daemonLockPath(sessionId);
30244
30247
  try {
30245
- fs66.mkdirSync(path72.dirname(lockPath), { recursive: true });
30248
+ fs66.mkdirSync(path73.dirname(lockPath), { recursive: true });
30246
30249
  try {
30247
30250
  fs66.writeFileSync(lockPath, ownLockBody(), { flag: "wx" });
30248
30251
  } catch (e) {
@@ -30268,7 +30271,7 @@ function acquireDaemonLock(sessionId) {
30268
30271
  function acquireSingletonLock() {
30269
30272
  const lockPath = pairAutoLockPath();
30270
30273
  try {
30271
- fs66.mkdirSync(path72.dirname(lockPath), { recursive: true });
30274
+ fs66.mkdirSync(path73.dirname(lockPath), { recursive: true });
30272
30275
  try {
30273
30276
  fs66.writeFileSync(lockPath, ownLockBody(), { flag: "wx" });
30274
30277
  } catch (e) {
@@ -30722,7 +30725,7 @@ var AgentService = class _AgentService {
30722
30725
  };
30723
30726
 
30724
30727
  // src/agents/acp/adapters.ts
30725
- var path73 = __toESM(require("path"));
30728
+ var path74 = __toESM(require("path"));
30726
30729
 
30727
30730
  // src/agents/kimi/installer.ts
30728
30731
  var import_node_child_process27 = require("child_process");
@@ -30842,13 +30845,13 @@ function resolveBin(pkgName, binName) {
30842
30845
  try {
30843
30846
  const manifestPath = require_.resolve(`${pkgName}/package.json`);
30844
30847
  const manifest = require_(`${pkgName}/package.json`);
30845
- const pkgDir = path73.dirname(manifestPath);
30848
+ const pkgDir = path74.dirname(manifestPath);
30846
30849
  const bin = manifest.bin;
30847
30850
  if (!bin) return null;
30848
- if (typeof bin === "string") return path73.resolve(pkgDir, bin);
30851
+ if (typeof bin === "string") return path74.resolve(pkgDir, bin);
30849
30852
  const target = binName ?? Object.keys(bin)[0];
30850
30853
  if (!target || !bin[target]) return null;
30851
- return path73.resolve(pkgDir, bin[target]);
30854
+ return path74.resolve(pkgDir, bin[target]);
30852
30855
  } catch {
30853
30856
  return null;
30854
30857
  }
@@ -31031,14 +31034,14 @@ async function resolveAcpAdapterWithRetry(agent, opts = {}) {
31031
31034
  var import_node_crypto11 = require("crypto");
31032
31035
  var fs78 = __toESM(require("fs"));
31033
31036
  var os62 = __toESM(require("os"));
31034
- var path86 = __toESM(require("path"));
31037
+ var path87 = __toESM(require("path"));
31035
31038
 
31036
31039
  // src/services/history.service.ts
31037
31040
  var fs67 = __toESM(require("fs"));
31038
- var path74 = __toESM(require("path"));
31041
+ var path75 = __toESM(require("path"));
31039
31042
  var os56 = __toESM(require("os"));
31040
31043
  var https7 = __toESM(require("https"));
31041
- var http8 = __toESM(require("http"));
31044
+ var http9 = __toESM(require("http"));
31042
31045
  var import_zod2 = require("zod");
31043
31046
  var historyRecordSchema = import_zod2.z.object({
31044
31047
  type: import_zod2.z.string().optional(),
@@ -31141,7 +31144,7 @@ function postWithStatus(endpoint, body, pluginAuthToken) {
31141
31144
  return new Promise((resolve11) => {
31142
31145
  const payload = JSON.stringify(body);
31143
31146
  const u2 = new URL(`${API_BASE8}${endpoint}`);
31144
- const transport = u2.protocol === "https:" ? https7 : http8;
31147
+ const transport = u2.protocol === "https:" ? https7 : http9;
31145
31148
  const req = transport.request(
31146
31149
  {
31147
31150
  hostname: u2.hostname,
@@ -31251,7 +31254,7 @@ var HistoryService = class _HistoryService {
31251
31254
  return this._quotaPercent === null || Date.now() - this._quotaFetchedAt > ttlMs;
31252
31255
  }
31253
31256
  get projectDir() {
31254
- return this.runtime.resolveHistoryDir(this.cwd) ?? path74.join(os56.homedir(), ".claude", "projects", encodeCwd(this.cwd));
31257
+ return this.runtime.resolveHistoryDir(this.cwd) ?? path75.join(os56.homedir(), ".claude", "projects", encodeCwd(this.cwd));
31255
31258
  }
31256
31259
  /** Set the current Claude conversation ID (extracted from /cost command or session start) */
31257
31260
  setCurrentConversationId(id) {
@@ -31263,7 +31266,7 @@ var HistoryService = class _HistoryService {
31263
31266
  /** Return the current message count in the active conversation. */
31264
31267
  getCurrentMessageCount() {
31265
31268
  if (!this.currentConversationId) return 0;
31266
- const filePath = path74.join(this.projectDir, `${this.currentConversationId}.jsonl`);
31269
+ const filePath = path75.join(this.projectDir, `${this.currentConversationId}.jsonl`);
31267
31270
  return parseJsonl(filePath).length;
31268
31271
  }
31269
31272
  /**
@@ -31274,7 +31277,7 @@ var HistoryService = class _HistoryService {
31274
31277
  const deadline = Date.now() + timeoutMs;
31275
31278
  while (Date.now() < deadline) {
31276
31279
  if (!this.currentConversationId) return null;
31277
- const filePath = path74.join(this.projectDir, `${this.currentConversationId}.jsonl`);
31280
+ const filePath = path75.join(this.projectDir, `${this.currentConversationId}.jsonl`);
31278
31281
  const messages = parseJsonl(filePath);
31279
31282
  if (messages.length > previousCount) {
31280
31283
  for (let i = messages.length - 1; i >= previousCount; i--) {
@@ -31302,14 +31305,14 @@ var HistoryService = class _HistoryService {
31302
31305
  try {
31303
31306
  const files = fs67.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
31304
31307
  try {
31305
- const stat3 = fs67.statSync(path74.join(dir, e.name));
31308
+ const stat3 = fs67.statSync(path75.join(dir, e.name));
31306
31309
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
31307
31310
  } catch {
31308
31311
  return { name: e.name, mtime: 0, birthtime: 0 };
31309
31312
  }
31310
31313
  }).filter((f) => f.birthtime >= cutoff).sort((a, b) => b.mtime - a.mtime);
31311
31314
  if (files.length > 0) {
31312
- this.currentConversationId = path74.basename(files[0].name, ".jsonl");
31315
+ this.currentConversationId = path75.basename(files[0].name, ".jsonl");
31313
31316
  }
31314
31317
  } catch {
31315
31318
  }
@@ -31349,7 +31352,7 @@ var HistoryService = class _HistoryService {
31349
31352
  }
31350
31353
  const files = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
31351
31354
  try {
31352
- const stat3 = fs67.statSync(path74.join(dir, e.name));
31355
+ const stat3 = fs67.statSync(path75.join(dir, e.name));
31353
31356
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
31354
31357
  } catch {
31355
31358
  return { name: e.name, mtime: 0, birthtime: 0 };
@@ -31358,7 +31361,7 @@ var HistoryService = class _HistoryService {
31358
31361
  if (files.length === 0) return null;
31359
31362
  const targetFile = this.currentConversationId ? `${this.currentConversationId}.jsonl` : files[0].name;
31360
31363
  if (!files.some((f) => f.name === targetFile)) return null;
31361
- return this.extractUsageFromFile(path74.join(dir, targetFile));
31364
+ return this.extractUsageFromFile(path75.join(dir, targetFile));
31362
31365
  }
31363
31366
  extractUsageFromFile(filePath) {
31364
31367
  let raw;
@@ -31417,7 +31420,7 @@ var HistoryService = class _HistoryService {
31417
31420
  try {
31418
31421
  files = fs67.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
31419
31422
  try {
31420
- return fs67.statSync(path74.join(projectDir, f)).mtimeMs >= monthStartMs;
31423
+ return fs67.statSync(path75.join(projectDir, f)).mtimeMs >= monthStartMs;
31421
31424
  } catch {
31422
31425
  return false;
31423
31426
  }
@@ -31428,7 +31431,7 @@ var HistoryService = class _HistoryService {
31428
31431
  for (const file of files) {
31429
31432
  let raw;
31430
31433
  try {
31431
- raw = fs67.readFileSync(path74.join(projectDir, file), "utf8");
31434
+ raw = fs67.readFileSync(path75.join(projectDir, file), "utf8");
31432
31435
  } catch {
31433
31436
  continue;
31434
31437
  }
@@ -31507,7 +31510,7 @@ var HistoryService = class _HistoryService {
31507
31510
  if (this.runtime.resolveHistoryFile) {
31508
31511
  return this.runtime.resolveHistoryFile(this.cwd, sessionId);
31509
31512
  }
31510
- return path74.join(this.projectDir, `${sessionId}.jsonl`);
31513
+ return path75.join(this.projectDir, `${sessionId}.jsonl`);
31511
31514
  }
31512
31515
  /**
31513
31516
  * Parse a conversation's messages from disk, agent-aware. Claude uses the
@@ -31545,7 +31548,7 @@ var HistoryService = class _HistoryService {
31545
31548
  };
31546
31549
  });
31547
31550
  }
31548
- return parseJsonl(path74.join(this.projectDir, `${sessionId}.jsonl`));
31551
+ return parseJsonl(path75.join(this.projectDir, `${sessionId}.jsonl`));
31549
31552
  }
31550
31553
  /** One in-flight full upload per conversation — the baton mirror and a
31551
31554
  * `get_conversation` used to upload the same transcript concurrently. */
@@ -31705,7 +31708,7 @@ var import_node_child_process29 = require("child_process");
31705
31708
  var fs68 = __toESM(require("fs/promises"));
31706
31709
  var fsSync = __toESM(require("fs"));
31707
31710
  var os58 = __toESM(require("os"));
31708
- var path76 = __toESM(require("path"));
31711
+ var path77 = __toESM(require("path"));
31709
31712
  var import_node_stream = require("stream");
31710
31713
 
31711
31714
  // ../../node_modules/@agentclientprotocol/sdk/dist/schema/index.js
@@ -35731,7 +35734,7 @@ function createIdleTimeout(idleMs, makeError, activeIdleMs = idleMs) {
35731
35734
  }
35732
35735
 
35733
35736
  // src/agents/acp/internal-paths.ts
35734
- var path75 = __toESM(require("path"));
35737
+ var path76 = __toESM(require("path"));
35735
35738
  var os57 = __toESM(require("os"));
35736
35739
  var INTERNAL_TOKENS = [".codeam", "house-claude"];
35737
35740
  var PROSE_ONLY_TOOL_KINDS = /* @__PURE__ */ new Set(["think", "switch_mode"]);
@@ -35746,11 +35749,11 @@ function textReferencesInternal(text) {
35746
35749
  }
35747
35750
  function pathIsInternal(p2, homeDir2 = os57.homedir()) {
35748
35751
  if (!p2) return false;
35749
- const abs = path75.resolve(p2);
35750
- const home = path75.resolve(homeDir2);
35751
- const within = (root) => abs === root || abs.startsWith(root + path75.sep);
35752
- if (within(path75.join(home, ".codeam", "self-hosted"))) return false;
35753
- return within(path75.join(home, ".codeam")) || within(path75.join(home, ".beads")) || abs === path75.join(home, ".codeam-host.log") || abs.includes(`${path75.sep}house-claude${path75.sep}`) || abs.endsWith(`${path75.sep}house-claude`);
35752
+ const abs = path76.resolve(p2);
35753
+ const home = path76.resolve(homeDir2);
35754
+ const within = (root) => abs === root || abs.startsWith(root + path76.sep);
35755
+ if (within(path76.join(home, ".codeam", "self-hosted"))) return false;
35756
+ return within(path76.join(home, ".codeam")) || within(path76.join(home, ".beads")) || abs === path76.join(home, ".codeam-host.log") || abs.includes(`${path76.sep}house-claude${path76.sep}`) || abs.endsWith(`${path76.sep}house-claude`);
35754
35757
  }
35755
35758
  function toolCallReferencesInternal(call, homeDir2) {
35756
35759
  if (call.locations?.some((l) => pathIsInternal(l.path, homeDir2))) return true;
@@ -36948,25 +36951,25 @@ function knownAgentBinaryDirs() {
36948
36951
  out2.push("/tmp/codeam-node20/bin");
36949
36952
  for (const root of [
36950
36953
  "/usr/local/share/nvm/versions/node",
36951
- path76.join(home, ".nvm/versions/node")
36954
+ path77.join(home, ".nvm/versions/node")
36952
36955
  ]) {
36953
36956
  try {
36954
36957
  for (const child of fsSync.readdirSync(root)) {
36955
- out2.push(path76.join(root, child, "bin"));
36958
+ out2.push(path77.join(root, child, "bin"));
36956
36959
  }
36957
36960
  } catch {
36958
36961
  }
36959
36962
  }
36960
- out2.push(path76.join(home, ".volta/bin"));
36963
+ out2.push(path77.join(home, ".volta/bin"));
36961
36964
  out2.push("/usr/local/bin");
36962
36965
  out2.push("/usr/bin");
36963
- out2.push(path76.join(home, ".local/bin"));
36964
- out2.push(path76.join(home, "bin"));
36966
+ out2.push(path77.join(home, ".local/bin"));
36967
+ out2.push(path77.join(home, "bin"));
36965
36968
  out2.push(...agentInstallBinDirs());
36966
36969
  if (process.platform === "win32") {
36967
36970
  const { LOCALAPPDATA, APPDATA } = process.env;
36968
- if (LOCALAPPDATA) out2.push(path76.join(LOCALAPPDATA, "cursor-agent"));
36969
- if (APPDATA) out2.push(path76.join(APPDATA, "npm"));
36971
+ if (LOCALAPPDATA) out2.push(path77.join(LOCALAPPDATA, "cursor-agent"));
36972
+ if (APPDATA) out2.push(path77.join(APPDATA, "npm"));
36970
36973
  }
36971
36974
  return out2.filter((p2) => {
36972
36975
  try {
@@ -36977,7 +36980,7 @@ function knownAgentBinaryDirs() {
36977
36980
  });
36978
36981
  }
36979
36982
  function expandPathForAgentBinaries(existingPath) {
36980
- const existing = new Set(existingPath.split(path76.delimiter).filter((p2) => p2.length > 0));
36983
+ const existing = new Set(existingPath.split(path77.delimiter).filter((p2) => p2.length > 0));
36981
36984
  const additions = [];
36982
36985
  for (const dir of knownAgentBinaryDirs()) {
36983
36986
  if (!existing.has(dir)) {
@@ -36986,7 +36989,7 @@ function expandPathForAgentBinaries(existingPath) {
36986
36989
  }
36987
36990
  }
36988
36991
  if (additions.length === 0) return existingPath;
36989
- return [...additions, existingPath].filter((p2) => p2.length > 0).join(path76.delimiter);
36992
+ return [...additions, existingPath].filter((p2) => p2.length > 0).join(path77.delimiter);
36990
36993
  }
36991
36994
 
36992
36995
  // src/agents/acp/headroom-budget-proxy.ts
@@ -37222,7 +37225,7 @@ async function performAgentSwitch(deps, rawAgentId, fastPath = {}) {
37222
37225
  }
37223
37226
 
37224
37227
  // src/services/streaming/transport.ts
37225
- var http9 = __toESM(require("http"));
37228
+ var http10 = __toESM(require("http"));
37226
37229
  var https8 = __toESM(require("https"));
37227
37230
  var _transport4 = {
37228
37231
  post: _post3,
@@ -37232,7 +37235,7 @@ function _post3(url2, headers, payload) {
37232
37235
  return new Promise((resolve11, reject) => {
37233
37236
  let settled = false;
37234
37237
  const u2 = new URL(url2);
37235
- const lib = u2.protocol === "https:" ? https8 : http9;
37238
+ const lib = u2.protocol === "https:" ? https8 : http10;
37236
37239
  const req = lib.request(
37237
37240
  {
37238
37241
  hostname: u2.hostname,
@@ -37274,7 +37277,7 @@ function _get(url2, headers) {
37274
37277
  return new Promise((resolve11, reject) => {
37275
37278
  let settled = false;
37276
37279
  const u2 = new URL(url2);
37277
- const lib = u2.protocol === "https:" ? https8 : http9;
37280
+ const lib = u2.protocol === "https:" ? https8 : http10;
37278
37281
  const req = lib.request(
37279
37282
  {
37280
37283
  hostname: u2.hostname,
@@ -37911,12 +37914,12 @@ function withholdTrailingPartialFenceMarker(text) {
37911
37914
  var import_child_process30 = require("child_process");
37912
37915
  var fs69 = __toESM(require("fs"));
37913
37916
  var os59 = __toESM(require("os"));
37914
- var path77 = __toESM(require("path"));
37917
+ var path78 = __toESM(require("path"));
37915
37918
  var _onboardingSeam = {
37916
- markerPath: (sessionId) => path77.join(os59.homedir(), ".codeam", "welcomed", `${sessionId}.done`),
37919
+ markerPath: (sessionId) => path78.join(os59.homedir(), ".codeam", "welcomed", `${sessionId}.done`),
37917
37920
  exists: (p2) => fs69.existsSync(p2),
37918
37921
  write: (p2) => {
37919
- fs69.mkdirSync(path77.dirname(p2), { recursive: true });
37922
+ fs69.mkdirSync(path78.dirname(p2), { recursive: true });
37920
37923
  fs69.writeFileSync(p2, "");
37921
37924
  },
37922
37925
  disabled: () => {
@@ -37954,7 +37957,7 @@ function resolveRepoName(cwd) {
37954
37957
  if (name) return name;
37955
37958
  }
37956
37959
  }
37957
- const base = path77.basename(cwd || "");
37960
+ const base = path78.basename(cwd || "");
37958
37961
  if (base && !isUuid(base)) return base;
37959
37962
  return "this project";
37960
37963
  }
@@ -38287,12 +38290,12 @@ var import_crypto5 = require("crypto");
38287
38290
  // src/services/turn-files/git-changeset.ts
38288
38291
  var import_child_process31 = require("child_process");
38289
38292
  var fs71 = __toESM(require("fs/promises"));
38290
- var path79 = __toESM(require("path"));
38293
+ var path80 = __toESM(require("path"));
38291
38294
 
38292
38295
  // src/services/turn-files/review-ignore.ts
38293
38296
  var import_ignore2 = __toESM(require("ignore"));
38294
38297
  var fs70 = __toESM(require("fs"));
38295
- var path78 = __toESM(require("path"));
38298
+ var path79 = __toESM(require("path"));
38296
38299
  var CURATED_REVIEW_IGNORE = [
38297
38300
  // Google Cloud SDK (the incident) — installs a huge python tree.
38298
38301
  "google-cloud-sdk/",
@@ -38331,7 +38334,7 @@ var CURATED_REVIEW_IGNORE = [
38331
38334
  function makeReviewIgnore(repoRoot) {
38332
38335
  const ig = (0, import_ignore2.default)().add(CURATED_REVIEW_IGNORE);
38333
38336
  try {
38334
- const custom = fs70.readFileSync(path78.join(repoRoot, ".codeam", "reviewignore"), "utf8");
38337
+ const custom = fs70.readFileSync(path79.join(repoRoot, ".codeam", "reviewignore"), "utf8");
38335
38338
  ig.add(custom);
38336
38339
  } catch {
38337
38340
  }
@@ -38376,7 +38379,7 @@ async function collectRepoChangeset(opts) {
38376
38379
  let stats;
38377
38380
  if (!truncated && row.fileStatus === "added" && numstatEntry === void 0) {
38378
38381
  const lineCount = await readUntrackedLineCount(
38379
- path79.join(opts.repoRoot, row.filePath)
38382
+ path80.join(opts.repoRoot, row.filePath)
38380
38383
  );
38381
38384
  stats = { added: lineCount, removed: 0 };
38382
38385
  } else {
@@ -38518,8 +38521,8 @@ async function discoverRepos(workingDir, maxDepth = 4) {
38518
38521
  if (hasGit) {
38519
38522
  out2.push({
38520
38523
  repoRoot: dir,
38521
- repoPath: path79.relative(workingDir, dir),
38522
- repoName: path79.basename(dir)
38524
+ repoPath: path80.relative(workingDir, dir),
38525
+ repoName: path80.basename(dir)
38523
38526
  });
38524
38527
  return;
38525
38528
  }
@@ -38527,14 +38530,14 @@ async function discoverRepos(workingDir, maxDepth = 4) {
38527
38530
  if (!entry.isDirectory) continue;
38528
38531
  if (entry.name === "node_modules") continue;
38529
38532
  if (entry.name === "dist" || entry.name === "build") continue;
38530
- await walk(path79.join(dir, entry.name), depth + 1);
38533
+ await walk(path80.join(dir, entry.name), depth + 1);
38531
38534
  }
38532
38535
  }
38533
38536
  }
38534
38537
 
38535
38538
  // src/services/turn-files/files-outbox.ts
38536
38539
  var fs72 = __toESM(require("fs/promises"));
38537
- var path80 = __toESM(require("path"));
38540
+ var path81 = __toESM(require("path"));
38538
38541
  var import_os12 = require("os");
38539
38542
  var HOME_OUTBOX_DIR = ".codeam/outbox";
38540
38543
  var MAX_AGE_MS = 24 * 60 * 60 * 1e3;
@@ -38567,15 +38570,15 @@ var FilesOutbox = class {
38567
38570
  backoffIndex = 0;
38568
38571
  stopped = false;
38569
38572
  constructor(opts) {
38570
- const base = opts.baseDir ?? path80.join(homeDir(), HOME_OUTBOX_DIR);
38571
- this.filePath = path80.join(base, `${opts.sessionId}.jsonl`);
38573
+ const base = opts.baseDir ?? path81.join(homeDir(), HOME_OUTBOX_DIR);
38574
+ this.filePath = path81.join(base, `${opts.sessionId}.jsonl`);
38572
38575
  this.post = opts.post;
38573
38576
  this.autoSchedule = opts.autoSchedule !== false;
38574
38577
  }
38575
38578
  /** Persist the entry to disk and trigger a flush. Returns once the
38576
38579
  * line is durable on disk (not once the POST succeeds). */
38577
38580
  async enqueue(entry) {
38578
- await fs72.mkdir(path80.dirname(this.filePath), { recursive: true });
38581
+ await fs72.mkdir(path81.dirname(this.filePath), { recursive: true });
38579
38582
  await fs72.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
38580
38583
  this.backoffIndex = 0;
38581
38584
  if (this.autoSchedule) this.scheduleFlush(0);
@@ -39214,7 +39217,7 @@ async function postBudgetReached(opts, fetchImpl = fetch) {
39214
39217
  // src/packs/gates.ts
39215
39218
  var import_node_child_process30 = require("child_process");
39216
39219
  var fs73 = __toESM(require("fs"));
39217
- var path81 = __toESM(require("path"));
39220
+ var path82 = __toESM(require("path"));
39218
39221
  var defaultCommandRunner = (file, args2, cwd, timeoutMs) => new Promise((resolve11) => {
39219
39222
  (0, import_node_child_process30.execFile)(
39220
39223
  file,
@@ -39251,14 +39254,14 @@ var NO_TEST_PLACEHOLDER = 'echo "Error: no test specified"';
39251
39254
  var CHECKS_TIMEOUT_MS = 5 * 6e4;
39252
39255
  function detectChecksCommand(cwd) {
39253
39256
  try {
39254
- const cfg = JSON.parse(fs73.readFileSync(path81.join(cwd, ".codeam", "pack.json"), "utf8"));
39257
+ const cfg = JSON.parse(fs73.readFileSync(path82.join(cwd, ".codeam", "pack.json"), "utf8"));
39255
39258
  if (typeof cfg.checksCommand === "string" && cfg.checksCommand.trim().length > 0) {
39256
39259
  return cfg.checksCommand.trim();
39257
39260
  }
39258
39261
  } catch {
39259
39262
  }
39260
39263
  try {
39261
- const pkg = JSON.parse(fs73.readFileSync(path81.join(cwd, "package.json"), "utf8"));
39264
+ const pkg = JSON.parse(fs73.readFileSync(path82.join(cwd, "package.json"), "utf8"));
39262
39265
  const test = pkg.scripts?.test;
39263
39266
  if (typeof test === "string" && test.trim().length > 0 && !test.includes(NO_TEST_PLACEHOLDER)) {
39264
39267
  return "npm test";
@@ -39277,36 +39280,36 @@ ${res.stderr}`.trim();
39277
39280
 
39278
39281
  // src/packs/run-store.ts
39279
39282
  var fs74 = __toESM(require("fs"));
39280
- var path82 = __toESM(require("path"));
39283
+ var path83 = __toESM(require("path"));
39281
39284
  var crypto5 = __toESM(require("crypto"));
39282
39285
  function packsDir(cwd) {
39283
- return path82.join(cwd, ".codeam", "packs");
39286
+ return path83.join(cwd, ".codeam", "packs");
39284
39287
  }
39285
39288
  function runDir(cwd, runId) {
39286
- return path82.join(packsDir(cwd), runId);
39289
+ return path83.join(packsDir(cwd), runId);
39287
39290
  }
39288
39291
  function newRunId() {
39289
39292
  return `pk_${Date.now().toString(36)}_${crypto5.randomBytes(4).toString("hex")}`;
39290
39293
  }
39291
39294
  function writeJsonAtomic(file, value) {
39292
- fs74.mkdirSync(path82.dirname(file), { recursive: true });
39295
+ fs74.mkdirSync(path83.dirname(file), { recursive: true });
39293
39296
  const tmp = `${file}.tmp`;
39294
39297
  fs74.writeFileSync(tmp, JSON.stringify(value, null, 2));
39295
39298
  fs74.renameSync(tmp, file);
39296
39299
  }
39297
39300
  function saveRun(cwd, state) {
39298
- writeJsonAtomic(path82.join(runDir(cwd, state.runId), "run.json"), state);
39301
+ writeJsonAtomic(path83.join(runDir(cwd, state.runId), "run.json"), state);
39299
39302
  }
39300
39303
  function saveStageHandoff(cwd, runId, stageIndex, role, handoff) {
39301
39304
  const name = `${String(stageIndex + 1).padStart(2, "0")}-${role}.json`;
39302
- writeJsonAtomic(path82.join(runDir(cwd, runId), name), handoff);
39305
+ writeJsonAtomic(path83.join(runDir(cwd, runId), name), handoff);
39303
39306
  }
39304
39307
  function loadLatestRun(cwd) {
39305
39308
  try {
39306
39309
  const dir = packsDir(cwd);
39307
39310
  const entries = fs74.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name).sort();
39308
39311
  for (let i = entries.length - 1; i >= 0; i--) {
39309
- const file = path82.join(dir, entries[i], "run.json");
39312
+ const file = path83.join(dir, entries[i], "run.json");
39310
39313
  try {
39311
39314
  const parsed = JSON.parse(fs74.readFileSync(file, "utf8"));
39312
39315
  if (parsed && typeof parsed.runId === "string") return parsed;
@@ -39319,16 +39322,16 @@ function loadLatestRun(cwd) {
39319
39322
  }
39320
39323
  function ensureLedgerIgnored(cwd) {
39321
39324
  try {
39322
- const gitDir = path82.join(cwd, ".git");
39325
+ const gitDir = path83.join(cwd, ".git");
39323
39326
  if (!fs74.existsSync(gitDir)) return;
39324
- const exclude = path82.join(gitDir, "info", "exclude");
39327
+ const exclude = path83.join(gitDir, "info", "exclude");
39325
39328
  let existing = "";
39326
39329
  try {
39327
39330
  existing = fs74.readFileSync(exclude, "utf8");
39328
39331
  } catch {
39329
39332
  }
39330
39333
  if (existing.includes(".codeam/packs/")) return;
39331
- fs74.mkdirSync(path82.dirname(exclude), { recursive: true });
39334
+ fs74.mkdirSync(path83.dirname(exclude), { recursive: true });
39332
39335
  fs74.writeFileSync(exclude, `${existing.trimEnd()}
39333
39336
  .codeam/packs/
39334
39337
  `.trimStart());
@@ -40273,18 +40276,18 @@ function buildAcpPromptBlocks(payload) {
40273
40276
 
40274
40277
  // src/agents/agent-standard.ts
40275
40278
  var fs77 = __toESM(require("fs"));
40276
- var path85 = __toESM(require("path"));
40279
+ var path86 = __toESM(require("path"));
40277
40280
  var os61 = __toESM(require("os"));
40278
40281
  function ensureAgentStandard(homeDir2 = os61.homedir()) {
40279
40282
  try {
40280
- const file = path85.join(homeDir2, ".claude", "CLAUDE.md");
40283
+ const file = path86.join(homeDir2, ".claude", "CLAUDE.md");
40281
40284
  let existing = "";
40282
40285
  try {
40283
40286
  existing = fs77.readFileSync(file, "utf8");
40284
40287
  } catch {
40285
40288
  }
40286
40289
  if (existing.includes(AGENT_STANDARD_MARKER)) return;
40287
- fs77.mkdirSync(path85.dirname(file), { recursive: true });
40290
+ fs77.mkdirSync(path86.dirname(file), { recursive: true });
40288
40291
  const next = existing.trim() ? `${existing.trimEnd()}
40289
40292
 
40290
40293
  ${AGENT_STANDARD_BLOCK}
@@ -40296,10 +40299,10 @@ ${AGENT_STANDARD_BLOCK}
40296
40299
  }
40297
40300
  var _agentStandardSeam = {
40298
40301
  isLocalSession: () => isLocalSession(),
40299
- markerPath: (sessionId) => path85.join(os61.homedir(), ".codeam", "agent-standard", `${sessionId}.done`),
40302
+ markerPath: (sessionId) => path86.join(os61.homedir(), ".codeam", "agent-standard", `${sessionId}.done`),
40300
40303
  exists: (p2) => fs77.existsSync(p2),
40301
40304
  write: (p2) => {
40302
- fs77.mkdirSync(path85.dirname(p2), { recursive: true });
40305
+ fs77.mkdirSync(path86.dirname(p2), { recursive: true });
40303
40306
  fs77.writeFileSync(p2, "");
40304
40307
  }
40305
40308
  };
@@ -42378,7 +42381,7 @@ async function runAcpSession(opts) {
42378
42381
  switchCredentialEnv = provisionAgentCredentials(agentId, auth);
42379
42382
  },
42380
42383
  provisionHouseProxy: ({ baseUrl, token }) => {
42381
- const claudeConfigDir = path86.join(
42384
+ const claudeConfigDir = path87.join(
42382
42385
  os62.homedir(),
42383
42386
  ".codeam",
42384
42387
  "house-claude",
@@ -43588,7 +43591,7 @@ function startClaudeCredentialSync(opts) {
43588
43591
 
43589
43592
  // src/beads/workflow-hint.ts
43590
43593
  var fs79 = __toESM(require("fs"));
43591
- var path87 = __toESM(require("path"));
43594
+ var path88 = __toESM(require("path"));
43592
43595
  var os63 = __toESM(require("os"));
43593
43596
  var BEADS_HINT_MARKER = "<!-- codeam:beads-workflow -->";
43594
43597
  var BEADS_HINT = `${BEADS_HINT_MARKER}
@@ -43605,14 +43608,14 @@ This environment uses **bd (beads)** for issue/task tracking and persistent memo
43605
43608
  ${BEADS_HINT_MARKER}`;
43606
43609
  function ensureBeadsWorkflowHint(homeDir2 = os63.homedir()) {
43607
43610
  try {
43608
- const file = path87.join(homeDir2, ".claude", "CLAUDE.md");
43611
+ const file = path88.join(homeDir2, ".claude", "CLAUDE.md");
43609
43612
  let existing = "";
43610
43613
  try {
43611
43614
  existing = fs79.readFileSync(file, "utf8");
43612
43615
  } catch {
43613
43616
  }
43614
43617
  if (existing.includes(BEADS_HINT_MARKER)) return;
43615
- fs79.mkdirSync(path87.dirname(file), { recursive: true });
43618
+ fs79.mkdirSync(path88.dirname(file), { recursive: true });
43616
43619
  const next = existing.trim() ? `${existing.trimEnd()}
43617
43620
 
43618
43621
  ${BEADS_HINT}
@@ -44580,11 +44583,11 @@ function keepDeviceAwake(deps = {}) {
44580
44583
  // src/agents/claude/onboarding.ts
44581
44584
  var fs81 = __toESM(require("fs"));
44582
44585
  var os65 = __toESM(require("os"));
44583
- var path88 = __toESM(require("path"));
44586
+ var path89 = __toESM(require("path"));
44584
44587
  var ONBOARDING_VERSION_SENTINEL = "9999.0.0";
44585
44588
  function ensureClaudeOnboarded(cwd) {
44586
44589
  try {
44587
- const file = path88.join(os65.homedir(), ".claude.json");
44590
+ const file = path89.join(os65.homedir(), ".claude.json");
44588
44591
  let config = {};
44589
44592
  try {
44590
44593
  config = JSON.parse(fs81.readFileSync(file, "utf8"));
@@ -44612,7 +44615,7 @@ function ensureClaudeOnboarded(cwd) {
44612
44615
  }
44613
44616
  }
44614
44617
  if (!changed) return;
44615
- fs81.mkdirSync(path88.dirname(file), { recursive: true });
44618
+ fs81.mkdirSync(path89.dirname(file), { recursive: true });
44616
44619
  fs81.writeFileSync(file, JSON.stringify(config, null, 2));
44617
44620
  log.info(
44618
44621
  "claude",
@@ -45376,7 +45379,7 @@ var import_picocolors11 = __toESM(require("picocolors"));
45376
45379
  var import_child_process32 = require("child_process");
45377
45380
  var import_util4 = require("util");
45378
45381
  var import_picocolors9 = __toESM(require("picocolors"));
45379
- var path89 = __toESM(require("path"));
45382
+ var path90 = __toESM(require("path"));
45380
45383
  var execFileP6 = (0, import_util4.promisify)(import_child_process32.execFile);
45381
45384
  var MAX_BUFFER = 8 * 1024 * 1024;
45382
45385
  function resetStdinForChild() {
@@ -45865,7 +45868,7 @@ var GitHubCodespacesProvider = class {
45865
45868
  });
45866
45869
  }
45867
45870
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
45868
- const remoteDir = path89.posix.dirname(remotePath);
45871
+ const remoteDir = path90.posix.dirname(remotePath);
45869
45872
  const parts = [
45870
45873
  `mkdir -p ${shellQuote(remoteDir)}`,
45871
45874
  `cat > ${shellQuote(remotePath)}`
@@ -45935,7 +45938,7 @@ function shellQuote(s) {
45935
45938
  // src/services/providers/gitpod.ts
45936
45939
  var import_child_process33 = require("child_process");
45937
45940
  var import_util5 = require("util");
45938
- var path90 = __toESM(require("path"));
45941
+ var path91 = __toESM(require("path"));
45939
45942
  var import_picocolors10 = __toESM(require("picocolors"));
45940
45943
  var execFileP7 = (0, import_util5.promisify)(import_child_process33.execFile);
45941
45944
  var MAX_BUFFER2 = 8 * 1024 * 1024;
@@ -46175,7 +46178,7 @@ var GitpodProvider = class {
46175
46178
  });
46176
46179
  }
46177
46180
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
46178
- const remoteDir = path90.posix.dirname(remotePath);
46181
+ const remoteDir = path91.posix.dirname(remotePath);
46179
46182
  const parts = [
46180
46183
  `mkdir -p ${shellQuote2(remoteDir)}`,
46181
46184
  `cat > ${shellQuote2(remotePath)}`
@@ -46211,7 +46214,7 @@ function shellQuote2(s) {
46211
46214
  // src/services/providers/gitlab-workspaces.ts
46212
46215
  var import_child_process34 = require("child_process");
46213
46216
  var import_util6 = require("util");
46214
- var path91 = __toESM(require("path"));
46217
+ var path92 = __toESM(require("path"));
46215
46218
  var execFileP8 = (0, import_util6.promisify)(import_child_process34.execFile);
46216
46219
  var MAX_BUFFER3 = 8 * 1024 * 1024;
46217
46220
  var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
@@ -46471,7 +46474,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
46471
46474
  }
46472
46475
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
46473
46476
  const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
46474
- const remoteDir = path91.posix.dirname(remotePath);
46477
+ const remoteDir = path92.posix.dirname(remotePath);
46475
46478
  const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
46476
46479
  if (options.mode != null) {
46477
46480
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
@@ -46539,7 +46542,7 @@ function shellQuote3(s) {
46539
46542
  // src/services/providers/railway.ts
46540
46543
  var import_child_process35 = require("child_process");
46541
46544
  var import_util7 = require("util");
46542
- var path92 = __toESM(require("path"));
46545
+ var path93 = __toESM(require("path"));
46543
46546
  var execFileP9 = (0, import_util7.promisify)(import_child_process35.execFile);
46544
46547
  var MAX_BUFFER4 = 8 * 1024 * 1024;
46545
46548
  function resetStdinForChild4() {
@@ -46775,7 +46778,7 @@ var RailwayProvider = class {
46775
46778
  if (!projectId || !serviceId) {
46776
46779
  throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
46777
46780
  }
46778
- const remoteDir = path92.posix.dirname(remotePath);
46781
+ const remoteDir = path93.posix.dirname(remotePath);
46779
46782
  const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
46780
46783
  if (options.mode != null) {
46781
46784
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
@@ -47422,7 +47425,7 @@ var import_node_dns = require("dns");
47422
47425
  var import_node_util5 = require("util");
47423
47426
  var import_node_crypto13 = require("crypto");
47424
47427
  var fs82 = __toESM(require("fs"));
47425
- var path93 = __toESM(require("path"));
47428
+ var path94 = __toESM(require("path"));
47426
47429
  var import_picocolors14 = __toESM(require("picocolors"));
47427
47430
  var dnsResolveP = (0, import_node_util5.promisify)(import_node_dns.resolve);
47428
47431
  async function checkDns(apiBase2) {
@@ -47478,10 +47481,10 @@ async function checkHealth(apiBase2) {
47478
47481
  }
47479
47482
  }
47480
47483
  function checkConfigDir() {
47481
- const dir = path93.join(require("os").homedir(), ".codeam");
47484
+ const dir = path94.join(require("os").homedir(), ".codeam");
47482
47485
  try {
47483
47486
  fs82.mkdirSync(dir, { recursive: true, mode: 448 });
47484
- const probe = path93.join(dir, ".doctor-probe");
47487
+ const probe = path94.join(dir, ".doctor-probe");
47485
47488
  fs82.writeFileSync(probe, "ok", { mode: 384 });
47486
47489
  const read2 = fs82.readFileSync(probe, "utf8");
47487
47490
  fs82.unlinkSync(probe);
@@ -47548,7 +47551,7 @@ function checkNodePty() {
47548
47551
  detail: "not required on this platform"
47549
47552
  };
47550
47553
  }
47551
- const vendoredPath = path93.join(__dirname, "vendor", "node-pty");
47554
+ const vendoredPath = path94.join(__dirname, "vendor", "node-pty");
47552
47555
  for (const target of [vendoredPath, "node-pty"]) {
47553
47556
  try {
47554
47557
  require(target);
@@ -47590,7 +47593,7 @@ function checkChokidar() {
47590
47593
  }
47591
47594
  async function doctor(args2 = []) {
47592
47595
  const json = args2.includes("--json");
47593
- const cliVersion = true ? "2.74.7" : "0.0.0-dev";
47596
+ const cliVersion = true ? "2.74.9" : "0.0.0-dev";
47594
47597
  const apiBase2 = resolveApiBaseUrl();
47595
47598
  const diagnosticId = (0, import_node_crypto13.randomUUID)();
47596
47599
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -48114,7 +48117,7 @@ async function mcpWarm(argv = [], opts = {}) {
48114
48117
  // src/commands/version.ts
48115
48118
  var import_picocolors15 = __toESM(require("picocolors"));
48116
48119
  function version2() {
48117
- const v = true ? "2.74.7" : "unknown";
48120
+ const v = true ? "2.74.9" : "unknown";
48118
48121
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
48119
48122
  }
48120
48123