codeam-cli 2.61.81 → 2.61.83

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 +17 -0
  2. package/dist/index.js +867 -460
  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(path85) {
2628
2628
  try {
2629
- fs2.rmSync(path82, { force: true });
2629
+ fs2.rmSync(path85, { force: true });
2630
2630
  } catch (err) {
2631
- log.debug(TAG, `rmIfExists failed for ${path82}`, err);
2631
+ log.debug(TAG, `rmIfExists failed for ${path85}`, 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"));
2778
- var os49 = __toESM(require("os"));
2779
- var path63 = __toESM(require("path"));
2777
+ var fs62 = __toESM(require("fs"));
2778
+ var os50 = __toESM(require("os"));
2779
+ var path66 = __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(path85) {
2816
+ return path85.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(path85, 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)(path85);
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(path85, 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(path85) {
5375
+ return path85.startsWith("node:") || path85.endsWith(".min.js") || path85.endsWith(".min.cjs") || path85.endsWith(".min.mjs") || path85.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.83" : "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.83",
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.83" ? { ideVersion: "2.61.83" } : {}
8943
8987
  }).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
8944
8988
  }
8945
8989
  /**
@@ -9166,10 +9210,10 @@ var WINDOWS_LEGACY_JUNCTIONS = [
9166
9210
  /[\\/]Start Menu([\\/]|$)/i,
9167
9211
  /[\\/]Templates([\\/]|$)/i
9168
9212
  ];
9169
- function isUnsafeWindowsWatchRoot(dir, homedir48) {
9213
+ function isUnsafeWindowsWatchRoot(dir, homedir49) {
9170
9214
  const norm = (p2) => p2.replace(/\//g, "\\").replace(/\\+$/, "").toLowerCase();
9171
9215
  const cwd = norm(dir);
9172
- const home = norm(homedir48);
9216
+ const home = norm(homedir49);
9173
9217
  if (cwd === home) return true;
9174
9218
  if (/^[a-z]:$/.test(cwd)) return true;
9175
9219
  const sysRoots = [
@@ -10313,9 +10357,9 @@ function closeAllTerminals() {
10313
10357
  }
10314
10358
 
10315
10359
  // src/commands/start/handlers.ts
10316
- var fs58 = __toESM(require("fs"));
10317
- var os48 = __toESM(require("os"));
10318
- var path62 = __toESM(require("path"));
10360
+ var fs61 = __toESM(require("fs"));
10361
+ var os49 = __toESM(require("os"));
10362
+ var path65 = __toESM(require("path"));
10319
10363
  var import_crypto3 = require("crypto");
10320
10364
  var import_child_process24 = require("child_process");
10321
10365
 
@@ -13795,10 +13839,10 @@ function buildForPlatform(platform3) {
13795
13839
  var import_node_crypto4 = require("crypto");
13796
13840
 
13797
13841
  // src/agents/claude/resolver.ts
13798
- function buildClaudeLaunch(extraArgs = [], os60 = createOsStrategy()) {
13799
- const found = os60.findInPath("claude") ?? os60.findInPath("claude-code");
13842
+ function buildClaudeLaunch(extraArgs = [], os61 = createOsStrategy()) {
13843
+ const found = os61.findInPath("claude") ?? os61.findInPath("claude-code");
13800
13844
  if (!found) return null;
13801
- return os60.buildLaunch(found, extraArgs);
13845
+ return os61.buildLaunch(found, extraArgs);
13802
13846
  }
13803
13847
 
13804
13848
  // src/agents/claude/installer.ts
@@ -14388,8 +14432,8 @@ var ClaudeRuntimeStrategy = class {
14388
14432
  meta = getAgent("claude");
14389
14433
  mode = "interactive";
14390
14434
  os;
14391
- constructor(os60) {
14392
- this.os = os60;
14435
+ constructor(os61) {
14436
+ this.os = os61;
14393
14437
  }
14394
14438
  /**
14395
14439
  * Claude Code's react-ink TUI enables bracketed-paste mode at
@@ -15169,8 +15213,8 @@ function codexCredentialLocator() {
15169
15213
  function codexLoginLauncher() {
15170
15214
  return {
15171
15215
  async ensureInstalled() {
15172
- const os60 = createOsStrategy();
15173
- return os60.findInPath("codex") !== null;
15216
+ const os61 = createOsStrategy();
15217
+ return os61.findInPath("codex") !== null;
15174
15218
  },
15175
15219
  launch() {
15176
15220
  return (0, import_node_child_process4.spawn)("codex", ["login"], { stdio: "inherit" });
@@ -15193,8 +15237,8 @@ var CodexRuntimeStrategy = class {
15193
15237
  meta = getAgent("codex");
15194
15238
  mode = "interactive";
15195
15239
  os;
15196
- constructor(os60) {
15197
- this.os = os60;
15240
+ constructor(os61) {
15241
+ this.os = os61;
15198
15242
  }
15199
15243
  async prepareLaunch() {
15200
15244
  let binary = this.os.findInPath("codex");
@@ -15303,12 +15347,12 @@ var CodexRuntimeStrategy = class {
15303
15347
  });
15304
15348
  }
15305
15349
  };
15306
- function resolveNpm(os60) {
15307
- return os60.id === "win32" ? "npm.cmd" : "npm";
15350
+ function resolveNpm(os61) {
15351
+ return os61.id === "win32" ? "npm.cmd" : "npm";
15308
15352
  }
15309
- async function installCodexViaNpm(os60) {
15353
+ async function installCodexViaNpm(os61) {
15310
15354
  return new Promise((resolve9, reject) => {
15311
- const proc = (0, import_node_child_process5.spawn)(resolveNpm(os60), ["install", "-g", "@openai/codex"], {
15355
+ const proc = (0, import_node_child_process5.spawn)(resolveNpm(os61), ["install", "-g", "@openai/codex"], {
15312
15356
  stdio: "inherit"
15313
15357
  });
15314
15358
  proc.on("close", (code) => {
@@ -15325,16 +15369,16 @@ async function installCodexViaNpm(os60) {
15325
15369
  });
15326
15370
  });
15327
15371
  }
15328
- function augmentNpmGlobalBin(os60) {
15372
+ function augmentNpmGlobalBin(os61) {
15329
15373
  try {
15330
- const result = (0, import_node_child_process5.spawnSync)(resolveNpm(os60), ["prefix", "-g"], {
15374
+ const result = (0, import_node_child_process5.spawnSync)(resolveNpm(os61), ["prefix", "-g"], {
15331
15375
  stdio: ["ignore", "pipe", "ignore"]
15332
15376
  });
15333
15377
  if (result.status !== 0) return;
15334
15378
  const prefix = result.stdout.toString().trim();
15335
15379
  if (!prefix) return;
15336
- const binDir = os60.id === "win32" ? prefix : path25.join(prefix, "bin");
15337
- os60.augmentPath([binDir]);
15380
+ const binDir = os61.id === "win32" ? prefix : path25.join(prefix, "bin");
15381
+ os61.augmentPath([binDir]);
15338
15382
  } catch {
15339
15383
  }
15340
15384
  }
@@ -15418,9 +15462,9 @@ var import_node_child_process8 = require("child_process");
15418
15462
  // src/agents/coderabbit/installer.ts
15419
15463
  var import_node_child_process6 = require("child_process");
15420
15464
  var INSTALL_URL = "https://cli.coderabbit.ai/install.sh";
15421
- async function ensureCoderabbitInstalled(os60) {
15422
- if (os60.findInPath("coderabbit")) return true;
15423
- if (os60.id === "win32") {
15465
+ async function ensureCoderabbitInstalled(os61) {
15466
+ if (os61.findInPath("coderabbit")) return true;
15467
+ if (os61.id === "win32") {
15424
15468
  console.error(
15425
15469
  "\n \u2717 CodeRabbit on Windows requires WSL.\n Install the CLI inside your WSL distribution\n (curl -fsSL https://cli.coderabbit.ai/install.sh | sh)\n then re-run `codeam link coderabbit` from WSL.\n"
15426
15470
  );
@@ -15453,8 +15497,8 @@ async function ensureCoderabbitInstalled(os60) {
15453
15497
  proc.on("error", () => finish(false));
15454
15498
  });
15455
15499
  if (!ok) return false;
15456
- os60.augmentPath([`${os60.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
15457
- return os60.findInPath("coderabbit") !== null;
15500
+ os61.augmentPath([`${os61.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
15501
+ return os61.findInPath("coderabbit") !== null;
15458
15502
  }
15459
15503
 
15460
15504
  // src/agents/coderabbit/link.ts
@@ -15489,10 +15533,10 @@ function coderabbitCredentialLocator() {
15489
15533
  validate: validateNonEmptyCredential
15490
15534
  };
15491
15535
  }
15492
- function coderabbitLoginLauncher(os60) {
15536
+ function coderabbitLoginLauncher(os61) {
15493
15537
  return {
15494
15538
  async ensureInstalled() {
15495
- return ensureCoderabbitInstalled(os60);
15539
+ return ensureCoderabbitInstalled(os61);
15496
15540
  },
15497
15541
  launch() {
15498
15542
  return (0, import_node_child_process7.spawn)("coderabbit", ["auth", "login"], { stdio: "inherit" });
@@ -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 path85 = asString(pick(o, ["file_path", "filePath", "file", "path", "filename", "fileName"])) ?? asString(pick(o, ["location"])?.path);
15596
+ if (!path85) 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: path85.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 [, path85, lineNo, sevToken, message] = m;
15697
+ if (!path85 || !lineNo || !message) continue;
15654
15698
  hunks.push({
15655
- path: path82.trim(),
15699
+ path: path85.trim(),
15656
15700
  line: Number(lineNo),
15657
15701
  severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
15658
15702
  message: message.trim().replace(/^[*-]\s+/, "")
@@ -15712,8 +15756,8 @@ var CoderabbitRuntimeStrategy = class {
15712
15756
  meta = getAgent("coderabbit");
15713
15757
  mode = "batch";
15714
15758
  os;
15715
- constructor(os60) {
15716
- this.os = os60;
15759
+ constructor(os61) {
15760
+ this.os = os61;
15717
15761
  }
15718
15762
  getDefaultArgs() {
15719
15763
  return ["review", "--agent"];
@@ -15984,10 +16028,10 @@ function cursorCredentialLocator() {
15984
16028
  validate: validateNonEmptyCredential
15985
16029
  };
15986
16030
  }
15987
- function cursorLoginLauncher(os60) {
16031
+ function cursorLoginLauncher(os61) {
15988
16032
  return {
15989
16033
  async ensureInstalled() {
15990
- if (os60.findInPath("cursor-agent")) return true;
16034
+ if (os61.findInPath("cursor-agent")) return true;
15991
16035
  console.error(
15992
16036
  "\n \u2717 cursor-agent binary not on PATH.\n Install Cursor (https://cursor.com/) and ensure the CLI\n plugin is enabled, then re-run `codeam link cursor`.\n"
15993
16037
  );
@@ -16051,8 +16095,8 @@ var CursorRuntimeStrategy = class {
16051
16095
  meta = getAgent("cursor");
16052
16096
  mode = "interactive";
16053
16097
  os;
16054
- constructor(os60) {
16055
- this.os = os60;
16098
+ constructor(os61) {
16099
+ this.os = os61;
16056
16100
  }
16057
16101
  async prepareLaunch() {
16058
16102
  const binary = this.os.findInPath("cursor-agent");
@@ -16268,10 +16312,10 @@ function aiderCredentialLocator() {
16268
16312
  validate: validateNonEmptyCredential
16269
16313
  };
16270
16314
  }
16271
- function aiderLoginLauncher(os60) {
16315
+ function aiderLoginLauncher(os61) {
16272
16316
  return {
16273
16317
  async ensureInstalled() {
16274
- if (os60.findInPath("aider")) return true;
16318
+ if (os61.findInPath("aider")) return true;
16275
16319
  console.error(
16276
16320
  "\n \u2717 aider binary not on PATH.\n Install Aider:\n pip install aider-chat\n then re-run `codeam link aider`.\n"
16277
16321
  );
@@ -16281,7 +16325,7 @@ function aiderLoginLauncher(os60) {
16281
16325
  console.error(
16282
16326
  "\n Aider has no interactive login flow.\n Set ANTHROPIC_API_KEY or OPENAI_API_KEY in your shell,\n or re-run `codeam link aider --api-key=<your-key>`.\n"
16283
16327
  );
16284
- return (0, import_node_child_process11.spawn)(os60.id === "win32" ? "cmd.exe" : "sh", os60.id === "win32" ? ["/c", "exit", "0"] : ["-c", "exit 0"], {
16328
+ return (0, import_node_child_process11.spawn)(os61.id === "win32" ? "cmd.exe" : "sh", os61.id === "win32" ? ["/c", "exit", "0"] : ["-c", "exit 0"], {
16285
16329
  stdio: "ignore"
16286
16330
  });
16287
16331
  }
@@ -16353,8 +16397,8 @@ var AiderRuntimeStrategy = class {
16353
16397
  meta = getAgent("aider");
16354
16398
  mode = "interactive";
16355
16399
  os;
16356
- constructor(os60) {
16357
- this.os = os60;
16400
+ constructor(os61) {
16401
+ this.os = os61;
16358
16402
  }
16359
16403
  async prepareLaunch() {
16360
16404
  const binary = this.os.findInPath("aider");
@@ -16486,8 +16530,8 @@ function geminiCredentialLocator() {
16486
16530
  function geminiLoginLauncher() {
16487
16531
  return {
16488
16532
  async ensureInstalled() {
16489
- const os60 = createOsStrategy();
16490
- return os60.findInPath("gemini") !== null;
16533
+ const os61 = createOsStrategy();
16534
+ return os61.findInPath("gemini") !== null;
16491
16535
  },
16492
16536
  launch() {
16493
16537
  return (0, import_node_child_process12.spawn)("gemini", ["auth", "login"], { stdio: "inherit" });
@@ -16677,8 +16721,8 @@ var GeminiRuntimeStrategy = class {
16677
16721
  meta = getAgent("gemini");
16678
16722
  mode = "interactive";
16679
16723
  os;
16680
- constructor(os60) {
16681
- this.os = os60;
16724
+ constructor(os61) {
16725
+ this.os = os61;
16682
16726
  }
16683
16727
  async prepareLaunch() {
16684
16728
  const binary = this.os.findInPath("gemini");
@@ -16969,8 +17013,8 @@ var KimiRuntimeStrategy = class {
16969
17013
  meta = getAgent("kimi");
16970
17014
  mode = "interactive";
16971
17015
  os;
16972
- constructor(os60) {
16973
- this.os = os60;
17016
+ constructor(os61) {
17017
+ this.os = os61;
16974
17018
  }
16975
17019
  async prepareLaunch() {
16976
17020
  const binary = this.os.findInPath("kimi");
@@ -17112,8 +17156,8 @@ var OpencodeRuntimeStrategy = class {
17112
17156
  meta = getAgent("opencode");
17113
17157
  mode = "interactive";
17114
17158
  os;
17115
- constructor(os60) {
17116
- this.os = os60;
17159
+ constructor(os61) {
17160
+ this.os = os61;
17117
17161
  }
17118
17162
  async prepareLaunch() {
17119
17163
  const binary = this.os.findInPath("opencode");
@@ -17197,20 +17241,20 @@ var OpencodeRuntimeStrategy = class {
17197
17241
 
17198
17242
  // src/agents/registry.ts
17199
17243
  var runtimeBuilders = {
17200
- claude: (os60) => new ClaudeRuntimeStrategy(os60),
17201
- codex: (os60) => new CodexRuntimeStrategy(os60),
17202
- coderabbit: (os60) => new CoderabbitRuntimeStrategy(os60),
17203
- cursor: (os60) => new CursorRuntimeStrategy(os60),
17204
- aider: (os60) => new AiderRuntimeStrategy(os60),
17205
- gemini: (os60) => new GeminiRuntimeStrategy(os60),
17206
- kimi: (os60) => new KimiRuntimeStrategy(os60),
17207
- opencode: (os60) => new OpencodeRuntimeStrategy(os60)
17244
+ claude: (os61) => new ClaudeRuntimeStrategy(os61),
17245
+ codex: (os61) => new CodexRuntimeStrategy(os61),
17246
+ coderabbit: (os61) => new CoderabbitRuntimeStrategy(os61),
17247
+ cursor: (os61) => new CursorRuntimeStrategy(os61),
17248
+ aider: (os61) => new AiderRuntimeStrategy(os61),
17249
+ gemini: (os61) => new GeminiRuntimeStrategy(os61),
17250
+ kimi: (os61) => new KimiRuntimeStrategy(os61),
17251
+ opencode: (os61) => new OpencodeRuntimeStrategy(os61)
17208
17252
  };
17209
17253
  var deployBuilders = {
17210
17254
  claude: () => new ClaudeDeployStrategy(),
17211
17255
  codex: () => new CodexDeployStrategy()
17212
17256
  };
17213
- function createAgentStrategy(agent, os60 = createOsStrategy()) {
17257
+ function createAgentStrategy(agent, os61 = createOsStrategy()) {
17214
17258
  if (!AGENT_REGISTRY[agent]?.enabled) {
17215
17259
  throw new Error(
17216
17260
  `Agent "${agent}" is not supported in this codeam-cli version. Upgrade with 'npm i -g codeam-cli@latest'.`
@@ -17220,10 +17264,10 @@ function createAgentStrategy(agent, os60 = createOsStrategy()) {
17220
17264
  if (!build) {
17221
17265
  throw new Error(`No runtime strategy registered for agent "${agent}"`);
17222
17266
  }
17223
- return build(os60);
17267
+ return build(os61);
17224
17268
  }
17225
- function createInteractiveAgentStrategy(agent, os60 = createOsStrategy()) {
17226
- const s = createAgentStrategy(agent, os60);
17269
+ function createInteractiveAgentStrategy(agent, os61 = createOsStrategy()) {
17270
+ const s = createAgentStrategy(agent, os61);
17227
17271
  if (s.mode !== "interactive") {
17228
17272
  throw new Error(
17229
17273
  `Agent "${agent}" is a batch agent; use createAgentStrategy + .runOneShot for one-shot reviews.`
@@ -17920,26 +17964,26 @@ function restoreCoderabbitOauthBlob(value) {
17920
17964
  (0, import_node_fs5.writeFileSync)(path37.join(dir, file), contents, { mode: 384 });
17921
17965
  }
17922
17966
  async function configureCoderabbit(input, deps = {}) {
17923
- const os60 = deps.os ?? createOsStrategy();
17967
+ const os61 = deps.os ?? createOsStrategy();
17924
17968
  const ensureInstalled = deps.ensureInstalled ?? ensureCoderabbitInstalled;
17925
17969
  const isLoggedIn = deps.isLoggedIn ?? defaultIsLoggedIn;
17926
17970
  const runOAuth = deps.runOAuthLogin ?? runCoderabbitOAuthLogin;
17927
17971
  const snapshot = deps.snapshotDir ?? (() => snapshotCredentialDir());
17928
17972
  const capture2 = deps.captureCredential ?? ((b) => diffCapturedCredential(b));
17929
17973
  const loginWithApiKey = deps.loginWithApiKey ?? defaultLoginWithApiKey;
17930
- const home = os60.homeDir();
17931
- os60.augmentPath(
17932
- os60.id === "win32" ? [
17974
+ const home = os61.homeDir();
17975
+ os61.augmentPath(
17976
+ os61.id === "win32" ? [
17933
17977
  path37.join(home, ".local", "bin"),
17934
17978
  path37.join(process.env.APPDATA ?? path37.join(home, "AppData", "Roaming"), "npm"),
17935
17979
  path37.join(home, "scoop", "shims")
17936
17980
  ] : [path37.join(home, ".local", "bin"), "/opt/homebrew/bin", "/usr/local/bin"]
17937
17981
  );
17938
- const installed2 = os60.findInPath("coderabbit") !== null;
17982
+ const installed2 = os61.findInPath("coderabbit") !== null;
17939
17983
  const base = () => ({
17940
17984
  action: input.action,
17941
17985
  supported: true,
17942
- installed: os60.findInPath("coderabbit") !== null,
17986
+ installed: os61.findInPath("coderabbit") !== null,
17943
17987
  loggedIn: false
17944
17988
  });
17945
17989
  if (input.action === "status") {
@@ -17953,7 +17997,7 @@ async function configureCoderabbit(input, deps = {}) {
17953
17997
  const key = (input.apiKey ?? "").trim();
17954
17998
  if (!key) return { ...res2, error: "No API key provided" };
17955
17999
  if (!res2.installed) {
17956
- const ok = await ensureInstalled(os60);
18000
+ const ok = await ensureInstalled(os61);
17957
18001
  res2.installed = ok;
17958
18002
  if (!ok) return { ...res2, error: "CodeRabbit CLI could not be installed" };
17959
18003
  }
@@ -17977,7 +18021,7 @@ async function configureCoderabbit(input, deps = {}) {
17977
18021
  }
17978
18022
  if (!res2.installed) {
17979
18023
  deps.onEvent?.({ kind: "installing" });
17980
- const ok = await ensureInstalled(os60);
18024
+ const ok = await ensureInstalled(os61);
17981
18025
  res2.installed = ok;
17982
18026
  if (!ok) return { ...res2, error: "CodeRabbit CLI could not be installed" };
17983
18027
  }
@@ -18007,7 +18051,7 @@ async function configureCoderabbit(input, deps = {}) {
18007
18051
  const res2 = base();
18008
18052
  if (!installed2) {
18009
18053
  deps.onEvent?.({ kind: "installing" });
18010
- const ok = await ensureInstalled(os60);
18054
+ const ok = await ensureInstalled(os61);
18011
18055
  res2.installed = ok;
18012
18056
  if (!ok) return { ...res2, error: "CodeRabbit CLI could not be installed" };
18013
18057
  }
@@ -18047,7 +18091,7 @@ async function configureCoderabbit(input, deps = {}) {
18047
18091
  }
18048
18092
  const res = base();
18049
18093
  if (!res.installed) {
18050
- const ok = await ensureInstalled(os60);
18094
+ const ok = await ensureInstalled(os61);
18051
18095
  res.installed = ok;
18052
18096
  if (!ok) return { ...res, error: "CodeRabbit CLI is not installed" };
18053
18097
  }
@@ -18231,9 +18275,9 @@ function defaultRunGh(args2) {
18231
18275
 
18232
18276
  // src/commands/host-agent.ts
18233
18277
  var import_node_child_process25 = require("child_process");
18234
- var os38 = __toESM(require("os"));
18235
- var fs44 = __toESM(require("fs"));
18236
- var path47 = __toESM(require("path"));
18278
+ var os39 = __toESM(require("os"));
18279
+ var fs45 = __toESM(require("fs"));
18280
+ var path48 = __toESM(require("path"));
18237
18281
 
18238
18282
  // src/integrations/manifest.ts
18239
18283
  var import_node_fs7 = __toESM(require("fs"));
@@ -19892,13 +19936,72 @@ async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner,
19892
19936
  return true;
19893
19937
  }
19894
19938
 
19939
+ // src/commands/host/house-proxy-config.ts
19940
+ var fs42 = __toESM(require("fs"));
19941
+ var os37 = __toESM(require("os"));
19942
+ var path46 = __toESM(require("path"));
19943
+ function houseProxyConfigPath() {
19944
+ return path46.join(os37.homedir(), ".codeam", "house-proxy.json");
19945
+ }
19946
+ function persistHouseProxyConfig(config) {
19947
+ try {
19948
+ const file = houseProxyConfigPath();
19949
+ fs42.mkdirSync(path46.dirname(file), { recursive: true, mode: 448 });
19950
+ const tmp = `${file}.tmp-${process.pid}`;
19951
+ fs42.writeFileSync(tmp, JSON.stringify(config, null, 2), { encoding: "utf8", mode: 384 });
19952
+ fs42.renameSync(tmp, file);
19953
+ restrictToOwner(file);
19954
+ } catch (err) {
19955
+ log.warn(
19956
+ "host-agent",
19957
+ `failed to persist house-proxy config (best-effort): ${err instanceof Error ? err.message : String(err)}`
19958
+ );
19959
+ }
19960
+ }
19961
+ function clearHouseProxyConfig() {
19962
+ try {
19963
+ fs42.rmSync(houseProxyConfigPath(), { force: true });
19964
+ } catch {
19965
+ }
19966
+ }
19967
+ function readHouseProxyChildEnv() {
19968
+ try {
19969
+ const raw = fs42.readFileSync(houseProxyConfigPath(), "utf8");
19970
+ const parsed = JSON.parse(raw);
19971
+ if (typeof parsed !== "object" || parsed === null) return {};
19972
+ const o = parsed;
19973
+ if (typeof o.baseUrl !== "string" || !o.baseUrl) return {};
19974
+ if (typeof o.token !== "string" || !o.token) return {};
19975
+ const env = {
19976
+ ANTHROPIC_BASE_URL: o.baseUrl,
19977
+ ANTHROPIC_AUTH_TOKEN: o.token,
19978
+ CLAUDE_CODE_AUTO_COMPACT_WINDOW: "512000",
19979
+ API_TIMEOUT_MS: "3000000"
19980
+ };
19981
+ if (o.openRouter === true) {
19982
+ env.ANTHROPIC_API_KEY = "";
19983
+ } else {
19984
+ env.ANTHROPIC_MODEL = "MiniMax-M3";
19985
+ env.ANTHROPIC_DEFAULT_SONNET_MODEL = "MiniMax-M3";
19986
+ env.ANTHROPIC_DEFAULT_OPUS_MODEL = "MiniMax-M3";
19987
+ env.ANTHROPIC_DEFAULT_HAIKU_MODEL = "MiniMax-M3";
19988
+ }
19989
+ if (typeof o.claudeConfigDir === "string" && o.claudeConfigDir) {
19990
+ env.CLAUDE_CONFIG_DIR = o.claudeConfigDir;
19991
+ }
19992
+ return env;
19993
+ } catch {
19994
+ return {};
19995
+ }
19996
+ }
19997
+
19895
19998
  // src/commands/host/self-update.ts
19896
19999
  var import_node_child_process23 = require("child_process");
19897
20000
 
19898
20001
  // src/lib/updateNotifier.ts
19899
- var fs42 = __toESM(require("fs"));
19900
- var os37 = __toESM(require("os"));
19901
- var path46 = __toESM(require("path"));
20002
+ var fs43 = __toESM(require("fs"));
20003
+ var os38 = __toESM(require("os"));
20004
+ var path47 = __toESM(require("path"));
19902
20005
  var https6 = __toESM(require("https"));
19903
20006
  var import_node_child_process22 = require("child_process");
19904
20007
  var import_picocolors3 = __toESM(require("picocolors"));
@@ -19907,12 +20010,12 @@ var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
19907
20010
  var TTL_MS = 24 * 60 * 60 * 1e3;
19908
20011
  var REQUEST_TIMEOUT_MS = 1500;
19909
20012
  function cachePath() {
19910
- const dir = path46.join(os37.homedir(), ".codeam");
19911
- return path46.join(dir, "update-check.json");
20013
+ const dir = path47.join(os38.homedir(), ".codeam");
20014
+ return path47.join(dir, "update-check.json");
19912
20015
  }
19913
20016
  function readCache() {
19914
20017
  try {
19915
- const raw = fs42.readFileSync(cachePath(), "utf8");
20018
+ const raw = fs43.readFileSync(cachePath(), "utf8");
19916
20019
  const parsed = JSON.parse(raw);
19917
20020
  if (typeof parsed.fetchedAt !== "number" || typeof parsed.latest !== "string") return null;
19918
20021
  return parsed;
@@ -19923,10 +20026,10 @@ function readCache() {
19923
20026
  function writeCache(cache) {
19924
20027
  try {
19925
20028
  const file = cachePath();
19926
- fs42.mkdirSync(path46.dirname(file), { recursive: true });
20029
+ fs43.mkdirSync(path47.dirname(file), { recursive: true });
19927
20030
  const tmp = `${file}.${process.pid}.tmp`;
19928
- fs42.writeFileSync(tmp, JSON.stringify(cache));
19929
- fs42.renameSync(tmp, file);
20031
+ fs43.writeFileSync(tmp, JSON.stringify(cache));
20032
+ fs43.renameSync(tmp, file);
19930
20033
  } catch {
19931
20034
  }
19932
20035
  }
@@ -20000,8 +20103,8 @@ function isLinkedInstall() {
20000
20103
  timeout: 2e3
20001
20104
  }).trim();
20002
20105
  if (!root) return false;
20003
- const pkgPath = path46.join(root, PKG_NAME);
20004
- return fs42.lstatSync(pkgPath).isSymbolicLink();
20106
+ const pkgPath = path47.join(root, PKG_NAME);
20107
+ return fs43.lstatSync(pkgPath).isSymbolicLink();
20005
20108
  } catch {
20006
20109
  return false;
20007
20110
  }
@@ -20037,7 +20140,7 @@ function maybeAutoUpdate(currentVersion, latest) {
20037
20140
  return;
20038
20141
  }
20039
20142
  try {
20040
- fs42.unlinkSync(cachePath());
20143
+ fs43.unlinkSync(cachePath());
20041
20144
  } catch {
20042
20145
  }
20043
20146
  process.stderr.write(` ${import_picocolors3.default.green("\u2713")} Updated. Resuming session...
@@ -20053,7 +20156,7 @@ async function autoUpgradeBeforeCriticalCommand() {
20053
20156
  if (process.env.NODE_ENV === "test") return;
20054
20157
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
20055
20158
  if (process.env.CI) return;
20056
- const current = true ? "2.61.81" : null;
20159
+ const current = true ? "2.61.83" : null;
20057
20160
  if (!current) return;
20058
20161
  const cache = readCache();
20059
20162
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -20070,7 +20173,7 @@ function checkForUpdates() {
20070
20173
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
20071
20174
  if (process.env.CI) return;
20072
20175
  if (!process.stdout.isTTY) return;
20073
- const current = true ? "2.61.81" : null;
20176
+ const current = true ? "2.61.83" : null;
20074
20177
  if (!current) return;
20075
20178
  const cache = readCache();
20076
20179
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -20090,7 +20193,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
20090
20193
  var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
20091
20194
  var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
20092
20195
  function currentCliVersion() {
20093
- return true ? "2.61.81" : null;
20196
+ return true ? "2.61.83" : null;
20094
20197
  }
20095
20198
  function runCmd(cmd, args2, timeoutMs) {
20096
20199
  return new Promise((resolve9) => {
@@ -20157,7 +20260,7 @@ async function runSelfUpdate() {
20157
20260
 
20158
20261
  // src/commands/host/teardown.ts
20159
20262
  var import_node_child_process24 = require("child_process");
20160
- var fs43 = __toESM(require("fs"));
20263
+ var fs44 = __toESM(require("fs"));
20161
20264
  var defaultDisableService = () => {
20162
20265
  try {
20163
20266
  (0, import_node_child_process24.execFileSync)("systemctl", ["disable", "--now", "codeam-host-agent"], { stdio: "ignore" });
@@ -20166,7 +20269,7 @@ var defaultDisableService = () => {
20166
20269
  };
20167
20270
  var defaultTeardownHeadroom = () => {
20168
20271
  try {
20169
- const kind = JSON.parse(fs43.readFileSync(headroomConfigPath(), "utf8")).agent;
20272
+ const kind = JSON.parse(fs44.readFileSync(headroomConfigPath(), "utf8")).agent;
20170
20273
  if (kind) {
20171
20274
  (0, import_node_child_process24.execFileSync)("headroom", ["unwrap", kind], { stdio: "ignore", timeout: 15e3 });
20172
20275
  }
@@ -20234,8 +20337,8 @@ function maybeResumeLocalHeadroomReporter(ctx) {
20234
20337
  if (process.env["HEADROOM_ENABLED"] === "1") return null;
20235
20338
  try {
20236
20339
  const file = headroomConfigPath();
20237
- if (!fs44.existsSync(file)) return null;
20238
- const cfg = JSON.parse(fs44.readFileSync(file, "utf8"));
20340
+ if (!fs45.existsSync(file)) return null;
20341
+ const cfg = JSON.parse(fs45.readFileSync(file, "utf8"));
20239
20342
  if (!cfg?.enabled) return null;
20240
20343
  const agent = cfg.agent ?? "claude";
20241
20344
  const ingestUrl = `${resolveApiBaseUrl()}/api/sessions/${ctx.sessionId}/headroom-savings`;
@@ -20820,13 +20923,13 @@ var HostAgentSupervisor = class {
20820
20923
  const relay = this.relay;
20821
20924
  if (!relay) return;
20822
20925
  const raw = cmd.payload?.path;
20823
- const target = typeof raw === "string" && raw.trim() ? path47.resolve(raw.trim()) : os38.homedir();
20926
+ const target = typeof raw === "string" && raw.trim() ? path48.resolve(raw.trim()) : os39.homedir();
20824
20927
  try {
20825
- const dirents = await fs44.promises.readdir(target, { withFileTypes: true });
20928
+ const dirents = await fs45.promises.readdir(target, { withFileTypes: true });
20826
20929
  const entries = dirents.filter((d3) => !d3.name.startsWith(".")).map((d3) => ({ name: d3.name, isDir: d3.isDirectory() })).sort(
20827
20930
  (a, b) => a.isDir === b.isDir ? a.name.localeCompare(b.name) : a.isDir ? -1 : 1
20828
20931
  );
20829
- const parent = path47.dirname(target);
20932
+ const parent = path48.dirname(target);
20830
20933
  await relay.sendResult(cmd.id, "completed", {
20831
20934
  path: target,
20832
20935
  // null at the filesystem root so the UI can hide the ".." affordance.
@@ -21056,18 +21159,24 @@ var HostAgentSupervisor = class {
21056
21159
  API_TIMEOUT_MS: "3000000",
21057
21160
  CODEAM_AUTO_TOKEN: payload.autoPairToken
21058
21161
  };
21059
- const houseConfigDir = path47.join(
21060
- os38.homedir(),
21162
+ const houseConfigDir = path48.join(
21163
+ os39.homedir(),
21061
21164
  ".codeam",
21062
21165
  "house-claude",
21063
21166
  payload.deployId
21064
21167
  );
21065
21168
  try {
21066
- fs44.mkdirSync(houseConfigDir, { recursive: true, mode: 448 });
21169
+ fs45.mkdirSync(houseConfigDir, { recursive: true, mode: 448 });
21067
21170
  } catch {
21068
21171
  }
21069
21172
  childEnv.CLAUDE_CONFIG_DIR = houseConfigDir;
21070
21173
  extraArgs = [`--agent=${agentKind || "claude"}`];
21174
+ persistHouseProxyConfig({
21175
+ baseUrl,
21176
+ token,
21177
+ openRouter: !!openRouter,
21178
+ claudeConfigDir: houseConfigDir
21179
+ });
21071
21180
  } else {
21072
21181
  const auth = await this.resolveAgentAuth(this.identity, payload.sealedAgentAuth);
21073
21182
  const credEnv = provisionAgentCredentials(payload.agentId, auth, void 0);
@@ -21075,6 +21184,7 @@ var HostAgentSupervisor = class {
21075
21184
  ...credEnv,
21076
21185
  CODEAM_AUTO_TOKEN: payload.autoPairToken
21077
21186
  };
21187
+ clearHouseProxyConfig();
21078
21188
  }
21079
21189
  childEnv = { ...childEnv, CODEAM_AUTO_APPROVE: "1" };
21080
21190
  childEnv = { ...childEnv, CODEAM_HOST_AGENT_CHILD: "1" };
@@ -21082,7 +21192,7 @@ var HostAgentSupervisor = class {
21082
21192
  report("installing", "installing agent CLI");
21083
21193
  await this.runAgentInstall(payload.agentInstallScript);
21084
21194
  }
21085
- const home = process.env.HOME || os38.homedir();
21195
+ const home = process.env.HOME || os39.homedir();
21086
21196
  childEnv.PATH = `${home}/.local/bin:${process.env.PATH ?? ""}`;
21087
21197
  if (payload.cloneToken) {
21088
21198
  try {
@@ -21090,13 +21200,13 @@ var HostAgentSupervisor = class {
21090
21200
  if ((payload.repoProvider ?? "github") === "gitlab") {
21091
21201
  const glabCmd = await ensureGlabCli(defaultGitToolingRunner);
21092
21202
  if (glabCmd) {
21093
- childEnv.PATH = `${codeamBinDir()}${path47.delimiter}${childEnv.PATH}`;
21203
+ childEnv.PATH = `${codeamBinDir()}${path48.delimiter}${childEnv.PATH}`;
21094
21204
  await ensureGlabAuth(defaultGitToolingRunner, glabCmd, payload.cloneToken);
21095
21205
  }
21096
21206
  } else {
21097
21207
  const ghCmd = await ensureGhCli(defaultGitToolingRunner, payload.cloneToken);
21098
21208
  if (ghCmd) {
21099
- childEnv.PATH = `${codeamBinDir()}${path47.delimiter}${childEnv.PATH}`;
21209
+ childEnv.PATH = `${codeamBinDir()}${path48.delimiter}${childEnv.PATH}`;
21100
21210
  await ensureGhAuth(defaultGitToolingRunner, ghCmd, payload.cloneToken);
21101
21211
  }
21102
21212
  }
@@ -21116,7 +21226,7 @@ var HostAgentSupervisor = class {
21116
21226
  }
21117
21227
  if (payload.headroomEnabled && payload.headroomAgent && payload.headroomSavingsIngestUrl && isHeadroomSupportedAgent(payload.headroomAgent)) {
21118
21228
  report("headroom", "setting up Headroom proxy");
21119
- const freeBytes = await this.getFreeDisk(os38.homedir());
21229
+ const freeBytes = await this.getFreeDisk(os39.homedir());
21120
21230
  const alreadyInstalled = this.isHeadroomInstalled();
21121
21231
  if (!alreadyInstalled && freeBytes !== null && freeBytes < HEADROOM_MIN_FREE_DISK_BYTES) {
21122
21232
  const freeGb = (freeBytes / 1e9).toFixed(1);
@@ -21261,8 +21371,11 @@ var HostAgentSupervisor = class {
21261
21371
  if (this.children.size > 0) return;
21262
21372
  const session = getActiveSession();
21263
21373
  if (!session || !session.pluginId || !session.pollSecret || !session.agent) return;
21264
- const cwd = session.cwd && fs44.existsSync(session.cwd) ? session.cwd : process.cwd();
21265
- const proc = this.resumeSpawner({ ...readHeadroomChildEnv() }, cwd);
21374
+ const cwd = session.cwd && fs45.existsSync(session.cwd) ? session.cwd : process.cwd();
21375
+ const proc = this.resumeSpawner(
21376
+ { ...readHeadroomChildEnv(), ...readHouseProxyChildEnv() },
21377
+ cwd
21378
+ );
21266
21379
  const child = {
21267
21380
  deployId: session.id,
21268
21381
  proc,
@@ -21307,7 +21420,7 @@ var HostAgentSupervisor = class {
21307
21420
  */
21308
21421
  runAgentInstall(script) {
21309
21422
  return new Promise((resolve9) => {
21310
- const home = process.env.HOME || os38.homedir();
21423
+ const home = process.env.HOME || os39.homedir();
21311
21424
  const child = (0, import_node_child_process25.spawn)("sh", ["-c", script], {
21312
21425
  env: { ...process.env, HOME: home },
21313
21426
  stdio: ["ignore", "pipe", "pipe"]
@@ -21395,12 +21508,12 @@ var HostAgentSupervisor = class {
21395
21508
  this.children.delete(deployId);
21396
21509
  }
21397
21510
  const dirs = [
21398
- path47.join(selfHostedWorkspaceRoot(), deployId),
21399
- path47.join(os38.homedir(), ".codeam", "house-claude", deployId)
21511
+ path48.join(selfHostedWorkspaceRoot(), deployId),
21512
+ path48.join(os39.homedir(), ".codeam", "house-claude", deployId)
21400
21513
  ];
21401
21514
  for (const dir of dirs) {
21402
21515
  try {
21403
- fs44.rmSync(dir, { recursive: true, force: true });
21516
+ fs45.rmSync(dir, { recursive: true, force: true });
21404
21517
  } catch (err) {
21405
21518
  log.warn(
21406
21519
  "host-agent",
@@ -21537,9 +21650,9 @@ async function configureHeadroom(action, ctx, deps) {
21537
21650
  }
21538
21651
 
21539
21652
  // src/services/headroom/budget-relaunch.ts
21540
- var fs45 = __toESM(require("fs"));
21541
- var os39 = __toESM(require("os"));
21542
- var path48 = __toESM(require("path"));
21653
+ var fs46 = __toESM(require("fs"));
21654
+ var os40 = __toESM(require("os"));
21655
+ var path49 = __toESM(require("path"));
21543
21656
  var import_child_process13 = require("child_process");
21544
21657
  function amendDeploymentManifestBudget(manifest, budget) {
21545
21658
  const rawArgs = manifest.proxy_args ?? [];
@@ -21573,7 +21686,7 @@ function amendDeploymentManifestBudget(manifest, budget) {
21573
21686
  return { ...manifest, proxy_args: newArgs, base_env: newEnv };
21574
21687
  }
21575
21688
  function findHeadroomDeployments(homeDir2, deps) {
21576
- const deployDir = path48.join(homeDir2, ".headroom", "deploy");
21689
+ const deployDir = path49.join(homeDir2, ".headroom", "deploy");
21577
21690
  let profiles;
21578
21691
  try {
21579
21692
  profiles = deps.readDir(deployDir);
@@ -21582,7 +21695,7 @@ function findHeadroomDeployments(homeDir2, deps) {
21582
21695
  }
21583
21696
  const results = [];
21584
21697
  for (const profile of profiles) {
21585
- const manifestPath = path48.join(deployDir, profile, "manifest.json");
21698
+ const manifestPath = path49.join(deployDir, profile, "manifest.json");
21586
21699
  let raw;
21587
21700
  try {
21588
21701
  raw = deps.readJson(manifestPath);
@@ -21614,8 +21727,8 @@ async function applyBudgetToHeadroom(budget, deps) {
21614
21727
  }
21615
21728
  function writeManifestReal(manifestPath, manifest) {
21616
21729
  const tmp = manifestPath + ".codeam.tmp";
21617
- fs45.writeFileSync(tmp, JSON.stringify(manifest, null, 2) + "\n", { mode: 384 });
21618
- fs45.renameSync(tmp, manifestPath);
21730
+ fs46.writeFileSync(tmp, JSON.stringify(manifest, null, 2) + "\n", { mode: 384 });
21731
+ fs46.renameSync(tmp, manifestPath);
21619
21732
  }
21620
21733
  function restartDeploymentReal(profile) {
21621
21734
  try {
@@ -21650,11 +21763,11 @@ function spawnProxyReal2(_budget) {
21650
21763
  );
21651
21764
  }
21652
21765
  function makeRealApplyBudgetDeps() {
21653
- const homeDir2 = os39.homedir();
21766
+ const homeDir2 = os40.homedir();
21654
21767
  return {
21655
21768
  findDeployments: () => findHeadroomDeployments(homeDir2, {
21656
- readDir: (dir) => fs45.readdirSync(dir),
21657
- readJson: (filePath) => JSON.parse(fs45.readFileSync(filePath, "utf8"))
21769
+ readDir: (dir) => fs46.readdirSync(dir),
21770
+ readJson: (filePath) => JSON.parse(fs46.readFileSync(filePath, "utf8"))
21658
21771
  }),
21659
21772
  writeManifest: writeManifestReal,
21660
21773
  restartDeployment: restartDeploymentReal,
@@ -21664,16 +21777,16 @@ function makeRealApplyBudgetDeps() {
21664
21777
  }
21665
21778
 
21666
21779
  // src/services/preview/port-registry.ts
21667
- var fs46 = __toESM(require("fs"));
21668
- var os40 = __toESM(require("os"));
21669
- var path49 = __toESM(require("path"));
21780
+ var fs47 = __toESM(require("fs"));
21781
+ var os41 = __toESM(require("os"));
21782
+ var path50 = __toESM(require("path"));
21670
21783
  var import_child_process14 = require("child_process");
21671
21784
  function registryPath() {
21672
- return path49.join(os40.homedir(), ".codeam", "preview-ports.json");
21785
+ return path50.join(os41.homedir(), ".codeam", "preview-ports.json");
21673
21786
  }
21674
21787
  function readRegistry() {
21675
21788
  try {
21676
- const raw = fs46.readFileSync(registryPath(), "utf8");
21789
+ const raw = fs47.readFileSync(registryPath(), "utf8");
21677
21790
  const parsed = JSON.parse(raw);
21678
21791
  if (parsed && typeof parsed === "object") return parsed;
21679
21792
  } catch {
@@ -21683,10 +21796,10 @@ function readRegistry() {
21683
21796
  function writeRegistry(reg) {
21684
21797
  try {
21685
21798
  const file = registryPath();
21686
- fs46.mkdirSync(path49.dirname(file), { recursive: true });
21799
+ fs47.mkdirSync(path50.dirname(file), { recursive: true });
21687
21800
  const tmp = `${file}.tmp`;
21688
- fs46.writeFileSync(tmp, JSON.stringify(reg), "utf8");
21689
- fs46.renameSync(tmp, file);
21801
+ fs47.writeFileSync(tmp, JSON.stringify(reg), "utf8");
21802
+ fs47.renameSync(tmp, file);
21690
21803
  } catch (err) {
21691
21804
  log.warn("preview", `port-registry write failed: ${err instanceof Error ? err.message : String(err)}`);
21692
21805
  }
@@ -21750,9 +21863,213 @@ function reclaimOwnOrphanPort(port) {
21750
21863
  return true;
21751
21864
  }
21752
21865
 
21866
+ // src/services/preview/host-allow.ts
21867
+ var import_fs = require("fs");
21868
+ var path51 = __toESM(require("path"));
21869
+ var NEXT_ALLOWED_ORIGINS = [
21870
+ "*.trycloudflare.com",
21871
+ "*.preview.codeagent-mobile.com",
21872
+ "*.codeagent-mobile.com"
21873
+ ];
21874
+ var VITE_ALLOWED_HOSTS = [
21875
+ ".trycloudflare.com",
21876
+ ".preview.codeagent-mobile.com",
21877
+ ".codeagent-mobile.com"
21878
+ ];
21879
+ var CONFIG_BASENAMES = {
21880
+ next: "next.config",
21881
+ vite: "vite.config"
21882
+ };
21883
+ var CONFIG_EXTS = [".ts", ".mjs", ".js", ".cjs", ".mts"];
21884
+ var MARKER_DIR = ".codeam";
21885
+ var MARKER_FILE = "preview-host-allow.json";
21886
+ var ORIG_INFIX = ".codeam-orig";
21887
+ function markerPath(cwd) {
21888
+ return path51.join(cwd, MARKER_DIR, MARKER_FILE);
21889
+ }
21890
+ async function fileExists(p2) {
21891
+ try {
21892
+ await import_fs.promises.access(p2);
21893
+ return true;
21894
+ } catch {
21895
+ return false;
21896
+ }
21897
+ }
21898
+ async function findConfigFile(cwd, framework) {
21899
+ const base = CONFIG_BASENAMES[framework];
21900
+ for (const ext of CONFIG_EXTS) {
21901
+ if (await fileExists(path51.join(cwd, `${base}${ext}`))) return `${base}${ext}`;
21902
+ }
21903
+ return null;
21904
+ }
21905
+ async function dependsOn(cwd, pkgName) {
21906
+ try {
21907
+ const raw = await import_fs.promises.readFile(path51.join(cwd, "package.json"), "utf8");
21908
+ const pkg = JSON.parse(raw);
21909
+ return !!(pkg.dependencies?.[pkgName] ?? pkg.devDependencies?.[pkgName]);
21910
+ } catch {
21911
+ return false;
21912
+ }
21913
+ }
21914
+ async function isEsmConfig(cwd, configFile) {
21915
+ const ext = path51.extname(configFile);
21916
+ if (ext === ".mjs" || ext === ".mts" || ext === ".ts") return true;
21917
+ if (ext === ".cjs") return false;
21918
+ try {
21919
+ const raw = await import_fs.promises.readFile(path51.join(cwd, "package.json"), "utf8");
21920
+ return JSON.parse(raw).type === "module";
21921
+ } catch {
21922
+ return false;
21923
+ }
21924
+ }
21925
+ function nextShim(origBasename, esm) {
21926
+ const list = JSON.stringify(NEXT_ALLOWED_ORIGINS);
21927
+ const merge = `
21928
+ function __codeamWithAllow(cfg) {
21929
+ var c = cfg && typeof cfg === 'object' ? Object.assign({}, cfg) : {};
21930
+ var existing = Array.isArray(c.allowedDevOrigins) ? c.allowedDevOrigins : [];
21931
+ c.allowedDevOrigins = Array.from(new Set(existing.concat(${list})));
21932
+ return c;
21933
+ }
21934
+ function __codeamMerge(base) {
21935
+ if (typeof base === 'function') {
21936
+ return function () {
21937
+ var r = base.apply(null, arguments);
21938
+ return r && typeof r.then === 'function' ? r.then(__codeamWithAllow) : __codeamWithAllow(r);
21939
+ };
21940
+ }
21941
+ return base && typeof base.then === 'function' ? base.then(__codeamWithAllow) : __codeamWithAllow(base);
21942
+ }`;
21943
+ if (origBasename) {
21944
+ return esm ? `// codeam preview host-allow shim \u2014 auto-generated, restored on preview stop.
21945
+ import __codeamUser from './${origBasename}';
21946
+ ${merge}
21947
+ export default __codeamMerge(__codeamUser);
21948
+ ` : `// codeam preview host-allow shim \u2014 auto-generated, restored on preview stop.
21949
+ var __codeamUser = require('./${origBasename}');
21950
+ ${merge}
21951
+ module.exports = __codeamMerge(__codeamUser && __codeamUser.default ? __codeamUser.default : __codeamUser);
21952
+ `;
21953
+ }
21954
+ return esm ? `// codeam preview host-allow shim \u2014 auto-generated, removed on preview stop.
21955
+ export default { allowedDevOrigins: ${list} };
21956
+ ` : `// codeam preview host-allow shim \u2014 auto-generated, removed on preview stop.
21957
+ module.exports = { allowedDevOrigins: ${list} };
21958
+ `;
21959
+ }
21960
+ function viteShim(origBasename, esm) {
21961
+ const list = JSON.stringify(VITE_ALLOWED_HOSTS);
21962
+ const merge = `
21963
+ function __codeamWithAllow(cfg) {
21964
+ var c = cfg && typeof cfg === 'object' ? Object.assign({}, cfg) : {};
21965
+ var server = Object.assign({}, c.server || {});
21966
+ if (server.allowedHosts === true) { c.server = server; return c; }
21967
+ var existing = Array.isArray(server.allowedHosts) ? server.allowedHosts : [];
21968
+ server.allowedHosts = Array.from(new Set(existing.concat(${list})));
21969
+ c.server = server;
21970
+ return c;
21971
+ }
21972
+ function __codeamMerge(base) {
21973
+ if (typeof base === 'function') {
21974
+ return function () {
21975
+ var r = base.apply(null, arguments);
21976
+ return r && typeof r.then === 'function' ? r.then(__codeamWithAllow) : __codeamWithAllow(r);
21977
+ };
21978
+ }
21979
+ return base && typeof base.then === 'function' ? base.then(__codeamWithAllow) : __codeamWithAllow(base);
21980
+ }`;
21981
+ if (origBasename) {
21982
+ return esm ? `// codeam preview host-allow shim \u2014 auto-generated, restored on preview stop.
21983
+ import __codeamUser from './${origBasename}';
21984
+ ${merge}
21985
+ export default __codeamMerge(__codeamUser);
21986
+ ` : `// codeam preview host-allow shim \u2014 auto-generated, restored on preview stop.
21987
+ var __codeamUser = require('./${origBasename}');
21988
+ ${merge}
21989
+ module.exports = __codeamMerge(__codeamUser && __codeamUser.default ? __codeamUser.default : __codeamUser);
21990
+ `;
21991
+ }
21992
+ return esm ? `// codeam preview host-allow shim \u2014 auto-generated, removed on preview stop.
21993
+ export default { server: { allowedHosts: ${list} } };
21994
+ ` : `// codeam preview host-allow shim \u2014 auto-generated, removed on preview stop.
21995
+ module.exports = { server: { allowedHosts: ${list} } };
21996
+ `;
21997
+ }
21998
+ function shimFor(framework, origBasename, esm) {
21999
+ return framework === "next" ? nextShim(origBasename, esm) : viteShim(origBasename, esm);
22000
+ }
22001
+ async function writeMarker(cwd, marker) {
22002
+ await import_fs.promises.mkdir(path51.join(cwd, MARKER_DIR), { recursive: true });
22003
+ await import_fs.promises.writeFile(markerPath(cwd), JSON.stringify(marker, null, 2), "utf8");
22004
+ }
22005
+ async function readMarker(cwd) {
22006
+ try {
22007
+ const parsed = JSON.parse(await import_fs.promises.readFile(markerPath(cwd), "utf8"));
22008
+ return parsed && parsed.configFile ? parsed : null;
22009
+ } catch {
22010
+ return null;
22011
+ }
22012
+ }
22013
+ async function restorePreviewHostAllow(cwd) {
22014
+ const marker = await readMarker(cwd);
22015
+ if (!marker) return;
22016
+ try {
22017
+ const configAbs = path51.join(cwd, marker.configFile);
22018
+ if (marker.backupFile) {
22019
+ const backupAbs = path51.join(cwd, marker.backupFile);
22020
+ if (await fileExists(backupAbs)) {
22021
+ await import_fs.promises.rm(configAbs, { force: true });
22022
+ await import_fs.promises.rename(backupAbs, configAbs);
22023
+ }
22024
+ } else {
22025
+ await import_fs.promises.rm(configAbs, { force: true });
22026
+ }
22027
+ } catch (err) {
22028
+ log.warn("preview", `host-allow restore failed: ${err instanceof Error ? err.message : err}`);
22029
+ } finally {
22030
+ await import_fs.promises.rm(markerPath(cwd), { force: true }).catch(() => void 0);
22031
+ }
22032
+ }
22033
+ async function applyPreviewHostAllow(cwd) {
22034
+ try {
22035
+ await restorePreviewHostAllow(cwd);
22036
+ let framework = null;
22037
+ let existing = null;
22038
+ for (const f of ["next", "vite"]) {
22039
+ const cfg = await findConfigFile(cwd, f);
22040
+ if (cfg) {
22041
+ framework = f;
22042
+ existing = cfg;
22043
+ break;
22044
+ }
22045
+ }
22046
+ if (!framework) {
22047
+ if (await dependsOn(cwd, "next")) framework = "next";
22048
+ else if (await dependsOn(cwd, "vite")) framework = "vite";
22049
+ }
22050
+ if (!framework) return;
22051
+ if (existing) {
22052
+ const ext = path51.extname(existing);
22053
+ const origBasename = `${CONFIG_BASENAMES[framework]}${ORIG_INFIX}${ext}`;
22054
+ const esm = await isEsmConfig(cwd, existing);
22055
+ await import_fs.promises.rename(path51.join(cwd, existing), path51.join(cwd, origBasename));
22056
+ await import_fs.promises.writeFile(path51.join(cwd, existing), shimFor(framework, origBasename, esm), "utf8");
22057
+ await writeMarker(cwd, { framework, configFile: existing, backupFile: origBasename });
22058
+ log.info("preview", `host-allow: wrapped ${existing} (${framework}) for tunnel access`);
22059
+ } else {
22060
+ const configFile = `${CONFIG_BASENAMES[framework]}.mjs`;
22061
+ await import_fs.promises.writeFile(path51.join(cwd, configFile), shimFor(framework, null, true), "utf8");
22062
+ await writeMarker(cwd, { framework, configFile, backupFile: null });
22063
+ log.info("preview", `host-allow: created ${configFile} (${framework}) for tunnel access`);
22064
+ }
22065
+ } catch (err) {
22066
+ log.warn("preview", `host-allow apply skipped: ${err instanceof Error ? err.message : err}`);
22067
+ }
22068
+ }
22069
+
21753
22070
  // src/services/preview/cloudflared.ts
21754
22071
  var import_child_process15 = require("child_process");
21755
- var import_fs = require("fs");
22072
+ var import_fs2 = require("fs");
21756
22073
  var import_promises = __toESM(require("fs/promises"));
21757
22074
  var import_os9 = __toESM(require("os"));
21758
22075
  var import_path4 = __toESM(require("path"));
@@ -21793,7 +22110,7 @@ async function downloadCloudflared(target) {
21793
22110
  const tmp = `${target}.download.tgz`;
21794
22111
  await (0, import_promises2.pipeline)(
21795
22112
  response.body,
21796
- (0, import_fs.createWriteStream)(tmp)
22113
+ (0, import_fs2.createWriteStream)(tmp)
21797
22114
  );
21798
22115
  try {
21799
22116
  await extractTgz(tmp, import_path4.default.dirname(target));
@@ -21810,7 +22127,7 @@ async function downloadCloudflared(target) {
21810
22127
  }
21811
22128
  await (0, import_promises2.pipeline)(
21812
22129
  response.body,
21813
- (0, import_fs.createWriteStream)(target, { mode: 493 })
22130
+ (0, import_fs2.createWriteStream)(target, { mode: 493 })
21814
22131
  );
21815
22132
  }
21816
22133
  async function isExecutableBinary(p2) {
@@ -22071,7 +22388,7 @@ async function waitForPortListening(port, opts) {
22071
22388
  }
22072
22389
 
22073
22390
  // src/services/preview/provision-deps.ts
22074
- var import_fs2 = require("fs");
22391
+ var import_fs3 = require("fs");
22075
22392
  var import_path6 = __toESM(require("path"));
22076
22393
 
22077
22394
  // src/services/preview/run-setup.ts
@@ -22219,7 +22536,7 @@ function pickMigrationScript(scripts) {
22219
22536
  }
22220
22537
  async function exists(p2) {
22221
22538
  try {
22222
- await import_fs2.promises.access(p2);
22539
+ await import_fs3.promises.access(p2);
22223
22540
  return true;
22224
22541
  } catch {
22225
22542
  return false;
@@ -22236,20 +22553,20 @@ async function ensureEnvFile(cwd, generated) {
22236
22553
  }
22237
22554
  const sample = await firstExisting(cwd, ENV_SAMPLES);
22238
22555
  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);
22556
+ const body = await import_fs3.promises.readFile(import_path6.default.join(cwd, sample), "utf8");
22557
+ await import_fs3.promises.writeFile(import_path6.default.join(cwd, ".env"), body);
22241
22558
  log.info("provision", `wrote .env from ${sample}`);
22242
22559
  return;
22243
22560
  }
22244
22561
  if (generated.length > 0) {
22245
22562
  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);
22563
+ await import_fs3.promises.writeFile(import_path6.default.join(cwd, ".env"), body);
22247
22564
  log.info("provision", `generated .env for ${generated.map((s) => s.name).join("+")}`);
22248
22565
  }
22249
22566
  }
22250
22567
  async function readPackageJson(cwd) {
22251
22568
  try {
22252
- return JSON.parse(await import_fs2.promises.readFile(import_path6.default.join(cwd, "package.json"), "utf8"));
22569
+ return JSON.parse(await import_fs3.promises.readFile(import_path6.default.join(cwd, "package.json"), "utf8"));
22253
22570
  } catch {
22254
22571
  return null;
22255
22572
  }
@@ -22290,9 +22607,9 @@ async function provisionProjectDependencies(cwd) {
22290
22607
  generated = detectServicesFromDeps(pkg);
22291
22608
  if (generated.length > 0) {
22292
22609
  const dir = import_path6.default.join(cwd, ".codeam", "provision");
22293
- await import_fs2.promises.mkdir(dir, { recursive: true });
22610
+ await import_fs3.promises.mkdir(dir, { recursive: true });
22294
22611
  const file = import_path6.default.join(dir, "compose.generated.yaml");
22295
- await import_fs2.promises.writeFile(file, renderComposeYaml(generated));
22612
+ await import_fs3.promises.writeFile(file, renderComposeYaml(generated));
22296
22613
  log.info(
22297
22614
  "provision",
22298
22615
  `no compose in repo \u2014 generated ${generated.map((s) => s.name).join("+")}`
@@ -22313,12 +22630,12 @@ async function provisionProjectDependencies(cwd) {
22313
22630
  }
22314
22631
 
22315
22632
  // src/services/preview/setup-deps.ts
22316
- var import_fs3 = __toESM(require("fs"));
22633
+ var import_fs4 = __toESM(require("fs"));
22317
22634
  var import_path7 = __toESM(require("path"));
22318
22635
  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"))) {
22636
+ if (!import_fs4.default.existsSync(import_path7.default.join(cwd, "package.json"))) return null;
22637
+ if (import_fs4.default.existsSync(import_path7.default.join(cwd, "node_modules"))) return null;
22638
+ if (import_fs4.default.existsSync(import_path7.default.join(cwd, "yarn.lock"))) {
22322
22639
  return { cmd: "yarn", args: ["install"] };
22323
22640
  }
22324
22641
  return { cmd: "npm", args: ["install", "--legacy-peer-deps"] };
@@ -22410,6 +22727,7 @@ async function killPreview(sessionId) {
22410
22727
  if (preview.tunnel) killProcessTree(preview.tunnel, "SIGKILL");
22411
22728
  }, 250);
22412
22729
  sigkillTimer.unref?.();
22730
+ await restorePreviewHostAllow(preview.cwd);
22413
22731
  activePreviews.delete(sessionId);
22414
22732
  }
22415
22733
  async function killAllPreviews() {
@@ -22421,10 +22739,153 @@ function activePreviewSessionIds() {
22421
22739
  }
22422
22740
 
22423
22741
  // 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"));
22742
+ var import_child_process19 = require("child_process");
22743
+ var fs55 = __toESM(require("fs"));
22744
+ var path58 = __toESM(require("path"));
22427
22745
  var import_which2 = __toESM(require("which"));
22746
+
22747
+ // src/services/project-env/index.ts
22748
+ var import_fs5 = require("fs");
22749
+ var path57 = __toESM(require("path"));
22750
+
22751
+ // src/beads/project-key.ts
22752
+ var import_child_process18 = require("child_process");
22753
+ var crypto2 = __toESM(require("crypto"));
22754
+ var fs53 = __toESM(require("fs"));
22755
+ var path56 = __toESM(require("path"));
22756
+ function normalizeOrigin(raw) {
22757
+ const trimmed = raw.trim();
22758
+ if (!trimmed) return null;
22759
+ let host2;
22760
+ let pathPart;
22761
+ const scpLike = /^[^/@]+@([^:]+):(.+)$/.exec(trimmed);
22762
+ if (scpLike && !trimmed.includes("://")) {
22763
+ host2 = scpLike[1];
22764
+ pathPart = scpLike[2];
22765
+ } else {
22766
+ let url2;
22767
+ try {
22768
+ url2 = new URL(trimmed);
22769
+ } catch {
22770
+ return null;
22771
+ }
22772
+ host2 = url2.hostname;
22773
+ pathPart = url2.pathname;
22774
+ }
22775
+ host2 = host2.toLowerCase();
22776
+ pathPart = pathPart.replace(/^\/+/, "").replace(/\.git$/i, "").replace(/\/+$/, "");
22777
+ if (!host2 || !pathPart) return null;
22778
+ return `${host2}/${pathPart}`;
22779
+ }
22780
+ function findRepoRoot(cwd) {
22781
+ let dir = path56.resolve(cwd);
22782
+ const seen = /* @__PURE__ */ new Set();
22783
+ for (let i = 0; i < 256; i++) {
22784
+ if (seen.has(dir)) return null;
22785
+ seen.add(dir);
22786
+ try {
22787
+ const stat3 = fs53.statSync(path56.join(dir, ".git"), { throwIfNoEntry: false });
22788
+ if (stat3 && (stat3.isDirectory() || stat3.isFile())) return dir;
22789
+ } catch {
22790
+ }
22791
+ const parent = path56.dirname(dir);
22792
+ if (parent === dir) return null;
22793
+ dir = parent;
22794
+ }
22795
+ return null;
22796
+ }
22797
+ var _execSeam2 = {
22798
+ exec: (file, args2, opts) => {
22799
+ const out2 = (0, import_child_process18.execFileSync)(file, args2, opts);
22800
+ return typeof out2 === "string" ? out2 : out2.toString("utf8");
22801
+ },
22802
+ realpath: (p2) => fs53.realpathSync(p2)
22803
+ };
22804
+ function readOrigin(cwd) {
22805
+ try {
22806
+ const raw = _execSeam2.exec("git", ["remote", "get-url", "origin"], {
22807
+ cwd,
22808
+ timeout: 1e3,
22809
+ stdio: ["ignore", "pipe", "ignore"],
22810
+ encoding: "utf8"
22811
+ });
22812
+ return raw.trim() || null;
22813
+ } catch {
22814
+ return null;
22815
+ }
22816
+ }
22817
+ function deriveProjectIdentity(cwd = process.cwd()) {
22818
+ const repoRoot = findRepoRoot(cwd) ?? cwd;
22819
+ const origin = readOrigin(repoRoot);
22820
+ const normalized = origin ? normalizeOrigin(origin) : null;
22821
+ if (normalized) {
22822
+ const label = normalized.split("/").pop() || normalized;
22823
+ return { projectKey: normalized, projectLabel: label };
22824
+ }
22825
+ let real = repoRoot;
22826
+ try {
22827
+ real = _execSeam2.realpath(repoRoot);
22828
+ } catch {
22829
+ }
22830
+ const hash = crypto2.createHash("sha256").update(real).digest("hex");
22831
+ return { projectKey: `path:${hash}`, projectLabel: path56.basename(real) || "project" };
22832
+ }
22833
+
22834
+ // src/services/project-env/index.ts
22835
+ async function readIfExists(p2) {
22836
+ try {
22837
+ return await import_fs5.promises.readFile(p2, "utf8");
22838
+ } catch {
22839
+ return null;
22840
+ }
22841
+ }
22842
+ async function syncProjectEnvUp(cwd, ctx) {
22843
+ if (!ctx.pluginAuthToken) return;
22844
+ const content = await readIfExists(path57.join(cwd, ".env"));
22845
+ if (content == null) return;
22846
+ try {
22847
+ const { projectKey, projectLabel } = deriveProjectIdentity(cwd);
22848
+ const keyCount = parseDotenv(content).length;
22849
+ const res = await pushProjectEnv({
22850
+ sessionId: ctx.sessionId,
22851
+ pluginId: ctx.pluginId,
22852
+ pluginAuthToken: ctx.pluginAuthToken,
22853
+ projectKey,
22854
+ projectLabel,
22855
+ content,
22856
+ keyCount
22857
+ });
22858
+ if (res.ok) log.info("project-env", `pushed .env (${keyCount} vars) for ${projectLabel}`);
22859
+ else log.debug("project-env", `push .env failed (${res.status}) \u2014 non-fatal`);
22860
+ } catch (err) {
22861
+ log.debug("project-env", `push .env skipped: ${err instanceof Error ? err.message : err}`);
22862
+ }
22863
+ }
22864
+ async function restoreProjectEnvIfMissing(cwd, ctx) {
22865
+ if (!ctx.pluginAuthToken) return false;
22866
+ const envPath = path57.join(cwd, ".env");
22867
+ if (await readIfExists(envPath) != null) return false;
22868
+ try {
22869
+ const { projectKey, projectLabel } = deriveProjectIdentity(cwd);
22870
+ const stored = await pullProjectEnv({
22871
+ sessionId: ctx.sessionId,
22872
+ pluginId: ctx.pluginId,
22873
+ pluginAuthToken: ctx.pluginAuthToken,
22874
+ projectKey
22875
+ });
22876
+ if (!stored) return false;
22877
+ const tmp = path57.join(cwd, ".env.codeam-restore.tmp");
22878
+ await import_fs5.promises.writeFile(tmp, stored.content, { encoding: "utf8", mode: 384 });
22879
+ await import_fs5.promises.rename(tmp, envPath);
22880
+ log.info("project-env", `restored .env (${stored.keyCount} vars) for ${projectLabel}`);
22881
+ return true;
22882
+ } catch (err) {
22883
+ log.debug("project-env", `restore .env skipped: ${err instanceof Error ? err.message : err}`);
22884
+ return false;
22885
+ }
22886
+ }
22887
+
22888
+ // src/services/preview/start-orchestrator.ts
22428
22889
  var INSTALL_TIMEOUT_MS = 5 * 6e4;
22429
22890
  var SETUP_TIMEOUT_MS = 2 * 6e4;
22430
22891
  var TUNNEL_REGISTER_DEADLINE_MS = 45e3;
@@ -22490,8 +22951,8 @@ function normalizeDetectionForSpawn(detection, cwd) {
22490
22951
  if (args2.length === 0) return detection;
22491
22952
  const binName = args2[0];
22492
22953
  if (binName.startsWith("-")) return detection;
22493
- const binPath = path54.join(cwd, "node_modules", ".bin", binName);
22494
- if (!fs51.existsSync(binPath)) return detection;
22954
+ const binPath = path58.join(cwd, "node_modules", ".bin", binName);
22955
+ if (!fs55.existsSync(binPath)) return detection;
22495
22956
  return {
22496
22957
  ...detection,
22497
22958
  command: binPath,
@@ -22537,7 +22998,8 @@ async function runPreviewStart(args2) {
22537
22998
  tunnel: tun.tunnel,
22538
22999
  url: tun.url,
22539
23000
  framework: detection.framework,
22540
- detection
23001
+ detection,
23002
+ cwd: ctx.cwd
22541
23003
  });
22542
23004
  recordPreviewPort(detection.port, dev.devServer.pid, sessionId, Date.now());
22543
23005
  log.info("preview", `ready: ${detection.framework} at ${tun.url}`);
@@ -22549,6 +23011,13 @@ async function runPreviewStart(args2) {
22549
23011
  }
22550
23012
  async function provisionDeps(ctx) {
22551
23013
  const { detection, cwd, emit: emit2, emitProgress } = ctx;
23014
+ if (ctx.projectEnvAuth?.pluginAuthToken) {
23015
+ await restoreProjectEnvIfMissing(cwd, {
23016
+ sessionId: ctx.sessionId,
23017
+ pluginId: ctx.projectEnvAuth.pluginId,
23018
+ pluginAuthToken: ctx.projectEnvAuth.pluginAuthToken
23019
+ });
23020
+ }
22552
23021
  const missingDeps = detectMissingNodeDeps(cwd);
22553
23022
  let preflightRan = false;
22554
23023
  if (missingDeps) {
@@ -22696,9 +23165,10 @@ async function startDevServer(ctx) {
22696
23165
  return null;
22697
23166
  }
22698
23167
  }
23168
+ await applyPreviewHostAllow(cwd);
22699
23169
  const spawnable = normalizeDetectionForSpawn(detection, cwd);
22700
23170
  emitProgress("BOOT_SEQUENCE", `${spawnable.command} ${spawnable.args.join(" ")}`);
22701
- const devServer = (0, import_child_process18.spawn)(spawnable.command, spawnable.args, {
23171
+ const devServer = (0, import_child_process19.spawn)(spawnable.command, spawnable.args, {
22702
23172
  cwd,
22703
23173
  env: { ...process.env, ...spawnable.env ?? {} },
22704
23174
  stdio: ["ignore", "pipe", "pipe"],
@@ -22823,7 +23293,7 @@ async function establishTunnel(ctx, dev) {
22823
23293
  `cloudflared quick tunnel (retry ${attempt}/${MAX_TUNNEL_ATTEMPTS})`
22824
23294
  );
22825
23295
  }
22826
- const candidate = (0, import_child_process18.spawn)(
23296
+ const candidate = (0, import_child_process19.spawn)(
22827
23297
  bin,
22828
23298
  ["tunnel", "--url", `http://localhost:${detection.port}`],
22829
23299
  { stdio: ["ignore", "pipe", "pipe"] }
@@ -22854,10 +23324,10 @@ async function establishTunnel(ctx, dev) {
22854
23324
  }
22855
23325
 
22856
23326
  // src/beads/bd-adapter.ts
22857
- var import_child_process19 = require("child_process");
22858
- var fs52 = __toESM(require("fs"));
22859
- var os42 = __toESM(require("os"));
22860
- var path55 = __toESM(require("path"));
23327
+ var import_child_process20 = require("child_process");
23328
+ var fs56 = __toESM(require("fs"));
23329
+ var os43 = __toESM(require("os"));
23330
+ var path59 = __toESM(require("path"));
22861
23331
  var BD_PACKAGE = "@beads/bd";
22862
23332
  function resolveBundledBdBinary() {
22863
23333
  return _resolveSeam.resolveBundled();
@@ -22869,11 +23339,11 @@ function _defaultResolveBundled() {
22869
23339
  } catch {
22870
23340
  return null;
22871
23341
  }
22872
- const binDir = path55.join(path55.dirname(pkgJsonPath), "bin");
23342
+ const binDir = path59.join(path59.dirname(pkgJsonPath), "bin");
22873
23343
  const binaryName = process.platform === "win32" ? "bd.exe" : "bd";
22874
- const binaryPath = path55.join(binDir, binaryName);
23344
+ const binaryPath = path59.join(binDir, binaryName);
22875
23345
  try {
22876
- fs52.accessSync(binaryPath, fs52.constants.F_OK);
23346
+ fs56.accessSync(binaryPath, fs56.constants.F_OK);
22877
23347
  return binaryPath;
22878
23348
  } catch {
22879
23349
  return null;
@@ -22883,13 +23353,13 @@ function resolveBdOnPath() {
22883
23353
  return _resolveSeam.resolveOnPath();
22884
23354
  }
22885
23355
  function _defaultResolveOnPath() {
22886
- const dirs = (process.env.PATH ?? "").split(path55.delimiter).filter(Boolean);
23356
+ const dirs = (process.env.PATH ?? "").split(path59.delimiter).filter(Boolean);
22887
23357
  const candidates = process.platform === "win32" ? ["bd.exe", "bd.cmd", "bd"] : ["bd"];
22888
23358
  for (const dir of dirs) {
22889
23359
  for (const candidate of candidates) {
22890
- const full = path55.join(dir, candidate);
23360
+ const full = path59.join(dir, candidate);
22891
23361
  try {
22892
- fs52.accessSync(full, fs52.constants.F_OK);
23362
+ fs56.accessSync(full, fs56.constants.F_OK);
22893
23363
  return full;
22894
23364
  } catch {
22895
23365
  }
@@ -22908,7 +23378,7 @@ function _defaultSpawn(binaryPath, args2, opts) {
22908
23378
  return new Promise((resolve9) => {
22909
23379
  let proc;
22910
23380
  try {
22911
- proc = (0, import_child_process19.spawn)(binaryPath, args2, { cwd: opts.cwd, env: opts.env });
23381
+ proc = (0, import_child_process20.spawn)(binaryPath, args2, { cwd: opts.cwd, env: opts.env });
22912
23382
  } catch (err) {
22913
23383
  resolve9({ code: -1, stdout: "", stderr: err.message });
22914
23384
  return;
@@ -22974,7 +23444,7 @@ var BdAdapter = class {
22974
23444
  const env = { ...process.env };
22975
23445
  if (!env.HOME) {
22976
23446
  try {
22977
- const home = os42.homedir();
23447
+ const home = os43.homedir();
22978
23448
  if (home) env.HOME = home;
22979
23449
  } catch {
22980
23450
  }
@@ -23066,12 +23536,12 @@ function coerceIssue(row, projectKey) {
23066
23536
 
23067
23537
  // src/beads/provisioner.ts
23068
23538
  var import_child_process23 = require("child_process");
23069
- var fs55 = __toESM(require("fs"));
23070
- var os44 = __toESM(require("os"));
23071
- var path58 = __toESM(require("path"));
23539
+ var fs58 = __toESM(require("fs"));
23540
+ var os45 = __toESM(require("os"));
23541
+ var path61 = __toESM(require("path"));
23072
23542
 
23073
23543
  // src/beads/install-bd.ts
23074
- var import_child_process20 = require("child_process");
23544
+ var import_child_process21 = require("child_process");
23075
23545
  var INSTALL_SH_URL = "https://raw.githubusercontent.com/gastownhall/beads/main/scripts/install.sh";
23076
23546
  var INSTALL_PS1_URL = "https://raw.githubusercontent.com/gastownhall/beads/main/install.ps1";
23077
23547
  function resolveInstallStrategy(platform3) {
@@ -23102,7 +23572,7 @@ function _defaultInstallSpawn(strategy) {
23102
23572
  return new Promise((resolve9) => {
23103
23573
  let proc;
23104
23574
  try {
23105
- proc = (0, import_child_process20.spawn)(strategy.command, strategy.args, { env: process.env });
23575
+ proc = (0, import_child_process21.spawn)(strategy.command, strategy.args, { env: process.env });
23106
23576
  } catch (err) {
23107
23577
  resolve9({ ok: false, code: -1, stderr: err.message });
23108
23578
  return;
@@ -23132,10 +23602,10 @@ async function installBd(platform3 = process.platform) {
23132
23602
  }
23133
23603
 
23134
23604
  // src/beads/install-dolt.ts
23135
- var import_child_process21 = require("child_process");
23136
- var fs53 = __toESM(require("fs"));
23137
- var os43 = __toESM(require("os"));
23138
- var path56 = __toESM(require("path"));
23605
+ var import_child_process22 = require("child_process");
23606
+ var fs57 = __toESM(require("fs"));
23607
+ var os44 = __toESM(require("os"));
23608
+ var path60 = __toESM(require("path"));
23139
23609
  var DOLT_INSTALL_SH_URL = "https://github.com/dolthub/dolt/releases/latest/download/install.sh";
23140
23610
  var DOLT_MSI_URL = "https://github.com/dolthub/dolt/releases/latest/download/dolt-windows-amd64.msi";
23141
23611
  function resolveDoltInstallStrategy(platform3) {
@@ -23175,11 +23645,11 @@ function resolveDoltInstallStrategy(platform3) {
23175
23645
  }
23176
23646
  var DOLT_RELEASE_BASE = "https://github.com/dolthub/dolt/releases/latest/download";
23177
23647
  function doltPlatformTuple(platform3, arch2) {
23178
- const os60 = platform3 === "win32" ? "windows" : platform3 === "darwin" ? "darwin" : "linux";
23648
+ const os61 = platform3 === "win32" ? "windows" : platform3 === "darwin" ? "darwin" : "linux";
23179
23649
  const a = arch2 === "x64" ? "amd64" : arch2 === "arm64" ? "arm64" : null;
23180
23650
  if (!a) return null;
23181
- if (os60 === "windows" && a !== "amd64") return null;
23182
- return `${os60}-${a}`;
23651
+ if (os61 === "windows" && a !== "amd64") return null;
23652
+ return `${os61}-${a}`;
23183
23653
  }
23184
23654
  function resolveDoltTarballStrategy(targetDir, platform3, arch2) {
23185
23655
  const tuple = doltPlatformTuple(platform3, arch2);
@@ -23224,14 +23694,14 @@ async function installDoltToDir(targetDir, platform3 = process.platform, arch2 =
23224
23694
  return result;
23225
23695
  }
23226
23696
  var _doltPathSeam = {
23227
- homedir: () => os43.homedir(),
23697
+ homedir: () => os44.homedir(),
23228
23698
  getPath: () => process.env.PATH ?? "",
23229
23699
  setPath: (p2) => {
23230
23700
  process.env.PATH = p2;
23231
23701
  },
23232
23702
  exists: (p2) => {
23233
23703
  try {
23234
- fs53.accessSync(p2, fs53.constants.F_OK);
23704
+ fs57.accessSync(p2, fs57.constants.F_OK);
23235
23705
  return true;
23236
23706
  } catch {
23237
23707
  return false;
@@ -23242,7 +23712,7 @@ function doltBinaryNames(platform3) {
23242
23712
  return platform3 === "win32" ? ["dolt.exe", "dolt.cmd", "dolt"] : ["dolt"];
23243
23713
  }
23244
23714
  function knownDoltDirs(platform3) {
23245
- const P3 = platform3 === "win32" ? path56.win32 : path56.posix;
23715
+ const P3 = platform3 === "win32" ? path60.win32 : path60.posix;
23246
23716
  const home = _doltPathSeam.homedir();
23247
23717
  if (platform3 === "win32") {
23248
23718
  return [
@@ -23258,7 +23728,7 @@ function knownDoltDirs(platform3) {
23258
23728
  ].filter(Boolean);
23259
23729
  }
23260
23730
  function ensureDoltResolvable(platform3 = process.platform) {
23261
- const P3 = platform3 === "win32" ? path56.win32 : path56.posix;
23731
+ const P3 = platform3 === "win32" ? path60.win32 : path60.posix;
23262
23732
  const delim = platform3 === "win32" ? ";" : ":";
23263
23733
  const names = doltBinaryNames(platform3);
23264
23734
  const pathDirs = _doltPathSeam.getPath().split(delim).filter(Boolean);
@@ -23294,7 +23764,7 @@ function _defaultDoltInstallSpawn(strategy) {
23294
23764
  };
23295
23765
  let proc;
23296
23766
  try {
23297
- proc = (0, import_child_process21.spawn)(strategy.command, strategy.args, {
23767
+ proc = (0, import_child_process22.spawn)(strategy.command, strategy.args, {
23298
23768
  env: process.env,
23299
23769
  stdio: ["ignore", "pipe", "pipe"]
23300
23770
  });
@@ -23391,89 +23861,6 @@ async function ensureSharedServer(adapter, options = {}) {
23391
23861
  return { up: false, started: false };
23392
23862
  }
23393
23863
 
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
23864
  // src/beads/project-prefix.ts
23478
23865
  var crypto3 = __toESM(require("crypto"));
23479
23866
  function prefixForProjectKey(projectKey) {
@@ -23518,17 +23905,17 @@ var _provisionSeam = {
23518
23905
  };
23519
23906
  var _linkSeam = {
23520
23907
  platform: () => process.platform,
23521
- homedir: () => os44.homedir(),
23908
+ homedir: () => os45.homedir(),
23522
23909
  isWritableDir: (dir) => {
23523
23910
  try {
23524
- fs55.accessSync(dir, fs55.constants.W_OK);
23911
+ fs58.accessSync(dir, fs58.constants.W_OK);
23525
23912
  return true;
23526
23913
  } catch {
23527
23914
  return false;
23528
23915
  }
23529
23916
  },
23530
23917
  ensureDir: (dir) => {
23531
- fs55.mkdirSync(dir, { recursive: true });
23918
+ fs58.mkdirSync(dir, { recursive: true });
23532
23919
  },
23533
23920
  /**
23534
23921
  * A directory to symlink `bd` into so the AGENT's shell + Claude Code's
@@ -23549,9 +23936,9 @@ var _linkSeam = {
23549
23936
  * which `linkBdOntoPath` creates if missing.
23550
23937
  */
23551
23938
  cliBinDir: () => {
23552
- const pathDirs = (process.env.PATH ?? "").split(path58.delimiter).filter(Boolean);
23939
+ const pathDirs = (process.env.PATH ?? "").split(path61.delimiter).filter(Boolean);
23553
23940
  const home = _linkSeam.homedir();
23554
- const localBin = home ? path58.join(home, ".local", "bin") : null;
23941
+ const localBin = home ? path61.join(home, ".local", "bin") : null;
23555
23942
  if (localBin) {
23556
23943
  try {
23557
23944
  _linkSeam.ensureDir(localBin);
@@ -23561,16 +23948,16 @@ var _linkSeam = {
23561
23948
  const candidates = [];
23562
23949
  if (localBin) candidates.push(localBin);
23563
23950
  try {
23564
- candidates.push(path58.dirname(process.execPath));
23951
+ candidates.push(path61.dirname(process.execPath));
23565
23952
  } catch {
23566
23953
  }
23567
23954
  candidates.push("/usr/local/bin");
23568
23955
  const entry = process.argv[1];
23569
23956
  if (entry) {
23570
23957
  try {
23571
- candidates.push(path58.dirname(fs55.realpathSync(entry)));
23958
+ candidates.push(path61.dirname(fs58.realpathSync(entry)));
23572
23959
  } catch {
23573
- candidates.push(path58.dirname(entry));
23960
+ candidates.push(path61.dirname(entry));
23574
23961
  }
23575
23962
  }
23576
23963
  const onPathWritable = candidates.find(
@@ -23582,20 +23969,20 @@ var _linkSeam = {
23582
23969
  /** Current symlink target at `linkPath`, or null when absent / not a link. */
23583
23970
  readlink: (linkPath) => {
23584
23971
  try {
23585
- return fs55.readlinkSync(linkPath);
23972
+ return fs58.readlinkSync(linkPath);
23586
23973
  } catch {
23587
23974
  return null;
23588
23975
  }
23589
23976
  },
23590
- unlink: (linkPath) => fs55.unlinkSync(linkPath),
23591
- symlink: (target, linkPath) => fs55.symlinkSync(target, linkPath)
23977
+ unlink: (linkPath) => fs58.unlinkSync(linkPath),
23978
+ symlink: (target, linkPath) => fs58.symlinkSync(target, linkPath)
23592
23979
  };
23593
23980
  function linkBdOntoPath(binaryPath) {
23594
23981
  if (_linkSeam.platform() === "win32") return;
23595
23982
  const binDir = _linkSeam.cliBinDir();
23596
23983
  if (!binDir) return;
23597
23984
  _linkSeam.ensureDir(binDir);
23598
- const linkPath = path58.join(binDir, "bd");
23985
+ const linkPath = path61.join(binDir, "bd");
23599
23986
  if (linkPath === binaryPath) return;
23600
23987
  const current = _linkSeam.readlink(linkPath);
23601
23988
  if (current === binaryPath) return;
@@ -23790,7 +24177,7 @@ function dedupeRecipes(agents) {
23790
24177
 
23791
24178
  // src/beads/watcher.ts
23792
24179
  var crypto4 = __toESM(require("crypto"));
23793
- var path59 = __toESM(require("path"));
24180
+ var path62 = __toESM(require("path"));
23794
24181
  var API_BASE6 = resolveApiBaseUrl();
23795
24182
  var DEBOUNCE_MS2 = 400;
23796
24183
  var ZERO_SUMMARY = {
@@ -23814,7 +24201,7 @@ var BeadsWatcher = class {
23814
24201
  constructor(opts) {
23815
24202
  this.opts = opts;
23816
24203
  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");
24204
+ this.feedPath = opts.feedPath ?? path62.join(opts.cwd ?? process.cwd(), ".beads", "last-touched");
23818
24205
  this.apiBase = opts.apiBaseUrl ?? API_BASE6;
23819
24206
  }
23820
24207
  opts;
@@ -24313,8 +24700,8 @@ function cleanupAttachmentTempFiles() {
24313
24700
  function saveFilesTemp(files) {
24314
24701
  return files.filter(({ base64 }) => base64 && base64.length > 0).map(({ filename, base64 }) => {
24315
24702
  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"));
24703
+ const tmpPath = path65.join(os49.tmpdir(), `codeam-${(0, import_crypto3.randomUUID)()}-${safeName}`);
24704
+ fs61.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
24318
24705
  pendingAttachmentFiles.add(tmpPath);
24319
24706
  return tmpPath;
24320
24707
  });
@@ -24526,9 +24913,10 @@ var listFiles = async (ctx, cmd, parsed) => {
24526
24913
  await ctx.relay.sendResult(cmd.id, "completed", result);
24527
24914
  };
24528
24915
  var envReadH = async (ctx, cmd) => {
24529
- const envPath = path62.join(process.cwd(), ".env");
24916
+ const envPath = path65.join(process.cwd(), ".env");
24917
+ await restoreProjectEnvIfMissing(process.cwd(), ctx);
24530
24918
  try {
24531
- const raw = await fs58.promises.readFile(envPath, "utf8");
24919
+ const raw = await fs61.promises.readFile(envPath, "utf8");
24532
24920
  await ctx.relay.sendResult(cmd.id, "completed", {
24533
24921
  exists: true,
24534
24922
  vars: parseDotenv(raw)
@@ -24559,14 +24947,15 @@ var envWriteH = async (ctx, cmd, parsed) => {
24559
24947
  }
24560
24948
  seen.add(v.key);
24561
24949
  }
24562
- const envPath = path62.join(process.cwd(), ".env");
24563
- const tmpPath = path62.join(process.cwd(), ".env.codeam.tmp");
24950
+ const envPath = path65.join(process.cwd(), ".env");
24951
+ const tmpPath = path65.join(process.cwd(), ".env.codeam.tmp");
24564
24952
  try {
24565
- await fs58.promises.writeFile(tmpPath, serializeDotenv(vars), "utf8");
24566
- await fs58.promises.rename(tmpPath, envPath);
24953
+ await fs61.promises.writeFile(tmpPath, serializeDotenv(vars), "utf8");
24954
+ await fs61.promises.rename(tmpPath, envPath);
24567
24955
  await ctx.relay.sendResult(cmd.id, "completed", { ok: true, count: vars.length });
24956
+ void syncProjectEnvUp(process.cwd(), ctx);
24568
24957
  } catch (err) {
24569
- await fs58.promises.rm(tmpPath, { force: true }).catch(() => void 0);
24958
+ await fs61.promises.rm(tmpPath, { force: true }).catch(() => void 0);
24570
24959
  await ctx.relay.sendResult(cmd.id, "failed", { error: err.message });
24571
24960
  }
24572
24961
  };
@@ -24615,7 +25004,7 @@ var headroomConfigureH = async (ctx, cmd, parsed) => {
24615
25004
  let configuredAgent = rawAgentId;
24616
25005
  if (!configuredAgent) {
24617
25006
  try {
24618
- const raw = JSON.parse(fs58.readFileSync(headroomConfigPath(), "utf8"));
25007
+ const raw = JSON.parse(fs61.readFileSync(headroomConfigPath(), "utf8"));
24619
25008
  configuredAgent = raw.agent ?? "";
24620
25009
  } catch {
24621
25010
  }
@@ -24649,7 +25038,7 @@ var headroomConfigureH = async (ctx, cmd, parsed) => {
24649
25038
  persist: persistHeadroomConfig,
24650
25039
  readEnabled: () => {
24651
25040
  try {
24652
- const raw = JSON.parse(fs58.readFileSync(headroomConfigPath(), "utf8"));
25041
+ const raw = JSON.parse(fs61.readFileSync(headroomConfigPath(), "utf8"));
24653
25042
  return raw.enabled === true;
24654
25043
  } catch {
24655
25044
  return false;
@@ -24906,7 +25295,7 @@ var vcsAgentReviewH = async (ctx, cmd, parsed) => {
24906
25295
  });
24907
25296
  const token = ctx.pluginAuthToken;
24908
25297
  void (async () => {
24909
- const os60 = createOsStrategy();
25298
+ const os61 = createOsStrategy();
24910
25299
  try {
24911
25300
  const report = await reviewPullRequest(
24912
25301
  {
@@ -24915,7 +25304,7 @@ var vcsAgentReviewH = async (ctx, cmd, parsed) => {
24915
25304
  baseBranch: parsed.baseBranch
24916
25305
  },
24917
25306
  {
24918
- runReview: (input) => new CoderabbitRuntimeStrategy(os60).runOneShot(input),
25307
+ runReview: (input) => new CoderabbitRuntimeStrategy(os61).runOneShot(input),
24919
25308
  runGh: (args2) => defaultRunGh(args2),
24920
25309
  postReport: async (r) => {
24921
25310
  if (!token) return;
@@ -24953,7 +25342,7 @@ var headroomBudgetH = async (ctx, cmd) => {
24953
25342
  }
24954
25343
  let headroomActive = false;
24955
25344
  try {
24956
- const raw = JSON.parse(fs58.readFileSync(headroomConfigPath(), "utf8"));
25345
+ const raw = JSON.parse(fs61.readFileSync(headroomConfigPath(), "utf8"));
24957
25346
  headroomActive = raw.enabled === true;
24958
25347
  } catch {
24959
25348
  }
@@ -24963,7 +25352,7 @@ var headroomBudgetH = async (ctx, cmd) => {
24963
25352
  }
24964
25353
  let existingConfig = { enabled: true };
24965
25354
  try {
24966
- existingConfig = JSON.parse(fs58.readFileSync(headroomConfigPath(), "utf8"));
25355
+ existingConfig = JSON.parse(fs61.readFileSync(headroomConfigPath(), "utf8"));
24967
25356
  } catch {
24968
25357
  }
24969
25358
  if (payload.budgetEnabled && payload.budgetUsd != null) {
@@ -25076,9 +25465,9 @@ var CLI_UPDATE_MAX_ATTEMPTS = 3;
25076
25465
  function buildNpmInstallInvocation(opts) {
25077
25466
  const entryScript = opts?.entryScript ?? process.argv[1] ?? "";
25078
25467
  const execPath = opts?.execPath ?? process.execPath;
25079
- const exists2 = opts?.existsSync ?? fs58.existsSync;
25468
+ const exists2 = opts?.existsSync ?? fs61.existsSync;
25080
25469
  const platform3 = opts?.platform ?? process.platform;
25081
- const p2 = platform3 === "win32" ? path62.win32 : path62.posix;
25470
+ const p2 = platform3 === "win32" ? path65.win32 : path65.posix;
25082
25471
  const normalized = entryScript.split(/[\\/]/).join("/");
25083
25472
  const marker = "/lib/node_modules/codeam-cli/";
25084
25473
  const markerIdx = normalized.indexOf(marker);
@@ -25100,7 +25489,7 @@ function isPermissionError(stderr) {
25100
25489
  function resolveGlobalNodeModulesDir(opts) {
25101
25490
  const entryScript = opts?.entryScript ?? process.argv[1] ?? "";
25102
25491
  const platform3 = opts?.platform ?? process.platform;
25103
- const p2 = platform3 === "win32" ? path62.win32 : path62.posix;
25492
+ const p2 = platform3 === "win32" ? path65.win32 : path65.posix;
25104
25493
  const marker = "/lib/node_modules/codeam-cli/";
25105
25494
  const markerIdx = entryScript.split(/[\\/]/).join("/").indexOf(marker);
25106
25495
  if (markerIdx <= 0) return null;
@@ -25110,9 +25499,9 @@ function resolveGlobalNodeModulesDir(opts) {
25110
25499
  var STALE_STAGING_AGE_MS = CLI_UPDATE_INSTALL_TIMEOUT_MS;
25111
25500
  function sweepStaleCliStagingDirs(nodeModulesDir, now = Date.now(), deps) {
25112
25501
  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;
25502
+ const readdirSync12 = deps?.readdirSync ?? fs61.readdirSync;
25503
+ const statSync17 = deps?.statSync ?? fs61.statSync;
25504
+ const rmSync9 = deps?.rmSync ?? fs61.rmSync;
25116
25505
  let removed = 0;
25117
25506
  let entries;
25118
25507
  try {
@@ -25122,11 +25511,11 @@ function sweepStaleCliStagingDirs(nodeModulesDir, now = Date.now(), deps) {
25122
25511
  }
25123
25512
  for (const name of entries) {
25124
25513
  if (!/^\.codeam-cli-/.test(name)) continue;
25125
- const full = path62.join(nodeModulesDir, name);
25514
+ const full = path65.join(nodeModulesDir, name);
25126
25515
  try {
25127
25516
  const st3 = statSync17(full);
25128
25517
  if (now - st3.mtimeMs < STALE_STAGING_AGE_MS) continue;
25129
- rmSync8(full, { recursive: true, force: true });
25518
+ rmSync9(full, { recursive: true, force: true });
25130
25519
  removed++;
25131
25520
  } catch {
25132
25521
  }
@@ -25611,7 +26000,12 @@ function startPreviewFromDetection(ctx, detection, pluginAuthToken) {
25611
26000
  sessionId: ctx.sessionId,
25612
26001
  detection,
25613
26002
  cwd: process.cwd(),
25614
- emit: emit2
26003
+ emit: emit2,
26004
+ // Auth for the per-repo `.env` vault restore, performed INSIDE the bring-up
26005
+ // (provisionDeps stage, after the reuse short-circuit) so a fresh session of
26006
+ // this repo picks up its saved `.env` before the dev server spawns. Optional
26007
+ // — a caller without a token just skips the restore.
26008
+ projectEnvAuth: { pluginId: ctx.pluginId, pluginAuthToken }
25615
26009
  }).catch((err) => {
25616
26010
  const message = err instanceof Error ? err.message : String(err);
25617
26011
  log.warn("preview", `start crashed before ready: ${message}`);
@@ -25984,11 +26378,11 @@ function resolveTokenValue(args2) {
25984
26378
  }
25985
26379
  const fileFlag = args2.find((a) => a.startsWith("--token-file="));
25986
26380
  if (fileFlag) {
25987
- const path82 = fileFlag.slice("--token-file=".length);
26381
+ const path85 = fileFlag.slice("--token-file=".length);
25988
26382
  try {
25989
- const content = fs59.readFileSync(path82, "utf8").trim();
25990
- if (content.length === 0) fail(`--token-file ${path82} is empty`);
25991
- rmIfExistsQuiet(path82);
26383
+ const content = fs62.readFileSync(path85, "utf8").trim();
26384
+ if (content.length === 0) fail(`--token-file ${path85} is empty`);
26385
+ rmIfExistsQuiet(path85);
25992
26386
  return content;
25993
26387
  } catch (err) {
25994
26388
  fail(`Could not read --token-file: ${err.message}`);
@@ -26017,7 +26411,7 @@ async function claimOnce(token, pluginId, pluginSecretHash) {
26017
26411
  pluginId,
26018
26412
  ideName: "codeam-cli (codespace)",
26019
26413
  ideVersion: process.env.npm_package_version ?? "unknown",
26020
- hostname: os49.hostname(),
26414
+ hostname: os50.hostname(),
26021
26415
  codespaceName: process.env.CODESPACE_NAME ?? "",
26022
26416
  // Current git branch of the codespace's working directory, so the
26023
26417
  // backend can populate `PairedSession.branch` for the codespace pair.
@@ -26078,7 +26472,7 @@ async function claim(token, pluginId, pluginSecretHash) {
26078
26472
  }
26079
26473
  }
26080
26474
  function pairAutoLockPath() {
26081
- return path63.join(os49.homedir(), ".codeam", "pair-auto.lock");
26475
+ return path66.join(os50.homedir(), ".codeam", "pair-auto.lock");
26082
26476
  }
26083
26477
  function isLivePairAuto(pid) {
26084
26478
  if (!Number.isInteger(pid) || pid <= 0 || pid === process.pid) return false;
@@ -26088,7 +26482,7 @@ function isLivePairAuto(pid) {
26088
26482
  if (e.code !== "EPERM") return false;
26089
26483
  }
26090
26484
  try {
26091
- return fs59.readFileSync(`/proc/${pid}/cmdline`, "utf8").includes("codeam");
26485
+ return fs62.readFileSync(`/proc/${pid}/cmdline`, "utf8").includes("codeam");
26092
26486
  } catch {
26093
26487
  return true;
26094
26488
  }
@@ -26098,24 +26492,24 @@ function isLiveCodeam(pid) {
26098
26492
  }
26099
26493
  function daemonLockPath(sessionId) {
26100
26494
  const safe = sessionId.replace(/[^a-zA-Z0-9_-]/g, "_");
26101
- return path63.join(os49.homedir(), ".codeam", `daemon-${safe}.lock`);
26495
+ return path66.join(os50.homedir(), ".codeam", `daemon-${safe}.lock`);
26102
26496
  }
26103
26497
  function acquireDaemonLock(sessionId) {
26104
26498
  const lockPath = daemonLockPath(sessionId);
26105
26499
  try {
26106
- fs59.mkdirSync(path63.dirname(lockPath), { recursive: true });
26500
+ fs62.mkdirSync(path66.dirname(lockPath), { recursive: true });
26107
26501
  try {
26108
- fs59.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
26502
+ fs62.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
26109
26503
  } catch (e) {
26110
26504
  if (e.code !== "EEXIST") throw e;
26111
- const holder = Number(fs59.readFileSync(lockPath, "utf8").trim());
26505
+ const holder = Number(fs62.readFileSync(lockPath, "utf8").trim());
26112
26506
  if (holder && holder !== process.pid && isLiveCodeam(holder)) return false;
26113
- fs59.writeFileSync(lockPath, String(process.pid));
26507
+ fs62.writeFileSync(lockPath, String(process.pid));
26114
26508
  }
26115
26509
  const release3 = () => {
26116
26510
  try {
26117
- if (fs59.existsSync(lockPath) && Number(fs59.readFileSync(lockPath, "utf8").trim()) === process.pid) {
26118
- fs59.unlinkSync(lockPath);
26511
+ if (fs62.existsSync(lockPath) && Number(fs62.readFileSync(lockPath, "utf8").trim()) === process.pid) {
26512
+ fs62.unlinkSync(lockPath);
26119
26513
  }
26120
26514
  } catch {
26121
26515
  }
@@ -26137,19 +26531,19 @@ function acquireDaemonLock(sessionId) {
26137
26531
  function acquireSingletonLock() {
26138
26532
  const lockPath = pairAutoLockPath();
26139
26533
  try {
26140
- fs59.mkdirSync(path63.dirname(lockPath), { recursive: true });
26534
+ fs62.mkdirSync(path66.dirname(lockPath), { recursive: true });
26141
26535
  try {
26142
- fs59.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
26536
+ fs62.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
26143
26537
  } catch (e) {
26144
26538
  if (e.code !== "EEXIST") throw e;
26145
- const holder = Number(fs59.readFileSync(lockPath, "utf8").trim());
26539
+ const holder = Number(fs62.readFileSync(lockPath, "utf8").trim());
26146
26540
  if (isLivePairAuto(holder)) return false;
26147
- fs59.writeFileSync(lockPath, String(process.pid));
26541
+ fs62.writeFileSync(lockPath, String(process.pid));
26148
26542
  }
26149
26543
  process.once("exit", () => {
26150
26544
  try {
26151
- if (fs59.existsSync(lockPath) && Number(fs59.readFileSync(lockPath, "utf8").trim()) === process.pid) {
26152
- fs59.unlinkSync(lockPath);
26545
+ if (fs62.existsSync(lockPath) && Number(fs62.readFileSync(lockPath, "utf8").trim()) === process.pid) {
26546
+ fs62.unlinkSync(lockPath);
26153
26547
  }
26154
26548
  } catch {
26155
26549
  }
@@ -26601,10 +26995,10 @@ var AgentService = class _AgentService {
26601
26995
  };
26602
26996
 
26603
26997
  // src/agents/acp/adapters.ts
26604
- var path65 = __toESM(require("path"));
26998
+ var path68 = __toESM(require("path"));
26605
26999
 
26606
27000
  // src/agents/acp/agent-binary.ts
26607
- var import_fs4 = __toESM(require("fs"));
27001
+ var import_fs6 = __toESM(require("fs"));
26608
27002
  var import_os11 = __toESM(require("os"));
26609
27003
  var import_path8 = __toESM(require("path"));
26610
27004
  var import_child_process26 = require("child_process");
@@ -26634,7 +27028,7 @@ function defaultSdkDir() {
26634
27028
  return resolveSdkDirViaRequire();
26635
27029
  }
26636
27030
  function resolveClaudeNativeBinary(deps = {}) {
26637
- const existsSync27 = deps.existsSync ?? import_fs4.default.existsSync;
27031
+ const existsSync27 = deps.existsSync ?? import_fs6.default.existsSync;
26638
27032
  const platformKey = deps.platformKey ?? currentPlatformKey();
26639
27033
  const sdkDir = deps.sdkDir !== void 0 ? deps.sdkDir : defaultSdkDir();
26640
27034
  if (!sdkDir) return null;
@@ -26692,7 +27086,7 @@ async function waitForCommandOnPath(cmd, opts = {}) {
26692
27086
  return check();
26693
27087
  }
26694
27088
  function resolveCursorAgentBinary(deps = {}) {
26695
- const existsSync27 = deps.existsSync ?? import_fs4.default.existsSync;
27089
+ const existsSync27 = deps.existsSync ?? import_fs6.default.existsSync;
26696
27090
  const platform3 = deps.platform ?? process.platform;
26697
27091
  const env = deps.env ?? process.env;
26698
27092
  if (platform3 === "win32") {
@@ -26891,13 +27285,13 @@ function resolveBin(pkgName, binName) {
26891
27285
  try {
26892
27286
  const manifestPath = require_.resolve(`${pkgName}/package.json`);
26893
27287
  const manifest = require_(`${pkgName}/package.json`);
26894
- const pkgDir = path65.dirname(manifestPath);
27288
+ const pkgDir = path68.dirname(manifestPath);
26895
27289
  const bin = manifest.bin;
26896
27290
  if (!bin) return null;
26897
- if (typeof bin === "string") return path65.resolve(pkgDir, bin);
27291
+ if (typeof bin === "string") return path68.resolve(pkgDir, bin);
26898
27292
  const target = binName ?? Object.keys(bin)[0];
26899
27293
  if (!target || !bin[target]) return null;
26900
- return path65.resolve(pkgDir, bin[target]);
27294
+ return path68.resolve(pkgDir, bin[target]);
26901
27295
  } catch {
26902
27296
  return null;
26903
27297
  }
@@ -27047,9 +27441,9 @@ async function resolveAcpAdapterWithRetry(agent, opts = {}) {
27047
27441
  var import_node_crypto11 = require("crypto");
27048
27442
 
27049
27443
  // src/services/history.service.ts
27050
- var fs61 = __toESM(require("fs"));
27051
- var path66 = __toESM(require("path"));
27052
- var os51 = __toESM(require("os"));
27444
+ var fs64 = __toESM(require("fs"));
27445
+ var path69 = __toESM(require("path"));
27446
+ var os52 = __toESM(require("os"));
27053
27447
  var https7 = __toESM(require("https"));
27054
27448
  var http6 = __toESM(require("http"));
27055
27449
  var import_zod2 = require("zod");
@@ -27076,7 +27470,7 @@ function parseJsonl(filePath) {
27076
27470
  const messages = [];
27077
27471
  let raw;
27078
27472
  try {
27079
- raw = fs61.readFileSync(filePath, "utf8");
27473
+ raw = fs64.readFileSync(filePath, "utf8");
27080
27474
  } catch (err) {
27081
27475
  if (err.code !== "ENOENT") {
27082
27476
  log.warn("history:parseJsonl", `read failed for ${filePath}`, err);
@@ -27217,7 +27611,7 @@ var HistoryService = class _HistoryService {
27217
27611
  return this._quotaPercent === null || Date.now() - this._quotaFetchedAt > ttlMs;
27218
27612
  }
27219
27613
  get projectDir() {
27220
- return this.runtime.resolveHistoryDir(this.cwd) ?? path66.join(os51.homedir(), ".claude", "projects", encodeCwd(this.cwd));
27614
+ return this.runtime.resolveHistoryDir(this.cwd) ?? path69.join(os52.homedir(), ".claude", "projects", encodeCwd(this.cwd));
27221
27615
  }
27222
27616
  /** Set the current Claude conversation ID (extracted from /cost command or session start) */
27223
27617
  setCurrentConversationId(id) {
@@ -27229,7 +27623,7 @@ var HistoryService = class _HistoryService {
27229
27623
  /** Return the current message count in the active conversation. */
27230
27624
  getCurrentMessageCount() {
27231
27625
  if (!this.currentConversationId) return 0;
27232
- const filePath = path66.join(this.projectDir, `${this.currentConversationId}.jsonl`);
27626
+ const filePath = path69.join(this.projectDir, `${this.currentConversationId}.jsonl`);
27233
27627
  return parseJsonl(filePath).length;
27234
27628
  }
27235
27629
  /**
@@ -27240,7 +27634,7 @@ var HistoryService = class _HistoryService {
27240
27634
  const deadline = Date.now() + timeoutMs;
27241
27635
  while (Date.now() < deadline) {
27242
27636
  if (!this.currentConversationId) return null;
27243
- const filePath = path66.join(this.projectDir, `${this.currentConversationId}.jsonl`);
27637
+ const filePath = path69.join(this.projectDir, `${this.currentConversationId}.jsonl`);
27244
27638
  const messages = parseJsonl(filePath);
27245
27639
  if (messages.length > previousCount) {
27246
27640
  for (let i = messages.length - 1; i >= previousCount; i--) {
@@ -27266,16 +27660,16 @@ var HistoryService = class _HistoryService {
27266
27660
  const dir = this.projectDir;
27267
27661
  const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
27268
27662
  try {
27269
- const files = fs61.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
27663
+ const files = fs64.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
27270
27664
  try {
27271
- const stat3 = fs61.statSync(path66.join(dir, e.name));
27665
+ const stat3 = fs64.statSync(path69.join(dir, e.name));
27272
27666
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
27273
27667
  } catch {
27274
27668
  return { name: e.name, mtime: 0, birthtime: 0 };
27275
27669
  }
27276
27670
  }).filter((f) => f.birthtime >= cutoff).sort((a, b) => b.mtime - a.mtime);
27277
27671
  if (files.length > 0) {
27278
- this.currentConversationId = path66.basename(files[0].name, ".jsonl");
27672
+ this.currentConversationId = path69.basename(files[0].name, ".jsonl");
27279
27673
  }
27280
27674
  } catch {
27281
27675
  }
@@ -27309,13 +27703,13 @@ var HistoryService = class _HistoryService {
27309
27703
  const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
27310
27704
  let entries;
27311
27705
  try {
27312
- entries = fs61.readdirSync(dir, { withFileTypes: true });
27706
+ entries = fs64.readdirSync(dir, { withFileTypes: true });
27313
27707
  } catch {
27314
27708
  return null;
27315
27709
  }
27316
27710
  const files = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
27317
27711
  try {
27318
- const stat3 = fs61.statSync(path66.join(dir, e.name));
27712
+ const stat3 = fs64.statSync(path69.join(dir, e.name));
27319
27713
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
27320
27714
  } catch {
27321
27715
  return { name: e.name, mtime: 0, birthtime: 0 };
@@ -27324,12 +27718,12 @@ var HistoryService = class _HistoryService {
27324
27718
  if (files.length === 0) return null;
27325
27719
  const targetFile = this.currentConversationId ? `${this.currentConversationId}.jsonl` : files[0].name;
27326
27720
  if (!files.some((f) => f.name === targetFile)) return null;
27327
- return this.extractUsageFromFile(path66.join(dir, targetFile));
27721
+ return this.extractUsageFromFile(path69.join(dir, targetFile));
27328
27722
  }
27329
27723
  extractUsageFromFile(filePath) {
27330
27724
  let raw;
27331
27725
  try {
27332
- raw = fs61.readFileSync(filePath, "utf8");
27726
+ raw = fs64.readFileSync(filePath, "utf8");
27333
27727
  } catch {
27334
27728
  return null;
27335
27729
  }
@@ -27374,9 +27768,9 @@ var HistoryService = class _HistoryService {
27374
27768
  let totalCost = 0;
27375
27769
  let files;
27376
27770
  try {
27377
- files = fs61.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
27771
+ files = fs64.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
27378
27772
  try {
27379
- return fs61.statSync(path66.join(projectDir, f)).mtimeMs >= monthStartMs;
27773
+ return fs64.statSync(path69.join(projectDir, f)).mtimeMs >= monthStartMs;
27380
27774
  } catch {
27381
27775
  return false;
27382
27776
  }
@@ -27387,7 +27781,7 @@ var HistoryService = class _HistoryService {
27387
27781
  for (const file of files) {
27388
27782
  let raw;
27389
27783
  try {
27390
- raw = fs61.readFileSync(path66.join(projectDir, file), "utf8");
27784
+ raw = fs64.readFileSync(path69.join(projectDir, file), "utf8");
27391
27785
  } catch {
27392
27786
  continue;
27393
27787
  }
@@ -27466,7 +27860,7 @@ var HistoryService = class _HistoryService {
27466
27860
  if (this.runtime.resolveHistoryFile) {
27467
27861
  return this.runtime.resolveHistoryFile(this.cwd, sessionId);
27468
27862
  }
27469
- return path66.join(this.projectDir, `${sessionId}.jsonl`);
27863
+ return path69.join(this.projectDir, `${sessionId}.jsonl`);
27470
27864
  }
27471
27865
  /**
27472
27866
  * Parse a conversation's messages from disk, agent-aware. Claude uses the
@@ -27500,7 +27894,7 @@ var HistoryService = class _HistoryService {
27500
27894
  };
27501
27895
  });
27502
27896
  }
27503
- return parseJsonl(path66.join(this.projectDir, `${sessionId}.jsonl`));
27897
+ return parseJsonl(path69.join(this.projectDir, `${sessionId}.jsonl`));
27504
27898
  }
27505
27899
  async loadConversation(sessionId) {
27506
27900
  const messages = this.readConversation(sessionId);
@@ -27568,7 +27962,7 @@ var HistoryService = class _HistoryService {
27568
27962
  if (!filePath) return false;
27569
27963
  let mtimeMs;
27570
27964
  try {
27571
- mtimeMs = fs61.statSync(filePath).mtimeMs;
27965
+ mtimeMs = fs64.statSync(filePath).mtimeMs;
27572
27966
  } catch {
27573
27967
  return false;
27574
27968
  }
@@ -27643,10 +28037,10 @@ var HistoryService = class _HistoryService {
27643
28037
 
27644
28038
  // src/agents/acp/client.ts
27645
28039
  var import_node_child_process29 = require("child_process");
27646
- var fs62 = __toESM(require("fs/promises"));
28040
+ var fs65 = __toESM(require("fs/promises"));
27647
28041
  var fsSync = __toESM(require("fs"));
27648
- var os53 = __toESM(require("os"));
27649
- var path68 = __toESM(require("path"));
28042
+ var os54 = __toESM(require("os"));
28043
+ var path71 = __toESM(require("path"));
27650
28044
  var import_node_stream = require("stream");
27651
28045
 
27652
28046
  // ../../node_modules/@agentclientprotocol/sdk/dist/schema/index.js
@@ -31672,19 +32066,19 @@ function createIdleTimeout(idleMs, makeError, activeIdleMs = idleMs) {
31672
32066
  }
31673
32067
 
31674
32068
  // src/agents/acp/internal-paths.ts
31675
- var path67 = __toESM(require("path"));
31676
- var os52 = __toESM(require("os"));
32069
+ var path70 = __toESM(require("path"));
32070
+ var os53 = __toESM(require("os"));
31677
32071
  var INTERNAL_TOKENS = [".codeam", "house-claude"];
31678
32072
  function textReferencesInternal(text) {
31679
32073
  if (!text) return false;
31680
32074
  return INTERNAL_TOKENS.some((t2) => text.includes(t2));
31681
32075
  }
31682
- function pathIsInternal(p2, homeDir2 = os52.homedir()) {
32076
+ function pathIsInternal(p2, homeDir2 = os53.homedir()) {
31683
32077
  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`);
32078
+ const abs = path70.resolve(p2);
32079
+ const home = path70.resolve(homeDir2);
32080
+ const within = (root) => abs === root || abs.startsWith(root + path70.sep);
32081
+ return within(path70.join(home, ".codeam")) || within(path70.join(home, ".beads")) || abs === path70.join(home, ".codeam-host.log") || abs.includes(`${path70.sep}house-claude${path70.sep}`) || abs.endsWith(`${path70.sep}house-claude`);
31688
32082
  }
31689
32083
  function toolCallReferencesInternal(call) {
31690
32084
  if (textReferencesInternal(call.title)) return true;
@@ -32513,7 +32907,7 @@ var AcpClient = class {
32513
32907
  throw new RequestError(-32002, INTERNAL_BLOCK_REASON, { uri: params.path });
32514
32908
  }
32515
32909
  try {
32516
- const content = await fs62.readFile(params.path, "utf8");
32910
+ const content = await fs65.readFile(params.path, "utf8");
32517
32911
  return applyLineRange(content, params.line ?? null, params.limit ?? null);
32518
32912
  } catch (err) {
32519
32913
  const code = err.code;
@@ -32536,7 +32930,7 @@ var AcpClient = class {
32536
32930
  throw new RequestError(-32002, INTERNAL_BLOCK_REASON, { uri: params.path });
32537
32931
  }
32538
32932
  try {
32539
- await fs62.writeFile(params.path, params.content, "utf8");
32933
+ await fs65.writeFile(params.path, params.content, "utf8");
32540
32934
  return {};
32541
32935
  } catch (err) {
32542
32936
  const code = err.code;
@@ -32596,29 +32990,29 @@ function applyLineRange(content, line, limit) {
32596
32990
  return { content: lines.slice(start2, end).join("\n") };
32597
32991
  }
32598
32992
  function knownAgentBinaryDirs() {
32599
- const home = os53.homedir();
32993
+ const home = os54.homedir();
32600
32994
  const out2 = [];
32601
32995
  out2.push("/tmp/codeam-node20/bin");
32602
32996
  for (const root of [
32603
32997
  "/usr/local/share/nvm/versions/node",
32604
- path68.join(home, ".nvm/versions/node")
32998
+ path71.join(home, ".nvm/versions/node")
32605
32999
  ]) {
32606
33000
  try {
32607
33001
  for (const child of fsSync.readdirSync(root)) {
32608
- out2.push(path68.join(root, child, "bin"));
33002
+ out2.push(path71.join(root, child, "bin"));
32609
33003
  }
32610
33004
  } catch {
32611
33005
  }
32612
33006
  }
32613
- out2.push(path68.join(home, ".volta/bin"));
33007
+ out2.push(path71.join(home, ".volta/bin"));
32614
33008
  out2.push("/usr/local/bin");
32615
33009
  out2.push("/usr/bin");
32616
- out2.push(path68.join(home, ".local/bin"));
32617
- out2.push(path68.join(home, "bin"));
33010
+ out2.push(path71.join(home, ".local/bin"));
33011
+ out2.push(path71.join(home, "bin"));
32618
33012
  if (process.platform === "win32") {
32619
33013
  const { LOCALAPPDATA, APPDATA } = process.env;
32620
- if (LOCALAPPDATA) out2.push(path68.join(LOCALAPPDATA, "cursor-agent"));
32621
- if (APPDATA) out2.push(path68.join(APPDATA, "npm"));
33014
+ if (LOCALAPPDATA) out2.push(path71.join(LOCALAPPDATA, "cursor-agent"));
33015
+ if (APPDATA) out2.push(path71.join(APPDATA, "npm"));
32622
33016
  }
32623
33017
  return out2.filter((p2) => {
32624
33018
  try {
@@ -32630,7 +33024,7 @@ function knownAgentBinaryDirs() {
32630
33024
  }
32631
33025
  function expandPathForAgentBinaries(existingPath) {
32632
33026
  const existing = new Set(
32633
- existingPath.split(path68.delimiter).filter((p2) => p2.length > 0)
33027
+ existingPath.split(path71.delimiter).filter((p2) => p2.length > 0)
32634
33028
  );
32635
33029
  const additions = [];
32636
33030
  for (const dir of knownAgentBinaryDirs()) {
@@ -32640,7 +33034,7 @@ function expandPathForAgentBinaries(existingPath) {
32640
33034
  }
32641
33035
  }
32642
33036
  if (additions.length === 0) return existingPath;
32643
- return [...additions, existingPath].filter((p2) => p2.length > 0).join(path68.delimiter);
33037
+ return [...additions, existingPath].filter((p2) => p2.length > 0).join(path71.delimiter);
32644
33038
  }
32645
33039
 
32646
33040
  // src/agents/acp/headroom-budget-proxy.ts
@@ -33122,15 +33516,15 @@ function commonPrefixLength(a, b) {
33122
33516
 
33123
33517
  // src/agents/acp/onboarding.ts
33124
33518
  var import_child_process27 = require("child_process");
33125
- var fs63 = __toESM(require("fs"));
33126
- var os54 = __toESM(require("os"));
33127
- var path69 = __toESM(require("path"));
33519
+ var fs66 = __toESM(require("fs"));
33520
+ var os55 = __toESM(require("os"));
33521
+ var path72 = __toESM(require("path"));
33128
33522
  var _onboardingSeam = {
33129
- markerPath: (sessionId) => path69.join(os54.homedir(), ".codeam", "welcomed", `${sessionId}.done`),
33130
- exists: (p2) => fs63.existsSync(p2),
33523
+ markerPath: (sessionId) => path72.join(os55.homedir(), ".codeam", "welcomed", `${sessionId}.done`),
33524
+ exists: (p2) => fs66.existsSync(p2),
33131
33525
  write: (p2) => {
33132
- fs63.mkdirSync(path69.dirname(p2), { recursive: true });
33133
- fs63.writeFileSync(p2, "");
33526
+ fs66.mkdirSync(path72.dirname(p2), { recursive: true });
33527
+ fs66.writeFileSync(p2, "");
33134
33528
  },
33135
33529
  disabled: () => {
33136
33530
  const v = process.env.CODEAM_ONBOARDING_DISABLED;
@@ -33167,7 +33561,7 @@ function resolveRepoName(cwd) {
33167
33561
  if (name) return name;
33168
33562
  }
33169
33563
  }
33170
- const base = path69.basename(cwd || "");
33564
+ const base = path72.basename(cwd || "");
33171
33565
  if (base && !isUuid(base)) return base;
33172
33566
  return "this project";
33173
33567
  }
@@ -33425,13 +33819,13 @@ var import_crypto5 = require("crypto");
33425
33819
 
33426
33820
  // src/services/turn-files/git-changeset.ts
33427
33821
  var import_child_process28 = require("child_process");
33428
- var fs65 = __toESM(require("fs/promises"));
33429
- var path71 = __toESM(require("path"));
33822
+ var fs68 = __toESM(require("fs/promises"));
33823
+ var path74 = __toESM(require("path"));
33430
33824
 
33431
33825
  // src/services/turn-files/review-ignore.ts
33432
33826
  var import_ignore2 = __toESM(require("ignore"));
33433
- var fs64 = __toESM(require("fs"));
33434
- var path70 = __toESM(require("path"));
33827
+ var fs67 = __toESM(require("fs"));
33828
+ var path73 = __toESM(require("path"));
33435
33829
  var CURATED_REVIEW_IGNORE = [
33436
33830
  // Google Cloud SDK (the incident) — installs a huge python tree.
33437
33831
  "google-cloud-sdk/",
@@ -33470,7 +33864,7 @@ var CURATED_REVIEW_IGNORE = [
33470
33864
  function makeReviewIgnore(repoRoot) {
33471
33865
  const ig = (0, import_ignore2.default)().add(CURATED_REVIEW_IGNORE);
33472
33866
  try {
33473
- const custom = fs64.readFileSync(path70.join(repoRoot, ".codeam", "reviewignore"), "utf8");
33867
+ const custom = fs67.readFileSync(path73.join(repoRoot, ".codeam", "reviewignore"), "utf8");
33474
33868
  ig.add(custom);
33475
33869
  } catch {
33476
33870
  }
@@ -33515,7 +33909,7 @@ async function collectRepoChangeset(opts) {
33515
33909
  let stats;
33516
33910
  if (!truncated && row.fileStatus === "added" && numstatEntry === void 0) {
33517
33911
  const lineCount = await readUntrackedLineCount(
33518
- path71.join(opts.repoRoot, row.filePath)
33912
+ path74.join(opts.repoRoot, row.filePath)
33519
33913
  );
33520
33914
  stats = { added: lineCount, removed: 0 };
33521
33915
  } else {
@@ -33546,7 +33940,7 @@ function readUntrackedLineCount(absPath) {
33546
33940
  }
33547
33941
  async function defaultReadUntrackedLineCount(absPath) {
33548
33942
  try {
33549
- const content = await fs65.readFile(absPath, "utf8");
33943
+ const content = await fs68.readFile(absPath, "utf8");
33550
33944
  let count = 0;
33551
33945
  let pos = -1;
33552
33946
  while ((pos = content.indexOf("\n", pos + 1)) !== -1) {
@@ -33638,7 +34032,7 @@ function defaultRunGit(cwd, args2) {
33638
34032
  });
33639
34033
  }
33640
34034
  async function discoverRepos(workingDir, maxDepth = 4) {
33641
- const fs72 = await import("fs/promises");
34035
+ const fs75 = await import("fs/promises");
33642
34036
  const out2 = [];
33643
34037
  await walk(workingDir, 0);
33644
34038
  return out2;
@@ -33646,7 +34040,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
33646
34040
  if (depth > maxDepth) return;
33647
34041
  let entries = [];
33648
34042
  try {
33649
- const dirents = await fs72.readdir(dir, { withFileTypes: true });
34043
+ const dirents = await fs75.readdir(dir, { withFileTypes: true });
33650
34044
  entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
33651
34045
  } catch {
33652
34046
  return;
@@ -33657,8 +34051,8 @@ async function discoverRepos(workingDir, maxDepth = 4) {
33657
34051
  if (hasGit) {
33658
34052
  out2.push({
33659
34053
  repoRoot: dir,
33660
- repoPath: path71.relative(workingDir, dir),
33661
- repoName: path71.basename(dir)
34054
+ repoPath: path74.relative(workingDir, dir),
34055
+ repoName: path74.basename(dir)
33662
34056
  });
33663
34057
  return;
33664
34058
  }
@@ -33666,14 +34060,14 @@ async function discoverRepos(workingDir, maxDepth = 4) {
33666
34060
  if (!entry.isDirectory) continue;
33667
34061
  if (entry.name === "node_modules") continue;
33668
34062
  if (entry.name === "dist" || entry.name === "build") continue;
33669
- await walk(path71.join(dir, entry.name), depth + 1);
34063
+ await walk(path74.join(dir, entry.name), depth + 1);
33670
34064
  }
33671
34065
  }
33672
34066
  }
33673
34067
 
33674
34068
  // src/services/turn-files/files-outbox.ts
33675
- var fs66 = __toESM(require("fs/promises"));
33676
- var path72 = __toESM(require("path"));
34069
+ var fs69 = __toESM(require("fs/promises"));
34070
+ var path75 = __toESM(require("path"));
33677
34071
  var import_os12 = require("os");
33678
34072
  var HOME_OUTBOX_DIR = ".codeam/outbox";
33679
34073
  var MAX_AGE_MS = 24 * 60 * 60 * 1e3;
@@ -33706,16 +34100,16 @@ var FilesOutbox = class {
33706
34100
  backoffIndex = 0;
33707
34101
  stopped = false;
33708
34102
  constructor(opts) {
33709
- const base = opts.baseDir ?? path72.join(homeDir(), HOME_OUTBOX_DIR);
33710
- this.filePath = path72.join(base, `${opts.sessionId}.jsonl`);
34103
+ const base = opts.baseDir ?? path75.join(homeDir(), HOME_OUTBOX_DIR);
34104
+ this.filePath = path75.join(base, `${opts.sessionId}.jsonl`);
33711
34105
  this.post = opts.post;
33712
34106
  this.autoSchedule = opts.autoSchedule !== false;
33713
34107
  }
33714
34108
  /** Persist the entry to disk and trigger a flush. Returns once the
33715
34109
  * line is durable on disk (not once the POST succeeds). */
33716
34110
  async enqueue(entry) {
33717
- await fs66.mkdir(path72.dirname(this.filePath), { recursive: true });
33718
- await fs66.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
34111
+ await fs69.mkdir(path75.dirname(this.filePath), { recursive: true });
34112
+ await fs69.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
33719
34113
  this.backoffIndex = 0;
33720
34114
  if (this.autoSchedule) this.scheduleFlush(0);
33721
34115
  }
@@ -33806,7 +34200,7 @@ var FilesOutbox = class {
33806
34200
  async readAll() {
33807
34201
  let raw = "";
33808
34202
  try {
33809
- raw = await fs66.readFile(this.filePath, "utf8");
34203
+ raw = await fs69.readFile(this.filePath, "utf8");
33810
34204
  } catch {
33811
34205
  return [];
33812
34206
  }
@@ -33830,12 +34224,12 @@ var FilesOutbox = class {
33830
34224
  async rewrite(entries) {
33831
34225
  const tmpPath = `${this.filePath}.${process.pid}.tmp`;
33832
34226
  if (entries.length === 0) {
33833
- await fs66.unlink(this.filePath).catch(() => void 0);
34227
+ await fs69.unlink(this.filePath).catch(() => void 0);
33834
34228
  return;
33835
34229
  }
33836
34230
  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);
34231
+ await fs69.writeFile(tmpPath, payload, "utf8");
34232
+ await fs69.rename(tmpPath, this.filePath);
33839
34233
  }
33840
34234
  };
33841
34235
  function applyJitter(ms) {
@@ -34580,11 +34974,13 @@ async function startTaskH(ctx) {
34580
34974
  }
34581
34975
  await streaming.beginTurn();
34582
34976
  history.appendUserPrompt(promptText);
34977
+ let turnClosed = false;
34583
34978
  try {
34584
34979
  const reply = await client3.prompt(blocks);
34585
34980
  const finalText = streaming.getCurrentText();
34586
34981
  if (agentHooks(opts.agent)?.classifyCompletedReply?.(finalText) === "upgrade_required") {
34587
34982
  await streaming.closeWithBubble(CURSOR_UPGRADE_MESSAGE);
34983
+ turnClosed = true;
34588
34984
  history.appendAgentReply(CURSOR_UPGRADE_MESSAGE);
34589
34985
  void history.flush();
34590
34986
  log.info("acpRunner", `start_task \u2190 cursor-plan-upgrade-required id=${cmd.id.slice(0, 8)}`);
@@ -34592,6 +34988,7 @@ async function startTaskH(ctx) {
34592
34988
  } else if (replyIsHouseAgentLimit(finalText)) {
34593
34989
  const houseBubble = houseAgentLimitMessage(finalText);
34594
34990
  await streaming.closeWithBubble(houseBubble);
34991
+ turnClosed = true;
34595
34992
  history.appendAgentReply(houseBubble);
34596
34993
  void history.flush();
34597
34994
  turnFiles.flushTurn().catch((err) => {
@@ -34603,6 +35000,7 @@ async function startTaskH(ctx) {
34603
35000
  });
34604
35001
  } else if (replyIsAuthFailure(finalText)) {
34605
35002
  await streaming.closeWithBubble(AUTH_FAILURE_MESSAGE);
35003
+ turnClosed = true;
34606
35004
  history.appendAgentReply(AUTH_FAILURE_MESSAGE);
34607
35005
  void history.flush();
34608
35006
  turnFiles.flushTurn().catch((err) => {
@@ -34613,6 +35011,7 @@ async function startTaskH(ctx) {
34613
35011
  await relay.sendResult(cmd.id, "failed", { error: "agent reply reported auth failure" });
34614
35012
  } else if (shouldOfferOneMRecovery({ detail: "", recentStderr: recentStderr.join("\n"), finalText })) {
34615
35013
  await streaming.closeWithBubble(ONE_M_CREDITS_MESSAGE);
35014
+ turnClosed = true;
34616
35015
  history.appendAgentReply(ONE_M_CREDITS_MESSAGE);
34617
35016
  void history.flush();
34618
35017
  turnFiles.flushTurn().catch((err) => {
@@ -34625,6 +35024,7 @@ async function startTaskH(ctx) {
34625
35024
  });
34626
35025
  } else {
34627
35026
  await streaming.closeTurnWithInteractiveDetection();
35027
+ turnClosed = true;
34628
35028
  const replyLine = formatAgentReplyLine(finalText);
34629
35029
  if (replyLine.length > 0) {
34630
35030
  showInfo(replyLine);
@@ -34643,6 +35043,13 @@ async function startTaskH(ctx) {
34643
35043
  await relay.sendResult(cmd.id, "completed", { stopReason: reply.stopReason });
34644
35044
  }
34645
35045
  } catch (err) {
35046
+ if (turnClosed) {
35047
+ log.warn(
35048
+ "acpRunner",
35049
+ `post-close ack failed (turn already delivered) id=${cmd.id.slice(0, 8)}: ${describeError(err)}`
35050
+ );
35051
+ return;
35052
+ }
34646
35053
  const hadText = streaming.hasVisibleProgress();
34647
35054
  const detail = describeError(err);
34648
35055
  log.warn("acpRunner", `prompt failed: ${detail}`);
@@ -37080,9 +37487,9 @@ function startClaudeCredentialSync(opts) {
37080
37487
  }
37081
37488
 
37082
37489
  // src/beads/workflow-hint.ts
37083
- var fs68 = __toESM(require("fs"));
37084
- var path74 = __toESM(require("path"));
37085
- var os55 = __toESM(require("os"));
37490
+ var fs71 = __toESM(require("fs"));
37491
+ var path77 = __toESM(require("path"));
37492
+ var os56 = __toESM(require("os"));
37086
37493
  var BEADS_HINT_MARKER = "<!-- codeam:beads-workflow -->";
37087
37494
  var BEADS_HINT = `${BEADS_HINT_MARKER}
37088
37495
  # Beads (bd) \u2014 task tracking + persistent memory (ALWAYS use it)
@@ -37096,22 +37503,22 @@ This environment uses **bd (beads)** for issue/task tracking and persistent memo
37096
37503
  - \`bd ready\` (available work) \xB7 \`bd show <id>\` \xB7 \`bd update <id> --claim\` \xB7 \`bd close <id>\`.
37097
37504
  - Use \`bd remember "..."\` for persistent knowledge \u2014 do NOT use MEMORY.md files.
37098
37505
  ${BEADS_HINT_MARKER}`;
37099
- function ensureBeadsWorkflowHint(homeDir2 = os55.homedir()) {
37506
+ function ensureBeadsWorkflowHint(homeDir2 = os56.homedir()) {
37100
37507
  try {
37101
- const file = path74.join(homeDir2, ".claude", "CLAUDE.md");
37508
+ const file = path77.join(homeDir2, ".claude", "CLAUDE.md");
37102
37509
  let existing = "";
37103
37510
  try {
37104
- existing = fs68.readFileSync(file, "utf8");
37511
+ existing = fs71.readFileSync(file, "utf8");
37105
37512
  } catch {
37106
37513
  }
37107
37514
  if (existing.includes(BEADS_HINT_MARKER)) return;
37108
- fs68.mkdirSync(path74.dirname(file), { recursive: true });
37515
+ fs71.mkdirSync(path77.dirname(file), { recursive: true });
37109
37516
  const next = existing.trim() ? `${existing.trimEnd()}
37110
37517
 
37111
37518
  ${BEADS_HINT}
37112
37519
  ` : `${BEADS_HINT}
37113
37520
  `;
37114
- fs68.writeFileSync(file, next);
37521
+ fs71.writeFileSync(file, next);
37115
37522
  } catch {
37116
37523
  }
37117
37524
  }
@@ -37483,7 +37890,7 @@ var AcpDriver = class {
37483
37890
  };
37484
37891
 
37485
37892
  // src/baton/transcript-mirror.ts
37486
- var fs69 = __toESM(require("fs"));
37893
+ var fs72 = __toESM(require("fs"));
37487
37894
  var TranscriptMirror = class {
37488
37895
  constructor(deps) {
37489
37896
  this.deps = deps;
@@ -37550,7 +37957,7 @@ var TranscriptMirror = class {
37550
37957
  }
37551
37958
  };
37552
37959
  function defaultWatch(file, onChange) {
37553
- const w3 = fs69.watch(file, { persistent: false }, () => onChange());
37960
+ const w3 = fs72.watch(file, { persistent: false }, () => onChange());
37554
37961
  return () => w3.close();
37555
37962
  }
37556
37963
 
@@ -37812,16 +38219,16 @@ function toEpochMs(ts) {
37812
38219
  }
37813
38220
 
37814
38221
  // src/agents/claude/onboarding.ts
37815
- var fs70 = __toESM(require("fs"));
37816
- var os57 = __toESM(require("os"));
37817
- var path75 = __toESM(require("path"));
38222
+ var fs73 = __toESM(require("fs"));
38223
+ var os58 = __toESM(require("os"));
38224
+ var path78 = __toESM(require("path"));
37818
38225
  var ONBOARDING_VERSION_SENTINEL = "9999.0.0";
37819
38226
  function ensureClaudeOnboarded(cwd) {
37820
38227
  try {
37821
- const file = path75.join(os57.homedir(), ".claude.json");
38228
+ const file = path78.join(os58.homedir(), ".claude.json");
37822
38229
  let config = {};
37823
38230
  try {
37824
- config = JSON.parse(fs70.readFileSync(file, "utf8"));
38231
+ config = JSON.parse(fs73.readFileSync(file, "utf8"));
37825
38232
  } catch {
37826
38233
  }
37827
38234
  let changed = false;
@@ -37846,8 +38253,8 @@ function ensureClaudeOnboarded(cwd) {
37846
38253
  }
37847
38254
  }
37848
38255
  if (!changed) return;
37849
- fs70.mkdirSync(path75.dirname(file), { recursive: true });
37850
- fs70.writeFileSync(file, JSON.stringify(config, null, 2));
38256
+ fs73.mkdirSync(path78.dirname(file), { recursive: true });
38257
+ fs73.writeFileSync(file, JSON.stringify(config, null, 2));
37851
38258
  log.info(
37852
38259
  "claude",
37853
38260
  `pre-completed Claude onboarding${cwd ? ` + trusted workspace ${cwd}` : ""}`
@@ -38574,7 +38981,7 @@ var import_picocolors11 = __toESM(require("picocolors"));
38574
38981
  var import_child_process29 = require("child_process");
38575
38982
  var import_util4 = require("util");
38576
38983
  var import_picocolors9 = __toESM(require("picocolors"));
38577
- var path76 = __toESM(require("path"));
38984
+ var path79 = __toESM(require("path"));
38578
38985
  var execFileP6 = (0, import_util4.promisify)(import_child_process29.execFile);
38579
38986
  var MAX_BUFFER = 8 * 1024 * 1024;
38580
38987
  function resetStdinForChild() {
@@ -39063,7 +39470,7 @@ var GitHubCodespacesProvider = class {
39063
39470
  });
39064
39471
  }
39065
39472
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
39066
- const remoteDir = path76.posix.dirname(remotePath);
39473
+ const remoteDir = path79.posix.dirname(remotePath);
39067
39474
  const parts = [
39068
39475
  `mkdir -p ${shellQuote(remoteDir)}`,
39069
39476
  `cat > ${shellQuote(remotePath)}`
@@ -39133,7 +39540,7 @@ function shellQuote(s) {
39133
39540
  // src/services/providers/gitpod.ts
39134
39541
  var import_child_process30 = require("child_process");
39135
39542
  var import_util5 = require("util");
39136
- var path77 = __toESM(require("path"));
39543
+ var path80 = __toESM(require("path"));
39137
39544
  var import_picocolors10 = __toESM(require("picocolors"));
39138
39545
  var execFileP7 = (0, import_util5.promisify)(import_child_process30.execFile);
39139
39546
  var MAX_BUFFER2 = 8 * 1024 * 1024;
@@ -39373,7 +39780,7 @@ var GitpodProvider = class {
39373
39780
  });
39374
39781
  }
39375
39782
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
39376
- const remoteDir = path77.posix.dirname(remotePath);
39783
+ const remoteDir = path80.posix.dirname(remotePath);
39377
39784
  const parts = [
39378
39785
  `mkdir -p ${shellQuote2(remoteDir)}`,
39379
39786
  `cat > ${shellQuote2(remotePath)}`
@@ -39409,7 +39816,7 @@ function shellQuote2(s) {
39409
39816
  // src/services/providers/gitlab-workspaces.ts
39410
39817
  var import_child_process31 = require("child_process");
39411
39818
  var import_util6 = require("util");
39412
- var path78 = __toESM(require("path"));
39819
+ var path81 = __toESM(require("path"));
39413
39820
  var execFileP8 = (0, import_util6.promisify)(import_child_process31.execFile);
39414
39821
  var MAX_BUFFER3 = 8 * 1024 * 1024;
39415
39822
  var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
@@ -39669,7 +40076,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
39669
40076
  }
39670
40077
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
39671
40078
  const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
39672
- const remoteDir = path78.posix.dirname(remotePath);
40079
+ const remoteDir = path81.posix.dirname(remotePath);
39673
40080
  const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
39674
40081
  if (options.mode != null) {
39675
40082
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
@@ -39737,7 +40144,7 @@ function shellQuote3(s) {
39737
40144
  // src/services/providers/railway.ts
39738
40145
  var import_child_process32 = require("child_process");
39739
40146
  var import_util7 = require("util");
39740
- var path79 = __toESM(require("path"));
40147
+ var path82 = __toESM(require("path"));
39741
40148
  var execFileP9 = (0, import_util7.promisify)(import_child_process32.execFile);
39742
40149
  var MAX_BUFFER4 = 8 * 1024 * 1024;
39743
40150
  function resetStdinForChild4() {
@@ -39973,7 +40380,7 @@ var RailwayProvider = class {
39973
40380
  if (!projectId || !serviceId) {
39974
40381
  throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
39975
40382
  }
39976
- const remoteDir = path79.posix.dirname(remotePath);
40383
+ const remoteDir = path82.posix.dirname(remotePath);
39977
40384
  const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
39978
40385
  if (options.mode != null) {
39979
40386
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
@@ -40619,8 +41026,8 @@ async function invite() {
40619
41026
  var import_node_dns = require("dns");
40620
41027
  var import_node_util5 = require("util");
40621
41028
  var import_node_crypto13 = require("crypto");
40622
- var fs71 = __toESM(require("fs"));
40623
- var path80 = __toESM(require("path"));
41029
+ var fs74 = __toESM(require("fs"));
41030
+ var path83 = __toESM(require("path"));
40624
41031
  var import_picocolors14 = __toESM(require("picocolors"));
40625
41032
  var dnsResolveP = (0, import_node_util5.promisify)(import_node_dns.resolve);
40626
41033
  async function checkDns(apiBase2) {
@@ -40676,13 +41083,13 @@ async function checkHealth(apiBase2) {
40676
41083
  }
40677
41084
  }
40678
41085
  function checkConfigDir() {
40679
- const dir = path80.join(require("os").homedir(), ".codeam");
41086
+ const dir = path83.join(require("os").homedir(), ".codeam");
40680
41087
  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);
41088
+ fs74.mkdirSync(dir, { recursive: true, mode: 448 });
41089
+ const probe = path83.join(dir, ".doctor-probe");
41090
+ fs74.writeFileSync(probe, "ok", { mode: 384 });
41091
+ const read2 = fs74.readFileSync(probe, "utf8");
41092
+ fs74.unlinkSync(probe);
40686
41093
  if (read2 !== "ok") throw new Error("write/read round-trip mismatch");
40687
41094
  return {
40688
41095
  id: "config-dir",
@@ -40722,9 +41129,9 @@ function checkSessions() {
40722
41129
  }
40723
41130
  }
40724
41131
  function checkAgentBinaries() {
40725
- const os60 = createOsStrategy();
41132
+ const os61 = createOsStrategy();
40726
41133
  return getEnabledAgents().map((meta) => {
40727
- const found = os60.findInPath(meta.binaryName);
41134
+ const found = os61.findInPath(meta.binaryName);
40728
41135
  return {
40729
41136
  id: `agent-${meta.id}`,
40730
41137
  label: `Agent binary: ${meta.displayName} (${meta.binaryName})`,
@@ -40746,7 +41153,7 @@ function checkNodePty() {
40746
41153
  detail: "not required on this platform"
40747
41154
  };
40748
41155
  }
40749
- const vendoredPath = path80.join(__dirname, "vendor", "node-pty");
41156
+ const vendoredPath = path83.join(__dirname, "vendor", "node-pty");
40750
41157
  for (const target of [vendoredPath, "node-pty"]) {
40751
41158
  try {
40752
41159
  require(target);
@@ -40788,7 +41195,7 @@ function checkChokidar() {
40788
41195
  }
40789
41196
  async function doctor(args2 = []) {
40790
41197
  const json = args2.includes("--json");
40791
- const cliVersion = true ? "2.61.81" : "0.0.0-dev";
41198
+ const cliVersion = true ? "2.61.83" : "0.0.0-dev";
40792
41199
  const apiBase2 = resolveApiBaseUrl();
40793
41200
  const diagnosticId = (0, import_node_crypto13.randomUUID)();
40794
41201
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -41378,7 +41785,7 @@ async function mcpRun(args2) {
41378
41785
  // src/commands/version.ts
41379
41786
  var import_picocolors15 = __toESM(require("picocolors"));
41380
41787
  function version2() {
41381
- const v = true ? "2.61.81" : "unknown";
41788
+ const v = true ? "2.61.83" : "unknown";
41382
41789
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
41383
41790
  }
41384
41791
 
@@ -41527,10 +41934,10 @@ var EXIT_CODE_NAMES = {
41527
41934
  };
41528
41935
 
41529
41936
  // src/index.ts
41530
- var os59 = __toESM(require("os"));
41937
+ var os60 = __toESM(require("os"));
41531
41938
  if (!process.env.HOME) {
41532
41939
  try {
41533
- const home = os59.homedir();
41940
+ const home = os60.homedir();
41534
41941
  if (home) process.env.HOME = home;
41535
41942
  } catch {
41536
41943
  }