codeam-cli 2.65.4 → 2.65.6
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 +7 -0
- package/dist/index.js +107 -53
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,13 @@ 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.65.4] — 2026-08-14
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **cli:** Handoff protocol tolerates display-name targets + inline degenerate fences
|
|
12
|
+
- **cli:** Degenerate handoff form must be reply-trailing (kills fabricated-proposal false positive)
|
|
13
|
+
|
|
7
14
|
## [2.65.3] — 2026-08-14
|
|
8
15
|
|
|
9
16
|
### Fixed
|
package/dist/index.js
CHANGED
|
@@ -8079,7 +8079,7 @@ function readAnonId() {
|
|
|
8079
8079
|
}
|
|
8080
8080
|
function superProperties() {
|
|
8081
8081
|
return {
|
|
8082
|
-
cliVersion: true ? "2.65.
|
|
8082
|
+
cliVersion: true ? "2.65.6" : "0.0.0-dev",
|
|
8083
8083
|
nodeVersion: process.version,
|
|
8084
8084
|
platform: process.platform,
|
|
8085
8085
|
arch: process.arch,
|
|
@@ -8260,7 +8260,7 @@ var os4 = __toESM(require("os"));
|
|
|
8260
8260
|
// package.json
|
|
8261
8261
|
var package_default = {
|
|
8262
8262
|
name: "codeam-cli",
|
|
8263
|
-
version: "2.65.
|
|
8263
|
+
version: "2.65.6",
|
|
8264
8264
|
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.",
|
|
8265
8265
|
type: "commonjs",
|
|
8266
8266
|
main: "dist/index.js",
|
|
@@ -9712,7 +9712,7 @@ var CommandRelayService = class _CommandRelayService {
|
|
|
9712
9712
|
// fresh + clear the "CLI update available" banner after a self-update
|
|
9713
9713
|
// (a codespace that reinstalls @latest reconnects via heartbeat, not
|
|
9714
9714
|
// pair/reconnect). Older backends ignore the extra field.
|
|
9715
|
-
..."2.65.
|
|
9715
|
+
..."2.65.6" ? { ideVersion: "2.65.6" } : {}
|
|
9716
9716
|
}).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
|
|
9717
9717
|
}
|
|
9718
9718
|
/**
|
|
@@ -21641,7 +21641,7 @@ async function autoUpgradeBeforeCriticalCommand() {
|
|
|
21641
21641
|
if (process.env.NODE_ENV === "test") return;
|
|
21642
21642
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
21643
21643
|
if (process.env.CI) return;
|
|
21644
|
-
const current2 = true ? "2.65.
|
|
21644
|
+
const current2 = true ? "2.65.6" : null;
|
|
21645
21645
|
if (!current2) return;
|
|
21646
21646
|
const cache = readCache();
|
|
21647
21647
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -21658,7 +21658,7 @@ function checkForUpdates() {
|
|
|
21658
21658
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
21659
21659
|
if (process.env.CI) return;
|
|
21660
21660
|
if (!process.stdout.isTTY) return;
|
|
21661
|
-
const current2 = true ? "2.65.
|
|
21661
|
+
const current2 = true ? "2.65.6" : null;
|
|
21662
21662
|
if (!current2) return;
|
|
21663
21663
|
const cache = readCache();
|
|
21664
21664
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -21678,7 +21678,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
|
21678
21678
|
var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
|
|
21679
21679
|
var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
|
|
21680
21680
|
function currentCliVersion() {
|
|
21681
|
-
return true ? "2.65.
|
|
21681
|
+
return true ? "2.65.6" : null;
|
|
21682
21682
|
}
|
|
21683
21683
|
function runCmd(cmd, args2, timeoutMs) {
|
|
21684
21684
|
return new Promise((resolve9) => {
|
|
@@ -33971,10 +33971,7 @@ var AcpClient = class {
|
|
|
33971
33971
|
const input = import_node_stream.Readable.toWeb(child.stdout);
|
|
33972
33972
|
const output = import_node_stream.Writable.toWeb(child.stdin);
|
|
33973
33973
|
const stream = ndJsonStream(output, input);
|
|
33974
|
-
this.connection = new ClientSideConnection(
|
|
33975
|
-
(_agent) => this.buildClient(),
|
|
33976
|
-
stream
|
|
33977
|
-
);
|
|
33974
|
+
this.connection = new ClientSideConnection((_agent) => this.buildClient(), stream);
|
|
33978
33975
|
const startAborted = new Promise((_2, reject) => {
|
|
33979
33976
|
this.startAbortReject = reject;
|
|
33980
33977
|
});
|
|
@@ -34105,14 +34102,8 @@ var AcpClient = class {
|
|
|
34105
34102
|
if (!this.connection || !this.sessionId) {
|
|
34106
34103
|
throw new Error("AcpClient.sendPromptOnce called before start()");
|
|
34107
34104
|
}
|
|
34108
|
-
const textLen = blocks.reduce(
|
|
34109
|
-
|
|
34110
|
-
0
|
|
34111
|
-
);
|
|
34112
|
-
const imageCount = blocks.reduce(
|
|
34113
|
-
(n, b) => b.type === "image" ? n + 1 : n,
|
|
34114
|
-
0
|
|
34115
|
-
);
|
|
34105
|
+
const textLen = blocks.reduce((n, b) => b.type === "text" ? n + b.text.length : n, 0);
|
|
34106
|
+
const imageCount = blocks.reduce((n, b) => b.type === "image" ? n + 1 : n, 0);
|
|
34116
34107
|
log.info(
|
|
34117
34108
|
"acpClient",
|
|
34118
34109
|
`prompt \u2192 session=${this.sessionId.slice(0, 8)} textChars=${textLen} imageBlocks=${imageCount}`
|
|
@@ -34133,6 +34124,7 @@ var AcpClient = class {
|
|
|
34133
34124
|
this.pendingToolCalls.clear();
|
|
34134
34125
|
try {
|
|
34135
34126
|
const result = await Promise.race([send, idle.promise]);
|
|
34127
|
+
await new Promise((resolve9) => setImmediate(resolve9));
|
|
34136
34128
|
log.info(
|
|
34137
34129
|
"acpClient",
|
|
34138
34130
|
`prompt \u2190 ok stopReason=${result.stopReason ?? "?"} elapsedMs=${Date.now() - t0}`
|
|
@@ -34413,9 +34405,7 @@ var AcpClient = class {
|
|
|
34413
34405
|
* hardcoded list, no guessed model.
|
|
34414
34406
|
*/
|
|
34415
34407
|
captureModelConfig(configOptions) {
|
|
34416
|
-
const modelOption = configOptions.find(
|
|
34417
|
-
(o) => o.category === "model" && o.type === "select"
|
|
34418
|
-
);
|
|
34408
|
+
const modelOption = configOptions.find((o) => o.category === "model" && o.type === "select");
|
|
34419
34409
|
if (!modelOption || modelOption.type !== "select") {
|
|
34420
34410
|
this.modelConfigId = void 0;
|
|
34421
34411
|
this.availableModels = [];
|
|
@@ -34447,9 +34437,7 @@ var AcpClient = class {
|
|
|
34447
34437
|
throw new Error("AcpClient.setMode called before start()");
|
|
34448
34438
|
}
|
|
34449
34439
|
if (this.availableModes.length === 0) {
|
|
34450
|
-
throw new Error(
|
|
34451
|
-
"mode selection not available: this agent advertises no ACP session modes"
|
|
34452
|
-
);
|
|
34440
|
+
throw new Error("mode selection not available: this agent advertises no ACP session modes");
|
|
34453
34441
|
}
|
|
34454
34442
|
log.info("acpClient", `setMode \u2192 ${modeId}`);
|
|
34455
34443
|
await this.connection.setSessionMode({
|
|
@@ -34594,11 +34582,9 @@ var AcpClient = class {
|
|
|
34594
34582
|
const code = err.code;
|
|
34595
34583
|
if (code === "ENOENT") throw RequestError.resourceNotFound(params.path);
|
|
34596
34584
|
if (code === "EACCES" || code === "EPERM") {
|
|
34597
|
-
throw new RequestError(
|
|
34598
|
-
|
|
34599
|
-
|
|
34600
|
-
{ uri: params.path }
|
|
34601
|
-
);
|
|
34585
|
+
throw new RequestError(-32002, `Permission denied: ${params.path}`, {
|
|
34586
|
+
uri: params.path
|
|
34587
|
+
});
|
|
34602
34588
|
}
|
|
34603
34589
|
if (code === "EISDIR") {
|
|
34604
34590
|
throw RequestError.invalidParams(`path is a directory: ${params.path}`);
|
|
@@ -34616,16 +34602,12 @@ var AcpClient = class {
|
|
|
34616
34602
|
} catch (err) {
|
|
34617
34603
|
const code = err.code;
|
|
34618
34604
|
if (code === "EACCES" || code === "EPERM") {
|
|
34619
|
-
throw new RequestError(
|
|
34620
|
-
|
|
34621
|
-
|
|
34622
|
-
{ uri: params.path }
|
|
34623
|
-
);
|
|
34605
|
+
throw new RequestError(-32002, `Permission denied: ${params.path}`, {
|
|
34606
|
+
uri: params.path
|
|
34607
|
+
});
|
|
34624
34608
|
}
|
|
34625
34609
|
if (code === "ENOENT") {
|
|
34626
|
-
throw RequestError.invalidParams(
|
|
34627
|
-
`Parent directory does not exist for: ${params.path}`
|
|
34628
|
-
);
|
|
34610
|
+
throw RequestError.invalidParams(`Parent directory does not exist for: ${params.path}`);
|
|
34629
34611
|
}
|
|
34630
34612
|
throw RequestError.internalError({ uri: params.path }, code ?? String(err));
|
|
34631
34613
|
}
|
|
@@ -34704,9 +34686,7 @@ function knownAgentBinaryDirs() {
|
|
|
34704
34686
|
});
|
|
34705
34687
|
}
|
|
34706
34688
|
function expandPathForAgentBinaries(existingPath) {
|
|
34707
|
-
const existing = new Set(
|
|
34708
|
-
existingPath.split(path74.delimiter).filter((p2) => p2.length > 0)
|
|
34709
|
-
);
|
|
34689
|
+
const existing = new Set(existingPath.split(path74.delimiter).filter((p2) => p2.length > 0));
|
|
34710
34690
|
const additions = [];
|
|
34711
34691
|
for (const dir of knownAgentBinaryDirs()) {
|
|
34712
34692
|
if (!existing.has(dir)) {
|
|
@@ -35382,6 +35362,10 @@ var FENCE_RE = new RegExp("```" + HANDOFF_FENCE_TAG + "\\s*\\n([\\s\\S]*?)\\n?``
|
|
|
35382
35362
|
var DEGENERATE_LINE_RE = new RegExp(
|
|
35383
35363
|
"^[ \\t]*(`{0,2})[ \\t]*" + HANDOFF_FENCE_TAG + "[ \\t]+(\\{.*\\})[ \\t]*\\1[ \\t]*\\r?$"
|
|
35384
35364
|
);
|
|
35365
|
+
var TAG_ONLY_LINE_RE = new RegExp(
|
|
35366
|
+
"^[ \\t]*`*[ \\t]*" + HANDOFF_FENCE_TAG + "[ \\t]*`*[ \\t]*\\r?$"
|
|
35367
|
+
);
|
|
35368
|
+
var CLOSING_BACKTICK_LINE_RE = /^[ \t]*`+[ \t]*\r?$/;
|
|
35385
35369
|
var OUTER_FENCE_RE = /(`{4,})[\s\S]*?\1/g;
|
|
35386
35370
|
var outerFencePlaceholder = (i) => `@@HANDOFF_MASK_${i}@@`;
|
|
35387
35371
|
function maskOuterFences(text) {
|
|
@@ -35453,24 +35437,92 @@ function collapseSeams(s) {
|
|
|
35453
35437
|
function stripFences(masked) {
|
|
35454
35438
|
return collapseSeams(masked.replace(FENCE_RE, ""));
|
|
35455
35439
|
}
|
|
35456
|
-
function
|
|
35457
|
-
const parts = masked.split("\n");
|
|
35440
|
+
function lineStarts(parts) {
|
|
35458
35441
|
const starts = [];
|
|
35459
35442
|
let offset = 0;
|
|
35460
35443
|
for (const p2 of parts) {
|
|
35461
35444
|
starts.push(offset);
|
|
35462
35445
|
offset += p2.length + 1;
|
|
35463
35446
|
}
|
|
35447
|
+
return starts;
|
|
35448
|
+
}
|
|
35449
|
+
function lastNonBlankLine(masked) {
|
|
35450
|
+
const parts = masked.split("\n");
|
|
35451
|
+
const starts = lineStarts(parts);
|
|
35464
35452
|
for (let i = parts.length - 1; i >= 0; i--) {
|
|
35465
35453
|
if (parts[i].trim().length > 0) return { line: parts[i], start: starts[i] };
|
|
35466
35454
|
}
|
|
35467
35455
|
return null;
|
|
35468
35456
|
}
|
|
35469
|
-
function
|
|
35457
|
+
function trailingSameLineMatch(masked) {
|
|
35470
35458
|
const last = lastNonBlankLine(masked);
|
|
35471
35459
|
if (!last) return null;
|
|
35472
|
-
const
|
|
35473
|
-
|
|
35460
|
+
const m = last.line.match(DEGENERATE_LINE_RE);
|
|
35461
|
+
if (!m) return null;
|
|
35462
|
+
return { jsonRaw: m[2], start: last.start, end: last.start + m[0].length };
|
|
35463
|
+
}
|
|
35464
|
+
function trailingBlockMatch(masked) {
|
|
35465
|
+
const lines = masked.split("\n");
|
|
35466
|
+
const starts = lineStarts(lines);
|
|
35467
|
+
let tagLineIdx = -1;
|
|
35468
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
35469
|
+
if (TAG_ONLY_LINE_RE.test(lines[i])) {
|
|
35470
|
+
tagLineIdx = i;
|
|
35471
|
+
break;
|
|
35472
|
+
}
|
|
35473
|
+
}
|
|
35474
|
+
if (tagLineIdx === -1) return null;
|
|
35475
|
+
let end = lines.length - 1;
|
|
35476
|
+
while (end > tagLineIdx && lines[end].trim().length === 0) end--;
|
|
35477
|
+
if (end > tagLineIdx && CLOSING_BACKTICK_LINE_RE.test(lines[end])) {
|
|
35478
|
+
end--;
|
|
35479
|
+
while (end > tagLineIdx && lines[end].trim().length === 0) end--;
|
|
35480
|
+
}
|
|
35481
|
+
if (end <= tagLineIdx) return null;
|
|
35482
|
+
const jsonRaw = lines.slice(tagLineIdx + 1, end + 1).join("\n");
|
|
35483
|
+
return { jsonRaw, start: starts[tagLineIdx], end: masked.length };
|
|
35484
|
+
}
|
|
35485
|
+
function trailingDegenerateMatch(masked) {
|
|
35486
|
+
return trailingSameLineMatch(masked) ?? trailingBlockMatch(masked);
|
|
35487
|
+
}
|
|
35488
|
+
function earlierShapeValidDegenerateSpans(masked, beforeOffset) {
|
|
35489
|
+
const lines = masked.split("\n");
|
|
35490
|
+
const starts = lineStarts(lines);
|
|
35491
|
+
const spans = [];
|
|
35492
|
+
for (let i = 0; i < lines.length && starts[i] < beforeOffset; i++) {
|
|
35493
|
+
const same = lines[i].match(DEGENERATE_LINE_RE);
|
|
35494
|
+
if (same) {
|
|
35495
|
+
const end = starts[i] + same[0].length;
|
|
35496
|
+
if (end <= beforeOffset && parseProposalShape(same[2].trim())) {
|
|
35497
|
+
spans.push({ start: starts[i], end });
|
|
35498
|
+
}
|
|
35499
|
+
continue;
|
|
35500
|
+
}
|
|
35501
|
+
if (TAG_ONLY_LINE_RE.test(lines[i])) {
|
|
35502
|
+
let j2 = i + 1;
|
|
35503
|
+
while (j2 < lines.length && lines[j2].trim().length === 0) j2++;
|
|
35504
|
+
if (j2 >= lines.length || starts[j2] >= beforeOffset) continue;
|
|
35505
|
+
if (!parseProposalShape(lines[j2].trim())) continue;
|
|
35506
|
+
let end = starts[j2] + lines[j2].length;
|
|
35507
|
+
let k2 = j2 + 1;
|
|
35508
|
+
if (k2 < lines.length && starts[k2] < beforeOffset && CLOSING_BACKTICK_LINE_RE.test(lines[k2])) {
|
|
35509
|
+
end = starts[k2] + lines[k2].length;
|
|
35510
|
+
}
|
|
35511
|
+
if (end <= beforeOffset) spans.push({ start: starts[i], end });
|
|
35512
|
+
}
|
|
35513
|
+
}
|
|
35514
|
+
return spans;
|
|
35515
|
+
}
|
|
35516
|
+
function removeSpans(text, spans) {
|
|
35517
|
+
const sorted = [...spans].sort((a, b) => a.start - b.start);
|
|
35518
|
+
let result = "";
|
|
35519
|
+
let cursor = 0;
|
|
35520
|
+
for (const span of sorted) {
|
|
35521
|
+
result += text.slice(cursor, span.start);
|
|
35522
|
+
cursor = span.end;
|
|
35523
|
+
}
|
|
35524
|
+
result += text.slice(cursor);
|
|
35525
|
+
return result;
|
|
35474
35526
|
}
|
|
35475
35527
|
function extractHandoffProposal(text, currentAgent, validTargets) {
|
|
35476
35528
|
const { masked, restore } = maskOuterFences(text);
|
|
@@ -35483,10 +35535,13 @@ function extractHandoffProposal(text, currentAgent, validTargets) {
|
|
|
35483
35535
|
}
|
|
35484
35536
|
const degenerate = trailingDegenerateMatch(masked);
|
|
35485
35537
|
if (degenerate) {
|
|
35486
|
-
const proposal = parseProposal(degenerate.
|
|
35538
|
+
const proposal = parseProposal(degenerate.jsonRaw.trim(), currentAgent, validTargets);
|
|
35487
35539
|
if (proposal) {
|
|
35488
|
-
const
|
|
35489
|
-
const stripped = masked
|
|
35540
|
+
const earlier = earlierShapeValidDegenerateSpans(masked, degenerate.start);
|
|
35541
|
+
const stripped = removeSpans(masked, [
|
|
35542
|
+
...earlier,
|
|
35543
|
+
{ start: degenerate.start, end: degenerate.end }
|
|
35544
|
+
]);
|
|
35490
35545
|
return { cleanText: restore(collapseSeams(stripped)), proposal };
|
|
35491
35546
|
}
|
|
35492
35547
|
return { cleanText: text, proposal: null };
|
|
@@ -35499,9 +35554,8 @@ function stripHandoffFences(text) {
|
|
|
35499
35554
|
return restore(stripFences(masked));
|
|
35500
35555
|
}
|
|
35501
35556
|
const degenerate = trailingDegenerateMatch(masked);
|
|
35502
|
-
if (degenerate && parseProposalShape(degenerate.
|
|
35503
|
-
const
|
|
35504
|
-
const stripped = masked.slice(0, start2) + masked.slice(start2 + degenerate.match[0].length);
|
|
35557
|
+
if (degenerate && parseProposalShape(degenerate.jsonRaw.trim())) {
|
|
35558
|
+
const stripped = masked.slice(0, degenerate.start) + masked.slice(degenerate.end);
|
|
35505
35559
|
return restore(collapseSeams(stripped));
|
|
35506
35560
|
}
|
|
35507
35561
|
return text;
|
|
@@ -44571,7 +44625,7 @@ function checkChokidar() {
|
|
|
44571
44625
|
}
|
|
44572
44626
|
async function doctor(args2 = []) {
|
|
44573
44627
|
const json = args2.includes("--json");
|
|
44574
|
-
const cliVersion = true ? "2.65.
|
|
44628
|
+
const cliVersion = true ? "2.65.6" : "0.0.0-dev";
|
|
44575
44629
|
const apiBase2 = resolveApiBaseUrl();
|
|
44576
44630
|
const diagnosticId = (0, import_node_crypto13.randomUUID)();
|
|
44577
44631
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -44962,7 +45016,7 @@ async function mcpRun(args2) {
|
|
|
44962
45016
|
// src/commands/version.ts
|
|
44963
45017
|
var import_picocolors15 = __toESM(require("picocolors"));
|
|
44964
45018
|
function version2() {
|
|
44965
|
-
const v = true ? "2.65.
|
|
45019
|
+
const v = true ? "2.65.6" : "unknown";
|
|
44966
45020
|
console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
|
|
44967
45021
|
}
|
|
44968
45022
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.65.
|
|
3
|
+
"version": "2.65.6",
|
|
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",
|