codeam-cli 2.75.2 → 2.75.4

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 +30 -0
  2. package/dist/index.js +232 -66
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,36 @@ 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.3] — 2026-09-16
8
+
9
+ ### Added
10
+
11
+ - **cli:** The agent can deploy, without ever seeing the deploy key (#758)
12
+
13
+ ### Fixed
14
+
15
+ - **shared:** Gemini solo acepta API key — Google retiró el nivel OAuth (#761)
16
+
17
+ ## [2.75.2] — 2026-09-15
18
+
19
+ ### Added
20
+
21
+ - **shared:** Declare the credits_changed user event
22
+
23
+ ### CI
24
+
25
+ - **release:** Wait up to 7.5 min for npm to serve the published version (#754)
26
+
27
+ ### Fixed
28
+
29
+ - **cli:** A managed-rail outage must never be blamed on Anthropic (#757)
30
+
31
+ ## [2.75.1] — 2026-09-12
32
+
33
+ ### Fixed
34
+
35
+ - **cli:** Managed sessions announce the managed agent, not the Claude Code runtime (#753)
36
+
7
37
  ## [2.75.0] — 2026-09-12
8
38
 
9
39
  ### 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",
@@ -2658,6 +2804,26 @@ var AGENT_STANDARD_TEXT = `# Working standard
2658
2804
 
2659
2805
  You are an AI coding agent working on the user's project through CodeAgent Mobile. Follow this standard on every task.
2660
2806
 
2807
+ ## How to answer \u2014 you are being read on a PHONE
2808
+
2809
+ Your reply is read on a narrow screen, often one-handed, often while the user is doing something else. Length is a cost they pay. Write accordingly.
2810
+
2811
+ - **Lead with the answer.** First line = the result, the decision, or what changed. No preamble, no restating the request, no "Great question!", no narrating what you are about to do.
2812
+ - **Default to a few sentences.** Most replies fit in 1-2 short paragraphs or 3-6 tight bullets. A long reply is a deliberate choice you make because the task genuinely needs it \u2014 not the default.
2813
+ - **Say it once.** No summary of the summary, no closing paragraph that repeats the opening, no "let me know if you need anything else".
2814
+ - **Cut every word that carries no information** \u2014 hedges, filler adverbs, throat-clearing, and praise for the question.
2815
+ - **Expand when asked.** "Explain in detail", "walk me through it", "why?" are requests for depth: give it fully. Brevity is the default, not a ceiling.
2816
+
2817
+ **Formatting for a narrow screen:**
2818
+ - Short paragraphs (1-3 sentences). Bullets over prose for anything that is a list. Never a wall of text.
2819
+ - **No wide tables** \u2014 they force horizontal scrolling and become unreadable. Use bullets, or at most two columns.
2820
+ - Code blocks only when the user needs the exact characters (a command to run, the changed lines). Show the relevant lines, not the whole file. Keep lines short so they don't wrap badly.
2821
+ - File references as \`path/to/file.ts:42\`, not pasted paths inside long prose.
2822
+ - Bold sparingly, for the one thing that matters in a block. Headings only when the reply genuinely has multiple sections.
2823
+ - No ASCII art, no banners, no decorative separators, no emoji unless the user uses them first.
2824
+
2825
+ **Compress evidence, don't drop it.** Report the outcome, not the transcript: "tests: 128/128 green", "build failed \u2014 \`TS2322\` in \`api/client.ts:80\`". Paste raw output only when the user needs to read it themselves, and only the relevant lines.
2826
+
2661
2827
  ## How to work
2662
2828
  - **Understand before acting.** Restate the goal, read the relevant code, and be clear on what "done" looks like before changing anything.
2663
2829
  - **Plan first for anything non-trivial** (3+ steps or a design decision): outline the approach and the files you'll touch, and share it before implementing. Skip the ceremony for small, obvious fixes.
@@ -3256,11 +3422,11 @@ function quiet(fn) {
3256
3422
  log.debug(TAG, "ignored sync error", err);
3257
3423
  }
3258
3424
  }
3259
- function rmIfExistsQuiet(path96) {
3425
+ function rmIfExistsQuiet(path97) {
3260
3426
  try {
3261
- fs2.rmSync(path96, { force: true });
3427
+ fs2.rmSync(path97, { force: true });
3262
3428
  } catch (err) {
3263
- log.debug(TAG, `rmIfExists failed for ${path96}`, err);
3429
+ log.debug(TAG, `rmIfExists failed for ${path97}`, err);
3264
3430
  }
3265
3431
  }
3266
3432
  function killQuiet(target, signal = "SIGTERM") {
@@ -3467,8 +3633,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
3467
3633
  return decodedFile;
3468
3634
  };
3469
3635
  }
3470
- function normalizeWindowsPath(path96) {
3471
- return path96.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
3636
+ function normalizeWindowsPath(path97) {
3637
+ return path97.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
3472
3638
  }
3473
3639
 
3474
3640
  // ../../node_modules/@posthog/core/dist/error-tracking/index.mjs
@@ -6201,13 +6367,13 @@ var PostHogCoreStateless = class {
6201
6367
  sentFromRoute += batchMessages.length;
6202
6368
  }
6203
6369
  }
6204
- async _sendOtlpBatch({ path: path96, payload }) {
6370
+ async _sendOtlpBatch({ path: path97, payload }) {
6205
6371
  if (this.disabled) return {
6206
6372
  kind: "fatal",
6207
6373
  error: new Error("The client is disabled")
6208
6374
  };
6209
6375
  const serialized = JSON.stringify(payload);
6210
- const url2 = `${this.host}/i/v1/${path96}?token=${encodeURIComponent(this.apiKey)}`;
6376
+ const url2 = `${this.host}/i/v1/${path97}?token=${encodeURIComponent(this.apiKey)}`;
6211
6377
  const gzippedPayload = this.disableCompression ? null : await this.compressPayload(serialized);
6212
6378
  const fetchOptions = {
6213
6379
  method: "POST",
@@ -7447,14 +7613,14 @@ async function addSourceContext(frames, openSourceFile = import_promises.open, l
7447
7613
  LRU_FILE_CONTENTS_CACHE.reduce();
7448
7614
  return frames;
7449
7615
  }
7450
- async function openRegularSourceFile(path96, openSourceFile, logger) {
7616
+ async function openRegularSourceFile(path97, openSourceFile, logger) {
7451
7617
  let fileHandle;
7452
7618
  let isValid = false;
7453
7619
  try {
7454
- fileHandle = await openSourceFile(path96, import_node_fs.constants.O_RDONLY | import_node_fs.constants.O_NONBLOCK);
7620
+ fileHandle = await openSourceFile(path97, import_node_fs.constants.O_RDONLY | import_node_fs.constants.O_NONBLOCK);
7455
7621
  const fileStat = await fileHandle.stat();
7456
7622
  if (!fileStat.isFile()) return;
7457
- 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}`);
7623
+ 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}`);
7458
7624
  isValid = true;
7459
7625
  return fileHandle;
7460
7626
  } catch {
@@ -7464,8 +7630,8 @@ async function openRegularSourceFile(path96, openSourceFile, logger) {
7464
7630
  });
7465
7631
  }
7466
7632
  }
7467
- async function getContextLinesFromFile(path96, ranges, output, cacheKey, openSourceFile, logger) {
7468
- const fileHandle = await openRegularSourceFile(path96, openSourceFile, logger);
7633
+ async function getContextLinesFromFile(path97, ranges, output, cacheKey, openSourceFile, logger) {
7634
+ const fileHandle = await openRegularSourceFile(path97, openSourceFile, logger);
7469
7635
  if (void 0 === fileHandle) return void LRU_FILE_CONTENTS_FS_READ_FAILED.set(cacheKey, 1);
7470
7636
  const openedFileHandle = fileHandle;
7471
7637
  return new Promise((resolve11) => {
@@ -7567,22 +7733,22 @@ function clearLineContext(frame) {
7567
7733
  delete frame.context_line;
7568
7734
  delete frame.post_context;
7569
7735
  }
7570
- function shouldSkipContextLinesForFile(path96) {
7571
- return path96.startsWith("node:") || path96.endsWith(".min.js") || path96.endsWith(".min.cjs") || path96.endsWith(".min.mjs") || path96.startsWith("data:");
7736
+ function shouldSkipContextLinesForFile(path97) {
7737
+ return path97.startsWith("node:") || path97.endsWith(".min.js") || path97.endsWith(".min.cjs") || path97.endsWith(".min.mjs") || path97.startsWith("data:");
7572
7738
  }
7573
7739
  function shouldSkipContextLinesForFrame(frame) {
7574
7740
  if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
7575
7741
  if (void 0 !== frame.colno && frame.colno > MAX_CONTEXTLINES_COLNO) return true;
7576
7742
  return false;
7577
7743
  }
7578
- function makeSourceCacheKey(path96, basePath) {
7579
- if ((0, import_node_path.isAbsolute)(path96)) return JSON.stringify([
7744
+ function makeSourceCacheKey(path97, basePath) {
7745
+ if ((0, import_node_path.isAbsolute)(path97)) return JSON.stringify([
7580
7746
  null,
7581
- path96
7747
+ path97
7582
7748
  ]);
7583
7749
  return void 0 === basePath ? void 0 : JSON.stringify([
7584
7750
  basePath,
7585
- path96
7751
+ path97
7586
7752
  ]);
7587
7753
  }
7588
7754
  function rangeExistsInContentCache(cacheKey, range) {
@@ -10243,7 +10409,7 @@ function readAnonId() {
10243
10409
  }
10244
10410
  function superProperties() {
10245
10411
  return {
10246
- cliVersion: true ? "2.75.2" : "0.0.0-dev",
10412
+ cliVersion: true ? "2.75.4" : "0.0.0-dev",
10247
10413
  nodeVersion: process.version,
10248
10414
  platform: process.platform,
10249
10415
  arch: process.arch,
@@ -10485,7 +10651,7 @@ var http = __toESM(require("http"));
10485
10651
  // package.json
10486
10652
  var package_default = {
10487
10653
  name: "codeam-cli",
10488
- version: "2.75.2",
10654
+ version: "2.75.4",
10489
10655
  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.",
10490
10656
  type: "commonjs",
10491
10657
  main: "dist/index.js",
@@ -12176,7 +12342,7 @@ var CommandRelayService = class _CommandRelayService {
12176
12342
  // fresh + clear the "CLI update available" banner after a self-update
12177
12343
  // (a codespace that reinstalls @latest reconnects via heartbeat, not
12178
12344
  // pair/reconnect). Older backends ignore the extra field.
12179
- ..."2.75.2" ? { ideVersion: "2.75.2" } : {}
12345
+ ..."2.75.4" ? { ideVersion: "2.75.4" } : {}
12180
12346
  }).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
12181
12347
  }
12182
12348
  /**
@@ -19812,8 +19978,8 @@ function pickLine(obj) {
19812
19978
  function toHunk(raw, groupSeverity) {
19813
19979
  if (!raw || typeof raw !== "object") return null;
19814
19980
  const o = raw;
19815
- const path96 = asString(pick(o, ["file_path", "filePath", "file", "path", "filename", "fileName"])) ?? asString(pick(o, ["location"])?.path);
19816
- if (!path96) return null;
19981
+ const path97 = asString(pick(o, ["file_path", "filePath", "file", "path", "filename", "fileName"])) ?? asString(pick(o, ["location"])?.path);
19982
+ if (!path97) return null;
19817
19983
  const message = asString(
19818
19984
  pick(o, [
19819
19985
  "comment",
@@ -19830,7 +19996,7 @@ function toHunk(raw, groupSeverity) {
19830
19996
  const severity = normSeverity(pick(o, ["severity", "level", "priority", "impact"])) ?? normSeverity(groupSeverity);
19831
19997
  const locObj = pick(o, ["location"]) ?? o;
19832
19998
  return {
19833
- path: path96.trim(),
19999
+ path: path97.trim(),
19834
20000
  line: pickLine(o) ?? pickLine(locObj),
19835
20001
  severity,
19836
20002
  message: (title && message ? `${title}: ${message}` : title || message).trim() || "(no message)"
@@ -19913,10 +20079,10 @@ function parsePlain(stdout) {
19913
20079
  for (const line of stdout.split(/\r?\n/)) {
19914
20080
  const m = line.match(HUNK_LINE_RE);
19915
20081
  if (!m) continue;
19916
- const [, path96, lineNo, sevToken, message] = m;
19917
- if (!path96 || !lineNo || !message) continue;
20082
+ const [, path97, lineNo, sevToken, message] = m;
20083
+ if (!path97 || !lineNo || !message) continue;
19918
20084
  hunks.push({
19919
- path: path96.trim(),
20085
+ path: path97.trim(),
19920
20086
  line: Number(lineNo),
19921
20087
  severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
19922
20088
  message: message.trim().replace(/^[*-]\s+/, "")
@@ -20634,14 +20800,14 @@ function defaultSdkDir() {
20634
20800
  return resolveSdkDirViaRequire();
20635
20801
  }
20636
20802
  function resolveClaudeNativeBinary(deps = {}) {
20637
- const existsSync29 = deps.existsSync ?? import_fs.default.existsSync;
20803
+ const existsSync30 = deps.existsSync ?? import_fs.default.existsSync;
20638
20804
  const platformKey = deps.platformKey ?? currentPlatformKey();
20639
20805
  const sdkDir = deps.sdkDir !== void 0 ? deps.sdkDir : defaultSdkDir();
20640
20806
  if (!sdkDir) return null;
20641
20807
  const scopeDir = import_path4.default.dirname(sdkDir);
20642
20808
  const binName = platformKey.startsWith("win32-") ? "claude.exe" : "claude";
20643
20809
  const candidate = import_path4.default.join(scopeDir, `claude-agent-sdk-${platformKey}`, binName);
20644
- return existsSync29(candidate) ? candidate : null;
20810
+ return existsSync30(candidate) ? candidate : null;
20645
20811
  }
20646
20812
  var realSleep = (ms) => new Promise((resolve11) => setTimeout(resolve11, ms));
20647
20813
  async function waitForClaudeNativeBinary(opts = {}) {
@@ -20723,18 +20889,18 @@ function augmentUserLocalBinPaths(deps = {}) {
20723
20889
  env.PATH = [...additions, ...parts].join(p2.delimiter);
20724
20890
  }
20725
20891
  function resolveCursorAgentBinary(deps = {}) {
20726
- const existsSync29 = deps.existsSync ?? import_fs.default.existsSync;
20892
+ const existsSync30 = deps.existsSync ?? import_fs.default.existsSync;
20727
20893
  const platform3 = deps.platform ?? process.platform;
20728
20894
  const env = deps.env ?? process.env;
20729
20895
  if (platform3 === "win32") {
20730
20896
  const localAppData = env.LOCALAPPDATA;
20731
20897
  if (!localAppData) return null;
20732
20898
  const exe = import_path4.default.win32.join(localAppData, "cursor-agent", "cursor-agent.exe");
20733
- return existsSync29(exe) ? exe : null;
20899
+ return existsSync30(exe) ? exe : null;
20734
20900
  }
20735
20901
  const home = deps.homedir ?? import_os4.default.homedir();
20736
20902
  const unix = import_path4.default.posix.join(home, ".local", "bin", "cursor-agent");
20737
- return existsSync29(unix) ? unix : null;
20903
+ return existsSync30(unix) ? unix : null;
20738
20904
  }
20739
20905
  async function waitForCursorAgent(opts = {}) {
20740
20906
  const timeoutMs = opts.timeoutMs ?? 18e4;
@@ -24510,7 +24676,7 @@ async function autoUpgradeBeforeCriticalCommand() {
24510
24676
  if (process.env.NODE_ENV === "test") return;
24511
24677
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
24512
24678
  if (process.env.CI) return;
24513
- const current2 = true ? "2.75.2" : null;
24679
+ const current2 = true ? "2.75.4" : null;
24514
24680
  if (!current2) return;
24515
24681
  const cache = readCache();
24516
24682
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -24527,7 +24693,7 @@ function checkForUpdates() {
24527
24693
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
24528
24694
  if (process.env.CI) return;
24529
24695
  if (!process.stdout.isTTY) return;
24530
- const current2 = true ? "2.75.2" : null;
24696
+ const current2 = true ? "2.75.4" : null;
24531
24697
  if (!current2) return;
24532
24698
  const cache = readCache();
24533
24699
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -24550,7 +24716,7 @@ var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
24550
24716
  var SELF_UPDATE_LS_TIMEOUT_MS = 15e3;
24551
24717
  var SUDO_PREFLIGHT_TIMEOUT_MS = 5e3;
24552
24718
  function currentCliVersion() {
24553
- return true ? "2.75.2" : null;
24719
+ return true ? "2.75.4" : null;
24554
24720
  }
24555
24721
  async function installedVersion(deps) {
24556
24722
  const ls = await deps.run(
@@ -26527,7 +26693,7 @@ async function defaultFetchJson(url2) {
26527
26693
  async function readUsageReport(deps = {}) {
26528
26694
  const port = deps.port ?? HEADROOM_PROXY_PORT;
26529
26695
  const base = `http://127.0.0.1:${port}`;
26530
- const get4 = deps.fetchJson ?? ((path96) => defaultFetchJson(`${base}${path96}`));
26696
+ const get4 = deps.fetchJson ?? ((path97) => defaultFetchJson(`${base}${path97}`));
26531
26697
  let history;
26532
26698
  try {
26533
26699
  history = await get4("/stats-history");
@@ -32301,11 +32467,11 @@ function resolveTokenValue(args2) {
32301
32467
  }
32302
32468
  const fileFlag = args2.find((a) => a.startsWith("--token-file="));
32303
32469
  if (fileFlag) {
32304
- const path96 = fileFlag.slice("--token-file=".length);
32470
+ const path97 = fileFlag.slice("--token-file=".length);
32305
32471
  try {
32306
- const content = fs66.readFileSync(path96, "utf8").trim();
32307
- if (content.length === 0) fail(`--token-file ${path96} is empty`);
32308
- rmIfExistsQuiet(path96);
32472
+ const content = fs66.readFileSync(path97, "utf8").trim();
32473
+ if (content.length === 0) fail(`--token-file ${path97} is empty`);
32474
+ rmIfExistsQuiet(path97);
32309
32475
  return content;
32310
32476
  } catch (err) {
32311
32477
  fail(`Could not read --token-file: ${err.message}`);
@@ -39238,12 +39404,12 @@ function buildRelaunchProxyEnv(baseEnv) {
39238
39404
  return env;
39239
39405
  }
39240
39406
  var relaunchProxyWithoutBudget = async () => {
39241
- const { spawn: spawn48 } = await import("child_process");
39407
+ const { spawn: spawn49 } = await import("child_process");
39242
39408
  killHeadroomProxy();
39243
39409
  await new Promise((r) => setTimeout(r, 500));
39244
39410
  const proxyEnv = buildRelaunchProxyEnv(process.env);
39245
39411
  try {
39246
- const proxy = spawn48(
39412
+ const proxy = spawn49(
39247
39413
  "headroom",
39248
39414
  ["proxy", "--port", "8787"],
39249
39415
  { stdio: "ignore", detached: true, env: proxyEnv }
@@ -40775,7 +40941,7 @@ function defaultRunGit(cwd, args2) {
40775
40941
  });
40776
40942
  }
40777
40943
  async function discoverRepos(workingDir, maxDepth = 4) {
40778
- const fs83 = await import("fs/promises");
40944
+ const fs84 = await import("fs/promises");
40779
40945
  const out2 = [];
40780
40946
  await walk(workingDir, 0);
40781
40947
  return out2;
@@ -40783,7 +40949,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
40783
40949
  if (depth > maxDepth) return;
40784
40950
  let entries = [];
40785
40951
  try {
40786
- const dirents = await fs83.readdir(dir, { withFileTypes: true });
40952
+ const dirents = await fs84.readdir(dir, { withFileTypes: true });
40787
40953
  entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
40788
40954
  } catch {
40789
40955
  return;
@@ -49989,7 +50155,7 @@ function checkChokidar() {
49989
50155
  }
49990
50156
  async function doctor(args2 = []) {
49991
50157
  const json = args2.includes("--json");
49992
- const cliVersion = true ? "2.75.2" : "0.0.0-dev";
50158
+ const cliVersion = true ? "2.75.4" : "0.0.0-dev";
49993
50159
  const apiBase2 = resolveApiBaseUrl();
49994
50160
  const diagnosticId = (0, import_node_crypto13.randomUUID)();
49995
50161
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -50186,7 +50352,7 @@ async function completion(args2) {
50186
50352
  }
50187
50353
 
50188
50354
  // src/integrations/mcp-run.ts
50189
- var import_node_child_process34 = require("child_process");
50355
+ var import_node_child_process35 = require("child_process");
50190
50356
 
50191
50357
  // src/integrations/launcher-env.ts
50192
50358
  var LAUNCHER_ENV = Object.freeze({
@@ -50270,7 +50436,7 @@ function resolveDelivery(id) {
50270
50436
  function commandExists(command2) {
50271
50437
  try {
50272
50438
  const probe = process.platform === "win32" ? "where" : "which";
50273
- (0, import_node_child_process34.execFileSync)(probe, [command2], { stdio: "ignore" });
50439
+ (0, import_node_child_process35.execFileSync)(probe, [command2], { stdio: "ignore" });
50274
50440
  return true;
50275
50441
  } catch {
50276
50442
  return false;
@@ -50303,7 +50469,7 @@ function ensureCommand(command2) {
50303
50469
  }
50304
50470
  if (command2 === "uvx") {
50305
50471
  try {
50306
- (0, import_node_child_process34.execSync)("curl -LsSf https://astral.sh/uv/install.sh | sh", {
50472
+ (0, import_node_child_process35.execSync)("curl -LsSf https://astral.sh/uv/install.sh | sh", {
50307
50473
  stdio: ["ignore", process.stderr, process.stderr],
50308
50474
  timeout: 18e4,
50309
50475
  env: { ...process.env, UV_NO_MODIFY_PATH: "1" }
@@ -50312,7 +50478,7 @@ function ensureCommand(command2) {
50312
50478
  }
50313
50479
  if (resolveLauncherPath(command2) !== command2) return;
50314
50480
  try {
50315
- (0, import_node_child_process34.execSync)("python3 -m pip install --user --quiet uv", {
50481
+ (0, import_node_child_process35.execSync)("python3 -m pip install --user --quiet uv", {
50316
50482
  stdio: ["ignore", process.stderr, process.stderr],
50317
50483
  timeout: 18e4
50318
50484
  });
@@ -50390,7 +50556,7 @@ async function mcpRun(args2) {
50390
50556
  }
50391
50557
 
50392
50558
  // src/integrations/mcp-warm.ts
50393
- var import_node_child_process35 = require("child_process");
50559
+ var import_node_child_process36 = require("child_process");
50394
50560
  function specOf(delivery) {
50395
50561
  if (!delivery.command) return null;
50396
50562
  const spec = (delivery.args ?? []).find((a) => !a.startsWith("-"));
@@ -50434,7 +50600,7 @@ var WARM_TOTAL_BUDGET_MS = 10 * 6e4;
50434
50600
  var WARM_CONCURRENCY = 4;
50435
50601
  function runCapturing(command2, args2, timeoutMs) {
50436
50602
  return new Promise((resolve11) => {
50437
- const child = (0, import_node_child_process35.spawn)(command2, args2, {
50603
+ const child = (0, import_node_child_process36.spawn)(command2, args2, {
50438
50604
  env: { ...process.env, ...LAUNCHER_ENV },
50439
50605
  stdio: ["ignore", "ignore", "pipe"],
50440
50606
  // `npx`/`uv` are `.cmd` shims on Windows; Node ≥ 20.12 refuses to spawn a
@@ -50513,7 +50679,7 @@ async function mcpWarm(argv = [], opts = {}) {
50513
50679
  // src/commands/version.ts
50514
50680
  var import_picocolors15 = __toESM(require("picocolors"));
50515
50681
  function version2() {
50516
- const v = true ? "2.75.2" : "unknown";
50682
+ const v = true ? "2.75.4" : "unknown";
50517
50683
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
50518
50684
  }
50519
50685
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.75.2",
3
+ "version": "2.75.4",
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",