agent-comms 2.20.2 → 2.21.1

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 (52) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +1 -1
  4. package/dist/core/agent-registry.d.ts +38 -0
  5. package/dist/core/agent-registry.d.ts.map +1 -0
  6. package/dist/core/agent-registry.js +117 -0
  7. package/dist/core/agent-registry.js.map +1 -0
  8. package/dist/core/connection-approval.d.ts +48 -0
  9. package/dist/core/connection-approval.d.ts.map +1 -0
  10. package/dist/core/connection-approval.js +89 -0
  11. package/dist/core/connection-approval.js.map +1 -0
  12. package/dist/core/delivery-engine.d.ts +82 -0
  13. package/dist/core/delivery-engine.d.ts.map +1 -0
  14. package/dist/core/delivery-engine.js +464 -0
  15. package/dist/core/delivery-engine.js.map +1 -0
  16. package/dist/core/federation-bridge.d.ts +32 -0
  17. package/dist/core/federation-bridge.d.ts.map +1 -0
  18. package/dist/core/federation-bridge.js +113 -0
  19. package/dist/core/federation-bridge.js.map +1 -0
  20. package/dist/core/mesh-store-shared.d.ts +39 -0
  21. package/dist/core/mesh-store-shared.d.ts.map +1 -0
  22. package/dist/core/mesh-store-shared.js +32 -0
  23. package/dist/core/mesh-store-shared.js.map +1 -0
  24. package/dist/core/mesh-store.d.ts +65 -256
  25. package/dist/core/mesh-store.d.ts.map +1 -1
  26. package/dist/core/mesh-store.js +211 -1917
  27. package/dist/core/mesh-store.js.map +1 -1
  28. package/dist/core/peer-lifecycle.d.ts +36 -0
  29. package/dist/core/peer-lifecycle.d.ts.map +1 -0
  30. package/dist/core/peer-lifecycle.js +85 -0
  31. package/dist/core/peer-lifecycle.js.map +1 -0
  32. package/dist/core/room-lifecycle.d.ts +82 -0
  33. package/dist/core/room-lifecycle.d.ts.map +1 -0
  34. package/dist/core/room-lifecycle.js +459 -0
  35. package/dist/core/room-lifecycle.js.map +1 -0
  36. package/dist/core/room-messaging.d.ts +31 -0
  37. package/dist/core/room-messaging.d.ts.map +1 -0
  38. package/dist/core/room-messaging.js +120 -0
  39. package/dist/core/room-messaging.js.map +1 -0
  40. package/dist/core/room-protocol.d.ts +85 -0
  41. package/dist/core/room-protocol.d.ts.map +1 -0
  42. package/dist/core/room-protocol.js +479 -0
  43. package/dist/core/room-protocol.js.map +1 -0
  44. package/dist/core/room-wire-extensions.d.ts +36 -0
  45. package/dist/core/room-wire-extensions.d.ts.map +1 -0
  46. package/dist/core/room-wire-extensions.js +52 -0
  47. package/dist/core/room-wire-extensions.js.map +1 -0
  48. package/dist/core/stale-agent-checker.d.ts +28 -0
  49. package/dist/core/stale-agent-checker.d.ts.map +1 -0
  50. package/dist/core/stale-agent-checker.js +77 -0
  51. package/dist/core/stale-agent-checker.js.map +1 -0
  52. package/package.json +1 -1
