codeam-cli 2.61.19 → 2.61.21

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 +17 -0
  2. package/dist/index.js +301 -49
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,23 @@ 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.61.20] — 2026-07-18
8
+
9
+ ### Added
10
+
11
+ - **shared:** Add vcs integration category + GitHub PR wire types
12
+ - **cli:** CodeRabbit PR-review handler + vcs_agent_review command
13
+
14
+ ### Changed
15
+
16
+ - **shared:** Defer first-class GitHub integration (keep PR wire types + event)
17
+
18
+ ## [2.61.19] — 2026-07-18
19
+
20
+ ### Fixed
21
+
22
+ - **cli:** Omit model context window when it isn't a real catalog match (no fake 200K)
23
+
7
24
  ## [2.61.18] — 2026-07-18
8
25
 
9
26
  ### Added
package/dist/index.js CHANGED
@@ -935,7 +935,11 @@ var USER_EVENTS = {
935
935
  // backend re-publishes them on the per-user SSE bus (mirrored in repo A).
936
936
  CODERABBIT_PROGRESS: "coderabbit_progress",
937
937
  CODERABBIT_STATUS: "coderabbit_status",
938
- CODERABBIT_REVIEW: "coderabbit_review"
938
+ CODERABBIT_REVIEW: "coderabbit_review",
939
+ // VCS / PR Command Center — the backend publishes this after an agent finishes
940
+ // reviewing a PR (verdict + comment count + findings), driving the mobile
941
+ // completion screen + push. Mirrored in repo A's app-shared events.ts.
942
+ VCS_AGENT_REVIEW_COMPLETE: "vcs_agent_review_complete"
939
943
  };
940
944
 
941
945
  // ../../packages/shared/src/preview-prompts.ts
@@ -6028,7 +6032,7 @@ function readAnonId() {
6028
6032
  }
