stoops 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/index.d.ts +3 -3
- package/dist/agent/index.js +4 -4
- package/dist/{chunk-BLGV3QN4.js → chunk-66EFQ2XO.js} +16 -2
- package/dist/chunk-66EFQ2XO.js.map +1 -0
- package/dist/{chunk-7PKT5MPI.js → chunk-B4LBE5QS.js} +2 -2
- package/dist/{chunk-HQS7HBZR.js → chunk-EPLQQF6S.js} +3 -1
- package/dist/chunk-EPLQQF6S.js.map +1 -0
- package/dist/{chunk-LC5WPWR2.js → chunk-HKFCJO7V.js} +4 -4
- package/dist/{chunk-LC5WPWR2.js.map → chunk-HKFCJO7V.js.map} +1 -1
- package/dist/{chunk-SS5NGUJM.js → chunk-OA3CODNP.js} +3 -3
- package/dist/claude/index.d.ts +2 -2
- package/dist/claude/index.js +3 -3
- package/dist/cli/index.js +43 -21
- package/dist/cli/index.js.map +1 -1
- package/dist/{index-DlxJ95ki.d.ts → index-ByKHLUOe.d.ts} +38 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/langgraph/index.d.ts +2 -2
- package/dist/langgraph/index.js +3 -3
- package/dist/{types-CzHDzfHA.d.ts → types-9iTDVOJG.d.ts} +1 -1
- package/package.json +1 -1
- package/dist/chunk-BLGV3QN4.js.map +0 -1
- package/dist/chunk-HQS7HBZR.js.map +0 -1
- /package/dist/{chunk-7PKT5MPI.js.map → chunk-B4LBE5QS.js.map} +0 -0
- /package/dist/{chunk-SS5NGUJM.js.map → chunk-OA3CODNP.js.map} +0 -0
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli/serve.ts","../../src/cli/auth.ts","../../src/cli/join.ts","../../src/cli/tui.tsx","../../src/cli/claude/run.ts","../../src/cli/tmux.ts","../../src/cli/claude/tmux-bridge.ts","../../src/cli/runtime-setup.ts","../../src/cli/opencode/run.ts","../../src/cli/index.ts"],"sourcesContent":["/**\n * stoops serve — dumb room server.\n *\n * One room, one HTTP API, SSE broadcasting, authority enforcement.\n * No EventProcessor, no tmux, no agent lifecycle — those live client-side.\n * Humans connect via `stoops join`, agents via `stoops run claude`.\n */\n\nimport { createServer, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport { spawn, execFileSync, type ChildProcess } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { createRequire } from \"node:module\";\n\nimport { Room } from \"../core/room.js\";\nimport { InMemoryStorage } from \"../core/storage.js\";\nimport { randomRoomName, randomName } from \"../core/names.js\";\nimport { createEvent, type ActivityEvent, type RoomEvent } from \"../core/events.js\";\nimport type { AuthorityLevel } from \"../core/types.js\";\nimport type { Channel } from \"../core/channel.js\";\nimport { formatTimestamp } from \"../agent/prompts.js\";\nimport { TokenManager, buildShareUrl } from \"./auth.js\";\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\ninterface ConnectedParticipant {\n id: string;\n name: string;\n authority: AuthorityLevel;\n channel: Channel;\n sessionToken: string;\n}\n\ninterface ConnectedObserver {\n id: string;\n authority: \"observer\";\n channel: Channel;\n sessionToken: string;\n}\n\nexport interface ServeOptions {\n room?: string;\n port?: number;\n share?: boolean;\n quiet?: boolean;\n /** Suppress all human-readable output; emit one JSON line with server info on stdout. */\n headless?: boolean;\n}\n\nexport interface ServeResult {\n serverUrl: string;\n publicUrl: string;\n roomName: string;\n adminToken: string;\n participantToken: string;\n}\n\n// ── SSE helper ───────────────────────────────────────────────────────────────\n\nasync function enrichAndSend(res: ServerResponse, event: RoomEvent, room: Room): Promise<void> {\n if (event.type === \"MessageSent\" && event.message.reply_to_id) {\n const replyMsg = await room.getMessage(event.message.reply_to_id);\n const enriched = {\n ...event,\n _replyToName: replyMsg?.sender_name ?? null,\n };\n res.write(`data: ${JSON.stringify(enriched)}\\n\\n`);\n return;\n }\n res.write(`data: ${JSON.stringify(event)}\\n\\n`);\n}\n\n// ── Main serve command ───────────────────────────────────────────────────────\n\nexport async function serve(options: ServeOptions): Promise<ServeResult> {\n const roomName = options.room ?? randomRoomName();\n const port = options.port ?? 7890;\n const serverUrl = `http://127.0.0.1:${port}`;\n const log = options.headless ? () => {} : logServer;\n\n let publicUrl = serverUrl;\n let tunnelProcess: ChildProcess | null = null;\n\n // Create room\n const storage = new InMemoryStorage();\n const room = new Room(roomName, storage);\n\n // Auth\n const tokens = new TokenManager();\n\n // Connected participants and observers (by session token for lookup)\n const participants = new Map<string, ConnectedParticipant>();\n const observers = new Map<string, ConnectedObserver>();\n // Reverse lookup: participantId → sessionToken\n const idToSession = new Map<string, string>();\n\n // Track active SSE connections for cleanup\n const sseConnections = new Map<string, ServerResponse>();\n\n // ── JSON body parser helper ──────────────────────────────────────────────\n\n async function parseBody(req: IncomingMessage): Promise<Record<string, unknown>> {\n const chunks: Buffer[] = [];\n for await (const chunk of req) chunks.push(chunk as Buffer);\n try { return JSON.parse(Buffer.concat(chunks).toString()); } catch { return {}; }\n }\n\n // ── Auth helper ──────────────────────────────────────────────────────────\n\n function getSession(token: string | null) {\n if (!token) return null;\n const p = participants.get(token);\n if (p) return { ...p, kind: \"participant\" as const };\n const o = observers.get(token);\n if (o) return { ...o, kind: \"observer\" as const };\n return null;\n }\n\n function jsonError(res: ServerResponse, status: number, error: string): void {\n res.writeHead(status, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error }));\n }\n\n function jsonOk(res: ServerResponse, data: Record<string, unknown> = {}): void {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: true, ...data }));\n }\n\n // ── HTTP API ────────────────────────────────────────────────────────────\n\n const httpServer = createServer(async (req, res) => {\n const url = new URL(req.url ?? \"/\", `http://localhost:${port}`);\n\n // ── SSE event stream ───────────────────────────────────────────────────\n // ⚠️ MUST accept POST — DO NOT change to GET-only.\n // Cloudflare Quick Tunnels buffer GET streaming responses and only flush\n // when the connection closes. POST streams in real-time. (cloudflared#1449)\n // https://github.com/cloudflare/cloudflared/issues/1449\n if (url.pathname === \"/events\" && (req.method === \"GET\" || req.method === \"POST\")) {\n const authHeader = req.headers.authorization;\n const sessionToken = authHeader?.startsWith(\"Bearer \")\n ? authHeader.slice(7)\n : null;\n const session = getSession(sessionToken);\n\n if (!session) {\n jsonError(res, 401, \"Invalid session token\");\n return;\n }\n\n // SSE headers\n res.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n \"Connection\": \"keep-alive\",\n \"Access-Control-Allow-Origin\": \"*\",\n });\n res.flushHeaders();\n\n sseConnections.set(session.id, res);\n\n // Send recent history so the joiner has context\n const history = await room.listEvents(undefined, 50);\n for (const event of [...history.items].reverse()) {\n await enrichAndSend(res, event, room);\n }\n\n // Live event stream\n const streamEvents = async () => {\n try {\n for await (const event of session.channel) {\n await enrichAndSend(res, event, room);\n }\n } catch {\n // Channel disconnected\n }\n };\n streamEvents();\n\n // Cleanup on client disconnect\n req.on(\"close\", () => {\n sseConnections.delete(session.id);\n });\n return;\n }\n\n // ── GET endpoints ─────────────────────────────────────────────────────\n\n if (req.method === \"GET\") {\n const sessionToken = url.searchParams.get(\"token\");\n const session = getSession(sessionToken);\n\n // ── GET /participants ────────────────────────────────────────────────\n if (url.pathname === \"/participants\") {\n if (!session) return jsonError(res, 401, \"Invalid session token\");\n const list = room.listParticipants().map((p) => ({\n id: p.id,\n name: p.name,\n type: p.type,\n authority: p.authority ?? \"participant\",\n }));\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ participants: list }));\n return;\n }\n\n // ── GET /message/:id ─────────────────────────────────────────────────\n if (url.pathname.startsWith(\"/message/\")) {\n if (!session) return jsonError(res, 401, \"Invalid session token\");\n const messageId = url.pathname.slice(\"/message/\".length);\n const msg = await room.getMessage(messageId);\n if (!msg) return jsonError(res, 404, \"Message not found\");\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ message: msg }));\n return;\n }\n\n // ── GET /messages ────────────────────────────────────────────────────\n if (url.pathname === \"/messages\") {\n if (!session) return jsonError(res, 401, \"Invalid session token\");\n const count = parseInt(url.searchParams.get(\"count\") ?? \"30\", 10);\n const cursor = url.searchParams.get(\"cursor\") ?? null;\n const result = await room.listMessages(count, cursor);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(result));\n return;\n }\n\n // ── GET /events/history ──────────────────────────────────────────────\n if (url.pathname === \"/events/history\") {\n if (!session) return jsonError(res, 401, \"Invalid session token\");\n const category = url.searchParams.get(\"category\") ?? null;\n const count = parseInt(url.searchParams.get(\"count\") ?? \"50\", 10);\n const cursor = url.searchParams.get(\"cursor\") ?? null;\n const result = await room.listEvents(category as any, count, cursor);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(result));\n return;\n }\n\n // ── GET /search ──────────────────────────────────────────────────────\n if (url.pathname === \"/search\") {\n if (!session) return jsonError(res, 401, \"Invalid session token\");\n const query = url.searchParams.get(\"query\") ?? \"\";\n if (!query) return jsonError(res, 400, \"Missing query parameter\");\n const count = parseInt(url.searchParams.get(\"count\") ?? \"10\", 10);\n const cursor = url.searchParams.get(\"cursor\") ?? null;\n const result = await room.searchMessages(query, count, cursor);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(result));\n return;\n }\n }\n\n // ── POST endpoints ────────────────────────────────────────────────────\n\n if (req.method === \"POST\") {\n const body = await parseBody(req);\n\n // ── POST /join ──────────────────────────────────────────────────────\n if (url.pathname === \"/join\") {\n // Accept share token OR legacy type-based join\n const shareToken = String(body.token ?? \"\");\n const legacyType = String(body.type ?? \"\");\n\n let authority: AuthorityLevel;\n\n if (shareToken) {\n const tokenAuthority = tokens.validateShareToken(shareToken);\n if (!tokenAuthority) return jsonError(res, 403, \"Invalid share token\");\n authority = tokenAuthority;\n } else if (legacyType === \"guest\") {\n authority = \"observer\";\n } else if (legacyType === \"human\") {\n authority = \"participant\";\n } else {\n // Default: agent joins as participant\n authority = \"participant\";\n }\n\n const participantType = String(body.type ?? \"human\") as \"human\" | \"agent\";\n const name = String(body.name ?? randomName());\n\n if (authority === \"observer\") {\n const id = `obs_${randomUUID().slice(0, 8)}`;\n const channel = room.observe();\n const sessionToken = tokens.createSessionToken(id, \"observer\");\n\n observers.set(sessionToken, { id, authority: \"observer\", channel, sessionToken });\n idToSession.set(id, sessionToken);\n\n const participantList = room.listParticipants().map((p) => ({\n id: p.id,\n name: p.name,\n type: p.type,\n authority: p.authority ?? \"participant\",\n }));\n\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({\n sessionToken,\n participantId: id,\n roomName,\n roomId: room.roomId,\n participants: participantList,\n authority: \"observer\",\n }));\n return;\n }\n\n // admin or participant — connect as a real participant\n const id = `${participantType}_${randomUUID().slice(0, 8)}`;\n const channel = await room.connect(id, name, { type: participantType, authority });\n const sessionToken = tokens.createSessionToken(id, authority);\n\n participants.set(sessionToken, { id, name, authority, channel, sessionToken });\n idToSession.set(id, sessionToken);\n\n const participantList = room.listParticipants().map((p) => ({\n id: p.id,\n name: p.name,\n type: p.type,\n authority: p.authority ?? \"participant\",\n }));\n\n log(`${name} joined (${authority})`);\n\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({\n sessionToken,\n participantId: id,\n roomName,\n roomId: room.roomId,\n participants: participantList,\n authority,\n }));\n return;\n }\n\n // ── All remaining POST endpoints require a session token ────────────\n\n const sessionToken = String(body.token ?? \"\");\n const session = getSession(sessionToken);\n\n // ── POST /message ───────────────────────────────────────────────────\n if (url.pathname === \"/message\") {\n if (!session) return jsonError(res, 401, \"Invalid session token\");\n if (session.authority === \"observer\") return jsonError(res, 403, \"Observers cannot send messages\");\n const content = String(body.content ?? \"\");\n const replyTo = body.replyTo ? String(body.replyTo) : undefined;\n if (!content) return jsonError(res, 400, \"Empty message\");\n\n const p = participants.get(sessionToken);\n if (!p) return jsonError(res, 403, \"Not a participant\");\n\n const msg = await p.channel.sendMessage(content, replyTo);\n jsonOk(res, { messageId: msg.id });\n return;\n }\n\n // ── POST /event ─────────────────────────────────────────────────────\n if (url.pathname === \"/event\") {\n if (!session) return jsonError(res, 401, \"Invalid session token\");\n if (session.authority === \"observer\") return jsonError(res, 403, \"Observers cannot emit events\");\n const event = body.event as RoomEvent | undefined;\n if (!event) return jsonError(res, 400, \"Missing event\");\n\n const p = participants.get(sessionToken);\n if (!p) return jsonError(res, 403, \"Not a participant\");\n\n await p.channel.emit(event);\n jsonOk(res);\n return;\n }\n\n // ── POST /set-mode ──────────────────────────────────────────────────\n if (url.pathname === \"/set-mode\") {\n if (!session) return jsonError(res, 401, \"Invalid session token\");\n const targetId = body.participantId ? String(body.participantId) : session.id;\n const mode = String(body.mode ?? \"\");\n if (!mode) return jsonError(res, 400, \"Missing mode\");\n\n // Setting someone else's mode requires admin\n if (targetId !== session.id && session.authority !== \"admin\") {\n return jsonError(res, 403, \"Only admins can change other participants' modes\");\n }\n\n // Emit mode_changed activity event\n const p = participants.get(sessionToken);\n if (!p) return jsonError(res, 403, \"Not a participant\");\n\n await p.channel.emit(createEvent<ActivityEvent>({\n type: \"Activity\",\n category: \"ACTIVITY\",\n room_id: room.roomId,\n participant_id: targetId,\n action: \"mode_changed\",\n detail: { mode },\n }));\n\n jsonOk(res);\n return;\n }\n\n // ── POST /set-authority ──────────────────────────────────────────────\n if (url.pathname === \"/set-authority\") {\n if (!session) return jsonError(res, 401, \"Invalid session token\");\n if (session.authority !== \"admin\") return jsonError(res, 403, \"Only admins can change authority\");\n const targetId = String(body.participantId ?? \"\");\n const newAuthority = String(body.authority ?? \"\") as AuthorityLevel;\n if (!targetId) return jsonError(res, 400, \"Missing participantId\");\n if (![\"admin\", \"participant\", \"observer\"].includes(newAuthority)) {\n return jsonError(res, 400, \"Invalid authority. Must be admin, participant, or observer.\");\n }\n if (targetId === session.id) return jsonError(res, 400, \"Cannot change own authority\");\n\n // Update all three places: ConnectedParticipant, TokenManager session, Room participant\n const targetSession = idToSession.get(targetId);\n if (!targetSession) return jsonError(res, 404, \"Participant not found\");\n const target = participants.get(targetSession);\n if (!target) return jsonError(res, 404, \"Participant not found\");\n\n target.authority = newAuthority;\n tokens.updateSessionAuthority(targetSession, newAuthority);\n room.setParticipantAuthority(targetId, newAuthority);\n\n // Emit authority_changed activity event\n const p = participants.get(sessionToken);\n if (p) {\n await p.channel.emit(createEvent<ActivityEvent>({\n type: \"Activity\",\n category: \"ACTIVITY\",\n room_id: room.roomId,\n participant_id: targetId,\n action: \"authority_changed\",\n detail: { authority: newAuthority },\n }));\n }\n\n log(`${target.name} authority → ${newAuthority}`);\n jsonOk(res);\n return;\n }\n\n // ── POST /kick ──────────────────────────────────────────────────────\n if (url.pathname === \"/kick\") {\n if (!session) return jsonError(res, 401, \"Invalid session token\");\n if (session.authority !== \"admin\") return jsonError(res, 403, \"Only admins can kick\");\n const targetId = String(body.participantId ?? \"\");\n if (!targetId) return jsonError(res, 400, \"Missing participantId\");\n\n // Find and disconnect the target\n const targetSession = idToSession.get(targetId);\n if (targetSession) {\n const target = participants.get(targetSession) ?? observers.get(targetSession);\n if (target) {\n await target.channel.disconnect();\n participants.delete(targetSession);\n observers.delete(targetSession);\n idToSession.delete(targetId);\n tokens.revokeSessionToken(targetSession);\n // Close SSE connection\n const sse = sseConnections.get(targetId);\n if (sse) {\n sse.end();\n sseConnections.delete(targetId);\n }\n log(`kicked ${targetId}`);\n }\n }\n\n jsonOk(res);\n return;\n }\n\n // ── POST /share ─────────────────────────────────────────────────────\n if (url.pathname === \"/share\") {\n if (!session) return jsonError(res, 401, \"Invalid session token\");\n if (session.authority === \"observer\") return jsonError(res, 403, \"Observers cannot create share links\");\n\n const targetAuthority = (body.authority as AuthorityLevel) ?? undefined;\n\n const links: Record<string, string> = {};\n\n if (targetAuthority) {\n // Generate a specific link\n const token = tokens.generateShareToken(session.authority, targetAuthority);\n if (!token) return jsonError(res, 403, `Cannot generate ${targetAuthority} link`);\n links[targetAuthority] = buildShareUrl(publicUrl, token);\n } else {\n // Generate all links the caller can create\n const tiers: AuthorityLevel[] = [\"admin\", \"participant\", \"observer\"];\n for (const tier of tiers) {\n const token = tokens.generateShareToken(session.authority, tier);\n if (token) links[tier] = buildShareUrl(publicUrl, token);\n }\n }\n\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ links }));\n return;\n }\n\n // ── POST /disconnect ────────────────────────────────────────────────\n if (url.pathname === \"/disconnect\") {\n // Accept either session token or legacy participantId/agentId\n const token = String(body.token ?? \"\");\n const legacyId = String(body.participantId ?? body.agentId ?? \"\");\n\n let targetToken = token;\n if (!targetToken && legacyId) {\n targetToken = idToSession.get(legacyId) ?? \"\";\n }\n\n if (targetToken) {\n const p = participants.get(targetToken);\n if (p) {\n await p.channel.disconnect();\n participants.delete(targetToken);\n idToSession.delete(p.id);\n tokens.revokeSessionToken(targetToken);\n const sse = sseConnections.get(p.id);\n if (sse) { sse.end(); sseConnections.delete(p.id); }\n log(`${p.name} disconnected`);\n }\n\n const o = observers.get(targetToken);\n if (o) {\n await o.channel.disconnect();\n observers.delete(targetToken);\n idToSession.delete(o.id);\n tokens.revokeSessionToken(targetToken);\n const sse = sseConnections.get(o.id);\n if (sse) { sse.end(); sseConnections.delete(o.id); }\n }\n }\n\n jsonOk(res);\n return;\n }\n }\n\n res.writeHead(404).end(\"Not found\");\n });\n\n httpServer.on(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n console.error(`\\nPort ${port} is already in use. Another stoops instance may be running.`);\n console.error(` Kill it: lsof -ti :${port} | xargs kill`);\n console.error(` Or use: stoops --port ${port + 1}\\n`);\n process.exit(1);\n }\n throw err;\n });\n\n await new Promise<void>((resolve) => {\n httpServer.listen(port, \"0.0.0.0\", () => resolve());\n });\n\n // Start tunnel if --share\n if (options.share) {\n tunnelProcess = await startTunnel(port);\n if (tunnelProcess) {\n const tunnelUrl = await waitForTunnelUrl(tunnelProcess);\n if (tunnelUrl) publicUrl = tunnelUrl;\n }\n }\n\n // Generate share tokens on boot\n const adminToken = tokens.generateShareToken(\"admin\", \"admin\")!;\n const participantToken = tokens.generateShareToken(\"admin\", \"participant\")!;\n\n if (options.headless) {\n process.stdout.write(JSON.stringify({ serverUrl, publicUrl, roomName, adminToken, participantToken }) + \"\\n\");\n } else if (!options.quiet) {\n let version = process.env.npm_package_version ?? \"\";\n if (!version) {\n try {\n const require = createRequire(import.meta.url);\n const pkg = require(\"../../package.json\");\n version = pkg.version ?? \"unknown\";\n } catch {\n version = \"unknown\";\n }\n }\n const adminUrl = buildShareUrl(publicUrl, adminToken);\n const joinUrl = buildShareUrl(publicUrl, participantToken);\n\n console.log(`\n stoops v${version}\n\n Room: ${roomName}\n Server: ${serverUrl}${publicUrl !== serverUrl ? `\\n Tunnel: ${publicUrl}` : \"\"}\n\n Join: stoops join ${joinUrl}\n Admin: stoops join ${adminUrl}\n Claude: stoops run claude → then tell agent to join: ${joinUrl}\n`);\n }\n\n // ── Graceful shutdown ──────────────────────────────────────────────────\n\n const shutdown = async () => {\n log(\"shutting down...\");\n if (tunnelProcess) { tunnelProcess.kill(); tunnelProcess = null; }\n for (const [id, sse] of sseConnections) { sse.end(); sseConnections.delete(id); }\n for (const p of participants.values()) { await p.channel.disconnect().catch(() => {}); }\n for (const o of observers.values()) { await o.channel.disconnect().catch(() => {}); }\n await new Promise<void>((resolve, reject) => {\n httpServer.close((err) => (err ? reject(err) : resolve()));\n });\n process.exit(0);\n };\n\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n\n return { serverUrl, publicUrl, roomName, adminToken, participantToken };\n}\n\n// ── Server log ────────────────────────────────────────────────────────────────\n\nfunction logServer(message: string): void {\n console.log(` [${formatTimestamp(new Date())}] ${message}`);\n}\n\n// ── Cloudflared tunnel ───────────────────────────────────────────────────────\n\nfunction cloudflaredAvailable(): boolean {\n try {\n execFileSync(\"which\", [\"cloudflared\"], { stdio: \"ignore\" });\n return true;\n } catch {\n return false;\n }\n}\n\nasync function startTunnel(port: number): Promise<ChildProcess | null> {\n if (!cloudflaredAvailable()) {\n console.error(\" --share requires cloudflared. Install: brew install cloudflared\");\n return null;\n }\n\n const child = spawn(\"cloudflared\", [\"tunnel\", \"--url\", `http://localhost:${port}`], {\n stdio: [\"ignore\", \"ignore\", \"pipe\"],\n });\n\n child.on(\"error\", () => {\n // cloudflared failed to start\n });\n\n return child;\n}\n\nfunction waitForTunnelUrl(child: ChildProcess, timeoutMs = 15000): Promise<string | null> {\n return new Promise((resolve) => {\n let resolved = false;\n let buffer = \"\";\n\n const timer = setTimeout(() => {\n if (!resolved) { resolved = true; resolve(null); }\n }, timeoutMs);\n\n child.stderr?.on(\"data\", (chunk: Buffer) => {\n buffer += chunk.toString();\n const match = buffer.match(/https:\\/\\/[a-z0-9-]+\\.trycloudflare\\.com/);\n if (match && !resolved) {\n resolved = true;\n clearTimeout(timer);\n resolve(match[0]);\n }\n });\n\n child.on(\"exit\", () => {\n if (!resolved) { resolved = true; clearTimeout(timer); resolve(null); }\n });\n });\n}\n","/**\n * Auth token system for stoops share links and session management.\n *\n * Two token types:\n * - Share tokens — embedded in URLs, map to an authority tier.\n * Anyone with the link joins at that tier.\n * - Session tokens — issued on join, identify a participant + authority.\n * Used for all subsequent API calls.\n */\n\nimport { randomBytes } from \"node:crypto\";\nimport type { AuthorityLevel } from \"../core/types.js\";\n\ninterface SessionData {\n participantId: string;\n authority: AuthorityLevel;\n}\n\nexport class TokenManager {\n /** share token hash → authority level */\n private _shareTokens = new Map<string, AuthorityLevel>();\n /** session token → participant data */\n private _sessionTokens = new Map<string, SessionData>();\n\n /**\n * Generate a share token at the given authority tier.\n * Callers can only generate tokens at their own tier or below.\n */\n generateShareToken(callerAuthority: AuthorityLevel, targetAuthority: AuthorityLevel): string | null {\n if (!canGrant(callerAuthority, targetAuthority)) return null;\n const token = randomBytes(16).toString(\"hex\");\n this._shareTokens.set(token, targetAuthority);\n return token;\n }\n\n /** Validate a share token and return its authority level. */\n validateShareToken(token: string): AuthorityLevel | null {\n return this._shareTokens.get(token) ?? null;\n }\n\n /** Create a session token for a participant. */\n createSessionToken(participantId: string, authority: AuthorityLevel): string {\n const token = randomBytes(16).toString(\"hex\");\n this._sessionTokens.set(token, { participantId, authority });\n return token;\n }\n\n /** Validate a session token and return participant data. */\n validateSessionToken(token: string): SessionData | null {\n return this._sessionTokens.get(token) ?? null;\n }\n\n /** Revoke a session token (on disconnect). */\n revokeSessionToken(token: string): void {\n this._sessionTokens.delete(token);\n }\n\n /** Update the authority level for an existing session. */\n updateSessionAuthority(token: string, newAuthority: AuthorityLevel): boolean {\n const data = this._sessionTokens.get(token);\n if (!data) return false;\n data.authority = newAuthority;\n return true;\n }\n\n /** Find a session token by participant ID (for cleanup). */\n findSessionByParticipant(participantId: string): string | null {\n for (const [token, data] of this._sessionTokens) {\n if (data.participantId === participantId) return token;\n }\n return null;\n }\n}\n\n/** Authority tier ordering: admin > participant > observer. */\nconst TIER_ORDER: Record<AuthorityLevel, number> = {\n admin: 2,\n participant: 1,\n observer: 0,\n};\n\n/** Can a caller at `callerLevel` grant authority at `targetLevel`? */\nfunction canGrant(callerLevel: AuthorityLevel, targetLevel: AuthorityLevel): boolean {\n return TIER_ORDER[callerLevel] >= TIER_ORDER[targetLevel];\n}\n\n/** Build a share URL from a base URL and token. */\nexport function buildShareUrl(baseUrl: string, token: string): string {\n const url = new URL(baseUrl);\n url.searchParams.set(\"token\", token);\n return url.toString();\n}\n\n/** Extract a token from a share URL. */\nexport function extractToken(url: string): string | null {\n try {\n const parsed = new URL(url);\n return parsed.searchParams.get(\"token\");\n } catch {\n return null;\n }\n}\n","/**\n * stoops join — connect to a room as a human participant.\n *\n * Opens the TUI and connects to a stoops server over HTTP.\n * Events stream in via SSE, messages sent via POST /message.\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport { createInterface } from \"node:readline\";\nimport { randomName } from \"../core/names.js\";\nimport type { RoomEvent } from \"../core/events.js\";\nimport type { AuthorityLevel } from \"../core/types.js\";\nimport { formatTimestamp } from \"../agent/prompts.js\";\nimport { startTUI, type TUIHandle, type DisplayEvent } from \"./tui.js\";\nimport { extractToken, buildShareUrl } from \"./auth.js\";\n\nexport interface JoinOptions {\n server: string;\n name?: string;\n guest?: boolean;\n /** Share URL to display before TUI starts (for host+join mode with --share). */\n shareUrl?: string;\n /** Skip TUI — stream events as JSON to stdout, read messages from stdin. */\n headless?: boolean;\n}\n\nexport async function join(options: JoinOptions): Promise<void> {\n // Extract token from URL if present\n const token = extractToken(options.server);\n // Strip query params to get clean server URL\n let serverUrl: string;\n try {\n const parsed = new URL(options.server);\n parsed.search = \"\";\n serverUrl = parsed.toString().replace(/\\/$/, \"\");\n } catch {\n serverUrl = options.server.replace(/\\/$/, \"\");\n }\n\n const name = options.name ?? randomName();\n const isGuest = options.guest ?? false;\n\n // ── Register with server ────────────────────────────────────────────────\n\n let sessionToken: string;\n let participantId: string;\n let roomName: string;\n let authority: AuthorityLevel;\n let participants: Array<{ id: string; name: string; type: string; authority?: string }>;\n\n try {\n const joinBody: Record<string, unknown> = {};\n if (token) {\n joinBody.token = token;\n joinBody.type = \"human\";\n joinBody.name = name;\n } else if (isGuest) {\n joinBody.type = \"guest\";\n } else {\n joinBody.type = \"human\";\n joinBody.name = name;\n }\n\n const res = await fetch(`${serverUrl}/join`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(joinBody),\n });\n\n if (!res.ok) {\n const err = await res.text();\n console.error(`Failed to join: ${err}`);\n process.exit(1);\n }\n\n const data = await res.json() as Record<string, unknown>;\n sessionToken = String(data.sessionToken ?? \"\");\n participantId = String(data.participantId);\n roomName = String(data.roomName);\n authority = (data.authority as AuthorityLevel) ?? \"participant\";\n participants = (data.participants as Array<{ id: string; name: string; type: string; authority?: string }>) ?? [];\n } catch {\n console.error(`Cannot reach stoops server at ${serverUrl}. Is it running?`);\n process.exit(1);\n }\n\n // ── Disconnect helper ───────────────────────────────────────────────────\n\n let disconnected = false;\n let cleanupStream: (() => void) | null = null;\n const disconnect = async () => {\n if (disconnected) return;\n disconnected = true;\n cleanupStream?.();\n try {\n await fetch(`${serverUrl}/disconnect`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token: sessionToken }),\n });\n } catch {\n // Server may be down\n }\n };\n\n // ── Headless mode — skip TUI, stream events as JSON, read messages from stdin ──\n\n if (options.headless) {\n const sseController = new AbortController();\n const cleanup = async () => {\n sseController.abort();\n await disconnect();\n };\n\n process.on(\"SIGINT\", async () => { await cleanup(); process.exit(0); });\n process.on(\"SIGTERM\", async () => { await cleanup(); process.exit(0); });\n\n // Read messages from stdin and send them\n const rl = createInterface({ input: process.stdin, terminal: false });\n rl.on(\"line\", async (line) => {\n const content = line.trim();\n if (!content || authority === \"observer\") return;\n try {\n await fetch(`${serverUrl}/message`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token: sessionToken, content }),\n });\n } catch { /* server may be down */ }\n });\n\n // Stream events from SSE and write as JSON lines to stdout\n try {\n const res = await fetch(`${serverUrl}/events`, {\n method: \"POST\",\n headers: { Accept: \"text/event-stream\", Authorization: `Bearer ${sessionToken}` },\n signal: sseController.signal,\n });\n\n if (!res.ok || !res.body) {\n process.stderr.write(\"Failed to connect event stream\\n\");\n await cleanup();\n process.exit(1);\n }\n\n const reader = res.body.getReader();\n const decoder = new TextDecoder();\n let buf = \"\";\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buf += decoder.decode(value, { stream: true });\n const parts = buf.split(\"\\n\\n\");\n buf = parts.pop()!;\n for (const part of parts) {\n const dataLine = part.split(\"\\n\").find((l) => l.startsWith(\"data: \"));\n if (!dataLine) continue;\n try {\n const event = JSON.parse(dataLine.slice(6));\n process.stdout.write(JSON.stringify(event) + \"\\n\");\n } catch { /* malformed */ }\n }\n }\n } catch {\n // Stream ended or aborted\n }\n\n if (!disconnected) { await cleanup(); }\n process.exit(0);\n }\n\n // ── Start TUI ───────────────────────────────────────────────────────────\n\n const isReadOnly = authority === \"observer\" || isGuest;\n\n // ── Slash command helper ──────────────────────────────────────────────\n\n function systemEvent(content: string): void {\n tui.push({\n id: randomUUID(),\n ts: formatTimestamp(new Date()),\n kind: \"system\",\n content,\n });\n }\n\n async function handleSlashCommand(input: string): Promise<void> {\n const parts = input.slice(1).split(/\\s+/);\n const cmd = parts[0]?.toLowerCase();\n const args = parts.slice(1);\n\n switch (cmd) {\n // ── /who ──────────────────────────────────────────────────────\n case \"who\": {\n try {\n const res = await fetch(`${serverUrl}/participants?token=${sessionToken}`);\n if (!res.ok) { systemEvent(\"Failed to get participant list.\"); return; }\n const data = (await res.json()) as { participants: Array<{ id: string; name: string; type: string; authority?: string }> };\n const lines = data.participants.map((p) => {\n const auth = p.authority ?? \"participant\";\n return ` ${p.type === \"agent\" ? \"agent\" : \"human\"} ${p.name} (${auth})`;\n });\n systemEvent(`Participants:\\n${lines.join(\"\\n\")}`);\n } catch {\n systemEvent(\"Failed to reach server.\");\n }\n return;\n }\n\n // ── /leave ────────────────────────────────────────────────────\n case \"leave\": {\n await disconnect();\n tui.stop();\n process.exit(0);\n return;\n }\n\n // ── /kick <name> (admin only) ─────────────────────────────────\n case \"kick\": {\n if (authority !== \"admin\") { systemEvent(\"Only admins can kick.\"); return; }\n const targetName = args[0];\n if (!targetName) { systemEvent(\"Usage: /kick <name>\"); return; }\n\n // Look up participant by name\n try {\n const res = await fetch(`${serverUrl}/participants?token=${sessionToken}`);\n if (!res.ok) { systemEvent(\"Failed to get participant list.\"); return; }\n const data = (await res.json()) as { participants: Array<{ id: string; name: string }> };\n const target = data.participants.find((p) => p.name.toLowerCase() === targetName.toLowerCase());\n if (!target) { systemEvent(`Participant \"${targetName}\" not found.`); return; }\n\n const kickRes = await fetch(`${serverUrl}/kick`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token: sessionToken, participantId: target.id }),\n });\n if (!kickRes.ok) { systemEvent(`Failed to kick: ${await kickRes.text()}`); return; }\n systemEvent(`Kicked ${targetName}.`);\n } catch {\n systemEvent(\"Failed to reach server.\");\n }\n return;\n }\n\n // ── /mute <name> (admin only) — demote to observer ────────────\n case \"mute\": {\n if (authority !== \"admin\") { systemEvent(\"Only admins can mute.\"); return; }\n const targetName = args[0];\n if (!targetName) { systemEvent(\"Usage: /mute <name>\"); return; }\n\n try {\n const res = await fetch(`${serverUrl}/participants?token=${sessionToken}`);\n if (!res.ok) { systemEvent(\"Failed to get participant list.\"); return; }\n const data = (await res.json()) as { participants: Array<{ id: string; name: string }> };\n const target = data.participants.find((p) => p.name.toLowerCase() === targetName.toLowerCase());\n if (!target) { systemEvent(`Participant \"${targetName}\" not found.`); return; }\n\n const authRes = await fetch(`${serverUrl}/set-authority`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token: sessionToken, participantId: target.id, authority: \"observer\" }),\n });\n if (!authRes.ok) { systemEvent(`Failed to mute: ${await authRes.text()}`); return; }\n systemEvent(`Muted ${targetName} (observer).`);\n } catch {\n systemEvent(\"Failed to reach server.\");\n }\n return;\n }\n\n // ── /unmute <name> (admin only) — restore to participant ──────\n case \"unmute\": {\n if (authority !== \"admin\") { systemEvent(\"Only admins can unmute.\"); return; }\n const targetName = args[0];\n if (!targetName) { systemEvent(\"Usage: /unmute <name>\"); return; }\n\n try {\n const res = await fetch(`${serverUrl}/participants?token=${sessionToken}`);\n if (!res.ok) { systemEvent(\"Failed to get participant list.\"); return; }\n const data = (await res.json()) as { participants: Array<{ id: string; name: string }> };\n const target = data.participants.find((p) => p.name.toLowerCase() === targetName.toLowerCase());\n if (!target) { systemEvent(`Participant \"${targetName}\" not found.`); return; }\n\n const authRes = await fetch(`${serverUrl}/set-authority`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token: sessionToken, participantId: target.id, authority: \"participant\" }),\n });\n if (!authRes.ok) { systemEvent(`Failed to unmute: ${await authRes.text()}`); return; }\n systemEvent(`Unmuted ${targetName} (participant).`);\n } catch {\n systemEvent(\"Failed to reach server.\");\n }\n return;\n }\n\n // ── /setmode <name> <mode> (admin only) ───────────────────────\n case \"setmode\": {\n if (authority !== \"admin\") { systemEvent(\"Only admins can set modes.\"); return; }\n const targetName = args[0];\n const mode = args[1];\n if (!targetName || !mode) { systemEvent(\"Usage: /setmode <name> <mode>\"); return; }\n\n try {\n const res = await fetch(`${serverUrl}/participants?token=${sessionToken}`);\n if (!res.ok) { systemEvent(\"Failed to get participant list.\"); return; }\n const data = (await res.json()) as { participants: Array<{ id: string; name: string }> };\n const target = data.participants.find((p) => p.name.toLowerCase() === targetName.toLowerCase());\n if (!target) { systemEvent(`Participant \"${targetName}\" not found.`); return; }\n\n const modeRes = await fetch(`${serverUrl}/set-mode`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token: sessionToken, participantId: target.id, mode }),\n });\n if (!modeRes.ok) { systemEvent(`Failed to set mode: ${await modeRes.text()}`); return; }\n systemEvent(`Set ${targetName} to ${mode}.`);\n } catch {\n systemEvent(\"Failed to reach server.\");\n }\n return;\n }\n\n // ── /share [--as <tier>] ──────────────────────────────────────\n case \"share\": {\n if (authority === \"observer\") { systemEvent(\"Observers cannot create share links.\"); return; }\n\n let targetAuthority: string | undefined;\n if (args[0] === \"--as\" && args[1]) {\n targetAuthority = args[1];\n }\n\n try {\n const body: Record<string, unknown> = { token: sessionToken };\n if (targetAuthority) body.authority = targetAuthority;\n\n const res = await fetch(`${serverUrl}/share`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n if (!res.ok) { systemEvent(`Failed: ${await res.text()}`); return; }\n const data = (await res.json()) as { links: Record<string, string> };\n const lines = Object.entries(data.links).map(([tier, url]) =>\n ` ${tier}: stoops join ${url}`\n );\n systemEvent(`Share links:\\n${lines.join(\"\\n\")}`);\n } catch {\n systemEvent(\"Failed to reach server.\");\n }\n return;\n }\n\n default:\n systemEvent(`Unknown command: /${cmd}`);\n }\n }\n\n // Print share info via console.log BEFORE Ink renders. This lands in the\n // terminal buffer above Ink's render area — plain text, no ANSI codes,\n // fully selectable. Each line is a complete copyable command.\n if (options.shareUrl) {\n console.log();\n console.log(` Invite a friend: npx stoops join \"${options.shareUrl}\"`);\n console.log(` Connect Claude Code: npx stoops run claude → then tell agent to join: ${options.shareUrl}`);\n console.log();\n }\n\n const tui = startTUI({\n roomName,\n readOnly: isReadOnly,\n isAdmin: authority === \"admin\",\n onSend: isReadOnly ? undefined : async (content: string) => {\n // Intercept slash commands\n if (content.startsWith(\"/\")) {\n await handleSlashCommand(content);\n return;\n }\n\n try {\n await fetch(`${serverUrl}/message`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token: sessionToken, content }),\n });\n } catch {\n // Server may be down — silently fail\n }\n },\n onCtrlC: async () => {\n await disconnect();\n tui.stop();\n process.exit(0);\n },\n });\n\n // Set initial agent names + participant names\n const agentNames = participants\n .filter((p) => p.type === \"agent\")\n .map((p) => p.name);\n if (agentNames.length > 0) {\n tui.setAgentNames(agentNames);\n }\n const participantNames = new Set(\n participants.filter((p) => p.id !== participantId).map((p) => p.name),\n );\n tui.setParticipants([...participantNames]);\n\n // ── Connect SSE event stream ────────────────────────────────────────────\n // ⚠️ MUST use POST — DO NOT change to GET.\n // Cloudflare Quick Tunnels buffer GET streaming responses and only flush\n // when the connection closes. POST streams in real-time. (cloudflared#1449)\n // https://github.com/cloudflare/cloudflared/issues/1449\n\n {\n const participantTypes = new Map<string, \"human\" | \"agent\">();\n for (const p of participants) {\n participantTypes.set(p.id, p.type as \"human\" | \"agent\");\n }\n const currentAgents = new Set(agentNames);\n let sseController: AbortController | null = null;\n\n cleanupStream = () => {\n if (sseController) { sseController.abort(); sseController = null; }\n };\n\n const connectSSE = async () => {\n sseController = new AbortController();\n\n try {\n const res = await fetch(`${serverUrl}/events`, {\n method: \"POST\",\n headers: {\n Accept: \"text/event-stream\",\n Authorization: `Bearer ${sessionToken}`,\n },\n signal: sseController.signal,\n });\n\n if (!res.ok || !res.body) {\n console.error(\"Failed to connect event stream\");\n await disconnect();\n process.exit(1);\n }\n\n const reader = res.body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const parts = buffer.split(\"\\n\\n\");\n buffer = parts.pop()!;\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 & { _replyToName?: string };\n\n if (event.type === \"ParticipantJoined\") {\n participantTypes.set(event.participant.id, event.participant.type);\n }\n\n const displayEvent = toDisplayEvent(event, participantId, participantTypes);\n if (displayEvent) {\n tui.push(displayEvent);\n }\n\n if (event.type === \"ParticipantJoined\") {\n if (event.participant.type === \"agent\") {\n currentAgents.add(event.participant.name);\n tui.setAgentNames([...currentAgents]);\n }\n if (event.participant.id !== participantId) {\n participantNames.add(event.participant.name);\n tui.setParticipants([...participantNames]);\n }\n }\n if (event.type === \"ParticipantLeft\") {\n if (event.participant.type === \"agent\") {\n currentAgents.delete(event.participant.name);\n tui.setAgentNames([...currentAgents]);\n }\n participantTypes.delete(event.participant.id);\n participantNames.delete(event.participant.name);\n tui.setParticipants([...participantNames]);\n }\n } catch {\n // Malformed event — skip\n }\n }\n }\n\n // Stream ended — server closed connection\n if (!disconnected) {\n tui.stop();\n console.log(\"\\nServer disconnected.\");\n process.exit(0);\n }\n } catch {\n if (!disconnected) {\n tui.stop();\n console.log(\"\\nServer disconnected.\");\n process.exit(0);\n }\n }\n };\n\n connectSSE();\n }\n\n // ── Graceful shutdown ───────────────────────────────────────────────────\n\n process.on(\"SIGINT\", async () => {\n await disconnect();\n tui.stop();\n process.exit(0);\n });\n process.on(\"SIGTERM\", async () => {\n await disconnect();\n tui.stop();\n process.exit(0);\n });\n}\n\n// ── RoomEvent → DisplayEvent conversion ───────────────────────────────────────\n\nfunction toDisplayEvent(\n event: RoomEvent & { _replyToName?: string },\n selfId: string,\n participantTypes: Map<string, \"human\" | \"agent\">,\n): DisplayEvent | null {\n const ts = formatTimestamp(new Date(event.timestamp));\n\n switch (event.type) {\n case \"MessageSent\": {\n const msg = event.message;\n const senderType = participantTypes.get(msg.sender_id) ?? \"human\";\n return {\n id: msg.id,\n ts,\n kind: \"message\",\n senderName: msg.sender_name,\n senderType,\n isSelf: msg.sender_id === selfId,\n content: msg.content,\n replyToName: event._replyToName ?? undefined,\n };\n }\n case \"ParticipantJoined\":\n return {\n id: randomUUID(),\n ts,\n kind: \"join\",\n name: event.participant.name,\n participantType: event.participant.type,\n };\n case \"ParticipantLeft\":\n return {\n id: randomUUID(),\n ts,\n kind: \"leave\",\n name: event.participant.name,\n participantType: event.participant.type,\n };\n case \"Activity\":\n if (event.action === \"mode_changed\") {\n return {\n id: randomUUID(),\n ts,\n kind: \"mode\",\n mode: String((event.detail as Record<string, unknown>)?.mode ?? \"\"),\n };\n }\n if (event.action === \"authority_changed\") {\n const newAuth = String((event.detail as Record<string, unknown>)?.authority ?? \"\");\n return {\n id: randomUUID(),\n ts,\n kind: \"system\",\n content: `authority → ${newAuth}`,\n };\n }\n return null;\n default:\n return null;\n }\n}\n","/**\n * stoops TUI — ink-based terminal UI for the room server.\n *\n * Uses ink's <Static> for events (rendered once, selectable terminal text)\n * and a dynamic footer for input + status. Same architecture as Claude Code.\n */\n\nimport React, { useState, useEffect, useCallback, useMemo } from \"react\";\nimport { render, Box, Text, Static, useStdout, useInput } from \"ink\";\n\n// ── Palette (from stoops-app) ─────────────────────────────────────────────────\n\nconst C = {\n cyan: \"#00d4ff\",\n purple: \"#8b5cf6\",\n orange: \"#ff8c42\",\n pink: \"#f472b6\",\n green: \"#34d399\",\n yellow: \"#fbbf24\",\n danger: \"#f87171\",\n text: \"#eceff4\",\n secondary: \"#b0b7c4\",\n dim: \"#7e8798\",\n muted: \"#5b6679\",\n border: \"#475264\",\n} as const;\n\nconst AGENT_COLORS = [C.cyan, C.purple, C.orange, C.pink, C.green, C.yellow] as const;\nconst SIGILS = [\"◆\", \"▲\", \"●\", \"■\", \"★\", \"◉\", \"◈\", \"▸\"] as const;\n\n// ── Banner ───────────────────────────────────────────────────────────────────\n// Figlet \"slant\" font, colored with a purple → cyan gradient per line.\n\nconst BANNER_LINES = [\n \" __ \",\n \" _____/ /_____ ____ ____ _____\",\n \" / ___/ __/ __ \\\\/ __ \\\\/ __ \\\\/ ___/\",\n \" (__ ) /_/ /_/ / /_/ / /_/ (__ ) \",\n \"/____/\\\\__/\\\\____/\\\\____/ .___/____/ \",\n \" /_/ \",\n];\n\nconst GRADIENT = [\"#9b6dff\", \"#7c8bff\", \"#5da8ff\", \"#3dc4ff\", \"#1ddcff\", \"#00e8ff\"];\n\n// ── Slash commands ────────────────────────────────────────────────────────────\n\ninterface SlashParam {\n label: string; // display hint: \"name\", \"mode\", etc.\n completions?: string[] | \"participants\"; // static values, dynamic lookup, or undefined (hint only)\n}\n\ninterface SlashCommand {\n name: string;\n description: string;\n adminOnly?: boolean;\n params?: SlashParam[];\n}\n\nconst ENGAGEMENT_MODES = [\n \"everyone\", \"people\", \"agents\", \"me\",\n \"standby-everyone\", \"standby-people\", \"standby-agents\", \"standby-me\",\n];\n\nconst SLASH_COMMANDS: SlashCommand[] = [\n { name: \"/who\", description: \"List participants\" },\n { name: \"/leave\", description: \"Disconnect and exit\" },\n { name: \"/share\", description: \"Generate share links\" },\n { name: \"/kick\", description: \"Remove a participant\", adminOnly: true, params: [\n { label: \"name\", completions: \"participants\" },\n ]},\n { name: \"/mute\", description: \"Make read-only (observer)\", adminOnly: true, params: [\n { label: \"name\", completions: \"participants\" },\n ]},\n { name: \"/unmute\", description: \"Restore to participant\", adminOnly: true, params: [\n { label: \"name\", completions: \"participants\" },\n ]},\n { name: \"/setmode\", description: \"Set engagement mode\", adminOnly: true, params: [\n { label: \"name\", completions: \"participants\" },\n { label: \"mode\", completions: ENGAGEMENT_MODES },\n ]},\n];\n\nconst CMD_DISPLAY_COL = 26; // width for command + params display column\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport type DisplayEvent =\n | { id: string; ts: string; kind: \"message\"; senderName: string; senderType: \"human\" | \"agent\"; isSelf: boolean; content: string; replyToName?: string }\n | { id: string; ts: string; kind: \"join\"; name: string; participantType: \"human\" | \"agent\" }\n | { id: string; ts: string; kind: \"leave\"; name: string; participantType: \"human\" | \"agent\" }\n | { id: string; ts: string; kind: \"mode\"; mode: string }\n | { id: string; ts: string; kind: \"system\"; content: string };\n\nexport interface TUIHandle {\n push(event: DisplayEvent): void;\n setAgentNames(names: string[]): void;\n setParticipants(names: string[]): void;\n stop(): void;\n}\n\nexport interface TUIOptions {\n roomName: string;\n onSend?(content: string): void;\n onCtrlC?(): void;\n readOnly?: boolean;\n isAdmin?: boolean;\n}\n\n// ── Identity (seed → color + sigil) ──────────────────────────────────────────\n\nfunction seedHash(s: string): number {\n let h = 0;\n for (let i = 0; i < s.length; i++) h = ((h << 5) - h + s.charCodeAt(i)) | 0;\n return Math.abs(h);\n}\n\nfunction makeIdentityAssigner(): (name: string) => { color: string; sigil: string } {\n const map = new Map<string, { color: string; sigil: string }>();\n let colorIdx = 0;\n return (name: string) => {\n if (!map.has(name)) {\n const h = seedHash(name);\n map.set(name, {\n color: AGENT_COLORS[colorIdx++ % AGENT_COLORS.length],\n sigil: SIGILS[h % SIGILS.length],\n });\n }\n return map.get(name)!;\n };\n}\n\n// ── Event line ────────────────────────────────────────────────────────────────\n\nconst NAME_COL = 12;\n\nfunction EventLine({\n event,\n identify,\n}: {\n event: DisplayEvent;\n identify: (n: string) => { color: string; sigil: string };\n}) {\n const ts = <Text color={C.muted}>{event.ts}{\" \"}</Text>;\n\n // ── Message ──\n if (event.kind === \"message\") {\n const { color, sigil } = identify(event.senderName);\n const isSelf = event.isSelf;\n const nameColor = isSelf ? C.text : event.senderType === \"agent\" ? color : C.secondary;\n const sigilColor = isSelf ? C.dim : event.senderType === \"agent\" ? color : C.dim;\n const sigilChar = isSelf ? \"›\" : event.senderType === \"agent\" ? sigil : \"·\";\n const contentColor = isSelf ? C.text : C.secondary;\n\n return (\n <Box paddingX={1}>\n <Box flexShrink={0}>\n {ts}\n <Text color={sigilColor}>{sigilChar}{\" \"}</Text>\n <Text color={nameColor} bold={isSelf}>\n {event.senderName.slice(0, NAME_COL).padEnd(NAME_COL)}\n </Text>\n <Text>{\" \"}</Text>\n </Box>\n <Box flexGrow={1} flexShrink={1}>\n <Text wrap=\"wrap\">\n {event.replyToName && <Text color={C.dim}>{\"→ \"}{event.replyToName}{\" \"}</Text>}\n <Text color={contentColor}>{event.content}</Text>\n </Text>\n </Box>\n </Box>\n );\n }\n\n // ── Join ──\n if (event.kind === \"join\") {\n const isAgent = event.participantType === \"agent\";\n const { color, sigil } = isAgent ? identify(event.name) : { color: C.dim, sigil: \"·\" };\n return (\n <Box paddingX={1}>\n {ts}\n <Text color={isAgent ? color : C.dim}>{sigil}{\" \"}</Text>\n <Text color={isAgent ? color : C.dim}>{event.name}</Text>\n <Text color={C.green}>{\" joined\"}</Text>\n </Box>\n );\n }\n\n // ── Leave ──\n if (event.kind === \"leave\") {\n const isAgent = event.participantType === \"agent\";\n const { color: nameColor } = isAgent ? identify(event.name) : { color: C.muted };\n return (\n <Box paddingX={1}>\n {ts}\n <Text color={C.muted}>{\"· \"}</Text>\n <Text color={nameColor}>{event.name}</Text>\n <Text color={C.danger}>{\" left\"}</Text>\n </Box>\n );\n }\n\n // ── Mode change ──\n if (event.kind === \"mode\") {\n return (\n <Box paddingX={1}>\n {ts}\n <Text color={C.dim}>{\"mode → \"}</Text>\n <Text color={C.yellow} bold>{event.mode}</Text>\n </Box>\n );\n }\n\n // ── System message (slash command output) ──\n if (event.kind === \"system\") {\n return (\n <Box paddingX={1}>\n {ts}\n <Text color={C.dim}>{\" \"}</Text>\n <Text color={C.secondary}>{event.content}</Text>\n </Box>\n );\n }\n\n return null;\n}\n\n// ── Internal bridge ───────────────────────────────────────────────────────────\n\ninterface AppHandle {\n push: (event: DisplayEvent) => void;\n setAgentNames: (names: string[]) => void;\n setParticipants: (names: string[]) => void;\n}\n\n// ── App ───────────────────────────────────────────────────────────────────────\n\ntype StaticEntry = { id: string; event?: DisplayEvent };\n\nfunction App({\n roomName,\n onSend,\n onCtrlC,\n onReady,\n readOnly,\n isAdmin,\n}: {\n roomName: string;\n onSend?: (content: string) => void;\n onCtrlC?: () => void;\n onReady: (handle: AppHandle) => void;\n readOnly?: boolean;\n isAdmin?: boolean;\n}) {\n const [events, setEvents] = useState<DisplayEvent[]>([]);\n const [agentNames, setAgentNames] = useState<string[]>([]);\n const [participants, setParticipants] = useState<string[]>([]);\n const [input, setInput] = useState(\"\");\n const [selectedIndex, setSelectedIndex] = useState(0);\n const { stdout } = useStdout();\n const identify = useMemo(makeIdentityAssigner, []);\n\n const push = useCallback((event: DisplayEvent) => {\n setEvents((prev) => [...prev, event]);\n }, []);\n\n useEffect(() => {\n onReady({ push, setAgentNames, setParticipants });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Note: no resize handler — Ink's <Static> items are already committed to the\n // terminal buffer. Forcing a re-render on resize causes cursor position\n // miscalculation and screen corruption. The divider width updates naturally\n // on the next state change (new event, input change, etc.).\n\n // ── Slash command suggestions ──────────────────────────────────────────────\n\n type SuggestionItem =\n | { kind: \"command\"; cmd: SlashCommand; insert: string }\n | { kind: \"param\"; value: string; insert: string }\n | { kind: \"mention\"; value: string; insert: string };\n\n const suggestionState = useMemo((): { items: SuggestionItem[]; ghostHint: string } => {\n // @mention detection — match @partial at end of input\n const mentionMatch = input.match(/@([a-zA-Z0-9_-]*)$/);\n if (mentionMatch && participants.length > 0) {\n const prefix = mentionMatch[1].toLowerCase();\n const filtered = participants.filter((p) => p.toLowerCase().startsWith(prefix));\n if (filtered.length > 0) {\n const before = input.slice(0, mentionMatch.index!);\n const items: SuggestionItem[] = filtered.map((p) => ({\n kind: \"mention\" as const,\n value: p,\n insert: before + \"@\" + p + \" \",\n }));\n const ghostHint = prefix.length === 0 ? \"\" : (filtered[0].slice(prefix.length));\n return { items, ghostHint };\n }\n }\n\n if (!input.startsWith(\"/\")) return { items: [], ghostHint: \"\" };\n\n const spaceIdx = input.indexOf(\" \");\n\n // Phase 1: completing command name (no space yet)\n if (spaceIdx === -1) {\n const prefix = input.toLowerCase();\n const items: SuggestionItem[] = SLASH_COMMANDS\n .filter((cmd) => {\n if (cmd.adminOnly && !isAdmin) return false;\n return cmd.name.startsWith(prefix);\n })\n .map((cmd) => ({\n kind: \"command\" as const,\n cmd,\n insert: cmd.name + \" \",\n }));\n return { items, ghostHint: \"\" };\n }\n\n // Phase 2: completing params\n const cmdName = input.slice(0, spaceIdx).toLowerCase();\n const cmd = SLASH_COMMANDS.find((c) => c.name === cmdName && (!c.adminOnly || isAdmin));\n if (!cmd?.params) return { items: [], ghostHint: \"\" };\n\n const rest = input.slice(spaceIdx + 1);\n const words = rest.split(/\\s+/);\n const hasTrailingSpace = rest.endsWith(\" \") || rest === \"\";\n const completedCount = hasTrailingSpace\n ? words.filter(Boolean).length\n : Math.max(0, words.length - 1);\n const currentPrefix = hasTrailingSpace ? \"\" : (words[words.length - 1] ?? \"\").toLowerCase();\n const paramIdx = completedCount;\n\n // All params filled\n if (paramIdx >= cmd.params.length) return { items: [], ghostHint: \"\" };\n\n const param = cmd.params[paramIdx];\n\n // Ghost hint: remaining unfilled params (skip current if partially typed)\n const ghostStart = currentPrefix ? paramIdx + 1 : paramIdx;\n const ghostHint = cmd.params.slice(ghostStart).map((p) => `<${p.label}>`).join(\" \");\n\n // No completions defined — hint only\n if (!param.completions) return { items: [], ghostHint };\n\n const values = param.completions === \"participants\" ? participants : param.completions;\n const filtered = currentPrefix\n ? values.filter((v) => v.toLowerCase().startsWith(currentPrefix))\n : values;\n\n // Build insert string: full command up to current param + selected value\n const completedWords = words.slice(0, completedCount).filter(Boolean);\n const base = cmdName + (completedWords.length ? \" \" + completedWords.join(\" \") : \"\") + \" \";\n\n const items: SuggestionItem[] = filtered.map((v) => ({\n kind: \"param\" as const,\n value: v,\n insert: base + v + \" \",\n }));\n\n return { items, ghostHint };\n }, [input, isAdmin, participants]);\n\n const suggestions = suggestionState.items;\n\n // Reset selection when input changes (arrow keys don't change input)\n useEffect(() => { setSelectedIndex(0); }, [input]);\n\n // ── Keyboard ───────────────────────────────────────────────────────────────\n // Single useInput handles everything — no TextInput, no dual-handler conflicts.\n\n useInput((char, key) => {\n if (key.ctrl && char === \"c\") { onCtrlC?.(); return; }\n if (readOnly || !onSend) return;\n\n // Suggestion navigation\n if (suggestions.length > 0) {\n if (key.downArrow) {\n setSelectedIndex((i) => Math.min(i + 1, suggestions.length - 1));\n return;\n }\n if (key.upArrow) {\n setSelectedIndex((i) => Math.max(i - 1, 0));\n return;\n }\n if (key.return || key.tab) {\n const picked = suggestions[selectedIndex];\n if (!picked) return;\n // No-param command + Enter → submit directly\n if (key.return && picked.kind === \"command\" && !picked.cmd.params) {\n onSend(picked.cmd.name);\n setInput(\"\");\n return;\n }\n setInput(picked.insert);\n return;\n }\n if (key.escape) {\n setInput(\"\");\n return;\n }\n }\n\n // Option+Enter → newline\n if (key.return && key.meta) {\n setInput((prev) => prev + \"\\n\");\n return;\n }\n\n // Enter → submit\n if (key.return) {\n const content = input.trim();\n if (content) onSend(content);\n setInput(\"\");\n return;\n }\n\n // Backspace\n if (key.backspace || key.delete) {\n setInput((prev) => prev.slice(0, -1));\n return;\n }\n\n // Ignore special keys\n if (key.ctrl || key.meta || key.escape || key.tab ||\n key.upArrow || key.downArrow || key.leftArrow || key.rightArrow) {\n return;\n }\n\n // Regular character\n if (char) {\n setInput((prev) => prev + char);\n }\n });\n\n const cols = stdout.columns ?? 80;\n\n // Static items: banner (rendered once) + events (appended over time)\n const entries: StaticEntry[] = useMemo(\n () => [{ id: \"__banner__\" }, ...events.map((e) => ({ id: e.id, event: e }))],\n [events],\n );\n\n return (\n <>\n {/* Permanent output — rendered once, selectable terminal text */}\n <Static items={entries}>\n {(entry) => {\n if (!entry.event) {\n return (\n <Box key={entry.id} flexDirection=\"column\" paddingX={2} paddingTop={1} paddingBottom={1}>\n {BANNER_LINES.map((line, i) => (\n <Text key={i} color={GRADIENT[i]}>{line}</Text>\n ))}\n <Text>{\" \"}</Text>\n <Text>\n <Text color={C.dim}>{\" room \"}</Text>\n <Text color={C.cyan} bold>{roomName}</Text>\n </Text>\n </Box>\n );\n }\n return <EventLine key={entry.id} event={entry.event} identify={identify} />;\n }}\n </Static>\n\n {/* Dynamic footer — only this area repaints */}\n <Box paddingX={1}>\n <Text color={C.purple}>{\"─\"}</Text>\n <Text color={C.border}>{\"─\".repeat(Math.max(0, cols - 4))}</Text>\n <Text color={C.cyan}>{\"─\"}</Text>\n </Box>\n {agentNames.length > 0 && (\n <Box paddingX={1}>\n {agentNames.map((name, i) => {\n const { color, sigil } = identify(name);\n return (\n <React.Fragment key={name}>\n {i > 0 && <Text color={C.border}>{\" · \"}</Text>}\n <Text color={color}>{sigil}{\" \"}{name}</Text>\n </React.Fragment>\n );\n })}\n </Box>\n )}\n {readOnly || !onSend ? (\n <Box paddingX={1}>\n <Text color={C.muted}>{\" watching as guest\"}</Text>\n </Box>\n ) : (\n <Box paddingX={1} flexDirection=\"column\">\n {/* Render each line; first line gets the prompt, rest get indentation */}\n {(input || \"\").split(\"\\n\").map((line, i, arr) => (\n <Box key={i}>\n <Text color={C.cyan} bold>{i === 0 ? \"› \" : \" \"}</Text>\n <Text>\n {line}\n {i === arr.length - 1 && <Text inverse>{\" \"}</Text>}\n {i === arr.length - 1 && suggestionState.ghostHint !== \"\" && (\n <Text color={C.muted}>{suggestionState.ghostHint}</Text>\n )}\n </Text>\n </Box>\n ))}\n </Box>\n )}\n {/* Slash command suggestions — below input */}\n {suggestions.length > 0 && (\n <Box flexDirection=\"column\" paddingX={1}>\n {suggestions.map((s, i) => {\n const selected = i === selectedIndex;\n if (s.kind === \"command\") {\n const paramHint = s.cmd.params\n ? \" \" + s.cmd.params.map((p) => `<${p.label}>`).join(\" \")\n : \"\";\n const display = s.cmd.name + paramHint;\n return (\n <Box key={s.cmd.name}>\n <Text color={selected ? C.cyan : C.muted}>{selected ? \"› \" : \" \"}</Text>\n <Text>\n <Text color={selected ? C.cyan : C.secondary} bold={selected}>\n {s.cmd.name}\n </Text>\n <Text color={C.muted}>\n {paramHint.padEnd(CMD_DISPLAY_COL - display.length + paramHint.length)}\n </Text>\n </Text>\n <Text color={C.dim}>{s.cmd.description}</Text>\n </Box>\n );\n }\n return (\n <Box key={s.value}>\n <Text color={selected ? C.cyan : C.muted}>{selected ? \"› \" : \" \"}</Text>\n {s.kind === \"mention\" && <Text color={C.dim}>{\"@\"}</Text>}\n <Text color={selected ? C.cyan : C.secondary} bold={selected}>{s.value}</Text>\n </Box>\n );\n })}\n </Box>\n )}\n </>\n );\n}\n\n// ── startTUI ──────────────────────────────────────────────────────────────────\n\nexport function startTUI(opts: TUIOptions): TUIHandle {\n let handle: AppHandle | null = null;\n const queue: DisplayEvent[] = [];\n\n const onReady = (h: AppHandle) => {\n handle = h;\n for (const event of queue.splice(0)) h.push(event);\n };\n\n const { unmount } = render(\n <App\n roomName={opts.roomName}\n onSend={opts.onSend}\n onCtrlC={opts.onCtrlC}\n onReady={onReady}\n readOnly={opts.readOnly}\n isAdmin={opts.isAdmin}\n />,\n { exitOnCtrlC: false },\n );\n\n return {\n push(event) {\n if (handle) handle.push(event);\n else queue.push(event);\n },\n setAgentNames(names) {\n handle?.setAgentNames(names);\n },\n setParticipants(names) {\n handle?.setParticipants(names);\n },\n stop() {\n unmount();\n },\n };\n}\n","/**\n * stoops run claude — client-side agent runtime for Claude Code.\n *\n * Uses the shared runtime setup (EventProcessor, MCP server)\n * then adds Claude-specific pieces: tmux session + TmuxBridge delivery.\n *\n * Claude Code connects to the runtime MCP server via a stdio bridge\n * (Claude's HTTP MCP transport requires OAuth, which hangs on localhost).\n * The agent joins rooms by calling join_room() — no auto-injection needed.\n */\n\nimport { writeFileSync, mkdtempSync, rmSync, chmodSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { tmpdir } from \"node:os\";\n\nimport {\n tmuxAvailable,\n tmuxCreateSession,\n tmuxSendCommand,\n tmuxAttach,\n tmuxKillSession,\n tmuxSessionExists,\n} from \"../tmux.js\";\nimport { TmuxBridge } from \"./tmux-bridge.js\";\nimport { setupAgentRuntime, type AgentRuntimeOptions } from \"../runtime-setup.js\";\nimport { contentPartsToString } from \"../../agent/prompts.js\";\n\nexport { type AgentRuntimeOptions as RunClaudeOptions };\n\n/**\n * Stdio-to-HTTP bridge script. Written to a temp file and spawned by Claude Code\n * as an MCP stdio server. Proxies JSON-RPC messages to the runtime HTTP MCP server.\n *\n * The HTTP MCP server returns SSE-formatted responses (event: message\\ndata: {...}).\n * The bridge extracts the JSON from data: lines and writes raw JSON-RPC to stdout.\n */\n// CommonJS (.cjs) for minimal startup latency — ESM requires module parsing which\n// can exceed Claude Code's MCP handshake timeout on first run.\nconst MCP_STDIO_BRIDGE = [\n '#!/usr/bin/env node',\n '\"use strict\";',\n 'const { createInterface } = require(\"readline\");',\n 'const url = `http://127.0.0.1:${process.argv[2]}/mcp`;',\n 'const rl = createInterface({ input: process.stdin });',\n '(async () => {',\n ' for await (const line of rl) {',\n ' if (!line.trim()) continue;',\n ' try {',\n ' const res = await fetch(url, {',\n ' method: \"POST\",',\n ' headers: { \"Content-Type\": \"application/json\", Accept: \"application/json, text/event-stream\" },',\n ' body: line,',\n ' });',\n ' if (res.status === 202) continue;',\n ' const body = await res.text();',\n ' for (const bl of body.split(\"\\\\n\")) {',\n ' const m = bl.match(/^data: (.+)/);',\n ' if (m) process.stdout.write(m[1] + \"\\\\n\");',\n ' }',\n ' } catch {',\n ' process.exit(1);',\n ' }',\n ' }',\n '})();',\n].join('\\n');\n\nexport async function runClaude(options: AgentRuntimeOptions): Promise<void> {\n // ── Headless mode — skip tmux, deliver events as plain text to stdout ────\n\n if (options.headless) {\n const setup = await setupAgentRuntime(options);\n\n const deliver = async (parts: Parameters<typeof contentPartsToString>[0]) => {\n const text = contentPartsToString(parts);\n if (text.trim()) process.stdout.write(text + \"\\n\");\n };\n\n const eventLoopPromise = setup.processor\n .run(deliver, setup.wrappedSource, setup.initialParts)\n .catch(() => {});\n\n process.stderr.write(`MCP server: ${setup.mcpServer.url}\\n`);\n\n await new Promise<void>((resolve) => {\n process.on(\"SIGINT\", resolve);\n process.on(\"SIGTERM\", resolve);\n });\n\n await setup.cleanup();\n await eventLoopPromise;\n return;\n }\n\n // ── Preflight checks ────────────────────────────────────────────────────\n\n if (!tmuxAvailable()) {\n console.error(\"Error: tmux is required but not found. Install it with: brew install tmux\");\n process.exit(1);\n }\n\n // ── Shared runtime setup ────────────────────────────────────────────────\n // Don't pass joinUrls — Claude Code agents join rooms manually via join_room()\n\n const setup = await setupAgentRuntime({ ...options, joinUrls: undefined });\n\n // ── Write MCP stdio bridge + config ────────────────────────────────────\n\n const tmpDir = mkdtempSync(join(tmpdir(), \"stoops_agent_\"));\n\n const bridgePath = join(tmpDir, \"mcp-bridge.cjs\");\n writeFileSync(bridgePath, MCP_STDIO_BRIDGE);\n chmodSync(bridgePath, 0o755);\n\n const mcpPort = new URL(setup.mcpServer.url).port;\n const mcpConfigPath = join(tmpDir, \"mcp.json\");\n\n // Use process.execPath (absolute path to Node) so the bridge works regardless\n // of whether `node` is in the tmux session's PATH.\n const mcpConfig = {\n mcpServers: {\n stoops: {\n type: \"stdio\",\n command: process.execPath,\n args: [bridgePath, mcpPort],\n },\n },\n };\n writeFileSync(mcpConfigPath, JSON.stringify(mcpConfig, null, 2));\n\n // ── Create tmux session + launch Claude Code ────────────────────────────\n\n const tmuxSession = `stoops_${setup.agentName}`;\n\n if (tmuxSessionExists(tmuxSession)) {\n tmuxKillSession(tmuxSession);\n }\n\n console.log(\"Launching Claude Code...\");\n tmuxCreateSession(tmuxSession);\n\n // Launch claude with MCP config + any passthrough args\n const extraArgs = options.extraArgs ?? [];\n const claudeCmd = [`claude --mcp-config ${mcpConfigPath}`, ...extraArgs].join(\" \");\n tmuxSendCommand(tmuxSession, claudeCmd);\n\n // ── Start event loop + attach ──────────────────────────────────────────\n\n const bridge = new TmuxBridge(tmuxSession);\n\n // Start the event loop in the background — no initial injection.\n // The agent joins rooms by calling join_room() when the user tells it to.\n const eventLoopPromise = setup.processor.run(bridge.deliver.bind(bridge), setup.wrappedSource)\n .catch(() => {}); // Prevent unhandled rejection from crashing the process\n\n // Wait for Claude to start, checking the session is still alive\n for (let i = 0; i < 10; i++) {\n await new Promise((r) => setTimeout(r, 500));\n if (!tmuxSessionExists(tmuxSession)) {\n console.error(\"Error: Claude Code exited during startup. Try running again.\");\n bridge.stop();\n await setup.cleanup();\n try { rmSync(tmpDir, { recursive: true }); } catch { /* ok */ }\n return;\n }\n }\n\n console.log(\"Attaching to Claude Code session...\\n\");\n\n try {\n await tmuxAttach(tmuxSession);\n } catch {\n // User detached or session ended\n }\n\n // ── Cleanup ─────────────────────────────────────────────────────────────\n\n bridge.stop();\n await setup.cleanup();\n tmuxKillSession(tmuxSession);\n try { rmSync(tmpDir, { recursive: true }); } catch { /* ok */ }\n\n console.log(\"Disconnected.\");\n}\n","/**\n * tmux helpers for stoops CLI.\n *\n * Thin wrappers around tmux commands. Used by the server process to\n * inject room events into Claude Code sessions.\n */\n\nimport { execFileSync, spawn } from \"node:child_process\";\n\n/** Sanitize a string for use as a tmux session name. Replaces tmux-special chars. */\nfunction sanitizeSessionName(name: string): string {\n return name.replace(/[.:$%]/g, \"_\");\n}\n\n/** Check if tmux is installed and available. */\nexport function tmuxAvailable(): boolean {\n try {\n execFileSync(\"tmux\", [\"-V\"], { stdio: \"ignore\" });\n return true;\n } catch {\n return false;\n }\n}\n\n/** Check if a tmux session exists. */\nexport function tmuxSessionExists(session: string): boolean {\n try {\n const name = sanitizeSessionName(session);\n execFileSync(\"tmux\", [\"has-session\", \"-t\", name], { stdio: \"ignore\" });\n return true;\n } catch {\n return false;\n }\n}\n\n/** Create a detached tmux session with no status bar. */\nexport function tmuxCreateSession(session: string): void {\n const name = sanitizeSessionName(session);\n execFileSync(\"tmux\", [\"new-session\", \"-d\", \"-s\", name]);\n execFileSync(\"tmux\", [\"set\", \"-t\", name, \"status\", \"off\"]);\n}\n\n/** Send a command to a tmux session (types it + presses Enter). */\nexport function tmuxSendCommand(session: string, command: string): void {\n const name = sanitizeSessionName(session);\n execFileSync(\"tmux\", [\"send-keys\", \"-t\", name, \"-l\", command]);\n execFileSync(\"tmux\", [\"send-keys\", \"-t\", name, \"Enter\"]);\n}\n\n/**\n * Inject text into a tmux session (literal keys, no Enter).\n * Used for room event injection.\n */\nexport function tmuxInjectText(session: string, text: string): void {\n const name = sanitizeSessionName(session);\n execFileSync(\"tmux\", [\"send-keys\", \"-t\", name, \"-l\", text]);\n}\n\n/** Send Enter key to a tmux session (submits input). */\nexport function tmuxSendEnter(session: string): void {\n const name = sanitizeSessionName(session);\n execFileSync(\"tmux\", [\"send-keys\", \"-t\", name, \"Enter\"]);\n}\n\n/** Attach to a tmux session. Returns a promise that resolves when detached/exited.\n *\n * Two modes:\n * - Outside tmux: `tmux attach` (blocks until user detaches, event loop stays free via spawn)\n * - Inside tmux: `tmux switch-client` (exits immediately) + polls until session ends\n */\nexport function tmuxAttach(session: string): Promise<void> {\n const name = sanitizeSessionName(session);\n\n if (process.env.TMUX) {\n // switch-client exits immediately after switching — poll until session is destroyed\n try {\n execFileSync(\"tmux\", [\"switch-client\", \"-t\", name], { stdio: \"ignore\" });\n } catch {\n // switch-client failed (e.g. no client) — fall through to polling\n }\n return new Promise<void>((resolve) => {\n const poll = setInterval(() => {\n try {\n execFileSync(\"tmux\", [\"has-session\", \"-t\", name], { stdio: \"ignore\" });\n } catch {\n clearInterval(poll);\n resolve();\n }\n }, 500);\n });\n }\n\n return new Promise<void>((resolve) => {\n const child = spawn(\"tmux\", [\"attach\", \"-t\", name], { stdio: \"inherit\" });\n child.on(\"exit\", () => resolve());\n child.on(\"error\", () => resolve());\n });\n}\n\n/** Capture visible screen content as array of lines. */\nexport function tmuxCapturePane(session: string): string[] {\n try {\n const name = sanitizeSessionName(session);\n const output = execFileSync(\"tmux\", [\"capture-pane\", \"-t\", name, \"-p\"], {\n encoding: \"utf-8\",\n });\n return output.split(\"\\n\");\n } catch {\n return [];\n }\n}\n\n/**\n * Send a control key sequence (e.g. \"C-u\", \"C-y\", \"Escape\").\n * Unlike tmuxInjectText, this does NOT use -l, so tmux interprets\n * the key name rather than treating it as literal text.\n */\nexport function tmuxSendKey(session: string, key: string): void {\n const name = sanitizeSessionName(session);\n execFileSync(\"tmux\", [\"send-keys\", \"-t\", name, key]);\n}\n\n/** Kill a tmux session. */\nexport function tmuxKillSession(session: string): void {\n try {\n const name = sanitizeSessionName(session);\n execFileSync(\"tmux\", [\"kill-session\", \"-t\", name], { stdio: \"ignore\" });\n } catch {\n // Session may already be dead\n }\n}\n","/**\n * TmuxBridge — state-aware event injection into Claude Code.\n *\n * Reads the Claude Code TUI screen via `tmux capture-pane`, detects the\n * current UI state, and applies the right injection strategy:\n *\n * idle → inject directly\n * typing → Ctrl+U (cut), inject, Ctrl+Y (restore)\n * dialog → queue and poll\n * permission → queue and poll\n * streaming → queue and poll\n * unknown → queue and poll (safe default)\n *\n * Events that can't be injected immediately are queued and drained\n * when the state becomes safe.\n */\n\nimport {\n tmuxCapturePane,\n tmuxInjectText,\n tmuxSendEnter,\n tmuxSendKey,\n} from \"../tmux.js\";\nimport { contentPartsToString } from \"../../agent/prompts.js\";\nimport type { ContentPart } from \"../../agent/types.js\";\n\nexport type TuiState =\n | \"idle\"\n | \"typing\"\n | \"dialog\"\n | \"permission\"\n | \"streaming\"\n | \"unknown\";\n\n// Spinner characters used by Claude Code during streaming\nconst SPINNER_CHARS = \"⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏\";\n\n// Patterns that indicate a selection/question dialog\nconst DIALOG_PATTERNS = [\n \"Enter to select\",\n \"to navigate\",\n \"Esc to cancel\",\n \"Ready to code?\",\n \"Review your answers\",\n \"ctrl+g to edit in\",\n];\n\n// Patterns that indicate a permission/confirmation prompt\nconst PERMISSION_PATTERNS = [\n \"(Y)\",\n \"Allow \",\n \"Deny \",\n \"approve\",\n \"Yes / No\",\n];\n\nexport interface TmuxBridgeOptions {\n /** How often to poll when events are queued (ms). Default: 200 */\n pollIntervalMs?: number;\n /** How long to wait between Ctrl+U/inject/Ctrl+Y steps (ms). Default: 50 */\n keystrokeDelayMs?: number;\n}\n\nexport class TmuxBridge {\n private session: string;\n private queue: string[] = [];\n private pollTimer: ReturnType<typeof setInterval> | null = null;\n private pollIntervalMs: number;\n private keystrokeDelayMs: number;\n private stopped = false;\n\n constructor(session: string, opts?: TmuxBridgeOptions) {\n this.session = session;\n this.pollIntervalMs = opts?.pollIntervalMs ?? 200;\n this.keystrokeDelayMs = opts?.keystrokeDelayMs ?? 50;\n }\n\n /**\n * Delivery callback — drop-in replacement for the raw tmuxDeliver lambda.\n * Pass `bridge.deliver.bind(bridge)` to EventProcessor.run().\n */\n async deliver(parts: ContentPart[]): Promise<void> {\n const text = contentPartsToString(parts);\n if (!text.trim()) return;\n\n this.inject(text);\n }\n\n /**\n * Detect the current TUI state by reading the screen.\n * Exported for testing — the heuristic logic is in detectStateFromLines().\n */\n detectState(): TuiState {\n const lines = this.captureScreen();\n return detectStateFromLines(lines);\n }\n\n /**\n * Try to inject text, choosing strategy based on TUI state.\n * If the state is unsafe, queues the text and starts polling.\n *\n * Text is flattened to a single line before injection to avoid triggering\n * Claude Code's paste detection. When multi-line text arrives via\n * `send-keys -l`, Claude Code detects it as a paste and collapses it into\n * \"[Pasted text #1 +N lines]\" which may not reliably submit with Enter.\n */\n private inject(text: string): void {\n const flat = text.replace(/\\n/g, \" \");\n const state = this.detectState();\n\n switch (state) {\n case \"idle\":\n this.injectIdle(flat);\n break;\n case \"typing\":\n this.injectWhileTyping(flat);\n break;\n default:\n // dialog, permission, streaming, unknown — queue it\n this.enqueue(flat);\n break;\n }\n }\n\n /** Capture the screen via tmux capture-pane. */\n private captureScreen(): string[] {\n return tmuxCapturePane(this.session);\n }\n\n /**\n * Inject into an idle prompt: type text + Enter.\n * Sends a second Enter after a short delay as a safety net — if Claude Code's\n * paste detection swallowed the first Enter, the second one submits. If the\n * first Enter worked, Claude is streaming and the second Enter is a no-op.\n */\n private injectIdle(text: string): void {\n tmuxInjectText(this.session, text);\n tmuxSendEnter(this.session);\n this.sleep(80);\n tmuxSendEnter(this.session);\n }\n\n /**\n * Inject while the user is typing:\n * 1. Ctrl+U — cut line to kill ring\n * 2. Inject our text + Enter\n * 3. Ctrl+Y — paste the user's text back\n */\n private injectWhileTyping(text: string): void {\n // Cut user's current input\n tmuxSendKey(this.session, \"C-u\");\n this.sleep(this.keystrokeDelayMs);\n\n // Inject our event (double-Enter for paste detection resilience)\n tmuxInjectText(this.session, text);\n tmuxSendEnter(this.session);\n this.sleep(80);\n tmuxSendEnter(this.session);\n this.sleep(this.keystrokeDelayMs);\n\n // Restore user's text\n tmuxSendKey(this.session, \"C-y\");\n }\n\n /** Add to queue and start polling if not already. */\n private enqueue(text: string): void {\n this.queue.push(text);\n this.startPolling();\n }\n\n /** Start the polling timer to drain queued events. */\n private startPolling(): void {\n if (this.pollTimer || this.stopped) return;\n this.pollTimer = setInterval(() => this.drainQueue(), this.pollIntervalMs);\n }\n\n /** Stop the polling timer. */\n private stopPolling(): void {\n if (this.pollTimer) {\n clearInterval(this.pollTimer);\n this.pollTimer = null;\n }\n }\n\n /**\n * Try to drain one queued event if the state is safe.\n *\n * Drains one event at a time rather than batching all into one multi-line\n * string — multi-line text triggers Claude Code's paste detection which\n * collapses it into \"[Pasted text #1 +N lines]\".\n *\n * After injecting one event, the poll continues. The next cycle re-checks\n * state: if Claude is busy (streaming), remaining events wait. If idle,\n * the next event is injected. Events are already flattened in inject().\n */\n private drainQueue(): void {\n if (this.queue.length === 0) {\n this.stopPolling();\n return;\n }\n\n const state = this.detectState();\n if (state === \"idle\" || state === \"typing\") {\n const text = this.queue.shift()!;\n\n if (state === \"idle\") {\n this.injectIdle(text);\n } else {\n this.injectWhileTyping(text);\n }\n\n if (this.queue.length === 0) {\n this.stopPolling();\n }\n // else: keep polling to drain remaining events\n }\n // else: still blocked, keep polling\n }\n\n /** Cleanup. */\n stop(): void {\n this.stopped = true;\n this.stopPolling();\n this.queue.length = 0;\n }\n\n /** Synchronous sleep — only used for tiny keystroke delays. */\n private sleep(ms: number): void {\n if (ms <= 0) return;\n Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);\n }\n}\n\n// ── State detection heuristics ──────────────────────────────────────────────\n\n/**\n * Detect TUI state from capture-pane output lines.\n * Exported separately so it can be unit-tested without tmux.\n *\n * Claude Code's TUI layout (v2.1+):\n * ────────────────────────\n * ❯ <user input here>\n * ────────────────────────\n * PR #2 /ide ...\n *\n * The ❯ prompt sits between separator lines (─). No ❯❯ footer in v2.1+.\n */\nexport function detectStateFromLines(lines: string[]): TuiState {\n if (lines.length === 0) return \"unknown\";\n\n // Work with the last ~15 lines (the visible bottom of the screen)\n const tail = lines.slice(-15);\n const tailText = tail.join(\"\\n\");\n\n // 1. Dialog: selection/question/plan approval\n for (const pattern of DIALOG_PATTERNS) {\n if (tailText.includes(pattern)) return \"dialog\";\n }\n\n // 2. Permission prompt\n for (const pattern of PERMISSION_PATTERNS) {\n if (tailText.includes(pattern)) return \"permission\";\n }\n\n // 3. Streaming: spinner characters in the last few lines\n const lastFew = tail.slice(-5).join(\"\");\n for (const ch of SPINNER_CHARS) {\n if (lastFew.includes(ch)) return \"streaming\";\n }\n\n // 4. Look for the ❯/› prompt line near the bottom.\n // Supports both old layout (❯❯ footer) and new layout (separator lines).\n const promptChar = /^[❯›](\\s|$)/;\n const footerChar = /^[❯›]{2}\\s/;\n const separatorLine = /^[─━─\\-]{10,}/;\n\n // Strategy A: old layout — find ❯❯ footer then ❯ prompt above it\n for (let i = tail.length - 1; i >= 0; i--) {\n const line = tail[i].trimStart();\n if (footerChar.test(line)) {\n // Found old-style footer, look for prompt above\n for (let j = i - 1; j >= 0; j--) {\n const above = tail[j].trimStart();\n if (promptChar.test(above)) {\n const content = above.replace(/^[❯›]\\s*/, \"\").trim();\n return content.length === 0 ? \"idle\" : \"typing\";\n }\n }\n break;\n }\n }\n\n // Strategy B: new layout — find ❯ prompt between/near separator lines\n for (let i = tail.length - 1; i >= 0; i--) {\n const line = tail[i].trimStart();\n if (promptChar.test(line)) {\n // Verify it's Claude's prompt by checking for separator line nearby\n const above = i > 0 ? tail[i - 1].trimStart() : \"\";\n const below = i < tail.length - 1 ? tail[i + 1].trimStart() : \"\";\n if (separatorLine.test(above) || separatorLine.test(below)) {\n const content = line.replace(/^[❯›]\\s*/, \"\").trim();\n return content.length === 0 ? \"idle\" : \"typing\";\n }\n }\n }\n\n return \"unknown\";\n}\n","/**\n * Shared agent runtime setup — extracted from cli/claude/run.ts.\n *\n * Both `stoops run claude` and `stoops run opencode` use this to:\n * 1. Create SSE multiplexer + EventProcessor\n * 2. Create local runtime MCP server\n * 3. Wire up participant cache updates\n * 4. Provide cleanup\n *\n * Rooms are NOT joined during setup. The agent joins rooms by calling\n * join_room() via MCP. If --join URLs are provided, the startup event\n * asks the agent to call join_room for each URL.\n *\n * Each runtime only needs to provide its own delivery mechanism\n * (TmuxBridge for Claude, HTTP API for OpenCode).\n */\n\nimport { randomName } from \"../core/names.js\";\nimport { extractToken } from \"./auth.js\";\nimport { RemoteRoomDataSource } from \"../agent/remote-room-data-source.js\";\nimport { SseMultiplexer } from \"../agent/sse-multiplexer.js\";\nimport { EventProcessor } from \"../agent/event-processor.js\";\nimport { createRuntimeMcpServer, type RuntimeMcpServer, type JoinRoomResult } from \"../agent/mcp/runtime.js\";\nimport { buildCatchUpLines } from \"../agent/tool-handlers.js\";\nimport type { Participant } from \"../core/types.js\";\nimport type { LabeledEvent } from \"../agent/multiplexer.js\";\nimport type { ContentPart } from \"../agent/types.js\";\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport interface AgentRuntimeOptions {\n joinUrls?: string[];\n name?: string;\n admin?: boolean;\n extraArgs?: string[];\n /** Skip tmux/UI — deliver events as plain text to stdout. MCP server still runs. */\n headless?: boolean;\n /** Called after a room is successfully joined via join_room MCP tool. */\n onRoomJoined?: () => void | Promise<void>;\n}\n\nexport interface JoinResult {\n serverUrl: string;\n sessionToken: string;\n participantId: string;\n roomName: string;\n roomId: string;\n authority: string;\n participants: Participant[];\n dataSource: RemoteRoomDataSource;\n}\n\nexport interface AgentRuntimeSetup {\n agentName: string;\n joinResults: JoinResult[];\n initialParts: ContentPart[] | undefined;\n processor: EventProcessor;\n sseMux: SseMultiplexer;\n mcpServer: RuntimeMcpServer;\n wrappedSource: AsyncIterable<LabeledEvent>;\n cleanup(): Promise<void>;\n}\n\n// ── Setup ─────────────────────────────────────────────────────────────────────\n\nexport async function setupAgentRuntime(options: AgentRuntimeOptions): Promise<AgentRuntimeSetup> {\n const agentName = options.name ?? randomName();\n\n // ── Pending join URLs (not joined yet — agent calls join_room) ─────────\n\n const pendingUrls = options.joinUrls ?? [];\n\n // ── Mutable join results (populated as agent calls join_room) ──────────\n\n const joinResults: JoinResult[] = [];\n\n // ── Create SSE multiplexer (starts empty) ──────────────────────────────\n\n const sseMux = new SseMultiplexer();\n\n // ── Create EventProcessor (selfId set on first join_room) ──────────────\n\n const processor = new EventProcessor(\"\", agentName, {\n defaultMode: \"everyone\",\n });\n\n // ── Create local runtime MCP server ───────────────────────────────────\n\n const mcpServer = await createRuntimeMcpServer({\n resolver: processor,\n toolOptions: {\n isEventSeen: (id) => processor.isEventSeen(id),\n markEventsSeen: (ids) => processor.markEventsSeen(ids),\n assignRef: (id) => processor.assignRef(id),\n resolveRef: (ref) => processor.resolveRef(ref),\n },\n admin: options.admin,\n onSetMode: async (room, mode) => {\n const conn = processor.resolve(room);\n if (!conn) return { success: false, error: `Unknown room \"${room}\".` };\n processor.setModeForRoom(conn.dataSource.roomId, mode as any, false);\n try {\n const ds = conn.dataSource as RemoteRoomDataSource;\n const res = await fetch(`${ds.serverUrl}/set-mode`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token: ds.sessionToken, mode }),\n });\n if (!res.ok) return { success: false, error: `Server rejected: ${await res.text()}` };\n } catch {\n // Server unreachable, local mode still set\n }\n return { success: true };\n },\n onJoinRoom: async (url, alias) => {\n const token = extractToken(url);\n let serverUrl: string;\n try {\n const parsed = new URL(url);\n parsed.search = \"\";\n serverUrl = parsed.toString().replace(/\\/$/, \"\");\n } catch {\n serverUrl = url.replace(/\\/$/, \"\");\n }\n\n try {\n const joinBody: Record<string, unknown> = { type: \"agent\", name: agentName };\n if (token) joinBody.token = token;\n\n const res = await fetch(`${serverUrl}/join`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(joinBody),\n signal: AbortSignal.timeout(15_000),\n });\n if (!res.ok) return { success: false, error: `Failed to join: ${await res.text()}` };\n\n const data = await res.json() as Record<string, unknown>;\n const sessionToken = String(data.sessionToken ?? \"\");\n const roomName = alias ?? String(data.roomName ?? \"\");\n const roomId = String(data.roomId ?? \"\");\n const authority = String(data.authority ?? \"participant\");\n const participants = (data.participants as Participant[]) ?? [];\n const newParticipantId = String(data.participantId ?? \"\");\n\n const dataSource = new RemoteRoomDataSource(serverUrl, sessionToken, roomId);\n dataSource.setParticipants(participants);\n dataSource.setSelf(newParticipantId, agentName);\n\n // Set global selfId on first join; always set per-room selfId\n if (joinResults.length === 0) {\n processor.participantId = newParticipantId;\n }\n processor.setRoomParticipantId(roomId, newParticipantId);\n\n // Register in EventProcessor and SSE multiplexer\n const mode = processor.getModeForRoom(roomId) ?? \"everyone\";\n processor.connectRemoteRoom(dataSource, roomName);\n sseMux.addConnection(serverUrl, sessionToken, roomName, roomId);\n\n // Track for cleanup\n const jr: JoinResult = {\n serverUrl,\n sessionToken,\n participantId: newParticipantId,\n roomName,\n roomId,\n authority,\n participants,\n dataSource,\n };\n joinResults.push(jr);\n\n // Build recent activity lines for the response\n const conn = processor.resolve(roomName);\n let recentLines: string[] = [];\n if (conn) {\n recentLines = await buildCatchUpLines(conn, {\n isEventSeen: (id) => processor.isEventSeen(id),\n markEventsSeen: (ids) => processor.markEventsSeen(ids),\n assignRef: (id) => processor.assignRef(id),\n });\n }\n\n await options.onRoomJoined?.();\n\n return {\n success: true,\n roomName,\n agentName,\n authority,\n mode,\n participants: participants\n .filter((p) => p.id !== newParticipantId)\n .map((p) => ({ name: p.name, authority: (p as any).authority ?? \"participant\" })),\n recentLines,\n } as JoinRoomResult;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return { success: false, error: `Unable to connect. Is the server running? (${serverUrl}) — ${msg}` };\n }\n },\n onLeaveRoom: async (room) => {\n const conn = processor.resolve(room);\n if (!conn) return { success: false, error: `Unknown room \"${room}\".` };\n const roomId = conn.dataSource.roomId;\n\n const idx = joinResults.findIndex((jr) => jr.roomId === roomId);\n if (idx >= 0) {\n const jr = joinResults[idx];\n sseMux.removeConnection(roomId);\n processor.disconnectRemoteRoom(roomId);\n\n try {\n await fetch(`${jr.serverUrl}/disconnect`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token: jr.sessionToken }),\n });\n } catch {\n // Server may be down\n }\n\n joinResults.splice(idx, 1);\n }\n return { success: true };\n },\n onAdminSetModeFor: options.admin ? async (room, participant, mode) => {\n const conn = processor.resolve(room);\n if (!conn) return { success: false, error: `Unknown room \"${room}\".` };\n const ds = conn.dataSource as RemoteRoomDataSource;\n\n const p = conn.dataSource.listParticipants().find((pp) => pp.name === participant);\n if (!p) return { success: false, error: `Unknown participant \"${participant}\".` };\n\n try {\n const res = await fetch(`${ds.serverUrl}/set-mode`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token: ds.sessionToken, participantId: p.id, mode }),\n });\n if (!res.ok) return { success: false, error: await res.text() };\n return { success: true };\n } catch {\n return { success: false, error: \"Server unreachable.\" };\n }\n } : undefined,\n onAdminMute: options.admin ? async (room, participant) => {\n const conn = processor.resolve(room);\n if (!conn) return { success: false, error: `Unknown room \"${room}\".` };\n const ds = conn.dataSource as RemoteRoomDataSource;\n\n const p = conn.dataSource.listParticipants().find((pp) => pp.name === participant);\n if (!p) return { success: false, error: `Unknown participant \"${participant}\".` };\n\n try {\n const res = await fetch(`${ds.serverUrl}/set-authority`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token: ds.sessionToken, participantId: p.id, authority: \"observer\" }),\n });\n if (!res.ok) return { success: false, error: await res.text() };\n return { success: true };\n } catch {\n return { success: false, error: \"Server unreachable.\" };\n }\n } : undefined,\n onAdminUnmute: options.admin ? async (room, participant) => {\n const conn = processor.resolve(room);\n if (!conn) return { success: false, error: `Unknown room \"${room}\".` };\n const ds = conn.dataSource as RemoteRoomDataSource;\n\n const p = conn.dataSource.listParticipants().find((pp) => pp.name === participant);\n if (!p) return { success: false, error: `Unknown participant \"${participant}\".` };\n\n try {\n const res = await fetch(`${ds.serverUrl}/set-authority`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token: ds.sessionToken, participantId: p.id, authority: \"participant\" }),\n });\n if (!res.ok) return { success: false, error: await res.text() };\n return { success: true };\n } catch {\n return { success: false, error: \"Server unreachable.\" };\n }\n } : undefined,\n onAdminKick: options.admin ? async (room, participant) => {\n const conn = processor.resolve(room);\n if (!conn) return { success: false, error: `Unknown room \"${room}\".` };\n const ds = conn.dataSource as RemoteRoomDataSource;\n\n const p = conn.dataSource.listParticipants().find((pp) => pp.name === participant);\n if (!p) return { success: false, error: `Unknown participant \"${participant}\".` };\n\n try {\n const res = await fetch(`${ds.serverUrl}/kick`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token: ds.sessionToken, participantId: p.id }),\n });\n if (!res.ok) return { success: false, error: await res.text() };\n return { success: true };\n } catch {\n return { success: false, error: \"Server unreachable.\" };\n }\n } : undefined,\n });\n\n // ── Wrap SSE source for participant cache updates ─────────────────────\n\n const wrappedSource: AsyncIterable<LabeledEvent> = {\n [Symbol.asyncIterator]() {\n const inner = sseMux[Symbol.asyncIterator]();\n return {\n async next() {\n const result = await inner.next();\n if (!result.done) {\n const { roomId, event } = result.value;\n const jr = joinResults.find((j) => j.roomId === roomId);\n if (jr) {\n if (event.type === \"ParticipantJoined\") {\n jr.dataSource.addParticipant(event.participant);\n } else if (event.type === \"ParticipantLeft\") {\n jr.dataSource.removeParticipant(event.participant_id);\n }\n }\n }\n return result;\n },\n };\n },\n };\n\n // ── Cleanup function ──────────────────────────────────────────────────\n\n async function cleanup(): Promise<void> {\n await processor.stop();\n sseMux.close();\n await mcpServer.stop();\n\n for (const jr of joinResults) {\n try {\n await fetch(`${jr.serverUrl}/disconnect`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token: jr.sessionToken }),\n });\n } catch {\n // Server may be down\n }\n }\n }\n\n // ── Build startup event (if --join URLs were provided) ────────────────\n\n let initialParts: ContentPart[] | undefined;\n if (pendingUrls.length > 0) {\n if (pendingUrls.length === 1) {\n initialParts = [{ type: \"text\", text: `Use join_room(\"${pendingUrls[0]}\") to connect.` }];\n } else {\n const lines = pendingUrls.map((u) => ` join_room(\"${u}\")`);\n initialParts = [{ type: \"text\", text: `Rooms to join:\\n${lines.join(\"\\n\")}` }];\n }\n }\n\n return {\n agentName,\n joinResults,\n initialParts,\n processor,\n sseMux,\n mcpServer,\n wrappedSource,\n cleanup,\n };\n}\n","/**\n * stoops run opencode — client-side agent runtime for OpenCode.\n *\n * Spawns `opencode serve` with OPENCODE_CONFIG_CONTENT to inject the stoops\n * MCP server. The user opens OpenCode's UI, starts a conversation, and tells\n * the agent to join a room URL.\n *\n * Session detection: we subscribe to OpenCode's global SSE event stream and\n * watch for stoops tool call events. Each event carries the sessionID of the\n * calling session — no guessing, no race conditions.\n */\n\nimport { spawn, type ChildProcess } from \"node:child_process\";\nimport { contentPartsToString } from \"../../agent/prompts.js\";\nimport type { ContentPart } from \"../../agent/types.js\";\nimport { setupAgentRuntime, type AgentRuntimeOptions } from \"../runtime-setup.js\";\n\nexport { type AgentRuntimeOptions as RunOpencodeOptions };\n\nexport async function runOpencode(options: AgentRuntimeOptions): Promise<void> {\n // ── Pick a port for OpenCode ────────────────────────────────────────────\n\n const opencodePort = 14096 + Math.floor(Math.random() * 1000);\n const opencodeUrl = `http://127.0.0.1:${opencodePort}`;\n\n // ── Room → OpenCode session mapping ────────────────────────────────────\n //\n // Each OpenCode session can join different rooms. Lazily detected on first\n // delivery for each room by inspecting session messages for stoops tool calls.\n\n const roomSessions = new Map<string, string>(); // roomId → OpenCode sessionId\n\n /** Find the OpenCode session that most recently called a stoops tool. */\n async function findStoopsSession(): Promise<string | null> {\n try {\n const res = await fetch(`${opencodeUrl}/session`);\n if (!res.ok) return null;\n // Sessions sorted by time.updated desc — first is most recent\n const sessions = await res.json() as Array<{ id: string; time: { updated: number } }>;\n\n // Check the most recently updated sessions for stoops tool parts\n for (const sess of sessions.slice(0, 3)) {\n const msgRes = await fetch(`${opencodeUrl}/session/${sess.id}/message`);\n if (!msgRes.ok) continue;\n const messages = await msgRes.json() as Array<{\n parts?: Array<{ type?: string; tool?: string }>;\n }>;\n for (const msg of messages) {\n for (const part of msg.parts ?? []) {\n if (part.type === \"tool\" && part.tool?.includes(\"stoops__\")) {\n return sess.id;\n }\n }\n }\n }\n // Fallback: most recently updated session\n return sessions.length > 0 ? sessions[0].id : null;\n } catch {\n return null;\n }\n }\n\n // ── Shared runtime setup ────────────────────────────────────────────────\n // No --join URLs — the user tells the agent to join from within OpenCode.\n\n const setup = await setupAgentRuntime({\n ...options,\n joinUrls: undefined,\n });\n\n // ── Build MCP config for OpenCode ───────────────────────────────────────\n\n const opencodeConfig = {\n mcp: {\n stoops: {\n type: \"remote\",\n url: setup.mcpServer.url,\n oauth: false,\n },\n },\n };\n\n // ── Spawn OpenCode in headless mode ─────────────────────────────────────\n\n const extraArgs = options.extraArgs ?? [];\n const opencodeArgs = [\"serve\", \"--port\", String(opencodePort), ...extraArgs];\n\n console.log(\"Launching OpenCode...\");\n\n let child: ChildProcess;\n try {\n child = spawn(\"opencode\", opencodeArgs, {\n env: {\n ...process.env,\n OPENCODE_CONFIG_CONTENT: JSON.stringify(opencodeConfig),\n },\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n } catch {\n console.error(\"Error: opencode is required but not found. Install it from https://opencode.ai\");\n await setup.cleanup();\n process.exit(1);\n }\n\n // Forward stderr to console for visibility\n child.stderr?.on(\"data\", (chunk: Buffer) => {\n process.stderr.write(chunk);\n });\n\n let childExited = false;\n child.on(\"exit\", () => { childExited = true; });\n\n child.on(\"error\", async () => {\n console.error(\"Error: failed to start opencode. Is it installed?\");\n await setup.cleanup();\n process.exit(1);\n });\n\n // ── Wait for OpenCode to be ready ───────────────────────────────────────\n\n const ready = await pollForReady(opencodeUrl, 30_000);\n if (!ready) {\n console.error(\"OpenCode did not become ready within 30 seconds.\");\n child.kill();\n await setup.cleanup();\n process.exit(1);\n }\n\n console.log(` OpenCode running on ${opencodeUrl}`);\n\n // ── Build deliver callback ──────────────────────────────────────────────\n //\n // OpenCode's POST /session/:id/message uses Hono stream() — headers (200)\n // arrive immediately but the LLM runs inside the stream callback. We MUST\n // consume the response body (await res.text()) to block until the LLM\n // finishes, preserving the EventProcessor's _processing lock.\n\n async function deliver(parts: ContentPart[]): Promise<void> {\n const roomId = setup.processor.currentContextRoomId;\n if (!roomId) return;\n\n // Lazy session detection: look up on first delivery for this room\n if (!roomSessions.has(roomId)) {\n const sid = await findStoopsSession();\n if (!sid) return;\n roomSessions.set(roomId, sid);\n console.log(` Linked room ${roomId} → session ${sid}`);\n }\n const targetSession = roomSessions.get(roomId)!;\n\n const text = contentPartsToString(parts);\n if (!text.trim()) return;\n\n try {\n const res = await fetch(`${opencodeUrl}/session/${targetSession}/message`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n parts: [{ type: \"text\", text }],\n }),\n });\n await res.text();\n } catch {\n // OpenCode may have exited\n }\n }\n\n // ── Start the event loop ────────────────────────────────────────────────\n // No initialParts — the user drives the conversation from OpenCode's UI.\n\n const eventLoopPromise = setup.processor.run(deliver, setup.wrappedSource);\n\n console.log(`\\n OpenCode agent running.`);\n console.log(` To watch: opencode attach ${opencodeUrl}\\n`);\n\n // ── Block until child exits or Ctrl+C ───────────────────────────────────\n\n const exitPromise = new Promise<void>((resolve) => {\n child.on(\"exit\", resolve);\n });\n\n const signalPromise = new Promise<void>((resolve) => {\n const handler = () => { resolve(); };\n process.on(\"SIGINT\", handler);\n process.on(\"SIGTERM\", handler);\n });\n\n await Promise.race([exitPromise, signalPromise]);\n\n // ── Cleanup ─────────────────────────────────────────────────────────────\n\n if (!childExited) {\n child.kill();\n }\n await setup.cleanup();\n\n console.log(\"Disconnected.\");\n}\n\n// ── Helpers ─────────────────────────────────────────────────────────────────\n\nasync function pollForReady(url: string, timeoutMs: number): Promise<boolean> {\n const start = Date.now();\n while (Date.now() - start < timeoutMs) {\n try {\n const res = await fetch(`${url}/session/status`);\n if (res.ok) return true;\n } catch {\n // Not ready yet\n }\n await new Promise((r) => setTimeout(r, 500));\n }\n return false;\n}\n","#!/usr/bin/env node\n\n/**\n * stoops CLI — shared rooms for AI agents.\n *\n * Usage:\n * stoops [--room <name>] [--port <port>] [--share] Host a room + join it\n * stoops serve [--room <name>] [--port <port>] [--share] Headless server only\n * stoops join <url> [--name <name>] [--guest] Join a room as a human\n * stoops run claude [--name <name>] [--admin] [-- <args>] Connect Claude Code\n * stoops run opencode [--name <name>] [--admin] [-- <args>] Connect OpenCode\n */\n\nimport { serve } from \"./serve.js\";\nimport { join } from \"./join.js\";\nimport { runClaude } from \"./claude/run.js\";\nimport { runOpencode } from \"./opencode/run.js\";\nimport { buildShareUrl } from \"./auth.js\";\n\nconst args = process.argv.slice(2);\n\nfunction getFlag(name: string, arr: string[] = args): string | undefined {\n const idx = arr.indexOf(`--${name}`);\n if (idx === -1) return undefined;\n const value = arr[idx + 1];\n if (value === undefined || value.startsWith(\"--\")) return undefined;\n return value;\n}\n\n/** Collect all values for a repeatable flag (e.g. --join url1 --join url2). */\nfunction getAllFlags(name: string, arr: string[] = args): string[] {\n const results: string[] = [];\n const flag = `--${name}`;\n for (let i = 0; i < arr.length; i++) {\n if (arr[i] === flag && arr[i + 1] && !arr[i + 1].startsWith(\"--\")) {\n results.push(arr[i + 1]);\n }\n }\n return results;\n}\n\nfunction printUsage(stream: typeof console.log = console.log): void {\n stream(\"Usage:\");\n stream(\" stoops [--room <name>] [--port <port>] [--share] Host + join\");\n stream(\" stoops serve [--room <name>] [--port <port>] [--share] Headless server\");\n stream(\" stoops join <url> [--name <name>] [--guest] Join a room\");\n stream(\" stoops run claude [--name <name>] [--admin] [-- <args>] Connect Claude Code\");\n stream(\" stoops run opencode [--name <name>] [--admin] [-- <args>] Connect OpenCode\");\n}\n\nasync function main(): Promise<void> {\n // ── --help anywhere ────────────────────────────────────────────────────\n if (args.includes(\"--help\") || args.includes(\"-h\")) {\n printUsage();\n return;\n }\n\n // ── stoops run <runtime> ───────────────────────────────────────────────\n if (args[0] === \"run\" && (args[1] === \"claude\" || args[1] === \"opencode\")) {\n const runtime = args[1];\n const restArgs = args.slice(2);\n\n // Split on -- separator: stoops flags before, passthrough args after\n const ddIndex = restArgs.indexOf(\"--\");\n const stoopsArgs = ddIndex >= 0 ? restArgs.slice(0, ddIndex) : restArgs;\n const extraArgs = ddIndex >= 0 ? restArgs.slice(ddIndex + 1) : [];\n\n const joinUrls = getAllFlags(\"join\", stoopsArgs);\n\n const runtimeOptions = {\n joinUrls: joinUrls.length > 0 ? joinUrls : undefined,\n name: getFlag(\"name\", stoopsArgs),\n admin: stoopsArgs.includes(\"--admin\"),\n headless: stoopsArgs.includes(\"--headless\"),\n extraArgs,\n };\n\n if (runtime === \"claude\") {\n await runClaude(runtimeOptions);\n } else {\n await runOpencode(runtimeOptions);\n }\n return;\n }\n\n // ── stoops join <url> ──────────────────────────────────────────────────\n if (args[0] === \"join\") {\n const server = args[1];\n if (!server || server.startsWith(\"--\")) {\n console.error(\"Usage: stoops join <url> [--name <name>] [--guest] [--headless]\");\n process.exit(1);\n }\n await join({\n server,\n name: getFlag(\"name\"),\n guest: args.includes(\"--guest\"),\n headless: args.includes(\"--headless\"),\n });\n return;\n }\n\n // ── stoops serve ───────────────────────────────────────────────────────\n if (args[0] === \"serve\") {\n const portStr = getFlag(\"port\");\n const port = portStr ? parseInt(portStr, 10) : undefined;\n if (port !== undefined && (isNaN(port) || port < 0 || port > 65535)) {\n console.error(`Invalid port: ${portStr}`);\n process.exit(1);\n }\n await serve({\n room: getFlag(\"room\"),\n port,\n share: args.includes(\"--share\"),\n headless: args.includes(\"--headless\"),\n });\n return;\n }\n\n // ── stoops (bare) — host + join ────────────────────────────────────────\n if (args.length === 0 || args[0]?.startsWith(\"--\")) {\n const portStr = getFlag(\"port\");\n const port = portStr ? parseInt(portStr, 10) : undefined;\n if (port !== undefined && (isNaN(port) || port < 0 || port > 65535)) {\n console.error(`Invalid port: ${portStr}`);\n process.exit(1);\n }\n const result = await serve({\n room: getFlag(\"room\"),\n port,\n share: args.includes(\"--share\"),\n quiet: true,\n });\n\n // Host joins locally as admin using the admin share token\n const adminJoinUrl = buildShareUrl(result.serverUrl, result.adminToken);\n const participantShareUrl = buildShareUrl(\n result.publicUrl !== result.serverUrl ? result.publicUrl : result.serverUrl,\n result.participantToken,\n );\n\n await join({\n server: adminJoinUrl,\n name: getFlag(\"name\"),\n shareUrl: participantShareUrl,\n });\n return;\n }\n\n // ── Unknown command ────────────────────────────────────────────────────\n console.error(`Unknown command: ${args[0]}\\n`);\n printUsage(console.error);\n process.exit(1);\n}\n\nmain().catch((err) => {\n console.error(err);\n process.exit(1);\n});\n"],"mappings":"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","names":["id","channel","sessionToken","participantList","require","randomUUID","filtered","items","ghostHint","cmd","randomUUID","args","join","execFileSync","spawn","setup","eventLoopPromise","join","spawn","spawn"]}
|
|
1
|
+
{"version":3,"sources":["../../src/cli/serve.ts","../../src/cli/auth.ts","../../src/cli/join.ts","../../src/cli/tui.tsx","../../src/cli/claude/run.ts","../../src/cli/tmux.ts","../../src/cli/claude/tmux-bridge.ts","../../src/cli/runtime-setup.ts","../../src/cli/opencode/run.ts","../../src/cli/index.ts"],"sourcesContent":["/**\n * stoops serve — dumb room server.\n *\n * One room, one HTTP API, SSE broadcasting, authority enforcement.\n * No EventProcessor, no tmux, no agent lifecycle — those live client-side.\n * Humans connect via `stoops join`, agents via `stoops run claude`.\n */\n\nimport { createServer, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport { spawn, execFileSync, type ChildProcess } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { createRequire } from \"node:module\";\n\nimport { Room } from \"../core/room.js\";\nimport { InMemoryStorage } from \"../core/storage.js\";\nimport { randomRoomName, randomName } from \"../core/names.js\";\nimport { createEvent, type ActivityEvent, type AuthorityChangedEvent, type ParticipantKickedEvent, type RoomEvent } from \"../core/events.js\";\nimport type { AuthorityLevel } from \"../core/types.js\";\nimport type { Channel } from \"../core/channel.js\";\nimport { formatTimestamp } from \"../agent/prompts.js\";\nimport { TokenManager, buildShareUrl } from \"./auth.js\";\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\ninterface ConnectedParticipant {\n id: string;\n name: string;\n authority: AuthorityLevel;\n channel: Channel;\n sessionToken: string;\n}\n\ninterface ConnectedObserver {\n id: string;\n authority: \"observer\";\n channel: Channel;\n sessionToken: string;\n}\n\nexport interface ServeOptions {\n room?: string;\n port?: number;\n share?: boolean;\n quiet?: boolean;\n /** Suppress all human-readable output; emit one JSON line with server info on stdout. */\n headless?: boolean;\n}\n\nexport interface ServeResult {\n serverUrl: string;\n publicUrl: string;\n roomName: string;\n adminToken: string;\n participantToken: string;\n}\n\n// ── SSE helper ───────────────────────────────────────────────────────────────\n\nasync function enrichAndSend(res: ServerResponse, event: RoomEvent, room: Room): Promise<void> {\n if (event.type === \"MessageSent\" && event.message.reply_to_id) {\n const replyMsg = await room.getMessage(event.message.reply_to_id);\n const enriched = {\n ...event,\n _replyToName: replyMsg?.sender_name ?? null,\n };\n res.write(`data: ${JSON.stringify(enriched)}\\n\\n`);\n return;\n }\n res.write(`data: ${JSON.stringify(event)}\\n\\n`);\n}\n\n// ── Main serve command ───────────────────────────────────────────────────────\n\nexport async function serve(options: ServeOptions): Promise<ServeResult> {\n const roomName = options.room ?? randomRoomName();\n const port = options.port ?? 7890;\n const serverUrl = `http://127.0.0.1:${port}`;\n const log = options.headless ? () => {} : logServer;\n\n let publicUrl = serverUrl;\n let tunnelProcess: ChildProcess | null = null;\n\n // Create room\n const storage = new InMemoryStorage();\n const room = new Room(roomName, storage);\n\n // Auth\n const tokens = new TokenManager();\n\n // Connected participants and observers (by session token for lookup)\n const participants = new Map<string, ConnectedParticipant>();\n const observers = new Map<string, ConnectedObserver>();\n // Reverse lookup: participantId → sessionToken\n const idToSession = new Map<string, string>();\n\n // Track active SSE connections for cleanup\n const sseConnections = new Map<string, ServerResponse>();\n\n // ── JSON body parser helper ──────────────────────────────────────────────\n\n async function parseBody(req: IncomingMessage): Promise<Record<string, unknown>> {\n const chunks: Buffer[] = [];\n for await (const chunk of req) chunks.push(chunk as Buffer);\n try { return JSON.parse(Buffer.concat(chunks).toString()); } catch { return {}; }\n }\n\n // ── Auth helper ──────────────────────────────────────────────────────────\n\n function getSession(token: string | null) {\n if (!token) return null;\n const p = participants.get(token);\n if (p) return { ...p, kind: \"participant\" as const };\n const o = observers.get(token);\n if (o) return { ...o, kind: \"observer\" as const };\n return null;\n }\n\n function jsonError(res: ServerResponse, status: number, error: string): void {\n res.writeHead(status, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error }));\n }\n\n function jsonOk(res: ServerResponse, data: Record<string, unknown> = {}): void {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ ok: true, ...data }));\n }\n\n // ── HTTP API ────────────────────────────────────────────────────────────\n\n const httpServer = createServer(async (req, res) => {\n const url = new URL(req.url ?? \"/\", `http://localhost:${port}`);\n\n // ── SSE event stream ───────────────────────────────────────────────────\n // ⚠️ MUST accept POST — DO NOT change to GET-only.\n // Cloudflare Quick Tunnels buffer GET streaming responses and only flush\n // when the connection closes. POST streams in real-time. (cloudflared#1449)\n // https://github.com/cloudflare/cloudflared/issues/1449\n if (url.pathname === \"/events\" && (req.method === \"GET\" || req.method === \"POST\")) {\n const authHeader = req.headers.authorization;\n const sessionToken = authHeader?.startsWith(\"Bearer \")\n ? authHeader.slice(7)\n : null;\n const session = getSession(sessionToken);\n\n if (!session) {\n jsonError(res, 401, \"Invalid session token\");\n return;\n }\n\n // SSE headers\n res.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n \"Connection\": \"keep-alive\",\n \"Access-Control-Allow-Origin\": \"*\",\n });\n res.flushHeaders();\n\n sseConnections.set(session.id, res);\n\n // Send recent history so the joiner has context\n const history = await room.listEvents(undefined, 50);\n for (const event of [...history.items].reverse()) {\n await enrichAndSend(res, event, room);\n }\n\n // Live event stream\n const streamEvents = async () => {\n try {\n for await (const event of session.channel) {\n await enrichAndSend(res, event, room);\n }\n } catch {\n // Channel disconnected\n }\n };\n streamEvents();\n\n // Cleanup on client disconnect\n req.on(\"close\", () => {\n sseConnections.delete(session.id);\n });\n return;\n }\n\n // ── GET endpoints ─────────────────────────────────────────────────────\n\n if (req.method === \"GET\") {\n const sessionToken = url.searchParams.get(\"token\");\n const session = getSession(sessionToken);\n\n // ── GET /participants ────────────────────────────────────────────────\n if (url.pathname === \"/participants\") {\n if (!session) return jsonError(res, 401, \"Invalid session token\");\n const list = room.listParticipants().map((p) => ({\n id: p.id,\n name: p.name,\n type: p.type,\n authority: p.authority ?? \"participant\",\n }));\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ participants: list }));\n return;\n }\n\n // ── GET /message/:id ─────────────────────────────────────────────────\n if (url.pathname.startsWith(\"/message/\")) {\n if (!session) return jsonError(res, 401, \"Invalid session token\");\n const messageId = url.pathname.slice(\"/message/\".length);\n const msg = await room.getMessage(messageId);\n if (!msg) return jsonError(res, 404, \"Message not found\");\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ message: msg }));\n return;\n }\n\n // ── GET /messages ────────────────────────────────────────────────────\n if (url.pathname === \"/messages\") {\n if (!session) return jsonError(res, 401, \"Invalid session token\");\n const count = parseInt(url.searchParams.get(\"count\") ?? \"30\", 10);\n const cursor = url.searchParams.get(\"cursor\") ?? null;\n const result = await room.listMessages(count, cursor);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(result));\n return;\n }\n\n // ── GET /events/history ──────────────────────────────────────────────\n if (url.pathname === \"/events/history\") {\n if (!session) return jsonError(res, 401, \"Invalid session token\");\n const category = url.searchParams.get(\"category\") ?? null;\n const count = parseInt(url.searchParams.get(\"count\") ?? \"50\", 10);\n const cursor = url.searchParams.get(\"cursor\") ?? null;\n const result = await room.listEvents(category as any, count, cursor);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(result));\n return;\n }\n\n // ── GET /search ──────────────────────────────────────────────────────\n if (url.pathname === \"/search\") {\n if (!session) return jsonError(res, 401, \"Invalid session token\");\n const query = url.searchParams.get(\"query\") ?? \"\";\n if (!query) return jsonError(res, 400, \"Missing query parameter\");\n const count = parseInt(url.searchParams.get(\"count\") ?? \"10\", 10);\n const cursor = url.searchParams.get(\"cursor\") ?? null;\n const result = await room.searchMessages(query, count, cursor);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(result));\n return;\n }\n }\n\n // ── POST endpoints ────────────────────────────────────────────────────\n\n if (req.method === \"POST\") {\n const body = await parseBody(req);\n\n // ── POST /join ──────────────────────────────────────────────────────\n if (url.pathname === \"/join\") {\n // Accept share token OR legacy type-based join\n const shareToken = String(body.token ?? \"\");\n const legacyType = String(body.type ?? \"\");\n\n let authority: AuthorityLevel;\n\n if (shareToken) {\n const tokenAuthority = tokens.validateShareToken(shareToken);\n if (!tokenAuthority) return jsonError(res, 403, \"Invalid share token\");\n authority = tokenAuthority;\n } else if (legacyType === \"guest\") {\n authority = \"observer\";\n } else if (legacyType === \"human\") {\n authority = \"participant\";\n } else {\n // Default: agent joins as participant\n authority = \"participant\";\n }\n\n const participantType = String(body.type ?? \"human\") as \"human\" | \"agent\";\n const name = String(body.name ?? randomName());\n\n if (authority === \"observer\") {\n const id = `obs_${randomUUID().slice(0, 8)}`;\n const channel = room.observe();\n const sessionToken = tokens.createSessionToken(id, \"observer\");\n\n observers.set(sessionToken, { id, authority: \"observer\", channel, sessionToken });\n idToSession.set(id, sessionToken);\n\n const participantList = room.listParticipants().map((p) => ({\n id: p.id,\n name: p.name,\n type: p.type,\n authority: p.authority ?? \"participant\",\n }));\n\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({\n sessionToken,\n participantId: id,\n roomName,\n roomId: room.roomId,\n participants: participantList,\n authority: \"observer\",\n }));\n return;\n }\n\n // admin or participant — connect as a real participant\n const id = `${participantType}_${randomUUID().slice(0, 8)}`;\n const channel = await room.connect(id, name, { type: participantType, authority });\n const sessionToken = tokens.createSessionToken(id, authority);\n\n participants.set(sessionToken, { id, name, authority, channel, sessionToken });\n idToSession.set(id, sessionToken);\n\n const participantList = room.listParticipants().map((p) => ({\n id: p.id,\n name: p.name,\n type: p.type,\n authority: p.authority ?? \"participant\",\n }));\n\n log(`${name} joined (${authority})`);\n\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({\n sessionToken,\n participantId: id,\n roomName,\n roomId: room.roomId,\n participants: participantList,\n authority,\n }));\n return;\n }\n\n // ── All remaining POST endpoints require a session token ────────────\n\n const sessionToken = String(body.token ?? \"\");\n const session = getSession(sessionToken);\n\n // ── POST /message ───────────────────────────────────────────────────\n if (url.pathname === \"/message\") {\n if (!session) return jsonError(res, 401, \"Invalid session token\");\n if (session.authority === \"observer\") return jsonError(res, 403, \"Observers cannot send messages\");\n const content = String(body.content ?? \"\");\n const replyTo = body.replyTo ? String(body.replyTo) : undefined;\n if (!content) return jsonError(res, 400, \"Empty message\");\n\n const p = participants.get(sessionToken);\n if (!p) return jsonError(res, 403, \"Not a participant\");\n\n const msg = await p.channel.sendMessage(content, replyTo);\n jsonOk(res, { messageId: msg.id });\n return;\n }\n\n // ── POST /event ─────────────────────────────────────────────────────\n if (url.pathname === \"/event\") {\n if (!session) return jsonError(res, 401, \"Invalid session token\");\n if (session.authority === \"observer\") return jsonError(res, 403, \"Observers cannot emit events\");\n const event = body.event as RoomEvent | undefined;\n if (!event) return jsonError(res, 400, \"Missing event\");\n\n const p = participants.get(sessionToken);\n if (!p) return jsonError(res, 403, \"Not a participant\");\n\n await p.channel.emit(event);\n jsonOk(res);\n return;\n }\n\n // ── POST /set-mode ──────────────────────────────────────────────────\n if (url.pathname === \"/set-mode\") {\n if (!session) return jsonError(res, 401, \"Invalid session token\");\n const targetId = body.participantId ? String(body.participantId) : session.id;\n const mode = String(body.mode ?? \"\");\n if (!mode) return jsonError(res, 400, \"Missing mode\");\n\n // Setting someone else's mode requires admin\n if (targetId !== session.id && session.authority !== \"admin\") {\n return jsonError(res, 403, \"Only admins can change other participants' modes\");\n }\n\n // Emit mode_changed activity event\n const p = participants.get(sessionToken);\n if (!p) return jsonError(res, 403, \"Not a participant\");\n\n await p.channel.emit(createEvent<ActivityEvent>({\n type: \"Activity\",\n category: \"ACTIVITY\",\n room_id: room.roomId,\n participant_id: targetId,\n action: \"mode_changed\",\n detail: { mode },\n }));\n\n jsonOk(res);\n return;\n }\n\n // ── POST /set-authority ──────────────────────────────────────────────\n if (url.pathname === \"/set-authority\") {\n if (!session) return jsonError(res, 401, \"Invalid session token\");\n if (session.authority !== \"admin\") return jsonError(res, 403, \"Only admins can change authority\");\n const targetId = String(body.participantId ?? \"\");\n const newAuthority = String(body.authority ?? \"\") as AuthorityLevel;\n if (!targetId) return jsonError(res, 400, \"Missing participantId\");\n if (![\"admin\", \"participant\", \"observer\"].includes(newAuthority)) {\n return jsonError(res, 400, \"Invalid authority. Must be admin, participant, or observer.\");\n }\n if (targetId === session.id) return jsonError(res, 400, \"Cannot change own authority\");\n\n // Update all three places: ConnectedParticipant, TokenManager session, Room participant\n const targetSession = idToSession.get(targetId);\n if (!targetSession) return jsonError(res, 404, \"Participant not found\");\n const target = participants.get(targetSession);\n if (!target) return jsonError(res, 404, \"Participant not found\");\n\n target.authority = newAuthority;\n tokens.updateSessionAuthority(targetSession, newAuthority);\n room.setParticipantAuthority(targetId, newAuthority);\n\n // Emit AuthorityChanged event\n const adminP = participants.get(sessionToken);\n const targetParticipant = room.listParticipants().find(p => p.id === targetId);\n if (adminP && targetParticipant) {\n await adminP.channel.emit(createEvent<AuthorityChangedEvent>({\n type: \"AuthorityChanged\",\n category: \"PRESENCE\",\n room_id: room.roomId,\n participant_id: targetId,\n participant: targetParticipant,\n new_authority: newAuthority,\n changed_by: adminP.name,\n }));\n }\n\n log(`${target.name} authority → ${newAuthority}`);\n jsonOk(res);\n return;\n }\n\n // ── POST /kick ──────────────────────────────────────────────────────\n if (url.pathname === \"/kick\") {\n if (!session) return jsonError(res, 401, \"Invalid session token\");\n if (session.authority !== \"admin\") return jsonError(res, 403, \"Only admins can kick\");\n const targetId = String(body.participantId ?? \"\");\n if (!targetId) return jsonError(res, 400, \"Missing participantId\");\n\n // Find and disconnect the target\n const targetSession = idToSession.get(targetId);\n if (targetSession) {\n const target = participants.get(targetSession) ?? observers.get(targetSession);\n if (target) {\n // Emit ParticipantKicked before disconnect so all participants see it\n const adminP = participants.get(sessionToken);\n const targetParticipant = room.listParticipants().find(p => p.id === targetId);\n if (adminP && targetParticipant) {\n await adminP.channel.emit(createEvent<ParticipantKickedEvent>({\n type: \"ParticipantKicked\",\n category: \"PRESENCE\",\n room_id: room.roomId,\n participant_id: targetId,\n participant: targetParticipant,\n kicked_by: adminP.name,\n }));\n }\n // Silent disconnect — the kicked event replaces ParticipantLeft\n await target.channel.disconnect(true);\n participants.delete(targetSession);\n observers.delete(targetSession);\n idToSession.delete(targetId);\n tokens.revokeSessionToken(targetSession);\n // Close SSE connection\n const sse = sseConnections.get(targetId);\n if (sse) {\n sse.end();\n sseConnections.delete(targetId);\n }\n log(`kicked ${targetId}`);\n }\n }\n\n jsonOk(res);\n return;\n }\n\n // ── POST /share ─────────────────────────────────────────────────────\n if (url.pathname === \"/share\") {\n if (!session) return jsonError(res, 401, \"Invalid session token\");\n if (session.authority === \"observer\") return jsonError(res, 403, \"Observers cannot create share links\");\n\n const targetAuthority = (body.authority as AuthorityLevel) ?? undefined;\n\n const links: Record<string, string> = {};\n\n if (targetAuthority) {\n // Generate a specific link\n const token = tokens.generateShareToken(session.authority, targetAuthority);\n if (!token) return jsonError(res, 403, `Cannot generate ${targetAuthority} link`);\n links[targetAuthority] = buildShareUrl(publicUrl, token);\n } else {\n // Generate all links the caller can create\n const tiers: AuthorityLevel[] = [\"admin\", \"participant\", \"observer\"];\n for (const tier of tiers) {\n const token = tokens.generateShareToken(session.authority, tier);\n if (token) links[tier] = buildShareUrl(publicUrl, token);\n }\n }\n\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ links }));\n return;\n }\n\n // ── POST /disconnect ────────────────────────────────────────────────\n if (url.pathname === \"/disconnect\") {\n // Accept either session token or legacy participantId/agentId\n const token = String(body.token ?? \"\");\n const legacyId = String(body.participantId ?? body.agentId ?? \"\");\n\n let targetToken = token;\n if (!targetToken && legacyId) {\n targetToken = idToSession.get(legacyId) ?? \"\";\n }\n\n if (targetToken) {\n const p = participants.get(targetToken);\n if (p) {\n await p.channel.disconnect();\n participants.delete(targetToken);\n idToSession.delete(p.id);\n tokens.revokeSessionToken(targetToken);\n const sse = sseConnections.get(p.id);\n if (sse) { sse.end(); sseConnections.delete(p.id); }\n log(`${p.name} disconnected`);\n }\n\n const o = observers.get(targetToken);\n if (o) {\n await o.channel.disconnect();\n observers.delete(targetToken);\n idToSession.delete(o.id);\n tokens.revokeSessionToken(targetToken);\n const sse = sseConnections.get(o.id);\n if (sse) { sse.end(); sseConnections.delete(o.id); }\n }\n }\n\n jsonOk(res);\n return;\n }\n }\n\n res.writeHead(404).end(\"Not found\");\n });\n\n httpServer.on(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n console.error(`\\nPort ${port} is already in use. Another stoops instance may be running.`);\n console.error(` Kill it: lsof -ti :${port} | xargs kill`);\n console.error(` Or use: stoops --port ${port + 1}\\n`);\n process.exit(1);\n }\n throw err;\n });\n\n await new Promise<void>((resolve) => {\n httpServer.listen(port, \"0.0.0.0\", () => resolve());\n });\n\n // Start tunnel if --share\n if (options.share) {\n tunnelProcess = await startTunnel(port);\n if (tunnelProcess) {\n const tunnelUrl = await waitForTunnelUrl(tunnelProcess);\n if (tunnelUrl) publicUrl = tunnelUrl;\n }\n }\n\n // Generate share tokens on boot\n const adminToken = tokens.generateShareToken(\"admin\", \"admin\")!;\n const participantToken = tokens.generateShareToken(\"admin\", \"participant\")!;\n\n if (options.headless) {\n process.stdout.write(JSON.stringify({ serverUrl, publicUrl, roomName, adminToken, participantToken }) + \"\\n\");\n } else if (!options.quiet) {\n let version = process.env.npm_package_version ?? \"\";\n if (!version) {\n try {\n const require = createRequire(import.meta.url);\n const pkg = require(\"../../package.json\");\n version = pkg.version ?? \"unknown\";\n } catch {\n version = \"unknown\";\n }\n }\n const adminUrl = buildShareUrl(publicUrl, adminToken);\n const joinUrl = buildShareUrl(publicUrl, participantToken);\n\n console.log(`\n stoops v${version}\n\n Room: ${roomName}\n Server: ${serverUrl}${publicUrl !== serverUrl ? `\\n Tunnel: ${publicUrl}` : \"\"}\n\n Join: stoops join ${joinUrl}\n Admin: stoops join ${adminUrl}\n Claude: stoops run claude → then tell agent to join: ${joinUrl}\n`);\n }\n\n // ── Graceful shutdown ──────────────────────────────────────────────────\n\n const shutdown = async () => {\n log(\"shutting down...\");\n if (tunnelProcess) { tunnelProcess.kill(); tunnelProcess = null; }\n for (const [id, sse] of sseConnections) { sse.end(); sseConnections.delete(id); }\n for (const p of participants.values()) { await p.channel.disconnect().catch(() => {}); }\n for (const o of observers.values()) { await o.channel.disconnect().catch(() => {}); }\n await new Promise<void>((resolve, reject) => {\n httpServer.close((err) => (err ? reject(err) : resolve()));\n });\n process.exit(0);\n };\n\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n\n return { serverUrl, publicUrl, roomName, adminToken, participantToken };\n}\n\n// ── Server log ────────────────────────────────────────────────────────────────\n\nfunction logServer(message: string): void {\n console.log(` [${formatTimestamp(new Date())}] ${message}`);\n}\n\n// ── Cloudflared tunnel ───────────────────────────────────────────────────────\n\nfunction cloudflaredAvailable(): boolean {\n try {\n execFileSync(\"which\", [\"cloudflared\"], { stdio: \"ignore\" });\n return true;\n } catch {\n return false;\n }\n}\n\nasync function startTunnel(port: number): Promise<ChildProcess | null> {\n if (!cloudflaredAvailable()) {\n console.error(\" --share requires cloudflared. Install: brew install cloudflared\");\n return null;\n }\n\n const child = spawn(\"cloudflared\", [\"tunnel\", \"--url\", `http://localhost:${port}`], {\n stdio: [\"ignore\", \"ignore\", \"pipe\"],\n });\n\n child.on(\"error\", () => {\n // cloudflared failed to start\n });\n\n return child;\n}\n\nfunction waitForTunnelUrl(child: ChildProcess, timeoutMs = 15000): Promise<string | null> {\n return new Promise((resolve) => {\n let resolved = false;\n let buffer = \"\";\n\n const timer = setTimeout(() => {\n if (!resolved) { resolved = true; resolve(null); }\n }, timeoutMs);\n\n child.stderr?.on(\"data\", (chunk: Buffer) => {\n buffer += chunk.toString();\n const match = buffer.match(/https:\\/\\/[a-z0-9-]+\\.trycloudflare\\.com/);\n if (match && !resolved) {\n resolved = true;\n clearTimeout(timer);\n resolve(match[0]);\n }\n });\n\n child.on(\"exit\", () => {\n if (!resolved) { resolved = true; clearTimeout(timer); resolve(null); }\n });\n });\n}\n","/**\n * Auth token system for stoops share links and session management.\n *\n * Two token types:\n * - Share tokens — embedded in URLs, map to an authority tier.\n * Anyone with the link joins at that tier.\n * - Session tokens — issued on join, identify a participant + authority.\n * Used for all subsequent API calls.\n */\n\nimport { randomBytes } from \"node:crypto\";\nimport type { AuthorityLevel } from \"../core/types.js\";\n\ninterface SessionData {\n participantId: string;\n authority: AuthorityLevel;\n}\n\nexport class TokenManager {\n /** share token hash → authority level */\n private _shareTokens = new Map<string, AuthorityLevel>();\n /** session token → participant data */\n private _sessionTokens = new Map<string, SessionData>();\n\n /**\n * Generate a share token at the given authority tier.\n * Callers can only generate tokens at their own tier or below.\n */\n generateShareToken(callerAuthority: AuthorityLevel, targetAuthority: AuthorityLevel): string | null {\n if (!canGrant(callerAuthority, targetAuthority)) return null;\n const token = randomBytes(16).toString(\"hex\");\n this._shareTokens.set(token, targetAuthority);\n return token;\n }\n\n /** Validate a share token and return its authority level. */\n validateShareToken(token: string): AuthorityLevel | null {\n return this._shareTokens.get(token) ?? null;\n }\n\n /** Create a session token for a participant. */\n createSessionToken(participantId: string, authority: AuthorityLevel): string {\n const token = randomBytes(16).toString(\"hex\");\n this._sessionTokens.set(token, { participantId, authority });\n return token;\n }\n\n /** Validate a session token and return participant data. */\n validateSessionToken(token: string): SessionData | null {\n return this._sessionTokens.get(token) ?? null;\n }\n\n /** Revoke a session token (on disconnect). */\n revokeSessionToken(token: string): void {\n this._sessionTokens.delete(token);\n }\n\n /** Update the authority level for an existing session. */\n updateSessionAuthority(token: string, newAuthority: AuthorityLevel): boolean {\n const data = this._sessionTokens.get(token);\n if (!data) return false;\n data.authority = newAuthority;\n return true;\n }\n\n /** Find a session token by participant ID (for cleanup). */\n findSessionByParticipant(participantId: string): string | null {\n for (const [token, data] of this._sessionTokens) {\n if (data.participantId === participantId) return token;\n }\n return null;\n }\n}\n\n/** Authority tier ordering: admin > participant > observer. */\nconst TIER_ORDER: Record<AuthorityLevel, number> = {\n admin: 2,\n participant: 1,\n observer: 0,\n};\n\n/** Can a caller at `callerLevel` grant authority at `targetLevel`? */\nfunction canGrant(callerLevel: AuthorityLevel, targetLevel: AuthorityLevel): boolean {\n return TIER_ORDER[callerLevel] >= TIER_ORDER[targetLevel];\n}\n\n/** Build a share URL from a base URL and token. */\nexport function buildShareUrl(baseUrl: string, token: string): string {\n const url = new URL(baseUrl);\n url.searchParams.set(\"token\", token);\n return url.toString();\n}\n\n/** Extract a token from a share URL. */\nexport function extractToken(url: string): string | null {\n try {\n const parsed = new URL(url);\n return parsed.searchParams.get(\"token\");\n } catch {\n return null;\n }\n}\n","/**\n * stoops join — connect to a room as a human participant.\n *\n * Opens the TUI and connects to a stoops server over HTTP.\n * Events stream in via SSE, messages sent via POST /message.\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport { createInterface } from \"node:readline\";\nimport { randomName } from \"../core/names.js\";\nimport type { RoomEvent } from \"../core/events.js\";\nimport type { AuthorityLevel } from \"../core/types.js\";\nimport { formatTimestamp } from \"../agent/prompts.js\";\nimport { startTUI, type TUIHandle, type DisplayEvent } from \"./tui.js\";\nimport { extractToken, buildShareUrl } from \"./auth.js\";\n\nexport interface JoinOptions {\n server: string;\n name?: string;\n guest?: boolean;\n /** Share URL to display before TUI starts (for host+join mode with --share). */\n shareUrl?: string;\n /** Skip TUI — stream events as JSON to stdout, read messages from stdin. */\n headless?: boolean;\n}\n\nexport async function join(options: JoinOptions): Promise<void> {\n // Extract token from URL if present\n const token = extractToken(options.server);\n // Strip query params to get clean server URL\n let serverUrl: string;\n try {\n const parsed = new URL(options.server);\n parsed.search = \"\";\n serverUrl = parsed.toString().replace(/\\/$/, \"\");\n } catch {\n serverUrl = options.server.replace(/\\/$/, \"\");\n }\n\n const name = options.name ?? randomName();\n const isGuest = options.guest ?? false;\n\n // ── Register with server ────────────────────────────────────────────────\n\n let sessionToken: string;\n let participantId: string;\n let roomName: string;\n let authority: AuthorityLevel;\n let participants: Array<{ id: string; name: string; type: string; authority?: string }>;\n\n try {\n const joinBody: Record<string, unknown> = {};\n if (token) {\n joinBody.token = token;\n joinBody.type = \"human\";\n joinBody.name = name;\n } else if (isGuest) {\n joinBody.type = \"guest\";\n } else {\n joinBody.type = \"human\";\n joinBody.name = name;\n }\n\n const res = await fetch(`${serverUrl}/join`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(joinBody),\n });\n\n if (!res.ok) {\n const err = await res.text();\n console.error(`Failed to join: ${err}`);\n process.exit(1);\n }\n\n const data = await res.json() as Record<string, unknown>;\n sessionToken = String(data.sessionToken ?? \"\");\n participantId = String(data.participantId);\n roomName = String(data.roomName);\n authority = (data.authority as AuthorityLevel) ?? \"participant\";\n participants = (data.participants as Array<{ id: string; name: string; type: string; authority?: string }>) ?? [];\n } catch {\n console.error(`Cannot reach stoops server at ${serverUrl}. Is it running?`);\n process.exit(1);\n }\n\n // ── Disconnect helper ───────────────────────────────────────────────────\n\n let disconnected = false;\n let cleanupStream: (() => void) | null = null;\n const disconnect = async () => {\n if (disconnected) return;\n disconnected = true;\n cleanupStream?.();\n try {\n await fetch(`${serverUrl}/disconnect`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token: sessionToken }),\n });\n } catch {\n // Server may be down\n }\n };\n\n // ── Headless mode — skip TUI, stream events as JSON, read messages from stdin ──\n\n if (options.headless) {\n const sseController = new AbortController();\n const cleanup = async () => {\n sseController.abort();\n await disconnect();\n };\n\n process.on(\"SIGINT\", async () => { await cleanup(); process.exit(0); });\n process.on(\"SIGTERM\", async () => { await cleanup(); process.exit(0); });\n\n // Read messages from stdin and send them\n const rl = createInterface({ input: process.stdin, terminal: false });\n rl.on(\"line\", async (line) => {\n const content = line.trim();\n if (!content || authority === \"observer\") return;\n try {\n await fetch(`${serverUrl}/message`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token: sessionToken, content }),\n });\n } catch { /* server may be down */ }\n });\n\n // Stream events from SSE and write as JSON lines to stdout\n try {\n const res = await fetch(`${serverUrl}/events`, {\n method: \"POST\",\n headers: { Accept: \"text/event-stream\", Authorization: `Bearer ${sessionToken}` },\n signal: sseController.signal,\n });\n\n if (!res.ok || !res.body) {\n process.stderr.write(\"Failed to connect event stream\\n\");\n await cleanup();\n process.exit(1);\n }\n\n const reader = res.body.getReader();\n const decoder = new TextDecoder();\n let buf = \"\";\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buf += decoder.decode(value, { stream: true });\n const parts = buf.split(\"\\n\\n\");\n buf = parts.pop()!;\n for (const part of parts) {\n const dataLine = part.split(\"\\n\").find((l) => l.startsWith(\"data: \"));\n if (!dataLine) continue;\n try {\n const event = JSON.parse(dataLine.slice(6));\n process.stdout.write(JSON.stringify(event) + \"\\n\");\n } catch { /* malformed */ }\n }\n }\n } catch {\n // Stream ended or aborted\n }\n\n if (!disconnected) { await cleanup(); }\n process.exit(0);\n }\n\n // ── Start TUI ───────────────────────────────────────────────────────────\n\n const isReadOnly = authority === \"observer\" || isGuest;\n\n // ── Slash command helper ──────────────────────────────────────────────\n\n function systemEvent(content: string): void {\n tui.push({\n id: randomUUID(),\n ts: formatTimestamp(new Date()),\n kind: \"system\",\n content,\n });\n }\n\n async function handleSlashCommand(input: string): Promise<void> {\n const parts = input.slice(1).split(/\\s+/);\n const cmd = parts[0]?.toLowerCase();\n const args = parts.slice(1);\n\n switch (cmd) {\n // ── /who ──────────────────────────────────────────────────────\n case \"who\": {\n try {\n const res = await fetch(`${serverUrl}/participants?token=${sessionToken}`);\n if (!res.ok) { systemEvent(\"Failed to get participant list.\"); return; }\n const data = (await res.json()) as { participants: Array<{ id: string; name: string; type: string; authority?: string }> };\n const lines = data.participants.map((p) => {\n const auth = p.authority ?? \"participant\";\n return ` ${p.type === \"agent\" ? \"agent\" : \"human\"} ${p.name} (${auth})`;\n });\n systemEvent(`Participants:\\n${lines.join(\"\\n\")}`);\n } catch {\n systemEvent(\"Failed to reach server.\");\n }\n return;\n }\n\n // ── /leave ────────────────────────────────────────────────────\n case \"leave\": {\n await disconnect();\n tui.stop();\n process.exit(0);\n return;\n }\n\n // ── /kick <name> (admin only) ─────────────────────────────────\n case \"kick\": {\n if (authority !== \"admin\") { systemEvent(\"Only admins can kick.\"); return; }\n const targetName = args[0];\n if (!targetName) { systemEvent(\"Usage: /kick <name>\"); return; }\n\n // Look up participant by name\n try {\n const res = await fetch(`${serverUrl}/participants?token=${sessionToken}`);\n if (!res.ok) { systemEvent(\"Failed to get participant list.\"); return; }\n const data = (await res.json()) as { participants: Array<{ id: string; name: string }> };\n const target = data.participants.find((p) => p.name.toLowerCase() === targetName.toLowerCase());\n if (!target) { systemEvent(`Participant \"${targetName}\" not found.`); return; }\n\n const kickRes = await fetch(`${serverUrl}/kick`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token: sessionToken, participantId: target.id }),\n });\n if (!kickRes.ok) { systemEvent(`Failed to kick: ${await kickRes.text()}`); return; }\n systemEvent(`Kicked ${targetName}.`);\n } catch {\n systemEvent(\"Failed to reach server.\");\n }\n return;\n }\n\n // ── /mute <name> (admin only) — demote to observer ────────────\n case \"mute\": {\n if (authority !== \"admin\") { systemEvent(\"Only admins can mute.\"); return; }\n const targetName = args[0];\n if (!targetName) { systemEvent(\"Usage: /mute <name>\"); return; }\n\n try {\n const res = await fetch(`${serverUrl}/participants?token=${sessionToken}`);\n if (!res.ok) { systemEvent(\"Failed to get participant list.\"); return; }\n const data = (await res.json()) as { participants: Array<{ id: string; name: string }> };\n const target = data.participants.find((p) => p.name.toLowerCase() === targetName.toLowerCase());\n if (!target) { systemEvent(`Participant \"${targetName}\" not found.`); return; }\n\n const authRes = await fetch(`${serverUrl}/set-authority`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token: sessionToken, participantId: target.id, authority: \"observer\" }),\n });\n if (!authRes.ok) { systemEvent(`Failed to mute: ${await authRes.text()}`); return; }\n systemEvent(`Muted ${targetName} (observer).`);\n } catch {\n systemEvent(\"Failed to reach server.\");\n }\n return;\n }\n\n // ── /unmute <name> (admin only) — restore to participant ──────\n case \"unmute\": {\n if (authority !== \"admin\") { systemEvent(\"Only admins can unmute.\"); return; }\n const targetName = args[0];\n if (!targetName) { systemEvent(\"Usage: /unmute <name>\"); return; }\n\n try {\n const res = await fetch(`${serverUrl}/participants?token=${sessionToken}`);\n if (!res.ok) { systemEvent(\"Failed to get participant list.\"); return; }\n const data = (await res.json()) as { participants: Array<{ id: string; name: string }> };\n const target = data.participants.find((p) => p.name.toLowerCase() === targetName.toLowerCase());\n if (!target) { systemEvent(`Participant \"${targetName}\" not found.`); return; }\n\n const authRes = await fetch(`${serverUrl}/set-authority`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token: sessionToken, participantId: target.id, authority: \"participant\" }),\n });\n if (!authRes.ok) { systemEvent(`Failed to unmute: ${await authRes.text()}`); return; }\n systemEvent(`Unmuted ${targetName} (participant).`);\n } catch {\n systemEvent(\"Failed to reach server.\");\n }\n return;\n }\n\n // ── /setmode <name> <mode> (admin only) ───────────────────────\n case \"setmode\": {\n if (authority !== \"admin\") { systemEvent(\"Only admins can set modes.\"); return; }\n const targetName = args[0];\n const mode = args[1];\n if (!targetName || !mode) { systemEvent(\"Usage: /setmode <name> <mode>\"); return; }\n\n try {\n const res = await fetch(`${serverUrl}/participants?token=${sessionToken}`);\n if (!res.ok) { systemEvent(\"Failed to get participant list.\"); return; }\n const data = (await res.json()) as { participants: Array<{ id: string; name: string }> };\n const target = data.participants.find((p) => p.name.toLowerCase() === targetName.toLowerCase());\n if (!target) { systemEvent(`Participant \"${targetName}\" not found.`); return; }\n\n const modeRes = await fetch(`${serverUrl}/set-mode`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token: sessionToken, participantId: target.id, mode }),\n });\n if (!modeRes.ok) { systemEvent(`Failed to set mode: ${await modeRes.text()}`); return; }\n systemEvent(`Set ${targetName} to ${mode}.`);\n } catch {\n systemEvent(\"Failed to reach server.\");\n }\n return;\n }\n\n // ── /share [--as <tier>] ──────────────────────────────────────\n case \"share\": {\n if (authority === \"observer\") { systemEvent(\"Observers cannot create share links.\"); return; }\n\n let targetAuthority: string | undefined;\n if (args[0] === \"--as\" && args[1]) {\n targetAuthority = args[1];\n }\n\n try {\n const body: Record<string, unknown> = { token: sessionToken };\n if (targetAuthority) body.authority = targetAuthority;\n\n const res = await fetch(`${serverUrl}/share`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n if (!res.ok) { systemEvent(`Failed: ${await res.text()}`); return; }\n const data = (await res.json()) as { links: Record<string, string> };\n const lines = Object.entries(data.links).map(([tier, url]) =>\n ` ${tier}: stoops join ${url}`\n );\n systemEvent(`Share links:\\n${lines.join(\"\\n\")}`);\n } catch {\n systemEvent(\"Failed to reach server.\");\n }\n return;\n }\n\n default:\n systemEvent(`Unknown command: /${cmd}`);\n }\n }\n\n // Print share info via console.log BEFORE Ink renders. This lands in the\n // terminal buffer above Ink's render area — plain text, no ANSI codes,\n // fully selectable. Each line is a complete copyable command.\n if (options.shareUrl) {\n console.log();\n console.log(` Invite a friend: npx stoops join \"${options.shareUrl}\"`);\n console.log(` Connect Claude Code: npx stoops run claude → then tell agent to join: ${options.shareUrl}`);\n console.log();\n }\n\n const tui = startTUI({\n roomName,\n readOnly: isReadOnly,\n isAdmin: authority === \"admin\",\n onSend: isReadOnly ? undefined : async (content: string) => {\n // Intercept slash commands\n if (content.startsWith(\"/\")) {\n await handleSlashCommand(content);\n return;\n }\n\n try {\n await fetch(`${serverUrl}/message`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token: sessionToken, content }),\n });\n } catch {\n // Server may be down — silently fail\n }\n },\n onCtrlC: async () => {\n await disconnect();\n tui.stop();\n process.exit(0);\n },\n });\n\n // Set initial agent names + participant names\n const agentNames = participants\n .filter((p) => p.type === \"agent\")\n .map((p) => p.name);\n if (agentNames.length > 0) {\n tui.setAgentNames(agentNames);\n }\n const participantNames = new Set(\n participants.filter((p) => p.id !== participantId).map((p) => p.name),\n );\n tui.setParticipants([...participantNames]);\n\n // ── Connect SSE event stream ────────────────────────────────────────────\n // ⚠️ MUST use POST — DO NOT change to GET.\n // Cloudflare Quick Tunnels buffer GET streaming responses and only flush\n // when the connection closes. POST streams in real-time. (cloudflared#1449)\n // https://github.com/cloudflare/cloudflared/issues/1449\n\n {\n const participantTypes = new Map<string, \"human\" | \"agent\">();\n for (const p of participants) {\n participantTypes.set(p.id, p.type as \"human\" | \"agent\");\n }\n const currentAgents = new Set(agentNames);\n let sseController: AbortController | null = null;\n\n cleanupStream = () => {\n if (sseController) { sseController.abort(); sseController = null; }\n };\n\n const connectSSE = async () => {\n sseController = new AbortController();\n\n try {\n const res = await fetch(`${serverUrl}/events`, {\n method: \"POST\",\n headers: {\n Accept: \"text/event-stream\",\n Authorization: `Bearer ${sessionToken}`,\n },\n signal: sseController.signal,\n });\n\n if (!res.ok || !res.body) {\n console.error(\"Failed to connect event stream\");\n await disconnect();\n process.exit(1);\n }\n\n const reader = res.body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const parts = buffer.split(\"\\n\\n\");\n buffer = parts.pop()!;\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 & { _replyToName?: string };\n\n if (event.type === \"ParticipantJoined\") {\n participantTypes.set(event.participant.id, event.participant.type);\n }\n\n const displayEvent = toDisplayEvent(event, participantId, participantTypes);\n if (displayEvent) {\n tui.push(displayEvent);\n }\n\n if (event.type === \"ParticipantJoined\") {\n if (event.participant.type === \"agent\") {\n currentAgents.add(event.participant.name);\n tui.setAgentNames([...currentAgents]);\n }\n if (event.participant.id !== participantId) {\n participantNames.add(event.participant.name);\n tui.setParticipants([...participantNames]);\n }\n }\n if (event.type === \"ParticipantLeft\") {\n if (event.participant.type === \"agent\") {\n currentAgents.delete(event.participant.name);\n tui.setAgentNames([...currentAgents]);\n }\n participantTypes.delete(event.participant.id);\n participantNames.delete(event.participant.name);\n tui.setParticipants([...participantNames]);\n }\n } catch {\n // Malformed event — skip\n }\n }\n }\n\n // Stream ended — server closed connection\n if (!disconnected) {\n tui.stop();\n console.log(\"\\nServer disconnected.\");\n process.exit(0);\n }\n } catch {\n if (!disconnected) {\n tui.stop();\n console.log(\"\\nServer disconnected.\");\n process.exit(0);\n }\n }\n };\n\n connectSSE();\n }\n\n // ── Graceful shutdown ───────────────────────────────────────────────────\n\n process.on(\"SIGINT\", async () => {\n await disconnect();\n tui.stop();\n process.exit(0);\n });\n process.on(\"SIGTERM\", async () => {\n await disconnect();\n tui.stop();\n process.exit(0);\n });\n}\n\n// ── RoomEvent → DisplayEvent conversion ───────────────────────────────────────\n\nfunction toDisplayEvent(\n event: RoomEvent & { _replyToName?: string },\n selfId: string,\n participantTypes: Map<string, \"human\" | \"agent\">,\n): DisplayEvent | null {\n const ts = formatTimestamp(new Date(event.timestamp));\n\n switch (event.type) {\n case \"MessageSent\": {\n const msg = event.message;\n const senderType = participantTypes.get(msg.sender_id) ?? \"human\";\n return {\n id: msg.id,\n ts,\n kind: \"message\",\n senderName: msg.sender_name,\n senderType,\n isSelf: msg.sender_id === selfId,\n content: msg.content,\n replyToName: event._replyToName ?? undefined,\n };\n }\n case \"ParticipantJoined\":\n return {\n id: randomUUID(),\n ts,\n kind: \"join\",\n name: event.participant.name,\n participantType: event.participant.type,\n };\n case \"ParticipantLeft\":\n return {\n id: randomUUID(),\n ts,\n kind: \"leave\",\n name: event.participant.name,\n participantType: event.participant.type,\n };\n case \"ParticipantKicked\":\n return {\n id: randomUUID(),\n ts,\n kind: \"system\",\n content: `${event.participant.name} was kicked`,\n };\n case \"AuthorityChanged\": {\n const name = event.participant.name;\n if (event.new_authority === \"observer\") {\n return { id: randomUUID(), ts, kind: \"system\", content: `${name} was muted` };\n }\n if (event.new_authority === \"participant\") {\n return { id: randomUUID(), ts, kind: \"system\", content: `${name} was unmuted` };\n }\n return { id: randomUUID(), ts, kind: \"system\", content: `${name} → ${event.new_authority}` };\n }\n case \"Activity\":\n if (event.action === \"mode_changed\") {\n return {\n id: randomUUID(),\n ts,\n kind: \"mode\",\n mode: String((event.detail as Record<string, unknown>)?.mode ?? \"\"),\n };\n }\n return null;\n default:\n return null;\n }\n}\n","/**\n * stoops TUI — ink-based terminal UI for the room server.\n *\n * Uses ink's <Static> for events (rendered once, selectable terminal text)\n * and a dynamic footer for input + status. Same architecture as Claude Code.\n */\n\nimport React, { useState, useEffect, useCallback, useMemo } from \"react\";\nimport { render, Box, Text, Static, useStdout, useInput } from \"ink\";\n\n// ── Palette (from stoops-app) ─────────────────────────────────────────────────\n\nconst C = {\n cyan: \"#00d4ff\",\n purple: \"#8b5cf6\",\n orange: \"#ff8c42\",\n pink: \"#f472b6\",\n green: \"#34d399\",\n yellow: \"#fbbf24\",\n danger: \"#f87171\",\n text: \"#eceff4\",\n secondary: \"#b0b7c4\",\n dim: \"#7e8798\",\n muted: \"#5b6679\",\n border: \"#475264\",\n} as const;\n\nconst AGENT_COLORS = [C.cyan, C.purple, C.orange, C.pink, C.green, C.yellow] as const;\nconst SIGILS = [\"◆\", \"▲\", \"●\", \"■\", \"★\", \"◉\", \"◈\", \"▸\"] as const;\n\n// ── Banner ───────────────────────────────────────────────────────────────────\n// Figlet \"slant\" font, colored with a purple → cyan gradient per line.\n\nconst BANNER_LINES = [\n \" __ \",\n \" _____/ /_____ ____ ____ _____\",\n \" / ___/ __/ __ \\\\/ __ \\\\/ __ \\\\/ ___/\",\n \" (__ ) /_/ /_/ / /_/ / /_/ (__ ) \",\n \"/____/\\\\__/\\\\____/\\\\____/ .___/____/ \",\n \" /_/ \",\n];\n\nconst GRADIENT = [\"#9b6dff\", \"#7c8bff\", \"#5da8ff\", \"#3dc4ff\", \"#1ddcff\", \"#00e8ff\"];\n\n// ── Slash commands ────────────────────────────────────────────────────────────\n\ninterface SlashParam {\n label: string; // display hint: \"name\", \"mode\", etc.\n completions?: string[] | \"participants\"; // static values, dynamic lookup, or undefined (hint only)\n}\n\ninterface SlashCommand {\n name: string;\n description: string;\n adminOnly?: boolean;\n params?: SlashParam[];\n}\n\nconst ENGAGEMENT_MODES = [\n \"everyone\", \"people\", \"agents\", \"me\",\n \"standby-everyone\", \"standby-people\", \"standby-agents\", \"standby-me\",\n];\n\nconst SLASH_COMMANDS: SlashCommand[] = [\n { name: \"/who\", description: \"List participants\" },\n { name: \"/leave\", description: \"Disconnect and exit\" },\n { name: \"/share\", description: \"Generate share links\" },\n { name: \"/kick\", description: \"Remove a participant\", adminOnly: true, params: [\n { label: \"name\", completions: \"participants\" },\n ]},\n { name: \"/mute\", description: \"Make read-only (observer)\", adminOnly: true, params: [\n { label: \"name\", completions: \"participants\" },\n ]},\n { name: \"/unmute\", description: \"Restore to participant\", adminOnly: true, params: [\n { label: \"name\", completions: \"participants\" },\n ]},\n { name: \"/setmode\", description: \"Set engagement mode\", adminOnly: true, params: [\n { label: \"name\", completions: \"participants\" },\n { label: \"mode\", completions: ENGAGEMENT_MODES },\n ]},\n];\n\nconst CMD_DISPLAY_COL = 26; // width for command + params display column\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport type DisplayEvent =\n | { id: string; ts: string; kind: \"message\"; senderName: string; senderType: \"human\" | \"agent\"; isSelf: boolean; content: string; replyToName?: string }\n | { id: string; ts: string; kind: \"join\"; name: string; participantType: \"human\" | \"agent\" }\n | { id: string; ts: string; kind: \"leave\"; name: string; participantType: \"human\" | \"agent\" }\n | { id: string; ts: string; kind: \"mode\"; mode: string }\n | { id: string; ts: string; kind: \"system\"; content: string };\n\nexport interface TUIHandle {\n push(event: DisplayEvent): void;\n setAgentNames(names: string[]): void;\n setParticipants(names: string[]): void;\n stop(): void;\n}\n\nexport interface TUIOptions {\n roomName: string;\n onSend?(content: string): void;\n onCtrlC?(): void;\n readOnly?: boolean;\n isAdmin?: boolean;\n}\n\n// ── Identity (seed → color + sigil) ──────────────────────────────────────────\n\nfunction seedHash(s: string): number {\n let h = 0;\n for (let i = 0; i < s.length; i++) h = ((h << 5) - h + s.charCodeAt(i)) | 0;\n return Math.abs(h);\n}\n\nfunction makeIdentityAssigner(): (name: string) => { color: string; sigil: string } {\n const map = new Map<string, { color: string; sigil: string }>();\n let colorIdx = 0;\n return (name: string) => {\n if (!map.has(name)) {\n const h = seedHash(name);\n map.set(name, {\n color: AGENT_COLORS[colorIdx++ % AGENT_COLORS.length],\n sigil: SIGILS[h % SIGILS.length],\n });\n }\n return map.get(name)!;\n };\n}\n\n// ── Event line ────────────────────────────────────────────────────────────────\n\nconst NAME_COL = 12;\n\nfunction EventLine({\n event,\n identify,\n}: {\n event: DisplayEvent;\n identify: (n: string) => { color: string; sigil: string };\n}) {\n const ts = <Text color={C.muted}>{event.ts}{\" \"}</Text>;\n\n // ── Message ──\n if (event.kind === \"message\") {\n const { color, sigil } = identify(event.senderName);\n const isSelf = event.isSelf;\n const nameColor = isSelf ? C.text : event.senderType === \"agent\" ? color : C.secondary;\n const sigilColor = isSelf ? C.dim : event.senderType === \"agent\" ? color : C.dim;\n const sigilChar = isSelf ? \"›\" : event.senderType === \"agent\" ? sigil : \"·\";\n const contentColor = isSelf ? C.text : C.secondary;\n\n return (\n <Box paddingX={1}>\n <Box flexShrink={0}>\n {ts}\n <Text color={sigilColor}>{sigilChar}{\" \"}</Text>\n <Text color={nameColor} bold={isSelf}>\n {event.senderName.slice(0, NAME_COL).padEnd(NAME_COL)}\n </Text>\n <Text>{\" \"}</Text>\n </Box>\n <Box flexGrow={1} flexShrink={1}>\n <Text wrap=\"wrap\">\n {event.replyToName && <Text color={C.dim}>{\"→ \"}{event.replyToName}{\" \"}</Text>}\n <Text color={contentColor}>{event.content}</Text>\n </Text>\n </Box>\n </Box>\n );\n }\n\n // ── Join ──\n if (event.kind === \"join\") {\n const isAgent = event.participantType === \"agent\";\n const { color, sigil } = isAgent ? identify(event.name) : { color: C.dim, sigil: \"·\" };\n return (\n <Box paddingX={1}>\n {ts}\n <Text color={isAgent ? color : C.dim}>{sigil}{\" \"}</Text>\n <Text color={isAgent ? color : C.dim}>{event.name}</Text>\n <Text color={C.green}>{\" joined\"}</Text>\n </Box>\n );\n }\n\n // ── Leave ──\n if (event.kind === \"leave\") {\n const isAgent = event.participantType === \"agent\";\n const { color: nameColor } = isAgent ? identify(event.name) : { color: C.muted };\n return (\n <Box paddingX={1}>\n {ts}\n <Text color={C.muted}>{\"· \"}</Text>\n <Text color={nameColor}>{event.name}</Text>\n <Text color={C.danger}>{\" left\"}</Text>\n </Box>\n );\n }\n\n // ── Mode change ──\n if (event.kind === \"mode\") {\n return (\n <Box paddingX={1}>\n {ts}\n <Text color={C.dim}>{\"mode → \"}</Text>\n <Text color={C.yellow} bold>{event.mode}</Text>\n </Box>\n );\n }\n\n // ── System message (slash command output) ──\n if (event.kind === \"system\") {\n return (\n <Box paddingX={1}>\n {ts}\n <Text color={C.dim}>{\" \"}</Text>\n <Text color={C.secondary}>{event.content}</Text>\n </Box>\n );\n }\n\n return null;\n}\n\n// ── Internal bridge ───────────────────────────────────────────────────────────\n\ninterface AppHandle {\n push: (event: DisplayEvent) => void;\n setAgentNames: (names: string[]) => void;\n setParticipants: (names: string[]) => void;\n}\n\n// ── App ───────────────────────────────────────────────────────────────────────\n\ntype StaticEntry = { id: string; event?: DisplayEvent };\n\nfunction App({\n roomName,\n onSend,\n onCtrlC,\n onReady,\n readOnly,\n isAdmin,\n}: {\n roomName: string;\n onSend?: (content: string) => void;\n onCtrlC?: () => void;\n onReady: (handle: AppHandle) => void;\n readOnly?: boolean;\n isAdmin?: boolean;\n}) {\n const [events, setEvents] = useState<DisplayEvent[]>([]);\n const [agentNames, setAgentNames] = useState<string[]>([]);\n const [participants, setParticipants] = useState<string[]>([]);\n const [input, setInput] = useState(\"\");\n const [selectedIndex, setSelectedIndex] = useState(0);\n const { stdout } = useStdout();\n const identify = useMemo(makeIdentityAssigner, []);\n\n const push = useCallback((event: DisplayEvent) => {\n setEvents((prev) => [...prev, event]);\n }, []);\n\n useEffect(() => {\n onReady({ push, setAgentNames, setParticipants });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Note: no resize handler — Ink's <Static> items are already committed to the\n // terminal buffer. Forcing a re-render on resize causes cursor position\n // miscalculation and screen corruption. The divider width updates naturally\n // on the next state change (new event, input change, etc.).\n\n // ── Slash command suggestions ──────────────────────────────────────────────\n\n type SuggestionItem =\n | { kind: \"command\"; cmd: SlashCommand; insert: string }\n | { kind: \"param\"; value: string; insert: string }\n | { kind: \"mention\"; value: string; insert: string };\n\n const suggestionState = useMemo((): { items: SuggestionItem[]; ghostHint: string } => {\n // @mention detection — match @partial at end of input\n const mentionMatch = input.match(/@([a-zA-Z0-9_-]*)$/);\n if (mentionMatch && participants.length > 0) {\n const prefix = mentionMatch[1].toLowerCase();\n const filtered = participants.filter((p) => p.toLowerCase().startsWith(prefix));\n if (filtered.length > 0) {\n const before = input.slice(0, mentionMatch.index!);\n const items: SuggestionItem[] = filtered.map((p) => ({\n kind: \"mention\" as const,\n value: p,\n insert: before + \"@\" + p + \" \",\n }));\n const ghostHint = prefix.length === 0 ? \"\" : (filtered[0].slice(prefix.length));\n return { items, ghostHint };\n }\n }\n\n if (!input.startsWith(\"/\")) return { items: [], ghostHint: \"\" };\n\n const spaceIdx = input.indexOf(\" \");\n\n // Phase 1: completing command name (no space yet)\n if (spaceIdx === -1) {\n const prefix = input.toLowerCase();\n const items: SuggestionItem[] = SLASH_COMMANDS\n .filter((cmd) => {\n if (cmd.adminOnly && !isAdmin) return false;\n return cmd.name.startsWith(prefix);\n })\n .map((cmd) => ({\n kind: \"command\" as const,\n cmd,\n insert: cmd.name + \" \",\n }));\n return { items, ghostHint: \"\" };\n }\n\n // Phase 2: completing params\n const cmdName = input.slice(0, spaceIdx).toLowerCase();\n const cmd = SLASH_COMMANDS.find((c) => c.name === cmdName && (!c.adminOnly || isAdmin));\n if (!cmd?.params) return { items: [], ghostHint: \"\" };\n\n const rest = input.slice(spaceIdx + 1);\n const words = rest.split(/\\s+/);\n const hasTrailingSpace = rest.endsWith(\" \") || rest === \"\";\n const completedCount = hasTrailingSpace\n ? words.filter(Boolean).length\n : Math.max(0, words.length - 1);\n const currentPrefix = hasTrailingSpace ? \"\" : (words[words.length - 1] ?? \"\").toLowerCase();\n const paramIdx = completedCount;\n\n // All params filled\n if (paramIdx >= cmd.params.length) return { items: [], ghostHint: \"\" };\n\n const param = cmd.params[paramIdx];\n\n // Ghost hint: remaining unfilled params (skip current if partially typed)\n const ghostStart = currentPrefix ? paramIdx + 1 : paramIdx;\n const ghostHint = cmd.params.slice(ghostStart).map((p) => `<${p.label}>`).join(\" \");\n\n // No completions defined — hint only\n if (!param.completions) return { items: [], ghostHint };\n\n const values = param.completions === \"participants\" ? participants : param.completions;\n const filtered = currentPrefix\n ? values.filter((v) => v.toLowerCase().startsWith(currentPrefix))\n : values;\n\n // Build insert string: full command up to current param + selected value\n const completedWords = words.slice(0, completedCount).filter(Boolean);\n const base = cmdName + (completedWords.length ? \" \" + completedWords.join(\" \") : \"\") + \" \";\n\n const items: SuggestionItem[] = filtered.map((v) => ({\n kind: \"param\" as const,\n value: v,\n insert: base + v + \" \",\n }));\n\n return { items, ghostHint };\n }, [input, isAdmin, participants]);\n\n const suggestions = suggestionState.items;\n\n // Reset selection when input changes (arrow keys don't change input)\n useEffect(() => { setSelectedIndex(0); }, [input]);\n\n // ── Keyboard ───────────────────────────────────────────────────────────────\n // Single useInput handles everything — no TextInput, no dual-handler conflicts.\n\n useInput((char, key) => {\n if (key.ctrl && char === \"c\") { onCtrlC?.(); return; }\n if (readOnly || !onSend) return;\n\n // Suggestion navigation\n if (suggestions.length > 0) {\n if (key.downArrow) {\n setSelectedIndex((i) => Math.min(i + 1, suggestions.length - 1));\n return;\n }\n if (key.upArrow) {\n setSelectedIndex((i) => Math.max(i - 1, 0));\n return;\n }\n if (key.return || key.tab) {\n const picked = suggestions[selectedIndex];\n if (!picked) return;\n // No-param command + Enter → submit directly\n if (key.return && picked.kind === \"command\" && !picked.cmd.params) {\n onSend(picked.cmd.name);\n setInput(\"\");\n return;\n }\n setInput(picked.insert);\n return;\n }\n if (key.escape) {\n setInput(\"\");\n return;\n }\n }\n\n // Option+Enter → newline\n if (key.return && key.meta) {\n setInput((prev) => prev + \"\\n\");\n return;\n }\n\n // Enter → submit\n if (key.return) {\n const content = input.trim();\n if (content) onSend(content);\n setInput(\"\");\n return;\n }\n\n // Backspace\n if (key.backspace || key.delete) {\n setInput((prev) => prev.slice(0, -1));\n return;\n }\n\n // Ignore special keys\n if (key.ctrl || key.meta || key.escape || key.tab ||\n key.upArrow || key.downArrow || key.leftArrow || key.rightArrow) {\n return;\n }\n\n // Regular character\n if (char) {\n setInput((prev) => prev + char);\n }\n });\n\n const cols = stdout.columns ?? 80;\n\n // Static items: banner (rendered once) + events (appended over time)\n const entries: StaticEntry[] = useMemo(\n () => [{ id: \"__banner__\" }, ...events.map((e) => ({ id: e.id, event: e }))],\n [events],\n );\n\n return (\n <>\n {/* Permanent output — rendered once, selectable terminal text */}\n <Static items={entries}>\n {(entry) => {\n if (!entry.event) {\n return (\n <Box key={entry.id} flexDirection=\"column\" paddingX={2} paddingTop={1} paddingBottom={1}>\n {BANNER_LINES.map((line, i) => (\n <Text key={i} color={GRADIENT[i]}>{line}</Text>\n ))}\n <Text>{\" \"}</Text>\n <Text>\n <Text color={C.dim}>{\" room \"}</Text>\n <Text color={C.cyan} bold>{roomName}</Text>\n </Text>\n </Box>\n );\n }\n return <EventLine key={entry.id} event={entry.event} identify={identify} />;\n }}\n </Static>\n\n {/* Dynamic footer — only this area repaints */}\n <Box paddingX={1}>\n <Text color={C.purple}>{\"─\"}</Text>\n <Text color={C.border}>{\"─\".repeat(Math.max(0, cols - 4))}</Text>\n <Text color={C.cyan}>{\"─\"}</Text>\n </Box>\n {agentNames.length > 0 && (\n <Box paddingX={1}>\n {agentNames.map((name, i) => {\n const { color, sigil } = identify(name);\n return (\n <React.Fragment key={name}>\n {i > 0 && <Text color={C.border}>{\" · \"}</Text>}\n <Text color={color}>{sigil}{\" \"}{name}</Text>\n </React.Fragment>\n );\n })}\n </Box>\n )}\n {readOnly || !onSend ? (\n <Box paddingX={1}>\n <Text color={C.muted}>{\" watching as guest\"}</Text>\n </Box>\n ) : (\n <Box paddingX={1} flexDirection=\"column\">\n {/* Render each line; first line gets the prompt, rest get indentation */}\n {(input || \"\").split(\"\\n\").map((line, i, arr) => (\n <Box key={i}>\n <Text color={C.cyan} bold>{i === 0 ? \"› \" : \" \"}</Text>\n <Text>\n {line}\n {i === arr.length - 1 && <Text inverse>{\" \"}</Text>}\n {i === arr.length - 1 && suggestionState.ghostHint !== \"\" && (\n <Text color={C.muted}>{suggestionState.ghostHint}</Text>\n )}\n </Text>\n </Box>\n ))}\n </Box>\n )}\n {/* Slash command suggestions — below input */}\n {suggestions.length > 0 && (\n <Box flexDirection=\"column\" paddingX={1}>\n {suggestions.map((s, i) => {\n const selected = i === selectedIndex;\n if (s.kind === \"command\") {\n const paramHint = s.cmd.params\n ? \" \" + s.cmd.params.map((p) => `<${p.label}>`).join(\" \")\n : \"\";\n const display = s.cmd.name + paramHint;\n return (\n <Box key={s.cmd.name}>\n <Text color={selected ? C.cyan : C.muted}>{selected ? \"› \" : \" \"}</Text>\n <Text>\n <Text color={selected ? C.cyan : C.secondary} bold={selected}>\n {s.cmd.name}\n </Text>\n <Text color={C.muted}>\n {paramHint.padEnd(CMD_DISPLAY_COL - display.length + paramHint.length)}\n </Text>\n </Text>\n <Text color={C.dim}>{s.cmd.description}</Text>\n </Box>\n );\n }\n return (\n <Box key={s.value}>\n <Text color={selected ? C.cyan : C.muted}>{selected ? \"› \" : \" \"}</Text>\n {s.kind === \"mention\" && <Text color={C.dim}>{\"@\"}</Text>}\n <Text color={selected ? C.cyan : C.secondary} bold={selected}>{s.value}</Text>\n </Box>\n );\n })}\n </Box>\n )}\n </>\n );\n}\n\n// ── startTUI ──────────────────────────────────────────────────────────────────\n\nexport function startTUI(opts: TUIOptions): TUIHandle {\n let handle: AppHandle | null = null;\n const queue: DisplayEvent[] = [];\n\n const onReady = (h: AppHandle) => {\n handle = h;\n for (const event of queue.splice(0)) h.push(event);\n };\n\n const { unmount } = render(\n <App\n roomName={opts.roomName}\n onSend={opts.onSend}\n onCtrlC={opts.onCtrlC}\n onReady={onReady}\n readOnly={opts.readOnly}\n isAdmin={opts.isAdmin}\n />,\n { exitOnCtrlC: false },\n );\n\n return {\n push(event) {\n if (handle) handle.push(event);\n else queue.push(event);\n },\n setAgentNames(names) {\n handle?.setAgentNames(names);\n },\n setParticipants(names) {\n handle?.setParticipants(names);\n },\n stop() {\n unmount();\n },\n };\n}\n","/**\n * stoops run claude — client-side agent runtime for Claude Code.\n *\n * Uses the shared runtime setup (EventProcessor, MCP server)\n * then adds Claude-specific pieces: tmux session + TmuxBridge delivery.\n *\n * Claude Code connects to the runtime MCP server via a stdio bridge\n * (Claude's HTTP MCP transport requires OAuth, which hangs on localhost).\n * The agent joins rooms by calling join_room() — no auto-injection needed.\n */\n\nimport { writeFileSync, mkdtempSync, rmSync, chmodSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { tmpdir } from \"node:os\";\n\nimport {\n tmuxAvailable,\n tmuxCreateSession,\n tmuxSendCommand,\n tmuxAttach,\n tmuxKillSession,\n tmuxSessionExists,\n} from \"../tmux.js\";\nimport { TmuxBridge } from \"./tmux-bridge.js\";\nimport { setupAgentRuntime, type AgentRuntimeOptions } from \"../runtime-setup.js\";\nimport { contentPartsToString } from \"../../agent/prompts.js\";\n\nexport { type AgentRuntimeOptions as RunClaudeOptions };\n\n/**\n * Stdio-to-HTTP bridge script. Written to a temp file and spawned by Claude Code\n * as an MCP stdio server. Proxies JSON-RPC messages to the runtime HTTP MCP server.\n *\n * The HTTP MCP server returns SSE-formatted responses (event: message\\ndata: {...}).\n * The bridge extracts the JSON from data: lines and writes raw JSON-RPC to stdout.\n */\n// CommonJS (.cjs) for minimal startup latency — ESM requires module parsing which\n// can exceed Claude Code's MCP handshake timeout on first run.\nconst MCP_STDIO_BRIDGE = [\n '#!/usr/bin/env node',\n '\"use strict\";',\n 'const { createInterface } = require(\"readline\");',\n 'const url = `http://127.0.0.1:${process.argv[2]}/mcp`;',\n 'const rl = createInterface({ input: process.stdin });',\n '(async () => {',\n ' for await (const line of rl) {',\n ' if (!line.trim()) continue;',\n ' try {',\n ' const res = await fetch(url, {',\n ' method: \"POST\",',\n ' headers: { \"Content-Type\": \"application/json\", Accept: \"application/json, text/event-stream\" },',\n ' body: line,',\n ' });',\n ' if (res.status === 202) continue;',\n ' const body = await res.text();',\n ' for (const bl of body.split(\"\\\\n\")) {',\n ' const m = bl.match(/^data: (.+)/);',\n ' if (m) process.stdout.write(m[1] + \"\\\\n\");',\n ' }',\n ' } catch {',\n ' process.exit(1);',\n ' }',\n ' }',\n '})();',\n].join('\\n');\n\nexport async function runClaude(options: AgentRuntimeOptions): Promise<void> {\n // ── Headless mode — skip tmux, deliver events as plain text to stdout ────\n\n if (options.headless) {\n const setup = await setupAgentRuntime(options);\n\n const deliver = async (parts: Parameters<typeof contentPartsToString>[0]) => {\n const text = contentPartsToString(parts);\n if (text.trim()) process.stdout.write(text + \"\\n\");\n };\n\n const eventLoopPromise = setup.processor\n .run(deliver, setup.wrappedSource, setup.initialParts)\n .catch(() => {});\n\n process.stderr.write(`MCP server: ${setup.mcpServer.url}\\n`);\n\n await new Promise<void>((resolve) => {\n process.on(\"SIGINT\", resolve);\n process.on(\"SIGTERM\", resolve);\n });\n\n await setup.cleanup();\n await eventLoopPromise;\n return;\n }\n\n // ── Preflight checks ────────────────────────────────────────────────────\n\n if (!tmuxAvailable()) {\n console.error(\"Error: tmux is required but not found. Install it with: brew install tmux\");\n process.exit(1);\n }\n\n // ── Shared runtime setup ────────────────────────────────────────────────\n // Don't pass joinUrls — Claude Code agents join rooms manually via join_room()\n\n const setup = await setupAgentRuntime({ ...options, joinUrls: undefined });\n\n // ── Write MCP stdio bridge + config ────────────────────────────────────\n\n const tmpDir = mkdtempSync(join(tmpdir(), \"stoops_agent_\"));\n\n const bridgePath = join(tmpDir, \"mcp-bridge.cjs\");\n writeFileSync(bridgePath, MCP_STDIO_BRIDGE);\n chmodSync(bridgePath, 0o755);\n\n const mcpPort = new URL(setup.mcpServer.url).port;\n const mcpConfigPath = join(tmpDir, \"mcp.json\");\n\n // Use process.execPath (absolute path to Node) so the bridge works regardless\n // of whether `node` is in the tmux session's PATH.\n const mcpConfig = {\n mcpServers: {\n stoops: {\n type: \"stdio\",\n command: process.execPath,\n args: [bridgePath, mcpPort],\n },\n },\n };\n writeFileSync(mcpConfigPath, JSON.stringify(mcpConfig, null, 2));\n\n // ── Create tmux session + launch Claude Code ────────────────────────────\n\n const tmuxSession = `stoops_${setup.agentName}`;\n\n if (tmuxSessionExists(tmuxSession)) {\n tmuxKillSession(tmuxSession);\n }\n\n console.log(\"Launching Claude Code...\");\n tmuxCreateSession(tmuxSession);\n\n // Launch claude with MCP config + any passthrough args\n const extraArgs = options.extraArgs ?? [];\n const claudeCmd = [`claude --mcp-config ${mcpConfigPath}`, ...extraArgs].join(\" \");\n tmuxSendCommand(tmuxSession, claudeCmd);\n\n // ── Start event loop + attach ──────────────────────────────────────────\n\n const bridge = new TmuxBridge(tmuxSession);\n\n // Start the event loop in the background — no initial injection.\n // The agent joins rooms by calling join_room() when the user tells it to.\n const eventLoopPromise = setup.processor.run(bridge.deliver.bind(bridge), setup.wrappedSource)\n .catch(() => {}); // Prevent unhandled rejection from crashing the process\n\n // Wait for Claude to start, checking the session is still alive\n for (let i = 0; i < 10; i++) {\n await new Promise((r) => setTimeout(r, 500));\n if (!tmuxSessionExists(tmuxSession)) {\n console.error(\"Error: Claude Code exited during startup. Try running again.\");\n bridge.stop();\n await setup.cleanup();\n try { rmSync(tmpDir, { recursive: true }); } catch { /* ok */ }\n return;\n }\n }\n\n console.log(\"Attaching to Claude Code session...\\n\");\n\n try {\n await tmuxAttach(tmuxSession);\n } catch {\n // User detached or session ended\n }\n\n // ── Cleanup ─────────────────────────────────────────────────────────────\n\n bridge.stop();\n await setup.cleanup();\n tmuxKillSession(tmuxSession);\n try { rmSync(tmpDir, { recursive: true }); } catch { /* ok */ }\n\n console.log(\"Disconnected.\");\n}\n","/**\n * tmux helpers for stoops CLI.\n *\n * Thin wrappers around tmux commands. Used by the server process to\n * inject room events into Claude Code sessions.\n */\n\nimport { execFileSync, spawn } from \"node:child_process\";\n\n/** Sanitize a string for use as a tmux session name. Replaces tmux-special chars. */\nfunction sanitizeSessionName(name: string): string {\n return name.replace(/[.:$%]/g, \"_\");\n}\n\n/** Check if tmux is installed and available. */\nexport function tmuxAvailable(): boolean {\n try {\n execFileSync(\"tmux\", [\"-V\"], { stdio: \"ignore\" });\n return true;\n } catch {\n return false;\n }\n}\n\n/** Check if a tmux session exists. */\nexport function tmuxSessionExists(session: string): boolean {\n try {\n const name = sanitizeSessionName(session);\n execFileSync(\"tmux\", [\"has-session\", \"-t\", name], { stdio: \"ignore\" });\n return true;\n } catch {\n return false;\n }\n}\n\n/** Create a detached tmux session with no status bar. */\nexport function tmuxCreateSession(session: string): void {\n const name = sanitizeSessionName(session);\n execFileSync(\"tmux\", [\"new-session\", \"-d\", \"-s\", name]);\n execFileSync(\"tmux\", [\"set\", \"-t\", name, \"status\", \"off\"]);\n}\n\n/** Send a command to a tmux session (types it + presses Enter). */\nexport function tmuxSendCommand(session: string, command: string): void {\n const name = sanitizeSessionName(session);\n execFileSync(\"tmux\", [\"send-keys\", \"-t\", name, \"-l\", command]);\n execFileSync(\"tmux\", [\"send-keys\", \"-t\", name, \"Enter\"]);\n}\n\n/**\n * Inject text into a tmux session (literal keys, no Enter).\n * Used for room event injection.\n */\nexport function tmuxInjectText(session: string, text: string): void {\n const name = sanitizeSessionName(session);\n execFileSync(\"tmux\", [\"send-keys\", \"-t\", name, \"-l\", text]);\n}\n\n/** Send Enter key to a tmux session (submits input). */\nexport function tmuxSendEnter(session: string): void {\n const name = sanitizeSessionName(session);\n execFileSync(\"tmux\", [\"send-keys\", \"-t\", name, \"Enter\"]);\n}\n\n/** Attach to a tmux session. Returns a promise that resolves when detached/exited.\n *\n * Two modes:\n * - Outside tmux: `tmux attach` (blocks until user detaches, event loop stays free via spawn)\n * - Inside tmux: `tmux switch-client` (exits immediately) + polls until session ends\n */\nexport function tmuxAttach(session: string): Promise<void> {\n const name = sanitizeSessionName(session);\n\n if (process.env.TMUX) {\n // switch-client exits immediately after switching — poll until session is destroyed\n try {\n execFileSync(\"tmux\", [\"switch-client\", \"-t\", name], { stdio: \"ignore\" });\n } catch {\n // switch-client failed (e.g. no client) — fall through to polling\n }\n return new Promise<void>((resolve) => {\n const poll = setInterval(() => {\n try {\n execFileSync(\"tmux\", [\"has-session\", \"-t\", name], { stdio: \"ignore\" });\n } catch {\n clearInterval(poll);\n resolve();\n }\n }, 500);\n });\n }\n\n return new Promise<void>((resolve) => {\n const child = spawn(\"tmux\", [\"attach\", \"-t\", name], { stdio: \"inherit\" });\n child.on(\"exit\", () => resolve());\n child.on(\"error\", () => resolve());\n });\n}\n\n/** Capture visible screen content as array of lines. */\nexport function tmuxCapturePane(session: string): string[] {\n try {\n const name = sanitizeSessionName(session);\n const output = execFileSync(\"tmux\", [\"capture-pane\", \"-t\", name, \"-p\"], {\n encoding: \"utf-8\",\n });\n return output.split(\"\\n\");\n } catch {\n return [];\n }\n}\n\n/**\n * Send a control key sequence (e.g. \"C-u\", \"C-y\", \"Escape\").\n * Unlike tmuxInjectText, this does NOT use -l, so tmux interprets\n * the key name rather than treating it as literal text.\n */\nexport function tmuxSendKey(session: string, key: string): void {\n const name = sanitizeSessionName(session);\n execFileSync(\"tmux\", [\"send-keys\", \"-t\", name, key]);\n}\n\n/** Kill a tmux session. */\nexport function tmuxKillSession(session: string): void {\n try {\n const name = sanitizeSessionName(session);\n execFileSync(\"tmux\", [\"kill-session\", \"-t\", name], { stdio: \"ignore\" });\n } catch {\n // Session may already be dead\n }\n}\n","/**\n * TmuxBridge — state-aware event injection into Claude Code.\n *\n * Reads the Claude Code TUI screen via `tmux capture-pane`, detects the\n * current UI state, and applies the right injection strategy:\n *\n * idle → inject directly\n * typing → Ctrl+U (cut), inject, Ctrl+Y (restore)\n * dialog → queue and poll\n * permission → queue and poll\n * streaming → queue and poll\n * unknown → queue and poll (safe default)\n *\n * Events that can't be injected immediately are queued and drained\n * when the state becomes safe.\n */\n\nimport {\n tmuxCapturePane,\n tmuxInjectText,\n tmuxSendEnter,\n tmuxSendKey,\n} from \"../tmux.js\";\nimport { contentPartsToString } from \"../../agent/prompts.js\";\nimport type { ContentPart } from \"../../agent/types.js\";\n\nexport type TuiState =\n | \"idle\"\n | \"typing\"\n | \"dialog\"\n | \"permission\"\n | \"streaming\"\n | \"unknown\";\n\n// Spinner characters used by Claude Code during streaming\nconst SPINNER_CHARS = \"⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏\";\n\n// Patterns that indicate a selection/question dialog\nconst DIALOG_PATTERNS = [\n \"Enter to select\",\n \"to navigate\",\n \"Esc to cancel\",\n \"Ready to code?\",\n \"Review your answers\",\n \"ctrl+g to edit in\",\n];\n\n// Patterns that indicate a permission/confirmation prompt\nconst PERMISSION_PATTERNS = [\n \"(Y)\",\n \"Allow \",\n \"Deny \",\n \"approve\",\n \"Yes / No\",\n];\n\nexport interface TmuxBridgeOptions {\n /** How often to poll when events are queued (ms). Default: 200 */\n pollIntervalMs?: number;\n /** How long to wait between Ctrl+U/inject/Ctrl+Y steps (ms). Default: 50 */\n keystrokeDelayMs?: number;\n}\n\nexport class TmuxBridge {\n private session: string;\n private queue: string[] = [];\n private pollTimer: ReturnType<typeof setInterval> | null = null;\n private pollIntervalMs: number;\n private keystrokeDelayMs: number;\n private stopped = false;\n\n constructor(session: string, opts?: TmuxBridgeOptions) {\n this.session = session;\n this.pollIntervalMs = opts?.pollIntervalMs ?? 200;\n this.keystrokeDelayMs = opts?.keystrokeDelayMs ?? 50;\n }\n\n /**\n * Delivery callback — drop-in replacement for the raw tmuxDeliver lambda.\n * Pass `bridge.deliver.bind(bridge)` to EventProcessor.run().\n */\n async deliver(parts: ContentPart[]): Promise<void> {\n const text = contentPartsToString(parts);\n if (!text.trim()) return;\n\n this.inject(text);\n }\n\n /**\n * Detect the current TUI state by reading the screen.\n * Exported for testing — the heuristic logic is in detectStateFromLines().\n */\n detectState(): TuiState {\n const lines = this.captureScreen();\n return detectStateFromLines(lines);\n }\n\n /**\n * Try to inject text, choosing strategy based on TUI state.\n * If the state is unsafe, queues the text and starts polling.\n *\n * Text is flattened to a single line before injection to avoid triggering\n * Claude Code's paste detection. When multi-line text arrives via\n * `send-keys -l`, Claude Code detects it as a paste and collapses it into\n * \"[Pasted text #1 +N lines]\" which may not reliably submit with Enter.\n */\n private inject(text: string): void {\n const flat = text.replace(/\\n/g, \" \");\n const state = this.detectState();\n\n switch (state) {\n case \"idle\":\n this.injectIdle(flat);\n break;\n case \"typing\":\n this.injectWhileTyping(flat);\n break;\n default:\n // dialog, permission, streaming, unknown — queue it\n this.enqueue(flat);\n break;\n }\n }\n\n /** Capture the screen via tmux capture-pane. */\n private captureScreen(): string[] {\n return tmuxCapturePane(this.session);\n }\n\n /**\n * Inject into an idle prompt: type text + Enter.\n * Sends a second Enter after a short delay as a safety net — if Claude Code's\n * paste detection swallowed the first Enter, the second one submits. If the\n * first Enter worked, Claude is streaming and the second Enter is a no-op.\n */\n private injectIdle(text: string): void {\n tmuxInjectText(this.session, text);\n tmuxSendEnter(this.session);\n this.sleep(80);\n tmuxSendEnter(this.session);\n }\n\n /**\n * Inject while the user is typing:\n * 1. Ctrl+U — cut line to kill ring\n * 2. Inject our text + Enter\n * 3. Ctrl+Y — paste the user's text back\n */\n private injectWhileTyping(text: string): void {\n // Cut user's current input\n tmuxSendKey(this.session, \"C-u\");\n this.sleep(this.keystrokeDelayMs);\n\n // Inject our event (double-Enter for paste detection resilience)\n tmuxInjectText(this.session, text);\n tmuxSendEnter(this.session);\n this.sleep(80);\n tmuxSendEnter(this.session);\n this.sleep(this.keystrokeDelayMs);\n\n // Restore user's text\n tmuxSendKey(this.session, \"C-y\");\n }\n\n /** Add to queue and start polling if not already. */\n private enqueue(text: string): void {\n this.queue.push(text);\n this.startPolling();\n }\n\n /** Start the polling timer to drain queued events. */\n private startPolling(): void {\n if (this.pollTimer || this.stopped) return;\n this.pollTimer = setInterval(() => this.drainQueue(), this.pollIntervalMs);\n }\n\n /** Stop the polling timer. */\n private stopPolling(): void {\n if (this.pollTimer) {\n clearInterval(this.pollTimer);\n this.pollTimer = null;\n }\n }\n\n /**\n * Try to drain one queued event if the state is safe.\n *\n * Drains one event at a time rather than batching all into one multi-line\n * string — multi-line text triggers Claude Code's paste detection which\n * collapses it into \"[Pasted text #1 +N lines]\".\n *\n * After injecting one event, the poll continues. The next cycle re-checks\n * state: if Claude is busy (streaming), remaining events wait. If idle,\n * the next event is injected. Events are already flattened in inject().\n */\n private drainQueue(): void {\n if (this.queue.length === 0) {\n this.stopPolling();\n return;\n }\n\n const state = this.detectState();\n if (state === \"idle\" || state === \"typing\") {\n const text = this.queue.shift()!;\n\n if (state === \"idle\") {\n this.injectIdle(text);\n } else {\n this.injectWhileTyping(text);\n }\n\n if (this.queue.length === 0) {\n this.stopPolling();\n }\n // else: keep polling to drain remaining events\n }\n // else: still blocked, keep polling\n }\n\n /** Cleanup. */\n stop(): void {\n this.stopped = true;\n this.stopPolling();\n this.queue.length = 0;\n }\n\n /** Synchronous sleep — only used for tiny keystroke delays. */\n private sleep(ms: number): void {\n if (ms <= 0) return;\n Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);\n }\n}\n\n// ── State detection heuristics ──────────────────────────────────────────────\n\n/**\n * Detect TUI state from capture-pane output lines.\n * Exported separately so it can be unit-tested without tmux.\n *\n * Claude Code's TUI layout (v2.1+):\n * ────────────────────────\n * ❯ <user input here>\n * ────────────────────────\n * PR #2 /ide ...\n *\n * The ❯ prompt sits between separator lines (─). No ❯❯ footer in v2.1+.\n */\nexport function detectStateFromLines(lines: string[]): TuiState {\n if (lines.length === 0) return \"unknown\";\n\n // Work with the last ~15 lines (the visible bottom of the screen)\n const tail = lines.slice(-15);\n const tailText = tail.join(\"\\n\");\n\n // 1. Dialog: selection/question/plan approval\n for (const pattern of DIALOG_PATTERNS) {\n if (tailText.includes(pattern)) return \"dialog\";\n }\n\n // 2. Permission prompt\n for (const pattern of PERMISSION_PATTERNS) {\n if (tailText.includes(pattern)) return \"permission\";\n }\n\n // 3. Streaming: spinner characters in the last few lines\n const lastFew = tail.slice(-5).join(\"\");\n for (const ch of SPINNER_CHARS) {\n if (lastFew.includes(ch)) return \"streaming\";\n }\n\n // 4. Look for the ❯/› prompt line near the bottom.\n // Supports both old layout (❯❯ footer) and new layout (separator lines).\n const promptChar = /^[❯›](\\s|$)/;\n const footerChar = /^[❯›]{2}\\s/;\n const separatorLine = /^[─━─\\-]{10,}/;\n\n // Strategy A: old layout — find ❯❯ footer then ❯ prompt above it\n for (let i = tail.length - 1; i >= 0; i--) {\n const line = tail[i].trimStart();\n if (footerChar.test(line)) {\n // Found old-style footer, look for prompt above\n for (let j = i - 1; j >= 0; j--) {\n const above = tail[j].trimStart();\n if (promptChar.test(above)) {\n const content = above.replace(/^[❯›]\\s*/, \"\").trim();\n return content.length === 0 ? \"idle\" : \"typing\";\n }\n }\n break;\n }\n }\n\n // Strategy B: new layout — find ❯ prompt between/near separator lines\n for (let i = tail.length - 1; i >= 0; i--) {\n const line = tail[i].trimStart();\n if (promptChar.test(line)) {\n // Verify it's Claude's prompt by checking for separator line nearby\n const above = i > 0 ? tail[i - 1].trimStart() : \"\";\n const below = i < tail.length - 1 ? tail[i + 1].trimStart() : \"\";\n if (separatorLine.test(above) || separatorLine.test(below)) {\n const content = line.replace(/^[❯›]\\s*/, \"\").trim();\n return content.length === 0 ? \"idle\" : \"typing\";\n }\n }\n }\n\n return \"unknown\";\n}\n","/**\n * Shared agent runtime setup — extracted from cli/claude/run.ts.\n *\n * Both `stoops run claude` and `stoops run opencode` use this to:\n * 1. Create SSE multiplexer + EventProcessor\n * 2. Create local runtime MCP server\n * 3. Wire up participant cache updates\n * 4. Provide cleanup\n *\n * Rooms are NOT joined during setup. The agent joins rooms by calling\n * join_room() via MCP. If --join URLs are provided, the startup event\n * asks the agent to call join_room for each URL.\n *\n * Each runtime only needs to provide its own delivery mechanism\n * (TmuxBridge for Claude, HTTP API for OpenCode).\n */\n\nimport { randomName } from \"../core/names.js\";\nimport { extractToken } from \"./auth.js\";\nimport { RemoteRoomDataSource } from \"../agent/remote-room-data-source.js\";\nimport { SseMultiplexer } from \"../agent/sse-multiplexer.js\";\nimport { EventProcessor } from \"../agent/event-processor.js\";\nimport { createRuntimeMcpServer, type RuntimeMcpServer, type JoinRoomResult } from \"../agent/mcp/runtime.js\";\nimport { buildCatchUpLines } from \"../agent/tool-handlers.js\";\nimport type { Participant } from \"../core/types.js\";\nimport type { LabeledEvent } from \"../agent/multiplexer.js\";\nimport type { ContentPart } from \"../agent/types.js\";\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport interface AgentRuntimeOptions {\n joinUrls?: string[];\n name?: string;\n admin?: boolean;\n extraArgs?: string[];\n /** Skip tmux/UI — deliver events as plain text to stdout. MCP server still runs. */\n headless?: boolean;\n /** Called after a room is successfully joined via join_room MCP tool. */\n onRoomJoined?: () => void | Promise<void>;\n}\n\nexport interface JoinResult {\n serverUrl: string;\n sessionToken: string;\n participantId: string;\n roomName: string;\n roomId: string;\n authority: string;\n participants: Participant[];\n dataSource: RemoteRoomDataSource;\n}\n\nexport interface AgentRuntimeSetup {\n agentName: string;\n joinResults: JoinResult[];\n initialParts: ContentPart[] | undefined;\n processor: EventProcessor;\n sseMux: SseMultiplexer;\n mcpServer: RuntimeMcpServer;\n wrappedSource: AsyncIterable<LabeledEvent>;\n cleanup(): Promise<void>;\n}\n\n// ── Setup ─────────────────────────────────────────────────────────────────────\n\nexport async function setupAgentRuntime(options: AgentRuntimeOptions): Promise<AgentRuntimeSetup> {\n const agentName = options.name ?? randomName();\n\n // ── Pending join URLs (not joined yet — agent calls join_room) ─────────\n\n const pendingUrls = options.joinUrls ?? [];\n\n // ── Mutable join results (populated as agent calls join_room) ──────────\n\n const joinResults: JoinResult[] = [];\n\n // ── Create SSE multiplexer (starts empty) ──────────────────────────────\n\n const sseMux = new SseMultiplexer();\n\n // ── Create EventProcessor (selfId set on first join_room) ──────────────\n\n const processor = new EventProcessor(\"\", agentName, {\n defaultMode: \"everyone\",\n });\n\n // ── Create local runtime MCP server ───────────────────────────────────\n\n const mcpServer = await createRuntimeMcpServer({\n resolver: processor,\n toolOptions: {\n isEventSeen: (id) => processor.isEventSeen(id),\n markEventsSeen: (ids) => processor.markEventsSeen(ids),\n assignRef: (id) => processor.assignRef(id),\n resolveRef: (ref) => processor.resolveRef(ref),\n },\n admin: options.admin,\n onSetMode: async (room, mode) => {\n const conn = processor.resolve(room);\n if (!conn) return { success: false, error: `Unknown room \"${room}\".` };\n processor.setModeForRoom(conn.dataSource.roomId, mode as any, false);\n try {\n const ds = conn.dataSource as RemoteRoomDataSource;\n const res = await fetch(`${ds.serverUrl}/set-mode`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token: ds.sessionToken, mode }),\n });\n if (!res.ok) return { success: false, error: `Server rejected: ${await res.text()}` };\n } catch {\n // Server unreachable, local mode still set\n }\n return { success: true };\n },\n onJoinRoom: async (url, alias) => {\n const token = extractToken(url);\n let serverUrl: string;\n try {\n const parsed = new URL(url);\n parsed.search = \"\";\n serverUrl = parsed.toString().replace(/\\/$/, \"\");\n } catch {\n serverUrl = url.replace(/\\/$/, \"\");\n }\n\n try {\n const joinBody: Record<string, unknown> = { type: \"agent\", name: agentName };\n if (token) joinBody.token = token;\n\n const res = await fetch(`${serverUrl}/join`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(joinBody),\n signal: AbortSignal.timeout(15_000),\n });\n if (!res.ok) return { success: false, error: `Failed to join: ${await res.text()}` };\n\n const data = await res.json() as Record<string, unknown>;\n const sessionToken = String(data.sessionToken ?? \"\");\n const roomName = alias ?? String(data.roomName ?? \"\");\n const roomId = String(data.roomId ?? \"\");\n const authority = String(data.authority ?? \"participant\");\n const participants = (data.participants as Participant[]) ?? [];\n const newParticipantId = String(data.participantId ?? \"\");\n\n const dataSource = new RemoteRoomDataSource(serverUrl, sessionToken, roomId);\n dataSource.setParticipants(participants);\n dataSource.setSelf(newParticipantId, agentName);\n\n // Set global selfId on first join; always set per-room selfId\n if (joinResults.length === 0) {\n processor.participantId = newParticipantId;\n }\n processor.setRoomParticipantId(roomId, newParticipantId);\n\n // Register in EventProcessor and SSE multiplexer\n const mode = processor.getModeForRoom(roomId) ?? \"everyone\";\n processor.connectRemoteRoom(dataSource, roomName);\n sseMux.addConnection(serverUrl, sessionToken, roomName, roomId);\n\n // Track for cleanup\n const jr: JoinResult = {\n serverUrl,\n sessionToken,\n participantId: newParticipantId,\n roomName,\n roomId,\n authority,\n participants,\n dataSource,\n };\n joinResults.push(jr);\n\n // Build recent activity lines for the response\n const conn = processor.resolve(roomName);\n let recentLines: string[] = [];\n if (conn) {\n recentLines = await buildCatchUpLines(conn, {\n isEventSeen: (id) => processor.isEventSeen(id),\n markEventsSeen: (ids) => processor.markEventsSeen(ids),\n assignRef: (id) => processor.assignRef(id),\n });\n }\n\n await options.onRoomJoined?.();\n\n return {\n success: true,\n roomName,\n agentName,\n authority,\n mode,\n participants: participants\n .filter((p) => p.id !== newParticipantId)\n .map((p) => ({ name: p.name, authority: (p as any).authority ?? \"participant\" })),\n recentLines,\n } as JoinRoomResult;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return { success: false, error: `Unable to connect. Is the server running? (${serverUrl}) — ${msg}` };\n }\n },\n onLeaveRoom: async (room) => {\n const conn = processor.resolve(room);\n if (!conn) return { success: false, error: `Unknown room \"${room}\".` };\n const roomId = conn.dataSource.roomId;\n\n const idx = joinResults.findIndex((jr) => jr.roomId === roomId);\n if (idx >= 0) {\n const jr = joinResults[idx];\n sseMux.removeConnection(roomId);\n processor.disconnectRemoteRoom(roomId);\n\n try {\n await fetch(`${jr.serverUrl}/disconnect`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token: jr.sessionToken }),\n });\n } catch {\n // Server may be down\n }\n\n joinResults.splice(idx, 1);\n }\n return { success: true };\n },\n onAdminSetModeFor: options.admin ? async (room, participant, mode) => {\n const conn = processor.resolve(room);\n if (!conn) return { success: false, error: `Unknown room \"${room}\".` };\n const ds = conn.dataSource as RemoteRoomDataSource;\n\n const p = conn.dataSource.listParticipants().find((pp) => pp.name === participant);\n if (!p) return { success: false, error: `Unknown participant \"${participant}\".` };\n\n try {\n const res = await fetch(`${ds.serverUrl}/set-mode`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token: ds.sessionToken, participantId: p.id, mode }),\n });\n if (!res.ok) return { success: false, error: await res.text() };\n return { success: true };\n } catch {\n return { success: false, error: \"Server unreachable.\" };\n }\n } : undefined,\n onAdminMute: options.admin ? async (room, participant) => {\n const conn = processor.resolve(room);\n if (!conn) return { success: false, error: `Unknown room \"${room}\".` };\n const ds = conn.dataSource as RemoteRoomDataSource;\n\n const p = conn.dataSource.listParticipants().find((pp) => pp.name === participant);\n if (!p) return { success: false, error: `Unknown participant \"${participant}\".` };\n\n try {\n const res = await fetch(`${ds.serverUrl}/set-authority`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token: ds.sessionToken, participantId: p.id, authority: \"observer\" }),\n });\n if (!res.ok) return { success: false, error: await res.text() };\n return { success: true };\n } catch {\n return { success: false, error: \"Server unreachable.\" };\n }\n } : undefined,\n onAdminUnmute: options.admin ? async (room, participant) => {\n const conn = processor.resolve(room);\n if (!conn) return { success: false, error: `Unknown room \"${room}\".` };\n const ds = conn.dataSource as RemoteRoomDataSource;\n\n const p = conn.dataSource.listParticipants().find((pp) => pp.name === participant);\n if (!p) return { success: false, error: `Unknown participant \"${participant}\".` };\n\n try {\n const res = await fetch(`${ds.serverUrl}/set-authority`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token: ds.sessionToken, participantId: p.id, authority: \"participant\" }),\n });\n if (!res.ok) return { success: false, error: await res.text() };\n return { success: true };\n } catch {\n return { success: false, error: \"Server unreachable.\" };\n }\n } : undefined,\n onAdminKick: options.admin ? async (room, participant) => {\n const conn = processor.resolve(room);\n if (!conn) return { success: false, error: `Unknown room \"${room}\".` };\n const ds = conn.dataSource as RemoteRoomDataSource;\n\n const p = conn.dataSource.listParticipants().find((pp) => pp.name === participant);\n if (!p) return { success: false, error: `Unknown participant \"${participant}\".` };\n\n try {\n const res = await fetch(`${ds.serverUrl}/kick`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token: ds.sessionToken, participantId: p.id }),\n });\n if (!res.ok) return { success: false, error: await res.text() };\n return { success: true };\n } catch {\n return { success: false, error: \"Server unreachable.\" };\n }\n } : undefined,\n });\n\n // ── Wrap SSE source for participant cache updates ─────────────────────\n\n const wrappedSource: AsyncIterable<LabeledEvent> = {\n [Symbol.asyncIterator]() {\n const inner = sseMux[Symbol.asyncIterator]();\n return {\n async next() {\n const result = await inner.next();\n if (!result.done) {\n const { roomId, event } = result.value;\n const jr = joinResults.find((j) => j.roomId === roomId);\n if (jr) {\n if (event.type === \"ParticipantJoined\") {\n jr.dataSource.addParticipant(event.participant);\n } else if (event.type === \"ParticipantLeft\") {\n jr.dataSource.removeParticipant(event.participant_id);\n }\n }\n }\n return result;\n },\n };\n },\n };\n\n // ── Cleanup function ──────────────────────────────────────────────────\n\n async function cleanup(): Promise<void> {\n await processor.stop();\n sseMux.close();\n await mcpServer.stop();\n\n for (const jr of joinResults) {\n try {\n await fetch(`${jr.serverUrl}/disconnect`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token: jr.sessionToken }),\n });\n } catch {\n // Server may be down\n }\n }\n }\n\n // ── Build startup event (if --join URLs were provided) ────────────────\n\n let initialParts: ContentPart[] | undefined;\n if (pendingUrls.length > 0) {\n if (pendingUrls.length === 1) {\n initialParts = [{ type: \"text\", text: `Use join_room(\"${pendingUrls[0]}\") to connect.` }];\n } else {\n const lines = pendingUrls.map((u) => ` join_room(\"${u}\")`);\n initialParts = [{ type: \"text\", text: `Rooms to join:\\n${lines.join(\"\\n\")}` }];\n }\n }\n\n return {\n agentName,\n joinResults,\n initialParts,\n processor,\n sseMux,\n mcpServer,\n wrappedSource,\n cleanup,\n };\n}\n","/**\n * stoops run opencode — client-side agent runtime for OpenCode.\n *\n * Spawns `opencode serve` with OPENCODE_CONFIG_CONTENT to inject the stoops\n * MCP server. The user opens OpenCode's UI, starts a conversation, and tells\n * the agent to join a room URL.\n *\n * Session detection: we subscribe to OpenCode's global SSE event stream and\n * watch for stoops tool call events. Each event carries the sessionID of the\n * calling session — no guessing, no race conditions.\n */\n\nimport { spawn, type ChildProcess } from \"node:child_process\";\nimport { contentPartsToString } from \"../../agent/prompts.js\";\nimport type { ContentPart } from \"../../agent/types.js\";\nimport { setupAgentRuntime, type AgentRuntimeOptions } from \"../runtime-setup.js\";\n\nexport { type AgentRuntimeOptions as RunOpencodeOptions };\n\nexport async function runOpencode(options: AgentRuntimeOptions): Promise<void> {\n // ── Pick a port for OpenCode ────────────────────────────────────────────\n\n const opencodePort = 14096 + Math.floor(Math.random() * 1000);\n const opencodeUrl = `http://127.0.0.1:${opencodePort}`;\n\n // ── Room → OpenCode session mapping ────────────────────────────────────\n //\n // Each OpenCode session can join different rooms. Lazily detected on first\n // delivery for each room by inspecting session messages for stoops tool calls.\n\n const roomSessions = new Map<string, string>(); // roomId → OpenCode sessionId\n\n /** Find the OpenCode session that most recently called a stoops tool. */\n async function findStoopsSession(): Promise<string | null> {\n try {\n const res = await fetch(`${opencodeUrl}/session`);\n if (!res.ok) return null;\n // Sessions sorted by time.updated desc — first is most recent\n const sessions = await res.json() as Array<{ id: string; time: { updated: number } }>;\n\n // Check the most recently updated sessions for stoops tool parts\n for (const sess of sessions.slice(0, 3)) {\n const msgRes = await fetch(`${opencodeUrl}/session/${sess.id}/message`);\n if (!msgRes.ok) continue;\n const messages = await msgRes.json() as Array<{\n parts?: Array<{ type?: string; tool?: string }>;\n }>;\n for (const msg of messages) {\n for (const part of msg.parts ?? []) {\n if (part.type === \"tool\" && part.tool?.includes(\"stoops__\")) {\n return sess.id;\n }\n }\n }\n }\n // Fallback: most recently updated session\n return sessions.length > 0 ? sessions[0].id : null;\n } catch {\n return null;\n }\n }\n\n // ── Shared runtime setup ────────────────────────────────────────────────\n // No --join URLs — the user tells the agent to join from within OpenCode.\n\n const setup = await setupAgentRuntime({\n ...options,\n joinUrls: undefined,\n });\n\n // ── Build MCP config for OpenCode ───────────────────────────────────────\n\n const opencodeConfig = {\n mcp: {\n stoops: {\n type: \"remote\",\n url: setup.mcpServer.url,\n oauth: false,\n },\n },\n };\n\n // ── Spawn OpenCode in headless mode ─────────────────────────────────────\n\n const extraArgs = options.extraArgs ?? [];\n const opencodeArgs = [\"serve\", \"--port\", String(opencodePort), ...extraArgs];\n\n console.log(\"Launching OpenCode...\");\n\n let child: ChildProcess;\n try {\n child = spawn(\"opencode\", opencodeArgs, {\n env: {\n ...process.env,\n OPENCODE_CONFIG_CONTENT: JSON.stringify(opencodeConfig),\n },\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n } catch {\n console.error(\"Error: opencode is required but not found. Install it from https://opencode.ai\");\n await setup.cleanup();\n process.exit(1);\n }\n\n // Forward stderr to console for visibility\n child.stderr?.on(\"data\", (chunk: Buffer) => {\n process.stderr.write(chunk);\n });\n\n let childExited = false;\n child.on(\"exit\", () => { childExited = true; });\n\n child.on(\"error\", async () => {\n console.error(\"Error: failed to start opencode. Is it installed?\");\n await setup.cleanup();\n process.exit(1);\n });\n\n // ── Wait for OpenCode to be ready ───────────────────────────────────────\n\n const ready = await pollForReady(opencodeUrl, 30_000);\n if (!ready) {\n console.error(\"OpenCode did not become ready within 30 seconds.\");\n child.kill();\n await setup.cleanup();\n process.exit(1);\n }\n\n console.log(` OpenCode running on ${opencodeUrl}`);\n\n // ── Build deliver callback ──────────────────────────────────────────────\n //\n // OpenCode's POST /session/:id/message uses Hono stream() — headers (200)\n // arrive immediately but the LLM runs inside the stream callback. We MUST\n // consume the response body (await res.text()) to block until the LLM\n // finishes, preserving the EventProcessor's _processing lock.\n\n async function deliver(parts: ContentPart[]): Promise<void> {\n const roomId = setup.processor.currentContextRoomId;\n if (!roomId) return;\n\n // Lazy session detection: look up on first delivery for this room\n if (!roomSessions.has(roomId)) {\n const sid = await findStoopsSession();\n if (!sid) return;\n roomSessions.set(roomId, sid);\n console.log(` Linked room ${roomId} → session ${sid}`);\n }\n const targetSession = roomSessions.get(roomId)!;\n\n const text = contentPartsToString(parts);\n if (!text.trim()) return;\n\n try {\n const res = await fetch(`${opencodeUrl}/session/${targetSession}/message`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n parts: [{ type: \"text\", text }],\n }),\n });\n await res.text();\n } catch {\n // OpenCode may have exited\n }\n }\n\n // ── Start the event loop ────────────────────────────────────────────────\n // No initialParts — the user drives the conversation from OpenCode's UI.\n\n const eventLoopPromise = setup.processor.run(deliver, setup.wrappedSource);\n\n console.log(`\\n OpenCode agent running.`);\n console.log(` To watch: opencode attach ${opencodeUrl}\\n`);\n\n // ── Block until child exits or Ctrl+C ───────────────────────────────────\n\n const exitPromise = new Promise<void>((resolve) => {\n child.on(\"exit\", resolve);\n });\n\n const signalPromise = new Promise<void>((resolve) => {\n const handler = () => { resolve(); };\n process.on(\"SIGINT\", handler);\n process.on(\"SIGTERM\", handler);\n });\n\n await Promise.race([exitPromise, signalPromise]);\n\n // ── Cleanup ─────────────────────────────────────────────────────────────\n\n if (!childExited) {\n child.kill();\n }\n await setup.cleanup();\n\n console.log(\"Disconnected.\");\n}\n\n// ── Helpers ─────────────────────────────────────────────────────────────────\n\nasync function pollForReady(url: string, timeoutMs: number): Promise<boolean> {\n const start = Date.now();\n while (Date.now() - start < timeoutMs) {\n try {\n const res = await fetch(`${url}/session/status`);\n if (res.ok) return true;\n } catch {\n // Not ready yet\n }\n await new Promise((r) => setTimeout(r, 500));\n }\n return false;\n}\n","#!/usr/bin/env node\n\n/**\n * stoops CLI — shared rooms for AI agents.\n *\n * Usage:\n * stoops [--room <name>] [--port <port>] [--share] Host a room + join it\n * stoops serve [--room <name>] [--port <port>] [--share] Headless server only\n * stoops join <url> [--name <name>] [--guest] Join a room as a human\n * stoops run claude [--name <name>] [--admin] [-- <args>] Connect Claude Code\n * stoops run opencode [--name <name>] [--admin] [-- <args>] Connect OpenCode\n */\n\nimport { serve } from \"./serve.js\";\nimport { join } from \"./join.js\";\nimport { runClaude } from \"./claude/run.js\";\nimport { runOpencode } from \"./opencode/run.js\";\nimport { buildShareUrl } from \"./auth.js\";\n\nconst args = process.argv.slice(2);\n\nfunction getFlag(name: string, arr: string[] = args): string | undefined {\n const idx = arr.indexOf(`--${name}`);\n if (idx === -1) return undefined;\n const value = arr[idx + 1];\n if (value === undefined || value.startsWith(\"--\")) return undefined;\n return value;\n}\n\n/** Collect all values for a repeatable flag (e.g. --join url1 --join url2). */\nfunction getAllFlags(name: string, arr: string[] = args): string[] {\n const results: string[] = [];\n const flag = `--${name}`;\n for (let i = 0; i < arr.length; i++) {\n if (arr[i] === flag && arr[i + 1] && !arr[i + 1].startsWith(\"--\")) {\n results.push(arr[i + 1]);\n }\n }\n return results;\n}\n\nfunction printUsage(stream: typeof console.log = console.log): void {\n stream(\"Usage:\");\n stream(\" stoops [--room <name>] [--port <port>] [--share] Host + join\");\n stream(\" stoops serve [--room <name>] [--port <port>] [--share] Headless server\");\n stream(\" stoops join <url> [--name <name>] [--guest] Join a room\");\n stream(\" stoops run claude [--name <name>] [--admin] [-- <args>] Connect Claude Code\");\n stream(\" stoops run opencode [--name <name>] [--admin] [-- <args>] Connect OpenCode\");\n}\n\nasync function main(): Promise<void> {\n // ── --help anywhere ────────────────────────────────────────────────────\n if (args.includes(\"--help\") || args.includes(\"-h\")) {\n printUsage();\n return;\n }\n\n // ── stoops run <runtime> ───────────────────────────────────────────────\n if (args[0] === \"run\" && (args[1] === \"claude\" || args[1] === \"opencode\")) {\n const runtime = args[1];\n const restArgs = args.slice(2);\n\n // Split on -- separator: stoops flags before, passthrough args after\n const ddIndex = restArgs.indexOf(\"--\");\n const stoopsArgs = ddIndex >= 0 ? restArgs.slice(0, ddIndex) : restArgs;\n const extraArgs = ddIndex >= 0 ? restArgs.slice(ddIndex + 1) : [];\n\n const joinUrls = getAllFlags(\"join\", stoopsArgs);\n\n const runtimeOptions = {\n joinUrls: joinUrls.length > 0 ? joinUrls : undefined,\n name: getFlag(\"name\", stoopsArgs),\n admin: stoopsArgs.includes(\"--admin\"),\n headless: stoopsArgs.includes(\"--headless\"),\n extraArgs,\n };\n\n if (runtime === \"claude\") {\n await runClaude(runtimeOptions);\n } else {\n await runOpencode(runtimeOptions);\n }\n return;\n }\n\n // ── stoops join <url> ──────────────────────────────────────────────────\n if (args[0] === \"join\") {\n const server = args[1];\n if (!server || server.startsWith(\"--\")) {\n console.error(\"Usage: stoops join <url> [--name <name>] [--guest] [--headless]\");\n process.exit(1);\n }\n await join({\n server,\n name: getFlag(\"name\"),\n guest: args.includes(\"--guest\"),\n headless: args.includes(\"--headless\"),\n });\n return;\n }\n\n // ── stoops serve ───────────────────────────────────────────────────────\n if (args[0] === \"serve\") {\n const portStr = getFlag(\"port\");\n const port = portStr ? parseInt(portStr, 10) : undefined;\n if (port !== undefined && (isNaN(port) || port < 0 || port > 65535)) {\n console.error(`Invalid port: ${portStr}`);\n process.exit(1);\n }\n await serve({\n room: getFlag(\"room\"),\n port,\n share: args.includes(\"--share\"),\n headless: args.includes(\"--headless\"),\n });\n return;\n }\n\n // ── stoops (bare) — host + join ────────────────────────────────────────\n if (args.length === 0 || args[0]?.startsWith(\"--\")) {\n const portStr = getFlag(\"port\");\n const port = portStr ? parseInt(portStr, 10) : undefined;\n if (port !== undefined && (isNaN(port) || port < 0 || port > 65535)) {\n console.error(`Invalid port: ${portStr}`);\n process.exit(1);\n }\n const result = await serve({\n room: getFlag(\"room\"),\n port,\n share: args.includes(\"--share\"),\n quiet: true,\n });\n\n // Host joins locally as admin using the admin share token\n const adminJoinUrl = buildShareUrl(result.serverUrl, result.adminToken);\n const participantShareUrl = buildShareUrl(\n result.publicUrl !== result.serverUrl ? result.publicUrl : result.serverUrl,\n result.participantToken,\n );\n\n await join({\n server: adminJoinUrl,\n name: getFlag(\"name\"),\n shareUrl: participantShareUrl,\n });\n return;\n }\n\n // ── Unknown command ────────────────────────────────────────────────────\n console.error(`Unknown command: ${args[0]}\\n`);\n printUsage(console.error);\n process.exit(1);\n}\n\nmain().catch((err) => {\n console.error(err);\n process.exit(1);\n});\n"],"mappings":"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","names":["id","channel","sessionToken","participantList","require","randomUUID","filtered","items","ghostHint","cmd","randomUUID","args","join","execFileSync","spawn","setup","eventLoopPromise","join","spawn","spawn"]}
|