codeam-cli 2.61.81 → 2.61.82

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 +6 -0
  2. package/dist/index.js +650 -312
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2624,11 +2624,11 @@ function quiet(fn) {
2624
2624
  log.debug(TAG, "ignored sync error", err);
2625
2625
  }
2626
2626
  }
2627
- function rmIfExistsQuiet(path82) {
2627
+ function rmIfExistsQuiet(path84) {
2628
2628
  try {
2629
- fs2.rmSync(path82, { force: true });
2629
+ fs2.rmSync(path84, { force: true });
2630
2630
  } catch (err) {
2631
- log.debug(TAG, `rmIfExists failed for ${path82}`, err);
2631
+ log.debug(TAG, `rmIfExists failed for ${path84}`, err);
2632
2632
  }
2633
2633
  }
2634
2634
  function killQuiet(target, signal = "SIGTERM") {
@@ -2774,9 +2774,9 @@ var _default = makeConfig();
2774
2774
  var { getConfig, ensurePluginId, addSession, removeSession, setActiveSession, getActiveSession, getActiveSessionForAgent, setDisable1mContext, clearAll, saveCliConfig, loadCliConfig } = _default;
2775
2775
 
2776
2776
  // src/commands/pair-auto.ts
2777
- var fs59 = __toESM(require("fs"));
2777
+ var fs61 = __toESM(require("fs"));
2778
2778
  var os49 = __toESM(require("os"));
2779
- var path63 = __toESM(require("path"));
2779
+ var path65 = __toESM(require("path"));
2780
2780
  var import_crypto4 = require("crypto");
2781
2781
 
2782
2782
  // src/services/telemetry.service.ts
@@ -2812,8 +2812,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
2812
2812
  return decodedFile;
2813
2813
  };
2814
2814
  }
