codeam-cli 2.20.0 → 2.20.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/index.js +288 -179
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -441,7 +441,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
441
441
  // package.json
442
442
  var package_default = {
443
443
  name: "codeam-cli",
444
- version: "2.20.0",
444
+ version: "2.20.2",
445
445
  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.",
446
446
  type: "commonjs",
447
447
  main: "dist/index.js",
@@ -735,7 +735,7 @@ async function postLinkCredential(input) {
735
735
  }
736
736
  }
737
737
  async function _postJsonAuthed(url, body, pluginAuthToken) {
738
- return new Promise((resolve3, reject) => {
738
+ return new Promise((resolve4, reject) => {
739
739
  const data = JSON.stringify(body);
740
740
  const u2 = new URL(url);
741
741
  const transport = u2.protocol === "https:" ? https : http;
@@ -767,9 +767,9 @@ async function _postJsonAuthed(url, body, pluginAuthToken) {
767
767
  return;
768
768
  }
769
769
  try {
770
- resolve3(JSON.parse(responseBody));
770
+ resolve4(JSON.parse(responseBody));
771
771
  } catch {
772
- resolve3(null);
772
+ resolve4(null);
773
773
  }
774
774
  });
775
775
  }
@@ -784,7 +784,7 @@ async function _postJsonAuthed(url, body, pluginAuthToken) {
784
784
  });
785
785
  }
786
786
  async function _postJson(url, body) {
787
- return new Promise((resolve3, reject) => {
787
+ return new Promise((resolve4, reject) => {
788
788
  const data = JSON.stringify(body);
789
789
  const u2 = new URL(url);
790
790
  const transport = u2.protocol === "https:" ? https : http;
@@ -813,9 +813,9 @@ async function _postJson(url, body) {
813
813
  return;
814
814
  }
815
815
  try {
816
- resolve3(JSON.parse(body2));
816
+ resolve4(JSON.parse(body2));
817
817
  } catch {
818
- resolve3(null);
818
+ resolve4(null);
819
819
  }
820
820
  });
821
821
  }
@@ -830,7 +830,7 @@ async function _postJson(url, body) {
830
830
  });
831
831
  }
