codeam-cli 2.60.68 → 2.60.70

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 +370 -104
  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.60.69] — 2026-07-15
8
+
9
+ ### Fixed
10
+
11
+ - **cli:** Provision uvx via the standalone uv installer and resolve per-user bin paths for MCP launchers
12
+
13
+ ## [2.60.68] — 2026-07-15
14
+
15
+ ### Added
16
+
17
+ - **shared:** 17 new COMING SOON integrations + official logos
18
+
7
19
  ## [2.60.67] — 2026-07-15
8
20
 
9
21
  ### Added
package/dist/index.js CHANGED
@@ -1068,11 +1068,11 @@ function quiet(fn) {
1068
1068
  log.debug(TAG, "ignored sync error", err);
1069
1069
  }
1070
1070
  }
1071
- function rmIfExistsQuiet(path74) {
1071
+ function rmIfExistsQuiet(path75) {
1072
1072
  try {
1073
- fs2.rmSync(path74, { force: true });
1073
+ fs2.rmSync(path75, { force: true });
1074
1074
  } catch (err) {
1075
- log.debug(TAG, `rmIfExists failed for ${path74}`, err);
1075
+ log.debug(TAG, `rmIfExists failed for ${path75}`, err);
1076
1076
  }
1077
1077
  }
1078
1078
  function killQuiet(target, signal = "SIGTERM") {
@@ -1256,8 +1256,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
1256
1256
  return decodedFile;
1257
1257
  };
1258
1258
  }
