codeam-cli 2.39.87 → 2.40.1
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 +23 -0
- package/dist/index.js +112 -44
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,29 @@ 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.40.0] — 2026-06-24
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **cli:** Add formatAgentReplyLine for the pair full-thread echo
|
|
12
|
+
- **cli:** Echo agent reply in codeam pair so the full thread is visible
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- **cli:** Refresh plugin-auth token and retry once on 401/403 output POST
|
|
17
|
+
- **cli:** Wire plugin-auth token refresh into ACP publisher
|
|
18
|
+
- **cli:** Await bounded terminal-frame flush before adapter-exit teardown
|
|
19
|
+
|
|
20
|
+
### Merge
|
|
21
|
+
|
|
22
|
+
- Session-hang CLI fix (token self-heal + flush-before-exit) + codeam pair agent-reply echo
|
|
23
|
+
|
|
24
|
+
## [2.39.87] — 2026-06-23
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- **cli:** Link Claude via setup-token (dedicated non-rotating codespace credential)
|
|
29
|
+
|
|
7
30
|
## [2.39.86] — 2026-06-23
|
|
8
31
|
|
|
9
32
|
### Fixed
|
package/dist/index.js
CHANGED
|
@@ -5390,7 +5390,7 @@ function readAnonId() {
|
|
|
5390
5390
|
}
|
|
5391
5391
|
function superProperties() {
|
|
5392
5392
|
return {
|
|
5393
|
-
cliVersion: true ? "2.
|
|
5393
|
+
cliVersion: true ? "2.40.1" : "0.0.0-dev",
|
|
5394
5394
|
nodeVersion: process.version,
|
|
5395
5395
|
platform: process.platform,
|
|
5396
5396
|
arch: process.arch,
|
|
@@ -5549,7 +5549,7 @@ var os4 = __toESM(require("os"));
|
|
|
5549
5549
|
// package.json
|
|
5550
5550
|
var package_default = {
|
|
5551
5551
|
name: "codeam-cli",
|
|
5552
|
-
version: "2.
|
|
5552
|
+
version: "2.40.1",
|
|
5553
5553
|
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.",
|
|
5554
5554
|
type: "commonjs",
|
|
5555
5555
|
main: "dist/index.js",
|
|
@@ -17749,7 +17749,7 @@ async function autoUpgradeBeforeCriticalCommand() {
|
|
|
17749
17749
|
if (process.env.NODE_ENV === "test") return;
|
|
17750
17750
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
17751
17751
|
if (process.env.CI) return;
|
|
17752
|
-
const current = true ? "2.
|
|
17752
|
+
const current = true ? "2.40.1" : null;
|
|
17753
17753
|
if (!current) return;
|
|
17754
17754
|
const cache = readCache();
|
|
17755
17755
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -17766,7 +17766,7 @@ function checkForUpdates() {
|
|
|
17766
17766
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
17767
17767
|
if (process.env.CI) return;
|
|
17768
17768
|
if (!process.stdout.isTTY) return;
|
|
17769
|
-
const current = true ? "2.
|
|
17769
|
+
const current = true ? "2.40.1" : null;
|
|
17770
17770
|
if (!current) return;
|
|
17771
17771
|
const cache = readCache();
|
|
17772
17772
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -18204,7 +18204,7 @@ var defaultSpawner = (env, cwd, args2 = []) => (0, import_node_child_process14.s
|
|
|
18204
18204
|
detached: false
|
|
18205
18205
|
});
|
|
18206
18206
|
function currentCliVersion() {
|
|
18207
|
-
return true ? "2.
|
|
18207
|
+
return true ? "2.40.1" : null;
|
|
18208
18208
|
}
|
|
18209
18209
|
function runCmd(cmd, args2, timeoutMs) {
|
|
18210
18210
|
return new Promise((resolve7) => {
|
|
@@ -23143,15 +23143,35 @@ var AcpPublisher = class {
|
|
|
23143
23143
|
constructor(opts) {
|
|
23144
23144
|
this.opts = opts;
|
|
23145
23145
|
this.apiBase = opts.apiBaseUrl ?? resolveApiBaseUrl();
|
|
23146
|
-
this.
|
|
23146
|
+
this.token = opts.pluginAuthToken;
|
|
23147
|
+
}
|
|
23148
|
+
opts;
|
|
23149
|
+
apiBase;
|
|
23150
|
+
token;
|
|
23151
|
+
authHeaders() {
|
|
23152
|
+
return {
|
|
23147
23153
|
"Content-Type": "application/json",
|
|
23148
23154
|
"X-Codeam-Protocol-Version": "2.0.0",
|
|
23149
|
-
"X-Plugin-Auth-Token":
|
|
23155
|
+
"X-Plugin-Auth-Token": this.token
|
|
23150
23156
|
};
|
|
23151
23157
|
}
|
|
23152
|
-
|
|
23153
|
-
|
|
23154
|
-
|
|
23158
|
+
/**
|
|
23159
|
+
* POST with the current plugin-auth token. On a 401/403 the token is
|
|
23160
|
+
* stale (JWT_SECRET rotated on deploy, or the session re-paired);
|
|
23161
|
+
* refresh it via the injected callback and retry ONCE. Any other
|
|
23162
|
+
* status (or a refresh that yields no token) returns the first
|
|
23163
|
+
* response unchanged — callers log non-2xx but never throw.
|
|
23164
|
+
*/
|
|
23165
|
+
async postWithReauth(url, payload) {
|
|
23166
|
+
const first = await _transport4.post(url, this.authHeaders(), payload);
|
|
23167
|
+
if (first.statusCode !== 401 && first.statusCode !== 403) return first;
|
|
23168
|
+
if (!this.opts.refreshAuthToken) return first;
|
|
23169
|
+
const fresh = await this.opts.refreshAuthToken();
|
|
23170
|
+
if (!fresh) return first;
|
|
23171
|
+
this.token = fresh;
|
|
23172
|
+
log.info("acpPublisher", `plugin-auth token refreshed after ${first.statusCode}; retrying POST`);
|
|
23173
|
+
return _transport4.post(url, this.authHeaders(), payload);
|
|
23174
|
+
}
|
|
23155
23175
|
/**
|
|
23156
23176
|
* Wrap the body with `sessionId` + `pluginId` at the top level.
|
|
23157
23177
|
* The backend's `PluginAuthGuard` reads both fields from the JSON
|
|
@@ -23182,16 +23202,11 @@ var AcpPublisher = class {
|
|
|
23182
23202
|
async publishOutput(body) {
|
|
23183
23203
|
const url = `${this.apiBase}/api/commands/output`;
|
|
23184
23204
|
try {
|
|
23185
|
-
const { statusCode, body: resBody } = await
|
|
23186
|
-
url,
|
|
23187
|
-
this.headers,
|
|
23188
|
-
this.envelope(body)
|
|
23189
|
-
);
|
|
23205
|
+
const { statusCode, body: resBody } = await this.postWithReauth(url, this.envelope(body));
|
|
23190
23206
|
if (statusCode < 200 || statusCode >= 300) {
|
|
23191
|
-
const tok = this.opts.pluginAuthToken;
|
|
23192
23207
|
log.warn(
|
|
23193
23208
|
"acpPublisher",
|
|
23194
|
-
`output type=${String(body.type)} done=${body.done === true} status=${statusCode} body=${resBody.slice(0, 200)} | sentSessionId=${this.opts.sessionId} sentPluginId=${this.opts.pluginId} tokenLen=${
|
|
23209
|
+
`output type=${String(body.type)} done=${body.done === true} status=${statusCode} body=${resBody.slice(0, 200)} | sentSessionId=${this.opts.sessionId} sentPluginId=${this.opts.pluginId} tokenLen=${this.token.length} tokenHead=${this.token.slice(0, 12)} tokenTail=${this.token.slice(-8)}`
|
|
23195
23210
|
);
|
|
23196
23211
|
}
|
|
23197
23212
|
} catch (err) {
|
|
@@ -23210,9 +23225,8 @@ var AcpPublisher = class {
|
|
|
23210
23225
|
async publishAwaitingAnswer(event) {
|
|
23211
23226
|
const url = `${this.apiBase}/api/sessions/${encodeURIComponent(this.opts.sessionId)}/awaiting-answer`;
|
|
23212
23227
|
try {
|
|
23213
|
-
const { statusCode, body } = await
|
|
23228
|
+
const { statusCode, body } = await this.postWithReauth(
|
|
23214
23229
|
url,
|
|
23215
|
-
this.headers,
|
|
23216
23230
|
this.envelope(event)
|
|
23217
23231
|
);
|
|
23218
23232
|
if (statusCode < 200 || statusCode >= 300) {
|
|
@@ -23244,9 +23258,8 @@ var AcpPublisher = class {
|
|
|
23244
23258
|
async publishStreamingChunk(event) {
|
|
23245
23259
|
const url = `${this.apiBase}/api/sessions/${encodeURIComponent(this.opts.sessionId)}/streaming-chunk`;
|
|
23246
23260
|
try {
|
|
23247
|
-
const { statusCode, body } = await
|
|
23261
|
+
const { statusCode, body } = await this.postWithReauth(
|
|
23248
23262
|
url,
|
|
23249
|
-
this.headers,
|
|
23250
23263
|
this.envelope(event)
|
|
23251
23264
|
);
|
|
23252
23265
|
if (statusCode < 200 || statusCode >= 300) {
|
|
@@ -23281,7 +23294,7 @@ var AcpPublisher = class {
|
|
|
23281
23294
|
sessions: args2.sessions
|
|
23282
23295
|
});
|
|
23283
23296
|
try {
|
|
23284
|
-
const { statusCode, body: resBody } = await
|
|
23297
|
+
const { statusCode, body: resBody } = await this.postWithReauth(url, body);
|
|
23285
23298
|
if (statusCode < 200 || statusCode >= 300) {
|
|
23286
23299
|
log.warn(
|
|
23287
23300
|
"acpPublisher",
|
|
@@ -23316,7 +23329,7 @@ var AcpPublisher = class {
|
|
|
23316
23329
|
mode: "replace"
|
|
23317
23330
|
});
|
|
23318
23331
|
try {
|
|
23319
|
-
const { statusCode, body: resBody } = await
|
|
23332
|
+
const { statusCode, body: resBody } = await this.postWithReauth(url, body);
|
|
23320
23333
|
if (statusCode < 200 || statusCode >= 300) {
|
|
23321
23334
|
log.warn(
|
|
23322
23335
|
"acpPublisher",
|
|
@@ -23447,6 +23460,7 @@ async function runOnboardingTurn(opts) {
|
|
|
23447
23460
|
|
|
23448
23461
|
// src/agents/acp/promptEcho.ts
|
|
23449
23462
|
var MAX_PROMPT_CHARS = 200;
|
|
23463
|
+
var MAX_AGENT_REPLY_CHARS = 280;
|
|
23450
23464
|
function formatPromptEchoLine(payload) {
|
|
23451
23465
|
const rawText = (payload.prompt ?? "").replace(/\s+/g, " ").trim();
|
|
23452
23466
|
const imageCount = (payload.files ?? []).filter(
|
|
@@ -23463,6 +23477,12 @@ function formatPromptEchoLine(payload) {
|
|
|
23463
23477
|
}
|
|
23464
23478
|
return `\u203A ${parts.join(" ")}`;
|
|
23465
23479
|
}
|
|
23480
|
+
function formatAgentReplyLine(text) {
|
|
23481
|
+
const collapsed = (text ?? "").replace(/\s+/g, " ").trim();
|
|
23482
|
+
if (collapsed.length === 0) return "";
|
|
23483
|
+
const truncated = collapsed.length > MAX_AGENT_REPLY_CHARS ? collapsed.slice(0, MAX_AGENT_REPLY_CHARS) + "\u2026" : collapsed;
|
|
23484
|
+
return `\u2039 Agent: ${truncated}`;
|
|
23485
|
+
}
|
|
23466
23486
|
|
|
23467
23487
|
// src/agents/acp/mappers.ts
|
|
23468
23488
|
var import_node_crypto6 = require("crypto");
|
|
@@ -24174,6 +24194,32 @@ function baselineKey(entry) {
|
|
|
24174
24194
|
return `${entry.repoPath}|${entry.filePath}`;
|
|
24175
24195
|
}
|
|
24176
24196
|
|
|
24197
|
+
// src/agents/acp/withTimeout.ts
|
|
24198
|
+
function withTimeout(p2, ms) {
|
|
24199
|
+
return new Promise((resolve7) => {
|
|
24200
|
+
let settled = false;
|
|
24201
|
+
const timer = setTimeout(() => {
|
|
24202
|
+
if (settled) return;
|
|
24203
|
+
settled = true;
|
|
24204
|
+
resolve7(void 0);
|
|
24205
|
+
}, ms);
|
|
24206
|
+
p2.then(
|
|
24207
|
+
(v) => {
|
|
24208
|
+
if (settled) return;
|
|
24209
|
+
settled = true;
|
|
24210
|
+
clearTimeout(timer);
|
|
24211
|
+
resolve7(v);
|
|
24212
|
+
},
|
|
24213
|
+
() => {
|
|
24214
|
+
if (settled) return;
|
|
24215
|
+
settled = true;
|
|
24216
|
+
clearTimeout(timer);
|
|
24217
|
+
resolve7(void 0);
|
|
24218
|
+
}
|
|
24219
|
+
);
|
|
24220
|
+
});
|
|
24221
|
+
}
|
|
24222
|
+
|
|
24177
24223
|
// src/agents/acp/runner.ts
|
|
24178
24224
|
var StreamingState = class {
|
|
24179
24225
|
constructor(publisher) {
|
|
@@ -24577,18 +24623,28 @@ function failureBubble(opts) {
|
|
|
24577
24623
|
return null;
|
|
24578
24624
|
}
|
|
24579
24625
|
async function reportCredentialInvalid(opts, fetchImpl = fetch) {
|
|
24626
|
+
const url = `${resolveApiBaseUrl()}/api/plugin/agents/${encodeURIComponent(opts.agent)}/credential-invalid`;
|
|
24627
|
+
const body = JSON.stringify({ sessionId: opts.sessionId, pluginId: opts.pluginId });
|
|
24580
24628
|
try {
|
|
24581
|
-
|
|
24582
|
-
|
|
24583
|
-
|
|
24584
|
-
|
|
24585
|
-
|
|
24586
|
-
|
|
24587
|
-
|
|
24588
|
-
|
|
24589
|
-
|
|
24629
|
+
const makeHeaders = (token) => ({
|
|
24630
|
+
"Content-Type": "application/json",
|
|
24631
|
+
"X-Plugin-Auth-Token": token
|
|
24632
|
+
});
|
|
24633
|
+
const response = await fetchImpl(url, {
|
|
24634
|
+
method: "POST",
|
|
24635
|
+
headers: makeHeaders(opts.pluginAuthToken),
|
|
24636
|
+
body
|
|
24637
|
+
});
|
|
24638
|
+
if (response.status === 401 || response.status === 403) {
|
|
24639
|
+
const freshToken = await fetchCurrentPluginAuthToken(
|
|
24640
|
+
opts.sessionId,
|
|
24641
|
+
opts.pluginId,
|
|
24642
|
+
opts.pollSecret
|
|
24643
|
+
);
|
|
24644
|
+
if (freshToken !== null) {
|
|
24645
|
+
await fetchImpl(url, { method: "POST", headers: makeHeaders(freshToken), body });
|
|
24590
24646
|
}
|
|
24591
|
-
|
|
24647
|
+
}
|
|
24592
24648
|
} catch {
|
|
24593
24649
|
}
|
|
24594
24650
|
}
|
|
@@ -24608,7 +24664,8 @@ async function runAcpSession(opts) {
|
|
|
24608
24664
|
const publisher = new AcpPublisher({
|
|
24609
24665
|
sessionId: opts.sessionId,
|
|
24610
24666
|
pluginId: opts.pluginId,
|
|
24611
|
-
pluginAuthToken: opts.pluginAuthToken
|
|
24667
|
+
pluginAuthToken: opts.pluginAuthToken,
|
|
24668
|
+
refreshAuthToken: () => fetchCurrentPluginAuthToken(opts.sessionId, opts.pluginId, opts.pollSecret)
|
|
24612
24669
|
});
|
|
24613
24670
|
const streaming = new StreamingState(publisher);
|
|
24614
24671
|
const recentStderr = [];
|
|
@@ -24682,14 +24739,20 @@ async function runAcpSession(opts) {
|
|
|
24682
24739
|
if (authFail) {
|
|
24683
24740
|
void reportCredentialInvalid(opts);
|
|
24684
24741
|
}
|
|
24685
|
-
void
|
|
24686
|
-
|
|
24687
|
-
|
|
24688
|
-
|
|
24689
|
-
|
|
24690
|
-
|
|
24691
|
-
|
|
24692
|
-
|
|
24742
|
+
void (async () => {
|
|
24743
|
+
await withTimeout(
|
|
24744
|
+
(async () => {
|
|
24745
|
+
await streaming.closeAll();
|
|
24746
|
+
await publisher.publishOutput({
|
|
24747
|
+
type: "text",
|
|
24748
|
+
content: authFail ? AUTH_FAILURE_MESSAGE : `Agent adapter exited unexpectedly (code=${code ?? "null"} signal=${signal ?? "null"}).`,
|
|
24749
|
+
done: true
|
|
24750
|
+
});
|
|
24751
|
+
})(),
|
|
24752
|
+
5e3
|
|
24753
|
+
);
|
|
24754
|
+
process.exit(1);
|
|
24755
|
+
})();
|
|
24693
24756
|
}
|
|
24694
24757
|
});
|
|
24695
24758
|
showInfo(`Starting ${opts.agent} via ACP adapter (${opts.adapter.requiresAgentBinary})\u2026`);
|
|
@@ -24851,6 +24914,10 @@ async function handleCommand(cmd, client2, relay, acpSessionId, models, streamin
|
|
|
24851
24914
|
const reply = await client2.prompt(blocks);
|
|
24852
24915
|
const finalText = streaming.getCurrentText();
|
|
24853
24916
|
await streaming.closeTurnWithInteractiveDetection();
|
|
24917
|
+
const replyLine = formatAgentReplyLine(finalText);
|
|
24918
|
+
if (replyLine.length > 0) {
|
|
24919
|
+
showInfo(replyLine);
|
|
24920
|
+
}
|
|
24854
24921
|
history.appendAgentReply(finalText);
|
|
24855
24922
|
void history.flush();
|
|
24856
24923
|
turnFiles.flushTurn().catch((err) => {
|
|
@@ -26353,6 +26420,7 @@ async function start(requestedAgent) {
|
|
|
26353
26420
|
adapter,
|
|
26354
26421
|
cwd,
|
|
26355
26422
|
getBeads,
|
|
26423
|
+
pollSecret: session.pollSecret,
|
|
26356
26424
|
// AUTO mode for headless, mobile-driven sessions: no human at the box
|
|
26357
26425
|
// to answer permission prompts, so auto-approve them rather than stall
|
|
26358
26426
|
// the turn (the agent-agnostic equivalent of
|
|
@@ -29024,7 +29092,7 @@ function checkChokidar() {
|
|
|
29024
29092
|
}
|
|
29025
29093
|
async function doctor(args2 = []) {
|
|
29026
29094
|
const json = args2.includes("--json");
|
|
29027
|
-
const cliVersion = true ? "2.
|
|
29095
|
+
const cliVersion = true ? "2.40.1" : "0.0.0-dev";
|
|
29028
29096
|
const apiBase2 = resolveApiBaseUrl();
|
|
29029
29097
|
const diagnosticId = (0, import_node_crypto8.randomUUID)();
|
|
29030
29098
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -29223,7 +29291,7 @@ async function completion(args2) {
|
|
|
29223
29291
|
// src/commands/version.ts
|
|
29224
29292
|
var import_picocolors14 = __toESM(require("picocolors"));
|
|
29225
29293
|
function version2() {
|
|
29226
|
-
const v = true ? "2.
|
|
29294
|
+
const v = true ? "2.40.1" : "unknown";
|
|
29227
29295
|
console.log(`${import_picocolors14.default.bold("codeam-cli")} ${import_picocolors14.default.cyan(v)}`);
|
|
29228
29296
|
}
|
|
29229
29297
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.40.1",
|
|
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",
|