832
832
  async function _getJson(url) {
833
- return new Promise((resolve3, reject) => {
833
+ return new Promise((resolve4, reject) => {
834
834
  const u2 = new URL(url);
835
835
  const transport = u2.protocol === "https:" ? https : http;
836
836
  const req = transport.request(
@@ -854,9 +854,9 @@ async function _getJson(url) {
854
854
  return;
855
855
  }
856
856
  try {
857
- resolve3(JSON.parse(body));
857
+ resolve4(JSON.parse(body));
858
858
  } catch {
859
- resolve3(null);
859
+ resolve4(null);
860
860
  }
861
861
  });
862
862
  }
@@ -3508,14 +3508,14 @@ async function addSourceContext(frames) {
3508
3508
  return frames;
3509
3509
  }
3510
3510
  function getContextLinesFromFile(path37, ranges, output) {
3511
- return new Promise((resolve3) => {
3511
+ return new Promise((resolve4) => {
3512
3512
  const stream = (0, import_node_fs.createReadStream)(path37);
3513
3513
  const lineReaded = (0, import_node_readline.createInterface)({
3514
3514
  input: stream
3515
3515
  });
3516
3516
  function destroyStreamAndResolve() {
3517
3517
  stream.destroy();
3518
- resolve3();
3518
+ resolve4();
3519
3519
  }
3520
3520
  let lineNumber = 0;
3521
3521
  let currentRangeIndex = 0;
@@ -4802,9 +4802,9 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
4802
4802
  if (!waitUntil) return;
4803
4803
  if (this.disabled || this.optedOut) return;
4804
4804
  if (!this._waitUntilCycle) {
4805
- let resolve3;
4805
+ let resolve4;
4806
4806
  const promise = new Promise((r) => {
4807
- resolve3 = r;
4807
+ resolve4 = r;
4808
4808
  });
4809
4809
  try {
4810
4810
  waitUntil(promise);
@@ -4812,7 +4812,7 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
4812
4812
  return;
4813
4813
  }
4814
4814
  this._waitUntilCycle = {
4815
- resolve: resolve3,
4815
+ resolve: resolve4,
4816
4816
  startedAt: Date.now(),
4817
4817
  timer: void 0
4818
4818
  };
@@ -4836,12 +4836,12 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
4836
4836
  return cycle?.resolve;
4837
4837
  }
4838
4838
  async resolveWaitUntilFlush() {
4839
- const resolve3 = this._consumeWaitUntilCycle();
4839
+ const resolve4 = this._consumeWaitUntilCycle();
4840
4840
  try {
4841
4841
  await super.flush();
4842
4842
  } catch {
4843
4843
  } finally {
4844
- resolve3?.();
4844
+ resolve4?.();
4845
4845
  }
4846
4846
  }
4847
4847
  getPersistedProperty(key) {
@@ -4933,15 +4933,15 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
4933
4933
  async waitForLocalEvaluationReady(timeoutMs = THIRTY_SECONDS) {
4934
4934
  if (this.isLocalEvaluationReady()) return true;
4935
4935
  if (void 0 === this.featureFlagsPoller) return false;
4936
- return new Promise((resolve3) => {
4936
+ return new Promise((resolve4) => {
4937
4937
  const timeout = setTimeout(() => {
4938
4938
  cleanup();
4939
- resolve3(false);
4939
+ resolve4(false);
4940
4940
  }, timeoutMs);
4941
4941
  const cleanup = this._events.on("localEvaluationFlagsLoaded", (count) => {
4942
4942
  clearTimeout(timeout);
4943
4943
  cleanup();
4944
- resolve3(count > 0);
4944
+ resolve4(count > 0);
4945
4945
  });
4946
4946
  });
4947
4947
  }
@@ -5378,13 +5378,13 @@ var PostHogBackendClient = class extends PostHogCoreStateless {
5378
5378
  this.context?.enter(data, options);
5379
5379
  }
5380
5380
  async _shutdown(shutdownTimeoutMs) {
5381
- const resolve3 = this._consumeWaitUntilCycle();
5381
+ const resolve4 = this._consumeWaitUntilCycle();
5382
5382
  await this.featureFlagsPoller?.stopPoller(shutdownTimeoutMs);
5383
5383
  this.errorTracking.shutdown();
5384
5384
  try {
5385
5385
  return await super._shutdown(shutdownTimeoutMs);
5386
5386
  } finally {
5387
- resolve3?.();
5387
+ resolve4?.();
5388
5388
  }
5389
5389
  }
5390
5390
  async _requestRemoteConfigPayload(flagKey) {
@@ -5740,7 +5740,7 @@ function readAnonId() {
5740
5740
  }
5741
5741
  function superProperties() {
5742
5742
  return {
5743
- cliVersion: true ? "2.20.0" : "0.0.0-dev",
5743
+ cliVersion: true ? "2.20.2" : "0.0.0-dev",
5744
5744
  nodeVersion: process.version,
5745
5745
  platform: process.platform,
5746
5746
  arch: process.arch,
@@ -8874,15 +8874,15 @@ function runInstaller() {
8874
8874
  "-Command",
8875
8875
  "irm https://claude.ai/install.ps1 | iex"
8876
8876
  ] : ["-c", "curl -fsSL https://claude.ai/install.sh | bash"];
8877
- return new Promise((resolve3) => {
8877
+ return new Promise((resolve4) => {
8878
8878
  const proc = (0, import_child_process4.spawn)(cmd, args2, { stdio: "inherit" });
8879
8879
  proc.on("error", (err) => {
8880
8880
  console.error(`
8881
8881
  \u2717 Installer failed to launch: ${err.message}`);
8882
- resolve3(false);
8882
+ resolve4(false);
8883
8883
  });
8884
8884
  proc.on("exit", (code) => {
8885
- resolve3(code === 0);
8885
+ resolve4(code === 0);
8886
8886
  });
8887
8887
  });
8888
8888
  }
@@ -9045,17 +9045,17 @@ function parseUsageOutput(raw) {
9045
9045
  return { percent, resetAt };
9046
9046
  }
9047
9047
  async function fetchClaudeQuota() {
9048
- return new Promise((resolve3) => {
9048
+ return new Promise((resolve4) => {
9049
9049
  const claudeCmd = findInPath("claude") ? "claude" : "claude-code";
9050
9050
  if (!claudeCmd) {
9051
- resolve3(null);
9051
+ resolve4(null);
9052
9052
  return;
9053
9053
  }
9054
9054
  const helperPath = path11.join(os10.tmpdir(), "codeam-quota-helper.py");
9055
9055
  fs8.writeFileSync(helperPath, HELPER_SCRIPT, { mode: 420 });
9056
9056
  const python = findInPath("python3") ?? findInPath("python");
9057
9057
  if (!python) {
9058
- resolve3(null);
9058
+ resolve4(null);
9059
9059
  return;
9060
9060
  }
9061
9061
  const proc = (0, import_child_process5.spawn)(python, [helperPath, claudeCmd, "--tools", ""], {
@@ -9082,13 +9082,13 @@ async function fetchClaudeQuota() {
9082
9082
  fs8.unlinkSync(helperPath);
9083
9083
  } catch {
9084
9084
  }
9085
- resolve3(result);
9085
+ resolve4(result);
9086
9086
  }, 5e3);
9087
9087
  }, 8e3);
9088
9088
  setTimeout(() => {
9089
9089
  if (!resolved) {
9090
9090
  resolved = true;
9091
- resolve3(null);
9091
+ resolve4(null);
9092
9092
  }
9093
9093
  try {
9094
9094
  proc.kill();
@@ -9531,6 +9531,9 @@ var ClaudeRuntimeStrategy = class {
9531
9531
  detectInteractivePrompt(lines) {
9532
9532
  return detectSelector(lines) ?? detectListSelector(lines);
9533
9533
  }
9534
+ detectReadyPrompt(lines) {
9535
+ return lines.some((l) => /^\?\s.*shortcut/i.test(l.trim()));
9536
+ }
9534
9537
  credentialLocator() {
9535
9538
  return claudeCredentialLocator();
9536
9539
  }
@@ -10411,6 +10414,9 @@ var CodexRuntimeStrategy = class {
10411
10414
  detectInteractivePrompt(lines) {
10412
10415
  return detectCodexSelector(lines);
10413
10416
  }
10417
+ detectReadyPrompt(lines) {
10418
+ return lines.some((l) => /[│┃]\s*›/u.test(l));
10419
+ }
10414
10420
  credentialLocator() {
10415
10421
  return codexCredentialLocator();
10416
10422
  }
@@ -10422,12 +10428,12 @@ function resolveNpm(os26) {
10422
10428
  return os26.id === "win32" ? "npm.cmd" : "npm";
10423
10429
  }
10424
10430
  async function installCodexViaNpm(os26) {
10425
- return new Promise((resolve3, reject) => {
10431
+ return new Promise((resolve4, reject) => {
10426
10432
  const proc = (0, import_node_child_process4.spawn)(resolveNpm(os26), ["install", "-g", "@openai/codex"], {
10427
10433
  stdio: "inherit"
10428
10434
  });
10429
10435
  proc.on("close", (code) => {
10430
- if (code === 0) resolve3();
10436
+ if (code === 0) resolve4();
10431
10437
  else reject(new Error(`npm install -g @openai/codex exited ${code}`));
10432
10438
  });
10433
10439
  proc.on("error", (err) => {
@@ -10542,12 +10548,12 @@ async function ensureCoderabbitInstalled(os26) {
10542
10548
  return false;
10543
10549
  }
10544
10550
  console.log("\n CodeRabbit CLI not found \u2014 installing via the official script\u2026\n");
10545
- const ok = await new Promise((resolve3) => {
10551
+ const ok = await new Promise((resolve4) => {
10546
10552
  const proc = (0, import_node_child_process5.spawn)("sh", ["-c", `curl -fsSL ${INSTALL_URL} | sh`], {
10547
10553
  stdio: "inherit"
10548
10554
  });
10549
- proc.on("close", (code) => resolve3(code === 0));
10550
- proc.on("error", () => resolve3(false));
10555
+ proc.on("close", (code) => resolve4(code === 0));
10556
+ proc.on("error", () => resolve4(false));
10551
10557
  });
10552
10558
  if (!ok) return false;
10553
10559
  os26.augmentPath([`${os26.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
@@ -10666,7 +10672,7 @@ var CoderabbitRuntimeStrategy = class {
10666
10672
  }
10667
10673
  async runOneShot(input) {
10668
10674
  const launch = await this.prepareInvocation(input);
10669
- return new Promise((resolve3, reject) => {
10675
+ return new Promise((resolve4, reject) => {
10670
10676
  const stdoutBuf = [];
10671
10677
  const stderrBuf = [];
10672
10678
  const proc = (0, import_node_child_process7.spawn)(launch.cmd, launch.args, {
@@ -10677,7 +10683,7 @@ var CoderabbitRuntimeStrategy = class {
10677
10683
  proc.stderr?.on("data", (b) => stderrBuf.push(b));
10678
10684
  proc.on("error", (err) => reject(err));
10679
10685
  proc.on("close", (code) => {
10680
- resolve3(
10686
+ resolve4(
10681
10687
  this.parseOutput({
10682
10688
  exitCode: code ?? 0,
10683
10689
  stdout: Buffer.concat(stdoutBuf).toString("utf8"),
@@ -10858,6 +10864,9 @@ var CursorRuntimeStrategy = class {
10858
10864
  detectInteractivePrompt(lines) {
10859
10865
  return detectCursorSelector(lines);
10860
10866
  }
10867
+ detectReadyPrompt(lines) {
10868
+ return lines.some((l) => /[│┃]\s*[›>]\s/u.test(l));
10869
+ }
10861
10870
  credentialLocator() {
10862
10871
  return cursorCredentialLocator();
10863
10872
  }
@@ -11065,6 +11074,12 @@ var AiderRuntimeStrategy = class {
11065
11074
  detectInteractivePrompt(lines) {
11066
11075
  return detectAiderSelector(lines);
11067
11076
  }
11077
+ detectReadyPrompt(lines) {
11078
+ return lines.some((l) => {
11079
+ const t2 = l.replace(/\x1B\[[^@-~]*[@-~]/g, "").trim();
11080
+ return t2 === ">" || /^>\s*$/.test(t2) || /^\.\.\.\s*>\s*$/.test(t2);
11081
+ });
11082
+ }
11068
11083
  credentialLocator() {
11069
11084
  return aiderCredentialLocator();
11070
11085
  }
@@ -11201,14 +11216,14 @@ var ChunkEmitter = class {
11201
11216
  "chunkEmitter",
11202
11217
  `send type=${body.type ?? "(clear)"} bytes=${payload.length} done=${body.done === true}`
11203
11218
  );
11204
- return new Promise((resolve3) => {
11219
+ return new Promise((resolve4) => {
11205
11220
  const attempt = (attemptsLeft) => {
11206
11221
  _transport2.post(this.url, this.headers, payload).then(({ statusCode, body: resBody }) => {
11207
11222
  const tookMs = Date.now() - t0;
11208
11223
  if (statusCode === 410 || statusCode === 404 && /SESSION_NOT_FOUND|SESSION_GONE/.test(resBody)) {
11209
11224
  process.stderr.write("[codeam] session was deleted/disconnected \u2014 stopping output stream.\n");
11210
11225
  log.info("chunkEmitter", `dead status=${statusCode} took=${tookMs}ms`);
11211
- resolve3({ dead: true });
11226
+ resolve4({ dead: true });
11212
11227
  return;
11213
11228
  }
11214
11229
  if (statusCode >= 400) {
@@ -11218,7 +11233,7 @@ var ChunkEmitter = class {
11218
11233
  } else {
11219
11234
  log.info("chunkEmitter", `ok status=${statusCode} took=${tookMs}ms`);
11220
11235
  }
11221
- resolve3({ dead: false });
11236
+ resolve4({ dead: false });
11222
11237
  }).catch((err) => {
11223
11238
  log.warn(
11224
11239
  "chunkEmitter",
@@ -11229,7 +11244,7 @@ var ChunkEmitter = class {
11229
11244
  const delay = 200 * (maxRetries - attemptsLeft + 1);
11230
11245
  setTimeout(() => attempt(attemptsLeft - 1), delay);
11231
11246
  } else {
11232
- resolve3({ dead: false });
11247
+ resolve4({ dead: false });
11233
11248
  }
11234
11249
  });
11235
11250
  };
@@ -11241,7 +11256,7 @@ var _transport2 = {
11241
11256
  post: _post
11242
11257
  };
11243
11258
  function _post(url, headers, payload) {
11244
- return new Promise((resolve3, reject) => {
11259
+ return new Promise((resolve4, reject) => {
11245
11260
  let settled = false;
11246
11261
  const u2 = new URL(url);
11247
11262
  const transport = u2.protocol === "https:" ? https3 : http3;
@@ -11265,7 +11280,7 @@ function _post(url, headers, payload) {
11265
11280
  res.on("end", () => {
11266
11281
  if (settled) return;
11267
11282
  settled = true;
11268
- resolve3({ statusCode: res.statusCode ?? 0, body: resData });
11283
+ resolve4({ statusCode: res.statusCode ?? 0, body: resData });
11269
11284
  });
11270
11285
  }
11271
11286
  );
@@ -11362,6 +11377,20 @@ var OutputService = class _OutputService {
11362
11377
  emitter;
11363
11378
  runtime;
11364
11379
  lastSentContent = "";
11380
+ /**
11381
+ * Wall-clock of the most recent tick where the rendered + filtered
11382
+ * content actually changed. Most agent TUIs keep redrawing a
11383
+ * spinner + input prompt after the response is settled (Claude:
11384
+ * `? for shortcuts`; Codex: ratatui input bar), which keeps
11385
+ * `pty.lastPushTime` moving and prevents the PTY-idle heuristic
11386
+ * from ever crossing the IDLE_MS threshold — so the turn never
11387
+ * finalises and `done: true` never reaches the webapp's
11388
+ * canonical-refresh path. Tracking content-stability separately
11389
+ * closes that hole: PTY can churn all it wants, but once the
11390
+ * filtered TUI output stops changing for a beat we know the
11391
+ * agent is done.
11392
+ */
11393
+ lastContentChangeAt = 0;
11365
11394
  pollTimer = null;
11366
11395
  startTime = 0;
11367
11396
  terminalTurnPending = false;
@@ -11375,6 +11404,22 @@ var OutputService = class _OutputService {
11375
11404
  static IDLE_MS = 3e3;
11376
11405
  /** Same threshold but tighter for selectors (UI is ready to interact immediately). */
11377
11406
  static SELECTOR_IDLE_MS = 1500;
11407
+ /**
11408
+ * Content-stable threshold. When the rendered + filtered content
11409
+ * hasn't changed for this long AND we can see Claude's "? for
11410
+ * shortcuts" prompt re-drawn at the bottom (= back to input
11411
+ * state), we know the response is settled even though the PTY
11412
+ * itself is still pushing spinner / status redraws. Tighter than
11413
+ * IDLE_MS because the ready-prompt is a strong signal on its own.
11414
+ */
11415
+ static READY_STABLE_MS = 800;
11416
+ /**
11417
+ * Hard content-stable fallback. If the filtered content has been
11418
+ * unchanged for this long, finalize regardless of the ready
11419
+ * prompt — covers cases where Claude's TUI doesn't redraw the
11420
+ * shortcuts line (older versions, headless runs).
11421
+ */
11422
+ static CONTENT_STABLE_MS = 8e3;
11378
11423
  /**
11379
11424
  * Grace period before tick processes anything — Claude needs ~100-
11380
11425
  * 200 ms after `\r` to clear the input echo and re-render the TUI.
@@ -11496,6 +11541,7 @@ var OutputService = class _OutputService {
11496
11541
  this.pty.activate();
11497
11542
  this.steps.reset();
11498
11543
  this.lastSentContent = "";
11544
+ this.lastContentChangeAt = 0;
11499
11545
  this.startTime = Date.now();
11500
11546
  this.pollTimer = setInterval(() => this.tick(), _OutputService.POLL_MS);
11501
11547
  }
@@ -11588,18 +11634,32 @@ var OutputService = class _OutputService {
11588
11634
  return;
11589
11635
  }
11590
11636
  const idleMs = this.pty.lastPushTime > 0 ? now - this.pty.lastPushTime : elapsed;
11637
+ if (content !== this.lastSentContent) {
11638
+ this.lastContentChangeAt = now;
11639
+ this.lastSentContent = content;
11640
+ this.send({ type: "text", content, done: false }).catch(() => {
11641
+ });
11642
+ }
11643
+ const contentStableMs = this.lastContentChangeAt > 0 ? now - this.lastContentChangeAt : 0;
11644
+ const readyPrompt = this.runtime.detectReadyPrompt?.(lines) ?? false;
11591
11645
  log.trace(
11592
11646
  "outputSvc",
11593
- `tick content (raw=${this.pty.size}B lines=${lines.length} content=${content.length} idleMs=${idleMs})`
11647
+ `tick content (raw=${this.pty.size}B lines=${lines.length} content=${content.length} idleMs=${idleMs} stableMs=${contentStableMs} ready=${readyPrompt})`
11594
11648
  );
11595
11649
  if (idleMs >= _OutputService.IDLE_MS) {
11650
+ log.trace("outputSvc", `finalize: idleMs=${idleMs}`);
11596
11651
  this.finalize();
11597
11652
  return;
11598
11653
  }
11599
- if (content !== this.lastSentContent) {
11600
- this.lastSentContent = content;
11601
- this.send({ type: "text", content, done: false }).catch(() => {
11602
- });
11654
+ if (readyPrompt && contentStableMs >= _OutputService.READY_STABLE_MS) {
11655
+ log.trace("outputSvc", `finalize: readyPrompt + stableMs=${contentStableMs}`);
11656
+ this.finalize();
11657
+ return;
11658
+ }
11659
+ if (contentStableMs >= _OutputService.CONTENT_STABLE_MS) {
11660
+ log.trace("outputSvc", `finalize: stableMs=${contentStableMs} (fallback)`);
11661
+ this.finalize();
11662
+ return;
11603
11663
  }
11604
11664
  }
11605
11665
  finalize() {
@@ -11721,7 +11781,7 @@ function parseJsonl(filePath) {
11721
11781
  return messages;
11722
11782
  }
11723
11783
  function post(endpoint, body) {
11724
- return new Promise((resolve3) => {
11784
+ return new Promise((resolve4) => {
11725
11785
  const payload = JSON.stringify(body);
11726
11786
  const u2 = new URL(`${API_BASE4}${endpoint}`);
11727
11787
  const transport = u2.protocol === "https:" ? https4 : http4;
@@ -11742,17 +11802,17 @@ function post(endpoint, body) {
11742
11802
  res.resume();
11743
11803
  const ok = res.statusCode !== void 0 && res.statusCode >= 200 && res.statusCode < 300;
11744
11804
  if (!ok) log.warn("history:post", `${endpoint} \u2192 HTTP ${res.statusCode}`);
11745
- resolve3(ok);
11805
+ resolve4(ok);
11746
11806
  }
11747
11807
  );
11748
11808
  req.on("error", (err) => {
11749
11809
  log.warn("history:post", `${endpoint} network error`, err);
11750
- resolve3(false);
11810
+ resolve4(false);
11751
11811
  });
11752
11812
  req.on("timeout", () => {
11753
11813
  log.warn("history:post", `${endpoint} timeout after 15s`);
11754
11814
  req.destroy();
11755
- resolve3(false);
11815
+ resolve4(false);
11756
11816
  });
11757
11817
  req.write(payload);
11758
11818
  req.end();
@@ -12146,6 +12206,7 @@ var HistoryService = class _HistoryService {
12146
12206
 
12147
12207
  // src/services/file-watcher.service.ts
12148
12208
  var import_child_process7 = require("child_process");
12209
+ var fs21 = __toESM(require("fs"));
12149
12210
  var os22 = __toESM(require("os"));
12150
12211
  var path25 = __toESM(require("path"));
12151
12212
 
@@ -12235,7 +12296,7 @@ var _transport3 = {
12235
12296
  post: _post2
12236
12297
  };
12237
12298
  function _post2(url, headers, payload) {
12238
- return new Promise((resolve3, reject) => {
12299
+ return new Promise((resolve4, reject) => {
12239
12300
  let settled = false;
12240
12301
  const u2 = new URL(url);
12241
12302
  const lib = u2.protocol === "https:" ? https5 : http5;
@@ -12260,7 +12321,7 @@ function _post2(url, headers, payload) {
12260
12321
  res.on("end", () => {
12261
12322
  if (settled) return;
12262
12323
  settled = true;
12263
- resolve3({ statusCode: res.statusCode ?? 0, body });
12324
+ resolve4({ statusCode: res.statusCode ?? 0, body });
12264
12325
  });
12265
12326
  }
12266
12327
  );
@@ -12320,6 +12381,30 @@ var _chokidarSeam = {
12320
12381
  }
12321
12382
  }
12322
12383
  };
12384
+ function findGitRoot(startDir) {
12385
+ return _findGitRootSeam.resolve(startDir);
12386
+ }
12387
+ var _findGitRootSeam = {
12388
+ resolve: _defaultFindGitRoot
12389
+ };
12390
+ function _defaultFindGitRoot(startDir) {
12391
+ let dir = path25.resolve(startDir);
12392
+ const seen = /* @__PURE__ */ new Set();
12393
+ for (let i = 0; i < 256; i++) {
12394
+ if (seen.has(dir)) return null;
12395
+ seen.add(dir);
12396
+ try {
12397
+ const gitPath = path25.join(dir, ".git");
12398
+ const stat3 = fs21.statSync(gitPath, { throwIfNoEntry: false });
12399
+ if (stat3 && (stat3.isDirectory() || stat3.isFile())) return dir;
12400
+ } catch {
12401
+ }
12402
+ const parent = path25.dirname(dir);
12403
+ if (parent === dir) return null;
12404
+ dir = parent;
12405
+ }
12406
+ return null;
12407
+ }
12323
12408
  var FileWatcherService = class {
12324
12409
  constructor(opts) {
12325
12410
  this.opts = opts;
@@ -12329,6 +12414,13 @@ var FileWatcherService = class {
12329
12414
  watcher = null;
12330
12415
  pending = /* @__PURE__ */ new Map();
12331
12416
  apiBase;
12417
+ /**
12418
+ * Cache of (file directory → git root). Resolved lazily on each
12419
+ * file event so brand-new sub-repos under the workingDir light up
12420
+ * automatically; cached so a hot session with thousands of writes
12421
+ * doesn't hammer `fs.statSync` for every event.
12422
+ */
12423
+ gitRootByDir = /* @__PURE__ */ new Map();
12332
12424
  stopped = false;
12333
12425
  /**
12334
12426
  * Start watching `opts.workingDir`. Idempotent (second call is a
@@ -12471,67 +12563,82 @@ var FileWatcherService = class {
12471
12563
  }
12472
12564
  async emitForFile(absPath, changeType) {
12473
12565
  if (this.stopped) return;
12474
- const relPath = path25.relative(this.opts.workingDir, absPath);
12475
- if (!relPath || relPath.startsWith("..")) {
12566
+ const fileDir = path25.dirname(absPath);
12567
+ let gitRoot = this.gitRootByDir.get(fileDir);
12568
+ if (gitRoot === void 0) {
12569
+ gitRoot = findGitRoot(fileDir);
12570
+ this.gitRootByDir.set(fileDir, gitRoot);
12571
+ }
12572
+ if (!gitRoot) {
12573
+ log.trace(
12574
+ "fileWatcher",
12575
+ `no enclosing git repo for ${absPath} \u2014 suppressing emit`
12576
+ );
12476
12577
  return;
12477
12578
  }
12579
+ const relPathInRepo = path25.relative(gitRoot, absPath);
12580
+ if (!relPathInRepo || relPathInRepo.startsWith("..")) return;
12581
+ const repoPath = path25.relative(this.opts.workingDir, gitRoot);
12582
+ const repoName = path25.basename(gitRoot);
12478
12583
  let diffText = "";
12479
12584
  let fileStatus = "modified";
12480
12585
  if (changeType === "unlink") {
12481
- const diff = await this.gitDiff(relPath);
12586
+ const diff = await this.gitDiff(gitRoot, relPathInRepo);
12482
12587
  if (diff !== null && diff.trim().length > 0) {
12483
12588
  diffText = diff;
12484
12589
  } else {
12485
12590
  await this.postFileChanged({
12486
12591
  sessionId: this.opts.sessionId,
12487
12592
  pluginId: this.opts.pluginId,
12488
- filePath: relPath,
12593
+ filePath: relPathInRepo,
12489
12594
  fileStatus: "deleted",
12490
12595
  linesAdded: 0,
12491
12596
  linesRemoved: 0,
12492
- hunkCount: 0
12597
+ hunkCount: 0,
12598
+ repoPath,
12599
+ repoName
12493
12600
  });
12494
12601
  return;
12495
12602
  }
12496
12603
  fileStatus = "deleted";
12497
12604
  } else {
12498
- const diff = await this.gitDiff(relPath);
12605
+ const diff = await this.gitDiff(gitRoot, relPathInRepo);
12499
12606
  if (diff === null) {
12500
12607
  log.warn(
12501
12608
  "fileWatcher",
12502
- `git diff failed for ${relPath} \u2014 emitting file-changed only`
12609
+ `git diff failed for ${relPathInRepo} in ${gitRoot} \u2014 suppressing emit`
12503
12610
  );
12504
- await this.postFileChanged({
12505
- sessionId: this.opts.sessionId,
12506
- pluginId: this.opts.pluginId,
12507
- filePath: relPath,
12508
- fileStatus: changeType === "add" ? "added" : "modified",
12509
- linesAdded: 0,
12510
- linesRemoved: 0,
12511
- hunkCount: 0
12512
- });
12513
12611
  return;
12514
12612
  }
12515
12613
  diffText = diff;
12516
12614
  }
12517
12615
  const parsed = parseUnifiedDiff(diffText);
12616
+ if (changeType !== "unlink" && parsed.totalLinesAdded === 0 && parsed.totalLinesRemoved === 0 && parsed.hunks.length === 0) {
12617
+ log.trace(
12618
+ "fileWatcher",
12619
+ `no content delta for ${relPathInRepo} in ${repoName} \u2014 suppressing emit`
12620
+ );
12621
+ return;
12622
+ }
12518
12623
  const finalStatus = parsed.fileStatus !== "modified" ? parsed.fileStatus : changeType === "add" ? "added" : changeType === "unlink" ? "deleted" : fileStatus;
12519
12624
  const reviewStatus = parsed.hunks.length > 0 ? "awaiting_review" : void 0;
12520
12625
  await this.postFileChanged({
12521
12626
  sessionId: this.opts.sessionId,
12522
12627
  pluginId: this.opts.pluginId,
12523
- filePath: relPath,
12628
+ filePath: relPathInRepo,
12524
12629
  fileStatus: finalStatus,
12525
12630
  linesAdded: parsed.totalLinesAdded,
12526
12631
  linesRemoved: parsed.totalLinesRemoved,
12527
12632
  hunkCount: parsed.hunks.length,
12528
- reviewStatus
12633
+ reviewStatus,
12634
+ repoPath,
12635
+ repoName
12529
12636
  });
12530
12637
  for (const hunk of parsed.hunks) {
12531
12638
  await this.postReviewHunk({
12532
12639
  sessionId: this.opts.sessionId,
12533
12640
  pluginId: this.opts.pluginId,
12534
- filePath: relPath,
12641
+ filePath: relPathInRepo,
12535
12642
  fileStatus: finalStatus,
12536
12643
  hunkHeader: hunk.header,
12537
12644
  lines: hunk.lines,
@@ -12542,9 +12649,11 @@ var FileWatcherService = class {
12542
12649
  }
12543
12650
  /**
12544
12651
  * Compute the unified diff for a single path relative to the
12545
- * working dir. Returns `null` when git is unavailable or the cwd
12546
- * is not a repo. Returns `''` when there's no diff (a touch that
12547
- * didn't change content).
12652
+ * enclosing git repo (NOT the CLI's workingDir see
12653
+ * `emitForFile`'s walk-up). Returns `null` when git is unavailable
12654
+ * or the discovered repo root is no longer a repo (race with
12655
+ * external removal). Returns `''` when there's no diff (a touch
12656
+ * that didn't change content).
12548
12657
  *
12549
12658
  * For tracked files we use `git diff --no-color -- <path>` which
12550
12659
  * compares the worktree against HEAD's blob.
@@ -12552,16 +12661,16 @@ var FileWatcherService = class {
12552
12661
  * zero) we use `git diff --no-color --no-index /dev/null <path>`,
12553
12662
  * which produces an "added"-shaped diff against an empty source.
12554
12663
  */
12555
- async gitDiff(relPath) {
12664
+ async gitDiff(repoRoot, relPath) {
12556
12665
  const tracked = await runGit(
12557
- this.opts.workingDir,
12666
+ repoRoot,
12558
12667
  ["diff", "--no-color", "--", relPath]
12559
12668
  );
12560
12669
  if (tracked === null) return null;
12561
12670
  if (tracked.trim().length > 0) return tracked;
12562
12671
  const devNull = process.platform === "win32" ? "NUL" : "/dev/null";
12563
12672
  const untracked = await runGit(
12564
- this.opts.workingDir,
12673
+ repoRoot,
12565
12674
  ["diff", "--no-color", "--no-index", "--", devNull, relPath],
12566
12675
  { allowNonZeroExit: true }
12567
12676
  );
@@ -12629,12 +12738,12 @@ var _gitSeam = {
12629
12738
  run: _runGitImpl
12630
12739
  };
12631
12740
  async function _runGitImpl(cwd, args2, opts = {}) {
12632
- return new Promise((resolve3) => {
12741
+ return new Promise((resolve4) => {
12633
12742
  let proc;
12634
12743
  try {
12635
12744
  proc = (0, import_child_process7.spawn)("git", args2, { cwd, env: process.env });
12636
12745
  } catch {
12637
- resolve3(null);
12746
+ resolve4(null);
12638
12747
  return;
12639
12748
  }
12640
12749
  let stdout = "";
@@ -12645,13 +12754,13 @@ async function _runGitImpl(cwd, args2, opts = {}) {
12645
12754
  proc.stderr?.on("data", (c2) => {
12646
12755
  stderr += c2.toString();
12647
12756
  });
12648
- proc.on("error", () => resolve3(null));
12757
+ proc.on("error", () => resolve4(null));
12649
12758
  proc.on("close", (code) => {
12650
12759
  if (code === 0 || opts.allowNonZeroExit) {
12651
- resolve3(stdout);
12760
+ resolve4(stdout);
12652
12761
  } else {
12653
12762
  log.trace("fileWatcher", `git ${args2.join(" ")} exited ${code} stderr=${stderr.slice(0, 200)}`);
12654
- resolve3(null);
12763
+ resolve4(null);
12655
12764
  }
12656
12765
  });
12657
12766
  });
@@ -12671,7 +12780,7 @@ var _transport4 = {
12671
12780
  get: _get
12672
12781
  };
12673
12782
  function _post3(url, headers, payload) {
12674
- return new Promise((resolve3, reject) => {
12783
+ return new Promise((resolve4, reject) => {
12675
12784
  let settled = false;
12676
12785
  const u2 = new URL(url);
12677
12786
  const lib = u2.protocol === "https:" ? https6 : http6;
@@ -12696,7 +12805,7 @@ function _post3(url, headers, payload) {
12696
12805
  res.on("end", () => {
12697
12806
  if (settled) return;
12698
12807
  settled = true;
12699
- resolve3({ statusCode: res.statusCode ?? 0, body });
12808
+ resolve4({ statusCode: res.statusCode ?? 0, body });
12700
12809
  });
12701
12810
  }
12702
12811
  );
@@ -12713,7 +12822,7 @@ function _post3(url, headers, payload) {
12713
12822
  });
12714
12823
  }
12715
12824
  function _get(url, headers) {
12716
- return new Promise((resolve3, reject) => {
12825
+ return new Promise((resolve4, reject) => {
12717
12826
  let settled = false;
12718
12827
  const u2 = new URL(url);
12719
12828
  const lib = u2.protocol === "https:" ? https6 : http6;
@@ -12737,7 +12846,7 @@ function _get(url, headers) {
12737
12846
  res.on("end", () => {
12738
12847
  if (settled) return;
12739
12848
  settled = true;
12740
- resolve3({ statusCode: res.statusCode ?? 0, body });
12849
+ resolve4({ statusCode: res.statusCode ?? 0, body });
12741
12850
  });
12742
12851
  }
12743
12852
  );
@@ -13120,7 +13229,7 @@ function buildKeepAlive(ctx) {
13120
13229
  let timer = null;
13121
13230
  async function setIdleTimeout(minutes) {
13122
13231
  if (!ctx.inCodespace || !ctx.codespaceName) return;
13123
- await new Promise((resolve3) => {
13232
+ await new Promise((resolve4) => {
13124
13233
  const proc = (0, import_child_process8.spawn)(
13125
13234
  "gh",
13126
13235
  [
@@ -13134,8 +13243,8 @@ function buildKeepAlive(ctx) {
13134
13243
  { stdio: "ignore", detached: true }
13135
13244
  );
13136
13245
  proc.unref();
13137
- proc.on("exit", () => resolve3());
13138
- proc.on("error", () => resolve3());
13246
+ proc.on("exit", () => resolve4());
13247
+ proc.on("error", () => resolve4());
13139
13248
  });
13140
13249
  }
13141
13250
  return {
@@ -13158,7 +13267,7 @@ function buildKeepAlive(ctx) {
13158
13267
  }
13159
13268
 
13160
13269
  // src/commands/start/handlers.ts
13161
- var fs23 = __toESM(require("fs"));
13270
+ var fs24 = __toESM(require("fs"));
13162
13271
  var os23 = __toESM(require("os"));
13163
13272
  var path29 = __toESM(require("path"));
13164
13273
  var import_crypto4 = require("crypto");
@@ -13218,7 +13327,7 @@ function parsePayload2(schema, raw) {
13218
13327
  }
13219
13328
 
13220
13329
  // src/services/file-ops.service.ts
13221
- var fs21 = __toESM(require("fs/promises"));
13330
+ var fs22 = __toESM(require("fs/promises"));
13222
13331
  var path26 = __toESM(require("path"));
13223
13332
  var MAX_FILE_BYTES = 5 * 1024 * 1024;
13224
13333
  var MAX_WALK_DEPTH = 6;
@@ -13259,7 +13368,7 @@ function isUnder(parent, candidate) {
13259
13368
  }
13260
13369
  async function isExistingFile(absPath) {
13261
13370
  try {
13262
- const stat3 = await fs21.stat(absPath);
13371
+ const stat3 = await fs22.stat(absPath);
13263
13372
  return stat3.isFile();
13264
13373
  } catch {
13265
13374
  return false;
@@ -13272,7 +13381,7 @@ async function walkForSuffix(dir, needleVariants, depth, ctx) {
13272
13381
  ctx.visited++;
13273
13382
  let entries = [];
13274
13383
  try {
13275
- entries = await fs21.readdir(dir, { withFileTypes: true });
13384
+ entries = await fs22.readdir(dir, { withFileTypes: true });
13276
13385
  } catch {
13277
13386
  return;
13278
13387
  }
@@ -13333,11 +13442,11 @@ async function readProjectFile(rawPath) {
13333
13442
  if (!abs) {
13334
13443
  return { error: `File not found in the project tree: ${rawPath}` };
13335
13444
  }
13336
- const stat3 = await fs21.stat(abs);
13445
+ const stat3 = await fs22.stat(abs);
13337
13446
  if (stat3.size > MAX_FILE_BYTES) {
13338
13447
  return { error: `File too large (${(stat3.size / 1024 / 1024).toFixed(1)} MB > ${MAX_FILE_BYTES / 1024 / 1024} MB).` };
13339
13448
  }
13340
- const buf = await fs21.readFile(abs);
13449
+ const buf = await fs22.readFile(abs);
13341
13450
  if (looksBinary(buf)) {
13342
13451
  return { error: "Binary file \u2014 refusing to open in a code editor." };
13343
13452
  }
@@ -13356,8 +13465,8 @@ async function writeProjectFile(rawPath, content) {
13356
13465
  if (Buffer.byteLength(content, "utf-8") > MAX_FILE_BYTES) {
13357
13466
  return { error: "Content too large." };
13358
13467
  }
13359
- await fs21.mkdir(path26.dirname(abs), { recursive: true });
13360
- await fs21.writeFile(abs, content, "utf-8");
13468
+ await fs22.mkdir(path26.dirname(abs), { recursive: true });
13469
+ await fs22.writeFile(abs, content, "utf-8");
13361
13470
  return { ok: true };
13362
13471
  } catch (e) {
13363
13472
  const msg = e instanceof Error ? e.message : "Write failed";
@@ -13368,7 +13477,7 @@ async function writeProjectFile(rawPath, content) {
13368
13477
  // src/services/project-ops.service.ts
13369
13478
  var import_child_process9 = require("child_process");
13370
13479
  var import_util2 = require("util");
13371
- var fs22 = __toESM(require("fs/promises"));
13480
+ var fs23 = __toESM(require("fs/promises"));
13372
13481
  var path27 = __toESM(require("path"));
13373
13482
  var execFileP3 = (0, import_util2.promisify)(import_child_process9.execFile);
13374
13483
  var PROJECT_IGNORE = /* @__PURE__ */ new Set([
@@ -13417,7 +13526,7 @@ async function listProjectFiles(opts = {}) {
13417
13526
  }
13418
13527
  let entries = [];
13419
13528
  try {
13420
- entries = await fs22.readdir(dir, { withFileTypes: true });
13529
+ entries = await fs23.readdir(dir, { withFileTypes: true });
13421
13530
  } catch {
13422
13531
  return;
13423
13532
  }
@@ -13438,7 +13547,7 @@ async function listProjectFiles(opts = {}) {
13438
13547
  }
13439
13548
  let size = 0;
13440
13549
  try {
13441
- const st3 = await fs22.stat(full);
13550
+ const st3 = await fs23.stat(full);
13442
13551
  size = st3.size;
13443
13552
  } catch {
13444
13553
  }
@@ -13541,7 +13650,7 @@ async function gitStatus(cwd) {
13541
13650
  try {
13542
13651
  const gitDir = (await git(["rev-parse", "--git-dir"], root)).stdout.trim();
13543
13652
  const mergeHead = path27.isAbsolute(gitDir) ? path27.join(gitDir, "MERGE_HEAD") : path27.join(root, gitDir, "MERGE_HEAD");
13544
- await fs22.access(mergeHead);
13653
+ await fs23.access(mergeHead);
13545
13654
  hasMergeInProgress = true;
13546
13655
  } catch {
13547
13656
  }
@@ -13687,7 +13796,7 @@ async function jsSearchFiles(opts, cwd, cap) {
13687
13796
  }
13688
13797
  let content = "";
13689
13798
  try {
13690
- content = await fs22.readFile(path27.join(cwd, f.path), "utf8");
13799
+ content = await fs23.readFile(path27.join(cwd, f.path), "utf8");
13691
13800
  } catch {
13692
13801
  continue;
13693
13802
  }
@@ -13971,7 +14080,7 @@ var pendingAttachmentFiles = /* @__PURE__ */ new Set();
13971
14080
  function cleanupAttachmentTempFiles() {
13972
14081
  for (const p2 of pendingAttachmentFiles) {
13973
14082
  try {
13974
- fs23.unlinkSync(p2);
14083
+ fs24.unlinkSync(p2);
13975
14084
  } catch {
13976
14085
  }
13977
14086
  }
@@ -13981,7 +14090,7 @@ function saveFilesTemp(files) {
13981
14090
  return files.filter(({ base64 }) => base64 && base64.length > 0).map(({ filename, base64 }) => {
13982
14091
  const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
13983
14092
  const tmpPath = path29.join(os23.tmpdir(), `codeam-${(0, import_crypto4.randomUUID)()}-${safeName}`);
13984
- fs23.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
14093
+ fs24.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
13985
14094
  pendingAttachmentFiles.add(tmpPath);
13986
14095
  return tmpPath;
13987
14096
  });
@@ -14001,7 +14110,7 @@ var startTask = (ctx, _cmd, parsed) => {
14001
14110
  setTimeout(() => {
14002
14111
  for (const p2 of paths) {
14003
14112
  try {
14004
- fs23.unlinkSync(p2);
14113
+ fs24.unlinkSync(p2);
14005
14114
  } catch {
14006
14115
  }
14007
14116
  pendingAttachmentFiles.delete(p2);
@@ -14567,7 +14676,7 @@ async function pair(args2 = []) {
14567
14676
  waitSpin.message(waitMessage());
14568
14677
  }, 1e3);
14569
14678
  countdownInterval.unref?.();
14570
- await new Promise((resolve3) => {
14679
+ await new Promise((resolve4) => {
14571
14680
  let stopPolling = null;
14572
14681
  function sigintHandler() {
14573
14682
  clearInterval(countdownInterval);
@@ -14607,7 +14716,7 @@ async function pair(args2 = []) {
14607
14716
  });
14608
14717
  showSuccess(`Paired with ${info.userName} (${info.plan})`);
14609
14718
  console.log("");
14610
- resolve3();
14719
+ resolve4();
14611
14720
  },
14612
14721
  () => {
14613
14722
  clearInterval(countdownInterval);
@@ -14623,7 +14732,7 @@ async function pair(args2 = []) {
14623
14732
  }
14624
14733
 
14625
14734
  // src/commands/pair-auto.ts
14626
- var fs24 = __toESM(require("fs"));
14735
+ var fs25 = __toESM(require("fs"));
14627
14736
  var os24 = __toESM(require("os"));
14628
14737
  var import_crypto6 = require("crypto");
14629
14738
  var API_BASE7 = resolveApiBaseUrl();
@@ -14643,10 +14752,10 @@ function readTokenFromArgs(args2) {
14643
14752
  if (fileFlag) {
14644
14753
  const path37 = fileFlag.slice("--token-file=".length);
14645
14754
  try {
14646
- const content = fs24.readFileSync(path37, "utf8").trim();
14755
+ const content = fs25.readFileSync(path37, "utf8").trim();
14647
14756
  if (content.length === 0) fail(`--token-file ${path37} is empty`);
14648
14757
  try {
14649
- fs24.unlinkSync(path37);
14758
+ fs25.unlinkSync(path37);
14650
14759
  } catch {
14651
14760
  }
14652
14761
  return content;
@@ -14943,12 +15052,12 @@ var GitHubCodespacesProvider = class {
14943
15052
  }
14944
15053
  if (!isAuthed) {
14945
15054
  resetStdinForChild();
14946
- await new Promise((resolve3, reject) => {
15055
+ await new Promise((resolve4, reject) => {
14947
15056
  const proc = (0, import_child_process12.spawn)("gh", ["auth", "login", "-s", "codespace,repo,read:user"], {
14948
15057
  stdio: "inherit"
14949
15058
  });
14950
15059
  proc.on("exit", (code) => {
14951
- if (code === 0) resolve3();
15060
+ if (code === 0) resolve4();
14952
15061
  else reject(new Error("gh auth login failed."));
14953
15062
  });
14954
15063
  proc.on("error", reject);
@@ -14977,13 +15086,13 @@ var GitHubCodespacesProvider = class {
14977
15086
  }
14978
15087
  wt(noteLines.join("\n"), "One more permission needed");
14979
15088
  resetStdinForChild();
14980
- const refreshCode = await new Promise((resolve3, reject) => {
15089
+ const refreshCode = await new Promise((resolve4, reject) => {
14981
15090
  const proc = (0, import_child_process12.spawn)(
14982
15091
  "gh",
14983
15092
  ["auth", "refresh", "-h", "github.com", "-s", "codespace"],
14984
15093
  { stdio: "inherit" }
14985
15094
  );
14986
- proc.on("exit", (code) => resolve3(code ?? 1));
15095
+ proc.on("exit", (code) => resolve4(code ?? 1));
14987
15096
  proc.on("error", reject);
14988
15097
  });
14989
15098
  if (refreshCode !== 0) {
@@ -15127,10 +15236,10 @@ var GitHubCodespacesProvider = class {
15127
15236
  if (q(proceed) || !proceed) return;
15128
15237
  O2.step(`Installing gh via ${installCmd.describe}\u2026`);
15129
15238
  resetStdinForChild();
15130
- const ok = await new Promise((resolve3) => {
15239
+ const ok = await new Promise((resolve4) => {
15131
15240
  const proc = (0, import_child_process12.spawn)(installCmd.exe, installCmd.args, { stdio: "inherit" });
15132
- proc.on("exit", (code) => resolve3(code === 0));
15133
- proc.on("error", () => resolve3(false));
15241
+ proc.on("exit", (code) => resolve4(code === 0));
15242
+ proc.on("error", () => resolve4(false));
15134
15243
  });
15135
15244
  if (ok) O2.success("gh installed");
15136
15245
  else O2.error("gh install failed");
@@ -15154,14 +15263,14 @@ var GitHubCodespacesProvider = class {
15154
15263
  "Expanding GitHub scopes"
15155
15264
  );
15156
15265
  resetStdinForChild();
15157
- await new Promise((resolve3, reject) => {
15266
+ await new Promise((resolve4, reject) => {
15158
15267
  const proc = (0, import_child_process12.spawn)(
15159
15268
  "gh",
15160
15269
  ["auth", "refresh", "-h", "github.com", "-s", "repo,read:org"],
15161
15270
  { stdio: "inherit" }
15162
15271
  );
15163
15272
  proc.on("exit", (code) => {
15164
- if (code === 0) resolve3();
15273
+ if (code === 0) resolve4();
15165
15274
  else reject(new Error(
15166
15275
  "gh auth refresh failed. Re-run `gh auth refresh -h github.com -s repo,read:org` manually."
15167
15276
  ));
@@ -15332,13 +15441,13 @@ var GitHubCodespacesProvider = class {
15332
15441
  }
15333
15442
  async streamCommand(workspaceId, command2) {
15334
15443
  resetStdinForChild();
15335
- return new Promise((resolve3, reject) => {
15444
+ return new Promise((resolve4, reject) => {
15336
15445
  const proc = (0, import_child_process12.spawn)(
15337
15446
  "gh",
15338
15447
  ["codespace", "ssh", "-c", workspaceId, "--", "-tt", command2],
15339
15448
  { stdio: "inherit" }
15340
15449
  );
15341
- proc.on("exit", (code) => resolve3({ code: code ?? 0 }));
15450
+ proc.on("exit", (code) => resolve4({ code: code ?? 0 }));
15342
15451
  proc.on("error", reject);
15343
15452
  });
15344
15453
  }
@@ -15359,7 +15468,7 @@ var GitHubCodespacesProvider = class {
15359
15468
  "--",
15360
15469
  `mkdir -p ${shellQuote(remoteDir)} && tar -xzf - -C ${shellQuote(remoteDir)}`
15361
15470
  ];
15362
- await new Promise((resolve3, reject) => {
15471
+ await new Promise((resolve4, reject) => {
15363
15472
  const tar = (0, import_child_process12.spawn)("tar", tarArgs, {
15364
15473
  stdio: ["ignore", "pipe", "pipe"],
15365
15474
  env: tarEnv
@@ -15379,7 +15488,7 @@ var GitHubCodespacesProvider = class {
15379
15488
  ssh.on("error", reject);
15380
15489
  ssh.on("exit", (code) => {
15381
15490
  if (code === 0) {
15382
- resolve3();
15491
+ resolve4();
15383
15492
  } else {
15384
15493
  const reason = (sshErr || tarErr || `exit ${code}`).trim().slice(0, 500);
15385
15494
  reject(new Error(`Remote tar failed: ${reason}`));
@@ -15397,7 +15506,7 @@ var GitHubCodespacesProvider = class {
15397
15506
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote(remotePath)}`);
15398
15507
  }
15399
15508
  const cmd = parts.join(" && ");
15400
- await new Promise((resolve3, reject) => {
15509
+ await new Promise((resolve4, reject) => {
15401
15510
  const proc = (0, import_child_process12.spawn)(
15402
15511
  "gh",
15403
15512
  ["codespace", "ssh", "-c", workspaceId, "--", cmd],
@@ -15409,7 +15518,7 @@ var GitHubCodespacesProvider = class {
15409
15518
  });
15410
15519
  proc.on("error", reject);
15411
15520
  proc.on("exit", (code) => {
15412
- if (code === 0) resolve3();
15521
+ if (code === 0) resolve4();
15413
15522
  else reject(new Error(`Remote write failed: ${(stderr || `exit ${code}`).trim().slice(0, 500)}`));
15414
15523
  });
15415
15524
  proc.stdin?.write(contents);
@@ -15499,10 +15608,10 @@ var GitpodProvider = class {
15499
15608
  "Authenticating Gitpod"
15500
15609
  );
15501
15610
  resetStdinForChild2();
15502
- await new Promise((resolve3, reject) => {
15611
+ await new Promise((resolve4, reject) => {
15503
15612
  const proc = (0, import_child_process13.spawn)("gitpod", ["login"], { stdio: "inherit" });
15504
15613
  proc.on("exit", (code) => {
15505
- if (code === 0) resolve3();
15614
+ if (code === 0) resolve4();
15506
15615
  else reject(new Error("gitpod login failed."));
15507
15616
  });
15508
15617
  proc.on("error", reject);
@@ -15651,13 +15760,13 @@ var GitpodProvider = class {
15651
15760
  }
15652
15761
  async streamCommand(workspaceId, command2) {
15653
15762
  resetStdinForChild2();
15654
- return new Promise((resolve3, reject) => {
15763
+ return new Promise((resolve4, reject) => {
15655
15764
  const proc = (0, import_child_process13.spawn)(
15656
15765
  "gitpod",
15657
15766
  ["workspace", "ssh", workspaceId, "--", "-tt", command2],
15658
15767
  { stdio: "inherit" }
15659
15768
  );
15660
- proc.on("exit", (code) => resolve3({ code: code ?? 0 }));
15769
+ proc.on("exit", (code) => resolve4({ code: code ?? 0 }));
15661
15770
  proc.on("error", reject);
15662
15771
  });
15663
15772
  }
@@ -15671,7 +15780,7 @@ var GitpodProvider = class {
15671
15780
  tarArgs.push(".");
15672
15781
  const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
15673
15782
  const remoteCmd = `mkdir -p ${shellQuote2(remoteDir)} && tar -xzf - -C ${shellQuote2(remoteDir)}`;
15674
- await new Promise((resolve3, reject) => {
15783
+ await new Promise((resolve4, reject) => {
15675
15784
  const tar = (0, import_child_process13.spawn)("tar", tarArgs, {
15676
15785
  stdio: ["ignore", "pipe", "pipe"],
15677
15786
  env: tarEnv
@@ -15692,7 +15801,7 @@ var GitpodProvider = class {
15692
15801
  tar.on("error", reject);
15693
15802
  ssh.on("error", reject);
15694
15803
  ssh.on("exit", (code) => {
15695
- if (code === 0) resolve3();
15804
+ if (code === 0) resolve4();
15696
15805
  else reject(new Error(`Remote tar failed: ${(sshErr || tarErr || `exit ${code}`).trim().slice(0, 500)}`));
15697
15806
  });
15698
15807
  });
@@ -15707,7 +15816,7 @@ var GitpodProvider = class {
15707
15816
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote2(remotePath)}`);
15708
15817
  }
15709
15818
  const cmd = parts.join(" && ");
15710
- await new Promise((resolve3, reject) => {
15819
+ await new Promise((resolve4, reject) => {
15711
15820
  const proc = (0, import_child_process13.spawn)(
15712
15821
  "gitpod",
15713
15822
  ["workspace", "ssh", workspaceId, "--", cmd],
@@ -15719,7 +15828,7 @@ var GitpodProvider = class {
15719
15828
  });
15720
15829
  proc.on("error", reject);
15721
15830
  proc.on("exit", (code) => {
15722
- if (code === 0) resolve3();
15831
+ if (code === 0) resolve4();
15723
15832
  else reject(new Error(`Remote write failed: ${(stderr || `exit ${code}`).trim().slice(0, 500)}`));
15724
15833
  });
15725
15834
  proc.stdin?.write(contents);
@@ -15776,14 +15885,14 @@ var GitLabWorkspacesProvider = class {
15776
15885
  "Authenticating GitLab"
15777
15886
  );
15778
15887
  resetStdinForChild3();
15779
- await new Promise((resolve3, reject) => {
15888
+ await new Promise((resolve4, reject) => {
15780
15889
  const proc = (0, import_child_process14.spawn)(
15781
15890
  "glab",
15782
15891
  ["auth", "login", "--scopes", "api,read_user,read_repository"],
15783
15892
  { stdio: "inherit" }
15784
15893
  );
15785
15894
  proc.on("exit", (code) => {
15786
- if (code === 0) resolve3();
15895
+ if (code === 0) resolve4();
15787
15896
  else reject(new Error("glab auth login failed."));
15788
15897
  });
15789
15898
  proc.on("error", reject);
@@ -15948,13 +16057,13 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
15948
16057
  async streamCommand(workspaceId, command2) {
15949
16058
  const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
15950
16059
  resetStdinForChild3();
15951
- return new Promise((resolve3, reject) => {
16060
+ return new Promise((resolve4, reject) => {
15952
16061
  const proc = (0, import_child_process14.spawn)(
15953
16062
  "ssh",
15954
16063
  ["-tt", "-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, command2],
15955
16064
  { stdio: "inherit" }
15956
16065
  );
15957
- proc.on("exit", (code) => resolve3({ code: code ?? 0 }));
16066
+ proc.on("exit", (code) => resolve4({ code: code ?? 0 }));
15958
16067
  proc.on("error", reject);
15959
16068
  });
15960
16069
  }
@@ -15969,7 +16078,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
15969
16078
  tarArgs.push(".");
15970
16079
  const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
15971
16080
  const remoteCmd = `mkdir -p ${shellQuote3(remoteDir)} && tar -xzf - -C ${shellQuote3(remoteDir)}`;
15972
- await new Promise((resolve3, reject) => {
16081
+ await new Promise((resolve4, reject) => {
15973
16082
  const tar = (0, import_child_process14.spawn)("tar", tarArgs, { stdio: ["ignore", "pipe", "pipe"], env: tarEnv });
15974
16083
  const ssh = (0, import_child_process14.spawn)(
15975
16084
  "ssh",
@@ -15987,7 +16096,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
15987
16096
  tar.on("error", reject);
15988
16097
  ssh.on("error", reject);
15989
16098
  ssh.on("exit", (code) => {
15990
- if (code === 0) resolve3();
16099
+ if (code === 0) resolve4();
15991
16100
  else reject(new Error(`Remote tar failed: ${(sshErr || tarErr || `exit ${code}`).trim().slice(0, 500)}`));
15992
16101
  });
15993
16102
  });
@@ -16000,7 +16109,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
16000
16109
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
16001
16110
  }
16002
16111
  const cmd = parts.join(" && ");
16003
- await new Promise((resolve3, reject) => {
16112
+ await new Promise((resolve4, reject) => {
16004
16113
  const proc = (0, import_child_process14.spawn)(
16005
16114
  "ssh",
16006
16115
  ["-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, cmd],
@@ -16012,7 +16121,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
16012
16121
  });
16013
16122
  proc.on("error", reject);
16014
16123
  proc.on("exit", (code) => {
16015
- if (code === 0) resolve3();
16124
+ if (code === 0) resolve4();
16016
16125
  else reject(new Error(`Remote write failed: ${(stderr || `exit ${code}`).trim().slice(0, 500)}`));
16017
16126
  });
16018
16127
  proc.stdin?.write(contents);
@@ -16103,10 +16212,10 @@ var RailwayProvider = class {
16103
16212
  "Authenticating Railway"
16104
16213
  );
16105
16214
  resetStdinForChild4();
16106
- await new Promise((resolve3, reject) => {
16215
+ await new Promise((resolve4, reject) => {
16107
16216
  const proc = (0, import_child_process15.spawn)("railway", ["login"], { stdio: "inherit" });
16108
16217
  proc.on("exit", (code) => {
16109
- if (code === 0) resolve3();
16218
+ if (code === 0) resolve4();
16110
16219
  else reject(new Error("railway login failed."));
16111
16220
  });
16112
16221
  proc.on("error", reject);
@@ -16246,13 +16355,13 @@ var RailwayProvider = class {
16246
16355
  throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
16247
16356
  }
16248
16357
  resetStdinForChild4();
16249
- return new Promise((resolve3, reject) => {
16358
+ return new Promise((resolve4, reject) => {
16250
16359
  const proc = (0, import_child_process15.spawn)(
16251
16360
  "railway",
16252
16361
  ["shell", "--project", projectId, "--service", serviceId, "--command", command2],
16253
16362
  { stdio: "inherit" }
16254
16363
  );
16255
- proc.on("exit", (code) => resolve3({ code: code ?? 0 }));
16364
+ proc.on("exit", (code) => resolve4({ code: code ?? 0 }));
16256
16365
  proc.on("error", reject);
16257
16366
  });
16258
16367
  }
@@ -16270,7 +16379,7 @@ var RailwayProvider = class {
16270
16379
  tarArgs.push(".");
16271
16380
  const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
16272
16381
  const remoteCmd = `mkdir -p ${shellQuote4(remoteDir)} && tar -xzf - -C ${shellQuote4(remoteDir)}`;
16273
- await new Promise((resolve3, reject) => {
16382
+ await new Promise((resolve4, reject) => {
16274
16383
  const tar = (0, import_child_process15.spawn)("tar", tarArgs, { stdio: ["ignore", "pipe", "pipe"], env: tarEnv });
16275
16384
  const sh = (0, import_child_process15.spawn)(
16276
16385
  "railway",
@@ -16288,7 +16397,7 @@ var RailwayProvider = class {
16288
16397
  tar.on("error", reject);
16289
16398
  sh.on("error", reject);
16290
16399
  sh.on("exit", (code) => {
16291
- if (code === 0) resolve3();
16400
+ if (code === 0) resolve4();
16292
16401
  else reject(new Error(`Remote tar failed: ${(shErr || tarErr || `exit ${code}`).trim().slice(0, 500)}`));
16293
16402
  });
16294
16403
  });
@@ -16304,7 +16413,7 @@ var RailwayProvider = class {
16304
16413
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
16305
16414
  }
16306
16415
  const cmd = parts.join(" && ");
16307
- await new Promise((resolve3, reject) => {
16416
+ await new Promise((resolve4, reject) => {
16308
16417
  const proc = (0, import_child_process15.spawn)(
16309
16418
  "railway",
16310
16419
  ["shell", "--project", projectId, "--service", serviceId, "--command", cmd],
@@ -16316,7 +16425,7 @@ var RailwayProvider = class {
16316
16425
  });
16317
16426
  proc.on("error", reject);
16318
16427
  proc.on("exit", (code) => {
16319
- if (code === 0) resolve3();
16428
+ if (code === 0) resolve4();
16320
16429
  else reject(new Error(`Remote write failed: ${(stderr || `exit ${code}`).trim().slice(0, 500)}`));
16321
16430
  });
16322
16431
  proc.stdin?.write(contents);
@@ -16839,7 +16948,7 @@ async function stopWorkspaceFromLocal(target) {
16839
16948
 
16840
16949
  // src/commands/link.ts
16841
16950
  var import_node_crypto4 = require("crypto");
16842
- var fs25 = __toESM(require("fs"));
16951
+ var fs26 = __toESM(require("fs"));
16843
16952
  var path34 = __toESM(require("path"));
16844
16953
  var import_chokidar = __toESM(require("chokidar"));
16845
16954
  var import_picocolors11 = __toESM(require("picocolors"));
@@ -16878,7 +16987,7 @@ function parseLinkArgs(args2) {
16878
16987
  if (apiKeyFileArg) {
16879
16988
  const filePath = apiKeyFileArg.slice("--api-key-file=".length);
16880
16989
  try {
16881
- apiKey = fs25.readFileSync(path34.resolve(filePath), "utf8").trim();
16990
+ apiKey = fs26.readFileSync(path34.resolve(filePath), "utf8").trim();
16882
16991
  } catch (err) {
16883
16992
  throw new Error(`Could not read --api-key-file ${filePath}: ${err.message}`);
16884
16993
  }
@@ -16923,7 +17032,7 @@ async function link(args2 = []) {
16923
17032
  waitSpin.start(waitMsg());
16924
17033
  const countdown = setInterval(() => waitSpin.message(waitMsg()), 1e3);
16925
17034
  countdown.unref?.();
16926
- const paired = await new Promise((resolve3, reject) => {
17035
+ const paired = await new Promise((resolve4, reject) => {
16927
17036
  let stopPoll = null;
16928
17037
  const sigint = () => {
16929
17038
  clearInterval(countdown);
@@ -16936,7 +17045,7 @@ async function link(args2 = []) {
16936
17045
  process.removeListener("SIGINT", sigint);
16937
17046
  clearInterval(countdown);
16938
17047
  waitSpin.stop("Paired");
16939
- resolve3(info);
17048
+ resolve4(info);
16940
17049
  },
16941
17050
  () => {
16942
17051
  clearInterval(countdown);
@@ -16972,7 +17081,7 @@ async function link(args2 = []) {
16972
17081
  return;
16973
17082
  }
16974
17083
  if (parsed.tokenFile) {
16975
- const credential = fs25.readFileSync(path34.resolve(parsed.tokenFile), "utf8").trim();
17084
+ const credential = fs26.readFileSync(path34.resolve(parsed.tokenFile), "utf8").trim();
16976
17085
  if (!credential) {
16977
17086
  showError(`--token-file ${parsed.tokenFile} is empty.`);
16978
17087
  process.exit(1);
@@ -17042,14 +17151,14 @@ async function captureFreshCredentials(ctx) {
17042
17151
  }
17043
17152
  };
17044
17153
  try {
17045
- const token = await new Promise((resolve3, reject) => {
17154
+ const token = await new Promise((resolve4, reject) => {
17046
17155
  let settled = false;
17047
17156
  const tryExtract = async () => {
17048
17157
  if (settled) return;
17049
17158
  const t2 = await ctx.locator.extract();
17050
17159
  if (t2 && !settled) {
17051
17160
  settled = true;
17052
- resolve3(t2);
17161
+ resolve4(t2);
17053
17162
  }
17054
17163
  };
17055
17164
  watcher.on("add", () => void tryExtract());
@@ -17161,7 +17270,7 @@ async function linkDryRunPreflight(ctx) {
17161
17270
  var import_node_dns = require("dns");
17162
17271
  var import_node_util4 = require("util");
17163
17272
  var import_node_crypto5 = require("crypto");
17164
- var fs26 = __toESM(require("fs"));
17273
+ var fs27 = __toESM(require("fs"));
17165
17274
  var path35 = __toESM(require("path"));
17166
17275
  var import_picocolors12 = __toESM(require("picocolors"));
17167
17276
  var dnsResolveP = (0, import_node_util4.promisify)(import_node_dns.resolve);
@@ -17220,11 +17329,11 @@ async function checkHealth(apiBase) {
17220
17329
  function checkConfigDir() {
17221
17330
  const dir = path35.join(require("os").homedir(), ".codeam");
17222
17331
  try {
17223
- fs26.mkdirSync(dir, { recursive: true, mode: 448 });
17332
+ fs27.mkdirSync(dir, { recursive: true, mode: 448 });
17224
17333
  const probe = path35.join(dir, ".doctor-probe");
17225
- fs26.writeFileSync(probe, "ok", { mode: 384 });
17226
- const read = fs26.readFileSync(probe, "utf8");
17227
- fs26.unlinkSync(probe);
17334
+ fs27.writeFileSync(probe, "ok", { mode: 384 });
17335
+ const read = fs27.readFileSync(probe, "utf8");
17336
+ fs27.unlinkSync(probe);
17228
17337
  if (read !== "ok") throw new Error("write/read round-trip mismatch");
17229
17338
  return {
17230
17339
  id: "config-dir",
@@ -17330,7 +17439,7 @@ function checkChokidar() {
17330
17439
  }
17331
17440
  async function doctor(args2 = []) {
17332
17441
  const json = args2.includes("--json");
17333
- const cliVersion = true ? "2.20.0" : "0.0.0-dev";
17442
+ const cliVersion = true ? "2.20.2" : "0.0.0-dev";
17334
17443
  const apiBase = resolveApiBaseUrl();
17335
17444
  const diagnosticId = (0, import_node_crypto5.randomUUID)();
17336
17445
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -17529,7 +17638,7 @@ async function completion(args2) {
17529
17638
  // src/commands/version.ts
17530
17639
  var import_picocolors13 = __toESM(require("picocolors"));
17531
17640
  function version2() {
17532
- const v = true ? "2.20.0" : "unknown";
17641
+ const v = true ? "2.20.2" : "unknown";
17533
17642
  console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
17534
17643
  }
17535
17644
 
@@ -17657,7 +17766,7 @@ function tryShowSubcommandHelp(cmd, args2) {
17657
17766
  var _subcommandHelpKeys = Object.keys(HELPS);
17658
17767
 
17659
17768
  // src/lib/updateNotifier.ts
17660
- var fs27 = __toESM(require("fs"));
17769
+ var fs28 = __toESM(require("fs"));
17661
17770
  var os25 = __toESM(require("os"));
17662
17771
  var path36 = __toESM(require("path"));
17663
17772
  var https7 = __toESM(require("https"));
@@ -17672,7 +17781,7 @@ function cachePath() {
17672
17781
  }
17673
17782
  function readCache() {
17674
17783
  try {
17675
- const raw = fs27.readFileSync(cachePath(), "utf8");
17784
+ const raw = fs28.readFileSync(cachePath(), "utf8");
17676
17785
  const parsed = JSON.parse(raw);
17677
17786
  if (typeof parsed.fetchedAt !== "number" || typeof parsed.latest !== "string") return null;
17678
17787
  return parsed;
@@ -17683,10 +17792,10 @@ function readCache() {
17683
17792
  function writeCache(cache) {
17684
17793
  try {
17685
17794
  const file = cachePath();
17686
- fs27.mkdirSync(path36.dirname(file), { recursive: true });
17795
+ fs28.mkdirSync(path36.dirname(file), { recursive: true });
17687
17796
  const tmp = `${file}.${process.pid}.tmp`;
17688
- fs27.writeFileSync(tmp, JSON.stringify(cache));
17689
- fs27.renameSync(tmp, file);
17797
+ fs28.writeFileSync(tmp, JSON.stringify(cache));
17798
+ fs28.renameSync(tmp, file);
17690
17799
  } catch {
17691
17800
  }
17692
17801
  }
@@ -17704,14 +17813,14 @@ function compareSemver(a, b) {
17704
17813
  return 0;
17705
17814
  }
17706
17815
  function fetchLatest() {
17707
- return new Promise((resolve3) => {
17816
+ return new Promise((resolve4) => {
17708
17817
  const req = https7.get(
17709
17818
  REGISTRY_URL,
17710
17819
  { headers: { Accept: "application/json" }, timeout: REQUEST_TIMEOUT_MS },
17711
17820
  (res) => {
17712
17821
  if (res.statusCode !== 200) {
17713
17822
  res.resume();
17714
- resolve3(null);
17823
+ resolve4(null);
17715
17824
  return;
17716
17825
  }
17717
17826
  let buf = "";
@@ -17723,21 +17832,21 @@ function fetchLatest() {
17723
17832
  try {
17724
17833
  const json = JSON.parse(buf);
17725
17834
  if (typeof json.version === "string") {
17726
- resolve3(json.version);
17835
+ resolve4(json.version);
17727
17836
  } else {
17728
- resolve3(null);
17837
+ resolve4(null);
17729
17838
  }
17730
17839
  } catch {
17731
- resolve3(null);
17840
+ resolve4(null);
17732
17841
  }
17733
17842
  });
17734
17843
  }
17735
17844
  );
17736
17845
  req.on("timeout", () => {
17737
17846
  req.destroy();
17738
- resolve3(null);
17847
+ resolve4(null);
17739
17848
  });
17740
- req.on("error", () => resolve3(null));
17849
+ req.on("error", () => resolve4(null));
17741
17850
  });
17742
17851
  }
17743
17852
  function notifyIfStale(currentVersion, latest) {
@@ -17757,7 +17866,7 @@ function checkForUpdates() {
17757
17866
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
17758
17867
  if (process.env.CI) return;
17759
17868
  if (!process.stdout.isTTY) return;
17760
- const current = true ? "2.20.0" : null;
17869
+ const current = true ? "2.20.2" : null;
17761
17870
  if (!current) return;
17762
17871
  const cache = readCache();
17763
17872
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;