@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.
- package/CHANGELOG.md +120 -0
- package/dist/backend/http-backend.d.ts +9 -1
- package/dist/backend/http-backend.d.ts.map +1 -1
- package/dist/backend/http-backend.js +59 -4
- package/dist/backend/http-backend.js.map +1 -1
- package/dist/backend/npm-update-check.d.ts +31 -1
- package/dist/backend/npm-update-check.d.ts.map +1 -1
- package/dist/backend/npm-update-check.js +53 -1
- package/dist/backend/npm-update-check.js.map +1 -1
- package/dist/backend/relay-version-cache.d.ts +18 -0
- package/dist/backend/relay-version-cache.d.ts.map +1 -1
- package/dist/backend/relay-version-cache.js +46 -2
- package/dist/backend/relay-version-cache.js.map +1 -1
- package/dist/backend/storage-backend.d.ts +7 -1
- package/dist/backend/storage-backend.d.ts.map +1 -1
- package/dist/cloud/credential-store.d.ts +14 -0
- package/dist/cloud/credential-store.d.ts.map +1 -1
- package/dist/cloud/credential-store.js.map +1 -1
- package/dist/index.js +5 -6
- package/dist/index.js.map +1 -1
- package/dist/services/auto-relay.d.ts +32 -13
- package/dist/services/auto-relay.d.ts.map +1 -1
- package/dist/services/auto-relay.js +107 -35
- package/dist/services/auto-relay.js.map +1 -1
- package/dist/startup.d.ts.map +1 -1
- package/dist/startup.js +3 -1
- package/dist/startup.js.map +1 -1
- package/dist/tools/register-peer.d.ts +15 -0
- package/dist/tools/register-peer.d.ts.map +1 -1
- package/dist/tools/register-peer.js +58 -9
- package/dist/tools/register-peer.js.map +1 -1
- package/dist/tools/send-message.d.ts.map +1 -1
- package/dist/tools/send-message.js +19 -1
- package/dist/tools/send-message.js.map +1 -1
- package/package.json +10 -3
- 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
|
|
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;
|
|
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
|
-
//
|
|
126
|
-
|
|
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":"
|
|
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
|
-
/**
|
|
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;
|
|
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
|
-
/**
|
|
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":"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,
|
|
1
|
+
{"version":3,"file":"npm-update-check.js","sourceRoot":"","sources":["../../src/backend/npm-update-check.ts"],"names":[],"mappings":"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"}
|
|
@@ -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;
|
|
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
|
-
|
|
47
|
-
|
|
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;
|
|
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
|
|
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,
|
|
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":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"credential-store.js","sourceRoot":"","sources":["../../src/cloud/credential-store.ts"],"names":[],"mappings":"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"}
|