codeam-cli 2.41.0 → 2.42.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 +10 -0
- package/dist/index.js +109 -24
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,16 @@ 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.41.0] — 2026-06-24
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **cli:** Surface friendly provider-outage message + status-page link instead of silent hang
|
|
12
|
+
|
|
13
|
+
### Merge
|
|
14
|
+
|
|
15
|
+
- Friendly provider-outage message + status-page link (no silent hang on provider 529/5xx)
|
|
16
|
+
|
|
7
17
|
## [2.40.2] — 2026-06-24
|
|
8
18
|
|
|
9
19
|
### Fixed
|
package/dist/index.js
CHANGED
|
@@ -5390,7 +5390,7 @@ function readAnonId() {
|
|
|
5390
5390
|
}
|
|
5391
5391
|
function superProperties() {
|
|
5392
5392
|
return {
|
|
5393
|
-
cliVersion: true ? "2.
|
|
5393
|
+
cliVersion: true ? "2.42.0" : "0.0.0-dev",
|
|
5394
5394
|
nodeVersion: process.version,
|
|
5395
5395
|
platform: process.platform,
|
|
5396
5396
|
arch: process.arch,
|
|
@@ -5536,6 +5536,28 @@ var _execSeam = {
|
|
|
5536
5536
|
return typeof out2 === "string" ? out2 : out2.toString("utf8");
|
|
5537
5537
|
}
|
|
5538
5538
|
};
|
|
5539
|
+
var _execSeamAsync = {
|
|
5540
|
+
exec: (file, args2, opts) => new Promise((resolve7, reject) => {
|
|
5541
|
+
(0, import_child_process.execFile)(file, args2, opts, (err, stdout) => {
|
|
5542
|
+
if (err) reject(err);
|
|
5543
|
+
else resolve7(typeof stdout === "string" ? stdout : stdout.toString("utf8"));
|
|
5544
|
+
});
|
|
5545
|
+
})
|
|
5546
|
+
};
|
|
5547
|
+
async function detectCurrentBranchAsync(cwd = process.cwd()) {
|
|
5548
|
+
try {
|
|
5549
|
+
const raw = await _execSeamAsync.exec("git", ["branch", "--show-current"], {
|
|
5550
|
+
cwd,
|
|
5551
|
+
timeout: 1e3,
|
|
5552
|
+
encoding: "utf8",
|
|
5553
|
+
windowsHide: true
|
|
5554
|
+
});
|
|
5555
|
+
const trimmed = raw.trim();
|
|
5556
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
5557
|
+
} catch {
|
|
5558
|
+
return null;
|
|
5559
|
+
}
|
|
5560
|
+
}
|
|
5539
5561
|
|
|
5540
5562
|
// src/services/command-relay.service.ts
|
|
5541
5563
|
var https2 = __toESM(require("https"));
|
|
@@ -5549,7 +5571,7 @@ var os4 = __toESM(require("os"));
|
|
|
5549
5571
|
// package.json
|
|
5550
5572
|
var package_default = {
|
|
5551
5573
|
name: "codeam-cli",
|
|
5552
|
-
version: "2.
|
|
5574
|
+
version: "2.42.0",
|
|
5553
5575
|
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.",
|
|
5554
5576
|
type: "commonjs",
|
|
5555
5577
|
main: "dist/index.js",
|
|
@@ -6044,13 +6066,31 @@ var CommandRelayService = class {
|
|
|
6044
6066
|
*/
|
|
6045
6067
|
sseWatchdog = null;
|
|
6046
6068
|
sseLastByteAt = 0;
|
|
6069
|
+
/**
|
|
6070
|
+
* Last-known git branch, shipped on every heartbeat. Seeded with a
|
|
6071
|
+
* single SYNCHRONOUS read at `start()` (before any turn is running)
|
|
6072
|
+
* for an accurate first beat, then refreshed ASYNCHRONOUSLY off the
|
|
6073
|
+
* recurring heartbeat tick. The heartbeat POST reads this cached
|
|
6074
|
+
* value and never spawns `git` synchronously — so the 20 s beat
|
|
6075
|
+
* stays punctual even while a long agent tool call is hammering the
|
|
6076
|
+
* event loop. Trade-off: because the async refresh fires alongside
|
|
6077
|
+
* the POST (not before it), a `git checkout` propagates on the NEXT
|
|
6078
|
+
* beat — up to ~40 s worst case vs the old at-POST-time read. The
|
|
6079
|
+
* backend dedupes a stable branch, so this lag costs nothing but
|
|
6080
|
+
* freshness, and a punctual heartbeat matters far more.
|
|
6081
|
+
*/
|
|
6082
|
+
cachedBranch = null;
|
|
6047
6083
|
start() {
|
|
6048
6084
|
this.cleanup();
|
|
6049
6085
|
this._running = true;
|
|
6050
6086
|
this.agentsRegistered = false;
|
|
6051
6087
|
log.info("relay", `start pluginId=${this.pluginId.slice(0, 8)} agent=${this.agentMeta.id}`);
|
|
6088
|
+
this.cachedBranch = detectCurrentBranch();
|
|
6052
6089
|
this.sendHeartbeat(true);
|
|
6053
|
-
this.heartbeatTimer = setInterval(() =>
|
|
6090
|
+
this.heartbeatTimer = setInterval(() => {
|
|
6091
|
+
void this.refreshBranch();
|
|
6092
|
+
this.sendHeartbeat(true);
|
|
6093
|
+
}, 2e4);
|
|
6054
6094
|
this.agentsTimer = setInterval(() => {
|
|
6055
6095
|
if (this._running && !this.agentsRegistered) this.reportAgents();
|
|
6056
6096
|
}, 5e3);
|
|
@@ -6294,9 +6334,20 @@ var CommandRelayService = class {
|
|
|
6294
6334
|
pluginId: this.pluginId,
|
|
6295
6335
|
online,
|
|
6296
6336
|
agentId: this.agentMeta.id,
|
|
6297
|
-
branch:
|
|
6337
|
+
branch: this.cachedBranch
|
|
6298
6338
|
}).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
|
|
6299
6339
|
}
|
|
6340
|
+
/**
|
|
6341
|
+
* Refresh {@link cachedBranch} without blocking the event loop.
|
|
6342
|
+
* Fire-and-forget from the heartbeat tick; failures leave the last
|
|
6343
|
+
* known value in place (the backend dedupes a stable branch).
|
|
6344
|
+
*/
|
|
6345
|
+
async refreshBranch() {
|
|
6346
|
+
try {
|
|
6347
|
+
this.cachedBranch = await detectCurrentBranchAsync();
|
|
6348
|
+
} catch {
|
|
6349
|
+
}
|
|
6350
|
+
}
|
|
6300
6351
|
reportAgents() {
|
|
6301
6352
|
const agents = this.agentsOverride ? [...this.agentsOverride] : [
|
|
6302
6353
|
{
|
|
@@ -17753,7 +17804,7 @@ async function autoUpgradeBeforeCriticalCommand() {
|
|
|
17753
17804
|
if (process.env.NODE_ENV === "test") return;
|
|
17754
17805
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
17755
17806
|
if (process.env.CI) return;
|
|
17756
|
-
const current = true ? "2.
|
|
17807
|
+
const current = true ? "2.42.0" : null;
|
|
17757
17808
|
if (!current) return;
|
|
17758
17809
|
const cache = readCache();
|
|
17759
17810
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -17770,7 +17821,7 @@ function checkForUpdates() {
|
|
|
17770
17821
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
17771
17822
|
if (process.env.CI) return;
|
|
17772
17823
|
if (!process.stdout.isTTY) return;
|
|
17773
|
-
const current = true ? "2.
|
|
17824
|
+
const current = true ? "2.42.0" : null;
|
|
17774
17825
|
if (!current) return;
|
|
17775
17826
|
const cache = readCache();
|
|
17776
17827
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -18208,7 +18259,7 @@ var defaultSpawner = (env, cwd, args2 = []) => (0, import_node_child_process14.s
|
|
|
18208
18259
|
detached: false
|
|
18209
18260
|
});
|
|
18210
18261
|
function currentCliVersion() {
|
|
18211
|
-
return true ? "2.
|
|
18262
|
+
return true ? "2.42.0" : null;
|
|
18212
18263
|
}
|
|
18213
18264
|
function runCmd(cmd, args2, timeoutMs) {
|
|
18214
18265
|
return new Promise((resolve7) => {
|
|
@@ -24450,6 +24501,22 @@ var StreamingState = class {
|
|
|
24450
24501
|
this.flushStreamingChunks()
|
|
24451
24502
|
]);
|
|
24452
24503
|
}
|
|
24504
|
+
/**
|
|
24505
|
+
* Close the turn but REPLACE the streamed reply with `bubble` as the
|
|
24506
|
+
* terminal chat frame. The chat pipe treats each `text` chunk's content as
|
|
24507
|
+
* the full (replacing) bubble body, so a final `done:true` carrying the
|
|
24508
|
+
* bubble overwrites whatever raw text streamed. Used when the agent's
|
|
24509
|
+
* completed-turn reply was itself an auth-failure notice
|
|
24510
|
+
* ({@link replyIsAuthFailure}) → swap the raw "Please run /login" for the
|
|
24511
|
+
* actionable re-auth bubble.
|
|
24512
|
+
*/
|
|
24513
|
+
async closeWithBubble(bubble) {
|
|
24514
|
+
this.text = "";
|
|
24515
|
+
await Promise.all([
|
|
24516
|
+
this.publisher.publishOutput({ type: "text", content: bubble, done: true }),
|
|
24517
|
+
this.flushStreamingChunks()
|
|
24518
|
+
]);
|
|
24519
|
+
}
|
|
24453
24520
|
/**
|
|
24454
24521
|
* Re-emit every open streaming-chunk buffer with `isFinal: true`
|
|
24455
24522
|
* so SessionDetailScreen's bubbles flip out of "still streaming"
|
|
@@ -24617,6 +24684,10 @@ var AUTH_FAILURE_RE = /invalid authentication credentials|authentication[_ ]erro
|
|
|
24617
24684
|
function looksLikeAuthFailure(text) {
|
|
24618
24685
|
return AUTH_FAILURE_RE.test(text);
|
|
24619
24686
|
}
|
|
24687
|
+
function replyIsAuthFailure(finalText) {
|
|
24688
|
+
const t2 = finalText.trim();
|
|
24689
|
+
return t2.length > 0 && t2.length <= 200 && looksLikeAuthFailure(t2);
|
|
24690
|
+
}
|
|
24620
24691
|
var AUTH_FAILURE_MESSAGE = "\u{1F512} **Authentication failed \u2014 your agent credentials are invalid or expired (API 401).**\n\nTap [Re-authenticate this agent](codeam://reauth) to renew your credentials in Profile \u203A Agents, then send your message again.";
|
|
24621
24692
|
var TURN_FAILURE_MESSAGE = "\u26A0\uFE0F **The agent hit an error and couldn\u2019t finish this turn.** Please send your message again.";
|
|
24622
24693
|
var PROVIDER_OUTAGE_RE = /overloaded_error|\boverloaded\b|service[ _]unavailable|temporarily[ _]unavailable|(?:api error|http|status)[:\s]+(?:529|503|502|504)\b|\b(?:529|503|502|504)\b[^\n]{0,40}(?:overload|unavailable|gateway|upstream|server error)|bad gateway|gateway time-?out|upstream (?:error|connect|timeout)/i;
|
|
@@ -24631,8 +24702,10 @@ function agentStatusPage(agent) {
|
|
|
24631
24702
|
return { vendor: "OpenAI", url: "https://status.openai.com" };
|
|
24632
24703
|
if (a.includes("gemini") || a.includes("google"))
|
|
24633
24704
|
return { vendor: "Google", url: "https://status.cloud.google.com" };
|
|
24634
|
-
if (a.includes("copilot"))
|
|
24635
|
-
|
|
24705
|
+
if (a.includes("copilot"))
|
|
24706
|
+
return { vendor: "GitHub", url: "https://www.githubstatus.com" };
|
|
24707
|
+
if (a.includes("cursor"))
|
|
24708
|
+
return { vendor: "Cursor", url: "https://status.cursor.com" };
|
|
24636
24709
|
return null;
|
|
24637
24710
|
}
|
|
24638
24711
|
function providerOutageMessage(agent) {
|
|
@@ -24946,18 +25019,30 @@ async function handleCommand(cmd, client2, relay, acpSessionId, models, streamin
|
|
|
24946
25019
|
try {
|
|
24947
25020
|
const reply = await client2.prompt(blocks);
|
|
24948
25021
|
const finalText = streaming.getCurrentText();
|
|
24949
|
-
|
|
24950
|
-
|
|
24951
|
-
|
|
24952
|
-
|
|
25022
|
+
if (replyIsAuthFailure(finalText)) {
|
|
25023
|
+
await streaming.closeWithBubble(AUTH_FAILURE_MESSAGE);
|
|
25024
|
+
history.appendAgentReply(AUTH_FAILURE_MESSAGE);
|
|
25025
|
+
void history.flush();
|
|
25026
|
+
turnFiles.flushTurn().catch((err) => {
|
|
25027
|
+
log.warn("acpRunner", `turnFiles.flushTurn failed: ${describeError(err)}`);
|
|
25028
|
+
});
|
|
25029
|
+
void reportCredentialInvalid(opts);
|
|
25030
|
+
log.info("acpRunner", `start_task \u2190 auth-failure-in-reply id=${cmd.id.slice(0, 8)}`);
|
|
25031
|
+
await relay.sendResult(cmd.id, "failed", { error: "agent reply reported auth failure" });
|
|
25032
|
+
} else {
|
|
25033
|
+
await streaming.closeTurnWithInteractiveDetection();
|
|
25034
|
+
const replyLine = formatAgentReplyLine(finalText);
|
|
25035
|
+
if (replyLine.length > 0) {
|
|
25036
|
+
showInfo(replyLine);
|
|
25037
|
+
}
|
|
25038
|
+
history.appendAgentReply(finalText);
|
|
25039
|
+
void history.flush();
|
|
25040
|
+
turnFiles.flushTurn().catch((err) => {
|
|
25041
|
+
log.warn("acpRunner", `turnFiles.flushTurn failed: ${describeError(err)}`);
|
|
25042
|
+
});
|
|
25043
|
+
log.info("acpRunner", `start_task \u2190 done stopReason=${reply.stopReason ?? "?"} id=${cmd.id.slice(0, 8)}`);
|
|
25044
|
+
await relay.sendResult(cmd.id, "completed", { stopReason: reply.stopReason });
|
|
24953
25045
|
}
|
|
24954
|
-
history.appendAgentReply(finalText);
|
|
24955
|
-
void history.flush();
|
|
24956
|
-
turnFiles.flushTurn().catch((err) => {
|
|
24957
|
-
log.warn("acpRunner", `turnFiles.flushTurn failed: ${describeError(err)}`);
|
|
24958
|
-
});
|
|
24959
|
-
log.info("acpRunner", `start_task \u2190 done stopReason=${reply.stopReason ?? "?"} id=${cmd.id.slice(0, 8)}`);
|
|
24960
|
-
await relay.sendResult(cmd.id, "completed", { stopReason: reply.stopReason });
|
|
24961
25046
|
} catch (err) {
|
|
24962
25047
|
const hadText = streaming.getCurrentText().trim().length > 0;
|
|
24963
25048
|
await recoverFromFailedTurn(client2, streaming);
|
|
@@ -28900,9 +28985,9 @@ async function probeCodeamPair(provider, workspace) {
|
|
|
28900
28985
|
}
|
|
28901
28986
|
async function stopWorkspaceFromLocal(target) {
|
|
28902
28987
|
if (target.provider.id === "github-codespaces") {
|
|
28903
|
-
const { execFile:
|
|
28988
|
+
const { execFile: execFile13 } = await import("child_process");
|
|
28904
28989
|
const { promisify: promisify11 } = await import("util");
|
|
28905
|
-
const execFileP10 = promisify11(
|
|
28990
|
+
const execFileP10 = promisify11(execFile13);
|
|
28906
28991
|
await execFileP10("gh", ["codespace", "stop", "-c", target.id], { maxBuffer: 8 * 1024 * 1024 });
|
|
28907
28992
|
return;
|
|
28908
28993
|
}
|
|
@@ -29126,7 +29211,7 @@ function checkChokidar() {
|
|
|
29126
29211
|
}
|
|
29127
29212
|
async function doctor(args2 = []) {
|
|
29128
29213
|
const json = args2.includes("--json");
|
|
29129
|
-
const cliVersion = true ? "2.
|
|
29214
|
+
const cliVersion = true ? "2.42.0" : "0.0.0-dev";
|
|
29130
29215
|
const apiBase2 = resolveApiBaseUrl();
|
|
29131
29216
|
const diagnosticId = (0, import_node_crypto8.randomUUID)();
|
|
29132
29217
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -29325,7 +29410,7 @@ async function completion(args2) {
|
|
|
29325
29410
|
// src/commands/version.ts
|
|
29326
29411
|
var import_picocolors14 = __toESM(require("picocolors"));
|
|
29327
29412
|
function version2() {
|
|
29328
|
-
const v = true ? "2.
|
|
29413
|
+
const v = true ? "2.42.0" : "unknown";
|
|
29329
29414
|
console.log(`${import_picocolors14.default.bold("codeam-cli")} ${import_picocolors14.default.cyan(v)}`);
|
|
29330
29415
|
}
|
|
29331
29416
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.42.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",
|