codeam-cli 2.46.3 → 2.46.5

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 +111 -23
  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.46.4] — 2026-06-26
8
+
9
+ ### Fixed
10
+
11
+ - **cli:** Retry + poll dolt sql-server start so it's up before the agent (codeagent-r5k)
12
+
13
+ ## [2.46.3] — 2026-06-26
14
+
15
+ ### Added
16
+
17
+ - **cli:** Detect Cursor plan paywall reply → actionable upgrade-link bubble
18
+
7
19
  ## [2.46.2] — 2026-06-26
8
20
 
9
21
  ### Added
package/dist/index.js CHANGED
@@ -5397,7 +5397,7 @@ function readAnonId() {
5397
5397
  }
5398
5398
  function superProperties() {
5399
5399
  return {
5400
- cliVersion: true ? "2.46.3" : "0.0.0-dev",
5400
+ cliVersion: true ? "2.46.5" : "0.0.0-dev",
5401
5401
  nodeVersion: process.version,
5402
5402
  platform: process.platform,
5403
5403
  arch: process.arch,
@@ -5578,7 +5578,7 @@ var os4 = __toESM(require("os"));
5578
5578
  // package.json
5579
5579
  var package_default = {
5580
5580
  name: "codeam-cli",
5581
- version: "2.46.3",
5581
+ version: "2.46.5",
5582
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.",
5583
5583
  type: "commonjs",
5584
5584
  main: "dist/index.js",
@@ -14895,29 +14895,54 @@ var _daemonSeam = {
14895
14895
  * `Dolt server: running`; down blocks say `Dolt server: not running`.
14896
14896
  * Match the affirmative form explicitly so "not running" can't false-positive.
14897
14897
  */
14898
- isRunning: (statusStdout) => /Dolt server:\s*running/i.test(statusStdout)
14898
+ isRunning: (statusStdout) => /Dolt server:\s*running/i.test(statusStdout),
14899
+ /**
14900
+ * Poll delay behind a seam so tests stub it to a no-op (no real timers).
14901
+ * Production uses a short fixed delay between status re-probes.
14902
+ */
14903
+ sleep: (ms) => new Promise((r) => setTimeout(r, ms))
14899
14904
  };
14900
- async function ensureSharedServer(adapter) {
14901
- const status2 = await adapter.run(["dolt", "status"]);
14902
- if (status2.code === 0 && _daemonSeam.isRunning(status2.stdout)) {
14905
+ var DEFAULTS = { startAttempts: 2, pollAttempts: 10, pollDelayMs: 500 };
14906
+ async function ensureSharedServer(adapter, options = {}) {
14907
+ const startAttempts = options.startAttempts ?? DEFAULTS.startAttempts;
14908
+ const pollAttempts = options.pollAttempts ?? DEFAULTS.pollAttempts;
14909
+ const pollDelayMs = options.pollDelayMs ?? DEFAULTS.pollDelayMs;
14910
+ const probe = async () => {
14911
+ const status2 = await adapter.run(["dolt", "status"]);
14912
+ return status2.code === 0 && _daemonSeam.isRunning(status2.stdout);
14913
+ };
14914
+ if (await probe()) {
14903
14915
  log.trace("beads", "shared dolt sql-server already running \u2014 reusing");
14904
14916
  return { up: true, started: false };
14905
14917
  }
14906
- log.info("beads", "shared dolt sql-server not running \u2014 starting (detached)");
14907
- const start2 = await adapter.run(["dolt", "start"]);
14908
- if (start2.code !== 0) {
14918
+ for (let attempt = 1; attempt <= startAttempts; attempt++) {
14919
+ log.info(
14920
+ "beads",
14921
+ `shared dolt sql-server not running \u2014 starting (detached), attempt ${attempt}/${startAttempts}`
14922
+ );
14923
+ const start2 = await adapter.run(["dolt", "start"]);
14924
+ if (start2.code !== 0) {
14925
+ log.warn(
14926
+ "beads",
14927
+ `bd dolt start failed (code=${start2.code}): ${start2.stderr.slice(0, 200)} \u2014 retrying`
14928
+ );
14929
+ if (attempt < startAttempts) await _daemonSeam.sleep(pollDelayMs);
14930
+ continue;
14931
+ }
14932
+ for (let poll = 1; poll <= pollAttempts; poll++) {
14933
+ if (await probe()) {
14934
+ log.info("beads", `shared dolt sql-server up after ${poll} status poll(s)`);
14935
+ return { up: true, started: true };
14936
+ }
14937
+ if (poll < pollAttempts) await _daemonSeam.sleep(pollDelayMs);
14938
+ }
14909
14939
  log.warn(
14910
14940
  "beads",
14911
- `bd dolt start failed (code=${start2.code}): ${start2.stderr.slice(0, 200)} \u2014 beads memory unavailable this run`
14941
+ `shared dolt sql-server not listening after ${pollAttempts} polls (start attempt ${attempt}/${startAttempts})`
14912
14942
  );
14913
- return { up: false, started: false };
14914
- }
14915
- const recheck = await adapter.run(["dolt", "status"]);
14916
- const up = recheck.code === 0 && _daemonSeam.isRunning(recheck.stdout);
14917
- if (!up) {
14918
- log.warn("beads", "shared dolt sql-server still not reachable after start \u2014 non-fatal");
14919
14943
  }
14920
- return { up, started: up };
14944
+ log.warn("beads", "shared dolt sql-server still not reachable after all retries \u2014 non-fatal");
14945
+ return { up: false, started: false };
14921
14946
  }
14922
14947
 
14923
14948
  // src/beads/project-key.ts
@@ -15214,6 +15239,34 @@ async function provisionBeads(opts = {}) {
15214
15239
  log.warn("beads", "shared dolt sql-server not up \u2014 beads disabled this run");
15215
15240
  return result;
15216
15241
  }
15242
+ try {
15243
+ if (!await projectDbReachable(bd)) {
15244
+ log.info(
15245
+ "beads",
15246
+ `prefix DB '${prefix}' not reachable on shared server \u2014 self-healing via bd bootstrap`
15247
+ );
15248
+ const boot = await bd.run(["bootstrap", "--non-interactive"]);
15249
+ if (boot.code !== 0) {
15250
+ log.warn(
15251
+ "beads",
15252
+ `bd bootstrap failed (code=${boot.code}): ${boot.stderr.slice(0, 200)} \u2014 prefix DB may be absent`
15253
+ );
15254
+ }
15255
+ const reachable = await projectDbReachable(bd);
15256
+ result.serverUp = reachable;
15257
+ result.initialized = reachable;
15258
+ if (!reachable) {
15259
+ log.warn(
15260
+ "beads",
15261
+ `prefix DB '${prefix}' still unreachable after bootstrap \u2014 beads disabled this run`
15262
+ );
15263
+ return result;
15264
+ }
15265
+ log.info("beads", `prefix DB '${prefix}' materialized on shared server`);
15266
+ }
15267
+ } catch (err) {
15268
+ log.warn("beads", "verifying/creating the prefix DB threw (non-fatal)", err);
15269
+ }
15217
15270
  const exp = await bd.run(["config", "set", "export.auto", "true"]);
15218
15271
  result.exportEnabled = exp.code === 0;
15219
15272
  result.agentsWired = await setupAgents(bd, opts.agents ?? []);
@@ -15223,6 +15276,10 @@ async function provisionBeads(opts = {}) {
15223
15276
  );
15224
15277
  return result;
15225
15278
  }
15279
+ async function projectDbReachable(bd) {
15280
+ const ping = await bd.run(["ping"]);
15281
+ return ping.code === 0;
15282
+ }
15226
15283
  async function setupAgents(bd, agents) {
15227
15284
  const wired = [];
15228
15285
  for (const recipe of dedupeRecipes(agents)) {
@@ -17943,7 +18000,7 @@ async function autoUpgradeBeforeCriticalCommand() {
17943
18000
  if (process.env.NODE_ENV === "test") return;
17944
18001
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
17945
18002
  if (process.env.CI) return;
17946
- const current = true ? "2.46.3" : null;
18003
+ const current = true ? "2.46.5" : null;
17947
18004
  if (!current) return;
17948
18005
  const cache = readCache();
17949
18006
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -17960,7 +18017,7 @@ function checkForUpdates() {
17960
18017
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
17961
18018
  if (process.env.CI) return;
17962
18019
  if (!process.stdout.isTTY) return;
17963
- const current = true ? "2.46.3" : null;
18020
+ const current = true ? "2.46.5" : null;
17964
18021
  if (!current) return;
17965
18022
  const cache = readCache();
17966
18023
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -18402,7 +18459,7 @@ var defaultSpawner = (env, cwd, args2 = []) => (0, import_node_child_process14.s
18402
18459
  detached: false
18403
18460
  });
18404
18461
  function currentCliVersion() {
18405
- return true ? "2.46.3" : null;
18462
+ return true ? "2.46.5" : null;
18406
18463
  }
18407
18464
  function runCmd(cmd, args2, timeoutMs) {
18408
18465
  return new Promise((resolve7) => {
@@ -23726,8 +23783,18 @@ function reconcileCumulative(existing, incoming) {
23726
23783
  if (incoming.length === 0) return existing;
23727
23784
  if (incoming.startsWith(existing)) return incoming;
23728
23785
  if (existing.startsWith(incoming)) return existing;
23786
+ const shared = commonPrefixLength(existing, incoming);
23787
+ if (shared > 0 && shared >= existing.length / 2) {
23788
+ return existing.slice(0, shared) + incoming.slice(shared);
23789
+ }
23729
23790
  return existing + incoming;
23730
23791
  }
23792
+ function commonPrefixLength(a, b) {
23793
+ const max = Math.min(a.length, b.length);
23794
+ let i = 0;
23795
+ while (i < max && a.charCodeAt(i) === b.charCodeAt(i)) i += 1;
23796
+ return i;
23797
+ }
23731
23798
 
23732
23799
  // src/agents/acp/onboarding.ts
23733
23800
  var import_child_process22 = require("child_process");
@@ -24653,6 +24720,26 @@ var StreamingState = class {
24653
24720
  * no matter how many message ids the adapter spreads it across.
24654
24721
  */
24655
24722
  turnTextChunkId = null;
24723
+ /**
24724
+ * Stable chunkId that ALL `thinking` segments of the current turn collapse
24725
+ * onto (set to the first thought chunk's id, reset each {@link beginTurn}) —
24726
+ * the thinking twin of {@link turnTextChunkId}.
24727
+ *
24728
+ * Why: `claude-agent-acp` (≥0.47) re-emits the CONSOLIDATED thought under a
24729
+ * DIFFERENT message id (the same dedupe misfire that doubles text). The
24730
+ * mapper derives the thinking chunkId from that message id
24731
+ * (`<messageId>::thought`), so the consolidated re-emit lands in a SECOND
24732
+ * `::thought` buffer, BOTH get flushed `isFinal:true`, and the mobile
24733
+ * activity card (which coalesces by chunkId) stacks the two copies → the
24734
+ * thinking doubles ("TheThe user said …briefly.The user said …briefly.").
24735
+ * Text was protected by {@link turnTextChunkId}; thinking was not. Collapsing
24736
+ * every thought segment of a turn onto one reconcile buffer makes the re-emit
24737
+ * a `reconcileCumulative` REPLACE (identical snapshot) instead of a second
24738
+ * buffer. tool_use / tool_result keep their own id within the turn (distinct
24739
+ * bubbles; the adapter does NOT re-emit a consolidated tool snapshot under a
24740
+ * fresh id, so they don't share this bug).
24741
+ */
24742
+ turnThoughtChunkId = null;
24656
24743
  /**
24657
24744
  * Monotonic turn counter, bumped each {@link beginTurn}. Used to NAMESPACE
24658
24745
  * every streaming-chunk id so an id the ACP adapter REUSES across turns can't
@@ -24759,6 +24846,7 @@ var StreamingState = class {
24759
24846
  this.text = "";
24760
24847
  this.streamingChunks.clear();
24761
24848
  this.turnTextChunkId = null;
24849
+ this.turnThoughtChunkId = null;
24762
24850
  this.turnSeq += 1;
24763
24851
  if (this.pending?.kind === "permission") {
24764
24852
  clearTimeout(this.pending.timeoutTimer);
@@ -24770,7 +24858,7 @@ var StreamingState = class {
24770
24858
  await this.publisher.publishOutput({ type: "new_turn", done: false });
24771
24859
  }
24772
24860
  append(delta) {
24773
- const baseId = delta.kind === "text" ? this.turnTextChunkId ??= delta.chunkId : delta.chunkId;
24861
+ const baseId = delta.kind === "text" ? this.turnTextChunkId ??= delta.chunkId : delta.kind === "thinking" ? this.turnThoughtChunkId ??= delta.chunkId : delta.chunkId;
24774
24862
  const chunkId = `t${this.turnSeq}:${baseId}`;
24775
24863
  const existing = this.streamingChunks.get(chunkId);
24776
24864
  if (existing && existing.kind !== delta.kind) {
@@ -29739,7 +29827,7 @@ function checkChokidar() {
29739
29827
  }
29740
29828
  async function doctor(args2 = []) {
29741
29829
  const json = args2.includes("--json");
29742
- const cliVersion = true ? "2.46.3" : "0.0.0-dev";
29830
+ const cliVersion = true ? "2.46.5" : "0.0.0-dev";
29743
29831
  const apiBase2 = resolveApiBaseUrl();
29744
29832
  const diagnosticId = (0, import_node_crypto8.randomUUID)();
29745
29833
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -29938,7 +30026,7 @@ async function completion(args2) {
29938
30026
  // src/commands/version.ts
29939
30027
  var import_picocolors15 = __toESM(require("picocolors"));
29940
30028
  function version2() {
29941
- const v = true ? "2.46.3" : "unknown";
30029
+ const v = true ? "2.46.5" : "unknown";
29942
30030
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
29943
30031
  }
29944
30032
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.46.3",
3
+ "version": "2.46.5",
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",