codeam-cli 2.39.9 → 2.39.11

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 +177 -122
  3. package/package.json +1 -1
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.39.10] — 2026-06-13
8
+
9
+ ### Fixed
10
+
11
+ - **cli:** Pre-complete Claude onboarding + persist on-demand preview detect
12
+
13
+ ## [2.39.9] — 2026-06-13
14
+
15
+ ### Added
16
+
17
+ - **cli:** Auto-provision project deps (docker compose) gated before the agent
18
+
7
19
  ## [2.39.8] — 2026-06-13
8
20
 
9
21
  ### Fixed
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.39.9",
501
+ version: "2.39.11",
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",
@@ -1186,8 +1186,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
1186
1186
  return decodedFile;
1187
1187
  };
1188
1188
  }
1189
- function normalizeWindowsPath(path54) {
1190
- return path54.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
1189
+ function normalizeWindowsPath(path55) {
1190
+ return path55.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
1191
1191
  }
1192
1192
 
1193
1193
  // ../../node_modules/@posthog/core/dist/featureFlagUtils.mjs
@@ -3667,9 +3667,9 @@ async function addSourceContext(frames) {
3667
3667
  LRU_FILE_CONTENTS_CACHE.reduce();
3668
3668
  return frames;
3669
3669
  }
3670
- function getContextLinesFromFile(path54, ranges, output) {
3670
+ function getContextLinesFromFile(path55, ranges, output) {
3671
3671
  return new Promise((resolve7) => {
3672
- const stream = (0, import_node_fs.createReadStream)(path54);
3672
+ const stream = (0, import_node_fs.createReadStream)(path55);
3673
3673
  const lineReaded = (0, import_node_readline.createInterface)({
3674
3674
  input: stream
3675
3675
  });
@@ -3684,7 +3684,7 @@ function getContextLinesFromFile(path54, ranges, output) {
3684
3684
  let rangeStart = range[0];
3685
3685
  let rangeEnd = range[1];
3686
3686
  function onStreamError() {
3687
- LRU_FILE_CONTENTS_FS_READ_FAILED.set(path54, 1);
3687
+ LRU_FILE_CONTENTS_FS_READ_FAILED.set(path55, 1);
3688
3688
  lineReaded.close();
3689
3689
  lineReaded.removeAllListeners();
3690
3690
  destroyStreamAndResolve();
@@ -3745,8 +3745,8 @@ function clearLineContext(frame) {
3745
3745
  delete frame.context_line;
3746
3746
  delete frame.post_context;
3747
3747
  }
3748
- function shouldSkipContextLinesForFile(path54) {
3749
- return path54.startsWith("node:") || path54.endsWith(".min.js") || path54.endsWith(".min.cjs") || path54.endsWith(".min.mjs") || path54.startsWith("data:");
3748
+ function shouldSkipContextLinesForFile(path55) {
3749
+ return path55.startsWith("node:") || path55.endsWith(".min.js") || path55.endsWith(".min.cjs") || path55.endsWith(".min.mjs") || path55.startsWith("data:");
3750
3750
  }
3751
3751
  function shouldSkipContextLinesForFrame(frame) {
3752
3752
  if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
@@ -5900,13 +5900,29 @@ function readAnonId() {
5900
5900
  }
5901
5901
  function superProperties() {
5902
5902
  return {
5903
- cliVersion: true ? "2.39.9" : "0.0.0-dev",
5903
+ cliVersion: true ? "2.39.11" : "0.0.0-dev",
5904
5904
  nodeVersion: process.version,
5905
5905
  platform: process.platform,
5906
5906
  arch: process.arch,
5907
5907
  osRelease: os4.release()
5908
5908
  };
5909
5909
  }
5910
+ var resilientFetch = async (url, options) => {
5911
+ try {
5912
+ return await fetch(url, options);
5913
+ } catch (err) {
5914
+ log.trace(
5915
+ "telemetry",
5916
+ `posthog transport failed \u2014 dropping batch (network unreachable): ${err instanceof Error ? err.message : String(err)}`
5917
+ );
5918
+ return {
5919
+ status: 200,
5920
+ text: async () => "",
5921
+ json: async () => ({}),
5922
+ body: null
5923
+ };
5924
+ }
5925
+ };
5910
5926
  function initTelemetry() {
5911
5927
  if (client) return true;
5912
5928
  if (isOptedOut()) {
@@ -5926,7 +5942,14 @@ function initTelemetry() {
5926
5942
  // and we shutdown() before exit anyway. Per-batch size caps
5927
5943
  // memory growth on long-lived `codeam start` sessions.
5928
5944
  flushAt: 20,
5929
- flushInterval: 1e4
5945
+ flushInterval: 1e4,
5946
+ // Network failures resolve to a synthetic 200 instead of throwing —
5947
+ // keeps a flaky/offline network from crashing the CLI or spamming the
5948
+ // session PTY. See resilientFetch above.
5949
+ fetch: resilientFetch
5950
+ });
5951
+ client.on("error", (err) => {
5952
+ log.trace("telemetry", "posthog error (ignored)", err);
5930
5953
  });
5931
5954
  client.register(superProperties());
5932
5955
  log.trace("telemetry", `posthog client initialised host=${host} distinctId=${distinctId}`);
@@ -7248,10 +7271,10 @@ function buildForPlatform(platform2) {
7248
7271
  var import_node_crypto4 = require("crypto");
7249
7272
 
7250
7273
  // src/agents/claude/resolver.ts
7251
- function buildClaudeLaunch(extraArgs = [], os32 = createOsStrategy()) {
7252
- const found = os32.findInPath("claude") ?? os32.findInPath("claude-code");
7274
+ function buildClaudeLaunch(extraArgs = [], os33 = createOsStrategy()) {
7275
+ const found = os33.findInPath("claude") ?? os33.findInPath("claude-code");
7253
7276
  if (!found) return null;
7254
- return os32.buildLaunch(found, extraArgs);
7277
+ return os33.buildLaunch(found, extraArgs);
7255
7278
  }
7256
7279
 
7257
7280
  // src/agents/claude/installer.ts
@@ -9978,13 +10001,13 @@ function detectStartupBanner(lines) {
9978
10001
  while (artStart > 0 && BANNER_ART_RE.test(lines[artStart - 1])) artStart--;
9979
10002
  if (metaIdx - artStart < 2) return null;
9980
10003
  const pathLine = (lines[metaIdx + 1] ?? "").trim();
9981
- const path54 = pathLine && !BANNER_ART_RE.test(pathLine) ? pathLine : "";
10004
+ const path55 = pathLine && !BANNER_ART_RE.test(pathLine) ? pathLine : "";
9982
10005
  return {
9983
10006
  title: "",
9984
10007
  subtitle: lines[metaIdx].trim(),
9985
- path: path54,
10008
+ path: path55,
9986
10009
  startIdx: artStart,
9987
- endIdx: metaIdx + (path54 ? 1 : 0)
10010
+ endIdx: metaIdx + (path55 ? 1 : 0)
9988
10011
  };
9989
10012
  }
9990
10013
 
@@ -9994,8 +10017,8 @@ var ClaudeRuntimeStrategy = class {
9994
10017
  meta = getAgent("claude");
9995
10018
  mode = "interactive";
9996
10019
  os;
9997
- constructor(os32) {
9998
- this.os = os32;
10020
+ constructor(os33) {
10021
+ this.os = os33;
9999
10022
  }
10000
10023
  /**
10001
10024
  * Claude Code's react-ink TUI enables bracketed-paste mode at
@@ -11025,8 +11048,8 @@ function codexCredentialLocator() {
11025
11048
  function codexLoginLauncher() {
11026
11049
  return {
11027
11050
  async ensureInstalled() {
11028
- const os32 = createOsStrategy();
11029
- return os32.findInPath("codex") !== null;
11051
+ const os33 = createOsStrategy();
11052
+ return os33.findInPath("codex") !== null;
11030
11053
  },
11031
11054
  launch() {
11032
11055
  return (0, import_node_child_process3.spawn)("codex", ["login"], { stdio: "inherit" });
@@ -11049,8 +11072,8 @@ var CodexRuntimeStrategy = class {
11049
11072
  meta = getAgent("codex");
11050
11073
  mode = "interactive";
11051
11074
  os;
11052
- constructor(os32) {
11053
- this.os = os32;
11075
+ constructor(os33) {
11076
+ this.os = os33;
11054
11077
  }
11055
11078
  async prepareLaunch() {
11056
11079
  let binary = this.os.findInPath("codex");
@@ -11156,12 +11179,12 @@ var CodexRuntimeStrategy = class {
11156
11179
  });
11157
11180
  }
11158
11181
  };
11159
- function resolveNpm(os32) {
11160
- return os32.id === "win32" ? "npm.cmd" : "npm";
11182
+ function resolveNpm(os33) {
11183
+ return os33.id === "win32" ? "npm.cmd" : "npm";
11161
11184
  }
11162
- async function installCodexViaNpm(os32) {
11185
+ async function installCodexViaNpm(os33) {
11163
11186
  return new Promise((resolve7, reject) => {
11164
- const proc = (0, import_node_child_process4.spawn)(resolveNpm(os32), ["install", "-g", "@openai/codex"], {
11187
+ const proc = (0, import_node_child_process4.spawn)(resolveNpm(os33), ["install", "-g", "@openai/codex"], {
11165
11188
  stdio: "inherit"
11166
11189
  });
11167
11190
  proc.on("close", (code) => {
@@ -11178,16 +11201,16 @@ async function installCodexViaNpm(os32) {
11178
11201
  });
11179
11202
  });
11180
11203
  }
11181
- function augmentNpmGlobalBin(os32) {
11204
+ function augmentNpmGlobalBin(os33) {
11182
11205
  try {
11183
- const result = (0, import_node_child_process4.spawnSync)(resolveNpm(os32), ["prefix", "-g"], {
11206
+ const result = (0, import_node_child_process4.spawnSync)(resolveNpm(os33), ["prefix", "-g"], {
11184
11207
  stdio: ["ignore", "pipe", "ignore"]
11185
11208
  });
11186
11209
  if (result.status !== 0) return;
11187
11210
  const prefix = result.stdout.toString().trim();
11188
11211
  if (!prefix) return;
11189
- const binDir = os32.id === "win32" ? prefix : path17.join(prefix, "bin");
11190
- os32.augmentPath([binDir]);
11212
+ const binDir = os33.id === "win32" ? prefix : path17.join(prefix, "bin");
11213
+ os33.augmentPath([binDir]);
11191
11214
  } catch {
11192
11215
  }
11193
11216
  }
@@ -11271,9 +11294,9 @@ var import_node_child_process7 = require("child_process");
11271
11294
  // src/agents/coderabbit/installer.ts
11272
11295
  var import_node_child_process5 = require("child_process");
11273
11296
  var INSTALL_URL = "https://cli.coderabbit.ai/install.sh";
11274
- async function ensureCoderabbitInstalled(os32) {
11275
- if (os32.findInPath("coderabbit")) return true;
11276
- if (os32.id === "win32") {
11297
+ async function ensureCoderabbitInstalled(os33) {
11298
+ if (os33.findInPath("coderabbit")) return true;
11299
+ if (os33.id === "win32") {
11277
11300
  console.error(
11278
11301
  "\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"
11279
11302
  );
@@ -11288,8 +11311,8 @@ async function ensureCoderabbitInstalled(os32) {
11288
11311
  proc.on("error", () => resolve7(false));
11289
11312
  });
11290
11313
  if (!ok) return false;
11291
- os32.augmentPath([`${os32.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
11292
- return os32.findInPath("coderabbit") !== null;
11314
+ os33.augmentPath([`${os33.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
11315
+ return os33.findInPath("coderabbit") !== null;
11293
11316
  }
11294
11317
 
11295
11318
  // src/agents/coderabbit/link.ts
@@ -11316,10 +11339,10 @@ function coderabbitCredentialLocator() {
11316
11339
  extract: extractLocalCoderabbitToken
11317
11340
  };
11318
11341
  }
11319
- function coderabbitLoginLauncher(os32) {
11342
+ function coderabbitLoginLauncher(os33) {
11320
11343
  return {
11321
11344
  async ensureInstalled() {
11322
- return ensureCoderabbitInstalled(os32);
11345
+ return ensureCoderabbitInstalled(os33);
11323
11346
  },
11324
11347
  launch() {
11325
11348
  return (0, import_node_child_process6.spawn)("coderabbit", ["login"], { stdio: "inherit" });
@@ -11342,11 +11365,11 @@ function parseReview(stdout) {
11342
11365
  for (const line of lines) {
11343
11366
  const m = line.match(HUNK_LINE_RE);
11344
11367
  if (!m) continue;
11345
- const [, path54, lineNo, sevToken, message] = m;
11346
- if (!path54 || !lineNo || !message) continue;
11368
+ const [, path55, lineNo, sevToken, message] = m;
11369
+ if (!path55 || !lineNo || !message) continue;
11347
11370
  const cleanedMessage = message.trim().replace(/^[*-]\s+/, "");
11348
11371
  hunks.push({
11349
- path: path54.trim(),
11372
+ path: path55.trim(),
11350
11373
  line: Number(lineNo),
11351
11374
  severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
11352
11375
  message: cleanedMessage
@@ -11365,8 +11388,8 @@ var CoderabbitRuntimeStrategy = class {
11365
11388
  meta = getAgent("coderabbit");
11366
11389
  mode = "batch";
11367
11390
  os;
11368
- constructor(os32) {
11369
- this.os = os32;
11391
+ constructor(os33) {
11392
+ this.os = os33;
11370
11393
  }
11371
11394
  getDefaultArgs() {
11372
11395
  return ["review"];
@@ -11481,10 +11504,10 @@ function cursorCredentialLocator() {
11481
11504
  extract: extractLocalCursorToken
11482
11505
  };
11483
11506
  }
11484
- function cursorLoginLauncher(os32) {
11507
+ function cursorLoginLauncher(os33) {
11485
11508
  return {
11486
11509
  async ensureInstalled() {
11487
- if (os32.findInPath("cursor-agent")) return true;
11510
+ if (os33.findInPath("cursor-agent")) return true;
11488
11511
  console.error(
11489
11512
  "\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"
11490
11513
  );
@@ -11546,8 +11569,8 @@ var CursorRuntimeStrategy = class {
11546
11569
  meta = getAgent("cursor");
11547
11570
  mode = "interactive";
11548
11571
  os;
11549
- constructor(os32) {
11550
- this.os = os32;
11572
+ constructor(os33) {
11573
+ this.os = os33;
11551
11574
  }
11552
11575
  async prepareLaunch() {
11553
11576
  const binary = this.os.findInPath("cursor-agent");
@@ -11667,10 +11690,10 @@ function aiderCredentialLocator() {
11667
11690
  extract: extractLocalAiderToken
11668
11691
  };
11669
11692
  }
11670
- function aiderLoginLauncher(os32) {
11693
+ function aiderLoginLauncher(os33) {
11671
11694
  return {
11672
11695
  async ensureInstalled() {
11673
- if (os32.findInPath("aider")) return true;
11696
+ if (os33.findInPath("aider")) return true;
11674
11697
  console.error(
11675
11698
  "\n \u2717 aider binary not on PATH.\n Install Aider:\n pip install aider-chat\n then re-run `codeam link aider`.\n"
11676
11699
  );
@@ -11680,7 +11703,7 @@ function aiderLoginLauncher(os32) {
11680
11703
  console.error(
11681
11704
  "\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"
11682
11705
  );
11683
- return (0, import_node_child_process9.spawn)(os32.id === "win32" ? "cmd.exe" : "sh", os32.id === "win32" ? ["/c", "exit", "0"] : ["-c", "exit 0"], {
11706
+ return (0, import_node_child_process9.spawn)(os33.id === "win32" ? "cmd.exe" : "sh", os33.id === "win32" ? ["/c", "exit", "0"] : ["-c", "exit 0"], {
11684
11707
  stdio: "ignore"
11685
11708
  });
11686
11709
  }
@@ -11752,8 +11775,8 @@ var AiderRuntimeStrategy = class {
11752
11775
  meta = getAgent("aider");
11753
11776
  mode = "interactive";
11754
11777
  os;
11755
- constructor(os32) {
11756
- this.os = os32;
11778
+ constructor(os33) {
11779
+ this.os = os33;
11757
11780
  }
11758
11781
  async prepareLaunch() {
11759
11782
  const binary = this.os.findInPath("aider");
@@ -11882,8 +11905,8 @@ function geminiCredentialLocator() {
11882
11905
  function geminiLoginLauncher() {
11883
11906
  return {
11884
11907
  async ensureInstalled() {
11885
- const os32 = createOsStrategy();
11886
- return os32.findInPath("gemini") !== null;
11908
+ const os33 = createOsStrategy();
11909
+ return os33.findInPath("gemini") !== null;
11887
11910
  },
11888
11911
  launch() {
11889
11912
  return (0, import_node_child_process10.spawn)("gemini", ["auth", "login"], { stdio: "inherit" });
@@ -11916,8 +11939,8 @@ var GeminiRuntimeStrategy = class {
11916
11939
  meta = getAgent("gemini");
11917
11940
  mode = "interactive";
11918
11941
  os;
11919
- constructor(os32) {
11920
- this.os = os32;
11942
+ constructor(os33) {
11943
+ this.os = os33;
11921
11944
  }
11922
11945
  async prepareLaunch() {
11923
11946
  const binary = this.os.findInPath("gemini");
@@ -12017,18 +12040,18 @@ var GeminiRuntimeStrategy = class {
12017
12040
 
12018
12041
  // src/agents/registry.ts
12019
12042
  var runtimeBuilders = {
12020
- claude: (os32) => new ClaudeRuntimeStrategy(os32),
12021
- codex: (os32) => new CodexRuntimeStrategy(os32),
12022
- coderabbit: (os32) => new CoderabbitRuntimeStrategy(os32),
12023
- cursor: (os32) => new CursorRuntimeStrategy(os32),
12024
- aider: (os32) => new AiderRuntimeStrategy(os32),
12025
- gemini: (os32) => new GeminiRuntimeStrategy(os32)
12043
+ claude: (os33) => new ClaudeRuntimeStrategy(os33),
12044
+ codex: (os33) => new CodexRuntimeStrategy(os33),
12045
+ coderabbit: (os33) => new CoderabbitRuntimeStrategy(os33),
12046
+ cursor: (os33) => new CursorRuntimeStrategy(os33),
12047
+ aider: (os33) => new AiderRuntimeStrategy(os33),
12048
+ gemini: (os33) => new GeminiRuntimeStrategy(os33)
12026
12049
  };
12027
12050
  var deployBuilders = {
12028
12051
  claude: () => new ClaudeDeployStrategy(),
12029
12052
  codex: () => new CodexDeployStrategy()
12030
12053
  };
12031
- function createAgentStrategy(agent, os32 = createOsStrategy()) {
12054
+ function createAgentStrategy(agent, os33 = createOsStrategy()) {
12032
12055
  if (!AGENT_REGISTRY[agent]?.enabled) {
12033
12056
  throw new Error(
12034
12057
  `Agent "${agent}" is not supported in this codeam-cli version. Upgrade with 'npm i -g codeam-cli@latest'.`
@@ -12038,10 +12061,10 @@ function createAgentStrategy(agent, os32 = createOsStrategy()) {
12038
12061
  if (!build) {
12039
12062
  throw new Error(`No runtime strategy registered for agent "${agent}"`);
12040
12063
  }
12041
- return build(os32);
12064
+ return build(os33);
12042
12065
  }
12043
- function createInteractiveAgentStrategy(agent, os32 = createOsStrategy()) {
12044
- const s = createAgentStrategy(agent, os32);
12066
+ function createInteractiveAgentStrategy(agent, os33 = createOsStrategy()) {
12067
+ const s = createAgentStrategy(agent, os33);
12045
12068
  if (s.mode !== "interactive") {
12046
12069
  throw new Error(
12047
12070
  `Agent "${agent}" is a batch agent; use createAgentStrategy + .runOneShot for one-shot reviews.`
@@ -17970,11 +17993,11 @@ function resolveDoltInstallStrategy(platform2) {
17970
17993
  }
17971
17994
  var DOLT_RELEASE_BASE = "https://github.com/dolthub/dolt/releases/latest/download";
17972
17995
  function doltPlatformTuple(platform2, arch) {
17973
- const os32 = platform2 === "win32" ? "windows" : platform2 === "darwin" ? "darwin" : "linux";
17996
+ const os33 = platform2 === "win32" ? "windows" : platform2 === "darwin" ? "darwin" : "linux";
17974
17997
  const a = arch === "x64" ? "amd64" : arch === "arm64" ? "arm64" : null;
17975
17998
  if (!a) return null;
17976
- if (os32 === "windows" && a !== "amd64") return null;
17977
- return `${os32}-${a}`;
17999
+ if (os33 === "windows" && a !== "amd64") return null;
18000
+ return `${os33}-${a}`;
17978
18001
  }
17979
18002
  function resolveDoltTarballStrategy(targetDir, platform2, arch) {
17980
18003
  const tuple = doltPlatformTuple(platform2, arch);
@@ -19457,6 +19480,9 @@ var requestPreviewDetectH = (ctx) => {
19457
19480
  return;
19458
19481
  }
19459
19482
  log.info("preview", `detect: ${detection.framework} on :${detection.port} (took ${tookMs}ms)`);
19483
+ void writePreviewConfig(process.cwd(), detection).catch((err) => {
19484
+ log.info("preview", `detect: writePreviewConfig failed (non-fatal): ${String(err)}`);
19485
+ });
19460
19486
  void postPreviewEvent({
19461
19487
  sessionId: ctx.sessionId,
19462
19488
  pluginId: ctx.pluginId,
@@ -20085,10 +20111,10 @@ var WINDOWS_LEGACY_JUNCTIONS = [
20085
20111
  /[\\/]Start Menu([\\/]|$)/i,
20086
20112
  /[\\/]Templates([\\/]|$)/i
20087
20113
  ];
20088
- function isUnsafeWindowsWatchRoot(dir, homedir25) {
20114
+ function isUnsafeWindowsWatchRoot(dir, homedir26) {
20089
20115
  const norm = (p2) => p2.replace(/\//g, "\\").replace(/\\+$/, "").toLowerCase();
20090
20116
  const cwd = norm(dir);
20091
- const home = norm(homedir25);
20117
+ const home = norm(homedir26);
20092
20118
  if (cwd === home) return true;
20093
20119
  if (/^[a-z]:$/.test(cwd)) return true;
20094
20120
  const sysRoots = [
@@ -20882,7 +20908,7 @@ function defaultRunGit(cwd, args2) {
20882
20908
  });
20883
20909
  }
20884
20910
  async function discoverRepos(workingDir, maxDepth = 4) {
20885
- const fs42 = await import("fs/promises");
20911
+ const fs43 = await import("fs/promises");
20886
20912
  const out2 = [];
20887
20913
  await walk(workingDir, 0);
20888
20914
  return out2;
@@ -20890,7 +20916,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
20890
20916
  if (depth > maxDepth) return;
20891
20917
  let entries = [];
20892
20918
  try {
20893
- const dirents = await fs42.readdir(dir, { withFileTypes: true });
20919
+ const dirents = await fs43.readdir(dir, { withFileTypes: true });
20894
20920
  entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
20895
20921
  } catch {
20896
20922
  return;
@@ -23843,6 +23869,34 @@ function buildKeepAlive(ctx) {
23843
23869
  };
23844
23870
  }
23845
23871
 
23872
+ // src/agents/claude/onboarding.ts
23873
+ var fs39 = __toESM(require("fs"));
23874
+ var os30 = __toESM(require("os"));
23875
+ var path47 = __toESM(require("path"));
23876
+ function ensureClaudeOnboarded() {
23877
+ try {
23878
+ const file = path47.join(os30.homedir(), ".claude.json");
23879
+ let config = {};
23880
+ try {
23881
+ config = JSON.parse(fs39.readFileSync(file, "utf8"));
23882
+ } catch {
23883
+ }
23884
+ if (config.hasCompletedOnboarding === true && typeof config.theme === "string") {
23885
+ return;
23886
+ }
23887
+ config.hasCompletedOnboarding = true;
23888
+ config.theme = typeof config.theme === "string" ? config.theme : "dark";
23889
+ if (typeof config.lastOnboardingVersion !== "string") {
23890
+ config.lastOnboardingVersion = "2.1.177";
23891
+ }
23892
+ fs39.mkdirSync(path47.dirname(file), { recursive: true });
23893
+ fs39.writeFileSync(file, JSON.stringify(config, null, 2));
23894
+ log.info("claude", "pre-completed Claude onboarding (skip first-run theme picker)");
23895
+ } catch (err) {
23896
+ log.warn("claude", `ensureClaudeOnboarded failed (non-fatal): ${err.message}`);
23897
+ }
23898
+ }
23899
+
23846
23900
  // src/commands/start.ts
23847
23901
  async function start(requestedAgent) {
23848
23902
  showIntro();
@@ -23897,6 +23951,7 @@ async function start(requestedAgent) {
23897
23951
  "pluginAuth",
23898
23952
  `boot triple sessionId=${session.id} pluginId=${pluginId} tokenLen=${tokenForLog.length} tokenHead=${tokenForLog.slice(0, 12)} tokenTail=${tokenForLog.slice(-8)} mintedEqualsCached=${refreshed === session.pluginAuthToken}`
23899
23953
  );
23954
+ if (process.env.CODESPACES === "true") ensureClaudeOnboarded();
23900
23955
  let beads = null;
23901
23956
  const getBeads = () => beads;
23902
23957
  const beadsReady = provisionBeadsForStart({
@@ -24312,9 +24367,9 @@ async function autoLinkAfterPair(opts) {
24312
24367
  }
24313
24368
 
24314
24369
  // src/commands/pair-auto.ts
24315
- var fs39 = __toESM(require("fs"));
24316
- var os30 = __toESM(require("os"));
24317
- var path47 = __toESM(require("path"));
24370
+ var fs40 = __toESM(require("fs"));
24371
+ var os31 = __toESM(require("os"));
24372
+ var path48 = __toESM(require("path"));
24318
24373
  var import_crypto7 = require("crypto");
24319
24374
 
24320
24375
  // src/commands/start-infra-only.ts
@@ -24509,12 +24564,12 @@ function readTokenFromArgs(args2) {
24509
24564
  }
24510
24565
  const fileFlag = args2.find((a) => a.startsWith("--token-file="));
24511
24566
  if (fileFlag) {
24512
- const path54 = fileFlag.slice("--token-file=".length);
24567
+ const path55 = fileFlag.slice("--token-file=".length);
24513
24568
  try {
24514
- const content = fs39.readFileSync(path54, "utf8").trim();
24515
- if (content.length === 0) fail(`--token-file ${path54} is empty`);
24569
+ const content = fs40.readFileSync(path55, "utf8").trim();
24570
+ if (content.length === 0) fail(`--token-file ${path55} is empty`);
24516
24571
  try {
24517
- fs39.unlinkSync(path54);
24572
+ fs40.unlinkSync(path55);
24518
24573
  } catch {
24519
24574
  }
24520
24575
  return content;
@@ -24540,7 +24595,7 @@ async function claimOnce(token, pluginId) {
24540
24595
  pluginId,
24541
24596
  ideName: "codeam-cli (codespace)",
24542
24597
  ideVersion: process.env.npm_package_version ?? "unknown",
24543
- hostname: os30.hostname(),
24598
+ hostname: os31.hostname(),
24544
24599
  codespaceName: process.env.CODESPACE_NAME ?? "",
24545
24600
  // Current git branch of the codespace's working directory, so the
24546
24601
  // backend can populate `PairedSession.branch` for the codespace pair.
@@ -24597,7 +24652,7 @@ async function claim(token, pluginId) {
24597
24652
  }
24598
24653
  }
24599
24654
  function pairAutoLockPath() {
24600
- return path47.join(os30.homedir(), ".codeam", "pair-auto.lock");
24655
+ return path48.join(os31.homedir(), ".codeam", "pair-auto.lock");
24601
24656
  }
24602
24657
  function isLivePairAuto(pid) {
24603
24658
  if (!Number.isInteger(pid) || pid <= 0 || pid === process.pid) return false;
@@ -24607,7 +24662,7 @@ function isLivePairAuto(pid) {
24607
24662
  if (e.code !== "EPERM") return false;
24608
24663
  }
24609
24664
  try {
24610
- return fs39.readFileSync(`/proc/${pid}/cmdline`, "utf8").includes("codeam");
24665
+ return fs40.readFileSync(`/proc/${pid}/cmdline`, "utf8").includes("codeam");
24611
24666
  } catch {
24612
24667
  return true;
24613
24668
  }
@@ -24615,19 +24670,19 @@ function isLivePairAuto(pid) {
24615
24670
  function acquireSingletonLock() {
24616
24671
  const lockPath = pairAutoLockPath();
24617
24672
  try {
24618
- fs39.mkdirSync(path47.dirname(lockPath), { recursive: true });
24673
+ fs40.mkdirSync(path48.dirname(lockPath), { recursive: true });
24619
24674
  try {
24620
- fs39.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
24675
+ fs40.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
24621
24676
  } catch (e) {
24622
24677
  if (e.code !== "EEXIST") throw e;
24623
- const holder = Number(fs39.readFileSync(lockPath, "utf8").trim());
24678
+ const holder = Number(fs40.readFileSync(lockPath, "utf8").trim());
24624
24679
  if (isLivePairAuto(holder)) return false;
24625
- fs39.writeFileSync(lockPath, String(process.pid));
24680
+ fs40.writeFileSync(lockPath, String(process.pid));
24626
24681
  }
24627
24682
  process.once("exit", () => {
24628
24683
  try {
24629
- if (fs39.existsSync(lockPath) && Number(fs39.readFileSync(lockPath, "utf8").trim()) === process.pid) {
24630
- fs39.unlinkSync(lockPath);
24684
+ if (fs40.existsSync(lockPath) && Number(fs40.readFileSync(lockPath, "utf8").trim()) === process.pid) {
24685
+ fs40.unlinkSync(lockPath);
24631
24686
  }
24632
24687
  } catch {
24633
24688
  }
@@ -24826,7 +24881,7 @@ var import_picocolors10 = __toESM(require("picocolors"));
24826
24881
  var import_child_process22 = require("child_process");
24827
24882
  var import_util4 = require("util");
24828
24883
  var import_picocolors8 = __toESM(require("picocolors"));
24829
- var path48 = __toESM(require("path"));
24884
+ var path49 = __toESM(require("path"));
24830
24885
  var execFileP5 = (0, import_util4.promisify)(import_child_process22.execFile);
24831
24886
  var MAX_BUFFER = 8 * 1024 * 1024;
24832
24887
  function resetStdinForChild() {
@@ -25315,7 +25370,7 @@ var GitHubCodespacesProvider = class {
25315
25370
  });
25316
25371
  }
25317
25372
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
25318
- const remoteDir = path48.posix.dirname(remotePath);
25373
+ const remoteDir = path49.posix.dirname(remotePath);
25319
25374
  const parts = [
25320
25375
  `mkdir -p ${shellQuote(remoteDir)}`,
25321
25376
  `cat > ${shellQuote(remotePath)}`
@@ -25385,7 +25440,7 @@ function shellQuote(s) {
25385
25440
  // src/services/providers/gitpod.ts
25386
25441
  var import_child_process23 = require("child_process");
25387
25442
  var import_util5 = require("util");
25388
- var path49 = __toESM(require("path"));
25443
+ var path50 = __toESM(require("path"));
25389
25444
  var import_picocolors9 = __toESM(require("picocolors"));
25390
25445
  var execFileP6 = (0, import_util5.promisify)(import_child_process23.execFile);
25391
25446
  var MAX_BUFFER2 = 8 * 1024 * 1024;
@@ -25625,7 +25680,7 @@ var GitpodProvider = class {
25625
25680
  });
25626
25681
  }
25627
25682
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
25628
- const remoteDir = path49.posix.dirname(remotePath);
25683
+ const remoteDir = path50.posix.dirname(remotePath);
25629
25684
  const parts = [
25630
25685
  `mkdir -p ${shellQuote2(remoteDir)}`,
25631
25686
  `cat > ${shellQuote2(remotePath)}`
@@ -25661,7 +25716,7 @@ function shellQuote2(s) {
25661
25716
  // src/services/providers/gitlab-workspaces.ts
25662
25717
  var import_child_process24 = require("child_process");
25663
25718
  var import_util6 = require("util");
25664
- var path50 = __toESM(require("path"));
25719
+ var path51 = __toESM(require("path"));
25665
25720
  var execFileP7 = (0, import_util6.promisify)(import_child_process24.execFile);
25666
25721
  var MAX_BUFFER3 = 8 * 1024 * 1024;
25667
25722
  var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
@@ -25921,7 +25976,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
25921
25976
  }
25922
25977
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
25923
25978
  const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
25924
- const remoteDir = path50.posix.dirname(remotePath);
25979
+ const remoteDir = path51.posix.dirname(remotePath);
25925
25980
  const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
25926
25981
  if (options.mode != null) {
25927
25982
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
@@ -25989,7 +26044,7 @@ function shellQuote3(s) {
25989
26044
  // src/services/providers/railway.ts
25990
26045
  var import_child_process25 = require("child_process");
25991
26046
  var import_util7 = require("util");
25992
- var path51 = __toESM(require("path"));
26047
+ var path52 = __toESM(require("path"));
25993
26048
  var execFileP8 = (0, import_util7.promisify)(import_child_process25.execFile);
25994
26049
  var MAX_BUFFER4 = 8 * 1024 * 1024;
25995
26050
  function resetStdinForChild4() {
@@ -26225,7 +26280,7 @@ var RailwayProvider = class {
26225
26280
  if (!projectId || !serviceId) {
26226
26281
  throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
26227
26282
  }
26228
- const remoteDir = path51.posix.dirname(remotePath);
26283
+ const remoteDir = path52.posix.dirname(remotePath);
26229
26284
  const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
26230
26285
  if (options.mode != null) {
26231
26286
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
@@ -26768,8 +26823,8 @@ async function stopWorkspaceFromLocal(target) {
26768
26823
  var import_node_dns = require("dns");
26769
26824
  var import_node_util4 = require("util");
26770
26825
  var import_node_crypto8 = require("crypto");
26771
- var fs40 = __toESM(require("fs"));
26772
- var path52 = __toESM(require("path"));
26826
+ var fs41 = __toESM(require("fs"));
26827
+ var path53 = __toESM(require("path"));
26773
26828
  var import_picocolors12 = __toESM(require("picocolors"));
26774
26829
  var dnsResolveP = (0, import_node_util4.promisify)(import_node_dns.resolve);
26775
26830
  async function checkDns(apiBase) {
@@ -26825,13 +26880,13 @@ async function checkHealth(apiBase) {
26825
26880
  }
26826
26881
  }
26827
26882
  function checkConfigDir() {
26828
- const dir = path52.join(require("os").homedir(), ".codeam");
26883
+ const dir = path53.join(require("os").homedir(), ".codeam");
26829
26884
  try {
26830
- fs40.mkdirSync(dir, { recursive: true, mode: 448 });
26831
- const probe = path52.join(dir, ".doctor-probe");
26832
- fs40.writeFileSync(probe, "ok", { mode: 384 });
26833
- const read = fs40.readFileSync(probe, "utf8");
26834
- fs40.unlinkSync(probe);
26885
+ fs41.mkdirSync(dir, { recursive: true, mode: 448 });
26886
+ const probe = path53.join(dir, ".doctor-probe");
26887
+ fs41.writeFileSync(probe, "ok", { mode: 384 });
26888
+ const read = fs41.readFileSync(probe, "utf8");
26889
+ fs41.unlinkSync(probe);
26835
26890
  if (read !== "ok") throw new Error("write/read round-trip mismatch");
26836
26891
  return {
26837
26892
  id: "config-dir",
@@ -26871,9 +26926,9 @@ function checkSessions() {
26871
26926
  }
26872
26927
  }
26873
26928
  function checkAgentBinaries() {
26874
- const os32 = createOsStrategy();
26929
+ const os33 = createOsStrategy();
26875
26930
  return getEnabledAgents().map((meta) => {
26876
- const found = os32.findInPath(meta.binaryName);
26931
+ const found = os33.findInPath(meta.binaryName);
26877
26932
  return {
26878
26933
  id: `agent-${meta.id}`,
26879
26934
  label: `Agent binary: ${meta.displayName} (${meta.binaryName})`,
@@ -26895,7 +26950,7 @@ function checkNodePty() {
26895
26950
  detail: "not required on this platform"
26896
26951
  };
26897
26952
  }
26898
- const vendoredPath = path52.join(__dirname, "vendor", "node-pty");
26953
+ const vendoredPath = path53.join(__dirname, "vendor", "node-pty");
26899
26954
  for (const target of [vendoredPath, "node-pty"]) {
26900
26955
  try {
26901
26956
  require(target);
@@ -26937,7 +26992,7 @@ function checkChokidar() {
26937
26992
  }
26938
26993
  async function doctor(args2 = []) {
26939
26994
  const json = args2.includes("--json");
26940
- const cliVersion = true ? "2.39.9" : "0.0.0-dev";
26995
+ const cliVersion = true ? "2.39.11" : "0.0.0-dev";
26941
26996
  const apiBase = resolveApiBaseUrl();
26942
26997
  const diagnosticId = (0, import_node_crypto8.randomUUID)();
26943
26998
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -27136,7 +27191,7 @@ async function completion(args2) {
27136
27191
  // src/commands/version.ts
27137
27192
  var import_picocolors13 = __toESM(require("picocolors"));
27138
27193
  function version2() {
27139
- const v = true ? "2.39.9" : "unknown";
27194
+ const v = true ? "2.39.11" : "unknown";
27140
27195
  console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
27141
27196
  }
27142
27197
 
@@ -27264,9 +27319,9 @@ function tryShowSubcommandHelp(cmd, args2) {
27264
27319
  var _subcommandHelpKeys = Object.keys(HELPS);
27265
27320
 
27266
27321
  // src/lib/updateNotifier.ts
27267
- var fs41 = __toESM(require("fs"));
27268
- var os31 = __toESM(require("os"));
27269
- var path53 = __toESM(require("path"));
27322
+ var fs42 = __toESM(require("fs"));
27323
+ var os32 = __toESM(require("os"));
27324
+ var path54 = __toESM(require("path"));
27270
27325
  var https8 = __toESM(require("https"));
27271
27326
  var import_node_child_process12 = require("child_process");
27272
27327
  var import_picocolors16 = __toESM(require("picocolors"));
@@ -27275,12 +27330,12 @@ var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
27275
27330
  var TTL_MS = 24 * 60 * 60 * 1e3;
27276
27331
  var REQUEST_TIMEOUT_MS = 1500;
27277
27332
  function cachePath() {
27278
- const dir = path53.join(os31.homedir(), ".codeam");
27279
- return path53.join(dir, "update-check.json");
27333
+ const dir = path54.join(os32.homedir(), ".codeam");
27334
+ return path54.join(dir, "update-check.json");
27280
27335
  }
27281
27336
  function readCache() {
27282
27337
  try {
27283
- const raw = fs41.readFileSync(cachePath(), "utf8");
27338
+ const raw = fs42.readFileSync(cachePath(), "utf8");
27284
27339
  const parsed = JSON.parse(raw);
27285
27340
  if (typeof parsed.fetchedAt !== "number" || typeof parsed.latest !== "string") return null;
27286
27341
  return parsed;
@@ -27291,10 +27346,10 @@ function readCache() {
27291
27346
  function writeCache(cache) {
27292
27347
  try {
27293
27348
  const file = cachePath();
27294
- fs41.mkdirSync(path53.dirname(file), { recursive: true });
27349
+ fs42.mkdirSync(path54.dirname(file), { recursive: true });
27295
27350
  const tmp = `${file}.${process.pid}.tmp`;
27296
- fs41.writeFileSync(tmp, JSON.stringify(cache));
27297
- fs41.renameSync(tmp, file);
27351
+ fs42.writeFileSync(tmp, JSON.stringify(cache));
27352
+ fs42.renameSync(tmp, file);
27298
27353
  } catch {
27299
27354
  }
27300
27355
  }
@@ -27368,8 +27423,8 @@ function isLinkedInstall() {
27368
27423
  timeout: 2e3
27369
27424
  }).trim();
27370
27425
  if (!root) return false;
27371
- const pkgPath = path53.join(root, PKG_NAME);
27372
- return fs41.lstatSync(pkgPath).isSymbolicLink();
27426
+ const pkgPath = path54.join(root, PKG_NAME);
27427
+ return fs42.lstatSync(pkgPath).isSymbolicLink();
27373
27428
  } catch {
27374
27429
  return false;
27375
27430
  }
@@ -27405,7 +27460,7 @@ function maybeAutoUpdate(currentVersion, latest) {
27405
27460
  return;
27406
27461
  }
27407
27462
  try {
27408
- fs41.unlinkSync(cachePath());
27463
+ fs42.unlinkSync(cachePath());
27409
27464
  } catch {
27410
27465
  }
27411
27466
  process.stderr.write(` ${import_picocolors16.default.green("\u2713")} Updated. Resuming session...
@@ -27422,7 +27477,7 @@ function checkForUpdates() {
27422
27477
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
27423
27478
  if (process.env.CI) return;
27424
27479
  if (!process.stdout.isTTY) return;
27425
- const current = true ? "2.39.9" : null;
27480
+ const current = true ? "2.39.11" : null;
27426
27481
  if (!current) return;
27427
27482
  const cache = readCache();
27428
27483
  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.39.9",
3
+ "version": "2.39.11",
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",