codeam-cli 2.76.29 → 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 +21 -0
- package/dist/index.js +84 -19
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,27 @@ 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
|
+
|
|
22
|
+
## [2.76.29] — 2026-10-13
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- **cli:** Run a queued message only after the running turn closes
|
|
27
|
+
|
|
7
28
|
## [2.76.28] — 2026-10-13
|
|
8
29
|
|
|
9
30
|
### Added
|
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.
|
|
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.
|
|
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",
|
|
@@ -11064,7 +11064,9 @@ async function fetchCurrentPluginAuthToken(sessionId, pluginId, pollSecret, onUs
|
|
|
11064
11064
|
const data = result?.data;
|
|
11065
11065
|
if (!data?.paired) return null;
|
|
11066
11066
|
if (onUserId && typeof data.userId === "string" && data.userId.length > 0) {
|
|
11067
|
-
|
|
11067
|
+
const user = data.user;
|
|
11068
|
+
const plan = typeof user === "object" && user !== null && "plan" in user && typeof user.plan === "string" ? user.plan : void 0;
|
|
11069
|
+
onUserId(data.userId, plan);
|
|
11068
11070
|
}
|
|
11069
11071
|
const token = data.pluginAuthToken;
|
|
11070
11072
|
return typeof token === "string" && token.length > 0 ? token : null;
|
|
@@ -12239,7 +12241,7 @@ var CommandRelayService = class _CommandRelayService {
|
|
|
12239
12241
|
// fresh + clear the "CLI update available" banner after a self-update
|
|
12240
12242
|
// (a codespace that reinstalls @latest reconnects via heartbeat, not
|
|
12241
12243
|
// pair/reconnect). Older backends ignore the extra field.
|
|
12242
|
-
..."2.76.
|
|
12244
|
+
..."2.76.31" ? { ideVersion: "2.76.31" } : {}
|
|
12243
12245
|
};
|
|
12244
12246
|
try {
|
|
12245
12247
|
const res = await _postJson(`${API_BASE2}/api/plugin/heartbeat`, body, this.pollSecretHeader());
|
|
@@ -19487,7 +19489,7 @@ var CodexRuntimeStrategy = class {
|
|
|
19487
19489
|
async generateOneShot(prompt, opts) {
|
|
19488
19490
|
const binary = this.os.findInPath("codex");
|
|
19489
19491
|
if (!binary) return null;
|
|
19490
|
-
const launch = this.os.buildLaunch(binary, ["exec", prompt]);
|
|
19492
|
+
const launch = this.os.buildLaunch(binary, ["exec", "--skip-git-repo-check", prompt]);
|
|
19491
19493
|
const runOnce = () => {
|
|
19492
19494
|
let stderr = "";
|
|
19493
19495
|
return spawnAndCapture(launch.cmd, launch.args, {
|
|
@@ -27278,7 +27280,12 @@ async function startDevServer(ctx, extraEnv = {}) {
|
|
|
27278
27280
|
emitProgress("BOOT_SEQUENCE", `${spawnable.command} ${spawnable.args.join(" ")}`);
|
|
27279
27281
|
const devServer = (0, import_child_process20.spawn)(spawnable.command, spawnable.args, {
|
|
27280
27282
|
cwd,
|
|
27281
|
-
|
|
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 },
|
|
27282
27289
|
stdio: ["ignore", "pipe", "pipe"],
|
|
27283
27290
|
// POSIX: lead a new process group so teardown can SIGTERM the whole
|
|
27284
27291
|
// tree. Dev servers fork worker children that bind the port; killing
|
|
@@ -30341,6 +30348,7 @@ function prewarmPreviewDetection(runtime) {
|
|
|
30341
30348
|
try {
|
|
30342
30349
|
const cwd = process.cwd();
|
|
30343
30350
|
if (await readPreviewConfig(cwd)) return;
|
|
30351
|
+
if (isEmptyScratchProject(cwd)) return;
|
|
30344
30352
|
const { raw } = await runDetectOneShot(generateOneShot);
|
|
30345
30353
|
const detection = safeParseDetection(raw);
|
|
30346
30354
|
if (!detection) {
|
|
@@ -38903,6 +38911,26 @@ function boundStreamingChunkContent(content, max = STREAMING_CHUNK_SNAPSHOT_MAX_
|
|
|
38903
38911
|
truncated: true
|
|
38904
38912
|
};
|
|
38905
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
|
+
}
|
|
38906
38934
|
var AcpPublisher = class {
|
|
38907
38935
|
constructor(opts) {
|
|
38908
38936
|
this.opts = opts;
|
|
@@ -38921,6 +38949,10 @@ var AcpPublisher = class {
|
|
|
38921
38949
|
* (2026-06-28 incident: a dead-token publisher spammed 401 ×34 while
|
|
38922
38950
|
* the agent's replies silently never reached the phone). */
|
|
38923
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;
|
|
38924
38956
|
authHeaders() {
|
|
38925
38957
|
return {
|
|
38926
38958
|
"Content-Type": "application/json",
|
|
@@ -39002,8 +39034,29 @@ var AcpPublisher = class {
|
|
|
39002
39034
|
*/
|
|
39003
39035
|
async publishOutput(body) {
|
|
39004
39036
|
const url2 = `${this.apiBase}/api/commands/output`;
|
|
39005
|
-
|
|
39006
|
-
|
|
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
|
+
}
|
|
39007
39060
|
if (statusCode < 200 || statusCode >= 300) {
|
|
39008
39061
|
log.warn(
|
|
39009
39062
|
"acpPublisher",
|
|
@@ -42058,7 +42111,11 @@ function describeResult(raw) {
|
|
|
42058
42111
|
return {
|
|
42059
42112
|
// The agent once answered a failed spawn with "the preview is open, here
|
|
42060
42113
|
// is the link" (2026-10-05). Say plainly that nothing is serving.
|
|
42061
|
-
text: `Preview failed at ${String(r.stage)}: ${String(r.message)}. The preview is NOT running \u2014 do not give the user a preview link
|
|
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."),
|
|
42062
42119
|
isError: true
|
|
42063
42120
|
};
|
|
42064
42121
|
default:
|
|
@@ -42391,6 +42448,7 @@ var MAX_AGENT_RESTARTS = 3;
|
|
|
42391
42448
|
var AGENT_RESTART_WINDOW_MS = 10 * 6e4;
|
|
42392
42449
|
var MAX_SELECTOR = 500;
|
|
42393
42450
|
var MAX_LABEL = 80;
|
|
42451
|
+
var AGENT_OUTPUT_TAIL = 2e3;
|
|
42394
42452
|
var AgentPreviewBridge = class {
|
|
42395
42453
|
server = null;
|
|
42396
42454
|
listening = null;
|
|
@@ -42596,9 +42654,11 @@ var AgentPreviewBridge = class {
|
|
|
42596
42654
|
origin: "agent",
|
|
42597
42655
|
onEvent: (type, payload) => {
|
|
42598
42656
|
if (type === USER_EVENTS.PREVIEW_ERROR) {
|
|
42657
|
+
const output = String(payload.stderrTail ?? "").trim().slice(-AGENT_OUTPUT_TAIL);
|
|
42599
42658
|
failure = {
|
|
42600
42659
|
stage: String(payload.stage ?? "spawn"),
|
|
42601
|
-
message: String(payload.message ?? "The preview failed to start.")
|
|
42660
|
+
message: String(payload.message ?? "The preview failed to start."),
|
|
42661
|
+
...output ? { output } : {}
|
|
42602
42662
|
};
|
|
42603
42663
|
}
|
|
42604
42664
|
}
|
|
@@ -47792,12 +47852,14 @@ async function start(requestedAgent, presetSession) {
|
|
|
47792
47852
|
`);
|
|
47793
47853
|
const cwd = process.cwd();
|
|
47794
47854
|
let reconnectUserId;
|
|
47855
|
+
let reconnectPlan;
|
|
47795
47856
|
const refreshed = await fetchCurrentPluginAuthToken(
|
|
47796
47857
|
session.id,
|
|
47797
47858
|
pluginId,
|
|
47798
47859
|
session.pollSecret,
|
|
47799
|
-
(userId) => {
|
|
47860
|
+
(userId, plan) => {
|
|
47800
47861
|
reconnectUserId = userId;
|
|
47862
|
+
reconnectPlan = plan;
|
|
47801
47863
|
}
|
|
47802
47864
|
);
|
|
47803
47865
|
if (refreshed && refreshed !== session.pluginAuthToken) {
|
|
@@ -47807,8 +47869,11 @@ async function start(requestedAgent, presetSession) {
|
|
|
47807
47869
|
} else if (refreshed) {
|
|
47808
47870
|
showInfo("Reconnected previous session.");
|
|
47809
47871
|
}
|
|
47810
|
-
|
|
47811
|
-
|
|
47872
|
+
const staleUserId = !!reconnectUserId && reconnectUserId !== session.userId;
|
|
47873
|
+
const stalePlan = !!reconnectPlan && reconnectPlan !== session.plan;
|
|
47874
|
+
if (staleUserId || stalePlan) {
|
|
47875
|
+
if (reconnectUserId) session.userId = reconnectUserId;
|
|
47876
|
+
if (reconnectPlan) session.plan = reconnectPlan;
|
|
47812
47877
|
addSession({ ...session });
|
|
47813
47878
|
}
|
|
47814
47879
|
if (session.userId) {
|
|
@@ -51413,7 +51478,7 @@ async function autoUpgradeBeforeCriticalCommand() {
|
|
|
51413
51478
|
if (process.env.NODE_ENV === "test") return;
|
|
51414
51479
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
51415
51480
|
if (process.env.CI) return;
|
|
51416
|
-
const current2 = true ? "2.76.
|
|
51481
|
+
const current2 = true ? "2.76.31" : null;
|
|
51417
51482
|
if (!current2) return;
|
|
51418
51483
|
const cache = readCache();
|
|
51419
51484
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -51430,7 +51495,7 @@ function checkForUpdates() {
|
|
|
51430
51495
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
51431
51496
|
if (process.env.CI) return;
|
|
51432
51497
|
if (!process.stdout.isTTY) return;
|
|
51433
|
-
const current2 = true ? "2.76.
|
|
51498
|
+
const current2 = true ? "2.76.31" : null;
|
|
51434
51499
|
if (!current2) return;
|
|
51435
51500
|
const cache = readCache();
|
|
51436
51501
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -51713,7 +51778,7 @@ var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
|
|
|
51713
51778
|
var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
|
|
51714
51779
|
var SELF_UPDATE_LS_TIMEOUT_MS = 15e3;
|
|
51715
51780
|
function currentCliVersion() {
|
|
51716
|
-
return true ? "2.76.
|
|
51781
|
+
return true ? "2.76.31" : null;
|
|
51717
51782
|
}
|
|
51718
51783
|
async function installedVersion(deps) {
|
|
51719
51784
|
const ls = await deps.run(
|
|
@@ -51924,7 +51989,7 @@ function signalHostReady(send = process.send?.bind(process)) {
|
|
|
51924
51989
|
}
|
|
51925
51990
|
function defaultDeps() {
|
|
51926
51991
|
return {
|
|
51927
|
-
ownVersion: true ? "2.76.
|
|
51992
|
+
ownVersion: true ? "2.76.31" : null,
|
|
51928
51993
|
root: cliVersionsRoot(),
|
|
51929
51994
|
args: process.argv.slice(3),
|
|
51930
51995
|
execPath: process.execPath,
|
|
@@ -54462,7 +54527,7 @@ function checkChokidar() {
|
|
|
54462
54527
|
}
|
|
54463
54528
|
async function doctor(args2 = []) {
|
|
54464
54529
|
const json = args2.includes("--json");
|
|
54465
|
-
const cliVersion = true ? "2.76.
|
|
54530
|
+
const cliVersion = true ? "2.76.31" : "0.0.0-dev";
|
|
54466
54531
|
const apiBase2 = resolveApiBaseUrl();
|
|
54467
54532
|
const diagnosticId = (0, import_node_crypto17.randomUUID)();
|
|
54468
54533
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -54998,7 +55063,7 @@ async function mcpWarm(argv = [], opts = {}) {
|
|
|
54998
55063
|
// src/commands/version.ts
|
|
54999
55064
|
var import_picocolors15 = __toESM(require("picocolors"));
|
|
55000
55065
|
function version2() {
|
|
55001
|
-
const v = true ? "2.76.
|
|
55066
|
+
const v = true ? "2.76.31" : "unknown";
|
|
55002
55067
|
console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
|
|
55003
55068
|
}
|
|
55004
55069
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.76.
|
|
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",
|