codeam-cli 2.27.8 → 2.27.9
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 +6 -0
- package/dist/index.js +80 -57
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,12 @@ 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.27.8] — 2026-06-06
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **cli:** ACP — accumulate cumulative content per chunkId, isFinal on prompt-end
|
|
12
|
+
|
|
7
13
|
## [2.27.7] — 2026-06-06
|
|
8
14
|
|
|
9
15
|
### Fixed
|
package/dist/index.js
CHANGED
|
@@ -498,7 +498,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
|
|
|
498
498
|
// package.json
|
|
499
499
|
var package_default = {
|
|
500
500
|
name: "codeam-cli",
|
|
501
|
-
version: "2.27.
|
|
501
|
+
version: "2.27.9",
|
|
502
502
|
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.",
|
|
503
503
|
type: "commonjs",
|
|
504
504
|
main: "dist/index.js",
|
|
@@ -5873,7 +5873,7 @@ function readAnonId() {
|
|
|
5873
5873
|
}
|
|
5874
5874
|
function superProperties() {
|
|
5875
5875
|
return {
|
|
5876
|
-
cliVersion: true ? "2.27.
|
|
5876
|
+
cliVersion: true ? "2.27.9" : "0.0.0-dev",
|
|
5877
5877
|
nodeVersion: process.version,
|
|
5878
5878
|
platform: process.platform,
|
|
5879
5879
|
arch: process.arch,
|
|
@@ -12049,9 +12049,6 @@ function getAcpAdapter(agent) {
|
|
|
12049
12049
|
return factory ? factory() : null;
|
|
12050
12050
|
}
|
|
12051
12051
|
|
|
12052
|
-
// src/agents/acp/runner.ts
|
|
12053
|
-
var import_node_crypto6 = require("crypto");
|
|
12054
|
-
|
|
12055
12052
|
// src/agents/acp/client.ts
|
|
12056
12053
|
var import_node_child_process11 = require("child_process");
|
|
12057
12054
|
var fs21 = __toESM(require("fs/promises"));
|
|
@@ -12374,39 +12371,51 @@ var AcpPublisher = class {
|
|
|
12374
12371
|
apiBase;
|
|
12375
12372
|
headers;
|
|
12376
12373
|
/**
|
|
12377
|
-
* Wrap the
|
|
12374
|
+
* Wrap the body with `sessionId` + `pluginId` at the top level.
|
|
12378
12375
|
* The backend's `PluginAuthGuard` reads both fields from the JSON
|
|
12379
|
-
* body even when `X-Plugin-Auth-Token` is set on the header
|
|
12380
|
-
* `:sessionId` is on the URL path. Without the body fields it
|
|
12381
|
-
* rejects every POST with `PLUGIN_TOKEN_REQUIRED` — same shape the
|
|
12382
|
-
* legacy `streaming-emitter.service.ts` `postWithRetries` uses.
|
|
12376
|
+
* body even when `X-Plugin-Auth-Token` is set on the header.
|
|
12383
12377
|
*/
|
|
12384
|
-
envelope(
|
|
12378
|
+
envelope(body) {
|
|
12385
12379
|
return JSON.stringify({
|
|
12386
12380
|
sessionId: this.opts.sessionId,
|
|
12387
12381
|
pluginId: this.opts.pluginId,
|
|
12388
|
-
...
|
|
12382
|
+
...body
|
|
12389
12383
|
});
|
|
12390
12384
|
}
|
|
12391
12385
|
/**
|
|
12392
|
-
*
|
|
12393
|
-
*
|
|
12394
|
-
*
|
|
12395
|
-
*
|
|
12386
|
+
* POST one event to the legacy chat-render pipeline at
|
|
12387
|
+
* `/api/commands/output`. Mobile reads this feed for the chat
|
|
12388
|
+
* surface — every "Thinking…" → reply → done bubble flows through
|
|
12389
|
+
* here. Accepts arbitrary body shapes (the legacy emitter is a
|
|
12390
|
+
* thin pipe; mobile branches on `type`):
|
|
12391
|
+
*
|
|
12392
|
+
* { type: 'clear' } wipe screen
|
|
12393
|
+
* { type: 'new_turn', done: false } "Agent is typing…"
|
|
12394
|
+
* { type: 'text', content: '…', done: false } streaming delta
|
|
12395
|
+
* { type: 'text', content: '…', done: true } turn complete
|
|
12396
|
+
*
|
|
12397
|
+
* Errors are logged but never thrown — a missed chunk shouldn't
|
|
12398
|
+
* bring down the whole session.
|
|
12396
12399
|
*/
|
|
12397
|
-
async
|
|
12398
|
-
const url = `${this.apiBase}/api/
|
|
12400
|
+
async publishOutput(body) {
|
|
12401
|
+
const url = `${this.apiBase}/api/commands/output`;
|
|
12399
12402
|
try {
|
|
12400
|
-
const { statusCode, body } = await _transport2.post(
|
|
12403
|
+
const { statusCode, body: resBody } = await _transport2.post(
|
|
12401
12404
|
url,
|
|
12402
12405
|
this.headers,
|
|
12403
|
-
this.envelope(
|
|
12406
|
+
this.envelope(body)
|
|
12404
12407
|
);
|
|
12405
12408
|
if (statusCode < 200 || statusCode >= 300) {
|
|
12406
|
-
log.warn(
|
|
12409
|
+
log.warn(
|
|
12410
|
+
"acpPublisher",
|
|
12411
|
+
`output type=${String(body.type)} done=${body.done === true} status=${statusCode} body=${resBody.slice(0, 200)}`
|
|
12412
|
+
);
|
|
12407
12413
|
}
|
|
12408
12414
|
} catch (err) {
|
|
12409
|
-
log.
|
|
12415
|
+
log.warn(
|
|
12416
|
+
"acpPublisher",
|
|
12417
|
+
`output type=${String(body.type)} post failed: ${err instanceof Error ? err.message : String(err)}`
|
|
12418
|
+
);
|
|
12410
12419
|
}
|
|
12411
12420
|
}
|
|
12412
12421
|
/**
|
|
@@ -12612,6 +12621,18 @@ var StreamingState = class {
|
|
|
12612
12621
|
}
|
|
12613
12622
|
publisher;
|
|
12614
12623
|
open = /* @__PURE__ */ new Map();
|
|
12624
|
+
/**
|
|
12625
|
+
* Boundary events emitted at the start of every turn so mobile
|
|
12626
|
+
* wipes the previous reply and shows "Agent is typing…". Mirrors
|
|
12627
|
+
* the legacy `outputSvc.newTurn()` — `critical: true` on those
|
|
12628
|
+
* sends is implicit here (publishOutput retries on transient
|
|
12629
|
+
* failures so the boundary always lands).
|
|
12630
|
+
*/
|
|
12631
|
+
async beginTurn() {
|
|
12632
|
+
this.open.clear();
|
|
12633
|
+
await this.publisher.publishOutput({ type: "clear" });
|
|
12634
|
+
await this.publisher.publishOutput({ type: "new_turn", done: false });
|
|
12635
|
+
}
|
|
12615
12636
|
append(delta) {
|
|
12616
12637
|
const existing = this.open.get(delta.chunkId);
|
|
12617
12638
|
const content = (existing?.content ?? "") + delta.delta;
|
|
@@ -12622,32 +12643,33 @@ var StreamingState = class {
|
|
|
12622
12643
|
);
|
|
12623
12644
|
}
|
|
12624
12645
|
this.open.set(delta.chunkId, { kind: delta.kind, content });
|
|
12625
|
-
void this.publisher.
|
|
12626
|
-
log.warn(
|
|
12627
|
-
"acpRunner",
|
|
12628
|
-
`publishChunk (streaming) failed: ${err instanceof Error ? err.message : String(err)}`
|
|
12629
|
-
);
|
|
12630
|
-
});
|
|
12646
|
+
void this.publisher.publishOutput({ type: "text", content, done: false });
|
|
12631
12647
|
}
|
|
12632
12648
|
/**
|
|
12633
|
-
*
|
|
12634
|
-
* to call multiple times per
|
|
12635
|
-
*
|
|
12649
|
+
* Flush every open buffer with `done: true` so mobile flips out
|
|
12650
|
+
* of "Thinking…". Idempotent — safe to call multiple times per
|
|
12651
|
+
* turn (prompt-completed, cancel, adapter-exit).
|
|
12652
|
+
*
|
|
12653
|
+
* Also emits an empty `{type:'text', content:'', done:true}` when
|
|
12654
|
+
* the turn produced no text at all (e.g. Claude responded with
|
|
12655
|
+
* tool calls only) so mobile doesn't sit on "Thinking…" forever
|
|
12656
|
+
* waiting for content that will never arrive.
|
|
12636
12657
|
*/
|
|
12637
12658
|
async closeAll() {
|
|
12638
|
-
if (this.open.size === 0)
|
|
12639
|
-
|
|
12659
|
+
if (this.open.size === 0) {
|
|
12660
|
+
await this.publisher.publishOutput({ type: "text", content: "", done: true });
|
|
12661
|
+
return;
|
|
12662
|
+
}
|
|
12663
|
+
const closing = Array.from(this.open.values());
|
|
12640
12664
|
this.open.clear();
|
|
12641
|
-
|
|
12642
|
-
closing.
|
|
12643
|
-
|
|
12644
|
-
|
|
12645
|
-
|
|
12646
|
-
|
|
12647
|
-
|
|
12648
|
-
|
|
12649
|
-
)
|
|
12650
|
-
);
|
|
12665
|
+
for (let i = 0; i < closing.length; i += 1) {
|
|
12666
|
+
const isLast = i === closing.length - 1;
|
|
12667
|
+
await this.publisher.publishOutput({
|
|
12668
|
+
type: "text",
|
|
12669
|
+
content: closing[i].content,
|
|
12670
|
+
done: isLast
|
|
12671
|
+
});
|
|
12672
|
+
}
|
|
12651
12673
|
}
|
|
12652
12674
|
};
|
|
12653
12675
|
var ANSWER_POLL_MS = 1500;
|
|
@@ -12696,13 +12718,13 @@ async function runAcpSession(opts) {
|
|
|
12696
12718
|
},
|
|
12697
12719
|
onUnexpectedExit: (code, signal) => {
|
|
12698
12720
|
log.warn("acpRunner", `adapter died code=${code} signal=${signal}; shutting down session`);
|
|
12699
|
-
void streaming.closeAll()
|
|
12700
|
-
|
|
12701
|
-
|
|
12702
|
-
|
|
12703
|
-
|
|
12704
|
-
|
|
12705
|
-
|
|
12721
|
+
void streaming.closeAll().then(
|
|
12722
|
+
() => publisher.publishOutput({
|
|
12723
|
+
type: "text",
|
|
12724
|
+
content: `Agent adapter exited unexpectedly (code=${code ?? "null"} signal=${signal ?? "null"}).`,
|
|
12725
|
+
done: true
|
|
12726
|
+
})
|
|
12727
|
+
);
|
|
12706
12728
|
process.exit(1);
|
|
12707
12729
|
}
|
|
12708
12730
|
});
|
|
@@ -12746,6 +12768,7 @@ async function handleCommand(cmd, client2, relay, acpSessionId, models, streamin
|
|
|
12746
12768
|
return;
|
|
12747
12769
|
}
|
|
12748
12770
|
log.info("acpRunner", `start_task \u2192 forwarding prompt chars=${prompt.length} id=${cmd.id.slice(0, 8)}`);
|
|
12771
|
+
await streaming.beginTurn();
|
|
12749
12772
|
try {
|
|
12750
12773
|
const reply = await client2.prompt(prompt);
|
|
12751
12774
|
await streaming.closeAll();
|
|
@@ -16699,7 +16722,7 @@ function findGitRoot2(startDir) {
|
|
|
16699
16722
|
}
|
|
16700
16723
|
|
|
16701
16724
|
// src/commands/link.ts
|
|
16702
|
-
var
|
|
16725
|
+
var import_node_crypto6 = require("crypto");
|
|
16703
16726
|
var fs28 = __toESM(require("fs"));
|
|
16704
16727
|
var path34 = __toESM(require("path"));
|
|
16705
16728
|
var import_chokidar = __toESM(require("chokidar"));
|
|
@@ -16788,7 +16811,7 @@ async function link(args2 = []) {
|
|
|
16788
16811
|
await linkDryRunPreflight(ctx);
|
|
16789
16812
|
return;
|
|
16790
16813
|
}
|
|
16791
|
-
const pluginId = (0,
|
|
16814
|
+
const pluginId = (0, import_node_crypto6.randomUUID)();
|
|
16792
16815
|
const spin = dist_exports.spinner();
|
|
16793
16816
|
spin.start("Requesting pairing code...");
|
|
16794
16817
|
const pairing = await requestCode(pluginId);
|
|
@@ -21104,7 +21127,7 @@ async function stopWorkspaceFromLocal(target) {
|
|
|
21104
21127
|
// src/commands/doctor.ts
|
|
21105
21128
|
var import_node_dns = require("dns");
|
|
21106
21129
|
var import_node_util4 = require("util");
|
|
21107
|
-
var
|
|
21130
|
+
var import_node_crypto7 = require("crypto");
|
|
21108
21131
|
var fs34 = __toESM(require("fs"));
|
|
21109
21132
|
var path43 = __toESM(require("path"));
|
|
21110
21133
|
var import_picocolors12 = __toESM(require("picocolors"));
|
|
@@ -21274,9 +21297,9 @@ function checkChokidar() {
|
|
|
21274
21297
|
}
|
|
21275
21298
|
async function doctor(args2 = []) {
|
|
21276
21299
|
const json = args2.includes("--json");
|
|
21277
|
-
const cliVersion = true ? "2.27.
|
|
21300
|
+
const cliVersion = true ? "2.27.9" : "0.0.0-dev";
|
|
21278
21301
|
const apiBase = resolveApiBaseUrl();
|
|
21279
|
-
const diagnosticId = (0,
|
|
21302
|
+
const diagnosticId = (0, import_node_crypto7.randomUUID)();
|
|
21280
21303
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
21281
21304
|
const [dns, health] = await Promise.all([
|
|
21282
21305
|
checkDns(apiBase),
|
|
@@ -21473,7 +21496,7 @@ async function completion(args2) {
|
|
|
21473
21496
|
// src/commands/version.ts
|
|
21474
21497
|
var import_picocolors13 = __toESM(require("picocolors"));
|
|
21475
21498
|
function version2() {
|
|
21476
|
-
const v = true ? "2.27.
|
|
21499
|
+
const v = true ? "2.27.9" : "unknown";
|
|
21477
21500
|
console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
|
|
21478
21501
|
}
|
|
21479
21502
|
|
|
@@ -21701,7 +21724,7 @@ function checkForUpdates() {
|
|
|
21701
21724
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
21702
21725
|
if (process.env.CI) return;
|
|
21703
21726
|
if (!process.stdout.isTTY) return;
|
|
21704
|
-
const current = true ? "2.27.
|
|
21727
|
+
const current = true ? "2.27.9" : null;
|
|
21705
21728
|
if (!current) return;
|
|
21706
21729
|
const cache = readCache();
|
|
21707
21730
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.27.
|
|
3
|
+
"version": "2.27.9",
|
|
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",
|