@dreb/dashboard 2.35.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +146 -0
  2. package/dist/index.d.ts +30 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +251 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/server/auth.d.ts +164 -0
  7. package/dist/server/auth.d.ts.map +1 -0
  8. package/dist/server/auth.js +396 -0
  9. package/dist/server/auth.js.map +1 -0
  10. package/dist/server/event-hub.d.ts +31 -0
  11. package/dist/server/event-hub.d.ts.map +1 -0
  12. package/dist/server/event-hub.js +73 -0
  13. package/dist/server/event-hub.js.map +1 -0
  14. package/dist/server/files.d.ts +48 -0
  15. package/dist/server/files.d.ts.map +1 -0
  16. package/dist/server/files.js +194 -0
  17. package/dist/server/files.js.map +1 -0
  18. package/dist/server/pairing-storage.d.ts +18 -0
  19. package/dist/server/pairing-storage.d.ts.map +1 -0
  20. package/dist/server/pairing-storage.js +83 -0
  21. package/dist/server/pairing-storage.js.map +1 -0
  22. package/dist/server/runtime-pool.d.ts +89 -0
  23. package/dist/server/runtime-pool.d.ts.map +1 -0
  24. package/dist/server/runtime-pool.js +377 -0
  25. package/dist/server/runtime-pool.js.map +1 -0
  26. package/dist/server/server.d.ts +30 -0
  27. package/dist/server/server.d.ts.map +1 -0
  28. package/dist/server/server.js +557 -0
  29. package/dist/server/server.js.map +1 -0
  30. package/dist/server/subagent-log.d.ts +42 -0
  31. package/dist/server/subagent-log.d.ts.map +1 -0
  32. package/dist/server/subagent-log.js +155 -0
  33. package/dist/server/subagent-log.js.map +1 -0
  34. package/dist/shared/protocol.d.ts +261 -0
  35. package/dist/shared/protocol.d.ts.map +1 -0
  36. package/dist/shared/protocol.js +26 -0
  37. package/dist/shared/protocol.js.map +1 -0
  38. package/dist/static/assets/index-Cgwg2zRA.js +77 -0
  39. package/dist/static/assets/index-DnFrQoI9.css +1 -0
  40. package/dist/static/icons/apple-touch-icon.png +0 -0
  41. package/dist/static/icons/favicon-32.png +0 -0
  42. package/dist/static/icons/punk-1024.png +0 -0
  43. package/dist/static/icons/punk-192.png +0 -0
  44. package/dist/static/icons/punk-512.png +0 -0
  45. package/dist/static/index.html +32 -0
  46. package/dist/static/manifest.webmanifest +30 -0
  47. package/dist/static/sw.js +110 -0
  48. package/package.json +57 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server/server.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Dashboard HTTP server — Express app wiring auth, the runtime pool, the SSE\n * hub, and the file API into the REST surface the browser client consumes.\n *\n * Bind address discipline: local mode binds 127.0.0.1 only. The\n * caller decides the bind address; `createDashboardServer` never listens by\n * itself. Remote mode still passes every request through DashboardAuth.\n */\n\nimport { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { basename, join } from \"node:path\";\nimport type { NextFunction, Request, Response } from \"express\";\nimport express from \"express\";\nimport type { AuthStatusDto, FleetDto, ImageAttachmentDto, PairingCodeDto } from \"../shared/protocol.js\";\nimport { MAX_PROMPT_BODY_BYTES } from \"../shared/protocol.js\";\nimport type { AuthDecision, DashboardAuth } from \"./auth.js\";\nimport { EventHub } from \"./event-hub.js\";\nimport { defaultPlaces, FileApi } from \"./files.js\";\nimport type { RuntimePool } from \"./runtime-pool.js\";\nimport { readSubagentMessages } from \"./subagent-log.js\";\n\nexport interface DashboardServerOptions {\n\tauth: DashboardAuth;\n\tpool: RuntimePool;\n\t/** Directory of built client assets; omit to skip static serving (tests). */\n\tstaticDir?: string;\n\t/** Session listing (cross-project) — injected so tests can stub it. */\n\tlistAllSessions: () => Promise<unknown[]>;\n\tdeleteSession: (path: string) => Promise<unknown>;\n\tlogger?: (line: string) => void;\n\t/** Build version of the running server process (for the settings footer / stale-server detection). */\n\tserverVersion?: string;\n\t/** Restart hook — when set, POST /api/server/restart invokes it (typically process exit for a supervisor to respawn). */\n\tonRestart?: () => void;\n}\n\nconst DEVICE_COOKIE = \"dreb_dashboard_device\";\nexport const MAX_SSE_BUFFERED_BYTES = 4 * 1024 * 1024;\n\n/** Parse the device cookie from a Cookie header. */\nexport function parseDeviceCookie(cookieHeader: string | undefined): string | undefined {\n\tif (!cookieHeader) return undefined;\n\tfor (const part of cookieHeader.split(\";\")) {\n\t\tconst eq = part.indexOf(\"=\");\n\t\tif (eq === -1) continue;\n\t\tif (part.slice(0, eq).trim() === DEVICE_COOKIE) return part.slice(eq + 1).trim();\n\t}\n\treturn undefined;\n}\n\ninterface AuthedRequest extends Request {\n\tauthDecision?: AuthDecision;\n}\n\nexport function createDashboardServer(options: DashboardServerOptions): express.Express {\n\tconst { auth, pool } = options;\n\tconst serverStartedAt = new Date().toISOString();\n\tconst log = options.logger ?? ((line: string) => console.log(`[dashboard] ${line}`));\n\tconst files = new FileApi((op, path, detail) => log(`file ${op}: ${path}${detail ? ` (${detail})` : \"\"}`));\n\tconst hub = new EventHub();\n\tpool.onEvent((key, event) => hub.publish(key, event));\n\n\tconst app = express();\n\tapp.disable(\"x-powered-by\");\n\tapp.use(express.json({ limit: MAX_PROMPT_BODY_BYTES }));\n\n\t// -- auth middleware (every route, fail-closed) ---------------------------\n\tapp.use((req: AuthedRequest, res: Response, next: NextFunction) => {\n\t\tauth\n\t\t\t.authenticate({\n\t\t\t\tremoteAddress: req.socket.remoteAddress,\n\t\t\t\thostHeader: req.headers.host,\n\t\t\t\toriginHeader: req.headers.origin,\n\t\t\t\tdeviceToken: parseDeviceCookie(req.headers.cookie),\n\t\t\t})\n\t\t\t.then((decision) => {\n\t\t\t\treq.authDecision = decision;\n\t\t\t\tif (decision.allowed) return next();\n\t\t\t\tconst canRenderAuthScreen = decision.needsPairing || Boolean(decision.identity);\n\t\t\t\tif (canRenderAuthScreen) {\n\t\t\t\t\t// The auth/pairing endpoints must be reachable by allowed-but-unpaired\n\t\t\t\t\t// identities, and /api/auth must also be reachable by rejected\n\t\t\t\t\t// Tailscale identities so the SPA denial screen can name them.\n\t\t\t\t\tif (req.path === \"/api/auth\" || (decision.needsPairing && req.path === \"/api/pair\")) return next();\n\t\t\t\t\t// Let the SPA shell + static assets load so the client-side pairing or\n\t\t\t\t\t// denial screen can render. No data exposure: every /api/* data route\n\t\t\t\t\t// below stays fail-closed — only non-API GETs (the app shell) are allowed.\n\t\t\t\t\tif (req.method === \"GET\" && !req.path.startsWith(\"/api/\")) return next();\n\t\t\t\t}\n\t\t\t\tlog(`denied ${req.method} ${req.path}: ${decision.reason}`);\n\t\t\t\tres.status(decision.status).json({\n\t\t\t\t\terror: decision.reason,\n\t\t\t\t\tneedsPairing: decision.needsPairing ?? false,\n\t\t\t\t\tidentity: decision.identity?.loginName,\n\t\t\t\t});\n\t\t\t})\n\t\t\t.catch((err) => {\n\t\t\t\t// authenticate() already catches internally; this is belt-and-suspenders.\n\t\t\t\tlog(`auth middleware error — denying: ${err instanceof Error ? err.message : String(err)}`);\n\t\t\t\tres.status(500).json({ error: \"Auth subsystem error — denied\" });\n\t\t\t});\n\t});\n\n\t// -- auth/pairing ----------------------------------------------------------\n\tapp.get(\"/api/auth\", (req: AuthedRequest, res) => {\n\t\tconst decision = req.authDecision!;\n\t\tif (decision.allowed) {\n\t\t\tconst status: AuthStatusDto =\n\t\t\t\tdecision.mode === \"local\"\n\t\t\t\t\t? { mode: \"local\" }\n\t\t\t\t\t: { mode: \"remote\", identity: decision.identity.loginName, device: decision.identity.device };\n\t\t\tres.json({ ...status, needsPairing: false });\n\t\t\treturn;\n\t\t}\n\t\tres.status(decision.status).json({\n\t\t\terror: decision.reason,\n\t\t\tneedsPairing: decision.needsPairing ?? false,\n\t\t\tidentity: decision.identity?.loginName,\n\t\t});\n\t});\n\n\tapp.get(\"/api/pairing-code\", (req: AuthedRequest, res) => {\n\t\tconst decision = req.authDecision!;\n\t\tif (!decision.allowed || decision.mode !== \"local\") {\n\t\t\tres.status(403).json({ error: \"Pairing code is only available from the host machine\" });\n\t\t\treturn;\n\t\t}\n\t\tif (!auth.isRemoteEnabled) {\n\t\t\tconst body: PairingCodeDto = { enabled: false };\n\t\t\tres.json(body);\n\t\t\treturn;\n\t\t}\n\t\tconst body: PairingCodeDto = { enabled: true, ...auth.currentPairingCode() };\n\t\tres.json(body);\n\t});\n\n\tapp.post(\"/api/pair\", (req: AuthedRequest, res) => {\n\t\tconst pin = typeof req.body?.pin === \"string\" ? req.body.pin : \"\";\n\t\tauth\n\t\t\t.pair(\n\t\t\t\t{\n\t\t\t\t\tremoteAddress: req.socket.remoteAddress,\n\t\t\t\t\thostHeader: req.headers.host,\n\t\t\t\t\toriginHeader: req.headers.origin,\n\t\t\t\t\tdeviceToken: undefined,\n\t\t\t\t},\n\t\t\t\tpin,\n\t\t\t)\n\t\t\t.then(({ token, device }) => {\n\t\t\t\tlog(`paired device ${device.id} (${device.identity})`);\n\t\t\t\tres.cookie(DEVICE_COOKIE, token, {\n\t\t\t\t\thttpOnly: true,\n\t\t\t\t\tsameSite: \"strict\",\n\t\t\t\t\tsecure: false, // Tailscale already encrypts; the dashboard serves plain HTTP on the tailnet.\n\t\t\t\t\texpires: new Date(device.expiresAt),\n\t\t\t\t}).json({ device });\n\t\t\t})\n\t\t\t.catch((err) => {\n\t\t\t\tconst status = typeof err?.status === \"number\" ? err.status : 500;\n\t\t\t\tlog(`pairing failed: ${err instanceof Error ? err.message : String(err)}`);\n\t\t\t\tres.status(status).json({ error: err instanceof Error ? err.message : String(err) });\n\t\t\t});\n\t});\n\n\tapp.get(\"/api/devices\", (_req, res) => {\n\t\tauth\n\t\t\t.listDevices()\n\t\t\t.then((devices) => res.json({ devices }))\n\t\t\t.catch((err) => res.status(500).json({ error: String(err?.message ?? err) }));\n\t});\n\n\tapp.delete(\"/api/devices/:id\", (req, res) => {\n\t\tauth\n\t\t\t.unpair(req.params.id)\n\t\t\t.then((removed) => {\n\t\t\t\tif (!removed) {\n\t\t\t\t\tres.status(404).json({ error: `No paired device with id ${String(req.params.id)}` });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlog(`unpaired device ${String(req.params.id)}`);\n\t\t\t\tres.json({ ok: true });\n\t\t\t})\n\t\t\t.catch((err) => res.status(500).json({ error: String(err?.message ?? err) }));\n\t});\n\n\t// -- events (SSE) ----------------------------------------------------------\n\tapp.get(\"/api/events\", (req, res) => {\n\t\tres.writeHead(200, {\n\t\t\t\"content-type\": \"text/event-stream\",\n\t\t\t\"cache-control\": \"no-cache\",\n\t\t\tconnection: \"keep-alive\",\n\t\t});\n\n\t\tconst guardedWrite = (chunk: string, context: string): boolean => {\n\t\t\tif (res.destroyed || res.writableEnded) return false;\n\t\t\tconst accepted = res.write(chunk);\n\t\t\tif (!accepted && res.writableLength > MAX_SSE_BUFFERED_BYTES) {\n\t\t\t\tlog(\n\t\t\t\t\t`SSE client buffer exceeded ${MAX_SSE_BUFFERED_BYTES} bytes during ${context} (${res.writableLength} bytes queued); destroying connection`,\n\t\t\t\t);\n\t\t\t\tres.destroy();\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn true;\n\t\t};\n\n\t\tif (!guardedWrite(\":ok\\n\\n\", \"initial handshake\")) return;\n\t\tconst lastIdRaw = req.headers[\"last-event-id\"] ?? req.query.lastEventId;\n\t\tconst lastEventId =\n\t\t\ttypeof lastIdRaw === \"string\" && /^\\d+$/.test(lastIdRaw) ? Number.parseInt(lastIdRaw, 10) : undefined;\n\t\tconst detach = hub.attach({ write: (chunk) => guardedWrite(chunk, \"event fanout\") }, lastEventId);\n\t\tconst keepAlive = setInterval(() => {\n\t\t\tguardedWrite(\":ka\\n\\n\", \"keepalive\");\n\t\t}, 25_000);\n\t\treq.on(\"close\", () => {\n\t\t\tclearInterval(keepAlive);\n\t\t\tdetach();\n\t\t});\n\t});\n\n\t// -- fleet -----------------------------------------------------------------\n\tapp.get(\"/api/fleet\", (_req, res) => {\n\t\t(async () => {\n\t\t\tconst runtimes = await Promise.all(pool.list().map((h) => pool.describe(h)));\n\t\t\tconst diskSessions = ((await options.listAllSessions()) as FleetDto[\"diskSessions\"]).filter((session) =>\n\t\t\t\texistsSync(session.cwd),\n\t\t\t);\n\t\t\tconst fleet: FleetDto = { runtimes, diskSessions };\n\t\t\tres.json(fleet);\n\t\t})().catch((err) => res.status(500).json({ error: String(err?.message ?? err) }));\n\t});\n\n\t// -- runtimes ---------------------------------------------------------------\n\tapp.post(\"/api/runtimes\", (req, res) => {\n\t\t(async () => {\n\t\t\tconst cwd = typeof req.body?.cwd === \"string\" ? req.body.cwd : \"\";\n\t\t\tif (!cwd || !existsSync(cwd)) {\n\t\t\t\tres.status(400).json({ error: `Working directory does not exist: ${cwd || \"(empty)\"}` });\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst sessionPath = typeof req.body?.sessionPath === \"string\" ? req.body.sessionPath : undefined;\n\t\t\tconst handle = await pool.create(cwd, sessionPath);\n\t\t\tlog(`runtime ${handle.key} started in ${cwd}${sessionPath ? ` (resume ${basename(sessionPath)})` : \"\"}`);\n\t\t\tconst firstPrompt = typeof req.body?.firstPrompt === \"string\" ? req.body.firstPrompt : undefined;\n\t\t\tif (firstPrompt) await handle.client.prompt(firstPrompt);\n\t\t\tres.status(201).json(await pool.describe(handle));\n\t\t})().catch((err) => res.status(500).json({ error: String(err?.message ?? err) }));\n\t});\n\n\tapp.delete(\"/api/runtimes/:key\", (req, res) => {\n\t\tpool\n\t\t\t.stop(req.params.key)\n\t\t\t.then((stopped) => {\n\t\t\t\tif (!stopped) {\n\t\t\t\t\tres.status(404).json({ error: `No runtime ${String(req.params.key)}` });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlog(`runtime ${String(req.params.key)} stopped`);\n\t\t\t\tres.json({ ok: true });\n\t\t\t})\n\t\t\t.catch((err) => res.status(500).json({ error: String(err?.message ?? err) }));\n\t});\n\n\t/** Helper: run an async op against a pooled runtime with uniform errors. */\n\tfunction withRuntime(\n\t\treq: Request,\n\t\tres: Response,\n\t\tfn: (handle: NonNullable<ReturnType<RuntimePool[\"get\"]>>) => Promise<unknown>,\n\t): void {\n\t\tconst handle = pool.get(String(req.params.key));\n\t\tif (!handle) {\n\t\t\tres.status(404).json({ error: `No runtime ${String(req.params.key)}` });\n\t\t\treturn;\n\t\t}\n\t\tfn(handle)\n\t\t\t.then((data) => res.json(data ?? { ok: true }))\n\t\t\t.catch((err) => {\n\t\t\t\tres.status(502).json({ error: String(err?.message ?? err) });\n\t\t\t});\n\t}\n\n\tapp.get(\"/api/runtimes/:key\", (req, res) => {\n\t\twithRuntime(req, res, (h) => pool.describe(h));\n\t});\n\n\tapp.get(\"/api/runtimes/:key/messages\", (req, res) => {\n\t\twithRuntime(req, res, async (h) => ({ messages: await h.client.getMessages() }));\n\t});\n\n\tapp.get(\"/api/runtimes/:key/pending\", (req, res) => {\n\t\twithRuntime(req, res, (h) => h.client.getPendingMessages());\n\t});\n\n\tapp.post(\"/api/runtimes/:key/dequeue\", (req, res) => {\n\t\twithRuntime(req, res, (h) => h.client.clearPendingMessages());\n\t});\n\n\tfunction parseImages(body: unknown): ImageAttachmentDto[] | undefined | \"invalid\" {\n\t\tconst images = (body as { images?: unknown } | undefined)?.images;\n\t\tif (images === undefined) return undefined;\n\t\tif (!Array.isArray(images)) return \"invalid\";\n\t\tconst parsed: ImageAttachmentDto[] = [];\n\t\tfor (const image of images) {\n\t\t\tif (\n\t\t\t\t!image ||\n\t\t\t\ttypeof image !== \"object\" ||\n\t\t\t\ttypeof (image as { data?: unknown }).data !== \"string\" ||\n\t\t\t\ttypeof (image as { mimeType?: unknown }).mimeType !== \"string\"\n\t\t\t) {\n\t\t\t\treturn \"invalid\";\n\t\t\t}\n\t\t\tparsed.push({ data: (image as ImageAttachmentDto).data, mimeType: (image as ImageAttachmentDto).mimeType });\n\t\t}\n\t\treturn parsed;\n\t}\n\n\tapp.post(\"/api/runtimes/:key/prompt\", (req, res) => {\n\t\tconst { message, mode } = req.body ?? {};\n\t\tif (typeof message !== \"string\" || message.length === 0) {\n\t\t\tres.status(400).json({ error: \"message is required\" });\n\t\t\treturn;\n\t\t}\n\t\tconst images = parseImages(req.body);\n\t\tif (images === \"invalid\") {\n\t\t\tres.status(400).json({ error: \"images must be an array of {data, mimeType} objects\" });\n\t\t\treturn;\n\t\t}\n\t\tconst rpcImages = images?.map((image) => ({\n\t\t\ttype: \"image\" as const,\n\t\t\tdata: image.data,\n\t\t\tmimeType: image.mimeType,\n\t\t}));\n\t\twithRuntime(req, res, async (h) => {\n\t\t\tif (mode === \"steer\") await h.client.steer(message, rpcImages);\n\t\t\telse if (mode === \"follow_up\") await h.client.followUp(message, rpcImages);\n\t\t\telse await h.client.prompt(message, rpcImages);\n\t\t});\n\t});\n\n\tapp.post(\"/api/runtimes/:key/abort\", (req, res) => {\n\t\twithRuntime(req, res, (h) => h.client.abort());\n\t});\n\n\tapp.post(\"/api/runtimes/:key/abort-compaction\", (req, res) => {\n\t\twithRuntime(req, res, (h) => h.client.abortCompaction());\n\t});\n\n\tapp.post(\"/api/runtimes/:key/abort-retry\", (req, res) => {\n\t\twithRuntime(req, res, (h) => h.client.abortRetry());\n\t});\n\n\tapp.post(\"/api/runtimes/:key/model\", (req, res) => {\n\t\tconst { provider, modelId } = req.body ?? {};\n\t\tif (typeof provider !== \"string\" || typeof modelId !== \"string\") {\n\t\t\tres.status(400).json({ error: \"provider and modelId are required\" });\n\t\t\treturn;\n\t\t}\n\t\twithRuntime(req, res, (h) => h.client.setModel(provider, modelId));\n\t});\n\n\tapp.get(\"/api/runtimes/:key/models\", (req, res) => {\n\t\twithRuntime(req, res, async (h) => ({ models: await h.client.getAvailableModels() }));\n\t});\n\n\tapp.post(\"/api/runtimes/:key/thinking\", (req, res) => {\n\t\tconst { level } = req.body ?? {};\n\t\tif (typeof level !== \"string\") {\n\t\t\tres.status(400).json({ error: \"level is required\" });\n\t\t\treturn;\n\t\t}\n\t\twithRuntime(req, res, (h) => h.client.setThinkingLevel(level as never));\n\t});\n\n\tapp.post(\"/api/runtimes/:key/compact\", (req, res) => {\n\t\tconst instructions = typeof req.body?.instructions === \"string\" ? req.body.instructions : undefined;\n\t\twithRuntime(req, res, (h) => h.client.compact(instructions));\n\t});\n\n\tapp.post(\"/api/runtimes/:key/name\", (req, res) => {\n\t\tconst { name } = req.body ?? {};\n\t\tif (typeof name !== \"string\" || name.length === 0) {\n\t\t\tres.status(400).json({ error: \"name is required\" });\n\t\t\treturn;\n\t\t}\n\t\twithRuntime(req, res, (h) => h.client.setSessionName(name));\n\t});\n\n\tapp.get(\"/api/runtimes/:key/stats\", (req, res) => {\n\t\twithRuntime(req, res, (h) => h.client.getSessionStats());\n\t});\n\n\tapp.get(\"/api/runtimes/:key/performance\", (req, res) => {\n\t\twithRuntime(req, res, (h) => h.client.getPerformanceStats());\n\t});\n\n\tapp.get(\"/api/runtimes/:key/resources\", (req, res) => {\n\t\twithRuntime(req, res, (h) => h.client.getResources());\n\t});\n\n\tapp.get(\"/api/runtimes/:key/commands\", (req, res) => {\n\t\twithRuntime(req, res, async (h) => ({ commands: await h.client.getCommands() }));\n\t});\n\n\tapp.get(\"/api/runtimes/:key/branch\", (req, res) => {\n\t\twithRuntime(req, res, async (h) => ({ branch: await h.client.getGitBranch() }));\n\t});\n\n\tapp.get(\"/api/runtimes/:key/fork-messages\", (req, res) => {\n\t\twithRuntime(req, res, async (h) => ({ messages: await h.client.getForkMessages() }));\n\t});\n\n\tapp.post(\"/api/runtimes/:key/fork\", (req, res) => {\n\t\tconst { entryId } = req.body ?? {};\n\t\tif (typeof entryId !== \"string\") {\n\t\t\tres.status(400).json({ error: \"entryId is required\" });\n\t\t\treturn;\n\t\t}\n\t\twithRuntime(req, res, (h) => h.client.fork(entryId));\n\t});\n\n\tapp.get(\"/api/runtimes/:key/export-html\", (req, res) => {\n\t\tconst handle = pool.get(String(req.params.key));\n\t\tif (!handle) {\n\t\t\tres.status(404).json({ error: `No runtime ${String(req.params.key)}` });\n\t\t\treturn;\n\t\t}\n\t\thandle.client\n\t\t\t.exportHtml()\n\t\t\t.then(({ path }) => {\n\t\t\t\tres.download(path);\n\t\t\t})\n\t\t\t.catch((err) => res.status(502).json({ error: String(err?.message ?? err) }));\n\t});\n\n\tapp.get(\"/api/runtimes/:key/background-agents\", (req, res) => {\n\t\twithRuntime(req, res, async (h) => ({ agents: await h.client.listBackgroundAgents() }));\n\t});\n\n\tapp.get(\"/api/runtimes/:key/subagents/:agentId/messages\", (req, res) => {\n\t\tconst agentId = String(req.params.agentId);\n\t\twithRuntime(req, res, async (h) => {\n\t\t\t// The runtime's registry is authoritative for status + log location.\n\t\t\tconst agents = await h.client.listBackgroundAgents();\n\t\t\tconst agent = agents.find((a) => a.agentId === agentId);\n\t\t\tif (!agent) throw new Error(`No background agent ${agentId} in this runtime`);\n\t\t\tconst messages = readSubagentMessages(agent);\n\t\t\treturn { agent, messages };\n\t\t});\n\t});\n\n\tapp.post(\"/api/runtimes/:key/extension-ui-response\", (req, res) => {\n\t\tconst handle = pool.get(String(req.params.key));\n\t\tif (!handle) {\n\t\t\tres.status(404).json({ error: `No runtime ${String(req.params.key)}` });\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\thandle.client.sendExtensionUIResponse(req.body);\n\t\t\tres.json({ ok: true });\n\t\t} catch (err) {\n\t\t\tres.status(502).json({ error: String((err as Error)?.message ?? err) });\n\t\t}\n\t});\n\n\t// -- disk sessions -----------------------------------------------------------\n\tapp.delete(\"/api/sessions\", (req, res) => {\n\t\tconst path = typeof req.body?.path === \"string\" ? req.body.path : \"\";\n\t\tif (!path) {\n\t\t\tres.status(400).json({ error: \"path is required\" });\n\t\t\treturn;\n\t\t}\n\t\toptions\n\t\t\t.deleteSession(path)\n\t\t\t.then((result) => {\n\t\t\t\tlog(`session deleted: ${path}`);\n\t\t\t\tres.json(result ?? { ok: true });\n\t\t\t})\n\t\t\t.catch((err) => res.status(500).json({ error: String(err?.message ?? err) }));\n\t});\n\n\t// -- settings ------------------------------------------------------------------\n\t// Settings are process-global persistent defaults. They route through hidden\n\t// utility runtimes instead of whichever user session happened to open first.\n\t// Agent-definition discovery is cwd-sensitive, so callers may pass an explicit\n\t// project cwd for endpoints that need project-local .dreb/agents.\n\tfunction withAnyRuntime(\n\t\tres: Response,\n\t\tfn: (h: NonNullable<ReturnType<RuntimePool[\"get\"]>>) => Promise<unknown>,\n\t\tcwd?: string,\n\t) {\n\t\tpool\n\t\t\t.ensureUtilityRuntime(cwd)\n\t\t\t.then((handle) => fn(handle))\n\t\t\t.then((data) => res.json(data ?? { ok: true }))\n\t\t\t.catch((err) => {\n\t\t\t\tres.status(502).json({ error: String(err?.message ?? err) });\n\t\t\t});\n\t}\n\n\tapp.get(\"/api/settings\", (_req, res) => {\n\t\twithAnyRuntime(res, (h) => h.client.getSettings());\n\t});\n\n\tapp.get(\"/api/settings/models\", (_req, res) => {\n\t\twithAnyRuntime(res, async (h) => ({ models: await h.client.getAvailableModels() }));\n\t});\n\n\tapp.get(\"/api/settings/agent-types\", (req, res) => {\n\t\tconst cwd = typeof req.query.cwd === \"string\" && req.query.cwd.trim() ? req.query.cwd : undefined;\n\t\tif (cwd && !existsSync(cwd)) {\n\t\t\tres.status(400).json({ error: `cwd does not exist: ${cwd}` });\n\t\t\treturn;\n\t\t}\n\t\twithAnyRuntime(res, async (h) => ({ agentTypes: await h.client.listAgentTypes() }), cwd);\n\t});\n\n\tapp.get(\"/api/daily-cost\", (_req, res) => {\n\t\twithAnyRuntime(res, async (h) => ({ cost: await h.client.getDailyCost() }));\n\t});\n\n\tapp.put(\"/api/settings\", (req, res) => {\n\t\twithAnyRuntime(res, (h) => h.client.setSettings(req.body ?? {}));\n\t});\n\n\tapp.get(\"/api/version\", (_req, res) => {\n\t\twithAnyRuntime(res, async (h) => ({ version: await h.client.getVersion() }));\n\t});\n\n\t// -- server lifecycle ----------------------------------------------------------\n\t// Build/version of the *server* process (distinct from a freshly-spawned RPC\n\t// child's version) so a stale long-running service is visible at a glance.\n\tapp.get(\"/api/server/info\", (_req, res) => {\n\t\tres.json({\n\t\t\tversion: options.serverVersion ?? null,\n\t\t\tstartedAt: serverStartedAt,\n\t\t\t// systemd sets INVOCATION_ID; other supervisors set LISTEN_PID. Best-effort.\n\t\t\tsupervised: Boolean(process.env.INVOCATION_ID || process.env.LISTEN_PID),\n\t\t\trestartable: Boolean(options.onRestart),\n\t\t});\n\t});\n\n\tapp.post(\"/api/server/restart\", (_req, res) => {\n\t\tif (!options.onRestart) {\n\t\t\tres.status(501).json({\n\t\t\t\terror: \"Restart is unavailable — the dashboard is not running under a supervisor that can respawn it\",\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tlog(\"restart requested via API\");\n\t\tres.json({ ok: true, restarting: true });\n\t\t// Defer so the HTTP response flushes before the process exits.\n\t\tsetTimeout(() => options.onRestart?.(), 100);\n\t});\n\n\t// -- files -----------------------------------------------------------------------\n\tapp.get(\"/api/files\", (req, res) => {\n\t\tconst path = typeof req.query.path === \"string\" ? req.query.path : homedir();\n\t\tfiles\n\t\t\t.list(path)\n\t\t\t.then((listing) => res.json(listing))\n\t\t\t.catch((err) => res.status(err?.status ?? 500).json({ error: String(err?.message ?? err) }));\n\t});\n\n\tapp.get(\"/api/files/places\", (_req, res) => {\n\t\tconst roots = [...new Set(pool.list().map((h) => h.cwd))];\n\t\tres.json({ places: defaultPlaces(homedir(), roots) });\n\t});\n\n\tapp.get(\"/api/files/download\", (req, res) => {\n\t\tconst path = typeof req.query.path === \"string\" ? req.query.path : \"\";\n\t\tfiles\n\t\t\t.resolveDownload(path)\n\t\t\t.then(({ path: real }) => {\n\t\t\t\tres.download(real);\n\t\t\t})\n\t\t\t.catch((err) => res.status(err?.status ?? 500).json({ error: String(err?.message ?? err) }));\n\t});\n\n\tapp.post(\"/api/files/upload\", (req, res) => {\n\t\t(async () => {\n\t\t\tconst dir = typeof req.query.dir === \"string\" ? req.query.dir : \"\";\n\t\t\tconst name = typeof req.query.name === \"string\" ? req.query.name : \"\";\n\t\t\tconst overwrite = req.query.overwrite === \"true\";\n\t\t\tconst upload = await files.prepareUpload(dir, name, overwrite);\n\t\t\ttry {\n\t\t\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\t\t\tlet settled = false;\n\t\t\t\t\tconst fail = (err: unknown) => {\n\t\t\t\t\t\tif (settled) return;\n\t\t\t\t\t\tsettled = true;\n\t\t\t\t\t\tupload.stream.destroy();\n\t\t\t\t\t\treject(err);\n\t\t\t\t\t};\n\t\t\t\t\treq.pipe(upload.stream);\n\t\t\t\t\tupload.stream.on(\"finish\", () => {\n\t\t\t\t\t\tif (settled) return;\n\t\t\t\t\t\tsettled = true;\n\t\t\t\t\t\tresolve();\n\t\t\t\t\t});\n\t\t\t\t\tupload.stream.on(\"error\", fail);\n\t\t\t\t\treq.on(\"error\", fail);\n\t\t\t\t\treq.on(\"aborted\", () => fail(Object.assign(new Error(\"Upload aborted\"), { status: 499 })));\n\t\t\t\t});\n\t\t\t\tawait upload.commit();\n\t\t\t\tres.json({ path: upload.path });\n\t\t\t} catch (err) {\n\t\t\t\tawait upload.cleanup();\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t})().catch((err) => {\n\t\t\tif (!res.headersSent) res.status(err?.status ?? 500).json({ error: String(err?.message ?? err) });\n\t\t});\n\t});\n\n\tapp.post(\"/api/files/mkdir\", (req, res) => {\n\t\tconst { dir, name } = req.body ?? {};\n\t\tif (typeof dir !== \"string\" || typeof name !== \"string\") {\n\t\t\tres.status(400).json({ error: \"dir and name are required\" });\n\t\t\treturn;\n\t\t}\n\t\tfiles\n\t\t\t.mkdir(dir, name)\n\t\t\t.then((path) => res.json({ path }))\n\t\t\t.catch((err) => res.status(err?.status ?? 500).json({ error: String(err?.message ?? err) }));\n\t});\n\n\t// -- static client -----------------------------------------------------------------\n\tif (options.staticDir) {\n\t\tapp.use(express.static(options.staticDir));\n\t\t// SPA fallback: serve index.html for non-API GETs (client-side routing).\n\t\tapp.get(/^\\/(?!api\\/).*/, (_req, res) => {\n\t\t\tres.sendFile(join(options.staticDir!, \"index.html\"));\n\t\t});\n\t}\n\n\treturn app;\n}\n"]}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Subagent session-log reader — turns a background agent's on-disk session
