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,464 @@
1
+ /**
2
+ * DeliveryEngine — the busiest hub in MeshStore: owns queued/local delivery, room-membership CRDT merge (mergeRoom/refreshMembership/recordMemberOp), patch application and broadcast, read receipts, and the two gossip callbacks (presence-advert, revocation-announce) that mutate this state directly. Split out of mesh-store.ts to reduce it under the repo's max-lines cap. Every core Map it touches (agents/rooms/messages/dms/deliveryQueues/localDeliveryKeys/pendingMarkReadTimers) is a direct reference into MeshStore's own fields, shared by construction rather than copied, since AgentRegistry, RoomLifecycle, RoomProtocol, RoomMessaging, FederationBridge, and StaleAgentChecker all read or mutate the same underlying state.
3
+ */
4
+ import { bytesFromHex } from "wire-mesh-core/domain/device-id";
5
+ import { loadRoomTokens } from "./identity-store.js";
6
+ import { MAX_QUEUED_DELIVERIES_PER_AGENT, mergeMessageHistories, } from "./mesh-store-shared.js";
7
+ export class DeliveryEngine {
8
+ deps;
9
+ constructor(deps) {
10
+ this.deps = deps;
11
+ }
12
+ // -----------------------------------------------------------------------
13
+ // Gossip callbacks
14
+ // -----------------------------------------------------------------------
15
+ /** Applies a peer's gossiped presence status to this store's own local record, without broadcasting it back onto the mesh -- gossip itself is already how this fact propagates (each side's WireMeshTransport re-advertises its own status periodically), so re-broadcasting a received one would just bounce it around indefinitely. Silently ignored for a device-id this store doesn't yet have an agent record for: presence gossip is a transport-layer fact about an already-known peer's current status, not itself a source of truth for who that peer is -- that still comes only from agent_upsert/registerAgent, which carries the name/harness/cwd/tags a fabricated partial record here never could. */
16
+ handlePresenceAdvert(agentId, status) {
17
+ const agent = this.deps.agents.get(agentId);
18
+ if (agent === undefined || agent.status === status)
19
+ return;
20
+ agent.status = status;
21
+ this.bump(agent);
22
+ void this.notifyRoomsOfStatus(agentId, status);
23
+ }
24
+ /** Verifies a gossiped revocation-entry and, if it verifies, records it in this store's own RevocationView -- future verifyRoomToken calls against this token's (token-id, issuer) pair fail with "revoked" from this point on. A failing entry is dropped silently: the same "hostile input produces a verdict, never a throw" contract verifyRevocationEntry itself already guarantees, so there is nothing further for a caller to react to. */
25
+ async handleRevocationAnnounce(entry) {
26
+ const { identity, revocation } = this.deps.requireIdentity();
27
+ await revocation.record(entry, { identity });
28
+ }
29
+ // -----------------------------------------------------------------------
30
+ // Queueing and membership merge
31
+ // -----------------------------------------------------------------------
32
+ /** Append to a target agent's delivery queue, bounded oldest-first (#28). */
33
+ queueDelivery(agentId, event) {
34
+ const arr = this.deps.deliveryQueues.get(agentId) ?? [];
35
+ arr.push(event);
36
+ if (arr.length > MAX_QUEUED_DELIVERIES_PER_AGENT) {
37
+ arr.splice(0, arr.length - MAX_QUEUED_DELIVERIES_PER_AGENT);
38
+ }
39
+ this.deps.deliveryQueues.set(agentId, arr);
40
+ }
41
+ /**
42
+ * Merge an incoming room record into the local one. Scalar fields follow the version gate the caller already applied (an equal or higher version reaches here), while membership is always element-merged per agent by highest operation revision, so concurrent joins of different agents survive and a kick racing a join converges with the kick honoured (#27). The members and invited views are re-derived from the merged operations.
43
+ */
44
+ mergeRoom(incoming) {
45
+ const existing = this.deps.rooms.get(incoming.id);
46
+ if (existing === undefined) {
47
+ this.refreshMembership(incoming);
48
+ this.deps.rooms.set(incoming.id, incoming);
49
+ return;
50
+ }
51
+ existing.version = Math.max(existing.version, incoming.version);
52
+ existing.name = incoming.name;
53
+ existing.type = incoming.type;
54
+ existing.owner = incoming.owner;
55
+ existing.createdAt = incoming.createdAt;
56
+ existing.description = incoming.description;
57
+ if (incoming.federated !== undefined)
58
+ existing.federated = incoming.federated;
59
+ existing.memberJoins = DeliveryEngine.mergeMemberOps(existing.memberJoins, incoming.memberJoins);
60
+ existing.memberLeaves = DeliveryEngine.mergeMemberOps(existing.memberLeaves, incoming.memberLeaves);
61
+ existing.invitedJoins = DeliveryEngine.mergeMemberOps(existing.invitedJoins, incoming.invitedJoins);
62
+ existing.invitedLeaves = DeliveryEngine.mergeMemberOps(existing.invitedLeaves, incoming.invitedLeaves);
63
+ this.refreshMembership(existing);
64
+ }
65
+ /**
66
+ * Derive the members and invited views from the per-agent operation maps. An agent is in the list when their latest join strictly outranks their latest leave; equal revisions mean the leave wins, so a kick racing a concurrent join converges with the kick honoured (#27).
67
+ */
68
+ refreshMembership(room) {
69
+ room.members = Object.keys(room.memberJoins).filter((id) => (room.memberJoins[id] ?? 0) > (room.memberLeaves[id] ?? 0));
70
+ room.invited = Object.keys(room.invitedJoins).filter((id) => (room.invitedJoins[id] ?? 0) > (room.invitedLeaves[id] ?? 0));
71
+ }
72
+ /** Record a membership operation at the room's current revision. */
73
+ recordMemberOp(room, list, op, agentId) {
74
+ const joins = list === "member" ? room.memberJoins : room.invitedJoins;
75
+ const leaves = list === "member" ? room.memberLeaves : room.invitedLeaves;
76
+ const stamp = room.version;
77
+ if (op === "join")
78
+ joins[agentId] = stamp;
79
+ else
80
+ leaves[agentId] = stamp;
81
+ }
82
+ /** Merge per-agent operation maps by highest revision per agent. */
83
+ static mergeMemberOps(local, incoming) {
84
+ const merged = { ...local };
85
+ for (const [id, stamp] of Object.entries(incoming)) {
86
+ if (stamp > (merged[id] ?? 0))
87
+ merged[id] = stamp;
88
+ }
89
+ return merged;
90
+ }
91
+ /** Bump an entity's sync revision; call before broadcasting a local mutation. */
92
+ bump(entity) {
93
+ entity.version += 1;
94
+ return entity;
95
+ }
96
+ // -----------------------------------------------------------------------
97
+ // State sync and patch application
98
+ // -----------------------------------------------------------------------
99
+ /**
100
+ * Merge a peer's state snapshot into the local state. Agents and rooms accept the incoming copy when it carries a revision at least as high as the local one, so a peer holding stale entities converges when it receives a fresher snapshot, while its own stale copies are rejected by peers that stayed current (#27). Message and DM histories are append-only: add unseen entries and union read receipts.
101
+ */
102
+ applyStateSync(state) {
103
+ const incoming = {
104
+ agents: new Map(Object.entries(state.agents)),
105
+ rooms: new Map(Object.entries(state.rooms)),
106
+ messages: new Map(Object.entries(state.messages)),
107
+ dms: new Map(Object.entries(state.dms)),
108
+ };
109
+ for (const [id, agent] of incoming.agents) {
110
+ const existingVersion = this.deps.agents.get(id)?.version;
111
+ if (existingVersion !== undefined && agent.version < existingVersion) {
112
+ continue;
113
+ }
114
+ if (existingVersion === agent.version) {
115
+ const existing = this.deps.agents.get(id);
116
+ if (existing) {
117
+ for (const r of existing.subscribedRooms) {
118
+ if (!agent.subscribedRooms.includes(r))
119
+ agent.subscribedRooms.push(r);
120
+ }
121
+ }
122
+ }
123
+ this.deps.agents.set(id, agent);
124
+ }
125
+ for (const [id, room] of incoming.rooms) {
126
+ const existingVersion = this.deps.rooms.get(id)?.version;
127
+ if (existingVersion !== undefined && room.version < existingVersion) {
128
+ continue;
129
+ }
130
+ this.mergeRoom(room);
131
+ }
132
+ for (const [id, msgs] of incoming.messages) {
133
+ const existing = this.deps.messages.get(id);
134
+ if (existing === undefined) {
135
+ this.deps.messages.set(id, msgs);
136
+ continue;
137
+ }
138
+ mergeMessageHistories(existing, msgs);
139
+ }
140
+ for (const [id, dmMsgs] of incoming.dms) {
141
+ const existing = this.deps.dms.get(id);
142
+ if (existing === undefined) {
143
+ this.deps.dms.set(id, dmMsgs);
144
+ continue;
145
+ }
146
+ mergeMessageHistories(existing, dmMsgs);
147
+ }
148
+ for (const [agentId, events] of Object.entries(state.deliveryQueues)) {
149
+ const seen = new Set((this.deps.deliveryQueues.get(agentId) ?? []).map((e) => JSON.stringify(e)));
150
+ for (const event of events) {
151
+ if (seen.has(JSON.stringify(event)))
152
+ continue;
153
+ this.queueDelivery(agentId, event);
154
+ // Replay fires only for events with consumption evidence (#28): messages are consumed by reading (readBy), invites by acceptance or decline (no longer in the invited list). Transient notifications (member_joined, room_members, connection_request, delivery status) carry no consumption evidence, so replaying them could only ever duplicate-notify; the state they describe arrives via the synced room and agent records instead. They still merge into the queue, so drain bridges see them.
155
+ if (event.type === "room_message" || event.type === "dm") {
156
+ this.fireLocalDelivery(agentId, event);
157
+ }
158
+ else if (event.type === "room_invite") {
159
+ const stillInvited = this.deps.rooms
160
+ .get(event.room)
161
+ ?.invited.includes(agentId);
162
+ if (stillInvited === true) {
163
+ this.fireLocalDelivery(agentId, event);
164
+ }
165
+ }
166
+ }
167
+ }
168
+ }
169
+ async applyPatch(patch) {
170
+ switch (patch.type) {
171
+ case "agent_upsert": {
172
+ const existingAgent = this.deps.agents.get(patch.agent.id);
173
+ if (existingAgent !== undefined &&
174
+ patch.agent.version < existingAgent.version) {
175
+ // Stale copy from a peer that missed updates (#27).
176
+ break;
177
+ }
178
+ const merged = patch.agent;
179
+ if (existingAgent?.version === patch.agent.version) {
180
+ // Concurrent mutations from the same base: keep subscriptions gained locally. A strictly higher version replaces the record.
181
+ for (const r of existingAgent.subscribedRooms) {
182
+ if (!merged.subscribedRooms.includes(r))
183
+ merged.subscribedRooms.push(r);
184
+ }
185
+ }
186
+ this.deps.agents.set(merged.id, merged);
187
+ break;
188
+ }
189
+ case "agent_offline": {
190
+ const agent = this.deps.agents.get(patch.agentId);
191
+ if (agent) {
192
+ agent.status = "offline";
193
+ this.deps.agents.set(patch.agentId, agent);
194
+ }
195
+ break;
196
+ }
197
+ case "room_upsert": {
198
+ const existing = this.deps.rooms.get(patch.room.id);
199
+ if (existing !== undefined && patch.room.version < existing.version) {
200
+ // Stale copy from a peer that missed updates (#27).
201
+ break;
202
+ }
203
+ this.mergeRoom(patch.room);
204
+ break;
205
+ }
206
+ case "room_delete":
207
+ this.deps.rooms.delete(patch.roomId);
208
+ break;
209
+ case "message_add": {
210
+ const arr = this.deps.messages.get(patch.roomId) ?? [];
211
+ arr.push(patch.message);
212
+ this.deps.messages.set(patch.roomId, arr);
213
+ break;
214
+ }
215
+ case "dm_add": {
216
+ const arr = this.deps.dms.get(patch.key) ?? [];
217
+ arr.push(patch.message);
218
+ this.deps.dms.set(patch.key, arr);
219
+ break;
220
+ }
221
+ case "delivery": {
222
+ this.queueDelivery(patch.agentId, patch.event);
223
+ const onDelivery = this.deps.getOnDelivery();
224
+ if (patch.agentId === this.deps.getPeerId() && onDelivery) {
225
+ // Deduplicate against local deliveries
226
+ const eventKey = JSON.stringify(patch.event);
227
+ if (this.deps.localDeliveryKeys.has(eventKey))
228
+ break;
229
+ this.deps.localDeliveryKeys.add(eventKey);
230
+ if (this.deps.localDeliveryKeys.size > 50) {
231
+ const oldest = this.deps.localDeliveryKeys.values().next().value;
232
+ if (oldest !== undefined)
233
+ this.deps.localDeliveryKeys.delete(oldest);
234
+ }
235
+ void onDelivery(patch.agentId, patch.event);
236
+ // Auto-mark read — scheduled as a macrotask to yield to the event loop. Without this yield, the delivery → markRead → broadcast → peer receives → handleDataMessage chain monopolises the microtask queue and starves macrotasks (timers, new connections, sendRoomMessage return values).
237
+ const evt = patch.event;
238
+ const timer = setTimeout(() => {
239
+ if (this.deps.isShutDown())
240
+ return;
241
+ if (evt.type === "room_message") {
242
+ void this.markRead(evt.message.id, this.deps.getPeerId(), evt.message.room);
243
+ }
244
+ else if (evt.type === "dm") {
245
+ void this.markRead(evt.message.id, this.deps.getPeerId());
246
+ }
247
+ }, 0);
248
+ if (!this.deps.isShutDown())
249
+ this.deps.pendingMarkReadTimers.push(timer);
250
+ }
251
+ break;
252
+ }
253
+ }
254
+ const onPatch = this.deps.getOnPatch();
255
+ if (onPatch) {
256
+ await onPatch(patch);
257
+ }
258
+ }
259
+ // -----------------------------------------------------------------------
260
+ // Broadcast and local delivery
261
+ // -----------------------------------------------------------------------
262
+ async broadcastPatch(patch) {
263
+ await this.deps
264
+ .requireTransport()
265
+ .broadcast({ method: "state_update", patch });
266
+ const onPatch = this.deps.getOnPatch();
267
+ if (onPatch) {
268
+ await onPatch(patch);
269
+ }
270
+ }
271
+ async deliverLocallyAndBroadcast(agentId, event) {
272
+ // Local delivery
273
+ this.queueDelivery(agentId, event);
274
+ // Auto-emit delivered status for messages
275
+ if (event.type === "room_message") {
276
+ await this.emitDeliveryStatus(event.message.id, agentId, "delivered", event.message.room);
277
+ }
278
+ else if (event.type === "dm") {
279
+ await this.emitDeliveryStatus(event.message.id, agentId, "delivered");
280
+ }
281
+ this.fireLocalDelivery(agentId, event);
282
+ // Remote delivery
283
+ const patch = { type: "delivery", agentId, event };
284
+ await this.broadcastPatch(patch);
285
+ }
286
+ /**
287
+ * Fire onDelivery for an event targeting this peer's own agent, deduped against events already delivered in this process. Used both for live deliveries and for replays of events that accumulated while this process was down (#28): the dedup set is per-process, so a replayed event this process never saw fires, and one it already handled does not.
288
+ */
289
+ fireLocalDelivery(agentId, event) {
290
+ const onDelivery = this.deps.getOnDelivery();
291
+ if (agentId !== this.deps.getPeerId() || !onDelivery)
292
+ return;
293
+ // A room message or DM this agent has already read was already pushed and consumed: read receipts mutate the event between snapshots, so a plain structural key would miss and re-fire on the next sync (#28).
294
+ if ((event.type === "room_message" || event.type === "dm") &&
295
+ event.message.readBy.includes(agentId)) {
296
+ return;
297
+ }
298
+ const eventKey = JSON.stringify(event);
299
+ if (this.deps.localDeliveryKeys.has(eventKey))
300
+ return;
301
+ this.deps.localDeliveryKeys.add(eventKey);
302
+ // Prevent unbounded growth — evict oldest when cap reached
303
+ if (this.deps.localDeliveryKeys.size > 50) {
304
+ const oldest = this.deps.localDeliveryKeys.values().next().value;
305
+ if (oldest !== undefined)
306
+ this.deps.localDeliveryKeys.delete(oldest);
307
+ }
308
+ void onDelivery(agentId, event);
309
+ // Delivered to this process, so no longer pending for it. Peers that never fired the event keep their copies, which is what a restart replays from (#28). Key-based match: replayed events are JSON clones.
310
+ const queued = this.deps.deliveryQueues.get(agentId);
311
+ if (queued !== undefined) {
312
+ const idx = queued.findIndex((e) => JSON.stringify(e) === eventKey);
313
+ if (idx !== -1)
314
+ queued.splice(idx, 1);
315
+ }
316
+ // Auto-mark read — scheduled as a macrotask to yield to the event loop.
317
+ const timer = setTimeout(() => {
318
+ if (this.deps.isShutDown())
319
+ return;
320
+ if (event.type === "room_message") {
321
+ void this.markRead(event.message.id, agentId, event.message.room);
322
+ }
323
+ else if (event.type === "dm") {
324
+ void this.markRead(event.message.id, agentId);
325
+ }
326
+ }, 0);
327
+ if (!this.deps.isShutDown())
328
+ this.deps.pendingMarkReadTimers.push(timer);
329
+ }
330
+ async deliverToRoom(roomId, event, excludeAgent) {
331
+ const room = this.deps.rooms.get(roomId);
332
+ if (!room)
333
+ return;
334
+ for (const memberId of room.members) {
335
+ if (memberId === excludeAgent)
336
+ continue;
337
+ await this.deliverLocallyAndBroadcast(memberId, event);
338
+ }
339
+ }
340
+ async notifyRoomsOfStatus(agentId, status) {
341
+ const agent = this.deps.agents.get(agentId);
342
+ if (!agent)
343
+ return;
344
+ for (const roomId of agent.subscribedRooms) {
345
+ await this.deliverToRoom(roomId, {
346
+ type: "member_status",
347
+ room: roomId,
348
+ agent: agentId,
349
+ status,
350
+ });
351
+ }
352
+ }
353
+ async notifyRoomsOfNameChange(agentId, oldName, newName) {
354
+ const agent = this.deps.agents.get(agentId);
355
+ if (!agent)
356
+ return;
357
+ const event = {
358
+ type: "name_changed",
359
+ agent: agentId,
360
+ oldName,
361
+ newName,
362
+ };
363
+ for (const roomId of agent.subscribedRooms) {
364
+ await this.deliverToRoom(roomId, event, agentId);
365
+ }
366
+ // Also deliver to the agent itself so it sees confirmation
367
+ await this.deliverLocallyAndBroadcast(agentId, event);
368
+ }
369
+ async emitDeliveryStatus(messageId, agentId, status, room) {
370
+ // Find the sender for this message
371
+ const senderId = this.findMessageSender(messageId, room);
372
+ if (!senderId)
373
+ return;
374
+ await this.deliverLocallyAndBroadcast(senderId, {
375
+ type: "delivery_status",
376
+ messageId,
377
+ agent: agentId,
378
+ status,
379
+ room,
380
+ });
381
+ }
382
+ findMessageSender(messageId, room) {
383
+ if (room) {
384
+ const msgs = this.deps.messages.get(room);
385
+ if (msgs) {
386
+ const msg = msgs.find((m) => m.id === messageId);
387
+ if (msg)
388
+ return msg.from;
389
+ }
390
+ }
391
+ else {
392
+ // DM — search all DM queues
393
+ for (const [, msgs] of this.deps.dms) {
394
+ const msg = msgs.find((m) => m.id === messageId);
395
+ if (msg)
396
+ return msg.from;
397
+ }
398
+ }
399
+ return undefined;
400
+ }
401
+ /** Like findMessageSender, but also returns the room-path a room.read needs to address: room itself for a room message, or the specific DM key (this.dms is keyed by dmRoomPath/"self:...", not the bare pair) the message was actually found under. */
402
+ findMessageLocation(messageId, room) {
403
+ if (room !== undefined) {
404
+ const msg = this.deps.messages.get(room)?.find((m) => m.id === messageId);
405
+ return msg === undefined ? undefined : { roomPath: room, from: msg.from };
406
+ }
407
+ for (const [key, msgs] of this.deps.dms) {
408
+ const msg = msgs.find((m) => m.id === messageId);
409
+ if (msg)
410
+ return { roomPath: key, from: msg.from };
411
+ }
412
+ return undefined;
413
+ }
414
+ /**
415
+ * Marks a message read by readBy (always this store's own identity -- see the auto-mark-read timers in fireLocalDelivery and drainDelivery, its only callers) and notifies the message's own author via a directed, wire-authenticated room.read (P3.5), replacing the legacy message_read patch's mesh-wide broadcast: only the author is a genuine audience for "did you read my message" per core/room's own always-voluntary read-receipt design, and a direct request to them is strictly more than the old broadcast actually needed. Silently does nothing beyond the local readBy update when the author is this store itself (a self-DM, or an already-own message) or when this store holds no room:member token for the message's own room-path -- read receipts stay best-effort by design, never a reason to throw.
416
+ */
417
+ async markRead(messageId, readBy, room) {
418
+ const location = this.findMessageLocation(messageId, room);
419
+ if (location === undefined)
420
+ return;
421
+ const { roomPath, from } = location;
422
+ const history = room !== undefined
423
+ ? this.deps.messages.get(room)
424
+ : this.deps.dms.get(roomPath);
425
+ const message = history?.find((m) => m.id === messageId);
426
+ if (message && !message.readBy.includes(readBy)) {
427
+ message.readBy.push(readBy);
428
+ }
429
+ if (from === readBy)
430
+ return;
431
+ const { slot, clock } = this.deps.requireIdentity();
432
+ const token = loadRoomTokens(slot)[roomPath];
433
+ if (token === undefined)
434
+ return;
435
+ const params = {
436
+ verb: "room.read",
437
+ messages: [bytesFromHex(messageId)],
438
+ at: clock.now(),
439
+ };
440
+ await this.deps.sendRoomRequestToMember(from, roomPath, token, params);
441
+ }
442
+ // -----------------------------------------------------------------------
443
+ // CommsStore — Delivery
444
+ // -----------------------------------------------------------------------
445
+ async deliver(agentId, event) {
446
+ await this.deliverLocallyAndBroadcast(agentId, event);
447
+ }
448
+ async drainDelivery(agentId) {
449
+ await Promise.resolve();
450
+ const events = this.deps.deliveryQueues.get(agentId) ?? [];
451
+ this.deps.deliveryQueues.set(agentId, []);
452
+ // Auto-mark messages as read — drain bridges consume on tool call
453
+ for (const event of events) {
454
+ if (event.type === "room_message") {
455
+ await this.markRead(event.message.id, agentId, event.message.room);
456
+ }
457
+ else if (event.type === "dm") {
458
+ await this.markRead(event.message.id, agentId);
459
+ }
460
+ }
461
+ return events;
462
+ }
463
+ }
464
+ //# sourceMappingURL=delivery-engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delivery-engine.js","sourceRoot":"","sources":["../../src/core/delivery-engine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * FederationBridge — implements FederationManager's own FedCallbacks contract as a real class rather than a closure bag, so the inbound-from-remote-mesh handling (a federated agent becoming visible/gone, a federated room's message/join/leave) and the two outbound sync queries (getVisibleAgents/getFederatedRoomMemberships) live together instead of scattered across mesh-store.ts. Split out to reduce mesh-store.ts under the repo's max-lines cap.
3
+ */
4
+ import type { FedCallbacks } from "./federation.js";
5
+ import type { DeliveryEngine } from "./delivery-engine.js";
6
+ import type { AgentIdentity, Room, RoomMessage } from "./types.js";
7
+ /** The state and DeliveryEngine operations FederationBridge needs from MeshStore -- the core agents/rooms/messages Maps are direct references into MeshStore's own fields, and deliveryEngine is the already-constructed instance (construction order: ... -> deliveryEngine -> federationBridge -> federation), narrowed to only the membership/broadcast/delivery operations a federation callback ever needs. */
8
+ export interface FederationBridgeDeps {
9
+ agents: Map<string, AgentIdentity>;
10
+ rooms: Map<string, Room>;
11
+ messages: Map<string, RoomMessage[]>;
12
+ deliveryEngine: Pick<DeliveryEngine, "bump" | "recordMemberOp" | "refreshMembership" | "broadcastPatch" | "deliverToRoom" | "deliverLocallyAndBroadcast">;
13
+ }
14
+ export declare class FederationBridge implements FedCallbacks {
15
+ private readonly deps;
16
+ constructor(deps: FederationBridgeDeps);
17
+ /** Called when a remote agent becomes visible over a federation link -- stores it locally under a `fed:`-prefixed id to avoid collisions with local agents. */
18
+ onAgentVisible(agent: AgentIdentity): Promise<void>;
19
+ /** Called when a remote agent goes offline/disappears -- the agentId comes from the remote mesh, so this finds the locally prefixed version. */
20
+ onAgentGone(agentId: string): Promise<void>;
21
+ /** Called when a message arrives for a federated room -- stores it locally and delivers to all local room members. */
22
+ onRoomMessage(roomId: string, message: RoomMessage): Promise<void>;
23
+ /** Called when a remote agent joins a federated room -- creates a shadow `fed:`-prefixed member and notifies local members. */
24
+ onRoomJoin(roomId: string, agentId: string, _agentName: string): Promise<void>;
25
+ /** Called when a remote agent leaves a federated room. */
26
+ onRoomLeave(roomId: string, agentId: string): Promise<void>;
27
+ /** Get all visible agents in the local mesh (for syncing to new links) -- excludes agents already federated in from elsewhere, to avoid re-broadcasting them back out. */
28
+ getVisibleAgents(): AgentIdentity[];
29
+ /** Get all federated rooms and their local member lists (for syncing to new links). */
30
+ getFederatedRoomMemberships(): Map<string, string[]>;
31
+ }
32
+ //# sourceMappingURL=federation-bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"federation-bridge.d.ts","sourceRoot":"","sources":["../../src/core/federation-bridge.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEnE,oZAAoZ;AACpZ,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACnC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACzB,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;IACrC,cAAc,EAAE,IAAI,CAClB,cAAc,EACZ,MAAM,GACN,gBAAgB,GAChB,mBAAmB,GACnB,gBAAgB,GAChB,eAAe,GACf,4BAA4B,CAC/B,CAAC;CACH;AAED,qBAAa,gBAAiB,YAAW,YAAY;IACvC,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,oBAAoB;IAEvD,+JAA+J;IACzJ,cAAc,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAczD,gJAAgJ;IAC1I,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAejD,sHAAsH;IAChH,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBxE,+HAA+H;IACzH,UAAU,CACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC;IAwBhB,0DAA0D;IACpD,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBjE,0KAA0K;IAC1K,gBAAgB,IAAI,aAAa,EAAE;IAUnC,uFAAuF;IACvF,2BAA2B,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;CAUrD"}
@@ -0,0 +1,113 @@
1
+ /**
2
+ * FederationBridge — implements FederationManager's own FedCallbacks contract as a real class rather than a closure bag, so the inbound-from-remote-mesh handling (a federated agent becoming visible/gone, a federated room's message/join/leave) and the two outbound sync queries (getVisibleAgents/getFederatedRoomMemberships) live together instead of scattered across mesh-store.ts. Split out to reduce mesh-store.ts under the repo's max-lines cap.
3
+ */
4
+ export class FederationBridge {
5
+ deps;
6
+ constructor(deps) {
7
+ this.deps = deps;
8
+ }
9
+ /** Called when a remote agent becomes visible over a federation link -- stores it locally under a `fed:`-prefixed id to avoid collisions with local agents. */
10
+ async onAgentVisible(agent) {
11
+ const remoteId = `fed:${agent.id}@${agent.harness}`;
12
+ const remoteAgent = {
13
+ ...agent,
14
+ id: remoteId,
15
+ tags: [...agent.tags, "federated"],
16
+ };
17
+ this.deps.agents.set(remoteId, remoteAgent);
18
+ await this.deps.deliveryEngine.broadcastPatch({
19
+ type: "agent_upsert",
20
+ agent: remoteAgent,
21
+ });
22
+ }
23
+ /** Called when a remote agent goes offline/disappears -- the agentId comes from the remote mesh, so this finds the locally prefixed version. */
24
+ async onAgentGone(agentId) {
25
+ const prefix = `fed:${agentId}@`;
26
+ for (const [localId, agent] of this.deps.agents) {
27
+ if (localId.startsWith(prefix)) {
28
+ agent.status = "offline";
29
+ this.deps.agents.set(localId, agent);
30
+ await this.deps.deliveryEngine.broadcastPatch({
31
+ type: "agent_offline",
32
+ agentId: localId,
33
+ });
34
+ break;
35
+ }
36
+ }
37
+ }
38
+ /** Called when a message arrives for a federated room -- stores it locally and delivers to all local room members. */
39
+ async onRoomMessage(roomId, message) {
40
+ const room = this.deps.rooms.get(roomId);
41
+ if (!room?.federated)
42
+ return;
43
+ const arr = this.deps.messages.get(roomId) ?? [];
44
+ arr.push(message);
45
+ this.deps.messages.set(roomId, arr);
46
+ for (const memberId of room.members) {
47
+ await this.deps.deliveryEngine.deliverLocallyAndBroadcast(memberId, {
48
+ type: "room_message",
49
+ message,
50
+ });
51
+ }
52
+ }
53
+ /** Called when a remote agent joins a federated room -- creates a shadow `fed:`-prefixed member and notifies local members. */
54
+ async onRoomJoin(roomId, agentId, _agentName) {
55
+ const room = this.deps.rooms.get(roomId);
56
+ if (!room?.federated)
57
+ return;
58
+ const remoteId = `fed:${agentId}`;
59
+ if (!room.members.includes(remoteId)) {
60
+ this.deps.deliveryEngine.bump(room);
61
+ this.deps.deliveryEngine.recordMemberOp(room, "member", "join", remoteId);
62
+ this.deps.deliveryEngine.refreshMembership(room);
63
+ this.deps.rooms.set(roomId, room);
64
+ await this.deps.deliveryEngine.broadcastPatch({
65
+ type: "room_upsert",
66
+ room,
67
+ });
68
+ }
69
+ await this.deps.deliveryEngine.deliverToRoom(roomId, { type: "member_joined", room: roomId, agent: remoteId }, remoteId);
70
+ }
71
+ /** Called when a remote agent leaves a federated room. */
72
+ async onRoomLeave(roomId, agentId) {
73
+ const room = this.deps.rooms.get(roomId);
74
+ if (!room?.federated)
75
+ return;
76
+ const remoteId = `fed:${agentId}`;
77
+ this.deps.deliveryEngine.bump(room);
78
+ this.deps.deliveryEngine.recordMemberOp(room, "member", "leave", remoteId);
79
+ this.deps.deliveryEngine.refreshMembership(room);
80
+ this.deps.rooms.set(roomId, room);
81
+ await this.deps.deliveryEngine.broadcastPatch({
82
+ type: "room_upsert",
83
+ room,
84
+ });
85
+ await this.deps.deliveryEngine.deliverToRoom(roomId, {
86
+ type: "member_left",
87
+ room: roomId,
88
+ agent: remoteId,
89
+ });
90
+ }
91
+ /** Get all visible agents in the local mesh (for syncing to new links) -- excludes agents already federated in from elsewhere, to avoid re-broadcasting them back out. */
92
+ getVisibleAgents() {
93
+ const result = [];
94
+ for (const agent of this.deps.agents.values()) {
95
+ if (agent.visibility === "visible" && !agent.id.startsWith("fed:")) {
96
+ result.push(agent);
97
+ }
98
+ }
99
+ return result;
100
+ }
101
+ /** Get all federated rooms and their local member lists (for syncing to new links). */
102
+ getFederatedRoomMemberships() {
103
+ const result = new Map();
104
+ for (const [roomId, room] of this.deps.rooms) {
105
+ if (room.federated) {
106
+ const localMembers = room.members.filter((m) => !m.startsWith("fed:"));
107
+ result.set(roomId, localMembers);
108
+ }
109
+ }
110
+ return result;
111
+ }
112
+ }
113
+ //# sourceMappingURL=federation-bridge.js.map