codeam-cli 2.61.10 → 2.61.13

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 +114 -12
  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.61.11] — 2026-07-16
8
+
9
+ ### Fixed
10
+
11
+ - **cli:** Periodic 12h re-baseline so an idle session's conversation outlives the backend TTL
12
+
13
+ ## [2.61.10] — 2026-07-16
14
+
15
+ ### Fixed
16
+
17
+ - **cli:** Fleet box hardening — self-updatable image, fresh-pull creates, dead-container rm
18
+
7
19
  ## [2.61.9] — 2026-07-16
8
20
 
9
21
  ### Fixed
package/dist/index.js CHANGED
@@ -742,6 +742,49 @@ var INTEGRATION_REGISTRY = {
742
742
  staticEnv: { AZURE_DEVOPS_AUTH_METHOD: "pat" }
743
743
  }
744
744
  }
745
+ },
746
+ figma: {
747
+ id: "figma",
748
+ name: "Figma",
749
+ icon: "figma",
750
+ // LIVE — the Figma OAuth app (Confidential, both prod+dev redirect URIs)
751
+ // is registered and FIGMA_OAUTH_CLIENT_ID/SECRET/REDIRECT_URI are in
752
+ // Secret Manager (prod+dev, created 2026-07-16). The backend
753
+ // FigmaOAuthProvider is config-gated (503 if env unset) so this is safe
754
+ // even mid-rollout before the secrets mount.
755
+ enabled: true,
756
+ auth: {
757
+ kind: "oauth_redirect",
758
+ // Granular READ-ONLY scopes (legacy `files:read` is deprecated for
759
+ // OAuth). Asset export (GET /v1/images) rides file_content:read.
760
+ // file_variables:read is Enterprise-only and would break linking for
761
+ // normal accounts — deliberately excluded. ⚠️ Changing these requires
762
+ // the user to RE-LINK Figma.
763
+ scopes: [
764
+ "current_user:read",
765
+ "file_content:read",
766
+ "file_metadata:read",
767
+ "file_dev_resources:read",
768
+ "library_content:read"
769
+ ]
770
+ },
771
+ delivery: {
772
+ mcp: {
773
+ // Framelink figma-developer-mcp (Node, stdio) in BYO-token headless
774
+ // mode — the ONLY known Figma MCP server that accepts an OAuth
775
+ // Bearer token: FIGMA_OAUTH_TOKEN → `Authorization: Bearer` (env
776
+ // only, never argv). Figma's official servers can't be used here
777
+ // (remote = interactive OAuth + client allowlist; Dev Mode =
778
+ // desktop app). Version PINNED; bump only after re-verifying
779
+ // headless. Tools: get_figma_data (condensed layout extraction) +
780
+ // download_figma_images (asset export).
781
+ command: "npx",
782
+ args: ["-y", "figma-developer-mcp@0.13.2", "--stdio", "--no-telemetry"],
783
+ envMapping: {
784
+ FIGMA_OAUTH_TOKEN: "accessToken"
785
+ }
786
+ }
787
+ }
745
788
  }
746
789
  };
