codeam-cli 2.75.13 → 2.75.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 +11 -0
- package/dist/index.js +96 -19
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,17 @@ 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.75.13] — 2026-09-24
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **cli:** Attribute provider 402s — routing in the debug log, BYO no-credits bubble, pack fail
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **cli:** Host-agent resumes every session live at shutdown, bounded, not just the last one
|
|
16
|
+
- **cli:** Collapse `bd prime` tool result so its docs tail no longer shows under the reply
|
|
17
|
+
|
|
7
18
|
## [2.75.12] — 2026-09-24
|
|
8
19
|
|
|
9
20
|
### Fixed
|
package/dist/index.js
CHANGED
|
@@ -10509,7 +10509,7 @@ function readAnonId() {
|
|
|
10509
10509
|
}
|
|
10510
10510
|
function superProperties() {
|
|
10511
10511
|
return {
|
|
10512
|
-
cliVersion: true ? "2.75.
|
|
10512
|
+
cliVersion: true ? "2.75.14" : "0.0.0-dev",
|
|
10513
10513
|
nodeVersion: process.version,
|
|
10514
10514
|
platform: process.platform,
|
|
10515
10515
|
arch: process.arch,
|
|
@@ -10751,7 +10751,7 @@ var http = __toESM(require("http"));
|
|
|
10751
10751
|
// package.json
|
|
10752
10752
|
var package_default = {
|
|
10753
10753
|
name: "codeam-cli",
|
|
10754
|
-
version: "2.75.
|
|
10754
|
+
version: "2.75.14",
|
|
10755
10755
|
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.",
|
|
10756
10756
|
type: "commonjs",
|
|
10757
10757
|
main: "dist/index.js",
|
|
@@ -12081,7 +12081,7 @@ var CommandRelayService = class _CommandRelayService {
|
|
|
12081
12081
|
// fresh + clear the "CLI update available" banner after a self-update
|
|
12082
12082
|
// (a codespace that reinstalls @latest reconnects via heartbeat, not
|
|
12083
12083
|
// pair/reconnect). Older backends ignore the extra field.
|
|
12084
|
-
..."2.75.
|
|
12084
|
+
..."2.75.14" ? { ideVersion: "2.75.14" } : {}
|
|
12085
12085
|
};
|
|
12086
12086
|
try {
|
|
12087
12087
|
const res = await _postJson(`${API_BASE2}/api/plugin/heartbeat`, body);
|
|
@@ -16510,9 +16510,13 @@ def onwinch(n,f):
|
|
|
16510
16510
|
sz=os.get_terminal_size(2)
|
|
16511
16511
|
fcntl.ioctl(m,termios.TIOCSWINSZ,struct.pack('HHHH',sz.lines,sz.columns,0,0))
|
|
16512
16512
|
except Exception:pass
|
|
16513
|
+
def onterm(n,f):
|
|
16514
|
+
done[0]=True
|
|
16513
16515
|
signal.signal(signal.SIGCHLD,onchld)
|
|
16514
16516
|
signal.signal(signal.SIGWINCH,onwinch)
|
|
16515
16517
|
signal.signal(signal.SIGHUP,signal.SIG_IGN)
|
|
16518
|
+
signal.signal(signal.SIGTERM,onterm)
|
|
16519
|
+
signal.signal(signal.SIGINT,onterm)
|
|
16516
16520
|
i=sys.stdin.fileno()
|
|
16517
16521
|
o=sys.stdout.fileno()
|
|
16518
16522
|
while not done[0]:
|
|
@@ -16533,10 +16537,20 @@ while not done[0]:
|
|
|
16533
16537
|
except OSError:done[0]=True
|
|
16534
16538
|
try:os.kill(pid,signal.SIGTERM)
|
|
16535
16539
|
except Exception:pass
|
|
16536
|
-
|
|
16537
|
-
|
|
16538
|
-
|
|
16539
|
-
|
|
16540
|
+
import time
|
|
16541
|
+
t0=time.time()
|
|
16542
|
+
while True:
|
|
16543
|
+
try:w,st=os.waitpid(pid,os.WNOHANG)
|
|
16544
|
+
except ChildProcessError:sys.exit(0)
|
|
16545
|
+
except Exception:sys.exit(0)
|
|
16546
|
+
if w==pid:sys.exit((st>>8)&0xFF)
|
|
16547
|
+
if time.time()-t0>5:
|
|
16548
|
+
try:os.kill(pid,signal.SIGKILL)
|
|
16549
|
+
except Exception:pass
|
|
16550
|
+
try:os.waitpid(pid,0)
|
|
16551
|
+
except Exception:pass
|
|
16552
|
+
sys.exit(137)
|
|
16553
|
+
time.sleep(0.05)
|
|
16540
16554
|
`;
|
|
16541
16555
|
var UnixPtyStrategy = class {
|
|
16542
16556
|
constructor(opts) {
|
|
@@ -16653,11 +16667,42 @@ var UnixPtyStrategy = class {
|
|
|
16653
16667
|
this.proc?.stdin?.write(data);
|
|
16654
16668
|
}
|
|
16655
16669
|
kill() {
|
|
16670
|
+
void this.killAndWait();
|
|
16671
|
+
}
|
|
16672
|
+
/**
|
|
16673
|
+
* SIGTERM the helper and resolve once it has EXITED (bounded; SIGKILL
|
|
16674
|
+
* fallback). The helper forwards the signal to the agent and waits for it,
|
|
16675
|
+
* so when this resolves the agent process is gone too.
|
|
16676
|
+
*
|
|
16677
|
+
* ⚠️ Why awaited (2026-09-24): the helper used to die under SIGTERM with no
|
|
16678
|
+
* handler, leaving the agent orphaned; on a baton hand-off and in the
|
|
16679
|
+
* baton integration suite the orphaned Claude exited a beat later and
|
|
16680
|
+
* rewrote `~/.claude.json` from memory, clobbering the just-written
|
|
16681
|
+
* workspace-trust entry for the NEXT session — which then wedged on the
|
|
16682
|
+
* trust dialog (CI run 35946818546). Callers that start a new agent or a
|
|
16683
|
+
* new session must `await` this.
|
|
16684
|
+
*/
|
|
16685
|
+
async killAndWait(timeoutMs = 6e3) {
|
|
16656
16686
|
const proc = this.proc;
|
|
16657
16687
|
this.proc = null;
|
|
16658
16688
|
if (proc) {
|
|
16659
16689
|
proc.removeAllListeners("exit");
|
|
16660
|
-
|
|
16690
|
+
const exited = new Promise((resolve12) => {
|
|
16691
|
+
if (proc.exitCode !== null || proc.signalCode !== null) return resolve12();
|
|
16692
|
+
proc.once("exit", () => resolve12());
|
|
16693
|
+
});
|
|
16694
|
+
proc.kill("SIGTERM");
|
|
16695
|
+
const timer = new Promise((resolve12) => {
|
|
16696
|
+
const t2 = setTimeout(() => resolve12("timeout"), timeoutMs);
|
|
16697
|
+
void exited.then(() => clearTimeout(t2));
|
|
16698
|
+
});
|
|
16699
|
+
if (await Promise.race([exited, timer]) === "timeout") {
|
|
16700
|
+
try {
|
|
16701
|
+
proc.kill("SIGKILL");
|
|
16702
|
+
} catch {
|
|
16703
|
+
}
|
|
16704
|
+
await Promise.race([exited, new Promise((r) => setTimeout(r, 1e3))]);
|
|
16705
|
+
}
|
|
16661
16706
|
}
|
|
16662
16707
|
this.removeTempFile();
|
|
16663
16708
|
this.dispose();
|
|
@@ -16847,6 +16892,9 @@ var WindowsConPtyStrategy = class _WindowsConPtyStrategy {
|
|
|
16847
16892
|
if (!this.pty) return;
|
|
16848
16893
|
this.pty.write(typeof data === "string" ? data : data.toString("utf8"));
|
|
16849
16894
|
}
|
|
16895
|
+
async killAndWait() {
|
|
16896
|
+
this.kill();
|
|
16897
|
+
}
|
|
16850
16898
|
kill() {
|
|
16851
16899
|
try {
|
|
16852
16900
|
this.pty?.kill();
|
|
@@ -16927,6 +16975,9 @@ var WindowsPtyStrategy = class {
|
|
|
16927
16975
|
this.proc?.kill();
|
|
16928
16976
|
this.dispose();
|
|
16929
16977
|
}
|
|
16978
|
+
async killAndWait() {
|
|
16979
|
+
this.kill();
|
|
16980
|
+
}
|
|
16930
16981
|
dispose() {
|
|
16931
16982
|
process.stdin.removeListener("data", this.stdinHandler);
|
|
16932
16983
|
if (process.stdin.isTTY) {
|
|
@@ -26515,7 +26566,7 @@ var resumeSession = async (ctx, _cmd, parsed) => {
|
|
|
26515
26566
|
ctx.historySvc.setCurrentConversationId(id);
|
|
26516
26567
|
await ctx.historySvc.loadConversation(id);
|
|
26517
26568
|
await ctx.outputSvc.newTurnResume(id);
|
|
26518
|
-
ctx.agent.restart(id, auto ?? false);
|
|
26569
|
+
void ctx.agent.restart(id, auto ?? false);
|
|
26519
26570
|
};
|
|
26520
26571
|
var getContext = async (ctx, cmd) => {
|
|
26521
26572
|
const usage = ctx.historySvc.getCurrentUsage();
|
|
@@ -28748,6 +28799,10 @@ var AgentService = class _AgentService {
|
|
|
28748
28799
|
kill() {
|
|
28749
28800
|
this.strategy?.kill();
|
|
28750
28801
|
}
|
|
28802
|
+
/** Kill and resolve once the agent process is gone (see `IPtyStrategy.killAndWait`). */
|
|
28803
|
+
async killAndWait() {
|
|
28804
|
+
await this.strategy?.killAndWait();
|
|
28805
|
+
}
|
|
28751
28806
|
/**
|
|
28752
28807
|
* Kill the current Claude process and relaunch it resuming the given session.
|
|
28753
28808
|
* Pass auto=true to add --dangerously-skip-permissions (no confirmation prompts).
|
|
@@ -28757,7 +28812,7 @@ var AgentService = class _AgentService {
|
|
|
28757
28812
|
* For agents that use a post-spawn PTY instruction (e.g. Codex), `resumeLaunchArgs`
|
|
28758
28813
|
* returns [] and `postSpawnInstruction` types the resume command into the PTY.
|
|
28759
28814
|
*/
|
|
28760
|
-
restart(sessionId, auto = false) {
|
|
28815
|
+
async restart(sessionId, auto = false) {
|
|
28761
28816
|
if (!this.strategy || !this.initialLaunch) return;
|
|
28762
28817
|
const resumeArgs = this.runtime.resumeLaunchArgs(sessionId, { auto });
|
|
28763
28818
|
const launch = this.runtime.prepareResumeLaunch?.(sessionId, { auto }) ?? {
|
|
@@ -28769,7 +28824,7 @@ var AgentService = class _AgentService {
|
|
|
28769
28824
|
clearTimeout(this.quietTimer);
|
|
28770
28825
|
this.quietTimer = null;
|
|
28771
28826
|
}
|
|
28772
|
-
this.strategy.
|
|
28827
|
+
await this.strategy.killAndWait();
|
|
28773
28828
|
this.strategy.spawn(launch.cmd, this.opts.cwd, launch.args);
|
|
28774
28829
|
if (resumeArgs.length === 0 && this.runtime.postSpawnInstruction) {
|
|
28775
28830
|
const { ptyInput } = this.runtime.postSpawnInstruction(sessionId);
|
|
@@ -40507,6 +40562,16 @@ var StreamingState = class {
|
|
|
40507
40562
|
* no matter how many message ids the adapter spreads it across.
|
|
40508
40563
|
*/
|
|
40509
40564
|
turnTextChunkId = null;
|
|
40565
|
+
/**
|
|
40566
|
+
* Adapter message id of the LAST text delta appended this turn. A text delta
|
|
40567
|
+
* under a NEW message id that appends (not a snapshot re-emit) is a new
|
|
40568
|
+
* paragraph — Codex emits several `agent_message_chunk` messages per turn
|
|
40569
|
+
* around tool calls ('…run every gate.' → tools → 'I'm resuming at…') and,
|
|
40570
|
+
* collapsed onto `turnTextChunkId`, they glued into 'gate.I'm resuming'
|
|
40571
|
+
* (replay 2026-09-23, bead codeagent-wqpi). Both feeds carry the joined
|
|
40572
|
+
* string, so the boundary can only be restored here.
|
|
40573
|
+
*/
|
|
40574
|
+
lastTextMessageId = null;
|
|
40510
40575
|
/**
|
|
40511
40576
|
* Stable chunkId that ALL `thinking` segments of the current turn collapse
|
|
40512
40577
|
* onto (set to the first thought chunk's id, reset each {@link beginTurn}) —
|
|
@@ -40675,6 +40740,7 @@ var StreamingState = class {
|
|
|
40675
40740
|
this.text = "";
|
|
40676
40741
|
this.streamingChunks.clear();
|
|
40677
40742
|
this.turnTextChunkId = null;
|
|
40743
|
+
this.lastTextMessageId = null;
|
|
40678
40744
|
this.turnThoughtChunkId = null;
|
|
40679
40745
|
this.turnSeq += 1;
|
|
40680
40746
|
if (this.pending?.kind === "permission") {
|
|
@@ -40707,7 +40773,18 @@ var StreamingState = class {
|
|
|
40707
40773
|
`streaming-chunk kind flip chunkId=${chunkId.slice(0, 8)} from=${existing.kind} to=${delta.kind}`
|
|
40708
40774
|
);
|
|
40709
40775
|
}
|
|
40710
|
-
const
|
|
40776
|
+
const prior = existing?.content ?? "";
|
|
40777
|
+
let cumulativeContent = reconcileCumulative(prior, delta.delta);
|
|
40778
|
+
if (delta.kind === "text") {
|
|
40779
|
+
const newMessage = this.lastTextMessageId !== null && this.lastTextMessageId !== delta.chunkId;
|
|
40780
|
+
const appended = cumulativeContent === prior + delta.delta;
|
|
40781
|
+
if (newMessage && appended && /\S$/.test(prior) && !/^\s/.test(delta.delta)) {
|
|
40782
|
+
cumulativeContent = `${prior}
|
|
40783
|
+
|
|
40784
|
+
${delta.delta}`;
|
|
40785
|
+
}
|
|
40786
|
+
this.lastTextMessageId = delta.chunkId;
|
|
40787
|
+
}
|
|
40711
40788
|
this.streamingChunks.set(chunkId, { kind: delta.kind, content: cumulativeContent });
|
|
40712
40789
|
let fenceCut = -1;
|
|
40713
40790
|
let textVisible = null;
|
|
@@ -43181,7 +43258,7 @@ var NativeTuiDriver = class _NativeTuiDriver {
|
|
|
43181
43258
|
async stop() {
|
|
43182
43259
|
this.unwatchSwitch?.();
|
|
43183
43260
|
this.unwatchSwitch = null;
|
|
43184
|
-
this.agent.
|
|
43261
|
+
await this.agent.killAndWait();
|
|
43185
43262
|
parkTerminalForReadonly();
|
|
43186
43263
|
}
|
|
43187
43264
|
async dispatch(cmd) {
|
|
@@ -43733,7 +43810,7 @@ async function runBatonSession(opts) {
|
|
|
43733
43810
|
process.removeListener("SIGTERM", onSignal);
|
|
43734
43811
|
process.removeListener("SIGHUP", onSignal);
|
|
43735
43812
|
mirror?.stop();
|
|
43736
|
-
|
|
43813
|
+
await controller.shutdown();
|
|
43737
43814
|
await stopRelayWithGoodbye(relay);
|
|
43738
43815
|
}
|
|
43739
43816
|
const onSignal = () => {
|
|
@@ -47512,7 +47589,7 @@ async function autoUpgradeBeforeCriticalCommand() {
|
|
|
47512
47589
|
if (process.env.NODE_ENV === "test") return;
|
|
47513
47590
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
47514
47591
|
if (process.env.CI) return;
|
|
47515
|
-
const current2 = true ? "2.75.
|
|
47592
|
+
const current2 = true ? "2.75.14" : null;
|
|
47516
47593
|
if (!current2) return;
|
|
47517
47594
|
const cache = readCache();
|
|
47518
47595
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -47529,7 +47606,7 @@ function checkForUpdates() {
|
|
|
47529
47606
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
47530
47607
|
if (process.env.CI) return;
|
|
47531
47608
|
if (!process.stdout.isTTY) return;
|
|
47532
|
-
const current2 = true ? "2.75.
|
|
47609
|
+
const current2 = true ? "2.75.14" : null;
|
|
47533
47610
|
if (!current2) return;
|
|
47534
47611
|
const cache = readCache();
|
|
47535
47612
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -47552,7 +47629,7 @@ var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
|
|
|
47552
47629
|
var SELF_UPDATE_LS_TIMEOUT_MS = 15e3;
|
|
47553
47630
|
var SUDO_PREFLIGHT_TIMEOUT_MS = 5e3;
|
|
47554
47631
|
function currentCliVersion() {
|
|
47555
|
-
return true ? "2.75.
|
|
47632
|
+
return true ? "2.75.14" : null;
|
|
47556
47633
|
}
|
|
47557
47634
|
async function installedVersion(deps) {
|
|
47558
47635
|
const ls = await deps.run(
|
|
@@ -49413,7 +49490,7 @@ function checkChokidar() {
|
|
|
49413
49490
|
}
|
|
49414
49491
|
async function doctor(args2 = []) {
|
|
49415
49492
|
const json = args2.includes("--json");
|
|
49416
|
-
const cliVersion = true ? "2.75.
|
|
49493
|
+
const cliVersion = true ? "2.75.14" : "0.0.0-dev";
|
|
49417
49494
|
const apiBase2 = resolveApiBaseUrl();
|
|
49418
49495
|
const diagnosticId = (0, import_node_crypto12.randomUUID)();
|
|
49419
49496
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -49937,7 +50014,7 @@ async function mcpWarm(argv = [], opts = {}) {
|
|
|
49937
50014
|
// src/commands/version.ts
|
|
49938
50015
|
var import_picocolors15 = __toESM(require("picocolors"));
|
|
49939
50016
|
function version2() {
|
|
49940
|
-
const v = true ? "2.75.
|
|
50017
|
+
const v = true ? "2.75.14" : "unknown";
|
|
49941
50018
|
console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
|
|
49942
50019
|
}
|
|
49943
50020
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.75.
|
|
3
|
+
"version": "2.75.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",
|