@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 +0,0 @@
1
- {"version":3,"sources":["../src/agent/sse-multiplexer.ts","../src/agent/engagement.ts","../src/agent/room-data-source.ts","../src/agent/remote-room-data-source.ts","../src/agent/multiplexer.ts","../src/agent/ref-map.ts","../src/agent/tool-handlers.ts","../src/agent/connection-registry.ts","../src/agent/content-buffer.ts","../src/agent/event-tracker.ts","../src/agent/event-processor.ts","../src/agent/mcp/runtime.ts"],"sourcesContent":["/**\n * SseMultiplexer — merges N SSE connections into one labeled event stream.\n *\n * Each connection is an HTTP fetch to a stoop server's /events endpoint.\n * Events are parsed from the SSE `data:` lines and wrapped as LabeledEvents\n * (same shape as EventMultiplexer output so EventProcessor can consume either).\n *\n * Connections can be added/removed while the multiplexer is running.\n * Each connection has its own AbortController for independent lifecycle.\n */\n\nimport type { RoomEvent } from \"../core/events.js\";\nimport type { LabeledEvent } from \"./multiplexer.js\";\n\ninterface SseConnection {\n serverUrl: string;\n sessionToken: string;\n roomName: string;\n roomId: string;\n abortController: AbortController;\n loopPromise: Promise<void>;\n}\n\nexport class SseMultiplexer {\n private _queue: LabeledEvent[] = [];\n private _waiters: Array<{ resolve: (value: LabeledEvent) => void }> = [];\n private _connections = new Map<string, SseConnection>();\n private _closed = false;\n\n /**\n * Add an SSE connection to a stoop server.\n * Starts streaming events immediately.\n */\n addConnection(serverUrl: string, sessionToken: string, roomName: string, roomId: string): void {\n if (this._connections.has(roomId) || this._closed) return;\n\n const abortController = new AbortController();\n const loopPromise = this._sseLoop(serverUrl, sessionToken, roomName, roomId, abortController.signal);\n this._connections.set(roomId, { serverUrl, sessionToken, roomName, roomId, abortController, loopPromise });\n }\n\n /** Remove a connection by room ID. */\n removeConnection(roomId: string): void {\n const entry = this._connections.get(roomId);\n if (!entry) return;\n entry.abortController.abort();\n this._connections.delete(roomId);\n }\n\n /** Close all connections and signal the iterator to finish. */\n close(): void {\n this._closed = true;\n for (const [, entry] of this._connections) {\n entry.abortController.abort();\n }\n this._connections.clear();\n\n // Resolve all pending waiters so the iterator returns done\n for (const waiter of this._waiters) {\n waiter.resolve(null as unknown as LabeledEvent);\n }\n this._waiters = [];\n }\n\n private async _sseLoop(\n serverUrl: string,\n sessionToken: string,\n roomName: string,\n roomId: string,\n signal: AbortSignal,\n ): Promise<void> {\n const INITIAL_BACKOFF = 1000;\n const MAX_BACKOFF = 30000;\n let backoff = INITIAL_BACKOFF;\n\n while (!signal.aborted && !this._closed) {\n try {\n // POST required — Cloudflare Quick Tunnels buffer GET streaming\n // responses and only flush on connection close. POST streams in real-time.\n const res = await fetch(`${serverUrl}/events`, {\n method: \"POST\",\n headers: {\n Accept: \"text/event-stream\",\n Authorization: `Bearer ${sessionToken}`,\n },\n signal,\n });\n\n if (!res.ok || !res.body) {\n throw new Error(`SSE connect failed: ${res.status}`);\n }\n\n // Connected — reset backoff\n backoff = INITIAL_BACKOFF;\n\n const reader = res.body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n while (!signal.aborted) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n\n // Parse SSE: split on double newline\n const parts = buffer.split(\"\\n\\n\");\n buffer = parts.pop()!; // keep incomplete chunk\n\n for (const part of parts) {\n const dataLine = part.split(\"\\n\").find((l) => l.startsWith(\"data: \"));\n if (!dataLine) continue;\n\n try {\n const event = JSON.parse(dataLine.slice(6)) as RoomEvent;\n this._push({ roomId, roomName, event });\n } catch {\n // Malformed event — skip\n }\n }\n }\n } catch (err) {\n if (signal.aborted) break;\n // Connection failed or dropped — backoff and retry\n }\n\n if (!signal.aborted && !this._closed) {\n await new Promise((r) => setTimeout(r, backoff));\n backoff = Math.min(backoff * 2, MAX_BACKOFF);\n }\n }\n }\n\n private _push(labeled: LabeledEvent): void {\n if (this._closed) return;\n if (this._waiters.length > 0) {\n const waiter = this._waiters.shift()!;\n waiter.resolve(labeled);\n } else {\n this._queue.push(labeled);\n }\n }\n\n [Symbol.asyncIterator](): AsyncIterator<LabeledEvent> {\n return {\n next: (): Promise<IteratorResult<LabeledEvent>> => {\n // Drain buffered events first\n if (this._queue.length > 0) {\n return Promise.resolve({ value: this._queue.shift()!, done: false });\n }\n\n if (this._closed) {\n return Promise.resolve({ value: undefined as unknown as LabeledEvent, done: true });\n }\n\n return new Promise<IteratorResult<LabeledEvent>>((resolve) => {\n this._waiters.push({\n resolve: (value) => {\n if (this._closed || value === null) {\n resolve({ value: undefined as unknown as LabeledEvent, done: true });\n } else {\n resolve({ value, done: false });\n }\n },\n });\n });\n },\n };\n }\n}\n","/**\n * Engagement — controls which room events trigger LLM evaluation.\n *\n * # Overview\n *\n * Every event that reaches an agent is classified into one of three dispositions:\n * - \"trigger\" — evaluate now (start an LLM call)\n * - \"content\" — buffer as context; deliver to LLM on the next trigger\n * - \"drop\" — ignore entirely (not delivered to LLM)\n *\n * The `EngagementStrategy` interface defines this contract. Implement it to\n * customize when your agent responds. The built-in `StoopsEngagement` provides\n * a 7-mode system; `classifyEvent()` is a standalone convenience function\n * using the same logic.\n *\n * # Built-in modes (StoopsEngagement / classifyEvent)\n *\n * Active modes (agent evaluates on matching messages):\n * - \"everyone\" — all messages trigger evaluation\n * - \"people\" — only messages from human participants trigger evaluation\n * - \"agents\" — only messages from other agents trigger evaluation\n * - \"fight\" — all messages trigger (novelty roast mode)\n *\n * Standby modes (agent only wakes on @mentions):\n * - \"standby-everyone\" — any @mention wakes the agent\n * - \"standby-people\" — only @mentions from humans wake the agent\n * - \"standby-agents\" — only @mentions from other agents wake the agent\n *\n * # Classification rules (in order)\n *\n * 1. Internal events (bookkeeping: edits, deletes, status changes, agent\n * activity) → always drop\n * 2. Self-sent events → drop (the agent ignores its own activity).\n * Exception: mentions are not self-dropped — a standby agent should wake\n * if it is @mentioned, even if the mention event's participant_id is itself.\n * 3. Standby modes: only @mentions directed at the agent from a matching\n * sender → trigger; everything else → drop.\n * 4. Active modes, @mention → drop (the MessageSent event already carries the\n * @mention text; delivering both would be redundant).\n * 5. Active modes, message from matching sender → trigger\n * 6. Active modes, message from non-matching sender → content (buffered context)\n * 7. Active modes, ambient event (join/leave/reaction) → content\n */\n\nimport { EVENT_ROLE } from \"../core/events.js\";\nimport type { RoomEvent } from \"../core/events.js\";\nimport type { ParticipantType } from \"../core/types.js\";\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\n/**\n * The outcome of classifying an event for a given agent.\n *\n * - \"trigger\" — run an LLM evaluation now\n * - \"content\" — buffer as context; include with the next evaluation\n * - \"drop\" — discard; never shown to the LLM\n */\nexport type EventDisposition = \"trigger\" | \"content\" | \"drop\";\n\n/**\n * Engagement strategy — decides which events trigger LLM evaluation.\n *\n * Implement this to customize when your agent responds. The runtime calls\n * `classify()` for every incoming event and acts on the returned disposition.\n *\n * @example\n * // Respond to everything:\n * class AlwaysEngage implements EngagementStrategy {\n * classify(event, roomId, selfId) {\n * if (event.participant_id === selfId) return \"drop\";\n * return \"trigger\";\n * }\n * }\n */\nexport interface EngagementStrategy {\n /**\n * Classify a room event for this agent.\n *\n * @param event — the room event to classify\n * @param roomId — the room the event came from\n * @param selfId — the agent's own participant ID (to drop self-events)\n * @param senderType — \"human\" or \"agent\" for the event's sender\n * @param senderId — participant ID of the sender. For `Mentioned` events,\n * pass `event.message.sender_id` (who wrote the mention),\n * not `event.participant_id` (who was mentioned).\n */\n classify(\n event: RoomEvent,\n roomId: string,\n selfId: string,\n senderType: ParticipantType,\n senderId: string,\n ): EventDisposition;\n\n /**\n * Return the current engagement mode for a room.\n *\n * Optional — strategies that don't use named modes may omit this.\n * The runtime falls back to `\"everyone\"` when absent.\n */\n getMode?(roomId: string): EngagementMode;\n\n /**\n * Update the engagement mode for a room.\n *\n * Optional — called by the runtime when a room connects with an initial mode\n * or when the user changes the mode at runtime. Strategies that don't use\n * named modes may omit this; the call will be silently ignored.\n */\n setMode?(roomId: string, mode: EngagementMode): void;\n\n /**\n * Called when a room is disconnected from the runtime.\n *\n * Optional — use this for cleanup, e.g. removing per-room state that is\n * no longer needed. Strategies with no per-room state may omit this.\n */\n onRoomDisconnected?(roomId: string): void;\n}\n\n// ── Built-in modes ────────────────────────────────────────────────────────────\n\nexport type EngagementMode =\n | \"people\" | \"agents\" | \"everyone\" | \"fight\"\n | \"standby-people\" | \"standby-agents\" | \"standby-everyone\";\n\n/** Every mode the CLI accepts, for validation and help text. */\nexport const ENGAGEMENT_MODE_NAMES: readonly EngagementMode[] = [\n \"everyone\", \"people\", \"agents\", \"fight\",\n \"standby-everyone\", \"standby-people\", \"standby-agents\",\n];\n\n/**\n * Validate a mode coming off the command line.\n *\n * Returns undefined for absent OR unrecognised input, so a typo falls back to\n * the default rather than starting an agent in a mode nobody chose.\n */\nexport function parseEngagementMode(value: string | undefined): EngagementMode | undefined {\n if (!value) return undefined;\n const lc = value.trim().toLowerCase();\n if (lc === \"standby\") return \"standby-everyone\";\n return (ENGAGEMENT_MODE_NAMES as readonly string[]).includes(lc)\n ? (lc as EngagementMode)\n : undefined;\n}\n\n// ── Core classification logic (shared) ────────────────────────────────────────\n\nfunction senderMatches(\n filter: string,\n senderType: ParticipantType,\n senderId: string,\n): boolean {\n switch (filter) {\n case \"everyone\": return true;\n case \"fight\": return true;\n case \"people\": return senderType === \"human\";\n case \"agents\": return senderType === \"agent\";\n default: return false;\n }\n}\n\n/**\n * True if `event` is a whisper (a message with explicit recipients) and this\n * agent is one of them.\n *\n * Note this reads `message.recipients`, not `participant_id` — on a\n * MessageSent the latter is the SENDER, unlike mention and ping events where\n * it is the recipient.\n */\nfunction isWhisperTo(event: RoomEvent, selfId: string): boolean {\n if (event.type !== \"MessageSent\") return false;\n const recipients = event.message.recipients;\n if (!recipients || recipients.length === 0) return false;\n return recipients.includes(selfId);\n}\n\n/** Internal classification logic shared by classifyEvent() and StoopsEngagement. */\nfunction classify(\n event: RoomEvent,\n mode: EngagementMode,\n selfId: string,\n senderType: ParticipantType,\n senderId: string,\n): EventDisposition {\n // 1. Internal events (agent activity, edits, deletes, status) — always drop.\n const role = EVENT_ROLE[event.type];\n if (role === \"internal\") return \"drop\";\n\n // 2. Self-sent events — drop. Skip this check for mentions and pings: a\n // standby agent should wake when @mentioned or pinged, and the event's\n // participant_id is the recipient (the agent itself), not the sender.\n if (role !== \"mention\" && role !== \"ping\" && event.participant_id === selfId) return \"drop\";\n\n const isStandby = mode.startsWith(\"standby-\");\n const filter = isStandby ? mode.slice(8) : mode; // \"standby-people\" → \"people\"\n\n // 3. Standby: only things ADDRESSED TO THIS AGENT wake it; everything else\n // is dropped entirely.\n if (isStandby) {\n if (\n (role === \"mention\" || role === \"ping\") &&\n event.participant_id === selfId &&\n senderMatches(filter, senderType, senderId)\n ) return \"trigger\";\n // A whisper names its recipients explicitly, which is addressing the agent\n // just as directly as an @mention — more so, since only they can see it.\n // Mentioned events are only fired by scanning \"@token\" in the text, so a\n // whisper carries no mention and would otherwise be dropped: the room's\n // one form of directed communication, silently ignored.\n if (isWhisperTo(event, selfId) && senderMatches(filter, senderType, senderId)) return \"trigger\";\n return \"drop\";\n }\n\n // 4a. Active: ping → trigger. Pings are status checks — they trigger\n // immediate evaluation so the agent responds quickly with its status.\n if (role === \"ping\") return \"trigger\";\n\n // 4b. Active: @mention → drop. The MessageSent event already carries the\n // @mention text, so delivering a separate Mentioned event would be redundant.\n if (role === \"mention\") return \"drop\";\n\n // 5–6. Active: message → trigger if sender matches filter, content otherwise.\n if (role === \"message\") {\n return senderMatches(filter, senderType, senderId)\n ? \"trigger\"\n : \"content\";\n }\n\n // 7. Active: ambient event (join, leave, reaction, compaction) → buffer as context.\n if (role === \"ambient\") return \"content\";\n\n return \"drop\";\n}\n\n// ── StoopsEngagement (stateful, per-room modes) ──────────────────────────────\n\n/**\n * StoopsEngagement — the built-in engagement strategy.\n *\n * Implements the 7-mode system: 4 active modes (everyone/people/agents/fight)\n * and 3 standby modes that only wake on @mentions. Maintains per-room mode\n * state internally.\n *\n * @example\n * const engagement = new StoopsEngagement(\"people\");\n * engagement.setMode(\"room-1\", \"agents\");\n * engagement.classify(event, \"room-1\", selfId, \"human\", senderId);\n */\nexport class StoopsEngagement implements EngagementStrategy {\n private _modes = new Map<string, EngagementMode>();\n private _defaultMode: EngagementMode;\n\n constructor(defaultMode: EngagementMode) {\n this._defaultMode = defaultMode;\n }\n\n /** Get the engagement mode for a room. Falls back to the default mode. */\n getMode(roomId: string): EngagementMode {\n return this._modes.get(roomId) ?? this._defaultMode;\n }\n\n /** Set the engagement mode for a room. */\n setMode(roomId: string, mode: EngagementMode): void {\n this._modes.set(roomId, mode);\n }\n\n /** Called when a room is disconnected. Removes the room's mode so it doesn't linger. */\n onRoomDisconnected(roomId: string): void {\n this._modes.delete(roomId);\n }\n\n classify(\n event: RoomEvent,\n roomId: string,\n selfId: string,\n senderType: ParticipantType,\n senderId: string,\n ): EventDisposition {\n const mode = this._modes.get(roomId) ?? this._defaultMode;\n return classify(event, mode, selfId, senderType, senderId);\n }\n}\n\n// ── Standalone convenience function ──────────────────────────────────────────\n\n/**\n * Classify a room event for an agent with the given engagement mode.\n *\n * Pure function — no state, no side effects, no SDK dependency.\n * Uses the same classification logic as `StoopsEngagement` but takes all\n * parameters explicitly. Useful for one-off classification or testing.\n *\n * @param event — the event to classify\n * @param mode — the agent's current engagement mode for this room\n * @param selfId — the agent's own participant ID (to drop self-events)\n * @param senderType — type of the participant who caused the event\n * @param senderId — participant ID of the sender.\n * For `Mentioned` events, pass `event.message.sender_id`\n * (who wrote the mention), not `event.participant_id`\n * (who was mentioned).\n */\nexport function classifyEvent(\n event: RoomEvent,\n mode: EngagementMode,\n selfId: string,\n senderType: ParticipantType,\n senderId: string,\n): EventDisposition {\n return classify(event, mode, selfId, senderType, senderId);\n}\n","/**\n * RoomDataSource — abstraction over room data access.\n *\n * Allows tool handlers and EventProcessor to work against either a local\n * Room object or a remote HTTP API. This is the critical enabler for\n * client-side agent runtimes that connect to remote stoop servers.\n */\n\nimport type { Room } from \"../core/room.js\";\nimport type { Channel } from \"../core/channel.js\";\nimport type { RoomEvent } from \"../core/events.js\";\nimport type { EventCategory, Message, PaginatedResult, Participant } from \"../core/types.js\";\n\n/**\n * Uniform interface for reading/writing room data.\n *\n * Implemented by:\n * - `LocalRoomDataSource` — wraps a Room + Channel for in-process access\n * - `RemoteRoomDataSource` — wraps HTTP calls to a stoop server (Phase 5)\n */\nexport interface RoomDataSource {\n readonly roomId: string;\n /** The agent's own participant ID in this room. Used for whisper filtering. */\n readonly selfId: string;\n\n listParticipants(): Participant[];\n getMessage(id: string): Promise<Message | null>;\n searchMessages(query: string, limit?: number, cursor?: string | null): Promise<PaginatedResult<Message>>;\n getMessages(limit?: number, cursor?: string | null): Promise<PaginatedResult<Message>>;\n getEvents(category?: EventCategory | null, limit?: number, cursor?: string | null): Promise<PaginatedResult<RoomEvent>>;\n sendMessage(content: string, replyToId?: string, image?: { url: string; mimeType: string; sizeBytes: number } | null, attachments?: import(\"../core/types.js\").Attachment[], recipients?: string[]): Promise<Message>;\n emitEvent?(event: RoomEvent): Promise<void>;\n}\n\n/**\n * LocalRoomDataSource — wraps a Room + Channel for in-process access.\n *\n * Used by app-path consumers (ClaudeSession, LangGraphSession) and the\n * CLI server's EventProcessor. Transparent — all calls delegate directly\n * to the Room and Channel.\n */\nexport class LocalRoomDataSource implements RoomDataSource {\n constructor(\n private _room: Room,\n private _channel: Channel,\n ) {}\n\n get roomId(): string {\n return this._room.roomId;\n }\n\n get selfId(): string {\n return this._channel.participantId;\n }\n\n /** Direct access to the underlying Room (for backward compat / internal use). */\n get room(): Room {\n return this._room;\n }\n\n /** Direct access to the underlying Channel (for backward compat / internal use). */\n get channel(): Channel {\n return this._channel;\n }\n\n listParticipants(): Participant[] {\n return this._room.listParticipants();\n }\n\n async getMessage(id: string): Promise<Message | null> {\n return this._room.getMessage(id);\n }\n\n async searchMessages(query: string, limit = 10, cursor: string | null = null): Promise<PaginatedResult<Message>> {\n return this._room.searchMessages(query, limit, cursor);\n }\n\n async getMessages(limit = 30, cursor: string | null = null): Promise<PaginatedResult<Message>> {\n return this._room.listMessages(limit, cursor);\n }\n\n async getEvents(category: EventCategory | null = null, limit = 50, cursor: string | null = null): Promise<PaginatedResult<RoomEvent>> {\n return this._room.listEvents(category, limit, cursor);\n }\n\n async sendMessage(content: string, replyToId?: string, image?: { url: string; mimeType: string; sizeBytes: number } | null, attachments?: import(\"../core/types.js\").Attachment[], recipients?: string[]): Promise<Message> {\n return this._channel.sendMessage(content, replyToId, image ?? undefined, attachments, recipients);\n }\n\n async emitEvent(event: RoomEvent): Promise<void> {\n await this._channel.emit(event);\n }\n}\n","/**\n * RemoteRoomDataSource — HTTP-backed RoomDataSource.\n *\n * Implements the RoomDataSource interface by making HTTP calls to a stoop\n * server. Used by the client-side agent runtime when connecting to remote\n * apiary.\n *\n * Participant list is cached locally and updated by the agent runtime\n * when it processes ParticipantJoined/Left events from the SSE stream.\n */\n\nimport type { RoomEvent } from \"../core/events.js\";\nimport type { EventCategory, Message, PaginatedResult, Participant } from \"../core/types.js\";\nimport type { RoomDataSource } from \"./room-data-source.js\";\n\nexport class RemoteRoomDataSource implements RoomDataSource {\n private _participants: Participant[] = [];\n private _selfId = \"\";\n private _selfName = \"\";\n\n constructor(\n private _serverUrl: string,\n private _sessionToken: string,\n private _roomId: string,\n ) {}\n\n /** Set own identity for populating outgoing message stubs. */\n setSelf(id: string, name: string): void {\n this._selfId = id;\n this._selfName = name;\n }\n\n get roomId(): string {\n return this._roomId;\n }\n\n get selfId(): string {\n return this._selfId;\n }\n\n get serverUrl(): string {\n return this._serverUrl;\n }\n\n get sessionToken(): string {\n return this._sessionToken;\n }\n\n // ── Participant cache ─────────────────────────────────────────────────────\n\n /** Set the initial participant list (from join response). */\n setParticipants(participants: Participant[]): void {\n this._participants = [...participants];\n }\n\n /** Add a participant (on ParticipantJoined event). */\n addParticipant(participant: Participant): void {\n // Remove any existing entry with same ID first\n this._participants = this._participants.filter((p) => p.id !== participant.id);\n this._participants.push(participant);\n }\n\n /** Remove a participant (on ParticipantLeft event). */\n removeParticipant(participantId: string): void {\n this._participants = this._participants.filter((p) => p.id !== participantId);\n }\n\n listParticipants(): Participant[] {\n return [...this._participants];\n }\n\n // ── HTTP-backed data access ───────────────────────────────────────────────\n\n async getMessage(id: string): Promise<Message | null> {\n try {\n const res = await fetch(\n `${this._serverUrl}/message/${encodeURIComponent(id)}`,\n { headers: { Authorization: `Bearer ${this._sessionToken}` } },\n );\n if (!res.ok) return null;\n const data = (await res.json()) as { message: Message };\n return data.message;\n } catch {\n return null;\n }\n }\n\n async searchMessages(\n query: string,\n limit = 10,\n cursor: string | null = null,\n ): Promise<PaginatedResult<Message>> {\n const params = new URLSearchParams({ query, count: String(limit) });\n if (cursor) params.set(\"cursor\", cursor);\n\n try {\n const res = await fetch(`${this._serverUrl}/search?${params}`, {\n headers: { Authorization: `Bearer ${this._sessionToken}` },\n });\n if (!res.ok) return { items: [], has_more: false, next_cursor: null };\n return (await res.json()) as PaginatedResult<Message>;\n } catch {\n return { items: [], has_more: false, next_cursor: null };\n }\n }\n\n async getMessages(\n limit = 30,\n cursor: string | null = null,\n ): Promise<PaginatedResult<Message>> {\n const params = new URLSearchParams({ count: String(limit) });\n if (cursor) params.set(\"cursor\", cursor);\n\n try {\n const res = await fetch(`${this._serverUrl}/messages?${params}`, {\n headers: { Authorization: `Bearer ${this._sessionToken}` },\n });\n if (!res.ok) return { items: [], has_more: false, next_cursor: null };\n return (await res.json()) as PaginatedResult<Message>;\n } catch {\n return { items: [], has_more: false, next_cursor: null };\n }\n }\n\n async getEvents(\n category: EventCategory | null = null,\n limit = 50,\n cursor: string | null = null,\n ): Promise<PaginatedResult<RoomEvent>> {\n const params = new URLSearchParams({ count: String(limit) });\n if (category) params.set(\"category\", category);\n if (cursor) params.set(\"cursor\", cursor);\n\n try {\n const res = await fetch(`${this._serverUrl}/events/history?${params}`, {\n headers: { Authorization: `Bearer ${this._sessionToken}` },\n });\n if (!res.ok) return { items: [], has_more: false, next_cursor: null };\n return (await res.json()) as PaginatedResult<RoomEvent>;\n } catch {\n return { items: [], has_more: false, next_cursor: null };\n }\n }\n\n async sendMessage(\n content: string,\n replyToId?: string,\n image?: { url: string; mimeType: string; sizeBytes: number } | null,\n attachments?: import(\"../core/types.js\").Attachment[],\n recipients?: string[],\n ): Promise<Message> {\n const body: Record<string, unknown> = { content };\n if (replyToId) body.replyTo = replyToId;\n if (image) body.image = image;\n if (attachments?.length) body.attachments = attachments;\n if (recipients?.length) body.recipients = recipients;\n\n const res = await fetch(`${this._serverUrl}/message`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", Authorization: `Bearer ${this._sessionToken}` },\n body: JSON.stringify(body),\n });\n\n if (!res.ok) {\n const err = await res.text();\n throw new Error(`Failed to send message: ${err}`);\n }\n\n const data = (await res.json()) as { ok: boolean; messageId: string };\n\n // Return a stub — the full message will arrive via SSE\n return {\n id: data.messageId,\n room_id: this._roomId,\n sender_id: this._selfId,\n sender_name: this._selfName,\n content,\n timestamp: new Date(),\n } as Message;\n }\n\n async emitEvent(event: RoomEvent): Promise<void> {\n const res = await fetch(`${this._serverUrl}/event`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", Authorization: `Bearer ${this._sessionToken}` },\n body: JSON.stringify({ event }),\n });\n\n if (!res.ok) {\n // Best effort — don't throw for event emission failures\n }\n }\n}\n","/** EventMultiplexer — merges N channel async streams into one labeled stream. */\n\nimport type { RoomEvent } from \"../core/events.js\";\nimport type { Channel } from \"../core/channel.js\";\n\nexport interface LabeledEvent {\n roomId: string;\n roomName: string;\n event: RoomEvent;\n}\n\ninterface ChannelEntry {\n channel: Channel;\n roomName: string;\n abortController: AbortController;\n loopPromise: Promise<void>;\n}\n\n/**\n * Merges events from multiple channels into a single async iterable stream.\n * Each event is labeled with its source room's ID and name.\n *\n * Channels can be added/removed while the multiplexer is running.\n */\nexport class EventMultiplexer {\n private _queue: LabeledEvent[] = [];\n private _waiters: Array<{ resolve: (value: LabeledEvent) => void }> = [];\n private _channels = new Map<string, ChannelEntry>();\n private _closed = false;\n private _closeResolve: (() => void) | null = null;\n\n addChannel(roomId: string, roomName: string, channel: Channel): void {\n if (this._channels.has(roomId) || this._closed) return;\n const abortController = new AbortController();\n const loopPromise = this._listenLoop(roomId, roomName, channel, abortController.signal);\n this._channels.set(roomId, { channel, roomName, abortController, loopPromise });\n }\n\n removeChannel(roomId: string): void {\n const entry = this._channels.get(roomId);\n if (!entry) return;\n entry.abortController.abort();\n this._channels.delete(roomId);\n }\n\n close(): void {\n this._closed = true;\n for (const [, entry] of this._channels) {\n entry.abortController.abort();\n }\n this._channels.clear();\n // Wake any pending iterator so it returns done\n if (this._closeResolve) {\n this._closeResolve();\n this._closeResolve = null;\n }\n // Resolve all waiters with a sentinel — they'll see done: true on next call\n for (const waiter of this._waiters) {\n // Push a dummy event — the iterator will check _closed on next call\n waiter.resolve(null as unknown as LabeledEvent);\n }\n this._waiters = [];\n }\n\n private async _listenLoop(\n roomId: string,\n roomName: string,\n channel: Channel,\n signal: AbortSignal,\n ): Promise<void> {\n try {\n for await (const event of channel) {\n if (signal.aborted) break;\n this._push({ roomId, roomName, event });\n }\n } catch {\n // Channel disconnected — exit gracefully\n }\n }\n\n private _push(labeled: LabeledEvent): void {\n if (this._closed) return;\n if (this._waiters.length > 0) {\n const waiter = this._waiters.shift()!;\n waiter.resolve(labeled);\n } else {\n this._queue.push(labeled);\n }\n }\n\n [Symbol.asyncIterator](): AsyncIterator<LabeledEvent> {\n return {\n next: (): Promise<IteratorResult<LabeledEvent>> => {\n // Drain buffered events first\n if (this._queue.length > 0) {\n return Promise.resolve({ value: this._queue.shift()!, done: false });\n }\n\n if (this._closed) {\n return Promise.resolve({ value: undefined as unknown as LabeledEvent, done: true });\n }\n\n return new Promise<IteratorResult<LabeledEvent>>((resolve) => {\n this._waiters.push({\n resolve: (value) => {\n if (this._closed || value === null) {\n resolve({ value: undefined as unknown as LabeledEvent, done: true });\n } else {\n resolve({ value, done: false });\n }\n },\n });\n });\n },\n };\n }\n}\n","/**\n * RefMap — bidirectional map between short decimal refs and full message UUIDs.\n *\n * Why 4 digits: a ref like #3847 tokenizes to 1–2 tokens in most LLMs, while a\n * raw UUID (a1b2c3d4-e5f6-...) burns 8–12 tokens for no benefit. Since refs\n * appear on every message in transcripts and tool output, the savings compound.\n *\n * 10,000 unique refs per cycle is far more than an LLM context window can hold\n * (a 200k-token window fits ~2000 messages at most). The map is cleared on every\n * context compaction, so overflow is essentially impossible in practice. If it\n * does happen, the fallback to a UUID-derived hash still works — just less tidy.\n *\n * Uses a linear congruential generator (n * 6337 mod 10000) to produce\n * non-sequential refs — gcd(6337, 10000) = 1 guarantees a full cycle through\n * all 10,000 values before any collision.\n *\n * @example\n * const refs = new RefMap();\n * const ref = refs.assign(\"msg-uuid-abc\"); // \"3847\"\n * refs.assign(\"msg-uuid-abc\"); // \"3847\" (idempotent)\n * refs.resolve(\"3847\"); // \"msg-uuid-abc\"\n * refs.clear(); // reset on compaction\n */\nexport class RefMap {\n private _counter = Math.floor(Math.random() * 10000);\n private _refToId = new Map<string, string>();\n private _idToRef = new Map<string, string>();\n\n /** Assign a short ref to a message ID. Returns existing ref if already assigned. */\n assign(messageId: string): string {\n const existing = this._idToRef.get(messageId);\n if (existing) return existing;\n\n const ref = String((this._counter * 6337) % 10000).padStart(4, \"0\");\n this._counter++;\n\n if (this._refToId.has(ref)) {\n // Wrap-around (>10000 assignments without compaction — rare in practice).\n // Fall back to hex-derived ref, checking for collisions.\n const hex = messageId.replace(/-/g, \"\");\n let fallback: string | null = null;\n for (let i = 0; i <= hex.length - 4; i++) {\n const candidate = hex.slice(i, i + 4);\n if (!this._refToId.has(candidate)) {\n fallback = candidate;\n break;\n }\n }\n if (!fallback) fallback = messageId.slice(0, 8);\n this._refToId.set(fallback, messageId);\n this._idToRef.set(messageId, fallback);\n return fallback;\n }\n\n this._refToId.set(ref, messageId);\n this._idToRef.set(messageId, ref);\n return ref;\n }\n\n /** Resolve a ref back to the full message UUID. Returns undefined if unknown. */\n resolve(ref: string): string | undefined {\n return this._refToId.get(ref);\n }\n\n /** Clear all mappings and reset the counter. Called on context compaction. */\n clear(): void {\n this._refToId.clear();\n this._idToRef.clear();\n this._counter = Math.floor(Math.random() * 10000);\n }\n}\n","/** Pure tool handler logic */\n\nimport { readFile } from \"node:fs/promises\";\nimport type { Attachment, Message } from \"../core/types.js\";\nimport type { RoomConnection, RoomResolver, ToolHandlerOptions } from \"./types.js\";\nimport { messageRef, formatTimestamp } from \"./prompts.js\";\n\nexport type ToolContent =\n | { type: \"text\"; text: string }\n | { type: \"image\"; source: { type: \"base64\"; media_type: string; data: string } };\n\n/** Tool result shape consumed by both backends. */\nexport interface ToolResult {\n content: ToolContent[];\n}\n\n/** Helper: resolve room name or return an error tool result. */\nexport function resolveOrError(resolver: RoomResolver, roomName: string):\n | { error: true; result: ToolResult }\n | { error: false; conn: RoomConnection } {\n const conn = resolver.resolve(roomName);\n if (!conn) {\n return {\n error: true as const,\n result: { content: [{ type: \"text\" as const, text: `Unknown room \"${roomName}\".` }] },\n };\n }\n return { error: false as const, conn };\n}\n\nexport function textResult(text: string): ToolResult {\n return { content: [{ type: \"text\" as const, text }] };\n}\n\n/** Format a single message as a transcript line (shared by catch_up and search tools). */\nexport async function formatMsgLine(\n msg: Message,\n conn: RoomConnection,\n mkRef: (id: string) => string,\n): Promise<string> {\n const ts = formatTimestamp(new Date(msg.timestamp));\n const ref = mkRef(msg.id);\n const imageNote = msg.image_url ? ` [[img:${msg.image_url}]]` : \"\";\n const attachmentNotes = (msg.attachments ?? []).map((a) => {\n if (a.type === \"path\") return ` [attachment: ${a.name} (${a.mime_type}, path: ${a.path} — same-machine only)]`;\n return ` [attachment: ${a.name} (${a.mime_type}, ${a.size}B, url: ${a.url})]`;\n }).join(\"\");\n const whisperNote = (msg.recipients?.length ?? 0) > 0\n ? ` [whisper → ${conn.dataSource.listParticipants().filter(p => msg.recipients!.includes(p.id)).map(p => p.name).join(\", \")}]`\n : \"\";\n let line = `[${ts}] ${ref} ${msg.sender_name}: ${msg.content}${whisperNote}${imageNote}${attachmentNotes}`;\n if (msg.reply_to_id) {\n const target = await conn.dataSource.getMessage(msg.reply_to_id);\n if (target) {\n const targetRef = mkRef(target.id);\n line = `[${ts}] ${ref} ${msg.sender_name} (→ ${targetRef} ${target.sender_name}): ${msg.content}${imageNote}${attachmentNotes}`;\n }\n }\n return line;\n}\n\n/** Try to read a path-type image attachment and return a base64 content block. */\nasync function tryReadImageAttachment(att: Attachment & { type: \"path\" }): Promise<ToolContent | null> {\n if (!att.mime_type.startsWith(\"image/\")) return null;\n try {\n const bytes = await readFile(att.path);\n return {\n type: \"image\",\n source: { type: \"base64\", media_type: att.mime_type as `image/${string}`, data: bytes.toString(\"base64\") },\n };\n } catch {\n return null;\n }\n}\n\n/**\n * Build catch-up event lines for a room — shared by the catch_up MCP tool and\n * the runtime's full_catch_up injection. Returns formatted transcript lines for\n * all unseen events (oldest first), marking them as seen, plus any image content\n * blocks for path-type image attachments.\n *\n * Upload-type attachments are included as text (URL) only — auto-fetch is a\n * future improvement once there's an HTTP client available in the tool layer.\n */\nexport async function buildCatchUpLines(\n conn: RoomConnection,\n options: Pick<ToolHandlerOptions, \"isEventSeen\" | \"markEventsSeen\" | \"assignRef\">,\n): Promise<{ lines: string[]; imageBlocks: ToolContent[] }> {\n const result = await conn.dataSource.getEvents(null, 50, null);\n const chronological = [...result.items].reverse();\n\n let startIdx = chronological.length;\n for (let i = 0; i < chronological.length; i++) {\n if (!options.isEventSeen?.(chronological[i].id)) {\n startIdx = i;\n break;\n }\n }\n const unseen = chronological.slice(startIdx);\n\n const lines: string[] = [];\n const imageBlocks: ToolContent[] = [];\n const seenIds: string[] = [];\n const mkRef = (id: string) => `#${options.assignRef?.(id) ?? messageRef(id)}`;\n\n // Undefined selfId → no whispers shown (safe default: fail closed, not open).\n const selfId = conn.dataSource.selfId || conn.channel?.participantId;\n\n for (const event of unseen) {\n seenIds.push(event.id);\n const ts = formatTimestamp(new Date(event.timestamp));\n\n if (event.type === \"MessageSent\") {\n const msg = event.message;\n // Filter whispers: only show if this agent is the sender or a recipient.\n if ((msg.recipients?.length ?? 0) > 0 && msg.sender_id !== selfId && (!selfId || !msg.recipients!.includes(selfId))) {\n continue;\n }\n lines.push(await formatMsgLine(event.message, conn, mkRef));\n // Collect path-type image attachments as content blocks\n for (const att of event.message.attachments ?? []) {\n if (att.type === \"path\") {\n const block = await tryReadImageAttachment(att);\n if (block) imageBlocks.push(block);\n }\n }\n } else if (event.type === \"ParticipantJoined\") {\n const participant = conn.dataSource.listParticipants().find((p) => p.id === event.participant_id);\n const name = participant?.name ?? event.participant_id;\n lines.push(`[${ts}] + ${name} joined`);\n } else if (event.type === \"ParticipantLeft\") {\n const name = event.participant?.name ?? event.participant_id;\n lines.push(`[${ts}] - ${name} left`);\n } else if (event.type === \"ReactionAdded\") {\n const participant = conn.dataSource.listParticipants().find((p) => p.id === event.participant_id);\n const name = participant?.name ?? event.participant_id;\n const target = await conn.dataSource.getMessage(event.message_id);\n const targetRef = target ? ` to ${mkRef(target.id)}` : \"\";\n lines.push(`[${ts}] ${name} reacted ${event.emoji}${targetRef}`);\n }\n // Other event types (ToolUse, Activity, Mentioned, etc.) are skipped\n }\n\n if (seenIds.length > 0) options.markEventsSeen?.(seenIds);\n return { lines, imageBlocks };\n}\n\n// ── Tool handler functions ────────────────────────────────────────────────────\n\nexport async function handleCatchUp(\n resolver: RoomResolver,\n args: { room: string },\n options: ToolHandlerOptions,\n): Promise<ToolResult> {\n const r = resolveOrError(resolver, args.room);\n if (r.error) return r.result;\n const { lines, imageBlocks } = await buildCatchUpLines(r.conn, options);\n const out: string[] = [`Catching up on [${args.room}]:`];\n if (lines.length > 0) {\n out.push(\"\", ...lines);\n } else {\n out.push(\"\", \"(nothing new)\");\n }\n const content: ToolContent[] = [{ type: \"text\" as const, text: out.join(\"\\n\") }];\n content.push(...imageBlocks);\n return { content };\n}\n\nexport async function handleSearchByText(\n resolver: RoomResolver,\n args: { room: string; query: string; count?: number; cursor?: string },\n options: ToolHandlerOptions,\n): Promise<ToolResult> {\n const r = resolveOrError(resolver, args.room);\n if (r.error) return r.result;\n const { conn } = r;\n const count = args.count ?? 3;\n const mkRef = (id: string) => `#${options.assignRef?.(id) ?? messageRef(id)}`;\n\n // Get up to 50 matches to know the total; slice to count for display\n const searchResult = await conn.dataSource.searchMessages(args.query, 50, args.cursor ?? null);\n const totalVisible = searchResult.items.length;\n\n if (totalVisible === 0) {\n return textResult(`No messages found in [${args.room}] matching \"${args.query}\".`);\n }\n\n const toShow = searchResult.items.slice(0, count); // newest-first\n\n // Load recent messages for context (before/after lookup)\n const recentResult = await conn.dataSource.getMessages(100, null);\n const recentChron = [...recentResult.items].reverse(); // chronological\n const msgIdxMap = new Map<string, number>();\n recentChron.forEach((m, i) => msgIdxMap.set(m.id, i));\n\n // Process clusters oldest-first (reverse the newest-first results)\n const clusters: string[][] = [];\n let newerCount: number | null = null;\n\n for (const match of [...toShow].reverse()) {\n const cluster: string[] = [];\n const matchIdx = msgIdxMap.get(match.id);\n\n if (matchIdx !== undefined) {\n // Before context\n if (matchIdx > 0) {\n cluster.push(await formatMsgLine(recentChron[matchIdx - 1], conn, mkRef));\n }\n // Match line\n cluster.push((await formatMsgLine(match, conn, mkRef)) + \" ←\");\n // After context\n if (matchIdx < recentChron.length - 1) {\n cluster.push(await formatMsgLine(recentChron[matchIdx + 1], conn, mkRef));\n }\n // Track newer count based on the newest match (first in toShow = newest)\n if (newerCount === null && match.id === toShow[0].id) {\n newerCount = recentChron.length - matchIdx - 1;\n }\n } else {\n // Match is older than the context window — show match only\n cluster.push((await formatMsgLine(match, conn, mkRef)) + \" ←\");\n }\n\n clusters.push(cluster);\n }\n\n // Build output\n const shownCount = toShow.length;\n const totalNote = searchResult.has_more\n ? `showing ${shownCount} of 50+`\n : `${shownCount} of ${totalVisible}`;\n const out: string[] = [`Search results in [${args.room}] for \"${args.query}\" (${totalNote} matches):`, \"\"];\n\n for (let i = 0; i < clusters.length; i++) {\n for (const line of clusters[i]) {\n out.push(` ${line}`);\n }\n if (i < clusters.length - 1) out.push(\"\");\n }\n\n if (newerCount !== null && newerCount > 0) {\n out.push(\"\", `${newerCount} newer message${newerCount === 1 ? \"\" : \"s\"} in this room.`);\n }\n if (searchResult.has_more && searchResult.next_cursor) {\n out.push(`(cursor: \"${searchResult.next_cursor}\" for next ${count} matches)`);\n }\n\n return textResult(out.join(\"\\n\"));\n}\n\nexport async function handleSearchByMessage(\n resolver: RoomResolver,\n args: { room: string; ref: string; direction?: \"before\" | \"after\"; count?: number },\n options: ToolHandlerOptions,\n): Promise<ToolResult> {\n const r = resolveOrError(resolver, args.room);\n if (r.error) return r.result;\n const { conn } = r;\n const direction = args.direction ?? \"before\";\n const count = args.count ?? 10;\n const mkRef = (id: string) => `#${options.assignRef?.(id) ?? messageRef(id)}`;\n\n // Resolve ref to message ID\n const rawRef = args.ref.startsWith(\"#\") ? args.ref.slice(1) : args.ref;\n const anchorId = options.resolveRef?.(rawRef) ?? rawRef;\n const anchor = await conn.dataSource.getMessage(anchorId);\n if (!anchor) return textResult(`Message ${args.ref} not found.`);\n\n // Load recent messages for \"after\" direction and \"newer count\"\n const recentResult = await conn.dataSource.getMessages(100, null);\n const recentChron = [...recentResult.items].reverse(); // chronological\n const anchorIdx = recentChron.findIndex((m) => m.id === anchor.id);\n\n let displayMessages: Message[];\n let newerCount: number;\n\n if (direction === \"before\") {\n // Get count messages before anchor from storage (works for any age)\n const beforeResult = await conn.dataSource.getMessages(count, anchor.id);\n const beforeMessages = [...beforeResult.items].reverse(); // chronological\n displayMessages = [...beforeMessages, anchor];\n newerCount = anchorIdx >= 0 ? recentChron.length - anchorIdx - 1 : 100; // 100+ if too old\n } else {\n // \"after\" — use recent window\n if (anchorIdx >= 0) {\n const afterMessages = recentChron.slice(anchorIdx + 1, anchorIdx + 1 + count);\n displayMessages = [anchor, ...afterMessages];\n newerCount = recentChron.length - anchorIdx - 1 - afterMessages.length;\n } else {\n // Anchor not in recent 100 — can't scroll forward, too many newer messages\n displayMessages = [anchor];\n newerCount = 100;\n }\n }\n\n const anchorRef = mkRef(anchor.id);\n const lines: string[] = [`Context in [${args.room}] around ${anchorRef}:`, \"\"];\n\n for (const msg of displayMessages) {\n const line = await formatMsgLine(msg, conn, mkRef);\n const isAnchor = msg.id === anchor.id;\n lines.push(` ${line}${isAnchor ? \" ←\" : \"\"}`);\n }\n\n if (newerCount > 0) {\n const countLabel = newerCount >= 100 ? \"100+\" : String(newerCount);\n lines.push(\"\", `${countLabel} newer message${newerCount === 1 ? \"\" : \"s\"} in this room.`);\n }\n\n return textResult(lines.join(\"\\n\"));\n}\n\nexport async function handleSendMessage(\n resolver: RoomResolver,\n args: {\n room: string;\n content: string;\n reply_to_id?: string;\n image_url?: string;\n image_mime_type?: string;\n image_size_bytes?: number;\n attachments?: Attachment[];\n to?: string[];\n },\n options: ToolHandlerOptions,\n): Promise<ToolResult> {\n const r = resolveOrError(resolver, args.room);\n if (r.error) return r.result;\n\n const image = args.image_url\n ? {\n url: args.image_url,\n mimeType: args.image_mime_type ?? \"image/*\",\n sizeBytes: args.image_size_bytes ?? 0,\n }\n : null;\n\n // Resolve ref to full UUID — accepts both \"#3847\" and \"3847\"\n let replyToId = args.reply_to_id;\n if (replyToId) {\n const rawRef = replyToId.startsWith(\"#\") ? replyToId.slice(1) : replyToId;\n replyToId = options.resolveRef?.(rawRef) ?? replyToId;\n }\n\n // Resolve recipient names to IDs for whisper delivery.\n let recipientIds: string[] | undefined;\n if (args.to && args.to.length > 0) {\n const participants = r.conn.dataSource.listParticipants();\n recipientIds = [];\n for (const name of args.to) {\n const matches = participants.filter((p) => p.name === name);\n if (matches.length === 0) return textResult(`Unknown participant \"${name}\". Known: ${participants.map((p) => p.name).join(\", \")}.`);\n if (matches.length > 1) return textResult(`Ambiguous name \"${name}\" — multiple participants match. Use a more specific name.`);\n recipientIds.push(matches[0].id);\n }\n }\n\n const message = await r.conn.dataSource.sendMessage(args.content, replyToId, image, args.attachments, recipientIds);\n\n const ref = options.assignRef?.(message.id) ?? messageRef(message.id);\n return textResult(`Message sent #${ref}.`);\n}\n","/** Room connection registry — manages live room connections for an agent. */\n\nimport type { RoomConnection } from \"./types.js\";\n\nexport interface InternalConnection extends RoomConnection {\n identifier?: string;\n}\n\nexport class ConnectionRegistry {\n private _connections = new Map<string, InternalConnection>();\n private _nameToId = new Map<string, string>();\n private _identifierToId = new Map<string, string>();\n private _lastMessages = new Map<string, string>();\n\n add(roomId: string, conn: InternalConnection): void {\n this._connections.set(roomId, conn);\n this._nameToId.set(conn.name, roomId);\n if (conn.identifier) this._identifierToId.set(conn.identifier, roomId);\n }\n\n remove(roomId: string): InternalConnection | undefined {\n const conn = this._connections.get(roomId);\n if (!conn) return undefined;\n this._nameToId.delete(conn.name);\n if (conn.identifier) this._identifierToId.delete(conn.identifier);\n this._connections.delete(roomId);\n this._lastMessages.delete(roomId);\n return conn;\n }\n\n get(roomId: string): InternalConnection | undefined {\n return this._connections.get(roomId);\n }\n\n has(roomId: string): boolean {\n return this._connections.has(roomId);\n }\n\n resolve(roomName: string): RoomConnection | null {\n const roomId = this._nameToId.get(roomName);\n if (roomId) return this._connections.get(roomId) ?? null;\n const idFromIdentifier = this._identifierToId.get(roomName);\n if (idFromIdentifier) return this._connections.get(idFromIdentifier) ?? null;\n return this._connections.get(roomName) ?? null;\n }\n\n listAll(getModeForRoom: (roomId: string) => string): Array<{\n name: string;\n roomId: string;\n identifier?: string;\n mode: string;\n participantCount: number;\n lastMessage?: string;\n }> {\n return [...this._connections.entries()].map(([roomId, conn]) => ({\n name: conn.name,\n roomId,\n ...(conn.identifier ? { identifier: conn.identifier } : {}),\n mode: getModeForRoom(roomId),\n participantCount: conn.dataSource.listParticipants().length,\n ...(this._lastMessages.has(roomId) ? { lastMessage: this._lastMessages.get(roomId) } : {}),\n }));\n }\n\n setLastMessage(roomId: string, text: string): void {\n this._lastMessages.set(roomId, text);\n }\n\n entries(): IterableIterator<[string, InternalConnection]> {\n return this._connections.entries();\n }\n\n get size(): number {\n return this._connections.size;\n }\n\n clear(): void {\n this._connections.clear();\n this._nameToId.clear();\n this._identifierToId.clear();\n this._lastMessages.clear();\n }\n\n values(): IterableIterator<InternalConnection> {\n return this._connections.values();\n }\n}\n","/** Per-room content buffer — accumulates events between triggers. */\n\nimport type { RoomEvent } from \"../core/events.js\";\n\nexport interface BufferedContent {\n event: RoomEvent;\n roomId: string;\n roomName: string;\n}\n\nexport class ContentBuffer {\n private _buffer = new Map<string, BufferedContent[]>();\n\n push(roomId: string, item: BufferedContent): void {\n const buf = this._buffer.get(roomId) ?? [];\n buf.push(item);\n this._buffer.set(roomId, buf);\n }\n\n flush(roomId: string): BufferedContent[] {\n const items = this._buffer.get(roomId) ?? [];\n this._buffer.delete(roomId);\n return items;\n }\n\n delete(roomId: string): void {\n this._buffer.delete(roomId);\n }\n\n clear(): void {\n this._buffer.clear();\n }\n}\n","/**\n * Deduplication and delivery tracking for event IDs.\n *\n * Both `_processedIds` and `_deliveredIds` are bounded by FIFO halving so a\n * long-running agent between compactions can't bloat memory (and, transitively,\n * its own LLM context if it re-reads tracker state).\n *\n * Halving keeps the newer half — older IDs are dropped. Re-delivery of a\n * dropped ID would require the same event to re-appear from the source, which\n * the SSE multiplexer does not do.\n */\n\nconst PROCESSED_CAP = 500;\nconst DELIVERED_CAP = 5000;\n\nexport class EventTracker {\n private _processedIds = new Set<string>();\n private _deliveredIds = new Set<string>();\n\n /** Returns true if this event was already processed (and adds it if not). */\n isDuplicate(id: string): boolean {\n if (this._processedIds.has(id)) return true;\n this._processedIds.add(id);\n if (this._processedIds.size > PROCESSED_CAP) {\n this._processedIds = halve(this._processedIds);\n }\n return false;\n }\n\n isDelivered(id: string): boolean {\n return this._deliveredIds.has(id);\n }\n\n markDelivered(id: string): void {\n this._deliveredIds.add(id);\n if (this._deliveredIds.size > DELIVERED_CAP) {\n this._deliveredIds = halve(this._deliveredIds);\n }\n }\n\n markManyDelivered(ids: string[]): void {\n for (const id of ids) {\n this._deliveredIds.add(id);\n this._processedIds.add(id);\n }\n if (this._deliveredIds.size > DELIVERED_CAP) this._deliveredIds = halve(this._deliveredIds);\n if (this._processedIds.size > PROCESSED_CAP) this._processedIds = halve(this._processedIds);\n }\n\n clearDelivered(): void {\n this._deliveredIds.clear();\n }\n\n clearAll(): void {\n this._processedIds.clear();\n this._deliveredIds.clear();\n }\n}\n\nfunction halve(set: Set<string>): Set<string> {\n const arr = [...set];\n return new Set(arr.slice(arr.length >> 1));\n}\n","/**\n * EventProcessor — core event loop for apiary agents.\n *\n * Owns: engagement classification, content buffering, event formatting,\n * ref map, room connections, mode management. Does NOT own: LLM sessions,\n * MCP servers, compaction hooks, stats tracking.\n *\n * Delivery is pluggable — pass a `deliver` callback to `run()`.\n * The callback receives formatted ContentPart[] and does whatever the\n * consumer needs (Claude SDK query, LangGraph injection, tmux send-keys).\n */\n\nimport { EventCategory, type Participant, type ParticipantType } from \"../core/types.js\";\nimport {\n createEvent,\n type RoomEvent,\n type ActivityEvent,\n type MentionedEvent,\n type ToolUseEvent,\n} from \"../core/events.js\";\nimport type { Room } from \"../core/room.js\";\nimport { type EngagementMode, type EventDisposition, type EngagementStrategy, StoopsEngagement } from \"./engagement.js\";\nimport type { ContentPart, RoomConnection, RoomResolver } from \"./types.js\";\nimport { LocalRoomDataSource } from \"./room-data-source.js\";\nimport type { RoomDataSource } from \"./room-data-source.js\";\nimport { RemoteRoomDataSource } from \"./remote-room-data-source.js\";\nimport { formatEvent } from \"./prompts.js\";\nimport { buildCatchUpLines } from \"./tool-handlers.js\";\nimport { EventMultiplexer, type LabeledEvent } from \"./multiplexer.js\";\nimport { RefMap } from \"./ref-map.js\";\nimport { ConnectionRegistry, type InternalConnection } from \"./connection-registry.js\";\nimport { ContentBuffer } from \"./content-buffer.js\";\nimport { EventTracker } from \"./event-tracker.js\";\n\n// ── Options ─────────────────────────────────────────────────────────────────────\n\nexport interface EventProcessorOptions {\n /** Engagement mode when no per-room override is set. */\n defaultMode?: EngagementMode;\n /** Custom engagement strategy. Defaults to StoopsEngagement. */\n engagement?: EngagementStrategy;\n /** The agent's own stable identifier slug (e.g. \"my-agent\"). */\n selfIdentifier?: string;\n /** Called when engagement mode changes for a room. */\n onModeChange?: (roomId: string, roomName: string, mode: EngagementMode) => void;\n /** Called before each delivery. Return false to skip. */\n preQuery?: () => Promise<boolean>;\n}\n\n// ── Helpers ─────────────────────────────────────────────────────────────────────\n\nfunction mergeParts(arrays: ContentPart[][]): ContentPart[] {\n const result: ContentPart[] = [];\n for (let i = 0; i < arrays.length; i++) {\n if (i > 0) result.push({ type: \"text\", text: \"\\n\" });\n result.push(...arrays[i]);\n }\n return result;\n}\n\n// ── EventProcessor ──────────────────────────────────────────────────────────────\n\n/**\n * What an agent runtime observed on its CLI's screen, as reported to the room.\n *\n * Deliberately coarser than each bridge's internal TUI states: the room only\n * needs to distinguish \"getting on with it\" from \"stuck until a human acts\",\n * because those look identical from the outside and only one of them resolves\n * by waiting.\n */\nexport type AgentActivityState = \"idle\" | \"working\" | \"blocked\";\n\n/**\n * Re-report an unchanged agent state at least this often.\n *\n * Must stay comfortably under the room server's state TTL, or a settled agent\n * ages out and looks like one that reports nothing.\n */\nexport const ACTIVITY_REPORT_MIN_MS = 10_000;\n\n/**\n * Should the runtime push its activity to the room now?\n *\n * Yes on any change, and yes when the last report has gone stale even if\n * nothing changed. Reporting only on change looked right and was wrong: the\n * room ages reported state out so a dead runtime cannot pin a stale value, so\n * a settled agent stopped reporting, aged out, and read as \"reports no state\n * at all\" — observed end-to-end roughly 15s after an agent went idle.\n */\nexport function shouldReportActivity(opts: {\n label: string | null;\n state: AgentActivityState | undefined;\n lastLabel: string | null;\n lastState: AgentActivityState | undefined;\n lastReportAt: number;\n now: number;\n minIntervalMs?: number;\n}): boolean {\n if (opts.label !== opts.lastLabel || opts.state !== opts.lastState) return true;\n return opts.now - opts.lastReportAt > (opts.minIntervalMs ?? ACTIVITY_REPORT_MIN_MS);\n}\n\nexport class EventProcessor implements RoomResolver {\n private _participantId: string;\n private _participantName: string;\n private _options: EventProcessorOptions;\n private _engagement: EngagementStrategy;\n\n private _deliver: ((parts: ContentPart[]) => Promise<void>) | null = null;\n private _multiplexer = new EventMultiplexer();\n private _registry = new ConnectionRegistry();\n private _buffer = new ContentBuffer();\n private _tracker = new EventTracker();\n private _processing = false;\n private _eventQueue: LabeledEvent[] = [];\n private _stopped = false;\n private _currentContextRoomId: string | null = null;\n private _log: RoomEvent[] = [];\n private _refMap = new RefMap();\n private _injectBuffer: ContentPart[][] = [];\n /** Per-room participant IDs (for multi-server CLI agents where each server assigns a different ID). */\n private _roomSelfIds = new Map<string, string>();\n\n constructor(\n participantId: string,\n participantName: string,\n options: EventProcessorOptions = {},\n ) {\n this._participantId = participantId;\n this._participantName = participantName;\n this._options = options;\n this._engagement = options.engagement\n ?? new StoopsEngagement(options.defaultMode ?? \"everyone\");\n }\n\n // ── Public accessors ────────────────────────────────────────────────────────\n\n get participantId(): string { return this._participantId; }\n set participantId(id: string) { this._participantId = id; }\n get participantName(): string { return this._participantName; }\n get currentContextRoomId(): string | null { return this._currentContextRoomId; }\n\n /** Set a room-specific participant ID (for multi-server CLI agents). */\n setRoomParticipantId(roomId: string, participantId: string): void {\n this._roomSelfIds.set(roomId, participantId);\n }\n\n /** Get the effective selfId for a room — room-specific if set, otherwise the global one. */\n getSelfIdForRoom(roomId: string): string {\n return this._roomSelfIds.get(roomId) ?? this._participantId;\n }\n\n // ── Ref map (consumer calls these for MCP tools) ────────────────────────────\n\n assignRef(messageId: string): string {\n return this._refMap.assign(messageId);\n }\n\n resolveRef(ref: string): string | undefined {\n return this._refMap.resolve(ref);\n }\n\n // ── Seen-event cache (consumer calls these for catch_up MCP tool) ───────────\n\n isEventSeen(eventId: string): boolean {\n return this._tracker.isDelivered(eventId);\n }\n\n markEventsSeen(eventIds: string[]): void {\n this._tracker.markManyDelivered(eventIds);\n }\n\n // ── Inject buffer (LangGraph mid-loop event injection) ──────────────────────\n\n drainInjectBuffer(): ContentPart[][] | null {\n if (this._injectBuffer.length === 0) return null;\n const drained = this._injectBuffer;\n this._injectBuffer = [];\n return drained;\n }\n\n // ── Consumer hooks (called by consumer during/after delivery) ────────────────\n\n /**\n * Called by the consumer when context was compacted.\n * Clears seen-event cache and ref map so catch_up returns full history.\n */\n onContextCompacted(): void {\n this._tracker.clearDelivered();\n this._refMap.clear();\n }\n\n /**\n * Called by the consumer when a tool call starts or completes.\n * Routes ToolUseEvent to the room that triggered the current evaluation.\n */\n emitToolUse(toolName: string, status: \"started\" | \"completed\"): void {\n if (this._currentContextRoomId) {\n const conn = this._registry.get(this._currentContextRoomId);\n if (conn) {\n const event = createEvent<ToolUseEvent>({\n type: \"ToolUse\",\n category: \"ACTIVITY\",\n room_id: this._currentContextRoomId,\n participant_id: this._participantId,\n tool_name: toolName,\n status,\n });\n const emitter = conn.dataSource.emitEvent\n ? (e: RoomEvent) => conn.dataSource.emitEvent!(e)\n : conn.channel\n ? (e: RoomEvent) => conn.channel!.emit(e)\n : null;\n if (!emitter) return;\n emitter(event).catch(() => {});\n }\n }\n }\n\n // ── RoomResolver implementation ─────────────────────────────────────────────\n\n resolve(roomName: string): RoomConnection | null {\n return this._registry.resolve(roomName);\n }\n\n listAll(): Array<{\n name: string;\n roomId: string;\n identifier?: string;\n mode: string;\n participantCount: number;\n lastMessage?: string;\n }> {\n return this._registry.listAll((roomId) => this.getModeForRoom(roomId));\n }\n\n /**\n * Push a live status label (\"Sautéed for 12s\", \"Compacting…\", null=idle)\n * to every connected REMOTE room (i.e. CLI-path agents talking to an\n * apiary HTTP server). Local app-path connections are skipped — they don't\n * have a /activity HTTP endpoint to hit.\n *\n * Called from the CLI runtime's tmux poll loop. Best-effort: failures are\n * swallowed so a flaky network never crashes the agent.\n */\n async broadcastActivity(label: string | null, state?: AgentActivityState): Promise<void> {\n for (const conn of this._registry.values()) {\n const ds = conn.dataSource;\n if (!(ds instanceof RemoteRoomDataSource)) continue;\n try {\n await fetch(`${ds.serverUrl}/activity`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${ds.sessionToken}`,\n },\n body: JSON.stringify(state === undefined ? { label } : { label, state }),\n });\n } catch { /* best-effort */ }\n }\n }\n\n /**\n * Push token usage + last-turn context size to every connected REMOTE\n * room so the room TUI can show per-agent context size and roll up a\n * room total. Mirrors broadcastActivity — same best-effort semantics.\n */\n async broadcastMetrics(metrics: {\n input_tokens: number;\n output_tokens: number;\n cache_read_tokens: number;\n cache_create_tokens: number;\n last_ctx_tokens: number;\n model: string;\n }): Promise<void> {\n for (const conn of this._registry.values()) {\n const ds = conn.dataSource;\n if (!(ds instanceof RemoteRoomDataSource)) continue;\n try {\n await fetch(`${ds.serverUrl}/metrics`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${ds.sessionToken}`,\n },\n body: JSON.stringify(metrics),\n });\n } catch { /* best-effort */ }\n }\n }\n\n // ── Room connection management ──────────────────────────────────────────────\n\n async connectRoom(\n room: Room,\n roomName: string,\n mode?: EngagementMode,\n identifier?: string,\n ): Promise<void> {\n if (this._registry.has(room.roomId)) return;\n\n const channel = await room.connect(this._participantId, this._participantName, {\n type: \"agent\",\n identifier: this._options.selfIdentifier,\n subscribe: new Set([\n EventCategory.MESSAGE,\n EventCategory.PRESENCE,\n EventCategory.ACTIVITY,\n EventCategory.MENTION,\n ]),\n silent: true,\n });\n\n const dataSource = new LocalRoomDataSource(room, channel);\n const conn: InternalConnection = { dataSource, room, channel, name: roomName, identifier };\n this._registry.add(room.roomId, conn);\n if (mode) this._engagement.setMode?.(room.roomId, mode);\n\n // Emit initial mode\n const initialMode = this.getModeForRoom(room.roomId);\n channel.emit(createEvent<ActivityEvent>({\n type: \"Activity\",\n category: \"ACTIVITY\",\n room_id: room.roomId,\n participant_id: this._participantId,\n action: \"mode_changed\",\n detail: { mode: initialMode },\n })).catch(() => {});\n\n this._multiplexer.addChannel(room.roomId, roomName, channel);\n }\n\n /**\n * Connect a remote room via a RoomDataSource (no local Room/Channel).\n *\n * Used by the client-side agent runtime to register rooms that are\n * accessed over HTTP. Events come from an external source (SSE multiplexer)\n * passed to run(), not from the internal EventMultiplexer.\n */\n connectRemoteRoom(\n dataSource: RoomDataSource,\n roomName: string,\n mode?: EngagementMode,\n identifier?: string,\n ): void {\n if (this._registry.has(dataSource.roomId)) return;\n\n const conn: InternalConnection = {\n dataSource,\n name: roomName,\n identifier,\n };\n this._registry.add(dataSource.roomId, conn);\n if (mode) this._engagement.setMode?.(dataSource.roomId, mode);\n }\n\n /** Disconnect a remote room (by room ID). */\n disconnectRemoteRoom(roomId: string): void {\n if (!this._registry.has(roomId)) return;\n this._registry.remove(roomId);\n this._engagement.onRoomDisconnected?.(roomId);\n this._buffer.delete(roomId);\n this._roomSelfIds.delete(roomId);\n }\n\n async disconnectRoom(roomId: string): Promise<void> {\n const conn = this._registry.get(roomId);\n if (!conn) return;\n\n this._multiplexer.removeChannel(roomId);\n await conn.channel?.disconnect(true);\n this._registry.remove(roomId);\n this._engagement.onRoomDisconnected?.(roomId);\n this._buffer.delete(roomId);\n this._roomSelfIds.delete(roomId);\n }\n\n // ── Mode management ─────────────────────────────────────────────────────────\n\n getModeForRoom(roomId: string): EngagementMode {\n return this._engagement.getMode?.(roomId) ?? \"everyone\";\n }\n\n setModeForRoom(roomId: string, mode: EngagementMode, notifyAgent = true): void {\n this._engagement.setMode?.(roomId, mode);\n const conn = this._registry.get(roomId);\n if (conn) {\n conn.channel?.emit(createEvent<ActivityEvent>({\n type: \"Activity\",\n category: \"ACTIVITY\",\n room_id: roomId,\n participant_id: this._participantId,\n action: \"mode_changed\",\n detail: { mode },\n }))?.catch(() => {});\n this._options.onModeChange?.(roomId, conn.name, mode);\n }\n }\n\n // ── Log ─────────────────────────────────────────────────────────────────────\n\n getLog(): RoomEvent[] {\n return this._log;\n }\n\n // ── Main event loop ─────────────────────────────────────────────────────────\n\n /**\n * Start the event loop.\n *\n * @param deliver — callback that receives formatted content and delivers\n * it to the agent. This is the consumer's responsibility. The function\n * should block until delivery is complete (e.g., LLM evaluation finished).\n * @param eventSource — optional external event source (e.g. SseMultiplexer).\n * If provided, events are consumed from this instead of the internal\n * EventMultiplexer. Used by the client-side agent runtime.\n * @param initialParts — optional content to deliver before entering the\n * event loop. Used by the runtime to deliver auto-join confirmation.\n */\n async run(\n deliver: (parts: ContentPart[]) => Promise<void>,\n eventSource?: AsyncIterable<LabeledEvent>,\n initialParts?: ContentPart[],\n ): Promise<void> {\n this._deliver = deliver;\n\n // Deliver initial content if provided (e.g. auto-join confirmation)\n if (initialParts && initialParts.length > 0) {\n await this._processRaw(\n initialParts,\n this._registry.values().next().value?.dataSource.roomId ?? null,\n );\n }\n\n // Main event loop — use external source if provided, otherwise internal multiplexer\n const source = eventSource ?? this._multiplexer;\n for await (const labeled of source) {\n if (this._stopped) break;\n await this._handleLabeledEvent(labeled);\n }\n }\n\n async stop(): Promise<void> {\n this._stopped = true;\n this._multiplexer.close();\n await Promise.allSettled(\n [...this._registry.values()]\n .filter((conn) => conn.channel)\n .map((conn) => conn.channel!.disconnect(true)),\n );\n this._registry.clear();\n this._buffer.clear();\n this._tracker.clearAll();\n this._refMap.clear();\n this._roomSelfIds.clear();\n this._deliver = null;\n }\n\n // ── Full catch-up (kept for app-path consumers) ────────────────────────────\n\n async buildFullCatchUp(): Promise<ContentPart[]> {\n return this._buildFullCatchUp();\n }\n\n private async _buildFullCatchUp(): Promise<ContentPart[]> {\n const sections: string[] = [\"[Session context — loaded automatically]\"];\n\n const nameCounts = new Map<string, number>();\n for (const [, c] of this._registry.entries()) nameCounts.set(c.name, (nameCounts.get(c.name) ?? 0) + 1);\n\n for (const [roomId, conn] of this._registry.entries()) {\n const mode = this.getModeForRoom(roomId);\n const isDuplicate = (nameCounts.get(conn.name) ?? 0) > 1;\n const ref = isDuplicate ? roomId : (conn.identifier ?? roomId);\n\n sections.push(`\\n${conn.name} [${ref}] — ${mode}`);\n\n if (mode.startsWith(\"standby-\")) {\n sections.push(\" (standby — @mentions only)\");\n } else {\n const participants = conn.dataSource.listParticipants()\n .filter((p) => p.id !== this._participantId);\n if (participants.length > 0) {\n const pList = participants\n .map((p) => `${p.type} ${p.name}`)\n .join(\", \");\n sections.push(`Participants: ${pList}`);\n }\n\n const { lines } = await buildCatchUpLines(conn, {\n isEventSeen: (id) => this._tracker.isDelivered(id),\n markEventsSeen: (ids) => { this._tracker.markManyDelivered(ids); },\n assignRef: (id) => this.assignRef(id),\n });\n if (lines.length > 0) {\n for (const line of lines) sections.push(` ${line}`);\n } else {\n sections.push(\" (nothing new)\");\n }\n }\n }\n\n sections.push(\n \"\\n────────────────────────────────────────────────\",\n \"Continue immediately if you see fit, or explore further in any active room.\",\n );\n\n return [{ type: \"text\", text: sections.join(\"\\n\") }];\n }\n\n // ── Event handling ──────────────────────────────────────────────────────────\n\n private async _handleLabeledEvent(labeled: LabeledEvent): Promise<void> {\n if (this._tracker.isDuplicate(labeled.event.id)) return;\n\n const { roomId, event } = labeled;\n\n const conn = this._registry.get(roomId);\n const senderLookupId =\n event.type === \"Mentioned\"\n ? (event as MentionedEvent).message.sender_id\n : event.participant_id;\n const sender = conn?.dataSource.listParticipants().find((p) => p.id === senderLookupId);\n const senderType: ParticipantType = sender?.type ?? \"human\";\n\n const selfId = this.getSelfIdForRoom(roomId);\n const disposition: EventDisposition = this._engagement.classify(event, roomId, selfId, senderType, senderLookupId);\n\n if (disposition === \"drop\") return;\n\n this._tracker.markDelivered(event.id);\n\n if (disposition === \"content\") {\n this._buffer.push(roomId, { event, roomId, roomName: labeled.roomName });\n return;\n }\n\n // trigger\n this._log.push(event);\n\n if (this._processing) {\n this._eventQueue.push(labeled);\n this._formatForLLM(event, roomId, labeled.roomName).then((parts) => {\n if (parts) this._injectBuffer.push(parts);\n }).catch((err) => {\n console.error(`[${this._participantName}] inject buffer format error:`, err);\n });\n return;\n }\n\n await this._processTrigger(labeled);\n\n // Drain queued events\n while (this._eventQueue.length > 0) {\n const queued = this._eventQueue;\n this._eventQueue = [];\n\n const formatted: ContentPart[][] = [];\n let batchContextRoom: string | null = null;\n const roomsProcessed = new Set<string>();\n\n for (const qe of queued) {\n const qConn = this._registry.get(qe.roomId);\n const qSenderLookupId =\n qe.event.type === \"Mentioned\"\n ? (qe.event as MentionedEvent).message.sender_id\n : qe.event.participant_id;\n const qSender = qConn?.dataSource.listParticipants().find((p) => p.id === qSenderLookupId);\n const qSenderType: ParticipantType = qSender?.type ?? \"human\";\n const qSelfId = this.getSelfIdForRoom(qe.roomId);\n const qDisposition = this._engagement.classify(qe.event, qe.roomId, qSelfId, qSenderType, qSenderLookupId);\n\n if (qDisposition === \"drop\") continue;\n\n if (!roomsProcessed.has(qe.roomId)) {\n roomsProcessed.add(qe.roomId);\n const buffered = this._buffer.flush(qe.roomId);\n for (const item of buffered) {\n const parts = await this._formatForLLM(item.event, item.roomId, item.roomName);\n if (parts) {\n formatted.push(parts);\n if (!batchContextRoom) batchContextRoom = qe.roomId;\n }\n }\n }\n\n this._log.push(qe.event);\n const parts = await this._formatForLLM(qe.event, qe.roomId, qe.roomName);\n if (parts) {\n formatted.push(parts);\n if (!batchContextRoom) batchContextRoom = qe.roomId;\n }\n }\n\n if (formatted.length > 0) {\n await this._processRaw(mergeParts(formatted), batchContextRoom);\n }\n }\n }\n\n private async _processTrigger(labeled: LabeledEvent): Promise<void> {\n const { roomId, roomName, event } = labeled;\n\n const buffered = this._buffer.flush(roomId);\n\n const contentPartArrays: ContentPart[][] = [];\n for (const item of buffered) {\n const parts = await this._formatForLLM(item.event, item.roomId, item.roomName);\n if (parts) contentPartArrays.push(parts);\n }\n\n // Cache lastMessage\n if (event.type === \"MessageSent\") {\n const conn = this._registry.get(roomId);\n const senderLabel = conn?.dataSource.listParticipants().find((p) => p.id === event.message.sender_id)?.name ?? event.message.sender_name;\n const contentPreview = event.message.content.length > 60 ? event.message.content.slice(0, 57) + \"...\" : event.message.content;\n const preview = event.message.image_url && !event.message.content.trim()\n ? \"sent an image\"\n : contentPreview;\n this._registry.setLastMessage(roomId, `${senderLabel}: ${preview}`);\n }\n\n const triggerParts = await this._formatForLLM(event, roomId, roomName);\n if (!triggerParts && contentPartArrays.length === 0) return;\n\n const mergedParts = mergeParts([...contentPartArrays, ...(triggerParts ? [triggerParts] : [])]);\n await this._processRaw(mergedParts, roomId);\n }\n\n // ── Formatting ──────────────────────────────────────────────────────────────\n\n private _resolveParticipantForRoom(roomId: string): (id: string) => Participant | null {\n return (id: string) => {\n const conn = this._registry.get(roomId);\n if (!conn) return null;\n return conn.dataSource.listParticipants().find((p) => p.id === id) ?? null;\n };\n }\n\n private async _resolveReplyContext(\n event: RoomEvent,\n roomId: string,\n ): Promise<{ senderName: string; content: string } | null> {\n if (event.type !== \"MessageSent\" && event.type !== \"Mentioned\") return null;\n const msg = event.message;\n if (!msg.reply_to_id) return null;\n const conn = this._registry.get(roomId);\n if (!conn) return null;\n const repliedTo = await conn.dataSource.getMessage(msg.reply_to_id);\n return repliedTo ? { senderName: repliedTo.sender_name, content: repliedTo.content } : null;\n }\n\n private async _resolveReactionTarget(\n event: RoomEvent,\n roomId: string,\n ): Promise<{ senderName: string; content: string; isSelf: boolean } | null> {\n if (event.type !== \"ReactionAdded\") return null;\n const conn = this._registry.get(roomId);\n if (!conn) return null;\n const target = await conn.dataSource.getMessage(event.message_id);\n if (!target) return null;\n return {\n senderName: target.sender_name,\n content: target.content,\n isSelf: target.sender_id === this._participantId,\n };\n }\n\n private async _formatForLLM(\n event: RoomEvent,\n roomId: string,\n roomName: string,\n ): Promise<ContentPart[] | null> {\n const mode = this.getModeForRoom(roomId);\n const label = mode !== \"everyone\" ? `${roomName} — ${mode}` : roomName;\n const replyContext = await this._resolveReplyContext(event, roomId);\n const reactionTarget = await this._resolveReactionTarget(event, roomId);\n return formatEvent(\n event,\n this._resolveParticipantForRoom(roomId),\n replyContext,\n label,\n reactionTarget,\n (id) => this.assignRef(id),\n );\n }\n\n // ── Delivery ────────────────────────────────────────────────────────────────\n\n private async _processRaw(\n parts: ContentPart[],\n contextRoomId: string | null,\n ): Promise<void> {\n if (this._options.preQuery && !(await this._options.preQuery())) {\n return;\n }\n\n this._processing = true;\n this._currentContextRoomId = contextRoomId;\n\n try {\n if (!this._deliver) return;\n await this._deliver(parts);\n } catch (err) {\n console.error(`[${this._participantName}] error:`, err);\n } finally {\n this._currentContextRoomId = null;\n this._processing = false;\n }\n }\n}\n","/**\n * Runtime MCP server — local MCP proxy for the client-side agent runtime.\n *\n * Claude Code / OpenCode connects to this local server. Tool calls are routed\n * to the right apiary server via the RoomResolver (which maps room names to\n * RemoteRoomDataSource instances).\n *\n * Tools:\n * Always present:\n * apiary__catch_up(room?) — with room: room catch-up. Without: list rooms + pending invites.\n * apiary__search_by_text(room, query, count?, cursor?)\n * apiary__search_by_message(room, ref, direction?, count?)\n * apiary__send_message(room, content, reply_to?)\n * apiary__set_mode(room, mode)\n * apiary__join_room(url, alias?)\n * apiary__leave_room(room)\n *\n * With --admin flag:\n * apiary__admin__set_mode_for(room, participant, mode)\n * apiary__admin__kick(room, participant)\n */\n\nimport { createServer } from \"node:http\";\nimport { z } from \"zod\";\nimport type { WaitTarget } from \"../wait-for-agent.js\";\nimport type { RoomResolver, ToolHandlerOptions } from \"../types.js\";\nimport type { AuthorityLevel } from \"../../core/types.js\";\nimport { can } from \"../../core/authority.js\";\nimport {\n handleCatchUp,\n handleSearchByText,\n handleSearchByMessage,\n handleSendMessage,\n textResult,\n} from \"../tool-handlers.js\";\nimport { MODE_DESCRIPTIONS } from \"../prompts.js\";\nimport { type EngagementMode } from \"../engagement.js\";\n\n/** Modes available in the CLI runtime. */\nconst RUNTIME_MODES: ReadonlySet<string> = new Set<EngagementMode>([\n \"everyone\", \"people\", \"agents\",\n \"standby-everyone\", \"standby-people\", \"standby-agents\",\n]);\nconst RUNTIME_MODES_LIST = \"everyone, people, agents, standby-everyone, standby-people, standby-agents\";\n\nfunction isValidRuntimeMode(mode: string): mode is EngagementMode {\n return RUNTIME_MODES.has(mode);\n}\nimport { EventEmitterAsyncResource } from \"node:events\"\n\nexport interface JoinRoomResult {\n success: boolean;\n error?: string;\n roomName?: string;\n agentName?: string;\n authority?: string;\n mode?: string;\n personName?: string;\n participants?: Array<{ name: string; authority: string }>;\n recentLines?: string[];\n /** Room rules — surfaced in the join response so the agent sees them on entry. */\n rules?: string[];\n}\n\nexport interface RuntimeMcpServerOptions {\n resolver: RoomResolver;\n toolOptions: ToolHandlerOptions;\n /**\n * Server-granted authority for this agent's session. Drives which admin /\n * product_owner tools are exposed. When undefined or \"member\"/\"guest\", only\n * non-privileged tools are registered. Updated after each `join_room`\n * because the agent's tier can vary per room.\n */\n authority?: AuthorityLevel;\n /** Called when the agent requests joining a new room mid-session. */\n onJoinRoom?: (url: string, alias?: string, name?: string) => Promise<JoinRoomResult>;\n /** Called when the agent requests leaving a room. */\n onLeaveRoom?: (room: string) => Promise<{ success: boolean; error?: string }>;\n /** Called when the agent changes its own mode. */\n onSetMode?: (room: string, mode: string) => Promise<{ success: boolean; error?: string }>;\n /** Called when the agent pings a participant for a status check. */\n onPing?: (room: string, participant: string) => Promise<{ success: boolean; error?: string }>;\n onWaitForAgent?: (\n room: string,\n participant: string,\n until?: WaitTarget,\n timeoutSec?: number,\n ) => Promise<{ success: boolean; message?: string; error?: string }>;\n /** Called for admin set-mode-for. */\n onAdminSetModeFor?: (room: string, participant: string, mode: string) => Promise<{ success: boolean; error?: string }>;\n /** Called for admin kick. */\n onAdminKick?: (room: string, participant: string) => Promise<{ success: boolean; error?: string }>;\n /** Called for admin mute (demote to guest). */\n onAdminMute?: (room: string, participant: string) => Promise<{ success: boolean; error?: string }>;\n /** Called for admin unmute (restore to member). */\n onAdminUnmute?: (room: string, participant: string) => Promise<{ success: boolean; error?: string }>;\n /** Called for admin promote (elevate to product_owner). */\n onAdminPromote?: (room: string, participant: string) => Promise<{ success: boolean; error?: string }>;\n /** Called for admin demote (drop product_owner back to member). */\n onAdminDemote?: (room: string, participant: string) => Promise<{ success: boolean; error?: string }>;\n}\n\nexport interface RuntimeMcpServer {\n url: string;\n stop: () => Promise<void>;\n}\n\n/** Format a rich join_room response from the callback result. */\nfunction formatJoinResponse(result: JoinRoomResult): string {\n const lines: string[] = [];\n\n lines.push(`Joined ${result.roomName} as \"${result.agentName}\" (${result.authority})`);\n lines.push(\"\");\n\n // Agents reliably answer in their own terminal, which nobody reads. From the\n // room's side that is indistinguishable from having finished — so a question\n // asked there is a silent stall. Say so explicitly on the way in; the room\n // rules tell them to ask, but not where.\n lines.push(\"Nobody reads your terminal — only this room:\");\n lines.push(\" - Ask questions and report blockers here with send_message, or they are invisible.\");\n lines.push(\" - Don't end a turn waiting on an answer you never posted.\");\n lines.push(\"\");\n\n // Mode\n if (result.mode) {\n lines.push(`Mode: ${result.mode}`);\n const desc = MODE_DESCRIPTIONS[result.mode];\n if (desc) lines.push(` ${desc}`);\n lines.push(` Change with set_mode.`);\n lines.push(\"\");\n }\n\n // Person\n if (result.personName) {\n lines.push(`Person: ${result.personName}`);\n lines.push(` Your person's messages always reach you regardless of mode.`);\n lines.push(\"\");\n }\n\n // Room rules — surface before participants so the agent sees them prominently.\n if (result.rules && result.rules.length > 0) {\n lines.push(\"Room rules — follow these:\");\n result.rules.forEach((r, i) => lines.push(` ${i + 1}. ${r}`));\n lines.push(\"\");\n }\n\n // Participants\n if (result.participants && result.participants.length > 0) {\n lines.push(\"Participants:\");\n for (const p of result.participants) {\n lines.push(` ${p.name} (${p.authority})`);\n }\n lines.push(\"\");\n }\n\n // Recent activity\n if (result.recentLines && result.recentLines.length > 0) {\n lines.push(\"Recent:\");\n for (const line of result.recentLines) {\n lines.push(` ${line}`);\n }\n lines.push(\"\");\n lines.push(`${result.recentLines.length} message${result.recentLines.length === 1 ? \"\" : \"s\"} shown. Use catch_up(\"${result.roomName}\") for more.`);\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Every tool the runtime MCP server registers.\n *\n * Exported so launchers can name apiary's own tools to the agent CLI — Codex\n * only auto-approves per tool, not per server, so an agent spawned to sit in a\n * room needs each of these named or it blocks on a keypress nobody will press.\n * `runtime-tool-names.test.ts` fails if this drifts from what is registered.\n */\nexport const RUNTIME_TOOL_NAMES = [\n \"apiary__catch_up\",\n \"apiary__search_by_text\",\n \"apiary__search_by_message\",\n \"apiary__send_message\",\n \"apiary__set_mode\",\n \"apiary__join_room\",\n \"apiary__leave_room\",\n \"apiary__ping\",\n \"apiary__wait_for_agent\",\n \"apiary__admin__set_mode_for\",\n \"apiary__admin__mute\",\n \"apiary__admin__unmute\",\n \"apiary__admin__kick\",\n \"apiary__admin__promote\",\n \"apiary__admin__demote\",\n] as const;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction registerTools(server: any, opts: RuntimeMcpServerOptions): void {\n const { resolver, toolOptions } = opts;\n\n // ── apiary__catch_up ────────────────────────────────────────────────────\n server.tool(\n \"apiary__catch_up\",\n \"List your rooms and status. Call with no arguments to see connected rooms. With a room name, returns recent activity you haven't seen.\",\n {\n room: z.string().optional().describe(\"Room name. Omit to list all connected rooms.\"),\n },\n { readOnlyHint: true },\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n async ({ room }: { room?: string }) => {\n if (!room) {\n const rooms = resolver.listAll();\n if (rooms.length === 0) {\n return textResult(\"Not connected to any rooms.\");\n }\n const lines = [\"Connected rooms:\", \"\"];\n for (const r of rooms) {\n const idPart = r.identifier ? ` [${r.identifier}]` : \"\";\n lines.push(` ${r.name}${idPart} — ${r.mode} (${r.participantCount} participants)`);\n if (r.lastMessage) lines.push(` Last: ${r.lastMessage}`);\n }\n return textResult(lines.join(\"\\n\"));\n }\n return handleCatchUp(resolver, { room }, toolOptions);\n },\n );\n\n // ── apiary__search_by_text ──────────────────────────────────────────────\n server.tool(\n \"apiary__search_by_text\",\n \"Search chat history by keyword.\",\n {\n room: z.string().describe(\"Room name\"),\n query: z.string().describe(\"Keyword or phrase to search for\"),\n count: z.number().int().min(1).max(10).default(3).optional()\n .describe(\"Number of matches (default 3)\"),\n cursor: z.string().optional().describe(\"Pagination cursor\"),\n },\n { readOnlyHint: true },\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n async (args: any) => handleSearchByText(resolver, args, toolOptions) as any,\n );\n\n // ── apiary__search_by_message ──────────────────────────────────────────\n server.tool(\n \"apiary__search_by_message\",\n \"Show messages around a known message ref.\",\n {\n room: z.string().describe(\"Room name\"),\n ref: z.string().describe(\"Message ref (e.g. #3847)\"),\n direction: z.enum([\"before\", \"after\"]).default(\"before\").optional()\n .describe(\"'before' to scroll back, 'after' to scroll forward\"),\n count: z.number().int().min(1).max(50).default(10).optional()\n .describe(\"Number of messages (default 10)\"),\n },\n { readOnlyHint: true },\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n async (args: any) => handleSearchByMessage(resolver, args, toolOptions) as any,\n );\n\n // ── apiary__send_message ────────────────────────────────────────────────\n server.tool(\n \"apiary__send_message\",\n \"Send a message to a room.\",\n {\n room: z.string().describe(\"Room name\"),\n content: z.string().describe(\"Message content. @name will notify that participant — use sparingly.\"),\n reply_to_id: z.string().optional()\n .describe(\"Message ref to reply to (e.g. #3847).\"),\n attachments: z.array(z.discriminatedUnion(\"type\", [\n z.object({\n type: z.literal(\"path\"),\n id: z.string().describe(\"Stable ID (use crypto.randomUUID())\"),\n name: z.string().describe(\"Display filename\"),\n mime_type: z.string().describe(\"MIME type, e.g. image/png\"),\n size: z.number().optional().describe(\"File size in bytes\"),\n path: z.string().describe(\"Absolute local filesystem path — readable by agents on the same machine\"),\n }),\n z.object({\n type: z.literal(\"upload\"),\n id: z.string().describe(\"Attachment ID returned by POST /attachment\"),\n name: z.string().describe(\"Display filename\"),\n mime_type: z.string().describe(\"MIME type, e.g. image/png\"),\n size: z.number().describe(\"File size in bytes\"),\n url: z.string().describe(\"URL returned by POST /attachment\"),\n }),\n ])).optional().describe(\"Typed file/image attachments\"),\n to: z.array(z.string()).optional()\n .describe(\"Participant display names to whisper to. Others see [sender → recipient] but not the content. Omit for a public message.\"),\n },\n { readOnlyHint: false, destructiveHint: false },\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n async (args: any) => handleSendMessage(resolver, args, toolOptions) as any,\n );\n\n // ── apiary__set_mode ────────────────────────────────────────────────────\n server.tool(\n \"apiary__set_mode\",\n \"Change your engagement mode. Controls which messages are pushed to you: everyone — all messages, people — human messages only, agents — agent messages only. Prefix with standby- for @mentions only.\",\n {\n room: z.string().describe(\"Room name\"),\n mode: z.string().describe(\"Engagement mode\"),\n },\n { readOnlyHint: false, destructiveHint: false, idempotentHint: true },\n async ({ room, mode }: { room: string; mode: string }) => {\n if (!opts.onSetMode) return textResult(\"Mode changes not supported.\");\n if (!isValidRuntimeMode(mode)) {\n return textResult(`Invalid mode \"${mode}\". Valid modes: ${RUNTIME_MODES_LIST}.`);\n }\n const result = await opts.onSetMode(room, mode);\n return result.success\n ? textResult(`Mode set to ${mode} for [${room}].`)\n : textResult(result.error ?? \"Failed to set mode.\");\n },\n );\n\n // ── apiary__join_room ──────────────────────────────────────────────────\n server.tool(\n \"apiary__join_room\",\n \"Join a room. Returns your identity, participants, mode, and recent activity.\",\n {\n url: z.string().describe(\"Share URL to join\"),\n alias: z.string().optional().describe(\"Local alias for the room (if name collides)\"),\n name: z.string().optional().describe(\"Display name to use in this room (overrides default)\"),\n },\n { readOnlyHint: false, destructiveHint: false },\n async ({ url, alias, name }: { url: string; alias?: string; name?: string }) => {\n if (!opts.onJoinRoom) return textResult(\"Joining rooms not supported.\");\n const result = await opts.onJoinRoom(url, alias, name);\n if (!result.success) return textResult(result.error ?? \"Failed to join room.\");\n\n // Rich response if we have room details\n if (result.roomName && result.agentName) {\n return textResult(formatJoinResponse(result));\n }\n return textResult(`Joined room successfully.`);\n },\n );\n\n // ── apiary__leave_room ─────────────────────────────────────────────────\n server.tool(\n \"apiary__leave_room\",\n \"Leave a room. Events stop flowing from it.\",\n {\n room: z.string().describe(\"Room name to leave\"),\n },\n { readOnlyHint: false, destructiveHint: false, idempotentHint: true },\n async ({ room }: { room: string }) => {\n if (!opts.onLeaveRoom) return textResult(\"Leaving rooms not supported.\");\n const result = await opts.onLeaveRoom(room);\n return result.success\n ? textResult(`Left [${room}].`)\n : textResult(result.error ?? \"Failed to leave room.\");\n },\n );\n\n // ── apiary__ping ──────────────────────────────────────────────────────\n server.tool(\n \"apiary__ping\",\n \"Ping a participant for a status check. Non-blocking — they'll see it as context, not an interrupt.\",\n {\n room: z.string().describe(\"Room name\"),\n participant: z.string().describe(\"Participant name to ping\"),\n },\n { readOnlyHint: false, destructiveHint: false },\n async ({ room, participant }: { room: string; participant: string }) => {\n if (!opts.onPing) return textResult(\"Ping not supported.\");\n const result = await opts.onPing(room, participant);\n return result.success\n ? textResult(`Pinged ${participant} in [${room}].`)\n : textResult(result.error ?? \"Failed to ping participant.\");\n },\n );\n\n // ── apiary__wait_for_agent ─────────────────────────────────────────────\n server.tool(\n \"apiary__wait_for_agent\",\n \"Wait until another agent is idle (finished), blocked (needs a human), or working. \"\n + \"Use this instead of re-reading the room in a loop to check on someone — polling costs a full turn each time, this costs one call. \"\n + \"Returns as soon as they reach the state, or after the timeout with whatever state they're in; call again to keep waiting.\",\n {\n room: z.string().describe(\"Room name\"),\n participant: z.string().describe(\"Agent to wait for\"),\n until: z.enum([\"idle\", \"blocked\", \"working\", \"change\"]).optional()\n .describe(\"What to wait for. idle = they finished (default). blocked = they need a human. change = any state change.\"),\n timeout_sec: z.number().optional()\n .describe(\"How long to wait, in seconds. Default 60, max 120.\"),\n },\n { readOnlyHint: true, destructiveHint: false, idempotentHint: true },\n async (\n { room, participant, until, timeout_sec }:\n { room: string; participant: string; until?: WaitTarget; timeout_sec?: number },\n ) => {\n if (!opts.onWaitForAgent) return textResult(\"Waiting not supported.\");\n const result = await opts.onWaitForAgent(room, participant, until, timeout_sec);\n return result.success\n ? textResult(result.message ?? \"Done.\")\n : textResult(result.error ?? \"Failed to wait.\");\n },\n );\n\n // ── Product owner-and-up tools (mute / unmute / set_mode_for) ───────────\n // These actions are accepted by the server for both admin and product_owner;\n // expose them whenever the agent's authority meets the threshold so a\n // promoted product_owner agent can actually use its powers.\n if (can(opts.authority, \"set_mode_for\")) {\n server.tool(\n \"apiary__admin__set_mode_for\",\n \"Admin: set engagement mode for another participant.\",\n {\n room: z.string().describe(\"Room name\"),\n participant: z.string().describe(\"Participant name\"),\n mode: z.string().describe(\"Engagement mode to set\"),\n },\n { readOnlyHint: false, destructiveHint: false, idempotentHint: true },\n async ({ room, participant, mode }: { room: string; participant: string; mode: string }) => {\n if (!opts.onAdminSetModeFor) return textResult(\"Admin mode changes not supported.\");\n if (!isValidRuntimeMode(mode)) {\n return textResult(`Invalid mode \"${mode}\". Valid modes: ${RUNTIME_MODES_LIST}.`);\n }\n const result = await opts.onAdminSetModeFor(room, participant, mode);\n return result.success\n ? textResult(`Set ${participant}'s mode to ${mode} in [${room}].`)\n : textResult(result.error ?? \"Failed to set mode.\");\n },\n );\n\n server.tool(\n \"apiary__admin__mute\",\n \"Admin: make a participant read-only (demote to guest).\",\n {\n room: z.string().describe(\"Room name\"),\n participant: z.string().describe(\"Participant name to mute\"),\n },\n { readOnlyHint: false, destructiveHint: false, idempotentHint: true },\n async ({ room, participant }: { room: string; participant: string }) => {\n if (!opts.onAdminMute) return textResult(\"Admin mute not supported.\");\n const result = await opts.onAdminMute(room, participant);\n return result.success\n ? textResult(`Muted ${participant} in [${room}] (guest).`)\n : textResult(result.error ?? \"Failed to mute participant.\");\n },\n );\n\n server.tool(\n \"apiary__admin__unmute\",\n \"Admin: restore a muted participant (promote to member).\",\n {\n room: z.string().describe(\"Room name\"),\n participant: z.string().describe(\"Participant name to unmute\"),\n },\n { readOnlyHint: false, destructiveHint: false, idempotentHint: true },\n async ({ room, participant }: { room: string; participant: string }) => {\n if (!opts.onAdminUnmute) return textResult(\"Admin unmute not supported.\");\n const result = await opts.onAdminUnmute(room, participant);\n return result.success\n ? textResult(`Unmuted ${participant} in [${room}] (member).`)\n : textResult(result.error ?? \"Failed to unmute participant.\");\n },\n );\n\n }\n\n // ── Admin-only tools (kick / promote / demote) ──────────────────────────\n // Destructive or authority-escalating operations. Server gates these on\n // strict admin; mirror that here so product_owners don't get tools that the\n // server will reject anyway.\n if (can(opts.authority, \"kick\")) {\n server.tool(\n \"apiary__admin__kick\",\n \"Admin: kick a participant from a room.\",\n {\n room: z.string().describe(\"Room name\"),\n participant: z.string().describe(\"Participant name to kick\"),\n },\n { readOnlyHint: false, destructiveHint: true },\n async ({ room, participant }: { room: string; participant: string }) => {\n if (!opts.onAdminKick) return textResult(\"Admin kick not supported.\");\n const result = await opts.onAdminKick(room, participant);\n return result.success\n ? textResult(`Kicked ${participant} from [${room}].`)\n : textResult(result.error ?? \"Failed to kick participant.\");\n },\n );\n\n server.tool(\n \"apiary__admin__promote\",\n \"Admin: promote a participant to product owner (can mute/unmute members, set modes).\",\n {\n room: z.string().describe(\"Room name\"),\n participant: z.string().describe(\"Participant name to promote\"),\n },\n { readOnlyHint: false, destructiveHint: false, idempotentHint: true },\n async ({ room, participant }: { room: string; participant: string }) => {\n if (!opts.onAdminPromote) return textResult(\"Admin promote not supported.\");\n const result = await opts.onAdminPromote(room, participant);\n return result.success\n ? textResult(`Promoted ${participant} to product owner in [${room}].`)\n : textResult(result.error ?? \"Failed to promote participant.\");\n },\n );\n\n server.tool(\n \"apiary__admin__demote\",\n \"Admin: demote a product owner back to member.\",\n {\n room: z.string().describe(\"Room name\"),\n participant: z.string().describe(\"Participant name to demote\"),\n },\n { readOnlyHint: false, destructiveHint: false, idempotentHint: true },\n async ({ room, participant }: { room: string; participant: string }) => {\n if (!opts.onAdminDemote) return textResult(\"Admin demote not supported.\");\n const result = await opts.onAdminDemote(room, participant);\n return result.success\n ? textResult(`Demoted ${participant} to member in [${room}].`)\n : textResult(result.error ?? \"Failed to demote participant.\");\n },\n );\n }\n}\n\n/**\n * Create a runtime MCP server on a random localhost port (HTTP transport).\n * Returns the URL for --mcp-config and a stop function.\n */\nexport async function createRuntimeMcpServer(\n opts: RuntimeMcpServerOptions,\n): Promise<RuntimeMcpServer> {\n const { McpServer } = await import(\"@modelcontextprotocol/sdk/server/mcp.js\");\n const { StreamableHTTPServerTransport } = await import(\n \"@modelcontextprotocol/sdk/server/streamableHttp.js\"\n );\n\n const httpServer = createServer(async (req, res) => {\n if (req.url !== \"/mcp\") {\n res.writeHead(404).end();\n return;\n }\n\n // Fresh McpServer per request (McpServer only allows one active transport)\n const reqServer = new McpServer({ name: \"apiary_runtime\", version: \"1.0.0\" });\n registerTools(reqServer, opts);\n\n const transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: undefined,\n });\n\n await reqServer.connect(transport);\n\n let body: unknown;\n if (req.method === \"POST\") {\n const chunks: Buffer[] = [];\n for await (const chunk of req) chunks.push(chunk as Buffer);\n try { body = JSON.parse(Buffer.concat(chunks).toString()); } catch { body = undefined; }\n }\n\n await transport.handleRequest(req, res, body);\n });\n\n const port = await new Promise<number>((resolve, reject) => {\n httpServer.listen(0, \"127.0.0.1\", () => {\n const addr = httpServer.address();\n if (addr && typeof addr === \"object\") resolve(addr.port);\n else reject(new Error(\"Could not determine server port\"));\n });\n httpServer.once(\"error\", reject);\n });\n\n const url = `http://127.0.0.1:${port}/mcp`;\n\n let stopPromise: Promise<void> | null = null;\n const stop = () => {\n if (!stopPromise) {\n stopPromise = new Promise<void>((resolve, reject) =>\n httpServer.close((err) => (err ? reject(err) : resolve())),\n );\n }\n return stopPromise;\n };\n\n return { url, stop };\n}\n\n/**\n * Create a runtime MCP server using stdio transport (stdin/stdout).\n * Used by `apiary mcp` — the server runs as a standalone process that\n * any MCP client (Claude Code, etc.) can connect to via stdio.\n *\n * Returns a stop function and signals when the transport closes.\n */\nexport async function createStdioRuntimeMcpServer(\n opts: RuntimeMcpServerOptions,\n): Promise<{ stop: () => Promise<void>; closed: Promise<void> }> {\n const { McpServer } = await import(\"@modelcontextprotocol/sdk/server/mcp.js\");\n const { StdioServerTransport } = await import(\n \"@modelcontextprotocol/sdk/server/stdio.js\"\n );\n\n const mcpServer = new McpServer({ name: \"apiary_runtime\", version: \"1.0.0\" });\n registerTools(mcpServer, opts);\n\n const transport = new StdioServerTransport();\n\n const closed = new Promise<void>((resolve) => {\n transport.onclose = () => resolve();\n });\n\n await mcpServer.connect(transport);\n\n const stop = async () => {\n await transport.close();\n await mcpServer.close();\n };\n\n return { stop, closed };\n}\n"],"mappings":"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","names":["parts"]}