codeam-cli 2.61.7 → 2.61.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 CHANGED
@@ -4,6 +4,13 @@ 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.61.7] — 2026-07-16
8
+
9
+ ### Fixed
10
+
11
+ - **cli:** Auto-resume the user's session on host-agent restart (no churn)
12
+ - **cli:** Engines-compat test uses CommonJS require (was import.meta → tsc fail)
13
+
7
14
  ## [2.61.5] — 2026-07-16
8
15
 
9
16
  ### Added
package/dist/index.js CHANGED
@@ -5975,7 +5975,7 @@ function readAnonId() {
5975
5975
  }
5976
5976
  function superProperties() {
5977
5977
  return {
5978
- cliVersion: true ? "2.61.7" : "0.0.0-dev",
5978
+ cliVersion: true ? "2.61.8" : "0.0.0-dev",
5979
5979
  nodeVersion: process.version,
5980
5980
  platform: process.platform,
5981
5981
  arch: process.arch,
@@ -6156,7 +6156,7 @@ var os4 = __toESM(require("os"));
6156
6156
  // package.json
6157
6157
  var package_default = {
6158
6158
  name: "codeam-cli",
6159
- version: "2.61.7",
6159
+ version: "2.61.8",
6160
6160
  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.",
6161
6161
  type: "commonjs",
6162
6162
  main: "dist/index.js",
@@ -7299,7 +7299,7 @@ var CommandRelayService = class _CommandRelayService {
7299
7299
  // fresh + clear the "CLI update available" banner after a self-update
7300
7300
  // (a codespace that reinstalls @latest reconnects via heartbeat, not
7301
7301
  // pair/reconnect). Older backends ignore the extra field.
7302
- ..."2.61.7" ? { ideVersion: "2.61.7" } : {}
7302
+ ..."2.61.8" ? { ideVersion: "2.61.8" } : {}
7303
7303
  }).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
7304
7304
  }
7305
7305
  /**
@@ -17900,7 +17900,7 @@ async function autoUpgradeBeforeCriticalCommand() {
17900
17900
  if (process.env.NODE_ENV === "test") return;
17901
17901
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
17902
17902
  if (process.env.CI) return;
17903
- const current = true ? "2.61.7" : null;
17903
+ const current = true ? "2.61.8" : null;
17904
17904
  if (!current) return;
17905
17905
  const cache = readCache();
17906
17906
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -17917,7 +17917,7 @@ function checkForUpdates() {
17917
17917
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
17918
17918
  if (process.env.CI) return;
17919
17919
  if (!process.stdout.isTTY) return;
17920
- const current = true ? "2.61.7" : null;
17920
+ const current = true ? "2.61.8" : null;
17921
17921
  if (!current) return;
17922
17922
  const cache = readCache();
17923
17923
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -17937,7 +17937,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
17937
17937
  var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
17938
17938
  var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
17939
17939
  function currentCliVersion() {
17940
- return true ? "2.61.7" : null;
17940
+ return true ? "2.61.8" : null;
17941
17941
  }
17942
17942
  function runCmd(cmd, args2, timeoutMs) {
17943
17943
  return new Promise((resolve8) => {
@@ -18256,7 +18256,10 @@ var defaultSpawner = (env, cwd, args2 = []) => (0, import_node_child_process23.s
18256
18256
  });
18257
18257
  var defaultResumeSpawner = (env, cwd) => (0, import_node_child_process23.spawn)(process.execPath, [process.argv[1]], {
18258
18258
  cwd,
18259
- env: { ...process.env, ...env, CODEAM_AUTO_APPROVE: "1" },
18259
+ // CODEAM_AUTO_APPROVE=1 ACP path (baton off). CODEAM_RESUME_LATEST=1
18260
+ // continue the user's most-recent conversation instead of opening an empty
18261
+ // one (runAcpSession loads it via the ACP session/list RPC).
18262
+ env: { ...process.env, ...env, CODEAM_AUTO_APPROVE: "1", CODEAM_RESUME_LATEST: "1" },
18260
18263
  stdio: ["ignore", "pipe", "pipe"],
18261
18264
  detached: false
18262
18265
  });
@@ -29068,6 +29071,7 @@ var AcpClient = class {
29068
29071
  * the conversation — whereas one without it falls back to a fresh
29069
29072
  * `session/new`. Set once during {@link startOnce}. */
29070
29073
  supportsLoadSession = false;
29074
+ supportsListSessions = false;
29071
29075
  /** Idle watchdog for the in-flight prompt. The `Client` handlers
29072
29076
  * (`sessionUpdate` / `requestPermission`) reach for this to keep
29073
29077
  * the turn alive while the adapter is demonstrably working. Null
@@ -29252,6 +29256,7 @@ var AcpClient = class {
29252
29256
  `initialize \u2190 ok protocolVersion=${initialize.protocolVersion} agentCaps=${JSON.stringify(initialize.agentCapabilities ?? {}).slice(0, 200)}`
29253
29257
  );
29254
29258
  this.supportsLoadSession = initialize.agentCapabilities?.loadSession === true;
29259
+ this.supportsListSessions = !!initialize.agentCapabilities?.sessionCapabilities?.list;
29255
29260
  log.info("acpClient", "newSession \u2192 sending");
29256
29261
  let startupTimer;
29257
29262
  const startupFailure = new Promise((_2, reject) => {
@@ -29495,14 +29500,44 @@ var AcpClient = class {
29495
29500
  return;
29496
29501
  }
29497
29502
  log.info("acpClient", `loadSession \u2192 sessionId=${sessionId.slice(0, 8)}`);
29498
- await this.connection.loadSession({
29499
- sessionId,
29500
- cwd: this.opts.cwd,
29501
- mcpServers: this.opts.mcpServers ?? []
29502
- });
29503
+ this.opts.beginLoadReplay?.();
29504
+ try {
29505
+ await this.connection.loadSession({
29506
+ sessionId,
29507
+ cwd: this.opts.cwd,
29508
+ mcpServers: this.opts.mcpServers ?? []
29509
+ });
29510
+ } finally {
29511
+ this.opts.endLoadReplay?.();
29512
+ }
29503
29513
  this.sessionId = sessionId;
29504
29514
  log.info("acpClient", `loadSession \u2190 ok sessionId=${sessionId.slice(0, 8)}`);
29505
29515
  }
29516
+ /**
29517
+ * Enumerate the workspace's conversations via the ACP `session/list` RPC.
29518
+ * Agent-agnostic — works for ANY adapter that advertises
29519
+ * `sessionCapabilities.list` (claude/codex/gemini alike), so the mobile RECENT
29520
+ * list no longer depends on per-agent JSONL scanning. Maps SessionInfo (id +
29521
+ * agent-authored title + updatedAt) to the backend's RECENT-list shape.
29522
+ *
29523
+ * Returns null when the agent doesn't advertise `list` (caller falls back or
29524
+ * skips). Best-effort — never throws out to the caller.
29525
+ */
29526
+ async listSessions() {
29527
+ if (!this.connection || !this.supportsListSessions) return null;
29528
+ try {
29529
+ const res = await this.connection.listSessions({ cwd: this.opts.cwd });
29530
+ return (res.sessions ?? []).map((s) => ({
29531
+ id: s.sessionId,
29532
+ summary: s.title ?? "",
29533
+ // updatedAt is an ISO string; fall back to now on absent/unparseable.
29534
+ timestamp: s.updatedAt ? Date.parse(s.updatedAt) || Date.now() : Date.now()
29535
+ }));
29536
+ } catch (err) {
29537
+ log.trace("acpClient", "listSessions failed (best-effort)", err);
29538
+ return null;
29539
+ }
29540
+ }
29506
29541
  /**
29507
29542
  * Switch the active session's model via the non-standard
29508
29543
  * `session/set_model` RPC. The standard ACP SDK doesn't expose
@@ -32330,17 +32365,17 @@ var AcpHistory = class {
32330
32365
  async flush() {
32331
32366
  if (this.summary === null || this.messages.length === 0) return;
32332
32367
  const timestamp = Date.now();
32368
+ const current = { id: this.opts.acpSessionId, summary: this.summary, timestamp };
32369
+ let sessions3 = [current];
32370
+ const listed = this.opts.listSessions ? await this.opts.listSessions() : null;
32371
+ if (listed && listed.length > 0) {
32372
+ sessions3 = listed.map(
32373
+ (s) => s.id === this.opts.acpSessionId && !s.summary ? { ...s, summary: this.summary } : s
32374
+ );
32375
+ if (!sessions3.some((s) => s.id === this.opts.acpSessionId)) sessions3.unshift(current);
32376
+ }
32333
32377
  await Promise.all([
32334
- this.publisher.pushSessionList({
32335
- agentId: this.opts.agent,
32336
- sessions: [
32337
- {
32338
- id: this.opts.acpSessionId,
32339
- summary: this.summary,
32340
- timestamp
32341
- }
32342
- ]
32343
- }),
32378
+ this.publisher.pushSessionList({ agentId: this.opts.agent, sessions: sessions3 }),
32344
32379
  this.publisher.pushConversation({
32345
32380
  agentId: this.opts.agent,
32346
32381
  sessionId: this.opts.acpSessionId,
@@ -32386,6 +32421,10 @@ function computeAdapterExtraEnv(params) {
32386
32421
  );
32387
32422
  return env;
32388
32423
  }
32424
+ function pickLatestResumableConversation(sessions3, currentId) {
32425
+ const prior = (sessions3 ?? []).filter((s) => s.id !== currentId).sort((a, b) => b.timestamp - a.timestamp)[0];
32426
+ return prior?.id ?? null;
32427
+ }
32389
32428
  async function runAcpSession(opts) {
32390
32429
  const publisher = new AcpPublisher({
32391
32430
  sessionId: opts.sessionId,
@@ -32534,16 +32573,24 @@ async function runAcpSession(opts) {
32534
32573
  });
32535
32574
  return;
32536
32575
  }
32537
- const {
32538
- sessionId: acpSessionId,
32539
- initialize,
32540
- model: handshakeModel,
32541
- tier: handshakeTier
32542
- } = handshake;
32576
+ let acpSessionId = handshake.sessionId;
32577
+ const { initialize, model: handshakeModel, tier: handshakeTier } = handshake;
32543
32578
  log.trace(
32544
32579
  "acpRunner",
32545
32580
  `adapter handshake ok protocolVersion=${initialize.protocolVersion} sessionId=${acpSessionId.slice(0, 8)}`
32546
32581
  );
32582
+ if (process.env.CODEAM_RESUME_LATEST === "1") {
32583
+ try {
32584
+ const priorId = pickLatestResumableConversation(await client3.listSessions(), acpSessionId);
32585
+ if (priorId) {
32586
+ await client3.loadSession(priorId);
32587
+ acpSessionId = priorId;
32588
+ log.info("acpRunner", `auto-resumed latest conversation ${priorId.slice(0, 8)}`);
32589
+ }
32590
+ } catch (err) {
32591
+ log.trace("acpRunner", "auto-resume-latest failed (best-effort)", err);
32592
+ }
32593
+ }
32547
32594
  showSuccess(`${opts.agent} online (ACP) \u2014 awaiting prompts from mobile.`);
32548
32595
  showRelayNotice();
32549
32596
  void publisher.publishOutput({
@@ -32565,7 +32612,14 @@ async function runAcpSession(opts) {
32565
32612
  });
32566
32613
  const runtime = createInteractiveAgentStrategy(opts.agent, createOsStrategy());
32567
32614
  const models = await runtime.listModels();
32568
- const history = new AcpHistory(publisher, { agent: opts.agent, acpSessionId });
32615
+ const history = new AcpHistory(publisher, {
32616
+ agent: opts.agent,
32617
+ acpSessionId,
32618
+ // Agent-agnostic RECENT list: enumerate via the ACP session/list RPC (any
32619
+ // adapter advertising sessionCapabilities.list). Returns null on unsupported
32620
+ // agents → flush() falls back to the current session only.
32621
+ listSessions: () => client3.listSessions()
32622
+ });
32569
32623
  const jsonlHistory = new HistoryService(runtime, opts.pluginId, opts.cwd, {
32570
32624
  pluginAuthToken: opts.pluginAuthToken
32571
32625
  });
@@ -37340,7 +37394,7 @@ function checkChokidar() {
37340
37394
  }
37341
37395
  async function doctor(args2 = []) {
37342
37396
  const json = args2.includes("--json");
37343
- const cliVersion = true ? "2.61.7" : "0.0.0-dev";
37397
+ const cliVersion = true ? "2.61.8" : "0.0.0-dev";
37344
37398
  const apiBase2 = resolveApiBaseUrl();
37345
37399
  const diagnosticId = (0, import_node_crypto12.randomUUID)();
37346
37400
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -37851,7 +37905,7 @@ async function mcpRun(args2) {
37851
37905
  // src/commands/version.ts
37852
37906
  var import_picocolors15 = __toESM(require("picocolors"));
37853
37907
  function version2() {
37854
- const v = true ? "2.61.7" : "unknown";
37908
+ const v = true ? "2.61.8" : "unknown";
37855
37909
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
37856
37910
  }
37857
37911
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.61.7",
3
+ "version": "2.61.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",