6029
6033
  function superProperties() {
6030
6034
  return {
6031
- cliVersion: true ? "2.61.19" : "0.0.0-dev",
6035
+ cliVersion: true ? "2.61.21" : "0.0.0-dev",
6032
6036
  nodeVersion: process.version,
6033
6037
  platform: process.platform,
6034
6038
  arch: process.arch,
@@ -6209,7 +6213,7 @@ var os4 = __toESM(require("os"));
6209
6213
  // package.json
6210
6214
  var package_default = {
6211
6215
  name: "codeam-cli",
6212
- version: "2.61.19",
6216
+ version: "2.61.21",
6213
6217
  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.",
6214
6218
  type: "commonjs",
6215
6219
  main: "dist/index.js",
@@ -6551,6 +6555,27 @@ async function fetchProvisionCredential(input) {
6551
6555
  return null;
6552
6556
  }
6553
6557
  }
6558
+ async function postAgentReviewReport(input) {
6559
+ try {
6560
+ await _transport.postJsonAuthed(
6561
+ `${API_BASE}/api/vcs/agent-review/report`,
6562
+ {
6563
+ sessionId: input.sessionId,
6564
+ pluginId: input.pluginId,
6565
+ report: input.report
6566
+ },
6567
+ input.pluginAuthToken
6568
+ );
6569
+ return { ok: true };
6570
+ } catch (err) {
6571
+ const e = err;
6572
+ return {
6573
+ ok: false,
6574
+ status: typeof e.statusCode === "number" ? e.statusCode : 0,
6575
+ message: e.message || "unknown"
6576
+ };
6577
+ }
6578
+ }
6554
6579
  async function postCoderabbitEvent(input) {
6555
6580
  try {
6556
6581
  await _transport.postJsonAuthed(
@@ -7352,7 +7377,7 @@ var CommandRelayService = class _CommandRelayService {
7352
7377
  // fresh + clear the "CLI update available" banner after a self-update
7353
7378
  // (a codespace that reinstalls @latest reconnects via heartbeat, not
7354
7379
  // pair/reconnect). Older backends ignore the extra field.
7355
- ..."2.61.19" ? { ideVersion: "2.61.19" } : {}
7380
+ ..."2.61.21" ? { ideVersion: "2.61.21" } : {}
7356
7381
  }).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
7357
7382
  }
7358
7383
  /**
@@ -8891,6 +8916,20 @@ var startCommandSchema = import_zod.z.object({
8891
8916
  ).max(32).optional(),
8892
8917
  notes: import_zod.z.string().max(4096).nullable().optional()
8893
8918
  }).optional(),
8919
+ // `vcs_agent_review` (Phase-2 "Ask an agent to review PR #X") — the PR the
8920
+ // review session should review + post its verdict to via `gh`. Only the
8921
+ // CodeRabbit CLI path consumes it; ACP agents get the task as an initial
8922
+ // prompt instead. `agentId` / `prompt` (declared above) carry the reviewing
8923
+ // agent + the composed review prompt. Spec:
8924
+ // docs/superpowers/specs/2026-07-18-pr-mr-command-center-design.md §6.
8925
+ pr: import_zod.z.object({
8926
+ owner: import_zod.z.string().min(1).max(255),
8927
+ repo: import_zod.z.string().min(1).max(255),
8928
+ number: import_zod.z.number().int().min(1),
8929
+ url: import_zod.z.string().max(2048).optional()
8930
+ }).optional(),
8931
+ // The PR base branch, so CodeRabbit reviews the PR diff (committed vs base).
8932
+ baseBranch: import_zod.z.string().max(255).optional(),
8894
8933
  // `env_write` carries the full desired set of environment variables
8895
8934
  // for the project `.env`. Bounded so a malformed payload can't flood
8896
8935
  // the disk-side serializer. `env_read` / `preview_restart` send no payload.
@@ -16349,8 +16388,163 @@ async function configureCoderabbit(input, deps = {}) {
16349
16388
  };
16350
16389
  }
16351
16390
 
16391
+ // src/agents/coderabbit/review-pr.ts
16392
+ var import_node_child_process16 = require("child_process");
16393
+ function repoSlug(prRef) {
16394
+ return `${prRef.owner}/${prRef.repo}`;
16395
+ }
16396
+ function decidePrVerdict(stats) {
16397
+ const critical = numStat(stats, "critical");
16398
+ const findingCount = numStat(stats, "findingCount");
16399
+ if (critical > 0) return "request_changes";
16400
+ if (findingCount > 0) return "comment";
16401
+ return "approve";
16402
+ }
16403
+ function numStat(stats, key) {
16404
+ const v = stats?.[key];
16405
+ return typeof v === "number" ? v : 0;
16406
+ }
16407
+ function severityBadge(sev) {
16408
+ if (sev === "error") return "\u{1F534} Critical";
16409
+ if (sev === "warn") return "\u{1F7E1} Warning";
16410
+ if (sev === "info") return "\u{1F535} Suggestion";
16411
+ return "Note";
16412
+ }
16413
+ function buildPrReviewBody(parsed, commentCount) {
16414
+ const head = parsed.markdown.trim().length > 0 ? parsed.markdown.trim() : parsed.hunks.length === 0 ? "No issues found \u2014 looks good to me." : `Found ${parsed.hunks.length} issue${parsed.hunks.length === 1 ? "" : "s"}.`;
16415
+ const inline = commentCount > 0 ? `
16416
+
16417
+ ${commentCount} inline comment${commentCount === 1 ? "" : "s"} posted.` : "";
16418
+ return `\u{1F407} **CodeRabbit review**
16419
+
16420
+ ${head}${inline}`;
16421
+ }
16422
+ function buildInlineCommentArgs(prRef, hunk, headSha) {
16423
+ return [
16424
+ "api",
16425
+ "--method",
16426
+ "POST",
16427
+ `/repos/${prRef.owner}/${prRef.repo}/pulls/${prRef.number}/comments`,
16428
+ "-f",
16429
+ `body=${severityBadge(hunk.severity)}: ${hunk.message}`,
16430
+ "-f",
16431
+ `commit_id=${headSha}`,
16432
+ "-f",
16433
+ `path=${hunk.path}`,
16434
+ "-F",
16435
+ `line=${hunk.line}`,
16436
+ "-f",
16437
+ "side=RIGHT"
16438
+ ];
16439
+ }
16440
+ function buildReviewVerdictArgs(prRef, verdict, body) {
16441
+ const flag = verdict === "approve" ? "--approve" : verdict === "request_changes" ? "--request-changes" : "--comment";
16442
+ return [
16443
+ "pr",
16444
+ "review",
16445
+ String(prRef.number),
16446
+ "--repo",
16447
+ repoSlug(prRef),
16448
+ flag,
16449
+ "--body",
16450
+ body
16451
+ ];
16452
+ }
16453
+ function toAgentReviewFindings(hunks) {
16454
+ return hunks.map((h) => ({
16455
+ path: h.path,
16456
+ ...typeof h.line === "number" ? { line: h.line } : {},
16457
+ ...h.severity ? { severity: h.severity } : {},
16458
+ message: h.message
16459
+ }));
16460
+ }
16461
+ function buildAgentReviewReport(prRef, agentId, verdict, hunks, commentCount) {
16462
+ const findings = toAgentReviewFindings(hunks);
16463
+ return {
16464
+ prRef,
16465
+ agentId,
16466
+ verdict,
16467
+ commentCount,
16468
+ ...findings.length > 0 ? { findings } : {}
16469
+ };
16470
+ }
16471
+ async function reviewPullRequest(params, deps) {
16472
+ const { prRef, agentId } = params;
16473
+ const out2 = await deps.runReview({
16474
+ changeSet: "committed",
16475
+ ...params.baseBranch ? { base: params.baseBranch } : {},
16476
+ structured: true
16477
+ });
16478
+ const parsed = {
16479
+ markdown: out2.markdown ?? "",
16480
+ hunks: out2.hunks ?? [],
16481
+ stats: out2.stats ?? { findingCount: 0, critical: 0, warning: 0, info: 0 }
16482
+ };
16483
+ let headSha = "";
16484
+ try {
16485
+ const meta = await deps.runGh([
16486
+ "pr",
16487
+ "view",
16488
+ String(prRef.number),
16489
+ "--repo",
16490
+ repoSlug(prRef),
16491
+ "--json",
16492
+ "headRefOid",
16493
+ "-q",
16494
+ ".headRefOid"
16495
+ ]);
16496
+ if (meta.code === 0) headSha = meta.stdout.trim();
16497
+ } catch {
16498
+ }
16499
+ let commentCount = 0;
16500
+ if (headSha) {
16501
+ for (const hunk of parsed.hunks) {
16502
+ if (typeof hunk.line !== "number") continue;
16503
+ try {
16504
+ const r = await deps.runGh(buildInlineCommentArgs(prRef, hunk, headSha));
16505
+ if (r.code === 0) commentCount += 1;
16506
+ } catch {
16507
+ }
16508
+ }
16509
+ }
16510
+ const verdict = decidePrVerdict(parsed.stats);
16511
+ const body = buildPrReviewBody(parsed, commentCount);
16512
+ try {
16513
+ await deps.runGh(buildReviewVerdictArgs(prRef, verdict, body));
16514
+ } catch {
16515
+ }
16516
+ const report = buildAgentReviewReport(prRef, agentId, verdict, parsed.hunks, commentCount);
16517
+ await deps.postReport(report);
16518
+ return report;
16519
+ }
16520
+ function defaultRunGh(args2) {
16521
+ return new Promise((resolve8) => {
16522
+ const stdout = [];
16523
+ const stderr = [];
16524
+ let proc;
16525
+ try {
16526
+ proc = (0, import_node_child_process16.spawn)("gh", args2, { stdio: ["ignore", "pipe", "pipe"] });
16527
+ } catch (err) {
16528
+ resolve8({ code: -1, stdout: "", stderr: err instanceof Error ? err.message : String(err) });
16529
+ return;
16530
+ }
16531
+ proc.stdout?.on("data", (b) => stdout.push(b));
16532
+ proc.stderr?.on("data", (b) => stderr.push(b));
16533
+ proc.on("error", (err) => {
16534
+ resolve8({ code: -1, stdout: "", stderr: err.message });
16535
+ });
16536
+ proc.on("close", (code) => {
16537
+ resolve8({
16538
+ code: code ?? 0,
16539
+ stdout: Buffer.concat(stdout).toString("utf8"),
16540
+ stderr: Buffer.concat(stderr).toString("utf8")
16541
+ });
16542
+ });
16543
+ });
16544
+ }
16545
+
16352
16546
  // src/commands/host-agent.ts
16353
- var import_node_child_process23 = require("child_process");
16547
+ var import_node_child_process24 = require("child_process");
16354
16548
  var os36 = __toESM(require("os"));
16355
16549
  var fs42 = __toESM(require("fs"));
16356
16550
  var path45 = __toESM(require("path"));
@@ -16363,7 +16557,7 @@ var import_node_path5 = __toESM(require("path"));
16363
16557
  // src/lib/restrict-to-owner.ts
16364
16558
  var import_node_fs6 = __toESM(require("fs"));
16365
16559
  var import_node_os5 = __toESM(require("os"));
16366
- var import_node_child_process16 = require("child_process");
16560
+ var import_node_child_process17 = require("child_process");
16367
16561
  var BROAD_WINDOWS_SIDS = [
16368
16562
  "*S-1-1-0",
16369
16563
  "*S-1-5-11",
@@ -16375,7 +16569,7 @@ function restrictToOwner(filePath) {
16375
16569
  try {
16376
16570
  if (process.platform === "win32") {
16377
16571
  const username = import_node_os5.default.userInfo().username;
16378
- (0, import_node_child_process16.execFileSync)(
16572
+ (0, import_node_child_process17.execFileSync)(
16379
16573
  "icacls",
16380
16574
  [
16381
16575
  filePath,
@@ -16681,9 +16875,9 @@ async function reportDeployProgress(auth, deployId, step, message, sessionId) {
16681
16875
  var fs35 = __toESM(require("fs"));
16682
16876
  var os31 = __toESM(require("os"));
16683
16877
  var path39 = __toESM(require("path"));
16684
- var import_node_child_process17 = require("child_process");
16878
+ var import_node_child_process18 = require("child_process");
16685
16879
  var import_node_util4 = require("util");
16686
- var execFileP4 = (0, import_node_util4.promisify)(import_node_child_process17.execFile);
16880
+ var execFileP4 = (0, import_node_util4.promisify)(import_node_child_process18.execFile);
16687
16881
  function isAbsolutePathTarget(target) {
16688
16882
  return path39.isAbsolute(target);
16689
16883
  }
@@ -16996,7 +17190,7 @@ function provisionAgentCredentials(publicAgentId, auth, homeDir2 = os32.homedir(
16996
17190
  }
16997
17191
 
16998
17192
  // src/commands/host/git-tooling.ts
16999
- var import_node_child_process18 = require("child_process");
17193
+ var import_node_child_process19 = require("child_process");
17000
17194
  var fs37 = __toESM(require("fs"));
17001
17195
  var os33 = __toESM(require("os"));
17002
17196
  var path41 = __toESM(require("path"));
@@ -17110,7 +17304,7 @@ var defaultGitToolingRunner = {
17110
17304
  which(cmd) {
17111
17305
  try {
17112
17306
  const probe = process.platform === "win32" ? "where" : "which";
17113
- (0, import_node_child_process18.execFileSync)(probe, [cmd], { stdio: "ignore" });
17307
+ (0, import_node_child_process19.execFileSync)(probe, [cmd], { stdio: "ignore" });
17114
17308
  return true;
17115
17309
  } catch {
17116
17310
  return false;
@@ -17118,7 +17312,7 @@ var defaultGitToolingRunner = {
17118
17312
  },
17119
17313
  run(cmd, args2, opts = {}) {
17120
17314
  return new Promise((resolve8) => {
17121
- const child = (0, import_node_child_process18.spawn)(cmd, args2, {
17315
+ const child = (0, import_node_child_process19.spawn)(cmd, args2, {
17122
17316
  stdio: [opts.input !== void 0 ? "pipe" : "ignore", "ignore", "pipe"]
17123
17317
  });
17124
17318
  let stderr = "";
@@ -17272,12 +17466,12 @@ var HeadroomStatsReporter = class {
17272
17466
  };
17273
17467
 
17274
17468
  // src/commands/host/os-packages.ts
17275
- var import_node_child_process19 = require("child_process");
17469
+ var import_node_child_process20 = require("child_process");
17276
17470
  var PM_INSTALL_TIMEOUT_MS = 18e4;
17277
17471
  var defaultHeadroomRunner = {
17278
17472
  which(cmd) {
17279
17473
  try {
17280
- (0, import_node_child_process19.execFileSync)("which", [cmd], { stdio: "ignore" });
17474
+ (0, import_node_child_process20.execFileSync)("which", [cmd], { stdio: "ignore" });
17281
17475
  return true;
17282
17476
  } catch {
17283
17477
  return false;
@@ -17286,7 +17480,7 @@ var defaultHeadroomRunner = {
17286
17480
  run(cmd, args2, opts = {}) {
17287
17481
  return new Promise((resolve8) => {
17288
17482
  const spawnEnv = opts.env ?? process.env;
17289
- const child = (0, import_node_child_process19.spawn)(cmd, args2, { stdio: ["ignore", "pipe", "pipe"], env: spawnEnv });
17483
+ const child = (0, import_node_child_process20.spawn)(cmd, args2, { stdio: ["ignore", "pipe", "pipe"], env: spawnEnv });
17290
17484
  let stderrBuf = "";
17291
17485
  let stdoutBuf = "";
17292
17486
  let settled = false;
@@ -17793,14 +17987,14 @@ async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner,
17793
17987
  }
17794
17988
 
17795
17989
  // src/commands/host/self-update.ts
17796
- var import_node_child_process21 = require("child_process");
17990
+ var import_node_child_process22 = require("child_process");
17797
17991
 
17798
17992
  // src/lib/updateNotifier.ts
17799
17993
  var fs40 = __toESM(require("fs"));
17800
17994
  var os35 = __toESM(require("os"));
17801
17995
  var path44 = __toESM(require("path"));
17802
17996
  var https6 = __toESM(require("https"));
17803
- var import_node_child_process20 = require("child_process");
17997
+ var import_node_child_process21 = require("child_process");
17804
17998
  var import_picocolors3 = __toESM(require("picocolors"));
17805
17999
  var PKG_NAME = "codeam-cli";
17806
18000
  var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
@@ -17894,7 +18088,7 @@ function notifyIfStale(currentVersion, latest) {
17894
18088
  }
17895
18089
  function isLinkedInstall() {
17896
18090
  try {
17897
- const root = (0, import_node_child_process20.execSync)("npm root -g", {
18091
+ const root = (0, import_node_child_process21.execSync)("npm root -g", {
17898
18092
  encoding: "utf8",
17899
18093
  stdio: ["ignore", "pipe", "ignore"],
17900
18094
  timeout: 2e3
@@ -17922,7 +18116,7 @@ function maybeAutoUpdate(currentVersion, latest) {
17922
18116
 
17923
18117
  `
17924
18118
  );
17925
- const install = (0, import_node_child_process20.spawnSync)("npm", ["install", "-g", `${PKG_NAME}@latest`], {
18119
+ const install = (0, import_node_child_process21.spawnSync)("npm", ["install", "-g", `${PKG_NAME}@latest`], {
17926
18120
  stdio: "inherit",
17927
18121
  env: process.env
17928
18122
  });
@@ -17943,7 +18137,7 @@ function maybeAutoUpdate(currentVersion, latest) {
17943
18137
  process.stderr.write(` ${import_picocolors3.default.green("\u2713")} Updated. Resuming session...
17944
18138
 
17945
18139
  `);
17946
- const child = (0, import_node_child_process20.spawnSync)("codeam", process.argv.slice(2), {
18140
+ const child = (0, import_node_child_process21.spawnSync)("codeam", process.argv.slice(2), {
17947
18141
  stdio: "inherit",
17948
18142
  env: process.env
17949
18143
  });
@@ -17953,7 +18147,7 @@ async function autoUpgradeBeforeCriticalCommand() {
17953
18147
  if (process.env.NODE_ENV === "test") return;
17954
18148
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
17955
18149
  if (process.env.CI) return;
17956
- const current = true ? "2.61.19" : null;
18150
+ const current = true ? "2.61.21" : null;
17957
18151
  if (!current) return;
17958
18152
  const cache = readCache();
17959
18153
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -17970,7 +18164,7 @@ function checkForUpdates() {
17970
18164
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
17971
18165
  if (process.env.CI) return;
17972
18166
  if (!process.stdout.isTTY) return;
17973
- const current = true ? "2.61.19" : null;
18167
+ const current = true ? "2.61.21" : null;
17974
18168
  if (!current) return;
17975
18169
  const cache = readCache();
17976
18170
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -17990,11 +18184,11 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
17990
18184
  var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
17991
18185
  var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
17992
18186
  function currentCliVersion() {
17993
- return true ? "2.61.19" : null;
18187
+ return true ? "2.61.21" : null;
17994
18188
  }
17995
18189
  function runCmd(cmd, args2, timeoutMs) {
17996
18190
  return new Promise((resolve8) => {
17997
- (0, import_node_child_process21.execFile)(cmd, args2, { timeout: timeoutMs }, (err, stdout, stderr) => {
18191
+ (0, import_node_child_process22.execFile)(cmd, args2, { timeout: timeoutMs }, (err, stdout, stderr) => {
17998
18192
  const code = err && typeof err.code === "number" ? err.code : err ? null : 0;
17999
18193
  resolve8({ code, stdout: stdout ?? "", stderr: stderr ?? "" });
18000
18194
  });
@@ -18056,11 +18250,11 @@ async function runSelfUpdate() {
18056
18250
  }
18057
18251
 
18058
18252
  // src/commands/host/teardown.ts
18059
- var import_node_child_process22 = require("child_process");
18253
+ var import_node_child_process23 = require("child_process");
18060
18254
  var fs41 = __toESM(require("fs"));
18061
18255
  var defaultDisableService = () => {
18062
18256
  try {
18063
- (0, import_node_child_process22.execFileSync)("systemctl", ["disable", "--now", "codeam-host-agent"], { stdio: "ignore" });
18257
+ (0, import_node_child_process23.execFileSync)("systemctl", ["disable", "--now", "codeam-host-agent"], { stdio: "ignore" });
18064
18258
  } catch {
18065
18259
  }
18066
18260
  };
@@ -18068,7 +18262,7 @@ var defaultTeardownHeadroom = () => {
18068
18262
  try {
18069
18263
  const kind = JSON.parse(fs41.readFileSync(headroomConfigPath(), "utf8")).agent;
18070
18264
  if (kind) {
18071
- (0, import_node_child_process22.execFileSync)("headroom", ["unwrap", kind], { stdio: "ignore", timeout: 15e3 });
18265
+ (0, import_node_child_process23.execFileSync)("headroom", ["unwrap", kind], { stdio: "ignore", timeout: 15e3 });
18072
18266
  }
18073
18267
  } catch {
18074
18268
  }
@@ -18255,7 +18449,7 @@ var DOCKER_RUN_TIMEOUT_MS = 12e4;
18255
18449
  var defaultDockerRunner = {
18256
18450
  run(args2, opts = {}) {
18257
18451
  return new Promise((resolve8) => {
18258
- const child = (0, import_node_child_process23.spawn)("docker", args2, {
18452
+ const child = (0, import_node_child_process24.spawn)("docker", args2, {
18259
18453
  stdio: ["ignore", "pipe", "pipe"],
18260
18454
  env: { ...process.env, ...opts.env }
18261
18455
  });
@@ -18301,13 +18495,13 @@ var CONTROL_AGENT_META = {
18301
18495
  headroomWrappable: false,
18302
18496
  acp: false
18303
18497
  };
18304
- var defaultSpawner = (env, cwd, args2 = []) => (0, import_node_child_process23.spawn)(process.execPath, [process.argv[1], "pair-auto", ...args2], {
18498
+ var defaultSpawner = (env, cwd, args2 = []) => (0, import_node_child_process24.spawn)(process.execPath, [process.argv[1], "pair-auto", ...args2], {
18305
18499
  cwd,
18306
18500
  env: { ...process.env, ...env },
18307
18501
  stdio: ["ignore", "pipe", "pipe"],
18308
18502
  detached: false
18309
18503
  });
18310
- var defaultResumeSpawner = (env, cwd) => (0, import_node_child_process23.spawn)(process.execPath, [process.argv[1]], {
18504
+ var defaultResumeSpawner = (env, cwd) => (0, import_node_child_process24.spawn)(process.execPath, [process.argv[1]], {
18311
18505
  cwd,
18312
18506
  // CODEAM_AUTO_APPROVE=1 → ACP path (baton off). CODEAM_RESUME_LATEST=1 →
18313
18507
  // continue the user's most-recent conversation instead of opening an empty
@@ -19080,7 +19274,7 @@ var HostAgentSupervisor = class {
19080
19274
  runAgentInstall(script) {
19081
19275
  return new Promise((resolve8) => {
19082
19276
  const home = process.env.HOME || os36.homedir();
19083
- const child = (0, import_node_child_process23.spawn)("sh", ["-c", script], {
19277
+ const child = (0, import_node_child_process24.spawn)("sh", ["-c", script], {
19084
19278
  env: { ...process.env, HOME: home },
19085
19279
  stdio: ["ignore", "pipe", "pipe"]
19086
19280
  });
@@ -22519,6 +22713,63 @@ var coderabbitConfigureH = async (ctx, cmd, parsed) => {
22519
22713
  await emitChain;
22520
22714
  await ctx.relay.sendResult(cmd.id, result.error && action !== "review" ? "failed" : "completed", result);
22521
22715
  };
22716
+ var vcsAgentReviewH = async (ctx, cmd, parsed) => {
22717
+ const pr = parsed.pr;
22718
+ if (!pr) {
22719
+ await ctx.relay.sendResult(cmd.id, "failed", { error: "Missing PR reference" });
22720
+ return;
22721
+ }
22722
+ const prRef = {
22723
+ owner: pr.owner,
22724
+ repo: pr.repo,
22725
+ number: pr.number,
22726
+ ...pr.url ? { url: pr.url } : {}
22727
+ };
22728
+ if (normalizeAgentId(ctx.agentId) !== "coderabbit") {
22729
+ await ctx.relay.sendResult(cmd.id, "completed", {
22730
+ action: "vcs_agent_review",
22731
+ skipped: true,
22732
+ reason: "non-coderabbit agent posts its review via the prompt + gh"
22733
+ });
22734
+ return;
22735
+ }
22736
+ await ctx.relay.sendResult(cmd.id, "completed", {
22737
+ action: "vcs_agent_review",
22738
+ started: true
22739
+ });
22740
+ const token = ctx.pluginAuthToken;
22741
+ void (async () => {
22742
+ const os53 = createOsStrategy();
22743
+ try {
22744
+ const report = await reviewPullRequest(
22745
+ {
22746
+ prRef,
22747
+ agentId: "coderabbit",
22748
+ baseBranch: parsed.baseBranch
22749
+ },
22750
+ {
22751
+ runReview: (input) => new CoderabbitRuntimeStrategy(os53).runOneShot(input),
22752
+ runGh: (args2) => defaultRunGh(args2),
22753
+ postReport: async (r) => {
22754
+ if (!token) return;
22755
+ await postAgentReviewReport({
22756
+ sessionId: ctx.sessionId,
22757
+ pluginId: ctx.pluginId,
22758
+ pluginAuthToken: token,
22759
+ report: r
22760
+ });
22761
+ }
22762
+ }
22763
+ );
22764
+ log.info(
22765
+ "vcs",
22766
+ `agent review of ${prRef.owner}/${prRef.repo}#${prRef.number} posted: ${report.verdict} (${report.commentCount} inline comment(s))`
22767
+ );
22768
+ } catch (err) {
22769
+ log.warn("vcs", "agent PR review failed (non-fatal)", err);
22770
+ }
22771
+ })();
22772
+ };
22522
22773
  var headroomBudgetH = async (ctx, cmd) => {
22523
22774
  const payload = cmd.payload;
22524
22775
  let rawAgentId = ctx.agentId || (typeof payload.agentId === "string" ? payload.agentId : "");
@@ -23250,6 +23501,7 @@ var handlers = {
23250
23501
  handback: handbackH,
23251
23502
  headroom_configure: headroomConfigureH,
23252
23503
  coderabbit_configure: coderabbitConfigureH,
23504
+ vcs_agent_review: vcsAgentReviewH,
23253
23505
  headroom_budget: headroomBudgetH,
23254
23506
  beads_configure: beadsConfigureH,
23255
23507
  cli_self_update: cliSelfUpdateH()
@@ -23792,7 +24044,7 @@ async function pairAuto(args2) {
23792
24044
  }
23793
24045
 
23794
24046
  // src/services/headroom/wrap-launch.ts
23795
- var import_node_child_process24 = require("child_process");
24047
+ var import_node_child_process25 = require("child_process");
23796
24048
  function wrapWithHeadroom(launch, opts) {
23797
24049
  if (!opts.enabled || !opts.headroomPresent) return launch;
23798
24050
  return {
@@ -23805,7 +24057,7 @@ var _present;
23805
24057
  function headroomPresent() {
23806
24058
  if (_present !== void 0) return Promise.resolve(_present);
23807
24059
  return new Promise((resolve8) => {
23808
- (0, import_node_child_process24.execFile)("headroom", ["--version"], (err) => {
24060
+ (0, import_node_child_process25.execFile)("headroom", ["--version"], (err) => {
23809
24061
  _present = !err;
23810
24062
  resolve8(_present);
23811
24063
  });
@@ -24330,7 +24582,7 @@ async function waitForAdapterModuleGraph(command2, args2, opts = {}) {
24330
24582
  }
24331
24583
 
24332
24584
  // src/agents/kimi/installer.ts
24333
- var import_node_child_process25 = require("child_process");
24585
+ var import_node_child_process26 = require("child_process");
24334
24586
  var import_node_os8 = require("os");
24335
24587
  var import_node_path7 = require("path");
24336
24588
  var INSTALL_URL2 = "https://code.kimi.com/kimi-code/install.sh";
@@ -24338,7 +24590,7 @@ function kimiBinDir() {
24338
24590
  return (0, import_node_path7.join)(process.env.KIMI_CODE_HOME || (0, import_node_path7.join)((0, import_node_os8.homedir)(), ".kimi-code"), "bin");
24339
24591
  }
24340
24592
  function kimiRuns() {
24341
- const r = (0, import_node_child_process25.spawnSync)("kimi", ["--version"], { stdio: "ignore", timeout: 15e3 });
24593
+ const r = (0, import_node_child_process26.spawnSync)("kimi", ["--version"], { stdio: "ignore", timeout: 15e3 });
24342
24594
  return !r.error && r.status === 0;
24343
24595
  }
24344
24596
  function augmentPath2() {
@@ -24348,7 +24600,7 @@ function augmentPath2() {
24348
24600
  }
24349
24601
  async function runInstaller2() {
24350
24602
  return new Promise((resolve8) => {
24351
- const proc = (0, import_node_child_process25.spawn)("sh", ["-c", `curl -fsSL ${INSTALL_URL2} | bash`], { stdio: "inherit" });
24603
+ const proc = (0, import_node_child_process26.spawn)("sh", ["-c", `curl -fsSL ${INSTALL_URL2} | bash`], { stdio: "inherit" });
24352
24604
  proc.on("close", (code) => resolve8(code === 0));
24353
24605
  proc.on("error", () => resolve8(false));
24354
24606
  });
@@ -25134,7 +25386,7 @@ var HistoryService = class _HistoryService {
25134
25386
  };
25135
25387
 
25136
25388
  // src/agents/acp/client.ts
25137
- var import_node_child_process26 = require("child_process");
25389
+ var import_node_child_process27 = require("child_process");
25138
25390
  var fs59 = __toESM(require("fs/promises"));
25139
25391
  var fsSync = __toESM(require("fs"));
25140
25392
  var os48 = __toESM(require("os"));
@@ -29340,7 +29592,7 @@ var AcpClient = class {
29340
29592
  "acpClient",
29341
29593
  `spawn cmd=${adapter.command} args=[${adapter.args.join(",")}] cwd=${cwd}`
29342
29594
  );
29343
- const child = (0, import_node_child_process26.spawn)(adapter.command, adapter.args, {
29595
+ const child = (0, import_node_child_process27.spawn)(adapter.command, adapter.args, {
29344
29596
  cwd,
29345
29597
  // extraEnv (e.g. CLAUDE_CODE_DISABLE_1M_CONTEXT=1 on an on-demand
29346
29598
  // re-spawn) layers over process.env; PATH stays last so the augmented
@@ -30058,12 +30310,12 @@ function buildRelaunchProxyEnv(baseEnv) {
30058
30310
  return env;
30059
30311
  }
30060
30312
  var relaunchProxyWithoutBudget = async () => {
30061
- const { spawn: spawn41 } = await import("child_process");
30313
+ const { spawn: spawn42 } = await import("child_process");
30062
30314
  killHeadroomProxy();
30063
30315
  await new Promise((r) => setTimeout(r, 500));
30064
30316
  const proxyEnv = buildRelaunchProxyEnv(process.env);
30065
30317
  try {
30066
- const proxy = spawn41(
30318
+ const proxy = spawn42(
30067
30319
  "headroom",
30068
30320
  ["proxy", "--port", "8787"],
30069
30321
  { stdio: "ignore", detached: true, env: proxyEnv }
@@ -37819,7 +38071,7 @@ function checkChokidar() {
37819
38071
  }
37820
38072
  async function doctor(args2 = []) {
37821
38073
  const json = args2.includes("--json");
37822
- const cliVersion = true ? "2.61.19" : "0.0.0-dev";
38074
+ const cliVersion = true ? "2.61.21" : "0.0.0-dev";
37823
38075
  const apiBase2 = resolveApiBaseUrl();
37824
38076
  const diagnosticId = (0, import_node_crypto12.randomUUID)();
37825
38077
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -38016,7 +38268,7 @@ async function completion(args2) {
38016
38268
  }
38017
38269
 
38018
38270
  // src/integrations/mcp-run.ts
38019
- var import_node_child_process28 = require("child_process");
38271
+ var import_node_child_process29 = require("child_process");
38020
38272
  var import_node_fs9 = require("fs");
38021
38273
  var import_node_os9 = __toESM(require("os"));
38022
38274
  var import_node_path8 = __toESM(require("path"));
@@ -38072,7 +38324,7 @@ var IntegrationTokenClient = class {
38072
38324
  };
38073
38325
 
38074
38326
  // src/integrations/stdio-proxy.ts
38075
- var import_node_child_process27 = require("child_process");
38327
+ var import_node_child_process28 = require("child_process");
38076
38328
  var import_node_readline3 = __toESM(require("readline"));
38077
38329
  var RESTART_CHECK_INTERVAL_MS = 3e4;
38078
38330
  var SIGKILL_ESCALATION_MS = 2e3;
@@ -38193,8 +38445,8 @@ var RestartableStdioProxy = class {
38193
38445
  }
38194
38446
  async spawnChild(stdout, preResolved) {
38195
38447
  const spec = preResolved ?? await this.opts.spawnSpec();
38196
- const spawn41 = this.opts.spawnImpl ?? import_node_child_process27.spawn;
38197
- const child = spawn41(spec.command, spec.args, {
38448
+ const spawn42 = this.opts.spawnImpl ?? import_node_child_process28.spawn;
38449
+ const child = spawn42(spec.command, spec.args, {
38198
38450
  env: { ...process.env, ...spec.env },
38199
38451
  // env only — never argv
38200
38452
  stdio: ["pipe", "pipe", "inherit"]
@@ -38233,7 +38485,7 @@ function resolveDelivery(id) {
38233
38485
  function commandExists(command2) {
38234
38486
  try {
38235
38487
  const probe = process.platform === "win32" ? "where" : "which";
38236
- (0, import_node_child_process28.execFileSync)(probe, [command2], { stdio: "ignore" });
38488
+ (0, import_node_child_process29.execFileSync)(probe, [command2], { stdio: "ignore" });
38237
38489
  return true;
38238
38490
  } catch {
38239
38491
  return false;
@@ -38266,7 +38518,7 @@ function ensureCommand(command2) {
38266
38518
  }
38267
38519
  if (command2 === "uvx") {
38268
38520
  try {
38269
- (0, import_node_child_process28.execSync)("curl -LsSf https://astral.sh/uv/install.sh | sh", {
38521
+ (0, import_node_child_process29.execSync)("curl -LsSf https://astral.sh/uv/install.sh | sh", {
38270
38522
  stdio: ["ignore", process.stderr, process.stderr],
38271
38523
  timeout: 18e4,
38272
38524
  env: { ...process.env, UV_NO_MODIFY_PATH: "1" }
@@ -38275,7 +38527,7 @@ function ensureCommand(command2) {
38275
38527
  }
38276
38528
  if (resolveLauncherPath(command2) !== command2) return;
38277
38529
  try {
38278
- (0, import_node_child_process28.execSync)("python3 -m pip install --user --quiet uv", {
38530
+ (0, import_node_child_process29.execSync)("python3 -m pip install --user --quiet uv", {
38279
38531
  stdio: ["ignore", process.stderr, process.stderr],
38280
38532
  timeout: 18e4
38281
38533
  });
@@ -38330,7 +38582,7 @@ async function mcpRun(args2) {
38330
38582
  // src/commands/version.ts
38331
38583
  var import_picocolors15 = __toESM(require("picocolors"));
38332
38584
  function version2() {
38333
- const v = true ? "2.61.19" : "unknown";
38585
+ const v = true ? "2.61.21" : "unknown";
38334
38586
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
38335
38587
  }
38336
38588
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.61.19",
3
+ "version": "2.61.21",
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",