codeam-cli 2.76.36 → 2.76.38

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 +17 -0
  2. package/dist/index.js +264 -48
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,23 @@ 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.76.37] — 2026-10-26
8
+
9
+ ### Fixed
10
+
11
+ - **cli:** Require cloudflared >= 2026.10.2 for previews (#994)
12
+
13
+ ## [2.76.36] — 2026-10-25
14
+
15
+ ### Added
16
+
17
+ - **shared:** One Point-at-it picker for Remix and the Preview
18
+ - **cli:** The Preview picker is Remix's Point at it
19
+
20
+ ### Fixed
21
+
22
+ - **shared:** Point picker swallows the post-pick click, valid selectors, reload-safe mark ids
23
+
7
24
  ## [2.76.35] — 2026-10-22
8
25
 
9
26
  ### Fixed
package/dist/index.js CHANGED
@@ -11354,7 +11354,7 @@ function readAnonId() {
11354
11354
  }
11355
11355
  function superProperties() {
11356
11356
  return {
11357
- cliVersion: true ? "2.76.36" : "0.0.0-dev",
11357
+ cliVersion: true ? "2.76.38" : "0.0.0-dev",
11358
11358
  nodeVersion: process.version,
11359
11359
  platform: process.platform,
11360
11360
  arch: process.arch,
@@ -11603,7 +11603,7 @@ var http = __toESM(require("http"));
11603
11603
  // package.json
11604
11604
  var package_default = {
11605
11605
  name: "codeam-cli",
11606
- version: "2.76.36",
11606
+ version: "2.76.38",
11607
11607
  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.",
11608
11608
  type: "commonjs",
11609
11609
  main: "dist/index.js",
@@ -12979,7 +12979,7 @@ var CommandRelayService = class _CommandRelayService {
12979
12979
  // fresh + clear the "CLI update available" banner after a self-update
12980
12980
  // (a codespace that reinstalls @latest reconnects via heartbeat, not
12981
12981
  // pair/reconnect). Older backends ignore the extra field.
12982
- ..."2.76.36" ? { ideVersion: "2.76.36" } : {}
12982
+ ..."2.76.38" ? { ideVersion: "2.76.38" } : {}
12983
12983
  };
12984
12984
  try {
12985
12985
  const res = await _postJson(`${API_BASE2}/api/plugin/heartbeat`, body, this.pollSecretHeader());
@@ -24113,27 +24113,153 @@ var import_os10 = __toESM(require("os"));
24113
24113
  var import_path5 = __toESM(require("path"));
24114
24114
  var import_promises3 = require("stream/promises");
24115
24115
  var import_which = __toESM(require("which"));
24116
- var CACHED_BINARY = import_path5.default.join(import_os10.default.homedir(), ".codeam", "bin", "cloudflared");
24116
+ var CACHE_DIR = import_path5.default.join(import_os10.default.homedir(), ".codeam", "bin");
24117
+ var LEGACY_CACHED_BINARY = import_path5.default.join(CACHE_DIR, "cloudflared");
24118
+ function cachedCloudflaredPath(platform3 = process.platform) {
24119
+ return platform3 === "win32" ? import_path5.default.join(CACHE_DIR, "cloudflared.exe") : LEGACY_CACHED_BINARY;
24120
+ }
24121
+ var MIN_CLOUDFLARED_VERSION = [2026, 10, 2];
24122
+ var MIN_CLOUDFLARED_VERSION_DARWIN_NON_BREW = [2026, 10, 3];
24123
+ var DEFAULT_HOMEBREW_PREFIXES = [
24124
+ "/opt/homebrew/",
24125
+ "/usr/local/Cellar/",
24126
+ "/usr/local/Homebrew/",
24127
+ "/home/linuxbrew/"
24128
+ ];
24129
+ function homebrewPrefixes(env = process.env) {
24130
+ const custom = env.HOMEBREW_PREFIX?.replace(/\/+$/, "");
24131
+ return custom ? [...DEFAULT_HOMEBREW_PREFIXES, `${custom}/`, `${custom}/Cellar/`] : [...DEFAULT_HOMEBREW_PREFIXES];
24132
+ }
24133
+ function parseCloudflaredVersion(output) {
24134
+ const m = /cloudflared version (\d+)\.(\d+)\.(\d+)/.exec(output);
24135
+ return m ? [Number(m[1]), Number(m[2]), Number(m[3])] : null;
24136
+ }
24137
+ function isHomebrewPath(bin, prefixes = homebrewPrefixes()) {
24138
+ return prefixes.some((prefix) => bin.startsWith(prefix));
24139
+ }
24140
+ function formatCloudflaredVersion(v) {
24141
+ return v.join(".");
24142
+ }
24143
+ function minimumCloudflaredVersion(bin, platform3 = process.platform, prefixes = homebrewPrefixes()) {
24144
+ return platform3 === "darwin" && !isHomebrewPath(bin, prefixes) ? MIN_CLOUDFLARED_VERSION_DARWIN_NON_BREW : MIN_CLOUDFLARED_VERSION;
24145
+ }
24146
+ function compareVersions(a, b) {
24147
+ for (let i = 0; i < 3; i++) {
24148
+ if (a[i] !== b[i]) return a[i] - b[i];
24149
+ }
24150
+ return 0;
24151
+ }
24152
+ function meetsMinimumCloudflaredVersion(version3, bin, platform3 = process.platform, prefixes = homebrewPrefixes()) {
24153
+ if (!version3) return false;
24154
+ return compareVersions(version3, minimumCloudflaredVersion(bin, platform3, prefixes)) >= 0;
24155
+ }
24156
+ var versionCache = /* @__PURE__ */ new Map();
24157
+ var warnedOutdated = /* @__PURE__ */ new Set();
24158
+ function readCloudflaredVersion(bin) {
24159
+ let cached2 = versionCache.get(bin);
24160
+ if (!cached2) {
24161
+ const pending2 = new Promise((resolve13) => {
24162
+ (0, import_child_process14.execFile)(bin, ["--version"], { timeout: 1e4 }, (err, stdout, stderr) => {
24163
+ resolve13(err ? null : parseCloudflaredVersion(`${stdout}
24164
+ ${stderr}`));
24165
+ });
24166
+ }).then((version3) => {
24167
+ if (!version3 && versionCache.get(bin) === pending2) versionCache.delete(bin);
24168
+ return version3;
24169
+ });
24170
+ cached2 = pending2;
24171
+ versionCache.set(bin, pending2);
24172
+ }
24173
+ return cached2;
24174
+ }
24175
+ async function realpathOrSelf(p2) {
24176
+ try {
24177
+ return await import_promises2.default.realpath(p2);
24178
+ } catch {
24179
+ return p2;
24180
+ }
24181
+ }
24182
+ async function checkCloudflaredVersion(bin) {
24183
+ const version3 = await readCloudflaredVersion(bin);
24184
+ const real = await realpathOrSelf(bin);
24185
+ const prefixes = homebrewPrefixes();
24186
+ const customPrefix = process.env.HOMEBREW_PREFIX?.replace(/\/+$/, "");
24187
+ if (customPrefix) {
24188
+ const realPrefix = await realpathOrSelf(customPrefix);
24189
+ if (realPrefix !== customPrefix) prefixes.push(`${realPrefix}/`, `${realPrefix}/Cellar/`);
24190
+ }
24191
+ const brewBin = isHomebrewPath(bin, prefixes) ? bin : real;
24192
+ return {
24193
+ ok: meetsMinimumCloudflaredVersion(version3, brewBin, process.platform, prefixes),
24194
+ version: version3,
24195
+ min: minimumCloudflaredVersion(brewBin, process.platform, prefixes)
24196
+ };
24197
+ }
24198
+ async function migrateLegacyWindowsCache(target) {
24199
+ if (target === LEGACY_CACHED_BINARY) return;
24200
+ try {
24201
+ await import_promises2.default.access(target);
24202
+ return;
24203
+ } catch {
24204
+ }
24205
+ try {
24206
+ await import_promises2.default.access(LEGACY_CACHED_BINARY);
24207
+ await import_promises2.default.rename(LEGACY_CACHED_BINARY, target);
24208
+ } catch {
24209
+ }
24210
+ }
24211
+ function describeVersion(v) {
24212
+ return v ? formatCloudflaredVersion(v) : "an unknown version";
24213
+ }
24117
24214
  async function resolveCloudflared(opts = {}) {
24215
+ let pathBin;
24118
24216
  try {
24119
- return await (0, import_which.default)("cloudflared");
24217
+ pathBin = await (0, import_which.default)("cloudflared");
24120
24218
  } catch {
24121
24219
  }
24220
+ if (pathBin) {
24221
+ const check2 = await checkCloudflaredVersion(pathBin);
24222
+ if (check2.ok) return pathBin;
24223
+ if (!warnedOutdated.has(pathBin)) {
24224
+ warnedOutdated.add(pathBin);
24225
+ log.warn(
24226
+ "preview",
24227
+ `ignoring ${pathBin} (${describeVersion(check2.version)}): previews need cloudflared >= ${formatCloudflaredVersion(check2.min)}; upgrade cloudflared with your package manager (e.g. \`brew upgrade cloudflared\`). Using a CodeAgent-managed copy instead.`
24228
+ );
24229
+ }
24230
+ }
24231
+ const cached2 = cachedCloudflaredPath();
24232
+ await migrateLegacyWindowsCache(cached2);
24233
+ let staleCache = false;
24122
24234
  try {
24123
- await import_promises2.default.access(CACHED_BINARY);
24124
- if (await isExecutableBinary(CACHED_BINARY)) {
24125
- return CACHED_BINARY;
24235
+ await import_promises2.default.access(cached2);
24236
+ if (!await isExecutableBinary(cached2)) {
24237
+ await import_promises2.default.rm(cached2, { force: true });
24238
+ } else if ((await checkCloudflaredVersion(cached2)).ok) {
24239
+ return cached2;
24240
+ } else {
24241
+ staleCache = true;
24126
24242
  }
24127
- await import_promises2.default.rm(CACHED_BINARY, { force: true });
24128
24243
  } catch {
24129
24244
  }
24130
24245
  if (opts.skipDownload) {
24131
24246
  throw new Error(
24132
- "cloudflared not installed. Install via `brew install cloudflared` (macOS) or download from https://github.com/cloudflare/cloudflared/releases."
24247
+ `cloudflared not installed (or older than ${formatCloudflaredVersion(minimumCloudflaredVersion(cached2))}). Install or upgrade via \`brew install cloudflared\` (macOS) or download from https://github.com/cloudflare/cloudflared/releases.`
24133
24248
  );
24134
24249
  }
24135
- await downloadCloudflared(CACHED_BINARY);
24136
- return CACHED_BINARY;
24250
+ if (staleCache) await import_promises2.default.rm(cached2, { force: true });
24251
+ versionCache.delete(cached2);
24252
+ await downloadCloudflared(cached2);
24253
+ versionCache.delete(cached2);
24254
+ const check = await checkCloudflaredVersion(cached2);
24255
+ if (!check.ok) {
24256
+ await import_promises2.default.rm(cached2, { force: true });
24257
+ versionCache.delete(cached2);
24258
+ throw new Error(
24259
+ `Downloaded cloudflared reports ${describeVersion(check.version)}, but previews need cloudflared >= ${formatCloudflaredVersion(check.min)}. Install the latest version manually via \`brew install cloudflared\` (macOS) or from https://github.com/cloudflare/cloudflared/releases.`
24260
+ );
24261
+ }
24262
+ return cached2;
24137
24263
  }
24138
24264
  async function downloadCloudflared(target) {
24139
24265
  const url2 = downloadUrlForPlatform();
@@ -39345,6 +39471,95 @@ function _get(url2, headers) {
39345
39471
  });
39346
39472
  }
39347
39473
 
39474
+ // src/services/streaming/chunk-coalescer.ts
39475
+ var STREAMING_CHUNK_MIN_INTERVAL_MS = 100;
39476
+ var FINALIZED_MEMORY = 512;
39477
+ var StreamingChunkCoalescer = class {
39478
+ constructor(opts) {
39479
+ this.opts = opts;
39480
+ }
39481
+ opts;
39482
+ chunks = /* @__PURE__ */ new Map();
39483
+ finalized = /* @__PURE__ */ new Set();
39484
+ submit(event) {
39485
+ const { chunkId } = event;
39486
+ if (this.finalized.has(chunkId)) return Promise.resolve();
39487
+ const state = this.chunks.get(chunkId) ?? this.open(chunkId);
39488
+ const settled = new Promise((resolve13) => {
39489
+ const waiters = state.pending ? state.pending.waiters : [];
39490
+ waiters.push(resolve13);
39491
+ state.pending = { event, waiters };
39492
+ });
39493
+ if (event.isFinal) {
39494
+ this.markFinalized(chunkId);
39495
+ this.drain(chunkId, state);
39496
+ } else {
39497
+ this.schedule(chunkId, state);
39498
+ }
39499
+ return settled;
39500
+ }
39501
+ /** Send every pending snapshot now (ignoring the spacing) and wait for all
39502
+ * requests to settle. Used on shutdown so the latest content is not lost. */
39503
+ async flush() {
39504
+ const work = Array.from(this.chunks.entries()).map(async ([chunkId, state]) => {
39505
+ while (state.inFlight || state.pending) {
39506
+ if (!state.inFlight) this.drain(chunkId, state);
39507
+ await state.inFlight;
39508
+ }
39509
+ });
39510
+ await Promise.all(work);
39511
+ }
39512
+ open(chunkId) {
39513
+ const state = { pending: null, inFlight: null, timer: null, lastSentAt: 0 };
39514
+ this.chunks.set(chunkId, state);
39515
+ return state;
39516
+ }
39517
+ schedule(chunkId, state) {
39518
+ if (state.inFlight || state.timer || !state.pending) return;
39519
+ const wait = this.intervalFor(state.pending.event) - (Date.now() - state.lastSentAt);
39520
+ if (wait <= 0) {
39521
+ this.drain(chunkId, state);
39522
+ return;
39523
+ }
39524
+ state.timer = setTimeout(() => {
39525
+ state.timer = null;
39526
+ this.drain(chunkId, state);
39527
+ }, wait);
39528
+ }
39529
+ /** Send the pending snapshot now, unless a request is still in flight
39530
+ * (its completion re-enters here or {@link schedule}). */
39531
+ drain(chunkId, state) {
39532
+ if (state.inFlight || !state.pending) return;
39533
+ if (state.timer) {
39534
+ clearTimeout(state.timer);
39535
+ state.timer = null;
39536
+ }
39537
+ const { event, waiters } = state.pending;
39538
+ state.pending = null;
39539
+ state.lastSentAt = Date.now();
39540
+ state.inFlight = this.opts.send(event).catch(() => void 0).then(() => {
39541
+ state.inFlight = null;
39542
+ for (const resolve13 of waiters) resolve13();
39543
+ if (!state.pending) {
39544
+ if (event.isFinal) this.chunks.delete(chunkId);
39545
+ return;
39546
+ }
39547
+ if (state.pending.event.isFinal) this.drain(chunkId, state);
39548
+ else this.schedule(chunkId, state);
39549
+ });
39550
+ }
39551
+ intervalFor(event) {
39552
+ return this.opts.intervalFor?.(event) ?? STREAMING_CHUNK_MIN_INTERVAL_MS;
39553
+ }
39554
+ markFinalized(chunkId) {
39555
+ this.finalized.add(chunkId);
39556
+ if (this.finalized.size > FINALIZED_MEMORY) {
39557
+ const oldest = this.finalized.values().next().value;
39558
+ if (oldest !== void 0) this.finalized.delete(oldest);
39559
+ }
39560
+ }
39561
+ };
39562
+
39348
39563
  // src/agents/acp/publisher.ts
39349
39564
  var STREAMING_CHUNK_SNAPSHOT_MAX_CHARS = 56 * 1024;
39350
39565
  var STREAMING_CHUNK_COALESCE_MIN_CHARS = 8 * 1024;
@@ -39390,8 +39605,12 @@ var AcpPublisher = class {
39390
39605
  /** chunkIds whose truncated snapshot already went out — nothing new to show
39391
39606
  * until the terminal frame. */
39392
39607
  truncatedChunks = /* @__PURE__ */ new Set();
39393
- lastChunkPostAt = /* @__PURE__ */ new Map();
39394
- pendingChunkPosts = /* @__PURE__ */ new Map();
39608
+ /** Latest-wins, one-in-flight-per-chunkId pacing of the streaming-chunk
39609
+ * feed (2026-10-29: one CLI posted 10–30 cumulative snapshots/s). */
39610
+ chunkCoalescer = new StreamingChunkCoalescer({
39611
+ send: (event) => this.postStreamingChunk(event),
39612
+ intervalFor: (event) => event.content.length >= STREAMING_CHUNK_COALESCE_MIN_CHARS ? STREAMING_CHUNK_COALESCE_WINDOW_MS : STREAMING_CHUNK_MIN_INTERVAL_MS
39613
+ });
39395
39614
  /** Latched on an unrecoverable 401/403 — every surface stops posting
39396
39615
  * (2026-06-28 incident: a dead-token publisher spammed 401 ×34 while
39397
39616
  * the agent's replies silently never reached the phone). */
@@ -39555,14 +39774,13 @@ var AcpPublisher = class {
39555
39774
  * ({@link publishOutput}) is independent and carries `type:'text'`
39556
39775
  * for the main chat bubble; this feed is purely additive for the
39557
39776
  * richer SessionDetail surface.
39777
+ *
39778
+ * POSTs are paced per chunkId by {@link StreamingChunkCoalescer}: latest
39779
+ * snapshot wins, one request in flight, and the `isFinal` frame always goes
39780
+ * last. The promise settles once this content (or a newer one) is sent.
39558
39781
  */
39559
39782
  async publishStreamingChunk(event) {
39560
39783
  const { chunkId, isFinal } = event;
39561
- const pending2 = this.pendingChunkPosts.get(chunkId);
39562
- if (pending2) {
39563
- clearTimeout(pending2.timer);
39564
- this.pendingChunkPosts.delete(chunkId);
39565
- }
39566
39784
  const bounded = boundStreamingChunkContent(event.content);
39567
39785
  if (bounded.truncated) {
39568
39786
  if (!isFinal && this.truncatedChunks.has(chunkId)) return;
@@ -39574,27 +39792,16 @@ var AcpPublisher = class {
39574
39792
  }
39575
39793
  this.truncatedChunks.add(chunkId);
39576
39794
  }
39577
- if (isFinal) {
39578
- this.truncatedChunks.delete(chunkId);
39579
- this.lastChunkPostAt.delete(chunkId);
39580
- } else if (!bounded.truncated && bounded.content.length >= STREAMING_CHUNK_COALESCE_MIN_CHARS) {
39581
- const last = this.lastChunkPostAt.get(chunkId) ?? 0;
39582
- const wait = STREAMING_CHUNK_COALESCE_WINDOW_MS - (Date.now() - last);
39583
- if (wait > 0) {
39584
- const timer = setTimeout(() => {
39585
- const latest = this.pendingChunkPosts.get(chunkId);
39586
- this.pendingChunkPosts.delete(chunkId);
39587
- if (latest) void this.postStreamingChunk(latest.event);
39588
- }, wait);
39589
- this.pendingChunkPosts.set(chunkId, { timer, event });
39590
- return;
39591
- }
39592
- }
39593
- await this.postStreamingChunk({ ...event, content: bounded.content });
39795
+ if (isFinal) this.truncatedChunks.delete(chunkId);
39796
+ await this.chunkCoalescer.submit({ ...event, content: bounded.content });
39797
+ }
39798
+ /** Send any coalesced streaming-chunk snapshot still waiting, and wait for
39799
+ * the in-flight ones — so shutdown never loses the latest content. */
39800
+ flushStreamingChunks() {
39801
+ return this.chunkCoalescer.flush();
39594
39802
  }
39595
39803
  async postStreamingChunk(event) {
39596
39804
  const url2 = `${this.apiBase}/api/sessions/${encodeURIComponent(this.opts.sessionId)}/streaming-chunk`;
39597
- if (!event.isFinal) this.lastChunkPostAt.set(event.chunkId, Date.now());
39598
39805
  try {
39599
39806
  const { statusCode, body } = await this.postWithReauth(
39600
39807
  url2,
@@ -45861,6 +46068,10 @@ async function runAcpSession(opts) {
45861
46068
  const shutdown = async (signal) => {
45862
46069
  showInfo(`Shutting down ACP session (${signal})\u2026`);
45863
46070
  clearTimeout(prewarmTimer);
46071
+ await Promise.race([
46072
+ publisher.flushStreamingChunks(),
46073
+ new Promise((resolve13) => setTimeout(resolve13, 2e3).unref())
46074
+ ]);
45864
46075
  await stopRelayWithGoodbye(relay);
45865
46076
  void fileWatcher.stop();
45866
46077
  turnFiles.stop();
@@ -46610,6 +46821,10 @@ var StreamingEmitterService = class {
46610
46821
  */
46611
46822
  lastSelectorSignature = null;
46612
46823
  selectorFirstSeenAt = 0;
46824
+ /** Latest-wins, one-in-flight-per-chunkId pacing of the chunk POSTs. */
46825
+ chunkCoalescer = new StreamingChunkCoalescer({
46826
+ send: (event) => this.postChunk(event)
46827
+ });
46613
46828
  // ─── Lifecycle ─────────────────────────────────────────────────────
46614
46829
  start() {
46615
46830
  if (this.active) return;
@@ -46640,13 +46855,14 @@ var StreamingEmitterService = class {
46640
46855
  const finalContent = this.activeChunk.currentContent;
46641
46856
  const chunk = this.activeChunk;
46642
46857
  this.activeChunk = null;
46643
- await this.postChunk({
46858
+ await this.chunkCoalescer.submit({
46644
46859
  chunkId: chunk.chunkId,
46645
46860
  kind: chunk.kind,
46646
46861
  content: finalContent,
46647
46862
  isFinal: true
46648
46863
  });
46649
46864
  }
46865
+ await this.chunkCoalescer.flush();
46650
46866
  log.trace("streamingEmitter", `stopped session=${this.opts.sessionId.slice(0, 8)}`);
46651
46867
  }
46652
46868
  // ─── Input pump ────────────────────────────────────────────────────
@@ -46697,7 +46913,7 @@ var StreamingEmitterService = class {
46697
46913
  if (this.activeChunk) {
46698
46914
  const closing = this.activeChunk;
46699
46915
  this.activeChunk = null;
46700
- void this.postChunk({
46916
+ void this.chunkCoalescer.submit({
46701
46917
  chunkId: closing.chunkId,
46702
46918
  kind: closing.kind,
46703
46919
  content: closing.currentContent,
@@ -46721,7 +46937,7 @@ var StreamingEmitterService = class {
46721
46937
  if (chunk.currentContent === chunk.emittedContent) return;
46722
46938
  chunk.emittedContent = chunk.currentContent;
46723
46939
  chunk.lastEmitAt = now;
46724
- void this.postChunk({
46940
+ void this.chunkCoalescer.submit({
46725
46941
  chunkId: chunk.chunkId,
46726
46942
  kind: chunk.kind,
46727
46943
  content: chunk.currentContent,
@@ -51037,9 +51253,9 @@ async function probeCodeamPair(provider, workspace) {
51037
51253
  }
51038
51254
  async function stopWorkspaceFromLocal(target) {
51039
51255
  if (target.provider.id === "github-codespaces") {
51040
- const { execFile: execFile21 } = await import("child_process");
51256
+ const { execFile: execFile22 } = await import("child_process");
51041
51257
  const { promisify: promisify17 } = await import("util");
51042
- const execFileP10 = promisify17(execFile21);
51258
+ const execFileP10 = promisify17(execFile22);
51043
51259
  await execFileP10("gh", ["codespace", "stop", "-c", target.id], { maxBuffer: 8 * 1024 * 1024 });
51044
51260
  return;
51045
51261
  }
@@ -51937,7 +52153,7 @@ async function autoUpgradeBeforeCriticalCommand() {
51937
52153
  if (process.env.NODE_ENV === "test") return;
51938
52154
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
51939
52155
  if (process.env.CI) return;
51940
- const current2 = true ? "2.76.36" : null;
52156
+ const current2 = true ? "2.76.38" : null;
51941
52157
  if (!current2) return;
51942
52158
  const cache = readCache();
51943
52159
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -51954,7 +52170,7 @@ function checkForUpdates() {
51954
52170
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
51955
52171
  if (process.env.CI) return;
51956
52172
  if (!process.stdout.isTTY) return;
51957
- const current2 = true ? "2.76.36" : null;
52173
+ const current2 = true ? "2.76.38" : null;
51958
52174
  if (!current2) return;
51959
52175
  const cache = readCache();
51960
52176
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -52260,7 +52476,7 @@ var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
52260
52476
  var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
52261
52477
  var SELF_UPDATE_LS_TIMEOUT_MS = 15e3;
52262
52478
  function currentCliVersion() {
52263
- return true ? "2.76.36" : null;
52479
+ return true ? "2.76.38" : null;
52264
52480
  }
52265
52481
  async function installedVersion(deps) {
52266
52482
  const ls = await deps.run(
@@ -52483,7 +52699,7 @@ function signalHostReady(send = process.send?.bind(process)) {
52483
52699
  }
52484
52700
  function defaultDeps() {
52485
52701
  return {
52486
- ownVersion: true ? "2.76.36" : null,
52702
+ ownVersion: true ? "2.76.38" : null,
52487
52703
  root: cliVersionsRoot(),
52488
52704
  args: process.argv.slice(3),
52489
52705
  execPath: process.execPath,
@@ -55021,7 +55237,7 @@ function checkChokidar() {
55021
55237
  }
55022
55238
  async function doctor(args2 = []) {
55023
55239
  const json = args2.includes("--json");
55024
- const cliVersion = true ? "2.76.36" : "0.0.0-dev";
55240
+ const cliVersion = true ? "2.76.38" : "0.0.0-dev";
55025
55241
  const apiBase2 = resolveApiBaseUrl();
55026
55242
  const diagnosticId = (0, import_node_crypto17.randomUUID)();
55027
55243
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -55557,7 +55773,7 @@ async function mcpWarm(argv = [], opts = {}) {
55557
55773
  // src/commands/version.ts
55558
55774
  var import_picocolors15 = __toESM(require("picocolors"));
55559
55775
  function version2() {
55560
- const v = true ? "2.76.36" : "unknown";
55776
+ const v = true ? "2.76.38" : "unknown";
55561
55777
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
55562
55778
  }
55563
55779
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.76.36",
3
+ "version": "2.76.38",
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",