@essentialai/cogent-bridge 3.21.8 → 3.22.0

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 (36) hide show
  1. package/CHANGELOG.md +120 -0
  2. package/dist/backend/http-backend.d.ts +9 -1
  3. package/dist/backend/http-backend.d.ts.map +1 -1
  4. package/dist/backend/http-backend.js +59 -4
  5. package/dist/backend/http-backend.js.map +1 -1
  6. package/dist/backend/npm-update-check.d.ts +31 -1
  7. package/dist/backend/npm-update-check.d.ts.map +1 -1
  8. package/dist/backend/npm-update-check.js +53 -1
  9. package/dist/backend/npm-update-check.js.map +1 -1
  10. package/dist/backend/relay-version-cache.d.ts +18 -0
  11. package/dist/backend/relay-version-cache.d.ts.map +1 -1
  12. package/dist/backend/relay-version-cache.js +46 -2
  13. package/dist/backend/relay-version-cache.js.map +1 -1
  14. package/dist/backend/storage-backend.d.ts +7 -1
  15. package/dist/backend/storage-backend.d.ts.map +1 -1
  16. package/dist/cloud/credential-store.d.ts +14 -0
  17. package/dist/cloud/credential-store.d.ts.map +1 -1
  18. package/dist/cloud/credential-store.js.map +1 -1
  19. package/dist/index.js +5 -6
  20. package/dist/index.js.map +1 -1
  21. package/dist/services/auto-relay.d.ts +32 -13
  22. package/dist/services/auto-relay.d.ts.map +1 -1
  23. package/dist/services/auto-relay.js +107 -35
  24. package/dist/services/auto-relay.js.map +1 -1
  25. package/dist/startup.d.ts.map +1 -1
  26. package/dist/startup.js +3 -1
  27. package/dist/startup.js.map +1 -1
  28. package/dist/tools/register-peer.d.ts +15 -0
  29. package/dist/tools/register-peer.d.ts.map +1 -1
  30. package/dist/tools/register-peer.js +58 -9
  31. package/dist/tools/register-peer.js.map +1 -1
  32. package/dist/tools/send-message.d.ts.map +1 -1
  33. package/dist/tools/send-message.js +19 -1
  34. package/dist/tools/send-message.js.map +1 -1
  35. package/package.json +10 -3
  36. package/server.json +2 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,125 @@
1
+ ## 3.22.0 — 2026-09-03 — audited-by-codex_2026-09-03
2
+
3
+ Closes an independent code + QA audit (12 findings) plus 4 from our own gate audit. **Every fix is
4
+ mutation-proven**: reverted in the shipped source, its tests observed RED, restored — 14/14.
5
+
6
+ ### Security
7
+
8
+ - **Peer identity is now enforced (AUD-003).** A bearer token proved only "I know the channel
9
+ secret" and carried no identity, so any channel member could register over any peer, send as
10
+ them, connect as them, and FORGE their delivery acknowledgments. Ownership is per-PEER (a token
11
+ owns the peers it created; a `peerSecret` reclaims one after a re-join) — deliberately NOT
12
+ per-token, because the Slack adapter registers one peer per human on a single token. Peers
13
+ predating this are adopted on first touch, so live channels keep working.
14
+ - **Path traversal in the file session store (AUD-008).** `getSession("../outside")` read other
15
+ files and `deleteSession("../victim")` deleted them. Two-layer confinement.
16
+ - **Relay state permissions (AUD-007).** Token hashes, secret hashes and full history were written
17
+ 0775/0664. Now 0700/0600.
18
+ - **WebSocket auth is header-only (AUD-010).** The `?token=` fallback for pre-3.1.0 clients is gone;
19
+ URL credentials leak into proxy logs and these tokens have no expiry.
20
+ - **Allocation limits (AUD-009).** 4 MiB body cap, field maxima (`FIELD_LIMITS`), and a throttle on
21
+ unauthenticated channel creation, which ran bcrypt + a durable write with nothing bounding it.
22
+
23
+ ### Delivery integrity
24
+
25
+ - **Delivery acks are correlated by MESSAGE ID (AUD-002).** Waiters were keyed by peer, so a second
26
+ concurrent send RESOLVED the first — reporting "delivered" with no acknowledgment from anyone.
27
+ - **Shutdown and cancellation now REJECT (AUD-012)** instead of resolving, so "we stopped mid-flight"
28
+ is no longer indistinguishable from "delivered".
29
+ - **The relay stops fabricating `success: true`.** It stamped that on every record for ~7 months
30
+ while its `.strict()` schema made it impossible for a client to report the truth. Four consumers
31
+ branched on that constant — including the production check-on-stop hook, which read the bridge's
32
+ own "could not wake" notice as an ANSWER and went silent on exactly the busy-miss it exists to
33
+ catch. `success`/`error`/`durationMs` are now accepted and persisted.
34
+ - **`pending:true` is persisted (AUD-005)** instead of being silently dropped by a non-strict schema.
35
+ - **Deregistration reports real failures (AUD-006).** 401/500/timeout/DNS were all reported as the
36
+ benign "peer was not registered" while the peer and mailbox stayed live.
37
+
38
+ ### Compatibility
39
+
40
+ - The relay advertises `capabilities` on `GET /api/health`
41
+ (`message-delivery-fields`, `peer-ownership`) and the client gates every new wire field on them,
42
+ failing SAFE when unknown. **There is no deploy-ordering dependency** — an un-upgraded relay
43
+ simply never receives the new fields. This replaces a rule that was forgotten once and took every
44
+ paying Team agent dark for two days (2026-08-07).
45
+
46
+ ### Assurance (AUD-011 — the reason the rest survived)
47
+
48
+ - The E2E harness was structurally dead (it instantiated an interface); `npm test` was RED and the
49
+ publish gate excluded the failures. Repaired, and it now exercises the real delivery-ack path.
50
+ - Tests are type-checked for the first time (`npm run typecheck`, new `tsconfig.test.json`) — 70
51
+ latent errors fixed.
52
+ - `npm run verify` = typecheck → all 8 packages → artifact staleness → **black-box of the real
53
+ `server/dist`**, which no test had ever executed. CI runs it on every change (both prior jobs were
54
+ path-gated to `server/**`, so a change to `src/` ran nothing).
55
+ - `npm test` had been exiting 1 on 7 unhandled rejections while reporting "892 passed" — a real
56
+ product bug (an abandoned response waiter) now fixed.
57
+
1
58
  # Changelog
