codeam-cli 2.27.2 → 2.27.4

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 +7 -0
  2. package/dist/index.js +377 -212
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -306,12 +306,12 @@ var AGENT_REGISTRY = {
306
306
  displayName: "Gemini CLI",
307
307
  binaryName: "gemini",
308
308
  enabled: true,
309
- // Gemini speaks ACP natively via `gemini --acp` pairing flows
310
- // through the ACP runtime, not a PTY parser. Auth is the user's
311
- // existing `gemini auth login` (OAuth) or GEMINI_API_KEY env var,
312
- // both managed by the gemini binary itself.
313
- supportedAuthKinds: ["api_key"],
314
- preferredAuthKind: "api_key"
309
+ // OAuth via `gemini auth login` (captured by `codeam link gemini`
310
+ // from ~/.gemini/oauth_creds.json) AND GEMINI_API_KEY are both
311
+ // accepted by the backend's GeminiProvisioningStrategy and propagated
312
+ // into codespace deploys.
313
+ supportedAuthKinds: ["oauth_token", "api_key"],
314
+ preferredAuthKind: "oauth_token"
315
315
  }
316
316
  };
317
317
  function getEnabledAgents() {
@@ -498,7 +498,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
498
498
  // package.json
499
499
  var package_default = {
500
500
  name: "codeam-cli",
501
- version: "2.27.2",
501
+ version: "2.27.4",
502
502
  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.",
503
503
  type: "commonjs",
504
504
  main: "dist/index.js",
@@ -1160,8 +1160,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
1160
1160
  return decodedFile;
1161
1161
  };
1162
1162
  }
