codeam-cli 2.60.64 → 2.60.66
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 +16 -0
- package/dist/index.js +77 -11
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,22 @@ 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.65] — 2026-07-15
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **cli:** At-least-once command delivery — dedupe + ack (bulletproof first-prompt loss)
|
|
12
|
+
|
|
13
|
+
## [2.60.64] — 2026-07-15
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- **shared:** Add Slack search:read scope (agent can search the user's messages)
|
|
18
|
+
|
|
19
|
+
### Documentation
|
|
20
|
+
|
|
21
|
+
- **shared:** Clarify Slack uses a USER token (agent acts as the user)
|
|
22
|
+
|
|
7
23
|
## [2.60.63] — 2026-07-15
|
|
8
24
|
|
|
9
25
|
### Added
|
package/dist/index.js
CHANGED
|
@@ -663,6 +663,38 @@ var INTEGRATION_REGISTRY = {
|
|
|
663
663
|
}
|
|
664
664
|
}
|
|
665
665
|
}
|
|
666
|
+
},
|
|
667
|
+
notion: {
|
|
668
|
+
id: "notion",
|
|
669
|
+
name: "Notion",
|
|
670
|
+
icon: "notion",
|
|
671
|
+
// LIVE — the Notion public OAuth integration is registered and
|
|
672
|
+
// NOTION_OAUTH_CLIENT_ID/SECRET/REDIRECT_URI are in Secret Manager
|
|
673
|
+
// (prod+dev). The backend NotionOAuthProvider is config-gated (503 if env
|
|
674
|
+
// unset) so this is safe even mid-rollout before the secrets mount.
|
|
675
|
+
enabled: true,
|
|
676
|
+
auth: {
|
|
677
|
+
kind: "oauth_redirect",
|
|
678
|
+
// Notion does NOT use per-request OAuth scopes — access is governed by
|
|
679
|
+
// the integration's configured CAPABILITIES (read/update/insert content
|
|
680
|
+
// + read user info), set once on the Notion integration, not passed in
|
|
681
|
+
// the authorize URL. So there is no `scope` param to request here.
|
|
682
|
+
scopes: []
|
|
683
|
+
},
|
|
684
|
+
delivery: {
|
|
685
|
+
mcp: {
|
|
686
|
+
// Notion's OFFICIAL stdio MCP server (Node). BYO-token headless: the
|
|
687
|
+
// OAuth access token is fed via NOTION_TOKEN and the server sends it as
|
|
688
|
+
// `Authorization: Bearer` + `Notion-Version: 2022-06-28` (env only,
|
|
689
|
+
// never argv). No discriminator — the token alone authenticates its
|
|
690
|
+
// workspace. Version PINNED; bump only after re-verifying headless.
|
|
691
|
+
command: "npx",
|
|
692
|
+
args: ["-y", "@notionhq/notion-mcp-server@2.4.1"],
|
|
693
|
+
envMapping: {
|
|
694
|
+
NOTION_TOKEN: "accessToken"
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
}
|
|
666
698
|
}
|
|
667
699
|
};
|
|
668
700
|
function getIntegration(id) {
|
|
@@ -5891,7 +5923,7 @@ function readAnonId() {
|
|
|
5891
5923
|
}
|
|
5892
5924
|
function superProperties() {
|
|
5893
5925
|
return {
|
|
5894
|
-
cliVersion: true ? "2.60.
|
|
5926
|
+
cliVersion: true ? "2.60.66" : "0.0.0-dev",
|
|
5895
5927
|
nodeVersion: process.version,
|
|
5896
5928
|
platform: process.platform,
|
|
5897
5929
|
arch: process.arch,
|
|
@@ -6072,7 +6104,7 @@ var os4 = __toESM(require("os"));
|
|
|
6072
6104
|
// package.json
|
|
6073
6105
|
var package_default = {
|
|
6074
6106
|
name: "codeam-cli",
|
|
6075
|
-
version: "2.60.
|
|
6107
|
+
version: "2.60.66",
|
|
6076
6108
|
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
6109
|
type: "commonjs",
|
|
6078
6110
|
main: "dist/index.js",
|
|
@@ -6840,7 +6872,7 @@ function httpStatusOf(err) {
|
|
|
6840
6872
|
var API_BASE2 = resolveApiBaseUrl();
|
|
6841
6873
|
var SSE_LIVENESS_TIMEOUT_MS = 45e3;
|
|
6842
6874
|
var SSE_WATCHDOG_INTERVAL_MS = 1e4;
|
|
6843
|
-
var CommandRelayService = class {
|
|
6875
|
+
var CommandRelayService = class _CommandRelayService {
|
|
6844
6876
|
constructor(pluginId, onCommand, agentMeta, agentsOverride) {
|
|
6845
6877
|
this.pluginId = pluginId;
|
|
6846
6878
|
this.onCommand = onCommand;
|
|
@@ -6862,6 +6894,16 @@ var CommandRelayService = class {
|
|
|
6862
6894
|
agentsRegistered = false;
|
|
6863
6895
|
/** SSE connection (null when on the polling fallback or stopped). */
|
|
6864
6896
|
sseRequest = null;
|
|
6897
|
+
// At-least-once delivery: the backend now delivers commands NON-DESTRUCTIVELY
|
|
6898
|
+
// (peek) when we advertise `X-Codeam-Cmd-Ack: 1`, and drains the queue only
|
|
6899
|
+
// when we ack the ids. So a command can never be lost to a ghost/racing SSE
|
|
6900
|
+
// subscriber during codespace boot (the 2026-07-15 first-prompt loss). The
|
|
6901
|
+
// trade-off is possible REDELIVERY (reconnect, publish re-fire, ghost race),
|
|
6902
|
+
// so we dedupe by id here — a bounded FIFO set of ids we've already
|
|
6903
|
+
// dispatched. Cap keeps memory flat over a long session; the oldest ids are
|
|
6904
|
+
// evicted (a command that old is long gone from the server queue anyway).
|
|
6905
|
+
processedIds = /* @__PURE__ */ new Set();
|
|
6906
|
+
static PROCESSED_ID_CAP = 1e3;
|
|
6865
6907
|
/** Polling backoff state (only used on the fallback). */
|
|
6866
6908
|
pollTimer = null;
|
|
6867
6909
|
pollFailures = 0;
|
|
@@ -7131,14 +7173,15 @@ var CommandRelayService = class {
|
|
|
7131
7173
|
// as X-Plugin-Poll-Secret. Empty {} for legacy sessions / older
|
|
7132
7174
|
// backends (which ignore it).
|
|
7133
7175
|
pollSecretHeader() {
|
|
7176
|
+
const headers = { "X-Codeam-Cmd-Ack": "1" };
|
|
7134
7177
|
try {
|
|
7135
7178
|
const secret = loadCliConfig().sessions.find(
|
|
7136
7179
|
(s) => s.pluginId === this.pluginId
|
|
7137
7180
|
)?.pollSecret;
|
|
7138
|
-
|
|
7181
|
+
if (secret) headers["X-Plugin-Poll-Secret"] = secret;
|
|
7139
7182
|
} catch {
|
|
7140
|
-
return {};
|
|
7141
7183
|
}
|
|
7184
|
+
return headers;
|
|
7142
7185
|
}
|
|
7143
7186
|
async pollOnce() {
|
|
7144
7187
|
try {
|
|
@@ -7161,7 +7204,13 @@ var CommandRelayService = class {
|
|
|
7161
7204
|
}
|
|
7162
7205
|
}
|
|
7163
7206
|
async dispatchCommands(commands) {
|
|
7207
|
+
this.ackCommands(commands.map((c2) => c2.id));
|
|
7164
7208
|
for (const cmd of commands) {
|
|
7209
|
+
if (cmd.id && this.processedIds.has(cmd.id)) {
|
|
7210
|
+
log.trace("relay", `dedupe skip already-dispatched id=${cmd.id}`);
|
|
7211
|
+
continue;
|
|
7212
|
+
}
|
|
7213
|
+
if (cmd.id) this.rememberProcessed(cmd.id);
|
|
7165
7214
|
try {
|
|
7166
7215
|
log.trace("relay", `dispatch type=${cmd.type} id=${cmd.id}`);
|
|
7167
7216
|
await this.onCommand(cmd);
|
|
@@ -7170,6 +7219,23 @@ var CommandRelayService = class {
|
|
|
7170
7219
|
}
|
|
7171
7220
|
}
|
|
7172
7221
|
}
|
|
7222
|
+
/** Record a dispatched id, evicting the oldest when over the cap (FIFO). */
|
|
7223
|
+
rememberProcessed(id) {
|
|
7224
|
+
this.processedIds.add(id);
|
|
7225
|
+
if (this.processedIds.size > _CommandRelayService.PROCESSED_ID_CAP) {
|
|
7226
|
+
const oldest = this.processedIds.values().next().value;
|
|
7227
|
+
if (oldest !== void 0) this.processedIds.delete(oldest);
|
|
7228
|
+
}
|
|
7229
|
+
}
|
|
7230
|
+
/** Confirm receipt of command ids so the backend removes them from the queue
|
|
7231
|
+
* (the at-least-once delivery guarantee). Best-effort — never throws. */
|
|
7232
|
+
ackCommands(ids) {
|
|
7233
|
+
const commandIds = ids.filter((id) => typeof id === "string" && id.length > 0);
|
|
7234
|
+
if (commandIds.length === 0) return;
|
|
7235
|
+
void _postJson(`${API_BASE2}/api/commands/ack`, { pluginId: this.pluginId, commandIds }, {
|
|
7236
|
+
...this.pollSecretHeader()
|
|
7237
|
+
}).catch((err) => log.trace("relay", "ack post failed (will redeliver+dedupe)", err));
|
|
7238
|
+
}
|
|
7173
7239
|
// ─── Heartbeat + agents ──────────────────────────────────────────
|
|
7174
7240
|
async sendHeartbeat(online) {
|
|
7175
7241
|
await _postJson(`${API_BASE2}/api/plugin/heartbeat`, {
|
|
@@ -7181,7 +7247,7 @@ var CommandRelayService = class {
|
|
|
7181
7247
|
// fresh + clear the "CLI update available" banner after a self-update
|
|
7182
7248
|
// (a codespace that reinstalls @latest reconnects via heartbeat, not
|
|
7183
7249
|
// pair/reconnect). Older backends ignore the extra field.
|
|
7184
|
-
..."2.60.
|
|
7250
|
+
..."2.60.66" ? { ideVersion: "2.60.66" } : {}
|
|
7185
7251
|
}).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
|
|
7186
7252
|
}
|
|
7187
7253
|
/**
|
|
@@ -17758,7 +17824,7 @@ async function autoUpgradeBeforeCriticalCommand() {
|
|
|
17758
17824
|
if (process.env.NODE_ENV === "test") return;
|
|
17759
17825
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
17760
17826
|
if (process.env.CI) return;
|
|
17761
|
-
const current = true ? "2.60.
|
|
17827
|
+
const current = true ? "2.60.66" : null;
|
|
17762
17828
|
if (!current) return;
|
|
17763
17829
|
const cache = readCache();
|
|
17764
17830
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -17775,7 +17841,7 @@ function checkForUpdates() {
|
|
|
17775
17841
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
17776
17842
|
if (process.env.CI) return;
|
|
17777
17843
|
if (!process.stdout.isTTY) return;
|
|
17778
|
-
const current = true ? "2.60.
|
|
17844
|
+
const current = true ? "2.60.66" : null;
|
|
17779
17845
|
if (!current) return;
|
|
17780
17846
|
const cache = readCache();
|
|
17781
17847
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -17795,7 +17861,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
|
17795
17861
|
var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
|
|
17796
17862
|
var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
|
|
17797
17863
|
function currentCliVersion() {
|
|
17798
|
-
return true ? "2.60.
|
|
17864
|
+
return true ? "2.60.66" : null;
|
|
17799
17865
|
}
|
|
17800
17866
|
function runCmd(cmd, args2, timeoutMs) {
|
|
17801
17867
|
return new Promise((resolve7) => {
|
|
@@ -35224,7 +35290,7 @@ function checkChokidar() {
|
|
|
35224
35290
|
}
|
|
35225
35291
|
async function doctor(args2 = []) {
|
|
35226
35292
|
const json = args2.includes("--json");
|
|
35227
|
-
const cliVersion = true ? "2.60.
|
|
35293
|
+
const cliVersion = true ? "2.60.66" : "0.0.0-dev";
|
|
35228
35294
|
const apiBase2 = resolveApiBaseUrl();
|
|
35229
35295
|
const diagnosticId = (0, import_node_crypto12.randomUUID)();
|
|
35230
35296
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -35701,7 +35767,7 @@ async function mcpRun(args2) {
|
|
|
35701
35767
|
// src/commands/version.ts
|
|
35702
35768
|
var import_picocolors15 = __toESM(require("picocolors"));
|
|
35703
35769
|
function version2() {
|
|
35704
|
-
const v = true ? "2.60.
|
|
35770
|
+
const v = true ? "2.60.66" : "unknown";
|
|
35705
35771
|
console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
|
|
35706
35772
|
}
|
|
35707
35773
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.60.
|
|
3
|
+
"version": "2.60.66",
|
|
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",
|