2
59
 
60
+ ## 3.21.9 — 2026-09-02
61
+
62
+ ### Fixed — the update check ran once at boot, on a process that runs for weeks
63
+
64
+ `checkForUpdate` fired exactly once, at startup. Every bridge in this fabric is long-lived, so a
65
+ version published *after* boot was invisible to the running process no matter how many releases
66
+ shipped — 3.21.4 through 3.21.8 all went out inside a single day, and an agent booted that morning
67
+ would still have reported itself current that evening.
68
+
69
+ `startUpdateCheckLoop` re-checks on an interval (6h default), with an `unref`'d timer so it can
70
+ never hold the process open. A failed check no longer clears a nudge already held: *"we could not
71
+ reach npm"* is not evidence that the client is current.
72
+
73
+ ### Added — the notice reaches the agent without spending a turn
74
+
75
+ A periodic check is worthless if nothing reads it. The nudge went to stderr, which the agent never
76
+ sees, and the tool responses carrying it (`register_peer`, `join_session`, `health_check`) are
77
+ called once at setup and effectively never again.
78
+
79
+ The notice now rides a turn that is already happening: when the agent is woken by a peer message,
80
+ **one line** is appended to that message — no extra wake, no extra tokens, no broadcast.
81
+ `consumeNudgeOnce()` makes it exactly once per release, because the same line on every message is
82
+ noise, and noise is what teaches people to ignore the notice that matters.
83
+
84
+ It is worded as an FYI for the **operator**, deliberately: a wake subprocess runs with
85
+ `--strict-mcp-config`, no MCP servers and `--no-session-persistence`, so **an agent cannot update
86
+ itself**. Its only useful role is to pass the message to a human, and telling it to "update" would
87
+ be an instruction it cannot follow.
88
+
89
+ ### Fixed — one config knob was doing two jobs with opposite blast radii
90
+
91
+ `MIN_CLIENT_VERSION` was simultaneously the **hard wire-compatibility floor** (peers below it are
92
+ rejected when enforcement is on) and the **recommended latest** (which drives the soft advisory).
93
+ Both relays run the floor at 3.8.0, so raising it to advertise a release would have hard-rejected
94
+ every agent below that release — the entire fabric, at register, instantly. Pinned at the floor it
95
+ can never advertise anything, which is exactly why free-tier agents got no advisory at all.
96
+
97
+ `RECOMMENDED_CLIENT_VERSION` (`COGENT_SERVER_RECOMMENDED_CLIENT_VERSION`) now drives the advisory
98
+ and is **never consulted by enforcement**. Unset → falls back to `MIN_CLIENT_VERSION`, so a relay
99
+ that does not set it behaves exactly as before.
100
+
101
+ ### Changed — hard rejection is opt-in; version skew that can still talk, still talks
102
+
103
+ Operator policy, stated 2026-09-02: *"We must be soft for different versions of agent until they
104
+ are able to communicate."*
105
+
106
+ Both relays were deployed with `ENFORCE_MIN_CLIENT_VERSION=true`. That is now **off** on both. A
107
+ hard reject at register turns a working-if-stale agent into a dead one, and it punishes the peer
108
+ who did nothing wrong — the same blast-radius mistake as 3.21.5. The advisory delivers the same
109
+ "please update" message at no such cost.
110
+
111
+ The code default was already `false` (only the literal string `"true"` enables it); tests now pin
112
+ that, so a future deploy cannot flip it by accident. Hard rejection stays reserved for a genuine
113
+ wire incompatibility where the old client truly *cannot* communicate.
114
+
115
+ ### Tests
116
+
117
+ +16 (755 → **766** client, 473 → **478** relay). The update loop (interval, stop, failure leaving a
118
+ held nudge intact), `consumeNudgeOnce` (once per release, re-arming on a newer one), the advisory
119
+ target split, and the soft-by-default policy. Plus the one that matters most: with nothing pending,
120
+ a relayed message is **byte-identical** to before this feature existed.
121
+
122
+
3
123
  ## 3.21.8 — 2026-09-02
4
124
 
5
125
  ### Fixed — a successful wake relayed a 20KB JSON blob instead of the agent's answer