@@ -0,0 +1,479 @@
1
+ /**
2
+ * RoomProtocol — the receiving/responding half of the room wire protocol: the room-verb handlers a WireMeshTransport dispatches into (room.send, room.read, room.members, room.join, room.invite, room.leave), the directed room-domain request fan-out primitives (sendRoomMessageDirected, sendRoomRequestToMember, its retry queue and flush), and the human accept/reject decision points for a pending room.join. Split out of mesh-store.ts to reduce it under the repo's max-lines cap. Owns pendingRoomRequests and pendingRoomJoins exclusively -- nothing outside this class ever reads or writes them.
3
+ */
4
+ import { bytesToHex, deviceIdFromHex } from "wire-mesh-core/domain/device-id";
5
+ import { mintCapabilityToken } from "wire-mesh-core/domain/tokens";
6
+ import { roomInviteSchema, roomLeaveSchema, roomReadSchema, roomSendSchema, } from "wire-mesh-core/generated/protocol";
7
+ import { parseRoomPath } from "./room-path.js";
8
+ import { ROOM_MEMBER_CAPABILITY, verifyRoomToken, } from "./room-token-verification.js";
9
+ import { loadRoomTokens, saveIssuedRoomGrant, saveRoomToken, } from "./identity-store.js";
10
+ import { randomId } from "./random-id.js";
11
+ import { CommsError } from "./store.js";
12
+ import { MAX_QUEUED_DELIVERIES_PER_AGENT, ROOM_TOKEN_LIFETIME_MS, } from "./mesh-store-shared.js";
13
+ import { parseInviterAgentExtension, parseRoomStateExtension, roomStateExtension, } from "./room-wire-extensions.js";
14
+ import { StreamingBehavior } from "./types.js";
15
+ export class RoomProtocol {
16
+ deps;
17
+ /** Directed room-domain requests (room.send, room.read) that failed because their target member wasn't reachable at send time, held for retry when that member's own connection is (re)established -- the wire-authenticated fan-out's substitute for the legacy full-state-sync's own automatic eventual consistency, since a direct request to a disconnected peer fails immediately with no protocol-level retry of its own. Keyed by member device-id hex, bounded oldest-first per member with the same cap ordinary delivery queues use. */
18
+ pendingRoomRequests = new Map();
19
+ /** Pending room.join requests awaiting owner approval, keyed by `${roomPath}::${requesterId}` -- the held-open manage-request's own resolve() function is stored here so acceptRoomJoin/rejectRoomJoin can settle it in place. */
20
+ pendingRoomJoins = new Map();
21
+ constructor(deps) {
22
+ this.deps = deps;
23
+ }
24
+ /** Room verb handlers this store registers with its own WireMeshTransport, keyed by params.verb per room-router.ts's own dispatch discipline. */
25
+ get roomVerbHandlers() {
26
+ return {
27
+ "room.join": (request, handle) => this.handleRoomJoin(request, handle),
28
+ "room.send": (request, handle) => this.handleRoomSend(request, handle),
29
+ "room.read": (request, handle) => this.handleRoomRead(request, handle),
30
+ "room.members": (request, handle) => this.handleRoomMembers(request, handle),
31
+ "room.invite": (request) => this.handleRoomInvite(request),
32
+ "room.leave": (request, handle) => this.handleRoomLeave(request, handle),
33
+ };
34
+ }
35
+ /** Reads the "reply" message-ref out of a room.send's own params (if any) and returns the hex id it names -- room.send's replyTo carries a single parent message, so the first reply-relation ref is the one that matters; any further refs are a future relation this handler doesn't yet act on. */
36
+ static replyToFromRefs(refs) {
37
+ const reply = refs?.find((ref) => ref.relation === "reply");
38
+ return reply === undefined ? undefined : bytesToHex(reply.id);
39
+ }
40
+ /** Reads room.send's own "streaming-behavior" extension field (open params tail, not a named schema field) and validates it against the same StreamingBehavior contract every other delivery path already enforces -- an unrecognised or malformed value is dropped rather than rejecting the whole send, matching core/room's own obligation to ignore what it doesn't understand instead of failing closed on an extension field. */
41
+ static streamingBehaviorFromParams(params) {
42
+ const raw = params["streaming-behavior"];
43
+ if (raw === undefined)
44
+ return undefined;
45
+ const result = StreamingBehavior.safeParse(raw);
46
+ return result.success ? result.data : undefined;
47
+ }
48
+ /**
49
+ * Receiving side of a directed room.send (P3.5): verifies the presented token against all six of core/room's own obligations, then delivers the message locally exactly once -- the manage-response this returns IS the delivery receipt, so there is no separate "delivered" event to emit the way the legacy broadcastPatch path needed one. Branches on the room-path's own shape: an owner-named path stores a RoomMessage in this room's own history and fires a room_message event; a DM path stores a DmMessage keyed by the same dm-path sendDm already uses and fires a dm event -- both ride the identical room:member-gated verb, since a DM is just a room-path variant, not a separate verb.
50
+ */
51
+ async handleRoomSend(request, handle) {
52
+ const roomPath = request.scope.path;
53
+ if (roomPath === undefined) {
54
+ return { result: "error", code: "missing_scope_path" };
55
+ }
56
+ if (request.token === undefined) {
57
+ return { result: "error", code: "unauthorized" };
58
+ }
59
+ const { identity, clock, revocation } = this.deps.requireIdentity();
60
+ const verdict = await verifyRoomToken(request.token, {
61
+ identity,
62
+ clock,
63
+ revocation,
64
+ expectedBearer: deviceIdFromHex(handle.id),
65
+ roomPath,
66
+ });
67
+ if (!verdict.ok) {
68
+ return { result: "error", code: "unauthorized" };
69
+ }
70
+ const parsedParams = roomSendSchema.safeParse(request.command.params);
71
+ if (!parsedParams.success) {
72
+ return { result: "error", code: "malformed_params" };
73
+ }
74
+ const params = parsedParams.data;
75
+ const replyTo = RoomProtocol.replyToFromRefs(params.refs);
76
+ const streamingBehavior = RoomProtocol.streamingBehaviorFromParams(params);
77
+ const id = bytesToHex(params["message-id"]);
78
+ const timestamp = new Date(params["sent-at"]).toISOString();
79
+ const peerId = this.deps.getPeerId();
80
+ const parsedPath = parseRoomPath(roomPath);
81
+ let event;
82
+ if (parsedPath.kind === "dm") {
83
+ const message = {
84
+ id,
85
+ from: handle.id,
86
+ to: peerId,
87
+ content: params.text,
88
+ timestamp,
89
+ readBy: [handle.id],
90
+ ...(streamingBehavior !== undefined && { streamingBehavior }),
91
+ };
92
+ const history = this.deps.dms.get(roomPath) ?? [];
93
+ history.push(message);
94
+ this.deps.dms.set(roomPath, history);
95
+ event = { type: "dm", message };
96
+ }
97
+ else {
98
+ const message = {
99
+ id,
100
+ from: handle.id,
101
+ room: roomPath,
102
+ content: params.text,
103
+ timestamp,
104
+ readBy: [handle.id],
105
+ ...(replyTo !== undefined && { replyTo }),
106
+ ...(streamingBehavior !== undefined && { streamingBehavior }),
107
+ };
108
+ const history = this.deps.messages.get(roomPath) ?? [];
109
+ history.push(message);
110
+ this.deps.messages.set(roomPath, history);
111
+ event = { type: "room_message", message };
112
+ }
113
+ this.deps.deliveryEngine.queueDelivery(peerId, event);
114
+ this.deps.deliveryEngine.fireLocalDelivery(peerId, event);
115
+ return { result: "ok" };
116
+ }
117
+ /**
118
+ * Receiving side of a directed room.read (P3.5): verifies the presented token the same way handleRoomSend does, then for each read message-id in the batch, updates this store's own local copy of that message's readBy (this store holds one because it's the message's own author -- the reason it's the one being notified) and fires a delivery_status event locally, replacing what markRead used to broadcast via the legacy message_read patch. Read receipts stay voluntary and best-effort by design: a message-id this store doesn't recognise (already expired from history, or simply never this store's own) is silently skipped rather than treated as an error.
119
+ */
120
+ async handleRoomRead(request, handle) {
121
+ const roomPath = request.scope.path;
122
+ if (roomPath === undefined) {
123
+ return { result: "error", code: "missing_scope_path" };
124
+ }
125
+ if (request.token === undefined) {
126
+ return { result: "error", code: "unauthorized" };
127
+ }
128
+ const { identity, clock, revocation } = this.deps.requireIdentity();
129
+ const verdict = await verifyRoomToken(request.token, {
130
+ identity,
131
+ clock,
132
+ revocation,
133
+ expectedBearer: deviceIdFromHex(handle.id),
134
+ roomPath,
135
+ });
136
+ if (!verdict.ok) {
137
+ return { result: "error", code: "unauthorized" };
138
+ }
139
+ const parsedParams = roomReadSchema.safeParse(request.command.params);
140
+ if (!parsedParams.success) {
141
+ return { result: "error", code: "malformed_params" };
142
+ }
143
+ const params = parsedParams.data;
144
+ const isDm = parseRoomPath(roomPath).kind === "dm";
145
+ const peerId = this.deps.getPeerId();
146
+ for (const messageIdBytes of params.messages) {
147
+ const messageId = bytesToHex(messageIdBytes);
148
+ const history = isDm
149
+ ? this.deps.dms.get(roomPath)
150
+ : this.deps.messages.get(roomPath);
151
+ const message = history?.find((m) => m.id === messageId);
152
+ if (message === undefined)
153
+ continue;
154
+ if (!message.readBy.includes(handle.id)) {
155
+ message.readBy.push(handle.id);
156
+ }
157
+ const event = {
158
+ type: "delivery_status",
159
+ messageId,
160
+ agent: handle.id,
161
+ status: "read",
162
+ ...(isDm ? {} : { room: roomPath }),
163
+ };
164
+ this.deps.deliveryEngine.queueDelivery(peerId, event);
165
+ this.deps.deliveryEngine.fireLocalDelivery(peerId, event);
166
+ }
167
+ return { result: "ok" };
168
+ }
169
+ /**
170
+ * Receiving side of room.members (P3.6): a plain membership + room-state refresh for an already-admitted member, verified the same way handleRoomSend/handleRoomRead are -- room.members grants nothing new, it just answers "who's here, and what's this room called" on demand, the same information room.join's own response already carries at admission time. A DM path has no Room record (this.rooms never holds one for a dm-shaped path) and no name/description/type to report, so its own members list is derived directly from the path's own two participants instead.
171
+ */
172
+ async handleRoomMembers(request, handle) {
173
+ const roomPath = request.scope.path;
174
+ if (roomPath === undefined) {
175
+ return { result: "error", code: "missing_scope_path" };
176
+ }
177
+ if (request.token === undefined) {
178
+ return { result: "error", code: "unauthorized" };
179
+ }
180
+ const { identity, clock, revocation } = this.deps.requireIdentity();
181
+ const verdict = await verifyRoomToken(request.token, {
182
+ identity,
183
+ clock,
184
+ revocation,
185
+ expectedBearer: deviceIdFromHex(handle.id),
186
+ roomPath,
187
+ });
188
+ if (!verdict.ok) {
189
+ return { result: "error", code: "unauthorized" };
190
+ }
191
+ const parsedPath = parseRoomPath(roomPath);
192
+ const room = this.deps.rooms.get(roomPath);
193
+ const members = parsedPath.kind === "dm"
194
+ ? parsedPath.participants.map((device) => ({
195
+ device: deviceIdFromHex(device),
196
+ }))
197
+ : (room?.members ?? []).map((memberId) => ({
198
+ device: deviceIdFromHex(memberId),
199
+ }));
200
+ return {
201
+ result: "ok",
202
+ members,
203
+ ...roomStateExtension(room),
204
+ };
205
+ }
206
+ /**
207
+ * Sends one directed room.send to a single member's own session, attaching this store's own persisted room:member token for the given room path -- the primitive P3.5's own directed fan-out (deliverToRoom) will loop over per member once it replaces the legacy broadcastPatch path this store still uses for message delivery today. Throws if this store holds no token for the room: never a member, or a token that expired or was revoked with nothing fresh persisted in its place.
208
+ */
209
+ async sendRoomMessageDirected(roomPath, memberId, text) {
210
+ const { slot, clock } = this.deps.requireIdentity();
211
+ const token = loadRoomTokens(slot)[roomPath];
212
+ if (token === undefined) {
213
+ throw new CommsError(`No room:member token for ${roomPath}`, "NOT_A_MEMBER");
214
+ }
215
+ const outcome = await this.deps.requireTransport().sendRoomRequest(memberId, {
216
+ verb: ROOM_MEMBER_CAPABILITY,
217
+ params: {
218
+ verb: "room.send",
219
+ "message-id": randomId(),
220
+ "sent-at": clock.now(),
221
+ text,
222
+ },
223
+ }, { kind: "room", path: roomPath }, token);
224
+ if (outcome.result !== "ok") {
225
+ throw new CommsError(`room.send to ${memberId} for ${roomPath} failed (${outcome.code})`, "SEND_FAILED");
226
+ }
227
+ }
228
+ /** Records a room-domain request that couldn't reach memberId right now, for a later flushPendingRoomRequests to retry once that member reconnects. Bounded oldest-first with the same cap ordinary delivery queues use, so an indefinitely-offline member cannot grow this without limit. */
229
+ queuePendingRoomRequest(memberId, roomPath, params) {
230
+ const queue = this.pendingRoomRequests.get(memberId) ?? [];
231
+ queue.push({ roomPath, params });
232
+ if (queue.length > MAX_QUEUED_DELIVERIES_PER_AGENT) {
233
+ queue.splice(0, queue.length - MAX_QUEUED_DELIVERIES_PER_AGENT);
234
+ }
235
+ this.pendingRoomRequests.set(memberId, queue);
236
+ }
237
+ /**
238
+ * Sends one directed room-domain request (room.send, room.read, or any future room:member-gated verb) to a single member, queuing it for retry instead of throwing when the member isn't currently reachable -- the fan-out's own per-recipient primitive, distinct from sendRoomMessageDirected's deliberate throw-on-failure contract for a caller sending to one specific, known recipient. Silently drops a request this store no longer holds a token for (no longer a member of the room) rather than queuing something that will only fail again on retry.
239
+ */
240
+ async sendRoomRequestToMember(memberId, roomPath, token, params) {
241
+ // sendRoomRequest can reject outright (e.g. the connection drops mid-request, per wire-mesh-core's own rejectPendingManageRequests), not just resolve with an error outcome -- both are exactly the same "memberId isn't reachable right now" fact from this method's own point of view, so both queue for retry rather than one of them propagating as an uncaught rejection out of what every caller treats as a fire-and-forget send.
242
+ let outcome;
243
+ try {
244
+ outcome = await this.deps
245
+ .requireTransport()
246
+ .sendRoomRequest(memberId, { verb: ROOM_MEMBER_CAPABILITY, params }, { kind: "room", path: roomPath }, token);
247
+ }
248
+ catch {
249
+ this.queuePendingRoomRequest(memberId, roomPath, params);
250
+ return;
251
+ }
252
+ if (outcome.result !== "ok") {
253
+ this.queuePendingRoomRequest(memberId, roomPath, params);
254
+ }
255
+ }
256
+ /** Retries every room.send queued for memberId since it was last reachable, dropping (not re-queuing) any whose room this store no longer holds a token for. Called once a connection to memberId is (re)established -- handlePeerConnected fires for both a fresh introduction and a reconnection after downtime, exactly the two cases a queued send needs to be retried on. */
257
+ async flushPendingRoomRequests(memberId) {
258
+ const queue = this.pendingRoomRequests.get(memberId);
259
+ if (queue === undefined || queue.length === 0)
260
+ return;
261
+ this.pendingRoomRequests.delete(memberId);
262
+ const { slot } = this.deps.requireIdentity();
263
+ for (const pending of queue) {
264
+ const token = loadRoomTokens(slot)[pending.roomPath];
265
+ if (token === undefined)
266
+ continue;
267
+ await this.sendRoomRequestToMember(memberId, pending.roomPath, token, pending.params);
268
+ }
269
+ }
270
+ /**
271
+ * Owner-side admission for an incoming room.join request, against either a named room this store owns or a DM path this store is a participant of. Named-room admission always needs a human decision; DM admission needs one only for the party being contacted first -- the reply half of the two-round consent flow (section 6) auto-approves, since a reply on a path this node itself opened is not unsolicited contact.
272
+ */
273
+ async handleRoomJoin(request, handle) {
274
+ const roomPath = request.scope.path;
275
+ if (roomPath === undefined) {
276
+ return { result: "error", code: "missing_scope_path" };
277
+ }
278
+ const parsed = parseRoomPath(roomPath);
279
+ const peerId = this.deps.getPeerId();
280
+ if (parsed.kind === "owner-named") {
281
+ if (parsed.owner !== peerId) {
282
+ return { result: "error", code: "not_owner" };
283
+ }
284
+ return this.admitRoomJoin(roomPath, handle, false);
285
+ }
286
+ if (!parsed.participants.includes(peerId)) {
287
+ return { result: "error", code: "not_participant" };
288
+ }
289
+ // The reciprocal half of section 6's own two-round DM flow: this node's own outbound room.join to the same path (recorded by joinRemoteRoom before this response was even awaited) is the consent that makes the counterpart's own reply not unsolicited contact.
290
+ const autoApprove = this.deps.dmRequestsInitiatedByMe.has(roomPath);
291
+ return this.admitRoomJoin(roomPath, handle, autoApprove);
292
+ }
293
+ /** Shared admission continuation for both room.join branches above: waits for a human decision (unless auto-approved), then mints and returns the requester's own independent, parent-less room:member grant. */
294
+ async admitRoomJoin(roomPath, handle, autoApprove) {
295
+ const decision = autoApprove
296
+ ? { kind: "accept" }
297
+ : await new Promise((resolve) => {
298
+ this.pendingRoomJoins.set(`${roomPath}::${handle.id}`, {
299
+ roomPath,
300
+ requesterId: handle.id,
301
+ resolve,
302
+ });
303
+ });
304
+ if (!autoApprove)
305
+ this.pendingRoomJoins.delete(`${roomPath}::${handle.id}`);
306
+ if (decision.kind === "reject") {
307
+ return {
308
+ result: "error",
309
+ code: "denied",
310
+ ...(decision.reason !== undefined ? { message: decision.reason } : {}),
311
+ };
312
+ }
313
+ // The granted token itself belongs to the requester's own node, which persists it itself once it receives this response -- but this identity slot must also remember the token-id it just issued (saveIssuedRoomGrant below), since revoking a specific member's grant later (kickFromRoom) has no other way to name which token-id to revoke: a token-id is never presented back on the wire, so a room owner's own memory of having minted it is the only record.
314
+ const { identity, clock, slot } = this.deps.requireIdentity();
315
+ const tokenId = randomId();
316
+ const verdict = await mintCapabilityToken({
317
+ identity,
318
+ clock,
319
+ tokenId,
320
+ bearer: deviceIdFromHex(handle.id),
321
+ capability: "room:member",
322
+ scope: { kind: "room", path: roomPath },
323
+ expires: clock.now() + ROOM_TOKEN_LIFETIME_MS,
324
+ delegationsRemaining: 0,
325
+ });
326
+ if (!verdict.ok) {
327
+ return { result: "error", code: "mint_failed" };
328
+ }
329
+ saveIssuedRoomGrant(slot, roomPath, handle.id, tokenId);
330
+ const room = this.deps.rooms.get(roomPath);
331
+ if (room !== undefined) {
332
+ this.deps.deliveryEngine.bump(room);
333
+ this.deps.deliveryEngine.recordMemberOp(room, "member", "join", handle.id);
334
+ this.deps.deliveryEngine.refreshMembership(room);
335
+ this.deps.rooms.set(roomPath, room);
336
+ }
337
+ const members = (room?.members ?? [this.deps.getPeerId(), handle.id]).map((memberId) => ({ device: deviceIdFromHex(memberId) }));
338
+ return {
339
+ result: "ok",
340
+ "granted-token": verdict.token,
341
+ members,
342
+ ...roomStateExtension(room),
343
+ };
344
+ }
345
+ /**
346
+ * Receiving side of a real, wire-level room.invite (P3.8): unlike every other room verb, the request itself is deliberately ungated (the sender already IS the room's own owner, with no need to prove capability to invite) -- the security instead lives entirely in the embedded params.token, which must genuinely name this store's own identity as bearer and root at the room path's own claimed owner. Persists the verified token via saveRoomToken (mirroring joinRemoteRoom's own persistence) and fires a local room_invite delivery event carrying the room's real name/description (room-state) and the inviter's real name/cwd (inviter-agent) when the sender includes them, falling back to the bare device-id and room path otherwise.
347
+ */
348
+ async handleRoomInvite(request) {
349
+ const roomPath = request.scope.path;
350
+ if (roomPath === undefined) {
351
+ return { result: "error", code: "missing_scope_path" };
352
+ }
353
+ const parsedParams = roomInviteSchema.safeParse(request.command.params);
354
+ if (!parsedParams.success) {
355
+ return { result: "error", code: "malformed_params" };
356
+ }
357
+ const { token } = parsedParams.data;
358
+ const peerId = this.deps.getPeerId();
359
+ const { identity, clock, slot, revocation } = this.deps.requireIdentity();
360
+ const verdict = await verifyRoomToken(token, {
361
+ identity,
362
+ clock,
363
+ revocation,
364
+ expectedBearer: deviceIdFromHex(peerId),
365
+ roomPath,
366
+ });
367
+ if (!verdict.ok) {
368
+ return { result: "error", code: "unauthorized" };
369
+ }
370
+ saveRoomToken(slot, roomPath, token);
371
+ const parsed = parseRoomPath(roomPath);
372
+ const inviterId = parsed.kind === "owner-named" ? parsed.owner : peerId;
373
+ const roomState = parseRoomStateExtension(parsedParams.data["room-state"]);
374
+ const inviterAgent = parseInviterAgentExtension(parsedParams.data["inviter-agent"]);
375
+ const event = {
376
+ type: "room_invite",
377
+ room: roomPath,
378
+ roomDescription: roomState?.description ?? "",
379
+ from: inviterId,
380
+ fromName: inviterAgent?.name ?? inviterId,
381
+ fromCwd: inviterAgent?.cwd ?? "",
382
+ };
383
+ this.deps.deliveryEngine.queueDelivery(peerId, event);
384
+ this.deps.deliveryEngine.fireLocalDelivery(peerId, event);
385
+ return { result: "ok" };
386
+ }
387
+ /**
388
+ * Receiving side of a real, wire-level room.leave (P3.8), covering both an actual member leaving and a decline of a never-joined invite -- the same wire request either way, since both are "give up a room:member grant I hold," per leaveRemoteRoom's own reasoning. Distinguishes the two purely from this store's own membership/invited lists (never from anything the sender claims), revokes the sender's grant for real via revokeMemberGrant, and notifies accordingly: member_left broadcast to the room's other members for a real leave, a local invite_declined event (carrying the sender's own optional reason extension) for a decline -- there is no third party to notify for a decline, since nobody else ever knew about an invite that was never accepted.
389
+ */
390
+ async handleRoomLeave(request, handle) {
391
+ const roomPath = request.scope.path;
392
+ if (roomPath === undefined) {
393
+ return { result: "error", code: "missing_scope_path" };
394
+ }
395
+ if (request.token === undefined) {
396
+ return { result: "error", code: "unauthorized" };
397
+ }
398
+ const { identity, clock, revocation } = this.deps.requireIdentity();
399
+ const verdict = await verifyRoomToken(request.token, {
400
+ identity,
401
+ clock,
402
+ revocation,
403
+ expectedBearer: deviceIdFromHex(handle.id),
404
+ roomPath,
405
+ });
406
+ if (!verdict.ok) {
407
+ return { result: "error", code: "unauthorized" };
408
+ }
409
+ const parsedParams = roomLeaveSchema.safeParse(request.command.params);
410
+ if (!parsedParams.success) {
411
+ return { result: "error", code: "malformed_params" };
412
+ }
413
+ const room = this.deps.rooms.get(roomPath);
414
+ if (room === undefined) {
415
+ return { result: "error", code: "room_not_found" };
416
+ }
417
+ const wasMember = room.members.includes(handle.id);
418
+ const wasInvited = room.invited.includes(handle.id);
419
+ if (!wasMember && !wasInvited) {
420
+ return { result: "ok" };
421
+ }
422
+ await this.deps.revokeMemberGrant(roomPath, handle.id);
423
+ this.deps.deliveryEngine.bump(room);
424
+ if (wasMember)
425
+ this.deps.deliveryEngine.recordMemberOp(room, "member", "leave", handle.id);
426
+ if (wasInvited)
427
+ this.deps.deliveryEngine.recordMemberOp(room, "invited", "leave", handle.id);
428
+ this.deps.deliveryEngine.refreshMembership(room);
429
+ this.deps.rooms.set(roomPath, room);
430
+ await this.deps.deliveryEngine.broadcastPatch({
431
+ type: "room_upsert",
432
+ room,
433
+ });
434
+ const peerId = this.deps.getPeerId();
435
+ if (wasMember) {
436
+ await this.deps.deliveryEngine.deliverToRoom(roomPath, { type: "member_left", room: roomPath, agent: handle.id }, handle.id);
437
+ }
438
+ else {
439
+ const reasonValue = parsedParams.data.reason;
440
+ const decliner = this.deps.agents.get(handle.id);
441
+ const event = {
442
+ type: "invite_declined",
443
+ room: roomPath,
444
+ agent: handle.id,
445
+ agentName: decliner?.name ?? handle.id,
446
+ reason: typeof reasonValue === "string" ? reasonValue : "",
447
+ };
448
+ this.deps.deliveryEngine.queueDelivery(peerId, event);
449
+ this.deps.deliveryEngine.fireLocalDelivery(peerId, event);
450
+ }
451
+ return { result: "ok" };
452
+ }
453
+ /** Every room.join request currently held open awaiting this store's own accept/reject decision. */
454
+ listPendingRoomJoins() {
455
+ return [...this.pendingRoomJoins.values()].map(({ roomPath, requesterId }) => ({ roomPath, requesterId }));
456
+ }
457
+ /** Approves a pending room.join request, resuming handleRoomJoin's own suspended mint-and-respond continuation. */
458
+ acceptRoomJoin(roomPath, requesterId) {
459
+ const key = `${roomPath}::${requesterId}`;
460
+ const pending = this.pendingRoomJoins.get(key);
461
+ if (pending === undefined) {
462
+ throw new CommsError(`No pending room.join for ${requesterId} on ${roomPath}`, "NOT_PENDING");
463
+ }
464
+ pending.resolve({ kind: "accept" });
465
+ }
466
+ /** Denies a pending room.join request, optionally with a reason surfaced to the requester in the resulting manage-error's own message field. */
467
+ rejectRoomJoin(roomPath, requesterId, reason) {
468
+ const key = `${roomPath}::${requesterId}`;
469
+ const pending = this.pendingRoomJoins.get(key);
470
+ if (pending === undefined) {
471
+ throw new CommsError(`No pending room.join for ${requesterId} on ${roomPath}`, "NOT_PENDING");
472
+ }
473
+ pending.resolve({
474
+ kind: "reject",
475
+ ...(reason !== undefined ? { reason } : {}),
476
+ });
477
+ }
478
+ }
479
+ //# sourceMappingURL=room-protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"room-protocol.js","sourceRoot":"","sources":["../../src/core/room-protocol.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Room-state and inviter-agent wire extensions riding room.join/room.members/room.invite's own open extension tails (P3.6/P3.8) -- agent-comms' own application data convention, since core/room itself has no concept of a display name, description, or inviter identity. Split out of MeshStore as plain functions (the originals were `private static` methods with zero `this` access) because both room-protocol.ts and room-lifecycle.ts need them.
3
+ */
4
+ import { RoomType } from "./types.js";
5
+ import type { AgentIdentity, Room } from "./types.js";
6
+ /**
7
+ * Room metadata (name/description/type) riding room-join-ok/room-members-ok's own open extension tail (P3.6), agent-comms' own convention for the "namespaced room-state extension" the design names -- core/room itself has no concept of a display name or description, so this is application data, not a wire-level field. Absent entirely for a DM path (room is undefined there; a DM has no name/description/type to report) rather than a hollow placeholder.
8
+ */
9
+ export declare function roomStateExtension(room: Readonly<Room> | undefined): {
10
+ "room-state"?: {
11
+ name: string;
12
+ description: string;
13
+ type: RoomType;
14
+ };
15
+ };
16
+ /** The receiving-side counterpart of roomStateExtension: narrows an incoming response's own "room-state" field (an unknown, since it rides the wire schema's open catchall tail) to the shape this store's own convention actually sends, or undefined for a peer running without it (an older version, or a DM's own room-join-ok, which never carries one). */
17
+ export declare function parseRoomStateExtension(value: unknown): {
18
+ name: string;
19
+ description: string;
20
+ type: RoomType;
21
+ } | undefined;
22
+ /**
23
+ * The inviter's own display name and cwd, riding room-invite's own open extension tail -- agent-comms' own application data, the same convention roomStateExtension already establishes for room metadata. Unlike room-state (which needs gossip on the requester's own side of room.join/members), the inviter here is always this store's own local agent record: inviteToRoom only ever succeeds for the room's real owner, which per this store's own organising fact (one bridge is one agent is one device) is always this.peerId, so the record is always this store's own registration, never a gossip-dependent lookup.
24
+ */
25
+ export declare function inviterAgentExtension(inviter: Readonly<AgentIdentity>): {
26
+ "inviter-agent": {
27
+ name: string;
28
+ cwd: string;
29
+ };
30
+ };
31
+ /** The receiving-side counterpart of inviterAgentExtension: narrows an incoming room.invite's own "inviter-agent" field to the shape this store's own convention sends, or undefined for a peer running without it (an older version) -- the caller falls back to the inviter's bare device-id in that case, the same honest degradation parseRoomStateExtension's own absent case already accepts. */
32
+ export declare function parseInviterAgentExtension(value: unknown): {
33
+ name: string;
34
+ cwd: string;
35
+ } | undefined;
36
+ //# sourceMappingURL=room-wire-extensions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"room-wire-extensions.d.ts","sourceRoot":"","sources":["../../src/core/room-wire-extensions.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEtD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,SAAS,GAAG;IACpE,YAAY,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,QAAQ,CAAA;KAAE,CAAC;CACtE,CASA;AAED,iWAAiW;AACjW,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,OAAO,GACb;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,GAAG,SAAS,CAanE;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG;IACvE,eAAe,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;CAChD,CAEA;AAED,uYAAuY;AACvY,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,OAAO,GACb;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAM3C"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Room-state and inviter-agent wire extensions riding room.join/room.members/room.invite's own open extension tails (P3.6/P3.8) -- agent-comms' own application data convention, since core/room itself has no concept of a display name, description, or inviter identity. Split out of MeshStore as plain functions (the originals were `private static` methods with zero `this` access) because both room-protocol.ts and room-lifecycle.ts need them.
3
+ */
4
+ import { RoomType } from "./types.js";
5
+ /**
6
+ * Room metadata (name/description/type) riding room-join-ok/room-members-ok's own open extension tail (P3.6), agent-comms' own convention for the "namespaced room-state extension" the design names -- core/room itself has no concept of a display name or description, so this is application data, not a wire-level field. Absent entirely for a DM path (room is undefined there; a DM has no name/description/type to report) rather than a hollow placeholder.
7
+ */
8
+ export function roomStateExtension(room) {
9
+ if (room === undefined)
10
+ return {};
11
+ return {
12
+ "room-state": {
13
+ name: room.name,
14
+ description: room.description,
15
+ type: room.type,
16
+ },
17
+ };
18
+ }
19
+ /** The receiving-side counterpart of roomStateExtension: narrows an incoming response's own "room-state" field (an unknown, since it rides the wire schema's open catchall tail) to the shape this store's own convention actually sends, or undefined for a peer running without it (an older version, or a DM's own room-join-ok, which never carries one). */
20
+ export function parseRoomStateExtension(value) {
21
+ if (typeof value !== "object" || value === null)
22
+ return undefined;
23
+ if (!("name" in value) || !("description" in value) || !("type" in value))
24
+ return undefined;
25
+ if (typeof value.name !== "string" || typeof value.description !== "string")
26
+ return undefined;
27
+ const parsedType = RoomType.safeParse(value.type);
28
+ if (!parsedType.success)
29
+ return undefined;
30
+ return {
31
+ name: value.name,
32
+ description: value.description,
33
+ type: parsedType.data,
34
+ };
35
+ }
36
+ /**
37
+ * The inviter's own display name and cwd, riding room-invite's own open extension tail -- agent-comms' own application data, the same convention roomStateExtension already establishes for room metadata. Unlike room-state (which needs gossip on the requester's own side of room.join/members), the inviter here is always this store's own local agent record: inviteToRoom only ever succeeds for the room's real owner, which per this store's own organising fact (one bridge is one agent is one device) is always this.peerId, so the record is always this store's own registration, never a gossip-dependent lookup.
38
+ */
39
+ export function inviterAgentExtension(inviter) {
40
+ return { "inviter-agent": { name: inviter.name, cwd: inviter.cwd } };
41
+ }
42
+ /** The receiving-side counterpart of inviterAgentExtension: narrows an incoming room.invite's own "inviter-agent" field to the shape this store's own convention sends, or undefined for a peer running without it (an older version) -- the caller falls back to the inviter's bare device-id in that case, the same honest degradation parseRoomStateExtension's own absent case already accepts. */
43
+ export function parseInviterAgentExtension(value) {
44
+ if (typeof value !== "object" || value === null)
45
+ return undefined;
46
+ if (!("name" in value) || !("cwd" in value))
47
+ return undefined;
48
+ if (typeof value.name !== "string" || typeof value.cwd !== "string")
49
+ return undefined;
50
+ return { name: value.name, cwd: value.cwd };
51
+ }
52
+ //# sourceMappingURL=room-wire-extensions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"room-wire-extensions.js","sourceRoot":"","sources":["../../src/core/room-wire-extensions.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGtC;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAgC;IAGjE,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,EAAE,CAAC;IAClC,OAAO;QACL,YAAY,EAAE;YACZ,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,IAAI,EAAE,IAAI,CAAC,IAAI;SAChB;KACF,CAAC;AACJ,CAAC;AAED,iWAAiW;AACjW,MAAM,UAAU,uBAAuB,CACrC,KAAc;IAEd,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IAClE,IAAI,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,aAAa,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC;QACvE,OAAO,SAAS,CAAC;IACnB,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,KAAK,CAAC,WAAW,KAAK,QAAQ;QACzE,OAAO,SAAS,CAAC;IACnB,MAAM,UAAU,GAAG,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClD,IAAI,CAAC,UAAU,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IAC1C,OAAO;QACL,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,IAAI,EAAE,UAAU,CAAC,IAAI;KACtB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAAgC;IAGpE,OAAO,EAAE,eAAe,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC;AACvE,CAAC;AAED,uYAAuY;AACvY,MAAM,UAAU,0BAA0B,CACxC,KAAc;IAEd,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IAClE,IAAI,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC9D,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,KAAK,CAAC,GAAG,KAAK,QAAQ;QACjE,OAAO,SAAS,CAAC;IACnB,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC;AAC9C,CAAC"}