1259
- function normalizeWindowsPath(path74) {
1260
- return path74.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
1259
+ function normalizeWindowsPath(path75) {
1260
+ return path75.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
1261
1261
  }
1262
1262
 
1263
1263
  // ../../node_modules/@posthog/core/dist/featureFlagUtils.mjs
@@ -3737,9 +3737,9 @@ async function addSourceContext(frames) {
3737
3737
  LRU_FILE_CONTENTS_CACHE.reduce();
3738
3738
  return frames;
3739
3739
  }
3740
- function getContextLinesFromFile(path74, ranges, output) {
3740
+ function getContextLinesFromFile(path75, ranges, output) {
3741
3741
  return new Promise((resolve7) => {
3742
- const stream = (0, import_node_fs.createReadStream)(path74);
3742
+ const stream = (0, import_node_fs.createReadStream)(path75);
3743
3743
  const lineReaded = (0, import_node_readline.createInterface)({
3744
3744
  input: stream
3745
3745
  });
@@ -3754,7 +3754,7 @@ function getContextLinesFromFile(path74, ranges, output) {
3754
3754
  let rangeStart = range[0];
3755
3755
  let rangeEnd = range[1];
3756
3756
  function onStreamError() {
3757
- LRU_FILE_CONTENTS_FS_READ_FAILED.set(path74, 1);
3757
+ LRU_FILE_CONTENTS_FS_READ_FAILED.set(path75, 1);
3758
3758
  lineReaded.close();
3759
3759
  lineReaded.removeAllListeners();
3760
3760
  destroyStreamAndResolve();
@@ -3815,8 +3815,8 @@ function clearLineContext(frame) {
3815
3815
  delete frame.context_line;
3816
3816
  delete frame.post_context;
3817
3817
  }
3818
- function shouldSkipContextLinesForFile(path74) {
3819
- return path74.startsWith("node:") || path74.endsWith(".min.js") || path74.endsWith(".min.cjs") || path74.endsWith(".min.mjs") || path74.startsWith("data:");
3818
+ function shouldSkipContextLinesForFile(path75) {
3819
+ return path75.startsWith("node:") || path75.endsWith(".min.js") || path75.endsWith(".min.cjs") || path75.endsWith(".min.mjs") || path75.startsWith("data:");
3820
3820
  }
3821
3821
  function shouldSkipContextLinesForFrame(frame) {
3822
3822
  if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
@@ -5970,7 +5970,7 @@ function readAnonId() {
5970
5970
  }
5971
5971
  function superProperties() {
5972
5972
  return {
5973
- cliVersion: true ? "2.60.68" : "0.0.0-dev",
5973
+ cliVersion: true ? "2.60.70" : "0.0.0-dev",
5974
5974
  nodeVersion: process.version,
5975
5975
  platform: process.platform,
5976
5976
  arch: process.arch,
@@ -6151,7 +6151,7 @@ var os4 = __toESM(require("os"));
6151
6151
  // package.json
6152
6152
  var package_default = {
6153
6153
  name: "codeam-cli",
6154
- version: "2.60.68",
6154
+ version: "2.60.70",
6155
6155
  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.",
6156
6156
  type: "commonjs",
6157
6157
  main: "dist/index.js",
@@ -7294,7 +7294,7 @@ var CommandRelayService = class _CommandRelayService {
7294
7294
  // fresh + clear the "CLI update available" banner after a self-update
7295
7295
  // (a codespace that reinstalls @latest reconnects via heartbeat, not
7296
7296
  // pair/reconnect). Older backends ignore the extra field.
7297
- ..."2.60.68" ? { ideVersion: "2.60.68" } : {}
7297
+ ..."2.60.70" ? { ideVersion: "2.60.70" } : {}
7298
7298
  }).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
7299
7299
  }
7300
7300
  /**
@@ -12127,10 +12127,10 @@ function buildForPlatform(platform3) {
12127
12127
  var import_node_crypto4 = require("crypto");
12128
12128
 
12129
12129
  // src/agents/claude/resolver.ts
12130
- function buildClaudeLaunch(extraArgs = [], os52 = createOsStrategy()) {
12131
- const found = os52.findInPath("claude") ?? os52.findInPath("claude-code");
12130
+ function buildClaudeLaunch(extraArgs = [], os53 = createOsStrategy()) {
12131
+ const found = os53.findInPath("claude") ?? os53.findInPath("claude-code");
12132
12132
  if (!found) return null;
12133
- return os52.buildLaunch(found, extraArgs);
12133
+ return os53.buildLaunch(found, extraArgs);
12134
12134
  }
12135
12135
 
12136
12136
  // src/agents/claude/installer.ts
@@ -12720,8 +12720,8 @@ var ClaudeRuntimeStrategy = class {
12720
12720
  meta = getAgent("claude");
12721
12721
  mode = "interactive";
12722
12722
  os;
12723
- constructor(os52) {
12724
- this.os = os52;
12723
+ constructor(os53) {
12724
+ this.os = os53;
12725
12725
  }
12726
12726
  /**
12727
12727
  * Claude Code's react-ink TUI enables bracketed-paste mode at
@@ -13501,8 +13501,8 @@ function codexCredentialLocator() {
13501
13501
  function codexLoginLauncher() {
13502
13502
  return {
13503
13503
  async ensureInstalled() {
13504
- const os52 = createOsStrategy();
13505
- return os52.findInPath("codex") !== null;
13504
+ const os53 = createOsStrategy();
13505
+ return os53.findInPath("codex") !== null;
13506
13506
  },
13507
13507
  launch() {
13508
13508
  return (0, import_node_child_process4.spawn)("codex", ["login"], { stdio: "inherit" });
@@ -13525,8 +13525,8 @@ var CodexRuntimeStrategy = class {
13525
13525
  meta = getAgent("codex");
13526
13526
  mode = "interactive";
13527
13527
  os;
13528
- constructor(os52) {
13529
- this.os = os52;
13528
+ constructor(os53) {
13529
+ this.os = os53;
13530
13530
  }
13531
13531
  async prepareLaunch() {
13532
13532
  let binary = this.os.findInPath("codex");
@@ -13635,12 +13635,12 @@ var CodexRuntimeStrategy = class {
13635
13635
  });
13636
13636
  }
13637
13637
  };
13638
- function resolveNpm(os52) {
13639
- return os52.id === "win32" ? "npm.cmd" : "npm";
13638
+ function resolveNpm(os53) {
13639
+ return os53.id === "win32" ? "npm.cmd" : "npm";
13640
13640
  }
13641
- async function installCodexViaNpm(os52) {
13641
+ async function installCodexViaNpm(os53) {
13642
13642
  return new Promise((resolve7, reject) => {
13643
- const proc = (0, import_node_child_process5.spawn)(resolveNpm(os52), ["install", "-g", "@openai/codex"], {
13643
+ const proc = (0, import_node_child_process5.spawn)(resolveNpm(os53), ["install", "-g", "@openai/codex"], {
13644
13644
  stdio: "inherit"
13645
13645
  });
13646
13646
  proc.on("close", (code) => {
@@ -13657,16 +13657,16 @@ async function installCodexViaNpm(os52) {
13657
13657
  });
13658
13658
  });
13659
13659
  }
13660
- function augmentNpmGlobalBin(os52) {
13660
+ function augmentNpmGlobalBin(os53) {
13661
13661
  try {
13662
- const result = (0, import_node_child_process5.spawnSync)(resolveNpm(os52), ["prefix", "-g"], {
13662
+ const result = (0, import_node_child_process5.spawnSync)(resolveNpm(os53), ["prefix", "-g"], {
13663
13663
  stdio: ["ignore", "pipe", "ignore"]
13664
13664
  });
13665
13665
  if (result.status !== 0) return;
13666
13666
  const prefix = result.stdout.toString().trim();
13667
13667
  if (!prefix) return;
13668
- const binDir = os52.id === "win32" ? prefix : path24.join(prefix, "bin");
13669
- os52.augmentPath([binDir]);
13668
+ const binDir = os53.id === "win32" ? prefix : path24.join(prefix, "bin");
13669
+ os53.augmentPath([binDir]);
13670
13670
  } catch {
13671
13671
  }
13672
13672
  }
@@ -13750,9 +13750,9 @@ var import_node_child_process8 = require("child_process");
13750
13750
  // src/agents/coderabbit/installer.ts
13751
13751
  var import_node_child_process6 = require("child_process");
13752
13752
  var INSTALL_URL = "https://cli.coderabbit.ai/install.sh";
13753
- async function ensureCoderabbitInstalled(os52) {
13754
- if (os52.findInPath("coderabbit")) return true;
13755
- if (os52.id === "win32") {
13753
+ async function ensureCoderabbitInstalled(os53) {
13754
+ if (os53.findInPath("coderabbit")) return true;
13755
+ if (os53.id === "win32") {
13756
13756
  console.error(
13757
13757
  "\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"
13758
13758
  );
@@ -13767,8 +13767,8 @@ async function ensureCoderabbitInstalled(os52) {
13767
13767
  proc.on("error", () => resolve7(false));
13768
13768
  });
13769
13769
  if (!ok) return false;
13770
- os52.augmentPath([`${os52.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
13771
- return os52.findInPath("coderabbit") !== null;
13770
+ os53.augmentPath([`${os53.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
13771
+ return os53.findInPath("coderabbit") !== null;
13772
13772
  }
13773
13773
 
13774
13774
  // src/agents/coderabbit/link.ts
@@ -13803,10 +13803,10 @@ function coderabbitCredentialLocator() {
13803
13803
  validate: validateNonEmptyCredential
13804
13804
  };
13805
13805
  }
13806
- function coderabbitLoginLauncher(os52) {
13806
+ function coderabbitLoginLauncher(os53) {
13807
13807
  return {
13808
13808
  async ensureInstalled() {
13809
- return ensureCoderabbitInstalled(os52);
13809
+ return ensureCoderabbitInstalled(os53);
13810
13810
  },
13811
13811
  launch() {
13812
13812
  return (0, import_node_child_process7.spawn)("coderabbit", ["auth", "login"], { stdio: "inherit" });
@@ -13862,8 +13862,8 @@ function pickLine(obj) {
13862
13862
  function toHunk(raw, groupSeverity) {
13863
13863
  if (!raw || typeof raw !== "object") return null;
13864
13864
  const o = raw;
13865
- const path74 = asString(pick(o, ["file_path", "filePath", "file", "path", "filename", "fileName"])) ?? asString(pick(o, ["location"])?.path);
13866
- if (!path74) return null;
13865
+ const path75 = asString(pick(o, ["file_path", "filePath", "file", "path", "filename", "fileName"])) ?? asString(pick(o, ["location"])?.path);
13866
+ if (!path75) return null;
13867
13867
  const message = asString(
13868
13868
  pick(o, [
13869
13869
  "comment",
@@ -13880,7 +13880,7 @@ function toHunk(raw, groupSeverity) {
13880
13880
  const severity = normSeverity(pick(o, ["severity", "level", "priority", "impact"])) ?? normSeverity(groupSeverity);
13881
13881
  const locObj = pick(o, ["location"]) ?? o;
13882
13882
  return {
13883
- path: path74.trim(),
13883
+ path: path75.trim(),
13884
13884
  line: pickLine(o) ?? pickLine(locObj),
13885
13885
  severity,
13886
13886
  message: (title && message ? `${title}: ${message}` : title || message).trim() || "(no message)"
@@ -13963,10 +13963,10 @@ function parsePlain(stdout) {
13963
13963
  for (const line of stdout.split(/\r?\n/)) {
13964
13964
  const m = line.match(HUNK_LINE_RE);
13965
13965
  if (!m) continue;
13966
- const [, path74, lineNo, sevToken, message] = m;
13967
- if (!path74 || !lineNo || !message) continue;
13966
+ const [, path75, lineNo, sevToken, message] = m;
13967
+ if (!path75 || !lineNo || !message) continue;
13968
13968
  hunks.push({
13969
- path: path74.trim(),
13969
+ path: path75.trim(),
13970
13970
  line: Number(lineNo),
13971
13971
  severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
13972
13972
  message: message.trim().replace(/^[*-]\s+/, "")
@@ -14026,8 +14026,8 @@ var CoderabbitRuntimeStrategy = class {
14026
14026
  meta = getAgent("coderabbit");
14027
14027
  mode = "batch";
14028
14028
  os;
14029
- constructor(os52) {
14030
- this.os = os52;
14029
+ constructor(os53) {
14030
+ this.os = os53;
14031
14031
  }
14032
14032
  getDefaultArgs() {
14033
14033
  return ["review", "--agent"];
@@ -14298,10 +14298,10 @@ function cursorCredentialLocator() {
14298
14298
  validate: validateNonEmptyCredential
14299
14299
  };
14300
14300
  }
14301
- function cursorLoginLauncher(os52) {
14301
+ function cursorLoginLauncher(os53) {
14302
14302
  return {
14303
14303
  async ensureInstalled() {
14304
- if (os52.findInPath("cursor-agent")) return true;
14304
+ if (os53.findInPath("cursor-agent")) return true;
14305
14305
  console.error(
14306
14306
  "\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"
14307
14307
  );
@@ -14365,8 +14365,8 @@ var CursorRuntimeStrategy = class {
14365
14365
  meta = getAgent("cursor");
14366
14366
  mode = "interactive";
14367
14367
  os;
14368
- constructor(os52) {
14369
- this.os = os52;
14368
+ constructor(os53) {
14369
+ this.os = os53;
14370
14370
  }
14371
14371
  async prepareLaunch() {
14372
14372
  const binary = this.os.findInPath("cursor-agent");
@@ -14582,10 +14582,10 @@ function aiderCredentialLocator() {
14582
14582
  validate: validateNonEmptyCredential
14583
14583
  };
14584
14584
  }
14585
- function aiderLoginLauncher(os52) {
14585
+ function aiderLoginLauncher(os53) {
14586
14586
  return {
14587
14587
  async ensureInstalled() {
14588
- if (os52.findInPath("aider")) return true;
14588
+ if (os53.findInPath("aider")) return true;
14589
14589
  console.error(
14590
14590
  "\n \u2717 aider binary not on PATH.\n Install Aider:\n pip install aider-chat\n then re-run `codeam link aider`.\n"
14591
14591
  );
@@ -14595,7 +14595,7 @@ function aiderLoginLauncher(os52) {
14595
14595
  console.error(
14596
14596
  "\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"
14597
14597
  );
14598
- return (0, import_node_child_process11.spawn)(os52.id === "win32" ? "cmd.exe" : "sh", os52.id === "win32" ? ["/c", "exit", "0"] : ["-c", "exit 0"], {
14598
+ return (0, import_node_child_process11.spawn)(os53.id === "win32" ? "cmd.exe" : "sh", os53.id === "win32" ? ["/c", "exit", "0"] : ["-c", "exit 0"], {
14599
14599
  stdio: "ignore"
14600
14600
  });
14601
14601
  }
@@ -14667,8 +14667,8 @@ var AiderRuntimeStrategy = class {
14667
14667
  meta = getAgent("aider");
14668
14668
  mode = "interactive";
14669
14669
  os;
14670
- constructor(os52) {
14671
- this.os = os52;
14670
+ constructor(os53) {
14671
+ this.os = os53;
14672
14672
  }
14673
14673
  async prepareLaunch() {
14674
14674
  const binary = this.os.findInPath("aider");
@@ -14800,8 +14800,8 @@ function geminiCredentialLocator() {
14800
14800
  function geminiLoginLauncher() {
14801
14801
  return {
14802
14802
  async ensureInstalled() {
14803
- const os52 = createOsStrategy();
14804
- return os52.findInPath("gemini") !== null;
14803
+ const os53 = createOsStrategy();
14804
+ return os53.findInPath("gemini") !== null;
14805
14805
  },
14806
14806
  launch() {
14807
14807
  return (0, import_node_child_process12.spawn)("gemini", ["auth", "login"], { stdio: "inherit" });
@@ -14991,8 +14991,8 @@ var GeminiRuntimeStrategy = class {
14991
14991
  meta = getAgent("gemini");
14992
14992
  mode = "interactive";
14993
14993
  os;
14994
- constructor(os52) {
14995
- this.os = os52;
14994
+ constructor(os53) {
14995
+ this.os = os53;
14996
14996
  }
14997
14997
  async prepareLaunch() {
14998
14998
  const binary = this.os.findInPath("gemini");
@@ -15283,8 +15283,8 @@ var KimiRuntimeStrategy = class {
15283
15283
  meta = getAgent("kimi");
15284
15284
  mode = "interactive";
15285
15285
  os;
15286
- constructor(os52) {
15287
- this.os = os52;
15286
+ constructor(os53) {
15287
+ this.os = os53;
15288
15288
  }
15289
15289
  async prepareLaunch() {
15290
15290
  const binary = this.os.findInPath("kimi");
@@ -15397,19 +15397,19 @@ var KimiRuntimeStrategy = class {
15397
15397
 
15398
15398
  // src/agents/registry.ts
15399
15399
  var runtimeBuilders = {
15400
- claude: (os52) => new ClaudeRuntimeStrategy(os52),
15401
- codex: (os52) => new CodexRuntimeStrategy(os52),
15402
- coderabbit: (os52) => new CoderabbitRuntimeStrategy(os52),
15403
- cursor: (os52) => new CursorRuntimeStrategy(os52),
15404
- aider: (os52) => new AiderRuntimeStrategy(os52),
15405
- gemini: (os52) => new GeminiRuntimeStrategy(os52),
15406
- kimi: (os52) => new KimiRuntimeStrategy(os52)
15400
+ claude: (os53) => new ClaudeRuntimeStrategy(os53),
15401
+ codex: (os53) => new CodexRuntimeStrategy(os53),
15402
+ coderabbit: (os53) => new CoderabbitRuntimeStrategy(os53),
15403
+ cursor: (os53) => new CursorRuntimeStrategy(os53),
15404
+ aider: (os53) => new AiderRuntimeStrategy(os53),
15405
+ gemini: (os53) => new GeminiRuntimeStrategy(os53),
15406
+ kimi: (os53) => new KimiRuntimeStrategy(os53)
15407
15407
  };
15408
15408
  var deployBuilders = {
15409
15409
  claude: () => new ClaudeDeployStrategy(),
15410
15410
  codex: () => new CodexDeployStrategy()
15411
15411
  };
15412
- function createAgentStrategy(agent, os52 = createOsStrategy()) {
15412
+ function createAgentStrategy(agent, os53 = createOsStrategy()) {
15413
15413
  if (!AGENT_REGISTRY[agent]?.enabled) {
15414
15414
  throw new Error(
15415
15415
  `Agent "${agent}" is not supported in this codeam-cli version. Upgrade with 'npm i -g codeam-cli@latest'.`
@@ -15419,10 +15419,10 @@ function createAgentStrategy(agent, os52 = createOsStrategy()) {
15419
15419
  if (!build) {
15420
15420
  throw new Error(`No runtime strategy registered for agent "${agent}"`);
15421
15421
  }
15422
- return build(os52);
15422
+ return build(os53);
15423
15423
  }
15424
- function createInteractiveAgentStrategy(agent, os52 = createOsStrategy()) {
15425
- const s = createAgentStrategy(agent, os52);
15424
+ function createInteractiveAgentStrategy(agent, os53 = createOsStrategy()) {
15425
+ const s = createAgentStrategy(agent, os53);
15426
15426
  if (s.mode !== "interactive") {
15427
15427
  throw new Error(
15428
15428
  `Agent "${agent}" is a batch agent; use createAgentStrategy + .runOneShot for one-shot reviews.`
@@ -16119,26 +16119,26 @@ function restoreCoderabbitOauthBlob(value) {
16119
16119
  (0, import_node_fs5.writeFileSync)(path36.join(dir, file), contents, { mode: 384 });
16120
16120
  }
16121
16121
  async function configureCoderabbit(input, deps = {}) {
16122
- const os52 = deps.os ?? createOsStrategy();
16122
+ const os53 = deps.os ?? createOsStrategy();
16123
16123
  const ensureInstalled = deps.ensureInstalled ?? ensureCoderabbitInstalled;
16124
16124
  const isLoggedIn = deps.isLoggedIn ?? defaultIsLoggedIn;
16125
16125
  const runOAuth = deps.runOAuthLogin ?? runCoderabbitOAuthLogin;
16126
16126
  const snapshot = deps.snapshotDir ?? (() => snapshotCredentialDir());
16127
16127
  const capture2 = deps.captureCredential ?? ((b) => diffCapturedCredential(b));
16128
16128
  const loginWithApiKey = deps.loginWithApiKey ?? defaultLoginWithApiKey;
16129
- const home = os52.homeDir();
16130
- os52.augmentPath(
16131
- os52.id === "win32" ? [
16129
+ const home = os53.homeDir();
16130
+ os53.augmentPath(
16131
+ os53.id === "win32" ? [
16132
16132
  path36.join(home, ".local", "bin"),
16133
16133
  path36.join(process.env.APPDATA ?? path36.join(home, "AppData", "Roaming"), "npm"),
16134
16134
  path36.join(home, "scoop", "shims")
16135
16135
  ] : [path36.join(home, ".local", "bin"), "/opt/homebrew/bin", "/usr/local/bin"]
16136
16136
  );
16137
- const installed2 = os52.findInPath("coderabbit") !== null;
16137
+ const installed2 = os53.findInPath("coderabbit") !== null;
16138
16138
  const base = () => ({
16139
16139
  action: input.action,
16140
16140
  supported: true,
16141
- installed: os52.findInPath("coderabbit") !== null,
16141
+ installed: os53.findInPath("coderabbit") !== null,
16142
16142
  loggedIn: false
16143
16143
  });
16144
16144
  if (input.action === "status") {
@@ -16152,7 +16152,7 @@ async function configureCoderabbit(input, deps = {}) {
16152
16152
  const key = (input.apiKey ?? "").trim();
16153
16153
  if (!key) return { ...res2, error: "No API key provided" };
16154
16154
  if (!res2.installed) {
16155
- const ok = await ensureInstalled(os52);
16155
+ const ok = await ensureInstalled(os53);
16156
16156
  res2.installed = ok;
16157
16157
  if (!ok) return { ...res2, error: "CodeRabbit CLI could not be installed" };
16158
16158
  }
@@ -16176,7 +16176,7 @@ async function configureCoderabbit(input, deps = {}) {
16176
16176
  }
16177
16177
  if (!res2.installed) {
16178
16178
  deps.onEvent?.({ kind: "installing" });
16179
- const ok = await ensureInstalled(os52);
16179
+ const ok = await ensureInstalled(os53);
16180
16180
  res2.installed = ok;
16181
16181
  if (!ok) return { ...res2, error: "CodeRabbit CLI could not be installed" };
16182
16182
  }
@@ -16206,7 +16206,7 @@ async function configureCoderabbit(input, deps = {}) {
16206
16206
  const res2 = base();
16207
16207
  if (!installed2) {
16208
16208
  deps.onEvent?.({ kind: "installing" });
16209
- const ok = await ensureInstalled(os52);
16209
+ const ok = await ensureInstalled(os53);
16210
16210
  res2.installed = ok;
16211
16211
  if (!ok) return { ...res2, error: "CodeRabbit CLI could not be installed" };
16212
16212
  }
@@ -16246,7 +16246,7 @@ async function configureCoderabbit(input, deps = {}) {
16246
16246
  }
16247
16247
  const res = base();
16248
16248
  if (!res.installed) {
16249
- const ok = await ensureInstalled(os52);
16249
+ const ok = await ensureInstalled(os53);
16250
16250
  res.installed = ok;
16251
16251
  if (!ok) return { ...res, error: "CodeRabbit CLI is not installed" };
16252
16252
  }
@@ -17871,7 +17871,7 @@ async function autoUpgradeBeforeCriticalCommand() {
17871
17871
  if (process.env.NODE_ENV === "test") return;
17872
17872
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
17873
17873
  if (process.env.CI) return;
17874
- const current = true ? "2.60.68" : null;
17874
+ const current = true ? "2.60.70" : null;
17875
17875
  if (!current) return;
17876
17876
  const cache = readCache();
17877
17877
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -17888,7 +17888,7 @@ function checkForUpdates() {
17888
17888
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
17889
17889
  if (process.env.CI) return;
17890
17890
  if (!process.stdout.isTTY) return;
17891
- const current = true ? "2.60.68" : null;
17891
+ const current = true ? "2.60.70" : null;
17892
17892
  if (!current) return;
17893
17893
  const cache = readCache();
17894
17894
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -17908,7 +17908,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
17908
17908
  var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
17909
17909
  var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
17910
17910
  function currentCliVersion() {
17911
- return true ? "2.60.68" : null;
17911
+ return true ? "2.60.70" : null;
17912
17912
  }
17913
17913
  function runCmd(cmd, args2, timeoutMs) {
17914
17914
  return new Promise((resolve7) => {
@@ -18136,6 +18136,78 @@ function isDeployPayload(p2) {
18136
18136
  function isStopPayload(p2) {
18137
18137
  return typeof p2.sessionId === "string";
18138
18138
  }
18139
+ var FLEET_CONTAINER_NAME_RE = /^codeam-box-[a-z0-9]+$/;
18140
+ function isFleetContainerName(v) {
18141
+ return typeof v === "string" && FLEET_CONTAINER_NAME_RE.test(v);
18142
+ }
18143
+ function isFiniteNumber(v) {
18144
+ return typeof v === "number" && Number.isFinite(v);
18145
+ }
18146
+ function isFleetLimits(v) {
18147
+ if (typeof v !== "object" || v === null) return false;
18148
+ const l = v;
18149
+ return isFiniteNumber(l.memoryMb) && isFiniteNumber(l.cpus) && isFiniteNumber(l.pidsLimit) && isFiniteNumber(l.diskGb);
18150
+ }
18151
+ function isFleetCreateBoxPayload(p2) {
18152
+ return typeof p2.boxId === "string" && isFleetContainerName(p2.containerName) && typeof p2.enrollToken === "string" && p2.enrollToken.length > 0 && typeof p2.apiOrigin === "string" && p2.apiOrigin.length > 0 && isFleetLimits(p2.limits);
18153
+ }
18154
+ function isFleetBoxRefPayload(p2) {
18155
+ if (typeof p2.boxId !== "string") return false;
18156
+ if (!isFleetContainerName(p2.containerName)) return false;
18157
+ if (p2.removeVolume !== void 0 && typeof p2.removeVolume !== "boolean") return false;
18158
+ return true;
18159
+ }
18160
+ function fleetUserIdFromContainerName(containerName) {
18161
+ return containerName.slice("codeam-box-".length);
18162
+ }
18163
+ function isMissingContainerError(stderr) {
18164
+ return /no such container/i.test(stderr);
18165
+ }
18166
+ function isMissingVolumeError(stderr) {
18167
+ return /no such volume/i.test(stderr);
18168
+ }
18169
+ function resolveFleetBoxImage() {
18170
+ return process.env.CODEAM_FLEET_BOX_IMAGE || "ghcr.io/edgar-durand/codeam-box:latest";
18171
+ }
18172
+ var DOCKER_RUN_TIMEOUT_MS = 12e4;
18173
+ var defaultDockerRunner = {
18174
+ run(args2, opts = {}) {
18175
+ return new Promise((resolve7) => {
18176
+ const child = (0, import_node_child_process23.spawn)("docker", args2, {
18177
+ stdio: ["ignore", "pipe", "pipe"],
18178
+ env: { ...process.env, ...opts.env }
18179
+ });
18180
+ let stdoutBuf = "";
18181
+ let stderrBuf = "";
18182
+ let settled = false;
18183
+ const timer = setTimeout(
18184
+ () => {
18185
+ if (settled) return;
18186
+ killQuiet(child);
18187
+ },
18188
+ opts.timeoutMs ?? DOCKER_RUN_TIMEOUT_MS
18189
+ );
18190
+ const done = (code) => {
18191
+ if (settled) return;
18192
+ settled = true;
18193
+ clearTimeout(timer);
18194
+ resolve7({ code, stderr: stderrBuf, stdout: stdoutBuf });
18195
+ };
18196
+ child.stdout?.on("data", (b) => {
18197
+ stdoutBuf += b.toString();
18198
+ });
18199
+ child.stderr?.on("data", (b) => {
18200
+ stderrBuf += b.toString();
18201
+ });
18202
+ child.once("error", (err) => {
18203
+ stderrBuf += stderrBuf ? `
18204
+ ${err.message}` : err.message;
18205
+ done(null);
18206
+ });
18207
+ child.once("exit", (code) => done(code));
18208
+ });
18209
+ }
18210
+ };
18139
18211
  var CONTROL_AGENT_META = {
18140
18212
  id: "claude",
18141
18213
  displayName: "CodeAgent Host Agent",
@@ -18177,6 +18249,7 @@ var HostAgentSupervisor = class {
18177
18249
  this.teardownHeadroom = deps.teardownHeadroom ?? defaultTeardownHeadroom;
18178
18250
  this.selfUpdate = deps.selfUpdate ?? runSelfUpdate;
18179
18251
  this.onUpdated = deps.onUpdated ?? defaultOnUpdated;
18252
+ this.docker = deps.docker ?? defaultDockerRunner;
18180
18253
  }
18181
18254
  identity;
18182
18255
  deps;
@@ -18213,6 +18286,8 @@ var HostAgentSupervisor = class {
18213
18286
  /** Best-effort systemd de-provision used by `self_hosted_wipe`. */
18214
18287
  disableService;
18215
18288
  teardownHeadroom;
18289
+ /** Docker runner for the fleet `fleet_*` control-plane handlers. */
18290
+ docker;
18216
18291
  /** Guards against firing the self-heal more than once. */
18217
18292
  healing = false;
18218
18293
  /**
@@ -18380,6 +18455,38 @@ var HostAgentSupervisor = class {
18380
18455
  * arbitrary command surface).
18381
18456
  */
18382
18457
  async handleCommand(cmd) {
18458
+ if (cmd.type === "fleet_create_box") {
18459
+ if (!isFleetCreateBoxPayload(cmd.payload)) {
18460
+ log.warn("host-agent", `ignoring malformed fleet_create_box id=${cmd.id}`);
18461
+ return;
18462
+ }
18463
+ await this.fleetCreateBox(cmd.payload);
18464
+ return;
18465
+ }
18466
+ if (cmd.type === "fleet_start_box") {
18467
+ if (!isFleetBoxRefPayload(cmd.payload)) {
18468
+ log.warn("host-agent", `ignoring malformed fleet_start_box id=${cmd.id}`);
18469
+ return;
18470
+ }
18471
+ await this.fleetStartBox(cmd.payload);
18472
+ return;
18473
+ }
18474
+ if (cmd.type === "fleet_stop_box") {
18475
+ if (!isFleetBoxRefPayload(cmd.payload)) {
18476
+ log.warn("host-agent", `ignoring malformed fleet_stop_box id=${cmd.id}`);
18477
+ return;
18478
+ }
18479
+ await this.fleetStopBox(cmd.payload);
18480
+ return;
18481
+ }
18482
+ if (cmd.type === "fleet_delete_box") {
18483
+ if (!isFleetBoxRefPayload(cmd.payload)) {
18484
+ log.warn("host-agent", `ignoring malformed fleet_delete_box id=${cmd.id}`);
18485
+ return;
18486
+ }
18487
+ await this.fleetDeleteBox(cmd.payload);
18488
+ return;
18489
+ }
18383
18490
  if (cmd.type === "self_hosted_deploy") {
18384
18491
  if (!isDeployPayload(cmd.payload)) {
18385
18492
  log.warn("host-agent", `ignoring malformed self_hosted_deploy id=${cmd.id}`);
@@ -18417,6 +18524,131 @@ var HostAgentSupervisor = class {
18417
18524
  }
18418
18525
  log.trace("host-agent", `ignoring unsupported command type=${cmd.type}`);
18419
18526
  }
18527
+ /**
18528
+ * `fleet_create_box` — `docker run` a per-user rescue box. Builds the FULL
18529
+ * argv from a fixed template (Global Constraints — nothing from the wire
18530
+ * is passed through as a raw docker argument beyond the already-validated
18531
+ * `containerName` and the numeric resource limits): hard isolation
18532
+ * (`--cap-drop ALL`, `--security-opt no-new-privileges`, resource caps,
18533
+ * the isolated `fleet-net` network, a SINGLE named volume mounted at
18534
+ * `/home/box` — named identically to the container, per the Global
18535
+ * Constraints — and the ops labels). NEVER `--privileged`, NEVER a
18536
+ * `docker.sock` mount, NEVER a host bind mount. The api origin (not a
18537
+ * secret) is delivered via a normal `-e KEY=value`. The enroll token IS a
18538
+ * secret — spec invariant #1 is "token via env, NEVER argv" — so it is
18539
+ * delivered as a BARE `-e CODEAM_ENROLL_TOKEN` (no `=value`) with the
18540
+ * actual value passed only through {@link DockerRunner.run}'s `env` map,
18541
+ * which the runner merges into the `docker` CLI process's OWN env; docker
18542
+ * then reads a bare `-e NAME` from its own env and forwards it into the
18543
+ * container. The value never appears in the `docker run` argv, so it's
18544
+ * never visible via `ps` on the shared fleet host; never logged either.
18545
+ */
18546
+ async fleetCreateBox(payload) {
18547
+ const { containerName, limits } = payload;
18548
+ const userId = fleetUserIdFromContainerName(containerName);
18549
+ log.info(
18550
+ "host-agent",
18551
+ `fleet_create_box id=${payload.boxId} name=${containerName} mem=${limits.memoryMb}m cpus=${limits.cpus} pids=${limits.pidsLimit}`
18552
+ );
18553
+ const args2 = [
18554
+ "run",
18555
+ "-d",
18556
+ "--name",
18557
+ containerName,
18558
+ "--cap-drop",
18559
+ "ALL",
18560
+ "--security-opt",
18561
+ "no-new-privileges",
18562
+ "--memory",
18563
+ `${limits.memoryMb}m`,
18564
+ "--cpus",
18565
+ String(limits.cpus),
18566
+ "--pids-limit",
18567
+ String(limits.pidsLimit),
18568
+ "--network",
18569
+ "fleet-net",
18570
+ "--label",
18571
+ `com.codeagent.user-id=${userId}`,
18572
+ "--label",
18573
+ `com.codeagent.box-id=${payload.boxId}`,
18574
+ "--label",
18575
+ "com.codeagent.created-by=fleet",
18576
+ "-v",
18577
+ `${containerName}:/home/box`,
18578
+ // Bare `-e NAME` (no `=value`) — docker reads the value from ITS OWN
18579
+ // process env (supplied below via `opts.env`), never from this argv.
18580
+ "-e",
18581
+ "CODEAM_ENROLL_TOKEN",
18582
+ "-e",
18583
+ `CODEAM_API_URL=${payload.apiOrigin}`,
18584
+ resolveFleetBoxImage()
18585
+ ];
18586
+ const res = await this.docker.run(args2, {
18587
+ timeoutMs: DOCKER_RUN_TIMEOUT_MS,
18588
+ env: { CODEAM_ENROLL_TOKEN: payload.enrollToken }
18589
+ });
18590
+ if (res.code === 0) {
18591
+ log.info(
18592
+ "host-agent",
18593
+ `fleet box ${containerName} created (${res.stdout.trim().slice(0, 12)})`
18594
+ );
18595
+ } else {
18596
+ log.warn(
18597
+ "host-agent",
18598
+ `fleet_create_box ${containerName} failed (code=${res.code}): ${res.stderr.trim().slice(-300)}`
18599
+ );
18600
+ }
18601
+ }
18602
+ /** `fleet_start_box` — wake a sleeping box (`docker start`). Idempotent: a
18603
+ * container the host already removed is treated as success. */
18604
+ async fleetStartBox(payload) {
18605
+ log.info("host-agent", `fleet_start_box id=${payload.boxId} name=${payload.containerName}`);
18606
+ const res = await this.docker.run(["start", payload.containerName]);
18607
+ if (res.code !== 0 && !isMissingContainerError(res.stderr)) {
18608
+ log.warn(
18609
+ "host-agent",
18610
+ `fleet_start_box ${payload.containerName} failed (code=${res.code}): ${res.stderr.trim().slice(-300)}`
18611
+ );
18612
+ }
18613
+ }
18614
+ /** `fleet_stop_box` — sleep an idle box (`docker stop`). MUST be
18615
+ * idempotent — the backend's reap sweeps may re-send a stop for a box
18616
+ * the host already stopped/removed; "No such container" is success. */
18617
+ async fleetStopBox(payload) {
18618
+ log.info("host-agent", `fleet_stop_box id=${payload.boxId} name=${payload.containerName}`);
18619
+ const res = await this.docker.run(["stop", payload.containerName]);
18620
+ if (res.code !== 0 && !isMissingContainerError(res.stderr)) {
18621
+ log.warn(
18622
+ "host-agent",
18623
+ `fleet_stop_box ${payload.containerName} failed (code=${res.code}): ${res.stderr.trim().slice(-300)}`
18624
+ );
18625
+ }
18626
+ }
18627
+ /** `fleet_delete_box` — `docker rm -f`, plus `docker volume rm` when the
18628
+ * backend asks for a reap (`removeVolume`). MUST be idempotent — deleting
18629
+ * an already-gone container/volume is success, never a failure. */
18630
+ async fleetDeleteBox(payload) {
18631
+ log.info(
18632
+ "host-agent",
18633
+ `fleet_delete_box id=${payload.boxId} name=${payload.containerName} removeVolume=${Boolean(payload.removeVolume)}`
18634
+ );
18635
+ const res = await this.docker.run(["rm", "-f", payload.containerName]);
18636
+ if (res.code !== 0 && !isMissingContainerError(res.stderr)) {
18637
+ log.warn(
18638
+ "host-agent",
18639
+ `fleet_delete_box ${payload.containerName} failed (code=${res.code}): ${res.stderr.trim().slice(-300)}`
18640
+ );
18641
+ }
18642
+ if (payload.removeVolume) {
18643
+ const volRes = await this.docker.run(["volume", "rm", payload.containerName]);
18644
+ if (volRes.code !== 0 && !isMissingVolumeError(volRes.stderr)) {
18645
+ log.warn(
18646
+ "host-agent",
18647
+ `fleet_delete_box volume rm ${payload.containerName} failed (code=${volRes.code}): ${volRes.stderr.trim().slice(-300)}`
18648
+ );
18649
+ }
18650
+ }
18651
+ }
18420
18652
  /**
18421
18653
  * Prepare the workspace, write the agent credential (same as codespace
18422
18654
  * provisioning), and spawn a supervised `codeam pair-auto` child.
@@ -20440,11 +20672,11 @@ function resolveDoltInstallStrategy(platform3) {
20440
20672
  }
20441
20673
  var DOLT_RELEASE_BASE = "https://github.com/dolthub/dolt/releases/latest/download";
20442
20674
  function doltPlatformTuple(platform3, arch2) {
20443
- const os52 = platform3 === "win32" ? "windows" : platform3 === "darwin" ? "darwin" : "linux";
20675
+ const os53 = platform3 === "win32" ? "windows" : platform3 === "darwin" ? "darwin" : "linux";
20444
20676
  const a = arch2 === "x64" ? "amd64" : arch2 === "arm64" ? "arm64" : null;
20445
20677
  if (!a) return null;
20446
- if (os52 === "windows" && a !== "amd64") return null;
20447
- return `${os52}-${a}`;
20678
+ if (os53 === "windows" && a !== "amd64") return null;
20679
+ return `${os53}-${a}`;
20448
20680
  }
20449
20681
  function resolveDoltTarballStrategy(targetDir, platform3, arch2) {
20450
20682
  const tuple = doltPlatformTuple(platform3, arch2);
@@ -23068,11 +23300,11 @@ function resolveTokenValue(args2) {
23068
23300
  }
23069
23301
  const fileFlag = args2.find((a) => a.startsWith("--token-file="));
23070
23302
  if (fileFlag) {
23071
- const path74 = fileFlag.slice("--token-file=".length);
23303
+ const path75 = fileFlag.slice("--token-file=".length);
23072
23304
  try {
23073
- const content = fs56.readFileSync(path74, "utf8").trim();
23074
- if (content.length === 0) fail(`--token-file ${path74} is empty`);
23075
- rmIfExistsQuiet(path74);
23305
+ const content = fs56.readFileSync(path75, "utf8").trim();
23306
+ if (content.length === 0) fail(`--token-file ${path75} is empty`);
23307
+ rmIfExistsQuiet(path75);
23076
23308
  return content;
23077
23309
  } catch (err) {
23078
23310
  fail(`Could not read --token-file: ${err.message}`);
@@ -23712,14 +23944,14 @@ function defaultSdkDir() {
23712
23944
  return resolveSdkDirViaRequire();
23713
23945
  }
23714
23946
  function resolveClaudeNativeBinary(deps = {}) {
23715
- const existsSync26 = deps.existsSync ?? import_fs4.default.existsSync;
23947
+ const existsSync27 = deps.existsSync ?? import_fs4.default.existsSync;
23716
23948
  const platformKey = deps.platformKey ?? currentPlatformKey();
23717
23949
  const sdkDir = deps.sdkDir !== void 0 ? deps.sdkDir : defaultSdkDir();
23718
23950
  if (!sdkDir) return null;
23719
23951
  const scopeDir = import_path8.default.dirname(sdkDir);
23720
23952
  const binName = platformKey.startsWith("win32-") ? "claude.exe" : "claude";
23721
23953
  const candidate = import_path8.default.join(scopeDir, `claude-agent-sdk-${platformKey}`, binName);
23722
- return existsSync26(candidate) ? candidate : null;
23954
+ return existsSync27(candidate) ? candidate : null;
23723
23955
  }
23724
23956
  var realSleep = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
23725
23957
  async function waitForClaudeNativeBinary(opts = {}) {
@@ -23770,18 +24002,18 @@ async function waitForCommandOnPath(cmd, opts = {}) {
23770
24002
  return check();
23771
24003
  }
23772
24004
  function resolveCursorAgentBinary(deps = {}) {
23773
- const existsSync26 = deps.existsSync ?? import_fs4.default.existsSync;
24005
+ const existsSync27 = deps.existsSync ?? import_fs4.default.existsSync;
23774
24006
  const platform3 = deps.platform ?? process.platform;
23775
24007
  const env = deps.env ?? process.env;
23776
24008
  if (platform3 === "win32") {
23777
24009
  const localAppData = env.LOCALAPPDATA;
23778
24010
  if (!localAppData) return null;
23779
24011
  const exe = import_path8.default.win32.join(localAppData, "cursor-agent", "cursor-agent.exe");
23780
- return existsSync26(exe) ? exe : null;
24012
+ return existsSync27(exe) ? exe : null;
23781
24013
  }
23782
24014
  const home = deps.homedir ?? import_os10.default.homedir();
23783
24015
  const unix = import_path8.default.posix.join(home, ".local", "bin", "cursor-agent");
23784
- return existsSync26(unix) ? unix : null;
24016
+ return existsSync27(unix) ? unix : null;
23785
24017
  }
23786
24018
  async function waitForCursorAgent(opts = {}) {
23787
24019
  const timeoutMs = opts.timeoutMs ?? 18e4;
@@ -35271,9 +35503,9 @@ function checkSessions() {
35271
35503
  }
35272
35504
  }
35273
35505
  function checkAgentBinaries() {
35274
- const os52 = createOsStrategy();
35506
+ const os53 = createOsStrategy();
35275
35507
  return getEnabledAgents().map((meta) => {
35276
- const found = os52.findInPath(meta.binaryName);
35508
+ const found = os53.findInPath(meta.binaryName);
35277
35509
  return {
35278
35510
  id: `agent-${meta.id}`,
35279
35511
  label: `Agent binary: ${meta.displayName} (${meta.binaryName})`,
@@ -35337,7 +35569,7 @@ function checkChokidar() {
35337
35569
  }
35338
35570
  async function doctor(args2 = []) {
35339
35571
  const json = args2.includes("--json");
35340
- const cliVersion = true ? "2.60.68" : "0.0.0-dev";
35572
+ const cliVersion = true ? "2.60.70" : "0.0.0-dev";
35341
35573
  const apiBase2 = resolveApiBaseUrl();
35342
35574
  const diagnosticId = (0, import_node_crypto12.randomUUID)();
35343
35575
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -35535,6 +35767,9 @@ async function completion(args2) {
35535
35767
 
35536
35768
  // src/integrations/mcp-run.ts
35537
35769
  var import_node_child_process28 = require("child_process");
35770
+ var import_node_fs9 = require("fs");
35771
+ var import_node_os9 = __toESM(require("os"));
35772
+ var import_node_path8 = __toESM(require("path"));
35538
35773
 
35539
35774
  // src/integrations/token-client.ts
35540
35775
  var REFRESH_AHEAD_MS = 5 * 60 * 1e3;
@@ -35754,8 +35989,24 @@ function commandExists(command2) {
35754
35989
  return false;
35755
35990
  }
35756
35991
  }
35992
+ function localBinCandidates(command2) {
35993
+ return [
35994
+ import_node_path8.default.join(import_node_os9.default.homedir(), ".local", "bin", command2),
35995
+ import_node_path8.default.join(import_node_os9.default.homedir(), ".cargo", "bin", command2)
35996
+ ];
35997
+ }
35998
+ function resolveLauncherPath(command2, deps = {
35999
+ commandExists,
36000
+ existsSync: import_node_fs9.existsSync
36001
+ }) {
36002
+ if (deps.commandExists(command2)) return command2;
36003
+ for (const candidate of localBinCandidates(command2)) {
36004
+ if (deps.existsSync(candidate)) return candidate;
36005
+ }
36006
+ return command2;
36007
+ }
35757
36008
  function ensureCommand(command2) {
35758
- if (commandExists(command2)) return;
36009
+ if (resolveLauncherPath(command2) !== command2 || commandExists(command2)) return;
35759
36010
  if (process.platform === "win32") {
35760
36011
  process.stderr.write(
35761
36012
  `[codeam mcp-run] '${command2}' not found on PATH \u2014 install it and retry.
@@ -35764,6 +36015,15 @@ function ensureCommand(command2) {
35764
36015
  return;
35765
36016
  }
35766
36017
  if (command2 === "uvx") {
36018
+ try {
36019
+ (0, import_node_child_process28.execSync)("curl -LsSf https://astral.sh/uv/install.sh | sh", {
36020
+ stdio: ["ignore", process.stderr, process.stderr],
36021
+ timeout: 18e4,
36022
+ env: { ...process.env, UV_NO_MODIFY_PATH: "1" }
36023
+ });
36024
+ } catch {
36025
+ }
36026
+ if (resolveLauncherPath(command2) !== command2) return;
35767
36027
  try {
35768
36028
  (0, import_node_child_process28.execSync)("python3 -m pip install --user --quiet uv", {
35769
36029
  stdio: ["ignore", process.stderr, process.stderr],
@@ -35771,6 +36031,11 @@ function ensureCommand(command2) {
35771
36031
  });
35772
36032
  } catch {
35773
36033
  }
36034
+ if (resolveLauncherPath(command2) !== command2) return;
36035
+ process.stderr.write(
36036
+ `[codeam mcp-run] could not provision '${command2}' (standalone installer + pip both failed) \u2014 the '${command2}'-launched MCP server will be unavailable.
36037
+ `
36038
+ );
35774
36039
  }
35775
36040
  }
35776
36041
  async function mcpRun(args2) {
@@ -35789,6 +36054,7 @@ async function mcpRun(args2) {
35789
36054
  process.exit(1);
35790
36055
  }
35791
36056
  ensureCommand(delivery.command);
36057
+ const launcher = resolveLauncherPath(delivery.command);
35792
36058
  const client2 = new IntegrationTokenClient({
35793
36059
  sessionId,
35794
36060
  pluginId,
@@ -35804,7 +36070,7 @@ async function mcpRun(args2) {
35804
36070
  const value = current[field];
35805
36071
  if (typeof value === "string" && value) env[envVar] = value;
35806
36072
  }
35807
- return { command: delivery.command, args: delivery.args, env };
36073
+ return { command: launcher, args: delivery.args, env };
35808
36074
  },
35809
36075
  shouldRestartNow: () => current !== null && new Date(current.expiresAt).getTime() - Date.now() < RESTART_AHEAD_MS
35810
36076
  });
@@ -35814,7 +36080,7 @@ async function mcpRun(args2) {
35814
36080
  // src/commands/version.ts
35815
36081
  var import_picocolors15 = __toESM(require("picocolors"));
35816
36082
  function version2() {
35817
- const v = true ? "2.60.68" : "unknown";
36083
+ const v = true ? "2.60.70" : "unknown";
35818
36084
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
35819
36085
  }
35820
36086
 
@@ -35963,10 +36229,10 @@ var EXIT_CODE_NAMES = {
35963
36229
  };
35964
36230
 
35965
36231
  // src/index.ts
35966
- var os51 = __toESM(require("os"));
36232
+ var os52 = __toESM(require("os"));
35967
36233
  if (!process.env.HOME) {
35968
36234
  try {
35969
- const home = os51.homedir();
36235
+ const home = os52.homedir();
35970
36236
  if (home) process.env.HOME = home;
35971
36237
  } catch {
35972
36238
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.60.68",
3
+ "version": "2.60.70",
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",