codeam-cli 2.74.13 → 2.74.14
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 +30 -0
- package/dist/index.js +91 -59
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,36 @@ 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.74.13] — 2026-09-10
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **cli:** Open the command stream on the stream host with a one-time api-host fallback (#745)
|
|
12
|
+
|
|
13
|
+
### Build
|
|
14
|
+
|
|
15
|
+
- **deps:** Bump gradle-wrapper in /apps/jetbrains-plugin (#661)
|
|
16
|
+
- **deps:** Bump com.squareup.okhttp3:okhttp in /apps/jetbrains-plugin (#641)
|
|
17
|
+
- **deps:** Bump actions/setup-java from 5 to 6 (#662)
|
|
18
|
+
|
|
19
|
+
### CI
|
|
20
|
+
|
|
21
|
+
- **workflow:** Root the npm Dependabot config at the workspace, so its PRs can actually install (#737)
|
|
22
|
+
|
|
23
|
+
### Chore
|
|
24
|
+
|
|
25
|
+
- **deps:** Bump org.jetbrains.kotlin.jvm in /apps/jetbrains-plugin (#743)
|
|
26
|
+
- **deps:** Bump docker/setup-buildx-action from 3 to 4 (#414)
|
|
27
|
+
- **deps:** Bump actions/checkout from 4 to 7 (#366)
|
|
28
|
+
- **deps:** Bump ws from 8.21.0 to 8.21.3 (#740)
|
|
29
|
+
- **deps:** Bump posthog-node from 5.35.1 to 5.51.6 (#741)
|
|
30
|
+
- **deps-dev:** Bump knip from 6.25.0 to 6.34.0 (#742)
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- **cli:** Local baton sessions go silent on mobile after the mirror's 10-min startup wait (#744)
|
|
35
|
+
- **vsc-plugin:** Stop advertising a Copilot agent the plugin cannot dispatch to (#746)
|
|
36
|
+
|
|
7
37
|
## [2.74.12] — 2026-09-09
|
|
8
38
|
|
|
9
39
|
### Fixed
|
package/dist/index.js
CHANGED
|
@@ -10199,7 +10199,7 @@ function readAnonId() {
|
|
|
10199
10199
|
}
|
|
10200
10200
|
function superProperties() {
|
|
10201
10201
|
return {
|
|
10202
|
-
cliVersion: true ? "2.74.
|
|
10202
|
+
cliVersion: true ? "2.74.14" : "0.0.0-dev",
|
|
10203
10203
|
nodeVersion: process.version,
|
|
10204
10204
|
platform: process.platform,
|
|
10205
10205
|
arch: process.arch,
|
|
@@ -10441,7 +10441,7 @@ var http = __toESM(require("http"));
|
|
|
10441
10441
|
// package.json
|
|
10442
10442
|
var package_default = {
|
|
10443
10443
|
name: "codeam-cli",
|
|
10444
|
-
version: "2.74.
|
|
10444
|
+
version: "2.74.14",
|
|
10445
10445
|
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.",
|
|
10446
10446
|
type: "commonjs",
|
|
10447
10447
|
main: "dist/index.js",
|
|
@@ -12131,7 +12131,7 @@ var CommandRelayService = class _CommandRelayService {
|
|
|
12131
12131
|
// fresh + clear the "CLI update available" banner after a self-update
|
|
12132
12132
|
// (a codespace that reinstalls @latest reconnects via heartbeat, not
|
|
12133
12133
|
// pair/reconnect). Older backends ignore the extra field.
|
|
12134
|
-
..."2.74.
|
|
12134
|
+
..."2.74.14" ? { ideVersion: "2.74.14" } : {}
|
|
12135
12135
|
}).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
|
|
12136
12136
|
}
|
|
12137
12137
|
/**
|
|
@@ -24451,7 +24451,7 @@ async function autoUpgradeBeforeCriticalCommand() {
|
|
|
24451
24451
|
if (process.env.NODE_ENV === "test") return;
|
|
24452
24452
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
24453
24453
|
if (process.env.CI) return;
|
|
24454
|
-
const current2 = true ? "2.74.
|
|
24454
|
+
const current2 = true ? "2.74.14" : null;
|
|
24455
24455
|
if (!current2) return;
|
|
24456
24456
|
const cache = readCache();
|
|
24457
24457
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -24468,7 +24468,7 @@ function checkForUpdates() {
|
|
|
24468
24468
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
24469
24469
|
if (process.env.CI) return;
|
|
24470
24470
|
if (!process.stdout.isTTY) return;
|
|
24471
|
-
const current2 = true ? "2.74.
|
|
24471
|
+
const current2 = true ? "2.74.14" : null;
|
|
24472
24472
|
if (!current2) return;
|
|
24473
24473
|
const cache = readCache();
|
|
24474
24474
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -24491,7 +24491,7 @@ var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
|
|
|
24491
24491
|
var SELF_UPDATE_LS_TIMEOUT_MS = 15e3;
|
|
24492
24492
|
var SUDO_PREFLIGHT_TIMEOUT_MS = 5e3;
|
|
24493
24493
|
function currentCliVersion() {
|
|
24494
|
-
return true ? "2.74.
|
|
24494
|
+
return true ? "2.74.14" : null;
|
|
24495
24495
|
}
|
|
24496
24496
|
async function installedVersion(deps) {
|
|
24497
24497
|
const ls = await deps.run(
|
|
@@ -39845,13 +39845,17 @@ function createWakeCredentialProbe(deps) {
|
|
|
39845
39845
|
function reconcileCumulative(existing, incoming) {
|
|
39846
39846
|
if (incoming.length === 0) return existing;
|
|
39847
39847
|
if (incoming.startsWith(existing)) return incoming;
|
|
39848
|
-
if (existing.startsWith(incoming)) return existing;
|
|
39849
39848
|
const shared = commonPrefixLength(existing, incoming);
|
|
39850
|
-
if (
|
|
39849
|
+
if (looksLikeSnapshot(existing, incoming, shared)) {
|
|
39850
|
+
if (shared === incoming.length) return existing;
|
|
39851
39851
|
return existing.slice(0, shared) + incoming.slice(shared);
|
|
39852
39852
|
}
|
|
39853
39853
|
return existing + incoming;
|
|
39854
39854
|
}
|
|
39855
|
+
var MIN_SNAPSHOT_PREFIX = 8;
|
|
39856
|
+
function looksLikeSnapshot(existing, incoming, shared) {
|
|
39857
|
+
return shared >= MIN_SNAPSHOT_PREFIX && shared * 2 >= existing.length && incoming.length * 2 >= existing.length;
|
|
39858
|
+
}
|
|
39855
39859
|
function commonPrefixLength(a, b) {
|
|
39856
39860
|
const max = Math.min(a.length, b.length);
|
|
39857
39861
|
let i = 0;
|
|
@@ -40262,25 +40266,19 @@ function mapSessionUpdate(notification) {
|
|
|
40262
40266
|
}
|
|
40263
40267
|
}
|
|
40264
40268
|
function mapPermissionRequest(request2) {
|
|
40265
|
-
const prompt =
|
|
40266
|
-
const
|
|
40267
|
-
|
|
40268
|
-
|
|
40269
|
-
|
|
40270
|
-
|
|
40271
|
-
if (label in optionIdByLabel) continue;
|
|
40272
|
-
optionIdByLabel[label] = opt.optionId;
|
|
40273
|
-
kindByLabel[label] = opt.kind;
|
|
40274
|
-
labels.push(label);
|
|
40275
|
-
}
|
|
40269
|
+
const prompt = describePermissionToolCall(request2.toolCall) ?? "The agent requested permission to continue.";
|
|
40270
|
+
const options = request2.options.map((opt) => ({
|
|
40271
|
+
label: opt.name?.trim() || humanizeKind(opt.kind),
|
|
40272
|
+
optionId: opt.optionId,
|
|
40273
|
+
kind: opt.kind
|
|
40274
|
+
}));
|
|
40276
40275
|
return {
|
|
40277
40276
|
event: {
|
|
40278
40277
|
questionId: (0, import_node_crypto10.randomUUID)(),
|
|
40279
40278
|
prompt,
|
|
40280
|
-
options:
|
|
40279
|
+
options: options.length > 0 ? options.map((o) => ({ label: o.label, value: o.optionId })) : void 0
|
|
40281
40280
|
},
|
|
40282
|
-
|
|
40283
|
-
kindByLabel
|
|
40281
|
+
options
|
|
40284
40282
|
};
|
|
40285
40283
|
}
|
|
40286
40284
|
function messageChunkId(messageId) {
|
|
@@ -40311,6 +40309,28 @@ function describeToolCall(call) {
|
|
|
40311
40309
|
}
|
|
40312
40310
|
return null;
|
|
40313
40311
|
}
|
|
40312
|
+
var PERMISSION_DETAIL_MAX = 400;
|
|
40313
|
+
function permissionInputDetail(rawInput) {
|
|
40314
|
+
if (!rawInput || typeof rawInput !== "object") return null;
|
|
40315
|
+
const input = rawInput;
|
|
40316
|
+
for (const key of ["command", "file_path", "path"]) {
|
|
40317
|
+
const v = input[key];
|
|
40318
|
+
if (typeof v === "string" && v.trim().length > 0) {
|
|
40319
|
+
const detail = v.trim();
|
|
40320
|
+
return detail.length > PERMISSION_DETAIL_MAX ? `${detail.slice(0, PERMISSION_DETAIL_MAX)}\u2026` : detail;
|
|
40321
|
+
}
|
|
40322
|
+
}
|
|
40323
|
+
return null;
|
|
40324
|
+
}
|
|
40325
|
+
function describePermissionToolCall(call) {
|
|
40326
|
+
const title = describeToolCall(call);
|
|
40327
|
+
const detail = permissionInputDetail(call.rawInput);
|
|
40328
|
+
if (!detail) return title;
|
|
40329
|
+
if (!title) return detail;
|
|
40330
|
+
if (title.includes(detail)) return title;
|
|
40331
|
+
return `${title}
|
|
40332
|
+
${detail}`;
|
|
40333
|
+
}
|
|
40314
40334
|
function describeToolCallUpdate(update) {
|
|
40315
40335
|
const parts = [];
|
|
40316
40336
|
if (Array.isArray(update.content)) {
|
|
@@ -40404,13 +40424,9 @@ function createOnRequestPermission(deps) {
|
|
|
40404
40424
|
}
|
|
40405
40425
|
log.warn("acpRunner", "AUTO mode \u2014 no allow option offered; falling back to interactive");
|
|
40406
40426
|
}
|
|
40407
|
-
const { event,
|
|
40427
|
+
const { event, options } = mapPermissionRequest(request2);
|
|
40408
40428
|
await deps.publisher.publishAwaitingAnswer(event);
|
|
40409
|
-
return deps.registerPermission({
|
|
40410
|
-
questionId: event.questionId,
|
|
40411
|
-
labels: event.options ?? [],
|
|
40412
|
-
optionIdByLabel
|
|
40413
|
-
});
|
|
40429
|
+
return deps.registerPermission({ questionId: event.questionId, options });
|
|
40414
40430
|
};
|
|
40415
40431
|
}
|
|
40416
40432
|
|
|
@@ -43172,20 +43188,19 @@ async function selectOptionH(ctx) {
|
|
|
43172
43188
|
const { cmd, client: client3, relay, streaming, history, budgetRecovery } = ctx;
|
|
43173
43189
|
const payload = cmd.payload;
|
|
43174
43190
|
const index = typeof payload?.index === "number" ? payload.index : 0;
|
|
43175
|
-
const
|
|
43176
|
-
|
|
43177
|
-
|
|
43178
|
-
const result = streaming.resolveSelection(absoluteIndex);
|
|
43191
|
+
const optionId = typeof payload?.optionId === "string" && payload.optionId.length > 0 ? payload.optionId : typeof payload?.answer === "string" && payload.answer.length > 0 ? payload.answer : void 0;
|
|
43192
|
+
if (await budgetRecovery.tryRecover(cmd.id, index)) return;
|
|
43193
|
+
const result = streaming.resolveSelection(index, optionId);
|
|
43179
43194
|
switch (result.kind) {
|
|
43180
43195
|
case "resolved":
|
|
43181
|
-
log.info("acpRunner", `select_option index=${absoluteIndex} \u2192 permission resolved`);
|
|
43182
|
-
await relay.sendResult(cmd.id, "completed", {});
|
|
43183
|
-
return;
|
|
43184
|
-
case "reprompt": {
|
|
43185
43196
|
log.info(
|
|
43186
43197
|
"acpRunner",
|
|
43187
|
-
`select_option index=${
|
|
43198
|
+
`select_option index=${index} \u2192 permission resolved optionId=${result.optionId ?? "cancelled"}`
|
|
43188
43199
|
);
|
|
43200
|
+
await relay.sendResult(cmd.id, "completed", {});
|
|
43201
|
+
return;
|
|
43202
|
+
case "reprompt": {
|
|
43203
|
+
log.info("acpRunner", `select_option index=${index} \u2192 reprompt chars=${result.text.length}`);
|
|
43189
43204
|
await streaming.beginTurn();
|
|
43190
43205
|
history.appendUserPrompt(result.text);
|
|
43191
43206
|
try {
|
|
@@ -43205,7 +43220,7 @@ async function selectOptionH(ctx) {
|
|
|
43205
43220
|
case "none":
|
|
43206
43221
|
log.warn(
|
|
43207
43222
|
"acpRunner",
|
|
43208
|
-
`select_option index=${
|
|
43223
|
+
`select_option index=${index} arrived with no pending question \u2014 likely stale`
|
|
43209
43224
|
);
|
|
43210
43225
|
await relay.sendResult(cmd.id, "failed", {
|
|
43211
43226
|
error: "No pending interactive question \u2014 the prompt may have expired."
|
|
@@ -43643,9 +43658,17 @@ var StreamingState = class {
|
|
|
43643
43658
|
turnSeq = 0;
|
|
43644
43659
|
/**
|
|
43645
43660
|
* Register a permission Promise. The Promise stays pending until
|
|
43646
|
-
* `resolveSelection(
|
|
43647
|
-
*
|
|
43648
|
-
*
|
|
43661
|
+
* `resolveSelection()` is called from the relay handler, OR the
|
|
43662
|
+
* safety timer fires after PERMISSION_TIMEOUT_MS and we auto-cancel.
|
|
43663
|
+
* Caller is the SDK's `onRequestPermission`.
|
|
43664
|
+
*
|
|
43665
|
+
* The auto-cancel is NEVER silent (same HARD RULE as the auto-denies
|
|
43666
|
+
* in ./permission-gate.ts): a visible chat line says the request
|
|
43667
|
+
* expired. The adapter reports a cancel to the model as a failed tool
|
|
43668
|
+
* ("Tool use aborted"), which the model then narrates as a refusal —
|
|
43669
|
+
* replay 01a08b05 (2026-09-10): two prompts expired while the user was
|
|
43670
|
+
* in the preview, Claude told him HE had refused them twice, and he
|
|
43671
|
+
* protested "J'ai rien refusé". The line is the user's evidence.
|
|
43649
43672
|
*/
|
|
43650
43673
|
registerPermission(args2) {
|
|
43651
43674
|
return new Promise((resolve11) => {
|
|
@@ -43656,14 +43679,18 @@ var StreamingState = class {
|
|
|
43656
43679
|
`permission ${args2.questionId.slice(0, 8)} TTL expired \u2014 auto-cancel`
|
|
43657
43680
|
);
|
|
43658
43681
|
this.pending = null;
|
|
43682
|
+
void this.publisher.publishOutput({
|
|
43683
|
+
type: "text",
|
|
43684
|
+
content: permissionExpiredNotice(),
|
|
43685
|
+
done: true
|
|
43686
|
+
});
|
|
43659
43687
|
resolve11({ outcome: { outcome: "cancelled" } });
|
|
43660
43688
|
}
|
|
43661
43689
|
}, PERMISSION_TIMEOUT_MS);
|
|
43662
43690
|
this.pending = {
|
|
43663
43691
|
kind: "permission",
|
|
43664
43692
|
questionId: args2.questionId,
|
|
43665
|
-
|
|
43666
|
-
optionIdByLabel: args2.optionIdByLabel,
|
|
43693
|
+
options: args2.options,
|
|
43667
43694
|
resolve: resolve11,
|
|
43668
43695
|
timeoutTimer
|
|
43669
43696
|
};
|
|
@@ -43683,28 +43710,33 @@ var StreamingState = class {
|
|
|
43683
43710
|
* routing instruction the runner uses to drive the next ACP RPC:
|
|
43684
43711
|
*
|
|
43685
43712
|
* - 'resolved' — permission Promise resolved; SDK is unblocked
|
|
43686
|
-
* and the runner just acks the relay command.
|
|
43713
|
+
* and the runner just acks the relay command. `optionId` is
|
|
43714
|
+
* what was answered (null = cancelled).
|
|
43687
43715
|
* - 'reprompt' — free-form selection; the runner must call
|
|
43688
43716
|
* `client.prompt(text)` with the returned text to send the
|
|
43689
43717
|
* user's pick to the adapter as a new turn.
|
|
43690
43718
|
* - 'none' — nothing pending; the runner acks the command as
|
|
43691
43719
|
* failed so mobile shows a stale-question affordance.
|
|
43720
|
+
*
|
|
43721
|
+
* For a permission, `optionId` (the wire `value` the client echoes
|
|
43722
|
+
* back) wins when it names one of the registered options; otherwise
|
|
43723
|
+
* `index` is the position in the options we put on the wire.
|
|
43692
43724
|
*/
|
|
43693
|
-
resolveSelection(index) {
|
|
43725
|
+
resolveSelection(index, optionId) {
|
|
43694
43726
|
if (!this.pending) return { kind: "none" };
|
|
43695
43727
|
if (this.pending.kind === "permission") {
|
|
43696
|
-
const
|
|
43697
|
-
const
|
|
43728
|
+
const byId = optionId ? this.pending.options.find((o) => o.optionId === optionId) : void 0;
|
|
43729
|
+
const picked = byId ?? this.pending.options[index];
|
|
43698
43730
|
clearTimeout(this.pending.timeoutTimer);
|
|
43699
43731
|
const resolve11 = this.pending.resolve;
|
|
43700
43732
|
this.pending = null;
|
|
43701
|
-
if (!
|
|
43733
|
+
if (!picked) {
|
|
43702
43734
|
log.warn("acpRunner", `select_option index=${index} out of bounds \u2014 cancel`);
|
|
43703
43735
|
resolve11({ outcome: { outcome: "cancelled" } });
|
|
43704
|
-
return { kind: "resolved" };
|
|
43736
|
+
return { kind: "resolved", optionId: null };
|
|
43705
43737
|
}
|
|
43706
|
-
resolve11({ outcome: { outcome: "selected", optionId } });
|
|
43707
|
-
return { kind: "resolved" };
|
|
43738
|
+
resolve11({ outcome: { outcome: "selected", optionId: picked.optionId } });
|
|
43739
|
+
return { kind: "resolved", optionId: picked.optionId };
|
|
43708
43740
|
}
|
|
43709
43741
|
const text = this.pending.options[index];
|
|
43710
43742
|
this.pending = null;
|
|
@@ -43968,6 +44000,10 @@ var StreamingState = class {
|
|
|
43968
44000
|
}
|
|
43969
44001
|
};
|
|
43970
44002
|
var PERMISSION_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
44003
|
+
function permissionExpiredNotice() {
|
|
44004
|
+
const minutes = Math.round(PERMISSION_TIMEOUT_MS / 6e4);
|
|
44005
|
+
return `\u23F1 A permission request expired after ${minutes} minutes with no answer, so CodeAgent cancelled it \u2014 this was a timeout, not a refusal by you. Ask the agent to try again and approve it from here.`;
|
|
44006
|
+
}
|
|
43971
44007
|
var AcpHistory = class {
|
|
43972
44008
|
constructor(publisher, opts) {
|
|
43973
44009
|
this.publisher = publisher;
|
|
@@ -46604,13 +46640,9 @@ async function runBatonSession(opts) {
|
|
|
46604
46640
|
beginLoadReplay: () => streaming.beginLoadReplay(),
|
|
46605
46641
|
endLoadReplay: () => streaming.endLoadReplay(),
|
|
46606
46642
|
onRequestPermission: async (request2) => {
|
|
46607
|
-
const { event,
|
|
46643
|
+
const { event, options } = mapPermissionRequest(request2);
|
|
46608
46644
|
await publisher.publishAwaitingAnswer(event);
|
|
46609
|
-
return streaming.registerPermission({
|
|
46610
|
-
questionId: event.questionId,
|
|
46611
|
-
labels: event.options ?? [],
|
|
46612
|
-
optionIdByLabel
|
|
46613
|
-
});
|
|
46645
|
+
return streaming.registerPermission({ questionId: event.questionId, options });
|
|
46614
46646
|
},
|
|
46615
46647
|
onStderr: (line) => {
|
|
46616
46648
|
recentStderr.push(line);
|
|
@@ -49825,7 +49857,7 @@ function checkChokidar() {
|
|
|
49825
49857
|
}
|
|
49826
49858
|
async function doctor(args2 = []) {
|
|
49827
49859
|
const json = args2.includes("--json");
|
|
49828
|
-
const cliVersion = true ? "2.74.
|
|
49860
|
+
const cliVersion = true ? "2.74.14" : "0.0.0-dev";
|
|
49829
49861
|
const apiBase2 = resolveApiBaseUrl();
|
|
49830
49862
|
const diagnosticId = (0, import_node_crypto13.randomUUID)();
|
|
49831
49863
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -50349,7 +50381,7 @@ async function mcpWarm(argv = [], opts = {}) {
|
|
|
50349
50381
|
// src/commands/version.ts
|
|
50350
50382
|
var import_picocolors15 = __toESM(require("picocolors"));
|
|
50351
50383
|
function version2() {
|
|
50352
|
-
const v = true ? "2.74.
|
|
50384
|
+
const v = true ? "2.74.14" : "unknown";
|
|
50353
50385
|
console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
|
|
50354
50386
|
}
|
|
50355
50387
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.74.
|
|
3
|
+
"version": "2.74.14",
|
|
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",
|