codeam-cli 2.30.0 → 2.32.0

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 +19 -0
  2. package/dist/index.js +272 -191
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,25 @@ All notable changes to `codeam-cli` are documented here.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [2.31.0] — 2026-06-07
8
+
9
+ ### Chore
10
+
11
+ - **cli:** Drop originator-HMAC fields from /api/pairing/code
12
+
13
+ ## [2.30.0] — 2026-06-06
14
+
15
+ ### Added
16
+
17
+ - **vsc-plugin:** Banner recommends update when marketplace ships a fix
18
+ - **jetbrains-plugin:** Banner recommends update when marketplace ships a fix
19
+
20
+ ### Fixed
21
+
22
+ - **cli:** Forward mobile image attachments to ACP as image blocks (QA #290)
23
+ - **cli, vsc-plugin:** Echo mobile prompts + clear Reconnecting UX (QA #287/#291)
24
+ - **cli:** Replace pair pollStatus with SSE pair_completed event (QA #285)
25
+
7
26
  ## [2.29.0] — 2026-06-06
8
27
 
9
28
  ### Added
package/dist/index.js CHANGED
@@ -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.30.0",
501
+ version: "2.32.0",
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",
@@ -685,7 +685,7 @@ var _execSeam = {
685
685
  // src/services/pairing.service.ts
686
686
  var API_BASE = resolveApiBaseUrl();
687
687
  var REQUEST_CODE_TIMEOUT_MS = 1e4;
688
- async function requestCode(pluginId, options = {}) {
688
+ async function requestCode(pluginId) {
689
689
  try {
690
690
  const runtime = process.env.CODESPACES === "true" ? "github-codespaces" : "local";
691
691
  const codespaceName = process.env.CODESPACE_NAME;
@@ -697,12 +697,7 @@ async function requestCode(pluginId, options = {}) {
697
697
  hostname: os2.hostname(),
698
698
  runtime,
699
699
  branch,
700
- ...codespaceName ? { codespaceName } : {},
701
- ...options.originatorSessionId && options.originatorPluginId && options.originatorAuthToken ? {
702
- originatorSessionId: options.originatorSessionId,
703
- originatorPluginId: options.originatorPluginId,
704
- originatorAuthToken: options.originatorAuthToken
705
- } : {}
700
+ ...codespaceName ? { codespaceName } : {}
706
701
  });
707
702
  let timer;
708
703
  const timeoutSentinel = /* @__PURE__ */ Symbol("request-code-timeout");
@@ -711,12 +706,27 @@ async function requestCode(pluginId, options = {}) {
711
706
  });
712
707
  const result = await Promise.race([post2, timeoutPromise]);
713
708
  clearTimeout(timer);
714
- if (result === timeoutSentinel) return null;
709
+ if (result === timeoutSentinel) return { ok: false, reason: "timeout" };
715
710
  const data = result?.data;
716
- if (!data?.code) return null;
717
- return { code: data.code, expiresAt: data.expiresAt };
718
- } catch {
719
- return null;
711
+ if (!data?.code) return { ok: false, reason: "network" };
712
+ return {
713
+ ok: true,
714
+ code: data.code,
715
+ expiresAt: data.expiresAt
716
+ };
717
+ } catch (err) {
718
+ const e = err;
719
+ if (e.statusCode === 429) {
720
+ return {
721
+ ok: false,
722
+ reason: "rate-limited",
723
+ retryAfterSeconds: typeof e.retryAfterSeconds === "number" && e.retryAfterSeconds > 0 ? e.retryAfterSeconds : 60
724
+ };
725
+ }
726
+ if (typeof e.statusCode === "number") {
727
+ return { ok: false, reason: "http", status: e.statusCode };
728
+ }
729
+ return { ok: false, reason: "network" };
720
730
  }
721
731
  }
722
732
  async function fetchCurrentPluginAuthToken(sessionId, pluginId) {
@@ -862,9 +872,9 @@ async function _postJsonAuthed(url, body, pluginAuthToken) {
862
872
  });
863
873
  res.on("end", () => {
864
874
  if (res.statusCode && res.statusCode >= 400) {
865
- const err = new Error(`HTTP ${res.statusCode}: ${responseBody.slice(0, 200)}`);
866
- err.statusCode = res.statusCode;
867
- reject(err);
875
+ reject(
876
+ makeHttpError(res.statusCode, res.headers["retry-after"], responseBody)
877
+ );
868
878
  return;
869
879
  }
870
880
  try {
@@ -884,6 +894,16 @@ async function _postJsonAuthed(url, body, pluginAuthToken) {
884
894
  req.end();
885
895
  });
886
896
  }
897
+ function makeHttpError(statusCode, retryAfterHeader, responseBody) {
898
+ const raw = Array.isArray(retryAfterHeader) ? retryAfterHeader[0] : retryAfterHeader;
899
+ const retryAfterSeconds = raw && /^\d+$/.test(raw.trim()) ? Number.parseInt(raw, 10) : void 0;
900
+ const err = new Error(
901
+ `HTTP ${statusCode}${responseBody ? ": " + responseBody.slice(0, 200) : ""}`
902
+ );
903
+ err.statusCode = statusCode;
904
+ if (typeof retryAfterSeconds === "number") err.retryAfterSeconds = retryAfterSeconds;
905
+ return err;
906
+ }
887
907
  async function _postJson(url, body) {
888
908
  return new Promise((resolve6, reject) => {
889
909
  const data = JSON.stringify(body);
@@ -910,7 +930,7 @@ async function _postJson(url, body) {
910
930
  });
911
931
  res.on("end", () => {
912
932
  if (res.statusCode && res.statusCode >= 400) {
913
- reject(new Error(`HTTP ${res.statusCode}`));
933
+ reject(makeHttpError(res.statusCode, res.headers["retry-after"], body2));
914
934
  return;
915
935
  }
916
936
  try {
@@ -951,7 +971,7 @@ async function _getJson(url) {
951
971
  });
952
972
  res.on("end", () => {
953
973
  if (res.statusCode && res.statusCode >= 400) {
954
- reject(new Error(`HTTP ${res.statusCode}`));
974
+ reject(makeHttpError(res.statusCode, res.headers["retry-after"], body));
955
975
  return;
956
976
  }
957
977
  try {
@@ -1135,8 +1155,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
1135
1155
  return decodedFile;
1136
1156
  };
1137
1157
  }
1138
- function normalizeWindowsPath(path45) {
1139
- return path45.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
1158
+ function normalizeWindowsPath(path46) {
1159
+ return path46.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
1140
1160
  }
1141
1161
 
1142
1162
  // ../../node_modules/@posthog/core/dist/featureFlagUtils.mjs
@@ -3616,9 +3636,9 @@ async function addSourceContext(frames) {
3616
3636
  LRU_FILE_CONTENTS_CACHE.reduce();
3617
3637
  return frames;
3618
3638
  }
3619
- function getContextLinesFromFile(path45, ranges, output) {
3639
+ function getContextLinesFromFile(path46, ranges, output) {
3620
3640
  return new Promise((resolve6) => {
3621
- const stream = (0, import_node_fs.createReadStream)(path45);
3641
+ const stream = (0, import_node_fs.createReadStream)(path46);
3622
3642
  const lineReaded = (0, import_node_readline.createInterface)({
3623
3643
  input: stream
3624
3644
  });
@@ -3633,7 +3653,7 @@ function getContextLinesFromFile(path45, ranges, output) {
3633
3653
  let rangeStart = range[0];
3634
3654
  let rangeEnd = range[1];
3635
3655
  function onStreamError() {
3636
- LRU_FILE_CONTENTS_FS_READ_FAILED.set(path45, 1);
3656
+ LRU_FILE_CONTENTS_FS_READ_FAILED.set(path46, 1);
3637
3657
  lineReaded.close();
3638
3658
  lineReaded.removeAllListeners();
3639
3659
  destroyStreamAndResolve();
@@ -3694,8 +3714,8 @@ function clearLineContext(frame) {
3694
3714
  delete frame.context_line;
3695
3715
  delete frame.post_context;
3696
3716
  }
3697
- function shouldSkipContextLinesForFile(path45) {
3698
- return path45.startsWith("node:") || path45.endsWith(".min.js") || path45.endsWith(".min.cjs") || path45.endsWith(".min.mjs") || path45.startsWith("data:");
3717
+ function shouldSkipContextLinesForFile(path46) {
3718
+ return path46.startsWith("node:") || path46.endsWith(".min.js") || path46.endsWith(".min.cjs") || path46.endsWith(".min.mjs") || path46.startsWith("data:");
3699
3719
  }
3700
3720
  function shouldSkipContextLinesForFrame(frame) {
3701
3721
  if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
@@ -5849,7 +5869,7 @@ function readAnonId() {
5849
5869
  }
5850
5870
  function superProperties() {
5851
5871
  return {
5852
- cliVersion: true ? "2.30.0" : "0.0.0-dev",
5872
+ cliVersion: true ? "2.32.0" : "0.0.0-dev",
5853
5873
  nodeVersion: process.version,
5854
5874
  platform: process.platform,
5855
5875
  arch: process.arch,
@@ -7191,10 +7211,10 @@ function buildForPlatform(platform2) {
7191
7211
  var import_node_crypto4 = require("crypto");
7192
7212
 
7193
7213
  // src/agents/claude/resolver.ts
7194
- function buildClaudeLaunch(extraArgs = [], os28 = createOsStrategy()) {
7195
- const found = os28.findInPath("claude") ?? os28.findInPath("claude-code");
7214
+ function buildClaudeLaunch(extraArgs = [], os29 = createOsStrategy()) {
7215
+ const found = os29.findInPath("claude") ?? os29.findInPath("claude-code");
7196
7216
  if (!found) return null;
7197
- return os28.buildLaunch(found, extraArgs);
7217
+ return os29.buildLaunch(found, extraArgs);
7198
7218
  }
7199
7219
 
7200
7220
  // src/agents/claude/installer.ts
@@ -9921,13 +9941,13 @@ function detectStartupBanner(lines) {
9921
9941
  while (artStart > 0 && BANNER_ART_RE.test(lines[artStart - 1])) artStart--;
9922
9942
  if (metaIdx - artStart < 2) return null;
9923
9943
  const pathLine = (lines[metaIdx + 1] ?? "").trim();
9924
- const path45 = pathLine && !BANNER_ART_RE.test(pathLine) ? pathLine : "";
9944
+ const path46 = pathLine && !BANNER_ART_RE.test(pathLine) ? pathLine : "";
9925
9945
  return {
9926
9946
  title: "",
9927
9947
  subtitle: lines[metaIdx].trim(),
9928
- path: path45,
9948
+ path: path46,
9929
9949
  startIdx: artStart,
9930
- endIdx: metaIdx + (path45 ? 1 : 0)
9950
+ endIdx: metaIdx + (path46 ? 1 : 0)
9931
9951
  };
9932
9952
  }
9933
9953
 
@@ -9937,8 +9957,8 @@ var ClaudeRuntimeStrategy = class {
9937
9957
  meta = getAgent("claude");
9938
9958
  mode = "interactive";
9939
9959
  os;
9940
- constructor(os28) {
9941
- this.os = os28;
9960
+ constructor(os29) {
9961
+ this.os = os29;
9942
9962
  }
9943
9963
  /**
9944
9964
  * Claude Code's react-ink TUI enables bracketed-paste mode at
@@ -10946,8 +10966,8 @@ function codexCredentialLocator() {
10946
10966
  function codexLoginLauncher() {
10947
10967
  return {
10948
10968
  async ensureInstalled() {
10949
- const os28 = createOsStrategy();
10950
- return os28.findInPath("codex") !== null;
10969
+ const os29 = createOsStrategy();
10970
+ return os29.findInPath("codex") !== null;
10951
10971
  },
10952
10972
  launch() {
10953
10973
  return (0, import_node_child_process3.spawn)("codex", ["login"], { stdio: "inherit" });
@@ -10970,8 +10990,8 @@ var CodexRuntimeStrategy = class {
10970
10990
  meta = getAgent("codex");
10971
10991
  mode = "interactive";
10972
10992
  os;
10973
- constructor(os28) {
10974
- this.os = os28;
10993
+ constructor(os29) {
10994
+ this.os = os29;
10975
10995
  }
10976
10996
  async prepareLaunch() {
10977
10997
  let binary = this.os.findInPath("codex");
@@ -11077,12 +11097,12 @@ var CodexRuntimeStrategy = class {
11077
11097
  });
11078
11098
  }
11079
11099
  };
11080
- function resolveNpm(os28) {
11081
- return os28.id === "win32" ? "npm.cmd" : "npm";
11100
+ function resolveNpm(os29) {
11101
+ return os29.id === "win32" ? "npm.cmd" : "npm";
11082
11102
  }
11083
- async function installCodexViaNpm(os28) {
11103
+ async function installCodexViaNpm(os29) {
11084
11104
  return new Promise((resolve6, reject) => {
11085
- const proc = (0, import_node_child_process4.spawn)(resolveNpm(os28), ["install", "-g", "@openai/codex"], {
11105
+ const proc = (0, import_node_child_process4.spawn)(resolveNpm(os29), ["install", "-g", "@openai/codex"], {
11086
11106
  stdio: "inherit"
11087
11107
  });
11088
11108
  proc.on("close", (code) => {
@@ -11099,16 +11119,16 @@ async function installCodexViaNpm(os28) {
11099
11119
  });
11100
11120
  });
11101
11121
  }
11102
- function augmentNpmGlobalBin(os28) {
11122
+ function augmentNpmGlobalBin(os29) {
11103
11123
  try {
11104
- const result = (0, import_node_child_process4.spawnSync)(resolveNpm(os28), ["prefix", "-g"], {
11124
+ const result = (0, import_node_child_process4.spawnSync)(resolveNpm(os29), ["prefix", "-g"], {
11105
11125
  stdio: ["ignore", "pipe", "ignore"]
11106
11126
  });
11107
11127
  if (result.status !== 0) return;
11108
11128
  const prefix = result.stdout.toString().trim();
11109
11129
  if (!prefix) return;
11110
- const binDir = os28.id === "win32" ? prefix : path17.join(prefix, "bin");
11111
- os28.augmentPath([binDir]);
11130
+ const binDir = os29.id === "win32" ? prefix : path17.join(prefix, "bin");
11131
+ os29.augmentPath([binDir]);
11112
11132
  } catch {
11113
11133
  }
11114
11134
  }
@@ -11192,9 +11212,9 @@ var import_node_child_process7 = require("child_process");
11192
11212
  // src/agents/coderabbit/installer.ts
11193
11213
  var import_node_child_process5 = require("child_process");
11194
11214
  var INSTALL_URL = "https://cli.coderabbit.ai/install.sh";
11195
- async function ensureCoderabbitInstalled(os28) {
11196
- if (os28.findInPath("coderabbit")) return true;
11197
- if (os28.id === "win32") {
11215
+ async function ensureCoderabbitInstalled(os29) {
11216
+ if (os29.findInPath("coderabbit")) return true;
11217
+ if (os29.id === "win32") {
11198
11218
  console.error(
11199
11219
  "\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"
11200
11220
  );
@@ -11209,8 +11229,8 @@ async function ensureCoderabbitInstalled(os28) {
11209
11229
  proc.on("error", () => resolve6(false));
11210
11230
  });
11211
11231
  if (!ok) return false;
11212
- os28.augmentPath([`${os28.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
11213
- return os28.findInPath("coderabbit") !== null;
11232
+ os29.augmentPath([`${os29.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
11233
+ return os29.findInPath("coderabbit") !== null;
11214
11234
  }
11215
11235
 
11216
11236
  // src/agents/coderabbit/link.ts
@@ -11237,10 +11257,10 @@ function coderabbitCredentialLocator() {
11237
11257
  extract: extractLocalCoderabbitToken
11238
11258
  };
11239
11259
  }
11240
- function coderabbitLoginLauncher(os28) {
11260
+ function coderabbitLoginLauncher(os29) {
11241
11261
  return {
11242
11262
  async ensureInstalled() {
11243
- return ensureCoderabbitInstalled(os28);
11263
+ return ensureCoderabbitInstalled(os29);
11244
11264
  },
11245
11265
  launch() {
11246
11266
  return (0, import_node_child_process6.spawn)("coderabbit", ["login"], { stdio: "inherit" });
@@ -11263,11 +11283,11 @@ function parseReview(stdout) {
11263
11283
  for (const line of lines) {
11264
11284
  const m = line.match(HUNK_LINE_RE);
11265
11285
  if (!m) continue;
11266
- const [, path45, lineNo, sevToken, message] = m;
11267
- if (!path45 || !lineNo || !message) continue;
11286
+ const [, path46, lineNo, sevToken, message] = m;
11287
+ if (!path46 || !lineNo || !message) continue;
11268
11288
  const cleanedMessage = message.trim().replace(/^[*-]\s+/, "");
11269
11289
  hunks.push({
11270
- path: path45.trim(),
11290
+ path: path46.trim(),
11271
11291
  line: Number(lineNo),
11272
11292
  severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
11273
11293
  message: cleanedMessage
@@ -11286,8 +11306,8 @@ var CoderabbitRuntimeStrategy = class {
11286
11306
  meta = getAgent("coderabbit");
11287
11307
  mode = "batch";
11288
11308
  os;
11289
- constructor(os28) {
11290
- this.os = os28;
11309
+ constructor(os29) {
11310
+ this.os = os29;
11291
11311
  }
11292
11312
  getDefaultArgs() {
11293
11313
  return ["review"];
@@ -11402,10 +11422,10 @@ function cursorCredentialLocator() {
11402
11422
  extract: extractLocalCursorToken
11403
11423
  };
11404
11424
  }
11405
- function cursorLoginLauncher(os28) {
11425
+ function cursorLoginLauncher(os29) {
11406
11426
  return {
11407
11427
  async ensureInstalled() {
11408
- if (os28.findInPath("cursor-agent")) return true;
11428
+ if (os29.findInPath("cursor-agent")) return true;
11409
11429
  console.error(
11410
11430
  "\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"
11411
11431
  );
@@ -11467,8 +11487,8 @@ var CursorRuntimeStrategy = class {
11467
11487
  meta = getAgent("cursor");
11468
11488
  mode = "interactive";
11469
11489
  os;
11470
- constructor(os28) {
11471
- this.os = os28;
11490
+ constructor(os29) {
11491
+ this.os = os29;
11472
11492
  }
11473
11493
  async prepareLaunch() {
11474
11494
  const binary = this.os.findInPath("cursor-agent");
@@ -11588,10 +11608,10 @@ function aiderCredentialLocator() {
11588
11608
  extract: extractLocalAiderToken
11589
11609
  };
11590
11610
  }
11591
- function aiderLoginLauncher(os28) {
11611
+ function aiderLoginLauncher(os29) {
11592
11612
  return {
11593
11613
  async ensureInstalled() {
11594
- if (os28.findInPath("aider")) return true;
11614
+ if (os29.findInPath("aider")) return true;
11595
11615
  console.error(
11596
11616
  "\n \u2717 aider binary not on PATH.\n Install Aider:\n pip install aider-chat\n then re-run `codeam link aider`.\n"
11597
11617
  );
@@ -11601,7 +11621,7 @@ function aiderLoginLauncher(os28) {
11601
11621
  console.error(
11602
11622
  "\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"
11603
11623
  );
11604
- return (0, import_node_child_process9.spawn)(os28.id === "win32" ? "cmd.exe" : "sh", os28.id === "win32" ? ["/c", "exit", "0"] : ["-c", "exit 0"], {
11624
+ return (0, import_node_child_process9.spawn)(os29.id === "win32" ? "cmd.exe" : "sh", os29.id === "win32" ? ["/c", "exit", "0"] : ["-c", "exit 0"], {
11605
11625
  stdio: "ignore"
11606
11626
  });
11607
11627
  }
@@ -11673,8 +11693,8 @@ var AiderRuntimeStrategy = class {
11673
11693
  meta = getAgent("aider");
11674
11694
  mode = "interactive";
11675
11695
  os;
11676
- constructor(os28) {
11677
- this.os = os28;
11696
+ constructor(os29) {
11697
+ this.os = os29;
11678
11698
  }
11679
11699
  async prepareLaunch() {
11680
11700
  const binary = this.os.findInPath("aider");
@@ -11797,8 +11817,8 @@ function geminiCredentialLocator() {
11797
11817
  function geminiLoginLauncher() {
11798
11818
  return {
11799
11819
  async ensureInstalled() {
11800
- const os28 = createOsStrategy();
11801
- return os28.findInPath("gemini") !== null;
11820
+ const os29 = createOsStrategy();
11821
+ return os29.findInPath("gemini") !== null;
11802
11822
  },
11803
11823
  launch() {
11804
11824
  return (0, import_node_child_process10.spawn)("gemini", ["auth", "login"], { stdio: "inherit" });
@@ -11831,8 +11851,8 @@ var GeminiRuntimeStrategy = class {
11831
11851
  meta = getAgent("gemini");
11832
11852
  mode = "interactive";
11833
11853
  os;
11834
- constructor(os28) {
11835
- this.os = os28;
11854
+ constructor(os29) {
11855
+ this.os = os29;
11836
11856
  }
11837
11857
  async prepareLaunch() {
11838
11858
  const binary = this.os.findInPath("gemini");
@@ -11932,18 +11952,18 @@ var GeminiRuntimeStrategy = class {
11932
11952
 
11933
11953
  // src/agents/registry.ts
11934
11954
  var runtimeBuilders = {
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)
11955
+ claude: (os29) => new ClaudeRuntimeStrategy(os29),
11956
+ codex: (os29) => new CodexRuntimeStrategy(os29),
11957
+ coderabbit: (os29) => new CoderabbitRuntimeStrategy(os29),
11958
+ cursor: (os29) => new CursorRuntimeStrategy(os29),
11959
+ aider: (os29) => new AiderRuntimeStrategy(os29),
11960
+ gemini: (os29) => new GeminiRuntimeStrategy(os29)
11941
11961
  };
11942
11962
  var deployBuilders = {
11943
11963
  claude: () => new ClaudeDeployStrategy(),
11944
11964
  codex: () => new CodexDeployStrategy()
11945
11965
  };
11946
- function createAgentStrategy(agent, os28 = createOsStrategy()) {
11966
+ function createAgentStrategy(agent, os29 = createOsStrategy()) {
11947
11967
  if (!AGENT_REGISTRY[agent]?.enabled) {
11948
11968
  throw new Error(
11949
11969
  `Agent "${agent}" is not supported in this codeam-cli version. Upgrade with 'npm i -g codeam-cli@latest'.`
@@ -11953,10 +11973,10 @@ function createAgentStrategy(agent, os28 = createOsStrategy()) {
11953
11973
  if (!build) {
11954
11974
  throw new Error(`No runtime strategy registered for agent "${agent}"`);
11955
11975
  }
11956
- return build(os28);
11976
+ return build(os29);
11957
11977
  }
11958
- function createInteractiveAgentStrategy(agent, os28 = createOsStrategy()) {
11959
- const s = createAgentStrategy(agent, os28);
11978
+ function createInteractiveAgentStrategy(agent, os29 = createOsStrategy()) {
11979
+ const s = createAgentStrategy(agent, os29);
11960
11980
  if (s.mode !== "interactive") {
11961
11981
  throw new Error(
11962
11982
  `Agent "${agent}" is a batch agent; use createAgentStrategy + .runOneShot for one-shot reviews.`
@@ -12056,6 +12076,9 @@ var import_node_crypto7 = require("crypto");
12056
12076
  // src/agents/acp/client.ts
12057
12077
  var import_node_child_process11 = require("child_process");
12058
12078
  var fs21 = __toESM(require("fs/promises"));
12079
+ var fsSync = __toESM(require("fs"));
12080
+ var os22 = __toESM(require("os"));
12081
+ var path26 = __toESM(require("path"));
12059
12082
  var import_node_stream = require("stream");
12060
12083
 
12061
12084
  // ../../node_modules/@agentclientprotocol/sdk/dist/acp.js
@@ -14534,13 +14557,14 @@ var AcpClient = class {
14534
14557
  async start() {
14535
14558
  if (this.child) throw new Error("AcpClient already started");
14536
14559
  const { adapter, cwd } = this.opts;
14560
+ const augmentedPath = expandPathForAgentBinaries(process.env.PATH ?? "");
14537
14561
  log.info(
14538
14562
  "acpClient",
14539
14563
  `spawn cmd=${adapter.command} args=[${adapter.args.join(",")}] cwd=${cwd}`
14540
14564
  );
14541
14565
  const child = (0, import_node_child_process11.spawn)(adapter.command, adapter.args, {
14542
14566
  cwd,
14543
- env: process.env,
14567
+ env: { ...process.env, PATH: augmentedPath },
14544
14568
  stdio: ["pipe", "pipe", "pipe"]
14545
14569
  });
14546
14570
  this.child = child;
@@ -14817,6 +14841,48 @@ function applyLineRange(content, line, limit) {
14817
14841
  const end = limit !== null ? start2 + limit : lines.length;
14818
14842
  return { content: lines.slice(start2, end).join("\n") };
14819
14843
  }
14844
+ function knownAgentBinaryDirs() {
14845
+ const home = os22.homedir();
14846
+ const out2 = [];
14847
+ out2.push("/tmp/codeam-node20/bin");
14848
+ for (const root of [
14849
+ "/usr/local/share/nvm/versions/node",
14850
+ path26.join(home, ".nvm/versions/node")
14851
+ ]) {
14852
+ try {
14853
+ for (const child of fsSync.readdirSync(root)) {
14854
+ out2.push(path26.join(root, child, "bin"));
14855
+ }
14856
+ } catch {
14857
+ }
14858
+ }
14859
+ out2.push(path26.join(home, ".volta/bin"));
14860
+ out2.push("/usr/local/bin");
14861
+ out2.push("/usr/bin");
14862
+ out2.push(path26.join(home, ".local/bin"));
14863
+ out2.push(path26.join(home, "bin"));
14864
+ return out2.filter((p2) => {
14865
+ try {
14866
+ return fsSync.statSync(p2).isDirectory();
14867
+ } catch {
14868
+ return false;
14869
+ }
14870
+ });
14871
+ }
14872
+ function expandPathForAgentBinaries(existingPath) {
14873
+ const existing = new Set(
14874
+ existingPath.split(path26.delimiter).filter((p2) => p2.length > 0)
14875
+ );
14876
+ const additions = [];
14877
+ for (const dir of knownAgentBinaryDirs()) {
14878
+ if (!existing.has(dir)) {
14879
+ additions.push(dir);
14880
+ existing.add(dir);
14881
+ }
14882
+ }
14883
+ if (additions.length === 0) return existingPath;
14884
+ return [...additions, existingPath].filter((p2) => p2.length > 0).join(path26.delimiter);
14885
+ }
14820
14886
 
14821
14887
  // src/services/streaming/transport.ts
14822
14888
  var http3 = __toESM(require("http"));
@@ -15602,8 +15668,8 @@ function extractSelectPrompt(text) {
15602
15668
 
15603
15669
  // src/commands/start/handlers.ts
15604
15670
  var fs29 = __toESM(require("fs"));
15605
- var os23 = __toESM(require("os"));
15606
- var path34 = __toESM(require("path"));
15671
+ var os24 = __toESM(require("os"));
15672
+ var path35 = __toESM(require("path"));
15607
15673
  var import_crypto3 = require("crypto");
15608
15674
  var import_child_process12 = require("child_process");
15609
15675
 
@@ -15728,7 +15794,7 @@ function parsePayload2(schema, raw) {
15728
15794
 
15729
15795
  // src/services/file-ops.service.ts
15730
15796
  var fs22 = __toESM(require("fs/promises"));
15731
- var path27 = __toESM(require("path"));
15797
+ var path28 = __toESM(require("path"));
15732
15798
  var MAX_FILE_BYTES = 5 * 1024 * 1024;
15733
15799
  var MAX_WALK_DEPTH = 6;
15734
15800
  var MAX_VISITED_DIRS = 5e3;
@@ -15763,8 +15829,8 @@ var SUBDIR_IGNORE = /* @__PURE__ */ new Set([
15763
15829
  "__pycache__"
15764
15830
  ]);
15765
15831
  function isUnder(parent, candidate) {
15766
- const rel = path27.relative(parent, candidate);
15767
- return rel === "" || !rel.startsWith("..") && !path27.isAbsolute(rel);
15832
+ const rel = path28.relative(parent, candidate);
15833
+ return rel === "" || !rel.startsWith("..") && !path28.isAbsolute(rel);
15768
15834
  }
15769
15835
  async function isExistingFile(absPath) {
15770
15836
  try {
@@ -15787,7 +15853,7 @@ async function walkForSuffix(dir, needleVariants, depth, ctx) {
15787
15853
  }
15788
15854
  for (const e of entries) {
15789
15855
  if (!e.isFile()) continue;
15790
- const full = path27.join(dir, e.name);
15856
+ const full = path28.join(dir, e.name);
15791
15857
  if (needleVariants.some((needle) => full.endsWith(needle))) {
15792
15858
  ctx.matches.push(full);
15793
15859
  if (ctx.matches.length >= ctx.cap) return;
@@ -15797,21 +15863,21 @@ async function walkForSuffix(dir, needleVariants, depth, ctx) {
15797
15863
  if (!e.isDirectory()) continue;
15798
15864
  if (SUBDIR_IGNORE.has(e.name)) continue;
15799
15865
  if (e.name.startsWith(".") && SUBDIR_IGNORE.has(e.name)) continue;
15800
- await walkForSuffix(path27.join(dir, e.name), needleVariants, depth + 1, ctx);
15866
+ await walkForSuffix(path28.join(dir, e.name), needleVariants, depth + 1, ctx);
15801
15867
  if (ctx.matches.length >= ctx.cap) return;
15802
15868
  }
15803
15869
  }
15804
15870
  async function findFile(rawPath) {
15805
15871
  const cwd = process.cwd();
15806
- if (path27.isAbsolute(rawPath)) {
15807
- const abs = path27.normalize(rawPath);
15872
+ if (path28.isAbsolute(rawPath)) {
15873
+ const abs = path28.normalize(rawPath);
15808
15874
  if (isUnder(cwd, abs) && await isExistingFile(abs)) return abs;
15809
15875
  }
15810
- const direct = path27.resolve(cwd, rawPath);
15876
+ const direct = path28.resolve(cwd, rawPath);
15811
15877
  if (isUnder(cwd, direct) && await isExistingFile(direct)) return direct;
15812
- const normalized = path27.normalize(rawPath).replace(/^[./\\]+/, "");
15878
+ const normalized = path28.normalize(rawPath).replace(/^[./\\]+/, "");
15813
15879
  const needles = [
15814
- `${path27.sep}${normalized}`,
15880
+ `${path28.sep}${normalized}`,
15815
15881
  `/${normalized}`
15816
15882
  ].filter((v, i, a) => a.indexOf(v) === i);
15817
15883
  const ctx = { visited: 0, matches: [], cap: 16 };
@@ -15825,7 +15891,7 @@ async function findWriteTarget(rawPath) {
15825
15891
  const found = await findFile(rawPath);
15826
15892
  if (found) return found;
15827
15893
  const cwd = process.cwd();
15828
- const fallback = path27.isAbsolute(rawPath) ? path27.normalize(rawPath) : path27.resolve(cwd, rawPath);
15894
+ const fallback = path28.isAbsolute(rawPath) ? path28.normalize(rawPath) : path28.resolve(cwd, rawPath);
15829
15895
  if (!isUnder(cwd, fallback)) return null;
15830
15896
  return fallback;
15831
15897
  }
@@ -15865,7 +15931,7 @@ async function writeProjectFile(rawPath, content) {
15865
15931
  if (Buffer.byteLength(content, "utf-8") > MAX_FILE_BYTES) {
15866
15932
  return { error: "Content too large." };
15867
15933
  }
15868
- await fs22.mkdir(path27.dirname(abs), { recursive: true });
15934
+ await fs22.mkdir(path28.dirname(abs), { recursive: true });
15869
15935
  await fs22.writeFile(abs, content, "utf-8");
15870
15936
  return { ok: true };
15871
15937
  } catch (e) {
@@ -15878,7 +15944,7 @@ async function writeProjectFile(rawPath, content) {
15878
15944
  var import_child_process9 = require("child_process");
15879
15945
  var import_util2 = require("util");
15880
15946
  var fs23 = __toESM(require("fs/promises"));
15881
- var path28 = __toESM(require("path"));
15947
+ var path29 = __toESM(require("path"));
15882
15948
  var execFileP3 = (0, import_util2.promisify)(import_child_process9.execFile);
15883
15949
  var PROJECT_IGNORE = /* @__PURE__ */ new Set([
15884
15950
  "node_modules",
@@ -15936,12 +16002,12 @@ async function listProjectFiles(opts = {}) {
15936
16002
  return;
15937
16003
  }
15938
16004
  if (PROJECT_IGNORE.has(e.name)) continue;
15939
- const full = path28.join(dir, e.name);
16005
+ const full = path29.join(dir, e.name);
15940
16006
  if (e.isDirectory()) {
15941
16007
  if (depth >= 12) continue;
15942
16008
  await walk(full, depth + 1);
15943
16009
  } else if (e.isFile()) {
15944
- const rel = path28.relative(root, full);
16010
+ const rel = path29.relative(root, full);
15945
16011
  if (q2 && !rel.toLowerCase().includes(q2) && !e.name.toLowerCase().includes(q2)) {
15946
16012
  continue;
15947
16013
  }
@@ -16049,7 +16115,7 @@ async function gitStatus(cwd) {
16049
16115
  let hasMergeInProgress = false;
16050
16116
  try {
16051
16117
  const gitDir = (await git(["rev-parse", "--git-dir"], root)).stdout.trim();
16052
- const mergeHead = path28.isAbsolute(gitDir) ? path28.join(gitDir, "MERGE_HEAD") : path28.join(root, gitDir, "MERGE_HEAD");
16118
+ const mergeHead = path29.isAbsolute(gitDir) ? path29.join(gitDir, "MERGE_HEAD") : path29.join(root, gitDir, "MERGE_HEAD");
16053
16119
  await fs23.access(mergeHead);
16054
16120
  hasMergeInProgress = true;
16055
16121
  } catch {
@@ -16196,7 +16262,7 @@ async function jsSearchFiles(opts, cwd, cap) {
16196
16262
  }
16197
16263
  let content = "";
16198
16264
  try {
16199
- content = await fs23.readFile(path28.join(cwd, f.path), "utf8");
16265
+ content = await fs23.readFile(path29.join(cwd, f.path), "utf8");
16200
16266
  } catch {
16201
16267
  continue;
16202
16268
  }
@@ -16221,13 +16287,13 @@ async function jsSearchFiles(opts, cwd, cap) {
16221
16287
  // src/services/apply-file-review.service.ts
16222
16288
  var import_child_process10 = require("child_process");
16223
16289
  var fs24 = __toESM(require("fs"));
16224
- var path29 = __toESM(require("path"));
16290
+ var path30 = __toESM(require("path"));
16225
16291
  async function applyFileReview(workingDir, filePath, action) {
16226
- if (filePath.includes("..") || path29.isAbsolute(filePath)) {
16292
+ if (filePath.includes("..") || path30.isAbsolute(filePath)) {
16227
16293
  return { ok: false, action, filePath, error: "invalid file path" };
16228
16294
  }
16229
- const absFile = path29.resolve(workingDir, filePath);
16230
- const repoRoot = findGitRoot(path29.dirname(absFile));
16295
+ const absFile = path30.resolve(workingDir, filePath);
16296
+ const repoRoot = findGitRoot(path30.dirname(absFile));
16231
16297
  if (!repoRoot) {
16232
16298
  return {
16233
16299
  ok: false,
@@ -16236,7 +16302,7 @@ async function applyFileReview(workingDir, filePath, action) {
16236
16302
  error: `no enclosing git repo for ${filePath}`
16237
16303
  };
16238
16304
  }
16239
- const relInRepo = path29.relative(repoRoot, absFile);
16305
+ const relInRepo = path30.relative(repoRoot, absFile);
16240
16306
  if (!relInRepo || relInRepo.startsWith("..")) {
16241
16307
  return { ok: false, action, filePath, error: "path escapes repo root" };
16242
16308
  }
@@ -16285,17 +16351,17 @@ function runGit(cwd, args2) {
16285
16351
  });
16286
16352
  }
16287
16353
  function findGitRoot(startDir) {
16288
- let dir = path29.resolve(startDir);
16354
+ let dir = path30.resolve(startDir);
16289
16355
  const seen = /* @__PURE__ */ new Set();
16290
16356
  for (let i = 0; i < 256; i++) {
16291
16357
  if (seen.has(dir)) return null;
16292
16358
  seen.add(dir);
16293
16359
  try {
16294
- const stat3 = fs24.statSync(path29.join(dir, ".git"), { throwIfNoEntry: false });
16360
+ const stat3 = fs24.statSync(path30.join(dir, ".git"), { throwIfNoEntry: false });
16295
16361
  if (stat3 && (stat3.isDirectory() || stat3.isFile())) return dir;
16296
16362
  } catch {
16297
16363
  }
16298
- const parent = path29.dirname(dir);
16364
+ const parent = path30.dirname(dir);
16299
16365
  if (parent === dir) return null;
16300
16366
  dir = parent;
16301
16367
  }
@@ -16305,7 +16371,7 @@ function findGitRoot(startDir) {
16305
16371
  // src/commands/link.ts
16306
16372
  var import_node_crypto6 = require("crypto");
16307
16373
  var fs25 = __toESM(require("fs"));
16308
- var path30 = __toESM(require("path"));
16374
+ var path31 = __toESM(require("path"));
16309
16375
  var import_chokidar = __toESM(require("chokidar"));
16310
16376
  var import_picocolors2 = __toESM(require("picocolors"));
16311
16377
 
@@ -16484,7 +16550,7 @@ function parseLinkArgs(args2) {
16484
16550
  if (apiKeyFileArg) {
16485
16551
  const filePath = apiKeyFileArg.slice("--api-key-file=".length);
16486
16552
  try {
16487
- apiKey = fs25.readFileSync(path30.resolve(filePath), "utf8").trim();
16553
+ apiKey = fs25.readFileSync(path31.resolve(filePath), "utf8").trim();
16488
16554
  } catch (err) {
16489
16555
  throw new Error(`Could not read --api-key-file ${filePath}: ${err.message}`);
16490
16556
  }
@@ -16514,15 +16580,20 @@ async function link(args2 = []) {
16514
16580
  const pluginId = (0, import_node_crypto6.randomUUID)();
16515
16581
  const spin = dist_exports.spinner();
16516
16582
  spin.start("Requesting pairing code...");
16517
- const originator = getActiveSession();
16518
- const pairing = await requestCode(pluginId, {
16519
- originatorSessionId: originator?.id,
16520
- originatorPluginId: originator?.pluginId,
16521
- originatorAuthToken: originator?.pluginAuthToken
16522
- });
16523
- if (!pairing) {
16583
+ const pairing = await requestCode(pluginId);
16584
+ if (!pairing.ok) {
16524
16585
  spin.stop("Failed");
16525
- showError("Could not reach the server. Check your connection and try again.");
16586
+ if (pairing.reason === "rate-limited") {
16587
+ showError(
16588
+ `Server is rate-limiting this request (HTTP 429). Retry in ${pairing.retryAfterSeconds}s.`
16589
+ );
16590
+ } else if (pairing.reason === "timeout") {
16591
+ showError("Server took too long to respond. Check your connection and try again.");
16592
+ } else if (pairing.reason === "http") {
16593
+ showError(`Server returned HTTP ${pairing.status}. Try again later.`);
16594
+ } else {
16595
+ showError("Could not reach the server. Check your connection and try again.");
16596
+ }
16526
16597
  process.exit(1);
16527
16598
  }
16528
16599
  spin.stop("Got pairing code");
@@ -16583,7 +16654,7 @@ async function link(args2 = []) {
16583
16654
  return;
16584
16655
  }
16585
16656
  if (parsed.tokenFile) {
16586
- const credential = fs25.readFileSync(path30.resolve(parsed.tokenFile), "utf8").trim();
16657
+ const credential = fs25.readFileSync(path31.resolve(parsed.tokenFile), "utf8").trim();
16587
16658
  if (!credential) {
16588
16659
  showError(`--token-file ${parsed.tokenFile} is empty.`);
16589
16660
  process.exit(1);
@@ -17102,7 +17173,7 @@ function cleanupAttachmentTempFiles() {
17102
17173
  function saveFilesTemp(files) {
17103
17174
  return files.filter(({ base64 }) => base64 && base64.length > 0).map(({ filename, base64 }) => {
17104
17175
  const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
17105
- const tmpPath = path34.join(os23.tmpdir(), `codeam-${(0, import_crypto3.randomUUID)()}-${safeName}`);
17176
+ const tmpPath = path35.join(os24.tmpdir(), `codeam-${(0, import_crypto3.randomUUID)()}-${safeName}`);
17106
17177
  fs29.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
17107
17178
  pendingAttachmentFiles.add(tmpPath);
17108
17179
  return tmpPath;
@@ -18049,8 +18120,8 @@ async function dispatchCommand(ctx, cmd) {
18049
18120
  // src/services/file-watcher.service.ts
18050
18121
  var import_child_process13 = require("child_process");
18051
18122
  var fs30 = __toESM(require("fs"));
18052
- var os24 = __toESM(require("os"));
18053
- var path35 = __toESM(require("path"));
18123
+ var os25 = __toESM(require("os"));
18124
+ var path36 = __toESM(require("path"));
18054
18125
  var import_ignore = __toESM(require("ignore"));
18055
18126
 
18056
18127
  // src/services/file-watcher/diff-parser.ts
@@ -18209,10 +18280,10 @@ var WINDOWS_LEGACY_JUNCTIONS = [
18209
18280
  /[\\/]Start Menu([\\/]|$)/i,
18210
18281
  /[\\/]Templates([\\/]|$)/i
18211
18282
  ];
18212
- function isUnsafeWindowsWatchRoot(dir, homedir20) {
18283
+ function isUnsafeWindowsWatchRoot(dir, homedir21) {
18213
18284
  const norm = (p2) => p2.replace(/\//g, "\\").replace(/\\+$/, "").toLowerCase();
18214
18285
  const cwd = norm(dir);
18215
- const home = norm(homedir20);
18286
+ const home = norm(homedir21);
18216
18287
  if (cwd === home) return true;
18217
18288
  if (/^[a-z]:$/.test(cwd)) return true;
18218
18289
  const sysRoots = [
@@ -18242,18 +18313,18 @@ var _findGitRootSeam = {
18242
18313
  resolve: _defaultFindGitRoot
18243
18314
  };
18244
18315
  function _defaultFindGitRoot(startDir) {
18245
- let dir = path35.resolve(startDir);
18316
+ let dir = path36.resolve(startDir);
18246
18317
  const seen = /* @__PURE__ */ new Set();
18247
18318
  for (let i = 0; i < 256; i++) {
18248
18319
  if (seen.has(dir)) return null;
18249
18320
  seen.add(dir);
18250
18321
  try {
18251
- const gitPath = path35.join(dir, ".git");
18322
+ const gitPath = path36.join(dir, ".git");
18252
18323
  const stat3 = fs30.statSync(gitPath, { throwIfNoEntry: false });
18253
18324
  if (stat3 && (stat3.isDirectory() || stat3.isFile())) return dir;
18254
18325
  } catch {
18255
18326
  }
18256
- const parent = path35.dirname(dir);
18327
+ const parent = path36.dirname(dir);
18257
18328
  if (parent === dir) return null;
18258
18329
  dir = parent;
18259
18330
  }
@@ -18311,7 +18382,7 @@ var FileWatcherService = class {
18311
18382
  throw new Error("FileWatcherService has already been stopped \u2014 re-instantiate to restart.");
18312
18383
  }
18313
18384
  const isWin = process.platform === "win32";
18314
- if (isWin && isUnsafeWindowsWatchRoot(this.opts.workingDir, os24.homedir())) {
18385
+ if (isWin && isUnsafeWindowsWatchRoot(this.opts.workingDir, os25.homedir())) {
18315
18386
  log.warn(
18316
18387
  "fileWatcher",
18317
18388
  `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.`
@@ -18498,7 +18569,7 @@ var FileWatcherService = class {
18498
18569
  }
18499
18570
  async emitForFile(absPath, changeType) {
18500
18571
  if (this.stopped) return;
18501
- const fileDir = path35.dirname(absPath);
18572
+ const fileDir = path36.dirname(absPath);
18502
18573
  let gitRoot = this.gitRootByDir.get(fileDir);
18503
18574
  if (gitRoot === void 0) {
18504
18575
  gitRoot = findGitRoot2(fileDir);
@@ -18511,19 +18582,19 @@ var FileWatcherService = class {
18511
18582
  );
18512
18583
  return;
18513
18584
  }
18514
- const relPathInRepo = path35.relative(gitRoot, absPath);
18585
+ const relPathInRepo = path36.relative(gitRoot, absPath);
18515
18586
  if (!relPathInRepo || relPathInRepo.startsWith("..")) return;
18516
18587
  const matcher = this.getGitIgnoreMatcher(gitRoot);
18517
18588
  if (matcher && matcher.ignores(relPathInRepo)) {
18518
18589
  log.trace(
18519
18590
  "fileWatcher",
18520
- `${relPathInRepo} ignored by ${path35.basename(gitRoot)}/.gitignore \u2014 suppressing emit`
18591
+ `${relPathInRepo} ignored by ${path36.basename(gitRoot)}/.gitignore \u2014 suppressing emit`
18521
18592
  );
18522
18593
  return;
18523
18594
  }
18524
18595
  this.opts.onRepoDirty?.(gitRoot);
18525
- const repoPath = path35.relative(this.opts.workingDir, gitRoot);
18526
- const repoName = path35.basename(gitRoot);
18596
+ const repoPath = path36.relative(this.opts.workingDir, gitRoot);
18597
+ const repoName = path36.basename(gitRoot);
18527
18598
  let diffText = "";
18528
18599
  let fileStatus = "modified";
18529
18600
  if (changeType === "unlink") {
@@ -18707,16 +18778,16 @@ var FileWatcherService = class {
18707
18778
  );
18708
18779
  if (gitignoreEntry) {
18709
18780
  try {
18710
- const body = fs30.readFileSync(path35.join(dir, ".gitignore"), "utf8");
18711
- const rel = path35.relative(repoRoot, dir).replace(/\\/g, "/");
18781
+ const body = fs30.readFileSync(path36.join(dir, ".gitignore"), "utf8");
18782
+ const rel = path36.relative(repoRoot, dir).replace(/\\/g, "/");
18712
18783
  const prefixed = body.split(/\r?\n/).map((line) => {
18713
18784
  const trimmed = line.trim();
18714
18785
  if (!trimmed || trimmed.startsWith("#")) return line;
18715
18786
  if (!rel) return line;
18716
18787
  if (trimmed.startsWith("!")) {
18717
- return "!" + path35.posix.join(rel, trimmed.slice(1));
18788
+ return "!" + path36.posix.join(rel, trimmed.slice(1));
18718
18789
  }
18719
- return path35.posix.join(rel, trimmed);
18790
+ return path36.posix.join(rel, trimmed);
18720
18791
  }).join("\n");
18721
18792
  matcher.add(prefixed);
18722
18793
  } catch {
@@ -18725,7 +18796,7 @@ var FileWatcherService = class {
18725
18796
  for (const entry of entries) {
18726
18797
  if (!entry.isDirectory()) continue;
18727
18798
  if (entry.name === ".git") continue;
18728
- const childAbs = path35.join(dir, entry.name);
18799
+ const childAbs = path36.join(dir, entry.name);
18729
18800
  if (isIgnoredFilePath(childAbs)) continue;
18730
18801
  this.collectGitignoreFiles(repoRoot, childAbs, matcher);
18731
18802
  }
@@ -18895,7 +18966,7 @@ var import_crypto4 = require("crypto");
18895
18966
 
18896
18967
  // src/services/turn-files/git-changeset.ts
18897
18968
  var import_child_process14 = require("child_process");
18898
- var path36 = __toESM(require("path"));
18969
+ var path37 = __toESM(require("path"));
18899
18970
  async function collectRepoChangeset(opts) {
18900
18971
  const status2 = await runGit3(opts.repoRoot, ["status", "--porcelain=v1", "-z"]);
18901
18972
  if (status2 === null) return null;
@@ -19025,8 +19096,8 @@ async function discoverRepos(workingDir, maxDepth = 4) {
19025
19096
  if (hasGit) {
19026
19097
  out2.push({
19027
19098
  repoRoot: dir,
19028
- repoPath: path36.relative(workingDir, dir),
19029
- repoName: path36.basename(dir)
19099
+ repoPath: path37.relative(workingDir, dir),
19100
+ repoName: path37.basename(dir)
19030
19101
  });
19031
19102
  return;
19032
19103
  }
@@ -19034,14 +19105,14 @@ async function discoverRepos(workingDir, maxDepth = 4) {
19034
19105
  if (!entry.isDirectory) continue;
19035
19106
  if (entry.name === "node_modules") continue;
19036
19107
  if (entry.name === "dist" || entry.name === "build") continue;
19037
- await walk(path36.join(dir, entry.name), depth + 1);
19108
+ await walk(path37.join(dir, entry.name), depth + 1);
19038
19109
  }
19039
19110
  }
19040
19111
  }
19041
19112
 
19042
19113
  // src/services/turn-files/files-outbox.ts
19043
19114
  var fs31 = __toESM(require("fs/promises"));
19044
- var path37 = __toESM(require("path"));
19115
+ var path38 = __toESM(require("path"));
19045
19116
  var import_os7 = require("os");
19046
19117
  var HOME_OUTBOX_DIR = ".codeam/outbox";
19047
19118
  var MAX_AGE_MS = 24 * 60 * 60 * 1e3;
@@ -19074,15 +19145,15 @@ var FilesOutbox = class {
19074
19145
  backoffIndex = 0;
19075
19146
  stopped = false;
19076
19147
  constructor(opts) {
19077
- const base = opts.baseDir ?? path37.join(homeDir(), HOME_OUTBOX_DIR);
19078
- this.filePath = path37.join(base, `${opts.sessionId}.jsonl`);
19148
+ const base = opts.baseDir ?? path38.join(homeDir(), HOME_OUTBOX_DIR);
19149
+ this.filePath = path38.join(base, `${opts.sessionId}.jsonl`);
19079
19150
  this.post = opts.post;
19080
19151
  this.autoSchedule = opts.autoSchedule !== false;
19081
19152
  }
19082
19153
  /** Persist the entry to disk and trigger a flush. Returns once the
19083
19154
  * line is durable on disk (not once the POST succeeds). */
19084
19155
  async enqueue(entry) {
19085
- await fs31.mkdir(path37.dirname(this.filePath), { recursive: true });
19156
+ await fs31.mkdir(path38.dirname(this.filePath), { recursive: true });
19086
19157
  await fs31.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
19087
19158
  this.backoffIndex = 0;
19088
19159
  if (this.autoSchedule) this.scheduleFlush(0);
@@ -20937,8 +21008,8 @@ var OutputService = class _OutputService {
20937
21008
 
20938
21009
  // src/services/history.service.ts
20939
21010
  var fs32 = __toESM(require("fs"));
20940
- var path38 = __toESM(require("path"));
20941
- var os25 = __toESM(require("os"));
21011
+ var path39 = __toESM(require("path"));
21012
+ var os26 = __toESM(require("os"));
20942
21013
  var https7 = __toESM(require("https"));
20943
21014
  var http7 = __toESM(require("http"));
20944
21015
  var import_zod2 = require("zod");
@@ -21100,7 +21171,7 @@ var HistoryService = class _HistoryService {
21100
21171
  return this._quotaPercent === null || Date.now() - this._quotaFetchedAt > ttlMs;
21101
21172
  }
21102
21173
  get projectDir() {
21103
- return this.runtime.resolveHistoryDir(this.cwd) ?? path38.join(os25.homedir(), ".claude", "projects", encodeCwd(this.cwd));
21174
+ return this.runtime.resolveHistoryDir(this.cwd) ?? path39.join(os26.homedir(), ".claude", "projects", encodeCwd(this.cwd));
21104
21175
  }
21105
21176
  /** Set the current Claude conversation ID (extracted from /cost command or session start) */
21106
21177
  setCurrentConversationId(id) {
@@ -21112,7 +21183,7 @@ var HistoryService = class _HistoryService {
21112
21183
  /** Return the current message count in the active conversation. */
21113
21184
  getCurrentMessageCount() {
21114
21185
  if (!this.currentConversationId) return 0;
21115
- const filePath = path38.join(this.projectDir, `${this.currentConversationId}.jsonl`);
21186
+ const filePath = path39.join(this.projectDir, `${this.currentConversationId}.jsonl`);
21116
21187
  return parseJsonl(filePath).length;
21117
21188
  }
21118
21189
  /**
@@ -21123,7 +21194,7 @@ var HistoryService = class _HistoryService {
21123
21194
  const deadline = Date.now() + timeoutMs;
21124
21195
  while (Date.now() < deadline) {
21125
21196
  if (!this.currentConversationId) return null;
21126
- const filePath = path38.join(this.projectDir, `${this.currentConversationId}.jsonl`);
21197
+ const filePath = path39.join(this.projectDir, `${this.currentConversationId}.jsonl`);
21127
21198
  const messages = parseJsonl(filePath);
21128
21199
  if (messages.length > previousCount) {
21129
21200
  for (let i = messages.length - 1; i >= previousCount; i--) {
@@ -21151,14 +21222,14 @@ var HistoryService = class _HistoryService {
21151
21222
  try {
21152
21223
  const files = fs32.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
21153
21224
  try {
21154
- const stat3 = fs32.statSync(path38.join(dir, e.name));
21225
+ const stat3 = fs32.statSync(path39.join(dir, e.name));
21155
21226
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
21156
21227
  } catch {
21157
21228
  return { name: e.name, mtime: 0, birthtime: 0 };
21158
21229
  }
21159
21230
  }).filter((f) => f.birthtime >= cutoff).sort((a, b) => b.mtime - a.mtime);
21160
21231
  if (files.length > 0) {
21161
- this.currentConversationId = path38.basename(files[0].name, ".jsonl");
21232
+ this.currentConversationId = path39.basename(files[0].name, ".jsonl");
21162
21233
  }
21163
21234
  } catch {
21164
21235
  }
@@ -21198,7 +21269,7 @@ var HistoryService = class _HistoryService {
21198
21269
  }
21199
21270
  const files = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
21200
21271
  try {
21201
- const stat3 = fs32.statSync(path38.join(dir, e.name));
21272
+ const stat3 = fs32.statSync(path39.join(dir, e.name));
21202
21273
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
21203
21274
  } catch {
21204
21275
  return { name: e.name, mtime: 0, birthtime: 0 };
@@ -21207,7 +21278,7 @@ var HistoryService = class _HistoryService {
21207
21278
  if (files.length === 0) return null;
21208
21279
  const targetFile = this.currentConversationId ? `${this.currentConversationId}.jsonl` : files[0].name;
21209
21280
  if (!files.some((f) => f.name === targetFile)) return null;
21210
- return this.extractUsageFromFile(path38.join(dir, targetFile));
21281
+ return this.extractUsageFromFile(path39.join(dir, targetFile));
21211
21282
  }
21212
21283
  extractUsageFromFile(filePath) {
21213
21284
  let raw;
@@ -21259,7 +21330,7 @@ var HistoryService = class _HistoryService {
21259
21330
  try {
21260
21331
  files = fs32.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
21261
21332
  try {
21262
- return fs32.statSync(path38.join(projectDir, f)).mtimeMs >= monthStartMs;
21333
+ return fs32.statSync(path39.join(projectDir, f)).mtimeMs >= monthStartMs;
21263
21334
  } catch {
21264
21335
  return false;
21265
21336
  }
@@ -21270,7 +21341,7 @@ var HistoryService = class _HistoryService {
21270
21341
  for (const file of files) {
21271
21342
  let raw;
21272
21343
  try {
21273
- raw = fs32.readFileSync(path38.join(projectDir, file), "utf8");
21344
+ raw = fs32.readFileSync(path39.join(projectDir, file), "utf8");
21274
21345
  } catch {
21275
21346
  continue;
21276
21347
  }
@@ -21334,7 +21405,7 @@ var HistoryService = class _HistoryService {
21334
21405
  * showing an empty conversation.
21335
21406
  */
21336
21407
  async loadConversation(sessionId) {
21337
- const filePath = path38.join(this.projectDir, `${sessionId}.jsonl`);
21408
+ const filePath = path39.join(this.projectDir, `${sessionId}.jsonl`);
21338
21409
  const messages = parseJsonl(filePath);
21339
21410
  if (messages.length === 0) return;
21340
21411
  const totalBatches = Math.ceil(messages.length / CONVERSATION_BATCH_SIZE);
@@ -21388,7 +21459,7 @@ var HistoryService = class _HistoryService {
21388
21459
  if (!this.currentConversationId) return 0;
21389
21460
  }
21390
21461
  const sessionId = this.currentConversationId;
21391
- const filePath = path38.join(this.projectDir, `${sessionId}.jsonl`);
21462
+ const filePath = path39.join(this.projectDir, `${sessionId}.jsonl`);
21392
21463
  const messages = parseJsonl(filePath);
21393
21464
  if (messages.length === 0) return 0;
21394
21465
  const marker = this.lastUploadedUuid.get(sessionId);
@@ -22145,9 +22216,19 @@ async function pair(args2 = []) {
22145
22216
  const spin = dist_exports.spinner();
22146
22217
  spin.start("Requesting pairing code...");
22147
22218
  const result = await requestCode(pluginId);
22148
- if (!result) {
22219
+ if (!result.ok) {
22149
22220
  spin.stop("Failed");
22150
- showError("Could not reach the server. Check your connection and try again.");
22221
+ if (result.reason === "rate-limited") {
22222
+ showError(
22223
+ `Server is rate-limiting this request (HTTP 429). Retry in ${result.retryAfterSeconds}s.`
22224
+ );
22225
+ } else if (result.reason === "timeout") {
22226
+ showError("Server took too long to respond. Check your connection and try again.");
22227
+ } else if (result.reason === "http") {
22228
+ showError(`Server returned HTTP ${result.status}. Try again later.`);
22229
+ } else {
22230
+ showError("Could not reach the server. Check your connection and try again.");
22231
+ }
22151
22232
  process.exit(1);
22152
22233
  }
22153
22234
  spin.stop("Got pairing code");
@@ -22276,7 +22357,7 @@ async function autoLinkAfterPair(opts) {
22276
22357
 
22277
22358
  // src/commands/pair-auto.ts
22278
22359
  var fs33 = __toESM(require("fs"));
22279
- var os26 = __toESM(require("os"));
22360
+ var os27 = __toESM(require("os"));
22280
22361
  var import_crypto7 = require("crypto");
22281
22362
 
22282
22363
  // src/commands/start-infra-only.ts
@@ -22444,12 +22525,12 @@ function readTokenFromArgs(args2) {
22444
22525
  }
22445
22526
  const fileFlag = args2.find((a) => a.startsWith("--token-file="));
22446
22527
  if (fileFlag) {
22447
- const path45 = fileFlag.slice("--token-file=".length);
22528
+ const path46 = fileFlag.slice("--token-file=".length);
22448
22529
  try {
22449
- const content = fs33.readFileSync(path45, "utf8").trim();
22450
- if (content.length === 0) fail(`--token-file ${path45} is empty`);
22530
+ const content = fs33.readFileSync(path46, "utf8").trim();
22531
+ if (content.length === 0) fail(`--token-file ${path46} is empty`);
22451
22532
  try {
22452
- fs33.unlinkSync(path45);
22533
+ fs33.unlinkSync(path46);
22453
22534
  } catch {
22454
22535
  }
22455
22536
  return content;
@@ -22475,7 +22556,7 @@ async function claimOnce(token, pluginId) {
22475
22556
  pluginId,
22476
22557
  ideName: "codeam-cli (codespace)",
22477
22558
  ideVersion: process.env.npm_package_version ?? "unknown",
22478
- hostname: os26.hostname(),
22559
+ hostname: os27.hostname(),
22479
22560
  codespaceName: process.env.CODESPACE_NAME ?? "",
22480
22561
  // Current git branch of the codespace's working directory, so the
22481
22562
  // backend can populate `PairedSession.branch` for the codespace pair.
@@ -22715,7 +22796,7 @@ var import_picocolors10 = __toESM(require("picocolors"));
22715
22796
  var import_child_process16 = require("child_process");
22716
22797
  var import_util4 = require("util");
22717
22798
  var import_picocolors8 = __toESM(require("picocolors"));
22718
- var path39 = __toESM(require("path"));
22799
+ var path40 = __toESM(require("path"));
22719
22800
  var execFileP5 = (0, import_util4.promisify)(import_child_process16.execFile);
22720
22801
  var MAX_BUFFER = 8 * 1024 * 1024;
22721
22802
  function resetStdinForChild() {
@@ -23204,7 +23285,7 @@ var GitHubCodespacesProvider = class {
23204
23285
  });
23205
23286
  }
23206
23287
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
23207
- const remoteDir = path39.posix.dirname(remotePath);
23288
+ const remoteDir = path40.posix.dirname(remotePath);
23208
23289
  const parts = [
23209
23290
  `mkdir -p ${shellQuote(remoteDir)}`,
23210
23291
  `cat > ${shellQuote(remotePath)}`
@@ -23274,7 +23355,7 @@ function shellQuote(s) {
23274
23355
  // src/services/providers/gitpod.ts
23275
23356
  var import_child_process17 = require("child_process");
23276
23357
  var import_util5 = require("util");
23277
- var path40 = __toESM(require("path"));
23358
+ var path41 = __toESM(require("path"));
23278
23359
  var import_picocolors9 = __toESM(require("picocolors"));
23279
23360
  var execFileP6 = (0, import_util5.promisify)(import_child_process17.execFile);
23280
23361
  var MAX_BUFFER2 = 8 * 1024 * 1024;
@@ -23514,7 +23595,7 @@ var GitpodProvider = class {
23514
23595
  });
23515
23596
  }
23516
23597
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
23517
- const remoteDir = path40.posix.dirname(remotePath);
23598
+ const remoteDir = path41.posix.dirname(remotePath);
23518
23599
  const parts = [
23519
23600
  `mkdir -p ${shellQuote2(remoteDir)}`,
23520
23601
  `cat > ${shellQuote2(remotePath)}`
@@ -23550,7 +23631,7 @@ function shellQuote2(s) {
23550
23631
  // src/services/providers/gitlab-workspaces.ts
23551
23632
  var import_child_process18 = require("child_process");
23552
23633
  var import_util6 = require("util");
23553
- var path41 = __toESM(require("path"));
23634
+ var path42 = __toESM(require("path"));
23554
23635
  var execFileP7 = (0, import_util6.promisify)(import_child_process18.execFile);
23555
23636
  var MAX_BUFFER3 = 8 * 1024 * 1024;
23556
23637
  var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
@@ -23810,7 +23891,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
23810
23891
  }
23811
23892
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
23812
23893
  const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
23813
- const remoteDir = path41.posix.dirname(remotePath);
23894
+ const remoteDir = path42.posix.dirname(remotePath);
23814
23895
  const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
23815
23896
  if (options.mode != null) {
23816
23897
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
@@ -23878,7 +23959,7 @@ function shellQuote3(s) {
23878
23959
  // src/services/providers/railway.ts
23879
23960
  var import_child_process19 = require("child_process");
23880
23961
  var import_util7 = require("util");
23881
- var path42 = __toESM(require("path"));
23962
+ var path43 = __toESM(require("path"));
23882
23963
  var execFileP8 = (0, import_util7.promisify)(import_child_process19.execFile);
23883
23964
  var MAX_BUFFER4 = 8 * 1024 * 1024;
23884
23965
  function resetStdinForChild4() {
@@ -24114,7 +24195,7 @@ var RailwayProvider = class {
24114
24195
  if (!projectId || !serviceId) {
24115
24196
  throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
24116
24197
  }
24117
- const remoteDir = path42.posix.dirname(remotePath);
24198
+ const remoteDir = path43.posix.dirname(remotePath);
24118
24199
  const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
24119
24200
  if (options.mode != null) {
24120
24201
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
@@ -24658,7 +24739,7 @@ var import_node_dns = require("dns");
24658
24739
  var import_node_util4 = require("util");
24659
24740
  var import_node_crypto8 = require("crypto");
24660
24741
  var fs34 = __toESM(require("fs"));
24661
- var path43 = __toESM(require("path"));
24742
+ var path44 = __toESM(require("path"));
24662
24743
  var import_picocolors12 = __toESM(require("picocolors"));
24663
24744
  var dnsResolveP = (0, import_node_util4.promisify)(import_node_dns.resolve);
24664
24745
  async function checkDns(apiBase) {
@@ -24714,10 +24795,10 @@ async function checkHealth(apiBase) {
24714
24795
  }
24715
24796
  }
24716
24797
  function checkConfigDir() {
24717
- const dir = path43.join(require("os").homedir(), ".codeam");
24798
+ const dir = path44.join(require("os").homedir(), ".codeam");
24718
24799
  try {
24719
24800
  fs34.mkdirSync(dir, { recursive: true, mode: 448 });
24720
- const probe = path43.join(dir, ".doctor-probe");
24801
+ const probe = path44.join(dir, ".doctor-probe");
24721
24802
  fs34.writeFileSync(probe, "ok", { mode: 384 });
24722
24803
  const read = fs34.readFileSync(probe, "utf8");
24723
24804
  fs34.unlinkSync(probe);
@@ -24760,9 +24841,9 @@ function checkSessions() {
24760
24841
  }
24761
24842
  }
24762
24843
  function checkAgentBinaries() {
24763
- const os28 = createOsStrategy();
24844
+ const os29 = createOsStrategy();
24764
24845
  return getEnabledAgents().map((meta) => {
24765
- const found = os28.findInPath(meta.binaryName);
24846
+ const found = os29.findInPath(meta.binaryName);
24766
24847
  return {
24767
24848
  id: `agent-${meta.id}`,
24768
24849
  label: `Agent binary: ${meta.displayName} (${meta.binaryName})`,
@@ -24784,7 +24865,7 @@ function checkNodePty() {
24784
24865
  detail: "not required on this platform"
24785
24866
  };
24786
24867
  }
24787
- const vendoredPath = path43.join(__dirname, "vendor", "node-pty");
24868
+ const vendoredPath = path44.join(__dirname, "vendor", "node-pty");
24788
24869
  for (const target of [vendoredPath, "node-pty"]) {
24789
24870
  try {
24790
24871
  require(target);
@@ -24826,7 +24907,7 @@ function checkChokidar() {
24826
24907
  }
24827
24908
  async function doctor(args2 = []) {
24828
24909
  const json = args2.includes("--json");
24829
- const cliVersion = true ? "2.30.0" : "0.0.0-dev";
24910
+ const cliVersion = true ? "2.32.0" : "0.0.0-dev";
24830
24911
  const apiBase = resolveApiBaseUrl();
24831
24912
  const diagnosticId = (0, import_node_crypto8.randomUUID)();
24832
24913
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -25025,7 +25106,7 @@ async function completion(args2) {
25025
25106
  // src/commands/version.ts
25026
25107
  var import_picocolors13 = __toESM(require("picocolors"));
25027
25108
  function version2() {
25028
- const v = true ? "2.30.0" : "unknown";
25109
+ const v = true ? "2.32.0" : "unknown";
25029
25110
  console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
25030
25111
  }
25031
25112
 
@@ -25154,8 +25235,8 @@ var _subcommandHelpKeys = Object.keys(HELPS);
25154
25235
 
25155
25236
  // src/lib/updateNotifier.ts
25156
25237
  var fs35 = __toESM(require("fs"));
25157
- var os27 = __toESM(require("os"));
25158
- var path44 = __toESM(require("path"));
25238
+ var os28 = __toESM(require("os"));
25239
+ var path45 = __toESM(require("path"));
25159
25240
  var https8 = __toESM(require("https"));
25160
25241
  var import_node_child_process12 = require("child_process");
25161
25242
  var import_picocolors16 = __toESM(require("picocolors"));
@@ -25164,8 +25245,8 @@ var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
25164
25245
  var TTL_MS = 24 * 60 * 60 * 1e3;
25165
25246
  var REQUEST_TIMEOUT_MS = 1500;
25166
25247
  function cachePath() {
25167
- const dir = path44.join(os27.homedir(), ".codeam");
25168
- return path44.join(dir, "update-check.json");
25248
+ const dir = path45.join(os28.homedir(), ".codeam");
25249
+ return path45.join(dir, "update-check.json");
25169
25250
  }
25170
25251
  function readCache() {
25171
25252
  try {
@@ -25180,7 +25261,7 @@ function readCache() {
25180
25261
  function writeCache(cache) {
25181
25262
  try {
25182
25263
  const file = cachePath();
25183
- fs35.mkdirSync(path44.dirname(file), { recursive: true });
25264
+ fs35.mkdirSync(path45.dirname(file), { recursive: true });
25184
25265
  const tmp = `${file}.${process.pid}.tmp`;
25185
25266
  fs35.writeFileSync(tmp, JSON.stringify(cache));
25186
25267
  fs35.renameSync(tmp, file);
@@ -25257,7 +25338,7 @@ function isLinkedInstall() {
25257
25338
  timeout: 2e3
25258
25339
  }).trim();
25259
25340
  if (!root) return false;
25260
- const pkgPath = path44.join(root, PKG_NAME);
25341
+ const pkgPath = path45.join(root, PKG_NAME);
25261
25342
  return fs35.lstatSync(pkgPath).isSymbolicLink();
25262
25343
  } catch {
25263
25344
  return false;
@@ -25311,7 +25392,7 @@ function checkForUpdates() {
25311
25392
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
25312
25393
  if (process.env.CI) return;
25313
25394
  if (!process.stdout.isTTY) return;
25314
- const current = true ? "2.30.0" : null;
25395
+ const current = true ? "2.32.0" : null;
25315
25396
  if (!current) return;
25316
25397
  const cache = readCache();
25317
25398
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.30.0",
3
+ "version": "2.32.0",
4
4
  "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 — async. The terminal companion for CodeAgent Mobile.",
5
5
  "type": "commonjs",
6
6
  "main": "dist/index.js",