codeam-cli 2.27.6 → 2.27.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.
Files changed (3) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/index.js +174 -71
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,18 @@ 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.27.7] — 2026-06-06
8
+
9
+ ### Fixed
10
+
11
+ - **cli:** ACP — wire-level instrumentation + prompt timeout
12
+
13
+ ## [2.27.6] — 2026-06-06
14
+
15
+ ### Fixed
16
+
17
+ - **cli:** ACP runner — ack every relay command + body envelope for auth
18
+
7
19
  ## [2.27.5] — 2026-06-06
8
20
 
9
21
  ### Chore
package/dist/index.js CHANGED
@@ -498,7 +498,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
498
498
  // package.json
499
499
  var package_default = {
500
500
  name: "codeam-cli",
501
- version: "2.27.6",
501
+ version: "2.27.8",
502
502
  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.",
503
503
  type: "commonjs",
504
504
  main: "dist/index.js",
@@ -889,8 +889,8 @@ async function _postJsonAuthed(url, body, pluginAuthToken) {
889
889
  (res) => {
890
890
  res.on("error", reject);
891
891
  let responseBody = "";
892
- res.on("data", (chunk2) => {
893
- responseBody += chunk2.toString();
892
+ res.on("data", (chunk) => {
893
+ responseBody += chunk.toString();
894
894
  });
895
895
  res.on("end", () => {
896
896
  if (res.statusCode && res.statusCode >= 400) {
@@ -937,8 +937,8 @@ async function _postJson(url, body) {
937
937
  (res) => {
938
938
  res.on("error", reject);
939
939
  let body2 = "";
940
- res.on("data", (chunk2) => {
941
- body2 += chunk2.toString();
940
+ res.on("data", (chunk) => {
941
+ body2 += chunk.toString();
942
942
  });
943
943
  res.on("end", () => {
944
944
  if (res.statusCode && res.statusCode >= 400) {
@@ -978,8 +978,8 @@ async function _getJson(url) {
978
978
  (res) => {
979
979
  res.on("error", reject);
980
980
  let body = "";
981
- res.on("data", (chunk2) => {
982
- body += chunk2.toString();
981
+ res.on("data", (chunk) => {
982
+ body += chunk.toString();
983
983
  });
984
984
  res.on("end", () => {
985
985
  if (res.statusCode && res.statusCode >= 400) {
@@ -5873,7 +5873,7 @@ function readAnonId() {
5873
5873
  }
5874
5874
  function superProperties() {
5875
5875
  return {
5876
- cliVersion: true ? "2.27.6" : "0.0.0-dev",
5876
+ cliVersion: true ? "2.27.8" : "0.0.0-dev",
5877
5877
  nodeVersion: process.version,
5878
5878
  platform: process.platform,
5879
5879
  arch: process.arch,
@@ -6080,9 +6080,9 @@ var CommandRelayService = class {
6080
6080
  this.armSseWatchdog();
6081
6081
  let buffer = "";
6082
6082
  res.setEncoding("utf8");
6083
- res.on("data", (chunk2) => {
6083
+ res.on("data", (chunk) => {
6084
6084
  this.sseLastByteAt = Date.now();
6085
- buffer += chunk2;
6085
+ buffer += chunk;
6086
6086
  let frameEnd;
6087
6087
  while ((frameEnd = buffer.indexOf("\n\n")) !== -1) {
6088
6088
  const frame = buffer.slice(0, frameEnd);
@@ -6751,9 +6751,9 @@ var UnixPtyStrategy = class {
6751
6751
  );
6752
6752
  process.exit(1);
6753
6753
  });
6754
- this.proc.stdout?.on("data", (chunk2) => {
6755
- process.stdout.write(chunk2);
6756
- this.opts.onData(chunk2.toString("utf8"));
6754
+ this.proc.stdout?.on("data", (chunk) => {
6755
+ process.stdout.write(chunk);
6756
+ this.opts.onData(chunk.toString("utf8"));
6757
6757
  });
6758
6758
  if (process.stdin.isTTY) process.stdin.setRawMode(true);
6759
6759
  process.stdin.resume();
@@ -6845,8 +6845,8 @@ var UnixPtyStrategy = class {
6845
6845
  }
6846
6846
  }
6847
6847
  }
6848
- stdinHandler = (chunk2) => {
6849
- this.proc?.stdin?.write(chunk2);
6848
+ stdinHandler = (chunk) => {
6849
+ this.proc?.stdin?.write(chunk);
6850
6850
  };
6851
6851
  handleResize = () => {
6852
6852
  if (this.proc?.pid) {
@@ -7032,8 +7032,8 @@ var WindowsConPtyStrategy = class _WindowsConPtyStrategy {
7032
7032
  }
7033
7033
  this.pty = null;
7034
7034
  }
7035
- stdinHandler = (chunk2) => {
7036
- this.pty?.write(chunk2.toString("utf8"));
7035
+ stdinHandler = (chunk) => {
7036
+ this.pty?.write(chunk.toString("utf8"));
7037
7037
  };
7038
7038
  };
7039
7039
 
@@ -7066,9 +7066,9 @@ var WindowsPtyStrategy = class {
7066
7066
  );
7067
7067
  process.exit(1);
7068
7068
  });
7069
- this.proc.stdout?.on("data", (chunk2) => {
7070
- process.stdout.write(chunk2);
7071
- this.opts.onData(chunk2.toString("utf8"));
7069
+ this.proc.stdout?.on("data", (chunk) => {
7070
+ process.stdout.write(chunk);
7071
+ this.opts.onData(chunk.toString("utf8"));
7072
7072
  });
7073
7073
  this.proc.stdin?.write("");
7074
7074
  if (process.stdin.isTTY) process.stdin.setRawMode(true);
@@ -7095,8 +7095,8 @@ var WindowsPtyStrategy = class {
7095
7095
  }
7096
7096
  }
7097
7097
  }
7098
- stdinHandler = (chunk2) => {
7099
- this.proc?.stdin?.write(chunk2);
7098
+ stdinHandler = (chunk) => {
7099
+ this.proc?.stdin?.write(chunk);
7100
7100
  };
7101
7101
  };
7102
7102
 
@@ -9379,8 +9379,8 @@ async function fetchClaudeQuota() {
9379
9379
  });
9380
9380
  let output = "";
9381
9381
  let resolved = false;
9382
- proc.stdout?.on("data", (chunk2) => {
9383
- output += chunk2.toString("utf8");
9382
+ proc.stdout?.on("data", (chunk) => {
9383
+ output += chunk.toString("utf8");
9384
9384
  });
9385
9385
  setTimeout(() => {
9386
9386
  proc.stdin?.write("/usage\r");
@@ -9453,11 +9453,11 @@ async function spawnAndCapture(cmd, args2, opts = {}) {
9453
9453
  }
9454
9454
  activeChildren.add(child);
9455
9455
  let stdout = "";
9456
- child.stdout?.on("data", (chunk2) => {
9457
- stdout += chunk2.toString("utf8");
9456
+ child.stdout?.on("data", (chunk) => {
9457
+ stdout += chunk.toString("utf8");
9458
9458
  });
9459
- child.stderr?.on("data", (chunk2) => {
9460
- opts.onStderr?.(chunk2.toString("utf8"));
9459
+ child.stderr?.on("data", (chunk) => {
9460
+ opts.onStderr?.(chunk.toString("utf8"));
9461
9461
  });
9462
9462
  const timer = setTimeout(() => {
9463
9463
  try {
@@ -12058,6 +12058,7 @@ var fs21 = __toESM(require("fs/promises"));
12058
12058
  var import_node_stream = require("stream");
12059
12059
  var import_sdk = require("@agentclientprotocol/sdk");
12060
12060
  var PROTOCOL_VERSION2 = 1;
12061
+ var PROMPT_TIMEOUT_MS = 9e4;
12061
12062
  var CLIENT_CAPABILITIES = {
12062
12063
  fs: { readTextFile: true, writeTextFile: true },
12063
12064
  terminal: false
@@ -12079,6 +12080,10 @@ var AcpClient = class {
12079
12080
  async start() {
12080
12081
  if (this.child) throw new Error("AcpClient already started");
12081
12082
  const { adapter, cwd } = this.opts;
12083
+ log.info(
12084
+ "acpClient",
12085
+ `spawn cmd=${adapter.command} args=[${adapter.args.join(",")}] cwd=${cwd}`
12086
+ );
12082
12087
  const child = (0, import_node_child_process11.spawn)(adapter.command, adapter.args, {
12083
12088
  cwd,
12084
12089
  env: process.env,
@@ -12086,10 +12091,13 @@ var AcpClient = class {
12086
12091
  });
12087
12092
  this.child = child;
12088
12093
  child.stderr?.setEncoding("utf8");
12089
- child.stderr?.on("data", (chunk2) => {
12090
- for (const line of chunk2.split(/\r?\n/)) {
12094
+ child.stderr?.on("data", (chunk) => {
12095
+ for (const line of chunk.split(/\r?\n/)) {
12091
12096
  const trimmed = line.trim();
12092
- if (trimmed) this.opts.onStderr?.(trimmed);
12097
+ if (trimmed) {
12098
+ log.info("acpAdapter", trimmed);
12099
+ this.opts.onStderr?.(trimmed);
12100
+ }
12093
12101
  }
12094
12102
  });
12095
12103
  child.on("exit", (code, signal) => {
@@ -12107,15 +12115,22 @@ var AcpClient = class {
12107
12115
  (_agent) => this.buildClient(),
12108
12116
  stream
12109
12117
  );
12118
+ log.info("acpClient", "initialize \u2192 sending");
12110
12119
  const initialize = await this.connection.initialize({
12111
12120
  protocolVersion: PROTOCOL_VERSION2,
12112
12121
  clientCapabilities: CLIENT_CAPABILITIES
12113
12122
  });
12123
+ log.info(
12124
+ "acpClient",
12125
+ `initialize \u2190 ok protocolVersion=${initialize.protocolVersion} agentCaps=${JSON.stringify(initialize.agentCapabilities ?? {}).slice(0, 200)}`
12126
+ );
12127
+ log.info("acpClient", "newSession \u2192 sending");
12114
12128
  const newSession = await this.connection.newSession({
12115
12129
  cwd,
12116
12130
  mcpServers: []
12117
12131
  });
12118
12132
  this.sessionId = newSession.sessionId;
12133
+ log.info("acpClient", `newSession \u2190 ok sessionId=${newSession.sessionId.slice(0, 8)}`);
12119
12134
  return { sessionId: newSession.sessionId, initialize };
12120
12135
  }
12121
12136
  /**
@@ -12123,15 +12138,49 @@ var AcpClient = class {
12123
12138
  * {@link PromptResponse} which carries the agent's stop reason
12124
12139
  * once the turn finishes. Session/update notifications keep
12125
12140
  * arriving on `onSessionUpdate` while the turn streams.
12141
+ *
12142
+ * Wrapped in a hard timeout because adapters CAN hang silently
12143
+ * when their underlying agent's auth/network is broken — without
12144
+ * a ceiling the relay command sits "pending" forever and mobile
12145
+ * shows a permanent "Thinking…" spinner with no way to recover.
12126
12146
  */
12127
12147
  async prompt(text) {
12128
12148
  if (!this.connection || !this.sessionId) {
12129
12149
  throw new Error("AcpClient.prompt called before start()");
12130
12150
  }
12131
- return this.connection.prompt({
12151
+ log.info(
12152
+ "acpClient",
12153
+ `prompt \u2192 session=${this.sessionId.slice(0, 8)} chars=${text.length}`
12154
+ );
12155
+ const t0 = Date.now();
12156
+ const send = this.connection.prompt({
12132
12157
  sessionId: this.sessionId,
12133
12158
  prompt: [{ type: "text", text }]
12134
12159
  });
12160
+ const timeout = new Promise((_resolve, reject) => {
12161
+ const id = setTimeout(() => {
12162
+ reject(
12163
+ new Error(
12164
+ `ACP prompt timed out after ${PROMPT_TIMEOUT_MS / 1e3}s \u2014 adapter never responded. Likely the underlying agent's auth or network is misconfigured; check the adapter stderr lines above (acpAdapter tag) for the actual error.`
12165
+ )
12166
+ );
12167
+ }, PROMPT_TIMEOUT_MS);
12168
+ void send.finally(() => clearTimeout(id));
12169
+ });
12170
+ try {
12171
+ const result = await Promise.race([send, timeout]);
12172
+ log.info(
12173
+ "acpClient",
12174
+ `prompt \u2190 ok stopReason=${result.stopReason ?? "?"} elapsedMs=${Date.now() - t0}`
12175
+ );
12176
+ return result;
12177
+ } catch (err) {
12178
+ log.warn(
12179
+ "acpClient",
12180
+ `prompt \u2190 failed elapsedMs=${Date.now() - t0} err=${err instanceof Error ? err.message : String(err)}`
12181
+ );
12182
+ throw err;
12183
+ }
12135
12184
  }
12136
12185
  /**
12137
12186
  * Cancel the in-flight prompt turn. Notification — no response.
@@ -12434,17 +12483,17 @@ function mapSessionUpdate(notification) {
12434
12483
  case "agent_message_chunk": {
12435
12484
  const text = extractText2(update.content);
12436
12485
  if (!text) return [];
12437
- return [chunk(messageChunkId(update.messageId), "text", text)];
12486
+ return [{ chunkId: messageChunkId(update.messageId), kind: "text", delta: text }];
12438
12487
  }
12439
12488
  case "agent_thought_chunk": {
12440
12489
  const text = extractText2(update.content);
12441
12490
  if (!text) return [];
12442
- return [chunk(messageChunkId(update.messageId), "thinking", text)];
12491
+ return [{ chunkId: messageChunkId(update.messageId), kind: "thinking", delta: text }];
12443
12492
  }
12444
12493
  case "tool_call": {
12445
12494
  const summary = describeToolCall(update);
12446
12495
  if (!summary) return [];
12447
- return [chunk(update.toolCallId, "tool_use", summary)];
12496
+ return [{ chunkId: update.toolCallId, kind: "tool_use", delta: summary }];
12448
12497
  }
12449
12498
  case "tool_call_update": {
12450
12499
  if (update.status !== "completed" && update.status !== "failed") {
@@ -12453,7 +12502,7 @@ function mapSessionUpdate(notification) {
12453
12502
  const body = describeToolCallUpdate(update);
12454
12503
  if (!body) return [];
12455
12504
  const prefix = update.status === "failed" ? "[failed] " : "";
12456
- return [chunk(update.toolCallId, "tool_result", prefix + body)];
12505
+ return [{ chunkId: update.toolCallId, kind: "tool_result", delta: prefix + body }];
12457
12506
  }
12458
12507
  case "user_message_chunk":
12459
12508
  return [];
@@ -12492,9 +12541,6 @@ function mapPermissionRequest(request) {
12492
12541
  kindByLabel
12493
12542
  };
12494
12543
  }
12495
- function chunk(chunkId, kind, content) {
12496
- return { chunkId, kind, content, isFinal: true };
12497
- }
12498
12544
  function messageChunkId(messageId) {
12499
12545
  if (typeof messageId === "string" && messageId.length > 0) return messageId;
12500
12546
  return (0, import_node_crypto5.randomUUID)();
@@ -12560,6 +12606,50 @@ function humanizeKind(kind) {
12560
12606
  }
12561
12607
 
12562
12608
  // src/agents/acp/runner.ts
12609
+ var StreamingState = class {
12610
+ constructor(publisher) {
12611
+ this.publisher = publisher;
12612
+ }
12613
+ publisher;
12614
+ open = /* @__PURE__ */ new Map();
12615
+ append(delta) {
12616
+ const existing = this.open.get(delta.chunkId);
12617
+ const content = (existing?.content ?? "") + delta.delta;
12618
+ if (existing && existing.kind !== delta.kind) {
12619
+ log.warn(
12620
+ "acpRunner",
12621
+ `chunk kind flip detected chunkId=${delta.chunkId.slice(0, 8)} from=${existing.kind} to=${delta.kind} \u2014 using new kind`
12622
+ );
12623
+ }
12624
+ this.open.set(delta.chunkId, { kind: delta.kind, content });
12625
+ void this.publisher.publishChunk({ chunkId: delta.chunkId, kind: delta.kind, content, isFinal: false }).catch((err) => {
12626
+ log.warn(
12627
+ "acpRunner",
12628
+ `publishChunk (streaming) failed: ${err instanceof Error ? err.message : String(err)}`
12629
+ );
12630
+ });
12631
+ }
12632
+ /**
12633
+ * Close every open chunk with `isFinal: true`. Idempotent — safe
12634
+ * to call multiple times per turn (e.g. once on prompt-completed,
12635
+ * once on cancel, once on adapter-exit).
12636
+ */
12637
+ async closeAll() {
12638
+ if (this.open.size === 0) return;
12639
+ const closing = Array.from(this.open.entries());
12640
+ this.open.clear();
12641
+ await Promise.all(
12642
+ closing.map(
12643
+ ([chunkId, { kind, content }]) => this.publisher.publishChunk({ chunkId, kind, content, isFinal: true }).catch((err) => {
12644
+ log.warn(
12645
+ "acpRunner",
12646
+ `publishChunk (closing) failed: ${err instanceof Error ? err.message : String(err)}`
12647
+ );
12648
+ })
12649
+ )
12650
+ );
12651
+ }
12652
+ };
12563
12653
  var ANSWER_POLL_MS = 1500;
12564
12654
  var PERMISSION_TIMEOUT_MS = 5 * 60 * 1e3;
12565
12655
  async function runAcpSession(opts) {
@@ -12568,13 +12658,21 @@ async function runAcpSession(opts) {
12568
12658
  pluginId: opts.pluginId,
12569
12659
  pluginAuthToken: opts.pluginAuthToken
12570
12660
  });
12661
+ const streaming = new StreamingState(publisher);
12662
+ let updateCount = 0;
12571
12663
  const client2 = new AcpClient({
12572
12664
  adapter: opts.adapter,
12573
12665
  cwd: opts.cwd,
12574
12666
  onSessionUpdate: (notification) => {
12575
- const chunks = mapSessionUpdate(notification);
12576
- for (const chunk2 of chunks) {
12577
- void publisher.publishChunk(chunk2);
12667
+ updateCount += 1;
12668
+ const variant = notification.update?.sessionUpdate ?? "unknown";
12669
+ const deltas = mapSessionUpdate(notification);
12670
+ log.info(
12671
+ "acpRunner",
12672
+ `update #${updateCount} variant=${variant} mappedDeltas=${deltas.length}`
12673
+ );
12674
+ for (const delta of deltas) {
12675
+ streaming.append(delta);
12578
12676
  }
12579
12677
  },
12580
12678
  onRequestPermission: async (request) => {
@@ -12594,11 +12692,11 @@ async function runAcpSession(opts) {
12594
12692
  }
12595
12693
  return { outcome: { outcome: "selected", optionId } };
12596
12694
  },
12597
- onStderr: (line) => {
12598
- log.trace("acpAdapter", line);
12695
+ onStderr: (_line) => {
12599
12696
  },
12600
12697
  onUnexpectedExit: (code, signal) => {
12601
12698
  log.warn("acpRunner", `adapter died code=${code} signal=${signal}; shutting down session`);
12699
+ void streaming.closeAll();
12602
12700
  void publisher.publishChunk({
12603
12701
  chunkId: (0, import_node_crypto6.randomUUID)(),
12604
12702
  kind: "text",
@@ -12620,7 +12718,7 @@ async function runAcpSession(opts) {
12620
12718
  const relay = new CommandRelayService(
12621
12719
  opts.pluginId,
12622
12720
  async (cmd) => {
12623
- await handleCommand(cmd, client2, relay, acpSessionId, models);
12721
+ await handleCommand(cmd, client2, relay, acpSessionId, models, streaming);
12624
12722
  },
12625
12723
  { id: opts.agent, name: opts.agent, displayName: opts.agent }
12626
12724
  );
@@ -12637,7 +12735,7 @@ async function runAcpSession(opts) {
12637
12735
  await new Promise(() => {
12638
12736
  });
12639
12737
  }
12640
- async function handleCommand(cmd, client2, relay, acpSessionId, models) {
12738
+ async function handleCommand(cmd, client2, relay, acpSessionId, models, streaming) {
12641
12739
  switch (cmd.type) {
12642
12740
  case "start_task": {
12643
12741
  const payload = cmd.payload;
@@ -12647,10 +12745,14 @@ async function handleCommand(cmd, client2, relay, acpSessionId, models) {
12647
12745
  await relay.sendResult(cmd.id, "failed", { error: "empty prompt" });
12648
12746
  return;
12649
12747
  }
12748
+ log.info("acpRunner", `start_task \u2192 forwarding prompt chars=${prompt.length} id=${cmd.id.slice(0, 8)}`);
12650
12749
  try {
12651
12750
  const reply = await client2.prompt(prompt);
12751
+ await streaming.closeAll();
12752
+ log.info("acpRunner", `start_task \u2190 done stopReason=${reply.stopReason ?? "?"} id=${cmd.id.slice(0, 8)}`);
12652
12753
  await relay.sendResult(cmd.id, "completed", { stopReason: reply.stopReason });
12653
12754
  } catch (err) {
12755
+ await streaming.closeAll();
12654
12756
  log.warn("acpRunner", `prompt failed: ${describeError(err)}`);
12655
12757
  await relay.sendResult(cmd.id, "failed", { error: describeError(err) });
12656
12758
  }
@@ -12660,6 +12762,7 @@ async function handleCommand(cmd, client2, relay, acpSessionId, models) {
12660
12762
  case "escape_key": {
12661
12763
  try {
12662
12764
  await client2.cancel();
12765
+ await streaming.closeAll();
12663
12766
  await relay.sendResult(cmd.id, "completed", {});
12664
12767
  } catch (err) {
12665
12768
  log.warn("acpRunner", `cancel failed: ${describeError(err)}`);
@@ -15129,13 +15232,13 @@ var TurnFileAggregator = class {
15129
15232
  return;
15130
15233
  }
15131
15234
  const chunks = chunkArray(novel, MAX_BATCH_SIZE);
15132
- for (const chunk2 of chunks) {
15235
+ for (const chunk of chunks) {
15133
15236
  const entry = {
15134
15237
  turnId: (0, import_crypto2.randomUUID)(),
15135
15238
  sessionId: this.opts.sessionId,
15136
15239
  pluginId: this.opts.pluginId,
15137
15240
  enqueuedAt: Date.now(),
15138
- files: chunk2
15241
+ files: chunk
15139
15242
  };
15140
15243
  await this.outbox.enqueue(entry);
15141
15244
  }
@@ -15296,11 +15399,11 @@ var StreamingEmitterService = class {
15296
15399
  }
15297
15400
  if (this.activeChunk) {
15298
15401
  const finalContent = this.activeChunk.currentContent;
15299
- const chunk2 = this.activeChunk;
15402
+ const chunk = this.activeChunk;
15300
15403
  this.activeChunk = null;
15301
15404
  await this.postChunk({
15302
- chunkId: chunk2.chunkId,
15303
- kind: chunk2.kind,
15405
+ chunkId: chunk.chunkId,
15406
+ kind: chunk.kind,
15304
15407
  content: finalContent,
15305
15408
  isFinal: true
15306
15409
  });
@@ -15372,17 +15475,17 @@ var StreamingEmitterService = class {
15372
15475
  this.maybeFlushActive(false);
15373
15476
  }
15374
15477
  maybeFlushActive(force) {
15375
- const chunk2 = this.activeChunk;
15376
- if (!chunk2) return;
15478
+ const chunk = this.activeChunk;
15479
+ if (!chunk) return;
15377
15480
  const now = Date.now();
15378
- if (!force && now - chunk2.lastEmitAt < TICK_MS) return;
15379
- if (chunk2.currentContent === chunk2.emittedContent) return;
15380
- chunk2.emittedContent = chunk2.currentContent;
15381
- chunk2.lastEmitAt = now;
15481
+ if (!force && now - chunk.lastEmitAt < TICK_MS) return;
15482
+ if (chunk.currentContent === chunk.emittedContent) return;
15483
+ chunk.emittedContent = chunk.currentContent;
15484
+ chunk.lastEmitAt = now;
15382
15485
  void this.postChunk({
15383
- chunkId: chunk2.chunkId,
15384
- kind: chunk2.kind,
15385
- content: chunk2.currentContent,
15486
+ chunkId: chunk.chunkId,
15487
+ kind: chunk.kind,
15488
+ content: chunk.currentContent,
15386
15489
  isFinal: false
15387
15490
  });
15388
15491
  }
@@ -17919,8 +18022,8 @@ var previewStartH = (ctx, _cmd, parsed) => {
17919
18022
  let readyMatched = false;
17920
18023
  let expoUrl = null;
17921
18024
  const readyRe = new RegExp(detection.ready_pattern);
17922
- const onChunk = (chunk2) => {
17923
- const s = chunk2.toString();
18025
+ const onChunk = (chunk) => {
18026
+ const s = chunk.toString();
17924
18027
  if (!readyMatched && readyRe.test(s)) readyMatched = true;
17925
18028
  if (!expoUrl && detection.framework === "Expo") expoUrl = parseExpoUrl(s);
17926
18029
  };
@@ -18043,8 +18146,8 @@ var previewStartH = (ctx, _cmd, parsed) => {
18043
18146
  stdio: ["ignore", "pipe", "pipe"]
18044
18147
  });
18045
18148
  let parsedUrl = null;
18046
- const onTunnelChunk = (chunk2) => {
18047
- const s = chunk2.toString();
18149
+ const onTunnelChunk = (chunk) => {
18150
+ const s = chunk.toString();
18048
18151
  if (!parsedUrl) parsedUrl = parseCloudflaredUrl(s);
18049
18152
  const trimmed = s.replace(/\n+$/g, "");
18050
18153
  if (trimmed.length > 0) log.info("preview", `cloudflared: ${trimmed}`);
@@ -18143,8 +18246,8 @@ function runOnce(cmd, args2, cwd, env) {
18143
18246
  stdio: ["ignore", "pipe", "pipe"]
18144
18247
  });
18145
18248
  const tag = `setup:${cmd}`;
18146
- const onChunk = (chunk2) => {
18147
- const text = chunk2.toString().replace(/\n+$/g, "");
18249
+ const onChunk = (chunk) => {
18250
+ const text = chunk.toString().replace(/\n+$/g, "");
18148
18251
  if (text.length === 0) return;
18149
18252
  log.info("preview", `${tag}: ${text}`);
18150
18253
  };
@@ -21171,7 +21274,7 @@ function checkChokidar() {
21171
21274
  }
21172
21275
  async function doctor(args2 = []) {
21173
21276
  const json = args2.includes("--json");
21174
- const cliVersion = true ? "2.27.6" : "0.0.0-dev";
21277
+ const cliVersion = true ? "2.27.8" : "0.0.0-dev";
21175
21278
  const apiBase = resolveApiBaseUrl();
21176
21279
  const diagnosticId = (0, import_node_crypto8.randomUUID)();
21177
21280
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -21370,7 +21473,7 @@ async function completion(args2) {
21370
21473
  // src/commands/version.ts
21371
21474
  var import_picocolors13 = __toESM(require("picocolors"));
21372
21475
  function version2() {
21373
- const v = true ? "2.27.6" : "unknown";
21476
+ const v = true ? "2.27.8" : "unknown";
21374
21477
  console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
21375
21478
  }
21376
21479
 
@@ -21557,8 +21660,8 @@ function fetchLatest() {
21557
21660
  }
21558
21661
  let buf = "";
21559
21662
  res.setEncoding("utf8");
21560
- res.on("data", (chunk2) => {
21561
- buf += chunk2;
21663
+ res.on("data", (chunk) => {
21664
+ buf += chunk;
21562
21665
  });
21563
21666
  res.on("end", () => {
21564
21667
  try {
@@ -21598,7 +21701,7 @@ function checkForUpdates() {
21598
21701
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
21599
21702
  if (process.env.CI) return;
21600
21703
  if (!process.stdout.isTTY) return;
21601
- const current = true ? "2.27.6" : null;
21704
+ const current = true ? "2.27.8" : null;
21602
21705
  if (!current) return;
21603
21706
  const cache = readCache();
21604
21707
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.27.6",
3
+ "version": "2.27.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",