3
+ * JSONL into the message list the client's transcript reducer consumes.
4
+ *
5
+ * Why disk: `background_agent_event` relays are ephemeral (they exist only on
6
+ * SSE clients connected while the agent streams). After a browser reload the
7
+ * reducer state is gone, so the session log is the only source of truth for
8
+ * a subagent transcript. The child process appends entries as it works, so
9
+ * reading the file mid-run yields the transcript up to the last completed
10
+ * message.
11
+ */
12
+ export interface SubagentLogSource {
13
+ /** Path to the agent's session JSONL (known after the child exits). */
14
+ sessionFile?: string;
15
+ /** Directory the child writes its session into (known at spawn time). */
16
+ sessionDir?: string;
17
+ }
18
+ /**
19
+ * Find chain step session JSONLs under step-N/ directories, ordered by numeric
20
+ * step index. Returns an empty list for missing/non-chain directories.
21
+ */
22
+ export declare function discoverSubagentStepSessionFiles(sessionDir: string): string[];
23
+ /**
24
+ * Find the most recently modified .jsonl in a session directory. Parity with
25
+ * discoverSessionFile in @dreb/coding-agent's subagent tool. Normal subagents
26
+ * write directly under sessionDir; chain-mode subagents register the chain root
27
+ * but write per-step logs under step-N/ subdirectories.
28
+ */
29
+ export declare function discoverSubagentSessionFile(sessionDir: string): string | undefined;
30
+ /**
31
+ * Read the message payloads from a subagent session log.
32
+ *
33
+ * Subagent sessions are single-shot and linear (no branching/compaction), so
34
+ * a straight scan of `type: "message"` entries reconstructs the transcript.
35
+ * Chain-mode subagents write one linear log per step; those step logs are
36
+ * concatenated in numeric step order. Malformed lines are skipped (the tail
37
+ * line can be mid-write).
38
+ *
39
+ * @throws when no session file can be located — callers surface this loudly.
40
+ */
41
+ export declare function readSubagentMessages(source: SubagentLogSource): unknown[];
42
+ //# sourceMappingURL=subagent-log.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subagent-log.d.ts","sourceRoot":"","sources":["../../src/server/subagent-log.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,MAAM,WAAW,iBAAiB;IACjC,uEAAuE;IACvE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAyDD;;;GAGG;AACH,wBAAgB,gCAAgC,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAQ7E;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAelF;AAyBD;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,EAAE,CAMzE","sourcesContent":["/**\n * Subagent session-log reader — turns a background agent's on-disk session\n * JSONL into the message list the client's transcript reducer consumes.\n *\n * Why disk: `background_agent_event` relays are ephemeral (they exist only on\n * SSE clients connected while the agent streams). After a browser reload the\n * reducer state is gone, so the session log is the only source of truth for\n * a subagent transcript. The child process appends entries as it works, so\n * reading the file mid-run yields the transcript up to the last completed\n * message.\n */\n\nimport { existsSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nexport interface SubagentLogSource {\n\t/** Path to the agent's session JSONL (known after the child exits). */\n\tsessionFile?: string;\n\t/** Directory the child writes its session into (known at spawn time). */\n\tsessionDir?: string;\n}\n\ninterface SessionFileCandidate {\n\tpath: string;\n\tmtime: number;\n}\n\nconst STEP_SESSION_DIR_RE = /^step-(\\d+)$/;\n\nfunction isExpectedFilesystemError(err: unknown): boolean {\n\treturn typeof (err as NodeJS.ErrnoException | undefined)?.code === \"string\";\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null;\n}\n\nfunction findNewestJsonlFileInDir(dir: string): SessionFileCandidate | undefined {\n\tlet best: SessionFileCandidate | undefined;\n\tfor (const entry of readdirSync(dir, { withFileTypes: true })) {\n\t\tif (!entry.name.endsWith(\".jsonl\")) continue;\n\t\tif (entry.isDirectory()) continue;\n\t\tconst path = join(dir, entry.name);\n\t\ttry {\n\t\t\tconst mtime = statSync(path).mtime.getTime();\n\t\t\tif (!best || mtime > best.mtime) best = { path, mtime };\n\t\t} catch (err) {\n\t\t\tif (isExpectedFilesystemError(err)) continue;\n\t\t\tthrow err;\n\t\t}\n\t}\n\treturn best;\n}\n\nfunction discoverStepSessionFileCandidates(sessionDir: string): SessionFileCandidate[] {\n\tconst steps: Array<{ name: string; index: number }> = [];\n\tfor (const entry of readdirSync(sessionDir, { withFileTypes: true })) {\n\t\tif (!entry.isDirectory()) continue;\n\t\tconst match = STEP_SESSION_DIR_RE.exec(entry.name);\n\t\tif (!match) continue;\n\t\tsteps.push({ name: entry.name, index: Number(match[1]) });\n\t}\n\tsteps.sort((a, b) => a.index - b.index || a.name.localeCompare(b.name));\n\n\tconst files: SessionFileCandidate[] = [];\n\tfor (const step of steps) {\n\t\ttry {\n\t\t\tconst candidate = findNewestJsonlFileInDir(join(sessionDir, step.name));\n\t\t\tif (candidate) files.push(candidate);\n\t\t} catch (err) {\n\t\t\tif (isExpectedFilesystemError(err)) continue;\n\t\t\tthrow err;\n\t\t}\n\t}\n\treturn files;\n}\n\n/**\n * Find chain step session JSONLs under step-N/ directories, ordered by numeric\n * step index. Returns an empty list for missing/non-chain directories.\n */\nexport function discoverSubagentStepSessionFiles(sessionDir: string): string[] {\n\ttry {\n\t\tif (!existsSync(sessionDir)) return [];\n\t\treturn discoverStepSessionFileCandidates(sessionDir).map((file) => file.path);\n\t} catch (err) {\n\t\tif (isExpectedFilesystemError(err)) return [];\n\t\tthrow err;\n\t}\n}\n\n/**\n * Find the most recently modified .jsonl in a session directory. Parity with\n * discoverSessionFile in @dreb/coding-agent's subagent tool. Normal subagents\n * write directly under sessionDir; chain-mode subagents register the chain root\n * but write per-step logs under step-N/ subdirectories.\n */\nexport function discoverSubagentSessionFile(sessionDir: string): string | undefined {\n\ttry {\n\t\tif (!existsSync(sessionDir)) return undefined;\n\t\tconst flatFile = findNewestJsonlFileInDir(sessionDir);\n\t\tif (flatFile) return flatFile.path;\n\n\t\tlet best: SessionFileCandidate | undefined;\n\t\tfor (const file of discoverStepSessionFileCandidates(sessionDir)) {\n\t\t\tif (!best || file.mtime > best.mtime) best = file;\n\t\t}\n\t\treturn best?.path;\n\t} catch (err) {\n\t\tif (isExpectedFilesystemError(err)) return undefined;\n\t\tthrow err;\n\t}\n}\n\nfunction readMessagesFromFile(file: string): unknown[] {\n\tconst messages: unknown[] = [];\n\tfor (const line of readFileSync(file, \"utf8\").split(\"\\n\")) {\n\t\tif (!line.trim()) continue;\n\t\ttry {\n\t\t\tconst entry = JSON.parse(line);\n\t\t\tif (isRecord(entry) && entry.type === \"message\" && entry.message) messages.push(entry.message);\n\t\t} catch (err) {\n\t\t\tif (err instanceof SyntaxError) continue;\n\t\t\tthrow err;\n\t\t}\n\t}\n\treturn messages;\n}\n\nfunction discoverMessageFiles(source: SubagentLogSource): string[] {\n\tconst stepFiles = source.sessionDir ? discoverSubagentStepSessionFiles(source.sessionDir) : [];\n\tif (stepFiles.length > 0) return stepFiles;\n\tif (source.sessionFile) return existsSync(source.sessionFile) ? [source.sessionFile] : [];\n\tconst file = source.sessionDir ? discoverSubagentSessionFile(source.sessionDir) : undefined;\n\treturn file ? [file] : [];\n}\n\n/**\n * Read the message payloads from a subagent session log.\n *\n * Subagent sessions are single-shot and linear (no branching/compaction), so\n * a straight scan of `type: \"message\"` entries reconstructs the transcript.\n * Chain-mode subagents write one linear log per step; those step logs are\n * concatenated in numeric step order. Malformed lines are skipped (the tail\n * line can be mid-write).\n *\n * @throws when no session file can be located — callers surface this loudly.\n */\nexport function readSubagentMessages(source: SubagentLogSource): unknown[] {\n\tconst files = discoverMessageFiles(source);\n\tif (files.length === 0) {\n\t\tthrow new Error(\"No session log found for this agent — it may not have produced output yet\");\n\t}\n\treturn files.flatMap((file) => readMessagesFromFile(file));\n}\n"]}
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Subagent session-log reader — turns a background agent's on-disk session
3
+ * JSONL into the message list the client's transcript reducer consumes.
4
+ *
5
+ * Why disk: `background_agent_event` relays are ephemeral (they exist only on
6
+ * SSE clients connected while the agent streams). After a browser reload the
7
+ * reducer state is gone, so the session log is the only source of truth for
8
+ * a subagent transcript. The child process appends entries as it works, so
9
+ * reading the file mid-run yields the transcript up to the last completed
10
+ * message.
11
+ */
12
+ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
13
+ import { join } from "node:path";
14
+ const STEP_SESSION_DIR_RE = /^step-(\d+)$/;
15
+ function isExpectedFilesystemError(err) {
16
+ return typeof err?.code === "string";
17
+ }
18
+ function isRecord(value) {
19
+ return typeof value === "object" && value !== null;
20
+ }
21
+ function findNewestJsonlFileInDir(dir) {
22
+ let best;
23
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
24
+ if (!entry.name.endsWith(".jsonl"))
25
+ continue;
26
+ if (entry.isDirectory())
27
+ continue;
28
+ const path = join(dir, entry.name);
29
+ try {
30
+ const mtime = statSync(path).mtime.getTime();
31
+ if (!best || mtime > best.mtime)
32
+ best = { path, mtime };
33
+ }
34
+ catch (err) {
35
+ if (isExpectedFilesystemError(err))
36
+ continue;
37
+ throw err;
38
+ }
39
+ }
40
+ return best;
41
+ }
42
+ function discoverStepSessionFileCandidates(sessionDir) {
43
+ const steps = [];
44
+ for (const entry of readdirSync(sessionDir, { withFileTypes: true })) {
45
+ if (!entry.isDirectory())
46
+ continue;
47
+ const match = STEP_SESSION_DIR_RE.exec(entry.name);
48
+ if (!match)
49
+ continue;
50
+ steps.push({ name: entry.name, index: Number(match[1]) });
51
+ }
52
+ steps.sort((a, b) => a.index - b.index || a.name.localeCompare(b.name));
53
+ const files = [];
54
+ for (const step of steps) {
55
+ try {
56
+ const candidate = findNewestJsonlFileInDir(join(sessionDir, step.name));
57
+ if (candidate)
58
+ files.push(candidate);
59
+ }
60
+ catch (err) {
61
+ if (isExpectedFilesystemError(err))
62
+ continue;
63
+ throw err;
64
+ }
65
+ }
66
+ return files;
67
+ }
68
+ /**
69
+ * Find chain step session JSONLs under step-N/ directories, ordered by numeric
70
+ * step index. Returns an empty list for missing/non-chain directories.
71
+ */
72
+ export function discoverSubagentStepSessionFiles(sessionDir) {
73
+ try {
74
+ if (!existsSync(sessionDir))
75
+ return [];
76
+ return discoverStepSessionFileCandidates(sessionDir).map((file) => file.path);
77
+ }
78
+ catch (err) {
79
+ if (isExpectedFilesystemError(err))
80
+ return [];
81
+ throw err;
82
+ }
83
+ }
84
+ /**
85
+ * Find the most recently modified .jsonl in a session directory. Parity with
86
+ * discoverSessionFile in @dreb/coding-agent's subagent tool. Normal subagents
87
+ * write directly under sessionDir; chain-mode subagents register the chain root
88
+ * but write per-step logs under step-N/ subdirectories.
89
+ */
90
+ export function discoverSubagentSessionFile(sessionDir) {
91
+ try {
92
+ if (!existsSync(sessionDir))
93
+ return undefined;
94
+ const flatFile = findNewestJsonlFileInDir(sessionDir);
95
+ if (flatFile)
96
+ return flatFile.path;
97
+ let best;
98
+ for (const file of discoverStepSessionFileCandidates(sessionDir)) {
99
+ if (!best || file.mtime > best.mtime)
100
+ best = file;
101
+ }
102
+ return best?.path;
103
+ }
104
+ catch (err) {
105
+ if (isExpectedFilesystemError(err))
106
+ return undefined;
107
+ throw err;
108
+ }
109
+ }
110
+ function readMessagesFromFile(file) {
111
+ const messages = [];
112
+ for (const line of readFileSync(file, "utf8").split("\n")) {
113
+ if (!line.trim())
114
+ continue;
115
+ try {
116
+ const entry = JSON.parse(line);
117
+ if (isRecord(entry) && entry.type === "message" && entry.message)
118
+ messages.push(entry.message);
119
+ }
120
+ catch (err) {
121
+ if (err instanceof SyntaxError)
122
+ continue;
123
+ throw err;
124
+ }
125
+ }
126
+ return messages;
127
+ }
128
+ function discoverMessageFiles(source) {
129
+ const stepFiles = source.sessionDir ? discoverSubagentStepSessionFiles(source.sessionDir) : [];
130
+ if (stepFiles.length > 0)
131
+ return stepFiles;
132
+ if (source.sessionFile)
133
+ return existsSync(source.sessionFile) ? [source.sessionFile] : [];
134
+ const file = source.sessionDir ? discoverSubagentSessionFile(source.sessionDir) : undefined;
135
+ return file ? [file] : [];
136
+ }
137
+ /**
138
+ * Read the message payloads from a subagent session log.
139
+ *
140
+ * Subagent sessions are single-shot and linear (no branching/compaction), so
141
+ * a straight scan of `type: "message"` entries reconstructs the transcript.
142
+ * Chain-mode subagents write one linear log per step; those step logs are
143
+ * concatenated in numeric step order. Malformed lines are skipped (the tail
144
+ * line can be mid-write).
145
+ *
146
+ * @throws when no session file can be located — callers surface this loudly.
147
+ */
148
+ export function readSubagentMessages(source) {
149
+ const files = discoverMessageFiles(source);
150
+ if (files.length === 0) {
151
+ throw new Error("No session log found for this agent — it may not have produced output yet");
152
+ }
153
+ return files.flatMap((file) => readMessagesFromFile(file));
154
+ }
155
+ //# sourceMappingURL=subagent-log.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subagent-log.js","sourceRoot":"","sources":["../../src/server/subagent-log.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Subagent session-log reader — turns a background agent's on-disk session\n * JSONL into the message list the client's transcript reducer consumes.\n *\n * Why disk: `background_agent_event` relays are ephemeral (they exist only on\n * SSE clients connected while the agent streams). After a browser reload the\n * reducer state is gone, so the session log is the only source of truth for\n * a subagent transcript. The child process appends entries as it works, so\n * reading the file mid-run yields the transcript up to the last completed\n * message.\n */\n\nimport { existsSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nexport interface SubagentLogSource {\n\t/** Path to the agent's session JSONL (known after the child exits). */\n\tsessionFile?: string;\n\t/** Directory the child writes its session into (known at spawn time). */\n\tsessionDir?: string;\n}\n\ninterface SessionFileCandidate {\n\tpath: string;\n\tmtime: number;\n}\n\nconst STEP_SESSION_DIR_RE = /^step-(\\d+)$/;\n\nfunction isExpectedFilesystemError(err: unknown): boolean {\n\treturn typeof (err as NodeJS.ErrnoException | undefined)?.code === \"string\";\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null;\n}\n\nfunction findNewestJsonlFileInDir(dir: string): SessionFileCandidate | undefined {\n\tlet best: SessionFileCandidate | undefined;\n\tfor (const entry of readdirSync(dir, { withFileTypes: true })) {\n\t\tif (!entry.name.endsWith(\".jsonl\")) continue;\n\t\tif (entry.isDirectory()) continue;\n\t\tconst path = join(dir, entry.name);\n\t\ttry {\n\t\t\tconst mtime = statSync(path).mtime.getTime();\n\t\t\tif (!best || mtime > best.mtime) best = { path, mtime };\n\t\t} catch (err) {\n\t\t\tif (isExpectedFilesystemError(err)) continue;\n\t\t\tthrow err;\n\t\t}\n\t}\n\treturn best;\n}\n\nfunction discoverStepSessionFileCandidates(sessionDir: string): SessionFileCandidate[] {\n\tconst steps: Array<{ name: string; index: number }> = [];\n\tfor (const entry of readdirSync(sessionDir, { withFileTypes: true })) {\n\t\tif (!entry.isDirectory()) continue;\n\t\tconst match = STEP_SESSION_DIR_RE.exec(entry.name);\n\t\tif (!match) continue;\n\t\tsteps.push({ name: entry.name, index: Number(match[1]) });\n\t}\n\tsteps.sort((a, b) => a.index - b.index || a.name.localeCompare(b.name));\n\n\tconst files: SessionFileCandidate[] = [];\n\tfor (const step of steps) {\n\t\ttry {\n\t\t\tconst candidate = findNewestJsonlFileInDir(join(sessionDir, step.name));\n\t\t\tif (candidate) files.push(candidate);\n\t\t} catch (err) {\n\t\t\tif (isExpectedFilesystemError(err)) continue;\n\t\t\tthrow err;\n\t\t}\n\t}\n\treturn files;\n}\n\n/**\n * Find chain step session JSONLs under step-N/ directories, ordered by numeric\n * step index. Returns an empty list for missing/non-chain directories.\n */\nexport function discoverSubagentStepSessionFiles(sessionDir: string): string[] {\n\ttry {\n\t\tif (!existsSync(sessionDir)) return [];\n\t\treturn discoverStepSessionFileCandidates(sessionDir).map((file) => file.path);\n\t} catch (err) {\n\t\tif (isExpectedFilesystemError(err)) return [];\n\t\tthrow err;\n\t}\n}\n\n/**\n * Find the most recently modified .jsonl in a session directory. Parity with\n * discoverSessionFile in @dreb/coding-agent's subagent tool. Normal subagents\n * write directly under sessionDir; chain-mode subagents register the chain root\n * but write per-step logs under step-N/ subdirectories.\n */\nexport function discoverSubagentSessionFile(sessionDir: string): string | undefined {\n\ttry {\n\t\tif (!existsSync(sessionDir)) return undefined;\n\t\tconst flatFile = findNewestJsonlFileInDir(sessionDir);\n\t\tif (flatFile) return flatFile.path;\n\n\t\tlet best: SessionFileCandidate | undefined;\n\t\tfor (const file of discoverStepSessionFileCandidates(sessionDir)) {\n\t\t\tif (!best || file.mtime > best.mtime) best = file;\n\t\t}\n\t\treturn best?.path;\n\t} catch (err) {\n\t\tif (isExpectedFilesystemError(err)) return undefined;\n\t\tthrow err;\n\t}\n}\n\nfunction readMessagesFromFile(file: string): unknown[] {\n\tconst messages: unknown[] = [];\n\tfor (const line of readFileSync(file, \"utf8\").split(\"\\n\")) {\n\t\tif (!line.trim()) continue;\n\t\ttry {\n\t\t\tconst entry = JSON.parse(line);\n\t\t\tif (isRecord(entry) && entry.type === \"message\" && entry.message) messages.push(entry.message);\n\t\t} catch (err) {\n\t\t\tif (err instanceof SyntaxError) continue;\n\t\t\tthrow err;\n\t\t}\n\t}\n\treturn messages;\n}\n\nfunction discoverMessageFiles(source: SubagentLogSource): string[] {\n\tconst stepFiles = source.sessionDir ? discoverSubagentStepSessionFiles(source.sessionDir) : [];\n\tif (stepFiles.length > 0) return stepFiles;\n\tif (source.sessionFile) return existsSync(source.sessionFile) ? [source.sessionFile] : [];\n\tconst file = source.sessionDir ? discoverSubagentSessionFile(source.sessionDir) : undefined;\n\treturn file ? [file] : [];\n}\n\n/**\n * Read the message payloads from a subagent session log.\n *\n * Subagent sessions are single-shot and linear (no branching/compaction), so\n * a straight scan of `type: \"message\"` entries reconstructs the transcript.\n * Chain-mode subagents write one linear log per step; those step logs are\n * concatenated in numeric step order. Malformed lines are skipped (the tail\n * line can be mid-write).\n *\n * @throws when no session file can be located — callers surface this loudly.\n */\nexport function readSubagentMessages(source: SubagentLogSource): unknown[] {\n\tconst files = discoverMessageFiles(source);\n\tif (files.length === 0) {\n\t\tthrow new Error(\"No session log found for this agent — it may not have produced output yet\");\n\t}\n\treturn files.flatMap((file) => readMessagesFromFile(file));\n}\n"]}
@@ -0,0 +1,261 @@
1
+ /**
2
+ * Wire types shared between the dashboard server and the browser client.
3
+ *
4
+ * These are standalone definitions (not imports from @dreb/coding-agent) so the
5
+ * client bundle stays free of node-flavored type resolution. Server code maps
6
+ * RPC DTOs onto these shapes; TypeScript structural typing enforces
7
+ * compatibility at the mapping sites.
8
+ */
9
+ /** Session metadata (mirrors RpcSessionInfo). */
10
+ export interface SessionInfoDto {
11
+ path: string;
12
+ id: string;
13
+ cwd: string;
14
+ name?: string;
15
+ created: string;
16
+ modified: string;
17
+ messageCount: number;
18
+ firstMessage: string;
19
+ }
20
+ /** Background agent metadata (mirrors RpcBackgroundAgentInfo). */
21
+ export interface BackgroundAgentDto {
22
+ agentId: string;
23
+ agentType: string;
24
+ taskSummary: string;
25
+ startedAt: string;
26
+ status: "running" | "completed" | "failed";
27
+ sessionDir?: string;
28
+ sessionFile?: string;
29
+ cwd?: string;
30
+ }
31
+ /**
32
+ * Shared eviction cap for completed/failed background agents. The server
33
+ * prunes its registry to this bound and the client applies the same cap as
34
+ * defense-in-depth — the two sides must agree on how many completed agents
35
+ * survive, so the constant lives here.
36
+ */
37
+ export declare const MAX_COMPLETED_BACKGROUND_AGENTS = 20;
38
+ /** Maximum JSON prompt request body accepted by the dashboard server. */
39
+ export declare const MAX_PROMPT_BODY_BYTES: number;
40
+ /**
41
+ * Inline images are base64-encoded inside the JSON prompt body. Base64 expands
42
+ * raw bytes by 4/3, so a 25 MiB body can carry at most floor(25 MiB * 3/4) =
43
+ * 18.75 MiB of raw image data before JSON syntax and prompt text. Reserve the
44
+ * remaining 0.75 MiB for that overhead and advertise an 18 MiB aggregate raw
45
+ * image budget to the browser.
46
+ */
47
+ export declare const MAX_TOTAL_IMAGE_BYTES: number;
48
+ /** Context usage (mirrors ContextUsage — the numbers the TUI footer shows). */
49
+ export interface ContextUsageDto {
50
+ tokens: number | null;
51
+ contextWindow: number;
52
+ percent: number | null;
53
+ }
54
+ export interface ScopedModelDto {
55
+ provider: string;
56
+ id: string;
57
+ name?: string;
58
+ reasoning?: boolean;
59
+ thinkingLevel?: string;
60
+ }
61
+ export interface SessionStatsDto {
62
+ sessionFile?: string;
63
+ sessionId: string;
64
+ userMessages: number;
65
+ assistantMessages: number;
66
+ toolCalls: number;
67
+ toolResults: number;
68
+ totalMessages: number;
69
+ tokens: {
70
+ input: number;
71
+ output: number;
72
+ cacheRead: number;
73
+ cacheWrite: number;
74
+ total: number;
75
+ };
76
+ cost: number;
77
+ contextUsage?: ContextUsageDto;
78
+ }
79
+ export interface PerformanceStatsDto {
80
+ models: Array<{
81
+ provider: string;
82
+ modelId: string;
83
+ median: number;
84
+ mean: number;
85
+ count: number;
86
+ }>;
87
+ }
88
+ export interface ResourcesDto {
89
+ contextFiles: Array<{
90
+ path: string;
91
+ }>;
92
+ skills: Array<{
93
+ name: string;
94
+ description: string;
95
+ }>;
96
+ extensions: Array<{
97
+ name?: string;
98
+ path: string;
99
+ }>;
100
+ promptTemplates: Array<{
101
+ name: string;
102
+ description?: string;
103
+ }>;
104
+ systemPromptPresent: boolean;
105
+ }
106
+ export interface ImageAttachmentDto {
107
+ data: string;
108
+ mimeType: string;
109
+ }
110
+ export interface QueuedMessageDto {
111
+ text: string;
112
+ images?: ImageAttachmentDto[];
113
+ }
114
+ export interface PendingMessagesDto {
115
+ /** Text-only compatibility view. */
116
+ steering: string[];
117
+ /** Text-only compatibility view. */
118
+ followUp: string[];
119
+ /** Full queued payloads, including inline image attachments. */
120
+ steeringMessages?: QueuedMessageDto[];
121
+ /** Full queued payloads, including inline image attachments. */
122
+ followUpMessages?: QueuedMessageDto[];
123
+ }
124
+ export interface CommandDto {
125
+ name: string;
126
+ description?: string;
127
+ source: "extension" | "prompt" | "skill";
128
+ }
129
+ export interface RuntimeStatsSummaryDto {
130
+ tokensTotal: number;
131
+ cost: number;
132
+ }
133
+ /** Live session state (mirrors RpcSessionState, model reduced to id fields). */
134
+ export interface SessionStateDto {
135
+ model?: {
136
+ provider: string;
137
+ id: string;
138
+ name?: string;
139
+ reasoning?: boolean;
140
+ };
141
+ scopedModels?: ScopedModelDto[];
142
+ usingSubscription?: boolean;
143
+ thinkingLevel: string;
144
+ isStreaming: boolean;
145
+ isCompacting: boolean;
146
+ steeringMode: "all" | "one-at-a-time";
147
+ followUpMode: "all" | "one-at-a-time";
148
+ sessionFile?: string;
149
+ sessionId: string;
150
+ sessionName?: string;
151
+ autoCompactionEnabled: boolean;
152
+ messageCount: number;
153
+ pendingMessageCount: number;
154
+ contextUsage?: ContextUsageDto;
155
+ modelFallbackMessage?: string;
156
+ }
157
+ /** A live runtime managed by the dashboard server's pool. */
158
+ export interface RuntimeInfoDto {
159
+ /** Pool key — stable identity for API calls and SSE envelopes. */
160
+ key: string;
161
+ cwd: string;
162
+ state: SessionStateDto;
163
+ /** Lean session stats for fleet cards; omitted when the runtime stats call fails. */
164
+ stats?: RuntimeStatsSummaryDto;
165
+ /** Background agents known to this runtime. */
166
+ backgroundAgents: BackgroundAgentDto[];
167
+ /** Server-derived needs-attention flag (extension UI pending, paused, error). */
168
+ needsAttention: boolean;
169
+ /** Runtime-level error that should survive browser reloads. */
170
+ error?: string;
171
+ /** Last assistant text, truncated for fleet-card previews. */
172
+ lastAssistantText?: string;
173
+ /** Session start timestamp (ISO) — stable tiebreak for deterministic fleet ordering. */
174
+ createdAt: string;
175
+ /** Last activity timestamp (ISO). */
176
+ lastActivity: string;
177
+ }
178
+ /** Fleet snapshot: live runtimes + on-disk inventory. */
179
+ export interface FleetDto {
180
+ runtimes: RuntimeInfoDto[];
181
+ diskSessions: SessionInfoDto[];
182
+ }
183
+ /**
184
+ * SSE envelope. Every event on the dashboard stream wraps a session event with
185
+ * the runtime key it came from plus a monotonically increasing sequence number
186
+ * used for Last-Event-ID catch-up on reconnect.
187
+ */
188
+ export interface EventEnvelope {
189
+ seq: number;
190
+ key: string;
191
+ /** An AgentSessionEvent (or dashboard-synthesized event) as emitted by the runtime. */
192
+ event: Record<string, unknown>;
193
+ }
194
+ /** File listing entry. */
195
+ export interface FileEntryDto {
196
+ name: string;
197
+ type: "file" | "dir" | "symlink" | "other";
198
+ size: number;
199
+ modified: string;
200
+ }
201
+ /** Directory listing response. */
202
+ export interface DirListingDto {
203
+ /** Canonicalized absolute path of the listed directory. */
204
+ path: string;
205
+ entries: FileEntryDto[];
206
+ }
207
+ /** Auth mode reported to the client. */
208
+ export interface AuthStatusDto {
209
+ mode: "local" | "remote";
210
+ /** Identity string for remote devices (e.g. Tailscale login name). */
211
+ identity?: string;
212
+ device?: string;
213
+ }
214
+ /** Current rotating pairing code, readable only from the host/local dashboard. */
215
+ export interface PairingCodeDto {
216
+ enabled: boolean;
217
+ code?: string;
218
+ expiresInMs?: number;
219
+ }
220
+ /** A paired device (settings → devices). */
221
+ export interface PairedDeviceDto {
222
+ id: string;
223
+ identity: string;
224
+ device?: string;
225
+ createdAt: string;
226
+ expiresAt: string;
227
+ }
228
+ /** Dashboard settings snapshot (mirrors RpcSettingsSnapshot). */
229
+ export interface SettingsDto {
230
+ defaultProvider?: string;
231
+ defaultModel?: string;
232
+ defaultThinkingLevel?: string;
233
+ steeringMode?: "all" | "one-at-a-time";
234
+ followUpMode?: "all" | "one-at-a-time";
235
+ compactionEnabled?: boolean;
236
+ retryEnabled?: boolean;
237
+ imageAutoResize?: boolean;
238
+ blockImages?: boolean;
239
+ enableSkillCommands?: boolean;
240
+ autoLoadNestedContext?: boolean;
241
+ transport?: "sse" | "websocket" | "auto";
242
+ hideThinkingBlock?: boolean;
243
+ agentModels?: Record<string, string[]>;
244
+ }
245
+ export type SettingsSaveResultDto = SettingsDto & {
246
+ warnings?: string[];
247
+ };
248
+ /** Available model entry (mirrors ModelInfo). */
249
+ export interface ModelInfoDto {
250
+ provider: string;
251
+ id: string;
252
+ name: string;
253
+ contextWindow: number;
254
+ reasoning: boolean;
255
+ }
256
+ /** Agent definition metadata (mirrors RpcAgentTypeInfo). */
257
+ export interface AgentTypeDto {
258
+ name: string;
259
+ description: string;
260
+ }
261
+ //# sourceMappingURL=protocol.d.ts.map