1163
- function normalizeWindowsPath(path44) {
1164
- return path44.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
1163
+ function normalizeWindowsPath(path45) {
1164
+ return path45.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
1165
1165
  }
1166
1166
 
1167
1167
  // ../../node_modules/@posthog/core/dist/featureFlagUtils.mjs
@@ -3641,9 +3641,9 @@ async function addSourceContext(frames) {
3641
3641
  LRU_FILE_CONTENTS_CACHE.reduce();
3642
3642
  return frames;
3643
3643
  }
3644
- function getContextLinesFromFile(path44, ranges, output) {
3644
+ function getContextLinesFromFile(path45, ranges, output) {
3645
3645
  return new Promise((resolve6) => {
3646
- const stream = (0, import_node_fs.createReadStream)(path44);
3646
+ const stream = (0, import_node_fs.createReadStream)(path45);
3647
3647
  const lineReaded = (0, import_node_readline.createInterface)({
3648
3648
  input: stream
3649
3649
  });
@@ -3658,7 +3658,7 @@ function getContextLinesFromFile(path44, ranges, output) {
3658
3658
  let rangeStart = range[0];
3659
3659
  let rangeEnd = range[1];
3660
3660
  function onStreamError() {
3661
- LRU_FILE_CONTENTS_FS_READ_FAILED.set(path44, 1);
3661
+ LRU_FILE_CONTENTS_FS_READ_FAILED.set(path45, 1);
3662
3662
  lineReaded.close();
3663
3663
  lineReaded.removeAllListeners();
3664
3664
  destroyStreamAndResolve();
@@ -3719,8 +3719,8 @@ function clearLineContext(frame) {
3719
3719
  delete frame.context_line;
3720
3720
  delete frame.post_context;
3721
3721
  }
3722
- function shouldSkipContextLinesForFile(path44) {
3723
- return path44.startsWith("node:") || path44.endsWith(".min.js") || path44.endsWith(".min.cjs") || path44.endsWith(".min.mjs") || path44.startsWith("data:");
3722
+ function shouldSkipContextLinesForFile(path45) {
3723
+ return path45.startsWith("node:") || path45.endsWith(".min.js") || path45.endsWith(".min.cjs") || path45.endsWith(".min.mjs") || path45.startsWith("data:");
3724
3724
  }
3725
3725
  function shouldSkipContextLinesForFrame(frame) {
3726
3726
  if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
@@ -5874,7 +5874,7 @@ function readAnonId() {
5874
5874
  }
5875
5875
  function superProperties() {
5876
5876
  return {
5877
- cliVersion: true ? "2.27.2" : "0.0.0-dev",
5877
+ cliVersion: true ? "2.27.4" : "0.0.0-dev",
5878
5878
  nodeVersion: process.version,
5879
5879
  platform: process.platform,
5880
5880
  arch: process.arch,
@@ -7216,10 +7216,10 @@ function buildForPlatform(platform2) {
7216
7216
  var import_node_crypto4 = require("crypto");
7217
7217
 
7218
7218
  // src/agents/claude/resolver.ts
7219
- function buildClaudeLaunch(extraArgs = [], os27 = createOsStrategy()) {
7220
- const found = os27.findInPath("claude") ?? os27.findInPath("claude-code");
7219
+ function buildClaudeLaunch(extraArgs = [], os28 = createOsStrategy()) {
7220
+ const found = os28.findInPath("claude") ?? os28.findInPath("claude-code");
7221
7221
  if (!found) return null;
7222
- return os27.buildLaunch(found, extraArgs);
7222
+ return os28.buildLaunch(found, extraArgs);
7223
7223
  }
7224
7224
 
7225
7225
  // src/agents/claude/installer.ts
@@ -9946,13 +9946,13 @@ function detectStartupBanner(lines) {
9946
9946
  while (artStart > 0 && BANNER_ART_RE.test(lines[artStart - 1])) artStart--;
9947
9947
  if (metaIdx - artStart < 2) return null;
9948
9948
  const pathLine = (lines[metaIdx + 1] ?? "").trim();
9949
- const path44 = pathLine && !BANNER_ART_RE.test(pathLine) ? pathLine : "";
9949
+ const path45 = pathLine && !BANNER_ART_RE.test(pathLine) ? pathLine : "";
9950
9950
  return {
9951
9951
  title: "",
9952
9952
  subtitle: lines[metaIdx].trim(),
9953
- path: path44,
9953
+ path: path45,
9954
9954
  startIdx: artStart,
9955
- endIdx: metaIdx + (path44 ? 1 : 0)
9955
+ endIdx: metaIdx + (path45 ? 1 : 0)
9956
9956
  };
9957
9957
  }
9958
9958
 
@@ -9962,8 +9962,8 @@ var ClaudeRuntimeStrategy = class {
9962
9962
  meta = getAgent("claude");
9963
9963
  mode = "interactive";
9964
9964
  os;
9965
- constructor(os27) {
9966
- this.os = os27;
9965
+ constructor(os28) {
9966
+ this.os = os28;
9967
9967
  }
9968
9968
  /**
9969
9969
  * Claude Code's react-ink TUI enables bracketed-paste mode at
@@ -10971,8 +10971,8 @@ function codexCredentialLocator() {
10971
10971
  function codexLoginLauncher() {
10972
10972
  return {
10973
10973
  async ensureInstalled() {
10974
- const os27 = createOsStrategy();
10975
- return os27.findInPath("codex") !== null;
10974
+ const os28 = createOsStrategy();
10975
+ return os28.findInPath("codex") !== null;
10976
10976
  },
10977
10977
  launch() {
10978
10978
  return (0, import_node_child_process3.spawn)("codex", ["login"], { stdio: "inherit" });
@@ -10995,8 +10995,8 @@ var CodexRuntimeStrategy = class {
10995
10995
  meta = getAgent("codex");
10996
10996
  mode = "interactive";
10997
10997
  os;
10998
- constructor(os27) {
10999
- this.os = os27;
10998
+ constructor(os28) {
10999
+ this.os = os28;
11000
11000
  }
11001
11001
  async prepareLaunch() {
11002
11002
  let binary = this.os.findInPath("codex");
@@ -11102,12 +11102,12 @@ var CodexRuntimeStrategy = class {
11102
11102
  });
11103
11103
  }
11104
11104
  };
11105
- function resolveNpm(os27) {
11106
- return os27.id === "win32" ? "npm.cmd" : "npm";
11105
+ function resolveNpm(os28) {
11106
+ return os28.id === "win32" ? "npm.cmd" : "npm";
11107
11107
  }
11108
- async function installCodexViaNpm(os27) {
11108
+ async function installCodexViaNpm(os28) {
11109
11109
  return new Promise((resolve6, reject) => {
11110
- const proc = (0, import_node_child_process4.spawn)(resolveNpm(os27), ["install", "-g", "@openai/codex"], {
11110
+ const proc = (0, import_node_child_process4.spawn)(resolveNpm(os28), ["install", "-g", "@openai/codex"], {
11111
11111
  stdio: "inherit"
11112
11112
  });
11113
11113
  proc.on("close", (code) => {
@@ -11124,16 +11124,16 @@ async function installCodexViaNpm(os27) {
11124
11124
  });
11125
11125
  });
11126
11126
  }
11127
- function augmentNpmGlobalBin(os27) {
11127
+ function augmentNpmGlobalBin(os28) {
11128
11128
  try {
11129
- const result = (0, import_node_child_process4.spawnSync)(resolveNpm(os27), ["prefix", "-g"], {
11129
+ const result = (0, import_node_child_process4.spawnSync)(resolveNpm(os28), ["prefix", "-g"], {
11130
11130
  stdio: ["ignore", "pipe", "ignore"]
11131
11131
  });
11132
11132
  if (result.status !== 0) return;
11133
11133
  const prefix = result.stdout.toString().trim();
11134
11134
  if (!prefix) return;
11135
- const binDir = os27.id === "win32" ? prefix : path17.join(prefix, "bin");
11136
- os27.augmentPath([binDir]);
11135
+ const binDir = os28.id === "win32" ? prefix : path17.join(prefix, "bin");
11136
+ os28.augmentPath([binDir]);
11137
11137
  } catch {
11138
11138
  }
11139
11139
  }
@@ -11217,9 +11217,9 @@ var import_node_child_process7 = require("child_process");
11217
11217
  // src/agents/coderabbit/installer.ts
11218
11218
  var import_node_child_process5 = require("child_process");
11219
11219
  var INSTALL_URL = "https://cli.coderabbit.ai/install.sh";
11220
- async function ensureCoderabbitInstalled(os27) {
11221
- if (os27.findInPath("coderabbit")) return true;
11222
- if (os27.id === "win32") {
11220
+ async function ensureCoderabbitInstalled(os28) {
11221
+ if (os28.findInPath("coderabbit")) return true;
11222
+ if (os28.id === "win32") {
11223
11223
  console.error(
11224
11224
  "\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"
11225
11225
  );
@@ -11234,8 +11234,8 @@ async function ensureCoderabbitInstalled(os27) {
11234
11234
  proc.on("error", () => resolve6(false));
11235
11235
  });
11236
11236
  if (!ok) return false;
11237
- os27.augmentPath([`${os27.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
11238
- return os27.findInPath("coderabbit") !== null;
11237
+ os28.augmentPath([`${os28.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
11238
+ return os28.findInPath("coderabbit") !== null;
11239
11239
  }
11240
11240
 
11241
11241
  // src/agents/coderabbit/link.ts
@@ -11262,10 +11262,10 @@ function coderabbitCredentialLocator() {
11262
11262
  extract: extractLocalCoderabbitToken
11263
11263
  };
11264
11264
  }
11265
- function coderabbitLoginLauncher(os27) {
11265
+ function coderabbitLoginLauncher(os28) {
11266
11266
  return {
11267
11267
  async ensureInstalled() {
11268
- return ensureCoderabbitInstalled(os27);
11268
+ return ensureCoderabbitInstalled(os28);
11269
11269
  },
11270
11270
  launch() {
11271
11271
  return (0, import_node_child_process6.spawn)("coderabbit", ["login"], { stdio: "inherit" });
@@ -11288,11 +11288,11 @@ function parseReview(stdout) {
11288
11288
  for (const line of lines) {
11289
11289
  const m = line.match(HUNK_LINE_RE);
11290
11290
  if (!m) continue;
11291
- const [, path44, lineNo, sevToken, message] = m;
11292
- if (!path44 || !lineNo || !message) continue;
11291
+ const [, path45, lineNo, sevToken, message] = m;
11292
+ if (!path45 || !lineNo || !message) continue;
11293
11293
  const cleanedMessage = message.trim().replace(/^[*-]\s+/, "");
11294
11294
  hunks.push({
11295
- path: path44.trim(),
11295
+ path: path45.trim(),
11296
11296
  line: Number(lineNo),
11297
11297
  severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
11298
11298
  message: cleanedMessage
@@ -11311,8 +11311,8 @@ var CoderabbitRuntimeStrategy = class {
11311
11311
  meta = getAgent("coderabbit");
11312
11312
  mode = "batch";
11313
11313
  os;
11314
- constructor(os27) {
11315
- this.os = os27;
11314
+ constructor(os28) {
11315
+ this.os = os28;
11316
11316
  }
11317
11317
  getDefaultArgs() {
11318
11318
  return ["review"];
@@ -11427,10 +11427,10 @@ function cursorCredentialLocator() {
11427
11427
  extract: extractLocalCursorToken
11428
11428
  };
11429
11429
  }
11430
- function cursorLoginLauncher(os27) {
11430
+ function cursorLoginLauncher(os28) {
11431
11431
  return {
11432
11432
  async ensureInstalled() {
11433
- if (os27.findInPath("cursor-agent")) return true;
11433
+ if (os28.findInPath("cursor-agent")) return true;
11434
11434
  console.error(
11435
11435
  "\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"
11436
11436
  );
@@ -11492,8 +11492,8 @@ var CursorRuntimeStrategy = class {
11492
11492
  meta = getAgent("cursor");
11493
11493
  mode = "interactive";
11494
11494
  os;
11495
- constructor(os27) {
11496
- this.os = os27;
11495
+ constructor(os28) {
11496
+ this.os = os28;
11497
11497
  }
11498
11498
  async prepareLaunch() {
11499
11499
  const binary = this.os.findInPath("cursor-agent");
@@ -11613,10 +11613,10 @@ function aiderCredentialLocator() {
11613
11613
  extract: extractLocalAiderToken
11614
11614
  };
11615
11615
  }
11616
- function aiderLoginLauncher(os27) {
11616
+ function aiderLoginLauncher(os28) {
11617
11617
  return {
11618
11618
  async ensureInstalled() {
11619
- if (os27.findInPath("aider")) return true;
11619
+ if (os28.findInPath("aider")) return true;
11620
11620
  console.error(
11621
11621
  "\n \u2717 aider binary not on PATH.\n Install Aider:\n pip install aider-chat\n then re-run `codeam link aider`.\n"
11622
11622
  );
@@ -11626,7 +11626,7 @@ function aiderLoginLauncher(os27) {
11626
11626
  console.error(
11627
11627
  "\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"
11628
11628
  );
11629
- return (0, import_node_child_process9.spawn)(os27.id === "win32" ? "cmd.exe" : "sh", os27.id === "win32" ? ["/c", "exit", "0"] : ["-c", "exit 0"], {
11629
+ return (0, import_node_child_process9.spawn)(os28.id === "win32" ? "cmd.exe" : "sh", os28.id === "win32" ? ["/c", "exit", "0"] : ["-c", "exit 0"], {
11630
11630
  stdio: "ignore"
11631
11631
  });
11632
11632
  }
@@ -11698,8 +11698,8 @@ var AiderRuntimeStrategy = class {
11698
11698
  meta = getAgent("aider");
11699
11699
  mode = "interactive";
11700
11700
  os;
11701
- constructor(os27) {
11702
- this.os = os27;
11701
+ constructor(os28) {
11702
+ this.os = os28;
11703
11703
  }
11704
11704
  async prepareLaunch() {
11705
11705
  const binary = this.os.findInPath("aider");
@@ -11766,19 +11766,184 @@ var AiderRuntimeStrategy = class {
11766
11766
  }
11767
11767
  };
11768
11768
 
11769
+ // src/agents/gemini/link.ts
11770
+ var import_node_child_process10 = require("child_process");
11771
+
11772
+ // src/agents/gemini/local-token.ts
11773
+ var fs20 = __toESM(require("fs"));
11774
+ var os21 = __toESM(require("os"));
11775
+ var path24 = __toESM(require("path"));
11776
+ function geminiCredentialsPath() {
11777
+ return path24.join(os21.homedir(), ".gemini", "oauth_creds.json");
11778
+ }
11779
+ function geminiCredentialsPaths() {
11780
+ return [geminiCredentialsPath()];
11781
+ }
11782
+ async function extractLocalGeminiToken() {
11783
+ const file = geminiCredentialsPath();
11784
+ if (!fs20.existsSync(file)) return null;
11785
+ const credential = fs20.readFileSync(file, "utf8").trim();
11786
+ if (credential.length === 0) return null;
11787
+ return { method: "oauth", credential, source: "flat-file" };
11788
+ }
11789
+ function validateLocalGeminiToken(credential) {
11790
+ let parsed;
11791
+ try {
11792
+ parsed = JSON.parse(credential);
11793
+ } catch {
11794
+ return { status: "unknown" };
11795
+ }
11796
+ if (typeof parsed.expiry_date !== "number") return { status: "unknown" };
11797
+ const expiresAt = parsed.expiry_date;
11798
+ if (Date.now() >= expiresAt) {
11799
+ return {
11800
+ status: "expired",
11801
+ reason: "Gemini OAuth access token expired",
11802
+ expiresAt
11803
+ };
11804
+ }
11805
+ return { status: "valid", expiresAt };
11806
+ }
11807
+
11808
+ // src/agents/gemini/link.ts
11809
+ function geminiCredentialLocator() {
11810
+ return {
11811
+ publicId: "gemini",
11812
+ vendor: "Google",
11813
+ hint: "~/.gemini/oauth_creds.json",
11814
+ watchPaths: geminiCredentialsPaths,
11815
+ extract: extractLocalGeminiToken,
11816
+ validate: (token) => {
11817
+ const result = validateLocalGeminiToken(token.credential);
11818
+ return { status: result.status, reason: result.reason };
11819
+ }
11820
+ };
11821
+ }
11822
+ function geminiLoginLauncher() {
11823
+ return {
11824
+ async ensureInstalled() {
11825
+ const os28 = createOsStrategy();
11826
+ return os28.findInPath("gemini") !== null;
11827
+ },
11828
+ launch() {
11829
+ return (0, import_node_child_process10.spawn)("gemini", ["auth", "login"], { stdio: "inherit" });
11830
+ }
11831
+ };
11832
+ }
11833
+
11834
+ // src/agents/gemini/runtime.ts
11835
+ var GEMINI_PRO_CONTEXT_WINDOW = 1e6;
11836
+ var GEMINI_FLASH_CONTEXT_WINDOW = 1e6;
11837
+ var GEMINI_MODELS = [
11838
+ {
11839
+ id: "gemini-2.5-pro",
11840
+ label: "Gemini 2.5 Pro",
11841
+ contextWindow: GEMINI_PRO_CONTEXT_WINDOW
11842
+ },
11843
+ {
11844
+ id: "gemini-2.5-flash",
11845
+ label: "Gemini 2.5 Flash",
11846
+ contextWindow: GEMINI_FLASH_CONTEXT_WINDOW
11847
+ },
11848
+ {
11849
+ id: "gemini-2.5-flash-lite",
11850
+ label: "Gemini 2.5 Flash-Lite",
11851
+ contextWindow: GEMINI_FLASH_CONTEXT_WINDOW
11852
+ }
11853
+ ];
11854
+ var GeminiRuntimeStrategy = class {
11855
+ id = "gemini";
11856
+ meta = getAgent("gemini");
11857
+ mode = "interactive";
11858
+ os;
11859
+ constructor(os28) {
11860
+ this.os = os28;
11861
+ }
11862
+ async prepareLaunch() {
11863
+ const binary = this.os.findInPath("gemini");
11864
+ if (!binary) {
11865
+ throw new Error(
11866
+ "Gemini CLI is not on PATH. Install it with:\n npm install -g @google/gemini-cli\n Then run `codeam pair` again.\n\n Tip: set CODEAM_ACP_ENABLED=1 before pairing to use the\n ACP runtime \u2014 it gives mobile typed messages instead of\n raw PTY output for Gemini."
11867
+ );
11868
+ }
11869
+ return this.os.buildLaunch(binary);
11870
+ }
11871
+ // Gemini's REPL has no documented "resume previous session" flag,
11872
+ // so a relaunch starts fresh. Returning an empty array is the
11873
+ // documented "no-op resume" path (Cursor / Aider do the same).
11874
+ resumeLaunchArgs(_sessionId, _opts) {
11875
+ return [];
11876
+ }
11877
+ resolveHistoryDir(_cwd) {
11878
+ return null;
11879
+ }
11880
+ parseHistoryFile(_filePath) {
11881
+ return [];
11882
+ }
11883
+ getCurrentUsage(_historyDir) {
11884
+ return null;
11885
+ }
11886
+ async fetchWeeklyUsage() {
11887
+ return null;
11888
+ }
11889
+ async listModels() {
11890
+ return GEMINI_MODELS;
11891
+ }
11892
+ /**
11893
+ * Gemini's `/model <id>` swaps the active model inside the REPL —
11894
+ * same shape as Claude / Codex / Cursor.
11895
+ */
11896
+ changeModelInstruction(modelId) {
11897
+ return { type: "pty", ptyInput: `/model ${modelId}\r` };
11898
+ }
11899
+ /**
11900
+ * `/compress` is Gemini's context-compression slash command (the
11901
+ * closest analogue to Claude's `/compact`). No auto-mode equivalent.
11902
+ */
11903
+ summarizeInstruction(_mode) {
11904
+ return { ptyInput: "/compress\r" };
11905
+ }
11906
+ /**
11907
+ * Pass-through filter. Gemini's TUI chrome isn't worth
11908
+ * hand-detecting — users who want clean output should use ACP
11909
+ * (`CODEAM_ACP_ENABLED=1`) instead. Returning the input verbatim
11910
+ * satisfies the contract's idempotency assertion and keeps mobile
11911
+ * showing whatever the REPL prints.
11912
+ */
11913
+ filterTuiOutput(lines) {
11914
+ return lines;
11915
+ }
11916
+ /**
11917
+ * No interactive-selector detection — Gemini's REPL uses input
11918
+ * lines, not arrow-key menus we'd need to detect. ACP surfaces
11919
+ * permission requests as typed messages, which is the path we want
11920
+ * users on anyway.
11921
+ */
11922
+ detectInteractivePrompt(_lines) {
11923
+ return null;
11924
+ }
11925
+ credentialLocator() {
11926
+ return geminiCredentialLocator();
11927
+ }
11928
+ loginLauncher() {
11929
+ return geminiLoginLauncher();
11930
+ }
11931
+ };
11932
+
11769
11933
  // src/agents/registry.ts
11770
11934
  var runtimeBuilders = {
11771
- claude: (os27) => new ClaudeRuntimeStrategy(os27),
11772
- codex: (os27) => new CodexRuntimeStrategy(os27),
11773
- coderabbit: (os27) => new CoderabbitRuntimeStrategy(os27),
11774
- cursor: (os27) => new CursorRuntimeStrategy(os27),
11775
- aider: (os27) => new AiderRuntimeStrategy(os27)
11935
+ claude: (os28) => new ClaudeRuntimeStrategy(os28),
11936
+ codex: (os28) => new CodexRuntimeStrategy(os28),
11937
+ coderabbit: (os28) => new CoderabbitRuntimeStrategy(os28),
11938
+ cursor: (os28) => new CursorRuntimeStrategy(os28),
11939
+ aider: (os28) => new AiderRuntimeStrategy(os28),
11940
+ gemini: (os28) => new GeminiRuntimeStrategy(os28)
11776
11941
  };
11777
11942
  var deployBuilders = {
11778
11943
  claude: () => new ClaudeDeployStrategy(),
11779
11944
  codex: () => new CodexDeployStrategy()
11780
11945
  };
11781
- function createAgentStrategy(agent, os27 = createOsStrategy()) {
11946
+ function createAgentStrategy(agent, os28 = createOsStrategy()) {
11782
11947
  if (!AGENT_REGISTRY[agent]?.enabled) {
11783
11948
  throw new Error(
11784
11949
  `Agent "${agent}" is not supported in this codeam-cli version. Upgrade with 'npm i -g codeam-cli@latest'.`
@@ -11788,10 +11953,10 @@ function createAgentStrategy(agent, os27 = createOsStrategy()) {
11788
11953
  if (!build) {
11789
11954
  throw new Error(`No runtime strategy registered for agent "${agent}"`);
11790
11955
  }
11791
- return build(os27);
11956
+ return build(os28);
11792
11957
  }
11793
- function createInteractiveAgentStrategy(agent, os27 = createOsStrategy()) {
11794
- const s = createAgentStrategy(agent, os27);
11958
+ function createInteractiveAgentStrategy(agent, os28 = createOsStrategy()) {
11959
+ const s = createAgentStrategy(agent, os28);
11795
11960
  if (s.mode !== "interactive") {
11796
11961
  throw new Error(
11797
11962
  `Agent "${agent}" is a batch agent; use createAgentStrategy + .runOneShot for one-shot reviews.`
@@ -11812,19 +11977,19 @@ function createDeployStrategy(agent) {
11812
11977
  }
11813
11978
 
11814
11979
  // src/agents/acp/adapters.ts
11815
- var path24 = __toESM(require("path"));
11980
+ var path25 = __toESM(require("path"));
11816
11981
  var require_ = require;
11817
11982
  function resolveBin(pkgName, binName) {
11818
11983
  try {
11819
11984
  const manifestPath = require_.resolve(`${pkgName}/package.json`);
11820
11985
  const manifest = require_(`${pkgName}/package.json`);
11821
- const pkgDir = path24.dirname(manifestPath);
11986
+ const pkgDir = path25.dirname(manifestPath);
11822
11987
  const bin = manifest.bin;
11823
11988
  if (!bin) return null;
11824
- if (typeof bin === "string") return path24.resolve(pkgDir, bin);
11989
+ if (typeof bin === "string") return path25.resolve(pkgDir, bin);
11825
11990
  const target = binName ?? Object.keys(bin)[0];
11826
11991
  if (!target || !bin[target]) return null;
11827
- return path24.resolve(pkgDir, bin[target]);
11992
+ return path25.resolve(pkgDir, bin[target]);
11828
11993
  } catch {
11829
11994
  return null;
11830
11995
  }
@@ -11876,8 +12041,8 @@ function getAcpAdapter(agent) {
11876
12041
  var import_node_crypto6 = require("crypto");
11877
12042
 
11878
12043
  // src/agents/acp/client.ts
11879
- var import_node_child_process10 = require("child_process");
11880
- var fs20 = __toESM(require("fs/promises"));
12044
+ var import_node_child_process11 = require("child_process");
12045
+ var fs21 = __toESM(require("fs/promises"));
11881
12046
  var import_node_stream = require("stream");
11882
12047
  var import_sdk = require("@agentclientprotocol/sdk");
11883
12048
  var PROTOCOL_VERSION2 = 1;
@@ -11902,7 +12067,7 @@ var AcpClient = class {
11902
12067
  async start() {
11903
12068
  if (this.child) throw new Error("AcpClient already started");
11904
12069
  const { adapter, cwd } = this.opts;
11905
- const child = (0, import_node_child_process10.spawn)(adapter.command, adapter.args, {
12070
+ const child = (0, import_node_child_process11.spawn)(adapter.command, adapter.args, {
11906
12071
  cwd,
11907
12072
  env: process.env,
11908
12073
  stdio: ["pipe", "pipe", "pipe"]
@@ -12006,11 +12171,11 @@ var AcpClient = class {
12006
12171
  return this.opts.onRequestPermission(params);
12007
12172
  },
12008
12173
  readTextFile: async (params) => {
12009
- const content = await fs20.readFile(params.path, "utf8");
12174
+ const content = await fs21.readFile(params.path, "utf8");
12010
12175
  return applyLineRange(content, params.line ?? null, params.limit ?? null);
12011
12176
  },
12012
12177
  writeTextFile: async (params) => {
12013
- await fs20.writeFile(params.path, params.content, "utf8");
12178
+ await fs21.writeFile(params.path, params.content, "utf8");
12014
12179
  return {};
12015
12180
  },
12016
12181
  // Terminal capability is declared `false` above so adapters
@@ -13255,9 +13420,9 @@ var OutputService = class _OutputService {
13255
13420
  };
13256
13421
 
13257
13422
  // src/services/history.service.ts
13258
- var fs21 = __toESM(require("fs"));
13259
- var path25 = __toESM(require("path"));
13260
- var os21 = __toESM(require("os"));
13423
+ var fs22 = __toESM(require("fs"));
13424
+ var path26 = __toESM(require("path"));
13425
+ var os22 = __toESM(require("os"));
13261
13426
  var https5 = __toESM(require("https"));
13262
13427
  var http5 = __toESM(require("http"));
13263
13428
  var import_zod = require("zod");
@@ -13284,7 +13449,7 @@ function parseJsonl(filePath) {
13284
13449
  const messages = [];
13285
13450
  let raw;
13286
13451
  try {
13287
- raw = fs21.readFileSync(filePath, "utf8");
13452
+ raw = fs22.readFileSync(filePath, "utf8");
13288
13453
  } catch (err) {
13289
13454
  if (err.code !== "ENOENT") {
13290
13455
  log.warn("history:parseJsonl", `read failed for ${filePath}`, err);
@@ -13419,7 +13584,7 @@ var HistoryService = class _HistoryService {
13419
13584
  return this._quotaPercent === null || Date.now() - this._quotaFetchedAt > ttlMs;
13420
13585
  }
13421
13586
  get projectDir() {
13422
- return this.runtime.resolveHistoryDir(this.cwd) ?? path25.join(os21.homedir(), ".claude", "projects", encodeCwd(this.cwd));
13587
+ return this.runtime.resolveHistoryDir(this.cwd) ?? path26.join(os22.homedir(), ".claude", "projects", encodeCwd(this.cwd));
13423
13588
  }
13424
13589
  /** Set the current Claude conversation ID (extracted from /cost command or session start) */
13425
13590
  setCurrentConversationId(id) {
@@ -13431,7 +13596,7 @@ var HistoryService = class _HistoryService {
13431
13596
  /** Return the current message count in the active conversation. */
13432
13597
  getCurrentMessageCount() {
13433
13598
  if (!this.currentConversationId) return 0;
13434
- const filePath = path25.join(this.projectDir, `${this.currentConversationId}.jsonl`);
13599
+ const filePath = path26.join(this.projectDir, `${this.currentConversationId}.jsonl`);
13435
13600
  return parseJsonl(filePath).length;
13436
13601
  }
13437
13602
  /**
@@ -13442,7 +13607,7 @@ var HistoryService = class _HistoryService {
13442
13607
  const deadline = Date.now() + timeoutMs;
13443
13608
  while (Date.now() < deadline) {
13444
13609
  if (!this.currentConversationId) return null;
13445
- const filePath = path25.join(this.projectDir, `${this.currentConversationId}.jsonl`);
13610
+ const filePath = path26.join(this.projectDir, `${this.currentConversationId}.jsonl`);
13446
13611
  const messages = parseJsonl(filePath);
13447
13612
  if (messages.length > previousCount) {
13448
13613
  for (let i = messages.length - 1; i >= previousCount; i--) {
@@ -13468,16 +13633,16 @@ var HistoryService = class _HistoryService {
13468
13633
  const dir = this.projectDir;
13469
13634
  const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
13470
13635
  try {
13471
- const files = fs21.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
13636
+ const files = fs22.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
13472
13637
  try {
13473
- const stat3 = fs21.statSync(path25.join(dir, e.name));
13638
+ const stat3 = fs22.statSync(path26.join(dir, e.name));
13474
13639
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
13475
13640
  } catch {
13476
13641
  return { name: e.name, mtime: 0, birthtime: 0 };
13477
13642
  }
13478
13643
  }).filter((f) => f.birthtime >= cutoff).sort((a, b) => b.mtime - a.mtime);
13479
13644
  if (files.length > 0) {
13480
- this.currentConversationId = path25.basename(files[0].name, ".jsonl");
13645
+ this.currentConversationId = path26.basename(files[0].name, ".jsonl");
13481
13646
  }
13482
13647
  } catch {
13483
13648
  }
@@ -13511,13 +13676,13 @@ var HistoryService = class _HistoryService {
13511
13676
  const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
13512
13677
  let entries;
13513
13678
  try {
13514
- entries = fs21.readdirSync(dir, { withFileTypes: true });
13679
+ entries = fs22.readdirSync(dir, { withFileTypes: true });
13515
13680
  } catch {
13516
13681
  return null;
13517
13682
  }
13518
13683
  const files = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
13519
13684
  try {
13520
- const stat3 = fs21.statSync(path25.join(dir, e.name));
13685
+ const stat3 = fs22.statSync(path26.join(dir, e.name));
13521
13686
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
13522
13687
  } catch {
13523
13688
  return { name: e.name, mtime: 0, birthtime: 0 };
@@ -13526,12 +13691,12 @@ var HistoryService = class _HistoryService {
13526
13691
  if (files.length === 0) return null;
13527
13692
  const targetFile = this.currentConversationId ? `${this.currentConversationId}.jsonl` : files[0].name;
13528
13693
  if (!files.some((f) => f.name === targetFile)) return null;
13529
- return this.extractUsageFromFile(path25.join(dir, targetFile));
13694
+ return this.extractUsageFromFile(path26.join(dir, targetFile));
13530
13695
  }
13531
13696
  extractUsageFromFile(filePath) {
13532
13697
  let raw;
13533
13698
  try {
13534
- raw = fs21.readFileSync(filePath, "utf8");
13699
+ raw = fs22.readFileSync(filePath, "utf8");
13535
13700
  } catch {
13536
13701
  return null;
13537
13702
  }
@@ -13576,9 +13741,9 @@ var HistoryService = class _HistoryService {
13576
13741
  let totalCost = 0;
13577
13742
  let files;
13578
13743
  try {
13579
- files = fs21.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
13744
+ files = fs22.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
13580
13745
  try {
13581
- return fs21.statSync(path25.join(projectDir, f)).mtimeMs >= monthStartMs;
13746
+ return fs22.statSync(path26.join(projectDir, f)).mtimeMs >= monthStartMs;
13582
13747
  } catch {
13583
13748
  return false;
13584
13749
  }
@@ -13589,7 +13754,7 @@ var HistoryService = class _HistoryService {
13589
13754
  for (const file of files) {
13590
13755
  let raw;
13591
13756
  try {
13592
- raw = fs21.readFileSync(path25.join(projectDir, file), "utf8");
13757
+ raw = fs22.readFileSync(path26.join(projectDir, file), "utf8");
13593
13758
  } catch {
13594
13759
  continue;
13595
13760
  }
@@ -13653,7 +13818,7 @@ var HistoryService = class _HistoryService {
13653
13818
  * showing an empty conversation.
13654
13819
  */
13655
13820
  async loadConversation(sessionId) {
13656
- const filePath = path25.join(this.projectDir, `${sessionId}.jsonl`);
13821
+ const filePath = path26.join(this.projectDir, `${sessionId}.jsonl`);
13657
13822
  const messages = parseJsonl(filePath);
13658
13823
  if (messages.length === 0) return;
13659
13824
  const totalBatches = Math.ceil(messages.length / CONVERSATION_BATCH_SIZE);
@@ -13707,7 +13872,7 @@ var HistoryService = class _HistoryService {
13707
13872
  if (!this.currentConversationId) return 0;
13708
13873
  }
13709
13874
  const sessionId = this.currentConversationId;
13710
- const filePath = path25.join(this.projectDir, `${sessionId}.jsonl`);
13875
+ const filePath = path26.join(this.projectDir, `${sessionId}.jsonl`);
13711
13876
  const messages = parseJsonl(filePath);
13712
13877
  if (messages.length === 0) return 0;
13713
13878
  const marker = this.lastUploadedUuid.get(sessionId);
@@ -13738,9 +13903,9 @@ var HistoryService = class _HistoryService {
13738
13903
 
13739
13904
  // src/services/file-watcher.service.ts
13740
13905
  var import_child_process8 = require("child_process");
13741
- var fs22 = __toESM(require("fs"));
13742
- var os22 = __toESM(require("os"));
13743
- var path26 = __toESM(require("path"));
13906
+ var fs23 = __toESM(require("fs"));
13907
+ var os23 = __toESM(require("os"));
13908
+ var path27 = __toESM(require("path"));
13744
13909
 
13745
13910
  // src/services/file-watcher/diff-parser.ts
13746
13911
  var HUNK_HEADER_RE = /^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/;
@@ -13898,10 +14063,10 @@ var WINDOWS_LEGACY_JUNCTIONS = [
13898
14063
  /[\\/]Start Menu([\\/]|$)/i,
13899
14064
  /[\\/]Templates([\\/]|$)/i
13900
14065
  ];
13901
- function isUnsafeWindowsWatchRoot(dir, homedir19) {
14066
+ function isUnsafeWindowsWatchRoot(dir, homedir20) {
13902
14067
  const norm = (p2) => p2.replace(/\//g, "\\").replace(/\\+$/, "").toLowerCase();
13903
14068
  const cwd = norm(dir);
13904
- const home = norm(homedir19);
14069
+ const home = norm(homedir20);
13905
14070
  if (cwd === home) return true;
13906
14071
  if (/^[a-z]:$/.test(cwd)) return true;
13907
14072
  const sysRoots = [
@@ -13931,18 +14096,18 @@ var _findGitRootSeam = {
13931
14096
  resolve: _defaultFindGitRoot
13932
14097
  };
13933
14098
  function _defaultFindGitRoot(startDir) {
13934
- let dir = path26.resolve(startDir);
14099
+ let dir = path27.resolve(startDir);
13935
14100
  const seen = /* @__PURE__ */ new Set();
13936
14101
  for (let i = 0; i < 256; i++) {
13937
14102
  if (seen.has(dir)) return null;
13938
14103
  seen.add(dir);
13939
14104
  try {
13940
- const gitPath = path26.join(dir, ".git");
13941
- const stat3 = fs22.statSync(gitPath, { throwIfNoEntry: false });
14105
+ const gitPath = path27.join(dir, ".git");
14106
+ const stat3 = fs23.statSync(gitPath, { throwIfNoEntry: false });
13942
14107
  if (stat3 && (stat3.isDirectory() || stat3.isFile())) return dir;
13943
14108
  } catch {
13944
14109
  }
13945
- const parent = path26.dirname(dir);
14110
+ const parent = path27.dirname(dir);
13946
14111
  if (parent === dir) return null;
13947
14112
  dir = parent;
13948
14113
  }
@@ -13989,7 +14154,7 @@ var FileWatcherService = class {
13989
14154
  throw new Error("FileWatcherService has already been stopped \u2014 re-instantiate to restart.");
13990
14155
  }
13991
14156
  const isWin = process.platform === "win32";
13992
- if (isWin && isUnsafeWindowsWatchRoot(this.opts.workingDir, os22.homedir())) {
14157
+ if (isWin && isUnsafeWindowsWatchRoot(this.opts.workingDir, os23.homedir())) {
13993
14158
  log.warn(
13994
14159
  "fileWatcher",
13995
14160
  `refusing to watch ${this.opts.workingDir} \u2014 looks like a Windows user-profile or system path. Run codeam from your project folder to enable file change emission.`
@@ -14176,7 +14341,7 @@ var FileWatcherService = class {
14176
14341
  }
14177
14342
  async emitForFile(absPath, changeType) {
14178
14343
  if (this.stopped) return;
14179
- const fileDir = path26.dirname(absPath);
14344
+ const fileDir = path27.dirname(absPath);
14180
14345
  let gitRoot = this.gitRootByDir.get(fileDir);
14181
14346
  if (gitRoot === void 0) {
14182
14347
  gitRoot = findGitRoot(fileDir);
@@ -14190,10 +14355,10 @@ var FileWatcherService = class {
14190
14355
  return;
14191
14356
  }
14192
14357
  this.opts.onRepoDirty?.(gitRoot);
14193
- const relPathInRepo = path26.relative(gitRoot, absPath);
14358
+ const relPathInRepo = path27.relative(gitRoot, absPath);
14194
14359
  if (!relPathInRepo || relPathInRepo.startsWith("..")) return;
14195
- const repoPath = path26.relative(this.opts.workingDir, gitRoot);
14196
- const repoName = path26.basename(gitRoot);
14360
+ const repoPath = path27.relative(this.opts.workingDir, gitRoot);
14361
+ const repoName = path27.basename(gitRoot);
14197
14362
  let diffText = "";
14198
14363
  let fileStatus = "modified";
14199
14364
  if (changeType === "unlink") {
@@ -14492,7 +14657,7 @@ var import_crypto2 = require("crypto");
14492
14657
 
14493
14658
  // src/services/turn-files/git-changeset.ts
14494
14659
  var import_child_process9 = require("child_process");
14495
- var path27 = __toESM(require("path"));
14660
+ var path28 = __toESM(require("path"));
14496
14661
  async function collectRepoChangeset(opts) {
14497
14662
  const status2 = await runGit2(opts.repoRoot, ["status", "--porcelain=v1", "-z"]);
14498
14663
  if (status2 === null) return null;
@@ -14603,7 +14768,7 @@ function defaultRunGit(cwd, args2) {
14603
14768
  });
14604
14769
  }
14605
14770
  async function discoverRepos(workingDir, maxDepth = 4) {
14606
- const fs35 = await import("fs/promises");
14771
+ const fs36 = await import("fs/promises");
14607
14772
  const out2 = [];
14608
14773
  await walk(workingDir, 0);
14609
14774
  return out2;
@@ -14611,7 +14776,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
14611
14776
  if (depth > maxDepth) return;
14612
14777
  let entries = [];
14613
14778
  try {
14614
- const dirents = await fs35.readdir(dir, { withFileTypes: true });
14779
+ const dirents = await fs36.readdir(dir, { withFileTypes: true });
14615
14780
  entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
14616
14781
  } catch {
14617
14782
  return;
@@ -14622,8 +14787,8 @@ async function discoverRepos(workingDir, maxDepth = 4) {
14622
14787
  if (hasGit) {
14623
14788
  out2.push({
14624
14789
  repoRoot: dir,
14625
- repoPath: path27.relative(workingDir, dir),
14626
- repoName: path27.basename(dir)
14790
+ repoPath: path28.relative(workingDir, dir),
14791
+ repoName: path28.basename(dir)
14627
14792
  });
14628
14793
  return;
14629
14794
  }
@@ -14631,15 +14796,15 @@ async function discoverRepos(workingDir, maxDepth = 4) {
14631
14796
  if (!entry.isDirectory) continue;
14632
14797
  if (entry.name === "node_modules") continue;
14633
14798
  if (entry.name === "dist" || entry.name === "build") continue;
14634
- await walk(path27.join(dir, entry.name), depth + 1);
14799
+ await walk(path28.join(dir, entry.name), depth + 1);
14635
14800
  }
14636
14801
  }
14637
14802
  }
14638
14803
 
14639
14804
  // src/services/turn-files/files-outbox.ts
14640
- var fs23 = __toESM(require("fs/promises"));
14641
- var path28 = __toESM(require("path"));
14642
- var import_os6 = require("os");
14805
+ var fs24 = __toESM(require("fs/promises"));
14806
+ var path29 = __toESM(require("path"));
14807
+ var import_os7 = require("os");
14643
14808
  var HOME_OUTBOX_DIR = ".codeam/outbox";
14644
14809
  var MAX_AGE_MS = 24 * 60 * 60 * 1e3;
14645
14810
  var BACKOFF_STEPS_MS = [
@@ -14671,16 +14836,16 @@ var FilesOutbox = class {
14671
14836
  backoffIndex = 0;
14672
14837
  stopped = false;
14673
14838
  constructor(opts) {
14674
- const base = opts.baseDir ?? path28.join(homeDir(), HOME_OUTBOX_DIR);
14675
- this.filePath = path28.join(base, `${opts.sessionId}.jsonl`);
14839
+ const base = opts.baseDir ?? path29.join(homeDir(), HOME_OUTBOX_DIR);
14840
+ this.filePath = path29.join(base, `${opts.sessionId}.jsonl`);
14676
14841
  this.post = opts.post;
14677
14842
  this.autoSchedule = opts.autoSchedule !== false;
14678
14843
  }
14679
14844
  /** Persist the entry to disk and trigger a flush. Returns once the
14680
14845
  * line is durable on disk (not once the POST succeeds). */
14681
14846
  async enqueue(entry) {
14682
- await fs23.mkdir(path28.dirname(this.filePath), { recursive: true });
14683
- await fs23.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
14847
+ await fs24.mkdir(path29.dirname(this.filePath), { recursive: true });
14848
+ await fs24.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
14684
14849
  this.backoffIndex = 0;
14685
14850
  if (this.autoSchedule) this.scheduleFlush(0);
14686
14851
  }
@@ -14769,7 +14934,7 @@ var FilesOutbox = class {
14769
14934
  async readAll() {
14770
14935
  let raw = "";
14771
14936
  try {
14772
- raw = await fs23.readFile(this.filePath, "utf8");
14937
+ raw = await fs24.readFile(this.filePath, "utf8");
14773
14938
  } catch {
14774
14939
  return [];
14775
14940
  }
@@ -14793,12 +14958,12 @@ var FilesOutbox = class {
14793
14958
  async rewrite(entries) {
14794
14959
  const tmpPath = `${this.filePath}.${process.pid}.tmp`;
14795
14960
  if (entries.length === 0) {
14796
- await fs23.unlink(this.filePath).catch(() => void 0);
14961
+ await fs24.unlink(this.filePath).catch(() => void 0);
14797
14962
  return;
14798
14963
  }
14799
14964
  const payload = entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
14800
- await fs23.writeFile(tmpPath, payload, "utf8");
14801
- await fs23.rename(tmpPath, this.filePath);
14965
+ await fs24.writeFile(tmpPath, payload, "utf8");
14966
+ await fs24.rename(tmpPath, this.filePath);
14802
14967
  }
14803
14968
  };
14804
14969
  function applyJitter(ms) {
@@ -14806,7 +14971,7 @@ function applyJitter(ms) {
14806
14971
  return Math.round(ms * factor);
14807
14972
  }
14808
14973
  function homeDir() {
14809
- return process.env.HOME ?? process.env.USERPROFILE ?? (0, import_os6.tmpdir)();
14974
+ return process.env.HOME ?? process.env.USERPROFILE ?? (0, import_os7.tmpdir)();
14810
14975
  }
14811
14976
 
14812
14977
  // src/services/turn-files/turn-file-aggregator.ts
@@ -15421,9 +15586,9 @@ function buildKeepAlive(ctx) {
15421
15586
  }
15422
15587
 
15423
15588
  // src/commands/start/handlers.ts
15424
- var fs31 = __toESM(require("fs"));
15425
- var os24 = __toESM(require("os"));
15426
- var path37 = __toESM(require("path"));
15589
+ var fs32 = __toESM(require("fs"));
15590
+ var os25 = __toESM(require("os"));
15591
+ var path38 = __toESM(require("path"));
15427
15592
  var import_crypto5 = require("crypto");
15428
15593
  var import_child_process15 = require("child_process");
15429
15594
 
@@ -15547,8 +15712,8 @@ function parsePayload2(schema, raw) {
15547
15712
  }
15548
15713
 
15549
15714
  // src/services/file-ops.service.ts
15550
- var fs24 = __toESM(require("fs/promises"));
15551
- var path29 = __toESM(require("path"));
15715
+ var fs25 = __toESM(require("fs/promises"));
15716
+ var path30 = __toESM(require("path"));
15552
15717
  var MAX_FILE_BYTES = 5 * 1024 * 1024;
15553
15718
  var MAX_WALK_DEPTH = 6;
15554
15719
  var MAX_VISITED_DIRS = 5e3;
@@ -15583,12 +15748,12 @@ var SUBDIR_IGNORE = /* @__PURE__ */ new Set([
15583
15748
  "__pycache__"
15584
15749
  ]);
15585
15750
  function isUnder(parent, candidate) {
15586
- const rel = path29.relative(parent, candidate);
15587
- return rel === "" || !rel.startsWith("..") && !path29.isAbsolute(rel);
15751
+ const rel = path30.relative(parent, candidate);
15752
+ return rel === "" || !rel.startsWith("..") && !path30.isAbsolute(rel);
15588
15753
  }
15589
15754
  async function isExistingFile(absPath) {
15590
15755
  try {
15591
- const stat3 = await fs24.stat(absPath);
15756
+ const stat3 = await fs25.stat(absPath);
15592
15757
  return stat3.isFile();
15593
15758
  } catch {
15594
15759
  return false;
@@ -15601,13 +15766,13 @@ async function walkForSuffix(dir, needleVariants, depth, ctx) {
15601
15766
  ctx.visited++;
15602
15767
  let entries = [];
15603
15768
  try {
15604
- entries = await fs24.readdir(dir, { withFileTypes: true });
15769
+ entries = await fs25.readdir(dir, { withFileTypes: true });
15605
15770
  } catch {
15606
15771
  return;
15607
15772
  }
15608
15773
  for (const e of entries) {
15609
15774
  if (!e.isFile()) continue;
15610
- const full = path29.join(dir, e.name);
15775
+ const full = path30.join(dir, e.name);
15611
15776
  if (needleVariants.some((needle) => full.endsWith(needle))) {
15612
15777
  ctx.matches.push(full);
15613
15778
  if (ctx.matches.length >= ctx.cap) return;
@@ -15617,21 +15782,21 @@ async function walkForSuffix(dir, needleVariants, depth, ctx) {
15617
15782
  if (!e.isDirectory()) continue;
15618
15783
  if (SUBDIR_IGNORE.has(e.name)) continue;
15619
15784
  if (e.name.startsWith(".") && SUBDIR_IGNORE.has(e.name)) continue;
15620
- await walkForSuffix(path29.join(dir, e.name), needleVariants, depth + 1, ctx);
15785
+ await walkForSuffix(path30.join(dir, e.name), needleVariants, depth + 1, ctx);
15621
15786
  if (ctx.matches.length >= ctx.cap) return;
15622
15787
  }
15623
15788
  }
15624
15789
  async function findFile(rawPath) {
15625
15790
  const cwd = process.cwd();
15626
- if (path29.isAbsolute(rawPath)) {
15627
- const abs = path29.normalize(rawPath);
15791
+ if (path30.isAbsolute(rawPath)) {
15792
+ const abs = path30.normalize(rawPath);
15628
15793
  if (isUnder(cwd, abs) && await isExistingFile(abs)) return abs;
15629
15794
  }
15630
- const direct = path29.resolve(cwd, rawPath);
15795
+ const direct = path30.resolve(cwd, rawPath);
15631
15796
  if (isUnder(cwd, direct) && await isExistingFile(direct)) return direct;
15632
- const normalized = path29.normalize(rawPath).replace(/^[./\\]+/, "");
15797
+ const normalized = path30.normalize(rawPath).replace(/^[./\\]+/, "");
15633
15798
  const needles = [
15634
- `${path29.sep}${normalized}`,
15799
+ `${path30.sep}${normalized}`,
15635
15800
  `/${normalized}`
15636
15801
  ].filter((v, i, a) => a.indexOf(v) === i);
15637
15802
  const ctx = { visited: 0, matches: [], cap: 16 };
@@ -15645,7 +15810,7 @@ async function findWriteTarget(rawPath) {
15645
15810
  const found = await findFile(rawPath);
15646
15811
  if (found) return found;
15647
15812
  const cwd = process.cwd();
15648
- const fallback = path29.isAbsolute(rawPath) ? path29.normalize(rawPath) : path29.resolve(cwd, rawPath);
15813
+ const fallback = path30.isAbsolute(rawPath) ? path30.normalize(rawPath) : path30.resolve(cwd, rawPath);
15649
15814
  if (!isUnder(cwd, fallback)) return null;
15650
15815
  return fallback;
15651
15816
  }
@@ -15662,11 +15827,11 @@ async function readProjectFile(rawPath) {
15662
15827
  if (!abs) {
15663
15828
  return { error: `File not found in the project tree: ${rawPath}` };
15664
15829
  }
15665
- const stat3 = await fs24.stat(abs);
15830
+ const stat3 = await fs25.stat(abs);
15666
15831
  if (stat3.size > MAX_FILE_BYTES) {
15667
15832
  return { error: `File too large (${(stat3.size / 1024 / 1024).toFixed(1)} MB > ${MAX_FILE_BYTES / 1024 / 1024} MB).` };
15668
15833
  }
15669
- const buf = await fs24.readFile(abs);
15834
+ const buf = await fs25.readFile(abs);
15670
15835
  if (looksBinary(buf)) {
15671
15836
  return { error: "Binary file \u2014 refusing to open in a code editor." };
15672
15837
  }
@@ -15685,8 +15850,8 @@ async function writeProjectFile(rawPath, content) {
15685
15850
  if (Buffer.byteLength(content, "utf-8") > MAX_FILE_BYTES) {
15686
15851
  return { error: "Content too large." };
15687
15852
  }
15688
- await fs24.mkdir(path29.dirname(abs), { recursive: true });
15689
- await fs24.writeFile(abs, content, "utf-8");
15853
+ await fs25.mkdir(path30.dirname(abs), { recursive: true });
15854
+ await fs25.writeFile(abs, content, "utf-8");
15690
15855
  return { ok: true };
15691
15856
  } catch (e) {
15692
15857
  const msg = e instanceof Error ? e.message : "Write failed";
@@ -15697,8 +15862,8 @@ async function writeProjectFile(rawPath, content) {
15697
15862
  // src/services/project-ops.service.ts
15698
15863
  var import_child_process11 = require("child_process");
15699
15864
  var import_util2 = require("util");
15700
- var fs25 = __toESM(require("fs/promises"));
15701
- var path30 = __toESM(require("path"));
15865
+ var fs26 = __toESM(require("fs/promises"));
15866
+ var path31 = __toESM(require("path"));
15702
15867
  var execFileP3 = (0, import_util2.promisify)(import_child_process11.execFile);
15703
15868
  var PROJECT_IGNORE = /* @__PURE__ */ new Set([
15704
15869
  "node_modules",
@@ -15746,7 +15911,7 @@ async function listProjectFiles(opts = {}) {
15746
15911
  }
15747
15912
  let entries = [];
15748
15913
  try {
15749
- entries = await fs25.readdir(dir, { withFileTypes: true });
15914
+ entries = await fs26.readdir(dir, { withFileTypes: true });
15750
15915
  } catch {
15751
15916
  return;
15752
15917
  }
@@ -15756,18 +15921,18 @@ async function listProjectFiles(opts = {}) {
15756
15921
  return;
15757
15922
  }
15758
15923
  if (PROJECT_IGNORE.has(e.name)) continue;
15759
- const full = path30.join(dir, e.name);
15924
+ const full = path31.join(dir, e.name);
15760
15925
  if (e.isDirectory()) {
15761
15926
  if (depth >= 12) continue;
15762
15927
  await walk(full, depth + 1);
15763
15928
  } else if (e.isFile()) {
15764
- const rel = path30.relative(root, full);
15929
+ const rel = path31.relative(root, full);
15765
15930
  if (q2 && !rel.toLowerCase().includes(q2) && !e.name.toLowerCase().includes(q2)) {
15766
15931
  continue;
15767
15932
  }
15768
15933
  let size = 0;
15769
15934
  try {
15770
- const st3 = await fs25.stat(full);
15935
+ const st3 = await fs26.stat(full);
15771
15936
  size = st3.size;
15772
15937
  } catch {
15773
15938
  }
@@ -15869,8 +16034,8 @@ async function gitStatus(cwd) {
15869
16034
  let hasMergeInProgress = false;
15870
16035
  try {
15871
16036
  const gitDir = (await git(["rev-parse", "--git-dir"], root)).stdout.trim();
15872
- const mergeHead = path30.isAbsolute(gitDir) ? path30.join(gitDir, "MERGE_HEAD") : path30.join(root, gitDir, "MERGE_HEAD");
15873
- await fs25.access(mergeHead);
16037
+ const mergeHead = path31.isAbsolute(gitDir) ? path31.join(gitDir, "MERGE_HEAD") : path31.join(root, gitDir, "MERGE_HEAD");
16038
+ await fs26.access(mergeHead);
15874
16039
  hasMergeInProgress = true;
15875
16040
  } catch {
15876
16041
  }
@@ -16016,7 +16181,7 @@ async function jsSearchFiles(opts, cwd, cap) {
16016
16181
  }
16017
16182
  let content = "";
16018
16183
  try {
16019
- content = await fs25.readFile(path30.join(cwd, f.path), "utf8");
16184
+ content = await fs26.readFile(path31.join(cwd, f.path), "utf8");
16020
16185
  } catch {
16021
16186
  continue;
16022
16187
  }
@@ -16297,14 +16462,14 @@ function closeAllTerminals() {
16297
16462
 
16298
16463
  // src/services/apply-file-review.service.ts
16299
16464
  var import_child_process13 = require("child_process");
16300
- var fs26 = __toESM(require("fs"));
16301
- var path32 = __toESM(require("path"));
16465
+ var fs27 = __toESM(require("fs"));
16466
+ var path33 = __toESM(require("path"));
16302
16467
  async function applyFileReview(workingDir, filePath, action) {
16303
- if (filePath.includes("..") || path32.isAbsolute(filePath)) {
16468
+ if (filePath.includes("..") || path33.isAbsolute(filePath)) {
16304
16469
  return { ok: false, action, filePath, error: "invalid file path" };
16305
16470
  }
16306
- const absFile = path32.resolve(workingDir, filePath);
16307
- const repoRoot = findGitRoot2(path32.dirname(absFile));
16471
+ const absFile = path33.resolve(workingDir, filePath);
16472
+ const repoRoot = findGitRoot2(path33.dirname(absFile));
16308
16473
  if (!repoRoot) {
16309
16474
  return {
16310
16475
  ok: false,
@@ -16313,7 +16478,7 @@ async function applyFileReview(workingDir, filePath, action) {
16313
16478
  error: `no enclosing git repo for ${filePath}`
16314
16479
  };
16315
16480
  }
16316
- const relInRepo = path32.relative(repoRoot, absFile);
16481
+ const relInRepo = path33.relative(repoRoot, absFile);
16317
16482
  if (!relInRepo || relInRepo.startsWith("..")) {
16318
16483
  return { ok: false, action, filePath, error: "path escapes repo root" };
16319
16484
  }
@@ -16362,17 +16527,17 @@ function runGit3(cwd, args2) {
16362
16527
  });
16363
16528
  }
16364
16529
  function findGitRoot2(startDir) {
16365
- let dir = path32.resolve(startDir);
16530
+ let dir = path33.resolve(startDir);
16366
16531
  const seen = /* @__PURE__ */ new Set();
16367
16532
  for (let i = 0; i < 256; i++) {
16368
16533
  if (seen.has(dir)) return null;
16369
16534
  seen.add(dir);
16370
16535
  try {
16371
- const stat3 = fs26.statSync(path32.join(dir, ".git"), { throwIfNoEntry: false });
16536
+ const stat3 = fs27.statSync(path33.join(dir, ".git"), { throwIfNoEntry: false });
16372
16537
  if (stat3 && (stat3.isDirectory() || stat3.isFile())) return dir;
16373
16538
  } catch {
16374
16539
  }
16375
- const parent = path32.dirname(dir);
16540
+ const parent = path33.dirname(dir);
16376
16541
  if (parent === dir) return null;
16377
16542
  dir = parent;
16378
16543
  }
@@ -16381,8 +16546,8 @@ function findGitRoot2(startDir) {
16381
16546
 
16382
16547
  // src/commands/link.ts
16383
16548
  var import_node_crypto7 = require("crypto");
16384
- var fs27 = __toESM(require("fs"));
16385
- var path33 = __toESM(require("path"));
16549
+ var fs28 = __toESM(require("fs"));
16550
+ var path34 = __toESM(require("path"));
16386
16551
  var import_chokidar = __toESM(require("chokidar"));
16387
16552
  var import_picocolors2 = __toESM(require("picocolors"));
16388
16553
 
@@ -16442,7 +16607,7 @@ function parseLinkArgs(args2) {
16442
16607
  if (apiKeyFileArg) {
16443
16608
  const filePath = apiKeyFileArg.slice("--api-key-file=".length);
16444
16609
  try {
16445
- apiKey = fs27.readFileSync(path33.resolve(filePath), "utf8").trim();
16610
+ apiKey = fs28.readFileSync(path34.resolve(filePath), "utf8").trim();
16446
16611
  } catch (err) {
16447
16612
  throw new Error(`Could not read --api-key-file ${filePath}: ${err.message}`);
16448
16613
  }
@@ -16536,7 +16701,7 @@ async function link(args2 = []) {
16536
16701
  return;
16537
16702
  }
16538
16703
  if (parsed.tokenFile) {
16539
- const credential = fs27.readFileSync(path33.resolve(parsed.tokenFile), "utf8").trim();
16704
+ const credential = fs28.readFileSync(path34.resolve(parsed.tokenFile), "utf8").trim();
16540
16705
  if (!credential) {
16541
16706
  showError(`--token-file ${parsed.tokenFile} is empty.`);
16542
16707
  process.exit(1);
@@ -16755,11 +16920,11 @@ async function linkDryRunPreflight(ctx) {
16755
16920
  var import_promises = require("dns/promises");
16756
16921
  var import_fs = require("fs");
16757
16922
  var import_promises2 = __toESM(require("fs/promises"));
16758
- var import_os7 = __toESM(require("os"));
16923
+ var import_os8 = __toESM(require("os"));
16759
16924
  var import_path4 = __toESM(require("path"));
16760
16925
  var import_promises3 = require("stream/promises");
16761
16926
  var import_which = __toESM(require("which"));
16762
- var CACHED_BINARY = import_path4.default.join(import_os7.default.homedir(), ".codeam", "bin", "cloudflared");
16927
+ var CACHED_BINARY = import_path4.default.join(import_os8.default.homedir(), ".codeam", "bin", "cloudflared");
16763
16928
  async function waitForCloudflaredReady(url, timeoutMs = 6e4) {
16764
16929
  const hostname3 = new URL(url).hostname;
16765
16930
  const resolver = new import_promises.Resolver();
@@ -17046,7 +17211,7 @@ var pendingAttachmentFiles = /* @__PURE__ */ new Set();
17046
17211
  function cleanupAttachmentTempFiles() {
17047
17212
  for (const p2 of pendingAttachmentFiles) {
17048
17213
  try {
17049
- fs31.unlinkSync(p2);
17214
+ fs32.unlinkSync(p2);
17050
17215
  } catch {
17051
17216
  }
17052
17217
  }
@@ -17055,8 +17220,8 @@ function cleanupAttachmentTempFiles() {
17055
17220
  function saveFilesTemp(files) {
17056
17221
  return files.filter(({ base64 }) => base64 && base64.length > 0).map(({ filename, base64 }) => {
17057
17222
  const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
17058
- const tmpPath = path37.join(os24.tmpdir(), `codeam-${(0, import_crypto5.randomUUID)()}-${safeName}`);
17059
- fs31.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
17223
+ const tmpPath = path38.join(os25.tmpdir(), `codeam-${(0, import_crypto5.randomUUID)()}-${safeName}`);
17224
+ fs32.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
17060
17225
  pendingAttachmentFiles.add(tmpPath);
17061
17226
  return tmpPath;
17062
17227
  });
@@ -17076,7 +17241,7 @@ var startTask = (ctx, _cmd, parsed) => {
17076
17241
  setTimeout(() => {
17077
17242
  for (const p2 of paths) {
17078
17243
  try {
17079
- fs31.unlinkSync(p2);
17244
+ fs32.unlinkSync(p2);
17080
17245
  } catch {
17081
17246
  }
17082
17247
  pendingAttachmentFiles.delete(p2);
@@ -18404,8 +18569,8 @@ async function autoLinkAfterPair(opts) {
18404
18569
  }
18405
18570
 
18406
18571
  // src/commands/pair-auto.ts
18407
- var fs32 = __toESM(require("fs"));
18408
- var os25 = __toESM(require("os"));
18572
+ var fs33 = __toESM(require("fs"));
18573
+ var os26 = __toESM(require("os"));
18409
18574
  var import_crypto7 = require("crypto");
18410
18575
 
18411
18576
  // src/commands/start-infra-only.ts
@@ -18573,12 +18738,12 @@ function readTokenFromArgs(args2) {
18573
18738
  }
18574
18739
  const fileFlag = args2.find((a) => a.startsWith("--token-file="));
18575
18740
  if (fileFlag) {
18576
- const path44 = fileFlag.slice("--token-file=".length);
18741
+ const path45 = fileFlag.slice("--token-file=".length);
18577
18742
  try {
18578
- const content = fs32.readFileSync(path44, "utf8").trim();
18579
- if (content.length === 0) fail(`--token-file ${path44} is empty`);
18743
+ const content = fs33.readFileSync(path45, "utf8").trim();
18744
+ if (content.length === 0) fail(`--token-file ${path45} is empty`);
18580
18745
  try {
18581
- fs32.unlinkSync(path44);
18746
+ fs33.unlinkSync(path45);
18582
18747
  } catch {
18583
18748
  }
18584
18749
  return content;
@@ -18604,7 +18769,7 @@ async function claimOnce(token, pluginId) {
18604
18769
  pluginId,
18605
18770
  ideName: "codeam-cli (codespace)",
18606
18771
  ideVersion: process.env.npm_package_version ?? "unknown",
18607
- hostname: os25.hostname(),
18772
+ hostname: os26.hostname(),
18608
18773
  codespaceName: process.env.CODESPACE_NAME ?? "",
18609
18774
  // Current git branch of the codespace's working directory, so the
18610
18775
  // backend can populate `PairedSession.branch` for the codespace pair.
@@ -18844,7 +19009,7 @@ var import_picocolors10 = __toESM(require("picocolors"));
18844
19009
  var import_child_process16 = require("child_process");
18845
19010
  var import_util4 = require("util");
18846
19011
  var import_picocolors8 = __toESM(require("picocolors"));
18847
- var path38 = __toESM(require("path"));
19012
+ var path39 = __toESM(require("path"));
18848
19013
  var execFileP5 = (0, import_util4.promisify)(import_child_process16.execFile);
18849
19014
  var MAX_BUFFER = 8 * 1024 * 1024;
18850
19015
  function resetStdinForChild() {
@@ -19333,7 +19498,7 @@ var GitHubCodespacesProvider = class {
19333
19498
  });
19334
19499
  }
19335
19500
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
19336
- const remoteDir = path38.posix.dirname(remotePath);
19501
+ const remoteDir = path39.posix.dirname(remotePath);
19337
19502
  const parts = [
19338
19503
  `mkdir -p ${shellQuote(remoteDir)}`,
19339
19504
  `cat > ${shellQuote(remotePath)}`
@@ -19403,7 +19568,7 @@ function shellQuote(s) {
19403
19568
  // src/services/providers/gitpod.ts
19404
19569
  var import_child_process17 = require("child_process");
19405
19570
  var import_util5 = require("util");
19406
- var path39 = __toESM(require("path"));
19571
+ var path40 = __toESM(require("path"));
19407
19572
  var import_picocolors9 = __toESM(require("picocolors"));
19408
19573
  var execFileP6 = (0, import_util5.promisify)(import_child_process17.execFile);
19409
19574
  var MAX_BUFFER2 = 8 * 1024 * 1024;
@@ -19643,7 +19808,7 @@ var GitpodProvider = class {
19643
19808
  });
19644
19809
  }
19645
19810
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
19646
- const remoteDir = path39.posix.dirname(remotePath);
19811
+ const remoteDir = path40.posix.dirname(remotePath);
19647
19812
  const parts = [
19648
19813
  `mkdir -p ${shellQuote2(remoteDir)}`,
19649
19814
  `cat > ${shellQuote2(remotePath)}`
@@ -19679,7 +19844,7 @@ function shellQuote2(s) {
19679
19844
  // src/services/providers/gitlab-workspaces.ts
19680
19845
  var import_child_process18 = require("child_process");
19681
19846
  var import_util6 = require("util");
19682
- var path40 = __toESM(require("path"));
19847
+ var path41 = __toESM(require("path"));
19683
19848
  var execFileP7 = (0, import_util6.promisify)(import_child_process18.execFile);
19684
19849
  var MAX_BUFFER3 = 8 * 1024 * 1024;
19685
19850
  var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
@@ -19939,7 +20104,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
19939
20104
  }
19940
20105
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
19941
20106
  const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
19942
- const remoteDir = path40.posix.dirname(remotePath);
20107
+ const remoteDir = path41.posix.dirname(remotePath);
19943
20108
  const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
19944
20109
  if (options.mode != null) {
19945
20110
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
@@ -20007,7 +20172,7 @@ function shellQuote3(s) {
20007
20172
  // src/services/providers/railway.ts
20008
20173
  var import_child_process19 = require("child_process");
20009
20174
  var import_util7 = require("util");
20010
- var path41 = __toESM(require("path"));
20175
+ var path42 = __toESM(require("path"));
20011
20176
  var execFileP8 = (0, import_util7.promisify)(import_child_process19.execFile);
20012
20177
  var MAX_BUFFER4 = 8 * 1024 * 1024;
20013
20178
  function resetStdinForChild4() {
@@ -20243,7 +20408,7 @@ var RailwayProvider = class {
20243
20408
  if (!projectId || !serviceId) {
20244
20409
  throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
20245
20410
  }
20246
- const remoteDir = path41.posix.dirname(remotePath);
20411
+ const remoteDir = path42.posix.dirname(remotePath);
20247
20412
  const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
20248
20413
  if (options.mode != null) {
20249
20414
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
@@ -20786,8 +20951,8 @@ async function stopWorkspaceFromLocal(target) {
20786
20951
  var import_node_dns = require("dns");
20787
20952
  var import_node_util4 = require("util");
20788
20953
  var import_node_crypto8 = require("crypto");
20789
- var fs33 = __toESM(require("fs"));
20790
- var path42 = __toESM(require("path"));
20954
+ var fs34 = __toESM(require("fs"));
20955
+ var path43 = __toESM(require("path"));
20791
20956
  var import_picocolors12 = __toESM(require("picocolors"));
20792
20957
  var dnsResolveP = (0, import_node_util4.promisify)(import_node_dns.resolve);
20793
20958
  async function checkDns(apiBase) {
@@ -20843,13 +21008,13 @@ async function checkHealth(apiBase) {
20843
21008
  }
20844
21009
  }
20845
21010
  function checkConfigDir() {
20846
- const dir = path42.join(require("os").homedir(), ".codeam");
21011
+ const dir = path43.join(require("os").homedir(), ".codeam");
20847
21012
  try {
20848
- fs33.mkdirSync(dir, { recursive: true, mode: 448 });
20849
- const probe = path42.join(dir, ".doctor-probe");
20850
- fs33.writeFileSync(probe, "ok", { mode: 384 });
20851
- const read = fs33.readFileSync(probe, "utf8");
20852
- fs33.unlinkSync(probe);
21013
+ fs34.mkdirSync(dir, { recursive: true, mode: 448 });
21014
+ const probe = path43.join(dir, ".doctor-probe");
21015
+ fs34.writeFileSync(probe, "ok", { mode: 384 });
21016
+ const read = fs34.readFileSync(probe, "utf8");
21017
+ fs34.unlinkSync(probe);
20853
21018
  if (read !== "ok") throw new Error("write/read round-trip mismatch");
20854
21019
  return {
20855
21020
  id: "config-dir",
@@ -20889,9 +21054,9 @@ function checkSessions() {
20889
21054
  }
20890
21055
  }
20891
21056
  function checkAgentBinaries() {
20892
- const os27 = createOsStrategy();
21057
+ const os28 = createOsStrategy();
20893
21058
  return getEnabledAgents().map((meta) => {
20894
- const found = os27.findInPath(meta.binaryName);
21059
+ const found = os28.findInPath(meta.binaryName);
20895
21060
  return {
20896
21061
  id: `agent-${meta.id}`,
20897
21062
  label: `Agent binary: ${meta.displayName} (${meta.binaryName})`,
@@ -20913,7 +21078,7 @@ function checkNodePty() {
20913
21078
  detail: "not required on this platform"
20914
21079
  };
20915
21080
  }
20916
- const vendoredPath = path42.join(__dirname, "vendor", "node-pty");
21081
+ const vendoredPath = path43.join(__dirname, "vendor", "node-pty");
20917
21082
  for (const target of [vendoredPath, "node-pty"]) {
20918
21083
  try {
20919
21084
  require(target);
@@ -20955,7 +21120,7 @@ function checkChokidar() {
20955
21120
  }
20956
21121
  async function doctor(args2 = []) {
20957
21122
  const json = args2.includes("--json");
20958
- const cliVersion = true ? "2.27.2" : "0.0.0-dev";
21123
+ const cliVersion = true ? "2.27.4" : "0.0.0-dev";
20959
21124
  const apiBase = resolveApiBaseUrl();
20960
21125
  const diagnosticId = (0, import_node_crypto8.randomUUID)();
20961
21126
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -21154,7 +21319,7 @@ async function completion(args2) {
21154
21319
  // src/commands/version.ts
21155
21320
  var import_picocolors13 = __toESM(require("picocolors"));
21156
21321
  function version2() {
21157
- const v = true ? "2.27.2" : "unknown";
21322
+ const v = true ? "2.27.4" : "unknown";
21158
21323
  console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
21159
21324
  }
21160
21325
 
@@ -21282,9 +21447,9 @@ function tryShowSubcommandHelp(cmd, args2) {
21282
21447
  var _subcommandHelpKeys = Object.keys(HELPS);
21283
21448
 
21284
21449
  // src/lib/updateNotifier.ts
21285
- var fs34 = __toESM(require("fs"));
21286
- var os26 = __toESM(require("os"));
21287
- var path43 = __toESM(require("path"));
21450
+ var fs35 = __toESM(require("fs"));
21451
+ var os27 = __toESM(require("os"));
21452
+ var path44 = __toESM(require("path"));
21288
21453
  var https7 = __toESM(require("https"));
21289
21454
  var import_picocolors16 = __toESM(require("picocolors"));
21290
21455
  var PKG_NAME = "codeam-cli";
@@ -21292,12 +21457,12 @@ var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
21292
21457
  var TTL_MS = 24 * 60 * 60 * 1e3;
21293
21458
  var REQUEST_TIMEOUT_MS = 1500;
21294
21459
  function cachePath() {
21295
- const dir = path43.join(os26.homedir(), ".codeam");
21296
- return path43.join(dir, "update-check.json");
21460
+ const dir = path44.join(os27.homedir(), ".codeam");
21461
+ return path44.join(dir, "update-check.json");
21297
21462
  }
21298
21463
  function readCache() {
21299
21464
  try {
21300
- const raw = fs34.readFileSync(cachePath(), "utf8");
21465
+ const raw = fs35.readFileSync(cachePath(), "utf8");
21301
21466
  const parsed = JSON.parse(raw);
21302
21467
  if (typeof parsed.fetchedAt !== "number" || typeof parsed.latest !== "string") return null;
21303
21468
  return parsed;
@@ -21308,10 +21473,10 @@ function readCache() {
21308
21473
  function writeCache(cache) {
21309
21474
  try {
21310
21475
  const file = cachePath();
21311
- fs34.mkdirSync(path43.dirname(file), { recursive: true });
21476
+ fs35.mkdirSync(path44.dirname(file), { recursive: true });
21312
21477
  const tmp = `${file}.${process.pid}.tmp`;
21313
- fs34.writeFileSync(tmp, JSON.stringify(cache));
21314
- fs34.renameSync(tmp, file);
21478
+ fs35.writeFileSync(tmp, JSON.stringify(cache));
21479
+ fs35.renameSync(tmp, file);
21315
21480
  } catch {
21316
21481
  }
21317
21482
  }
@@ -21382,7 +21547,7 @@ function checkForUpdates() {
21382
21547
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
21383
21548
  if (process.env.CI) return;
21384
21549
  if (!process.stdout.isTTY) return;
21385
- const current = true ? "2.27.2" : null;
21550
+ const current = true ? "2.27.4" : null;
21386
21551
  if (!current) return;
21387
21552
  const cache = readCache();
21388
21553
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;