@gorlitzer-labs/apiary 1.13.8 → 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/README.md +15 -3
  2. package/dist/agent/index.d.ts +7 -0
  3. package/dist/agent/index.js +2 -2
  4. package/dist/chunk-36WX2UAF.js +663 -0
  5. package/dist/chunk-36WX2UAF.js.map +1 -0
  6. package/dist/{chunk-3O76FESR.js → chunk-LNSDH2V5.js} +7 -7
  7. package/dist/{chunk-FTN3D6WM.js → chunk-LOONM4G3.js} +8 -177
  8. package/dist/chunk-LOONM4G3.js.map +1 -0
  9. package/dist/{chunk-63Q3KJ4W.js → chunk-N2LPKMPO.js} +186 -3
  10. package/dist/chunk-N2LPKMPO.js.map +1 -0
  11. package/dist/{chunk-YP4K2A7G.js → chunk-TMXQDGMN.js} +30 -30
  12. package/dist/chunk-TMXQDGMN.js.map +1 -0
  13. package/dist/{chunk-LN6ATWE3.js → chunk-WJD5EKO6.js} +158 -158
  14. package/dist/chunk-WJD5EKO6.js.map +1 -0
  15. package/dist/{chunk-J3T2PS3M.js → chunk-XP5F5NCQ.js} +2 -2
  16. package/dist/cli/index.js +38 -380
  17. package/dist/cli/index.js.map +1 -1
  18. package/dist/{invites-YZWCUC67.js → invites-ID5SRM3D.js} +5 -5
  19. package/dist/{join-FSKOS5BO.js → join-W53OPEHR.js} +5 -5
  20. package/dist/{room-MAUAV2XD.js → room-XC546NTX.js} +11 -11
  21. package/dist/run-6JRFWMAQ.js +164 -0
  22. package/dist/run-6JRFWMAQ.js.map +1 -0
  23. package/package.json +1 -1
  24. package/dist/chunk-63Q3KJ4W.js.map +0 -1
  25. package/dist/chunk-FTN3D6WM.js.map +0 -1
  26. package/dist/chunk-LN6ATWE3.js.map +0 -1
  27. package/dist/chunk-XKFWEK7W.js +0 -288
  28. package/dist/chunk-XKFWEK7W.js.map +0 -1
  29. package/dist/chunk-YP4K2A7G.js.map +0 -1
  30. package/dist/run-4EJB2KC3.js +0 -90
  31. package/dist/run-4EJB2KC3.js.map +0 -1
  32. /package/dist/{chunk-3O76FESR.js.map → chunk-LNSDH2V5.js.map} +0 -0
  33. /package/dist/{chunk-J3T2PS3M.js.map → chunk-XP5F5NCQ.js.map} +0 -0
  34. /package/dist/{invites-YZWCUC67.js.map → invites-ID5SRM3D.js.map} +0 -0
  35. /package/dist/{join-FSKOS5BO.js.map → join-W53OPEHR.js.map} +0 -0
  36. /package/dist/{room-MAUAV2XD.js.map → room-XC546NTX.js.map} +0 -0
@@ -1,29 +1,3 @@
1
- // src/core/authority.ts
2
- var MIN_AUTHORITY = {
3
- send_message: "member",
4
- set_own_mode: "member",
5
- ping: "member",
6
- create_share_link: "member",
7
- mute: "product_owner",
8
- unmute: "product_owner",
9
- set_mode_for: "product_owner",
10
- kick: "admin",
11
- clear_history: "admin",
12
- start_tunnel: "admin",
13
- promote: "admin",
14
- demote: "admin"
15
- };
16
- var TIER_ORDER = {
17
- guest: 0,
18
- member: 1,
19
- product_owner: 2,
20
- admin: 3
21
- };
22
- function can(authority, op) {
23
- if (!authority) return false;
24
- return TIER_ORDER[authority] >= TIER_ORDER[MIN_AUTHORITY[op]];
25
- }
26
-
27
1
  // src/agent/prompts.ts
