codeam-cli 2.66.1 → 2.67.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 +17 -0
- package/dist/index.js +99 -18
- 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.67.0] — 2026-08-24
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **cli:** Ask the backend for a named preview tunnel when the env has none
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **cli:** Cap how long a self-update restart can be deferred
|
|
16
|
+
|
|
17
|
+
## [2.66.1] — 2026-08-24
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- **jetbrains-plugin:** An undeliverable prompt must answer "failed", never "completed" (#650)
|
|
22
|
+
- **cli:** Restart onto the version already on disk instead of failing to install it
|
|
23
|
+
|
|
7
24
|
## [2.66.0] — 2026-08-21
|
|
8
25
|
|
|
9
26
|
### Added
|
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.1" : "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.1",
|
|
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.1" ? { ideVersion: "2.67.1" } : {}
|
|
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.1" : 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.1" : null;
|
|
22091
22101
|
if (!current2) return;
|
|
22092
22102
|
const cache = readCache();
|
|
22093
22103
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -22104,12 +22114,13 @@ 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;
|
|
22109
22120
|
var SELF_UPDATE_LS_TIMEOUT_MS = 15e3;
|
|
22110
22121
|
var SUDO_PREFLIGHT_TIMEOUT_MS = 5e3;
|
|
22111
22122
|
function currentCliVersion() {
|
|
22112
|
-
return true ? "2.
|
|
22123
|
+
return true ? "2.67.1" : null;
|
|
22113
22124
|
}
|
|
22114
22125
|
async function installedVersion(deps) {
|
|
22115
22126
|
const ls = await deps.run(
|
|
@@ -22578,6 +22589,7 @@ var HostAgentSupervisor = class {
|
|
|
22578
22589
|
this.disableService = deps.disableService ?? defaultDisableService;
|
|
22579
22590
|
this.teardownHeadroom = deps.teardownHeadroom ?? defaultTeardownHeadroom;
|
|
22580
22591
|
this.selfUpdate = deps.selfUpdate ?? runSelfUpdate;
|
|
22592
|
+
this.now = deps.now ?? (() => Date.now());
|
|
22581
22593
|
this.onUpdated = deps.onUpdated ?? defaultOnUpdated;
|
|
22582
22594
|
this.docker = deps.docker ?? defaultDockerRunner;
|
|
22583
22595
|
this.postResumeFailure = deps.postResumeFailure ?? postSessionErrorBubble;
|
|
@@ -22599,6 +22611,7 @@ var HostAgentSupervisor = class {
|
|
|
22599
22611
|
selfUpdateTimer = null;
|
|
22600
22612
|
/** Self-update check + install (injectable; defaults to runSelfUpdate). */
|
|
22601
22613
|
selfUpdate;
|
|
22614
|
+
now;
|
|
22602
22615
|
/** Restart action after a successful self-update (defaults to process.exit). */
|
|
22603
22616
|
onUpdated;
|
|
22604
22617
|
/** Guards against overlapping self-update ticks (a slow npm install). */
|
|
@@ -22609,6 +22622,9 @@ var HostAgentSupervisor = class {
|
|
|
22609
22622
|
* already-installed version for the restart log.
|
|
22610
22623
|
*/
|
|
22611
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;
|
|
22612
22628
|
/** Guards the one-shot 'connected' telemetry on the first heartbeat. */
|
|
22613
22629
|
reportedConnected = false;
|
|
22614
22630
|
/** Live-metrics collector — stateful across beats (CPU delta + latency). */
|
|
@@ -22752,12 +22768,12 @@ var HostAgentSupervisor = class {
|
|
|
22752
22768
|
this.selfUpdating = true;
|
|
22753
22769
|
try {
|
|
22754
22770
|
if (this.pendingRestartVersion !== null) {
|
|
22755
|
-
this.maybeRestartForUpdate(this.pendingRestartVersion);
|
|
22756
|
-
return;
|
|
22771
|
+
if (this.maybeRestartForUpdate(this.pendingRestartVersion)) return;
|
|
22757
22772
|
}
|
|
22758
22773
|
const result = await this.selfUpdate();
|
|
22759
22774
|
if (result.status !== "updated") return;
|
|
22760
22775
|
const version3 = result.version ?? "latest";
|
|
22776
|
+
if (this.pendingRestartVersion === null) this.pendingRestartSince = this.now();
|
|
22761
22777
|
this.pendingRestartVersion = version3;
|
|
22762
22778
|
this.maybeRestartForUpdate(version3);
|
|
22763
22779
|
} catch (err) {
|
|
@@ -22776,13 +22792,22 @@ var HostAgentSupervisor = class {
|
|
|
22776
22792
|
*/
|
|
22777
22793
|
maybeRestartForUpdate(version3) {
|
|
22778
22794
|
if (this.children.size > 0) {
|
|
22779
|
-
|
|
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(
|
|
22780
22805
|
"host-agent",
|
|
22781
|
-
`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`
|
|
22782
22807
|
);
|
|
22783
|
-
return;
|
|
22784
22808
|
}
|
|
22785
22809
|
this.onUpdated(version3);
|
|
22810
|
+
return true;
|
|
22786
22811
|
}
|
|
22787
22812
|
/** Number of live children — for tests + diagnostics. */
|
|
22788
22813
|
childCount() {
|
|
@@ -25123,6 +25148,26 @@ async function restoreProjectEnvIfMissing(cwd, ctx) {
|
|
|
25123
25148
|
}
|
|
25124
25149
|
}
|
|
25125
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
|
+
|
|
25126
25171
|
// src/services/preview/start-orchestrator.ts
|
|
25127
25172
|
var INSTALL_TIMEOUT_MS2 = 5 * 6e4;
|
|
25128
25173
|
var SETUP_TIMEOUT_MS = 2 * 6e4;
|
|
@@ -25495,8 +25540,16 @@ async function establishTunnel(ctx, dev) {
|
|
|
25495
25540
|
let tunnel = null;
|
|
25496
25541
|
let parsedUrl = null;
|
|
25497
25542
|
let lastTunnelErr = "cloudflared did not emit a URL within 45s";
|
|
25498
|
-
const
|
|
25499
|
-
|
|
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;
|
|
25500
25553
|
if (namedToken && namedHostname) {
|
|
25501
25554
|
try {
|
|
25502
25555
|
emitProgress("TUNNEL_STARTING", `named tunnel ${namedHostname}`);
|
|
@@ -37383,8 +37436,14 @@ var HOUSE_AGENT_LIMIT_RE = /HOUSE_AGENT_CEILING|CodeAgent Cloud[^\n]{0,60}(?:usa
|
|
|
37383
37436
|
function looksLikeHouseAgentLimit(text) {
|
|
37384
37437
|
return HOUSE_AGENT_LIMIT_RE.test(text);
|
|
37385
37438
|
}
|
|
37439
|
+
var LOCAL_PROXY_RE = /(?:127\.0\.0\.1|localhost|\[::1\]):\d+/i;
|
|
37440
|
+
var CONNECTION_ERROR_RE = /ECONNREFUSED|ECONNRESET|ETIMEDOUT|EHOSTUNREACH|socket hang up|fetch failed|network error|connection (?:refused|reset|closed)/i;
|
|
37441
|
+
function looksLikeLocalProxyUnavailable(text) {
|
|
37442
|
+
return LOCAL_PROXY_RE.test(text) && CONNECTION_ERROR_RE.test(text);
|
|
37443
|
+
}
|
|
37386
37444
|
function looksLikeAuthFailure(text) {
|
|
37387
37445
|
if (looksLikeHouseAgentLimit(text)) return false;
|
|
37446
|
+
if (looksLikeLocalProxyUnavailable(text)) return false;
|
|
37388
37447
|
return AUTH_FAILURE_RE.test(text);
|
|
37389
37448
|
}
|
|
37390
37449
|
function replyIsAuthFailure(finalText) {
|
|
@@ -37402,7 +37461,14 @@ function houseAgentLimitMessage(text) {
|
|
|
37402
37461
|
const canUpgrade = /upgrade to pro/i.test(text);
|
|
37403
37462
|
return "\u{1F4CA} **You\u2019ve reached your daily CodeAgent Cloud limit.**\n\nThe free CodeAgent Cloud agent has a daily usage ceiling that resets at midnight UTC. This is a usage limit, not a problem with your login \u2014 re-authenticating won\u2019t change it. " + (canUpgrade ? "To keep going now, upgrade to **Pro** for a higher ceiling, or connect your own agent (Claude, Codex, \u2026) in **Profile \u203A Agents** to run without this limit." : "To keep going now, connect your own agent (Claude, Codex, \u2026) in **Profile \u203A Agents** to run without this limit, or wait for the reset.");
|
|
37404
37463
|
}
|
|
37405
|
-
var AUTH_FAILURE_MESSAGE =
|
|
37464
|
+
var AUTH_FAILURE_MESSAGE = (
|
|
37465
|
+
// ⚠️ Do NOT name a status code here. This bubble fires for several
|
|
37466
|
+
// different failures, and the old hard-coded "(API 401)" told users the API
|
|
37467
|
+
// had answered 401 when it never had — it also sent a live investigation
|
|
37468
|
+
// hunting for 401s in proxy logs that were serving 200s throughout
|
|
37469
|
+
// (2026-08-24). Say what happened, not a number we did not see.
|
|
37470
|
+
"\u{1F512} **Authentication failed \u2014 your agent credentials are invalid or expired.**\n\nTap [Re-authenticate this agent](codeam://reauth) to renew your credentials in Profile \u203A Agents, then send your message again."
|
|
37471
|
+
);
|
|
37406
37472
|
var CURSOR_UPGRADE_MESSAGE = "\u26A1 **Cursor needs a paid plan to run the agent.**\n\nThe headless Cursor Agent requires Cursor **Pro** \u2014 your Free plan\u2019s included usage does NOT cover Agent runs, even with quota left. This is your Cursor account (not CodeAgent). Upgrade, then send your message again:\n\n[Upgrade to Cursor Pro \u2192](https://cursor.com/dashboard)";
|
|
37407
37473
|
var ONE_M_CREDITS_MESSAGE = "\u{1F504} **Reconnect your Claude subscription to continue.**\n\nClaude requested 1M-context but your account doesn\u2019t have the usage credits for it on this credential. Reconnecting refreshes your subscription so the agent can keep going \u2014 disabling 1M context won\u2019t fix a credits gate.\n\nTap [Reconnect this agent](codeam://reauth) to reconnect your Claude subscription in Profile \u203A Agents, then send your message again.";
|
|
37408
37474
|
var TURN_FAILURE_MESSAGE = "\u26A0\uFE0F **The agent hit an error and couldn\u2019t finish this turn.** Please send your message again.";
|
|
@@ -37500,6 +37566,10 @@ async function reportCredentialInvalid(opts, fetchImpl = fetch) {
|
|
|
37500
37566
|
pluginId: opts.pluginId,
|
|
37501
37567
|
...opts.reason ? { reason: opts.reason } : {}
|
|
37502
37568
|
});
|
|
37569
|
+
log.info(
|
|
37570
|
+
"acpRunner",
|
|
37571
|
+
`credential-invalid \u2192 reporting agent=${opts.agent} reason=${opts.reason ?? "unspecified"}`
|
|
37572
|
+
);
|
|
37503
37573
|
try {
|
|
37504
37574
|
const makeHeaders = (token) => ({
|
|
37505
37575
|
"Content-Type": "application/json",
|
|
@@ -37517,10 +37587,21 @@ async function reportCredentialInvalid(opts, fetchImpl = fetch) {
|
|
|
37517
37587
|
opts.pollSecret
|
|
37518
37588
|
);
|
|
37519
37589
|
if (freshToken !== null) {
|
|
37520
|
-
await fetchImpl(url2, {
|
|
37590
|
+
const retried = await fetchImpl(url2, {
|
|
37591
|
+
method: "POST",
|
|
37592
|
+
headers: makeHeaders(freshToken),
|
|
37593
|
+
body
|
|
37594
|
+
});
|
|
37595
|
+
log.info("acpRunner", `credential-invalid \u2190 ${retried.status} (after token refresh)`);
|
|
37596
|
+
return;
|
|
37521
37597
|
}
|
|
37522
37598
|
}
|
|
37523
|
-
|
|
37599
|
+
log.info("acpRunner", `credential-invalid \u2190 ${response.status}`);
|
|
37600
|
+
} catch (err) {
|
|
37601
|
+
log.warn(
|
|
37602
|
+
"acpRunner",
|
|
37603
|
+
`credential-invalid \u2192 failed: ${err instanceof Error ? err.message : String(err)}`
|
|
37604
|
+
);
|
|
37524
37605
|
}
|
|
37525
37606
|
}
|
|
37526
37607
|
async function postCredentialSync(opts, fetchImpl = fetch) {
|
|
@@ -45671,7 +45752,7 @@ function checkChokidar() {
|
|
|
45671
45752
|
}
|
|
45672
45753
|
async function doctor(args2 = []) {
|
|
45673
45754
|
const json = args2.includes("--json");
|
|
45674
|
-
const cliVersion = true ? "2.
|
|
45755
|
+
const cliVersion = true ? "2.67.1" : "0.0.0-dev";
|
|
45675
45756
|
const apiBase2 = resolveApiBaseUrl();
|
|
45676
45757
|
const diagnosticId = (0, import_node_crypto13.randomUUID)();
|
|
45677
45758
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -46062,7 +46143,7 @@ async function mcpRun(args2) {
|
|
|
46062
46143
|
// src/commands/version.ts
|
|
46063
46144
|
var import_picocolors15 = __toESM(require("picocolors"));
|
|
46064
46145
|
function version2() {
|
|
46065
|
-
const v = true ? "2.
|
|
46146
|
+
const v = true ? "2.67.1" : "unknown";
|
|
46066
46147
|
console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
|
|
46067
46148
|
}
|
|
46068
46149
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.67.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",
|