codeam-cli 2.65.6 → 2.65.8
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 +13 -0
- package/dist/index.js +149 -37
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,19 @@ 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.65.7] — 2026-08-15
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **cli:** Honest credential/empty-turn errors + partial-fence holdback
|
|
12
|
+
- **cli:** Credential error propagation matches the real transport error shape
|
|
13
|
+
|
|
14
|
+
## [2.65.6] — 2026-08-15
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- **cli:** Accumulated stream keeps post-cut deltas + unclosed trailing fence tolerated
|
|
19
|
+
|
|
7
20
|
## [2.65.4] — 2026-08-14
|
|
8
21
|
|
|
9
22
|
### Fixed
|
package/dist/index.js
CHANGED
|
@@ -8079,7 +8079,7 @@ function readAnonId() {
|
|
|
8079
8079
|
}
|
|
8080
8080
|
function superProperties() {
|
|
8081
8081
|
return {
|
|
8082
|
-
cliVersion: true ? "2.65.
|
|
8082
|
+
cliVersion: true ? "2.65.8" : "0.0.0-dev",
|
|
8083
8083
|
nodeVersion: process.version,
|
|
8084
8084
|
platform: process.platform,
|
|
8085
8085
|
arch: process.arch,
|
|
@@ -8260,7 +8260,7 @@ var os4 = __toESM(require("os"));
|
|
|
8260
8260
|
// package.json
|
|
8261
8261
|
var package_default = {
|
|
8262
8262
|
name: "codeam-cli",
|
|
8263
|
-
version: "2.65.
|
|
8263
|
+
version: "2.65.8",
|
|
8264
8264
|
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.",
|
|
8265
8265
|
type: "commonjs",
|
|
8266
8266
|
main: "dist/index.js",
|
|
@@ -8632,7 +8632,19 @@ async function postHeadroomEvent(input) {
|
|
|
8632
8632
|
};
|
|
8633
8633
|
}
|
|
8634
8634
|
}
|
|
8635
|
-
|
|
8635
|
+
function parseBackendErrorBody(body) {
|
|
8636
|
+
if (!body) return null;
|
|
8637
|
+
try {
|
|
8638
|
+
const parsed = JSON.parse(body);
|
|
8639
|
+
const nested = parsed.error;
|
|
8640
|
+
const code = typeof nested?.code === "string" ? nested.code : typeof parsed.code === "string" ? parsed.code : void 0;
|
|
8641
|
+
const message = typeof nested?.message === "string" ? nested.message : typeof parsed.message === "string" ? parsed.message : void 0;
|
|
8642
|
+
return code || message ? { code, message } : null;
|
|
8643
|
+
} catch {
|
|
8644
|
+
return null;
|
|
8645
|
+
}
|
|
8646
|
+
}
|
|
8647
|
+
async function fetchProvisionCredentialDetailed(input) {
|
|
8636
8648
|
try {
|
|
8637
8649
|
const res = await _transport.postJsonAuthed(
|
|
8638
8650
|
`${API_BASE}/api/plugin/agents/${input.agentId}/provision-credential`,
|
|
@@ -8646,16 +8658,29 @@ async function fetchProvisionCredential(input) {
|
|
|
8646
8658
|
const data = res?.data;
|
|
8647
8659
|
if (data && (data.method === "api_key" || data.method === "oauth") && typeof data.credential === "string" && data.credential.length > 0) {
|
|
8648
8660
|
return {
|
|
8661
|
+
ok: true,
|
|
8649
8662
|
method: data.method,
|
|
8650
8663
|
credential: data.credential,
|
|
8651
8664
|
...typeof data.installScript === "string" && data.installScript.length > 0 ? { installScript: data.installScript } : {}
|
|
8652
8665
|
};
|
|
8653
8666
|
}
|
|
8654
|
-
return
|
|
8655
|
-
} catch {
|
|
8656
|
-
|
|
8667
|
+
return { ok: false, status: 0 };
|
|
8668
|
+
} catch (err) {
|
|
8669
|
+
const e = err;
|
|
8670
|
+
const status2 = typeof e.statusCode === "number" ? e.statusCode : 0;
|
|
8671
|
+
const parsed = parseBackendErrorBody(e.body);
|
|
8672
|
+
return { ok: false, status: status2, code: parsed?.code, message: parsed?.message };
|
|
8657
8673
|
}
|
|
8658
8674
|
}
|
|
8675
|
+
async function fetchProvisionCredential(input) {
|
|
8676
|
+
const res = await fetchProvisionCredentialDetailed(input);
|
|
8677
|
+
if (!res.ok) return null;
|
|
8678
|
+
return {
|
|
8679
|
+
method: res.method,
|
|
8680
|
+
credential: res.credential,
|
|
8681
|
+
...res.installScript ? { installScript: res.installScript } : {}
|
|
8682
|
+
};
|
|
8683
|
+
}
|
|
8659
8684
|
async function fetchSquadRoster(input) {
|
|
8660
8685
|
try {
|
|
8661
8686
|
const res = await _transport.postJsonAuthed(
|
|
@@ -8860,6 +8885,7 @@ function makeHttpError(statusCode, retryAfterHeader, responseBody) {
|
|
|
8860
8885
|
);
|
|
8861
8886
|
err.statusCode = statusCode;
|
|
8862
8887
|
if (typeof retryAfterSeconds === "number") err.retryAfterSeconds = retryAfterSeconds;
|
|
8888
|
+
if (responseBody) err.body = responseBody;
|
|
8863
8889
|
return err;
|
|
8864
8890
|
}
|
|
8865
8891
|
async function _postJson(url2, body, extraHeaders) {
|
|
@@ -9332,18 +9358,20 @@ var API_BASE2 = resolveApiBaseUrl();
|
|
|
9332
9358
|
var SSE_LIVENESS_TIMEOUT_MS = 45e3;
|
|
9333
9359
|
var SSE_WATCHDOG_INTERVAL_MS = 1e4;
|
|
9334
9360
|
var CommandRelayService = class _CommandRelayService {
|
|
9335
|
-
constructor(pluginId, onCommand, agentMeta, agentsOverride, explicitPollSecret) {
|
|
9361
|
+
constructor(pluginId, onCommand, agentMeta, agentsOverride, explicitPollSecret, onHeartbeat) {
|
|
9336
9362
|
this.pluginId = pluginId;
|
|
9337
9363
|
this.onCommand = onCommand;
|
|
9338
9364
|
this.agentMeta = agentMeta;
|
|
9339
9365
|
this.agentsOverride = agentsOverride;
|
|
9340
9366
|
this.explicitPollSecret = explicitPollSecret;
|
|
9367
|
+
this.onHeartbeat = onHeartbeat;
|
|
9341
9368
|
}
|
|
9342
9369
|
pluginId;
|
|
9343
9370
|
onCommand;
|
|
9344
9371
|
agentMeta;
|
|
9345
9372
|
agentsOverride;
|
|
9346
9373
|
explicitPollSecret;
|
|
9374
|
+
onHeartbeat;
|
|
9347
9375
|
_running = false;
|
|
9348
9376
|
pairingInvalid = false;
|
|
9349
9377
|
heartbeatTimer = null;
|
|
@@ -9406,16 +9434,35 @@ var CommandRelayService = class _CommandRelayService {
|
|
|
9406
9434
|
* freshness, and a punctual heartbeat matters far more.
|
|
9407
9435
|
*/
|
|
9408
9436
|
cachedBranch = null;
|
|
9437
|
+
/**
|
|
9438
|
+
* Set whenever the command channel is (re-)established; consumed by the
|
|
9439
|
+
* next {@link emitHeartbeatTick}. See the `onHeartbeat` ctor param.
|
|
9440
|
+
*/
|
|
9441
|
+
heartbeatFirstAfterConnect = true;
|
|
9442
|
+
/** Invoke the heartbeat rider (if any) exactly once per beat. Never throws. */
|
|
9443
|
+
emitHeartbeatTick() {
|
|
9444
|
+
if (!this.onHeartbeat) return;
|
|
9445
|
+
const firstAfterConnect = this.heartbeatFirstAfterConnect;
|
|
9446
|
+
this.heartbeatFirstAfterConnect = false;
|
|
9447
|
+
try {
|
|
9448
|
+
this.onHeartbeat({ firstAfterConnect });
|
|
9449
|
+
} catch (err) {
|
|
9450
|
+
log.trace("relay", "heartbeat rider threw (ignored)", err);
|
|
9451
|
+
}
|
|
9452
|
+
}
|
|
9409
9453
|
start() {
|
|
9410
9454
|
this.cleanup();
|
|
9411
9455
|
this._running = true;
|
|
9456
|
+
this.heartbeatFirstAfterConnect = true;
|
|
9412
9457
|
this.agentsRegistered = false;
|
|
9413
9458
|
log.info("relay", `start pluginId=${this.pluginId.slice(0, 8)} agent=${this.agentMeta.id}`);
|
|
9414
9459
|
this.cachedBranch = detectCurrentBranch();
|
|
9415
9460
|
this.sendHeartbeat(true);
|
|
9461
|
+
this.emitHeartbeatTick();
|
|
9416
9462
|
this.heartbeatTimer = setInterval(() => {
|
|
9417
9463
|
void this.refreshBranch();
|
|
9418
9464
|
this.sendHeartbeat(true);
|
|
9465
|
+
this.emitHeartbeatTick();
|
|
9419
9466
|
}, 2e4);
|
|
9420
9467
|
this.agentsTimer = setInterval(() => {
|
|
9421
9468
|
if (this._running && !this.agentsRegistered) this.reportAgents();
|
|
@@ -9499,6 +9546,7 @@ var CommandRelayService = class _CommandRelayService {
|
|
|
9499
9546
|
}
|
|
9500
9547
|
log.info("relay", "sse connected");
|
|
9501
9548
|
this.sseFailures = 0;
|
|
9549
|
+
this.heartbeatFirstAfterConnect = true;
|
|
9502
9550
|
this.armSseWatchdog();
|
|
9503
9551
|
let buffer = "";
|
|
9504
9552
|
res.setEncoding("utf8");
|
|
@@ -9616,6 +9664,7 @@ var CommandRelayService = class _CommandRelayService {
|
|
|
9616
9664
|
// ─── Polling fallback ────────────────────────────────────────────
|
|
9617
9665
|
startPollingFallback() {
|
|
9618
9666
|
if (this.pollTimer) return;
|
|
9667
|
+
this.heartbeatFirstAfterConnect = true;
|
|
9619
9668
|
void this.pollLoop();
|
|
9620
9669
|
}
|
|
9621
9670
|
async pollLoop() {
|
|
@@ -9712,7 +9761,7 @@ var CommandRelayService = class _CommandRelayService {
|
|
|
9712
9761
|
// fresh + clear the "CLI update available" banner after a self-update
|
|
9713
9762
|
// (a codespace that reinstalls @latest reconnects via heartbeat, not
|
|
9714
9763
|
// pair/reconnect). Older backends ignore the extra field.
|
|
9715
|
-
..."2.65.
|
|
9764
|
+
..."2.65.8" ? { ideVersion: "2.65.8" } : {}
|
|
9716
9765
|
}).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
|
|
9717
9766
|
}
|
|
9718
9767
|
/**
|
|
@@ -21641,7 +21690,7 @@ async function autoUpgradeBeforeCriticalCommand() {
|
|
|
21641
21690
|
if (process.env.NODE_ENV === "test") return;
|
|
21642
21691
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
21643
21692
|
if (process.env.CI) return;
|
|
21644
|
-
const current2 = true ? "2.65.
|
|
21693
|
+
const current2 = true ? "2.65.8" : null;
|
|
21645
21694
|
if (!current2) return;
|
|
21646
21695
|
const cache = readCache();
|
|
21647
21696
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -21658,7 +21707,7 @@ function checkForUpdates() {
|
|
|
21658
21707
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
21659
21708
|
if (process.env.CI) return;
|
|
21660
21709
|
if (!process.stdout.isTTY) return;
|
|
21661
|
-
const current2 = true ? "2.65.
|
|
21710
|
+
const current2 = true ? "2.65.8" : null;
|
|
21662
21711
|
if (!current2) return;
|
|
21663
21712
|
const cache = readCache();
|
|
21664
21713
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -21678,7 +21727,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
|
21678
21727
|
var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
|
|
21679
21728
|
var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
|
|
21680
21729
|
function currentCliVersion() {
|
|
21681
|
-
return true ? "2.65.
|
|
21730
|
+
return true ? "2.65.8" : null;
|
|
21682
21731
|
}
|
|
21683
21732
|
function runCmd(cmd, args2, timeoutMs) {
|
|
21684
21733
|
return new Promise((resolve9) => {
|
|
@@ -34738,6 +34787,10 @@ var NON_SWITCHABLE = /* @__PURE__ */ new Set([
|
|
|
34738
34787
|
function displayName(id) {
|
|
34739
34788
|
return isKnownAgentId(id) ? AGENT_REGISTRY[id]?.displayName ?? id : id;
|
|
34740
34789
|
}
|
|
34790
|
+
function credentialFailureMessage(agentId, failure) {
|
|
34791
|
+
if (failure.message) return failure.message;
|
|
34792
|
+
return `No linked credential for ${displayName(agentId)}. Link it in Profile \u203A Agents first.`;
|
|
34793
|
+
}
|
|
34741
34794
|
function resolveSwitchTarget(raw, currentAgent) {
|
|
34742
34795
|
if (typeof raw !== "string" || raw.length === 0) {
|
|
34743
34796
|
return { ok: false, error: "switch_agent: missing agentId" };
|
|
@@ -34854,10 +34907,8 @@ async function performAgentSwitch(deps, rawAgentId, fastPath = {}) {
|
|
|
34854
34907
|
if (!fastPath.skipProvision) {
|
|
34855
34908
|
void emitStep("credential");
|
|
34856
34909
|
const cred = await deps.fetchCredential(agentId);
|
|
34857
|
-
if (!cred) {
|
|
34858
|
-
return fail2(
|
|
34859
|
-
`No linked credential for ${displayName(agentId)}. Link it in Profile \u203A Agents first.`
|
|
34860
|
-
);
|
|
34910
|
+
if (!cred.ok) {
|
|
34911
|
+
return fail2(credentialFailureMessage(agentId, cred));
|
|
34861
34912
|
}
|
|
34862
34913
|
try {
|
|
34863
34914
|
deps.provisionCredential(agentId, toAgentAuth(cred.method, cred.credential));
|
|
@@ -35574,6 +35625,15 @@ function handoffFenceStartMasked(text) {
|
|
|
35574
35625
|
}
|
|
35575
35626
|
return -1;
|
|
35576
35627
|
}
|
|
35628
|
+
function withholdTrailingPartialFenceMarker(text) {
|
|
35629
|
+
const maxLen = Math.min(text.length, FENCE_OPEN.length - 1);
|
|
35630
|
+
for (let len = maxLen; len > 0; len--) {
|
|
35631
|
+
if (FENCE_OPEN.startsWith(text.slice(text.length - len))) {
|
|
35632
|
+
return text.slice(0, text.length - len);
|
|
35633
|
+
}
|
|
35634
|
+
}
|
|
35635
|
+
return text;
|
|
35636
|
+
}
|
|
35577
35637
|
|
|
35578
35638
|
// src/agents/acp/onboarding.ts
|
|
35579
35639
|
var import_child_process28 = require("child_process");
|
|
@@ -36608,6 +36668,11 @@ var AUTH_FAILURE_MESSAGE = "\u{1F512} **Authentication failed \u2014 your agent
|
|
|
36608
36668
|
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)";
|
|
36609
36669
|
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.";
|
|
36610
36670
|
var TURN_FAILURE_MESSAGE = "\u26A0\uFE0F **The agent hit an error and couldn\u2019t finish this turn.** Please send your message again.";
|
|
36671
|
+
function emptyReplyMessage(agent) {
|
|
36672
|
+
const label = isKnownAgentId(agent) ? AGENT_REGISTRY[agent].displayName : agent;
|
|
36673
|
+
const binary = isKnownAgentId(agent) ? AGENT_REGISTRY[agent].binaryName : agent;
|
|
36674
|
+
return `\u26A0\uFE0F **${label} returned an empty reply.** Its provider may be having issues \u2014 check the agent's login/subscription on this machine (e.g. run \`${binary} -p "test"\` there).`;
|
|
36675
|
+
}
|
|
36611
36676
|
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;
|
|
36612
36677
|
function looksLikeProviderOutage(text) {
|
|
36613
36678
|
return PROVIDER_OUTAGE_RE.test(text);
|
|
@@ -36643,12 +36708,10 @@ ${recentStderr}`;
|
|
|
36643
36708
|
if (looksLikeAuthFailure(haystack2)) return AUTH_FAILURE_MESSAGE;
|
|
36644
36709
|
if (looksLikeProviderOutage(haystack2)) return providerOutageMessage(agent);
|
|
36645
36710
|
const tail = recentStderr.split("\n").filter(Boolean).slice(-3).join("\n");
|
|
36646
|
-
return [
|
|
36647
|
-
|
|
36648
|
-
""
|
|
36649
|
-
|
|
36650
|
-
${tail}` : detail
|
|
36651
|
-
].join("\n");
|
|
36711
|
+
return [`\u26A0\uFE0F The ${agent} agent failed to start.`, "", tail ? `Details:
|
|
36712
|
+
${tail}` : detail].join(
|
|
36713
|
+
"\n"
|
|
36714
|
+
);
|
|
36652
36715
|
}
|
|
36653
36716
|
function budgetBubbleMessage(agent, period) {
|
|
36654
36717
|
return `\u{1F4B8} **Headroom budget reached for the ${period} period.**
|
|
@@ -38064,6 +38127,18 @@ async function startTaskH(ctx) {
|
|
|
38064
38127
|
error: "agent reply reported 1M-context usage-credits gate"
|
|
38065
38128
|
});
|
|
38066
38129
|
return;
|
|
38130
|
+
} else if (reply.stopReason === "end_turn" && finalText.trim().length === 0 && !streaming.hasVisibleProgress()) {
|
|
38131
|
+
const bubble = emptyReplyMessage(opts.agent);
|
|
38132
|
+
await streaming.closeWithBubble(bubble);
|
|
38133
|
+
turnClosed = true;
|
|
38134
|
+
history.appendAgentReply(bubble);
|
|
38135
|
+
void history.flush();
|
|
38136
|
+
turnFiles.flushTurn().catch((err) => {
|
|
38137
|
+
log.warn("acpRunner", `turnFiles.flushTurn failed: ${describeError(err)}`);
|
|
38138
|
+
});
|
|
38139
|
+
log.info("acpRunner", `start_task \u2190 empty-reply id=${cmd.id.slice(0, 8)}`);
|
|
38140
|
+
await relay.sendResult(cmd.id, "failed", { error: "agent turn ended with an empty reply" });
|
|
38141
|
+
return;
|
|
38067
38142
|
} else {
|
|
38068
38143
|
await streaming.closeTurnWithInteractiveDetection();
|
|
38069
38144
|
turnClosed = true;
|
|
@@ -38956,13 +39031,14 @@ var StreamingState = class {
|
|
|
38956
39031
|
const cumulativeContent = reconcileCumulative(existing?.content ?? "", delta.delta);
|
|
38957
39032
|
this.streamingChunks.set(chunkId, { kind: delta.kind, content: cumulativeContent });
|
|
38958
39033
|
let fenceCut = -1;
|
|
39034
|
+
let textVisible = null;
|
|
38959
39035
|
if (delta.kind === "text") {
|
|
38960
39036
|
this.recomputeText();
|
|
38961
39037
|
fenceCut = handoffFenceStartMasked(this.text);
|
|
38962
|
-
|
|
38963
|
-
void this.publisher.publishOutput({ type: "text", content:
|
|
39038
|
+
textVisible = fenceCut === -1 ? withholdTrailingPartialFenceMarker(this.text) : this.text.slice(0, fenceCut).trimEnd();
|
|
39039
|
+
void this.publisher.publishOutput({ type: "text", content: textVisible, done: false });
|
|
38964
39040
|
}
|
|
38965
|
-
const visibleChunkContent = delta.kind === "text"
|
|
39041
|
+
const visibleChunkContent = delta.kind === "text" ? textVisible : cumulativeContent;
|
|
38966
39042
|
void this.publisher.publishStreamingChunk({
|
|
38967
39043
|
chunkId,
|
|
38968
39044
|
kind: delta.kind,
|
|
@@ -39697,7 +39773,7 @@ async function runAcpSession(opts) {
|
|
|
39697
39773
|
const switchDeps = {
|
|
39698
39774
|
currentAgent: () => opts.agent,
|
|
39699
39775
|
postEvent: emitSwitchEvent,
|
|
39700
|
-
fetchCredential: (agentId) =>
|
|
39776
|
+
fetchCredential: (agentId) => fetchProvisionCredentialDetailed({
|
|
39701
39777
|
agentId,
|
|
39702
39778
|
sessionId: opts.sessionId,
|
|
39703
39779
|
pluginId: opts.pluginId,
|
|
@@ -40956,6 +41032,17 @@ var BatonController = class {
|
|
|
40956
41032
|
get conversationId() {
|
|
40957
41033
|
return this._conversationId;
|
|
40958
41034
|
}
|
|
41035
|
+
/** The exact triple the last `publishState` emitted — the CLI's current view
|
|
41036
|
+
* of who holds the baton. Read by the heartbeat re-affirmation rider
|
|
41037
|
+
* ({@link makeBatonHeartbeatReaffirm}), which re-posts it periodically so the
|
|
41038
|
+
* backend's 1 h Redis snapshot never expires under a live session. */
|
|
41039
|
+
currentState() {
|
|
41040
|
+
return {
|
|
41041
|
+
state: this._state,
|
|
41042
|
+
driver: this._active,
|
|
41043
|
+
conversationId: this._conversationId
|
|
41044
|
+
};
|
|
41045
|
+
}
|
|
40959
41046
|
async begin() {
|
|
40960
41047
|
this._conversationId = await this.deps.local.start(void 0);
|
|
40961
41048
|
this._active = "local_tui";
|
|
@@ -41431,6 +41518,21 @@ function makeSerializedBatonPoster(post2) {
|
|
|
41431
41518
|
void chain;
|
|
41432
41519
|
};
|
|
41433
41520
|
}
|
|
41521
|
+
var BATON_REAFFIRM_INTERVAL_MS = 5 * 6e4;
|
|
41522
|
+
function makeBatonHeartbeatReaffirm(deps) {
|
|
41523
|
+
const now = deps.now ?? Date.now;
|
|
41524
|
+
const intervalMs = deps.intervalMs ?? BATON_REAFFIRM_INTERVAL_MS;
|
|
41525
|
+
let lastAffirmedAt = null;
|
|
41526
|
+
return ({ firstAfterConnect }) => {
|
|
41527
|
+
const current2 = deps.currentState();
|
|
41528
|
+
if (!current2) return;
|
|
41529
|
+
if (current2.state === "SWITCHING") return;
|
|
41530
|
+
const at3 = now();
|
|
41531
|
+
if (!firstAfterConnect && lastAffirmedAt !== null && at3 - lastAffirmedAt < intervalMs) return;
|
|
41532
|
+
lastAffirmedAt = at3;
|
|
41533
|
+
deps.publish(current2.state, current2.driver, current2.conversationId);
|
|
41534
|
+
};
|
|
41535
|
+
}
|
|
41434
41536
|
async function runBatonSession(opts) {
|
|
41435
41537
|
const publisher = new AcpPublisher({
|
|
41436
41538
|
sessionId: opts.sessionId,
|
|
@@ -41542,18 +41644,21 @@ async function runBatonSession(opts) {
|
|
|
41542
41644
|
mirror.start();
|
|
41543
41645
|
};
|
|
41544
41646
|
const postBatonState = makeSerializedBatonPoster(postBatonEvent);
|
|
41647
|
+
const publishBatonState = (state, driver, conversationId) => {
|
|
41648
|
+
postBatonState({
|
|
41649
|
+
sessionId: opts.sessionId,
|
|
41650
|
+
pluginId: opts.pluginId,
|
|
41651
|
+
pluginAuthToken: opts.pluginAuthToken,
|
|
41652
|
+
state,
|
|
41653
|
+
driver,
|
|
41654
|
+
conversationId
|
|
41655
|
+
});
|
|
41656
|
+
};
|
|
41545
41657
|
const controller = new BatonController({
|
|
41546
41658
|
local: nativeDriver,
|
|
41547
41659
|
mobile: mobileDriver,
|
|
41548
41660
|
publishState: (state, driver, conversationId) => {
|
|
41549
|
-
|
|
41550
|
-
sessionId: opts.sessionId,
|
|
41551
|
-
pluginId: opts.pluginId,
|
|
41552
|
-
pluginAuthToken: opts.pluginAuthToken,
|
|
41553
|
-
state,
|
|
41554
|
-
driver,
|
|
41555
|
-
conversationId
|
|
41556
|
-
});
|
|
41661
|
+
publishBatonState(state, driver, conversationId);
|
|
41557
41662
|
if (state === "LOCAL_DRIVE" && conversationId) {
|
|
41558
41663
|
startMirror(conversationId, firstLocalDrive);
|
|
41559
41664
|
firstLocalDrive = false;
|
|
@@ -41563,6 +41668,7 @@ async function runBatonSession(opts) {
|
|
|
41563
41668
|
}
|
|
41564
41669
|
});
|
|
41565
41670
|
const dispatchActive = (cmd) => controller.activeSessionDriver.dispatch(cmd);
|
|
41671
|
+
let torn = false;
|
|
41566
41672
|
relay = new CommandRelayService(
|
|
41567
41673
|
opts.pluginId,
|
|
41568
41674
|
makeOnCommand({
|
|
@@ -41570,9 +41676,15 @@ async function runBatonSession(opts) {
|
|
|
41570
41676
|
dispatchActive,
|
|
41571
41677
|
ack: (id, status2, result) => relay.sendResult(id, status2, result)
|
|
41572
41678
|
}),
|
|
41573
|
-
runtime.meta
|
|
41679
|
+
runtime.meta,
|
|
41680
|
+
void 0,
|
|
41681
|
+
void 0,
|
|
41682
|
+
makeBatonHeartbeatReaffirm({
|
|
41683
|
+
// Nothing to affirm once the session is torn down.
|
|
41684
|
+
currentState: () => torn ? null : controller.currentState(),
|
|
41685
|
+
publish: publishBatonState
|
|
41686
|
+
})
|
|
41574
41687
|
);
|
|
41575
|
-
let torn = false;
|
|
41576
41688
|
function teardown() {
|
|
41577
41689
|
if (torn) return;
|
|
41578
41690
|
torn = true;
|
|
@@ -44625,7 +44737,7 @@ function checkChokidar() {
|
|
|
44625
44737
|
}
|
|
44626
44738
|
async function doctor(args2 = []) {
|
|
44627
44739
|
const json = args2.includes("--json");
|
|
44628
|
-
const cliVersion = true ? "2.65.
|
|
44740
|
+
const cliVersion = true ? "2.65.8" : "0.0.0-dev";
|
|
44629
44741
|
const apiBase2 = resolveApiBaseUrl();
|
|
44630
44742
|
const diagnosticId = (0, import_node_crypto13.randomUUID)();
|
|
44631
44743
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -45016,7 +45128,7 @@ async function mcpRun(args2) {
|
|
|
45016
45128
|
// src/commands/version.ts
|
|
45017
45129
|
var import_picocolors15 = __toESM(require("picocolors"));
|
|
45018
45130
|
function version2() {
|
|
45019
|
-
const v = true ? "2.65.
|
|
45131
|
+
const v = true ? "2.65.8" : "unknown";
|
|
45020
45132
|
console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
|
|
45021
45133
|
}
|
|
45022
45134
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.65.
|
|
3
|
+
"version": "2.65.8",
|
|
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",
|