codeam-cli 2.65.6 → 2.65.7

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 CHANGED
@@ -4,6 +4,12 @@ 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.6] — 2026-08-15
8
+
9
+ ### Fixed
10
+
11
+ - **cli:** Accumulated stream keeps post-cut deltas + unclosed trailing fence tolerated
12
+
7
13
  ## [2.65.4] — 2026-08-14
8
14
 
9
15
  ### 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.6" : "0.0.0-dev",
8082
+ cliVersion: true ? "2.65.7" : "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.6",
8263
+ version: "2.65.7",
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
- async function fetchProvisionCredential(input) {
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 null;
8655
- } catch {
8656
- return null;
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) {
@@ -9712,7 +9738,7 @@ var CommandRelayService = class _CommandRelayService {
9712
9738
  // fresh + clear the "CLI update available" banner after a self-update
9713
9739
  // (a codespace that reinstalls @latest reconnects via heartbeat, not
9714
9740
  // pair/reconnect). Older backends ignore the extra field.
9715
- ..."2.65.6" ? { ideVersion: "2.65.6" } : {}
9741
+ ..."2.65.7" ? { ideVersion: "2.65.7" } : {}
9716
9742
  }).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
9717
9743
  }
9718
9744
  /**
@@ -21641,7 +21667,7 @@ async function autoUpgradeBeforeCriticalCommand() {
21641
21667
  if (process.env.NODE_ENV === "test") return;
21642
21668
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
21643
21669
  if (process.env.CI) return;
21644
- const current2 = true ? "2.65.6" : null;
21670
+ const current2 = true ? "2.65.7" : null;
21645
21671
  if (!current2) return;
21646
21672
  const cache = readCache();
21647
21673
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -21658,7 +21684,7 @@ function checkForUpdates() {
21658
21684
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
21659
21685
  if (process.env.CI) return;
21660
21686
  if (!process.stdout.isTTY) return;
21661
- const current2 = true ? "2.65.6" : null;
21687
+ const current2 = true ? "2.65.7" : null;
21662
21688
  if (!current2) return;
21663
21689
  const cache = readCache();
21664
21690
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -21678,7 +21704,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
21678
21704
  var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
21679
21705
  var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
21680
21706
  function currentCliVersion() {
21681
- return true ? "2.65.6" : null;
21707
+ return true ? "2.65.7" : null;
21682
21708
  }
21683
21709
  function runCmd(cmd, args2, timeoutMs) {
21684
21710
  return new Promise((resolve9) => {
@@ -34738,6 +34764,10 @@ var NON_SWITCHABLE = /* @__PURE__ */ new Set([
34738
34764
  function displayName(id) {
34739
34765
  return isKnownAgentId(id) ? AGENT_REGISTRY[id]?.displayName ?? id : id;
34740
34766
  }
34767
+ function credentialFailureMessage(agentId, failure) {
34768
+ if (failure.message) return failure.message;
34769
+ return `No linked credential for ${displayName(agentId)}. Link it in Profile \u203A Agents first.`;
34770
+ }
34741
34771
  function resolveSwitchTarget(raw, currentAgent) {
34742
34772
  if (typeof raw !== "string" || raw.length === 0) {
34743
34773
  return { ok: false, error: "switch_agent: missing agentId" };
@@ -34854,10 +34884,8 @@ async function performAgentSwitch(deps, rawAgentId, fastPath = {}) {
34854
34884
  if (!fastPath.skipProvision) {
34855
34885
  void emitStep("credential");
34856
34886
  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
- );
34887
+ if (!cred.ok) {
34888
+ return fail2(credentialFailureMessage(agentId, cred));
34861
34889
  }
34862
34890
  try {
34863
34891
  deps.provisionCredential(agentId, toAgentAuth(cred.method, cred.credential));
@@ -35574,6 +35602,15 @@ function handoffFenceStartMasked(text) {
35574
35602
  }
35575
35603
  return -1;
35576
35604
  }
35605
+ function withholdTrailingPartialFenceMarker(text) {
35606
+ const maxLen = Math.min(text.length, FENCE_OPEN.length - 1);
35607
+ for (let len = maxLen; len > 0; len--) {
35608
+ if (FENCE_OPEN.startsWith(text.slice(text.length - len))) {
35609
+ return text.slice(0, text.length - len);
35610
+ }
35611
+ }
35612
+ return text;
35613
+ }
35577
35614
 
35578
35615
  // src/agents/acp/onboarding.ts
35579
35616
  var import_child_process28 = require("child_process");
@@ -36608,6 +36645,11 @@ var AUTH_FAILURE_MESSAGE = "\u{1F512} **Authentication failed \u2014 your agent
36608
36645
  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
36646
  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
36647
  var TURN_FAILURE_MESSAGE = "\u26A0\uFE0F **The agent hit an error and couldn\u2019t finish this turn.** Please send your message again.";
36648
+ function emptyReplyMessage(agent) {
36649
+ const label = isKnownAgentId(agent) ? AGENT_REGISTRY[agent].displayName : agent;
36650
+ const binary = isKnownAgentId(agent) ? AGENT_REGISTRY[agent].binaryName : agent;
36651
+ 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).`;
36652
+ }
36611
36653
  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
36654
  function looksLikeProviderOutage(text) {
36613
36655
  return PROVIDER_OUTAGE_RE.test(text);
@@ -36643,12 +36685,10 @@ ${recentStderr}`;
36643
36685
  if (looksLikeAuthFailure(haystack2)) return AUTH_FAILURE_MESSAGE;
36644
36686
  if (looksLikeProviderOutage(haystack2)) return providerOutageMessage(agent);
36645
36687
  const tail = recentStderr.split("\n").filter(Boolean).slice(-3).join("\n");
36646
- return [
36647
- `\u26A0\uFE0F The ${agent} agent failed to start.`,
36648
- "",
36649
- tail ? `Details:
36650
- ${tail}` : detail
36651
- ].join("\n");
36688
+ return [`\u26A0\uFE0F The ${agent} agent failed to start.`, "", tail ? `Details:
36689
+ ${tail}` : detail].join(
36690
+ "\n"
36691
+ );
36652
36692
  }
36653
36693
  function budgetBubbleMessage(agent, period) {
36654
36694
  return `\u{1F4B8} **Headroom budget reached for the ${period} period.**
@@ -38064,6 +38104,18 @@ async function startTaskH(ctx) {
38064
38104
  error: "agent reply reported 1M-context usage-credits gate"
38065
38105
  });
38066
38106
  return;
38107
+ } else if (reply.stopReason === "end_turn" && finalText.trim().length === 0 && !streaming.hasVisibleProgress()) {
38108
+ const bubble = emptyReplyMessage(opts.agent);
38109
+ await streaming.closeWithBubble(bubble);
38110
+ turnClosed = true;
38111
+ history.appendAgentReply(bubble);
38112
+ void history.flush();
38113
+ turnFiles.flushTurn().catch((err) => {
38114
+ log.warn("acpRunner", `turnFiles.flushTurn failed: ${describeError(err)}`);
38115
+ });
38116
+ log.info("acpRunner", `start_task \u2190 empty-reply id=${cmd.id.slice(0, 8)}`);
38117
+ await relay.sendResult(cmd.id, "failed", { error: "agent turn ended with an empty reply" });
38118
+ return;
38067
38119
  } else {
38068
38120
  await streaming.closeTurnWithInteractiveDetection();
38069
38121
  turnClosed = true;
@@ -38956,13 +39008,14 @@ var StreamingState = class {
38956
39008
  const cumulativeContent = reconcileCumulative(existing?.content ?? "", delta.delta);
38957
39009
  this.streamingChunks.set(chunkId, { kind: delta.kind, content: cumulativeContent });
38958
39010
  let fenceCut = -1;
39011
+ let textVisible = null;
38959
39012
  if (delta.kind === "text") {
38960
39013
  this.recomputeText();
38961
39014
  fenceCut = handoffFenceStartMasked(this.text);
38962
- const visibleText = fenceCut === -1 ? this.text : this.text.slice(0, fenceCut).trimEnd();
38963
- void this.publisher.publishOutput({ type: "text", content: visibleText, done: false });
39015
+ textVisible = fenceCut === -1 ? withholdTrailingPartialFenceMarker(this.text) : this.text.slice(0, fenceCut).trimEnd();
39016
+ void this.publisher.publishOutput({ type: "text", content: textVisible, done: false });
38964
39017
  }
38965
- const visibleChunkContent = delta.kind === "text" && fenceCut !== -1 ? cumulativeContent.slice(0, fenceCut).trimEnd() : cumulativeContent;
39018
+ const visibleChunkContent = delta.kind === "text" ? textVisible : cumulativeContent;
38966
39019
  void this.publisher.publishStreamingChunk({
38967
39020
  chunkId,
38968
39021
  kind: delta.kind,
@@ -39697,7 +39750,7 @@ async function runAcpSession(opts) {
39697
39750
  const switchDeps = {
39698
39751
  currentAgent: () => opts.agent,
39699
39752
  postEvent: emitSwitchEvent,
39700
- fetchCredential: (agentId) => fetchProvisionCredential({
39753
+ fetchCredential: (agentId) => fetchProvisionCredentialDetailed({
39701
39754
  agentId,
39702
39755
  sessionId: opts.sessionId,
39703
39756
  pluginId: opts.pluginId,
@@ -44625,7 +44678,7 @@ function checkChokidar() {
44625
44678
  }
44626
44679
  async function doctor(args2 = []) {
44627
44680
  const json = args2.includes("--json");
44628
- const cliVersion = true ? "2.65.6" : "0.0.0-dev";
44681
+ const cliVersion = true ? "2.65.7" : "0.0.0-dev";
44629
44682
  const apiBase2 = resolveApiBaseUrl();
44630
44683
  const diagnosticId = (0, import_node_crypto13.randomUUID)();
44631
44684
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -45016,7 +45069,7 @@ async function mcpRun(args2) {
45016
45069
  // src/commands/version.ts
45017
45070
  var import_picocolors15 = __toESM(require("picocolors"));
45018
45071
  function version2() {
45019
- const v = true ? "2.65.6" : "unknown";
45072
+ const v = true ? "2.65.7" : "unknown";
45020
45073
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
45021
45074
  }
45022
45075
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.65.6",
3
+ "version": "2.65.7",
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",