28
2
  var MODE_DESCRIPTIONS = {
29
3
  "everyone": "All messages are pushed to you.",
@@ -147,14 +121,40 @@ function formatEvent(event, resolveParticipant, replyContext, roomLabel, reactio
147
121
  }
148
122
  }
149
123
 
124
+ // src/core/authority.ts
125
+ var MIN_AUTHORITY = {
126
+ send_message: "member",
127
+ set_own_mode: "member",
128
+ ping: "member",
129
+ create_share_link: "member",
130
+ mute: "product_owner",
131
+ unmute: "product_owner",
132
+ set_mode_for: "product_owner",
133
+ kick: "admin",
134
+ clear_history: "admin",
135
+ start_tunnel: "admin",
136
+ promote: "admin",
137
+ demote: "admin"
138
+ };
139
+ var TIER_ORDER = {
140
+ guest: 0,
141
+ member: 1,
142
+ product_owner: 2,
143
+ admin: 3
144
+ };
145
+ function can(authority, op) {
146
+ if (!authority) return false;
147
+ return TIER_ORDER[authority] >= TIER_ORDER[MIN_AUTHORITY[op]];
148
+ }
149
+
150
150
  export {
151
- TIER_ORDER,
152
- can,
153
151
  MODE_DESCRIPTIONS,
154
152
  messageRef,
155
153
  participantLabel,
156
154
  formatTimestamp,
157
155
  contentPartsToString,
158
- formatEvent
156
+ formatEvent,
157
+ TIER_ORDER,
158
+ can
159
159
  };