747
790
  function getIntegration(id) {
@@ -5975,7 +6018,7 @@ function readAnonId() {
5975
6018
  }
5976
6019
  function superProperties() {
5977
6020
  return {
5978
- cliVersion: true ? "2.61.10" : "0.0.0-dev",
6021
+ cliVersion: true ? "2.61.13" : "0.0.0-dev",
5979
6022
  nodeVersion: process.version,
5980
6023
  platform: process.platform,
5981
6024
  arch: process.arch,
@@ -6156,7 +6199,7 @@ var os4 = __toESM(require("os"));
6156
6199
  // package.json
6157
6200
  var package_default = {
6158
6201
  name: "codeam-cli",
6159
- version: "2.61.10",
6202
+ version: "2.61.13",
6160
6203
  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
6204
  type: "commonjs",
6162
6205
  main: "dist/index.js",
@@ -7299,7 +7342,7 @@ var CommandRelayService = class _CommandRelayService {
7299
7342
  // fresh + clear the "CLI update available" banner after a self-update
7300
7343
  // (a codespace that reinstalls @latest reconnects via heartbeat, not
7301
7344
  // pair/reconnect). Older backends ignore the extra field.
7302
- ..."2.61.10" ? { ideVersion: "2.61.10" } : {}
7345
+ ..."2.61.13" ? { ideVersion: "2.61.13" } : {}
7303
7346
  }).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
7304
7347
  }
7305
7348
  /**
@@ -17900,7 +17943,7 @@ async function autoUpgradeBeforeCriticalCommand() {
17900
17943
  if (process.env.NODE_ENV === "test") return;
17901
17944
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
17902
17945
  if (process.env.CI) return;
17903
- const current = true ? "2.61.10" : null;
17946
+ const current = true ? "2.61.13" : null;
17904
17947
  if (!current) return;
17905
17948
  const cache = readCache();
17906
17949
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -17917,7 +17960,7 @@ function checkForUpdates() {
17917
17960
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
17918
17961
  if (process.env.CI) return;
17919
17962
  if (!process.stdout.isTTY) return;
17920
- const current = true ? "2.61.10" : null;
17963
+ const current = true ? "2.61.13" : null;
17921
17964
  if (!current) return;
17922
17965
  const cache = readCache();
17923
17966
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -17937,7 +17980,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
17937
17980
  var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
17938
17981
  var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
17939
17982
  function currentCliVersion() {
17940
- return true ? "2.61.10" : null;
17983
+ return true ? "2.61.13" : null;
17941
17984
  }
17942
17985
  function runCmd(cmd, args2, timeoutMs) {
17943
17986
  return new Promise((resolve8) => {
@@ -24941,6 +24984,18 @@ var HistoryService = class _HistoryService {
24941
24984
  }
24942
24985
  /** Per-session JSONL mtime at the last upload — gates {@link uploadConversationIfChanged}. */
24943
24986
  lastTranscriptMtimeMs = /* @__PURE__ */ new Map();
24987
+ /** Wall-clock of the last upload per session — drives the periodic
24988
+ * re-baseline below. */
24989
+ lastUploadWallMs = /* @__PURE__ */ new Map();
24990
+ /** The backend stores the conversation with a bounded TTL (24 h,
24991
+ * `WS_SESSION_TTL`). An IDLE session's JSONL never changes, so a pure
24992
+ * mtime gate would never re-ship and the backend copy would expire —
24993
+ * every later `get_conversation` → GET then returns EMPTY forever (the
24994
+ * 2026-07-16 "la sesión no carga" regression, second occurrence: the
24995
+ * first fix pushed at session START but nothing refreshed an idle
24996
+ * session past the TTL). Re-baseline at half the backend TTL so the
24997
+ * stored copy can never lapse while the session lives. */
24998
+ static REBASELINE_INTERVAL_MS = 12 * 60 * 60 * 1e3;
24944
24999
  /**
24945
25000
  * Upload a session's transcript when its JSONL changed since the last upload.
24946
25001
  * Scales to long/heavy conversations: the ACP `get_conversation` handler is
@@ -24966,7 +25021,12 @@ var HistoryService = class _HistoryService {
24966
25021
  } catch {
24967
25022
  return false;
24968
25023
  }
24969
- if (this.lastTranscriptMtimeMs.get(sessionId) === mtimeMs) return false;
25024
+ const now = Date.now();
25025
+ const staleBaseline = now - (this.lastUploadWallMs.get(sessionId) ?? 0) > _HistoryService.REBASELINE_INTERVAL_MS;
25026
+ if (!staleBaseline && this.lastTranscriptMtimeMs.get(sessionId) === mtimeMs) {
25027
+ return false;
25028
+ }
25029
+ if (staleBaseline) this.lastUploadedUuid.delete(sessionId);
24970
25030
  let uploaded;
24971
25031
  if (this.lastUploadedUuid.has(sessionId)) {
24972
25032
  uploaded = await this.uploadDelta(sessionId) > 0;
@@ -24975,6 +25035,7 @@ var HistoryService = class _HistoryService {
24975
25035
  uploaded = true;
24976
25036
  }
24977
25037
  this.lastTranscriptMtimeMs.set(sessionId, mtimeMs);
25038
+ this.lastUploadWallMs.set(sessionId, now);
24978
25039
  return uploaded;
24979
25040
  }
24980
25041
  /**
@@ -31789,6 +31850,23 @@ async function resumeSessionH(ctx) {
31789
31850
  }
31790
31851
  try {
31791
31852
  await client3.loadSession(id);
31853
+ ctx.history.switchActiveSession(id);
31854
+ ctx.onActiveSessionChanged?.(id);
31855
+ try {
31856
+ await ctx.jsonlHistory.uploadConversationIfChanged(id);
31857
+ } catch (err) {
31858
+ log.warn("acpRunner", `resume_session: transcript upload failed: ${describeError(err)}`);
31859
+ }
31860
+ void (async () => {
31861
+ try {
31862
+ const listed = await client3.listSessions();
31863
+ if (listed && listed.length > 0) {
31864
+ await ctx.publisher.pushSessionList({ agentId: opts.agent, sessions: listed });
31865
+ }
31866
+ } catch (err) {
31867
+ log.warn("acpRunner", `resume_session: list push failed: ${describeError(err)}`);
31868
+ }
31869
+ })();
31792
31870
  await relay.sendResult(cmd.id, "completed", { sessionId: id });
31793
31871
  } catch (err) {
31794
31872
  log.warn("acpRunner", `resume_session failed: ${describeError(err)}`);
@@ -32342,6 +32420,21 @@ var AcpHistory = class {
32342
32420
  opts;
32343
32421
  messages = [];
32344
32422
  summary = null;
32423
+ /**
32424
+ * Switch the active conversation after a `resume_session` loadSession
32425
+ * (2026-07-16 "conversation never loads on resume" fix). The buffered
32426
+ * turns belong to the PREVIOUS conversation — flushing them under the
32427
+ * new id would corrupt it — so the buffer and summary reset; the loaded
32428
+ * conversation's real history lives in its JSONL, which the resume
32429
+ * handler uploads via HistoryService. Future turn flushes then push
32430
+ * under the new id.
32431
+ */
32432
+ switchActiveSession(id) {
32433
+ if (id === this.opts.acpSessionId) return;
32434
+ this.opts.acpSessionId = id;
32435
+ this.messages.length = 0;
32436
+ this.summary = null;
32437
+ }
32345
32438
  appendUserPrompt(text) {
32346
32439
  if (this.summary === null) {
32347
32440
  const trimmed = text.trim().replace(/\s+/g, " ");
@@ -32727,7 +32820,15 @@ async function runAcpSession(opts) {
32727
32820
  budgetRecovery,
32728
32821
  { get: () => _budgetReachedPosted, set: (v) => {
32729
32822
  _budgetReachedPosted = v;
32730
- } }
32823
+ } },
32824
+ // resume_session re-points the runner's active conversation: the
32825
+ // relay callback reads `acpSessionId` per command, so every FUTURE
32826
+ // get_conversation / upload / one-shot serves the RESUMED id — not
32827
+ // the boot-time one (2026-07-16 "resume loads the old/blank
32828
+ // conversation" fix).
32829
+ (id) => {
32830
+ acpSessionId = id;
32831
+ }
32731
32832
  );
32732
32833
  },
32733
32834
  { id: opts.agent, name: opts.agent, displayName: opts.agent }
@@ -32762,7 +32863,7 @@ async function runAcpSession(opts) {
32762
32863
  await new Promise(() => {
32763
32864
  });
32764
32865
  }
32765
- async function handleCommand(cmd, client3, relay, acpSessionId, models, streaming, opts, history, jsonlHistory, agentCaps, turnFiles, getBeads, publisher, recentStderr, budgetRecovery, budgetReachedFlag) {
32866
+ async function handleCommand(cmd, client3, relay, acpSessionId, models, streaming, opts, history, jsonlHistory, agentCaps, turnFiles, getBeads, publisher, recentStderr, budgetRecovery, budgetReachedFlag, onActiveSessionChanged) {
32766
32867
  const session = {
32767
32868
  client: client3,
32768
32869
  relay,
@@ -32778,7 +32879,8 @@ async function handleCommand(cmd, client3, relay, acpSessionId, models, streamin
32778
32879
  publisher,
32779
32880
  recentStderr,
32780
32881
  budgetRecovery,
32781
- budgetReachedFlag
32882
+ budgetReachedFlag,
32883
+ onActiveSessionChanged
32782
32884
  };
32783
32885
  await dispatchAcpCommand(assembleAcpCommandContext(session, cmd));
32784
32886
  }
@@ -37437,7 +37539,7 @@ function checkChokidar() {
37437
37539
  }
37438
37540
  async function doctor(args2 = []) {
37439
37541
  const json = args2.includes("--json");
37440
- const cliVersion = true ? "2.61.10" : "0.0.0-dev";
37542
+ const cliVersion = true ? "2.61.13" : "0.0.0-dev";
37441
37543
  const apiBase2 = resolveApiBaseUrl();
37442
37544
  const diagnosticId = (0, import_node_crypto12.randomUUID)();
37443
37545
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -37948,7 +38050,7 @@ async function mcpRun(args2) {
37948
38050
  // src/commands/version.ts
37949
38051
  var import_picocolors15 = __toESM(require("picocolors"));
37950
38052
  function version2() {
37951
- const v = true ? "2.61.10" : "unknown";
38053
+ const v = true ? "2.61.13" : "unknown";
37952
38054
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
37953
38055
  }
37954
38056
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.61.10",
3
+ "version": "2.61.13",
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",