codeam-cli 2.60.64 → 2.60.65

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,16 @@ 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.60.64] — 2026-07-15
8
+
9
+ ### Added
10
+
11
+ - **shared:** Add Slack search:read scope (agent can search the user's messages)
12
+
13
+ ### Documentation
14
+
15
+ - **shared:** Clarify Slack uses a USER token (agent acts as the user)
16
+
7
17
  ## [2.60.63] — 2026-07-15
8
18
 
9
19
  ### Added
package/dist/index.js CHANGED
@@ -5891,7 +5891,7 @@ function readAnonId() {
5891
5891
  }
5892
5892
  function superProperties() {
5893
5893
  return {
5894
- cliVersion: true ? "2.60.64" : "0.0.0-dev",
5894
+ cliVersion: true ? "2.60.65" : "0.0.0-dev",
5895
5895
  nodeVersion: process.version,
5896
5896
  platform: process.platform,
5897
5897
  arch: process.arch,
@@ -6072,7 +6072,7 @@ var os4 = __toESM(require("os"));
6072
6072
  // package.json
6073
6073
  var package_default = {
6074
6074
  name: "codeam-cli",
6075
- version: "2.60.64",
6075
+ version: "2.60.65",
6076
6076
  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.",
6077
6077
  type: "commonjs",
6078
6078
  main: "dist/index.js",
@@ -6840,7 +6840,7 @@ function httpStatusOf(err) {
6840
6840
  var API_BASE2 = resolveApiBaseUrl();
6841
6841
  var SSE_LIVENESS_TIMEOUT_MS = 45e3;
6842
6842
  var SSE_WATCHDOG_INTERVAL_MS = 1e4;
6843
- var CommandRelayService = class {
6843
+ var CommandRelayService = class _CommandRelayService {
6844
6844
  constructor(pluginId, onCommand, agentMeta, agentsOverride) {
6845
6845
  this.pluginId = pluginId;
6846
6846
  this.onCommand = onCommand;
@@ -6862,6 +6862,16 @@ var CommandRelayService = class {
6862
6862
  agentsRegistered = false;
6863
6863
  /** SSE connection (null when on the polling fallback or stopped). */
6864
6864
  sseRequest = null;
6865
+ // At-least-once delivery: the backend now delivers commands NON-DESTRUCTIVELY
6866
+ // (peek) when we advertise `X-Codeam-Cmd-Ack: 1`, and drains the queue only
6867
+ // when we ack the ids. So a command can never be lost to a ghost/racing SSE
6868
+ // subscriber during codespace boot (the 2026-07-15 first-prompt loss). The
6869
+ // trade-off is possible REDELIVERY (reconnect, publish re-fire, ghost race),
6870
+ // so we dedupe by id here — a bounded FIFO set of ids we've already
6871
+ // dispatched. Cap keeps memory flat over a long session; the oldest ids are
6872
+ // evicted (a command that old is long gone from the server queue anyway).
6873
+ processedIds = /* @__PURE__ */ new Set();
6874
+ static PROCESSED_ID_CAP = 1e3;
6865
6875
  /** Polling backoff state (only used on the fallback). */
6866
6876
  pollTimer = null;
6867
6877
  pollFailures = 0;
@@ -7131,14 +7141,15 @@ var CommandRelayService = class {
7131
7141
  // as X-Plugin-Poll-Secret. Empty {} for legacy sessions / older
7132
7142
  // backends (which ignore it).
7133
7143
  pollSecretHeader() {
7144
+ const headers = { "X-Codeam-Cmd-Ack": "1" };
7134
7145
  try {
7135
7146
  const secret = loadCliConfig().sessions.find(
7136
7147
  (s) => s.pluginId === this.pluginId
7137
7148
  )?.pollSecret;
7138
- return secret ? { "X-Plugin-Poll-Secret": secret } : {};
7149
+ if (secret) headers["X-Plugin-Poll-Secret"] = secret;
7139
7150
  } catch {
7140
- return {};
7141
7151
  }
7152
+ return headers;
7142
7153
  }
7143
7154
  async pollOnce() {
7144
7155
  try {
@@ -7161,7 +7172,13 @@ var CommandRelayService = class {
7161
7172
  }
7162
7173
  }
7163
7174
  async dispatchCommands(commands) {
7175
+ this.ackCommands(commands.map((c2) => c2.id));
7164
7176
  for (const cmd of commands) {
7177
+ if (cmd.id && this.processedIds.has(cmd.id)) {
7178
+ log.trace("relay", `dedupe skip already-dispatched id=${cmd.id}`);
7179
+ continue;
7180
+ }
7181
+ if (cmd.id) this.rememberProcessed(cmd.id);
7165
7182
  try {
7166
7183
  log.trace("relay", `dispatch type=${cmd.type} id=${cmd.id}`);
7167
7184
  await this.onCommand(cmd);
@@ -7170,6 +7187,23 @@ var CommandRelayService = class {
7170
7187
  }
7171
7188
  }
7172
7189
  }
7190
+ /** Record a dispatched id, evicting the oldest when over the cap (FIFO). */
7191
+ rememberProcessed(id) {
7192
+ this.processedIds.add(id);
7193
+ if (this.processedIds.size > _CommandRelayService.PROCESSED_ID_CAP) {
7194
+ const oldest = this.processedIds.values().next().value;
7195
+ if (oldest !== void 0) this.processedIds.delete(oldest);
7196
+ }
7197
+ }
7198
+ /** Confirm receipt of command ids so the backend removes them from the queue
7199
+ * (the at-least-once delivery guarantee). Best-effort — never throws. */
7200
+ ackCommands(ids) {
7201
+ const commandIds = ids.filter((id) => typeof id === "string" && id.length > 0);
7202
+ if (commandIds.length === 0) return;
7203
+ void _postJson(`${API_BASE2}/api/commands/ack`, { pluginId: this.pluginId, commandIds }, {
7204
+ ...this.pollSecretHeader()
7205
+ }).catch((err) => log.trace("relay", "ack post failed (will redeliver+dedupe)", err));
7206
+ }
7173
7207
  // ─── Heartbeat + agents ──────────────────────────────────────────
7174
7208
  async sendHeartbeat(online) {
7175
7209
  await _postJson(`${API_BASE2}/api/plugin/heartbeat`, {
@@ -7181,7 +7215,7 @@ var CommandRelayService = class {
7181
7215
  // fresh + clear the "CLI update available" banner after a self-update
7182
7216
  // (a codespace that reinstalls @latest reconnects via heartbeat, not
7183
7217
  // pair/reconnect). Older backends ignore the extra field.
7184
- ..."2.60.64" ? { ideVersion: "2.60.64" } : {}
7218
+ ..."2.60.65" ? { ideVersion: "2.60.65" } : {}
7185
7219
  }).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
7186
7220
  }
7187
7221
  /**
@@ -17758,7 +17792,7 @@ async function autoUpgradeBeforeCriticalCommand() {
17758
17792
  if (process.env.NODE_ENV === "test") return;
17759
17793
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
17760
17794
  if (process.env.CI) return;
17761
- const current = true ? "2.60.64" : null;
17795
+ const current = true ? "2.60.65" : null;
17762
17796
  if (!current) return;
17763
17797
  const cache = readCache();
17764
17798
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -17775,7 +17809,7 @@ function checkForUpdates() {
17775
17809
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
17776
17810
  if (process.env.CI) return;
17777
17811
  if (!process.stdout.isTTY) return;
17778
- const current = true ? "2.60.64" : null;
17812
+ const current = true ? "2.60.65" : null;
17779
17813
  if (!current) return;
17780
17814
  const cache = readCache();
17781
17815
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -17795,7 +17829,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
17795
17829
  var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
17796
17830
  var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
17797
17831
  function currentCliVersion() {
17798
- return true ? "2.60.64" : null;
17832
+ return true ? "2.60.65" : null;
17799
17833
  }
17800
17834
  function runCmd(cmd, args2, timeoutMs) {
17801
17835
  return new Promise((resolve7) => {
@@ -35224,7 +35258,7 @@ function checkChokidar() {
35224
35258
  }
35225
35259
  async function doctor(args2 = []) {
35226
35260
  const json = args2.includes("--json");
35227
- const cliVersion = true ? "2.60.64" : "0.0.0-dev";
35261
+ const cliVersion = true ? "2.60.65" : "0.0.0-dev";
35228
35262
  const apiBase2 = resolveApiBaseUrl();
35229
35263
  const diagnosticId = (0, import_node_crypto12.randomUUID)();
35230
35264
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -35701,7 +35735,7 @@ async function mcpRun(args2) {
35701
35735
  // src/commands/version.ts
35702
35736
  var import_picocolors15 = __toESM(require("picocolors"));
35703
35737
  function version2() {
35704
- const v = true ? "2.60.64" : "unknown";
35738
+ const v = true ? "2.60.65" : "unknown";
35705
35739
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
35706
35740
  }
35707
35741
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.60.64",
3
+ "version": "2.60.65",
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",