160
- //# sourceMappingURL=chunk-YP4K2A7G.js.map
160
+ //# sourceMappingURL=chunk-TMXQDGMN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/agent/prompts.ts","../src/core/authority.ts"],"sourcesContent":["/** Event formatting and mode descriptions for apiary agents. */\n\nimport type { Participant } from \"../core/types.js\";\nimport type { RoomEvent } from \"../core/events.js\";\nimport type { ContentPart } from \"./types.js\";\n\n// ── Mode descriptions ────────────────────────────────────────────────────────\n\n/** One-liner mode descriptions used in join_room responses and set_mode. */\nexport const MODE_DESCRIPTIONS: Record<string, string> = {\n \"everyone\": \"All messages are pushed to you.\",\n \"people\": \"Human messages are pushed to you. Agent messages are delivered as context.\",\n \"agents\": \"Agent messages are pushed to you. Human messages are delivered as context.\",\n \"fight\": \"⚔️ FIGHT MODE. All messages trigger. Gloves are off. Talk trash, roast, clap back. No mercy.\",\n \"standby-everyone\": \"Only @mentions are pushed to you.\",\n \"standby-people\": \"Only human @mentions are pushed to you.\",\n \"standby-agents\": \"Only agent @mentions are pushed to you.\",\n};\n\n// ── Formatting ────────────────────────────────────────────────────────────────\n\n/** Short 4-char ref for a message ID, used in transcripts. */\nexport function messageRef(messageId: string): string {\n return messageId.replace(/-/g, \"\").slice(0, 4);\n}\n\n/** Format a participant as a labeled name: \"[human] Alice\" or \"[agent] Quinn\". */\nexport function participantLabel(p: Participant | null, fallback?: string): string {\n if (!p) return fallback ?? \"someone\";\n return `[${p.type}] ${p.name}`;\n}\n\n/** Resolve participant name, with fallback. */\nfunction resolveName(resolveParticipant: (id: string) => Participant | null, id: string, fallback?: string): string {\n return resolveParticipant(id)?.name ?? fallback ?? \"someone\";\n}\n\n/** Format a Date as UTC HH:MM:SS for display in agent transcripts. */\nexport function formatTimestamp(date: Date): string {\n return date.toISOString().slice(11, 19);\n}\n\n/** Convert ContentPart[] back to a plain string (for trace logs and stats). */\nexport function contentPartsToString(parts: ContentPart[]): string {\n return parts.map(p => p.type === \"text\" ? p.text : ` [image: ${p.url}]`).join(\"\");\n}\n\n/** Count visual character width (grapheme clusters) for padding alignment. */\nfunction visualLength(s: string): number {\n // Use Intl.Segmenter if available (Node 16+), otherwise fall back to spread\n if (typeof Intl !== \"undefined\" && Intl.Segmenter) {\n const segmenter = new Intl.Segmenter(undefined, { granularity: \"grapheme\" });\n let count = 0;\n for (const _ of segmenter.segment(s)) count++;\n return count;\n }\n return [...s].length;\n}\n\n/**\n * Format multiline content with room label continuation.\n * First line is returned as-is. Subsequent lines get [room] prefix aligned.\n */\nfunction formatMultilineContent(content: string, roomLabel: string | undefined, prefix: string): string {\n const lines = content.split(\"\\n\");\n if (lines.length <= 1) return content;\n const continuation = roomLabel ? `[${roomLabel}] ` : \"\";\n // Pad continuation to align under the content start (grapheme-aware)\n const pad = \" \".repeat(visualLength(prefix));\n return lines[0] + \"\\n\" + lines.slice(1).map(l => `${pad}${continuation}${l}`).join(\"\\n\");\n}\n\n/**\n * Render `prefix` followed by content whose wrapped continuation lines align\n * under the text after `prefix`. Passing `prefix` in one place keeps the visible\n * prefix and the alignment padding from silently drifting apart.\n */\nfunction renderLine(prefix: string, content: string, roomLabel: string | undefined): string {\n return `${prefix}${formatMultilineContent(content, roomLabel, prefix)}`;\n}\n\n/**\n * Format a typed event as ContentPart[] for the LLM session.\n * Returns null for events that shouldn't be sent to the LLM (noise).\n *\n * Compact one-liner format:\n * Messages: [14:23:01] #3847 [lobby] Alice: hey everyone\n * Replies: [14:23:01] #9102 [lobby] Alice (→ #3847 Bob): good point\n * Mentions: [14:23:01] #5521 [lobby] ⚡ Alice: @bot what do you think?\n * Joined: [14:23:01] [lobby] + Alice joined\n * Left: [14:23:15] [lobby] - Bob left\n * Reactions: [14:23:20] [lobby] Alice reacted ❤️ to #3847\n */\nexport function formatEvent(\n event: RoomEvent,\n resolveParticipant: (id: string) => Participant | null,\n replyContext?: { senderName: string; content: string } | null,\n roomLabel?: string,\n reactionTarget?: { senderName: string; content: string; isSelf: boolean } | null,\n assignRef?: (messageId: string) => string,\n): ContentPart[] | null {\n const r = roomLabel ? `[${roomLabel}] ` : \"\";\n const ts = `[${formatTimestamp(\"timestamp\" in event ? new Date(event.timestamp as Date) : new Date())}] `;\n const mkRef = (id: string) => `#${assignRef ? assignRef(id) : messageRef(id)}`;\n\n switch (event.type) {\n case \"MessageSent\": {\n const msg = event.message;\n const name = resolveName(resolveParticipant, msg.sender_id, msg.sender_name);\n const ref = mkRef(msg.id);\n const linePrefix = `${ts}${ref} ${r}`;\n let text: string;\n if (msg.reply_to_id && replyContext) {\n const rRef = assignRef ? mkRef(msg.reply_to_id) : ref;\n text = renderLine(`${linePrefix}${name} (→ ${rRef} ${replyContext.senderName}): `, msg.content, roomLabel);\n } else {\n text = renderLine(`${linePrefix}${name}: `, msg.content, roomLabel);\n }\n const parts: ContentPart[] = [{ type: \"text\", text }];\n if (msg.image_url) parts.push({ type: \"image\", url: msg.image_url });\n return parts;\n }\n case \"Mentioned\": {\n const msg = event.message;\n const name = resolveName(resolveParticipant, msg.sender_id, msg.sender_name);\n const ref = mkRef(msg.id);\n const linePrefix = `${ts}${ref} ${r}⚡ `;\n const text = renderLine(`${linePrefix}${name}: `, msg.content, roomLabel);\n const parts: ContentPart[] = [{ type: \"text\", text }];\n if (msg.image_url) parts.push({ type: \"image\", url: msg.image_url });\n return parts;\n }\n case \"Pinged\": {\n const pingerName = event.pinger_name ?? \"someone\";\n return [{ type: \"text\", text: `${ts}${r}🔔 ${pingerName} pinged you — respond NOW with a one-line status of what you're working on. Keep it short, don't stop your current task.` }];\n }\n case \"ToolUse\":\n return null;\n case \"Activity\":\n return null;\n case \"ReactionAdded\": {\n const name = resolveName(resolveParticipant, event.participant_id);\n const targetRef = reactionTarget ? ` to ${mkRef(event.message_id)}` : \"\";\n return [{ type: \"text\", text: `${ts}${r}${name} reacted ${event.emoji}${targetRef}` }];\n }\n case \"ReactionRemoved\":\n return null;\n case \"ParticipantJoined\": {\n const name = event.participant?.name ?? \"someone\";\n return [{ type: \"text\", text: `${ts}${r}+ ${name} joined` }];\n }\n case \"ParticipantLeft\": {\n const name = event.participant?.name ?? \"someone\";\n return [{ type: \"text\", text: `${ts}${r}- ${name} left` }];\n }\n case \"ParticipantKicked\": {\n const name = event.participant?.name ?? \"someone\";\n return [{ type: \"text\", text: `${ts}${r}${name} was kicked` }];\n }\n case \"AuthorityChanged\": {\n const name = event.participant?.name ?? \"someone\";\n if (event.new_authority === \"guest\") {\n return [{ type: \"text\", text: `${ts}${r}${name} was muted` }];\n }\n if (event.new_authority === \"member\") {\n return [{ type: \"text\", text: `${ts}${r}${name} was unmuted` }];\n }\n if (event.new_authority === \"product_owner\") {\n return [{ type: \"text\", text: `${ts}${r}${name} was promoted to product owner` }];\n }\n return [{ type: \"text\", text: `${ts}${r}${name} → ${event.new_authority}` }];\n }\n case \"ContextCompacted\":\n return null;\n default:\n return null;\n }\n}\n","/**\n * Centralized authority tier model.\n *\n * Four ordered tiers — admin > product_owner > member > guest — gate every\n * privileged operation. Historically each call site had its own\n * `authority === \"admin\" || authority === \"product_owner\"` chain. That style\n * drifted (product_owner was silently excluded from /mute autocomplete; the\n * MCP runtime gated admin tools on a static CLI flag instead of the\n * server-granted tier; etc.) and is exactly the kind of bug that recurs when\n * a 5th tier eventually lands.\n *\n * One table here. Every call site reads from it. Adding an operation = one\n * row. Adding a tier = one entry in `TIER_ORDER`. No more scattered string\n * comparisons.\n */\n\nimport type { AuthorityLevel } from \"./types.js\";\n\n/** Every operation the system gates. Keep this list narrow — it's the surface. */\nexport type Operation =\n // Member-and-up — basic participation\n | \"send_message\"\n | \"set_own_mode\"\n | \"ping\"\n | \"create_share_link\"\n // Product owner-and-up — room management\n | \"mute\"\n | \"unmute\"\n | \"set_mode_for\"\n // Admin-only — destructive or escalation\n | \"kick\"\n | \"clear_history\"\n | \"start_tunnel\"\n | \"promote\"\n | \"demote\";\n\n/**\n * The single source of truth. Adding a new operation = one row here; the gate\n * is automatically enforceable everywhere via `can()`.\n */\nconst MIN_AUTHORITY: Record<Operation, AuthorityLevel> = {\n send_message: \"member\",\n set_own_mode: \"member\",\n ping: \"member\",\n create_share_link: \"member\",\n\n mute: \"product_owner\",\n unmute: \"product_owner\",\n set_mode_for: \"product_owner\",\n\n kick: \"admin\",\n clear_history: \"admin\",\n start_tunnel: \"admin\",\n promote: \"admin\",\n demote: \"admin\",\n};\n\n/**\n * Numeric ordering. Authority strings MUST NOT be compared with `<`/`>`\n * directly — lexical ordering \"p\" > \"m\" makes `\"product_owner\" > \"member\"`\n * accidentally true and silently breaks the moment any string changes. Always\n * go through `TIER_ORDER`.\n */\nexport const TIER_ORDER: Record<AuthorityLevel, number> = {\n guest: 0,\n member: 1,\n product_owner: 2,\n admin: 3,\n};\n\n/** Can the bearer of `authority` perform `op`? The check everyone calls. */\nexport function can(authority: AuthorityLevel | undefined, op: Operation): boolean {\n if (!authority) return false;\n return TIER_ORDER[authority] >= TIER_ORDER[MIN_AUTHORITY[op]];\n}\n"],"mappings":"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","names":[]}
@@ -4,125 +4,55 @@ import {
4
4
  formatEvent,
5
5
  formatTimestamp,
6
6
  messageRef
7
- } from "./chunk-YP4K2A7G.js";
7
+ } from "./chunk-TMXQDGMN.js";
8
8
  import {
9
9
  EVENT_ROLE,
10
10
  EventCategory,
11
11
  createEvent
12
12
  } from "./chunk-BZ4VDWC2.js";
