codeam-cli 2.26.12 → 2.26.14

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 +12 -0
  2. package/dist/index.js +129 -59
  3. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -4,6 +4,18 @@ 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.26.13] — 2026-06-04
8
+
9
+ ### Added
10
+
11
+ - **cli:** Pre-flight install for missing node_modules before preview (#250)
12
+
13
+ ## [2.26.12] — 2026-06-04
14
+
15
+ ### Fixed
16
+
17
+ - **cli:** Gate preview_ready on DNS resolution via c-ares + 1.1.1.1 (#249)
18
+
7
19
  ## [2.26.11] — 2026-06-03
8
20
 
9
21
  ### Added
package/dist/index.js CHANGED
@@ -344,7 +344,7 @@ Return ONLY a JSON object on stdout (no prose, no markdown fences):
344
344
  "port": <number>,
345
345
  "ready_pattern": "<regex matching the server-ready stdout line>",
346
346
  "env": { "HOST": "0.0.0.0" },
347
- "setup_commands": [{"cmd":"npm","args":["install"]}],
347
+ "setup_commands": [],
348
348
  "notes": "<one-line caveat or null>"
349
349
  }
350
350
 
@@ -354,6 +354,20 @@ Rules:
354
354
  - For Expo: framework="Expo", command="npx", args=["expo","start","--tunnel"], port=8081, notes="Scan QR with Expo Go".
355
355
  - If no dev server applies (CLI library, lambda, batch script): {"framework":"unsupported","notes":"<reason>"}.
356
356
 
357
+ CRITICAL \u2014 setup_commands:
358
+ - DO NOT include an install command (npm install, pnpm install, yarn install,
359
+ yarn, bun install) in setup_commands. A lockfile-aware pre-flight installer
360
+ runs BEFORE setup_commands and picks the correct package manager from the
361
+ lockfile present (pnpm-lock.yaml -> pnpm, yarn.lock -> yarn, bun.lockb -> bun,
362
+ else npm). Emitting an install here either duplicates that work or, worse,
363
+ uses the WRONG package manager on top of node_modules just populated by the
364
+ pre-flight, which crashes (e.g. npm errors with "Cannot read properties of
365
+ null (reading 'matches')" when run over pnpm's .pnpm/ layout).
366
+ - ONLY include setup_commands for genuinely non-install work the project needs
367
+ before its dev server can boot: prisma generate, codegen, prebuild scripts,
368
+ database migrations against a local SQLite, etc.
369
+ - For most projects, setup_commands should be an empty array [].
370
+
357
371
  OUTPUT JSON ONLY. NO MARKDOWN. NO COMMENTARY.
358
372
  `.trim();
359
373
 
@@ -472,7 +486,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
472
486
  // package.json
473
487
  var package_default = {
474
488
  name: "codeam-cli",
475
- version: "2.26.12",
489
+ version: "2.26.14",
476
490
  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.",
477
491
  type: "commonjs",
478
492
  main: "dist/index.js",
@@ -546,7 +560,7 @@ var package_default = {
546
560
  chokidar: "^3.6.0",
547
561
  picocolors: "^1.1.0",
548
562
  "qrcode-terminal": "^0.12.0",
549
- which: "^2.0.2",
563
+ which: "^5.0.0",
550
564
  ws: "^8.18.0",
551
565
  zod: "^4.3.6"
552
566
  },
@@ -1115,8 +1129,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
1115
1129
  return decodedFile;
1116
1130
  };
1117
1131
  }
1118
- function normalizeWindowsPath(path42) {
1119
- return path42.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
1132
+ function normalizeWindowsPath(path43) {
1133
+ return path43.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
1120
1134
  }
1121
1135
 
1122
1136
  // ../../node_modules/@posthog/core/dist/featureFlagUtils.mjs
@@ -3596,9 +3610,9 @@ async function addSourceContext(frames) {
3596
3610
  LRU_FILE_CONTENTS_CACHE.reduce();
3597
3611
  return frames;
3598
3612
  }
3599
- function getContextLinesFromFile(path42, ranges, output) {
3613
+ function getContextLinesFromFile(path43, ranges, output) {
3600
3614
  return new Promise((resolve5) => {
3601
- const stream = (0, import_node_fs.createReadStream)(path42);
3615
+ const stream = (0, import_node_fs.createReadStream)(path43);
3602
3616
  const lineReaded = (0, import_node_readline.createInterface)({
3603
3617
  input: stream
3604
3618
  });
@@ -3613,7 +3627,7 @@ function getContextLinesFromFile(path42, ranges, output) {
3613
3627
  let rangeStart = range[0];
3614
3628
  let rangeEnd = range[1];
3615
3629
  function onStreamError() {
3616
- LRU_FILE_CONTENTS_FS_READ_FAILED.set(path42, 1);
3630
+ LRU_FILE_CONTENTS_FS_READ_FAILED.set(path43, 1);
3617
3631
  lineReaded.close();
3618
3632
  lineReaded.removeAllListeners();
3619
3633
  destroyStreamAndResolve();
@@ -3674,8 +3688,8 @@ function clearLineContext(frame) {
3674
3688
  delete frame.context_line;
3675
3689
  delete frame.post_context;
3676
3690
  }
3677
- function shouldSkipContextLinesForFile(path42) {
3678
- return path42.startsWith("node:") || path42.endsWith(".min.js") || path42.endsWith(".min.cjs") || path42.endsWith(".min.mjs") || path42.startsWith("data:");
3691
+ function shouldSkipContextLinesForFile(path43) {
3692
+ return path43.startsWith("node:") || path43.endsWith(".min.js") || path43.endsWith(".min.cjs") || path43.endsWith(".min.mjs") || path43.startsWith("data:");
3679
3693
  }
3680
3694
  function shouldSkipContextLinesForFrame(frame) {
3681
3695
  if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
@@ -5829,7 +5843,7 @@ function readAnonId() {
5829
5843
  }
5830
5844
  function superProperties() {
5831
5845
  return {
5832
- cliVersion: true ? "2.26.12" : "0.0.0-dev",
5846
+ cliVersion: true ? "2.26.14" : "0.0.0-dev",
5833
5847
  nodeVersion: process.version,
5834
5848
  platform: process.platform,
5835
5849
  arch: process.arch,
@@ -9901,13 +9915,13 @@ function detectStartupBanner(lines) {
9901
9915
  while (artStart > 0 && BANNER_ART_RE.test(lines[artStart - 1])) artStart--;
9902
9916
  if (metaIdx - artStart < 2) return null;
9903
9917
  const pathLine = (lines[metaIdx + 1] ?? "").trim();
9904
- const path42 = pathLine && !BANNER_ART_RE.test(pathLine) ? pathLine : "";
9918
+ const path43 = pathLine && !BANNER_ART_RE.test(pathLine) ? pathLine : "";
9905
9919
  return {
9906
9920
  title: "",
9907
9921
  subtitle: lines[metaIdx].trim(),
9908
- path: path42,
9922
+ path: path43,
9909
9923
  startIdx: artStart,
9910
- endIdx: metaIdx + (path42 ? 1 : 0)
9924
+ endIdx: metaIdx + (path43 ? 1 : 0)
9911
9925
  };
9912
9926
  }
9913
9927
 
@@ -11205,11 +11219,11 @@ function parseReview(stdout) {
11205
11219
  for (const line of lines) {
11206
11220
  const m = line.match(HUNK_LINE_RE);
11207
11221
  if (!m) continue;
11208
- const [, path42, lineNo, sevToken, message] = m;
11209
- if (!path42 || !lineNo || !message) continue;
11222
+ const [, path43, lineNo, sevToken, message] = m;
11223
+ if (!path43 || !lineNo || !message) continue;
11210
11224
  const cleanedMessage = message.trim().replace(/^[*-]\s+/, "");
11211
11225
  hunks.push({
11212
- path: path42.trim(),
11226
+ path: path43.trim(),
11213
11227
  line: Number(lineNo),
11214
11228
  severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
11215
11229
  message: cleanedMessage
@@ -13845,7 +13859,7 @@ function defaultRunGit(cwd, args2) {
13845
13859
  });
13846
13860
  }
13847
13861
  async function discoverRepos(workingDir, maxDepth = 4) {
13848
- const fs33 = await import("fs/promises");
13862
+ const fs34 = await import("fs/promises");
13849
13863
  const out2 = [];
13850
13864
  await walk(workingDir, 0);
13851
13865
  return out2;
@@ -13853,7 +13867,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
13853
13867
  if (depth > maxDepth) return;
13854
13868
  let entries = [];
13855
13869
  try {
13856
- const dirents = await fs33.readdir(dir, { withFileTypes: true });
13870
+ const dirents = await fs34.readdir(dir, { withFileTypes: true });
13857
13871
  entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
13858
13872
  } catch {
13859
13873
  return;
@@ -14755,9 +14769,9 @@ function buildKeepAlive(ctx) {
14755
14769
  }
14756
14770
 
14757
14771
  // src/commands/start/handlers.ts
14758
- var fs29 = __toESM(require("fs"));
14772
+ var fs30 = __toESM(require("fs"));
14759
14773
  var os24 = __toESM(require("os"));
14760
- var path35 = __toESM(require("path"));
14774
+ var path36 = __toESM(require("path"));
14761
14775
  var import_crypto5 = require("crypto");
14762
14776
  var import_child_process15 = require("child_process");
14763
14777
 
@@ -16281,6 +16295,31 @@ function parseExpoUrl(stdout) {
16281
16295
  return match ? match[0] : null;
16282
16296
  }
16283
16297
 
16298
+ // src/services/preview/setup-deps.ts
16299
+ var import_fs2 = __toESM(require("fs"));
16300
+ var import_path6 = __toESM(require("path"));
16301
+ function detectMissingNodeDeps(cwd) {
16302
+ if (!import_fs2.default.existsSync(import_path6.default.join(cwd, "package.json"))) return null;
16303
+ if (import_fs2.default.existsSync(import_path6.default.join(cwd, "node_modules"))) return null;
16304
+ if (import_fs2.default.existsSync(import_path6.default.join(cwd, "pnpm-lock.yaml"))) {
16305
+ return { cmd: "pnpm", args: ["install"] };
16306
+ }
16307
+ if (import_fs2.default.existsSync(import_path6.default.join(cwd, "yarn.lock"))) {
16308
+ return { cmd: "yarn", args: ["install"] };
16309
+ }
16310
+ if (import_fs2.default.existsSync(import_path6.default.join(cwd, "bun.lockb")) || import_fs2.default.existsSync(import_path6.default.join(cwd, "bun.lock"))) {
16311
+ return { cmd: "bun", args: ["install"] };
16312
+ }
16313
+ return { cmd: "npm", args: ["install"] };
16314
+ }
16315
+ function isJsInstallCommand(cmd, args2) {
16316
+ const known = ["npm", "pnpm", "yarn", "bun"];
16317
+ if (!known.includes(cmd)) return false;
16318
+ if (cmd === "yarn" && args2.length === 0) return true;
16319
+ const verb = args2[0];
16320
+ return verb === "install" || verb === "i" || verb === "ci";
16321
+ }
16322
+
16284
16323
  // src/services/preview/index.ts
16285
16324
  var activePreviews = /* @__PURE__ */ new Map();
16286
16325
  function registerPreview(sessionId, preview) {
@@ -16326,7 +16365,7 @@ var pendingAttachmentFiles = /* @__PURE__ */ new Set();
16326
16365
  function cleanupAttachmentTempFiles() {
16327
16366
  for (const p2 of pendingAttachmentFiles) {
16328
16367
  try {
16329
- fs29.unlinkSync(p2);
16368
+ fs30.unlinkSync(p2);
16330
16369
  } catch {
16331
16370
  }
16332
16371
  }
@@ -16335,8 +16374,8 @@ function cleanupAttachmentTempFiles() {
16335
16374
  function saveFilesTemp(files) {
16336
16375
  return files.filter(({ base64 }) => base64 && base64.length > 0).map(({ filename, base64 }) => {
16337
16376
  const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
16338
- const tmpPath = path35.join(os24.tmpdir(), `codeam-${(0, import_crypto5.randomUUID)()}-${safeName}`);
16339
- fs29.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
16377
+ const tmpPath = path36.join(os24.tmpdir(), `codeam-${(0, import_crypto5.randomUUID)()}-${safeName}`);
16378
+ fs30.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
16340
16379
  pendingAttachmentFiles.add(tmpPath);
16341
16380
  return tmpPath;
16342
16381
  });
@@ -16356,7 +16395,7 @@ var startTask = (ctx, _cmd, parsed) => {
16356
16395
  setTimeout(() => {
16357
16396
  for (const p2 of paths) {
16358
16397
  try {
16359
- fs29.unlinkSync(p2);
16398
+ fs30.unlinkSync(p2);
16360
16399
  } catch {
16361
16400
  }
16362
16401
  pendingAttachmentFiles.delete(p2);
@@ -16921,7 +16960,38 @@ var previewStartH = (ctx, _cmd, parsed) => {
16921
16960
  payload: { framework: detection.framework, port: detection.port }
16922
16961
  });
16923
16962
  emitProgress("ENV_DETECTED", `${detection.framework}`);
16924
- for (const setup of detection.setup_commands ?? []) {
16963
+ const missingDeps = detectMissingNodeDeps(process.cwd());
16964
+ let preflightRan = false;
16965
+ if (missingDeps) {
16966
+ emitProgress(
16967
+ "SETUP_RUN",
16968
+ `${missingDeps.cmd} ${missingDeps.args.join(" ")} (pre-flight \u2014 node_modules missing)`
16969
+ );
16970
+ const exitCode = await runOnce(
16971
+ missingDeps.cmd,
16972
+ missingDeps.args,
16973
+ process.cwd(),
16974
+ detection.env
16975
+ );
16976
+ if (exitCode !== 0) {
16977
+ void postPreviewEvent({
16978
+ sessionId: ctx.sessionId,
16979
+ pluginId: ctx.pluginId,
16980
+ pluginAuthToken,
16981
+ type: "preview_error",
16982
+ payload: {
16983
+ stage: "spawn",
16984
+ message: `Dependency install failed (${missingDeps.cmd} ${missingDeps.args.join(" ")}, exit ${exitCode}). Run it manually in this project and try again.`
16985
+ }
16986
+ });
16987
+ return;
16988
+ }
16989
+ preflightRan = true;
16990
+ }
16991
+ const agentSetupCommands = preflightRan ? (detection.setup_commands ?? []).filter(
16992
+ (s) => !isJsInstallCommand(s.cmd, s.args)
16993
+ ) : detection.setup_commands ?? [];
16994
+ for (const setup of agentSetupCommands) {
16925
16995
  emitProgress("SETUP_RUN", `${setup.cmd} ${setup.args.join(" ")}`);
16926
16996
  const exitCode = await runOnce(setup.cmd, setup.args, process.cwd(), detection.env);
16927
16997
  if (exitCode !== 0) {
@@ -17636,7 +17706,7 @@ async function autoLinkAfterPair(opts) {
17636
17706
  }
17637
17707
 
17638
17708
  // src/commands/pair-auto.ts
17639
- var fs30 = __toESM(require("fs"));
17709
+ var fs31 = __toESM(require("fs"));
17640
17710
  var os25 = __toESM(require("os"));
17641
17711
  var import_crypto7 = require("crypto");
17642
17712
 
@@ -17805,12 +17875,12 @@ function readTokenFromArgs(args2) {
17805
17875
  }
17806
17876
  const fileFlag = args2.find((a) => a.startsWith("--token-file="));
17807
17877
  if (fileFlag) {
17808
- const path42 = fileFlag.slice("--token-file=".length);
17878
+ const path43 = fileFlag.slice("--token-file=".length);
17809
17879
  try {
17810
- const content = fs30.readFileSync(path42, "utf8").trim();
17811
- if (content.length === 0) fail(`--token-file ${path42} is empty`);
17880
+ const content = fs31.readFileSync(path43, "utf8").trim();
17881
+ if (content.length === 0) fail(`--token-file ${path43} is empty`);
17812
17882
  try {
17813
- fs30.unlinkSync(path42);
17883
+ fs31.unlinkSync(path43);
17814
17884
  } catch {
17815
17885
  }
17816
17886
  return content;
@@ -18076,7 +18146,7 @@ var import_picocolors10 = __toESM(require("picocolors"));
18076
18146
  var import_child_process16 = require("child_process");
18077
18147
  var import_util4 = require("util");
18078
18148
  var import_picocolors8 = __toESM(require("picocolors"));
18079
- var path36 = __toESM(require("path"));
18149
+ var path37 = __toESM(require("path"));
18080
18150
  var execFileP5 = (0, import_util4.promisify)(import_child_process16.execFile);
18081
18151
  var MAX_BUFFER = 8 * 1024 * 1024;
18082
18152
  function resetStdinForChild() {
@@ -18565,7 +18635,7 @@ var GitHubCodespacesProvider = class {
18565
18635
  });
18566
18636
  }
18567
18637
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
18568
- const remoteDir = path36.posix.dirname(remotePath);
18638
+ const remoteDir = path37.posix.dirname(remotePath);
18569
18639
  const parts = [
18570
18640
  `mkdir -p ${shellQuote(remoteDir)}`,
18571
18641
  `cat > ${shellQuote(remotePath)}`
@@ -18635,7 +18705,7 @@ function shellQuote(s) {
18635
18705
  // src/services/providers/gitpod.ts
18636
18706
  var import_child_process17 = require("child_process");
18637
18707
  var import_util5 = require("util");
18638
- var path37 = __toESM(require("path"));
18708
+ var path38 = __toESM(require("path"));
18639
18709
  var import_picocolors9 = __toESM(require("picocolors"));
18640
18710
  var execFileP6 = (0, import_util5.promisify)(import_child_process17.execFile);
18641
18711
  var MAX_BUFFER2 = 8 * 1024 * 1024;
@@ -18875,7 +18945,7 @@ var GitpodProvider = class {
18875
18945
  });
18876
18946
  }
18877
18947
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
18878
- const remoteDir = path37.posix.dirname(remotePath);
18948
+ const remoteDir = path38.posix.dirname(remotePath);
18879
18949
  const parts = [
18880
18950
  `mkdir -p ${shellQuote2(remoteDir)}`,
18881
18951
  `cat > ${shellQuote2(remotePath)}`
@@ -18911,7 +18981,7 @@ function shellQuote2(s) {
18911
18981
  // src/services/providers/gitlab-workspaces.ts
18912
18982
  var import_child_process18 = require("child_process");
18913
18983
  var import_util6 = require("util");
18914
- var path38 = __toESM(require("path"));
18984
+ var path39 = __toESM(require("path"));
18915
18985
  var execFileP7 = (0, import_util6.promisify)(import_child_process18.execFile);
18916
18986
  var MAX_BUFFER3 = 8 * 1024 * 1024;
18917
18987
  var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
@@ -19171,7 +19241,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
19171
19241
  }
19172
19242
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
19173
19243
  const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
19174
- const remoteDir = path38.posix.dirname(remotePath);
19244
+ const remoteDir = path39.posix.dirname(remotePath);
19175
19245
  const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
19176
19246
  if (options.mode != null) {
19177
19247
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
@@ -19239,7 +19309,7 @@ function shellQuote3(s) {
19239
19309
  // src/services/providers/railway.ts
19240
19310
  var import_child_process19 = require("child_process");
19241
19311
  var import_util7 = require("util");
19242
- var path39 = __toESM(require("path"));
19312
+ var path40 = __toESM(require("path"));
19243
19313
  var execFileP8 = (0, import_util7.promisify)(import_child_process19.execFile);
19244
19314
  var MAX_BUFFER4 = 8 * 1024 * 1024;
19245
19315
  function resetStdinForChild4() {
@@ -19475,7 +19545,7 @@ var RailwayProvider = class {
19475
19545
  if (!projectId || !serviceId) {
19476
19546
  throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
19477
19547
  }
19478
- const remoteDir = path39.posix.dirname(remotePath);
19548
+ const remoteDir = path40.posix.dirname(remotePath);
19479
19549
  const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
19480
19550
  if (options.mode != null) {
19481
19551
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
@@ -20018,8 +20088,8 @@ async function stopWorkspaceFromLocal(target) {
20018
20088
  var import_node_dns = require("dns");
20019
20089
  var import_node_util4 = require("util");
20020
20090
  var import_node_crypto6 = require("crypto");
20021
- var fs31 = __toESM(require("fs"));
20022
- var path40 = __toESM(require("path"));
20091
+ var fs32 = __toESM(require("fs"));
20092
+ var path41 = __toESM(require("path"));
20023
20093
  var import_picocolors12 = __toESM(require("picocolors"));
20024
20094
  var dnsResolveP = (0, import_node_util4.promisify)(import_node_dns.resolve);
20025
20095
  async function checkDns(apiBase) {
@@ -20075,13 +20145,13 @@ async function checkHealth(apiBase) {
20075
20145
  }
20076
20146
  }
20077
20147
  function checkConfigDir() {
20078
- const dir = path40.join(require("os").homedir(), ".codeam");
20148
+ const dir = path41.join(require("os").homedir(), ".codeam");
20079
20149
  try {
20080
- fs31.mkdirSync(dir, { recursive: true, mode: 448 });
20081
- const probe = path40.join(dir, ".doctor-probe");
20082
- fs31.writeFileSync(probe, "ok", { mode: 384 });
20083
- const read = fs31.readFileSync(probe, "utf8");
20084
- fs31.unlinkSync(probe);
20150
+ fs32.mkdirSync(dir, { recursive: true, mode: 448 });
20151
+ const probe = path41.join(dir, ".doctor-probe");
20152
+ fs32.writeFileSync(probe, "ok", { mode: 384 });
20153
+ const read = fs32.readFileSync(probe, "utf8");
20154
+ fs32.unlinkSync(probe);
20085
20155
  if (read !== "ok") throw new Error("write/read round-trip mismatch");
20086
20156
  return {
20087
20157
  id: "config-dir",
@@ -20145,7 +20215,7 @@ function checkNodePty() {
20145
20215
  detail: "not required on this platform"
20146
20216
  };
20147
20217
  }
20148
- const vendoredPath = path40.join(__dirname, "vendor", "node-pty");
20218
+ const vendoredPath = path41.join(__dirname, "vendor", "node-pty");
20149
20219
  for (const target of [vendoredPath, "node-pty"]) {
20150
20220
  try {
20151
20221
  require(target);
@@ -20187,7 +20257,7 @@ function checkChokidar() {
20187
20257
  }
20188
20258
  async function doctor(args2 = []) {
20189
20259
  const json = args2.includes("--json");
20190
- const cliVersion = true ? "2.26.12" : "0.0.0-dev";
20260
+ const cliVersion = true ? "2.26.14" : "0.0.0-dev";
20191
20261
  const apiBase = resolveApiBaseUrl();
20192
20262
  const diagnosticId = (0, import_node_crypto6.randomUUID)();
20193
20263
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -20386,7 +20456,7 @@ async function completion(args2) {
20386
20456
  // src/commands/version.ts
20387
20457
  var import_picocolors13 = __toESM(require("picocolors"));
20388
20458
  function version2() {
20389
- const v = true ? "2.26.12" : "unknown";
20459
+ const v = true ? "2.26.14" : "unknown";
20390
20460
  console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
20391
20461
  }
20392
20462
 
@@ -20514,9 +20584,9 @@ function tryShowSubcommandHelp(cmd, args2) {
20514
20584
  var _subcommandHelpKeys = Object.keys(HELPS);
20515
20585
 
20516
20586
  // src/lib/updateNotifier.ts
20517
- var fs32 = __toESM(require("fs"));
20587
+ var fs33 = __toESM(require("fs"));
20518
20588
  var os26 = __toESM(require("os"));
20519
- var path41 = __toESM(require("path"));
20589
+ var path42 = __toESM(require("path"));
20520
20590
  var https7 = __toESM(require("https"));
20521
20591
  var import_picocolors16 = __toESM(require("picocolors"));
20522
20592
  var PKG_NAME = "codeam-cli";
@@ -20524,12 +20594,12 @@ var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
20524
20594
  var TTL_MS = 24 * 60 * 60 * 1e3;
20525
20595
  var REQUEST_TIMEOUT_MS = 1500;
20526
20596
  function cachePath() {
20527
- const dir = path41.join(os26.homedir(), ".codeam");
20528
- return path41.join(dir, "update-check.json");
20597
+ const dir = path42.join(os26.homedir(), ".codeam");
20598
+ return path42.join(dir, "update-check.json");
20529
20599
  }
20530
20600
  function readCache() {
20531
20601
  try {
20532
- const raw = fs32.readFileSync(cachePath(), "utf8");
20602
+ const raw = fs33.readFileSync(cachePath(), "utf8");
20533
20603
  const parsed = JSON.parse(raw);
20534
20604
  if (typeof parsed.fetchedAt !== "number" || typeof parsed.latest !== "string") return null;
20535
20605
  return parsed;
@@ -20540,10 +20610,10 @@ function readCache() {
20540
20610
  function writeCache(cache) {
20541
20611
  try {
20542
20612
  const file = cachePath();
20543
- fs32.mkdirSync(path41.dirname(file), { recursive: true });
20613
+ fs33.mkdirSync(path42.dirname(file), { recursive: true });
20544
20614
  const tmp = `${file}.${process.pid}.tmp`;
20545
- fs32.writeFileSync(tmp, JSON.stringify(cache));
20546
- fs32.renameSync(tmp, file);
20615
+ fs33.writeFileSync(tmp, JSON.stringify(cache));
20616
+ fs33.renameSync(tmp, file);
20547
20617
  } catch {
20548
20618
  }
20549
20619
  }
@@ -20614,7 +20684,7 @@ function checkForUpdates() {
20614
20684
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
20615
20685
  if (process.env.CI) return;
20616
20686
  if (!process.stdout.isTTY) return;
20617
- const current = true ? "2.26.12" : null;
20687
+ const current = true ? "2.26.14" : null;
20618
20688
  if (!current) return;
20619
20689
  const cache = readCache();
20620
20690
  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.26.12",
3
+ "version": "2.26.14",
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",
@@ -74,7 +74,7 @@
74
74
  "chokidar": "^3.6.0",
75
75
  "picocolors": "^1.1.0",
76
76
  "qrcode-terminal": "^0.12.0",
77
- "which": "^2.0.2",
77
+ "which": "^5.0.0",
78
78
  "ws": "^8.18.0",
79
79
  "zod": "^4.3.6"
80
80
  },