codeam-cli 2.75.1 → 2.75.3

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 +20 -0
  2. package/dist/index.js +254 -76
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,26 @@ 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.75.2] — 2026-09-15
8
+
9
+ ### Added
10
+
11
+ - **shared:** Declare the credits_changed user event
12
+
13
+ ### CI
14
+
15
+ - **release:** Wait up to 7.5 min for npm to serve the published version (#754)
16
+
17
+ ### Fixed
18
+
19
+ - **cli:** A managed-rail outage must never be blamed on Anthropic (#757)
20
+
21
+ ## [2.75.1] — 2026-09-12
22
+
23
+ ### Fixed
24
+
25
+ - **cli:** Managed sessions announce the managed agent, not the Claude Code runtime (#753)
26
+
7
27
  ## [2.75.0] — 2026-09-12
8
28
 
9
29
  ### Added
package/dist/index.js CHANGED
@@ -271,8 +271,8 @@ var init_stdio_proxy = __esm({
271
271
  }
272
272
  async spawnChild(stdout, preResolved) {
273
273
  const spec = preResolved ?? await this.opts.spawnSpec();
274
- const spawn48 = this.opts.spawnImpl ?? import_node_child_process33.spawn;
275
- const child = spawn48(spec.command, spec.args, {
274
+ const spawn49 = this.opts.spawnImpl ?? import_node_child_process33.spawn;
275
+ const child = spawn49(spec.command, spec.args, {
276
276
  env: { ...process.env, ...spec.env },
277
277
  // env only — never argv
278
278
  stdio: ["pipe", "pipe", "inherit"]
@@ -300,7 +300,9 @@ var convex_admin_mcp_exports = {};
300
300
  __export(convex_admin_mcp_exports, {
301
301
  callConvexTool: () => callConvexTool,
302
302
  deploymentNameFromKey: () => deploymentNameFromKey,
303
- runConvexAdminMcp: () => runConvexAdminMcp
303
+ resolveConvexBin: () => resolveConvexBin,
304
+ runConvexAdminMcp: () => runConvexAdminMcp,
305
+ runConvexDeploy: () => runConvexDeploy
304
306
  });
305
307
  function deploymentNameFromKey(key) {
306
308
  const prefix = key.split("|")[0];
@@ -310,6 +312,81 @@ function deploymentNameFromKey(key) {
310
312
  }
311
313
  return null;
312
314
  }
315
+ function defaultSpawn(timeoutMs) {
316
+ return (cmd, args2, opts) => new Promise((resolve11) => {
317
+ let out2 = "";
318
+ let err = "";
319
+ let done = false;
320
+ const finish = (code) => {
321
+ if (done) return;
322
+ done = true;
323
+ resolve11({ code, stdout: out2, stderr: err });
324
+ };
325
+ let child;
326
+ try {
327
+ child = (0, import_node_child_process34.spawn)(cmd, args2, { cwd: opts.cwd, env: opts.env, stdio: ["ignore", "pipe", "pipe"] });
328
+ } catch (e) {
329
+ finish(1);
330
+ err = e instanceof Error ? e.message : String(e);
331
+ return;
332
+ }
333
+ const timer = setTimeout(() => {
334
+ try {
335
+ child.kill("SIGKILL");
336
+ } catch {
337
+ }
338
+ err += `
339
+ [codeam] convex deploy timed out after ${Math.round(timeoutMs / 1e3)}s`;
340
+ finish(124);
341
+ }, timeoutMs);
342
+ child.stdout?.on("data", (c2) => {
343
+ out2 += c2.toString();
344
+ });
345
+ child.stderr?.on("data", (c2) => {
346
+ err += c2.toString();
347
+ });
348
+ child.on("error", (e) => {
349
+ clearTimeout(timer);
350
+ err += (err ? "\n" : "") + e.message;
351
+ finish(1);
352
+ });
353
+ child.on("close", (code) => {
354
+ clearTimeout(timer);
355
+ finish(code ?? 1);
356
+ });
357
+ });
358
+ }
359
+ function resolveConvexBin(cwd) {
360
+ const local = path95.join(cwd, "node_modules", ".bin", process.platform === "win32" ? "convex.cmd" : "convex");
361
+ if (fs83.existsSync(local)) return { cmd: local, args: [] };
362
+ return { cmd: "npx", args: ["--yes", "convex"] };
363
+ }
364
+ function redact(text, key) {
365
+ if (!key) return text;
366
+ return text.split(key).join("***");
367
+ }
368
+ async function runConvexDeploy(key, args2, opts = {}) {
369
+ const cwd = args2.projectDir ?? opts.cwd ?? process.cwd();
370
+ const timeoutMs = opts.timeoutMs ?? 3e5;
371
+ const run = opts.spawnImpl ?? defaultSpawn(timeoutMs);
372
+ const bin = resolveConvexBin(cwd);
373
+ const argv = [...bin.args, "deploy"];
374
+ if (args2.previewName) argv.push("--preview-create", String(args2.previewName));
375
+ const { code, stdout, stderr } = await run(bin.cmd, argv, {
376
+ cwd,
377
+ // The ONLY place the secret travels.
378
+ env: { ...process.env, CONVEX_DEPLOY_KEY: key }
379
+ });
380
+ const body = redact([stdout, stderr].filter(Boolean).join("\n").trim(), key);
381
+ if (code === 0) {
382
+ return { ok: true, text: body || "Convex deploy completed." };
383
+ }
384
+ return {
385
+ ok: false,
386
+ text: `Convex deploy failed (exit ${code}).
387
+ ${body}`
388
+ };
389
+ }
313
390
  async function adminQuery(baseUrl, key, api, body, fetchImpl = fetch) {
314
391
  const res = await fetchImpl(`${baseUrl}/api/${api}`, {
315
392
  method: "POST",
@@ -320,7 +397,24 @@ async function adminQuery(baseUrl, key, api, body, fetchImpl = fetch) {
320
397
  const ok = res.ok && !/"status"\s*:\s*"error"/.test(text);
321
398
  return { ok, text };
322
399
  }
323
- async function callConvexTool(baseUrl, key, tool, args2, fetchImpl = fetch) {
400
+ async function callConvexTool(baseUrl, key, tool, args2, fetchImpl = fetch, deployOpts = {}) {
401
+ switch (tool) {
402
+ case "deploy":
403
+ return runConvexDeploy(
404
+ key,
405
+ {
406
+ projectDir: typeof args2.projectDir === "string" ? args2.projectDir : void 0,
407
+ previewName: typeof args2.previewName === "string" ? args2.previewName : void 0
408
+ },
409
+ deployOpts
410
+ );
411
+ }
412
+ if (!baseUrl) {
413
+ return {
414
+ ok: false,
415
+ text: `The connected Convex deploy key is a PROJECT key, which names no single deployment, so '${tool}' (and the other data tools) cannot reach one. Use the 'deploy' tool \u2014 it resolves the target from the key itself \u2014 or reconnect Convex with a dev/prod deploy key (Convex Dashboard \u2192 Project Settings \u2192 Deploy Keys) to enable the data tools.`
416
+ };
417
+ }
324
418
  switch (tool) {
325
419
  case "tables":
326
420
  return adminQuery(baseUrl, key, "query", {
@@ -362,12 +456,11 @@ async function runConvexAdminMcp(client3, id) {
362
456
  const name = deploymentNameFromKey(key);
363
457
  if (!name) {
364
458
  process.stderr.write(
365
- `[codeam mcp-run convex] could not derive a deployment from the deploy key (expected a dev/prod deploy key like dev:name|\u2026 \u2014 got prefix "${key.split(":")[0]}"). Generate a deploy key at Convex Dashboard \u2192 Project Settings \u2192 Deploy Keys.
459
+ `[codeam mcp-run convex] the deploy key names no single deployment (prefix "${key.split(":")[0]}"): the data tools are unavailable, 'deploy' still works. For the data tools, reconnect with a dev/prod deploy key (Convex Dashboard \u2192 Project Settings \u2192 Deploy Keys).
366
460
  `
367
461
  );
368
- process.exit(1);
369
462
  }
370
- const baseUrl = `https://${name}.convex.cloud`;
463
+ const baseUrl = name ? `https://${name}.convex.cloud` : "";
371
464
  const { Server } = await import("@modelcontextprotocol/sdk/server/index.js");
372
465
  const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js");
373
466
  const { ListToolsRequestSchema, CallToolRequestSchema } = await import("@modelcontextprotocol/sdk/types.js");
@@ -396,10 +489,13 @@ async function runConvexAdminMcp(client3, id) {
396
489
  });
397
490
  await server.connect(new StdioServerTransport());
398
491
  }
399
- var TOOLS;
492
+ var import_node_child_process34, fs83, path95, TOOLS;
400
493
  var init_convex_admin_mcp = __esm({
401
494
  "src/integrations/convex-admin-mcp.ts"() {
402
495
  "use strict";
496
+ import_node_child_process34 = require("child_process");
497
+ fs83 = __toESM(require("fs"));
498
+ path95 = __toESM(require("path"));
403
499
  TOOLS = [
404
500
  {
405
501
  name: "tables",
@@ -449,6 +545,24 @@ var init_convex_admin_mcp = __esm({
449
545
  required: ["functionPath"],
450
546
  additionalProperties: false
451
547
  }
548
+ },
549
+ {
550
+ name: "deploy",
551
+ description: 'Deploy this repo\'s `convex/` functions, schema and indexes to the Convex deployment this integration is connected to. Use this after editing anything under `convex/` \u2014 a function you just wrote does NOT exist for the running app until it is deployed ("Could not find public function for ..." means exactly this). Do NOT run `npx convex deploy` or `npx convex dev` in the shell: those need an interactive login, and this tool already holds the credential.',
552
+ inputSchema: {
553
+ type: "object",
554
+ properties: {
555
+ projectDir: {
556
+ type: "string",
557
+ description: "Repo root holding the `convex/` directory. Defaults to the session cwd."
558
+ },
559
+ previewName: {
560
+ type: "string",
561
+ description: "Only for a PREVIEW deploy key: name the preview deployment to create (e.g. a branch name)."
562
+ }
563
+ },
564
+ additionalProperties: false
565
+ }
452
566
  }
453
567
  ];
454
568
  }
@@ -889,12 +1003,34 @@ var AGENT_REGISTRY = {
889
1003
  displayName: "Gemini CLI",
890
1004
  binaryName: "gemini",
891
1005
  enabled: true,
892
- // OAuth via `gemini auth login` (captured by `codeam link gemini`
893
- // from ~/.gemini/oauth_creds.json) AND GEMINI_API_KEY are both
894
- // accepted by the backend's GeminiProvisioningStrategy and propagated
895
- // into codespace deploys.
896
- supportedAuthKinds: ["oauth_token", "api_key"],
897
- preferredAuthKind: "oauth_token",
1006
+ // ⚠️ API KEY ONLY since 2026-06-18, when Google stopped Gemini CLI (and the
1007
+ // Gemini Code Assist IDE extensions) serving requests for AI Pro, AI Ultra
1008
+ // and free users, in the move to Antigravity CLI. Its announcement is
1009
+ // explicit about what survives: "Gemini CLI will remain accessible via paid
1010
+ // Gemini and Gemini Enterprise Agent Platform API keys."
1011
+ //
1012
+ // So the agent stays — `@google/gemini-cli` is NOT deprecated, it still
1013
+ // ships weekly — but the OAuth door has to go: it captures a
1014
+ // `~/.gemini/oauth_creds.json` from a CONSUMER Google account, which is
1015
+ // exactly the tier that no longer serves requests. We used to PREFER that
1016
+ // path, so it was the one we recommended first; on 2026-09-15 prod held 63
1017
+ // Gemini links, 46 of them OAuth, 19 created after 2026-09-01 and the
1018
+ // newest that same day. Three months of sending people through a bricked
1019
+ // door — each one landing on `isGeminiIneligibleTier` at first use.
1020
+ //
1021
+ // ⚠️ Antigravity CLI is NOT a drop-in replacement for us: no official ACP
1022
+ // mode (google-antigravity/antigravity-cli#31 open, 192 comments, zero
1023
+ // `acp` hits in the repo as of 2026-09-15), and every third-party ACP
1024
+ // adapter warns that driving `agy` that way matches what Google's FAQ calls
1025
+ // a ToS violation — risking the USER's Google account. Our whole Gemini
1026
+ // path is ACP, so adopting it would mean shipping that risk. Revisit only
1027
+ // when #31 ships an official mode.
1028
+ //
1029
+ // Existing OAuth rows are NOT migrated: `supportedAuthMethods` gates the
1030
+ // LINK call only, so the 46 stay readable and simply keep failing at the
1031
+ // provider, where the ineligible-tier message already explains why.
1032
+ supportedAuthKinds: ["api_key"],
1033
+ preferredAuthKind: "api_key",
898
1034
  // Not listed by `headroom wrap --help` — runs native.
899
1035
  headroomWrappable: false,
900
1036
  // Native ACP server: `gemini --skip-trust --acp`.
@@ -2058,6 +2194,16 @@ var INTEGRATION_REGISTRY = {
2058
2194
  // tools ourselves via a BUILT-IN MCP (delivery.builtin) against that admin
2059
2195
  // API — see apps/cli/src/integrations/convex-admin-mcp.ts. The user still
2060
2196
  // pastes a deploy key (Dashboard → Project Settings → Deploy Keys).
2197
+ //
2198
+ // ⚠️ That built-in ALSO owns `deploy`, and it is the only way an agent can
2199
+ // push `convex/` changes. Deploying is bundle + push, not a REST call, so
2200
+ // that one tool drives Convex's own CLI with the deploy key injected into
2201
+ // THAT CHILD's env — the agent's shell never sees the credential. Before
2202
+ // it existed the agent had the credential's power through the MCP but no
2203
+ // way to deploy, so it looped on `npx convex dev` (interactive login) and
2204
+ // asked the user to paste the token into the chat; the user ended up
2205
+ // re-entering the SAME key by hand in Environment Variables, after burning
2206
+ // real credits (2026-09-15).
2061
2207
  enabled: true,
2062
2208
  auth: {
2063
2209
  kind: "api_key",
@@ -3059,7 +3205,13 @@ var USER_EVENTS = {
3059
3205
  * pipeline transition (stage start/done, pause, stall, completion). CLI
3060
3206
  * posts to /api/packs/events; mobile's pack.store renders the pipeline.
3061
3207
  * Mirrored in repo A's app-shared events.ts. */
3062
- PACK_STATE: "pack_state"
3208
+ PACK_STATE: "pack_state",
3209
+ /** The prepaid credit balance moved by something the client could not have
3210
+ * predicted — a purchase landing, a refund, a grant. Carries the new
3211
+ * balance, so nothing has to be fetched to render it. ⚠️ NOT published on
3212
+ * debits: those are one per agent hop, and the client already walks its
3213
+ * own balance down as metered usage streams in. */
3214
+ CREDITS_CHANGED: "credits_changed"
3063
3215
  };
3064
3216
 
3065
3217
  // ../../packages/shared/src/preview-prompts.ts
@@ -3250,11 +3402,11 @@ function quiet(fn) {
3250
3402
  log.debug(TAG, "ignored sync error", err);
3251
3403
  }
3252
3404
  }
3253
- function rmIfExistsQuiet(path96) {
3405
+ function rmIfExistsQuiet(path97) {
3254
3406
  try {
3255
- fs2.rmSync(path96, { force: true });
3407
+ fs2.rmSync(path97, { force: true });
3256
3408
  } catch (err) {
3257
- log.debug(TAG, `rmIfExists failed for ${path96}`, err);
3409
+ log.debug(TAG, `rmIfExists failed for ${path97}`, err);
3258
3410
  }
3259
3411
  }
3260
3412
  function killQuiet(target, signal = "SIGTERM") {
@@ -3461,8 +3613,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
3461
3613
  return decodedFile;
3462
3614
  };
3463
3615
  }
3464
- function normalizeWindowsPath(path96) {
3465
- return path96.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
3616
+ function normalizeWindowsPath(path97) {
3617
+ return path97.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
3466
3618
  }
3467
3619
 
3468
3620
  // ../../node_modules/@posthog/core/dist/error-tracking/index.mjs
@@ -6195,13 +6347,13 @@ var PostHogCoreStateless = class {
6195
6347
  sentFromRoute += batchMessages.length;
6196
6348
  }
6197
6349
  }
6198
- async _sendOtlpBatch({ path: path96, payload }) {
6350
+ async _sendOtlpBatch({ path: path97, payload }) {
6199
6351
  if (this.disabled) return {
6200
6352
  kind: "fatal",
6201
6353
  error: new Error("The client is disabled")
6202
6354
  };
6203
6355
  const serialized = JSON.stringify(payload);
6204
- const url2 = `${this.host}/i/v1/${path96}?token=${encodeURIComponent(this.apiKey)}`;
6356
+ const url2 = `${this.host}/i/v1/${path97}?token=${encodeURIComponent(this.apiKey)}`;
6205
6357
  const gzippedPayload = this.disableCompression ? null : await this.compressPayload(serialized);
6206
6358
  const fetchOptions = {
6207
6359
  method: "POST",
@@ -7441,14 +7593,14 @@ async function addSourceContext(frames, openSourceFile = import_promises.open, l
7441
7593
  LRU_FILE_CONTENTS_CACHE.reduce();
7442
7594
  return frames;
7443
7595
  }
7444
- async function openRegularSourceFile(path96, openSourceFile, logger) {
7596
+ async function openRegularSourceFile(path97, openSourceFile, logger) {
7445
7597
  let fileHandle;
7446
7598
  let isValid = false;
7447
7599
  try {
7448
- fileHandle = await openSourceFile(path96, import_node_fs.constants.O_RDONLY | import_node_fs.constants.O_NONBLOCK);
7600
+ fileHandle = await openSourceFile(path97, import_node_fs.constants.O_RDONLY | import_node_fs.constants.O_NONBLOCK);
7449
7601
  const fileStat = await fileHandle.stat();
7450
7602
  if (!fileStat.isFile()) return;
7451
- if (fileStat.size > MAX_CONTEXTLINES_FILE_SIZE) return void logger?.debug(`Skipping source context for oversized file ${path96}: ${fileStat.size} bytes exceeds ${MAX_CONTEXTLINES_FILE_SIZE}`);
7603
+ if (fileStat.size > MAX_CONTEXTLINES_FILE_SIZE) return void logger?.debug(`Skipping source context for oversized file ${path97}: ${fileStat.size} bytes exceeds ${MAX_CONTEXTLINES_FILE_SIZE}`);
7452
7604
  isValid = true;
7453
7605
  return fileHandle;
7454
7606
  } catch {
@@ -7458,8 +7610,8 @@ async function openRegularSourceFile(path96, openSourceFile, logger) {
7458
7610
  });
7459
7611
  }
7460
7612
  }
7461
- async function getContextLinesFromFile(path96, ranges, output, cacheKey, openSourceFile, logger) {
7462
- const fileHandle = await openRegularSourceFile(path96, openSourceFile, logger);
7613
+ async function getContextLinesFromFile(path97, ranges, output, cacheKey, openSourceFile, logger) {
7614
+ const fileHandle = await openRegularSourceFile(path97, openSourceFile, logger);
7463
7615
  if (void 0 === fileHandle) return void LRU_FILE_CONTENTS_FS_READ_FAILED.set(cacheKey, 1);
7464
7616
  const openedFileHandle = fileHandle;
7465
7617
  return new Promise((resolve11) => {
@@ -7561,22 +7713,22 @@ function clearLineContext(frame) {
7561
7713
  delete frame.context_line;
7562
7714
  delete frame.post_context;
7563
7715
  }
7564
- function shouldSkipContextLinesForFile(path96) {
7565
- return path96.startsWith("node:") || path96.endsWith(".min.js") || path96.endsWith(".min.cjs") || path96.endsWith(".min.mjs") || path96.startsWith("data:");
7716
+ function shouldSkipContextLinesForFile(path97) {
7717
+ return path97.startsWith("node:") || path97.endsWith(".min.js") || path97.endsWith(".min.cjs") || path97.endsWith(".min.mjs") || path97.startsWith("data:");
7566
7718
  }
7567
7719
  function shouldSkipContextLinesForFrame(frame) {
7568
7720
  if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
7569
7721
  if (void 0 !== frame.colno && frame.colno > MAX_CONTEXTLINES_COLNO) return true;
7570
7722
  return false;
7571
7723
  }
7572
- function makeSourceCacheKey(path96, basePath) {
7573
- if ((0, import_node_path.isAbsolute)(path96)) return JSON.stringify([
7724
+ function makeSourceCacheKey(path97, basePath) {
7725
+ if ((0, import_node_path.isAbsolute)(path97)) return JSON.stringify([
7574
7726
  null,
7575
- path96
7727
+ path97
7576
7728
  ]);
7577
7729
  return void 0 === basePath ? void 0 : JSON.stringify([
7578
7730
  basePath,
7579
- path96
7731
+ path97
7580
7732
  ]);
7581
7733
  }
7582
7734
  function rangeExistsInContentCache(cacheKey, range) {
@@ -10237,7 +10389,7 @@ function readAnonId() {
10237
10389
  }
10238
10390
  function superProperties() {
10239
10391
  return {
10240
- cliVersion: true ? "2.75.1" : "0.0.0-dev",
10392
+ cliVersion: true ? "2.75.3" : "0.0.0-dev",
10241
10393
  nodeVersion: process.version,
10242
10394
  platform: process.platform,
10243
10395
  arch: process.arch,
@@ -10479,7 +10631,7 @@ var http = __toESM(require("http"));
10479
10631
  // package.json
10480
10632
  var package_default = {
10481
10633
  name: "codeam-cli",
10482
- version: "2.75.1",
10634
+ version: "2.75.3",
10483
10635
  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.",
10484
10636
  type: "commonjs",
10485
10637
  main: "dist/index.js",
@@ -12170,7 +12322,7 @@ var CommandRelayService = class _CommandRelayService {
12170
12322
  // fresh + clear the "CLI update available" banner after a self-update
12171
12323
  // (a codespace that reinstalls @latest reconnects via heartbeat, not
12172
12324
  // pair/reconnect). Older backends ignore the extra field.
12173
- ..."2.75.1" ? { ideVersion: "2.75.1" } : {}
12325
+ ..."2.75.3" ? { ideVersion: "2.75.3" } : {}
12174
12326
  }).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
12175
12327
  }
12176
12328
  /**
@@ -19806,8 +19958,8 @@ function pickLine(obj) {
19806
19958
  function toHunk(raw, groupSeverity) {
19807
19959
  if (!raw || typeof raw !== "object") return null;
19808
19960
  const o = raw;
19809
- const path96 = asString(pick(o, ["file_path", "filePath", "file", "path", "filename", "fileName"])) ?? asString(pick(o, ["location"])?.path);
19810
- if (!path96) return null;
19961
+ const path97 = asString(pick(o, ["file_path", "filePath", "file", "path", "filename", "fileName"])) ?? asString(pick(o, ["location"])?.path);
19962
+ if (!path97) return null;
19811
19963
  const message = asString(
19812
19964
  pick(o, [
19813
19965
  "comment",
@@ -19824,7 +19976,7 @@ function toHunk(raw, groupSeverity) {
19824
19976
  const severity = normSeverity(pick(o, ["severity", "level", "priority", "impact"])) ?? normSeverity(groupSeverity);
19825
19977
  const locObj = pick(o, ["location"]) ?? o;
19826
19978
  return {
19827
- path: path96.trim(),
19979
+ path: path97.trim(),
19828
19980
  line: pickLine(o) ?? pickLine(locObj),
19829
19981
  severity,
19830
19982
  message: (title && message ? `${title}: ${message}` : title || message).trim() || "(no message)"
@@ -19907,10 +20059,10 @@ function parsePlain(stdout) {
19907
20059
  for (const line of stdout.split(/\r?\n/)) {
19908
20060
  const m = line.match(HUNK_LINE_RE);
19909
20061
  if (!m) continue;
19910
- const [, path96, lineNo, sevToken, message] = m;
19911
- if (!path96 || !lineNo || !message) continue;
20062
+ const [, path97, lineNo, sevToken, message] = m;
20063
+ if (!path97 || !lineNo || !message) continue;
19912
20064
  hunks.push({
19913
- path: path96.trim(),
20065
+ path: path97.trim(),
19914
20066
  line: Number(lineNo),
19915
20067
  severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
19916
20068
  message: message.trim().replace(/^[*-]\s+/, "")
@@ -20628,14 +20780,14 @@ function defaultSdkDir() {
20628
20780
  return resolveSdkDirViaRequire();
20629
20781
  }
20630
20782
  function resolveClaudeNativeBinary(deps = {}) {
20631
- const existsSync29 = deps.existsSync ?? import_fs.default.existsSync;
20783
+ const existsSync30 = deps.existsSync ?? import_fs.default.existsSync;
20632
20784
  const platformKey = deps.platformKey ?? currentPlatformKey();
20633
20785
  const sdkDir = deps.sdkDir !== void 0 ? deps.sdkDir : defaultSdkDir();
20634
20786
  if (!sdkDir) return null;
20635
20787
  const scopeDir = import_path4.default.dirname(sdkDir);
20636
20788
  const binName = platformKey.startsWith("win32-") ? "claude.exe" : "claude";
20637
20789
  const candidate = import_path4.default.join(scopeDir, `claude-agent-sdk-${platformKey}`, binName);
20638
- return existsSync29(candidate) ? candidate : null;
20790
+ return existsSync30(candidate) ? candidate : null;
20639
20791
  }
20640
20792
  var realSleep = (ms) => new Promise((resolve11) => setTimeout(resolve11, ms));
20641
20793
  async function waitForClaudeNativeBinary(opts = {}) {
@@ -20717,18 +20869,18 @@ function augmentUserLocalBinPaths(deps = {}) {
20717
20869
  env.PATH = [...additions, ...parts].join(p2.delimiter);
20718
20870
  }
20719
20871
  function resolveCursorAgentBinary(deps = {}) {
20720
- const existsSync29 = deps.existsSync ?? import_fs.default.existsSync;
20872
+ const existsSync30 = deps.existsSync ?? import_fs.default.existsSync;
20721
20873
  const platform3 = deps.platform ?? process.platform;
20722
20874
  const env = deps.env ?? process.env;
20723
20875
  if (platform3 === "win32") {
20724
20876
  const localAppData = env.LOCALAPPDATA;
20725
20877
  if (!localAppData) return null;
20726
20878
  const exe = import_path4.default.win32.join(localAppData, "cursor-agent", "cursor-agent.exe");
20727
- return existsSync29(exe) ? exe : null;
20879
+ return existsSync30(exe) ? exe : null;
20728
20880
  }
20729
20881
  const home = deps.homedir ?? import_os4.default.homedir();
20730
20882
  const unix = import_path4.default.posix.join(home, ".local", "bin", "cursor-agent");
20731
- return existsSync29(unix) ? unix : null;
20883
+ return existsSync30(unix) ? unix : null;
20732
20884
  }
20733
20885
  async function waitForCursorAgent(opts = {}) {
20734
20886
  const timeoutMs = opts.timeoutMs ?? 18e4;
@@ -24331,6 +24483,9 @@ function clearHouseProxyEnvOverrides() {
24331
24483
  function isHouseProxyEnv(env) {
24332
24484
  return typeof env.ANTHROPIC_AUTH_TOKEN === "string" && env.ANTHROPIC_AUTH_TOKEN.length > 0 && (env.ANTHROPIC_BASE_URL ?? "").includes("/api/v1/agent-proxy");
24333
24485
  }
24486
+ function currentRailWireId(env = process.env) {
24487
+ return isHouseProxyEnv(env) ? houseRailWireId(env) : null;
24488
+ }
24334
24489
  function pickHouseProxyEnv(env) {
24335
24490
  const out2 = {};
24336
24491
  for (const key of HOUSE_PROXY_ENV_KEYS) {
@@ -24501,7 +24656,7 @@ async function autoUpgradeBeforeCriticalCommand() {
24501
24656
  if (process.env.NODE_ENV === "test") return;
24502
24657
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
24503
24658
  if (process.env.CI) return;
24504
- const current2 = true ? "2.75.1" : null;
24659
+ const current2 = true ? "2.75.3" : null;
24505
24660
  if (!current2) return;
24506
24661
  const cache = readCache();
24507
24662
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -24518,7 +24673,7 @@ function checkForUpdates() {
24518
24673
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
24519
24674
  if (process.env.CI) return;
24520
24675
  if (!process.stdout.isTTY) return;
24521
- const current2 = true ? "2.75.1" : null;
24676
+ const current2 = true ? "2.75.3" : null;
24522
24677
  if (!current2) return;
24523
24678
  const cache = readCache();
24524
24679
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -24541,7 +24696,7 @@ var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
24541
24696
  var SELF_UPDATE_LS_TIMEOUT_MS = 15e3;
24542
24697
  var SUDO_PREFLIGHT_TIMEOUT_MS = 5e3;
24543
24698
  function currentCliVersion() {
24544
- return true ? "2.75.1" : null;
24699
+ return true ? "2.75.3" : null;
24545
24700
  }
24546
24701
  async function installedVersion(deps) {
24547
24702
  const ls = await deps.run(
@@ -26518,7 +26673,7 @@ async function defaultFetchJson(url2) {
26518
26673
  async function readUsageReport(deps = {}) {
26519
26674
  const port = deps.port ?? HEADROOM_PROXY_PORT;
26520
26675
  const base = `http://127.0.0.1:${port}`;
26521
- const get4 = deps.fetchJson ?? ((path96) => defaultFetchJson(`${base}${path96}`));
26676
+ const get4 = deps.fetchJson ?? ((path97) => defaultFetchJson(`${base}${path97}`));
26522
26677
  let history;
26523
26678
  try {
26524
26679
  history = await get4("/stats-history");
@@ -32292,11 +32447,11 @@ function resolveTokenValue(args2) {
32292
32447
  }
32293
32448
  const fileFlag = args2.find((a) => a.startsWith("--token-file="));
32294
32449
  if (fileFlag) {
32295
- const path96 = fileFlag.slice("--token-file=".length);
32450
+ const path97 = fileFlag.slice("--token-file=".length);
32296
32451
  try {
32297
- const content = fs66.readFileSync(path96, "utf8").trim();
32298
- if (content.length === 0) fail(`--token-file ${path96} is empty`);
32299
- rmIfExistsQuiet(path96);
32452
+ const content = fs66.readFileSync(path97, "utf8").trim();
32453
+ if (content.length === 0) fail(`--token-file ${path97} is empty`);
32454
+ rmIfExistsQuiet(path97);
32300
32455
  return content;
32301
32456
  } catch (err) {
32302
32457
  fail(`Could not read --token-file: ${err.message}`);
@@ -39229,12 +39384,12 @@ function buildRelaunchProxyEnv(baseEnv) {
39229
39384
  return env;
39230
39385
  }
39231
39386
  var relaunchProxyWithoutBudget = async () => {
39232
- const { spawn: spawn48 } = await import("child_process");
39387
+ const { spawn: spawn49 } = await import("child_process");
39233
39388
  killHeadroomProxy();
39234
39389
  await new Promise((r) => setTimeout(r, 500));
39235
39390
  const proxyEnv = buildRelaunchProxyEnv(process.env);
39236
39391
  try {
39237
- const proxy = spawn48(
39392
+ const proxy = spawn49(
39238
39393
  "headroom",
39239
39394
  ["proxy", "--port", "8787"],
39240
39395
  { stdio: "ignore", detached: true, env: proxyEnv }
@@ -40766,7 +40921,7 @@ function defaultRunGit(cwd, args2) {
40766
40921
  });
40767
40922
  }
40768
40923
  async function discoverRepos(workingDir, maxDepth = 4) {
40769
- const fs83 = await import("fs/promises");
40924
+ const fs84 = await import("fs/promises");
40770
40925
  const out2 = [];
40771
40926
  await walk(workingDir, 0);
40772
40927
  return out2;
@@ -40774,7 +40929,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
40774
40929
  if (depth > maxDepth) return;
40775
40930
  let entries = [];
40776
40931
  try {
40777
- const dirents = await fs83.readdir(dir, { withFileTypes: true });
40932
+ const dirents = await fs84.readdir(dir, { withFileTypes: true });
40778
40933
  entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
40779
40934
  } catch {
40780
40935
  return;
@@ -41303,12 +41458,19 @@ var PROVIDER_OUTAGE_RE = /overloaded_error|\boverloaded\b|service[ _]unavailable
41303
41458
  function looksLikeProviderOutage(text) {
41304
41459
  return PROVIDER_OUTAGE_RE.test(text);
41305
41460
  }
41306
- function agentStatusPage(agent) {
41461
+ function agentStatusPage(agent, railWireId) {
41462
+ if (railWireId) return null;
41307
41463
  const a = (agent ?? "").toLowerCase();
41308
41464
  const id = a.includes("claude") || a.includes("anthropic") ? "claude" : a.includes("codex") || a.includes("openai") ? "codex" : a.includes("gemini") || a.includes("google") ? "gemini" : a.includes("copilot") ? "copilot" : a.includes("cursor") ? "cursor" : null;
41309
41465
  return id ? agentHooks(id)?.statusPage ?? null : null;
41310
41466
  }
41311
- function providerOutageMessage(agent) {
41467
+ function providerOutageMessage(agent, railWireId) {
41468
+ if (railWireId) {
41469
+ const who2 = isManagedProviderId(railWireId) ? MANAGED_PROVIDER_DISPLAY_NAMES[railWireId] : HOUSE_AGENT_NAME;
41470
+ return `\u{1F310} **CodeAgent's agent service is having a disruption \u2014 this isn't your session.**
41471
+
41472
+ Your ${who2} agent couldn't finish this turn because our provider returned an overload error. It usually clears up on its own \u2014 just send your message again in a bit.`;
41473
+ }
41312
41474
  const info = agentStatusPage(agent);
41313
41475
  const who = info ? info.vendor : "The agent provider";
41314
41476
  return `\u{1F310} **${who} is having a service disruption \u2014 this isn\u2019t your session.**
@@ -41317,7 +41479,7 @@ The agent provider returned an overload/outage error, so this turn couldn\u2019t
41317
41479
 
41318
41480
  Follow the status here: [${info.url}](${info.url})` : "");
41319
41481
  }
41320
- function startupFailureMessage(agent, detail, recentStderr) {
41482
+ function startupFailureMessage(agent, detail, recentStderr, railWireId) {
41321
41483
  const haystack2 = `${detail}
41322
41484
  ${recentStderr}`;
41323
41485
  if (agentHooks(agent)?.classifyStartupFailure?.(haystack2) === "ineligible_tier") {
@@ -41332,7 +41494,7 @@ ${recentStderr}`;
41332
41494
  ].join("\n");
41333
41495
  }
41334
41496
  if (looksLikeAuthFailure(haystack2)) return AUTH_FAILURE_MESSAGE;
41335
- if (looksLikeProviderOutage(haystack2)) return providerOutageMessage(agent);
41497
+ if (looksLikeProviderOutage(haystack2)) return providerOutageMessage(agent, railWireId);
41336
41498
  const tail = recentStderr.split("\n").filter(Boolean).slice(-3).join("\n");
41337
41499
  return [`\u26A0\uFE0F The ${agent} agent failed to start.`, "", tail ? `Details:
41338
41500
  ${tail}` : detail].join(
@@ -41366,7 +41528,7 @@ ${opts.recentStderr}`;
41366
41528
  return budgetBubbleMessage(opts.agent, extractBudgetPeriod(budgetHaystack));
41367
41529
  }
41368
41530
  if (looksLikeProviderOutage(opts.detail) || looksLikeProviderOutage(opts.recentStderr)) {
41369
- return providerOutageMessage(opts.agent);
41531
+ return providerOutageMessage(opts.agent, opts.railWireId);
41370
41532
  }
41371
41533
  if (!opts.hadText) return TURN_FAILURE_MESSAGE;
41372
41534
  return null;
@@ -41376,7 +41538,7 @@ function adapterExitMessage(opts) {
41376
41538
  if (opts.code === WINDOWS_CONTROL_C_EXIT) return null;
41377
41539
  if (opts.signal === "SIGINT") return null;
41378
41540
  if (opts.authFail) return AUTH_FAILURE_MESSAGE;
41379
- if (opts.outageFail) return providerOutageMessage(opts.agent);
41541
+ if (opts.outageFail) return providerOutageMessage(opts.agent, opts.railWireId);
41380
41542
  return `Agent adapter exited unexpectedly (code=${opts.code ?? "null"} signal=${opts.signal ?? "null"}).`;
41381
41543
  }
41382
41544
 
@@ -43074,7 +43236,11 @@ ${recentStderr.join("\n")}`);
43074
43236
  detail,
43075
43237
  recentStderr: recentStderr.join("\n"),
43076
43238
  hadText,
43077
- agent: opts.agent
43239
+ agent: opts.agent,
43240
+ // On the managed/house rail the runtime is Claude Code for EVERY
43241
+ // provider, so without this the bubble names Anthropic for OUR
43242
+ // proxy's outage. See `agentStatusPage`.
43243
+ railWireId: currentRailWireId()
43078
43244
  });
43079
43245
  const failed = { error: detail };
43080
43246
  if (bubble) {
@@ -44211,7 +44377,12 @@ var AcpHistory = class {
44211
44377
  };
44212
44378
  var _startupCredentialReportGuard = { reported: false };
44213
44379
  async function surfaceStartupFailure(opts) {
44214
- const msg = startupFailureMessage(opts.agent, opts.detail, opts.recentStderr);
44380
+ const msg = startupFailureMessage(
44381
+ opts.agent,
44382
+ opts.detail,
44383
+ opts.recentStderr,
44384
+ currentRailWireId()
44385
+ );
44215
44386
  const reason = startupCredentialInvalidReason(opts.agent, opts.detail, opts.recentStderr);
44216
44387
  if (reason !== null && !_startupCredentialReportGuard.reported && opts.sessionId && opts.pluginAuthToken) {
44217
44388
  _startupCredentialReportGuard.reported = true;
@@ -44348,7 +44519,14 @@ async function runAcpSession(opts) {
44348
44519
  log.warn("acpRunner", `adapter died code=${code} signal=${signal}; shutting down session`);
44349
44520
  const authFail = looksLikeAuthFailure(recentStderr.join("\n"));
44350
44521
  const outageFail = !authFail && looksLikeProviderOutage(recentStderr.join("\n"));
44351
- const message = adapterExitMessage({ code, signal, authFail, outageFail, agent: opts.agent });
44522
+ const message = adapterExitMessage({
44523
+ code,
44524
+ signal,
44525
+ authFail,
44526
+ outageFail,
44527
+ agent: opts.agent,
44528
+ railWireId: currentRailWireId()
44529
+ });
44352
44530
  const benign = message === null;
44353
44531
  if (authFail) {
44354
44532
  void reportCredentialInvalid(opts);
@@ -49957,7 +50135,7 @@ function checkChokidar() {
49957
50135
  }
49958
50136
  async function doctor(args2 = []) {
49959
50137
  const json = args2.includes("--json");
49960
- const cliVersion = true ? "2.75.1" : "0.0.0-dev";
50138
+ const cliVersion = true ? "2.75.3" : "0.0.0-dev";
49961
50139
  const apiBase2 = resolveApiBaseUrl();
49962
50140
  const diagnosticId = (0, import_node_crypto13.randomUUID)();
49963
50141
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -50154,7 +50332,7 @@ async function completion(args2) {
50154
50332
  }
50155
50333
 
50156
50334
  // src/integrations/mcp-run.ts
50157
- var import_node_child_process34 = require("child_process");
50335
+ var import_node_child_process35 = require("child_process");
50158
50336
 
50159
50337
  // src/integrations/launcher-env.ts
50160
50338
  var LAUNCHER_ENV = Object.freeze({
@@ -50238,7 +50416,7 @@ function resolveDelivery(id) {
50238
50416
  function commandExists(command2) {
50239
50417
  try {
50240
50418
  const probe = process.platform === "win32" ? "where" : "which";
50241
- (0, import_node_child_process34.execFileSync)(probe, [command2], { stdio: "ignore" });
50419
+ (0, import_node_child_process35.execFileSync)(probe, [command2], { stdio: "ignore" });
50242
50420
  return true;
50243
50421
  } catch {
50244
50422
  return false;
@@ -50271,7 +50449,7 @@ function ensureCommand(command2) {
50271
50449
  }
50272
50450
  if (command2 === "uvx") {
50273
50451
  try {
50274
- (0, import_node_child_process34.execSync)("curl -LsSf https://astral.sh/uv/install.sh | sh", {
50452
+ (0, import_node_child_process35.execSync)("curl -LsSf https://astral.sh/uv/install.sh | sh", {
50275
50453
  stdio: ["ignore", process.stderr, process.stderr],
50276
50454
  timeout: 18e4,
50277
50455
  env: { ...process.env, UV_NO_MODIFY_PATH: "1" }
@@ -50280,7 +50458,7 @@ function ensureCommand(command2) {
50280
50458
  }
50281
50459
  if (resolveLauncherPath(command2) !== command2) return;
50282
50460
  try {
50283
- (0, import_node_child_process34.execSync)("python3 -m pip install --user --quiet uv", {
50461
+ (0, import_node_child_process35.execSync)("python3 -m pip install --user --quiet uv", {
50284
50462
  stdio: ["ignore", process.stderr, process.stderr],
50285
50463
  timeout: 18e4
50286
50464
  });
@@ -50358,7 +50536,7 @@ async function mcpRun(args2) {
50358
50536
  }
50359
50537
 
50360
50538
  // src/integrations/mcp-warm.ts
50361
- var import_node_child_process35 = require("child_process");
50539
+ var import_node_child_process36 = require("child_process");
50362
50540
  function specOf(delivery) {
50363
50541
  if (!delivery.command) return null;
50364
50542
  const spec = (delivery.args ?? []).find((a) => !a.startsWith("-"));
@@ -50402,7 +50580,7 @@ var WARM_TOTAL_BUDGET_MS = 10 * 6e4;
50402
50580
  var WARM_CONCURRENCY = 4;
50403
50581
  function runCapturing(command2, args2, timeoutMs) {
50404
50582
  return new Promise((resolve11) => {
50405
- const child = (0, import_node_child_process35.spawn)(command2, args2, {
50583
+ const child = (0, import_node_child_process36.spawn)(command2, args2, {
50406
50584
  env: { ...process.env, ...LAUNCHER_ENV },
50407
50585
  stdio: ["ignore", "ignore", "pipe"],
50408
50586
  // `npx`/`uv` are `.cmd` shims on Windows; Node ≥ 20.12 refuses to spawn a
@@ -50481,7 +50659,7 @@ async function mcpWarm(argv = [], opts = {}) {
50481
50659
  // src/commands/version.ts
50482
50660
  var import_picocolors15 = __toESM(require("picocolors"));
50483
50661
  function version2() {
50484
- const v = true ? "2.75.1" : "unknown";
50662
+ const v = true ? "2.75.3" : "unknown";
50485
50663
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
50486
50664
  }
50487
50665
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.75.1",
3
+ "version": "2.75.3",
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",