codeam-cli 2.76.30 → 2.76.31

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.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,21 @@ 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.76.30] — 2026-10-14
8
+
9
+ ### CI
10
+
11
+ - **release:** Build the Box image only after npm serves the version
12
+
13
+ ### Documentation
14
+
15
+ - **release:** Describe the next → canary → latest release gate in the README
16
+
17
+ ### Fixed
18
+
19
+ - **cli:** Preview prewarm skips an empty scratch project
20
+ - **cli:** Identify with the current plan from /reconnect, not the pair-time one
21
+
7
22
  ## [2.76.29] — 2026-10-13
8
23
 
9
24
  ### Fixed
package/dist/index.js CHANGED
@@ -10627,7 +10627,7 @@ function readAnonId() {
10627
10627
  }
10628
10628
  function superProperties() {
10629
10629
  return {
10630
- cliVersion: true ? "2.76.30" : "0.0.0-dev",
10630
+ cliVersion: true ? "2.76.31" : "0.0.0-dev",
10631
10631
  nodeVersion: process.version,
10632
10632
  platform: process.platform,
10633
10633
  arch: process.arch,
@@ -10876,7 +10876,7 @@ var http = __toESM(require("http"));
10876
10876
  // package.json
10877
10877
  var package_default = {
10878
10878
  name: "codeam-cli",
10879
- version: "2.76.30",
10879
+ version: "2.76.31",
10880
10880
  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.",
10881
10881
  type: "commonjs",
10882
10882
  main: "dist/index.js",
@@ -12241,7 +12241,7 @@ var CommandRelayService = class _CommandRelayService {
12241
12241
  // fresh + clear the "CLI update available" banner after a self-update
12242
12242
  // (a codespace that reinstalls @latest reconnects via heartbeat, not
12243
12243
  // pair/reconnect). Older backends ignore the extra field.
12244
- ..."2.76.30" ? { ideVersion: "2.76.30" } : {}
12244
+ ..."2.76.31" ? { ideVersion: "2.76.31" } : {}
12245
12245
  };
12246
12246
  try {
12247
12247
  const res = await _postJson(`${API_BASE2}/api/plugin/heartbeat`, body, this.pollSecretHeader());
@@ -19489,7 +19489,7 @@ var CodexRuntimeStrategy = class {
19489
19489
  async generateOneShot(prompt, opts) {
19490
19490
  const binary = this.os.findInPath("codex");
19491
19491
  if (!binary) return null;
19492
- const launch = this.os.buildLaunch(binary, ["exec", prompt]);
19492
+ const launch = this.os.buildLaunch(binary, ["exec", "--skip-git-repo-check", prompt]);
19493
19493
  const runOnce = () => {
19494
19494
  let stderr = "";
19495
19495
  return spawnAndCapture(launch.cmd, launch.args, {
@@ -27280,7 +27280,12 @@ async function startDevServer(ctx, extraEnv = {}) {
27280
27280
  emitProgress("BOOT_SEQUENCE", `${spawnable.command} ${spawnable.args.join(" ")}`);
27281
27281
  const devServer = (0, import_child_process20.spawn)(spawnable.command, spawnable.args, {
27282
27282
  cwd,
27283
- env: { ...process.env, ...spawnable.env ?? {}, ...extraEnv },
27283
+ // PYTHONUNBUFFERED: Python block-buffers stdout into a pipe, so a
27284
+ // `python3 -m http.server` (what the detector picks for a plain HTML site)
27285
+ // never shows its "Serving HTTP on … (http://0.0.0.0:8000/)" line while it
27286
+ // already serves — every such preview ended in a 120 s ready_timeout
27287
+ // (codeagent-nczt.9). First, so the project's own env can still override it.
27288
+ env: { PYTHONUNBUFFERED: "1", ...process.env, ...spawnable.env ?? {}, ...extraEnv },
27284
27289
  stdio: ["ignore", "pipe", "pipe"],
27285
27290
  // POSIX: lead a new process group so teardown can SIGTERM the whole
27286
27291
  // tree. Dev servers fork worker children that bind the port; killing
@@ -38906,6 +38911,26 @@ function boundStreamingChunkContent(content, max = STREAMING_CHUNK_SNAPSHOT_MAX_
38906
38911
  truncated: true
38907
38912
  };
38908
38913
  }
38914
+ var CHAT_TEXT_MAX_BYTES = 192 * 1024;
38915
+ var CHAT_TEXT_FALLBACK_MAX_BYTES = 32 * 1024;
38916
+ function boundChatText(content, maxBytes = CHAT_TEXT_MAX_BYTES) {
38917
+ const bytes = Buffer.from(content, "utf8");
38918
+ if (bytes.length <= maxBytes) return { content, truncated: false };
38919
+ const budget = Math.max(0, maxBytes - 256);
38920
+ const headBytes = Math.floor(budget * 0.4);
38921
+ const tailBytes = budget - headBytes;
38922
+ const head = bytes.subarray(0, headBytes).toString("utf8").replace(/\uFFFD+$/, "");
38923
+ const tail = bytes.subarray(bytes.length - tailBytes).toString("utf8").replace(/^\uFFFD+/, "");
38924
+ const omittedKb = Math.max(1, Math.round((bytes.length - headBytes - tailBytes) / 1024));
38925
+ return {
38926
+ content: `${head}
38927
+
38928
+ \u2026 [${omittedKb} KB of this reply left out \u2014 too long to show in full] \u2026
38929
+
38930
+ ${tail}`,
38931
+ truncated: true
38932
+ };
38933
+ }
38909
38934
  var AcpPublisher = class {
38910
38935
  constructor(opts) {
38911
38936
  this.opts = opts;
@@ -38924,6 +38949,10 @@ var AcpPublisher = class {
38924
38949
  * (2026-06-28 incident: a dead-token publisher spammed 401 ×34 while
38925
38950
  * the agent's replies silently never reached the phone). */
38926
38951
  pairingInvalid = false;
38952
+ /** Set when the server refused a streaming `text` frame with 413: further
38953
+ * partial frames of the turn would be refused too, so they are dropped
38954
+ * until the next `new_turn` / `clear`. The terminal frame still goes. */
38955
+ oversizeTextTurn = false;
38927
38956
  authHeaders() {
38928
38957
  return {
38929
38958
  "Content-Type": "application/json",
@@ -39005,8 +39034,29 @@ var AcpPublisher = class {
39005
39034
  */
39006
39035
  async publishOutput(body) {
39007
39036
  const url2 = `${this.apiBase}/api/commands/output`;
39008
- try {
39009
- const { statusCode, body: resBody } = await this.postWithReauth(url2, this.envelope(body));
39037
+ const isText = body.type === "text" && typeof body.content === "string";
39038
+ const isFinal = body.done === true;
39039
+ if (body.type === "new_turn" || body.type === "clear") this.oversizeTextTurn = false;
39040
+ if (isText && !isFinal && this.oversizeTextTurn) return;
39041
+ if (isText) {
39042
+ const bounded = boundChatText(body.content);
39043
+ if (bounded.truncated) body = { ...body, content: bounded.content };
39044
+ }
39045
+ try {
39046
+ let { statusCode, body: resBody } = await this.postWithReauth(url2, this.envelope(body));
39047
+ if (statusCode === 413 && isText) {
39048
+ if (!isFinal) {
39049
+ this.oversizeTextTurn = true;
39050
+ log.warn("acpPublisher", "output text frame refused 413 \u2014 dropping partial frames until the turn ends");
39051
+ return;
39052
+ }
39053
+ const fallback = boundChatText(body.content, CHAT_TEXT_FALLBACK_MAX_BYTES);
39054
+ log.warn("acpPublisher", "output done:true refused 413 \u2014 retrying once with a shortened reply");
39055
+ ({ statusCode, body: resBody } = await this.postWithReauth(
39056
+ url2,
39057
+ this.envelope({ ...body, content: fallback.content })
39058
+ ));
39059
+ }
39010
39060
  if (statusCode < 200 || statusCode >= 300) {
39011
39061
  log.warn(
39012
39062
  "acpPublisher",
@@ -42061,7 +42111,11 @@ function describeResult(raw) {
42061
42111
  return {
42062
42112
  // The agent once answered a failed spawn with "the preview is open, here
42063
42113
  // is the link" (2026-10-05). Say plainly that nothing is serving.
42064
- text: `Preview failed at ${String(r.stage)}: ${String(r.message)}. The preview is NOT running \u2014 do not give the user a preview link; tell them what failed.`,
42114
+ text: `Preview failed at ${String(r.stage)}: ${String(r.message).replace(/\.+$/, "")}. The preview is NOT running \u2014 do not give the user a preview link.` + (r.output ? ` The dev server's last output:
42115
+ \`\`\`
42116
+ ${String(r.output)}
42117
+ \`\`\`
42118
+ If it shows a mistake in the command (a wrong flag, a missing file), call start_preview again with the fixed command; otherwise tell the user what failed.` : " Tell the user what failed."),
42065
42119
  isError: true
42066
42120
  };
42067
42121
  default:
@@ -42394,6 +42448,7 @@ var MAX_AGENT_RESTARTS = 3;
42394
42448
  var AGENT_RESTART_WINDOW_MS = 10 * 6e4;
42395
42449
  var MAX_SELECTOR = 500;
42396
42450
  var MAX_LABEL = 80;
42451
+ var AGENT_OUTPUT_TAIL = 2e3;
42397
42452
  var AgentPreviewBridge = class {
42398
42453
  server = null;
42399
42454
  listening = null;
@@ -42599,9 +42654,11 @@ var AgentPreviewBridge = class {
42599
42654
  origin: "agent",
42600
42655
  onEvent: (type, payload) => {
42601
42656
  if (type === USER_EVENTS.PREVIEW_ERROR) {
42657
+ const output = String(payload.stderrTail ?? "").trim().slice(-AGENT_OUTPUT_TAIL);
42602
42658
  failure = {
42603
42659
  stage: String(payload.stage ?? "spawn"),
42604
- message: String(payload.message ?? "The preview failed to start.")
42660
+ message: String(payload.message ?? "The preview failed to start."),
42661
+ ...output ? { output } : {}
42605
42662
  };
42606
42663
  }
42607
42664
  }
@@ -51421,7 +51478,7 @@ async function autoUpgradeBeforeCriticalCommand() {
51421
51478
  if (process.env.NODE_ENV === "test") return;
51422
51479
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
51423
51480
  if (process.env.CI) return;
51424
- const current2 = true ? "2.76.30" : null;
51481
+ const current2 = true ? "2.76.31" : null;
51425
51482
  if (!current2) return;
51426
51483
  const cache = readCache();
51427
51484
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -51438,7 +51495,7 @@ function checkForUpdates() {
51438
51495
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
51439
51496
  if (process.env.CI) return;
51440
51497
  if (!process.stdout.isTTY) return;
51441
- const current2 = true ? "2.76.30" : null;
51498
+ const current2 = true ? "2.76.31" : null;
51442
51499
  if (!current2) return;
51443
51500
  const cache = readCache();
51444
51501
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -51721,7 +51778,7 @@ var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
51721
51778
  var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
51722
51779
  var SELF_UPDATE_LS_TIMEOUT_MS = 15e3;
51723
51780
  function currentCliVersion() {
51724
- return true ? "2.76.30" : null;
51781
+ return true ? "2.76.31" : null;
51725
51782
  }
51726
51783
  async function installedVersion(deps) {
51727
51784
  const ls = await deps.run(
@@ -51932,7 +51989,7 @@ function signalHostReady(send = process.send?.bind(process)) {
51932
51989
  }
51933
51990
  function defaultDeps() {
51934
51991
  return {
51935
- ownVersion: true ? "2.76.30" : null,
51992
+ ownVersion: true ? "2.76.31" : null,
51936
51993
  root: cliVersionsRoot(),
51937
51994
  args: process.argv.slice(3),
51938
51995
  execPath: process.execPath,
@@ -54470,7 +54527,7 @@ function checkChokidar() {
54470
54527
  }
54471
54528
  async function doctor(args2 = []) {
54472
54529
  const json = args2.includes("--json");
54473
- const cliVersion = true ? "2.76.30" : "0.0.0-dev";
54530
+ const cliVersion = true ? "2.76.31" : "0.0.0-dev";
54474
54531
  const apiBase2 = resolveApiBaseUrl();
54475
54532
  const diagnosticId = (0, import_node_crypto17.randomUUID)();
54476
54533
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -55006,7 +55063,7 @@ async function mcpWarm(argv = [], opts = {}) {
55006
55063
  // src/commands/version.ts
55007
55064
  var import_picocolors15 = __toESM(require("picocolors"));
55008
55065
  function version2() {
55009
- const v = true ? "2.76.30" : "unknown";
55066
+ const v = true ? "2.76.31" : "unknown";
55010
55067
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
55011
55068
  }
55012
55069
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.76.30",
3
+ "version": "2.76.31",
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",