codeam-cli 2.73.3 → 2.73.5
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 +140 -25
- 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.73.4] — 2026-09-03
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **cli:** MCP startup budget that fits our shim + stop the baton mirror replaying history as live turns (#686)
|
|
12
|
+
|
|
13
|
+
## [2.73.3] — 2026-09-02
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- **cli:** Debounce MCP reprovisions so a run of changes costs ONE respawn (#684)
|
|
18
|
+
|
|
7
19
|
## [2.73.2] — 2026-09-02
|
|
8
20
|
|
|
9
21
|
### CI
|
package/dist/index.js
CHANGED
|
@@ -1872,8 +1872,27 @@ var INTEGRATION_REGISTRY = {
|
|
|
1872
1872
|
mcp: {
|
|
1873
1873
|
// Postman's OFFICIAL stdio MCP server (Node). BYO key via POSTMAN_API_KEY
|
|
1874
1874
|
// (env only). Version PINNED; bump only after re-verifying headless.
|
|
1875
|
+
//
|
|
1876
|
+
// ⚠️ `--ignore-scripts` IS LOAD-BEARING — without it this integration
|
|
1877
|
+
// does not work at all, on any box, and never did. The package declares
|
|
1878
|
+
// a `preinstall` guard of `npx only-allow pnpm`, so npm REFUSES to
|
|
1879
|
+
// install it:
|
|
1880
|
+
// info run @postman/postman-mcp-server@2.11.2 preinstall npx only-allow pnpm
|
|
1881
|
+
// info run @postman/postman-mcp-server@2.11.2 preinstall { code: 1 }
|
|
1882
|
+
// and `npx -y @postman/postman-mcp-server@2.11.2` exits 1 before the
|
|
1883
|
+
// server is ever reached — which the agent reports as
|
|
1884
|
+
// `Server "postman" is not connected`, indistinguishable from a slow
|
|
1885
|
+
// start (found while pre-warming the box image, 2026-09-03; the user's
|
|
1886
|
+
// report was "Postman: idem", alongside clickup/trello, whose cause was
|
|
1887
|
+
// entirely different).
|
|
1888
|
+
//
|
|
1889
|
+
// Skipping scripts is safe here: the guard is the only preinstall step
|
|
1890
|
+
// and the published tarball already ships the built
|
|
1891
|
+
// `dist/src/index.js` its `bin` points at. Verified on node:22-slim:
|
|
1892
|
+
// `npx -y <pkg>` → exit 1; `npx -y --ignore-scripts <pkg>` with a key in
|
|
1893
|
+
// the env → starts; and warmed once, the bin resolves offline.
|
|
1875
1894
|
command: "npx",
|
|
1876
|
-
args: ["-y", "@postman/postman-mcp-server@2.11.2"],
|
|
1895
|
+
args: ["-y", "--ignore-scripts", "@postman/postman-mcp-server@2.11.2"],
|
|
1877
1896
|
envMapping: {
|
|
1878
1897
|
POSTMAN_API_KEY: "accessToken"
|
|
1879
1898
|
}
|
|
@@ -8097,7 +8116,7 @@ function readAnonId() {
|
|
|
8097
8116
|
}
|
|
8098
8117
|
function superProperties() {
|
|
8099
8118
|
return {
|
|
8100
|
-
cliVersion: true ? "2.73.
|
|
8119
|
+
cliVersion: true ? "2.73.5" : "0.0.0-dev",
|
|
8101
8120
|
nodeVersion: process.version,
|
|
8102
8121
|
platform: process.platform,
|
|
8103
8122
|
arch: process.arch,
|
|
@@ -8339,7 +8358,7 @@ var http = __toESM(require("http"));
|
|
|
8339
8358
|
// package.json
|
|
8340
8359
|
var package_default = {
|
|
8341
8360
|
name: "codeam-cli",
|
|
8342
|
-
version: "2.73.
|
|
8361
|
+
version: "2.73.5",
|
|
8343
8362
|
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.",
|
|
8344
8363
|
type: "commonjs",
|
|
8345
8364
|
main: "dist/index.js",
|
|
@@ -9932,7 +9951,7 @@ var CommandRelayService = class _CommandRelayService {
|
|
|
9932
9951
|
// fresh + clear the "CLI update available" banner after a self-update
|
|
9933
9952
|
// (a codespace that reinstalls @latest reconnects via heartbeat, not
|
|
9934
9953
|
// pair/reconnect). Older backends ignore the extra field.
|
|
9935
|
-
..."2.73.
|
|
9954
|
+
..."2.73.5" ? { ideVersion: "2.73.5" } : {}
|
|
9936
9955
|
}).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
|
|
9937
9956
|
}
|
|
9938
9957
|
/**
|
|
@@ -22208,7 +22227,7 @@ async function autoUpgradeBeforeCriticalCommand() {
|
|
|
22208
22227
|
if (process.env.NODE_ENV === "test") return;
|
|
22209
22228
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
22210
22229
|
if (process.env.CI) return;
|
|
22211
|
-
const current2 = true ? "2.73.
|
|
22230
|
+
const current2 = true ? "2.73.5" : null;
|
|
22212
22231
|
if (!current2) return;
|
|
22213
22232
|
const cache = readCache();
|
|
22214
22233
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -22225,7 +22244,7 @@ function checkForUpdates() {
|
|
|
22225
22244
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
22226
22245
|
if (process.env.CI) return;
|
|
22227
22246
|
if (!process.stdout.isTTY) return;
|
|
22228
|
-
const current2 = true ? "2.73.
|
|
22247
|
+
const current2 = true ? "2.73.5" : null;
|
|
22229
22248
|
if (!current2) return;
|
|
22230
22249
|
const cache = readCache();
|
|
22231
22250
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -22248,7 +22267,7 @@ var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
|
|
|
22248
22267
|
var SELF_UPDATE_LS_TIMEOUT_MS = 15e3;
|
|
22249
22268
|
var SUDO_PREFLIGHT_TIMEOUT_MS = 5e3;
|
|
22250
22269
|
function currentCliVersion() {
|
|
22251
|
-
return true ? "2.73.
|
|
22270
|
+
return true ? "2.73.5" : null;
|
|
22252
22271
|
}
|
|
22253
22272
|
async function installedVersion(deps) {
|
|
22254
22273
|
const ls = await deps.run(
|
|
@@ -35677,6 +35696,7 @@ var _acpStartSeam = {
|
|
|
35677
35696
|
var PROTOCOL_VERSION3 = 1;
|
|
35678
35697
|
var FATAL_STARTUP_RE = /IneligibleTierError|UNSUPPORTED_CLIENT|no longer supported for Gemini Code Assist|not eligible for Gemini Code Assist|Error authenticating|ProjectIdRequiredError/i;
|
|
35679
35698
|
var NEWSESSION_TIMEOUT_MS = 12e4;
|
|
35699
|
+
var MCP_STARTUP_TIMEOUT_MS = NEWSESSION_TIMEOUT_MS - 3e4;
|
|
35680
35700
|
var LOADSESSION_TIMEOUT_MS = 6e4;
|
|
35681
35701
|
var PROMPT_IDLE_TIMEOUT_MS = 9e4;
|
|
35682
35702
|
var PROMPT_ACTIVE_IDLE_TIMEOUT_MS = 6e5;
|
|
@@ -35855,7 +35875,15 @@ var AcpClient = class {
|
|
|
35855
35875
|
// extraEnv (e.g. CLAUDE_CODE_DISABLE_1M_CONTEXT=1 on an on-demand
|
|
35856
35876
|
// re-spawn) layers over process.env; PATH stays last so the augmented
|
|
35857
35877
|
// PATH always wins.
|
|
35858
|
-
|
|
35878
|
+
//
|
|
35879
|
+
// MCP_TIMEOUT comes FIRST so the caller can still override it, and it is
|
|
35880
|
+
// load-bearing — see MCP_STARTUP_TIMEOUT_MS.
|
|
35881
|
+
env: {
|
|
35882
|
+
...process.env,
|
|
35883
|
+
MCP_TIMEOUT: String(MCP_STARTUP_TIMEOUT_MS),
|
|
35884
|
+
...this.opts.extraEnv ?? {},
|
|
35885
|
+
PATH: augmentedPath
|
|
35886
|
+
},
|
|
35859
35887
|
stdio: ["pipe", "pipe", "pipe"]
|
|
35860
35888
|
});
|
|
35861
35889
|
this.child = child;
|
|
@@ -43702,12 +43730,22 @@ var TranscriptMirror = class {
|
|
|
43702
43730
|
unwatch = null;
|
|
43703
43731
|
pollHandle = null;
|
|
43704
43732
|
attached = false;
|
|
43733
|
+
/** True while `start()`'s own synchronous attach attempt is running, so
|
|
43734
|
+
* `tryAttach` can tell "the file was already there" from "it appeared while
|
|
43735
|
+
* we waited". The distinction is the whole basis for whether the first
|
|
43736
|
+
* batch is history or live content. */
|
|
43737
|
+
attachingAtStart = false;
|
|
43705
43738
|
pollIntervalMs;
|
|
43706
43739
|
waitTimeoutMs;
|
|
43707
43740
|
setIntervalFn;
|
|
43708
43741
|
clearIntervalFn;
|
|
43709
43742
|
start() {
|
|
43710
|
-
|
|
43743
|
+
this.attachingAtStart = true;
|
|
43744
|
+
try {
|
|
43745
|
+
if (this.tryAttach()) return;
|
|
43746
|
+
} finally {
|
|
43747
|
+
this.attachingAtStart = false;
|
|
43748
|
+
}
|
|
43711
43749
|
let waited = 0;
|
|
43712
43750
|
this.pollHandle = this.setIntervalFn(() => {
|
|
43713
43751
|
waited += this.pollIntervalMs;
|
|
@@ -43730,7 +43768,7 @@ var TranscriptMirror = class {
|
|
|
43730
43768
|
const file = this.deps.runtime.resolveHistoryFile?.(this.deps.cwd, this.deps.conversationId);
|
|
43731
43769
|
if (!file) return false;
|
|
43732
43770
|
this.attached = true;
|
|
43733
|
-
this.emit(file);
|
|
43771
|
+
this.emit(file, this.attachingAtStart);
|
|
43734
43772
|
const watch4 = this.deps.watch ?? defaultWatch;
|
|
43735
43773
|
this.unwatch = watch4(file, () => this.emit(file));
|
|
43736
43774
|
return true;
|
|
@@ -43741,7 +43779,7 @@ var TranscriptMirror = class {
|
|
|
43741
43779
|
this.pollHandle = null;
|
|
43742
43780
|
}
|
|
43743
43781
|
}
|
|
43744
|
-
emit(file) {
|
|
43782
|
+
emit(file, preexisting = false) {
|
|
43745
43783
|
let all;
|
|
43746
43784
|
try {
|
|
43747
43785
|
all = this.deps.runtime.parseHistoryFile(file);
|
|
@@ -43751,7 +43789,7 @@ var TranscriptMirror = class {
|
|
|
43751
43789
|
if (all.length <= this.emitted) return;
|
|
43752
43790
|
const delta = all.slice(this.emitted);
|
|
43753
43791
|
this.emitted = all.length;
|
|
43754
|
-
this.deps.onNewMessages(delta);
|
|
43792
|
+
this.deps.onNewMessages(delta, { preexisting });
|
|
43755
43793
|
}
|
|
43756
43794
|
};
|
|
43757
43795
|
function defaultWatch(file, onChange) {
|
|
@@ -43803,10 +43841,9 @@ async function publishMirroredTurnsLive(publisher, messages) {
|
|
|
43803
43841
|
}
|
|
43804
43842
|
}
|
|
43805
43843
|
function makeMirrorOnNewMessages(deps) {
|
|
43806
|
-
let isFirstEmit = true;
|
|
43807
43844
|
let publishChain = Promise.resolve();
|
|
43808
43845
|
const conversation = [];
|
|
43809
|
-
return (messages) => {
|
|
43846
|
+
return (messages, meta) => {
|
|
43810
43847
|
const relevant = messages.filter((m) => m.role !== "system");
|
|
43811
43848
|
if (relevant.length === 0) return;
|
|
43812
43849
|
const mapped = relevant.map((m) => ({
|
|
@@ -43821,7 +43858,7 @@ function makeMirrorOnNewMessages(deps) {
|
|
|
43821
43858
|
sessionId: deps.conversationId,
|
|
43822
43859
|
messages: conversation.slice()
|
|
43823
43860
|
});
|
|
43824
|
-
if (
|
|
43861
|
+
if (meta?.preexisting !== true) {
|
|
43825
43862
|
publishChain = publishChain.then(() => publishMirroredTurnsLive(deps.publisher, relevant)).catch((err) => {
|
|
43826
43863
|
log.warn(
|
|
43827
43864
|
"wireBaton",
|
|
@@ -43829,7 +43866,6 @@ function makeMirrorOnNewMessages(deps) {
|
|
|
43829
43866
|
);
|
|
43830
43867
|
});
|
|
43831
43868
|
}
|
|
43832
|
-
isFirstEmit = false;
|
|
43833
43869
|
};
|
|
43834
43870
|
}
|
|
43835
43871
|
function makeSerializedBatonPoster(post2) {
|
|
@@ -43956,9 +43992,8 @@ async function runBatonSession(opts) {
|
|
|
43956
43992
|
onConversationSwitch: (id) => controller.switchConversation(id)
|
|
43957
43993
|
});
|
|
43958
43994
|
let mirror = null;
|
|
43959
|
-
let firstLocalDrive = true;
|
|
43960
43995
|
let lastPublished = null;
|
|
43961
|
-
const startMirror = (conversationId
|
|
43996
|
+
const startMirror = (conversationId) => {
|
|
43962
43997
|
mirror?.stop();
|
|
43963
43998
|
mirror = new TranscriptMirror({
|
|
43964
43999
|
runtime,
|
|
@@ -43967,8 +44002,7 @@ async function runBatonSession(opts) {
|
|
|
43967
44002
|
onNewMessages: makeMirrorOnNewMessages({
|
|
43968
44003
|
publisher,
|
|
43969
44004
|
agentId: opts.agent,
|
|
43970
|
-
conversationId
|
|
43971
|
-
fresh
|
|
44005
|
+
conversationId
|
|
43972
44006
|
})
|
|
43973
44007
|
});
|
|
43974
44008
|
mirror.start();
|
|
@@ -43990,9 +44024,7 @@ async function runBatonSession(opts) {
|
|
|
43990
44024
|
publishState: (state, driver, conversationId) => {
|
|
43991
44025
|
publishBatonState(state, driver, conversationId);
|
|
43992
44026
|
if (state === "LOCAL_DRIVE" && conversationId) {
|
|
43993
|
-
|
|
43994
|
-
startMirror(conversationId, firstLocalDrive || switched);
|
|
43995
|
-
firstLocalDrive = false;
|
|
44027
|
+
startMirror(conversationId);
|
|
43996
44028
|
} else if (state !== "LOCAL_DRIVE") {
|
|
43997
44029
|
mirror?.stop();
|
|
43998
44030
|
}
|
|
@@ -47086,7 +47118,7 @@ function checkChokidar() {
|
|
|
47086
47118
|
}
|
|
47087
47119
|
async function doctor(args2 = []) {
|
|
47088
47120
|
const json = args2.includes("--json");
|
|
47089
|
-
const cliVersion = true ? "2.73.
|
|
47121
|
+
const cliVersion = true ? "2.73.5" : "0.0.0-dev";
|
|
47090
47122
|
const apiBase2 = resolveApiBaseUrl();
|
|
47091
47123
|
const diagnosticId = (0, import_node_crypto13.randomUUID)();
|
|
47092
47124
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -47474,10 +47506,90 @@ async function mcpRun(args2) {
|
|
|
47474
47506
|
await proxy.start();
|
|
47475
47507
|
}
|
|
47476
47508
|
|
|
47509
|
+
// src/integrations/mcp-warm.ts
|
|
47510
|
+
var import_node_child_process35 = require("child_process");
|
|
47511
|
+
function specOf(delivery) {
|
|
47512
|
+
if (!delivery.command) return null;
|
|
47513
|
+
const spec = (delivery.args ?? []).find((a) => !a.startsWith("-"));
|
|
47514
|
+
return spec ?? null;
|
|
47515
|
+
}
|
|
47516
|
+
function launcherFlagsOf(delivery) {
|
|
47517
|
+
const args2 = delivery.args ?? [];
|
|
47518
|
+
const specIndex = args2.findIndex((a) => !a.startsWith("-"));
|
|
47519
|
+
return specIndex === -1 ? [...args2] : args2.slice(0, specIndex);
|
|
47520
|
+
}
|
|
47521
|
+
function warmTargets() {
|
|
47522
|
+
const bySpec = /* @__PURE__ */ new Map();
|
|
47523
|
+
for (const integration of getEnabledIntegrations()) {
|
|
47524
|
+
const delivery = integration.delivery?.mcp;
|
|
47525
|
+
if (!delivery) continue;
|
|
47526
|
+
const spec = specOf(delivery);
|
|
47527
|
+
if (!spec) continue;
|
|
47528
|
+
if (!bySpec.has(spec)) {
|
|
47529
|
+
bySpec.set(spec, {
|
|
47530
|
+
id: integration.id,
|
|
47531
|
+
launcher: delivery.command,
|
|
47532
|
+
flags: launcherFlagsOf(delivery),
|
|
47533
|
+
spec
|
|
47534
|
+
});
|
|
47535
|
+
}
|
|
47536
|
+
}
|
|
47537
|
+
return [...bySpec.values()];
|
|
47538
|
+
}
|
|
47539
|
+
function warmCommand(target) {
|
|
47540
|
+
if (target.launcher === "npx") {
|
|
47541
|
+
const extra = target.flags.filter((f) => f !== "-y");
|
|
47542
|
+
return { command: "npx", args: ["-y", ...extra, "--package", target.spec, "-c", "true"] };
|
|
47543
|
+
}
|
|
47544
|
+
if (target.launcher === "uvx") {
|
|
47545
|
+
return { command: "uv", args: ["tool", "install", target.spec] };
|
|
47546
|
+
}
|
|
47547
|
+
return null;
|
|
47548
|
+
}
|
|
47549
|
+
async function mcpWarm(argv = []) {
|
|
47550
|
+
const timeoutMs = 3e5;
|
|
47551
|
+
const targets = warmTargets();
|
|
47552
|
+
const only = argv.filter((a) => !a.startsWith("-"));
|
|
47553
|
+
const selected = only.length > 0 ? targets.filter((t2) => only.includes(t2.id)) : targets;
|
|
47554
|
+
const result = { warmed: [], skipped: [], failed: [] };
|
|
47555
|
+
console.log(`[codeam mcp-warm] ${selected.length} MCP package(s) to pre-fetch`);
|
|
47556
|
+
for (const target of selected) {
|
|
47557
|
+
const cmd = warmCommand(target);
|
|
47558
|
+
if (!cmd) {
|
|
47559
|
+
result.skipped.push(`${target.spec} (no warm recipe for '${target.launcher}')`);
|
|
47560
|
+
continue;
|
|
47561
|
+
}
|
|
47562
|
+
const started = Date.now();
|
|
47563
|
+
const run = (0, import_node_child_process35.spawnSync)(cmd.command, cmd.args, {
|
|
47564
|
+
stdio: ["ignore", "ignore", "pipe"],
|
|
47565
|
+
timeout: timeoutMs,
|
|
47566
|
+
encoding: "utf8"
|
|
47567
|
+
});
|
|
47568
|
+
const secs = ((Date.now() - started) / 1e3).toFixed(1);
|
|
47569
|
+
if (run.status === 0) {
|
|
47570
|
+
result.warmed.push(target.spec);
|
|
47571
|
+
console.log(` OK ${target.spec} (${secs}s)`);
|
|
47572
|
+
} else {
|
|
47573
|
+
const noise = /^npm (warn|notice)\b/;
|
|
47574
|
+
const lines = (run.stderr ?? "").split("\n").map((l) => l.trim()).filter((l) => l.length > 0 && !noise.test(l));
|
|
47575
|
+
const reason = run.error?.message ?? lines[lines.length - 1] ?? `exit ${String(run.status)} (no stderr)`;
|
|
47576
|
+
result.failed.push({ spec: target.spec, reason });
|
|
47577
|
+
console.log(` MISS ${target.spec} (${secs}s) \u2014 fetched at runtime instead: ${reason}`);
|
|
47578
|
+
}
|
|
47579
|
+
}
|
|
47580
|
+
console.log(
|
|
47581
|
+
`[codeam mcp-warm] warmed=${result.warmed.length} failed=${result.failed.length} skipped=${result.skipped.length}`
|
|
47582
|
+
);
|
|
47583
|
+
log.info(
|
|
47584
|
+
"mcpWarm",
|
|
47585
|
+
`warmed=${result.warmed.length} failed=${result.failed.length} skipped=${result.skipped.length}`
|
|
47586
|
+
);
|
|
47587
|
+
}
|
|
47588
|
+
|
|
47477
47589
|
// src/commands/version.ts
|
|
47478
47590
|
var import_picocolors15 = __toESM(require("picocolors"));
|
|
47479
47591
|
function version2() {
|
|
47480
|
-
const v = true ? "2.73.
|
|
47592
|
+
const v = true ? "2.73.5" : "unknown";
|
|
47481
47593
|
console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
|
|
47482
47594
|
}
|
|
47483
47595
|
|
|
@@ -47678,6 +47790,9 @@ async function main() {
|
|
|
47678
47790
|
if (command === "mcp-run") {
|
|
47679
47791
|
return mcpRun(args);
|
|
47680
47792
|
}
|
|
47793
|
+
if (command === "mcp-warm") {
|
|
47794
|
+
return mcpWarm(args);
|
|
47795
|
+
}
|
|
47681
47796
|
if (command === "deploy") {
|
|
47682
47797
|
if (args[0] === "ls" || args[0] === "list") return deployList();
|
|
47683
47798
|
if (args[0] === "stop" || args[0] === "remove") return deployStop();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.73.
|
|
3
|
+
"version": "2.73.5",
|
|
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",
|