codeam-cli 2.27.8 → 2.27.10
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 +12 -0
- package/dist/index.js +75 -71
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,18 @@ 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.9] — 2026-06-06
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **cli:** ACP publishes to /api/commands/output (mobile's chat pipe)
|
|
12
|
+
|
|
13
|
+
## [2.27.8] — 2026-06-06
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- **cli:** ACP — accumulate cumulative content per chunkId, isFinal on prompt-end
|
|
18
|
+
|
|
7
19
|
## [2.27.7] — 2026-06-06
|
|
8
20
|
|
|
9
21
|
### 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.10",
|
|
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.10" : "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"));
|
|
@@ -12130,7 +12127,11 @@ var AcpClient = class {
|
|
|
12130
12127
|
mcpServers: []
|
|
12131
12128
|
});
|
|
12132
12129
|
this.sessionId = newSession.sessionId;
|
|
12133
|
-
|
|
12130
|
+
const newSessionMeta = newSession;
|
|
12131
|
+
log.info(
|
|
12132
|
+
"acpClient",
|
|
12133
|
+
`newSession \u2190 ok sessionId=${newSession.sessionId.slice(0, 8)} model=${newSessionMeta.currentModelId ?? "?"} tier=${newSessionMeta.currentServiceTier ?? "?"}`
|
|
12134
|
+
);
|
|
12134
12135
|
return { sessionId: newSession.sessionId, initialize };
|
|
12135
12136
|
}
|
|
12136
12137
|
/**
|
|
@@ -12157,15 +12158,15 @@ var AcpClient = class {
|
|
|
12157
12158
|
sessionId: this.sessionId,
|
|
12158
12159
|
prompt: [{ type: "text", text }]
|
|
12159
12160
|
});
|
|
12161
|
+
let timeoutId;
|
|
12160
12162
|
const timeout = new Promise((_resolve, reject) => {
|
|
12161
|
-
|
|
12163
|
+
timeoutId = setTimeout(() => {
|
|
12162
12164
|
reject(
|
|
12163
12165
|
new Error(
|
|
12164
12166
|
`ACP prompt timed out after ${PROMPT_TIMEOUT_MS / 1e3}s \u2014 adapter never responded. Likely the underlying agent's auth or network is misconfigured; check the adapter stderr lines above (acpAdapter tag) for the actual error.`
|
|
12165
12167
|
)
|
|
12166
12168
|
);
|
|
12167
12169
|
}, PROMPT_TIMEOUT_MS);
|
|
12168
|
-
void send.finally(() => clearTimeout(id));
|
|
12169
12170
|
});
|
|
12170
12171
|
try {
|
|
12171
12172
|
const result = await Promise.race([send, timeout]);
|
|
@@ -12180,6 +12181,8 @@ var AcpClient = class {
|
|
|
12180
12181
|
`prompt \u2190 failed elapsedMs=${Date.now() - t0} err=${err instanceof Error ? err.message : String(err)}`
|
|
12181
12182
|
);
|
|
12182
12183
|
throw err;
|
|
12184
|
+
} finally {
|
|
12185
|
+
if (timeoutId !== void 0) clearTimeout(timeoutId);
|
|
12183
12186
|
}
|
|
12184
12187
|
}
|
|
12185
12188
|
/**
|
|
@@ -12374,39 +12377,51 @@ var AcpPublisher = class {
|
|
|
12374
12377
|
apiBase;
|
|
12375
12378
|
headers;
|
|
12376
12379
|
/**
|
|
12377
|
-
* Wrap the
|
|
12380
|
+
* Wrap the body with `sessionId` + `pluginId` at the top level.
|
|
12378
12381
|
* 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.
|
|
12382
|
+
* body even when `X-Plugin-Auth-Token` is set on the header.
|
|
12383
12383
|
*/
|
|
12384
|
-
envelope(
|
|
12384
|
+
envelope(body) {
|
|
12385
12385
|
return JSON.stringify({
|
|
12386
12386
|
sessionId: this.opts.sessionId,
|
|
12387
12387
|
pluginId: this.opts.pluginId,
|
|
12388
|
-
...
|
|
12388
|
+
...body
|
|
12389
12389
|
});
|
|
12390
12390
|
}
|
|
12391
12391
|
/**
|
|
12392
|
-
*
|
|
12393
|
-
*
|
|
12394
|
-
*
|
|
12395
|
-
*
|
|
12392
|
+
* POST one event to the legacy chat-render pipeline at
|
|
12393
|
+
* `/api/commands/output`. Mobile reads this feed for the chat
|
|
12394
|
+
* surface — every "Thinking…" → reply → done bubble flows through
|
|
12395
|
+
* here. Accepts arbitrary body shapes (the legacy emitter is a
|
|
12396
|
+
* thin pipe; mobile branches on `type`):
|
|
12397
|
+
*
|
|
12398
|
+
* { type: 'clear' } wipe screen
|
|
12399
|
+
* { type: 'new_turn', done: false } "Agent is typing…"
|
|
12400
|
+
* { type: 'text', content: '…', done: false } streaming delta
|
|
12401
|
+
* { type: 'text', content: '…', done: true } turn complete
|
|
12402
|
+
*
|
|
12403
|
+
* Errors are logged but never thrown — a missed chunk shouldn't
|
|
12404
|
+
* bring down the whole session.
|
|
12396
12405
|
*/
|
|
12397
|
-
async
|
|
12398
|
-
const url = `${this.apiBase}/api/
|
|
12406
|
+
async publishOutput(body) {
|
|
12407
|
+
const url = `${this.apiBase}/api/commands/output`;
|
|
12399
12408
|
try {
|
|
12400
|
-
const { statusCode, body } = await _transport2.post(
|
|
12409
|
+
const { statusCode, body: resBody } = await _transport2.post(
|
|
12401
12410
|
url,
|
|
12402
12411
|
this.headers,
|
|
12403
|
-
this.envelope(
|
|
12412
|
+
this.envelope(body)
|
|
12404
12413
|
);
|
|
12405
12414
|
if (statusCode < 200 || statusCode >= 300) {
|
|
12406
|
-
log.warn(
|
|
12415
|
+
log.warn(
|
|
12416
|
+
"acpPublisher",
|
|
12417
|
+
`output type=${String(body.type)} done=${body.done === true} status=${statusCode} body=${resBody.slice(0, 200)}`
|
|
12418
|
+
);
|
|
12407
12419
|
}
|
|
12408
12420
|
} catch (err) {
|
|
12409
|
-
log.
|
|
12421
|
+
log.warn(
|
|
12422
|
+
"acpPublisher",
|
|
12423
|
+
`output type=${String(body.type)} post failed: ${err instanceof Error ? err.message : String(err)}`
|
|
12424
|
+
);
|
|
12410
12425
|
}
|
|
12411
12426
|
}
|
|
12412
12427
|
/**
|
|
@@ -12611,43 +12626,31 @@ var StreamingState = class {
|
|
|
12611
12626
|
this.publisher = publisher;
|
|
12612
12627
|
}
|
|
12613
12628
|
publisher;
|
|
12614
|
-
|
|
12629
|
+
text = "";
|
|
12630
|
+
/**
|
|
12631
|
+
* Boundary events emitted at the start of every turn so mobile
|
|
12632
|
+
* wipes the previous reply and shows "Agent is typing…". Mirrors
|
|
12633
|
+
* the legacy `outputSvc.newTurn()`.
|
|
12634
|
+
*/
|
|
12635
|
+
async beginTurn() {
|
|
12636
|
+
this.text = "";
|
|
12637
|
+
await this.publisher.publishOutput({ type: "clear" });
|
|
12638
|
+
await this.publisher.publishOutput({ type: "new_turn", done: false });
|
|
12639
|
+
}
|
|
12615
12640
|
append(delta) {
|
|
12616
|
-
|
|
12617
|
-
|
|
12618
|
-
|
|
12619
|
-
log.warn(
|
|
12620
|
-
"acpRunner",
|
|
12621
|
-
`chunk kind flip detected chunkId=${delta.chunkId.slice(0, 8)} from=${existing.kind} to=${delta.kind} \u2014 using new kind`
|
|
12622
|
-
);
|
|
12623
|
-
}
|
|
12624
|
-
this.open.set(delta.chunkId, { kind: delta.kind, content });
|
|
12625
|
-
void this.publisher.publishChunk({ chunkId: delta.chunkId, kind: delta.kind, content, isFinal: false }).catch((err) => {
|
|
12626
|
-
log.warn(
|
|
12627
|
-
"acpRunner",
|
|
12628
|
-
`publishChunk (streaming) failed: ${err instanceof Error ? err.message : String(err)}`
|
|
12629
|
-
);
|
|
12630
|
-
});
|
|
12641
|
+
if (delta.kind !== "text") return;
|
|
12642
|
+
this.text += delta.delta;
|
|
12643
|
+
void this.publisher.publishOutput({ type: "text", content: this.text, done: false });
|
|
12631
12644
|
}
|
|
12632
12645
|
/**
|
|
12633
|
-
*
|
|
12634
|
-
*
|
|
12635
|
-
*
|
|
12646
|
+
* Flip the chat out of "Thinking…" with one final cumulative
|
|
12647
|
+
* `done: true`. Idempotent — safe to call from happy + error +
|
|
12648
|
+
* adapter-exit paths.
|
|
12636
12649
|
*/
|
|
12637
12650
|
async closeAll() {
|
|
12638
|
-
|
|
12639
|
-
|
|
12640
|
-
this.
|
|
12641
|
-
await Promise.all(
|
|
12642
|
-
closing.map(
|
|
12643
|
-
([chunkId, { kind, content }]) => this.publisher.publishChunk({ chunkId, kind, content, isFinal: true }).catch((err) => {
|
|
12644
|
-
log.warn(
|
|
12645
|
-
"acpRunner",
|
|
12646
|
-
`publishChunk (closing) failed: ${err instanceof Error ? err.message : String(err)}`
|
|
12647
|
-
);
|
|
12648
|
-
})
|
|
12649
|
-
)
|
|
12650
|
-
);
|
|
12651
|
+
const finalText = this.text;
|
|
12652
|
+
this.text = "";
|
|
12653
|
+
await this.publisher.publishOutput({ type: "text", content: finalText, done: true });
|
|
12651
12654
|
}
|
|
12652
12655
|
};
|
|
12653
12656
|
var ANSWER_POLL_MS = 1500;
|
|
@@ -12696,13 +12699,13 @@ async function runAcpSession(opts) {
|
|
|
12696
12699
|
},
|
|
12697
12700
|
onUnexpectedExit: (code, signal) => {
|
|
12698
12701
|
log.warn("acpRunner", `adapter died code=${code} signal=${signal}; shutting down session`);
|
|
12699
|
-
void streaming.closeAll()
|
|
12700
|
-
|
|
12701
|
-
|
|
12702
|
-
|
|
12703
|
-
|
|
12704
|
-
|
|
12705
|
-
|
|
12702
|
+
void streaming.closeAll().then(
|
|
12703
|
+
() => publisher.publishOutput({
|
|
12704
|
+
type: "text",
|
|
12705
|
+
content: `Agent adapter exited unexpectedly (code=${code ?? "null"} signal=${signal ?? "null"}).`,
|
|
12706
|
+
done: true
|
|
12707
|
+
})
|
|
12708
|
+
);
|
|
12706
12709
|
process.exit(1);
|
|
12707
12710
|
}
|
|
12708
12711
|
});
|
|
@@ -12746,6 +12749,7 @@ async function handleCommand(cmd, client2, relay, acpSessionId, models, streamin
|
|
|
12746
12749
|
return;
|
|
12747
12750
|
}
|
|
12748
12751
|
log.info("acpRunner", `start_task \u2192 forwarding prompt chars=${prompt.length} id=${cmd.id.slice(0, 8)}`);
|
|
12752
|
+
await streaming.beginTurn();
|
|
12749
12753
|
try {
|
|
12750
12754
|
const reply = await client2.prompt(prompt);
|
|
12751
12755
|
await streaming.closeAll();
|
|
@@ -16699,7 +16703,7 @@ function findGitRoot2(startDir) {
|
|
|
16699
16703
|
}
|
|
16700
16704
|
|
|
16701
16705
|
// src/commands/link.ts
|
|
16702
|
-
var
|
|
16706
|
+
var import_node_crypto6 = require("crypto");
|
|
16703
16707
|
var fs28 = __toESM(require("fs"));
|
|
16704
16708
|
var path34 = __toESM(require("path"));
|
|
16705
16709
|
var import_chokidar = __toESM(require("chokidar"));
|
|
@@ -16788,7 +16792,7 @@ async function link(args2 = []) {
|
|
|
16788
16792
|
await linkDryRunPreflight(ctx);
|
|
16789
16793
|
return;
|
|
16790
16794
|
}
|
|
16791
|
-
const pluginId = (0,
|
|
16795
|
+
const pluginId = (0, import_node_crypto6.randomUUID)();
|
|
16792
16796
|
const spin = dist_exports.spinner();
|
|
16793
16797
|
spin.start("Requesting pairing code...");
|
|
16794
16798
|
const pairing = await requestCode(pluginId);
|
|
@@ -21104,7 +21108,7 @@ async function stopWorkspaceFromLocal(target) {
|
|
|
21104
21108
|
// src/commands/doctor.ts
|
|
21105
21109
|
var import_node_dns = require("dns");
|
|
21106
21110
|
var import_node_util4 = require("util");
|
|
21107
|
-
var
|
|
21111
|
+
var import_node_crypto7 = require("crypto");
|
|
21108
21112
|
var fs34 = __toESM(require("fs"));
|
|
21109
21113
|
var path43 = __toESM(require("path"));
|
|
21110
21114
|
var import_picocolors12 = __toESM(require("picocolors"));
|
|
@@ -21274,9 +21278,9 @@ function checkChokidar() {
|
|
|
21274
21278
|
}
|
|
21275
21279
|
async function doctor(args2 = []) {
|
|
21276
21280
|
const json = args2.includes("--json");
|
|
21277
|
-
const cliVersion = true ? "2.27.
|
|
21281
|
+
const cliVersion = true ? "2.27.10" : "0.0.0-dev";
|
|
21278
21282
|
const apiBase = resolveApiBaseUrl();
|
|
21279
|
-
const diagnosticId = (0,
|
|
21283
|
+
const diagnosticId = (0, import_node_crypto7.randomUUID)();
|
|
21280
21284
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
21281
21285
|
const [dns, health] = await Promise.all([
|
|
21282
21286
|
checkDns(apiBase),
|
|
@@ -21473,7 +21477,7 @@ async function completion(args2) {
|
|
|
21473
21477
|
// src/commands/version.ts
|
|
21474
21478
|
var import_picocolors13 = __toESM(require("picocolors"));
|
|
21475
21479
|
function version2() {
|
|
21476
|
-
const v = true ? "2.27.
|
|
21480
|
+
const v = true ? "2.27.10" : "unknown";
|
|
21477
21481
|
console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
|
|
21478
21482
|
}
|
|
21479
21483
|
|
|
@@ -21701,7 +21705,7 @@ function checkForUpdates() {
|
|
|
21701
21705
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
21702
21706
|
if (process.env.CI) return;
|
|
21703
21707
|
if (!process.stdout.isTTY) return;
|
|
21704
|
-
const current = true ? "2.27.
|
|
21708
|
+
const current = true ? "2.27.10" : null;
|
|
21705
21709
|
if (!current) return;
|
|
21706
21710
|
const cache = readCache();
|
|
21707
21711
|
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.10",
|
|
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",
|