2815
- function normalizeWindowsPath(path82) {
2816
- return path82.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
2815
+ function normalizeWindowsPath(path84) {
2816
+ return path84.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
2817
2817
  }
2818
2818
 
2819
2819
  // ../../node_modules/@posthog/core/dist/featureFlagUtils.mjs
@@ -5293,9 +5293,9 @@ async function addSourceContext(frames) {
5293
5293
  LRU_FILE_CONTENTS_CACHE.reduce();
5294
5294
  return frames;
5295
5295
  }
5296
- function getContextLinesFromFile(path82, ranges, output) {
5296
+ function getContextLinesFromFile(path84, ranges, output) {
5297
5297
  return new Promise((resolve9) => {
5298
- const stream = (0, import_node_fs.createReadStream)(path82);
5298
+ const stream = (0, import_node_fs.createReadStream)(path84);
5299
5299
  const lineReaded = (0, import_node_readline.createInterface)({
5300
5300
  input: stream
5301
5301
  });
@@ -5310,7 +5310,7 @@ function getContextLinesFromFile(path82, ranges, output) {
5310
5310
  let rangeStart = range[0];
5311
5311
  let rangeEnd = range[1];
5312
5312
  function onStreamError() {
5313
- LRU_FILE_CONTENTS_FS_READ_FAILED.set(path82, 1);
5313
+ LRU_FILE_CONTENTS_FS_READ_FAILED.set(path84, 1);
5314
5314
  lineReaded.close();
5315
5315
  lineReaded.removeAllListeners();
5316
5316
  destroyStreamAndResolve();
@@ -5371,8 +5371,8 @@ function clearLineContext(frame) {
5371
5371
  delete frame.context_line;
5372
5372
  delete frame.post_context;
5373
5373
  }
5374
- function shouldSkipContextLinesForFile(path82) {
5375
- return path82.startsWith("node:") || path82.endsWith(".min.js") || path82.endsWith(".min.cjs") || path82.endsWith(".min.mjs") || path82.startsWith("data:");
5374
+ function shouldSkipContextLinesForFile(path84) {
5375
+ return path84.startsWith("node:") || path84.endsWith(".min.js") || path84.endsWith(".min.cjs") || path84.endsWith(".min.mjs") || path84.startsWith("data:");
5376
5376
  }
5377
5377
  function shouldSkipContextLinesForFrame(frame) {
5378
5378
  if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
@@ -7526,7 +7526,7 @@ function readAnonId() {
7526
7526
  }
7527
7527
  function superProperties() {
7528
7528
  return {
7529
- cliVersion: true ? "2.61.81" : "0.0.0-dev",
7529
+ cliVersion: true ? "2.61.82" : "0.0.0-dev",
7530
7530
  nodeVersion: process.version,
7531
7531
  platform: process.platform,
7532
7532
  arch: process.arch,
@@ -7707,7 +7707,7 @@ var os4 = __toESM(require("os"));
7707
7707
  // package.json
7708
7708
  var package_default = {
7709
7709
  name: "codeam-cli",
7710
- version: "2.61.81",
7710
+ version: "2.61.82",
7711
7711
  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.",
7712
7712
  type: "commonjs",
7713
7713
  main: "dist/index.js",
@@ -7990,6 +7990,50 @@ async function postPreviewEvent(input) {
7990
7990
  };
7991
7991
  }
7992
7992
  }
7993
+ async function pushProjectEnv(input) {
7994
+ try {
7995
+ await _transport.postJsonAuthed(
7996
+ `${API_BASE}/api/project-env/push`,
7997
+ {
7998
+ sessionId: input.sessionId,
7999
+ pluginId: input.pluginId,
8000
+ projectKey: input.projectKey,
8001
+ projectLabel: input.projectLabel,
8002
+ content: input.content,
8003
+ keyCount: input.keyCount
8004
+ },
8005
+ input.pluginAuthToken
8006
+ );
8007
+ return { ok: true };
8008
+ } catch (err) {
8009
+ const e = err;
8010
+ return {
8011
+ ok: false,
8012
+ status: typeof e.statusCode === "number" ? e.statusCode : 0,
8013
+ message: e.message || "unknown"
8014
+ };
8015
+ }
8016
+ }
8017
+ async function pullProjectEnv(input) {
8018
+ try {
8019
+ const res = await _transport.postJsonAuthed(
8020
+ `${API_BASE}/api/project-env/pull`,
8021
+ {
8022
+ sessionId: input.sessionId,
8023
+ pluginId: input.pluginId,
8024
+ projectKey: input.projectKey
8025
+ },
8026
+ input.pluginAuthToken
8027
+ );
8028
+ if (res && res.exists === true && typeof res.content === "string") {
8029
+ const keyCount = typeof res.keyCount === "number" ? res.keyCount : 0;
8030
+ return { content: res.content, keyCount };
8031
+ }
8032
+ return null;
8033
+ } catch {
8034
+ return null;
8035
+ }
8036
+ }
7993
8037
  async function postBatonEvent(input) {
7994
8038
  try {
7995
8039
  await _transport.postJsonAuthed(
@@ -8939,7 +8983,7 @@ var CommandRelayService = class _CommandRelayService {
8939
8983
  // fresh + clear the "CLI update available" banner after a self-update
8940
8984
  // (a codespace that reinstalls @latest reconnects via heartbeat, not
8941
8985
  // pair/reconnect). Older backends ignore the extra field.
8942
- ..."2.61.81" ? { ideVersion: "2.61.81" } : {}
8986
+ ..."2.61.82" ? { ideVersion: "2.61.82" } : {}
8943
8987
  }).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
8944
8988
  }
8945
8989
  /**
@@ -10313,9 +10357,9 @@ function closeAllTerminals() {
10313
10357
  }
10314
10358
 
10315
10359
  // src/commands/start/handlers.ts
10316
- var fs58 = __toESM(require("fs"));
10360
+ var fs60 = __toESM(require("fs"));
10317
10361
  var os48 = __toESM(require("os"));
10318
- var path62 = __toESM(require("path"));
10362
+ var path64 = __toESM(require("path"));
10319
10363
  var import_crypto3 = require("crypto");
10320
10364
  var import_child_process24 = require("child_process");
10321
10365
 
@@ -15548,8 +15592,8 @@ function pickLine(obj) {
15548
15592
  function toHunk(raw, groupSeverity) {
15549
15593
  if (!raw || typeof raw !== "object") return null;
15550
15594
  const o = raw;
15551
- const path82 = asString(pick(o, ["file_path", "filePath", "file", "path", "filename", "fileName"])) ?? asString(pick(o, ["location"])?.path);
15552
- if (!path82) return null;
15595
+ const path84 = asString(pick(o, ["file_path", "filePath", "file", "path", "filename", "fileName"])) ?? asString(pick(o, ["location"])?.path);
15596
+ if (!path84) return null;
15553
15597
  const message = asString(
15554
15598
  pick(o, [
15555
15599
  "comment",
@@ -15566,7 +15610,7 @@ function toHunk(raw, groupSeverity) {
15566
15610
  const severity = normSeverity(pick(o, ["severity", "level", "priority", "impact"])) ?? normSeverity(groupSeverity);
15567
15611
  const locObj = pick(o, ["location"]) ?? o;
15568
15612
  return {
15569
- path: path82.trim(),
15613
+ path: path84.trim(),
15570
15614
  line: pickLine(o) ?? pickLine(locObj),
15571
15615
  severity,
15572
15616
  message: (title && message ? `${title}: ${message}` : title || message).trim() || "(no message)"
@@ -15649,10 +15693,10 @@ function parsePlain(stdout) {
15649
15693
  for (const line of stdout.split(/\r?\n/)) {
15650
15694
  const m = line.match(HUNK_LINE_RE);
15651
15695
  if (!m) continue;
15652
- const [, path82, lineNo, sevToken, message] = m;
15653
- if (!path82 || !lineNo || !message) continue;
15696
+ const [, path84, lineNo, sevToken, message] = m;
15697
+ if (!path84 || !lineNo || !message) continue;
15654
15698
  hunks.push({
15655
- path: path82.trim(),
15699
+ path: path84.trim(),
15656
15700
  line: Number(lineNo),
15657
15701
  severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
15658
15702
  message: message.trim().replace(/^[*-]\s+/, "")
@@ -20053,7 +20097,7 @@ async function autoUpgradeBeforeCriticalCommand() {
20053
20097
  if (process.env.NODE_ENV === "test") return;
20054
20098
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
20055
20099
  if (process.env.CI) return;
20056
- const current = true ? "2.61.81" : null;
20100
+ const current = true ? "2.61.82" : null;
20057
20101
  if (!current) return;
20058
20102
  const cache = readCache();
20059
20103
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -20070,7 +20114,7 @@ function checkForUpdates() {
20070
20114
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
20071
20115
  if (process.env.CI) return;
20072
20116
  if (!process.stdout.isTTY) return;
20073
- const current = true ? "2.61.81" : null;
20117
+ const current = true ? "2.61.82" : null;
20074
20118
  if (!current) return;
20075
20119
  const cache = readCache();
20076
20120
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -20090,7 +20134,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
20090
20134
  var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
20091
20135
  var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
20092
20136
  function currentCliVersion() {
20093
- return true ? "2.61.81" : null;
20137
+ return true ? "2.61.82" : null;
20094
20138
  }
20095
20139
  function runCmd(cmd, args2, timeoutMs) {
20096
20140
  return new Promise((resolve9) => {
@@ -21750,9 +21794,213 @@ function reclaimOwnOrphanPort(port) {
21750
21794
  return true;
21751
21795
  }
21752
21796
 
21797
+ // src/services/preview/host-allow.ts
21798
+ var import_fs = require("fs");
21799
+ var path50 = __toESM(require("path"));
21800
+ var NEXT_ALLOWED_ORIGINS = [
21801
+ "*.trycloudflare.com",
21802
+ "*.preview.codeagent-mobile.com",
21803
+ "*.codeagent-mobile.com"
21804
+ ];
21805
+ var VITE_ALLOWED_HOSTS = [
21806
+ ".trycloudflare.com",
21807
+ ".preview.codeagent-mobile.com",
21808
+ ".codeagent-mobile.com"
21809
+ ];
21810
+ var CONFIG_BASENAMES = {
21811
+ next: "next.config",
21812
+ vite: "vite.config"
21813
+ };
21814
+ var CONFIG_EXTS = [".ts", ".mjs", ".js", ".cjs", ".mts"];
21815
+ var MARKER_DIR = ".codeam";
21816
+ var MARKER_FILE = "preview-host-allow.json";
21817
+ var ORIG_INFIX = ".codeam-orig";
21818
+ function markerPath(cwd) {
21819
+ return path50.join(cwd, MARKER_DIR, MARKER_FILE);
21820
+ }
21821
+ async function fileExists(p2) {
21822
+ try {
21823
+ await import_fs.promises.access(p2);
21824
+ return true;
21825
+ } catch {
21826
+ return false;
21827
+ }
21828
+ }
21829
+ async function findConfigFile(cwd, framework) {
21830
+ const base = CONFIG_BASENAMES[framework];
21831
+ for (const ext of CONFIG_EXTS) {
21832
+ if (await fileExists(path50.join(cwd, `${base}${ext}`))) return `${base}${ext}`;
21833
+ }
21834
+ return null;
21835
+ }
21836
+ async function dependsOn(cwd, pkgName) {
21837
+ try {
21838
+ const raw = await import_fs.promises.readFile(path50.join(cwd, "package.json"), "utf8");
21839
+ const pkg = JSON.parse(raw);
21840
+ return !!(pkg.dependencies?.[pkgName] ?? pkg.devDependencies?.[pkgName]);
21841
+ } catch {
21842
+ return false;
21843
+ }
21844
+ }
21845
+ async function isEsmConfig(cwd, configFile) {
21846
+ const ext = path50.extname(configFile);
21847
+ if (ext === ".mjs" || ext === ".mts" || ext === ".ts") return true;
21848
+ if (ext === ".cjs") return false;
21849
+ try {
21850
+ const raw = await import_fs.promises.readFile(path50.join(cwd, "package.json"), "utf8");
21851
+ return JSON.parse(raw).type === "module";
21852
+ } catch {
21853
+ return false;
21854
+ }
21855
+ }
21856
+ function nextShim(origBasename, esm) {
21857
+ const list = JSON.stringify(NEXT_ALLOWED_ORIGINS);
21858
+ const merge = `
21859
+ function __codeamWithAllow(cfg) {
21860
+ var c = cfg && typeof cfg === 'object' ? Object.assign({}, cfg) : {};
21861
+ var existing = Array.isArray(c.allowedDevOrigins) ? c.allowedDevOrigins : [];
21862
+ c.allowedDevOrigins = Array.from(new Set(existing.concat(${list})));
21863
+ return c;
21864
+ }
21865
+ function __codeamMerge(base) {
21866
+ if (typeof base === 'function') {
21867
+ return function () {
21868
+ var r = base.apply(null, arguments);
21869
+ return r && typeof r.then === 'function' ? r.then(__codeamWithAllow) : __codeamWithAllow(r);
21870
+ };
21871
+ }
21872
+ return base && typeof base.then === 'function' ? base.then(__codeamWithAllow) : __codeamWithAllow(base);
21873
+ }`;
21874
+ if (origBasename) {
21875
+ return esm ? `// codeam preview host-allow shim \u2014 auto-generated, restored on preview stop.
21876
+ import __codeamUser from './${origBasename}';
21877
+ ${merge}
21878
+ export default __codeamMerge(__codeamUser);
21879
+ ` : `// codeam preview host-allow shim \u2014 auto-generated, restored on preview stop.
21880
+ var __codeamUser = require('./${origBasename}');
21881
+ ${merge}
21882
+ module.exports = __codeamMerge(__codeamUser && __codeamUser.default ? __codeamUser.default : __codeamUser);
21883
+ `;
21884
+ }
21885
+ return esm ? `// codeam preview host-allow shim \u2014 auto-generated, removed on preview stop.
21886
+ export default { allowedDevOrigins: ${list} };
21887
+ ` : `// codeam preview host-allow shim \u2014 auto-generated, removed on preview stop.
21888
+ module.exports = { allowedDevOrigins: ${list} };
21889
+ `;
21890
+ }
21891
+ function viteShim(origBasename, esm) {
21892
+ const list = JSON.stringify(VITE_ALLOWED_HOSTS);
21893
+ const merge = `
21894
+ function __codeamWithAllow(cfg) {
21895
+ var c = cfg && typeof cfg === 'object' ? Object.assign({}, cfg) : {};
21896
+ var server = Object.assign({}, c.server || {});
21897
+ if (server.allowedHosts === true) { c.server = server; return c; }
21898
+ var existing = Array.isArray(server.allowedHosts) ? server.allowedHosts : [];
21899
+ server.allowedHosts = Array.from(new Set(existing.concat(${list})));
21900
+ c.server = server;
21901
+ return c;
21902
+ }
21903
+ function __codeamMerge(base) {
21904
+ if (typeof base === 'function') {
21905
+ return function () {
21906
+ var r = base.apply(null, arguments);
21907
+ return r && typeof r.then === 'function' ? r.then(__codeamWithAllow) : __codeamWithAllow(r);
21908
+ };
21909
+ }
21910
+ return base && typeof base.then === 'function' ? base.then(__codeamWithAllow) : __codeamWithAllow(base);
21911
+ }`;
21912
+ if (origBasename) {
21913
+ return esm ? `// codeam preview host-allow shim \u2014 auto-generated, restored on preview stop.
21914
+ import __codeamUser from './${origBasename}';
21915
+ ${merge}
21916
+ export default __codeamMerge(__codeamUser);
21917
+ ` : `// codeam preview host-allow shim \u2014 auto-generated, restored on preview stop.
21918
+ var __codeamUser = require('./${origBasename}');
21919
+ ${merge}
21920
+ module.exports = __codeamMerge(__codeamUser && __codeamUser.default ? __codeamUser.default : __codeamUser);
21921
+ `;
21922
+ }
21923
+ return esm ? `// codeam preview host-allow shim \u2014 auto-generated, removed on preview stop.
21924
+ export default { server: { allowedHosts: ${list} } };
21925
+ ` : `// codeam preview host-allow shim \u2014 auto-generated, removed on preview stop.
21926
+ module.exports = { server: { allowedHosts: ${list} } };
21927
+ `;
21928
+ }
21929
+ function shimFor(framework, origBasename, esm) {
21930
+ return framework === "next" ? nextShim(origBasename, esm) : viteShim(origBasename, esm);
21931
+ }
21932
+ async function writeMarker(cwd, marker) {
21933
+ await import_fs.promises.mkdir(path50.join(cwd, MARKER_DIR), { recursive: true });
21934
+ await import_fs.promises.writeFile(markerPath(cwd), JSON.stringify(marker, null, 2), "utf8");
21935
+ }
21936
+ async function readMarker(cwd) {
21937
+ try {
21938
+ const parsed = JSON.parse(await import_fs.promises.readFile(markerPath(cwd), "utf8"));
21939
+ return parsed && parsed.configFile ? parsed : null;
21940
+ } catch {
21941
+ return null;
21942
+ }
21943
+ }
21944
+ async function restorePreviewHostAllow(cwd) {
21945
+ const marker = await readMarker(cwd);
21946
+ if (!marker) return;
21947
+ try {
21948
+ const configAbs = path50.join(cwd, marker.configFile);
21949
+ if (marker.backupFile) {
21950
+ const backupAbs = path50.join(cwd, marker.backupFile);
21951
+ if (await fileExists(backupAbs)) {
21952
+ await import_fs.promises.rm(configAbs, { force: true });
21953
+ await import_fs.promises.rename(backupAbs, configAbs);
21954
+ }
21955
+ } else {
21956
+ await import_fs.promises.rm(configAbs, { force: true });
21957
+ }
21958
+ } catch (err) {
21959
+ log.warn("preview", `host-allow restore failed: ${err instanceof Error ? err.message : err}`);
21960
+ } finally {
21961
+ await import_fs.promises.rm(markerPath(cwd), { force: true }).catch(() => void 0);
21962
+ }
21963
+ }
21964
+ async function applyPreviewHostAllow(cwd) {
21965
+ try {
21966
+ await restorePreviewHostAllow(cwd);
21967
+ let framework = null;
21968
+ let existing = null;
21969
+ for (const f of ["next", "vite"]) {
21970
+ const cfg = await findConfigFile(cwd, f);
21971
+ if (cfg) {
21972
+ framework = f;
21973
+ existing = cfg;
21974
+ break;
21975
+ }
21976
+ }
21977
+ if (!framework) {
21978
+ if (await dependsOn(cwd, "next")) framework = "next";
21979
+ else if (await dependsOn(cwd, "vite")) framework = "vite";
21980
+ }
21981
+ if (!framework) return;
21982
+ if (existing) {
21983
+ const ext = path50.extname(existing);
21984
+ const origBasename = `${CONFIG_BASENAMES[framework]}${ORIG_INFIX}${ext}`;
21985
+ const esm = await isEsmConfig(cwd, existing);
21986
+ await import_fs.promises.rename(path50.join(cwd, existing), path50.join(cwd, origBasename));
21987
+ await import_fs.promises.writeFile(path50.join(cwd, existing), shimFor(framework, origBasename, esm), "utf8");
21988
+ await writeMarker(cwd, { framework, configFile: existing, backupFile: origBasename });
21989
+ log.info("preview", `host-allow: wrapped ${existing} (${framework}) for tunnel access`);
21990
+ } else {
21991
+ const configFile = `${CONFIG_BASENAMES[framework]}.mjs`;
21992
+ await import_fs.promises.writeFile(path50.join(cwd, configFile), shimFor(framework, null, true), "utf8");
21993
+ await writeMarker(cwd, { framework, configFile, backupFile: null });
21994
+ log.info("preview", `host-allow: created ${configFile} (${framework}) for tunnel access`);
21995
+ }
21996
+ } catch (err) {
21997
+ log.warn("preview", `host-allow apply skipped: ${err instanceof Error ? err.message : err}`);
21998
+ }
21999
+ }
22000
+
21753
22001
  // src/services/preview/cloudflared.ts
21754
22002
  var import_child_process15 = require("child_process");
21755
- var import_fs = require("fs");
22003
+ var import_fs2 = require("fs");
21756
22004
  var import_promises = __toESM(require("fs/promises"));
21757
22005
  var import_os9 = __toESM(require("os"));
21758
22006
  var import_path4 = __toESM(require("path"));
@@ -21793,7 +22041,7 @@ async function downloadCloudflared(target) {
21793
22041
  const tmp = `${target}.download.tgz`;
21794
22042
  await (0, import_promises2.pipeline)(
21795
22043
  response.body,
21796
- (0, import_fs.createWriteStream)(tmp)
22044
+ (0, import_fs2.createWriteStream)(tmp)
21797
22045
  );
21798
22046
  try {
21799
22047
  await extractTgz(tmp, import_path4.default.dirname(target));
@@ -21810,7 +22058,7 @@ async function downloadCloudflared(target) {
21810
22058
  }
21811
22059
  await (0, import_promises2.pipeline)(
21812
22060
  response.body,
21813
- (0, import_fs.createWriteStream)(target, { mode: 493 })
22061
+ (0, import_fs2.createWriteStream)(target, { mode: 493 })
21814
22062
  );
21815
22063
  }
21816
22064
  async function isExecutableBinary(p2) {
@@ -22071,7 +22319,7 @@ async function waitForPortListening(port, opts) {
22071
22319
  }
22072
22320
 
22073
22321
  // src/services/preview/provision-deps.ts
22074
- var import_fs2 = require("fs");
22322
+ var import_fs3 = require("fs");
22075
22323
  var import_path6 = __toESM(require("path"));
22076
22324
 
22077
22325
  // src/services/preview/run-setup.ts
@@ -22219,7 +22467,7 @@ function pickMigrationScript(scripts) {
22219
22467
  }
22220
22468
  async function exists(p2) {
22221
22469
  try {
22222
- await import_fs2.promises.access(p2);
22470
+ await import_fs3.promises.access(p2);
22223
22471
  return true;
22224
22472
  } catch {
22225
22473
  return false;
@@ -22236,20 +22484,20 @@ async function ensureEnvFile(cwd, generated) {
22236
22484
  }
22237
22485
  const sample = await firstExisting(cwd, ENV_SAMPLES);
22238
22486
  if (sample) {
22239
- const body = await import_fs2.promises.readFile(import_path6.default.join(cwd, sample), "utf8");
22240
- await import_fs2.promises.writeFile(import_path6.default.join(cwd, ".env"), body);
22487
+ const body = await import_fs3.promises.readFile(import_path6.default.join(cwd, sample), "utf8");
22488
+ await import_fs3.promises.writeFile(import_path6.default.join(cwd, ".env"), body);
22241
22489
  log.info("provision", `wrote .env from ${sample}`);
22242
22490
  return;
22243
22491
  }
22244
22492
  if (generated.length > 0) {
22245
22493
  const body = "# Generated by codeam \u2014 points at the auto-provisioned local services.\n" + generated.flatMap((s) => s.envLines).join("\n") + "\n";
22246
- await import_fs2.promises.writeFile(import_path6.default.join(cwd, ".env"), body);
22494
+ await import_fs3.promises.writeFile(import_path6.default.join(cwd, ".env"), body);
22247
22495
  log.info("provision", `generated .env for ${generated.map((s) => s.name).join("+")}`);
22248
22496
  }
22249
22497
  }
22250
22498
  async function readPackageJson(cwd) {
22251
22499
  try {
22252
- return JSON.parse(await import_fs2.promises.readFile(import_path6.default.join(cwd, "package.json"), "utf8"));
22500
+ return JSON.parse(await import_fs3.promises.readFile(import_path6.default.join(cwd, "package.json"), "utf8"));
22253
22501
  } catch {
22254
22502
  return null;
22255
22503
  }
@@ -22290,9 +22538,9 @@ async function provisionProjectDependencies(cwd) {
22290
22538
  generated = detectServicesFromDeps(pkg);
22291
22539
  if (generated.length > 0) {
22292
22540
  const dir = import_path6.default.join(cwd, ".codeam", "provision");
22293
- await import_fs2.promises.mkdir(dir, { recursive: true });
22541
+ await import_fs3.promises.mkdir(dir, { recursive: true });
22294
22542
  const file = import_path6.default.join(dir, "compose.generated.yaml");
22295
- await import_fs2.promises.writeFile(file, renderComposeYaml(generated));
22543
+ await import_fs3.promises.writeFile(file, renderComposeYaml(generated));
22296
22544
  log.info(
22297
22545
  "provision",
22298
22546
  `no compose in repo \u2014 generated ${generated.map((s) => s.name).join("+")}`
@@ -22313,12 +22561,12 @@ async function provisionProjectDependencies(cwd) {
22313
22561
  }
22314
22562
 
22315
22563
  // src/services/preview/setup-deps.ts
22316
- var import_fs3 = __toESM(require("fs"));
22564
+ var import_fs4 = __toESM(require("fs"));
22317
22565
  var import_path7 = __toESM(require("path"));
22318
22566
  function detectMissingNodeDeps(cwd) {
22319
- if (!import_fs3.default.existsSync(import_path7.default.join(cwd, "package.json"))) return null;
22320
- if (import_fs3.default.existsSync(import_path7.default.join(cwd, "node_modules"))) return null;
22321
- if (import_fs3.default.existsSync(import_path7.default.join(cwd, "yarn.lock"))) {
22567
+ if (!import_fs4.default.existsSync(import_path7.default.join(cwd, "package.json"))) return null;
22568
+ if (import_fs4.default.existsSync(import_path7.default.join(cwd, "node_modules"))) return null;
22569
+ if (import_fs4.default.existsSync(import_path7.default.join(cwd, "yarn.lock"))) {
22322
22570
  return { cmd: "yarn", args: ["install"] };
22323
22571
  }
22324
22572
  return { cmd: "npm", args: ["install", "--legacy-peer-deps"] };
@@ -22410,6 +22658,7 @@ async function killPreview(sessionId) {
22410
22658
  if (preview.tunnel) killProcessTree(preview.tunnel, "SIGKILL");
22411
22659
  }, 250);
22412
22660
  sigkillTimer.unref?.();
22661
+ await restorePreviewHostAllow(preview.cwd);
22413
22662
  activePreviews.delete(sessionId);
22414
22663
  }
22415
22664
  async function killAllPreviews() {
@@ -22421,10 +22670,153 @@ function activePreviewSessionIds() {
22421
22670
  }
22422
22671
 
22423
22672
  // src/services/preview/start-orchestrator.ts
22424
- var import_child_process18 = require("child_process");
22425
- var fs51 = __toESM(require("fs"));
22426
- var path54 = __toESM(require("path"));
22673
+ var import_child_process19 = require("child_process");
22674
+ var fs54 = __toESM(require("fs"));
22675
+ var path57 = __toESM(require("path"));
22427
22676
  var import_which2 = __toESM(require("which"));
22677
+
22678
+ // src/services/project-env/index.ts
22679
+ var import_fs5 = require("fs");
22680
+ var path56 = __toESM(require("path"));
22681
+
22682
+ // src/beads/project-key.ts
22683
+ var import_child_process18 = require("child_process");
22684
+ var crypto2 = __toESM(require("crypto"));
22685
+ var fs52 = __toESM(require("fs"));
22686
+ var path55 = __toESM(require("path"));
22687
+ function normalizeOrigin(raw) {
22688
+ const trimmed = raw.trim();
22689
+ if (!trimmed) return null;
22690
+ let host2;
22691
+ let pathPart;
22692
+ const scpLike = /^[^/@]+@([^:]+):(.+)$/.exec(trimmed);
22693
+ if (scpLike && !trimmed.includes("://")) {
22694
+ host2 = scpLike[1];
22695
+ pathPart = scpLike[2];
22696
+ } else {
22697
+ let url2;
22698
+ try {
22699
+ url2 = new URL(trimmed);
22700
+ } catch {
22701
+ return null;
22702
+ }
22703
+ host2 = url2.hostname;
22704
+ pathPart = url2.pathname;
22705
+ }
22706
+ host2 = host2.toLowerCase();
22707
+ pathPart = pathPart.replace(/^\/+/, "").replace(/\.git$/i, "").replace(/\/+$/, "");
22708
+ if (!host2 || !pathPart) return null;
22709
+ return `${host2}/${pathPart}`;
22710
+ }
22711
+ function findRepoRoot(cwd) {
22712
+ let dir = path55.resolve(cwd);
22713
+ const seen = /* @__PURE__ */ new Set();
22714
+ for (let i = 0; i < 256; i++) {
22715
+ if (seen.has(dir)) return null;
22716
+ seen.add(dir);
22717
+ try {
22718
+ const stat3 = fs52.statSync(path55.join(dir, ".git"), { throwIfNoEntry: false });
22719
+ if (stat3 && (stat3.isDirectory() || stat3.isFile())) return dir;
22720
+ } catch {
22721
+ }
22722
+ const parent = path55.dirname(dir);
22723
+ if (parent === dir) return null;
22724
+ dir = parent;
22725
+ }
22726
+ return null;
22727
+ }
22728
+ var _execSeam2 = {
22729
+ exec: (file, args2, opts) => {
22730
+ const out2 = (0, import_child_process18.execFileSync)(file, args2, opts);
22731
+ return typeof out2 === "string" ? out2 : out2.toString("utf8");
22732
+ },
22733
+ realpath: (p2) => fs52.realpathSync(p2)
22734
+ };
22735
+ function readOrigin(cwd) {
22736
+ try {
22737
+ const raw = _execSeam2.exec("git", ["remote", "get-url", "origin"], {
22738
+ cwd,
22739
+ timeout: 1e3,
22740
+ stdio: ["ignore", "pipe", "ignore"],
22741
+ encoding: "utf8"
22742
+ });
22743
+ return raw.trim() || null;
22744
+ } catch {
22745
+ return null;
22746
+ }
22747
+ }
22748
+ function deriveProjectIdentity(cwd = process.cwd()) {
22749
+ const repoRoot = findRepoRoot(cwd) ?? cwd;
22750
+ const origin = readOrigin(repoRoot);
22751
+ const normalized = origin ? normalizeOrigin(origin) : null;
22752
+ if (normalized) {
22753
+ const label = normalized.split("/").pop() || normalized;
22754
+ return { projectKey: normalized, projectLabel: label };
22755
+ }
22756
+ let real = repoRoot;
22757
+ try {
22758
+ real = _execSeam2.realpath(repoRoot);
22759
+ } catch {
22760
+ }
22761
+ const hash = crypto2.createHash("sha256").update(real).digest("hex");
22762
+ return { projectKey: `path:${hash}`, projectLabel: path55.basename(real) || "project" };
22763
+ }
22764
+
22765
+ // src/services/project-env/index.ts
22766
+ async function readIfExists(p2) {
22767
+ try {
22768
+ return await import_fs5.promises.readFile(p2, "utf8");
22769
+ } catch {
22770
+ return null;
22771
+ }
22772
+ }
22773
+ async function syncProjectEnvUp(cwd, ctx) {
22774
+ if (!ctx.pluginAuthToken) return;
22775
+ const content = await readIfExists(path56.join(cwd, ".env"));
22776
+ if (content == null) return;
22777
+ try {
22778
+ const { projectKey, projectLabel } = deriveProjectIdentity(cwd);
22779
+ const keyCount = parseDotenv(content).length;
22780
+ const res = await pushProjectEnv({
22781
+ sessionId: ctx.sessionId,
22782
+ pluginId: ctx.pluginId,
22783
+ pluginAuthToken: ctx.pluginAuthToken,
22784
+ projectKey,
22785
+ projectLabel,
22786
+ content,
22787
+ keyCount
22788
+ });
22789
+ if (res.ok) log.info("project-env", `pushed .env (${keyCount} vars) for ${projectLabel}`);
22790
+ else log.debug("project-env", `push .env failed (${res.status}) \u2014 non-fatal`);
22791
+ } catch (err) {
22792
+ log.debug("project-env", `push .env skipped: ${err instanceof Error ? err.message : err}`);
22793
+ }
22794
+ }
22795
+ async function restoreProjectEnvIfMissing(cwd, ctx) {
22796
+ if (!ctx.pluginAuthToken) return false;
22797
+ const envPath = path56.join(cwd, ".env");
22798
+ if (await readIfExists(envPath) != null) return false;
22799
+ try {
22800
+ const { projectKey, projectLabel } = deriveProjectIdentity(cwd);
22801
+ const stored = await pullProjectEnv({
22802
+ sessionId: ctx.sessionId,
22803
+ pluginId: ctx.pluginId,
22804
+ pluginAuthToken: ctx.pluginAuthToken,
22805
+ projectKey
22806
+ });
22807
+ if (!stored) return false;
22808
+ const tmp = path56.join(cwd, ".env.codeam-restore.tmp");
22809
+ await import_fs5.promises.writeFile(tmp, stored.content, { encoding: "utf8", mode: 384 });
22810
+ await import_fs5.promises.rename(tmp, envPath);
22811
+ log.info("project-env", `restored .env (${stored.keyCount} vars) for ${projectLabel}`);
22812
+ return true;
22813
+ } catch (err) {
22814
+ log.debug("project-env", `restore .env skipped: ${err instanceof Error ? err.message : err}`);
22815
+ return false;
22816
+ }
22817
+ }
22818
+
22819
+ // src/services/preview/start-orchestrator.ts
22428
22820
  var INSTALL_TIMEOUT_MS = 5 * 6e4;
22429
22821
  var SETUP_TIMEOUT_MS = 2 * 6e4;
22430
22822
  var TUNNEL_REGISTER_DEADLINE_MS = 45e3;
@@ -22490,8 +22882,8 @@ function normalizeDetectionForSpawn(detection, cwd) {
22490
22882
  if (args2.length === 0) return detection;
22491
22883
  const binName = args2[0];
22492
22884
  if (binName.startsWith("-")) return detection;
22493
- const binPath = path54.join(cwd, "node_modules", ".bin", binName);
22494
- if (!fs51.existsSync(binPath)) return detection;
22885
+ const binPath = path57.join(cwd, "node_modules", ".bin", binName);
22886
+ if (!fs54.existsSync(binPath)) return detection;
22495
22887
  return {
22496
22888
  ...detection,
22497
22889
  command: binPath,
@@ -22537,7 +22929,8 @@ async function runPreviewStart(args2) {
22537
22929
  tunnel: tun.tunnel,
22538
22930
  url: tun.url,
22539
22931
  framework: detection.framework,
22540
- detection
22932
+ detection,
22933
+ cwd: ctx.cwd
22541
22934
  });
22542
22935
  recordPreviewPort(detection.port, dev.devServer.pid, sessionId, Date.now());
22543
22936
  log.info("preview", `ready: ${detection.framework} at ${tun.url}`);
@@ -22549,6 +22942,13 @@ async function runPreviewStart(args2) {
22549
22942
  }
22550
22943
  async function provisionDeps(ctx) {
22551
22944
  const { detection, cwd, emit: emit2, emitProgress } = ctx;
22945
+ if (ctx.projectEnvAuth?.pluginAuthToken) {
22946
+ await restoreProjectEnvIfMissing(cwd, {
22947
+ sessionId: ctx.sessionId,
22948
+ pluginId: ctx.projectEnvAuth.pluginId,
22949
+ pluginAuthToken: ctx.projectEnvAuth.pluginAuthToken
22950
+ });
22951
+ }
22552
22952
  const missingDeps = detectMissingNodeDeps(cwd);
22553
22953
  let preflightRan = false;
22554
22954
  if (missingDeps) {
@@ -22696,9 +23096,10 @@ async function startDevServer(ctx) {
22696
23096
  return null;
22697
23097
  }
22698
23098
  }
23099
+ await applyPreviewHostAllow(cwd);
22699
23100
  const spawnable = normalizeDetectionForSpawn(detection, cwd);
22700
23101
  emitProgress("BOOT_SEQUENCE", `${spawnable.command} ${spawnable.args.join(" ")}`);
22701
- const devServer = (0, import_child_process18.spawn)(spawnable.command, spawnable.args, {
23102
+ const devServer = (0, import_child_process19.spawn)(spawnable.command, spawnable.args, {
22702
23103
  cwd,
22703
23104
  env: { ...process.env, ...spawnable.env ?? {} },
22704
23105
  stdio: ["ignore", "pipe", "pipe"],
@@ -22823,7 +23224,7 @@ async function establishTunnel(ctx, dev) {
22823
23224
  `cloudflared quick tunnel (retry ${attempt}/${MAX_TUNNEL_ATTEMPTS})`
22824
23225
  );
22825
23226
  }
22826
- const candidate = (0, import_child_process18.spawn)(
23227
+ const candidate = (0, import_child_process19.spawn)(
22827
23228
  bin,
22828
23229
  ["tunnel", "--url", `http://localhost:${detection.port}`],
22829
23230
  { stdio: ["ignore", "pipe", "pipe"] }
@@ -22854,10 +23255,10 @@ async function establishTunnel(ctx, dev) {
22854
23255
  }
22855
23256
 
22856
23257
  // src/beads/bd-adapter.ts
22857
- var import_child_process19 = require("child_process");
22858
- var fs52 = __toESM(require("fs"));
23258
+ var import_child_process20 = require("child_process");
23259
+ var fs55 = __toESM(require("fs"));
22859
23260
  var os42 = __toESM(require("os"));
22860
- var path55 = __toESM(require("path"));
23261
+ var path58 = __toESM(require("path"));
22861
23262
  var BD_PACKAGE = "@beads/bd";
22862
23263
  function resolveBundledBdBinary() {
22863
23264
  return _resolveSeam.resolveBundled();
@@ -22869,11 +23270,11 @@ function _defaultResolveBundled() {
22869
23270
  } catch {
22870
23271
  return null;
22871
23272
  }
22872
- const binDir = path55.join(path55.dirname(pkgJsonPath), "bin");
23273
+ const binDir = path58.join(path58.dirname(pkgJsonPath), "bin");
22873
23274
  const binaryName = process.platform === "win32" ? "bd.exe" : "bd";
22874
- const binaryPath = path55.join(binDir, binaryName);
23275
+ const binaryPath = path58.join(binDir, binaryName);
22875
23276
  try {
22876
- fs52.accessSync(binaryPath, fs52.constants.F_OK);
23277
+ fs55.accessSync(binaryPath, fs55.constants.F_OK);
22877
23278
  return binaryPath;
22878
23279
  } catch {
22879
23280
  return null;
@@ -22883,13 +23284,13 @@ function resolveBdOnPath() {
22883
23284
  return _resolveSeam.resolveOnPath();
22884
23285
  }
22885
23286
  function _defaultResolveOnPath() {
22886
- const dirs = (process.env.PATH ?? "").split(path55.delimiter).filter(Boolean);
23287
+ const dirs = (process.env.PATH ?? "").split(path58.delimiter).filter(Boolean);
22887
23288
  const candidates = process.platform === "win32" ? ["bd.exe", "bd.cmd", "bd"] : ["bd"];
22888
23289
  for (const dir of dirs) {
22889
23290
  for (const candidate of candidates) {
22890
- const full = path55.join(dir, candidate);
23291
+ const full = path58.join(dir, candidate);
22891
23292
  try {
22892
- fs52.accessSync(full, fs52.constants.F_OK);
23293
+ fs55.accessSync(full, fs55.constants.F_OK);
22893
23294
  return full;
22894
23295
  } catch {
22895
23296
  }
@@ -22908,7 +23309,7 @@ function _defaultSpawn(binaryPath, args2, opts) {
22908
23309
  return new Promise((resolve9) => {
22909
23310
  let proc;
22910
23311
  try {
22911
- proc = (0, import_child_process19.spawn)(binaryPath, args2, { cwd: opts.cwd, env: opts.env });
23312
+ proc = (0, import_child_process20.spawn)(binaryPath, args2, { cwd: opts.cwd, env: opts.env });
22912
23313
  } catch (err) {
22913
23314
  resolve9({ code: -1, stdout: "", stderr: err.message });
22914
23315
  return;
@@ -23066,12 +23467,12 @@ function coerceIssue(row, projectKey) {
23066
23467
 
23067
23468
  // src/beads/provisioner.ts
23068
23469
  var import_child_process23 = require("child_process");
23069
- var fs55 = __toESM(require("fs"));
23470
+ var fs57 = __toESM(require("fs"));
23070
23471
  var os44 = __toESM(require("os"));
23071
- var path58 = __toESM(require("path"));
23472
+ var path60 = __toESM(require("path"));
23072
23473
 
23073
23474
  // src/beads/install-bd.ts
23074
- var import_child_process20 = require("child_process");
23475
+ var import_child_process21 = require("child_process");
23075
23476
  var INSTALL_SH_URL = "https://raw.githubusercontent.com/gastownhall/beads/main/scripts/install.sh";
23076
23477
  var INSTALL_PS1_URL = "https://raw.githubusercontent.com/gastownhall/beads/main/install.ps1";
23077
23478
  function resolveInstallStrategy(platform3) {
@@ -23102,7 +23503,7 @@ function _defaultInstallSpawn(strategy) {
23102
23503
  return new Promise((resolve9) => {
23103
23504
  let proc;
23104
23505
  try {
23105
- proc = (0, import_child_process20.spawn)(strategy.command, strategy.args, { env: process.env });
23506
+ proc = (0, import_child_process21.spawn)(strategy.command, strategy.args, { env: process.env });
23106
23507
  } catch (err) {
23107
23508
  resolve9({ ok: false, code: -1, stderr: err.message });
23108
23509
  return;
@@ -23132,10 +23533,10 @@ async function installBd(platform3 = process.platform) {
23132
23533
  }
23133
23534
 
23134
23535
  // src/beads/install-dolt.ts
23135
- var import_child_process21 = require("child_process");
23136
- var fs53 = __toESM(require("fs"));
23536
+ var import_child_process22 = require("child_process");
23537
+ var fs56 = __toESM(require("fs"));
23137
23538
  var os43 = __toESM(require("os"));
23138
- var path56 = __toESM(require("path"));
23539
+ var path59 = __toESM(require("path"));
23139
23540
  var DOLT_INSTALL_SH_URL = "https://github.com/dolthub/dolt/releases/latest/download/install.sh";
23140
23541
  var DOLT_MSI_URL = "https://github.com/dolthub/dolt/releases/latest/download/dolt-windows-amd64.msi";
23141
23542
  function resolveDoltInstallStrategy(platform3) {
@@ -23231,7 +23632,7 @@ var _doltPathSeam = {
23231
23632
  },
23232
23633
  exists: (p2) => {
23233
23634
  try {
23234
- fs53.accessSync(p2, fs53.constants.F_OK);
23635
+ fs56.accessSync(p2, fs56.constants.F_OK);
23235
23636
  return true;
23236
23637
  } catch {
23237
23638
  return false;
@@ -23242,7 +23643,7 @@ function doltBinaryNames(platform3) {
23242
23643
  return platform3 === "win32" ? ["dolt.exe", "dolt.cmd", "dolt"] : ["dolt"];
23243
23644
  }
23244
23645
  function knownDoltDirs(platform3) {
23245
- const P3 = platform3 === "win32" ? path56.win32 : path56.posix;
23646
+ const P3 = platform3 === "win32" ? path59.win32 : path59.posix;
23246
23647
  const home = _doltPathSeam.homedir();
23247
23648
  if (platform3 === "win32") {
23248
23649
  return [
@@ -23258,7 +23659,7 @@ function knownDoltDirs(platform3) {
23258
23659
  ].filter(Boolean);
23259
23660
  }
23260
23661
  function ensureDoltResolvable(platform3 = process.platform) {
23261
- const P3 = platform3 === "win32" ? path56.win32 : path56.posix;
23662
+ const P3 = platform3 === "win32" ? path59.win32 : path59.posix;
23262
23663
  const delim = platform3 === "win32" ? ";" : ":";
23263
23664
  const names = doltBinaryNames(platform3);
23264
23665
  const pathDirs = _doltPathSeam.getPath().split(delim).filter(Boolean);
@@ -23294,7 +23695,7 @@ function _defaultDoltInstallSpawn(strategy) {
23294
23695
  };
23295
23696
  let proc;
23296
23697
  try {
23297
- proc = (0, import_child_process21.spawn)(strategy.command, strategy.args, {
23698
+ proc = (0, import_child_process22.spawn)(strategy.command, strategy.args, {
23298
23699
  env: process.env,
23299
23700
  stdio: ["ignore", "pipe", "pipe"]
23300
23701
  });
@@ -23391,89 +23792,6 @@ async function ensureSharedServer(adapter, options = {}) {
23391
23792
  return { up: false, started: false };
23392
23793
  }
23393
23794
 
23394
- // src/beads/project-key.ts
23395
- var import_child_process22 = require("child_process");
23396
- var crypto2 = __toESM(require("crypto"));
23397
- var fs54 = __toESM(require("fs"));
23398
- var path57 = __toESM(require("path"));
23399
- function normalizeOrigin(raw) {
23400
- const trimmed = raw.trim();
23401
- if (!trimmed) return null;
23402
- let host2;
23403
- let pathPart;
23404
- const scpLike = /^[^/@]+@([^:]+):(.+)$/.exec(trimmed);
23405
- if (scpLike && !trimmed.includes("://")) {
23406
- host2 = scpLike[1];
23407
- pathPart = scpLike[2];
23408
- } else {
23409
- let url2;
23410
- try {
23411
- url2 = new URL(trimmed);
23412
- } catch {
23413
- return null;
23414
- }
23415
- host2 = url2.hostname;
23416
- pathPart = url2.pathname;
23417
- }
23418
- host2 = host2.toLowerCase();
23419
- pathPart = pathPart.replace(/^\/+/, "").replace(/\.git$/i, "").replace(/\/+$/, "");
23420
- if (!host2 || !pathPart) return null;
23421
- return `${host2}/${pathPart}`;
23422
- }
23423
- function findRepoRoot(cwd) {
23424
- let dir = path57.resolve(cwd);
23425
- const seen = /* @__PURE__ */ new Set();
23426
- for (let i = 0; i < 256; i++) {
23427
- if (seen.has(dir)) return null;
23428
- seen.add(dir);
23429
- try {
23430
- const stat3 = fs54.statSync(path57.join(dir, ".git"), { throwIfNoEntry: false });
23431
- if (stat3 && (stat3.isDirectory() || stat3.isFile())) return dir;
23432
- } catch {
23433
- }
23434
- const parent = path57.dirname(dir);
23435
- if (parent === dir) return null;
23436
- dir = parent;
23437
- }
23438
- return null;
23439
- }
23440
- var _execSeam2 = {
23441
- exec: (file, args2, opts) => {
23442
- const out2 = (0, import_child_process22.execFileSync)(file, args2, opts);
23443
- return typeof out2 === "string" ? out2 : out2.toString("utf8");
23444
- },
23445
- realpath: (p2) => fs54.realpathSync(p2)
23446
- };
23447
- function readOrigin(cwd) {
23448
- try {
23449
- const raw = _execSeam2.exec("git", ["remote", "get-url", "origin"], {
23450
- cwd,
23451
- timeout: 1e3,
23452
- stdio: ["ignore", "pipe", "ignore"],
23453
- encoding: "utf8"
23454
- });
23455
- return raw.trim() || null;
23456
- } catch {
23457
- return null;
23458
- }
23459
- }
23460
- function deriveProjectIdentity(cwd = process.cwd()) {
23461
- const repoRoot = findRepoRoot(cwd) ?? cwd;
23462
- const origin = readOrigin(repoRoot);
23463
- const normalized = origin ? normalizeOrigin(origin) : null;
23464
- if (normalized) {
23465
- const label = normalized.split("/").pop() || normalized;
23466
- return { projectKey: normalized, projectLabel: label };
23467
- }
23468
- let real = repoRoot;
23469
- try {
23470
- real = _execSeam2.realpath(repoRoot);
23471
- } catch {
23472
- }
23473
- const hash = crypto2.createHash("sha256").update(real).digest("hex");
23474
- return { projectKey: `path:${hash}`, projectLabel: path57.basename(real) || "project" };
23475
- }
23476
-
23477
23795
  // src/beads/project-prefix.ts
23478
23796
  var crypto3 = __toESM(require("crypto"));
23479
23797
  function prefixForProjectKey(projectKey) {
@@ -23521,14 +23839,14 @@ var _linkSeam = {
23521
23839
  homedir: () => os44.homedir(),
23522
23840
  isWritableDir: (dir) => {
23523
23841
  try {
23524
- fs55.accessSync(dir, fs55.constants.W_OK);
23842
+ fs57.accessSync(dir, fs57.constants.W_OK);
23525
23843
  return true;
23526
23844
  } catch {
23527
23845
  return false;
23528
23846
  }
23529
23847
  },
23530
23848
  ensureDir: (dir) => {
23531
- fs55.mkdirSync(dir, { recursive: true });
23849
+ fs57.mkdirSync(dir, { recursive: true });
23532
23850
  },
23533
23851
  /**
23534
23852
  * A directory to symlink `bd` into so the AGENT's shell + Claude Code's
@@ -23549,9 +23867,9 @@ var _linkSeam = {
23549
23867
  * which `linkBdOntoPath` creates if missing.
23550
23868
  */
23551
23869
  cliBinDir: () => {
23552
- const pathDirs = (process.env.PATH ?? "").split(path58.delimiter).filter(Boolean);
23870
+ const pathDirs = (process.env.PATH ?? "").split(path60.delimiter).filter(Boolean);
23553
23871
  const home = _linkSeam.homedir();
23554
- const localBin = home ? path58.join(home, ".local", "bin") : null;
23872
+ const localBin = home ? path60.join(home, ".local", "bin") : null;
23555
23873
  if (localBin) {
23556
23874
  try {
23557
23875
  _linkSeam.ensureDir(localBin);
@@ -23561,16 +23879,16 @@ var _linkSeam = {
23561
23879
  const candidates = [];
23562
23880
  if (localBin) candidates.push(localBin);
23563
23881
  try {
23564
- candidates.push(path58.dirname(process.execPath));
23882
+ candidates.push(path60.dirname(process.execPath));
23565
23883
  } catch {
23566
23884
  }
23567
23885
  candidates.push("/usr/local/bin");
23568
23886
  const entry = process.argv[1];
23569
23887
  if (entry) {
23570
23888
  try {
23571
- candidates.push(path58.dirname(fs55.realpathSync(entry)));
23889
+ candidates.push(path60.dirname(fs57.realpathSync(entry)));
23572
23890
  } catch {
23573
- candidates.push(path58.dirname(entry));
23891
+ candidates.push(path60.dirname(entry));
23574
23892
  }
23575
23893
  }
23576
23894
  const onPathWritable = candidates.find(
@@ -23582,20 +23900,20 @@ var _linkSeam = {
23582
23900
  /** Current symlink target at `linkPath`, or null when absent / not a link. */
23583
23901
  readlink: (linkPath) => {
23584
23902
  try {
23585
- return fs55.readlinkSync(linkPath);
23903
+ return fs57.readlinkSync(linkPath);
23586
23904
  } catch {
23587
23905
  return null;
23588
23906
  }
23589
23907
  },
23590
- unlink: (linkPath) => fs55.unlinkSync(linkPath),
23591
- symlink: (target, linkPath) => fs55.symlinkSync(target, linkPath)
23908
+ unlink: (linkPath) => fs57.unlinkSync(linkPath),
23909
+ symlink: (target, linkPath) => fs57.symlinkSync(target, linkPath)
23592
23910
  };
23593
23911
  function linkBdOntoPath(binaryPath) {
23594
23912
  if (_linkSeam.platform() === "win32") return;
23595
23913
  const binDir = _linkSeam.cliBinDir();
23596
23914
  if (!binDir) return;
23597
23915
  _linkSeam.ensureDir(binDir);
23598
- const linkPath = path58.join(binDir, "bd");
23916
+ const linkPath = path60.join(binDir, "bd");
23599
23917
  if (linkPath === binaryPath) return;
23600
23918
  const current = _linkSeam.readlink(linkPath);
23601
23919
  if (current === binaryPath) return;
@@ -23790,7 +24108,7 @@ function dedupeRecipes(agents) {
23790
24108
 
23791
24109
  // src/beads/watcher.ts
23792
24110
  var crypto4 = __toESM(require("crypto"));
23793
- var path59 = __toESM(require("path"));
24111
+ var path61 = __toESM(require("path"));
23794
24112
  var API_BASE6 = resolveApiBaseUrl();
23795
24113
  var DEBOUNCE_MS2 = 400;
23796
24114
  var ZERO_SUMMARY = {
@@ -23814,7 +24132,7 @@ var BeadsWatcher = class {
23814
24132
  constructor(opts) {
23815
24133
  this.opts = opts;
23816
24134
  this.bd = opts.adapter ?? new BdAdapter({ cwd: opts.cwd, beadsDir: opts.beadsDir });
23817
- this.feedPath = opts.feedPath ?? path59.join(opts.cwd ?? process.cwd(), ".beads", "last-touched");
24135
+ this.feedPath = opts.feedPath ?? path61.join(opts.cwd ?? process.cwd(), ".beads", "last-touched");
23818
24136
  this.apiBase = opts.apiBaseUrl ?? API_BASE6;
23819
24137
  }
23820
24138
  opts;
@@ -24313,8 +24631,8 @@ function cleanupAttachmentTempFiles() {
24313
24631
  function saveFilesTemp(files) {
24314
24632
  return files.filter(({ base64 }) => base64 && base64.length > 0).map(({ filename, base64 }) => {
24315
24633
  const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
24316
- const tmpPath = path62.join(os48.tmpdir(), `codeam-${(0, import_crypto3.randomUUID)()}-${safeName}`);
24317
- fs58.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
24634
+ const tmpPath = path64.join(os48.tmpdir(), `codeam-${(0, import_crypto3.randomUUID)()}-${safeName}`);
24635
+ fs60.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
24318
24636
  pendingAttachmentFiles.add(tmpPath);
24319
24637
  return tmpPath;
24320
24638
  });
@@ -24526,9 +24844,10 @@ var listFiles = async (ctx, cmd, parsed) => {
24526
24844
  await ctx.relay.sendResult(cmd.id, "completed", result);
24527
24845
  };
24528
24846
  var envReadH = async (ctx, cmd) => {
24529
- const envPath = path62.join(process.cwd(), ".env");
24847
+ const envPath = path64.join(process.cwd(), ".env");
24848
+ await restoreProjectEnvIfMissing(process.cwd(), ctx);
24530
24849
  try {
24531
- const raw = await fs58.promises.readFile(envPath, "utf8");
24850
+ const raw = await fs60.promises.readFile(envPath, "utf8");
24532
24851
  await ctx.relay.sendResult(cmd.id, "completed", {
24533
24852
  exists: true,
24534
24853
  vars: parseDotenv(raw)
@@ -24559,14 +24878,15 @@ var envWriteH = async (ctx, cmd, parsed) => {
24559
24878
  }
24560
24879
  seen.add(v.key);
24561
24880
  }
24562
- const envPath = path62.join(process.cwd(), ".env");
24563
- const tmpPath = path62.join(process.cwd(), ".env.codeam.tmp");
24881
+ const envPath = path64.join(process.cwd(), ".env");
24882
+ const tmpPath = path64.join(process.cwd(), ".env.codeam.tmp");
24564
24883
  try {
24565
- await fs58.promises.writeFile(tmpPath, serializeDotenv(vars), "utf8");
24566
- await fs58.promises.rename(tmpPath, envPath);
24884
+ await fs60.promises.writeFile(tmpPath, serializeDotenv(vars), "utf8");
24885
+ await fs60.promises.rename(tmpPath, envPath);
24567
24886
  await ctx.relay.sendResult(cmd.id, "completed", { ok: true, count: vars.length });
24887
+ void syncProjectEnvUp(process.cwd(), ctx);
24568
24888
  } catch (err) {
24569
- await fs58.promises.rm(tmpPath, { force: true }).catch(() => void 0);
24889
+ await fs60.promises.rm(tmpPath, { force: true }).catch(() => void 0);
24570
24890
  await ctx.relay.sendResult(cmd.id, "failed", { error: err.message });
24571
24891
  }
24572
24892
  };
@@ -24615,7 +24935,7 @@ var headroomConfigureH = async (ctx, cmd, parsed) => {
24615
24935
  let configuredAgent = rawAgentId;
24616
24936
  if (!configuredAgent) {
24617
24937
  try {
24618
- const raw = JSON.parse(fs58.readFileSync(headroomConfigPath(), "utf8"));
24938
+ const raw = JSON.parse(fs60.readFileSync(headroomConfigPath(), "utf8"));
24619
24939
  configuredAgent = raw.agent ?? "";
24620
24940
  } catch {
24621
24941
  }
@@ -24649,7 +24969,7 @@ var headroomConfigureH = async (ctx, cmd, parsed) => {
24649
24969
  persist: persistHeadroomConfig,
24650
24970
  readEnabled: () => {
24651
24971
  try {
24652
- const raw = JSON.parse(fs58.readFileSync(headroomConfigPath(), "utf8"));
24972
+ const raw = JSON.parse(fs60.readFileSync(headroomConfigPath(), "utf8"));
24653
24973
  return raw.enabled === true;
24654
24974
  } catch {
24655
24975
  return false;
@@ -24953,7 +25273,7 @@ var headroomBudgetH = async (ctx, cmd) => {
24953
25273
  }
24954
25274
  let headroomActive = false;
24955
25275
  try {
24956
- const raw = JSON.parse(fs58.readFileSync(headroomConfigPath(), "utf8"));
25276
+ const raw = JSON.parse(fs60.readFileSync(headroomConfigPath(), "utf8"));
24957
25277
  headroomActive = raw.enabled === true;
24958
25278
  } catch {
24959
25279
  }
@@ -24963,7 +25283,7 @@ var headroomBudgetH = async (ctx, cmd) => {
24963
25283
  }
24964
25284
  let existingConfig = { enabled: true };
24965
25285
  try {
24966
- existingConfig = JSON.parse(fs58.readFileSync(headroomConfigPath(), "utf8"));
25286
+ existingConfig = JSON.parse(fs60.readFileSync(headroomConfigPath(), "utf8"));
24967
25287
  } catch {
24968
25288
  }
24969
25289
  if (payload.budgetEnabled && payload.budgetUsd != null) {
@@ -25076,9 +25396,9 @@ var CLI_UPDATE_MAX_ATTEMPTS = 3;
25076
25396
  function buildNpmInstallInvocation(opts) {
25077
25397
  const entryScript = opts?.entryScript ?? process.argv[1] ?? "";
25078
25398
  const execPath = opts?.execPath ?? process.execPath;
25079
- const exists2 = opts?.existsSync ?? fs58.existsSync;
25399
+ const exists2 = opts?.existsSync ?? fs60.existsSync;
25080
25400
  const platform3 = opts?.platform ?? process.platform;
25081
- const p2 = platform3 === "win32" ? path62.win32 : path62.posix;
25401
+ const p2 = platform3 === "win32" ? path64.win32 : path64.posix;
25082
25402
  const normalized = entryScript.split(/[\\/]/).join("/");
25083
25403
  const marker = "/lib/node_modules/codeam-cli/";
25084
25404
  const markerIdx = normalized.indexOf(marker);
@@ -25100,7 +25420,7 @@ function isPermissionError(stderr) {
25100
25420
  function resolveGlobalNodeModulesDir(opts) {
25101
25421
  const entryScript = opts?.entryScript ?? process.argv[1] ?? "";
25102
25422
  const platform3 = opts?.platform ?? process.platform;
25103
- const p2 = platform3 === "win32" ? path62.win32 : path62.posix;
25423
+ const p2 = platform3 === "win32" ? path64.win32 : path64.posix;
25104
25424
  const marker = "/lib/node_modules/codeam-cli/";
25105
25425
  const markerIdx = entryScript.split(/[\\/]/).join("/").indexOf(marker);
25106
25426
  if (markerIdx <= 0) return null;
@@ -25110,9 +25430,9 @@ function resolveGlobalNodeModulesDir(opts) {
25110
25430
  var STALE_STAGING_AGE_MS = CLI_UPDATE_INSTALL_TIMEOUT_MS;
25111
25431
  function sweepStaleCliStagingDirs(nodeModulesDir, now = Date.now(), deps) {
25112
25432
  if (!nodeModulesDir) return 0;
25113
- const readdirSync12 = deps?.readdirSync ?? fs58.readdirSync;
25114
- const statSync17 = deps?.statSync ?? fs58.statSync;
25115
- const rmSync8 = deps?.rmSync ?? fs58.rmSync;
25433
+ const readdirSync12 = deps?.readdirSync ?? fs60.readdirSync;
25434
+ const statSync17 = deps?.statSync ?? fs60.statSync;
25435
+ const rmSync8 = deps?.rmSync ?? fs60.rmSync;
25116
25436
  let removed = 0;
25117
25437
  let entries;
25118
25438
  try {
@@ -25122,7 +25442,7 @@ function sweepStaleCliStagingDirs(nodeModulesDir, now = Date.now(), deps) {
25122
25442
  }
25123
25443
  for (const name of entries) {
25124
25444
  if (!/^\.codeam-cli-/.test(name)) continue;
25125
- const full = path62.join(nodeModulesDir, name);
25445
+ const full = path64.join(nodeModulesDir, name);
25126
25446
  try {
25127
25447
  const st3 = statSync17(full);
25128
25448
  if (now - st3.mtimeMs < STALE_STAGING_AGE_MS) continue;
@@ -25611,7 +25931,12 @@ function startPreviewFromDetection(ctx, detection, pluginAuthToken) {
25611
25931
  sessionId: ctx.sessionId,
25612
25932
  detection,
25613
25933
  cwd: process.cwd(),
25614
- emit: emit2
25934
+ emit: emit2,
25935
+ // Auth for the per-repo `.env` vault restore, performed INSIDE the bring-up
25936
+ // (provisionDeps stage, after the reuse short-circuit) so a fresh session of
25937
+ // this repo picks up its saved `.env` before the dev server spawns. Optional
25938
+ // — a caller without a token just skips the restore.
25939
+ projectEnvAuth: { pluginId: ctx.pluginId, pluginAuthToken }
25615
25940
  }).catch((err) => {
25616
25941
  const message = err instanceof Error ? err.message : String(err);
25617
25942
  log.warn("preview", `start crashed before ready: ${message}`);
@@ -25984,11 +26309,11 @@ function resolveTokenValue(args2) {
25984
26309
  }
25985
26310
  const fileFlag = args2.find((a) => a.startsWith("--token-file="));
25986
26311
  if (fileFlag) {
25987
- const path82 = fileFlag.slice("--token-file=".length);
26312
+ const path84 = fileFlag.slice("--token-file=".length);
25988
26313
  try {
25989
- const content = fs59.readFileSync(path82, "utf8").trim();
25990
- if (content.length === 0) fail(`--token-file ${path82} is empty`);
25991
- rmIfExistsQuiet(path82);
26314
+ const content = fs61.readFileSync(path84, "utf8").trim();
26315
+ if (content.length === 0) fail(`--token-file ${path84} is empty`);
26316
+ rmIfExistsQuiet(path84);
25992
26317
  return content;
25993
26318
  } catch (err) {
25994
26319
  fail(`Could not read --token-file: ${err.message}`);
@@ -26078,7 +26403,7 @@ async function claim(token, pluginId, pluginSecretHash) {
26078
26403
  }
26079
26404
  }
26080
26405
  function pairAutoLockPath() {
26081
- return path63.join(os49.homedir(), ".codeam", "pair-auto.lock");
26406
+ return path65.join(os49.homedir(), ".codeam", "pair-auto.lock");
26082
26407
  }
26083
26408
  function isLivePairAuto(pid) {
26084
26409
  if (!Number.isInteger(pid) || pid <= 0 || pid === process.pid) return false;
@@ -26088,7 +26413,7 @@ function isLivePairAuto(pid) {
26088
26413
  if (e.code !== "EPERM") return false;
26089
26414
  }
26090
26415
  try {
26091
- return fs59.readFileSync(`/proc/${pid}/cmdline`, "utf8").includes("codeam");
26416
+ return fs61.readFileSync(`/proc/${pid}/cmdline`, "utf8").includes("codeam");
26092
26417
  } catch {
26093
26418
  return true;
26094
26419
  }
@@ -26098,24 +26423,24 @@ function isLiveCodeam(pid) {
26098
26423
  }
26099
26424
  function daemonLockPath(sessionId) {
26100
26425
  const safe = sessionId.replace(/[^a-zA-Z0-9_-]/g, "_");
26101
- return path63.join(os49.homedir(), ".codeam", `daemon-${safe}.lock`);
26426
+ return path65.join(os49.homedir(), ".codeam", `daemon-${safe}.lock`);
26102
26427
  }
26103
26428
  function acquireDaemonLock(sessionId) {
26104
26429
  const lockPath = daemonLockPath(sessionId);
26105
26430
  try {
26106
- fs59.mkdirSync(path63.dirname(lockPath), { recursive: true });
26431
+ fs61.mkdirSync(path65.dirname(lockPath), { recursive: true });
26107
26432
  try {
26108
- fs59.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
26433
+ fs61.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
26109
26434
  } catch (e) {
26110
26435
  if (e.code !== "EEXIST") throw e;
26111
- const holder = Number(fs59.readFileSync(lockPath, "utf8").trim());
26436
+ const holder = Number(fs61.readFileSync(lockPath, "utf8").trim());
26112
26437
  if (holder && holder !== process.pid && isLiveCodeam(holder)) return false;
26113
- fs59.writeFileSync(lockPath, String(process.pid));
26438
+ fs61.writeFileSync(lockPath, String(process.pid));
26114
26439
  }
26115
26440
  const release3 = () => {
26116
26441
  try {
26117
- if (fs59.existsSync(lockPath) && Number(fs59.readFileSync(lockPath, "utf8").trim()) === process.pid) {
26118
- fs59.unlinkSync(lockPath);
26442
+ if (fs61.existsSync(lockPath) && Number(fs61.readFileSync(lockPath, "utf8").trim()) === process.pid) {
26443
+ fs61.unlinkSync(lockPath);
26119
26444
  }
26120
26445
  } catch {
26121
26446
  }
@@ -26137,19 +26462,19 @@ function acquireDaemonLock(sessionId) {
26137
26462
  function acquireSingletonLock() {
26138
26463
  const lockPath = pairAutoLockPath();
26139
26464
  try {
26140
- fs59.mkdirSync(path63.dirname(lockPath), { recursive: true });
26465
+ fs61.mkdirSync(path65.dirname(lockPath), { recursive: true });
26141
26466
  try {
26142
- fs59.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
26467
+ fs61.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
26143
26468
  } catch (e) {
26144
26469
  if (e.code !== "EEXIST") throw e;
26145
- const holder = Number(fs59.readFileSync(lockPath, "utf8").trim());
26470
+ const holder = Number(fs61.readFileSync(lockPath, "utf8").trim());
26146
26471
  if (isLivePairAuto(holder)) return false;
26147
- fs59.writeFileSync(lockPath, String(process.pid));
26472
+ fs61.writeFileSync(lockPath, String(process.pid));
26148
26473
  }
26149
26474
  process.once("exit", () => {
26150
26475
  try {
26151
- if (fs59.existsSync(lockPath) && Number(fs59.readFileSync(lockPath, "utf8").trim()) === process.pid) {
26152
- fs59.unlinkSync(lockPath);
26476
+ if (fs61.existsSync(lockPath) && Number(fs61.readFileSync(lockPath, "utf8").trim()) === process.pid) {
26477
+ fs61.unlinkSync(lockPath);
26153
26478
  }
26154
26479
  } catch {
26155
26480
  }
@@ -26601,10 +26926,10 @@ var AgentService = class _AgentService {
26601
26926
  };
26602
26927
 
26603
26928
  // src/agents/acp/adapters.ts
26604
- var path65 = __toESM(require("path"));
26929
+ var path67 = __toESM(require("path"));
26605
26930
 
26606
26931
  // src/agents/acp/agent-binary.ts
26607
- var import_fs4 = __toESM(require("fs"));
26932
+ var import_fs6 = __toESM(require("fs"));
26608
26933
  var import_os11 = __toESM(require("os"));
26609
26934
  var import_path8 = __toESM(require("path"));
26610
26935
  var import_child_process26 = require("child_process");
@@ -26634,7 +26959,7 @@ function defaultSdkDir() {
26634
26959
  return resolveSdkDirViaRequire();
26635
26960
  }
26636
26961
  function resolveClaudeNativeBinary(deps = {}) {
26637
- const existsSync27 = deps.existsSync ?? import_fs4.default.existsSync;
26962
+ const existsSync27 = deps.existsSync ?? import_fs6.default.existsSync;
26638
26963
  const platformKey = deps.platformKey ?? currentPlatformKey();
26639
26964
  const sdkDir = deps.sdkDir !== void 0 ? deps.sdkDir : defaultSdkDir();
26640
26965
  if (!sdkDir) return null;
@@ -26692,7 +27017,7 @@ async function waitForCommandOnPath(cmd, opts = {}) {
26692
27017
  return check();
26693
27018
  }
26694
27019
  function resolveCursorAgentBinary(deps = {}) {
26695
- const existsSync27 = deps.existsSync ?? import_fs4.default.existsSync;
27020
+ const existsSync27 = deps.existsSync ?? import_fs6.default.existsSync;
26696
27021
  const platform3 = deps.platform ?? process.platform;
26697
27022
  const env = deps.env ?? process.env;
26698
27023
  if (platform3 === "win32") {
@@ -26891,13 +27216,13 @@ function resolveBin(pkgName, binName) {
26891
27216
  try {
26892
27217
  const manifestPath = require_.resolve(`${pkgName}/package.json`);
26893
27218
  const manifest = require_(`${pkgName}/package.json`);
26894
- const pkgDir = path65.dirname(manifestPath);
27219
+ const pkgDir = path67.dirname(manifestPath);
26895
27220
  const bin = manifest.bin;
26896
27221
  if (!bin) return null;
26897
- if (typeof bin === "string") return path65.resolve(pkgDir, bin);
27222
+ if (typeof bin === "string") return path67.resolve(pkgDir, bin);
26898
27223
  const target = binName ?? Object.keys(bin)[0];
26899
27224
  if (!target || !bin[target]) return null;
26900
- return path65.resolve(pkgDir, bin[target]);
27225
+ return path67.resolve(pkgDir, bin[target]);
26901
27226
  } catch {
26902
27227
  return null;
26903
27228
  }
@@ -27047,8 +27372,8 @@ async function resolveAcpAdapterWithRetry(agent, opts = {}) {
27047
27372
  var import_node_crypto11 = require("crypto");
27048
27373
 
27049
27374
  // src/services/history.service.ts
27050
- var fs61 = __toESM(require("fs"));
27051
- var path66 = __toESM(require("path"));
27375
+ var fs63 = __toESM(require("fs"));
27376
+ var path68 = __toESM(require("path"));
27052
27377
  var os51 = __toESM(require("os"));
27053
27378
  var https7 = __toESM(require("https"));
27054
27379
  var http6 = __toESM(require("http"));
@@ -27076,7 +27401,7 @@ function parseJsonl(filePath) {
27076
27401
  const messages = [];
27077
27402
  let raw;
27078
27403
  try {
27079
- raw = fs61.readFileSync(filePath, "utf8");
27404
+ raw = fs63.readFileSync(filePath, "utf8");
27080
27405
  } catch (err) {
27081
27406
  if (err.code !== "ENOENT") {
27082
27407
  log.warn("history:parseJsonl", `read failed for ${filePath}`, err);
@@ -27217,7 +27542,7 @@ var HistoryService = class _HistoryService {
27217
27542
  return this._quotaPercent === null || Date.now() - this._quotaFetchedAt > ttlMs;
27218
27543
  }
27219
27544
  get projectDir() {
27220
- return this.runtime.resolveHistoryDir(this.cwd) ?? path66.join(os51.homedir(), ".claude", "projects", encodeCwd(this.cwd));
27545
+ return this.runtime.resolveHistoryDir(this.cwd) ?? path68.join(os51.homedir(), ".claude", "projects", encodeCwd(this.cwd));
27221
27546
  }
27222
27547
  /** Set the current Claude conversation ID (extracted from /cost command or session start) */
27223
27548
  setCurrentConversationId(id) {
@@ -27229,7 +27554,7 @@ var HistoryService = class _HistoryService {
27229
27554
  /** Return the current message count in the active conversation. */
27230
27555
  getCurrentMessageCount() {
27231
27556
  if (!this.currentConversationId) return 0;
27232
- const filePath = path66.join(this.projectDir, `${this.currentConversationId}.jsonl`);
27557
+ const filePath = path68.join(this.projectDir, `${this.currentConversationId}.jsonl`);
27233
27558
  return parseJsonl(filePath).length;
27234
27559
  }
27235
27560
  /**
@@ -27240,7 +27565,7 @@ var HistoryService = class _HistoryService {
27240
27565
  const deadline = Date.now() + timeoutMs;
27241
27566
  while (Date.now() < deadline) {
27242
27567
  if (!this.currentConversationId) return null;
27243
- const filePath = path66.join(this.projectDir, `${this.currentConversationId}.jsonl`);
27568
+ const filePath = path68.join(this.projectDir, `${this.currentConversationId}.jsonl`);
27244
27569
  const messages = parseJsonl(filePath);
27245
27570
  if (messages.length > previousCount) {
27246
27571
  for (let i = messages.length - 1; i >= previousCount; i--) {
@@ -27266,16 +27591,16 @@ var HistoryService = class _HistoryService {
27266
27591
  const dir = this.projectDir;
27267
27592
  const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
27268
27593
  try {
27269
- const files = fs61.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
27594
+ const files = fs63.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
27270
27595
  try {
27271
- const stat3 = fs61.statSync(path66.join(dir, e.name));
27596
+ const stat3 = fs63.statSync(path68.join(dir, e.name));
27272
27597
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
27273
27598
  } catch {
27274
27599
  return { name: e.name, mtime: 0, birthtime: 0 };
27275
27600
  }
27276
27601
  }).filter((f) => f.birthtime >= cutoff).sort((a, b) => b.mtime - a.mtime);
27277
27602
  if (files.length > 0) {
27278
- this.currentConversationId = path66.basename(files[0].name, ".jsonl");
27603
+ this.currentConversationId = path68.basename(files[0].name, ".jsonl");
27279
27604
  }
27280
27605
  } catch {
27281
27606
  }
@@ -27309,13 +27634,13 @@ var HistoryService = class _HistoryService {
27309
27634
  const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
27310
27635
  let entries;
27311
27636
  try {
27312
- entries = fs61.readdirSync(dir, { withFileTypes: true });
27637
+ entries = fs63.readdirSync(dir, { withFileTypes: true });
27313
27638
  } catch {
27314
27639
  return null;
27315
27640
  }
27316
27641
  const files = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
27317
27642
  try {
27318
- const stat3 = fs61.statSync(path66.join(dir, e.name));
27643
+ const stat3 = fs63.statSync(path68.join(dir, e.name));
27319
27644
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
27320
27645
  } catch {
27321
27646
  return { name: e.name, mtime: 0, birthtime: 0 };
@@ -27324,12 +27649,12 @@ var HistoryService = class _HistoryService {
27324
27649
  if (files.length === 0) return null;
27325
27650
  const targetFile = this.currentConversationId ? `${this.currentConversationId}.jsonl` : files[0].name;
27326
27651
  if (!files.some((f) => f.name === targetFile)) return null;
27327
- return this.extractUsageFromFile(path66.join(dir, targetFile));
27652
+ return this.extractUsageFromFile(path68.join(dir, targetFile));
27328
27653
  }
27329
27654
  extractUsageFromFile(filePath) {
27330
27655
  let raw;
27331
27656
  try {
27332
- raw = fs61.readFileSync(filePath, "utf8");
27657
+ raw = fs63.readFileSync(filePath, "utf8");
27333
27658
  } catch {
27334
27659
  return null;
27335
27660
  }
@@ -27374,9 +27699,9 @@ var HistoryService = class _HistoryService {
27374
27699
  let totalCost = 0;
27375
27700
  let files;
27376
27701
  try {
27377
- files = fs61.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
27702
+ files = fs63.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
27378
27703
  try {
27379
- return fs61.statSync(path66.join(projectDir, f)).mtimeMs >= monthStartMs;
27704
+ return fs63.statSync(path68.join(projectDir, f)).mtimeMs >= monthStartMs;
27380
27705
  } catch {
27381
27706
  return false;
27382
27707
  }
@@ -27387,7 +27712,7 @@ var HistoryService = class _HistoryService {
27387
27712
  for (const file of files) {
27388
27713
  let raw;
27389
27714
  try {
27390
- raw = fs61.readFileSync(path66.join(projectDir, file), "utf8");
27715
+ raw = fs63.readFileSync(path68.join(projectDir, file), "utf8");
27391
27716
  } catch {
27392
27717
  continue;
27393
27718
  }
@@ -27466,7 +27791,7 @@ var HistoryService = class _HistoryService {
27466
27791
  if (this.runtime.resolveHistoryFile) {
27467
27792
  return this.runtime.resolveHistoryFile(this.cwd, sessionId);
27468
27793
  }
27469
- return path66.join(this.projectDir, `${sessionId}.jsonl`);
27794
+ return path68.join(this.projectDir, `${sessionId}.jsonl`);
27470
27795
  }
27471
27796
  /**
27472
27797
  * Parse a conversation's messages from disk, agent-aware. Claude uses the
@@ -27500,7 +27825,7 @@ var HistoryService = class _HistoryService {
27500
27825
  };
27501
27826
  });
27502
27827
  }
27503
- return parseJsonl(path66.join(this.projectDir, `${sessionId}.jsonl`));
27828
+ return parseJsonl(path68.join(this.projectDir, `${sessionId}.jsonl`));
27504
27829
  }
27505
27830
  async loadConversation(sessionId) {
27506
27831
  const messages = this.readConversation(sessionId);
@@ -27568,7 +27893,7 @@ var HistoryService = class _HistoryService {
27568
27893
  if (!filePath) return false;
27569
27894
  let mtimeMs;
27570
27895
  try {
27571
- mtimeMs = fs61.statSync(filePath).mtimeMs;
27896
+ mtimeMs = fs63.statSync(filePath).mtimeMs;
27572
27897
  } catch {
27573
27898
  return false;
27574
27899
  }
@@ -27643,10 +27968,10 @@ var HistoryService = class _HistoryService {
27643
27968
 
27644
27969
  // src/agents/acp/client.ts
27645
27970
  var import_node_child_process29 = require("child_process");
27646
- var fs62 = __toESM(require("fs/promises"));
27971
+ var fs64 = __toESM(require("fs/promises"));
27647
27972
  var fsSync = __toESM(require("fs"));
27648
27973
  var os53 = __toESM(require("os"));
27649
- var path68 = __toESM(require("path"));
27974
+ var path70 = __toESM(require("path"));
27650
27975
  var import_node_stream = require("stream");
27651
27976
 
27652
27977
  // ../../node_modules/@agentclientprotocol/sdk/dist/schema/index.js
@@ -31672,7 +31997,7 @@ function createIdleTimeout(idleMs, makeError, activeIdleMs = idleMs) {
31672
31997
  }
31673
31998
 
31674
31999
  // src/agents/acp/internal-paths.ts
31675
- var path67 = __toESM(require("path"));
32000
+ var path69 = __toESM(require("path"));
31676
32001
  var os52 = __toESM(require("os"));
31677
32002
  var INTERNAL_TOKENS = [".codeam", "house-claude"];
31678
32003
  function textReferencesInternal(text) {
@@ -31681,10 +32006,10 @@ function textReferencesInternal(text) {
31681
32006
  }
31682
32007
  function pathIsInternal(p2, homeDir2 = os52.homedir()) {
31683
32008
  if (!p2) return false;
31684
- const abs = path67.resolve(p2);
31685
- const home = path67.resolve(homeDir2);
31686
- const within = (root) => abs === root || abs.startsWith(root + path67.sep);
31687
- return within(path67.join(home, ".codeam")) || within(path67.join(home, ".beads")) || abs === path67.join(home, ".codeam-host.log") || abs.includes(`${path67.sep}house-claude${path67.sep}`) || abs.endsWith(`${path67.sep}house-claude`);
32009
+ const abs = path69.resolve(p2);
32010
+ const home = path69.resolve(homeDir2);
32011
+ const within = (root) => abs === root || abs.startsWith(root + path69.sep);
32012
+ return within(path69.join(home, ".codeam")) || within(path69.join(home, ".beads")) || abs === path69.join(home, ".codeam-host.log") || abs.includes(`${path69.sep}house-claude${path69.sep}`) || abs.endsWith(`${path69.sep}house-claude`);
31688
32013
  }
31689
32014
  function toolCallReferencesInternal(call) {
31690
32015
  if (textReferencesInternal(call.title)) return true;
@@ -32513,7 +32838,7 @@ var AcpClient = class {
32513
32838
  throw new RequestError(-32002, INTERNAL_BLOCK_REASON, { uri: params.path });
32514
32839
  }
32515
32840
  try {
32516
- const content = await fs62.readFile(params.path, "utf8");
32841
+ const content = await fs64.readFile(params.path, "utf8");
32517
32842
  return applyLineRange(content, params.line ?? null, params.limit ?? null);
32518
32843
  } catch (err) {
32519
32844
  const code = err.code;
@@ -32536,7 +32861,7 @@ var AcpClient = class {
32536
32861
  throw new RequestError(-32002, INTERNAL_BLOCK_REASON, { uri: params.path });
32537
32862
  }
32538
32863
  try {
32539
- await fs62.writeFile(params.path, params.content, "utf8");
32864
+ await fs64.writeFile(params.path, params.content, "utf8");
32540
32865
  return {};
32541
32866
  } catch (err) {
32542
32867
  const code = err.code;
@@ -32601,24 +32926,24 @@ function knownAgentBinaryDirs() {
32601
32926
  out2.push("/tmp/codeam-node20/bin");
32602
32927
  for (const root of [
32603
32928
  "/usr/local/share/nvm/versions/node",
32604
- path68.join(home, ".nvm/versions/node")
32929
+ path70.join(home, ".nvm/versions/node")
32605
32930
  ]) {
32606
32931
  try {
32607
32932
  for (const child of fsSync.readdirSync(root)) {
32608
- out2.push(path68.join(root, child, "bin"));
32933
+ out2.push(path70.join(root, child, "bin"));
32609
32934
  }
32610
32935
  } catch {
32611
32936
  }
32612
32937
  }
32613
- out2.push(path68.join(home, ".volta/bin"));
32938
+ out2.push(path70.join(home, ".volta/bin"));
32614
32939
  out2.push("/usr/local/bin");
32615
32940
  out2.push("/usr/bin");
32616
- out2.push(path68.join(home, ".local/bin"));
32617
- out2.push(path68.join(home, "bin"));
32941
+ out2.push(path70.join(home, ".local/bin"));
32942
+ out2.push(path70.join(home, "bin"));
32618
32943
  if (process.platform === "win32") {
32619
32944
  const { LOCALAPPDATA, APPDATA } = process.env;
32620
- if (LOCALAPPDATA) out2.push(path68.join(LOCALAPPDATA, "cursor-agent"));
32621
- if (APPDATA) out2.push(path68.join(APPDATA, "npm"));
32945
+ if (LOCALAPPDATA) out2.push(path70.join(LOCALAPPDATA, "cursor-agent"));
32946
+ if (APPDATA) out2.push(path70.join(APPDATA, "npm"));
32622
32947
  }
32623
32948
  return out2.filter((p2) => {
32624
32949
  try {
@@ -32630,7 +32955,7 @@ function knownAgentBinaryDirs() {
32630
32955
  }
32631
32956
  function expandPathForAgentBinaries(existingPath) {
32632
32957
  const existing = new Set(
32633
- existingPath.split(path68.delimiter).filter((p2) => p2.length > 0)
32958
+ existingPath.split(path70.delimiter).filter((p2) => p2.length > 0)
32634
32959
  );
32635
32960
  const additions = [];
32636
32961
  for (const dir of knownAgentBinaryDirs()) {
@@ -32640,7 +32965,7 @@ function expandPathForAgentBinaries(existingPath) {
32640
32965
  }
32641
32966
  }
32642
32967
  if (additions.length === 0) return existingPath;
32643
- return [...additions, existingPath].filter((p2) => p2.length > 0).join(path68.delimiter);
32968
+ return [...additions, existingPath].filter((p2) => p2.length > 0).join(path70.delimiter);
32644
32969
  }
32645
32970
 
32646
32971
  // src/agents/acp/headroom-budget-proxy.ts
@@ -33122,15 +33447,15 @@ function commonPrefixLength(a, b) {
33122
33447
 
33123
33448
  // src/agents/acp/onboarding.ts
33124
33449
  var import_child_process27 = require("child_process");
33125
- var fs63 = __toESM(require("fs"));
33450
+ var fs65 = __toESM(require("fs"));
33126
33451
  var os54 = __toESM(require("os"));
33127
- var path69 = __toESM(require("path"));
33452
+ var path71 = __toESM(require("path"));
33128
33453
  var _onboardingSeam = {
33129
- markerPath: (sessionId) => path69.join(os54.homedir(), ".codeam", "welcomed", `${sessionId}.done`),
33130
- exists: (p2) => fs63.existsSync(p2),
33454
+ markerPath: (sessionId) => path71.join(os54.homedir(), ".codeam", "welcomed", `${sessionId}.done`),
33455
+ exists: (p2) => fs65.existsSync(p2),
33131
33456
  write: (p2) => {
33132
- fs63.mkdirSync(path69.dirname(p2), { recursive: true });
33133
- fs63.writeFileSync(p2, "");
33457
+ fs65.mkdirSync(path71.dirname(p2), { recursive: true });
33458
+ fs65.writeFileSync(p2, "");
33134
33459
  },
33135
33460
  disabled: () => {
33136
33461
  const v = process.env.CODEAM_ONBOARDING_DISABLED;
@@ -33167,7 +33492,7 @@ function resolveRepoName(cwd) {
33167
33492
  if (name) return name;
33168
33493
  }
33169
33494
  }
33170
- const base = path69.basename(cwd || "");
33495
+ const base = path71.basename(cwd || "");
33171
33496
  if (base && !isUuid(base)) return base;
33172
33497
  return "this project";
33173
33498
  }
@@ -33425,13 +33750,13 @@ var import_crypto5 = require("crypto");
33425
33750
 
33426
33751
  // src/services/turn-files/git-changeset.ts
33427
33752
  var import_child_process28 = require("child_process");
33428
- var fs65 = __toESM(require("fs/promises"));
33429
- var path71 = __toESM(require("path"));
33753
+ var fs67 = __toESM(require("fs/promises"));
33754
+ var path73 = __toESM(require("path"));
33430
33755
 
33431
33756
  // src/services/turn-files/review-ignore.ts
33432
33757
  var import_ignore2 = __toESM(require("ignore"));
33433
- var fs64 = __toESM(require("fs"));
33434
- var path70 = __toESM(require("path"));
33758
+ var fs66 = __toESM(require("fs"));
33759
+ var path72 = __toESM(require("path"));
33435
33760
  var CURATED_REVIEW_IGNORE = [
33436
33761
  // Google Cloud SDK (the incident) — installs a huge python tree.
33437
33762
  "google-cloud-sdk/",
@@ -33470,7 +33795,7 @@ var CURATED_REVIEW_IGNORE = [
33470
33795
  function makeReviewIgnore(repoRoot) {
33471
33796
  const ig = (0, import_ignore2.default)().add(CURATED_REVIEW_IGNORE);
33472
33797
  try {
33473
- const custom = fs64.readFileSync(path70.join(repoRoot, ".codeam", "reviewignore"), "utf8");
33798
+ const custom = fs66.readFileSync(path72.join(repoRoot, ".codeam", "reviewignore"), "utf8");
33474
33799
  ig.add(custom);
33475
33800
  } catch {
33476
33801
  }
@@ -33515,7 +33840,7 @@ async function collectRepoChangeset(opts) {
33515
33840
  let stats;
33516
33841
  if (!truncated && row.fileStatus === "added" && numstatEntry === void 0) {
33517
33842
  const lineCount = await readUntrackedLineCount(
33518
- path71.join(opts.repoRoot, row.filePath)
33843
+ path73.join(opts.repoRoot, row.filePath)
33519
33844
  );
33520
33845
  stats = { added: lineCount, removed: 0 };
33521
33846
  } else {
@@ -33546,7 +33871,7 @@ function readUntrackedLineCount(absPath) {
33546
33871
  }
33547
33872
  async function defaultReadUntrackedLineCount(absPath) {
33548
33873
  try {
33549
- const content = await fs65.readFile(absPath, "utf8");
33874
+ const content = await fs67.readFile(absPath, "utf8");
33550
33875
  let count = 0;
33551
33876
  let pos = -1;
33552
33877
  while ((pos = content.indexOf("\n", pos + 1)) !== -1) {
@@ -33638,7 +33963,7 @@ function defaultRunGit(cwd, args2) {
33638
33963
  });
33639
33964
  }
33640
33965
  async function discoverRepos(workingDir, maxDepth = 4) {
33641
- const fs72 = await import("fs/promises");
33966
+ const fs74 = await import("fs/promises");
33642
33967
  const out2 = [];
33643
33968
  await walk(workingDir, 0);
33644
33969
  return out2;
@@ -33646,7 +33971,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
33646
33971
  if (depth > maxDepth) return;
33647
33972
  let entries = [];
33648
33973
  try {
33649
- const dirents = await fs72.readdir(dir, { withFileTypes: true });
33974
+ const dirents = await fs74.readdir(dir, { withFileTypes: true });
33650
33975
  entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
33651
33976
  } catch {
33652
33977
  return;
@@ -33657,8 +33982,8 @@ async function discoverRepos(workingDir, maxDepth = 4) {
33657
33982
  if (hasGit) {
33658
33983
  out2.push({
33659
33984
  repoRoot: dir,
33660
- repoPath: path71.relative(workingDir, dir),
33661
- repoName: path71.basename(dir)
33985
+ repoPath: path73.relative(workingDir, dir),
33986
+ repoName: path73.basename(dir)
33662
33987
  });
33663
33988
  return;
33664
33989
  }
@@ -33666,14 +33991,14 @@ async function discoverRepos(workingDir, maxDepth = 4) {
33666
33991
  if (!entry.isDirectory) continue;
33667
33992
  if (entry.name === "node_modules") continue;
33668
33993
  if (entry.name === "dist" || entry.name === "build") continue;
33669
- await walk(path71.join(dir, entry.name), depth + 1);
33994
+ await walk(path73.join(dir, entry.name), depth + 1);
33670
33995
  }
33671
33996
  }
33672
33997
  }
33673
33998
 
33674
33999
  // src/services/turn-files/files-outbox.ts
33675
- var fs66 = __toESM(require("fs/promises"));
33676
- var path72 = __toESM(require("path"));
34000
+ var fs68 = __toESM(require("fs/promises"));
34001
+ var path74 = __toESM(require("path"));
33677
34002
  var import_os12 = require("os");
33678
34003
  var HOME_OUTBOX_DIR = ".codeam/outbox";
33679
34004
  var MAX_AGE_MS = 24 * 60 * 60 * 1e3;
@@ -33706,16 +34031,16 @@ var FilesOutbox = class {
33706
34031
  backoffIndex = 0;
33707
34032
  stopped = false;
33708
34033
  constructor(opts) {
33709
- const base = opts.baseDir ?? path72.join(homeDir(), HOME_OUTBOX_DIR);
33710
- this.filePath = path72.join(base, `${opts.sessionId}.jsonl`);
34034
+ const base = opts.baseDir ?? path74.join(homeDir(), HOME_OUTBOX_DIR);
34035
+ this.filePath = path74.join(base, `${opts.sessionId}.jsonl`);
33711
34036
  this.post = opts.post;
33712
34037
  this.autoSchedule = opts.autoSchedule !== false;
33713
34038
  }
33714
34039
  /** Persist the entry to disk and trigger a flush. Returns once the
33715
34040
  * line is durable on disk (not once the POST succeeds). */
33716
34041
  async enqueue(entry) {
33717
- await fs66.mkdir(path72.dirname(this.filePath), { recursive: true });
33718
- await fs66.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
34042
+ await fs68.mkdir(path74.dirname(this.filePath), { recursive: true });
34043
+ await fs68.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
33719
34044
  this.backoffIndex = 0;
33720
34045
  if (this.autoSchedule) this.scheduleFlush(0);
33721
34046
  }
@@ -33806,7 +34131,7 @@ var FilesOutbox = class {
33806
34131
  async readAll() {
33807
34132
  let raw = "";
33808
34133
  try {
33809
- raw = await fs66.readFile(this.filePath, "utf8");
34134
+ raw = await fs68.readFile(this.filePath, "utf8");
33810
34135
  } catch {
33811
34136
  return [];
33812
34137
  }
@@ -33830,12 +34155,12 @@ var FilesOutbox = class {
33830
34155
  async rewrite(entries) {
33831
34156
  const tmpPath = `${this.filePath}.${process.pid}.tmp`;
33832
34157
  if (entries.length === 0) {
33833
- await fs66.unlink(this.filePath).catch(() => void 0);
34158
+ await fs68.unlink(this.filePath).catch(() => void 0);
33834
34159
  return;
33835
34160
  }
33836
34161
  const payload = entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
33837
- await fs66.writeFile(tmpPath, payload, "utf8");
33838
- await fs66.rename(tmpPath, this.filePath);
34162
+ await fs68.writeFile(tmpPath, payload, "utf8");
34163
+ await fs68.rename(tmpPath, this.filePath);
33839
34164
  }
33840
34165
  };
33841
34166
  function applyJitter(ms) {
@@ -34580,11 +34905,13 @@ async function startTaskH(ctx) {
34580
34905
  }
34581
34906
  await streaming.beginTurn();
34582
34907
  history.appendUserPrompt(promptText);
34908
+ let turnClosed = false;
34583
34909
  try {
34584
34910
  const reply = await client3.prompt(blocks);
34585
34911
  const finalText = streaming.getCurrentText();
34586
34912
  if (agentHooks(opts.agent)?.classifyCompletedReply?.(finalText) === "upgrade_required") {
34587
34913
  await streaming.closeWithBubble(CURSOR_UPGRADE_MESSAGE);
34914
+ turnClosed = true;
34588
34915
  history.appendAgentReply(CURSOR_UPGRADE_MESSAGE);
34589
34916
  void history.flush();
34590
34917
  log.info("acpRunner", `start_task \u2190 cursor-plan-upgrade-required id=${cmd.id.slice(0, 8)}`);
@@ -34592,6 +34919,7 @@ async function startTaskH(ctx) {
34592
34919
  } else if (replyIsHouseAgentLimit(finalText)) {
34593
34920
  const houseBubble = houseAgentLimitMessage(finalText);
34594
34921
  await streaming.closeWithBubble(houseBubble);
34922
+ turnClosed = true;
34595
34923
  history.appendAgentReply(houseBubble);
34596
34924
  void history.flush();
34597
34925
  turnFiles.flushTurn().catch((err) => {
@@ -34603,6 +34931,7 @@ async function startTaskH(ctx) {
34603
34931
  });
34604
34932
  } else if (replyIsAuthFailure(finalText)) {
34605
34933
  await streaming.closeWithBubble(AUTH_FAILURE_MESSAGE);
34934
+ turnClosed = true;
34606
34935
  history.appendAgentReply(AUTH_FAILURE_MESSAGE);
34607
34936
  void history.flush();
34608
34937
  turnFiles.flushTurn().catch((err) => {
@@ -34613,6 +34942,7 @@ async function startTaskH(ctx) {
34613
34942
  await relay.sendResult(cmd.id, "failed", { error: "agent reply reported auth failure" });
34614
34943
  } else if (shouldOfferOneMRecovery({ detail: "", recentStderr: recentStderr.join("\n"), finalText })) {
34615
34944
  await streaming.closeWithBubble(ONE_M_CREDITS_MESSAGE);
34945
+ turnClosed = true;
34616
34946
  history.appendAgentReply(ONE_M_CREDITS_MESSAGE);
34617
34947
  void history.flush();
34618
34948
  turnFiles.flushTurn().catch((err) => {
@@ -34625,6 +34955,7 @@ async function startTaskH(ctx) {
34625
34955
  });
34626
34956
  } else {
34627
34957
  await streaming.closeTurnWithInteractiveDetection();
34958
+ turnClosed = true;
34628
34959
  const replyLine = formatAgentReplyLine(finalText);
34629
34960
  if (replyLine.length > 0) {
34630
34961
  showInfo(replyLine);
@@ -34643,6 +34974,13 @@ async function startTaskH(ctx) {
34643
34974
  await relay.sendResult(cmd.id, "completed", { stopReason: reply.stopReason });
34644
34975
  }
34645
34976
  } catch (err) {
34977
+ if (turnClosed) {
34978
+ log.warn(
34979
+ "acpRunner",
34980
+ `post-close ack failed (turn already delivered) id=${cmd.id.slice(0, 8)}: ${describeError(err)}`
34981
+ );
34982
+ return;
34983
+ }
34646
34984
  const hadText = streaming.hasVisibleProgress();
34647
34985
  const detail = describeError(err);
34648
34986
  log.warn("acpRunner", `prompt failed: ${detail}`);
@@ -37080,8 +37418,8 @@ function startClaudeCredentialSync(opts) {
37080
37418
  }
37081
37419
 
37082
37420
  // src/beads/workflow-hint.ts
37083
- var fs68 = __toESM(require("fs"));
37084
- var path74 = __toESM(require("path"));
37421
+ var fs70 = __toESM(require("fs"));
37422
+ var path76 = __toESM(require("path"));
37085
37423
  var os55 = __toESM(require("os"));
37086
37424
  var BEADS_HINT_MARKER = "<!-- codeam:beads-workflow -->";
37087
37425
  var BEADS_HINT = `${BEADS_HINT_MARKER}
@@ -37098,20 +37436,20 @@ This environment uses **bd (beads)** for issue/task tracking and persistent memo
37098
37436
  ${BEADS_HINT_MARKER}`;
37099
37437
  function ensureBeadsWorkflowHint(homeDir2 = os55.homedir()) {
37100
37438
  try {
37101
- const file = path74.join(homeDir2, ".claude", "CLAUDE.md");
37439
+ const file = path76.join(homeDir2, ".claude", "CLAUDE.md");
37102
37440
  let existing = "";
37103
37441
  try {
37104
- existing = fs68.readFileSync(file, "utf8");
37442
+ existing = fs70.readFileSync(file, "utf8");
37105
37443
  } catch {
37106
37444
  }
37107
37445
  if (existing.includes(BEADS_HINT_MARKER)) return;
37108
- fs68.mkdirSync(path74.dirname(file), { recursive: true });
37446
+ fs70.mkdirSync(path76.dirname(file), { recursive: true });
37109
37447
  const next = existing.trim() ? `${existing.trimEnd()}
37110
37448
 
37111
37449
  ${BEADS_HINT}
37112
37450
  ` : `${BEADS_HINT}
37113
37451
  `;
37114
- fs68.writeFileSync(file, next);
37452
+ fs70.writeFileSync(file, next);
37115
37453
  } catch {
37116
37454
  }
37117
37455
  }
@@ -37483,7 +37821,7 @@ var AcpDriver = class {
37483
37821
  };
37484
37822
 
37485
37823
  // src/baton/transcript-mirror.ts
37486
- var fs69 = __toESM(require("fs"));
37824
+ var fs71 = __toESM(require("fs"));
37487
37825
  var TranscriptMirror = class {
37488
37826
  constructor(deps) {
37489
37827
  this.deps = deps;
@@ -37550,7 +37888,7 @@ var TranscriptMirror = class {
37550
37888
  }
37551
37889
  };
37552
37890
  function defaultWatch(file, onChange) {
37553
- const w3 = fs69.watch(file, { persistent: false }, () => onChange());
37891
+ const w3 = fs71.watch(file, { persistent: false }, () => onChange());
37554
37892
  return () => w3.close();
37555
37893
  }
37556
37894
 
@@ -37812,16 +38150,16 @@ function toEpochMs(ts) {
37812
38150
  }
37813
38151
 
37814
38152
  // src/agents/claude/onboarding.ts
37815
- var fs70 = __toESM(require("fs"));
38153
+ var fs72 = __toESM(require("fs"));
37816
38154
  var os57 = __toESM(require("os"));
37817
- var path75 = __toESM(require("path"));
38155
+ var path77 = __toESM(require("path"));
37818
38156
  var ONBOARDING_VERSION_SENTINEL = "9999.0.0";
37819
38157
  function ensureClaudeOnboarded(cwd) {
37820
38158
  try {
37821
- const file = path75.join(os57.homedir(), ".claude.json");
38159
+ const file = path77.join(os57.homedir(), ".claude.json");
37822
38160
  let config = {};
37823
38161
  try {
37824
- config = JSON.parse(fs70.readFileSync(file, "utf8"));
38162
+ config = JSON.parse(fs72.readFileSync(file, "utf8"));
37825
38163
  } catch {
37826
38164
  }
37827
38165
  let changed = false;
@@ -37846,8 +38184,8 @@ function ensureClaudeOnboarded(cwd) {
37846
38184
  }
37847
38185
  }
37848
38186
  if (!changed) return;
37849
- fs70.mkdirSync(path75.dirname(file), { recursive: true });
37850
- fs70.writeFileSync(file, JSON.stringify(config, null, 2));
38187
+ fs72.mkdirSync(path77.dirname(file), { recursive: true });
38188
+ fs72.writeFileSync(file, JSON.stringify(config, null, 2));
37851
38189
  log.info(
37852
38190
  "claude",
37853
38191
  `pre-completed Claude onboarding${cwd ? ` + trusted workspace ${cwd}` : ""}`
@@ -38574,7 +38912,7 @@ var import_picocolors11 = __toESM(require("picocolors"));
38574
38912
  var import_child_process29 = require("child_process");
38575
38913
  var import_util4 = require("util");
38576
38914
  var import_picocolors9 = __toESM(require("picocolors"));
38577
- var path76 = __toESM(require("path"));
38915
+ var path78 = __toESM(require("path"));
38578
38916
  var execFileP6 = (0, import_util4.promisify)(import_child_process29.execFile);
38579
38917
  var MAX_BUFFER = 8 * 1024 * 1024;
38580
38918
  function resetStdinForChild() {
@@ -39063,7 +39401,7 @@ var GitHubCodespacesProvider = class {
39063
39401
  });
39064
39402
  }
39065
39403
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
39066
- const remoteDir = path76.posix.dirname(remotePath);
39404
+ const remoteDir = path78.posix.dirname(remotePath);
39067
39405
  const parts = [
39068
39406
  `mkdir -p ${shellQuote(remoteDir)}`,
39069
39407
  `cat > ${shellQuote(remotePath)}`
@@ -39133,7 +39471,7 @@ function shellQuote(s) {
39133
39471
  // src/services/providers/gitpod.ts
39134
39472
  var import_child_process30 = require("child_process");
39135
39473
  var import_util5 = require("util");
39136
- var path77 = __toESM(require("path"));
39474
+ var path79 = __toESM(require("path"));
39137
39475
  var import_picocolors10 = __toESM(require("picocolors"));
39138
39476
  var execFileP7 = (0, import_util5.promisify)(import_child_process30.execFile);
39139
39477
  var MAX_BUFFER2 = 8 * 1024 * 1024;
@@ -39373,7 +39711,7 @@ var GitpodProvider = class {
39373
39711
  });
39374
39712
  }
39375
39713
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
39376
- const remoteDir = path77.posix.dirname(remotePath);
39714
+ const remoteDir = path79.posix.dirname(remotePath);
39377
39715
  const parts = [
39378
39716
  `mkdir -p ${shellQuote2(remoteDir)}`,
39379
39717
  `cat > ${shellQuote2(remotePath)}`
@@ -39409,7 +39747,7 @@ function shellQuote2(s) {
39409
39747
  // src/services/providers/gitlab-workspaces.ts
39410
39748
  var import_child_process31 = require("child_process");
39411
39749
  var import_util6 = require("util");
39412
- var path78 = __toESM(require("path"));
39750
+ var path80 = __toESM(require("path"));
39413
39751
  var execFileP8 = (0, import_util6.promisify)(import_child_process31.execFile);
39414
39752
  var MAX_BUFFER3 = 8 * 1024 * 1024;
39415
39753
  var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
@@ -39669,7 +40007,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
39669
40007
  }
39670
40008
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
39671
40009
  const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
39672
- const remoteDir = path78.posix.dirname(remotePath);
40010
+ const remoteDir = path80.posix.dirname(remotePath);
39673
40011
  const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
39674
40012
  if (options.mode != null) {
39675
40013
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
@@ -39737,7 +40075,7 @@ function shellQuote3(s) {
39737
40075
  // src/services/providers/railway.ts
39738
40076
  var import_child_process32 = require("child_process");
39739
40077
  var import_util7 = require("util");
39740
- var path79 = __toESM(require("path"));
40078
+ var path81 = __toESM(require("path"));
39741
40079
  var execFileP9 = (0, import_util7.promisify)(import_child_process32.execFile);
39742
40080
  var MAX_BUFFER4 = 8 * 1024 * 1024;
39743
40081
  function resetStdinForChild4() {
@@ -39973,7 +40311,7 @@ var RailwayProvider = class {
39973
40311
  if (!projectId || !serviceId) {
39974
40312
  throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
39975
40313
  }
39976
- const remoteDir = path79.posix.dirname(remotePath);
40314
+ const remoteDir = path81.posix.dirname(remotePath);
39977
40315
  const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
39978
40316
  if (options.mode != null) {
39979
40317
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
@@ -40619,8 +40957,8 @@ async function invite() {
40619
40957
  var import_node_dns = require("dns");
40620
40958
  var import_node_util5 = require("util");
40621
40959
  var import_node_crypto13 = require("crypto");
40622
- var fs71 = __toESM(require("fs"));
40623
- var path80 = __toESM(require("path"));
40960
+ var fs73 = __toESM(require("fs"));
40961
+ var path82 = __toESM(require("path"));
40624
40962
  var import_picocolors14 = __toESM(require("picocolors"));
40625
40963
  var dnsResolveP = (0, import_node_util5.promisify)(import_node_dns.resolve);
40626
40964
  async function checkDns(apiBase2) {
@@ -40676,13 +41014,13 @@ async function checkHealth(apiBase2) {
40676
41014
  }
40677
41015
  }
40678
41016
  function checkConfigDir() {
40679
- const dir = path80.join(require("os").homedir(), ".codeam");
41017
+ const dir = path82.join(require("os").homedir(), ".codeam");
40680
41018
  try {
40681
- fs71.mkdirSync(dir, { recursive: true, mode: 448 });
40682
- const probe = path80.join(dir, ".doctor-probe");
40683
- fs71.writeFileSync(probe, "ok", { mode: 384 });
40684
- const read2 = fs71.readFileSync(probe, "utf8");
40685
- fs71.unlinkSync(probe);
41019
+ fs73.mkdirSync(dir, { recursive: true, mode: 448 });
41020
+ const probe = path82.join(dir, ".doctor-probe");
41021
+ fs73.writeFileSync(probe, "ok", { mode: 384 });
41022
+ const read2 = fs73.readFileSync(probe, "utf8");
41023
+ fs73.unlinkSync(probe);
40686
41024
  if (read2 !== "ok") throw new Error("write/read round-trip mismatch");
40687
41025
  return {
40688
41026
  id: "config-dir",
@@ -40746,7 +41084,7 @@ function checkNodePty() {
40746
41084
  detail: "not required on this platform"
40747
41085
  };
40748
41086
  }
40749
- const vendoredPath = path80.join(__dirname, "vendor", "node-pty");
41087
+ const vendoredPath = path82.join(__dirname, "vendor", "node-pty");
40750
41088
  for (const target of [vendoredPath, "node-pty"]) {
40751
41089
  try {
40752
41090
  require(target);
@@ -40788,7 +41126,7 @@ function checkChokidar() {
40788
41126
  }
40789
41127
  async function doctor(args2 = []) {
40790
41128
  const json = args2.includes("--json");
40791
- const cliVersion = true ? "2.61.81" : "0.0.0-dev";
41129
+ const cliVersion = true ? "2.61.82" : "0.0.0-dev";
40792
41130
  const apiBase2 = resolveApiBaseUrl();
40793
41131
  const diagnosticId = (0, import_node_crypto13.randomUUID)();
40794
41132
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -41378,7 +41716,7 @@ async function mcpRun(args2) {
41378
41716
  // src/commands/version.ts
41379
41717
  var import_picocolors15 = __toESM(require("picocolors"));
41380
41718
  function version2() {
41381
- const v = true ? "2.61.81" : "unknown";
41719
+ const v = true ? "2.61.82" : "unknown";
41382
41720
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
41383
41721
  }
41384
41722