codeam-cli 2.41.1 → 2.43.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 +21 -0
- package/dist/index.js +229 -67
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,27 @@ 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.42.0] — 2026-06-24
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **cli:** Confirm provider outage via status page on turn stall/failure (catch-all)
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **cli:** Make agent-failure messaging honest — outage only on real provider error, re-auth on auth-notice replies
|
|
16
|
+
- **cli:** Keep the heartbeat punctual by detecting the git branch off the hot path
|
|
17
|
+
|
|
18
|
+
## [2.41.0] — 2026-06-24
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- **cli:** Surface friendly provider-outage message + status-page link instead of silent hang
|
|
23
|
+
|
|
24
|
+
### Merge
|
|
25
|
+
|
|
26
|
+
- Friendly provider-outage message + status-page link (no silent hang on provider 529/5xx)
|
|
27
|
+
|
|
7
28
|
## [2.40.2] — 2026-06-24
|
|
8
29
|
|
|
9
30
|
### Fixed
|
package/dist/index.js
CHANGED
|
@@ -476,6 +476,13 @@ function makeConfig(baseDir) {
|
|
|
476
476
|
matches.sort((a, b) => b.pairedAt - a.pairedAt);
|
|
477
477
|
return matches[0];
|
|
478
478
|
}
|
|
479
|
+
function setDisable1mContext2(pluginId, value) {
|
|
480
|
+
const c2 = load();
|
|
481
|
+
const s = c2.sessions.find((x) => x.pluginId === pluginId);
|
|
482
|
+
if (!s) return;
|
|
483
|
+
s.disable1mContext = value;
|
|
484
|
+
save(c2);
|
|
485
|
+
}
|
|
479
486
|
function clearAll2() {
|
|
480
487
|
try {
|
|
481
488
|
fs.unlinkSync(file);
|
|
@@ -488,7 +495,7 @@ function makeConfig(baseDir) {
|
|
|
488
495
|
function loadCliConfig2() {
|
|
489
496
|
return load();
|
|
490
497
|
}
|
|
491
|
-
return { getConfig: getConfig2, ensurePluginId: ensurePluginId2, addSession: addSession2, removeSession: removeSession2, setActiveSession: setActiveSession2, getActiveSession: getActiveSession2, getActiveSessionForAgent: getActiveSessionForAgent2, clearAll: clearAll2, saveCliConfig: saveCliConfig2, loadCliConfig: loadCliConfig2 };
|
|
498
|
+
return { getConfig: getConfig2, ensurePluginId: ensurePluginId2, addSession: addSession2, removeSession: removeSession2, setActiveSession: setActiveSession2, getActiveSession: getActiveSession2, getActiveSessionForAgent: getActiveSessionForAgent2, setDisable1mContext: setDisable1mContext2, clearAll: clearAll2, saveCliConfig: saveCliConfig2, loadCliConfig: loadCliConfig2 };
|
|
492
499
|
}
|
|
493
500
|
var CODESPACE_ENV_KEYS = [
|
|
494
501
|
"PREVIEW_TUNNEL_TOKEN",
|
|
@@ -512,7 +519,7 @@ function loadCodespaceEnv() {
|
|
|
512
519
|
}
|
|
513
520
|
}
|
|
514
521
|
var _default = makeConfig();
|
|
515
|
-
var { getConfig, ensurePluginId, addSession, removeSession, setActiveSession, getActiveSession, getActiveSessionForAgent, clearAll, saveCliConfig, loadCliConfig } = _default;
|
|
522
|
+
var { getConfig, ensurePluginId, addSession, removeSession, setActiveSession, getActiveSession, getActiveSessionForAgent, setDisable1mContext, clearAll, saveCliConfig, loadCliConfig } = _default;
|
|
516
523
|
|
|
517
524
|
// src/commands/pair-auto.ts
|
|
518
525
|
var fs41 = __toESM(require("fs"));
|
|
@@ -5390,7 +5397,7 @@ function readAnonId() {
|
|
|
5390
5397
|
}
|
|
5391
5398
|
function superProperties() {
|
|
5392
5399
|
return {
|
|
5393
|
-
cliVersion: true ? "2.
|
|
5400
|
+
cliVersion: true ? "2.43.0" : "0.0.0-dev",
|
|
5394
5401
|
nodeVersion: process.version,
|
|
5395
5402
|
platform: process.platform,
|
|
5396
5403
|
arch: process.arch,
|
|
@@ -5536,6 +5543,28 @@ var _execSeam = {
|
|
|
5536
5543
|
return typeof out2 === "string" ? out2 : out2.toString("utf8");
|
|
5537
5544
|
}
|
|
5538
5545
|
};
|
|
5546
|
+
var _execSeamAsync = {
|
|
5547
|
+
exec: (file, args2, opts) => new Promise((resolve7, reject) => {
|
|
5548
|
+
(0, import_child_process.execFile)(file, args2, opts, (err, stdout) => {
|
|
5549
|
+
if (err) reject(err);
|
|
5550
|
+
else resolve7(typeof stdout === "string" ? stdout : stdout.toString("utf8"));
|
|
5551
|
+
});
|
|
5552
|
+
})
|
|
5553
|
+
};
|
|
5554
|
+
async function detectCurrentBranchAsync(cwd = process.cwd()) {
|
|
5555
|
+
try {
|
|
5556
|
+
const raw = await _execSeamAsync.exec("git", ["branch", "--show-current"], {
|
|
5557
|
+
cwd,
|
|
5558
|
+
timeout: 1e3,
|
|
5559
|
+
encoding: "utf8",
|
|
5560
|
+
windowsHide: true
|
|
5561
|
+
});
|
|
5562
|
+
const trimmed = raw.trim();
|
|
5563
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
5564
|
+
} catch {
|
|
5565
|
+
return null;
|
|
5566
|
+
}
|
|
5567
|
+
}
|
|
5539
5568
|
|
|
5540
5569
|
// src/services/command-relay.service.ts
|
|
5541
5570
|
var https2 = __toESM(require("https"));
|
|
@@ -5549,7 +5578,7 @@ var os4 = __toESM(require("os"));
|
|
|
5549
5578
|
// package.json
|
|
5550
5579
|
var package_default = {
|
|
5551
5580
|
name: "codeam-cli",
|
|
5552
|
-
version: "2.
|
|
5581
|
+
version: "2.43.0",
|
|
5553
5582
|
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
5583
|
type: "commonjs",
|
|
5555
5584
|
main: "dist/index.js",
|
|
@@ -6044,13 +6073,31 @@ var CommandRelayService = class {
|
|
|
6044
6073
|
*/
|
|
6045
6074
|
sseWatchdog = null;
|
|
6046
6075
|
sseLastByteAt = 0;
|
|
6076
|
+
/**
|
|
6077
|
+
* Last-known git branch, shipped on every heartbeat. Seeded with a
|
|
6078
|
+
* single SYNCHRONOUS read at `start()` (before any turn is running)
|
|
6079
|
+
* for an accurate first beat, then refreshed ASYNCHRONOUSLY off the
|
|
6080
|
+
* recurring heartbeat tick. The heartbeat POST reads this cached
|
|
6081
|
+
* value and never spawns `git` synchronously — so the 20 s beat
|
|
6082
|
+
* stays punctual even while a long agent tool call is hammering the
|
|
6083
|
+
* event loop. Trade-off: because the async refresh fires alongside
|
|
6084
|
+
* the POST (not before it), a `git checkout` propagates on the NEXT
|
|
6085
|
+
* beat — up to ~40 s worst case vs the old at-POST-time read. The
|
|
6086
|
+
* backend dedupes a stable branch, so this lag costs nothing but
|
|
6087
|
+
* freshness, and a punctual heartbeat matters far more.
|
|
6088
|
+
*/
|
|
6089
|
+
cachedBranch = null;
|
|
6047
6090
|
start() {
|
|
6048
6091
|
this.cleanup();
|
|
6049
6092
|
this._running = true;
|
|
6050
6093
|
this.agentsRegistered = false;
|
|
6051
6094
|
log.info("relay", `start pluginId=${this.pluginId.slice(0, 8)} agent=${this.agentMeta.id}`);
|
|
6095
|
+
this.cachedBranch = detectCurrentBranch();
|
|
6052
6096
|
this.sendHeartbeat(true);
|
|
6053
|
-
this.heartbeatTimer = setInterval(() =>
|
|
6097
|
+
this.heartbeatTimer = setInterval(() => {
|
|
6098
|
+
void this.refreshBranch();
|
|
6099
|
+
this.sendHeartbeat(true);
|
|
6100
|
+
}, 2e4);
|
|
6054
6101
|
this.agentsTimer = setInterval(() => {
|
|
6055
6102
|
if (this._running && !this.agentsRegistered) this.reportAgents();
|
|
6056
6103
|
}, 5e3);
|
|
@@ -6294,9 +6341,20 @@ var CommandRelayService = class {
|
|
|
6294
6341
|
pluginId: this.pluginId,
|
|
6295
6342
|
online,
|
|
6296
6343
|
agentId: this.agentMeta.id,
|
|
6297
|
-
branch:
|
|
6344
|
+
branch: this.cachedBranch
|
|
6298
6345
|
}).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
|
|
6299
6346
|
}
|
|
6347
|
+
/**
|
|
6348
|
+
* Refresh {@link cachedBranch} without blocking the event loop.
|
|
6349
|
+
* Fire-and-forget from the heartbeat tick; failures leave the last
|
|
6350
|
+
* known value in place (the backend dedupes a stable branch).
|
|
6351
|
+
*/
|
|
6352
|
+
async refreshBranch() {
|
|
6353
|
+
try {
|
|
6354
|
+
this.cachedBranch = await detectCurrentBranchAsync();
|
|
6355
|
+
} catch {
|
|
6356
|
+
}
|
|
6357
|
+
}
|
|
6300
6358
|
reportAgents() {
|
|
6301
6359
|
const agents = this.agentsOverride ? [...this.agentsOverride] : [
|
|
6302
6360
|
{
|
|
@@ -17753,7 +17811,7 @@ async function autoUpgradeBeforeCriticalCommand() {
|
|
|
17753
17811
|
if (process.env.NODE_ENV === "test") return;
|
|
17754
17812
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
17755
17813
|
if (process.env.CI) return;
|
|
17756
|
-
const current = true ? "2.
|
|
17814
|
+
const current = true ? "2.43.0" : null;
|
|
17757
17815
|
if (!current) return;
|
|
17758
17816
|
const cache = readCache();
|
|
17759
17817
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -17770,7 +17828,7 @@ function checkForUpdates() {
|
|
|
17770
17828
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
17771
17829
|
if (process.env.CI) return;
|
|
17772
17830
|
if (!process.stdout.isTTY) return;
|
|
17773
|
-
const current = true ? "2.
|
|
17831
|
+
const current = true ? "2.43.0" : null;
|
|
17774
17832
|
if (!current) return;
|
|
17775
17833
|
const cache = readCache();
|
|
17776
17834
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -18208,7 +18266,7 @@ var defaultSpawner = (env, cwd, args2 = []) => (0, import_node_child_process14.s
|
|
|
18208
18266
|
detached: false
|
|
18209
18267
|
});
|
|
18210
18268
|
function currentCliVersion() {
|
|
18211
|
-
return true ? "2.
|
|
18269
|
+
return true ? "2.43.0" : null;
|
|
18212
18270
|
}
|
|
18213
18271
|
function runCmd(cmd, args2, timeoutMs) {
|
|
18214
18272
|
return new Promise((resolve7) => {
|
|
@@ -22686,7 +22744,10 @@ var AcpClient = class {
|
|
|
22686
22744
|
);
|
|
22687
22745
|
const child = (0, import_node_child_process16.spawn)(adapter.command, adapter.args, {
|
|
22688
22746
|
cwd,
|
|
22689
|
-
|
|
22747
|
+
// extraEnv (e.g. CLAUDE_CODE_DISABLE_1M_CONTEXT=1 on an on-demand
|
|
22748
|
+
// re-spawn) layers over process.env; PATH stays last so the augmented
|
|
22749
|
+
// PATH always wins.
|
|
22750
|
+
env: { ...process.env, ...this.opts.extraEnv ?? {}, PATH: augmentedPath },
|
|
22690
22751
|
stdio: ["pipe", "pipe", "pipe"]
|
|
22691
22752
|
});
|
|
22692
22753
|
this.child = child;
|
|
@@ -23380,6 +23441,66 @@ function buildAcpPromptBlocks(payload) {
|
|
|
23380
23441
|
return blocks;
|
|
23381
23442
|
}
|
|
23382
23443
|
|
|
23444
|
+
// src/agents/acp/oneMContextRecovery.ts
|
|
23445
|
+
var ONE_M_CONTEXT_CREDITS_RE = /usage credits required for 1m context/i;
|
|
23446
|
+
function looksLike1mContextCreditsError(text) {
|
|
23447
|
+
return ONE_M_CONTEXT_CREDITS_RE.test(text);
|
|
23448
|
+
}
|
|
23449
|
+
var ONE_M_DISABLE_OPTION = "Disable 1M context and continue";
|
|
23450
|
+
function shouldOfferOneMRecovery(opts) {
|
|
23451
|
+
return looksLike1mContextCreditsError(opts.detail) || looksLike1mContextCreditsError(opts.recentStderr) || looksLike1mContextCreditsError(opts.finalText);
|
|
23452
|
+
}
|
|
23453
|
+
function oneMRecoverySelectPrompt() {
|
|
23454
|
+
return {
|
|
23455
|
+
question: "\u26A0\uFE0F This agent's Anthropic account needs usage credits for 1M context. You can disable 1M context (uses standard 200K context) and continue.",
|
|
23456
|
+
options: [ONE_M_DISABLE_OPTION]
|
|
23457
|
+
};
|
|
23458
|
+
}
|
|
23459
|
+
function createOneMRecovery(deps) {
|
|
23460
|
+
let pending = null;
|
|
23461
|
+
const sp = oneMRecoverySelectPrompt();
|
|
23462
|
+
return {
|
|
23463
|
+
offer: async (commandId, blocks) => {
|
|
23464
|
+
pending = { blocks };
|
|
23465
|
+
await deps.publishText(sp.question);
|
|
23466
|
+
await deps.publishSelectPrompt(sp.question, sp.options);
|
|
23467
|
+
deps.appendAgentReply(sp.question);
|
|
23468
|
+
deps.flushHistory();
|
|
23469
|
+
deps.log?.(`1M-context credits gate \u2014 recovery offered id=${commandId.slice(0, 8)}`);
|
|
23470
|
+
await deps.sendResult(commandId, "failed", {
|
|
23471
|
+
error: "1M context requires usage credits \u2014 recovery offered"
|
|
23472
|
+
});
|
|
23473
|
+
},
|
|
23474
|
+
tryRecover: async (commandId) => {
|
|
23475
|
+
if (!pending) return false;
|
|
23476
|
+
const blocks = pending.blocks;
|
|
23477
|
+
pending = null;
|
|
23478
|
+
deps.log?.("1M-context recovery \u2192 disable + reconnect + rerun");
|
|
23479
|
+
await deps.reconnectWith1mDisabled();
|
|
23480
|
+
await deps.beginTurn();
|
|
23481
|
+
try {
|
|
23482
|
+
const reply = await deps.promptAgent(blocks);
|
|
23483
|
+
const finalText = deps.getCurrentText();
|
|
23484
|
+
await deps.closeTurn();
|
|
23485
|
+
deps.appendAgentReply(finalText);
|
|
23486
|
+
deps.flushHistory();
|
|
23487
|
+
await deps.sendResult(commandId, "completed", { stopReason: reply.stopReason });
|
|
23488
|
+
} catch (err) {
|
|
23489
|
+
await deps.recoverFromFailedTurn();
|
|
23490
|
+
const d3 = deps.describeError(err);
|
|
23491
|
+
const b = deps.failureBubbleFor(d3);
|
|
23492
|
+
if (b) {
|
|
23493
|
+
await deps.publishText(b);
|
|
23494
|
+
deps.appendAgentReply(b);
|
|
23495
|
+
deps.flushHistory();
|
|
23496
|
+
}
|
|
23497
|
+
await deps.sendResult(commandId, "failed", { error: d3 });
|
|
23498
|
+
}
|
|
23499
|
+
return true;
|
|
23500
|
+
}
|
|
23501
|
+
};
|
|
23502
|
+
}
|
|
23503
|
+
|
|
23383
23504
|
// src/agents/acp/reconcileDelta.ts
|
|
23384
23505
|
function reconcileCumulative(existing, incoming) {
|
|
23385
23506
|
if (incoming.length === 0) return existing;
|
|
@@ -24450,6 +24571,22 @@ var StreamingState = class {
|
|
|
24450
24571
|
this.flushStreamingChunks()
|
|
24451
24572
|
]);
|
|
24452
24573
|
}
|
|
24574
|
+
/**
|
|
24575
|
+
* Close the turn but REPLACE the streamed reply with `bubble` as the
|
|
24576
|
+
* terminal chat frame. The chat pipe treats each `text` chunk's content as
|
|
24577
|
+
* the full (replacing) bubble body, so a final `done:true` carrying the
|
|
24578
|
+
* bubble overwrites whatever raw text streamed. Used when the agent's
|
|
24579
|
+
* completed-turn reply was itself an auth-failure notice
|
|
24580
|
+
* ({@link replyIsAuthFailure}) → swap the raw "Please run /login" for the
|
|
24581
|
+
* actionable re-auth bubble.
|
|
24582
|
+
*/
|
|
24583
|
+
async closeWithBubble(bubble) {
|
|
24584
|
+
this.text = "";
|
|
24585
|
+
await Promise.all([
|
|
24586
|
+
this.publisher.publishOutput({ type: "text", content: bubble, done: true }),
|
|
24587
|
+
this.flushStreamingChunks()
|
|
24588
|
+
]);
|
|
24589
|
+
}
|
|
24453
24590
|
/**
|
|
24454
24591
|
* Re-emit every open streaming-chunk buffer with `isFinal: true`
|
|
24455
24592
|
* so SessionDetailScreen's bubbles flip out of "still streaming"
|
|
@@ -24617,6 +24754,10 @@ var AUTH_FAILURE_RE = /invalid authentication credentials|authentication[_ ]erro
|
|
|
24617
24754
|
function looksLikeAuthFailure(text) {
|
|
24618
24755
|
return AUTH_FAILURE_RE.test(text);
|
|
24619
24756
|
}
|
|
24757
|
+
function replyIsAuthFailure(finalText) {
|
|
24758
|
+
const t2 = finalText.trim();
|
|
24759
|
+
return t2.length > 0 && t2.length <= 200 && looksLikeAuthFailure(t2);
|
|
24760
|
+
}
|
|
24620
24761
|
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
24762
|
var TURN_FAILURE_MESSAGE = "\u26A0\uFE0F **The agent hit an error and couldn\u2019t finish this turn.** Please send your message again.";
|
|
24622
24763
|
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;
|
|
@@ -24626,46 +24767,17 @@ function looksLikeProviderOutage(text) {
|
|
|
24626
24767
|
function agentStatusPage(agent) {
|
|
24627
24768
|
const a = (agent ?? "").toLowerCase();
|
|
24628
24769
|
if (a.includes("claude") || a.includes("anthropic"))
|
|
24629
|
-
return {
|
|
24630
|
-
vendor: "Anthropic",
|
|
24631
|
-
url: "https://status.anthropic.com",
|
|
24632
|
-
statusApi: "https://status.anthropic.com/api/v2/status.json"
|
|
24633
|
-
};
|
|
24770
|
+
return { vendor: "Anthropic", url: "https://status.anthropic.com" };
|
|
24634
24771
|
if (a.includes("codex") || a.includes("openai"))
|
|
24635
|
-
return {
|
|
24636
|
-
vendor: "OpenAI",
|
|
24637
|
-
url: "https://status.openai.com",
|
|
24638
|
-
statusApi: "https://status.openai.com/api/v2/status.json"
|
|
24639
|
-
};
|
|
24772
|
+
return { vendor: "OpenAI", url: "https://status.openai.com" };
|
|
24640
24773
|
if (a.includes("gemini") || a.includes("google"))
|
|
24641
24774
|
return { vendor: "Google", url: "https://status.cloud.google.com" };
|
|
24642
24775
|
if (a.includes("copilot"))
|
|
24643
|
-
return {
|
|
24644
|
-
vendor: "GitHub",
|
|
24645
|
-
url: "https://www.githubstatus.com",
|
|
24646
|
-
statusApi: "https://www.githubstatus.com/api/v2/status.json"
|
|
24647
|
-
};
|
|
24776
|
+
return { vendor: "GitHub", url: "https://www.githubstatus.com" };
|
|
24648
24777
|
if (a.includes("cursor"))
|
|
24649
|
-
return {
|
|
24650
|
-
vendor: "Cursor",
|
|
24651
|
-
url: "https://status.cursor.com",
|
|
24652
|
-
statusApi: "https://status.cursor.com/api/v2/status.json"
|
|
24653
|
-
};
|
|
24778
|
+
return { vendor: "Cursor", url: "https://status.cursor.com" };
|
|
24654
24779
|
return null;
|
|
24655
24780
|
}
|
|
24656
|
-
async function checkProviderStatus(agent, fetchImpl = fetch) {
|
|
24657
|
-
const info = agentStatusPage(agent);
|
|
24658
|
-
if (!info?.statusApi) return false;
|
|
24659
|
-
try {
|
|
24660
|
-
const res = await withTimeout(fetchImpl(info.statusApi), 4e3);
|
|
24661
|
-
if (!res || !res.ok) return false;
|
|
24662
|
-
const body = await res.json();
|
|
24663
|
-
const indicator = body?.status?.indicator;
|
|
24664
|
-
return typeof indicator === "string" && indicator.toLowerCase() !== "none";
|
|
24665
|
-
} catch {
|
|
24666
|
-
return false;
|
|
24667
|
-
}
|
|
24668
|
-
}
|
|
24669
24781
|
function providerOutageMessage(agent) {
|
|
24670
24782
|
const info = agentStatusPage(agent);
|
|
24671
24783
|
const who = info ? info.vendor : "The agent provider";
|
|
@@ -24751,9 +24863,11 @@ async function runAcpSession(opts) {
|
|
|
24751
24863
|
}
|
|
24752
24864
|
});
|
|
24753
24865
|
let updateCount = 0;
|
|
24754
|
-
const
|
|
24866
|
+
const disable1mContext = loadCliConfig().sessions.find((s) => s.pluginId === opts.pluginId)?.disable1mContext === true;
|
|
24867
|
+
const clientOptions = {
|
|
24755
24868
|
adapter: opts.adapter,
|
|
24756
24869
|
cwd: opts.cwd,
|
|
24870
|
+
extraEnv: disable1mContext ? { CLAUDE_CODE_DISABLE_1M_CONTEXT: "1" } : {},
|
|
24757
24871
|
onSessionUpdate: (notification) => {
|
|
24758
24872
|
updateCount += 1;
|
|
24759
24873
|
const variant = notification.update?.sessionUpdate ?? "unknown";
|
|
@@ -24818,6 +24932,39 @@ async function runAcpSession(opts) {
|
|
|
24818
24932
|
process.exit(1);
|
|
24819
24933
|
})();
|
|
24820
24934
|
}
|
|
24935
|
+
};
|
|
24936
|
+
let client2 = new AcpClient(clientOptions);
|
|
24937
|
+
const reconnectWith1mDisabled = async () => {
|
|
24938
|
+
setDisable1mContext(opts.pluginId, true);
|
|
24939
|
+
try {
|
|
24940
|
+
await client2.stop();
|
|
24941
|
+
} catch {
|
|
24942
|
+
}
|
|
24943
|
+
client2 = new AcpClient({ ...clientOptions, extraEnv: { CLAUDE_CODE_DISABLE_1M_CONTEXT: "1" } });
|
|
24944
|
+
await client2.start();
|
|
24945
|
+
};
|
|
24946
|
+
const oneMRecovery = createOneMRecovery({
|
|
24947
|
+
publishText: (text) => publisher.publishOutput({ type: "text", content: text, done: true }),
|
|
24948
|
+
publishSelectPrompt: (question, options) => publisher.publishOutput({
|
|
24949
|
+
type: "select_prompt",
|
|
24950
|
+
content: question,
|
|
24951
|
+
options,
|
|
24952
|
+
optionDescriptions: options.map(() => ""),
|
|
24953
|
+
currentIndex: 0,
|
|
24954
|
+
done: true
|
|
24955
|
+
}),
|
|
24956
|
+
sendResult: (commandId, status2, result) => relay.sendResult(commandId, status2, result),
|
|
24957
|
+
appendAgentReply: (text) => history.appendAgentReply(text),
|
|
24958
|
+
flushHistory: () => void history.flush(),
|
|
24959
|
+
beginTurn: () => streaming.beginTurn(),
|
|
24960
|
+
getCurrentText: () => streaming.getCurrentText(),
|
|
24961
|
+
closeTurn: () => streaming.closeTurnWithInteractiveDetection(),
|
|
24962
|
+
recoverFromFailedTurn: () => recoverFromFailedTurn(client2, streaming),
|
|
24963
|
+
reconnectWith1mDisabled,
|
|
24964
|
+
promptAgent: (blocks) => client2.prompt(blocks),
|
|
24965
|
+
failureBubbleFor: (detail) => failureBubble({ detail, recentStderr: recentStderr.join("\n"), hadText: false, agent: opts.agent }),
|
|
24966
|
+
describeError,
|
|
24967
|
+
log: (msg) => log.info("acpRunner", msg)
|
|
24821
24968
|
});
|
|
24822
24969
|
showInfo(`Starting ${opts.agent} via ACP adapter (${opts.adapter.requiresAgentBinary})\u2026`);
|
|
24823
24970
|
const {
|
|
@@ -24912,7 +25059,8 @@ async function runAcpSession(opts) {
|
|
|
24912
25059
|
turnFiles,
|
|
24913
25060
|
getBeads,
|
|
24914
25061
|
publisher,
|
|
24915
|
-
recentStderr
|
|
25062
|
+
recentStderr,
|
|
25063
|
+
oneMRecovery
|
|
24916
25064
|
);
|
|
24917
25065
|
},
|
|
24918
25066
|
{ id: opts.agent, name: opts.agent, displayName: opts.agent }
|
|
@@ -24936,7 +25084,7 @@ async function runAcpSession(opts) {
|
|
|
24936
25084
|
await new Promise(() => {
|
|
24937
25085
|
});
|
|
24938
25086
|
}
|
|
24939
|
-
async function handleCommand(cmd, client2, relay, acpSessionId, models, streaming, opts, history, jsonlHistory, agentCaps, turnFiles, getBeads, publisher, recentStderr) {
|
|
25087
|
+
async function handleCommand(cmd, client2, relay, acpSessionId, models, streaming, opts, history, jsonlHistory, agentCaps, turnFiles, getBeads, publisher, recentStderr, oneMRecovery) {
|
|
24940
25088
|
switch (cmd.type) {
|
|
24941
25089
|
case "beads_action": {
|
|
24942
25090
|
const beads = getBeads();
|
|
@@ -24977,34 +25125,47 @@ async function handleCommand(cmd, client2, relay, acpSessionId, models, streamin
|
|
|
24977
25125
|
try {
|
|
24978
25126
|
const reply = await client2.prompt(blocks);
|
|
24979
25127
|
const finalText = streaming.getCurrentText();
|
|
24980
|
-
|
|
24981
|
-
|
|
24982
|
-
|
|
24983
|
-
|
|
25128
|
+
if (replyIsAuthFailure(finalText)) {
|
|
25129
|
+
await streaming.closeWithBubble(AUTH_FAILURE_MESSAGE);
|
|
25130
|
+
history.appendAgentReply(AUTH_FAILURE_MESSAGE);
|
|
25131
|
+
void history.flush();
|
|
25132
|
+
turnFiles.flushTurn().catch((err) => {
|
|
25133
|
+
log.warn("acpRunner", `turnFiles.flushTurn failed: ${describeError(err)}`);
|
|
25134
|
+
});
|
|
25135
|
+
void reportCredentialInvalid(opts);
|
|
25136
|
+
log.info("acpRunner", `start_task \u2190 auth-failure-in-reply id=${cmd.id.slice(0, 8)}`);
|
|
25137
|
+
await relay.sendResult(cmd.id, "failed", { error: "agent reply reported auth failure" });
|
|
25138
|
+
} else if (shouldOfferOneMRecovery({ detail: "", recentStderr: recentStderr.join("\n"), finalText })) {
|
|
25139
|
+
await oneMRecovery.offer(cmd.id, blocks);
|
|
25140
|
+
} else {
|
|
25141
|
+
await streaming.closeTurnWithInteractiveDetection();
|
|
25142
|
+
const replyLine = formatAgentReplyLine(finalText);
|
|
25143
|
+
if (replyLine.length > 0) {
|
|
25144
|
+
showInfo(replyLine);
|
|
25145
|
+
}
|
|
25146
|
+
history.appendAgentReply(finalText);
|
|
25147
|
+
void history.flush();
|
|
25148
|
+
turnFiles.flushTurn().catch((err) => {
|
|
25149
|
+
log.warn("acpRunner", `turnFiles.flushTurn failed: ${describeError(err)}`);
|
|
25150
|
+
});
|
|
25151
|
+
log.info("acpRunner", `start_task \u2190 done stopReason=${reply.stopReason ?? "?"} id=${cmd.id.slice(0, 8)}`);
|
|
25152
|
+
await relay.sendResult(cmd.id, "completed", { stopReason: reply.stopReason });
|
|
24984
25153
|
}
|
|
24985
|
-
history.appendAgentReply(finalText);
|
|
24986
|
-
void history.flush();
|
|
24987
|
-
turnFiles.flushTurn().catch((err) => {
|
|
24988
|
-
log.warn("acpRunner", `turnFiles.flushTurn failed: ${describeError(err)}`);
|
|
24989
|
-
});
|
|
24990
|
-
log.info("acpRunner", `start_task \u2190 done stopReason=${reply.stopReason ?? "?"} id=${cmd.id.slice(0, 8)}`);
|
|
24991
|
-
await relay.sendResult(cmd.id, "completed", { stopReason: reply.stopReason });
|
|
24992
25154
|
} catch (err) {
|
|
24993
25155
|
const hadText = streaming.getCurrentText().trim().length > 0;
|
|
24994
25156
|
await recoverFromFailedTurn(client2, streaming);
|
|
24995
25157
|
const detail = describeError(err);
|
|
24996
25158
|
log.warn("acpRunner", `prompt failed: ${detail}`);
|
|
24997
|
-
|
|
25159
|
+
if (shouldOfferOneMRecovery({ detail, recentStderr: recentStderr.join("\n"), finalText: "" })) {
|
|
25160
|
+
await oneMRecovery.offer(cmd.id, blocks);
|
|
25161
|
+
return;
|
|
25162
|
+
}
|
|
25163
|
+
const bubble = failureBubble({
|
|
24998
25164
|
detail,
|
|
24999
25165
|
recentStderr: recentStderr.join("\n"),
|
|
25000
25166
|
hadText,
|
|
25001
25167
|
agent: opts.agent
|
|
25002
25168
|
});
|
|
25003
|
-
if (bubble !== AUTH_FAILURE_MESSAGE && bubble !== providerOutageMessage(opts.agent)) {
|
|
25004
|
-
if (await checkProviderStatus(opts.agent)) {
|
|
25005
|
-
bubble = providerOutageMessage(opts.agent);
|
|
25006
|
-
}
|
|
25007
|
-
}
|
|
25008
25169
|
if (bubble) {
|
|
25009
25170
|
await publisher.publishOutput({ type: "text", content: bubble, done: true });
|
|
25010
25171
|
history.appendAgentReply(bubble);
|
|
@@ -25093,6 +25254,7 @@ async function handleCommand(cmd, client2, relay, acpSessionId, models, streamin
|
|
|
25093
25254
|
return;
|
|
25094
25255
|
}
|
|
25095
25256
|
case "select_option": {
|
|
25257
|
+
if (await oneMRecovery.tryRecover(cmd.id)) return;
|
|
25096
25258
|
const payload = cmd.payload;
|
|
25097
25259
|
const index = typeof payload?.index === "number" ? payload.index : 0;
|
|
25098
25260
|
const offset = typeof payload?.from === "number" ? payload.from : 0;
|
|
@@ -28936,9 +29098,9 @@ async function probeCodeamPair(provider, workspace) {
|
|
|
28936
29098
|
}
|
|
28937
29099
|
async function stopWorkspaceFromLocal(target) {
|
|
28938
29100
|
if (target.provider.id === "github-codespaces") {
|
|
28939
|
-
const { execFile:
|
|
29101
|
+
const { execFile: execFile13 } = await import("child_process");
|
|
28940
29102
|
const { promisify: promisify11 } = await import("util");
|
|
28941
|
-
const execFileP10 = promisify11(
|
|
29103
|
+
const execFileP10 = promisify11(execFile13);
|
|
28942
29104
|
await execFileP10("gh", ["codespace", "stop", "-c", target.id], { maxBuffer: 8 * 1024 * 1024 });
|
|
28943
29105
|
return;
|
|
28944
29106
|
}
|
|
@@ -29162,7 +29324,7 @@ function checkChokidar() {
|
|
|
29162
29324
|
}
|
|
29163
29325
|
async function doctor(args2 = []) {
|
|
29164
29326
|
const json = args2.includes("--json");
|
|
29165
|
-
const cliVersion = true ? "2.
|
|
29327
|
+
const cliVersion = true ? "2.43.0" : "0.0.0-dev";
|
|
29166
29328
|
const apiBase2 = resolveApiBaseUrl();
|
|
29167
29329
|
const diagnosticId = (0, import_node_crypto8.randomUUID)();
|
|
29168
29330
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -29361,7 +29523,7 @@ async function completion(args2) {
|
|
|
29361
29523
|
// src/commands/version.ts
|
|
29362
29524
|
var import_picocolors14 = __toESM(require("picocolors"));
|
|
29363
29525
|
function version2() {
|
|
29364
|
-
const v = true ? "2.
|
|
29526
|
+
const v = true ? "2.43.0" : "unknown";
|
|
29365
29527
|
console.log(`${import_picocolors14.default.bold("codeam-cli")} ${import_picocolors14.default.cyan(v)}`);
|
|
29366
29528
|
}
|
|
29367
29529
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.43.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",
|