13
13
 
14
- // src/agent/sse-multiplexer.ts
15
- var SseMultiplexer = class {
16
- _queue = [];
17
- _waiters = [];
18
- _connections = /* @__PURE__ */ new Map();
19
- _closed = false;
20
- /**
21
- * Add an SSE connection to a stoop server.
22
- * Starts streaming events immediately.
23
- */
24
- addConnection(serverUrl, sessionToken, roomName, roomId) {
25
- if (this._connections.has(roomId) || this._closed) return;
26
- const abortController = new AbortController();
27
- const loopPromise = this._sseLoop(serverUrl, sessionToken, roomName, roomId, abortController.signal);
28
- this._connections.set(roomId, { serverUrl, sessionToken, roomName, roomId, abortController, loopPromise });
14
+ // src/agent/room-data-source.ts
15
+ var LocalRoomDataSource = class {
16
+ constructor(_room, _channel) {
17
+ this._room = _room;
18
+ this._channel = _channel;
29
19
  }
30
- /** Remove a connection by room ID. */
31
- removeConnection(roomId) {
32
- const entry = this._connections.get(roomId);
33
- if (!entry) return;
34
- entry.abortController.abort();
35
- this._connections.delete(roomId);
20
+ _room;
21
+ _channel;
22
+ get roomId() {
23
+ return this._room.roomId;
36
24
  }
37
- /** Close all connections and signal the iterator to finish. */
38
- close() {
39
- this._closed = true;
40
- for (const [, entry] of this._connections) {
41
- entry.abortController.abort();
42
- }
43
- this._connections.clear();
44
- for (const waiter of this._waiters) {
45
- waiter.resolve(null);
46
- }
47
- this._waiters = [];
25
+ get selfId() {
26
+ return this._channel.participantId;
48
27
  }
49
- async _sseLoop(serverUrl, sessionToken, roomName, roomId, signal) {
50
- const INITIAL_BACKOFF = 1e3;
51
- const MAX_BACKOFF = 3e4;
52
- let backoff = INITIAL_BACKOFF;
53
- while (!signal.aborted && !this._closed) {
54
- try {
55
- const res = await fetch(`${serverUrl}/events`, {
56
- method: "POST",
57
- headers: {
58
- Accept: "text/event-stream",
59
- Authorization: `Bearer ${sessionToken}`
60
- },
61
- signal
62
- });
63
- if (!res.ok || !res.body) {
64
- throw new Error(`SSE connect failed: ${res.status}`);
65
- }
66
- backoff = INITIAL_BACKOFF;
67
- const reader = res.body.getReader();
68
- const decoder = new TextDecoder();
69
- let buffer = "";
70
- while (!signal.aborted) {
71
- const { done, value } = await reader.read();
72
- if (done) break;
73
- buffer += decoder.decode(value, { stream: true });
74
- const parts = buffer.split("\n\n");
75
- buffer = parts.pop();
76
- for (const part of parts) {
77
- const dataLine = part.split("\n").find((l) => l.startsWith("data: "));
78
- if (!dataLine) continue;
79
- try {
80
- const event = JSON.parse(dataLine.slice(6));
81
- this._push({ roomId, roomName, event });
82
- } catch {
83
- }
84
- }
85
- }
86
- } catch (err) {
87
- if (signal.aborted) break;
88
- }
89
- if (!signal.aborted && !this._closed) {
90
- await new Promise((r) => setTimeout(r, backoff));
91
- backoff = Math.min(backoff * 2, MAX_BACKOFF);
92
- }
93
- }
28
+ /** Direct access to the underlying Room (for backward compat / internal use). */
29
+ get room() {
30
+ return this._room;
94
31
  }
95
- _push(labeled) {
96
- if (this._closed) return;
97
- if (this._waiters.length > 0) {
98
- const waiter = this._waiters.shift();
99
- waiter.resolve(labeled);
100
- } else {
101
- this._queue.push(labeled);
102
- }
32
+ /** Direct access to the underlying Channel (for backward compat / internal use). */
33
+ get channel() {
34
+ return this._channel;
103
35
  }
104
- [Symbol.asyncIterator]() {
105
- return {
106
- next: () => {
107
- if (this._queue.length > 0) {
108
- return Promise.resolve({ value: this._queue.shift(), done: false });
109
- }
110
- if (this._closed) {
111
- return Promise.resolve({ value: void 0, done: true });
112
- }
113
- return new Promise((resolve) => {
114
- this._waiters.push({
115
- resolve: (value) => {
116
- if (this._closed || value === null) {
117
- resolve({ value: void 0, done: true });
118
- } else {
119
- resolve({ value, done: false });
120
- }
121
- }
122
- });
123
- });
124
- }
125
- };
36
+ listParticipants() {
37
+ return this._room.listParticipants();
38
+ }
39
+ async getMessage(id) {
40
+ return this._room.getMessage(id);
41
+ }
42
+ async searchMessages(query, limit = 10, cursor = null) {
43
+ return this._room.searchMessages(query, limit, cursor);
44
+ }
45
+ async getMessages(limit = 30, cursor = null) {
46
+ return this._room.listMessages(limit, cursor);
47
+ }
48
+ async getEvents(category = null, limit = 50, cursor = null) {
49
+ return this._room.listEvents(category, limit, cursor);
50
+ }
51
+ async sendMessage(content, replyToId, image, attachments, recipients) {
52
+ return this._channel.sendMessage(content, replyToId, image ?? void 0, attachments, recipients);
53
+ }
54
+ async emitEvent(event) {
55
+ await this._channel.emit(event);
126
56
  }
127
57
  };
128
58
 
@@ -208,51 +138,6 @@ function classifyEvent(event, mode, selfId, senderType, senderId) {
208
138
  return classify(event, mode, selfId, senderType, senderId);
209
139
  }
210
140
 
211
- // src/agent/room-data-source.ts
212
- var LocalRoomDataSource = class {
213
- constructor(_room, _channel) {
214
- this._room = _room;
215
- this._channel = _channel;
216
- }
217
- _room;
218
- _channel;
219
- get roomId() {
220
- return this._room.roomId;
221
- }
222
- get selfId() {
223
- return this._channel.participantId;
224
- }
225
- /** Direct access to the underlying Room (for backward compat / internal use). */
226
- get room() {
227
- return this._room;
228
- }
229
- /** Direct access to the underlying Channel (for backward compat / internal use). */
230
- get channel() {
231
- return this._channel;
232
- }
233
- listParticipants() {
234
- return this._room.listParticipants();
235
- }
236
- async getMessage(id) {
237
- return this._room.getMessage(id);
238
- }
239
- async searchMessages(query, limit = 10, cursor = null) {
240
- return this._room.searchMessages(query, limit, cursor);
241
- }
242
- async getMessages(limit = 30, cursor = null) {
243
- return this._room.listMessages(limit, cursor);
244
- }
245
- async getEvents(category = null, limit = 50, cursor = null) {
246
- return this._room.listEvents(category, limit, cursor);
247
- }
248
- async sendMessage(content, replyToId, image, attachments, recipients) {
249
- return this._channel.sendMessage(content, replyToId, image ?? void 0, attachments, recipients);
250
- }
251
- async emitEvent(event) {
252
- await this._channel.emit(event);
253
- }
254
- };
255
-
256
141
  // src/agent/remote-room-data-source.ts
257
142
  var RemoteRoomDataSource = class {
258
143
  constructor(_serverUrl, _sessionToken, _roomId) {
@@ -1224,7 +1109,7 @@ ${conn.name} [${ref}] \u2014 ${mode}`);
1224
1109
  const selfId = this.getSelfIdForRoom(roomId);
1225
1110
  const disposition = this._engagement.classify(event, roomId, selfId, senderType, senderLookupId);
1226
1111
  if (disposition === "drop") return;
1227
- this._tracker.markDelivered(event.id);
1112
+ if (!this._options.pullOnly) this._tracker.markDelivered(event.id);
1228
1113
  if (disposition === "content") {
1229
1114
  this._buffer.push(roomId, { event, roomId, roomName: labeled.roomName });
1230
1115
  return;
@@ -1752,12 +1637,126 @@ async function createStdioRuntimeMcpServer(opts) {
1752
1637
  return { stop, closed };
1753
1638
  }
1754
1639
 
1640
+ // src/agent/sse-multiplexer.ts
1641
+ var SseMultiplexer = class {
1642
+ _queue = [];
1643
+ _waiters = [];
1644
+ _connections = /* @__PURE__ */ new Map();
1645
+ _closed = false;
1646
+ /**
1647
+ * Add an SSE connection to a stoop server.
1648
+ * Starts streaming events immediately.
1649
+ */
1650
+ addConnection(serverUrl, sessionToken, roomName, roomId) {
1651
+ if (this._connections.has(roomId) || this._closed) return;
1652
+ const abortController = new AbortController();
1653
+ const loopPromise = this._sseLoop(serverUrl, sessionToken, roomName, roomId, abortController.signal);
1654
+ this._connections.set(roomId, { serverUrl, sessionToken, roomName, roomId, abortController, loopPromise });
1655
+ }
1656
+ /** Remove a connection by room ID. */
1657
+ removeConnection(roomId) {
1658
+ const entry = this._connections.get(roomId);
1659
+ if (!entry) return;
1660
+ entry.abortController.abort();
1661
+ this._connections.delete(roomId);
1662
+ }
1663
+ /** Close all connections and signal the iterator to finish. */
1664
+ close() {
1665
+ this._closed = true;
1666
+ for (const [, entry] of this._connections) {
1667
+ entry.abortController.abort();
1668
+ }
1669
+ this._connections.clear();
1670
+ for (const waiter of this._waiters) {
1671
+ waiter.resolve(null);
1672
+ }
1673
+ this._waiters = [];
1674
+ }
1675
+ async _sseLoop(serverUrl, sessionToken, roomName, roomId, signal) {
1676
+ const INITIAL_BACKOFF = 1e3;
1677
+ const MAX_BACKOFF = 3e4;
1678
+ let backoff = INITIAL_BACKOFF;
1679
+ while (!signal.aborted && !this._closed) {
1680
+ try {
1681
+ const res = await fetch(`${serverUrl}/events`, {
1682
+ method: "POST",
1683
+ headers: {
1684
+ Accept: "text/event-stream",
1685
+ Authorization: `Bearer ${sessionToken}`
1686
+ },
1687
+ signal
1688
+ });
1689
+ if (!res.ok || !res.body) {
1690
+ throw new Error(`SSE connect failed: ${res.status}`);
1691
+ }
1692
+ backoff = INITIAL_BACKOFF;
1693
+ const reader = res.body.getReader();
1694
+ const decoder = new TextDecoder();
1695
+ let buffer = "";
1696
+ while (!signal.aborted) {
1697
+ const { done, value } = await reader.read();
1698
+ if (done) break;
1699
+ buffer += decoder.decode(value, { stream: true });
1700
+ const parts = buffer.split("\n\n");
1701
+ buffer = parts.pop();
1702
+ for (const part of parts) {
1703
+ const dataLine = part.split("\n").find((l) => l.startsWith("data: "));
1704
+ if (!dataLine) continue;
1705
+ try {
1706
+ const event = JSON.parse(dataLine.slice(6));
1707
+ this._push({ roomId, roomName, event });
1708
+ } catch {
1709
+ }
1710
+ }
1711
+ }
1712
+ } catch (err) {
1713
+ if (signal.aborted) break;
1714
+ }
1715
+ if (!signal.aborted && !this._closed) {
1716
+ await new Promise((r) => setTimeout(r, backoff));
1717
+ backoff = Math.min(backoff * 2, MAX_BACKOFF);
1718
+ }
1719
+ }
1720
+ }
1721
+ _push(labeled) {
1722
+ if (this._closed) return;
1723
+ if (this._waiters.length > 0) {
1724
+ const waiter = this._waiters.shift();
1725
+ waiter.resolve(labeled);
1726
+ } else {
1727
+ this._queue.push(labeled);
1728
+ }
1729
+ }
1730
+ [Symbol.asyncIterator]() {
1731
+ return {
1732
+ next: () => {
1733
+ if (this._queue.length > 0) {
1734
+ return Promise.resolve({ value: this._queue.shift(), done: false });
1735
+ }
1736
+ if (this._closed) {
1737
+ return Promise.resolve({ value: void 0, done: true });
1738
+ }
1739
+ return new Promise((resolve) => {
1740
+ this._waiters.push({
1741
+ resolve: (value) => {
1742
+ if (this._closed || value === null) {
1743
+ resolve({ value: void 0, done: true });
1744
+ } else {
1745
+ resolve({ value, done: false });
1746
+ }
1747
+ }
1748
+ });
1749
+ });
1750
+ }
1751
+ };
1752
+ }
1753
+ };
1754
+
1755
1755
  export {
1756
- SseMultiplexer,
1756
+ LocalRoomDataSource,
1757
1757
  parseEngagementMode,
1758
1758
  StoopsEngagement,
1759
1759
  classifyEvent,
1760
- LocalRoomDataSource,
1761
1760
  RemoteRoomDataSource,
1762
1761
  buildCatchUpLines,
1763
1762
  EventMultiplexer,
@@ -1766,6 +1765,7 @@ export {
1766
1765
  EventProcessor,
1767
1766
  RUNTIME_TOOL_NAMES,
1768
1767
  createRuntimeMcpServer,
1769
- createStdioRuntimeMcpServer
1768
+ createStdioRuntimeMcpServer,
1769
+ SseMultiplexer
1770
1770
  };
1771
- //# sourceMappingURL=chunk-LN6ATWE3.js.map
1771
+ //# sourceMappingURL=chunk-WJD5EKO6.js.map