codeam-cli 2.65.1 → 2.65.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 +21 -0
  2. package/dist/index.js +299 -183
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,27 @@ 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.65.1] — 2026-08-14
8
+
9
+ ### Added
10
+
11
+ - **shared:** Canonical per-agent install snippets (INSTALL_SNIPPETS)
12
+
13
+ ### CI
14
+
15
+ - **workflow:** Nightly + path-triggered real agent-install gate
16
+
17
+ ### Fixed
18
+
19
+ - **cli:** Retry agent install once on post-install probe failure + 300s switch install budget
20
+ - **cli:** Codex adapter augments user-local bin PATH before probing (stale-PATH class)
21
+ - **cli:** Three stale-PATH/misreported-install bugs found by the real install gate
22
+ - **cli:** Pre-tag wave — coderabbit runnability authority, retry progress, harness hardening
23
+
24
+ ### Tests
25
+
26
+ - **cli:** Real per-agent install integration gate (Docker, minimal PATH)
27
+
7
28
  ## [2.65.0] — 2026-08-14
8
29
 
9
30
  ### Added
package/dist/index.js CHANGED
@@ -3148,11 +3148,11 @@ function quiet(fn) {
3148
3148
  log.debug(TAG, "ignored sync error", err);
3149
3149
  }
3150
3150
  }
3151
- function rmIfExistsQuiet(path91) {
3151
+ function rmIfExistsQuiet(path92) {
3152
3152
  try {
3153
- fs2.rmSync(path91, { force: true });
3153
+ fs2.rmSync(path92, { force: true });
3154
3154
  } catch (err) {
3155
- log.debug(TAG, `rmIfExists failed for ${path91}`, err);
3155
+ log.debug(TAG, `rmIfExists failed for ${path92}`, err);
3156
3156
  }
3157
3157
  }
3158
3158
  function killQuiet(target, signal = "SIGTERM") {
@@ -3359,8 +3359,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
3359
3359
  return decodedFile;
3360
3360
  };
3361
3361
  }