@@ -26,7 +26,15 @@ export declare class HttpBackend implements StorageBackend {
26
26
  * The sessionId parameter from StorageBackend is the local CC sessionId;
27
27
  * in cloud mode we ignore it and use this.sessionId (the cloud session).
28
28
  */
29
- registerPeer(peerId: string, _sessionId: string, cwd: string, label: string, clientVersion?: string, mode?: "observer" | "agent", _channelSessionId?: string, capabilities?: string[], workspaceId?: string, threadId?: string): Promise<PeerInfo>;
29
+ registerPeer(peerId: string, _sessionId: string, cwd: string, label: string, clientVersion?: string, mode?: "observer" | "agent", _channelSessionId?: string, capabilities?: string[], workspaceId?: string, threadId?: string,
30
+ /**
31
+ * AUD-003 ownership proof, replayed from the local credential file when this agent's token has
32
+ * changed since the peer was created (a re-join). Gated on the relay advertising
33
+ * `peer-ownership`: the register schema is .strict(), so sending it to a relay that does not
34
+ * know the field would 400 EVERY registration — the exact shape of AUD-001 and of the
35
+ * 2026-08-07 outage.
36
+ */
37
+ peerSecret?: string): Promise<PeerInfo>;
30
38
  /**
31
39
  * Deregister a peer from the cloud session.
32
40
  * DELETE /api/sessions/:sessionId/peers/:peerId
@@ -1 +1 @@
1
- {"version":3,"file":"http-backend.d.ts","sourceRoot":"","sources":["../../src/backend/http-backend.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAQ1E,OAAO,EAAE,KAAK,iBAAiB,EAAqB,MAAM,6BAA6B,CAAC;AACxF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAkB1D;;;;;;;;;;;;GAYG;AACH,qBAAa,WAAY,YAAW,cAAc;IAE9C,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,SAAS;gBADT,IAAI,EAAE,UAAU,EAChB,SAAS,EAAE,MAAM;IAGpC;;;;;;OAMG;IACG,YAAY,CAChB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,aAAa,CAAC,EAAE,MAAM,EACtB,IAAI,CAAC,EAAE,UAAU,GAAG,OAAO,EAG3B,iBAAiB,CAAC,EAAE,MAAM,EAI1B,YAAY,CAAC,EAAE,MAAM,EAAE,EAIvB,WAAW,CAAC,EAAE,MAAM,EACpB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,QAAQ,CAAC;IA8CpB;;;;;;;;OAQG;IACG,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAc/D;;;;OAIG;IACG,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC;IAK5D;;;OAGG;IACG,SAAS,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;IAMtC;;;OAGG;IACG,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKnD;;;;;;;OAOG;IACG,aAAa,CACjB,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,GAAG,WAAW,CAAC,GAC9C,OAAO,CAAC,aAAa,CAAC;IAiCzB;;;;;OAKG;IACG,UAAU,CACd,MAAM,CAAC,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,MAAM,EACd,kBAAkB,CAAC,EAAE,OAAO,EAC5B,YAAY,CAAC,EAAE,OAAO,EACtB,mBAAmB,CAAC,EAAE,OAAO,GAC5B,OAAO,CAAC,aAAa,EAAE,CAAC;IAmC3B;;;;;;OAMG;IACG,qBAAqB,CACzB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,OAAO,GAChB,OAAO,CAAC,IAAI,CAAC;IAchB;;;;OAIG;IACG,eAAe,CACnB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,OAAO,CAAC;IAInB;;;;;;;OAOG;IACG,UAAU,CACd,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,aAAa,CAAC;IAQzB;;;;;;OAMG;IACG,WAAW,IAAI,OAAO,CAAC,iBAAiB,CAAC;IA4C/C;;;;;;;;;OASG;IACG,eAAe,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAGhD"}
1
+ {"version":3,"file":"http-backend.d.ts","sourceRoot":"","sources":["../../src/backend/http-backend.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAG7E,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAQ1E,OAAO,EAAE,KAAK,iBAAiB,EAAqB,MAAM,6BAA6B,CAAC;AACxF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAkB1D;;;;;;;;;;;;GAYG;AACH,qBAAa,WAAY,YAAW,cAAc;IAE9C,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,SAAS;gBADT,IAAI,EAAE,UAAU,EAChB,SAAS,EAAE,MAAM;IAGpC;;;;;;OAMG;IACG,YAAY,CAChB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,aAAa,CAAC,EAAE,MAAM,EACtB,IAAI,CAAC,EAAE,UAAU,GAAG,OAAO,EAG3B,iBAAiB,CAAC,EAAE,MAAM,EAI1B,YAAY,CAAC,EAAE,MAAM,EAAE,EAIvB,WAAW,CAAC,EAAE,MAAM,EACpB,QAAQ,CAAC,EAAE,MAAM;IACjB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,QAAQ,CAAC;IAiDpB;;;;;;;;OAQG;IACG,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAwB/D;;;;OAIG;IACG,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC;IAK5D;;;OAGG;IACG,SAAS,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;IAMtC;;;OAGG;IACG,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKnD;;;;;;;OAOG;IACG,aAAa,CACjB,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,GAAG,WAAW,CAAC,GAC9C,OAAO,CAAC,aAAa,CAAC;IAiEzB;;;;;OAKG;IACG,UAAU,CACd,MAAM,CAAC,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,MAAM,EACd,kBAAkB,CAAC,EAAE,OAAO,EAC5B,YAAY,CAAC,EAAE,OAAO,EACtB,mBAAmB,CAAC,EAAE,OAAO,GAC5B,OAAO,CAAC,aAAa,EAAE,CAAC;IAmC3B;;;;;;OAMG;IACG,qBAAqB,CACzB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,OAAO,GAChB,OAAO,CAAC,IAAI,CAAC;IAchB;;;;OAIG;IACG,eAAe,CACnB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,OAAO,CAAC;IAInB;;;;;;;OAOG;IACG,UAAU,CACd,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,aAAa,CAAC;IAQzB;;;;;;OAMG;IACG,WAAW,IAAI,OAAO,CAAC,iBAAiB,CAAC;IA4C/C;;;;;;;;;OASG;IACG,eAAe,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAGhD"}
@@ -1,3 +1,5 @@
1
+ import { relaySupports } from "./relay-version-cache.js";
2
+ import { BridgeError, BridgeErrorCode } from "../errors.js";
1
3
  /**
2
4
  * Relay response header (Cogent Mail F3) set on DELETE /peers when a Team mailbox was reaped.
3
5
  * MUST match the relay's `MAILBOX_DEPROVISIONED_HEADER` (server/src/routes/peers.ts) — the bridge
@@ -58,7 +60,15 @@ export class HttpBackend {
58
60
  // Slice 5 / Story 8.6: durable identity that DOES go on the wire (unlike the
59
61
  // local-only rails above) — the relay's .strict() schema was extended in
60
62
  // lockstep (relay-first deploy) to accept these optional fields.
61
- workspaceId, threadId) {
63
+ workspaceId, threadId,
64
+ /**
65
+ * AUD-003 ownership proof, replayed from the local credential file when this agent's token has
66
+ * changed since the peer was created (a re-join). Gated on the relay advertising
67
+ * `peer-ownership`: the register schema is .strict(), so sending it to a relay that does not
68
+ * know the field would 400 EVERY registration — the exact shape of AUD-001 and of the
69
+ * 2026-08-07 outage.
70
+ */
71
+ peerSecret) {
62
72
  const path = PATHS.peers.replace(":sessionId", this.sessionId);
63
73
  // Build body conditionally: omit clientVersion entirely for older clients
64
74
  // / undefined inputs so the wire payload stays clean (no JSON null) and
@@ -101,6 +111,9 @@ export class HttpBackend {
101
111
  body.role = roleCap.slice("role:".length);
102
112
  }
103
113
  }
114
+ if (peerSecret !== undefined && (await relaySupports(this.http, "peer-ownership"))) {
115
+ body.peerSecret = peerSecret;
116
+ }
104
117
  return this.http.post(path, body);
105
118
  }
