codeam-cli 2.66.0 → 2.67.0
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 +17 -0
- package/dist/index.js +113 -23
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,23 @@ 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.66.1] — 2026-08-24
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **jetbrains-plugin:** An undeliverable prompt must answer "failed", never "completed" (#650)
|
|
12
|
+
- **cli:** Restart onto the version already on disk instead of failing to install it
|
|
13
|
+
|
|
14
|
+
## [2.66.0] — 2026-08-21
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- **cli:** Handle fleet_prune_host — reclaim Docker residue on the fleet host
|
|
19
|
+
|
|
20
|
+
### Documentation
|
|
21
|
+
|
|
22
|
+
- **cli:** Document the least-privilege Headroom installer resolution
|
|
23
|
+
|
|
7
24
|
## [2.65.17] — 2026-08-21
|
|
8
25
|
|
|
9
26
|
### Fixed
|
package/dist/index.js
CHANGED
|
@@ -8081,7 +8081,7 @@ function readAnonId() {
|
|
|
8081
8081
|
}
|
|
8082
8082
|
function superProperties() {
|
|
8083
8083
|
return {
|
|
8084
|
-
cliVersion: true ? "2.
|
|
8084
|
+
cliVersion: true ? "2.67.0" : "0.0.0-dev",
|
|
8085
8085
|
nodeVersion: process.version,
|
|
8086
8086
|
platform: process.platform,
|
|
8087
8087
|
arch: process.arch,
|
|
@@ -8323,7 +8323,7 @@ var http = __toESM(require("http"));
|
|
|
8323
8323
|
// package.json
|
|
8324
8324
|
var package_default = {
|
|
8325
8325
|
name: "codeam-cli",
|
|
8326
|
-
version: "2.
|
|
8326
|
+
version: "2.67.0",
|
|
8327
8327
|
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.",
|
|
8328
8328
|
type: "commonjs",
|
|
8329
8329
|
main: "dist/index.js",
|
|
@@ -8586,6 +8586,16 @@ async function postAiResult(input) {
|
|
|
8586
8586
|
};
|
|
8587
8587
|
}
|
|
8588
8588
|
}
|
|
8589
|
+
async function fetchNamedPreviewTunnel(input) {
|
|
8590
|
+
const res = await _transport.postJsonAuthed(
|
|
8591
|
+
`${API_BASE}/api/preview/tunnel`,
|
|
8592
|
+
{ pluginId: input.pluginId },
|
|
8593
|
+
input.pluginAuthToken
|
|
8594
|
+
);
|
|
8595
|
+
const body = res;
|
|
8596
|
+
if (typeof body?.hostname !== "string" || typeof body?.token !== "string") return null;
|
|
8597
|
+
return { hostname: body.hostname, token: body.token };
|
|
8598
|
+
}
|
|
8589
8599
|
async function postPreviewEvent(input) {
|
|
8590
8600
|
try {
|
|
8591
8601
|
await _transport.postJsonAuthed(
|
|
@@ -9845,7 +9855,7 @@ var CommandRelayService = class _CommandRelayService {
|
|
|
9845
9855
|
// fresh + clear the "CLI update available" banner after a self-update
|
|
9846
9856
|
// (a codespace that reinstalls @latest reconnects via heartbeat, not
|
|
9847
9857
|
// pair/reconnect). Older backends ignore the extra field.
|
|
9848
|
-
..."2.
|
|
9858
|
+
..."2.67.0" ? { ideVersion: "2.67.0" } : {}
|
|
9849
9859
|
}).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
|
|
9850
9860
|
}
|
|
9851
9861
|
/**
|
|
@@ -22070,7 +22080,7 @@ async function autoUpgradeBeforeCriticalCommand() {
|
|
|
22070
22080
|
if (process.env.NODE_ENV === "test") return;
|
|
22071
22081
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
22072
22082
|
if (process.env.CI) return;
|
|
22073
|
-
const current2 = true ? "2.
|
|
22083
|
+
const current2 = true ? "2.67.0" : null;
|
|
22074
22084
|
if (!current2) return;
|
|
22075
22085
|
const cache = readCache();
|
|
22076
22086
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -22087,7 +22097,7 @@ function checkForUpdates() {
|
|
|
22087
22097
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
22088
22098
|
if (process.env.CI) return;
|
|
22089
22099
|
if (!process.stdout.isTTY) return;
|
|
22090
|
-
const current2 = true ? "2.
|
|
22100
|
+
const current2 = true ? "2.67.0" : null;
|
|
22091
22101
|
if (!current2) return;
|
|
22092
22102
|
const cache = readCache();
|
|
22093
22103
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -22104,10 +22114,26 @@ function checkForUpdates() {
|
|
|
22104
22114
|
// src/commands/host/self-update.ts
|
|
22105
22115
|
var SELF_UPDATE_PKG = "codeam-cli";
|
|
22106
22116
|
var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
22117
|
+
var SELF_UPDATE_DEFER_MAX_MS = 24 * 60 * 60 * 1e3;
|
|
22107
22118
|
var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
|
|
22108
22119
|
var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
|
|
22120
|
+
var SELF_UPDATE_LS_TIMEOUT_MS = 15e3;
|
|
22121
|
+
var SUDO_PREFLIGHT_TIMEOUT_MS = 5e3;
|
|
22109
22122
|
function currentCliVersion() {
|
|
22110
|
-
return true ? "2.
|
|
22123
|
+
return true ? "2.67.0" : null;
|
|
22124
|
+
}
|
|
22125
|
+
async function installedVersion(deps) {
|
|
22126
|
+
const ls = await deps.run(
|
|
22127
|
+
"npm",
|
|
22128
|
+
["ls", "-g", "--depth=0", "--json", SELF_UPDATE_PKG],
|
|
22129
|
+
SELF_UPDATE_LS_TIMEOUT_MS
|
|
22130
|
+
);
|
|
22131
|
+
try {
|
|
22132
|
+
const parsed = JSON.parse(ls.stdout);
|
|
22133
|
+
return parsed.dependencies?.[SELF_UPDATE_PKG]?.version ?? null;
|
|
22134
|
+
} catch {
|
|
22135
|
+
return null;
|
|
22136
|
+
}
|
|
22111
22137
|
}
|
|
22112
22138
|
function runCmd(cmd, args2, timeoutMs) {
|
|
22113
22139
|
return new Promise((resolve10) => {
|
|
@@ -22118,13 +22144,28 @@ function runCmd(cmd, args2, timeoutMs) {
|
|
|
22118
22144
|
});
|
|
22119
22145
|
}
|
|
22120
22146
|
async function runSelfUpdate() {
|
|
22147
|
+
return runSelfUpdateWith({
|
|
22148
|
+
run: runCmd,
|
|
22149
|
+
currentVersion: currentCliVersion,
|
|
22150
|
+
isRoot: () => process.getuid?.() === 0
|
|
22151
|
+
});
|
|
22152
|
+
}
|
|
22153
|
+
async function runSelfUpdateWith(deps) {
|
|
22121
22154
|
try {
|
|
22122
|
-
const current2 =
|
|
22155
|
+
const current2 = deps.currentVersion();
|
|
22123
22156
|
if (!current2) {
|
|
22124
22157
|
log.trace("host-agent", "self-update: no __CLI_VERSION__ \u2014 skipping");
|
|
22125
22158
|
return { status: "skipped" };
|
|
22126
22159
|
}
|
|
22127
|
-
const
|
|
22160
|
+
const onDisk = await installedVersion(deps);
|
|
22161
|
+
if (onDisk && compareSemver(onDisk, current2) > 0) {
|
|
22162
|
+
log.info(
|
|
22163
|
+
"host-agent",
|
|
22164
|
+
`self-update: ${onDisk} already installed on disk (running ${current2}) \u2014 restarting onto it`
|
|
22165
|
+
);
|
|
22166
|
+
return { status: "updated", version: onDisk };
|
|
22167
|
+
}
|
|
22168
|
+
const view = await deps.run(
|
|
22128
22169
|
"npm",
|
|
22129
22170
|
["view", SELF_UPDATE_PKG, "version"],
|
|
22130
22171
|
SELF_UPDATE_VIEW_TIMEOUT_MS
|
|
@@ -22143,11 +22184,18 @@ async function runSelfUpdate() {
|
|
|
22143
22184
|
}
|
|
22144
22185
|
log.info("host-agent", `self-update: ${current2} \u2192 ${latest} available \u2014 installing`);
|
|
22145
22186
|
const installArgs = ["install", "-g", `${SELF_UPDATE_PKG}@latest`];
|
|
22146
|
-
let install = await
|
|
22147
|
-
|
|
22148
|
-
|
|
22149
|
-
|
|
22150
|
-
|
|
22187
|
+
let install = await deps.run("npm", installArgs, SELF_UPDATE_INSTALL_TIMEOUT_MS);
|
|
22188
|
+
if (install.code !== 0 && !deps.isRoot() && /EACCES/i.test(install.stderr)) {
|
|
22189
|
+
const canSudo = await deps.run("sudo", ["-n", "true"], SUDO_PREFLIGHT_TIMEOUT_MS);
|
|
22190
|
+
if (canSudo.code === 0) {
|
|
22191
|
+
log.info("host-agent", "self-update: install hit EACCES \u2014 retrying with sudo");
|
|
22192
|
+
install = await deps.run("sudo", ["npm", ...installArgs], SELF_UPDATE_INSTALL_TIMEOUT_MS);
|
|
22193
|
+
} else {
|
|
22194
|
+
log.warn(
|
|
22195
|
+
"host-agent",
|
|
22196
|
+
"self-update: the npm global prefix is not writable by this user and passwordless sudo is unavailable \u2014 install codeam-cli under a user-writable prefix, or let a privileged agent on this host install it (this box restarts onto it automatically)"
|
|
22197
|
+
);
|
|
22198
|
+
}
|
|
22151
22199
|
}
|
|
22152
22200
|
if (install.code !== 0) {
|
|
22153
22201
|
log.warn(
|
|
@@ -22156,7 +22204,7 @@ async function runSelfUpdate() {
|
|
|
22156
22204
|
);
|
|
22157
22205
|
return { status: "skipped" };
|
|
22158
22206
|
}
|
|
22159
|
-
const after = await
|
|
22207
|
+
const after = await deps.run(
|
|
22160
22208
|
"npm",
|
|
22161
22209
|
["view", SELF_UPDATE_PKG, "version"],
|
|
22162
22210
|
SELF_UPDATE_VIEW_TIMEOUT_MS
|
|
@@ -22541,6 +22589,7 @@ var HostAgentSupervisor = class {
|
|
|
22541
22589
|
this.disableService = deps.disableService ?? defaultDisableService;
|
|
22542
22590
|
this.teardownHeadroom = deps.teardownHeadroom ?? defaultTeardownHeadroom;
|
|
22543
22591
|
this.selfUpdate = deps.selfUpdate ?? runSelfUpdate;
|
|
22592
|
+
this.now = deps.now ?? (() => Date.now());
|
|
22544
22593
|
this.onUpdated = deps.onUpdated ?? defaultOnUpdated;
|
|
22545
22594
|
this.docker = deps.docker ?? defaultDockerRunner;
|
|
22546
22595
|
this.postResumeFailure = deps.postResumeFailure ?? postSessionErrorBubble;
|
|
@@ -22562,6 +22611,7 @@ var HostAgentSupervisor = class {
|
|
|
22562
22611
|
selfUpdateTimer = null;
|
|
22563
22612
|
/** Self-update check + install (injectable; defaults to runSelfUpdate). */
|
|
22564
22613
|
selfUpdate;
|
|
22614
|
+
now;
|
|
22565
22615
|
/** Restart action after a successful self-update (defaults to process.exit). */
|
|
22566
22616
|
onUpdated;
|
|
22567
22617
|
/** Guards against overlapping self-update ticks (a slow npm install). */
|
|
@@ -22572,6 +22622,9 @@ var HostAgentSupervisor = class {
|
|
|
22572
22622
|
* already-installed version for the restart log.
|
|
22573
22623
|
*/
|
|
22574
22624
|
pendingRestartVersion = null;
|
|
22625
|
+
/** epoch ms when the CURRENT pending restart was first owed — the ceiling
|
|
22626
|
+
* in {@link SELF_UPDATE_DEFER_MAX_MS} is measured from here. */
|
|
22627
|
+
pendingRestartSince = null;
|
|
22575
22628
|
/** Guards the one-shot 'connected' telemetry on the first heartbeat. */
|
|
22576
22629
|
reportedConnected = false;
|
|
22577
22630
|
/** Live-metrics collector — stateful across beats (CPU delta + latency). */
|
|
@@ -22715,12 +22768,12 @@ var HostAgentSupervisor = class {
|
|
|
22715
22768
|
this.selfUpdating = true;
|
|
22716
22769
|
try {
|
|
22717
22770
|
if (this.pendingRestartVersion !== null) {
|
|
22718
|
-
this.maybeRestartForUpdate(this.pendingRestartVersion);
|
|
22719
|
-
return;
|
|
22771
|
+
if (this.maybeRestartForUpdate(this.pendingRestartVersion)) return;
|
|
22720
22772
|
}
|
|
22721
22773
|
const result = await this.selfUpdate();
|
|
22722
22774
|
if (result.status !== "updated") return;
|
|
22723
22775
|
const version3 = result.version ?? "latest";
|
|
22776
|
+
if (this.pendingRestartVersion === null) this.pendingRestartSince = this.now();
|
|
22724
22777
|
this.pendingRestartVersion = version3;
|
|
22725
22778
|
this.maybeRestartForUpdate(version3);
|
|
22726
22779
|
} catch (err) {
|
|
@@ -22739,13 +22792,22 @@ var HostAgentSupervisor = class {
|
|
|
22739
22792
|
*/
|
|
22740
22793
|
maybeRestartForUpdate(version3) {
|
|
22741
22794
|
if (this.children.size > 0) {
|
|
22742
|
-
|
|
22795
|
+
const since = this.pendingRestartSince ?? this.now();
|
|
22796
|
+
const waited = this.now() - since;
|
|
22797
|
+
if (waited < SELF_UPDATE_DEFER_MAX_MS) {
|
|
22798
|
+
log.info(
|
|
22799
|
+
"host-agent",
|
|
22800
|
+
`self-update: ${version3} installed but ${this.children.size} child(ren) busy \u2014 deferring restart`
|
|
22801
|
+
);
|
|
22802
|
+
return false;
|
|
22803
|
+
}
|
|
22804
|
+
log.warn(
|
|
22743
22805
|
"host-agent",
|
|
22744
|
-
`self-update: ${version3}
|
|
22806
|
+
`self-update: ${version3} has been owed for ${Math.round(waited / 36e5)}h with ${this.children.size} child(ren) still running \u2014 restarting anyway rather than staying on old code`
|
|
22745
22807
|
);
|
|
22746
|
-
return;
|
|
22747
22808
|
}
|
|
22748
22809
|
this.onUpdated(version3);
|
|
22810
|
+
return true;
|
|
22749
22811
|
}
|
|
22750
22812
|
/** Number of live children — for tests + diagnostics. */
|
|
22751
22813
|
childCount() {
|
|
@@ -25086,6 +25148,26 @@ async function restoreProjectEnvIfMissing(cwd, ctx) {
|
|
|
25086
25148
|
}
|
|
25087
25149
|
}
|
|
25088
25150
|
|
|
25151
|
+
// src/services/preview/named-tunnel.ts
|
|
25152
|
+
async function resolveNamedTunnel(ctx, fetchTunnel) {
|
|
25153
|
+
const envToken = process.env.PREVIEW_TUNNEL_TOKEN;
|
|
25154
|
+
const envHostname = process.env.PREVIEW_TUNNEL_HOSTNAME;
|
|
25155
|
+
if (envToken && envHostname) return { token: envToken, hostname: envHostname };
|
|
25156
|
+
if (!ctx.pluginAuthToken) return null;
|
|
25157
|
+
try {
|
|
25158
|
+
const minted = await fetchTunnel(ctx);
|
|
25159
|
+
if (!minted?.token || !minted.hostname) return null;
|
|
25160
|
+
log.info("preview", `named tunnel minted on demand: ${minted.hostname}`);
|
|
25161
|
+
return { token: minted.token, hostname: minted.hostname };
|
|
25162
|
+
} catch (err) {
|
|
25163
|
+
log.trace(
|
|
25164
|
+
"preview",
|
|
25165
|
+
`named tunnel unavailable (${err instanceof Error ? err.message : String(err)}) \u2014 quick tunnel`
|
|
25166
|
+
);
|
|
25167
|
+
return null;
|
|
25168
|
+
}
|
|
25169
|
+
}
|
|
25170
|
+
|
|
25089
25171
|
// src/services/preview/start-orchestrator.ts
|
|
25090
25172
|
var INSTALL_TIMEOUT_MS2 = 5 * 6e4;
|
|
25091
25173
|
var SETUP_TIMEOUT_MS = 2 * 6e4;
|
|
@@ -25458,8 +25540,16 @@ async function establishTunnel(ctx, dev) {
|
|
|
25458
25540
|
let tunnel = null;
|
|
25459
25541
|
let parsedUrl = null;
|
|
25460
25542
|
let lastTunnelErr = "cloudflared did not emit a URL within 45s";
|
|
25461
|
-
const
|
|
25462
|
-
|
|
25543
|
+
const named = await resolveNamedTunnel(
|
|
25544
|
+
{
|
|
25545
|
+
sessionId: ctx.sessionId,
|
|
25546
|
+
pluginId: ctx.projectEnvAuth?.pluginId ?? "",
|
|
25547
|
+
pluginAuthToken: ctx.projectEnvAuth?.pluginAuthToken ?? ""
|
|
25548
|
+
},
|
|
25549
|
+
(c2) => fetchNamedPreviewTunnel({ pluginId: c2.pluginId, pluginAuthToken: c2.pluginAuthToken })
|
|
25550
|
+
);
|
|
25551
|
+
const namedToken = named?.token;
|
|
25552
|
+
const namedHostname = named?.hostname;
|
|
25463
25553
|
if (namedToken && namedHostname) {
|
|
25464
25554
|
try {
|
|
25465
25555
|
emitProgress("TUNNEL_STARTING", `named tunnel ${namedHostname}`);
|
|
@@ -45634,7 +45724,7 @@ function checkChokidar() {
|
|
|
45634
45724
|
}
|
|
45635
45725
|
async function doctor(args2 = []) {
|
|
45636
45726
|
const json = args2.includes("--json");
|
|
45637
|
-
const cliVersion = true ? "2.
|
|
45727
|
+
const cliVersion = true ? "2.67.0" : "0.0.0-dev";
|
|
45638
45728
|
const apiBase2 = resolveApiBaseUrl();
|
|
45639
45729
|
const diagnosticId = (0, import_node_crypto13.randomUUID)();
|
|
45640
45730
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -46025,7 +46115,7 @@ async function mcpRun(args2) {
|
|
|
46025
46115
|
// src/commands/version.ts
|
|
46026
46116
|
var import_picocolors15 = __toESM(require("picocolors"));
|
|
46027
46117
|
function version2() {
|
|
46028
|
-
const v = true ? "2.
|
|
46118
|
+
const v = true ? "2.67.0" : "unknown";
|
|
46029
46119
|
console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
|
|
46030
46120
|
}
|
|
46031
46121
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.67.0",
|
|
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",
|