3362
- function normalizeWindowsPath(path91) {
3363
- return path91.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
3362
+ function normalizeWindowsPath(path92) {
3363
+ return path92.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
3364
3364
  }
3365
3365
 
3366
3366
  // ../../node_modules/@posthog/core/dist/featureFlagUtils.mjs
@@ -5840,9 +5840,9 @@ async function addSourceContext(frames) {
5840
5840
  LRU_FILE_CONTENTS_CACHE.reduce();
5841
5841
  return frames;
5842
5842
  }
5843
- function getContextLinesFromFile(path91, ranges, output) {
5843
+ function getContextLinesFromFile(path92, ranges, output) {
5844
5844
  return new Promise((resolve9) => {
5845
- const stream = (0, import_node_fs.createReadStream)(path91);
5845
+ const stream = (0, import_node_fs.createReadStream)(path92);
5846
5846
  const lineReaded = (0, import_node_readline.createInterface)({
5847
5847
  input: stream
5848
5848
  });
@@ -5857,7 +5857,7 @@ function getContextLinesFromFile(path91, ranges, output) {
5857
5857
  let rangeStart = range[0];
5858
5858
  let rangeEnd = range[1];
5859
5859
  function onStreamError() {
5860
- LRU_FILE_CONTENTS_FS_READ_FAILED.set(path91, 1);
5860
+ LRU_FILE_CONTENTS_FS_READ_FAILED.set(path92, 1);
5861
5861
  lineReaded.close();
5862
5862
  lineReaded.removeAllListeners();
5863
5863
  destroyStreamAndResolve();
@@ -5918,8 +5918,8 @@ function clearLineContext(frame) {
5918
5918
  delete frame.context_line;
5919
5919
  delete frame.post_context;
5920
5920
  }
5921
- function shouldSkipContextLinesForFile(path91) {
5922
- return path91.startsWith("node:") || path91.endsWith(".min.js") || path91.endsWith(".min.cjs") || path91.endsWith(".min.mjs") || path91.startsWith("data:");
5921
+ function shouldSkipContextLinesForFile(path92) {
5922
+ return path92.startsWith("node:") || path92.endsWith(".min.js") || path92.endsWith(".min.cjs") || path92.endsWith(".min.mjs") || path92.startsWith("data:");
5923
5923
  }
5924
5924
  function shouldSkipContextLinesForFrame(frame) {
5925
5925
  if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
@@ -8073,7 +8073,7 @@ function readAnonId() {
8073
8073
  }
8074
8074
  function superProperties() {
8075
8075
  return {
8076
- cliVersion: true ? "2.65.1" : "0.0.0-dev",
8076
+ cliVersion: true ? "2.65.2" : "0.0.0-dev",
8077
8077
  nodeVersion: process.version,
8078
8078
  platform: process.platform,
8079
8079
  arch: process.arch,
@@ -8254,7 +8254,7 @@ var os4 = __toESM(require("os"));
8254
8254
  // package.json
8255
8255
  var package_default = {
8256
8256
  name: "codeam-cli",
8257
- version: "2.65.1",
8257
+ version: "2.65.2",
8258
8258
  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.",
8259
8259
  type: "commonjs",
8260
8260
  main: "dist/index.js",
@@ -9706,7 +9706,7 @@ var CommandRelayService = class _CommandRelayService {
9706
9706
  // fresh + clear the "CLI update available" banner after a self-update
9707
9707
  // (a codespace that reinstalls @latest reconnects via heartbeat, not
9708
9708
  // pair/reconnect). Older backends ignore the extra field.
9709
- ..."2.65.1" ? { ideVersion: "2.65.1" } : {}
9709
+ ..."2.65.2" ? { ideVersion: "2.65.2" } : {}
9710
9710
  }).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
9711
9711
  }
9712
9712
  /**
@@ -14610,10 +14610,10 @@ function buildForPlatform(platform3) {
14610
14610
  var import_node_crypto4 = require("crypto");
14611
14611
 
14612
14612
  // src/agents/claude/resolver.ts
14613
- function buildClaudeLaunch(extraArgs = [], os66 = createOsStrategy()) {
14614
- const found = os66.findInPath("claude") ?? os66.findInPath("claude-code");
14613
+ function buildClaudeLaunch(extraArgs = [], os67 = createOsStrategy()) {
14614
+ const found = os67.findInPath("claude") ?? os67.findInPath("claude-code");
14615
14615
  if (!found) return null;
14616
- return os66.buildLaunch(found, extraArgs);
14616
+ return os67.buildLaunch(found, extraArgs);
14617
14617
  }
14618
14618
 
14619
14619
  // src/agents/claude/installer.ts
@@ -15203,8 +15203,8 @@ var ClaudeRuntimeStrategy = class {
15203
15203
  meta = getAgent("claude");
15204
15204
  mode = "interactive";
15205
15205
  os;
15206
- constructor(os66) {
15207
- this.os = os66;
15206
+ constructor(os67) {
15207
+ this.os = os67;
15208
15208
  }
15209
15209
  /**
15210
15210
  * Claude Code's react-ink TUI enables bracketed-paste mode at
@@ -15984,8 +15984,8 @@ function codexCredentialLocator() {
15984
15984
  function codexLoginLauncher() {
15985
15985
  return {
15986
15986
  async ensureInstalled() {
15987
- const os66 = createOsStrategy();
15988
- return os66.findInPath("codex") !== null;
15987
+ const os67 = createOsStrategy();
15988
+ return os67.findInPath("codex") !== null;
15989
15989
  },
15990
15990
  launch() {
15991
15991
  return (0, import_node_child_process4.spawn)("codex", ["login"], { stdio: "inherit" });
@@ -16008,8 +16008,8 @@ var CodexRuntimeStrategy = class {
16008
16008
  meta = getAgent("codex");
16009
16009
  mode = "interactive";
16010
16010
  os;
16011
- constructor(os66) {
16012
- this.os = os66;
16011
+ constructor(os67) {
16012
+ this.os = os67;
16013
16013
  }
16014
16014
  async prepareLaunch() {
16015
16015
  let binary = this.os.findInPath("codex");
@@ -16118,12 +16118,12 @@ var CodexRuntimeStrategy = class {
16118
16118
  });
16119
16119
  }
16120
16120
  };
16121
- function resolveNpm(os66) {
16122
- return os66.id === "win32" ? "npm.cmd" : "npm";
16121
+ function resolveNpm(os67) {
16122
+ return os67.id === "win32" ? "npm.cmd" : "npm";
16123
16123
  }
16124
- async function installCodexViaNpm(os66) {
16124
+ async function installCodexViaNpm(os67) {
16125
16125
  return new Promise((resolve9, reject) => {
16126
- const proc = (0, import_node_child_process5.spawn)(resolveNpm(os66), ["install", "-g", "@openai/codex"], {
16126
+ const proc = (0, import_node_child_process5.spawn)(resolveNpm(os67), ["install", "-g", "@openai/codex"], {
16127
16127
  stdio: "inherit"
16128
16128
  });
16129
16129
  proc.on("close", (code) => {
@@ -16140,16 +16140,16 @@ async function installCodexViaNpm(os66) {
16140
16140
  });
16141
16141
  });
16142
16142
  }
16143
- function augmentNpmGlobalBin(os66) {
16143
+ function augmentNpmGlobalBin(os67) {
16144
16144
  try {
16145
- const result = (0, import_node_child_process5.spawnSync)(resolveNpm(os66), ["prefix", "-g"], {
16145
+ const result = (0, import_node_child_process5.spawnSync)(resolveNpm(os67), ["prefix", "-g"], {
16146
16146
  stdio: ["ignore", "pipe", "ignore"]
16147
16147
  });
16148
16148
  if (result.status !== 0) return;
16149
16149
  const prefix = result.stdout.toString().trim();
16150
16150
  if (!prefix) return;
16151
- const binDir = os66.id === "win32" ? prefix : path25.join(prefix, "bin");
16152
- os66.augmentPath([binDir]);
16151
+ const binDir = os67.id === "win32" ? prefix : path25.join(prefix, "bin");
16152
+ os67.augmentPath([binDir]);
16153
16153
  } catch {
16154
16154
  }
16155
16155
  }
@@ -16560,10 +16560,10 @@ function manualInstallHint(runner, tools) {
16560
16560
  const argv = osPackageInstallArgv(detectPackageManager(runner), [...tools]);
16561
16561
  return argv ? `\`sudo ${argv.join(" ")}\`` : `your package manager (e.g. \`${pkgs}\`)`;
16562
16562
  }
16563
- function writeUnzipShim(os66, runner) {
16563
+ function writeUnzipShim(os67, runner) {
16564
16564
  const python = ["python3", "python"].find((p2) => runner.which(p2));
16565
16565
  if (!python) return null;
16566
- const dir = os66.scratchPath("codeam-cr-prereq");
16566
+ const dir = os67.scratchPath("codeam-cr-prereq");
16567
16567
  const shim = path27.join(dir, "unzip");
16568
16568
  const script = `#!/bin/sh
16569
16569
  set -e
@@ -16585,9 +16585,9 @@ exec ${python} -m zipfile -e "$archive" "$dest"
16585
16585
  (0, import_node_fs5.chmodSync)(shim, 448);
16586
16586
  return dir;
16587
16587
  }
16588
- async function ensureInstallPrerequisites(os66, deps = {}) {
16588
+ async function ensureInstallPrerequisites(os67, deps = {}) {
16589
16589
  const runner = deps.runner ?? defaultHeadroomRunner;
16590
- const missing = REQUIRED_TOOLS.filter((t2) => os66.findInPath(t2) === null);
16590
+ const missing = REQUIRED_TOOLS.filter((t2) => os67.findInPath(t2) === null);
16591
16591
  if (missing.length === 0) return { ok: true, extraPath: [] };
16592
16592
  log.info(
16593
16593
  "coderabbit",
@@ -16606,10 +16606,10 @@ async function ensureInstallPrerequisites(os66, deps = {}) {
16606
16606
  );
16607
16607
  }
16608
16608
  }
16609
- const stillMissing = REQUIRED_TOOLS.filter((t2) => os66.findInPath(t2) === null);
16609
+ const stillMissing = REQUIRED_TOOLS.filter((t2) => os67.findInPath(t2) === null);
16610
16610
  if (stillMissing.length === 0) return { ok: true, extraPath: [] };
16611
16611
  if (stillMissing.length === 1 && stillMissing[0] === "unzip") {
16612
- const shimDir = writeUnzipShim(os66, runner);
16612
+ const shimDir = writeUnzipShim(os67, runner);
16613
16613
  if (shimDir) {
16614
16614
  log.info("coderabbit", "unzip is unavailable \u2014 using a scoped python zipfile shim");
16615
16615
  return { ok: true, extraPath: [shimDir] };
@@ -16672,15 +16672,15 @@ function summarizeInstallFailure(output) {
16672
16672
  }
16673
16673
  return lines.length > 0 ? lines[lines.length - 1] : null;
16674
16674
  }
16675
- async function ensureCoderabbitInstalled(os66, deps = {}) {
16676
- if (os66.findInPath("coderabbit")) return { ok: true };
16677
- if (os66.id === "win32") {
16675
+ async function ensureCoderabbitInstalled(os67, deps = {}) {
16676
+ if (os67.findInPath("coderabbit")) return { ok: true };
16677
+ if (os67.id === "win32") {
16678
16678
  return {
16679
16679
  ok: false,
16680
16680
  error: "CodeRabbit on Windows requires WSL. Install the CLI inside your WSL distribution (curl -fsSL https://cli.coderabbit.ai/install.sh | sh), then try again."
16681
16681
  };
16682
16682
  }
16683
- const prereq = await ensureInstallPrerequisites(os66, deps);
16683
+ const prereq = await ensureInstallPrerequisites(os67, deps);
16684
16684
  if (!prereq.ok) return { ok: false, error: prereq.error };
16685
16685
  const env = { ...process.env };
16686
16686
  if (prereq.extraPath.length > 0) {
@@ -16689,8 +16689,8 @@ async function ensureCoderabbitInstalled(os66, deps = {}) {
16689
16689
  log.info("coderabbit", "CodeRabbit CLI not found \u2014 installing via the official script");
16690
16690
  const run = deps.runInstallScript ?? defaultRunInstallScript;
16691
16691
  const { code, output } = await run(env);
16692
- os66.augmentPath([`${os66.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
16693
- const binary = os66.findInPath("coderabbit");
16692
+ os67.augmentPath([`${os67.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
16693
+ const binary = os67.findInPath("coderabbit");
16694
16694
  const detail = summarizeInstallFailure(output);
16695
16695
  if (binary !== null) {
16696
16696
  if (code === 0) return { ok: true };
@@ -16744,10 +16744,10 @@ function coderabbitCredentialLocator() {
16744
16744
  validate: validateNonEmptyCredential
16745
16745
  };
16746
16746
  }
16747
- function coderabbitLoginLauncher(os66) {
16747
+ function coderabbitLoginLauncher(os67) {
16748
16748
  return {
16749
16749
  async ensureInstalled() {
16750
- const result = await ensureCoderabbitInstalled(os66);
16750
+ const result = await ensureCoderabbitInstalled(os67);
16751
16751
  if (!result.ok && result.error) console.error(`
16752
16752
  \u2717 ${result.error}
16753
16753
  `);
@@ -16807,8 +16807,8 @@ function pickLine(obj) {
16807
16807
  function toHunk(raw, groupSeverity) {
16808
16808
  if (!raw || typeof raw !== "object") return null;
16809
16809
  const o = raw;
16810
- const path91 = asString(pick(o, ["file_path", "filePath", "file", "path", "filename", "fileName"])) ?? asString(pick(o, ["location"])?.path);
16811
- if (!path91) return null;
16810
+ const path92 = asString(pick(o, ["file_path", "filePath", "file", "path", "filename", "fileName"])) ?? asString(pick(o, ["location"])?.path);
16811
+ if (!path92) return null;
16812
16812
  const message = asString(
16813
16813
  pick(o, [
16814
16814
  "comment",
@@ -16825,7 +16825,7 @@ function toHunk(raw, groupSeverity) {
16825
16825
  const severity = normSeverity(pick(o, ["severity", "level", "priority", "impact"])) ?? normSeverity(groupSeverity);
16826
16826
  const locObj = pick(o, ["location"]) ?? o;
16827
16827
  return {
16828
- path: path91.trim(),
16828
+ path: path92.trim(),
16829
16829
  line: pickLine(o) ?? pickLine(locObj),
16830
16830
  severity,
16831
16831
  message: (title && message ? `${title}: ${message}` : title || message).trim() || "(no message)"
@@ -16908,10 +16908,10 @@ function parsePlain(stdout) {
16908
16908
  for (const line of stdout.split(/\r?\n/)) {
16909
16909
  const m = line.match(HUNK_LINE_RE);
16910
16910
  if (!m) continue;
16911
- const [, path91, lineNo, sevToken, message] = m;
16912
- if (!path91 || !lineNo || !message) continue;
16911
+ const [, path92, lineNo, sevToken, message] = m;
16912
+ if (!path92 || !lineNo || !message) continue;
16913
16913
  hunks.push({
16914
- path: path91.trim(),
16914
+ path: path92.trim(),
16915
16915
  line: Number(lineNo),
16916
16916
  severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
16917
16917
  message: message.trim().replace(/^[*-]\s+/, "")
@@ -16971,8 +16971,8 @@ var CoderabbitRuntimeStrategy = class {
16971
16971
  meta = getAgent("coderabbit");
16972
16972
  mode = "batch";
16973
16973
  os;
16974
- constructor(os66) {
16975
- this.os = os66;
16974
+ constructor(os67) {
16975
+ this.os = os67;
16976
16976
  }
16977
16977
  getDefaultArgs() {
16978
16978
  return ["review", "--agent"];
@@ -17243,10 +17243,10 @@ function cursorCredentialLocator() {
17243
17243
  validate: validateNonEmptyCredential
17244
17244
  };
17245
17245
  }
17246
- function cursorLoginLauncher(os66) {
17246
+ function cursorLoginLauncher(os67) {
17247
17247
  return {
17248
17248
  async ensureInstalled() {
17249
- if (os66.findInPath("cursor-agent")) return true;
17249
+ if (os67.findInPath("cursor-agent")) return true;
17250
17250
  console.error(
17251
17251
  "\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"
17252
17252
  );
@@ -17310,8 +17310,8 @@ var CursorRuntimeStrategy = class {
17310
17310
  meta = getAgent("cursor");
17311
17311
  mode = "interactive";
17312
17312
  os;
17313
- constructor(os66) {
17314
- this.os = os66;
17313
+ constructor(os67) {
17314
+ this.os = os67;
17315
17315
  }
17316
17316
  async prepareLaunch() {
17317
17317
  const binary = this.os.findInPath("cursor-agent");
@@ -17527,10 +17527,10 @@ function aiderCredentialLocator() {
17527
17527
  validate: validateNonEmptyCredential
17528
17528
  };
17529
17529
  }
17530
- function aiderLoginLauncher(os66) {
17530
+ function aiderLoginLauncher(os67) {
17531
17531
  return {
17532
17532
  async ensureInstalled() {
17533
- if (os66.findInPath("aider")) return true;
17533
+ if (os67.findInPath("aider")) return true;
17534
17534
  console.error(
17535
17535
  "\n \u2717 aider binary not on PATH.\n Install Aider:\n pip install aider-chat\n then re-run `codeam link aider`.\n"
17536
17536
  );
@@ -17540,7 +17540,7 @@ function aiderLoginLauncher(os66) {
17540
17540
  console.error(
17541
17541
  "\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"
17542
17542
  );
17543
- return (0, import_node_child_process12.spawn)(os66.id === "win32" ? "cmd.exe" : "sh", os66.id === "win32" ? ["/c", "exit", "0"] : ["-c", "exit 0"], {
17543
+ return (0, import_node_child_process12.spawn)(os67.id === "win32" ? "cmd.exe" : "sh", os67.id === "win32" ? ["/c", "exit", "0"] : ["-c", "exit 0"], {
17544
17544
  stdio: "ignore"
17545
17545
  });
17546
17546
  }
@@ -17804,8 +17804,8 @@ var AiderRuntimeStrategy = class {
17804
17804
  meta = getAgent("aider");
17805
17805
  mode = "interactive";
17806
17806
  os;
17807
- constructor(os66) {
17808
- this.os = os66;
17807
+ constructor(os67) {
17808
+ this.os = os67;
17809
17809
  }
17810
17810
  async prepareLaunch() {
17811
17811
  augmentUserLocalBinPaths();
@@ -17938,8 +17938,8 @@ function geminiCredentialLocator() {
17938
17938
  function geminiLoginLauncher() {
17939
17939
  return {
17940
17940
  async ensureInstalled() {
17941
- const os66 = createOsStrategy();
17942
- return os66.findInPath("gemini") !== null;
17941
+ const os67 = createOsStrategy();
17942
+ return os67.findInPath("gemini") !== null;
17943
17943
  },
17944
17944
  launch() {
17945
17945
  return (0, import_node_child_process13.spawn)("gemini", ["auth", "login"], { stdio: "inherit" });
@@ -18129,8 +18129,8 @@ var GeminiRuntimeStrategy = class {
18129
18129
  meta = getAgent("gemini");
18130
18130
  mode = "interactive";
18131
18131
  os;
18132
- constructor(os66) {
18133
- this.os = os66;
18132
+ constructor(os67) {
18133
+ this.os = os67;
18134
18134
  }
18135
18135
  async prepareLaunch() {
18136
18136
  const binary = this.os.findInPath("gemini");
@@ -18421,8 +18421,8 @@ var KimiRuntimeStrategy = class {
18421
18421
  meta = getAgent("kimi");
18422
18422
  mode = "interactive";
18423
18423
  os;
18424
- constructor(os66) {
18425
- this.os = os66;
18424
+ constructor(os67) {
18425
+ this.os = os67;
18426
18426
  }
18427
18427
  async prepareLaunch() {
18428
18428
  const binary = this.os.findInPath("kimi");
@@ -18564,8 +18564,8 @@ var OpencodeRuntimeStrategy = class {
18564
18564
  meta = getAgent("opencode");
18565
18565
  mode = "interactive";
18566
18566
  os;
18567
- constructor(os66) {
18568
- this.os = os66;
18567
+ constructor(os67) {
18568
+ this.os = os67;
18569
18569
  }
18570
18570
  async prepareLaunch() {
18571
18571
  const binary = this.os.findInPath("opencode");
@@ -18649,20 +18649,20 @@ var OpencodeRuntimeStrategy = class {
18649
18649
 
18650
18650
  // src/agents/registry.ts
18651
18651
  var runtimeBuilders = {
18652
- claude: (os66) => new ClaudeRuntimeStrategy(os66),
18653
- codex: (os66) => new CodexRuntimeStrategy(os66),
18654
- coderabbit: (os66) => new CoderabbitRuntimeStrategy(os66),
18655
- cursor: (os66) => new CursorRuntimeStrategy(os66),
18656
- aider: (os66) => new AiderRuntimeStrategy(os66),
18657
- gemini: (os66) => new GeminiRuntimeStrategy(os66),
18658
- kimi: (os66) => new KimiRuntimeStrategy(os66),
18659
- opencode: (os66) => new OpencodeRuntimeStrategy(os66)
18652
+ claude: (os67) => new ClaudeRuntimeStrategy(os67),
18653
+ codex: (os67) => new CodexRuntimeStrategy(os67),
18654
+ coderabbit: (os67) => new CoderabbitRuntimeStrategy(os67),
18655
+ cursor: (os67) => new CursorRuntimeStrategy(os67),
18656
+ aider: (os67) => new AiderRuntimeStrategy(os67),
18657
+ gemini: (os67) => new GeminiRuntimeStrategy(os67),
18658
+ kimi: (os67) => new KimiRuntimeStrategy(os67),
18659
+ opencode: (os67) => new OpencodeRuntimeStrategy(os67)
18660
18660
  };
18661
18661
  var deployBuilders = {
18662
18662
  claude: () => new ClaudeDeployStrategy(),
18663
18663
  codex: () => new CodexDeployStrategy()
18664
18664
  };
18665
- function createAgentStrategy(agent, os66 = createOsStrategy()) {
18665
+ function createAgentStrategy(agent, os67 = createOsStrategy()) {
18666
18666
  if (!AGENT_REGISTRY[agent]?.enabled) {
18667
18667
  throw new Error(
18668
18668
  `Agent "${agent}" is not supported in this codeam-cli version. Upgrade with 'npm i -g codeam-cli@latest'.`
@@ -18672,10 +18672,10 @@ function createAgentStrategy(agent, os66 = createOsStrategy()) {
18672
18672
  if (!build) {
18673
18673
  throw new Error(`No runtime strategy registered for agent "${agent}"`);
18674
18674
  }
18675
- return build(os66);
18675
+ return build(os67);
18676
18676
  }
18677
- function createInteractiveAgentStrategy(agent, os66 = createOsStrategy()) {
18678
- const s = createAgentStrategy(agent, os66);
18677
+ function createInteractiveAgentStrategy(agent, os67 = createOsStrategy()) {
18678
+ const s = createAgentStrategy(agent, os67);
18679
18679
  if (s.mode !== "interactive") {
18680
18680
  throw new Error(
18681
18681
  `Agent "${agent}" is a batch agent; use createAgentStrategy + .runOneShot for one-shot reviews.`
@@ -19353,8 +19353,8 @@ function collectChangedFiles(cwd) {
19353
19353
  }
19354
19354
  return [...byPath.values()];
19355
19355
  }
19356
- function restoreCoderabbitOauthBlob(os66, value) {
19357
- const dir = path39.join(os66.homeDir(), ".coderabbit");
19356
+ function restoreCoderabbitOauthBlob(os67, value) {
19357
+ const dir = path39.join(os67.homeDir(), ".coderabbit");
19358
19358
  (0, import_node_fs6.mkdirSync)(dir, { recursive: true });
19359
19359
  let file = "auth.json";
19360
19360
  let contents = value.trim();
@@ -19374,26 +19374,26 @@ function installFailureMessage(result) {
19374
19374
  return result.error ?? "CodeRabbit CLI could not be installed";
19375
19375
  }
19376
19376
  async function configureCoderabbit(input, deps = {}) {
19377
- const os66 = deps.os ?? createOsStrategy();
19377
+ const os67 = deps.os ?? createOsStrategy();
19378
19378
  const ensureInstalled = deps.ensureInstalled ?? ensureCoderabbitInstalled;
19379
19379
  const isLoggedIn = deps.isLoggedIn ?? defaultIsLoggedIn;
19380
19380
  const runOAuth = deps.runOAuthLogin ?? runCoderabbitOAuthLogin;
19381
19381
  const snapshot = deps.snapshotDir ?? (() => snapshotCredentialDir());
19382
19382
  const capture2 = deps.captureCredential ?? ((b) => diffCapturedCredential(b));
19383
19383
  const loginWithApiKey = deps.loginWithApiKey ?? defaultLoginWithApiKey;
19384
- const home = os66.homeDir();
19385
- os66.augmentPath(
19386
- os66.id === "win32" ? [
19384
+ const home = os67.homeDir();
19385
+ os67.augmentPath(
19386
+ os67.id === "win32" ? [
19387
19387
  path39.join(home, ".local", "bin"),
19388
19388
  path39.join(process.env.APPDATA ?? path39.join(home, "AppData", "Roaming"), "npm"),
19389
19389
  path39.join(home, "scoop", "shims")
19390
19390
  ] : [path39.join(home, ".local", "bin"), "/opt/homebrew/bin", "/usr/local/bin"]
19391
19391
  );
19392
- const installed2 = os66.findInPath("coderabbit") !== null;
19392
+ const installed2 = os67.findInPath("coderabbit") !== null;
19393
19393
  const base = () => ({
19394
19394
  action: input.action,
19395
19395
  supported: true,
19396
- installed: os66.findInPath("coderabbit") !== null,
19396
+ installed: os67.findInPath("coderabbit") !== null,
19397
19397
  loggedIn: false
19398
19398
  });
19399
19399
  if (input.action === "status") {
@@ -19407,7 +19407,7 @@ async function configureCoderabbit(input, deps = {}) {
19407
19407
  const key = (input.apiKey ?? "").trim();
19408
19408
  if (!key) return { ...res2, error: "No API key provided" };
19409
19409
  if (!res2.installed) {
19410
- const inst = await ensureInstalled(os66);
19410
+ const inst = await ensureInstalled(os67);
19411
19411
  res2.installed = inst.ok;
19412
19412
  if (!inst.ok) return { ...res2, error: installFailureMessage(inst) };
19413
19413
  }
@@ -19431,7 +19431,7 @@ async function configureCoderabbit(input, deps = {}) {
19431
19431
  }
19432
19432
  if (!res2.installed) {
19433
19433
  deps.onEvent?.({ kind: "installing" });
19434
- const inst = await ensureInstalled(os66);
19434
+ const inst = await ensureInstalled(os67);
19435
19435
  res2.installed = inst.ok;
19436
19436
  if (!inst.ok) return { ...res2, error: installFailureMessage(inst) };
19437
19437
  }
@@ -19448,7 +19448,7 @@ async function configureCoderabbit(input, deps = {}) {
19448
19448
  return { ...res2, loggedIn: true, linked: true };
19449
19449
  }
19450
19450
  try {
19451
- restoreCoderabbitOauthBlob(os66, cred.credential);
19451
+ restoreCoderabbitOauthBlob(os67, cred.credential);
19452
19452
  } catch (err) {
19453
19453
  return {
19454
19454
  ...res2,
@@ -19472,7 +19472,7 @@ async function configureCoderabbit(input, deps = {}) {
19472
19472
  const res2 = base();
19473
19473
  if (!installed2) {
19474
19474
  deps.onEvent?.({ kind: "installing" });
19475
- const inst = await ensureInstalled(os66);
19475
+ const inst = await ensureInstalled(os67);
19476
19476
  res2.installed = inst.ok;
19477
19477
  if (!inst.ok) return { ...res2, error: installFailureMessage(inst) };
19478
19478
  }
@@ -19512,7 +19512,7 @@ async function configureCoderabbit(input, deps = {}) {
19512
19512
  }
19513
19513
  const res = base();
19514
19514
  if (!res.installed) {
19515
- const inst = await ensureInstalled(os66);
19515
+ const inst = await ensureInstalled(os67);
19516
19516
  res.installed = inst.ok;
19517
19517
  if (!inst.ok) return { ...res, error: installFailureMessage(inst) };
19518
19518
  }
@@ -21335,7 +21335,7 @@ async function autoUpgradeBeforeCriticalCommand() {
21335
21335
  if (process.env.NODE_ENV === "test") return;
21336
21336
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
21337
21337
  if (process.env.CI) return;
21338
- const current2 = true ? "2.65.1" : null;
21338
+ const current2 = true ? "2.65.2" : null;
21339
21339
  if (!current2) return;
21340
21340
  const cache = readCache();
21341
21341
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -21352,7 +21352,7 @@ function checkForUpdates() {
21352
21352
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
21353
21353
  if (process.env.CI) return;
21354
21354
  if (!process.stdout.isTTY) return;
21355
- const current2 = true ? "2.65.1" : null;
21355
+ const current2 = true ? "2.65.2" : null;
21356
21356
  if (!current2) return;
21357
21357
  const cache = readCache();
21358
21358
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -21372,7 +21372,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
21372
21372
  var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
21373
21373
  var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
21374
21374
  function currentCliVersion() {
21375
- return true ? "2.65.1" : null;
21375
+ return true ? "2.65.2" : null;
21376
21376
  }
21377
21377
  function runCmd(cmd, args2, timeoutMs) {
21378
21378
  return new Promise((resolve9) => {
@@ -23041,7 +23041,7 @@ async function defaultFetchJson(url2) {
23041
23041
  async function readUsageReport(deps = {}) {
23042
23042
  const port = deps.port ?? HEADROOM_PROXY_PORT;
23043
23043
  const base = `http://127.0.0.1:${port}`;
23044
- const get2 = deps.fetchJson ?? ((path91) => defaultFetchJson(`${base}${path91}`));
23044
+ const get2 = deps.fetchJson ?? ((path92) => defaultFetchJson(`${base}${path92}`));
23045
23045
  let history;
23046
23046
  try {
23047
23047
  history = await get2("/stats-history");
@@ -24958,11 +24958,11 @@ function resolveDoltInstallStrategy(platform3) {
24958
24958
  }
24959
24959
  var DOLT_RELEASE_BASE = "https://github.com/dolthub/dolt/releases/latest/download";
24960
24960
  function doltPlatformTuple(platform3, arch2) {
24961
- const os66 = platform3 === "win32" ? "windows" : platform3 === "darwin" ? "darwin" : "linux";
24961
+ const os67 = platform3 === "win32" ? "windows" : platform3 === "darwin" ? "darwin" : "linux";
24962
24962
  const a = arch2 === "x64" ? "amd64" : arch2 === "arm64" ? "arm64" : null;
24963
24963
  if (!a) return null;
24964
- if (os66 === "windows" && a !== "amd64") return null;
24965
- return `${os66}-${a}`;
24964
+ if (os67 === "windows" && a !== "amd64") return null;
24965
+ return `${os67}-${a}`;
24966
24966
  }
24967
24967
  function resolveDoltTarballStrategy(targetDir, platform3, arch2) {
24968
24968
  const tuple = doltPlatformTuple(platform3, arch2);
@@ -26614,7 +26614,7 @@ var vcsAgentReviewH = async (ctx, cmd, parsed) => {
26614
26614
  });
26615
26615
  const token = ctx.pluginAuthToken;
26616
26616
  void (async () => {
26617
- const os66 = createOsStrategy();
26617
+ const os67 = createOsStrategy();
26618
26618
  try {
26619
26619
  const report = await reviewPullRequest(
26620
26620
  {
@@ -26623,7 +26623,7 @@ var vcsAgentReviewH = async (ctx, cmd, parsed) => {
26623
26623
  baseBranch: parsed.baseBranch
26624
26624
  },
26625
26625
  {
26626
- runReview: (input) => new CoderabbitRuntimeStrategy(os66).runOneShot(input),
26626
+ runReview: (input) => new CoderabbitRuntimeStrategy(os67).runOneShot(input),
26627
26627
  runGh: (args2) => defaultRunGh(args2),
26628
26628
  postReport: async (r) => {
26629
26629
  if (!token) return;
@@ -27726,11 +27726,11 @@ function resolveTokenValue(args2) {
27726
27726
  }
27727
27727
  const fileFlag = args2.find((a) => a.startsWith("--token-file="));
27728
27728
  if (fileFlag) {
27729
- const path91 = fileFlag.slice("--token-file=".length);
27729
+ const path92 = fileFlag.slice("--token-file=".length);
27730
27730
  try {
27731
- const content = fs64.readFileSync(path91, "utf8").trim();
27732
- if (content.length === 0) fail(`--token-file ${path91} is empty`);
27733
- rmIfExistsQuiet(path91);
27731
+ const content = fs64.readFileSync(path92, "utf8").trim();
27732
+ if (content.length === 0) fail(`--token-file ${path92} is empty`);
27733
+ rmIfExistsQuiet(path92);
27734
27734
  return content;
27735
27735
  } catch (err) {
27736
27736
  fail(`Could not read --token-file: ${err.message}`);
@@ -35941,7 +35941,7 @@ function defaultRunGit(cwd, args2) {
35941
35941
  });
35942
35942
  }
35943
35943
  async function discoverRepos(workingDir, maxDepth = 4) {
35944
- const fs80 = await import("fs/promises");
35944
+ const fs81 = await import("fs/promises");
35945
35945
  const out2 = [];
35946
35946
  await walk(workingDir, 0);
35947
35947
  return out2;
@@ -35949,7 +35949,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
35949
35949
  if (depth > maxDepth) return;
35950
35950
  let entries = [];
35951
35951
  try {
35952
- const dirents = await fs80.readdir(dir, { withFileTypes: true });
35952
+ const dirents = await fs81.readdir(dir, { withFileTypes: true });
35953
35953
  entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
35954
35954
  } catch {
35955
35955
  return;
@@ -37184,12 +37184,124 @@ function buildMcpServersForStart(ctx) {
37184
37184
  return servers;
37185
37185
  }
37186
37186
 
37187
- // src/integrations/detect-stack.ts
37187
+ // src/services/local-mcp-servers.ts
37188
37188
  var import_node_fs12 = __toESM(require("fs"));
37189
+ var import_node_os12 = __toESM(require("os"));
37189
37190
  var import_node_path11 = __toESM(require("path"));
37191
+ var MAX_LOCAL_MCP_SERVERS = 10;
37192
+ function localMcpServersPath() {
37193
+ return import_node_path11.default.join(import_node_os12.default.homedir(), ".codeam", "mcp-servers.json");
37194
+ }
37195
+ function isStringArray(v) {
37196
+ return Array.isArray(v) && v.every((item) => typeof item === "string");
37197
+ }
37198
+ function toEnvVariables(v) {
37199
+ if (v === void 0) return [];
37200
+ if (v === null || typeof v !== "object" || Array.isArray(v)) return null;
37201
+ const entries = Object.entries(v);
37202
+ if (entries.some(([, value]) => typeof value !== "string")) return null;
37203
+ return entries.map(([name, value]) => ({ name, value }));
37204
+ }
37205
+ function isValidEntry(entry) {
37206
+ return typeof entry.name === "string" && entry.name.length > 0 && typeof entry.command === "string" && entry.command.length > 0 && isStringArray(entry.args);
37207
+ }
37208
+ function readLocalMcpServers() {
37209
+ let raw;
37210
+ try {
37211
+ raw = import_node_fs12.default.readFileSync(localMcpServersPath(), "utf8");
37212
+ } catch {
37213
+ return [];
37214
+ }
37215
+ let parsed;
37216
+ try {
37217
+ parsed = JSON.parse(raw);
37218
+ } catch (err) {
37219
+ log.warn(
37220
+ "localMcp",
37221
+ `~/.codeam/mcp-servers.json is not valid JSON \u2014 ignoring (${err instanceof Error ? err.message : String(err)})`
37222
+ );
37223
+ return [];
37224
+ }
37225
+ if (!Array.isArray(parsed)) {
37226
+ log.warn("localMcp", "~/.codeam/mcp-servers.json must be a JSON array \u2014 ignoring");
37227
+ return [];
37228
+ }
37229
+ const servers = [];
37230
+ let sawInvalid = false;
37231
+ let sawTruncated = false;
37232
+ let sawDuplicate = false;
37233
+ const seenNames = /* @__PURE__ */ new Set();
37234
+ for (const entry of parsed) {
37235
+ if (servers.length >= MAX_LOCAL_MCP_SERVERS) {
37236
+ sawTruncated = true;
37237
+ continue;
37238
+ }
37239
+ if (entry === null || typeof entry !== "object" || !isValidEntry(entry)) {
37240
+ sawInvalid = true;
37241
+ continue;
37242
+ }
37243
+ const env = toEnvVariables(entry.env);
37244
+ if (env === null) {
37245
+ sawInvalid = true;
37246
+ continue;
37247
+ }
37248
+ if (seenNames.has(entry.name)) {
37249
+ sawDuplicate = true;
37250
+ continue;
37251
+ }
37252
+ seenNames.add(entry.name);
37253
+ servers.push({ name: entry.name, command: entry.command, args: entry.args, env });
37254
+ }
37255
+ if (sawDuplicate) {
37256
+ log.warn(
37257
+ "localMcp",
37258
+ "~/.codeam/mcp-servers.json has duplicate server names \u2014 kept the first of each"
37259
+ );
37260
+ }
37261
+ if (sawInvalid) {
37262
+ log.warn(
37263
+ "localMcp",
37264
+ '~/.codeam/mcp-servers.json contains one or more invalid entries \u2014 skipped (each needs a non-empty "name", non-empty "command", "args" as a string array, and "env" as an object of string values)'
37265
+ );
37266
+ }
37267
+ if (sawTruncated) {
37268
+ log.warn(
37269
+ "localMcp",
37270
+ `~/.codeam/mcp-servers.json has more than ${MAX_LOCAL_MCP_SERVERS} entries \u2014 only the first ${MAX_LOCAL_MCP_SERVERS} were loaded`
37271
+ );
37272
+ }
37273
+ if (servers.length) {
37274
+ log.info(
37275
+ "localMcp",
37276
+ `loaded ${servers.length} local MCP server(s): ${servers.map((s) => s.name).join(", ")}`
37277
+ );
37278
+ }
37279
+ return servers;
37280
+ }
37281
+ function mergeWithLocalMcpServers(integrationServers) {
37282
+ const localServers = readLocalMcpServers();
37283
+ if (localServers.length === 0) return integrationServers;
37284
+ const integrationNames = new Set(integrationServers.map((s) => s.name));
37285
+ const merged = [...integrationServers];
37286
+ for (const local of localServers) {
37287
+ if (integrationNames.has(local.name)) {
37288
+ log.warn(
37289
+ "localMcp",
37290
+ `local MCP server "${local.name}" collides with an Agent Toolkit integration of the same name \u2014 the integration wins, skipping the local entry`
37291
+ );
37292
+ continue;
37293
+ }
37294
+ merged.push(local);
37295
+ }
37296
+ return merged;
37297
+ }
37298
+
37299
+ // src/integrations/detect-stack.ts
37300
+ var import_node_fs13 = __toESM(require("fs"));
37301
+ var import_node_path12 = __toESM(require("path"));
37190
37302
  function readSafe(cwd, rel) {
37191
37303
  try {
37192
- return import_node_fs12.default.readFileSync(import_node_path11.default.join(cwd, rel), "utf8");
37304
+ return import_node_fs13.default.readFileSync(import_node_path12.default.join(cwd, rel), "utf8");
37193
37305
  } catch {
37194
37306
  return "";
37195
37307
  }
@@ -37372,35 +37484,35 @@ function buildAcpPromptBlocks(payload) {
37372
37484
  }
37373
37485
 
37374
37486
  // src/agents/agent-standard.ts
37375
- var fs75 = __toESM(require("fs"));
37376
- var path82 = __toESM(require("path"));
37377
- var os60 = __toESM(require("os"));
37378
- function ensureAgentStandard(homeDir2 = os60.homedir()) {
37487
+ var fs76 = __toESM(require("fs"));
37488
+ var path83 = __toESM(require("path"));
37489
+ var os61 = __toESM(require("os"));
37490
+ function ensureAgentStandard(homeDir2 = os61.homedir()) {
37379
37491
  try {
37380
- const file = path82.join(homeDir2, ".claude", "CLAUDE.md");
37492
+ const file = path83.join(homeDir2, ".claude", "CLAUDE.md");
37381
37493
  let existing = "";
37382
37494
  try {
37383
- existing = fs75.readFileSync(file, "utf8");
37495
+ existing = fs76.readFileSync(file, "utf8");
37384
37496
  } catch {
37385
37497
  }
37386
37498
  if (existing.includes(AGENT_STANDARD_MARKER)) return;
37387
- fs75.mkdirSync(path82.dirname(file), { recursive: true });
37499
+ fs76.mkdirSync(path83.dirname(file), { recursive: true });
37388
37500
  const next = existing.trim() ? `${existing.trimEnd()}
37389
37501
 
37390
37502
  ${AGENT_STANDARD_BLOCK}
37391
37503
  ` : `${AGENT_STANDARD_BLOCK}
37392
37504
  `;
37393
- fs75.writeFileSync(file, next);
37505
+ fs76.writeFileSync(file, next);
37394
37506
  } catch {
37395
37507
  }
37396
37508
  }
37397
37509
  var _agentStandardSeam = {
37398
37510
  isLocalSession: () => isLocalSession(),
37399
- markerPath: (sessionId) => path82.join(os60.homedir(), ".codeam", "agent-standard", `${sessionId}.done`),
37400
- exists: (p2) => fs75.existsSync(p2),
37511
+ markerPath: (sessionId) => path83.join(os61.homedir(), ".codeam", "agent-standard", `${sessionId}.done`),
37512
+ exists: (p2) => fs76.existsSync(p2),
37401
37513
  write: (p2) => {
37402
- fs75.mkdirSync(path82.dirname(p2), { recursive: true });
37403
- fs75.writeFileSync(p2, "");
37514
+ fs76.mkdirSync(path83.dirname(p2), { recursive: true });
37515
+ fs76.writeFileSync(p2, "");
37404
37516
  }
37405
37517
  };
37406
37518
  function isClaude(agent) {
@@ -38338,12 +38450,14 @@ async function integrationsSyncH(ctx) {
38338
38450
  const previousIds = new Set((readIntegrationsManifest()?.integrations ?? []).map((e) => e.id));
38339
38451
  persistIntegrationsManifest(manifest);
38340
38452
  await prewarmNewMcpEntries(manifest, previousIds);
38341
- const servers = buildMcpServersForStart({
38342
- sessionId: opts.sessionId,
38343
- pluginId: opts.pluginId,
38344
- pluginAuthToken: opts.pluginAuthToken,
38345
- pollSecret: opts.pollSecret
38346
- });
38453
+ const servers = mergeWithLocalMcpServers(
38454
+ buildMcpServersForStart({
38455
+ sessionId: opts.sessionId,
38456
+ pluginId: opts.pluginId,
38457
+ pluginAuthToken: opts.pluginAuthToken,
38458
+ pollSecret: opts.pollSecret
38459
+ })
38460
+ );
38347
38461
  const applied = await client3.reprovisionMcp(servers);
38348
38462
  await relay.sendResult(cmd.id, "completed", {
38349
38463
  synced: true,
@@ -40608,9 +40722,9 @@ function startClaudeCredentialSync(opts) {
40608
40722
  }
40609
40723
 
40610
40724
  // src/beads/workflow-hint.ts
40611
- var fs76 = __toESM(require("fs"));
40612
- var path83 = __toESM(require("path"));
40613
- var os61 = __toESM(require("os"));
40725
+ var fs77 = __toESM(require("fs"));
40726
+ var path84 = __toESM(require("path"));
40727
+ var os62 = __toESM(require("os"));
40614
40728
  var BEADS_HINT_MARKER = "<!-- codeam:beads-workflow -->";
40615
40729
  var BEADS_HINT = `${BEADS_HINT_MARKER}
40616
40730
  # Beads (bd) \u2014 task tracking + persistent memory (ALWAYS use it)
@@ -40624,29 +40738,29 @@ This environment uses **bd (beads)** for issue/task tracking and persistent memo
40624
40738
  - \`bd ready\` (available work) \xB7 \`bd show <id>\` \xB7 \`bd update <id> --claim\` \xB7 \`bd close <id>\`.
40625
40739
  - Use \`bd remember "..."\` for persistent knowledge \u2014 do NOT use MEMORY.md files.
40626
40740
  ${BEADS_HINT_MARKER}`;
40627
- function ensureBeadsWorkflowHint(homeDir2 = os61.homedir()) {
40741
+ function ensureBeadsWorkflowHint(homeDir2 = os62.homedir()) {
40628
40742
  try {
40629
- const file = path83.join(homeDir2, ".claude", "CLAUDE.md");
40743
+ const file = path84.join(homeDir2, ".claude", "CLAUDE.md");
40630
40744
  let existing = "";
40631
40745
  try {
40632
- existing = fs76.readFileSync(file, "utf8");
40746
+ existing = fs77.readFileSync(file, "utf8");
40633
40747
  } catch {
40634
40748
  }
40635
40749
  if (existing.includes(BEADS_HINT_MARKER)) return;
40636
- fs76.mkdirSync(path83.dirname(file), { recursive: true });
40750
+ fs77.mkdirSync(path84.dirname(file), { recursive: true });
40637
40751
  const next = existing.trim() ? `${existing.trimEnd()}
40638
40752
 
40639
40753
  ${BEADS_HINT}
40640
40754
  ` : `${BEADS_HINT}
40641
40755
  `;
40642
- fs76.writeFileSync(file, next);
40756
+ fs77.writeFileSync(file, next);
40643
40757
  } catch {
40644
40758
  }
40645
40759
  }
40646
40760
 
40647
40761
  // src/skills/provision.ts
40648
- var import_node_os12 = __toESM(require("os"));
40649
- function provisionSkillsForStart(home = import_node_os12.default.homedir()) {
40762
+ var import_node_os13 = __toESM(require("os"));
40763
+ function provisionSkillsForStart(home = import_node_os13.default.homedir()) {
40650
40764
  const materialized = [];
40651
40765
  try {
40652
40766
  const manifest = readSkillsManifest();
@@ -41011,7 +41125,7 @@ var AcpDriver = class {
41011
41125
  };
41012
41126
 
41013
41127
  // src/baton/transcript-mirror.ts
41014
- var fs77 = __toESM(require("fs"));
41128
+ var fs78 = __toESM(require("fs"));
41015
41129
  var TranscriptMirror = class {
41016
41130
  constructor(deps) {
41017
41131
  this.deps = deps;
@@ -41078,7 +41192,7 @@ var TranscriptMirror = class {
41078
41192
  }
41079
41193
  };
41080
41194
  function defaultWatch(file, onChange) {
41081
- const w3 = fs77.watch(file, { persistent: false }, () => onChange());
41195
+ const w3 = fs78.watch(file, { persistent: false }, () => onChange());
41082
41196
  return () => w3.close();
41083
41197
  }
41084
41198
 
@@ -41376,16 +41490,16 @@ function keepDeviceAwake(deps = {}) {
41376
41490
  }
41377
41491
 
41378
41492
  // src/agents/claude/onboarding.ts
41379
- var fs78 = __toESM(require("fs"));
41380
- var os63 = __toESM(require("os"));
41381
- var path84 = __toESM(require("path"));
41493
+ var fs79 = __toESM(require("fs"));
41494
+ var os64 = __toESM(require("os"));
41495
+ var path85 = __toESM(require("path"));
41382
41496
  var ONBOARDING_VERSION_SENTINEL = "9999.0.0";
41383
41497
  function ensureClaudeOnboarded(cwd) {
41384
41498
  try {
41385
- const file = path84.join(os63.homedir(), ".claude.json");
41499
+ const file = path85.join(os64.homedir(), ".claude.json");
41386
41500
  let config = {};
41387
41501
  try {
41388
- config = JSON.parse(fs78.readFileSync(file, "utf8"));
41502
+ config = JSON.parse(fs79.readFileSync(file, "utf8"));
41389
41503
  } catch {
41390
41504
  }
41391
41505
  let changed = false;
@@ -41410,8 +41524,8 @@ function ensureClaudeOnboarded(cwd) {
41410
41524
  }
41411
41525
  }
41412
41526
  if (!changed) return;
41413
- fs78.mkdirSync(path84.dirname(file), { recursive: true });
41414
- fs78.writeFileSync(file, JSON.stringify(config, null, 2));
41527
+ fs79.mkdirSync(path85.dirname(file), { recursive: true });
41528
+ fs79.writeFileSync(file, JSON.stringify(config, null, 2));
41415
41529
  log.info(
41416
41530
  "claude",
41417
41531
  `pre-completed Claude onboarding${cwd ? ` + trusted workspace ${cwd}` : ""}`
@@ -41529,12 +41643,14 @@ async function start(requestedAgent, presetSession) {
41529
41643
  beads = started;
41530
41644
  return started;
41531
41645
  });
41532
- const mcpServers = buildMcpServersForStart({
41533
- sessionId: session.id,
41534
- pluginId,
41535
- pluginAuthToken: session.pluginAuthToken ?? void 0,
41536
- pollSecret: session.pollSecret
41537
- });
41646
+ const mcpServers = mergeWithLocalMcpServers(
41647
+ buildMcpServersForStart({
41648
+ sessionId: session.id,
41649
+ pluginId,
41650
+ pluginAuthToken: session.pluginAuthToken ?? void 0,
41651
+ pollSecret: session.pollSecret
41652
+ })
41653
+ );
41538
41654
  provisionSkillsForStart();
41539
41655
  const depsReady = process.env.CODESPACES === "true" ? provisionProjectDependencies(cwd).catch(() => void 0) : Promise.resolve();
41540
41656
  if (process.env.CODESPACES === "true") {
@@ -42143,7 +42259,7 @@ var import_picocolors11 = __toESM(require("picocolors"));
42143
42259
  var import_child_process30 = require("child_process");
42144
42260
  var import_util4 = require("util");
42145
42261
  var import_picocolors9 = __toESM(require("picocolors"));
42146
- var path85 = __toESM(require("path"));
42262
+ var path86 = __toESM(require("path"));
42147
42263
  var execFileP6 = (0, import_util4.promisify)(import_child_process30.execFile);
42148
42264
  var MAX_BUFFER = 8 * 1024 * 1024;
42149
42265
  function resetStdinForChild() {
@@ -42632,7 +42748,7 @@ var GitHubCodespacesProvider = class {
42632
42748
  });
42633
42749
  }
42634
42750
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
42635
- const remoteDir = path85.posix.dirname(remotePath);
42751
+ const remoteDir = path86.posix.dirname(remotePath);
42636
42752
  const parts = [
42637
42753
  `mkdir -p ${shellQuote(remoteDir)}`,
42638
42754
  `cat > ${shellQuote(remotePath)}`
@@ -42702,7 +42818,7 @@ function shellQuote(s) {
42702
42818
  // src/services/providers/gitpod.ts
42703
42819
  var import_child_process31 = require("child_process");
42704
42820
  var import_util5 = require("util");
42705
- var path86 = __toESM(require("path"));
42821
+ var path87 = __toESM(require("path"));
42706
42822
  var import_picocolors10 = __toESM(require("picocolors"));
42707
42823
  var execFileP7 = (0, import_util5.promisify)(import_child_process31.execFile);
42708
42824
  var MAX_BUFFER2 = 8 * 1024 * 1024;
@@ -42942,7 +43058,7 @@ var GitpodProvider = class {
42942
43058
  });
42943
43059
  }
42944
43060
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
42945
- const remoteDir = path86.posix.dirname(remotePath);
43061
+ const remoteDir = path87.posix.dirname(remotePath);
42946
43062
  const parts = [
42947
43063
  `mkdir -p ${shellQuote2(remoteDir)}`,
42948
43064
  `cat > ${shellQuote2(remotePath)}`
@@ -42978,7 +43094,7 @@ function shellQuote2(s) {
42978
43094
  // src/services/providers/gitlab-workspaces.ts
42979
43095
  var import_child_process32 = require("child_process");
42980
43096
  var import_util6 = require("util");
42981
- var path87 = __toESM(require("path"));
43097
+ var path88 = __toESM(require("path"));
42982
43098
  var execFileP8 = (0, import_util6.promisify)(import_child_process32.execFile);
42983
43099
  var MAX_BUFFER3 = 8 * 1024 * 1024;
42984
43100
  var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
@@ -43238,7 +43354,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
43238
43354
  }
43239
43355
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
43240
43356
  const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
43241
- const remoteDir = path87.posix.dirname(remotePath);
43357
+ const remoteDir = path88.posix.dirname(remotePath);
43242
43358
  const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
43243
43359
  if (options.mode != null) {
43244
43360
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
@@ -43306,7 +43422,7 @@ function shellQuote3(s) {
43306
43422
  // src/services/providers/railway.ts
43307
43423
  var import_child_process33 = require("child_process");
43308
43424
  var import_util7 = require("util");
43309
- var path88 = __toESM(require("path"));
43425
+ var path89 = __toESM(require("path"));
43310
43426
  var execFileP9 = (0, import_util7.promisify)(import_child_process33.execFile);
43311
43427
  var MAX_BUFFER4 = 8 * 1024 * 1024;
43312
43428
  function resetStdinForChild4() {
@@ -43542,7 +43658,7 @@ var RailwayProvider = class {
43542
43658
  if (!projectId || !serviceId) {
43543
43659
  throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
43544
43660
  }
43545
- const remoteDir = path88.posix.dirname(remotePath);
43661
+ const remoteDir = path89.posix.dirname(remotePath);
43546
43662
  const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
43547
43663
  if (options.mode != null) {
43548
43664
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
@@ -44188,8 +44304,8 @@ async function invite() {
44188
44304
  var import_node_dns = require("dns");
44189
44305
  var import_node_util5 = require("util");
44190
44306
  var import_node_crypto13 = require("crypto");
44191
- var fs79 = __toESM(require("fs"));
44192
- var path89 = __toESM(require("path"));
44307
+ var fs80 = __toESM(require("fs"));
44308
+ var path90 = __toESM(require("path"));
44193
44309
  var import_picocolors14 = __toESM(require("picocolors"));
44194
44310
  var dnsResolveP = (0, import_node_util5.promisify)(import_node_dns.resolve);
44195
44311
  async function checkDns(apiBase2) {
@@ -44245,13 +44361,13 @@ async function checkHealth(apiBase2) {
44245
44361
  }
44246
44362
  }
44247
44363
  function checkConfigDir() {
44248
- const dir = path89.join(require("os").homedir(), ".codeam");
44364
+ const dir = path90.join(require("os").homedir(), ".codeam");
44249
44365
  try {
44250
- fs79.mkdirSync(dir, { recursive: true, mode: 448 });
44251
- const probe = path89.join(dir, ".doctor-probe");
44252
- fs79.writeFileSync(probe, "ok", { mode: 384 });
44253
- const read2 = fs79.readFileSync(probe, "utf8");
44254
- fs79.unlinkSync(probe);
44366
+ fs80.mkdirSync(dir, { recursive: true, mode: 448 });
44367
+ const probe = path90.join(dir, ".doctor-probe");
44368
+ fs80.writeFileSync(probe, "ok", { mode: 384 });
44369
+ const read2 = fs80.readFileSync(probe, "utf8");
44370
+ fs80.unlinkSync(probe);
44255
44371
  if (read2 !== "ok") throw new Error("write/read round-trip mismatch");
44256
44372
  return {
44257
44373
  id: "config-dir",
@@ -44291,9 +44407,9 @@ function checkSessions() {
44291
44407
  }
44292
44408
  }
44293
44409
  function checkAgentBinaries() {
44294
- const os66 = createOsStrategy();
44410
+ const os67 = createOsStrategy();
44295
44411
  return getEnabledAgents().map((meta) => {
44296
- const found = os66.findInPath(meta.binaryName);
44412
+ const found = os67.findInPath(meta.binaryName);
44297
44413
  return {
44298
44414
  id: `agent-${meta.id}`,
44299
44415
  label: `Agent binary: ${meta.displayName} (${meta.binaryName})`,
@@ -44315,7 +44431,7 @@ function checkNodePty() {
44315
44431
  detail: "not required on this platform"
44316
44432
  };
44317
44433
  }
44318
- const vendoredPath = path89.join(__dirname, "vendor", "node-pty");
44434
+ const vendoredPath = path90.join(__dirname, "vendor", "node-pty");
44319
44435
  for (const target of [vendoredPath, "node-pty"]) {
44320
44436
  try {
44321
44437
  require(target);
@@ -44357,7 +44473,7 @@ function checkChokidar() {
44357
44473
  }
44358
44474
  async function doctor(args2 = []) {
44359
44475
  const json = args2.includes("--json");
44360
- const cliVersion = true ? "2.65.1" : "0.0.0-dev";
44476
+ const cliVersion = true ? "2.65.2" : "0.0.0-dev";
44361
44477
  const apiBase2 = resolveApiBaseUrl();
44362
44478
  const diagnosticId = (0, import_node_crypto13.randomUUID)();
44363
44479
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -44555,9 +44671,9 @@ async function completion(args2) {
44555
44671
 
44556
44672
  // src/integrations/mcp-run.ts
44557
44673
  var import_node_child_process34 = require("child_process");
44558
- var import_node_fs13 = require("fs");
44559
- var import_node_os13 = __toESM(require("os"));
44560
- var import_node_path12 = __toESM(require("path"));
44674
+ var import_node_fs14 = require("fs");
44675
+ var import_node_os14 = __toESM(require("os"));
44676
+ var import_node_path13 = __toESM(require("path"));
44561
44677
 
44562
44678
  // src/integrations/token-client.ts
44563
44679
  var REFRESH_AHEAD_MS = 5 * 60 * 1e3;
@@ -44637,13 +44753,13 @@ function commandExists(command2) {
44637
44753
  }
44638
44754
  function localBinCandidates(command2) {
44639
44755
  return [
44640
- import_node_path12.default.join(import_node_os13.default.homedir(), ".local", "bin", command2),
44641
- import_node_path12.default.join(import_node_os13.default.homedir(), ".cargo", "bin", command2)
44756
+ import_node_path13.default.join(import_node_os14.default.homedir(), ".local", "bin", command2),
44757
+ import_node_path13.default.join(import_node_os14.default.homedir(), ".cargo", "bin", command2)
44642
44758
  ];
44643
44759
  }
44644
44760
  function resolveLauncherPath(command2, deps = {
44645
44761
  commandExists,
44646
- existsSync: import_node_fs13.existsSync
44762
+ existsSync: import_node_fs14.existsSync
44647
44763
  }) {
44648
44764
  if (deps.commandExists(command2)) return command2;
44649
44765
  for (const candidate of localBinCandidates(command2)) {
@@ -44748,7 +44864,7 @@ async function mcpRun(args2) {
44748
44864
  // src/commands/version.ts
44749
44865
  var import_picocolors15 = __toESM(require("picocolors"));
44750
44866
  function version2() {
44751
- const v = true ? "2.65.1" : "unknown";
44867
+ const v = true ? "2.65.2" : "unknown";
44752
44868
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
44753
44869
  }
44754
44870
 
@@ -44897,10 +45013,10 @@ var EXIT_CODE_NAMES = {
44897
45013
  };
44898
45014
 
44899
45015
  // src/index.ts
44900
- var os65 = __toESM(require("os"));
45016
+ var os66 = __toESM(require("os"));
44901
45017
  if (!process.env.HOME) {
44902
45018
  try {
44903
- const home = os65.homedir();
45019
+ const home = os66.homedir();
44904
45020
  if (home) process.env.HOME = home;
44905
45021
  } catch {
44906
45022
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.65.1",
3
+ "version": "2.65.2",
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",