106
119
  /**
@@ -121,9 +134,19 @@ export class HttpBackend {
121
134
  const mailboxDeprovisioned = headers.get(MAILBOX_DEPROVISIONED_HEADER) === "true";
122
135
  return { removed: true, mailboxDeprovisioned };
123
136
  }
124
- catch {
125
- // Server returns 404 if peer not found, which HttpClient throws as BridgeError
126
- return { removed: false, mailboxDeprovisioned: false };
137
+ catch (err) {
138
+ // 🔴 AUD-006. This used to be a bare `catch {}` returning removed:false for ANY failure, so
139
+ // 401, 403, 500, timeout, DNS and transport errors were all reported to the operator as the
140
+ // benign "peer was not registered" — while the peer and its mailbox stayed live and nothing
141
+ // suggested action was needed.
142
+ //
143
+ // A not-found answer is a FACT about the server's state. A network failure is the ABSENCE of
144
+ // any answer. They must not share a return value: only a verified PEER_NOT_FOUND is
145
+ // "already gone"; everything else is an unknown outcome and must reach the caller.
146
+ if (err instanceof BridgeError && err.code === BridgeErrorCode.PEER_NOT_FOUND) {
147
+ return { removed: false, mailboxDeprovisioned: false };
148
+ }
149
+ throw err;
127
150
  }
128
151
  }
129
152
  /**
@@ -174,6 +197,38 @@ export class HttpBackend {
174
197
  if (record.isRelayEcho === true) {
175
198
  body.isRelayEcho = true;
176
199
  }
200
+ // 🔴 REPORT A FAILED WAKE — BUT ONLY TO A RELAY THAT SAID IT ACCEPTS THE REPORT.
201
+ //
202
+ // The problem: until 2026-09-02 this method dropped `success`/`error`/`durationMs`, so the
203
+ // bridge's own `success: false` (auto-relay.ts:1082/1165/1245/1248) never reached anyone and
204
+ // the relay stamped `true` on every record. Four consumers then branched on that constant —
205
+ // rail C in production among them, which read the bridge's "could not wake" notice as an
206
+ // ANSWER and went silent on exactly the busy-miss it exists to catch.
207
+ //
208
+ // The trap in the obvious fix: the relay's POST schema is `.strict()`, so an unknown key is a
209
+ // hard 400 on EVERY send, not a degraded record. send-message.ts:214-222 passes a computed
210
+ // NUMERIC durationMs on every ordinary cloud send, so forwarding unconditionally would have
211
+ // 400'd the entire fabric against the then-deployed 3.13.3 relays (AUD-001).
212
+ //
213
+ // A deploy-ORDER rule ("relay first, both tiers") is the standing mitigation and it was
214
+ // forgotten once already — 2026-08-07, two days of dark paying agents. So the client ASKS
215
+ // instead: the relay advertises `message-delivery-fields` on /api/health, and unknown fails
216
+ // SAFE (omit). Cost is nothing — capabilities ride the same 60s-TTL cached health probe the
217
+ // version already uses.
218
+ //
219
+ // Within that gate, the same omit-when-empty convention as isRelayEcho above: a field is sent
220
+ // only when it carries information.
221
+ if (await relaySupports(this.http, "message-delivery-fields")) {
222
+ if (record.success === false) {
223
+ body.success = false;
224
+ }
225
+ if (record.error != null) {
226
+ body.error = record.error;
227
+ }
228
+ if (record.durationMs != null) {
229
+ body.durationMs = record.durationMs;
230
+ }
231
+ }
177
232
  // Cogent Mail M2.5: forward file references only when present (same
178
233
  // omit-when-empty convention as isRelayEcho) so no-attachment records stay
179
234
  // byte-identical on the wire and older relays simply ignore an absent field.
@@ -1 +1 @@
1
- {"version":3,"file":"http-backend.js","sourceRoot":"","sources":["../../src/backend/http-backend.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"http-backend.js","sourceRoot":"","sources":["../../src/backend/http-backend.ts"],"names":[],"mappings":"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"}
@@ -7,8 +7,38 @@ export interface CheckForUpdateOptions {
7
7
  url?: string;
8
8
  fetchImpl?: typeof fetch;
9
9
  }
10
- /** Record the startup check's result (the nudge string, or null when current/unchecked). */
10
+ /**
11
+ * Record a check's result (the nudge string, or null when current/unchecked).
12
+ *
13
+ * A CHANGED nudge re-arms {@link consumeNudgeOnce}: a second release must still be announced even
14
+ * though the first one already was. Re-setting the SAME text does not re-arm — that is what keeps
15
+ * a periodic check from becoming a periodic nag.
16
+ */
11
17
  export declare function setLastNudge(nudge: string | null): void;
18
+ /**
19
+ * The pending nudge, returned EXACTLY ONCE per distinct nudge; null afterwards.
20
+ *
21
+ * 🔴 WHY "ONCE" IS PART OF THE CONTRACT. The surfacing path rides a message the agent is already
22
+ * processing (auto-relay), so it costs no extra turn — but that also means it would otherwise fire
23
+ * on EVERY inbound message. One line per release is information; the same line on every message is
24
+ * noise, and noise is what teaches people to ignore the notice that matters.
25
+ */
26
+ export declare function consumeNudgeOnce(): string | null;
27
+ /**
28
+ * Re-check for a newer published client on an interval, forever.
29
+ *
30
+ * 🔴 WHY A ONE-SHOT CHECK WAS NEARLY USELESS. The check ran once, at boot. Every bridge here is
31
+ * long-lived — some run for weeks — so a version published after startup was invisible to the
32
+ * running process no matter how many releases shipped. 3.21.4 through 3.21.8 all went out inside a
33
+ * single day; an agent booted that morning would still have reported itself current that evening.
34
+ *
35
+ * Checks immediately, then every `intervalMs`. Never throws (checkForUpdate already swallows), and
36
+ * the timer is `unref`'d so it can never hold the process open at shutdown. Returns a stop
37
+ * function — used by tests, and available to any caller that needs a clean teardown.
38
+ */
39
+ export declare function startUpdateCheckLoop(current: string, opts?: CheckForUpdateOptions & {
40
+ intervalMs?: number;
41
+ }): () => void;
12
42
  /** The most recent update nudge, or null. Read by health-check to surface it to the user. */
13
43
  export declare function getLastNudge(): string | null;
14
44
  /** Test-only: clear the stored nudge between suites. @internal */
