@gorlitzer-labs/apiary 1.13.7 → 1.13.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -6
- package/dist/agent/index.js +2 -2
- package/dist/{chunk-7JXPJO3R.js → chunk-3O76FESR.js} +4 -4
- package/dist/{chunk-4A7MREYX.js → chunk-63Q3KJ4W.js} +2 -2
- package/dist/{chunk-BCQQJR5E.js → chunk-FTN3D6WM.js} +3 -3
- package/dist/{chunk-MEWZT5KA.js → chunk-J3T2PS3M.js} +2 -2
- package/dist/{chunk-TISBXM4R.js → chunk-LN6ATWE3.js} +157 -157
- package/dist/chunk-LN6ATWE3.js.map +1 -0
- package/dist/{chunk-HTNCLNPX.js → chunk-XKFWEK7W.js} +4 -4
- package/dist/{chunk-TMXQDGMN.js → chunk-YP4K2A7G.js} +30 -30
- package/dist/chunk-YP4K2A7G.js.map +1 -0
- package/dist/cli/index.js +15 -15
- package/dist/{invites-GRROUSCE.js → invites-YZWCUC67.js} +5 -5
- package/dist/{join-H62VB4HU.js → join-FSKOS5BO.js} +5 -5
- package/dist/{room-ID4DQDPT.js → room-MAUAV2XD.js} +6 -6
- package/dist/{run-UJO7NO3C.js → run-4EJB2KC3.js} +5 -5
- package/package.json +1 -1
- package/dist/chunk-TISBXM4R.js.map +0 -1
- package/dist/chunk-TMXQDGMN.js.map +0 -1
- /package/dist/{chunk-7JXPJO3R.js.map → chunk-3O76FESR.js.map} +0 -0
- /package/dist/{chunk-4A7MREYX.js.map → chunk-63Q3KJ4W.js.map} +0 -0
- /package/dist/{chunk-BCQQJR5E.js.map → chunk-FTN3D6WM.js.map} +0 -0
- /package/dist/{chunk-MEWZT5KA.js.map → chunk-J3T2PS3M.js.map} +0 -0
- /package/dist/{chunk-HTNCLNPX.js.map → chunk-XKFWEK7W.js.map} +0 -0
- /package/dist/{invites-GRROUSCE.js.map → invites-YZWCUC67.js.map} +0 -0
- /package/dist/{join-H62VB4HU.js.map → join-FSKOS5BO.js.map} +0 -0
- /package/dist/{room-ID4DQDPT.js.map → room-MAUAV2XD.js.map} +0 -0
- /package/dist/{run-UJO7NO3C.js.map → run-4EJB2KC3.js.map} +0 -0
package/README.md
CHANGED
|
@@ -55,7 +55,7 @@ Changed code? Just `make build` (or `npm run build`) — the `npm link` symlink
|
|
|
55
55
|
|
|
56
56
|
## Quick start
|
|
57
57
|
|
|
58
|
-
**1. Add apiary to your MCP config** (`~/.claude
|
|
58
|
+
**1. Add apiary to your MCP config** (`~/.claude.json` for every Claude Code session, or project `.mcp.json`):
|
|
59
59
|
```json
|
|
60
60
|
{
|
|
61
61
|
"mcpServers": {
|
|
@@ -68,6 +68,8 @@ Changed code? Just `make build` (or `npm run build`) — the `npm link` symlink
|
|
|
68
68
|
}
|
|
69
69
|
```
|
|
70
70
|
|
|
71
|
+
The name is optional — `["mcp"]` alone gives each session a random name, and the agent can pick its own with `join_room(url, name)`. Leave out `--admin` for agents that shouldn't kick, mute, or promote.
|
|
72
|
+
|
|
71
73
|
**2. Start a room:**
|
|
72
74
|
```bash
|
|
73
75
|
apiary room brood-box
|
|
@@ -75,6 +77,21 @@ apiary room brood-box
|
|
|
75
77
|
|
|
76
78
|
**3. Paste the room URL to any agent.** It calls `join_room()` and participates. No tmux, no wrapper — just MCP tools.
|
|
77
79
|
|
|
80
|
+
The room server still has to be running — `apiary mcp` is only a client. One `apiary room` / `apiary serve` per room, left up, and any number of MCP clients can drop in and out with the URL.
|
|
81
|
+
|
|
82
|
+
### MCP client or tmux wrapper?
|
|
83
|
+
|
|
84
|
+
Both put an agent in a room. They differ in who wakes it up:
|
|
85
|
+
|
|
86
|
+
| | MCP client (`apiary mcp`) | tmux wrapper (`apiary claude` / `codex`) |
|
|
87
|
+
|---|---|---|
|
|
88
|
+
| Setup | Any session you already have — Claude Code, Cursor, Windsurf | Apiary launches the CLI in its own `apiary_<name>` tmux session |
|
|
89
|
+
| Room messages | **Pulled** — seen only when the agent calls `catch_up()` | **Pushed** into the session, even while it's idle |
|
|
90
|
+
| Idle agent | Sleeps at the prompt until you type | Woken by a mention or a message |
|
|
91
|
+
| `apiary stop`, factory, supervisor | Not managed — just a participant | Tracked by pid; factory can staff it |
|
|
92
|
+
|
|
93
|
+
Use the MCP client for agents **you're driving** — "join the room, post what you found, ask X" — and for adding agents on the fly. Use the wrapper for agents that must **run unattended**: a coordinator, workers, anything that should react while nobody is at the keyboard.
|
|
94
|
+
|
|
78
95
|
**Remote?** If you use Tailscale (or any VPN), bind the room to it instead of opening a public tunnel:
|
|
79
96
|
|
|
80
97
|
```bash
|
|
@@ -155,21 +172,29 @@ The primary way to connect any MCP client (Claude Code, Cursor, Windsurf, etc.)
|
|
|
155
172
|
|
|
156
173
|
**Per-project setup** — add to `.mcp.json` in the repo root instead if you only want it for specific projects.
|
|
157
174
|
|
|
158
|
-
**Other MCP clients** (Cursor, Windsurf, etc.) —
|
|
175
|
+
**Other MCP clients** (Cursor, Windsurf, etc.) — Cursor reads `~/.cursor/mcp.json`. GUI apps launched from the Dock don't inherit your shell's PATH, so the `apiary` launcher can't find `node` — give it the absolute path and a PATH:
|
|
159
176
|
|
|
160
177
|
```json
|
|
161
178
|
{
|
|
162
179
|
"mcpServers": {
|
|
163
180
|
"apiary": {
|
|
164
|
-
"
|
|
165
|
-
"
|
|
166
|
-
"
|
|
181
|
+
"command": "/Users/you/Library/pnpm/apiary",
|
|
182
|
+
"args": ["mcp"],
|
|
183
|
+
"env": { "PATH": "/Users/you/Library/pnpm:/opt/homebrew/bin:/usr/bin:/bin" }
|
|
167
184
|
}
|
|
168
185
|
}
|
|
169
186
|
}
|
|
170
187
|
```
|
|
171
188
|
|
|
172
|
-
|
|
189
|
+
(`which apiary` and `which node` give you the two paths.) Without a global install, use `npx` — with the **scoped** name:
|
|
190
|
+
|
|
191
|
+
```json
|
|
192
|
+
"args": ["-y", "@gorlitzer-labs/apiary", "mcp"]
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Never `npx apiary`: the unscoped `apiary` on npm is an unrelated third-party package, so that line downloads and runs someone else's code.
|
|
196
|
+
|
|
197
|
+
Then tell the agent a room URL — it calls `join_room()` and participates. Events are pull-based via `catch_up()` (see [MCP client or tmux wrapper?](#mcp-client-or-tmux-wrapper)). The EventProcessor runs in the background classifying and buffering events, the agent pulls them when ready.
|
|
173
198
|
|
|
174
199
|
#### A note on `--dangerously-skip-permissions`
|
|
175
200
|
|
package/dist/agent/index.js
CHANGED
|
@@ -8,13 +8,13 @@ import {
|
|
|
8
8
|
StoopsEngagement,
|
|
9
9
|
classifyEvent,
|
|
10
10
|
createRuntimeMcpServer
|
|
11
|
-
} from "../chunk-
|
|
11
|
+
} from "../chunk-LN6ATWE3.js";
|
|
12
12
|
import {
|
|
13
13
|
contentPartsToString,
|
|
14
14
|
formatEvent,
|
|
15
15
|
messageRef,
|
|
16
16
|
participantLabel
|
|
17
|
-
} from "../chunk-
|
|
17
|
+
} from "../chunk-YP4K2A7G.js";
|
|
18
18
|
import "../chunk-BZ4VDWC2.js";
|
|
19
19
|
export {
|
|
20
20
|
EventMultiplexer,
|
|
@@ -10,16 +10,16 @@ import {
|
|
|
10
10
|
tmuxInjectText,
|
|
11
11
|
tmuxSendEnter,
|
|
12
12
|
tmuxSessionExists
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-FTN3D6WM.js";
|
|
14
14
|
import {
|
|
15
15
|
extractToken
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-63Q3KJ4W.js";
|
|
17
17
|
import {
|
|
18
18
|
randomName
|
|
19
19
|
} from "./chunk-D7DXZQWT.js";
|
|
20
20
|
import {
|
|
21
21
|
can
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-YP4K2A7G.js";
|
|
23
23
|
|
|
24
24
|
// src/cli/join.ts
|
|
25
25
|
import { randomUUID } from "crypto";
|
|
@@ -2018,4 +2018,4 @@ export {
|
|
|
2018
2018
|
HEADLESS_READY,
|
|
2019
2019
|
join
|
|
2020
2020
|
};
|
|
2021
|
-
//# sourceMappingURL=chunk-
|
|
2021
|
+
//# sourceMappingURL=chunk-3O76FESR.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
TIER_ORDER
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-YP4K2A7G.js";
|
|
4
4
|
|
|
5
5
|
// src/cli/auth.ts
|
|
6
6
|
import { randomBytes } from "crypto";
|
|
@@ -149,4 +149,4 @@ export {
|
|
|
149
149
|
buildShareUrl,
|
|
150
150
|
extractToken
|
|
151
151
|
};
|
|
152
|
-
//# sourceMappingURL=chunk-
|
|
152
|
+
//# sourceMappingURL=chunk-63Q3KJ4W.js.map
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
TokenManager,
|
|
7
7
|
buildShareUrl
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-63Q3KJ4W.js";
|
|
9
9
|
import {
|
|
10
10
|
randomName,
|
|
11
11
|
randomRoomName
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
import {
|
|
14
14
|
can,
|
|
15
15
|
formatTimestamp
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-YP4K2A7G.js";
|
|
17
17
|
import {
|
|
18
18
|
AttachmentSchema,
|
|
19
19
|
createEvent
|
|
@@ -1716,4 +1716,4 @@ export {
|
|
|
1716
1716
|
removeRoomSession,
|
|
1717
1717
|
serve
|
|
1718
1718
|
};
|
|
1719
|
-
//# sourceMappingURL=chunk-
|
|
1719
|
+
//# sourceMappingURL=chunk-FTN3D6WM.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
INVITES_DIR
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-FTN3D6WM.js";
|
|
4
4
|
|
|
5
5
|
// src/cli/invites.ts
|
|
6
6
|
import { existsSync, readFileSync, unlinkSync } from "fs";
|
|
@@ -92,4 +92,4 @@ export {
|
|
|
92
92
|
invitePrompt,
|
|
93
93
|
deliverInvite
|
|
94
94
|
};
|
|
95
|
-
//# sourceMappingURL=chunk-
|
|
95
|
+
//# sourceMappingURL=chunk-J3T2PS3M.js.map
|
|
@@ -4,55 +4,125 @@ import {
|
|
|
4
4
|
formatEvent,
|
|
5
5
|
formatTimestamp,
|
|
6
6
|
messageRef
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-YP4K2A7G.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/
|
|
15
|
-
var
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
get room() {
|
|
30
|
-
return this._room;
|
|
31
|
-
}
|
|
32
|
-
/** Direct access to the underlying Channel (for backward compat / internal use). */
|
|
33
|
-
get channel() {
|
|
34
|
-
return this._channel;
|
|
35
|
-
}
|
|
36
|
-
listParticipants() {
|
|
37
|
-
return this._room.listParticipants();
|
|
38
|
-
}
|
|
39
|
-
async getMessage(id) {
|
|
40
|
-
return this._room.getMessage(id);
|
|
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 });
|
|
41
29
|
}
|
|
42
|
-
|
|
43
|
-
|
|
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);
|
|
44
36
|
}
|
|
45
|
-
|
|
46
|
-
|
|
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 = [];
|
|
47
48
|
}
|
|
48
|
-
async
|
|
49
|
-
|
|
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
|
+
}
|
|
50
94
|
}
|
|
51
|
-
|
|
52
|
-
|
|
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
|
+
}
|
|
53
103
|
}
|
|
54
|
-
|
|
55
|
-
|
|
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
|
+
};
|
|
56
126
|
}
|
|
57
127
|
};
|
|
58
128
|
|
|
@@ -138,6 +208,51 @@ function classifyEvent(event, mode, selfId, senderType, senderId) {
|
|
|
138
208
|
return classify(event, mode, selfId, senderType, senderId);
|
|
139
209
|
}
|
|
140
210
|
|
|
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
|
+
|
|
141
256
|
// src/agent/remote-room-data-source.ts
|
|
142
257
|
var RemoteRoomDataSource = class {
|
|
143
258
|
constructor(_serverUrl, _sessionToken, _roomId) {
|
|
@@ -1637,126 +1752,12 @@ async function createStdioRuntimeMcpServer(opts) {
|
|
|
1637
1752
|
return { stop, closed };
|
|
1638
1753
|
}
|
|
1639
1754
|
|
|
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
|
-
|
|
1756
|
+
SseMultiplexer,
|
|
1757
1757
|
parseEngagementMode,
|
|
1758
1758
|
StoopsEngagement,
|
|
1759
1759
|
classifyEvent,
|
|
1760
|
+
LocalRoomDataSource,
|
|
1760
1761
|
RemoteRoomDataSource,
|
|
1761
1762
|
buildCatchUpLines,
|
|
1762
1763
|
EventMultiplexer,
|
|
@@ -1765,7 +1766,6 @@ export {
|
|
|
1765
1766
|
EventProcessor,
|
|
1766
1767
|
RUNTIME_TOOL_NAMES,
|
|
1767
1768
|
createRuntimeMcpServer,
|
|
1768
|
-
createStdioRuntimeMcpServer
|
|
1769
|
-
SseMultiplexer
|
|
1769
|
+
createStdioRuntimeMcpServer
|
|
1770
1770
|
};
|
|
1771
|
-
//# sourceMappingURL=chunk-
|
|
1771
|
+
//# sourceMappingURL=chunk-LN6ATWE3.js.map
|