stoops 0.1.0 → 0.2.5

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/agent/prompts.ts","../src/agent/mcp/runtime.ts","../src/agent/tool-handlers.ts"],"sourcesContent":["/** Event formatting and mode descriptions for stoops agents. */\n\nimport type { Participant } from \"../core/types.js\";\nimport type { RoomEvent } from \"../core/events.js\";\nimport type { ContentPart } from \"./types.js\";\n\n// ── Mode descriptions ────────────────────────────────────────────────────────\n\n/** One-liner mode descriptions used in join_room responses and set_mode. */\nexport const MODE_DESCRIPTIONS: Record<string, string> = {\n \"everyone\": \"All messages are pushed to you.\",\n \"people\": \"Human messages are pushed to you. Agent messages are delivered as context.\",\n \"agents\": \"Agent messages are pushed to you. Human messages are delivered as context.\",\n \"me\": \"Only your person's messages are pushed to you. Others are delivered as context.\",\n \"standby-everyone\": \"Only @mentions are pushed to you.\",\n \"standby-people\": \"Only human @mentions are pushed to you.\",\n \"standby-agents\": \"Only agent @mentions are pushed to you.\",\n \"standby-me\": \"Only your person's @mentions are pushed to you.\",\n};\n\n// ── System preamble ──────────────────────────────────────────────────────────\n\nconst SYSTEM_PREAMBLE = `You are a participant in group chats. You may be connected to multiple rooms at once — events from all of them flow to you, labeled with the room name.\n\n## How this works\n- Messages appear labeled: \"[Design Room] [human] Alice: hey everyone\"\n- Replies: \"[Design Room] [human] Alice (replying to [human] Bob): good point\"\n- @mentions: \"⚡ [Design Room] [human] Alice mentioned you: @Bob what do you think?\"\n- All your tools require a room name as the first parameter\n- Rooms have a stable \\`identifier\\` (e.g., design-room) that doesn't change even if renamed\n- Message references like #3847 are internal tool labels only. Never include them in messages — participants don't see them.\n\n## Your memory\nYou have no persistent memory between sessions. Each time you start, you're waking up fresh. Your conversations are still there — read them via tools.\n\nIf you lack context for something someone references, say so directly — don't invent explanations.\n\n## Your person\nYou were created by someone — that's your person. You know their participant ID from your identity block below. Their messages carry more weight: they're the one who set you up and knows what they want from you. In group rooms, stay tuned to them even when others are talking.\n\nWhen someone who isn't your person addresses you in a group room, respond if it's useful and natural. But don't lose track of who you're ultimately here for.\n\n## Engagement modes\nEach room has a mode controlling when you evaluate and respond:\n- everyone — all messages trigger evaluation. Respond when you have something genuine to add.\n- people — any human message triggers you. Agent messages are buffered as context.\n- agents — any agent message triggers you. Human messages are buffered as context.\n- me — only your person's messages trigger evaluation. Read everything else quietly.\n- standby-everyone — only @mentions wake you. Stay silent unless directly called, by anyone.\n- standby-people — only human @mentions wake you.\n- standby-agents — only agent @mentions wake you.\n- standby-me — only your person's @mention wakes you.\n\nNon-everyone rooms show the mode in the room label (e.g., \"[Design Room — people]\").`;\n\nexport function getSystemPreamble(identifier?: string, personParticipantId?: string): string {\n const lines: string[] = [];\n if (identifier) lines.push(`Your identifier: @${identifier}`);\n if (personParticipantId) lines.push(`Your person's participant ID: ${personParticipantId}`);\n if (identifier) lines.push(`Recognize other participants by their identifier. Address them by their current display name.`);\n const identityBlock = lines.length > 0 ? `## Your identity\\n${lines.join(\"\\n\")}\\n\\n` : \"\";\n return identityBlock + SYSTEM_PREAMBLE;\n}\n\n// ── Formatting ────────────────────────────────────────────────────────────────\n\n/** Short 4-char ref for a message ID, used in transcripts. */\nexport function messageRef(messageId: string): string {\n return messageId.replace(/-/g, \"\").slice(0, 4);\n}\n\n/** Format a participant as a labeled name: \"[human] Alice\" or \"[agent] Quinn\". */\nexport function participantLabel(p: Participant | null, fallback?: string): string {\n if (!p) return fallback ?? \"someone\";\n return `[${p.type}] ${p.name}`;\n}\n\n/** Resolve participant name, with fallback. */\nfunction resolveName(resolveParticipant: (id: string) => Participant | null, id: string, fallback?: string): string {\n return resolveParticipant(id)?.name ?? fallback ?? \"someone\";\n}\n\n/** Format a Date as UTC HH:MM:SS for display in agent transcripts. */\nexport function formatTimestamp(date: Date): string {\n return date.toISOString().slice(11, 19);\n}\n\n/** Convert ContentPart[] back to a plain string (for trace logs and stats). */\nexport function contentPartsToString(parts: ContentPart[]): string {\n return parts.map(p => p.type === \"text\" ? p.text : ` [image: ${p.url}]`).join(\"\");\n}\n\n/** Count visual character width (grapheme clusters) for padding alignment. */\nfunction visualLength(s: string): number {\n // Use Intl.Segmenter if available (Node 16+), otherwise fall back to spread\n if (typeof Intl !== \"undefined\" && Intl.Segmenter) {\n const segmenter = new Intl.Segmenter(undefined, { granularity: \"grapheme\" });\n let count = 0;\n for (const _ of segmenter.segment(s)) count++;\n return count;\n }\n return [...s].length;\n}\n\n/**\n * Format multiline content with room label continuation.\n * First line is returned as-is. Subsequent lines get [room] prefix aligned.\n */\nfunction formatMultilineContent(content: string, roomLabel: string | undefined, prefix: string): string {\n const lines = content.split(\"\\n\");\n if (lines.length <= 1) return content;\n const continuation = roomLabel ? `[${roomLabel}] ` : \"\";\n // Pad continuation to align under the content start (grapheme-aware)\n const pad = \" \".repeat(visualLength(prefix));\n return lines[0] + \"\\n\" + lines.slice(1).map(l => `${pad}${continuation}${l}`).join(\"\\n\");\n}\n\n/**\n * Format a typed event as ContentPart[] for the LLM session.\n * Returns null for events that shouldn't be sent to the LLM (noise).\n *\n * Compact one-liner format:\n * Messages: [14:23:01] #3847 [lobby] Alice: hey everyone\n * Replies: [14:23:01] #9102 [lobby] Alice (→ #3847 Bob): good point\n * Mentions: [14:23:01] #5521 [lobby] ⚡ Alice: @bot what do you think?\n * Joined: [14:23:01] [lobby] + Alice joined\n * Left: [14:23:15] [lobby] - Bob left\n * Reactions: [14:23:20] [lobby] Alice reacted ❤️ to #3847\n */\nexport function formatEvent(\n event: RoomEvent,\n resolveParticipant: (id: string) => Participant | null,\n replyContext?: { senderName: string; content: string } | null,\n roomLabel?: string,\n reactionTarget?: { senderName: string; content: string; isSelf: boolean } | null,\n assignRef?: (messageId: string) => string,\n): ContentPart[] | null {\n const r = roomLabel ? `[${roomLabel}] ` : \"\";\n const ts = `[${formatTimestamp(\"timestamp\" in event ? new Date(event.timestamp as Date) : new Date())}] `;\n const mkRef = (id: string) => `#${assignRef ? assignRef(id) : messageRef(id)}`;\n\n switch (event.type) {\n case \"MessageSent\": {\n const msg = event.message;\n const name = resolveName(resolveParticipant, msg.sender_id, msg.sender_name);\n const ref = mkRef(msg.id);\n const linePrefix = `${ts}${ref} ${r}`;\n let text: string;\n if (msg.reply_to_id && replyContext) {\n const rRef = assignRef ? mkRef(msg.reply_to_id) : ref;\n text = `${linePrefix}${name} (→ ${rRef} ${replyContext.senderName}): ${formatMultilineContent(msg.content, roomLabel, `${linePrefix}${name} (→ ${rRef} ${replyContext.senderName}): `)}`;\n } else {\n text = `${linePrefix}${name}: ${formatMultilineContent(msg.content, roomLabel, `${linePrefix}${name}: `)}`;\n }\n const parts: ContentPart[] = [{ type: \"text\", text }];\n if (msg.image_url) parts.push({ type: \"image\", url: msg.image_url });\n return parts;\n }\n case \"Mentioned\": {\n const msg = event.message;\n const name = resolveName(resolveParticipant, msg.sender_id, msg.sender_name);\n const ref = mkRef(msg.id);\n const linePrefix = `${ts}${ref} ${r}⚡ `;\n const text = `${linePrefix}${name}: ${formatMultilineContent(msg.content, roomLabel, `${linePrefix}${name}: `)}`;\n const parts: ContentPart[] = [{ type: \"text\", text }];\n if (msg.image_url) parts.push({ type: \"image\", url: msg.image_url });\n return parts;\n }\n case \"ToolUse\":\n return null;\n case \"Activity\":\n return null;\n case \"ReactionAdded\": {\n const name = resolveName(resolveParticipant, event.participant_id);\n const targetRef = reactionTarget ? ` to ${mkRef(event.message_id)}` : \"\";\n return [{ type: \"text\", text: `${ts}${r}${name} reacted ${event.emoji}${targetRef}` }];\n }\n case \"ReactionRemoved\":\n return null;\n case \"ParticipantJoined\": {\n const name = event.participant?.name ?? \"someone\";\n return [{ type: \"text\", text: `${ts}${r}+ ${name} joined` }];\n }\n case \"ParticipantLeft\": {\n const name = event.participant?.name ?? \"someone\";\n return [{ type: \"text\", text: `${ts}${r}- ${name} left` }];\n }\n case \"ParticipantKicked\": {\n const name = event.participant?.name ?? \"someone\";\n return [{ type: \"text\", text: `${ts}${r}${name} was kicked` }];\n }\n case \"AuthorityChanged\": {\n const name = event.participant?.name ?? \"someone\";\n if (event.new_authority === \"guest\") {\n return [{ type: \"text\", text: `${ts}${r}${name} was muted` }];\n }\n if (event.new_authority === \"member\") {\n return [{ type: \"text\", text: `${ts}${r}${name} was unmuted` }];\n }\n return [{ type: \"text\", text: `${ts}${r}${name} → ${event.new_authority}` }];\n }\n case \"ContextCompacted\":\n return null;\n default:\n return null;\n }\n}\n","/**\n * 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 stoop server via the RoomResolver (which maps room names to\n * RemoteRoomDataSource instances).\n *\n * Tools:\n * Always present:\n * stoops__catch_up(room?) — with room: room catch-up. Without: list rooms + pending invites.\n * stoops__search_by_text(room, query, count?, cursor?)\n * stoops__search_by_message(room, ref, direction?, count?)\n * stoops__send_message(room, content, reply_to?)\n * stoops__set_mode(room, mode)\n * stoops__join_room(url, alias?)\n * stoops__leave_room(room)\n *\n * With --admin flag:\n * stoops__admin__set_mode_for(room, participant, mode)\n * stoops__admin__kick(room, participant)\n */\n\nimport { createServer } from \"node:http\";\nimport { z } from \"zod\";\nimport type { RoomResolver, ToolHandlerOptions } from \"../types.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 (no personParticipantId → no \"me\" modes). */\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}\n\nexport interface RuntimeMcpServerOptions {\n resolver: RoomResolver;\n toolOptions: ToolHandlerOptions;\n admin?: boolean;\n /** Called when the agent requests joining a new room mid-session. */\n onJoinRoom?: (url: string, alias?: 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 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}\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 // 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 // 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// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction registerTools(server: any, opts: RuntimeMcpServerOptions): void {\n const { resolver, toolOptions } = opts;\n\n // ── stoops__catch_up ────────────────────────────────────────────────────\n server.tool(\n \"stoops__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 // ── stoops__search_by_text ──────────────────────────────────────────────\n server.tool(\n \"stoops__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 // ── stoops__search_by_message ──────────────────────────────────────────\n server.tool(\n \"stoops__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 // ── stoops__send_message ────────────────────────────────────────────────\n server.tool(\n \"stoops__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 },\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 // ── stoops__set_mode ────────────────────────────────────────────────────\n server.tool(\n \"stoops__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 // ── stoops__join_room ──────────────────────────────────────────────────\n server.tool(\n \"stoops__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 },\n { readOnlyHint: false, destructiveHint: false },\n async ({ url, alias }: { url: string; alias?: string }) => {\n if (!opts.onJoinRoom) return textResult(\"Joining rooms not supported.\");\n const result = await opts.onJoinRoom(url, alias);\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 // ── stoops__leave_room ─────────────────────────────────────────────────\n server.tool(\n \"stoops__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 // ── Admin tools (only with --admin flag) ────────────────────────────────\n if (opts.admin) {\n server.tool(\n \"stoops__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 \"stoops__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 \"stoops__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 \"stoops__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/**\n * Create a runtime MCP server on a random localhost port.\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: \"stoops_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","/** Pure tool handler logic */\n\nimport type { Message } from \"../core/types.js\";\nimport type { RoomConnection, RoomResolver, ToolHandlerOptions } from \"./types.js\";\nimport { messageRef, formatTimestamp } from \"./prompts.js\";\n\n/** Tool result shape consumed by both backends. */\nexport interface ToolResult {\n content: Array<{ type: \"text\"; text: string }>;\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 let line = `[${ts}] ${ref} ${msg.sender_name}: ${msg.content}${imageNote}`;\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}`;\n }\n }\n return line;\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.\n */\nexport async function buildCatchUpLines(\n conn: RoomConnection,\n options: Pick<ToolHandlerOptions, \"isEventSeen\" | \"markEventsSeen\" | \"assignRef\">,\n): Promise<string[]> {\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 seenIds: string[] = [];\n const mkRef = (id: string) => `#${options.assignRef?.(id) ?? messageRef(id)}`;\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 lines.push(await formatMsgLine(event.message, conn, (id) => mkRef(id)));\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;\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 = 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 return { content: [{ type: \"text\" as const, text: out.join(\"\\n\") }] };\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 },\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 const message = await r.conn.dataSource.sendMessage(args.content, replyToId, image);\n\n const ref = options.assignRef?.(message.id) ?? messageRef(message.id);\n return textResult(`Message sent #${ref}.`);\n}\n"],"mappings":"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","names":[]}