@@ -1 +1 @@
1
- {"version":3,"file":"npm-update-check.d.ts","sourceRoot":"","sources":["../../src/backend/npm-update-check.ts"],"names":[],"mappings":"AAmBA,wFAAwF;AACxF,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAIvE;AAED,0FAA0F;AAC1F,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAShE;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AASD,4FAA4F;AAC5F,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAEvD;AAED,6FAA6F;AAC7F,wBAAgB,YAAY,IAAI,MAAM,GAAG,IAAI,CAE5C;AAED,kEAAkE;AAClE,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,qBAA0B,GAC/B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAwBxB"}
1
+ {"version":3,"file":"npm-update-check.d.ts","sourceRoot":"","sources":["../../src/backend/npm-update-check.ts"],"names":[],"mappings":"AAmBA,wFAAwF;AACxF,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAIvE;AAED,0FAA0F;AAC1F,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAShE;AAED,MAAM,WAAW,qBAAqB;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAYD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAGvD;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,IAAI,CAIhD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,qBAAqB,GAAG;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAO,GACzD,MAAM,IAAI,CAaZ;AAED,6FAA6F;AAC7F,wBAAgB,YAAY,IAAI,MAAM,GAAG,IAAI,CAE5C;AAED,kEAAkE;AAClE,wBAAgB,uBAAuB,IAAI,IAAI,CAG9C;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,qBAA0B,GAC/B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAwBxB"}
@@ -40,10 +40,61 @@ export function isNewer(current, latest) {
40
40
  * MCP server is long-lived and checks once at boot; null means "current or not yet/failed".
41
41
  */
42
42
  let lastNudge = null;
43
- /** Record the startup check's result (the nudge string, or null when current/unchecked). */
43
+ /** Nudge text already handed to a surfacing path, so it is announced ONCE, not on repeat. */
44
+ let shownNudge = null;
45
+ /**
46
+ * Record a check's result (the nudge string, or null when current/unchecked).
47
+ *
48
+ * A CHANGED nudge re-arms {@link consumeNudgeOnce}: a second release must still be announced even
49
+ * though the first one already was. Re-setting the SAME text does not re-arm — that is what keeps
50
+ * a periodic check from becoming a periodic nag.
51
+ */
44
52
  export function setLastNudge(nudge) {
53
+ if (nudge !== lastNudge)
54
+ shownNudge = null;
45
55
  lastNudge = nudge;
46
56
  }
57
+ /**
58
+ * The pending nudge, returned EXACTLY ONCE per distinct nudge; null afterwards.
59
+ *
60
+ * 🔴 WHY "ONCE" IS PART OF THE CONTRACT. The surfacing path rides a message the agent is already
61
+ * processing (auto-relay), so it costs no extra turn — but that also means it would otherwise fire
62
+ * on EVERY inbound message. One line per release is information; the same line on every message is
63
+ * noise, and noise is what teaches people to ignore the notice that matters.
64
+ */
65
+ export function consumeNudgeOnce() {
66
+ if (!lastNudge || lastNudge === shownNudge)
67
+ return null;
68
+ shownNudge = lastNudge;
69
+ return lastNudge;
70
+ }
71
+ /**
72
+ * Re-check for a newer published client on an interval, forever.
73
+ *
74
+ * 🔴 WHY A ONE-SHOT CHECK WAS NEARLY USELESS. The check ran once, at boot. Every bridge here is
75
+ * long-lived — some run for weeks — so a version published after startup was invisible to the
76
+ * running process no matter how many releases shipped. 3.21.4 through 3.21.8 all went out inside a
77
+ * single day; an agent booted that morning would still have reported itself current that evening.
78
+ *
79
+ * Checks immediately, then every `intervalMs`. Never throws (checkForUpdate already swallows), and
80
+ * the timer is `unref`'d so it can never hold the process open at shutdown. Returns a stop
81
+ * function — used by tests, and available to any caller that needs a clean teardown.
82
+ */
83
+ export function startUpdateCheckLoop(current, opts = {}) {
84
+ const { intervalMs = 6 * 60 * 60 * 1000, ...checkOpts } = opts;
85
+ const run = () => {
86
+ void checkForUpdate(current, checkOpts).then((nudge) => {
87
+ // Only ADOPT a positive result. A failed/timed-out check must not erase a nudge we already
88
+ // hold — "we could not reach npm" is not evidence that the client is current.
89
+ if (nudge)
90
+ setLastNudge(nudge);
91
+ });
92
+ };
93
+ run();
94
+ const timer = setInterval(run, intervalMs);
95
+ timer.unref?.();
96
+ return () => clearInterval(timer);
97
+ }
47
98
  /** The most recent update nudge, or null. Read by health-check to surface it to the user. */
48
99
  export function getLastNudge() {
49
100
  return lastNudge;
@@ -51,6 +102,7 @@ export function getLastNudge() {
51
102
  /** Test-only: clear the stored nudge between suites. @internal */
52
103
  export function __resetLastNudgeForTest() {
53
104
  lastNudge = null;
105
+ shownNudge = null;
54
106
  }
55
107
  /**
56
108
  * Fetch the latest published cogent-bridge version; if newer than `current`, return a
@@ -1 +1 @@
1
- {"version":3,"file":"npm-update-check.js","sourceRoot":"","sources":["../../src/backend/npm-update-check.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"npm-update-check.js","sourceRoot":"","sources":["../../src/backend/npm-update-check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC;;;;;;;;;;;;GAYG;AAEH,MAAM,cAAc,GAClB,8DAA8D,CAAC;AAEjE,wFAAwF;AACxF,MAAM,UAAU,YAAY,CAAC,CAAS;IACpC,MAAM,CAAC,GAAG,sBAAsB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAChD,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACpD,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,OAAO,CAAC,OAAe,EAAE,MAAc;IACrD,MAAM,CAAC,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IAChC,MAAM,CAAC,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IAC/B,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;QAC7B,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;IAChC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAQD;;;;GAIG;AACH,IAAI,SAAS,GAAkB,IAAI,CAAC;AAEpC,6FAA6F;AAC7F,IAAI,UAAU,GAAkB,IAAI,CAAC;AAErC;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,KAAoB;IAC/C,IAAI,KAAK,KAAK,SAAS;QAAE,UAAU,GAAG,IAAI,CAAC;IAC3C,SAAS,GAAG,KAAK,CAAC;AACpB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB;IAC9B,IAAI,CAAC,SAAS,IAAI,SAAS,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IACxD,UAAU,GAAG,SAAS,CAAC;IACvB,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,oBAAoB,CAClC,OAAe,EACf,OAAwD,EAAE;IAE1D,MAAM,EAAE,UAAU,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,SAAS,EAAE,GAAG,IAAI,CAAC;IAC/D,MAAM,GAAG,GAAG,GAAS,EAAE;QACrB,KAAK,cAAc,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;YACrD,2FAA2F;YAC3F,8EAA8E;YAC9E,IAAI,KAAK;gBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IACF,GAAG,EAAE,CAAC;IACN,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;IAC3C,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;IAChB,OAAO,GAAG,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;AACpC,CAAC;AAED,6FAA6F;AAC7F,MAAM,UAAU,YAAY;IAC1B,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,uBAAuB;IACrC,SAAS,GAAG,IAAI,CAAC;IACjB,UAAU,GAAG,IAAI,CAAC;AACpB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,OAAe,EACf,OAA8B,EAAE;IAEhC,MAAM,EAAE,SAAS,GAAG,IAAI,EAAE,GAAG,GAAG,cAAc,EAAE,SAAS,GAAG,KAAK,EAAE,GAAG,IAAI,CAAC;IAC3E,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,SAAS,CAAC,CAAC;IAC9D,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;QACjE,IAAI,CAAC,IAAI,CAAC,EAAE;YAAE,OAAO,IAAI,CAAC;QAC1B,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAA0B,CAAC;QAC1D,MAAM,MAAM,GAAG,IAAI,EAAE,OAAO,CAAC;QAC7B,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC;YAAE,OAAO,IAAI,CAAC;QACzE,OAAO,CACL,+BAA+B,OAAO,OAAO,MAAM,IAAI;YACvD,+EAA+E;YAC/E,sFAAsF;YACtF,6DAA6D,CAC9D,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,KAAK,CACV,qBAAqB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CACxE,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;AACH,CAAC"}
@@ -7,6 +7,24 @@ import type { HttpClient } from "../cloud/http-client.js";
7
7
  * @param nowFn Override for `Date.now()` (test seam). Defaults to `Date.now`.
8
8
  */
9
9
  export declare function getRelayVersion(http: HttpClient, nowFn?: () => number): Promise<string | null>;
10
+ /**
11
+ * Wire contracts the relay advertises, or null when the relay could not be reached.
12
+ *
13
+ * 🔴 null and [] MEAN DIFFERENT THINGS and callers must treat both as "no support":
14
+ * - `[]` the relay answered and named nothing (an older build).
15
+ * - `null` we do not know (unreachable / malformed).
16
+ * Use relaySupports() rather than inspecting this directly.
17
+ */
18
+ export declare function getRelayCapabilities(http: HttpClient, nowFn?: () => number): Promise<string[] | null>;
19
+ /**
20
+ * Does the relay accept this wire contract?
21
+ *
22
+ * 🔴 FAILS SAFE. Unknown is NOT support. The message POST schema is `.strict()`, so guessing wrong
23
+ * in the optimistic direction is a hard 400 on every send — the 2026-08-07 outage and the
24
+ * 2026-09-02 near-miss were both exactly that. Guessing wrong in this direction merely omits an
25
+ * optional field.
26
+ */
27
+ export declare function relaySupports(http: HttpClient, capability: string, nowFn?: () => number): Promise<boolean>;
10
28
  /**
11
29
  * Test-only helper to clear the module-scoped cache. Call from beforeEach
12
30
  * in test suites that exercise the cache.
@@ -1 +1 @@
1
- {"version":3,"file":"relay-version-cache.d.ts","sourceRoot":"","sources":["../../src/backend/relay-version-cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAmC1D;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,UAAU,EAChB,KAAK,GAAE,MAAM,MAAiB,GAC7B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAyBxB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C"}
1
+ {"version":3,"file":"relay-version-cache.d.ts","sourceRoot":"","sources":["../../src/backend/relay-version-cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAqC1D;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,UAAU,EAChB,KAAK,GAAE,MAAM,MAAiB,GAC7B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAQxB;AA2CD;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,UAAU,EAChB,KAAK,GAAE,MAAM,MAAiB,GAC7B,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAM1B;AAED;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,UAAU,EAChB,UAAU,EAAE,MAAM,EAClB,KAAK,GAAE,MAAM,MAAiB,GAC7B,OAAO,CAAC,OAAO,CAAC,CAElB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C"}
@@ -35,6 +35,16 @@ export async function getRelayVersion(http, nowFn = Date.now) {
35
35
  if (cached !== null && now - cached.fetchedAt < TTL_MS) {
36
36
  return cached.version;
37
37
  }
38
+ return (await _refresh(http, now))?.version ?? null;
39
+ }
40
+ /**
41
+ * Fetch and cache /api/health. Returns null (and caches nothing) on transport failure or a
42
+ * payload with no usable `version`, so the next call retries.
43
+ *
44
+ * Shared by getRelayVersion and getRelayCapabilities so gating a wire field costs no extra
45
+ * request — both read the same 60s-TTL entry.
46
+ */
47
+ async function _refresh(http, now) {
38
48
  try {
39
49
  const resp = await http.get("/api/health");
40
50
  const version = resp?.version;
@@ -43,8 +53,16 @@ export async function getRelayVersion(http, nowFn = Date.now) {
43
53
  logger.debug(`relay-version-cache: /api/health response missing string 'version' field`);
44
54
  return null;
45
55
  }
46
- cached = { version, fetchedAt: now };
47
- return version;
56
+ // A relay older than 2026-09-03 advertises nothing. That is a VALID answer meaning "supports
57
+ // no new wire contracts", not a failure — so it is cached like any other. Anything that is
58
+ // not an array of strings is ignored rather than trusted: a malformed field must never be
59
+ // read as support, because the cost of a false positive is a 400 on every send.
60
+ const raw = resp?.capabilities;
61
+ const capabilities = Array.isArray(raw)
62
+ ? raw.filter((c) => typeof c === "string")
63
+ : [];
64
+ cached = { version, capabilities, fetchedAt: now };
65
+ return cached;
48
66
  }
49
67
  catch (err) {
50
68
  const msg = err instanceof Error ? err.message : String(err);
@@ -53,6 +71,32 @@ export async function getRelayVersion(http, nowFn = Date.now) {
53
71
  return null;
54
72
  }
55
73
  }
74
+ /**
75
+ * Wire contracts the relay advertises, or null when the relay could not be reached.
76
+ *
77
+ * 🔴 null and [] MEAN DIFFERENT THINGS and callers must treat both as "no support":
78
+ * - `[]` the relay answered and named nothing (an older build).
79
+ * - `null` we do not know (unreachable / malformed).
80
+ * Use relaySupports() rather than inspecting this directly.
81
+ */
82
+ export async function getRelayCapabilities(http, nowFn = Date.now) {
83
+ const now = nowFn();
84
+ if (cached !== null && now - cached.fetchedAt < TTL_MS) {
85
+ return cached.capabilities;
86
+ }
87
+ return (await _refresh(http, now))?.capabilities ?? null;
88
+ }
89
+ /**
90
+ * Does the relay accept this wire contract?
91
+ *
92
+ * 🔴 FAILS SAFE. Unknown is NOT support. The message POST schema is `.strict()`, so guessing wrong
93
+ * in the optimistic direction is a hard 400 on every send — the 2026-08-07 outage and the
94
+ * 2026-09-02 near-miss were both exactly that. Guessing wrong in this direction merely omits an
95
+ * optional field.
96
+ */
97
+ export async function relaySupports(http, capability, nowFn = Date.now) {
98
+ return (await getRelayCapabilities(http, nowFn))?.includes(capability) ?? false;
99
+ }
56
100
  /**
57
101
  * Test-only helper to clear the module-scoped cache. Call from beforeEach
58
102
  * in test suites that exercise the cache.
@@ -1 +1 @@
1
- {"version":3,"file":"relay-version-cache.js","sourceRoot":"","sources":["../../src/backend/relay-version-cache.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,MAAM,MAAM,GAAG,MAAM,CAAC;AAOtB,IAAI,MAAM,GAAsB,IAAI,CAAC;AAErC;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAAgB,EAChB,QAAsB,IAAI,CAAC,GAAG;IAE9B,MAAM,GAAG,GAAG,KAAK,EAAE,CAAC;IAEpB,IAAI,MAAM,KAAK,IAAI,IAAI,GAAG,GAAG,MAAM,CAAC,SAAS,GAAG,MAAM,EAAE,CAAC;QACvD,OAAO,MAAM,CAAC,OAAO,CAAC;IACxB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,GAAG,CAAwB,aAAa,CAAC,CAAC;QAClE,MAAM,OAAO,GAAG,IAAI,EAAE,OAAO,CAAC;QAC9B,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxD,mEAAmE;YACnE,MAAM,CAAC,KAAK,CACV,0EAA0E,CAC3E,CAAC;YACF,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC;QACrC,OAAO,OAAO,CAAC;IACjB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,MAAM,CAAC,KAAK,CAAC,kDAAkD,GAAG,EAAE,CAAC,CAAC;QACtE,8CAA8C;QAC9C,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB;IACjC,MAAM,GAAG,IAAI,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"relay-version-cache.js","sourceRoot":"","sources":["../../src/backend/relay-version-cache.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,MAAM,MAAM,GAAG,MAAM,CAAC;AAStB,IAAI,MAAM,GAAsB,IAAI,CAAC;AAErC;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAAgB,EAChB,QAAsB,IAAI,CAAC,GAAG;IAE9B,MAAM,GAAG,GAAG,KAAK,EAAE,CAAC;IAEpB,IAAI,MAAM,KAAK,IAAI,IAAI,GAAG,GAAG,MAAM,CAAC,SAAS,GAAG,MAAM,EAAE,CAAC;QACvD,OAAO,MAAM,CAAC,OAAO,CAAC;IACxB,CAAC;IAED,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,EAAE,OAAO,IAAI,IAAI,CAAC;AACtD,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,QAAQ,CACrB,IAAgB,EAChB,GAAW;IAEX,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,GAAG,CACzB,aAAa,CACd,CAAC;QACF,MAAM,OAAO,GAAG,IAAI,EAAE,OAAO,CAAC;QAC9B,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxD,mEAAmE;YACnE,MAAM,CAAC,KAAK,CACV,0EAA0E,CAC3E,CAAC;YACF,OAAO,IAAI,CAAC;QACd,CAAC;QACD,6FAA6F;QAC7F,2FAA2F;QAC3F,0FAA0F;QAC1F,gFAAgF;QAChF,MAAM,GAAG,GAAG,IAAI,EAAE,YAAY,CAAC;QAC/B,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;YACrC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC;YACvD,CAAC,CAAC,EAAE,CAAC;QACP,MAAM,GAAG,EAAE,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC;QACnD,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,MAAM,CAAC,KAAK,CAAC,kDAAkD,GAAG,EAAE,CAAC,CAAC;QACtE,8CAA8C;QAC9C,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,IAAgB,EAChB,QAAsB,IAAI,CAAC,GAAG;IAE9B,MAAM,GAAG,GAAG,KAAK,EAAE,CAAC;IACpB,IAAI,MAAM,KAAK,IAAI,IAAI,GAAG,GAAG,MAAM,CAAC,SAAS,GAAG,MAAM,EAAE,CAAC;QACvD,OAAO,MAAM,CAAC,YAAY,CAAC;IAC7B,CAAC;IACD,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,EAAE,YAAY,IAAI,IAAI,CAAC;AAC3D,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,IAAgB,EAChB,UAAkB,EAClB,QAAsB,IAAI,CAAC,GAAG;IAE9B,OAAO,CAAC,MAAM,oBAAoB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC;AAClF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB;IACjC,MAAM,GAAG,IAAI,CAAC;AAChB,CAAC"}
@@ -30,7 +30,13 @@ export interface StorageBackend {
30
30
  /** Durable workspace id — on the wire in cloud mode (Slice 5 / Story 8.6). */
31
31
  workspaceId?: string,
32
32
  /** Durable thread/conversation id — on the wire in cloud mode (Slice 5 / Story 8.6). */
33
- threadId?: string): Promise<PeerInfo>;
33
+ threadId?: string,
34
+ /**
35
+ * AUD-003 ownership proof, replayed from local credentials when this agent's token changed
36
+ * since the peer was created (a re-join). Cloud-only, and only sent when the relay advertises
37
+ * `peer-ownership` — the register schema is .strict().
38
+ */
39
+ peerSecret?: string): Promise<PeerInfo>;
34
40
  deregisterPeer(peerId: string): Promise<DeregisterResult>;
35
41
  getPeer(peerId: string): Promise<PeerInfo | undefined>;
36
42
  listPeers(): Promise<PeerInfo[]>;
@@ -1 +1 @@
1
- {"version":3,"file":"storage-backend.d.ts","sourceRoot":"","sources":["../../src/backend/storage-backend.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAEhE;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,oBAAoB,EAAE,OAAO,CAAC;CAC/B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAE7B,YAAY,CACV,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM;IACb,6EAA6E;IAC7E,aAAa,CAAC,EAAE,MAAM;IACtB,4FAA4F;IAC5F,IAAI,CAAC,EAAE,UAAU,GAAG,OAAO;IAC3B,0FAA0F;IAC1F,gBAAgB,CAAC,EAAE,MAAM;IACzB,8EAA8E;IAC9E,YAAY,CAAC,EAAE,MAAM,EAAE;IACvB,8EAA8E;IAC9E,WAAW,CAAC,EAAE,MAAM;IACpB,wFAAwF;IACxF,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,QAAQ,CAAC,CAAC;IAErB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAE1D,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,CAAC;IAEvD,SAAS,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAEjC,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAG9C,aAAa,CACX,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,GAAG,WAAW,CAAC,GAC9C,OAAO,CAAC,aAAa,CAAC,CAAC;IAE1B;;;;;;;;;;;;;OAaG;IACH,UAAU,CACR,MAAM,CAAC,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,MAAM,EACd,kBAAkB,CAAC,EAAE,OAAO,EAC5B,YAAY,CAAC,EAAE,OAAO,EACtB,mBAAmB,CAAC,EAAE,OAAO,GAC5B,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;IAG5B,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAElE,UAAU,CACR,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,aAAa,CAAC,CAAC;IAG1B;;;;;;;;;OASG;IACH,qBAAqB,CAAC,CACpB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,OAAO,GAChB,OAAO,CAAC,IAAI,CAAC,CAAC;IAGjB,WAAW,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAE1C;;;;;OAKG;IACH,eAAe,CAAC,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC5C"}
1
+ {"version":3,"file":"storage-backend.d.ts","sourceRoot":"","sources":["../../src/backend/storage-backend.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAEhE;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,oBAAoB,EAAE,OAAO,CAAC;CAC/B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAE7B,YAAY,CACV,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM;IACb,6EAA6E;IAC7E,aAAa,CAAC,EAAE,MAAM;IACtB,4FAA4F;IAC5F,IAAI,CAAC,EAAE,UAAU,GAAG,OAAO;IAC3B,0FAA0F;IAC1F,gBAAgB,CAAC,EAAE,MAAM;IACzB,8EAA8E;IAC9E,YAAY,CAAC,EAAE,MAAM,EAAE;IACvB,8EAA8E;IAC9E,WAAW,CAAC,EAAE,MAAM;IACpB,wFAAwF;IACxF,QAAQ,CAAC,EAAE,MAAM;IACjB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,QAAQ,CAAC,CAAC;IAErB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAE1D,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,CAAC;IAEvD,SAAS,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAEjC,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAG9C,aAAa,CACX,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,GAAG,WAAW,CAAC,GAC9C,OAAO,CAAC,aAAa,CAAC,CAAC;IAE1B;;;;;;;;;;;;;OAaG;IACH,UAAU,CACR,MAAM,CAAC,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,MAAM,EACd,kBAAkB,CAAC,EAAE,OAAO,EAC5B,YAAY,CAAC,EAAE,OAAO,EACtB,mBAAmB,CAAC,EAAE,OAAO,GAC5B,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;IAG5B,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAElE,UAAU,CACR,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,aAAa,CAAC,CAAC;IAG1B;;;;;;;;;OASG;IACH,qBAAqB,CAAC,CACpB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,OAAO,GAChB,OAAO,CAAC,IAAI,CAAC,CAAC;IAGjB,WAAW,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAE1C;;;;;OAKG;IACH,eAAe,CAAC,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC5C"}
@@ -18,6 +18,20 @@ export interface PersistedCredentials {
18
18
  * a register) omit it, and the hook falls back to the state file.
19
19
  */
20
20
  peerId?: string;
21
+ /**
22
+ * AUD-003 peer-ownership credential, issued once by the relay when this peer was first
23
+ * registered.
24
+ *
25
+ * WHY IT MUST BE PERSISTED: a peer is owned by the token that created it, and re-joining a
26
+ * channel issues a NEW token. Without this secret an agent that re-joins can never re-register
27
+ * its own peerId again — it would be locked out of its own identity by the very check that
28
+ * protects it. Stored here (0600, same file as the bearer token, same threat model) and replayed
29
+ * on register.
30
+ *
31
+ * Optional: absent for peers created before ownership existed, and absent on the common path
32
+ * where the token has not changed.
33
+ */
34
+ peerSecret?: string;
21
35
  savedAt: string;
22
36
  }
23
37
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"credential-store.d.ts","sourceRoot":"","sources":["../../src/cloud/credential-store.ts"],"names":[],"mappings":"AAKA;;;;;;GAMG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,QAGzC,CAAC;AAsBF;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,CAKrE;AAaD,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAED,wBAAgB,kBAAkB,IAAI,OAAO,CAE5C;AAED;;GAEG;AACH,wBAAgB,8BAA8B,IAAI,IAAI,CAErD;AAkBD,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD;AAED,wBAAgB,wBAAwB,IAAI,OAAO,CAElD;AAED;;GAEG;AACH,wBAAgB,oCAAoC,IAAI,IAAI,CAE3D;AAMD;;;GAGG;AACH,wBAAsB,eAAe,CACnC,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAQtC;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,oBAAoB,EAC3B,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,IAAI,CAAC,CAaf;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,IAAI,CAAC,CASf;AAED;;;GAGG;AACH,wBAAsB,4BAA4B,IAAI,OAAO,CAAC,OAAO,CAAC,CAOrE"}
1
+ {"version":3,"file":"credential-store.d.ts","sourceRoot":"","sources":["../../src/cloud/credential-store.ts"],"names":[],"mappings":"AAKA;;;;;;GAMG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;;;;;;;OAYG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,QAGzC,CAAC;AAsBF;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,CAKrE;AAaD,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAED,wBAAgB,kBAAkB,IAAI,OAAO,CAE5C;AAED;;GAEG;AACH,wBAAgB,8BAA8B,IAAI,IAAI,CAErD;AAkBD,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD;AAED,wBAAgB,wBAAwB,IAAI,OAAO,CAElD;AAED;;GAEG;AACH,wBAAgB,oCAAoC,IAAI,IAAI,CAE3D;AAMD;;;GAGG;AACH,wBAAsB,eAAe,CACnC,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAQtC;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,oBAAoB,EAC3B,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,IAAI,CAAC,CAaf;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,IAAI,CAAC,CASf;AAED;;;GAGG;AACH,wBAAsB,4BAA4B,IAAI,OAAO,CAAC,OAAO,CAAC,CAOrE"}
@@ -1 +1 @@
1
- {"version":3,"file":"credential-store.js","sourceRoot":"","sources":["../../src/cloud/credential-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"credential-store.js","sourceRoot":"","sources":["../../src/cloud/credential-store.ts"],"names":[],"mappings":"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"}