codeam-cli 2.60.41 → 2.60.43

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 +180 -32
  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.42] — 2026-07-10
8
+
9
+ ### Added
10
+
11
+ - **cli:** CodeRabbit 'provision' action — restore the vaulted credential, no re-login
12
+
13
+ ## [2.60.41] — 2026-07-10
14
+
15
+ ### Fixed
16
+
17
+ - **cli:** Surface a clean error when a CodeRabbit review times out
18
+
7
19
  ## [2.60.40] — 2026-07-10
8
20
 
9
21
  ### Added
package/dist/index.js CHANGED
@@ -5689,7 +5689,7 @@ function readAnonId() {
5689
5689
  }
5690
5690
  function superProperties() {
5691
5691
  return {
5692
- cliVersion: true ? "2.60.41" : "0.0.0-dev",
5692
+ cliVersion: true ? "2.60.43" : "0.0.0-dev",
5693
5693
  nodeVersion: process.version,
5694
5694
  platform: process.platform,
5695
5695
  arch: process.arch,
@@ -5870,7 +5870,7 @@ var os4 = __toESM(require("os"));
5870
5870
  // package.json
5871
5871
  var package_default = {
5872
5872
  name: "codeam-cli",
5873
- version: "2.60.41",
5873
+ version: "2.60.43",
5874
5874
  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.",
5875
5875
  type: "commonjs",
5876
5876
  main: "dist/index.js",
@@ -6196,6 +6196,22 @@ async function postHeadroomEvent(input) {
6196
6196
  };
6197
6197
  }
6198
6198
  }
6199
+ async function fetchProvisionCredential(input) {
6200
+ try {
6201
+ const res = await _transport.postJsonAuthed(
6202
+ `${API_BASE}/api/plugin/agents/${input.agentId}/provision-credential`,
6203
+ { sessionId: input.sessionId, pluginId: input.pluginId },
6204
+ input.pluginAuthToken
6205
+ );
6206
+ const data = res?.data;
6207
+ if (data && (data.method === "api_key" || data.method === "oauth") && typeof data.credential === "string" && data.credential.length > 0) {
6208
+ return { method: data.method, credential: data.credential };
6209
+ }
6210
+ return null;
6211
+ } catch {
6212
+ return null;
6213
+ }
6214
+ }
6199
6215
  async function postCoderabbitEvent(input) {
6200
6216
  try {
6201
6217
  await _transport.postJsonAuthed(
@@ -6963,7 +6979,7 @@ var CommandRelayService = class {
6963
6979
  // fresh + clear the "CLI update available" banner after a self-update
6964
6980
  // (a codespace that reinstalls @latest reconnects via heartbeat, not
6965
6981
  // pair/reconnect). Older backends ignore the extra field.
6966
- ..."2.60.41" ? { ideVersion: "2.60.41" } : {}
6982
+ ..."2.60.43" ? { ideVersion: "2.60.43" } : {}
6967
6983
  }).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
6968
6984
  }
6969
6985
  /**
@@ -7190,10 +7206,10 @@ var WINDOWS_LEGACY_JUNCTIONS = [
7190
7206
  /[\\/]Start Menu([\\/]|$)/i,
7191
7207
  /[\\/]Templates([\\/]|$)/i
7192
7208
  ];
7193
- function isUnsafeWindowsWatchRoot(dir, homedir42) {
7209
+ function isUnsafeWindowsWatchRoot(dir, homedir43) {
7194
7210
  const norm = (p2) => p2.replace(/\//g, "\\").replace(/\\+$/, "").toLowerCase();
7195
7211
  const cwd = norm(dir);
7196
- const home = norm(homedir42);
7212
+ const home = norm(homedir43);
7197
7213
  if (cwd === home) return true;
7198
7214
  if (/^[a-z]:$/.test(cwd)) return true;
7199
7215
  const sysRoots = [
@@ -8414,6 +8430,9 @@ var startCommandSchema = import_zod.z.object({
8414
8430
  // loopback so a remote-host `link_oauth` login completes (session-relay).
8415
8431
  "link_deliver_callback",
8416
8432
  "link_apikey",
8433
+ // Restore the caller's already-vaulted CodeRabbit credential onto this
8434
+ // session (no re-login) — fetches from the backend + installs + writes it.
8435
+ "provision",
8417
8436
  "review"
8418
8437
  ]).optional(),
8419
8438
  // `headroom_configure` — savings ingest URL delivered from the session
@@ -12419,8 +12438,8 @@ var ClaudeRuntimeStrategy = class {
12419
12438
  const sessionArgs = ["--session-id", sessionId];
12420
12439
  let launch = buildClaudeLaunch(sessionArgs, this.os);
12421
12440
  if (!launch) {
12422
- const installed = await ensureClaudeInstalled();
12423
- if (installed) launch = buildClaudeLaunch(sessionArgs, this.os);
12441
+ const installed2 = await ensureClaudeInstalled();
12442
+ if (installed2) launch = buildClaudeLaunch(sessionArgs, this.os);
12424
12443
  }
12425
12444
  if (!launch) {
12426
12445
  const cmd = this.os.id === "win32" ? "irm https://claude.ai/install.ps1 | iex" : "curl -fsSL https://claude.ai/install.sh | bash";
@@ -15285,8 +15304,8 @@ async function link(args2 = []) {
15285
15304
  }
15286
15305
  const installSpin = dist_exports.spinner();
15287
15306
  installSpin.start(`Checking that ${ctx.binary} is installed...`);
15288
- const installed = await ctx.launcher.ensureInstalled();
15289
- if (!installed) {
15307
+ const installed2 = await ctx.launcher.ensureInstalled();
15308
+ if (!installed2) {
15290
15309
  installSpin.stop("Failed");
15291
15310
  showError(`Could not install ${ctx.displayName}. Install it manually then re-run.`);
15292
15311
  process.exit(1);
@@ -15489,6 +15508,8 @@ async function linkDryRunPreflight(ctx) {
15489
15508
 
15490
15509
  // src/agents/coderabbit/configure.ts
15491
15510
  var import_node_child_process15 = require("child_process");
15511
+ var import_node_os4 = require("os");
15512
+ var import_node_fs5 = require("fs");
15492
15513
  var path36 = __toESM(require("path"));
15493
15514
 
15494
15515
  // src/agents/coderabbit/oauth.ts
@@ -15760,6 +15781,23 @@ function collectChangedFiles(cwd) {
15760
15781
  }
15761
15782
  return [...byPath.values()];
15762
15783
  }
15784
+ function restoreCoderabbitOauthBlob(value) {
15785
+ const dir = path36.join((0, import_node_os4.homedir)(), ".coderabbit");
15786
+ (0, import_node_fs5.mkdirSync)(dir, { recursive: true });
15787
+ let file = "auth.json";
15788
+ let contents = value.trim();
15789
+ if (contents.startsWith("{")) {
15790
+ try {
15791
+ const parsed = JSON.parse(contents);
15792
+ if (typeof parsed.file === "string" && typeof parsed.contents === "string") {
15793
+ file = path36.basename(parsed.file);
15794
+ contents = parsed.contents;
15795
+ }
15796
+ } catch {
15797
+ }
15798
+ }
15799
+ (0, import_node_fs5.writeFileSync)(path36.join(dir, file), contents, { mode: 384 });
15800
+ }
15763
15801
  async function configureCoderabbit(input, deps = {}) {
15764
15802
  const os50 = deps.os ?? createOsStrategy();
15765
15803
  const ensureInstalled = deps.ensureInstalled ?? ensureCoderabbitInstalled;
@@ -15776,7 +15814,7 @@ async function configureCoderabbit(input, deps = {}) {
15776
15814
  path36.join(home, "scoop", "shims")
15777
15815
  ] : [path36.join(home, ".local", "bin"), "/opt/homebrew/bin", "/usr/local/bin"]
15778
15816
  );
15779
- const installed = os50.findInPath("coderabbit") !== null;
15817
+ const installed2 = os50.findInPath("coderabbit") !== null;
15780
15818
  const base = () => ({
15781
15819
  action: input.action,
15782
15820
  supported: true,
@@ -15810,9 +15848,43 @@ async function configureCoderabbit(input, deps = {}) {
15810
15848
  ...stored ? {} : { error: "Signed in, but storing the API key for reuse failed" }
15811
15849
  };
15812
15850
  }
15851
+ if (input.action === "provision") {
15852
+ const res2 = base();
15853
+ const cred = input.provisionCredential;
15854
+ if (!cred || !cred.credential.trim()) {
15855
+ return { ...res2, error: "No vaulted CodeRabbit credential to provision" };
15856
+ }
15857
+ if (!res2.installed) {
15858
+ deps.onEvent?.({ kind: "installing" });
15859
+ const ok = await ensureInstalled(os50);
15860
+ res2.installed = ok;
15861
+ if (!ok) return { ...res2, error: "CodeRabbit CLI could not be installed" };
15862
+ }
15863
+ if (cred.method === "api_key") {
15864
+ const login = loginWithApiKey(cred.credential.trim());
15865
+ if (!login.ok) {
15866
+ return {
15867
+ ...res2,
15868
+ loggedIn: false,
15869
+ linked: false,
15870
+ error: login.error ?? "The vaulted CodeRabbit API key was rejected \u2014 re-link it."
15871
+ };
15872
+ }
15873
+ return { ...res2, loggedIn: true, linked: true };
15874
+ }
15875
+ try {
15876
+ restoreCoderabbitOauthBlob(cred.credential);
15877
+ } catch (err) {
15878
+ return {
15879
+ ...res2,
15880
+ error: err instanceof Error ? err.message : "Failed to restore the vaulted credential"
15881
+ };
15882
+ }
15883
+ return { ...res2, loggedIn: true, linked: true };
15884
+ }
15813
15885
  if (input.action === "link_oauth") {
15814
15886
  const res2 = base();
15815
- if (!installed) {
15887
+ if (!installed2) {
15816
15888
  deps.onEvent?.({ kind: "installing" });
15817
15889
  const ok = await ensureInstalled(os50);
15818
15890
  res2.installed = ok;
@@ -15890,8 +15962,8 @@ var os29 = __toESM(require("os"));
15890
15962
  var path37 = __toESM(require("path"));
15891
15963
 
15892
15964
  // src/lib/restrict-to-owner.ts
15893
- var import_node_fs5 = __toESM(require("fs"));
15894
- var import_node_os4 = __toESM(require("os"));
15965
+ var import_node_fs6 = __toESM(require("fs"));
15966
+ var import_node_os5 = __toESM(require("os"));
15895
15967
  var import_node_child_process16 = require("child_process");
15896
15968
  var BROAD_WINDOWS_SIDS = [
15897
15969
  "*S-1-1-0",
@@ -15903,7 +15975,7 @@ var BROAD_WINDOWS_SIDS = [
15903
15975
  function restrictToOwner(filePath) {
15904
15976
  try {
15905
15977
  if (process.platform === "win32") {
15906
- const username = import_node_os4.default.userInfo().username;
15978
+ const username = import_node_os5.default.userInfo().username;
15907
15979
  (0, import_node_child_process16.execFileSync)(
15908
15980
  "icacls",
15909
15981
  [
@@ -15916,7 +15988,7 @@ function restrictToOwner(filePath) {
15916
15988
  { stdio: "ignore" }
15917
15989
  );
15918
15990
  } else {
15919
- import_node_fs5.default.chmodSync(filePath, 384);
15991
+ import_node_fs6.default.chmodSync(filePath, 384);
15920
15992
  }
15921
15993
  } catch {
15922
15994
  }
@@ -17421,7 +17493,7 @@ async function autoUpgradeBeforeCriticalCommand() {
17421
17493
  if (process.env.NODE_ENV === "test") return;
17422
17494
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
17423
17495
  if (process.env.CI) return;
17424
- const current = true ? "2.60.41" : null;
17496
+ const current = true ? "2.60.43" : null;
17425
17497
  if (!current) return;
17426
17498
  const cache = readCache();
17427
17499
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -17438,7 +17510,7 @@ function checkForUpdates() {
17438
17510
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
17439
17511
  if (process.env.CI) return;
17440
17512
  if (!process.stdout.isTTY) return;
17441
- const current = true ? "2.60.41" : null;
17513
+ const current = true ? "2.60.43" : null;
17442
17514
  if (!current) return;
17443
17515
  const cache = readCache();
17444
17516
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -17458,7 +17530,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
17458
17530
  var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
17459
17531
  var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
17460
17532
  function currentCliVersion() {
17461
- return true ? "2.60.41" : null;
17533
+ return true ? "2.60.43" : null;
17462
17534
  }
17463
17535
  function runCmd(cmd, args2, timeoutMs) {
17464
17536
  return new Promise((resolve7) => {
@@ -17512,8 +17584,8 @@ async function runSelfUpdate() {
17512
17584
  ["view", SELF_UPDATE_PKG, "version"],
17513
17585
  SELF_UPDATE_VIEW_TIMEOUT_MS
17514
17586
  );
17515
- const installed = after.code === 0 ? after.stdout.trim() || latest : latest;
17516
- return { status: "updated", version: installed };
17587
+ const installed2 = after.code === 0 ? after.stdout.trim() || latest : latest;
17588
+ return { status: "updated", version: installed2 };
17517
17589
  } catch (err) {
17518
17590
  log.warn(
17519
17591
  "host-agent",
@@ -20776,15 +20848,15 @@ async function handleBeadsActionCommand(action, started) {
20776
20848
  }
20777
20849
 
20778
20850
  // src/beads/config-store.ts
20779
- var import_node_fs6 = __toESM(require("fs"));
20780
- var import_node_os5 = __toESM(require("os"));
20851
+ var import_node_fs7 = __toESM(require("fs"));
20852
+ var import_node_os6 = __toESM(require("os"));
20781
20853
  var import_node_path5 = __toESM(require("path"));
20782
20854
  function beadsConfigPath() {
20783
- return import_node_path5.default.join(import_node_os5.default.homedir(), ".codeam", "beads-config.json");
20855
+ return import_node_path5.default.join(import_node_os6.default.homedir(), ".codeam", "beads-config.json");
20784
20856
  }
20785
20857
  function readBeadsEnabled() {
20786
20858
  try {
20787
- const raw = import_node_fs6.default.readFileSync(beadsConfigPath(), "utf8");
20859
+ const raw = import_node_fs7.default.readFileSync(beadsConfigPath(), "utf8");
20788
20860
  const cfg = JSON.parse(raw);
20789
20861
  return cfg.enabled !== false;
20790
20862
  } catch {
@@ -20793,10 +20865,10 @@ function readBeadsEnabled() {
20793
20865
  }
20794
20866
  function persistBeadsConfig(cfg) {
20795
20867
  const file = beadsConfigPath();
20796
- import_node_fs6.default.mkdirSync(import_node_path5.default.dirname(file), { recursive: true });
20868
+ import_node_fs7.default.mkdirSync(import_node_path5.default.dirname(file), { recursive: true });
20797
20869
  const tmp = `${file}.tmp`;
20798
- import_node_fs6.default.writeFileSync(tmp, JSON.stringify(cfg), { mode: 384 });
20799
- import_node_fs6.default.renameSync(tmp, file);
20870
+ import_node_fs7.default.writeFileSync(tmp, JSON.stringify(cfg), { mode: 384 });
20871
+ import_node_fs7.default.renameSync(tmp, file);
20800
20872
  restrictToOwner(file);
20801
20873
  }
20802
20874
 
@@ -21404,6 +21476,54 @@ var coderabbitConfigureH = async (ctx, cmd, parsed) => {
21404
21476
  });
21405
21477
  return r.ok === true;
21406
21478
  } : void 0;
21479
+ if (action === "provision") {
21480
+ await ctx.relay.sendResult(cmd.id, "completed", {
21481
+ action: "provision",
21482
+ supported: true,
21483
+ installed: false,
21484
+ loggedIn: false,
21485
+ linked: false
21486
+ });
21487
+ void (async () => {
21488
+ try {
21489
+ const cred = token ? await fetchProvisionCredential({
21490
+ agentId: "coderabbit",
21491
+ sessionId: ctx.sessionId,
21492
+ pluginId: ctx.pluginId,
21493
+ pluginAuthToken: token
21494
+ }) : null;
21495
+ if (!cred) {
21496
+ emit2("coderabbit_status", {
21497
+ installed: false,
21498
+ loggedIn: false,
21499
+ linked: false,
21500
+ error: "No vaulted CodeRabbit credential \u2014 sign in once to link it."
21501
+ });
21502
+ await emitChain;
21503
+ return;
21504
+ }
21505
+ const result2 = await configureCoderabbit(
21506
+ { action: "provision", provisionCredential: cred },
21507
+ { onEvent }
21508
+ );
21509
+ emit2("coderabbit_status", {
21510
+ installed: result2.installed,
21511
+ loggedIn: result2.loggedIn,
21512
+ linked: result2.linked ?? false,
21513
+ ...result2.error ? { error: result2.error } : {}
21514
+ });
21515
+ } catch (err) {
21516
+ emit2("coderabbit_status", {
21517
+ installed: false,
21518
+ loggedIn: false,
21519
+ linked: false,
21520
+ error: err instanceof Error ? err.message : "CodeRabbit provisioning failed"
21521
+ });
21522
+ }
21523
+ await emitChain;
21524
+ })();
21525
+ return;
21526
+ }
21407
21527
  if (action === "link_oauth") {
21408
21528
  await ctx.relay.sendResult(cmd.id, "completed", {
21409
21529
  action: "link_oauth",
@@ -22249,6 +22369,29 @@ function buildKeepAlive(ctx) {
22249
22369
  };
22250
22370
  }
22251
22371
 
22372
+ // src/lib/process-guards.ts
22373
+ var installed = false;
22374
+ function installRelayCrashGuards() {
22375
+ if (installed) return;
22376
+ installed = true;
22377
+ process.on("unhandledRejection", (reason) => {
22378
+ log.error("process", `unhandledRejection \u2014 relay kept alive \u2014 ${describeReason(reason)}`);
22379
+ });
22380
+ process.on("uncaughtException", (err) => {
22381
+ log.error("process", `uncaughtException \u2014 relay kept alive \u2014 ${describeReason(err)}`);
22382
+ });
22383
+ }
22384
+ function describeReason(reason) {
22385
+ if (reason instanceof Error) {
22386
+ return reason.stack ?? `${reason.name}: ${reason.message}`;
22387
+ }
22388
+ try {
22389
+ return typeof reason === "string" ? reason : JSON.stringify(reason);
22390
+ } catch {
22391
+ return String(reason);
22392
+ }
22393
+ }
22394
+
22252
22395
  // src/commands/start-infra-only.ts
22253
22396
  var INFRA_ONLY_COMMAND_TYPES = /* @__PURE__ */ new Set([
22254
22397
  // File ops (drive the dashboard's Files panel + open-file).
@@ -22282,6 +22425,7 @@ var INFRA_ONLY_COMMAND_TYPES = /* @__PURE__ */ new Set([
22282
22425
  "set_keep_alive"
22283
22426
  ]);
22284
22427
  async function startInfraOnly(agentId) {
22428
+ installRelayCrashGuards();
22285
22429
  const session = getActiveSession();
22286
22430
  if (!session?.pluginId) {
22287
22431
  throw new Error("startInfraOnly: no active session found in config");
@@ -22620,6 +22764,7 @@ function acquireSingletonLock() {
22620
22764
  }
22621
22765
  }
22622
22766
  async function pairAuto(args2) {
22767
+ installRelayCrashGuards();
22623
22768
  if (!acquireSingletonLock()) {
22624
22769
  capture("pair_auto_deferred_singleton", {});
22625
22770
  console.log(" A codeam session is already running here \u2014 deferring to it.");
@@ -23229,11 +23374,11 @@ async function waitForAdapterModuleGraph(command2, args2, opts = {}) {
23229
23374
 
23230
23375
  // src/agents/kimi/installer.ts
23231
23376
  var import_node_child_process25 = require("child_process");
23232
- var import_node_os6 = require("os");
23377
+ var import_node_os7 = require("os");
23233
23378
  var import_node_path6 = require("path");
23234
23379
  var INSTALL_URL2 = "https://code.kimi.com/kimi-code/install.sh";
23235
23380
  function kimiBinDir() {
23236
- return (0, import_node_path6.join)(process.env.KIMI_CODE_HOME || (0, import_node_path6.join)((0, import_node_os6.homedir)(), ".kimi-code"), "bin");
23381
+ return (0, import_node_path6.join)(process.env.KIMI_CODE_HOME || (0, import_node_path6.join)((0, import_node_os7.homedir)(), ".kimi-code"), "bin");
23237
23382
  }
23238
23383
  function kimiRuns() {
23239
23384
  const r = (0, import_node_child_process25.spawnSync)("kimi", ["--version"], { stdio: "ignore", timeout: 15e3 });
@@ -28075,7 +28220,9 @@ var FilesOutbox = class {
28075
28220
  const jittered = delayMs === 0 ? 0 : applyJitter(delayMs);
28076
28221
  this.flushTimer = setTimeout(() => {
28077
28222
  this.flushTimer = null;
28078
- void this.flush();
28223
+ this.flush().catch((err) => {
28224
+ log.warn("turnFiles", `outbox flush loop threw: ${err.message}`);
28225
+ });
28079
28226
  }, jittered);
28080
28227
  }
28081
28228
  async flush() {
@@ -31639,6 +31786,7 @@ function ensureClaudeOnboarded(cwd) {
31639
31786
 
31640
31787
  // src/commands/start.ts
31641
31788
  async function start(requestedAgent) {
31789
+ installRelayCrashGuards();
31642
31790
  showIntro();
31643
31791
  const session = requestedAgent ? getActiveSessionForAgent(requestedAgent) : getActiveSession();
31644
31792
  if (!session) {
@@ -34518,7 +34666,7 @@ function checkChokidar() {
34518
34666
  }
34519
34667
  async function doctor(args2 = []) {
34520
34668
  const json = args2.includes("--json");
34521
- const cliVersion = true ? "2.60.41" : "0.0.0-dev";
34669
+ const cliVersion = true ? "2.60.43" : "0.0.0-dev";
34522
34670
  const apiBase2 = resolveApiBaseUrl();
34523
34671
  const diagnosticId = (0, import_node_crypto12.randomUUID)();
34524
34672
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -34717,7 +34865,7 @@ async function completion(args2) {
34717
34865
  // src/commands/version.ts
34718
34866
  var import_picocolors15 = __toESM(require("picocolors"));
34719
34867
  function version2() {
34720
- const v = true ? "2.60.41" : "unknown";
34868
+ const v = true ? "2.60.43" : "unknown";
34721
34869
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
34722
34870
  }
34723
34871
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.60.41",
3
+ "version": "2.60.43",
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",