@wrongstack/cli 0.296.2 → 0.296.4
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/boot/dispatch-webui.d.ts +1 -0
- package/dist/boot/dispatch-webui.d.ts.map +1 -1
- package/dist/boot/tui-session-resume.d.ts.map +1 -1
- package/dist/{chunk-IN4GXGYW.js → chunk-BQCAJ7FI.js} +2 -2
- package/dist/{chunk-IN4GXGYW.js.map → chunk-BQCAJ7FI.js.map} +2 -2
- package/dist/{chunk-X5DQTPXT.js → chunk-OI7GWJDS.js} +1048 -804
- package/dist/chunk-OI7GWJDS.js.map +7 -0
- package/dist/{cli-main-6AU6E4XZ.js → cli-main-TOAWVJDY.js} +197 -60
- package/dist/cli-main-TOAWVJDY.js.map +7 -0
- package/dist/cli-main-helpers.d.ts +1 -1
- package/dist/cli-main-helpers.d.ts.map +1 -1
- package/dist/cli-main.d.ts.map +1 -1
- package/dist/execute-deps.d.ts +1 -0
- package/dist/execute-deps.d.ts.map +1 -1
- package/dist/{execution-V26SE52F.js → execution-O7I5DYE6.js} +34 -8
- package/dist/execution-O7I5DYE6.js.map +7 -0
- package/dist/execution-storage-observability.d.ts.map +1 -1
- package/dist/execution.d.ts.map +1 -1
- package/dist/fleet/host-subagent-factory.d.ts.map +1 -1
- package/dist/{hq-BECGICEZ.js → hq-JUYKUNJX.js} +2 -2
- package/dist/hq-server/auth.d.ts +15 -4
- package/dist/hq-server/auth.d.ts.map +1 -1
- package/dist/hq-server/routes/auth-handlers.d.ts +6 -13
- package/dist/hq-server/routes/auth-handlers.d.ts.map +1 -1
- package/dist/hq-server/routes.d.ts +6 -4
- package/dist/hq-server/routes.d.ts.map +1 -1
- package/dist/hq-server/snapshot.d.ts +44 -0
- package/dist/hq-server/snapshot.d.ts.map +1 -1
- package/dist/hq-server/types.d.ts +22 -4
- package/dist/hq-server/types.d.ts.map +1 -1
- package/dist/hq-server/utils.d.ts +8 -0
- package/dist/hq-server/utils.d.ts.map +1 -1
- package/dist/hq-server/ws.d.ts +1 -1
- package/dist/hq-server/ws.d.ts.map +1 -1
- package/dist/{hq-server-FJOVOERO.js → hq-server-6AQ3BXZA.js} +2 -2
- package/dist/hq-server.d.ts +3 -3
- package/dist/hq-server.d.ts.map +1 -1
- package/dist/{hq-tunnel-YZLRONPV.js → hq-tunnel-RFKGC4HI.js} +8 -5
- package/dist/{hq-tunnel-YZLRONPV.js.map → hq-tunnel-RFKGC4HI.js.map} +2 -2
- package/dist/hq-tunnel.d.ts +1 -1
- package/dist/hq-tunnel.d.ts.map +1 -1
- package/dist/index.js +5 -5
- package/dist/{sdd-runtime-IKPROVV2.js → sdd-runtime-JG4EEKL6.js} +2 -2
- package/dist/services/sdd/task-manager.d.ts.map +1 -1
- package/dist/slash-commands/settings.d.ts.map +1 -1
- package/dist/{webui-server-G3TISUIY.js → webui-server-ZF5KVGC5.js} +3 -2
- package/dist/webui-server-ZF5KVGC5.js.map +7 -0
- package/dist/webui-server-options.d.ts +2 -0
- package/dist/webui-server-options.d.ts.map +1 -1
- package/dist/webui-server.d.ts.map +1 -1
- package/dist/wiring/sage.d.ts.map +1 -1
- package/dist/wiring/session.d.ts +3 -1
- package/dist/wiring/session.d.ts.map +1 -1
- package/package.json +22 -22
- package/dist/chunk-X5DQTPXT.js.map +0 -7
- package/dist/cli-main-6AU6E4XZ.js.map +0 -7
- package/dist/execution-V26SE52F.js.map +0 -7
- package/dist/webui-server-G3TISUIY.js.map +0 -7
- /package/dist/{hq-BECGICEZ.js.map → hq-JUYKUNJX.js.map} +0 -0
- /package/dist/{hq-server-FJOVOERO.js.map → hq-server-6AQ3BXZA.js.map} +0 -0
- /package/dist/{sdd-runtime-IKPROVV2.js.map → sdd-runtime-JG4EEKL6.js.map} +0 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/hq-server.ts", "../src/hq-recovery-html.ts", "../src/hq-server/auth.ts", "../src/hq-server/auth-state.ts", "../src/hq-server/preflight.ts", "../src/hq-server/routes.ts", "../src/hq-static-serve.ts", "../src/hq-server/snapshot.ts", "../src/hq-server/utils.ts", "../src/hq-server/trust-boundary.ts", "../src/hq-server/routes/auth-handlers.ts", "../src/hq-server/routes/system-handlers.ts", "../src/hq-server/routes/session-handlers.ts", "../src/hq-server/project-root.ts", "../src/hq-server/startup.ts", "../src/hq-server/ws.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * HQ server \u2014 the read-only command-center backend for `wstack --hq`.\n *\n * Single HTTP server, single port. Two WebSocket upgrade paths:\n * /ws/client \u2014 TUI/REPL/WebUI clients publish telemetry\n * /ws/browser \u2014 HQ browser connects and receives snapshot + events\n *\n * @module hq-server\n */\n\nimport { randomUUID } from 'node:crypto';\nimport * as fs from 'node:fs/promises';\nimport type { Server as HttpServer } from 'node:http';\nimport * as http from 'node:http';\nimport * as path from 'node:path';\nimport {\n createMailboxHttpRouter,\n createProjectMailbox,\n getSharedProjectMailbox,\n MAILBOX_HTTP_DEFAULT_MAX_AGE_MS,\n MailboxEventEmitter,\n type MailboxHttpAccessDecision,\n MailboxHttpRateLimiter,\n} from '@wrongstack/core/coordination';\nimport {\n createHqPersistence,\n type EnsureHqFirstRunAuthResult,\n type HqAlert,\n HqAlertEngine,\n type HqAlertRuleConfig,\n type HqCommandAuditEntry,\n HqCommandAuditLog,\n type HqEventEnvelope,\n type HqTranscriptEntry,\n HqBootstrapCodeStore,\n mintHqCookieSecret,\n mutateHqAuthFile,\n toAlertMessage,\n watchHqAuthFile,\n} from '@wrongstack/core/hq';\nimport { createCompatibilityTrustBoundary, type TrustBoundary } from '@wrongstack/core/security';\nimport { WebSocket, WebSocketServer } from 'ws';\nimport { HQ_HTML } from './hq-recovery-html.js';\nimport * as HqServerAuth from './hq-server/auth.js';\nimport { createHqAuthState } from './hq-server/auth-state.js';\nimport { prepareHqServerStart } from './hq-server/preflight.js';\nimport {\n agentMessageToEntry,\n agentRingKey,\n authenticateBrowserRequest,\n buildClientWsUrl,\n buildBootstrapHttpUrl,\n buildHttpUrl,\n createHqRouter,\n decodePathSegment,\n HQ_SESSION_COOKIE,\n type HqRouterDeps,\n type HqRouterMailboxGateway,\n hasTrustedBrowserOrigin,\n isCookieAuth,\n isTokenAuth,\n parseCookieHeader,\n parseHqSessionCookie,\n readLocalSubagentTranscript,\n sanitizeApiError,\n} from './hq-server/routes.js';\nimport * as HqServerSnapshot from './hq-server/snapshot.js';\nimport {\n clearHqRuntimeMarker,\n writeHqRuntimeMarker,\n writeHqStartupInfo,\n} from './hq-server/startup.js';\nimport type { ConnectedClient, HqSessionEntry, TranscriptRing } from './hq-server/types.js';\nimport * as HqServerWs from './hq-server/ws.js';\n\nexport { HqInsecureExposureError } from '@wrongstack/core/hq';\nexport type { ConnectedClient, TranscriptRing };\n\n// \u2500\u2500 Re-exports for backward compatibility \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport { HQ_HTML };\nexport const DEFAULT_HOST = '127.0.0.1';\nexport const DEFAULT_PORT = 3499;\nexport const MAX_EVENT_LOG = 5000;\nexport const MAX_NON_STRICT_PORT_SCAN = 50;\nexport const CLIENT_TTL_MS = 60_000;\nexport const CLIENT_CLEANUP_INTERVAL_MS = 30_000;\nexport const BROWSER_HEARTBEAT_INTERVAL_MS = 15_000;\nexport const SESSION_SNAPSHOT_TTL_MS = 30_000;\n\nexport {\n agentMessageToEntry,\n agentRingKey,\n decodePathSegment,\n readLocalSubagentTranscript,\n sanitizeApiError,\n};\n\n// \u2500\u2500 Public interfaces \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface HqServerOptions {\n /** Policy authority for control-plane command enqueue decisions. */\n trustBoundary?: TrustBoundary | undefined;\n host?: string;\n port?: number;\n strictPort?: boolean;\n exactPort?: boolean;\n dataDir?: string;\n browserHeartbeatIntervalMs?: number;\n clientTtlMs?: number;\n clientCleanupIntervalMs?: number;\n sessionSnapshotTtlMs?: number;\n password?: string;\n allowInsecureOpen?: boolean;\n secureCookies?: boolean;\n requireBrowserAuth?: boolean;\n /**\n * Optional time-to-live (milliseconds) stamped on the first-run browser\n * and client tokens minted on a brand-new HQ data directory. Existing\n * auth.json files are not modified. When set, tokens carry an `expiresAt`\n * and the server refuses them past that timestamp; default is no expiry.\n *\n * Useful for short-lived deployments (CI, ephemeral relays) where a leaked\n * first-run token should not outlive the deployment window. Set via the\n * `--hq-token-ttl-ms` CLI flag.\n */\n tokenTtlMs?: number;\n}\n\nexport interface HqStartupConnectionInfo {\n dataDir: string;\n browserUrl: string;\n clientUrl: string;\n clientEnv: {\n WRONGSTACK_HQ_URL: string;\n WRONGSTACK_HQ_TOKEN?: string;\n };\n createdAuth: boolean;\n browserTokenMode: boolean;\n passwordMode: boolean;\n}\n\nexport type HqFirstRunSetup = HqStartupConnectionInfo;\n\nexport interface HqServerHandle {\n host: string;\n port: number;\n firstRunSetup?: HqFirstRunSetup;\n trustPublicOrigin(origin: string): void;\n close(): Promise<void>;\n}\n\n// \u2500\u2500 Server entry points \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport async function startHqServer(options: HqServerOptions = {}): Promise<HqServerHandle> {\n const { host, port, dataDir, firstRunAuth } = await prepareHqServerStart(options, {\n host: DEFAULT_HOST,\n port: DEFAULT_PORT,\n });\n return startHqServerWithAuth(options, host, port, dataDir, firstRunAuth);\n}\n\nasync function startHqServerWithAuth(\n options: HqServerOptions,\n host: string,\n port: number,\n dataDir: string,\n firstRunAuth: EnsureHqFirstRunAuthResult,\n): Promise<HqServerHandle> {\n const trustBoundary =\n options.trustBoundary ??\n createCompatibilityTrustBoundary({ policyId: 'hq-trusted-host-compat-v1' });\n const authFile = firstRunAuth.authFile;\n\n const authState = createHqAuthState(authFile, dataDir);\n const { mutableAuth } = authState;\n\n // Provision a cookie-signing secret for token-only mode so bootstrap\n // exchange can produce signed session cookies without a password.\n if (!mutableAuth.cookieSecret && mutableAuth.browserTokens.size > 0) {\n const secret = mintHqCookieSecret();\n const next = await mutateHqAuthFile(dataDir, (current) => ({\n ...current,\n cookieSecret: secret,\n }));\n mutableAuth.cookieSecret = next.cookieSecret;\n console.warn(\n JSON.stringify({\n level: 'info',\n event: 'hq.cookie_secret_provisioned',\n message: 'Cookie signing secret provisioned for token-mode bootstrap exchange.',\n timestamp: new Date().toISOString(),\n }),\n );\n }\n\n // Bootstrap code store for one-time token-to-cookie exchange.\n const bootstrapStore = new HqBootstrapCodeStore();\n\n console.warn(\n JSON.stringify({\n level: 'info',\n event: 'hq.startup',\n message: 'WrongStack HQ starting',\n dataDir,\n host,\n port,\n operatorPolicyActive: authFile.redactionPolicy !== undefined,\n browserTokenMode: mutableAuth.browserTokens.size > 0,\n clientTokenMode: mutableAuth.clientTokens.size > 0,\n passwordMode: mutableAuth.passwordHash !== undefined,\n timestamp: new Date().toISOString(),\n }),\n );\n\n return new Promise((resolve, reject) => {\n const trustedPublicOrigins = new Set<string>();\n let listeningPort = port;\n const clients = new Map<WebSocket, ConnectedClient>();\n const browsers = new Set<WebSocket>();\n const sessions = new Map<string, HqSessionEntry>();\n const eventLog: HqEventEnvelope[] = [];\n const transcripts = new Map<string, TranscriptRing>();\n const agentMessages = new Map<string, HqTranscriptEntry[]>();\n const mailboxGateways = new Map<string, HqRouterMailboxGateway>();\n const mailboxGatewayRateLimiter = new MailboxHttpRateLimiter();\n const mailboxGatewayRateLimitCleanup = setInterval(\n () => mailboxGatewayRateLimiter.cleanup(),\n 120_000,\n );\n mailboxGatewayRateLimitCleanup.unref?.();\n\n // \u2500\u2500 Login rate limiting \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const loginAttempts = new Map<\n string,\n { count: number; blockedUntil: number; lastAttempt: number }\n >();\n const LOGIN_ATTEMPT_RETENTION_MS = 15 * 60_000;\n\n // \u2500\u2500 Browser-session lifecycle \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const HQ_SESSION_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000;\n const SESSION_CLEANUP_INTERVAL_MS = 60_000;\n const sessionCleanupTimer = setInterval(() => {\n const cutoff = Date.now() - HQ_SESSION_MAX_AGE_MS;\n for (const [id, session] of sessions) {\n if (session.createdAt < cutoff) sessions.delete(id);\n }\n const now = Date.now();\n for (const [ip, entry] of loginAttempts) {\n if (now - entry.lastAttempt > LOGIN_ATTEMPT_RETENTION_MS) loginAttempts.delete(ip);\n }\n }, SESSION_CLEANUP_INTERVAL_MS);\n sessionCleanupTimer.unref?.();\n\n // \u2500\u2500 Persistence \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const persistence = createHqPersistence(dataDir);\n const auditLog = new HqCommandAuditLog(1000, (entry) => persistence.commandLog.append(entry));\n\n // One-shot startup housekeeping: purge stale client registrations from\n // every known project's mailbox.\n //\n // Each `getSharedProjectMailbox` here *starts* that project's mailbox\n // daemon if it isn't already running, and the shared wrapper keeps its IPC\n // connection open for the life of this process. Leaving them open pinned\n // every daemon alive permanently: `mailbox-project-server`'s idle-stop is\n // gated on `clients.size === 0`, so one lingering connection per project\n // defeats it. Measured on a machine with 165 project directories: 165\n // resident daemons at ~63 MB each, ~10.4 GB, none of which had ever served\n // a request after this sweep. Closing each mailbox releases the connection\n // so idle daemons shut themselves down on their own 5-minute timer.\n void (async () => {\n const projectsDir = path.join(path.dirname(dataDir), 'projects');\n const entries = await fs.readdir(projectsDir, { withFileTypes: true }).catch(() => []);\n await Promise.all(\n entries\n .filter((entry) => entry.isDirectory())\n .map(async (entry) => {\n const projectDir = path.join(projectsDir, entry.name);\n // Sweep only projects whose daemon is actually running.\n //\n // `getSharedProjectMailbox` *starts* a daemon when none is live,\n // so an unconditional sweep turns HQ startup into one spawn per\n // project directory \u2014 measured at 165 on a real machine. Metadata\n // presence alone is not enough of a filter either: a daemon that\n // was killed rather than stopped leaves its file behind, and 163\n // of those 165 were exactly that.\n //\n // A dead owner has no clients to purge (its registrations died\n // with it), so skipping costs nothing; clear the orphaned file\n // while we are here so it stops advertising a daemon that is gone.\n const metadataPath = path.join(projectDir, '.mailbox-server.json');\n const ownerPid = await fs\n .readFile(metadataPath, 'utf8')\n .then((raw) => (JSON.parse(raw) as { pid?: number }).pid)\n .catch(() => undefined);\n if (ownerPid === undefined) return;\n let ownerAlive = false;\n try {\n process.kill(ownerPid, 0);\n ownerAlive = true;\n } catch {\n ownerAlive = false;\n }\n if (!ownerAlive) {\n await fs.rm(metadataPath, { force: true }).catch(() => {});\n return;\n }\n const mailbox = getSharedProjectMailbox(projectDir);\n try {\n await Promise.all([mailbox.getAgentStatuses(), mailbox.purgeClients()]);\n } finally {\n await mailbox.close().catch(() => {});\n }\n }),\n );\n })().catch(() => {});\n const hqSessionTag = randomUUID().slice(0, 8);\n\n const authorizeMailboxGateway = (\n req: http.IncomingMessage,\n projectDir: string,\n ): MailboxHttpAccessDecision => {\n const requestUrl = new URL(req.url ?? '/', `http://${host}:${port}`);\n const auth = authenticateBrowserRequest(req, requestUrl, mutableAuth, sessions);\n const tokenMode = mutableAuth.browserTokens.size > 0;\n const passwordMode = mutableAuth.passwordHash !== undefined;\n if ((tokenMode || passwordMode) && auth === undefined) {\n return {\n allowed: false,\n status: 401,\n body: { error: { code: 'UNAUTHORIZED', message: 'unauthorized' } },\n };\n }\n const token = isTokenAuth(auth) ? mutableAuth.browserTokenObjs.get(auth.token) : undefined;\n const canUseMailbox = isCookieAuth(auth)\n ? auth.capabilities === undefined || auth.capabilities.includes('control.enqueue')\n : isTokenAuth(auth)\n ? token?.capabilities === undefined || !!token?.capabilities.includes('control.enqueue')\n : !tokenMode;\n if (!canUseMailbox) {\n return {\n allowed: false,\n status: 403,\n body: {\n error: {\n code: 'FORBIDDEN',\n message: 'forbidden: token lacks control.enqueue capability',\n },\n },\n };\n }\n const identity = isTokenAuth(auth) ? auth.id : isCookieAuth(auth) ? 'cookie' : 'open';\n return { allowed: true, rateLimitKey: `hq:${identity}:${projectDir}` };\n };\n\n const getMailboxGateway = (projectDir: string): HqRouterMailboxGateway => {\n const existing = mailboxGateways.get(projectDir);\n if (existing) return existing;\n const eventEmitter = new MailboxEventEmitter();\n const mailbox = createProjectMailbox({ projectDir, eventEmitter });\n const router = createMailboxHttpRouter({\n mailbox,\n eventEmitter,\n rateLimiter: mailboxGatewayRateLimiter,\n authorize: (request) => authorizeMailboxGateway(request, projectDir),\n // Wire the 1h look-back that the router's docs promise at\n // mailbox-http-router.ts:25-32 / :47-62. The router itself is\n // opt-in (L146-152): without this option, every retained\n // message would be returned. Per-request opt-in to the full\n // history remains available via `?sinceMs=0`.\n defaultMaxAgeMs: MAILBOX_HTTP_DEFAULT_MAX_AGE_MS,\n });\n const gateway = { mailbox, router };\n mailboxGateways.set(projectDir, gateway);\n return gateway;\n };\n\n // \u2500\u2500 Alerting \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const alertEngine = new HqAlertEngine({\n onAlert: (alert) => {\n const msg = toAlertMessage(alert);\n const data = JSON.stringify(msg);\n for (const ws of browsers) {\n if (ws.readyState === WebSocket.OPEN) ws.send(data);\n }\n },\n onPersist: (alert) => persistence.alertLog.append(alert),\n });\n void persistence.eventLog.hydrate().catch(() => undefined);\n void persistence.timeseries.load().catch(() => undefined);\n persistence.eventLog\n .recent(MAX_EVENT_LOG)\n .then((prior) => {\n for (let i = prior.length - 1; i >= 0; i--) eventLog.push(prior[i]!);\n })\n .catch(() => {});\n persistence.alertLog\n .readAll()\n .then((prior) => {\n alertEngine.seed(prior as readonly HqAlert[]);\n })\n .catch(() => {});\n persistence.commandLog\n .readAll()\n .then((prior) => {\n auditLog.seed(prior as readonly HqCommandAuditEntry[]);\n })\n .catch(() => {});\n\n const timeseriesFlushTimer = setInterval(() => {\n persistence.timeseries.flush();\n }, 60_000);\n timeseriesFlushTimer.unref?.();\n\n const snapshotBroadcaster = HqServerSnapshot.createSnapshotBroadcaster(\n clients,\n browsers,\n persistence,\n );\n snapshotBroadcaster.currentSerialized();\n\n const stopAlertEngine = alertEngine.startPeriodic(\n () => HqServerSnapshot.buildSnapshot(clients, { tokenStats: authState.tokenStats() }),\n (): HqAlertRuleConfig | undefined => mutableAuth.alertRules,\n );\n\n // \u2500\u2500 Stale client cleanup \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const clientTtlMs = options.clientTtlMs ?? CLIENT_TTL_MS;\n const sessionSnapshotTtlMs = options.sessionSnapshotTtlMs ?? SESSION_SNAPSHOT_TTL_MS;\n const cleanupTimer = setInterval(() => {\n const cutoff = Date.now() - clientTtlMs;\n const sessionCutoff = Date.now() - sessionSnapshotTtlMs;\n let changed = false;\n for (const [ws, client] of clients.entries()) {\n if (new Date(client.lastSeenAt).getTime() < cutoff) {\n ws.terminate();\n clients.delete(ws);\n changed = true;\n continue;\n }\n const expiredSessions = new Set<string>();\n for (const [sessionId, tracked] of client.sessions.entries()) {\n if (tracked.receivedAt < sessionCutoff) {\n client.sessions.delete(sessionId);\n client.mcpSnapshots.delete(sessionId);\n expiredSessions.add(sessionId);\n changed = true;\n }\n }\n for (const [runId, fleet] of client.fleets) {\n if (fleet.sessionId !== undefined && expiredSessions.has(fleet.sessionId)) {\n client.fleets.delete(runId);\n changed = true;\n }\n }\n if (\n client.capabilities.includes('session.summary') &&\n client.sessions.size === 0 &&\n Date.now() - Date.parse(client.connectedAt) > sessionSnapshotTtlMs\n ) {\n ws.terminate();\n clients.delete(ws);\n changed = true;\n }\n }\n if (changed) snapshotBroadcaster.broadcast();\n }, options.clientCleanupIntervalMs ?? CLIENT_CLEANUP_INTERVAL_MS);\n // Match sibling timers (sessionCleanup/timeseriesFlush/browserHeartbeat): do\n // not keep the Node event loop alive purely for the stale-client sweep.\n cleanupTimer.unref?.();\n\n // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n // HTTP server with extracted route handlers\n // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n const routerDeps: HqRouterDeps = {\n trustBoundary,\n host,\n listeningPort,\n trustedPublicOrigins,\n mutableAuth,\n sessions,\n loginAttempts,\n clients,\n browsers,\n eventLog,\n transcripts,\n agentMessages,\n mailboxGateways,\n mailboxGatewayRateLimiter,\n alertEngine,\n auditLog,\n persistence,\n dataDir,\n hqSessionTag,\n requireBrowserAuth: options.requireBrowserAuth,\n secureCookies: options.secureCookies,\n authorizeMailboxGateway,\n getMailboxGateway,\n getTokenStats: () => authState.tokenStats(),\n bootstrapStore,\n };\n const handleRequest = createHqRouter(routerDeps);\n\n const httpServer: HttpServer = http.createServer((req, res) => {\n void handleRequest(req, res);\n });\n\n // \u2500\u2500 WebSocket \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const wss = new WebSocketServer({ noServer: true, maxPayload: 1 * 1024 * 1024 });\n\n const browserHeartbeatTimer = setInterval(() => {\n const heartbeat = JSON.stringify({\n type: 'hq.heartbeat',\n serverTime: new Date().toISOString(),\n });\n for (const browser of browsers) {\n if (browser.readyState === WebSocket.OPEN) browser.send(heartbeat);\n }\n }, options.browserHeartbeatIntervalMs ?? BROWSER_HEARTBEAT_INTERVAL_MS);\n browserHeartbeatTimer.unref?.();\n\n httpServer.on('upgrade', (req, socket, head) => {\n const url = new URL(req.url ?? '/', `http://${host}:${port}`);\n const pathname = url.pathname;\n\n if (pathname !== '/ws/client' && pathname !== '/ws/browser') {\n socket.destroy();\n return;\n }\n\n if (!hasTrustedBrowserOrigin(req, host, listeningPort, trustedPublicOrigins)) {\n socket.write(\n 'HTTP/1.1 403 Forbidden\\r\\nContent-Type: application/json\\r\\nConnection: close\\r\\n\\r\\n' +\n JSON.stringify({\n error: {\n code: 'INVALID_ORIGIN',\n message: 'Cross-origin WebSocket upgrade rejected.',\n },\n }),\n );\n socket.destroy();\n return;\n }\n\n const tokenSet =\n pathname === '/ws/browser' ? mutableAuth.browserTokens : mutableAuth.clientTokens;\n const needsAuth =\n pathname === '/ws/browser'\n ? options.requireBrowserAuth ||\n tokenSet.size > 0 ||\n mutableAuth.passwordHash !== undefined\n : tokenSet.size > 0;\n if (needsAuth) {\n const supplied = url.searchParams.get('token') ?? '';\n const tokenValid = HqServerAuth.timingSafeTokenMatch(tokenSet, supplied) !== undefined;\n const cookieValid =\n pathname === '/ws/browser' &&\n mutableAuth.cookieSecret !== undefined &&\n (() => {\n const cookies = parseCookieHeader(req.headers.cookie);\n const raw = cookies[HQ_SESSION_COOKIE];\n if (!raw) return false;\n const sessionId = parseHqSessionCookie(raw, mutableAuth.cookieSecret!);\n if (sessionId === undefined) return false;\n const session = sessions.get(sessionId);\n if (!session || Date.now() - session.createdAt >= HqServerAuth.HQ_SESSION_MAX_AGE_MS)\n return false;\n // For token-origin sessions, verify the source token is still live.\n if (session.kind === 'token' && session.tokenId !== undefined) {\n return [...mutableAuth.browserTokenObjs.values()].some(\n (obj) => obj.id === session.tokenId,\n );\n }\n return true;\n })();\n if (!tokenValid && !cookieValid) {\n socket.write(\n 'HTTP/1.1 401 Unauthorized\\r\\nContent-Type: application/json\\r\\nConnection: close\\r\\n\\r\\n' +\n JSON.stringify({\n error: {\n code: 'UNAUTHORIZED',\n message:\n pathname === '/ws/browser'\n ? 'A valid ?token= or password session is required for browser connections.'\n : 'A valid ?token= is required for client connections in token mode.',\n },\n }),\n );\n socket.destroy();\n return;\n }\n }\n\n wss.handleUpgrade(req, socket, head, (ws) => {\n wss.emit('connection', ws, req, pathname);\n });\n });\n\n wss.on('connection', (ws: WebSocket, req: http.IncomingMessage, pathname: string) => {\n if (pathname === '/ws/browser') {\n HqServerWs.handleBrowser(ws, snapshotBroadcaster, browsers);\n } else {\n const token = new URL(req.url ?? '/', `http://${host}:${port}`).searchParams.get('token');\n HqServerWs.handleClient(\n ws,\n clients,\n browsers,\n eventLog,\n {\n ...(token ? { token: mutableAuth.clientTokenObjs.get(token) } : {}),\n getOperatorPolicy: () => mutableAuth.operatorPolicyOverride,\n },\n snapshotBroadcaster,\n transcripts,\n agentMessages,\n persistence,\n auditLog,\n );\n }\n });\n\n // \u2500\u2500 Live auth.json reload \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const authWatcher = watchHqAuthFile(\n dataDir,\n (next) => {\n authState.apply(next);\n if (\n options.requireBrowserAuth &&\n mutableAuth.browserTokens.size === 0 &&\n mutableAuth.passwordHash === undefined\n ) {\n sessions.clear();\n for (const browser of browsers) browser.close(1008, 'Browser authentication removed');\n }\n console.warn(\n JSON.stringify({\n level: 'info',\n event: 'hq.auth.reloaded',\n message: 'HQ auth.json reloaded',\n browserTokenCount: mutableAuth.browserTokens.size,\n clientTokenCount: mutableAuth.clientTokens.size,\n passwordMode: mutableAuth.passwordHash !== undefined,\n alertRulesActive: mutableAuth.alertRules !== undefined,\n timestamp: new Date().toISOString(),\n }),\n );\n },\n {\n warn: (msg) =>\n console.warn(\n JSON.stringify({\n level: 'warn',\n event: 'hq.auth.reload_failed',\n message: msg,\n timestamp: new Date().toISOString(),\n }),\n ),\n },\n );\n\n // \u2500\u2500 Listen \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n let bindAttempts = 0;\n const listen = (nextPort: number): void => {\n httpServer.listen(nextPort, host);\n };\n const onError = (err: NodeJS.ErrnoException) => {\n if (\n err.code === 'EADDRINUSE' &&\n !options.strictPort &&\n !options.exactPort &&\n bindAttempts < MAX_NON_STRICT_PORT_SCAN\n ) {\n bindAttempts += 1;\n listen(port + bindAttempts);\n } else {\n authWatcher.close();\n snapshotBroadcaster.close();\n wss.close();\n reject(err);\n }\n };\n\n httpServer.on('error', onError);\n listen(port);\n httpServer.once('listening', () => {\n void (async () => {\n httpServer.removeListener('error', onError);\n const addr = httpServer.address();\n const actualPort = typeof addr === 'object' && addr ? addr.port : port;\n listeningPort = actualPort;\n\n const browserToken =\n firstRunAuth.browserToken?.token ??\n authFile.browserTokens?.find((t) => t.token.trim().length > 0)?.token;\n const clientToken =\n firstRunAuth.clientToken?.token ??\n authFile.clientTokens?.find((t) => t.token.trim().length > 0)?.token;\n const hqUrl = `http://${host === '0.0.0.0' ? '127.0.0.1' : host}:${actualPort}`;\n await writeHqRuntimeMarker(dataDir, hqUrl).catch(() => {});\n\n // Build the browser URL with a one-time bootstrap code (in the\n // fragment) when a browser token exists. The code is exchanged for\n // a session cookie on first load and never appears in HTTP traffic.\n const browserTokenObj = mutableAuth.browserTokenObjs.get(browserToken ?? '');\n let browserUrl: string;\n if (browserToken && browserTokenObj) {\n const code = bootstrapStore.issue({\n tokenId: browserTokenObj.id,\n ...(browserTokenObj.capabilities !== undefined\n ? { capabilities: browserTokenObj.capabilities }\n : {}),\n });\n browserUrl = buildBootstrapHttpUrl(host, actualPort, code);\n } else {\n browserUrl = buildHttpUrl(host, actualPort);\n }\n\n const startupInfo: HqStartupConnectionInfo = {\n dataDir,\n browserUrl,\n clientUrl: buildClientWsUrl(host, actualPort, clientToken),\n clientEnv: {\n WRONGSTACK_HQ_URL: hqUrl,\n ...(clientToken ? { WRONGSTACK_HQ_TOKEN: clientToken } : {}),\n },\n createdAuth: firstRunAuth.created,\n browserTokenMode: mutableAuth.browserTokens.size > 0,\n passwordMode: mutableAuth.passwordHash !== undefined,\n };\n\n let closed = false;\n const handle: HqServerHandle = {\n host,\n port: actualPort,\n firstRunSetup: startupInfo,\n trustPublicOrigin: (origin) => {\n const parsed = new URL(origin);\n if (parsed.protocol !== 'https:' || parsed.origin !== origin) {\n throw new TypeError(\n 'Trusted HQ public origin must be an exact HTTPS origin without a path.',\n );\n }\n trustedPublicOrigins.add(parsed.origin.toLowerCase());\n },\n close: () =>\n new Promise<void>((res) => {\n if (closed) {\n res();\n return;\n }\n closed = true;\n clearInterval(cleanupTimer);\n clearInterval(browserHeartbeatTimer);\n clearInterval(timeseriesFlushTimer);\n clearInterval(mailboxGatewayRateLimitCleanup);\n clearInterval(sessionCleanupTimer);\n stopAlertEngine();\n authWatcher.close();\n snapshotBroadcaster.close();\n bootstrapStore.clear();\n persistence.timeseries.flush();\n for (const ws of browsers) ws.close(1001, 'HQ shutting down');\n for (const ws of clients.keys()) ws.close(1001, 'HQ shutting down');\n wss.close();\n for (const { router } of mailboxGateways.values()) router.close();\n httpServer.close(() => {\n const mailboxCloses = [...mailboxGateways.values()].map(({ mailbox }) =>\n mailbox.close().catch(() => undefined),\n );\n mailboxGateways.clear();\n void Promise.all([\n ...mailboxCloses,\n persistence.eventLog.drain(),\n persistence.snapshotStore.drain(),\n persistence.timeseries.drain(),\n persistence.kanban.drain(),\n ])\n .then(() => clearHqRuntimeMarker(dataDir, hqUrl))\n .catch(() => undefined)\n .finally(() => res());\n });\n }),\n };\n\n writeHqStartupInfo((line) => console.log(line.trimEnd()), {\n host,\n port: actualPort,\n firstRunSetup: startupInfo,\n });\n resolve(handle);\n })();\n });\n });\n}\n", "/**\n * Minimal diagnostic page used only when the packaged HQ SPA assets cannot be found.\n * It intentionally contains no telemetry UI or control-plane implementation.\n */\nexport const HQ_RECOVERY_HTML = `<!doctype html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n <title>WrongStack HQ \u2014 assets unavailable</title>\n <style>\n :root{color-scheme:dark;background:#0c111b;color:#e7edf7;font:16px/1.5 system-ui,sans-serif}\n body{margin:0;min-height:100vh;display:grid;place-items:center;padding:24px;box-sizing:border-box}\n main{max-width:680px;border:1px solid #334155;background:#111827;padding:28px}\n h1{margin-top:0;font-size:1.5rem}code{color:#93c5fd}p{color:#cbd5e1}\n </style>\n</head>\n<body>\n <main data-hq-recovery-shell>\n <h1>HQ frontend assets are unavailable</h1>\n <p>The HQ backend is running, but the packaged React application could not be resolved.</p>\n <p>Rebuild or reinstall <code>@wrongstack/webui-hq</code>, then restart HQ. API routes remain available for diagnostics.</p>\n </main>\n</body>\n</html>`;\n\n/** Backward-compatible public name; now always represents the diagnostic shell. */\nexport const HQ_HTML = HQ_RECOVERY_HTML;\n", "/**\n * HQ server \u2014 authentication, cookie management, and security headers.\n *\n * @module hq-server/auth\n */\n\nimport { createHmac, timingSafeEqual } from 'node:crypto';\nimport type * as http from 'node:http';\nimport { isIP } from 'node:net';\nimport type { HqSessionEntry } from './types.js';\n\n// \u2500\u2500 Cookie / session constants \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const HQ_SESSION_COOKIE = 'hq.session';\nexport const HQ_SESSION_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000;\n\n// \u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface HqBrowserAuthContext {\n kind: 'token';\n token: string;\n id: string;\n capabilities?: string[];\n}\n\n/**\n * Cookie-session auth context \u2014 returned when a valid `hq.session` cookie\n * is presented. Password-origin cookies have `kind: 'cookie'` (full\n * access). Token-origin cookies carry the source token's capabilities\n * so capability checks (e.g. `control.enqueue`) still apply.\n */\nexport interface HqCookieAuthContext {\n kind: 'cookie';\n tokenId?: string;\n capabilities?: string[];\n}\n\nexport type HqBrowserAuthResult = HqBrowserAuthContext | HqCookieAuthContext | undefined;\n\n// \u2500\u2500 Security headers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * The only featureful frontend is the packaged, same-origin React SPA.\n * The missing-assets recovery document contains inline CSS but no script.\n */\nexport function setHqSecurityHeaders(res: http.ServerResponse): void {\n res.setHeader('X-Content-Type-Options', 'nosniff');\n res.setHeader('X-Frame-Options', 'DENY');\n res.setHeader('Referrer-Policy', 'no-referrer');\n res.setHeader('Permissions-Policy', 'camera=(), microphone=(), geolocation=()');\n res.setHeader(\n 'Content-Security-Policy',\n [\n \"default-src 'self'\",\n \"base-uri 'none'\",\n \"object-src 'none'\",\n \"frame-ancestors 'none'\",\n \"form-action 'self'\",\n \"script-src 'self' 'unsafe-inline' 'wasm-unsafe-eval'\",\n \"style-src 'self' 'unsafe-inline'\",\n \"font-src 'self' data:\",\n \"img-src 'self' data:\",\n \"connect-src 'self'\",\n ].join('; '),\n );\n}\n\n// \u2500\u2500 CORS / origin guard \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction hasTrustedRequestAuthority(\n req: http.IncomingMessage,\n boundHost: string | undefined,\n boundPort: number | undefined,\n trustedPublicOrigins: ReadonlySet<string>,\n): boolean {\n const rawHost = req.headers.host?.trim();\n if (!rawHost) return false;\n\n try {\n const requestUrl = new URL(`http://${rawHost}`);\n // Reject anything other than a bare authority (for example, userinfo, a\n // path, query, or fragment). Do not compare normalized `.host` with the\n // raw value: URL parsing intentionally removes explicit default ports.\n if (\n requestUrl.username ||\n requestUrl.password ||\n requestUrl.pathname !== '/' ||\n requestUrl.search ||\n requestUrl.hash\n ) {\n return false;\n }\n\n for (const origin of trustedPublicOrigins) {\n const trusted = new URL(origin);\n const normalizedRequest = new URL(`${trusted.protocol}//${rawHost}`);\n if (trusted.host.toLowerCase() === normalizedRequest.host.toLowerCase()) return true;\n }\n\n const hostname = requestUrl.hostname.toLowerCase().replace(/^\\[(.*)\\]$/, '$1');\n const requestPort = requestUrl.port || '80';\n // Port 0 asks the OS to assign an ephemeral port; the handler receives the\n // actual port only in Host, so treat 0 like an unspecified expected port.\n const portMatches =\n boundPort === undefined || boundPort === 0 || requestPort === String(boundPort);\n const isLoopback = hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '::1';\n if (isLoopback) return portMatches;\n\n // Literal LAN addresses are safe from hostname rebinding. They are trusted\n // only for a wildcard bind (or when they equal an explicit IP bind).\n if (isIP(hostname) !== 0) {\n const normalizedBoundHost = boundHost?.toLowerCase().replace(/^\\[(.*)\\]$/, '$1');\n const permitsIpHost =\n normalizedBoundHost === undefined ||\n normalizedBoundHost === '0.0.0.0' ||\n normalizedBoundHost === '::' ||\n normalizedBoundHost === hostname;\n return permitsIpHost && portMatches;\n }\n\n // An explicitly configured named bind is an operator-owned trust decision.\n // Arbitrary request-selected hostnames are never authorized.\n return boundHost?.toLowerCase() === hostname && portMatches;\n } catch {\n return false;\n }\n}\n\nexport function hasTrustedBrowserOrigin(\n req: http.IncomingMessage,\n boundHost?: string,\n boundPort?: number,\n trustedPublicOrigins: ReadonlySet<string> = new Set(),\n): boolean {\n // Host authorization is required even when browsers omit Origin (notably on\n // same-origin GET/HEAD). Otherwise DNS rebinding can still read open-mode HQ\n // telemetry through an attacker-selected authority.\n if (!hasTrustedRequestAuthority(req, boundHost, boundPort, trustedPublicOrigins)) return false;\n\n const origin = req.headers.origin;\n // Non-browser clients commonly omit Origin, but their Host authority still\n // has to identify the configured HQ endpoint.\n if (origin === undefined) return true;\n try {\n const parsed = new URL(origin);\n // File:// origins (the HQ dashboard served from a local file for\n // air-gapped use) are also trusted. The request Host was checked above.\n if (parsed.protocol === 'file:') return true;\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') return false;\n\n const rawRequestHost = req.headers.host?.trim();\n if (!rawRequestHost) return false;\n const requestHost = new URL(`${parsed.protocol}//${rawRequestHost}`).host.toLowerCase();\n if (parsed.host.toLowerCase() !== requestHost) return false;\n\n // Public hostnames must match the exact registered scheme as well as the\n // authority. Local/LAN requests are served over HTTP directly.\n const registeredPublicOrigin = [...trustedPublicOrigins].some(\n (trustedOrigin) => new URL(trustedOrigin).host.toLowerCase() === requestHost,\n );\n return !registeredPublicOrigin || trustedPublicOrigins.has(parsed.origin.toLowerCase());\n } catch {\n // Unparseable origin \u2192 reject.\n return false;\n }\n}\n\n// \u2500\u2500 Session cookie helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction signHqSession(sessionId: string, secret: string): string {\n return createHmac('sha256', secret).update(sessionId).digest('hex');\n}\n\nexport function serializeHqSessionCookie(sessionId: string, secret: string): string {\n return `${sessionId}.${signHqSession(sessionId, secret)}`;\n}\n\nexport function parseHqSessionCookie(value: string, secret: string): string | undefined {\n const dot = value.indexOf('.');\n if (dot === -1) return undefined;\n const sessionId = value.slice(0, dot);\n const sig = value.slice(dot + 1);\n if (!sessionId || !sig) return undefined;\n const expected = signHqSession(sessionId, secret);\n try {\n if (!timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) return undefined;\n } catch {\n return undefined;\n }\n return sessionId;\n}\n\nexport function parseCookieHeader(cookieHeader: string | undefined): Record<string, string> {\n const out: Record<string, string> = {};\n if (typeof cookieHeader !== 'string') return out;\n for (const part of cookieHeader.split(';')) {\n const idx = part.indexOf('=');\n if (idx === -1) continue;\n const key = part.slice(0, idx).trim();\n const value = part.slice(idx + 1).trim();\n if (key) {\n try {\n out[key] = decodeURIComponent(value);\n } catch {\n // Malformed percent-encoding (e.g. %ZZ, %FF without valid UTF-8)\n // throws URIError. Return the raw value rather than crashing.\n out[key] = value;\n }\n }\n }\n return out;\n}\n\nexport function setHqSessionCookie(\n res: http.ServerResponse,\n value: string,\n secure?: boolean,\n): void {\n const parts = [\n `${HQ_SESSION_COOKIE}=${encodeURIComponent(value)}`,\n 'Path=/',\n 'HttpOnly',\n 'SameSite=Lax',\n `Max-Age=${Math.floor(HQ_SESSION_MAX_AGE_MS / 1000)}`,\n ];\n if (secure) parts.push('Secure');\n res.setHeader('Set-Cookie', parts.join('; '));\n}\n\nexport function clearHqSessionCookie(res: http.ServerResponse, secure?: boolean): void {\n const parts = [`${HQ_SESSION_COOKIE}=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0`];\n if (secure) parts.push('Secure');\n res.setHeader('Set-Cookie', parts.join('; '));\n}\n\n// \u2500\u2500 Auth result helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function isTokenAuth(auth: HqBrowserAuthResult): auth is HqBrowserAuthContext {\n return auth !== undefined && auth.kind === 'token';\n}\n\nexport function isCookieAuth(auth: HqBrowserAuthResult): auth is HqCookieAuthContext {\n return auth !== undefined && auth.kind === 'cookie';\n}\n\n// \u2500\u2500 Request auth \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction extractBrowserToken(req: http.IncomingMessage, url: URL): string | undefined {\n const queryToken = url.searchParams.get('token');\n if (queryToken) {\n // Tokens in URL query strings can leak through browser history, server\n // access logs, and Referer headers. On loopback this risk is low, but\n // operators exposing HQ beyond localhost should use the Authorization\n // header instead. The built React dashboard uses the header; the inline\n // fallback and manual curl access use the query param.\n console.warn(\n JSON.stringify({\n level: 'warn',\n event: 'hq.token_from_query_param',\n message:\n 'Browser token accepted from URL query parameter \u2014 token can leak through browser history, server access logs, and Referer headers.',\n timestamp: new Date().toISOString(),\n }),\n );\n return queryToken;\n }\n\n const auth = req.headers.authorization;\n if (typeof auth === 'string' && auth.toLowerCase().startsWith('bearer ')) {\n return auth.slice(7).trim();\n }\n\n return undefined;\n}\n\n/**\n * Constant-time membership test for a token set. Returns the matching stored\n * token (so callers can look up its metadata) or undefined. Iterates and\n * compares each candidate with `timingSafeEqual` instead of `Set.has()`, whose\n * hash lookup can leak token length/prefix via timing. Use this everywhere an\n * HQ token is checked \u2014 the HTTP path and the WS-upgrade path alike.\n */\nexport function timingSafeTokenMatch(tokens: Set<string>, supplied: string): string | undefined {\n if (!supplied) return undefined;\n const b = Buffer.from(supplied);\n for (const candidate of tokens) {\n const a = Buffer.from(candidate);\n if (a.length === b.length && timingSafeEqual(a, b)) return candidate;\n }\n return undefined;\n}\n\nexport function authenticateBrowserRequest(\n req: http.IncomingMessage,\n url: URL,\n mutableAuth: {\n browserTokens: Set<string>;\n browserTokenObjs: Map<string, { id: string; capabilities?: string[] }>;\n passwordHash?: string | undefined;\n cookieSecret?: string | undefined;\n },\n sessions: Map<string, HqSessionEntry>,\n): HqBrowserAuthResult {\n const token = extractBrowserToken(req, url);\n if (token) {\n const matchedToken = timingSafeTokenMatch(mutableAuth.browserTokens, token);\n if (matchedToken) {\n const obj = mutableAuth.browserTokenObjs.get(matchedToken);\n const ctx: HqBrowserAuthContext = {\n kind: 'token',\n token: matchedToken,\n id: obj?.id ?? 'unknown',\n };\n if (obj?.capabilities !== undefined) ctx.capabilities = obj.capabilities;\n return ctx;\n }\n }\n if (mutableAuth.cookieSecret) {\n const cookies = parseCookieHeader(req.headers.cookie);\n const raw = cookies[HQ_SESSION_COOKIE];\n if (raw) {\n const sessionId = parseHqSessionCookie(raw, mutableAuth.cookieSecret);\n // Server-side session expiry: reject and evict entries past Max-Age\n // even if the periodic cleanup timer hasn't run yet.\n if (sessionId) {\n const session = sessions.get(sessionId);\n if (session && Date.now() - session.createdAt < HQ_SESSION_MAX_AGE_MS) {\n // For token-origin sessions, resolve capabilities from the LIVE\n // token record (not the cached session entry) so that a capability\n // change in auth.json takes effect immediately rather than at\n // session expiry.\n if (session.kind === 'token' && session.tokenId !== undefined) {\n const liveToken = [...mutableAuth.browserTokenObjs.values()].find(\n (obj) => obj.id === session.tokenId,\n );\n if (!liveToken) {\n sessions.delete(sessionId);\n return undefined;\n }\n const ctx: HqCookieAuthContext = { kind: 'cookie', tokenId: session.tokenId };\n if (liveToken.capabilities !== undefined) ctx.capabilities = liveToken.capabilities;\n return ctx;\n }\n // Password-origin sessions have full access.\n return { kind: 'cookie' as const };\n }\n // Stale session \u2014 evict so a replayed cookie doesn't linger.\n if (session) sessions.delete(sessionId);\n }\n }\n }\n return undefined;\n}\n", "import { DEFAULT_HQ_REDACTION_POLICY, hqAuthContentHash, isTokenExpired, logHqAuthAudit } from '@wrongstack/core/hq';\nimport type { HqAuthFile, HqSnapshot, HqToken } from '@wrongstack/core/hq';\nimport type { HqRouterMutableAuth } from './types.js';\n\nconst TOKEN_EXPIRY_WARNING_MS = 24 * 60 * 60 * 1000;\n\nexport interface HqAuthState {\n mutableAuth: HqRouterMutableAuth;\n apply(next: HqAuthFile): void;\n tokenStats(): NonNullable<HqSnapshot['totals']['tokenStats']>;\n}\n\nfunction liveTokens<T extends { token: string; expiresAt?: string }>(list: T[] | undefined): T[] {\n return (list ?? []).filter((token) => !isTokenExpired(token));\n}\n\n/** Owns the live auth projection, expiry statistics, and reload audit diff. */\nexport function createHqAuthState(authFile: HqAuthFile, dataDir: string): HqAuthState {\n let rawBrowserTokens: readonly HqToken[] = authFile.browserTokens ?? [];\n let rawClientTokens: readonly HqToken[] = authFile.clientTokens ?? [];\n const mutableAuth: HqRouterMutableAuth = {\n operatorPolicy: { ...DEFAULT_HQ_REDACTION_POLICY, ...(authFile.redactionPolicy ?? {}) },\n operatorPolicyOverride: authFile.redactionPolicy,\n browserTokens: new Set(liveTokens(authFile.browserTokens).map(({ token }) => token)),\n clientTokens: new Set(liveTokens(authFile.clientTokens).map(({ token }) => token)),\n browserTokenObjs: browserTokenMap(authFile.browserTokens),\n clientTokenObjs: new Map(liveTokens(authFile.clientTokens).map((token) => [token.token, token])),\n passwordHash: authFile.passwordHash,\n cookieSecret: authFile.cookieSecret,\n alertRules: authFile.alertRules,\n };\n\n return {\n mutableAuth,\n tokenStats: () => {\n const now = Date.now();\n const all = [...rawBrowserTokens, ...rawClientTokens];\n const live = all.filter((token) => !isTokenExpired(token, now));\n return {\n browserTotal: mutableAuth.browserTokens.size,\n clientTotal: mutableAuth.clientTokens.size,\n expired: all.length - live.length,\n expiringSoon: live.filter((token) => {\n if (token.expiresAt === undefined) return false;\n const expiry = Date.parse(token.expiresAt);\n return Number.isFinite(expiry) && expiry - now <= TOKEN_EXPIRY_WARNING_MS;\n }).length,\n };\n },\n apply: (next) => {\n const newBrowser = next.browserTokens ?? [];\n const newClient = next.clientTokens ?? [];\n auditPrunedTokens('browser', rawBrowserTokens, newBrowser, next, dataDir);\n auditPrunedTokens('client', rawClientTokens, newClient, next, dataDir);\n rawBrowserTokens = newBrowser;\n rawClientTokens = newClient;\n mutableAuth.operatorPolicy = {\n ...DEFAULT_HQ_REDACTION_POLICY,\n ...(next.redactionPolicy ?? {}),\n };\n mutableAuth.operatorPolicyOverride = next.redactionPolicy;\n mutableAuth.browserTokens = new Set(liveTokens(next.browserTokens).map(({ token }) => token));\n mutableAuth.clientTokens = new Set(liveTokens(next.clientTokens).map(({ token }) => token));\n mutableAuth.browserTokenObjs = browserTokenMap(next.browserTokens);\n mutableAuth.clientTokenObjs = new Map(\n liveTokens(next.clientTokens).map((token) => [token.token, token]),\n );\n mutableAuth.passwordHash = next.passwordHash;\n mutableAuth.cookieSecret = next.cookieSecret;\n mutableAuth.alertRules = next.alertRules;\n },\n };\n}\n\nfunction browserTokenMap(tokens: HqToken[] | undefined): HqRouterMutableAuth['browserTokenObjs'] {\n return new Map(\n liveTokens(tokens).map((token) => [\n token.token,\n {\n id: token.id,\n ...(token.capabilities !== undefined ? { capabilities: token.capabilities } : {}),\n ...(token.expiresAt !== undefined ? { expiresAt: token.expiresAt } : {}),\n },\n ]),\n );\n}\n\nfunction auditPrunedTokens(\n scope: 'browser' | 'client',\n previous: readonly HqToken[],\n next: readonly HqToken[],\n authFile: HqAuthFile,\n dataDir: string,\n): void {\n const previouslyLive = new Set(previous.filter((token) => !isTokenExpired(token)).map(({ id }) => id));\n const prunedCount = next.filter((token) => isTokenExpired(token) && previouslyLive.has(token.id)).length;\n if (prunedCount === 0) return;\n const contentHash = hqAuthContentHash(authFile);\n logHqAuthAudit(dataDir, {\n kind: 'expired-prune',\n scope,\n tokenId: '(aggregate)',\n prunedCount,\n ...(contentHash !== undefined ? { contentHash } : {}),\n });\n}\n", "import { assessHqExposure, ensureHqFirstRunAuthFile, resolveHqDataDir } from '@wrongstack/core/hq';\nimport { HqInsecureExposureError, type EnsureHqFirstRunAuthResult } from '@wrongstack/core/hq';\nimport { resolveAuditActor } from './audit-actor.js';\n\nexport interface HqPreflightOptions {\n host?: string;\n port?: number;\n dataDir?: string;\n password?: string;\n tokenTtlMs?: number;\n requireBrowserAuth?: boolean;\n allowInsecureOpen?: boolean;\n}\n\nexport interface HqPreflightResult {\n host: string;\n port: number;\n dataDir: string;\n firstRunAuth: EnsureHqFirstRunAuthResult;\n}\n\n/** Resolves startup inputs and enforces exposure/auth policy before binding a socket. */\nexport async function prepareHqServerStart(\n options: HqPreflightOptions,\n defaults: { host: string; port: number },\n): Promise<HqPreflightResult> {\n const host = options.host ?? defaults.host;\n const port = options.port ?? defaults.port;\n const dataDir = resolveHqDataDir(options.dataDir);\n const firstRunAuth = await ensureHqFirstRunAuthFile(dataDir, {\n warn: (message) =>\n console.warn(\n JSON.stringify({\n level: 'warn',\n event: 'hq.auth_load_failed',\n message,\n timestamp: new Date().toISOString(),\n }),\n ),\n actor: resolveAuditActor(),\n ...(options.password !== undefined ? { password: options.password } : {}),\n ...(options.tokenTtlMs !== undefined ? { tokenTtlMs: options.tokenTtlMs } : {}),\n });\n const { authFile } = firstRunAuth;\n if (\n options.requireBrowserAuth &&\n (authFile.browserTokens ?? []).length === 0 &&\n authFile.passwordHash === undefined\n ) {\n throw new HqInsecureExposureError(\n 'HQ public relay requires browser authentication. Set --password or create a browser token first.',\n );\n }\n const exposure = assessHqExposure({\n host,\n hasBrowserTokens: (authFile.browserTokens ?? []).length > 0,\n hasPassword: authFile.passwordHash !== undefined,\n allowInsecure: options.allowInsecureOpen,\n });\n if (exposure.kind === 'refuse') throw new HqInsecureExposureError(exposure.message);\n if (exposure.kind === 'warn') {\n console.warn(\n JSON.stringify({\n level: 'warn',\n event: 'hq.insecure_exposure',\n message: exposure.message,\n host,\n timestamp: new Date().toISOString(),\n }),\n );\n }\n return { host, port, dataDir, firstRunAuth };\n}\n", "/**\n * HQ server \u2014 HTTP API route handlers.\n *\n * All routes for the HQ server's REST API live here, extracted from the\n * monolithic request handler in {@link startHqServerWithAuth}. A single\n * factory {@link createHqRouter} wires them into one request listener.\n *\n * @module hq-server/routes\n */\n\nimport { randomUUID } from 'node:crypto';\nimport * as path from 'node:path';\nimport type * as http from 'node:http';\nimport type { WebSocket } from 'ws';\nimport type { TrustBoundary } from '@wrongstack/core/security';\nimport { type createHqPersistence, tokenHasCapability, validateHqCommand } from '@wrongstack/core/hq';\nimport type { HqSnapshot, HqAlertEngine, HqCommand, HqCommandAuditEntry, HqCommandAuditLog, HqEventEnvelope, HqQueuedCommand, HqTimeseriesSample, HqTranscriptEntry } from '@wrongstack/core/hq';\nimport type { createMailboxHttpRouter } from '@wrongstack/core/coordination';\nimport {\n type Mailbox,\n type MailboxHttpAccessDecision,\n type MailboxHttpRateLimiter,\n resolveProjectDir,\n} from '@wrongstack/core/coordination';\nimport { HQ_HTML } from '../hq-recovery-html.js';\nimport { resolveHqDistDir, serveHqStatic } from '../hq-static-serve.js';\nimport * as HqServerAuth from './auth.js';\nimport * as HqServerSnapshot from './snapshot.js';\nimport * as HqServerUtils from './utils.js';\nimport { authorizeHqCommand } from './trust-boundary.js';\nimport {\n handleApiAuthStatus,\n handleApiBootstrap,\n handleApiLogin,\n handleApiLogout,\n handleApiPassword,\n} from './routes/auth-handlers.js';\nimport {\n handleApiAlerts,\n handleApiCommandsAudit,\n handleApiSystemHealth,\n handleApiSystemUpdate,\n} from './routes/system-handlers.js';\nimport {\n handleApiAgentMessages,\n handleApiSessionAgentMessages,\n handleApiSessionEvents,\n handleApiSessions,\n} from './routes/session-handlers.js';\nimport { resolveHqProjectRoot } from './project-root.js';\n\n// \u2500\u2500 Re-exports for hq-server.ts backward compat \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const setHqSecurityHeaders = HqServerAuth.setHqSecurityHeaders;\nexport const hasTrustedBrowserOrigin = HqServerAuth.hasTrustedBrowserOrigin;\nexport const authenticateBrowserRequest = HqServerAuth.authenticateBrowserRequest;\nexport const isTokenAuth = HqServerAuth.isTokenAuth;\nexport const isCookieAuth = HqServerAuth.isCookieAuth;\nexport const setHqSessionCookie = HqServerAuth.setHqSessionCookie;\nexport const clearHqSessionCookie = HqServerAuth.clearHqSessionCookie;\nexport const serializeHqSessionCookie = HqServerAuth.serializeHqSessionCookie;\nexport const parseHqSessionCookie = HqServerAuth.parseHqSessionCookie;\nexport const parseCookieHeader = HqServerAuth.parseCookieHeader;\nexport const HQ_SESSION_COOKIE = HqServerAuth.HQ_SESSION_COOKIE;\n\nexport const decodePathSegment = HqServerUtils.decodePathSegment;\nexport const readRequestBody = HqServerUtils.readRequestBody;\nexport const writeInvalidBody = HqServerUtils.writeInvalidBody;\nexport const sanitizeApiError = HqServerUtils.sanitizeApiError;\nexport const buildHttpUrl = HqServerUtils.buildHttpUrl;\nexport const buildBootstrapHttpUrl = HqServerUtils.buildBootstrapHttpUrl;\nexport const buildClientWsUrl = HqServerUtils.buildClientWsUrl;\nexport const agentRingKey = HqServerUtils.agentRingKey;\nexport const agentMessageToEntry = HqServerUtils.agentMessageToEntry;\nexport const readLocalSubagentTranscript = HqServerUtils.readLocalSubagentTranscript;\nexport const lanIPv4Addresses = HqServerUtils.lanIPv4Addresses;\nexport const hqRuntimeMarkerPath = HqServerUtils.hqRuntimeMarkerPath;\n\n// \u2500\u2500 Shared helpers used in routes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nimport type {\n ConnectedClient,\n HqRouterMutableAuth,\n HqSessionEntry,\n HqSnapshotBroadcaster,\n ProjectDetail,\n TranscriptRing,\n} from './types.js';\n\nexport type {\n ConnectedClient,\n HqSnapshotBroadcaster,\n ProjectDetail,\n TranscriptRing,\n};\n\n// \u2500\u2500 Router dependency interface \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface HqRouterMailboxGateway {\n mailbox: Mailbox;\n router: ReturnType<typeof createMailboxHttpRouter>;\n}\n\nexport interface HqRouterDeps {\n trustBoundary: TrustBoundary;\n host: string;\n listeningPort: number;\n trustedPublicOrigins: Set<string>;\n mutableAuth: HqRouterMutableAuth;\n sessions: Map<string, HqSessionEntry>;\n loginAttempts: Map<string, { count: number; blockedUntil: number; lastAttempt: number }>;\n clients: Map<WebSocket, ConnectedClient>;\n browsers: Set<WebSocket>;\n eventLog: HqEventEnvelope[];\n transcripts: Map<string, TranscriptRing>;\n agentMessages: Map<string, HqTranscriptEntry[]>;\n mailboxGateways: Map<string, HqRouterMailboxGateway>;\n mailboxGatewayRateLimiter: MailboxHttpRateLimiter;\n alertEngine: HqAlertEngine;\n auditLog: HqCommandAuditLog;\n persistence: ReturnType<typeof createHqPersistence>;\n dataDir: string;\n hqSessionTag: string;\n requireBrowserAuth: boolean | undefined;\n secureCookies: boolean | undefined;\n authorizeMailboxGateway: (\n req: http.IncomingMessage,\n projectDir: string,\n ) => MailboxHttpAccessDecision;\n getMailboxGateway: (projectDir: string) => HqRouterMailboxGateway;\n /** Aggregate token-expiry stats for snapshot totals + alert engine. */\n getTokenStats?: (() => HqSnapshot['totals']['tokenStats'] | undefined) | undefined;\n /** One-time bootstrap code store for token-to-cookie exchange. */\n bootstrapStore?: import('@wrongstack/core/hq').HqBootstrapCodeStore | undefined;\n}\n\n// \u2500\u2500 Route handler factory \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Create the HTTP request listener that handles all `/api/*` routes as well\n * as static dashboard serving (React app or inline HTML fallback).\n *\n * Kept as a factory so the dependencies from the server setup closure are\n * explicitly visible \u2014 every closure reference is a named field.\n */\nexport function createHqRouter(deps: HqRouterDeps): (req: http.IncomingMessage, res: http.ServerResponse) => Promise<void> {\n const {\n host,\n listeningPort,\n trustedPublicOrigins,\n mutableAuth,\n sessions,\n loginAttempts,\n clients,\n browsers,\n eventLog,\n transcripts,\n agentMessages,\n alertEngine,\n auditLog,\n persistence,\n dataDir,\n hqSessionTag,\n requireBrowserAuth,\n secureCookies,\n authorizeMailboxGateway,\n getMailboxGateway,\n getTokenStats,\n trustBoundary,\n bootstrapStore,\n } = deps;\n\n return async (req: http.IncomingMessage, res: http.ServerResponse): Promise<void> => {\n try {\n const url = new URL(req.url ?? '/', `http://${host}:${listeningPort}`);\n setHqSecurityHeaders(res);\n\n // \u2500\u2500 Origin guard (DNS-rebinding / CSRF boundary) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (!hasTrustedBrowserOrigin(req, host, listeningPort, trustedPublicOrigins)) {\n res.writeHead(403, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'forbidden: untrusted request origin' }));\n return;\n }\n\n // \u2500\u2500 Auth gate for /api/* routes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (\n url.pathname.startsWith('/api/') &&\n url.pathname !== '/api/auth/status' &&\n url.pathname !== '/api/login' &&\n url.pathname !== '/api/auth/bootstrap' &&\n (requireBrowserAuth ||\n mutableAuth.browserTokens.size > 0 ||\n mutableAuth.passwordHash)\n ) {\n const auth = authenticateBrowserRequest(req, url, mutableAuth, sessions);\n if (!auth) {\n const tokenOnly = mutableAuth.browserTokens.size > 0 && !mutableAuth.passwordHash;\n res.writeHead(401, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n error: {\n code: tokenOnly ? 'INVALID_TOKEN' : 'UNAUTHORIZED',\n message: tokenOnly\n ? 'A valid ?token= or Authorization: Bearer is required for HTTP access in browser token mode.'\n : 'A valid browser token or password session is required.',\n },\n }),\n );\n return;\n }\n }\n\n // \u2500\u2500 Static dashboard (React app, fallback inline HTML) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const hqDistDir = resolveHqDistDir();\n const isApiOrWsPath = url.pathname.startsWith('/api/') || url.pathname.startsWith('/ws/');\n if (hqDistDir !== null && !isApiOrWsPath) {\n const served = await serveHqStatic(req, res, url.pathname, hqDistDir);\n if (served.handled) return;\n }\n\n if (url.pathname === '/' || url.pathname === '/index.html') {\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(HQ_HTML);\n return;\n }\n\n // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n // HQ API routes\n // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\n if (url.pathname === '/api/auth/status' && req.method === 'GET') {\n await handleApiAuthStatus(req, res, url, mutableAuth, sessions, requireBrowserAuth, trustedPublicOrigins, secureCookies);\n return;\n }\n\n if (url.pathname === '/api/login' && req.method === 'POST') {\n await handleApiLogin(req, res, mutableAuth, sessions, loginAttempts, secureCookies);\n return;\n }\n\n if (url.pathname === '/api/auth/bootstrap' && req.method === 'POST') {\n if (bootstrapStore) {\n await handleApiBootstrap(req, res, mutableAuth, sessions, secureCookies, bootstrapStore);\n } else {\n res.writeHead(503, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n error: {\n code: 'BOOTSTRAP_UNAVAILABLE',\n message: 'Bootstrap exchange is not enabled on this HQ server.',\n },\n }),\n );\n }\n return;\n }\n\n if (url.pathname === '/api/logout' && req.method === 'POST') {\n await handleApiLogout(req, res, mutableAuth, sessions, secureCookies);\n return;\n }\n\n if (url.pathname === '/api/auth/password' && (req.method === 'POST' || req.method === 'DELETE')) {\n await handleApiPassword(req, res, mutableAuth, sessions, dataDir, secureCookies, requireBrowserAuth);\n return;\n }\n\n if (url.pathname === '/api/snapshot' && req.method === 'GET') {\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify(HqServerSnapshot.buildSnapshot(clients, { tokenStats: getTokenStats?.() })));\n return;\n }\n\n if (url.pathname === '/api/system/update' && req.method === 'GET') {\n await handleApiSystemUpdate(res);\n return;\n }\n\n if (url.pathname === '/api/system/health' && req.method === 'GET') {\n await handleApiSystemHealth(res, clients, persistence, eventLog);\n return;\n }\n\n // \u2500\u2500 Project-scoped mailbox gateway \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const mailboxGatewayMatch = url.pathname.match(\n /^\\/api\\/projects\\/([^/]+)\\/mailbox(?:\\/(.*))?$/,\n );\n if (mailboxGatewayMatch) {\n await handleMailboxGateway(req, res, mailboxGatewayMatch, authorizeMailboxGateway, getMailboxGateway, dataDir);\n return;\n }\n\n const projectKanbanMatch = url.pathname.match(/^\\/api\\/projects\\/([^/]+)\\/kanban$/);\n if (projectKanbanMatch && req.method === 'GET') {\n const projectId = decodePathSegment(projectKanbanMatch[1]!);\n if (projectId === null) {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: { code: 'VALIDATION_ERROR', message: 'Invalid project id.' } }));\n return;\n }\n const snapshot = await persistence.kanban.load(projectId);\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify(snapshot));\n return;\n }\n\n if (url.pathname.startsWith('/api/projects/') && req.method === 'GET') {\n await handleApiProjectDetail(req, res, url, clients);\n return;\n }\n\n // \u2500\u2500 Fleet tree \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (url.pathname === '/api/fleet' && req.method === 'GET') {\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify(HqServerSnapshot.buildSnapshot(clients, { tokenStats: getTokenStats?.() })));\n return;\n }\n\n // \u2500\u2500 Events \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (url.pathname === '/api/events' && req.method === 'GET') {\n await handleApiEvents(req, res, persistence);\n return;\n }\n\n // \u2500\u2500 Trends \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (url.pathname === '/api/trends/cost' && req.method === 'GET') {\n await handleApiTrendsCost(req, res, persistence);\n return;\n }\n\n // \u2500\u2500 Command \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (url.pathname === '/api/command' && req.method === 'POST') {\n await handleApiCommand(\n req,\n res,\n url,\n mutableAuth,\n sessions,\n clients,\n browsers,\n auditLog,\n trustBoundary,\n );\n return;\n }\n\n // \u2500\u2500 Mailbox send \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (url.pathname === '/api/mailbox-send' && req.method === 'POST') {\n await handleApiMailboxSend(req, res, mutableAuth, sessions, dataDir, getMailboxGateway, hqSessionTag);\n return;\n }\n\n const mailboxActionMatch = url.pathname.match(\n /^\\/api\\/mailbox\\/messages\\/([^/]+)\\/action$/,\n );\n if (mailboxActionMatch && req.method === 'POST') {\n await handleMailboxAction(req, res, mailboxActionMatch, mutableAuth, sessions, dataDir, getMailboxGateway);\n return;\n }\n\n // \u2500\u2500 Commands audit \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (url.pathname === '/api/commands' && req.method === 'GET') {\n await handleApiCommandsAudit(req, res, auditLog);\n return;\n }\n\n // \u2500\u2500 Alerts \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (url.pathname === '/api/alerts' && req.method === 'GET') {\n await handleApiAlerts(req, res, alertEngine);\n return;\n }\n\n // \u2500\u2500 Sessions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (url.pathname === '/api/sessions' && req.method === 'GET') {\n await handleApiSessions(res);\n return;\n }\n\n const eventsMatch = url.pathname.match(/^\\/api\\/sessions\\/([^/]+)\\/events$/);\n if (eventsMatch && req.method === 'GET') {\n await handleApiSessionEvents(req, res, eventsMatch, transcripts);\n return;\n }\n\n // \u2500\u2500 Agent messages (session-scoped) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const sessionAgentMsgMatch = url.pathname.match(\n /^\\/api\\/sessions\\/([^/]+)\\/agents\\/([^/]+)\\/messages$/,\n );\n if (sessionAgentMsgMatch && req.method === 'GET') {\n await handleApiSessionAgentMessages(req, res, sessionAgentMsgMatch, agentMessages);\n return;\n }\n\n // \u2500\u2500 Agent messages (legacy, un-scoped) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const agentMsgMatch = url.pathname.match(/^\\/api\\/agents\\/([^/]+)\\/messages$/);\n if (agentMsgMatch && req.method === 'GET') {\n await handleApiAgentMessages(req, res, agentMsgMatch, agentMessages);\n return;\n }\n\n res.writeHead(404, { 'Content-Type': 'text/plain' });\n res.end('Not found');\n } catch (err) {\n console.error(\n JSON.stringify({\n level: 'error',\n event: 'hq.http_handler_error',\n message: String(err),\n timestamp: new Date().toISOString(),\n }),\n );\n if (!res.headersSent) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Internal server error' }));\n }\n }\n };\n}\n\n// \u2500\u2500 Login rate-limit state (scoped to routes, mutable) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n// \u2500\u2500 Individual route handlers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nasync function handleMailboxGateway(\n _req: http.IncomingMessage,\n res: http.ServerResponse,\n match: RegExpMatchArray,\n authorizeMailboxGateway: (req: http.IncomingMessage, projectDir: string) => MailboxHttpAccessDecision,\n getMailboxGateway: (projectDir: string) => HqRouterMailboxGateway,\n dataDir: string,\n): Promise<void> {\n const projectId = decodePathSegment(match[1]!);\n if (projectId === null || projectId.length === 0) {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({ error: { code: 'BAD_REQUEST', message: 'invalid projectId encoding' } }),\n );\n return;\n }\n const gatewayGlobalRoot = path.dirname(dataDir);\n const preliminaryAccess = authorizeMailboxGateway(_req, `project:${projectId}`);\n if (!preliminaryAccess.allowed) {\n res.writeHead(preliminaryAccess.status ?? 401, {\n 'Content-Type': 'application/json; charset=utf-8',\n 'Cache-Control': 'no-store',\n });\n res.end(JSON.stringify(preliminaryAccess.body));\n return;\n }\n const projectRoot = await resolveHqProjectRoot(gatewayGlobalRoot, { projectId });\n if (!projectRoot) {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({ error: { code: 'NOT_FOUND', message: `Unknown project: ${projectId}` } }),\n );\n return;\n }\n const suffix = match[2];\n // Preserve the query string (e.g. `?sinceMs=\u2026`) so the router's\n // `parseSinceMs` sees per-request overrides. Without this the HQ\n // gateway would forward the canonical path without the query and\n // the look-back filter would never engage \u2014 a silent contract\n // regression for clients that pass `?sinceMs=\u2026` through HQ.\n const rawUrl = _req.url ?? '';\n const queryIndex = rawUrl.indexOf('?');\n const querySuffix = queryIndex === -1 ? '' : rawUrl.slice(queryIndex);\n const canonicalPath = suffix\n ? `/mailbox/${suffix}${querySuffix}`\n : `/mailbox${querySuffix}`;\n const projectDir = resolveProjectDir(projectRoot, gatewayGlobalRoot);\n await getMailboxGateway(projectDir).router.handle(_req, res, canonicalPath);\n}\n\nasync function handleApiProjectDetail(\n _req: http.IncomingMessage,\n res: http.ServerResponse,\n url: URL,\n clients: Map<WebSocket, ConnectedClient>,\n): Promise<void> {\n const projectId = decodePathSegment(url.pathname.slice('/api/projects/'.length));\n if (projectId === null) {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({ error: { code: 'BAD_REQUEST', message: 'invalid projectId encoding' } }),\n );\n return;\n }\n if (!projectId) {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({ error: { code: 'BAD_REQUEST', message: 'projectId is required' } }),\n );\n return;\n }\n const detail = HqServerSnapshot.buildProjectDetail(clients, projectId);\n if (!detail) {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({ error: { code: 'NOT_FOUND', message: `Unknown project: ${projectId}` } }),\n );\n return;\n }\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify(detail));\n}\n\nasync function handleApiEvents(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n persistence: ReturnType<typeof createHqPersistence>,\n): Promise<void> {\n const url = new URL(req.url ?? '/', 'http://localhost');\n const rawLimit = Number.parseInt(url.searchParams.get('limit') ?? '200', 10);\n const limit = Math.min(5000, Math.max(1, Number.isFinite(rawLimit) ? rawLimit : 200));\n const typeFilter = url.searchParams.get('type') ?? undefined;\n const events = await persistence.eventLog.recent(limit, typeFilter);\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ events, total: events.length }));\n}\n\nasync function handleApiTrendsCost(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n persistence: ReturnType<typeof createHqPersistence>,\n): Promise<void> {\n const url = new URL(req.url ?? '/', 'http://localhost');\n const rawSince = Number.parseInt(url.searchParams.get('since') ?? '0', 10);\n const since = Number.isFinite(rawSince) ? rawSince : 0;\n const samples: HqTimeseriesSample[] = await persistence.timeseries.read(since);\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ samples }));\n}\n\nasync function handleApiCommand(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n url: URL,\n mutableAuth: HqRouterMutableAuth,\n sessions: Map<string, HqSessionEntry>,\n clients: Map<WebSocket, ConnectedClient>,\n browsers: Set<WebSocket>,\n auditLog: HqCommandAuditLog,\n trustBoundary: TrustBoundary,\n): Promise<void> {\n const auth = authenticateBrowserRequest(req, url, mutableAuth, sessions);\n const inBrowserTokenMode = mutableAuth.browserTokens.size > 0;\n const inPasswordMode = mutableAuth.passwordHash !== undefined;\n if ((inBrowserTokenMode || inPasswordMode) && !auth) {\n res.writeHead(401, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'unauthorized' }));\n return;\n }\n const canEnqueue = isCookieAuth(auth)\n ? auth.tokenId === undefined ||\n auth.capabilities === undefined ||\n auth.capabilities.includes('control.enqueue')\n : isTokenAuth(auth)\n ? auth.capabilities === undefined || auth.capabilities.includes('control.enqueue')\n : !inBrowserTokenMode;\n if (!canEnqueue) {\n res.writeHead(403, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'forbidden: token lacks control.enqueue capability' }));\n return;\n }\n\n let body: { clientId?: string; type?: string; payload?: unknown };\n try {\n body = JSON.parse(await readRequestBody(req)) as {\n clientId?: string;\n type?: string;\n payload?: unknown;\n };\n } catch (error) {\n writeInvalidBody(res, error);\n return;\n }\n if (typeof body.clientId !== 'string' || typeof body.type !== 'string') {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'missing clientId or type' }));\n return;\n }\n\n let target: ConnectedClient | undefined;\n for (const c of clients.values()) {\n if (c.clientId === body.clientId) {\n target = c;\n break;\n }\n }\n if (target === undefined) {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'client not connected', clientId: body.clientId }));\n return;\n }\n if (!target.capabilities.includes('control.receive')) {\n res.writeHead(409, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n error: 'client does not accept control commands',\n clientId: body.clientId,\n }),\n );\n return;\n }\n\n const commandId = randomUUID();\n const queued: HqQueuedCommand = {\n commandId,\n type: body.type,\n createdAt: new Date().toISOString(),\n payload: body.payload ?? {},\n requiresAck: true,\n };\n const validated: HqCommand | null = validateHqCommand(queued);\n if (validated === null) {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({ error: 'unrecognized or malformed command', type: body.type }),\n );\n return;\n }\n\n if (\n validated.type === 'run-command' &&\n !tokenHasCapability(target.authToken, 'control.execute')\n ) {\n res.writeHead(403, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n error: 'forbidden: target client token lacks control.execute capability',\n }),\n );\n return;\n }\n\n const enqueuedBy = isCookieAuth(auth)\n ? (auth.tokenId ?? 'password-session')\n : isTokenAuth(auth)\n ? auth.id\n : 'open-mode';\n const authorization = await authorizeHqCommand({\n boundary: trustBoundary,\n command: validated,\n commandId,\n enqueuedBy,\n authMethod: isCookieAuth(auth) ? 'session' : 'bearer-token',\n target,\n });\n if (!authorization.allowed) {\n res.writeHead(403, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: `command denied: ${authorization.reason}` }));\n return;\n }\n\n target.commandQueue.push(queued);\n if (target.commandQueue.length > 200)\n target.commandQueue.splice(0, target.commandQueue.length - 200);\n\n const auditEntry: HqCommandAuditEntry = {\n commandId,\n type: validated.type,\n clientId: target.clientId,\n enqueuedBy,\n enqueuedAt: queued.createdAt,\n status: 'queued',\n };\n auditLog.record(auditEntry);\n HqServerSnapshot.broadcastCommandStatus(auditEntry, browsers);\n\n res.writeHead(202, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ commandId, queued: true, clientId: target.clientId }));\n}\n\nasync function handleApiMailboxSend(\n _req: http.IncomingMessage,\n res: http.ServerResponse,\n mutableAuth: HqRouterMutableAuth,\n sessions: Map<string, HqSessionEntry>,\n dataDir: string,\n getMailboxGateway: (projectDir: string) => HqRouterMailboxGateway,\n hqSessionTag: string,\n): Promise<void> {\n const auth = authenticateBrowserRequest(\n _req,\n new URL(_req.url ?? '/', 'http://localhost'),\n mutableAuth,\n sessions,\n );\n const canEnqueue = isCookieAuth(auth)\n ? auth.tokenId === undefined ||\n auth.capabilities === undefined ||\n auth.capabilities.includes('control.enqueue')\n : isTokenAuth(auth)\n ? auth.capabilities === undefined || auth.capabilities.includes('control.enqueue')\n : mutableAuth.browserTokens.size === 0;\n if (!canEnqueue) {\n res.writeHead(403, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'forbidden: token lacks control.enqueue capability' }));\n return;\n }\n\n let mbody: {\n sessionId?: string;\n projectId?: string;\n type?: string;\n to?: string;\n subject?: string;\n body?: string;\n priority?: string;\n audience?: string;\n };\n try {\n mbody = JSON.parse(await readRequestBody(_req));\n } catch (error) {\n writeInvalidBody(res, error);\n return;\n }\n if (typeof mbody.type !== 'string' || typeof mbody.body !== 'string') {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'missing type or body' }));\n return;\n }\n if (typeof mbody.sessionId !== 'string' && typeof mbody.projectId !== 'string') {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'missing sessionId or projectId' }));\n return;\n }\n if (mbody.audience !== undefined && mbody.audience !== 'all' && mbody.audience !== 'leaders') {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'audience must be all or leaders' }));\n return;\n }\n\n const mbGlobalRoot = path.dirname(dataDir);\n const projectRoot = await resolveHqProjectRoot(mbGlobalRoot, {\n sessionId: mbody.sessionId,\n projectId: mbody.projectId,\n });\n if (typeof projectRoot !== 'string' || projectRoot.length === 0) {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'could not resolve target project mailbox' }));\n return;\n }\n\n const to = typeof mbody.to === 'string' ? mbody.to : 'leader';\n const subject = typeof mbody.subject === 'string' ? mbody.subject : 'HQ prompt';\n const priority =\n mbody.priority === 'high' ? 'high' : mbody.priority === 'low' ? 'low' : 'normal';\n const audience = mbody.audience === 'leaders' ? 'leaders' : 'all';\n const mailboxType =\n mbody.type === 'queue'\n ? 'note'\n : ['note', 'ask', 'assign', 'steer', 'btw', 'broadcast', 'status', 'result', 'review'].includes(\n mbody.type,\n )\n ? (mbody.type as\n | 'note'\n | 'ask'\n | 'assign'\n | 'steer'\n | 'btw'\n | 'broadcast'\n | 'status'\n | 'result'\n | 'review')\n : undefined;\n if (mailboxType === undefined) {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n error: 'unrecognized or malformed mailbox message',\n type: mbody.type,\n }),\n );\n return;\n }\n if (\n (mailboxType === 'assign' || mailboxType === 'steer') &&\n (to === '*' || to.trim().toLowerCase() === 'all')\n ) {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: `${mailboxType} requires a specific recipient` }));\n return;\n }\n\n try {\n const projectDir = resolveProjectDir(projectRoot, mbGlobalRoot);\n const mailbox = getMailboxGateway(projectDir).mailbox;\n const from = `hq@${hqSessionTag}`;\n const deliveryTo = mailboxType === 'broadcast' ? 'all' : to;\n const sent = await mailbox.send({\n from,\n to: deliveryTo,\n type: mailboxType,\n subject,\n body: mbody.body,\n priority,\n audience,\n });\n res.writeHead(202, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n delivered: true,\n messageId: sent?.id,\n to: sent?.to ?? deliveryTo,\n type: mailboxType,\n audience,\n }),\n );\n } catch (err) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'mailbox write failed', detail: String(err) }));\n }\n}\n\nasync function handleMailboxAction(\n _req: http.IncomingMessage,\n res: http.ServerResponse,\n match: RegExpMatchArray,\n _mutableAuth: HqRouterMutableAuth,\n _sessions: Map<string, HqSessionEntry>,\n dataDir: string,\n getMailboxGateway: (projectDir: string) => HqRouterMailboxGateway,\n): Promise<void> {\n const MAILBOX_ACTIONS = [\n 'mark-read',\n 'acknowledge',\n 'reopen',\n 'soft-delete',\n 'restore',\n ] as const;\n\n let abody: {\n action?: string;\n readerId?: string;\n sessionId?: string;\n projectId?: string;\n };\n try {\n abody = JSON.parse(await readRequestBody(_req));\n } catch (error) {\n writeInvalidBody(res, error);\n return;\n }\n const mailId = decodePathSegment(match[1]!);\n if (mailId === null) {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'invalid mailId encoding' }));\n return;\n }\n const action = MAILBOX_ACTIONS.find((a) => a === abody.action);\n if (action === undefined) {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'unrecognized action', action: abody.action }));\n return;\n }\n if (typeof abody.readerId !== 'string' || abody.readerId.length === 0) {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'missing readerId' }));\n return;\n }\n if (typeof abody.sessionId !== 'string' && typeof abody.projectId !== 'string') {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'missing sessionId or projectId' }));\n return;\n }\n\n const actGlobalRoot = path.dirname(dataDir);\n const projectRoot = await resolveHqProjectRoot(actGlobalRoot, {\n sessionId: abody.sessionId,\n projectId: abody.projectId,\n });\n if (typeof projectRoot !== 'string' || projectRoot.length === 0) {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'could not resolve target project mailbox' }));\n return;\n }\n\n try {\n const { actionToAckInput } = await import('@wrongstack/core/coordination');\n const projectDir = resolveProjectDir(projectRoot, actGlobalRoot);\n const mailbox = getMailboxGateway(projectDir).mailbox;\n const readerId = abody.readerId;\n const message =\n action === 'soft-delete'\n ? await mailbox.softDelete(mailId, readerId)\n : action === 'restore'\n ? await mailbox.restore(mailId)\n : await mailbox.ack(actionToAckInput(action, { action, mailId, readerId }));\n if (message === null) {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'message not found', mailId }));\n return;\n }\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ action, mailId, message: null, changed: true }));\n } catch (err) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n error: 'mailbox action failed',\n detail: sanitizeApiError(err),\n }),\n );\n }\n}\n", "/**\n * HQ static-serve \u2014 resolve and serve the built `@wrongstack/webui-hq/dist`\n * dashboard. Mirrors the pattern in `webui-server/static-serve.ts` but for\n * the HQ app. Missing assets are reported to the caller, which serves a small\n * diagnostic shell instead of maintaining a second dashboard implementation.\n *\n * @module hq-static-serve\n */\n\nimport * as fs from 'node:fs';\nimport type * as http from 'node:http';\nimport { createRequire } from 'node:module';\nimport * as path from 'node:path';\n\nconst requireFromHere = createRequire(import.meta.url);\n\nconst MIME: Record<string, string> = {\n '.html': 'text/html; charset=utf-8',\n '.js': 'application/javascript; charset=utf-8',\n '.mjs': 'application/javascript; charset=utf-8',\n '.css': 'text/css; charset=utf-8',\n '.json': 'application/json; charset=utf-8',\n '.svg': 'image/svg+xml',\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.ico': 'image/x-icon',\n};\n\nlet cachedDistDir: string | null | undefined;\n\n/**\n * Resolve the HQ dashboard dist directory. Returns the absolute path to\n * `@wrongstack/webui-hq/dist`, or `null` when the package/dist is not\n * present (e.g. unbuilt). Result is cached for the process lifetime.\n */\nexport function resolveHqDistDir(): string | null {\n if (cachedDistDir !== undefined) return cachedDistDir;\n\n // Strategy 1: resolve the package root via its package.json export. The\n // \".\" entry points at dist/index.js which the vite build does NOT emit\n // (the package is an asset carrier \u2014 dist holds index.html + assets/), so\n // resolving the bare specifier throws ERR_PACKAGE_PATH_NOT_EXPORTED /\n // MODULE_NOT_FOUND and, before this fix, HQ silently ALWAYS fell back to\n // the legacy inline HTML.\n try {\n const pkgJson = requireFromHere.resolve('@wrongstack/webui-hq/package.json');\n const dist = path.join(path.dirname(pkgJson), 'dist');\n if (fs.existsSync(path.join(dist, 'index.html'))) {\n cachedDistDir = dist;\n return dist;\n }\n } catch {\n /* fall through to strategy 2 */\n }\n\n // Strategy 2: walk up from this module looking for the workspace/installed\n // package under node_modules (also covers older installs whose package.json\n // exports map does not expose \"./package.json\").\n try {\n let dir = path.dirname(new URL(import.meta.url).pathname.replace(/^\\/(\\w:)/, '$1'));\n for (let i = 0; i < 8; i++) {\n const candidate = path.join(dir, 'node_modules', '@wrongstack', 'webui-hq', 'dist');\n if (fs.existsSync(path.join(candidate, 'index.html'))) {\n cachedDistDir = candidate;\n return candidate;\n }\n const parent = path.dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n } catch {\n /* not found */\n }\n\n cachedDistDir = null;\n return null;\n}\n\n/** Check whether a resolved path stays inside the dist directory (no traversal). */\nfunction isInsideDist(filePath: string, distDir: string): boolean {\n const rel = path.relative(distDir, filePath);\n return rel !== '' && !rel.startsWith('..') && !path.isAbsolute(rel);\n}\n\nexport interface ServeStaticResult {\n handled: boolean;\n}\n\nfunction isMissingPath(error: unknown): boolean {\n const code = (error as NodeJS.ErrnoException).code;\n return code === 'ENOENT' || code === 'ENOTDIR';\n}\n\nasync function readRegularFile(filePath: string): Promise<Buffer | null> {\n try {\n const info = await fs.promises.stat(filePath);\n if (!info.isFile()) return null;\n return await fs.promises.readFile(filePath);\n } catch (error) {\n if (isMissingPath(error)) return null;\n throw error;\n }\n}\n\n/**\n * Serve a static file from the HQ dist for an HTTP request. Handles the SPA\n * fallback (unknown routes \u2192 index.html). Returns `{handled:false}` when the\n * dist is not available (caller should serve the diagnostic shell) or the\n * path doesn't match a static asset.\n */\nexport async function serveHqStatic(\n _req: http.IncomingMessage,\n res: http.ServerResponse,\n urlPath: string,\n distDir: string,\n): Promise<ServeStaticResult> {\n // Normalize: `/` \u2192 index.html; otherwise decode + resolve.\n const relPath = urlPath === '/' || urlPath === '' ? '/index.html' : urlPath;\n let decodedPath: string;\n try {\n decodedPath = decodeURIComponent(relPath);\n } catch {\n return { handled: false };\n }\n const filePath = path.join(distDir, decodedPath);\n\n if (!isInsideDist(filePath, distDir)) {\n return { handled: false };\n }\n\n const data = await readRegularFile(filePath);\n if (data === null) {\n // SPA fallback: serve index.html for client-side routes.\n const indexPath = path.join(distDir, 'index.html');\n const html = await readRegularFile(indexPath);\n if (html !== null) {\n res.writeHead(200, {\n 'Content-Type': MIME['.html']!,\n 'Cache-Control': 'no-cache',\n 'Content-Length': html.byteLength,\n });\n res.end(html);\n return { handled: true };\n }\n return { handled: false };\n }\n\n const ext = path.extname(filePath).toLowerCase();\n const mime = MIME[ext] ?? 'application/octet-stream';\n const cacheControl = decodedPath.startsWith('/assets/')\n ? 'public, max-age=31536000, immutable'\n : ext === '.html'\n ? 'no-cache'\n : 'public, max-age=3600';\n res.writeHead(200, {\n 'Content-Type': mime,\n 'Cache-Control': cacheControl,\n 'Content-Length': data.byteLength,\n });\n res.end(data);\n return { handled: true };\n}\n", "/**\n * HQ server \u2014 snapshot builders for browser push and HTTP API responses.\n *\n * @module hq-server/snapshot\n */\n\nimport type {\n HqBrowserMessage,\n HqClientCapability,\n HqClientRecord,\n HqCommandAuditEntry,\n HqEventEnvelope,\n HqFleetSnapshotPayload,\n HqFleetSummary,\n HqMachineRecord,\n HqMailboxSnapshotPayload,\n HqMailboxSummary,\n HqMcpServerHealth,\n HqPersistence,\n HqProjectRecord,\n HqSessionSnapshotPayload,\n HqSessionSummary,\n HqSnapshot,\n} from '@wrongstack/core/hq';\nimport { WebSocket } from 'ws';\nimport type { ConnectedClient, HqSnapshotBroadcaster, ProjectDetail } from './types.js';\nimport { hqMachineKey } from './utils.js';\n\n// \u2500\u2500 Broadcast debounce \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const HQ_SNAPSHOT_BROADCAST_DEBOUNCE_MS = 100;\n/**\n * Minimum spacing between disk checkpoints of snapshot.json. Browser broadcasts\n * stay at the 100ms debounce, but the on-disk checkpoint (only used to re-seed a\n * restarted HQ) does not need to be rewritten at broadcast rate. Throttling it\n * stops an idle HQ \u2014 running behind active local TUIs/REPLs with nobody viewing\n * the dashboard \u2014 from doing a full rebuild + atomic disk write at up to 10 Hz.\n */\nexport const HQ_SNAPSHOT_PERSIST_MIN_INTERVAL_MS = 3_000;\n\n/** Unsent bytes retained for one dashboard socket before it is disconnected. */\nexport const HQ_BROWSER_MAX_BUFFERED_BYTES = 32 * 1024 * 1024;\n\n/**\n * Send an already-serialized frame to a WebSocket peer, enforcing\n * per-client backpressure.\n *\n * A `readyState === OPEN` check alone says the socket is connected, not that\n * anyone is reading it. `ws` buffers whatever it cannot flush, so a tab that\n * stalled \u2014 backgrounded, throttled, paused in devtools \u2014 makes this process\n * retain every subsequent broadcast for it. These are full fleet snapshots,\n * historically as large as 9 MB each, which is the difference between a\n * bounded cost and an unbounded one.\n *\n * Mirrors `sendSerialized` in `@wrongstack/webui-server`, deliberately\n * duplicated rather than imported: HQ's snapshot path is in the CLI's\n * always-loaded graph, and a static import would drag that whole package into\n * boot, which the CLI keeps behind a lazy import on purpose.\n */\nexport function sendGuarded(ws: WebSocket, data: string): boolean {\n if (ws.readyState !== WebSocket.OPEN) return false;\n const buffered = Number.isFinite(ws.bufferedAmount) ? ws.bufferedAmount : 0;\n if (buffered + Buffer.byteLength(data, 'utf8') > HQ_BROWSER_MAX_BUFFERED_BYTES) {\n try {\n ws.terminate();\n } catch {\n try {\n ws.close(1013, 'client cannot keep up');\n } catch {\n // Socket is already gone.\n }\n }\n return false;\n }\n try {\n ws.send(data);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * How long a session/fleet snapshot may go unrefreshed before it is treated\n * as gone.\n *\n * `session.ended` is the only thing that used to remove these entries, so any\n * session that died without sending one \u2014 crash, SIGKILL, dropped network,\n * closed laptop \u2014 stayed in its client's map for as long as the socket lived.\n * That is both retained memory and, worse, permanent weight in every\n * `buildSnapshot()` broadcast to every browser.\n *\n * A live session republishes unconditionally every 2.5s (`session-bridge.ts`\n * forces the snapshot on a timer, bypassing its own dedupe hash), so\n * `receivedAt` is a true liveness signal rather than a change signal. Five\n * minutes is 120 consecutive missed publishes \u2014 far past any GC pause,\n * scheduler stall, or transient hiccup, so this never evicts a live session.\n */\nexport const HQ_STALE_SNAPSHOT_MS = 5 * 60_000;\n\n/**\n * Drop session/fleet/MCP entries whose publisher has stopped refreshing them.\n *\n * Runs from `buildSnapshot` because that is exactly the moment stale entries\n * would otherwise be serialized into a broadcast \u2014 no separate timer to own,\n * and no window where a reaped entry is still visible to a reader.\n */\nexport function reapStaleClientState(\n clients: Map<WebSocket, ConnectedClient>,\n nowMs: number = Date.now(),\n): void {\n for (const client of clients.values()) {\n for (const [sessionId, tracked] of client.sessions) {\n if (nowMs - tracked.receivedAt > HQ_STALE_SNAPSHOT_MS) client.sessions.delete(sessionId);\n }\n for (const [runId, fleet] of client.fleets) {\n if (nowMs - fleet.receivedAt > HQ_STALE_SNAPSHOT_MS) client.fleets.delete(runId);\n }\n // MCP health ages on its own clock rather than following `sessions`:\n // a health snapshot can arrive before the session's first snapshot (and\n // is keyed 'unknown' when the envelope carries no sessionId), so keying\n // its lifetime off session membership would drop it in that window.\n for (const [sessionId, tracked] of client.mcpSnapshots) {\n if (nowMs - tracked.receivedAt > HQ_STALE_SNAPSHOT_MS) client.mcpSnapshots.delete(sessionId);\n }\n }\n}\n\n// \u2500\u2500 buildSnapshot \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function buildSnapshot(\n clients: Map<WebSocket, ConnectedClient>,\n options?: { tokenStats?: HqSnapshot['totals']['tokenStats'] },\n): HqSnapshot {\n reapStaleClientState(clients);\n const now = new Date().toISOString();\n // Dedupe client records by clientId \u2014 one process may hold two sockets (a\n // mailbox publisher + a telemetry publisher) sharing the same clientId.\n const clientRecordById = new Map<string, HqClientRecord>();\n const projectMap = new Map<string, HqProjectRecord>();\n const mailboxSummaries: HqMailboxSummary[] = [];\n // Live sessions, deduped by sessionId across sockets (latest wins).\n const sessionById = new Map<string, HqSessionSnapshotPayload>();\n // Fleet snapshots, deduped by runId across sockets (latest wins).\n const fleetByRunId = new Map<\n string,\n { payload: HqFleetSnapshotPayload; clientId: string; projectId: string; lastActivityAt: string }\n >();\n\n for (const client of clients.values()) {\n const machineId = client.machineId || client.project.machineId || '';\n if (!clientRecordById.has(client.clientId)) {\n clientRecordById.set(client.clientId, {\n clientId: client.clientId,\n kind: client.kind as HqClientRecord['kind'],\n machineId,\n ...(client.hostname ? { hostname: client.hostname } : {}),\n ...(client.pid ? { pid: client.pid } : {}),\n ...(client.version ? { version: client.version } : {}),\n connected: true,\n connectedAt: client.connectedAt,\n lastSeenAt: client.lastSeenAt,\n projectId: client.projectId,\n capabilities: client.capabilities as readonly HqClientCapability[],\n });\n }\n\n let project = projectMap.get(client.projectId);\n if (!project) {\n project = {\n projectId: client.projectId,\n projectName: client.project.projectName || client.projectId,\n projectRootDisplay: client.project.projectRoot,\n machineIds: [machineId],\n ...(client.project.gitBranch ? { gitBranch: client.project.gitBranch } : {}),\n activeClients: 0,\n activeSessions: 0,\n activeSubagents: 0,\n totalCostUsd: 0,\n lastActivityAt: now,\n status: 'active',\n };\n projectMap.set(client.projectId, project);\n } else if (machineId && !project.machineIds.includes(machineId)) {\n project.machineIds = [...project.machineIds, machineId];\n }\n\n for (const tracked of client.sessions.values()) {\n const cutoff = Date.now() - 5 * 60_000;\n const agents = tracked.payload.agents.filter((agent) => {\n if (agent.id === 'leader') return true;\n const lastActivityAt = Date.parse(agent.lastActivityAt);\n return Number.isFinite(lastActivityAt) && lastActivityAt >= cutoff;\n });\n sessionById.set(tracked.payload.sessionId, {\n ...tracked.payload,\n clientId: client.clientId,\n agents,\n agentCount: agents.length,\n });\n }\n\n for (const snapshot of client.mailboxes.values()) {\n mailboxSummaries.push({\n mailboxId: snapshot.mailboxId,\n projectId: client.projectId,\n scope: snapshot.scope,\n messageCount: snapshot.totals.messages,\n unreadCount: snapshot.totals.unread,\n incompleteCount: snapshot.totals.incomplete,\n highPriorityCount: snapshot.totals.highPriority,\n onlineAgentCount: snapshot.totals.onlineAgents,\n lastActivityAt: now,\n });\n }\n\n // Collect fleet snapshots \u2014 latest per runId wins.\n for (const fleet of client.fleets.values()) {\n fleetByRunId.set(fleet.payload.runId, {\n payload: fleet.payload,\n clientId: client.clientId,\n projectId: client.projectId,\n lastActivityAt: new Date(fleet.receivedAt).toISOString(),\n });\n }\n }\n\n // One PROCESS = one client. A single wstack process legitimately holds\n // several publisher sockets (session telemetry + mailbox + webui), so\n // counting client records would inflate every client counter 2-3\u00D7.\n const processKeyOf = (rec: HqClientRecord): string =>\n rec.pid !== undefined ? `${rec.machineId}:${rec.pid}` : rec.clientId;\n\n // Per-project active-client counts \u2014 distinct processes per project.\n const countedProjectProcesses = new Set<string>();\n for (const rec of clientRecordById.values()) {\n const key = `${rec.projectId}|${processKeyOf(rec)}`;\n if (countedProjectProcesses.has(key)) continue;\n countedProjectProcesses.add(key);\n const project = projectMap.get(rec.projectId);\n if (project) project.activeClients++;\n }\n\n // Fold live sessions into projects + machines.\n const liveSessions = Array.from(sessionById.values());\n const machineMap = new Map<string, { record: HqMachineRecord; projects: Set<string> }>();\n let totalAgents = 0;\n let totalSubagents = 0;\n let totalCostUsd = 0;\n\n for (const session of liveSessions) {\n // Ensure the project exists even if only a session (no mailbox/client\n // record under this projectId yet) reported it.\n let project = projectMap.get(session.projectId);\n if (!project) {\n project = {\n projectId: session.projectId,\n projectName: session.projectName || session.projectId,\n projectRootDisplay: session.projectRoot,\n machineIds: [session.machineId],\n ...(session.gitBranch ? { gitBranch: session.gitBranch } : {}),\n activeClients: 0,\n activeSessions: 0,\n activeSubagents: 0,\n totalCostUsd: 0,\n lastActivityAt: session.lastActivityAt,\n status: 'active',\n };\n projectMap.set(session.projectId, project);\n } else if (session.machineId && !project.machineIds.includes(session.machineId)) {\n project.machineIds = [...project.machineIds, session.machineId];\n }\n project.activeSessions++;\n\n let sessionCost = 0;\n for (const agent of session.agents) {\n totalAgents++;\n if (agent.id !== 'leader') totalSubagents++;\n if (typeof agent.costUsd === 'number') {\n sessionCost += agent.costUsd;\n }\n }\n project.activeSubagents += session.agents.filter((a) => a.id !== 'leader').length;\n project.totalCostUsd += sessionCost;\n totalCostUsd += sessionCost;\n\n // Machine aggregation \u2014 keyed by hostname so the SAME computer is one\n // machine even when clients report different per-process machineIds.\n const mKey = hqMachineKey(session.hostname, session.machineId);\n let machine = machineMap.get(mKey);\n if (!machine) {\n machine = {\n record: {\n machineId: session.machineId,\n ...(session.hostname ? { hostname: session.hostname } : {}),\n clientCount: 0,\n sessionCount: 0,\n agentCount: 0,\n projectIds: [],\n lastActivityAt: session.lastActivityAt,\n },\n projects: new Set<string>(),\n };\n machineMap.set(mKey, machine);\n }\n machine.record.sessionCount++;\n machine.record.agentCount += session.agents.length;\n machine.projects.add(session.projectId);\n if (session.lastActivityAt > machine.record.lastActivityAt) {\n machine.record.lastActivityAt = session.lastActivityAt;\n }\n }\n\n // Attribute connected clients to machines too (so a machine with a client\n // but no session yet still appears). clientCount is per PROCESS, not per\n // publisher socket \u2014 see processKeyOf above.\n const countedMachineProcesses = new Set<string>();\n for (const rec of clientRecordById.values()) {\n if (!rec.machineId && !rec.hostname) continue;\n const rKey = hqMachineKey(rec.hostname, rec.machineId);\n let machine = machineMap.get(rKey);\n if (!machine) {\n machine = {\n record: {\n machineId: rec.machineId,\n ...(rec.hostname ? { hostname: rec.hostname } : {}),\n clientCount: 0,\n sessionCount: 0,\n agentCount: 0,\n projectIds: [],\n lastActivityAt: rec.lastSeenAt,\n },\n projects: new Set<string>(),\n };\n machineMap.set(rKey, machine);\n }\n const processKey = `${rKey}|${processKeyOf(rec)}`;\n if (!countedMachineProcesses.has(processKey)) {\n countedMachineProcesses.add(processKey);\n machine.record.clientCount++;\n }\n machine.projects.add(rec.projectId);\n if (rec.hostname && !machine.record.hostname) machine.record.hostname = rec.hostname;\n }\n\n const machines: HqMachineRecord[] = Array.from(machineMap.values()).map((m) => ({\n ...m.record,\n projectIds: Array.from(m.projects),\n }));\n\n const clientRecords = Array.from(clientRecordById.values());\n const projects = Array.from(projectMap.values());\n\n let unread = 0;\n let incomplete = 0;\n for (const m of mailboxSummaries) {\n unread += m.unreadCount;\n incomplete += m.incompleteCount;\n }\n\n // Derive session summaries from live sessions (the spine of the fleet tree)\n // so the dashboard's sessions[] rollup is populated alongside liveSessions.\n const sessions: HqSessionSummary[] = liveSessions.map((s) => {\n let sessionCost = 0;\n for (const agent of s.agents) {\n if (typeof agent.costUsd === 'number') sessionCost += agent.costUsd;\n }\n const provider = s.agents.find((a) => a.model !== undefined)?.model;\n return {\n sessionId: s.sessionId,\n projectId: s.projectId,\n clientId: s.clientId ?? `${s.machineId}:${s.clientKind}`,\n status: s.status === 'active' ? 'running' : 'idle',\n ...(provider !== undefined ? { model: provider } : {}),\n startedAt: s.startedAt,\n lastActivityAt: s.lastActivityAt,\n ...(sessionCost > 0 ? { costUsd: sessionCost } : {}),\n };\n });\n\n // Derive fleet summaries from collected coordinator snapshots so the\n // dashboard's fleets[] rollup reflects every connected machine's fleet.\n const fleets: HqFleetSummary[] = Array.from(fleetByRunId.values()).map((f) => ({\n runId: f.payload.runId,\n projectId: f.projectId,\n clientId: f.clientId,\n activeSubagents: f.payload.activeSubagents,\n queuedTasks: f.payload.queuedTasks,\n completedTasks: f.payload.completedTasks,\n failedTasks: f.payload.failedTasks,\n ...(f.payload.totalCostUsd !== undefined ? { totalCostUsd: f.payload.totalCostUsd } : {}),\n lastActivityAt: f.lastActivityAt,\n }));\n\n // Collect MCP server health \u2014 latest per (client, sessionId, serverName).\n const mcpServers: HqMcpServerHealth[] = [];\n const seenMcp = new Set<string>();\n for (const client of clients.values()) {\n for (const [sessionId, tracked] of client.mcpSnapshots.entries()) {\n for (const server of tracked.servers) {\n const key = `${client.clientId}:${sessionId}:${server.name}`;\n if (seenMcp.has(key)) continue;\n seenMcp.add(key);\n mcpServers.push(server);\n }\n }\n }\n\n return {\n generatedAt: now,\n clients: clientRecords,\n projects,\n sessions,\n fleets,\n mailboxes: mailboxSummaries,\n machines,\n liveSessions,\n mcpServers,\n totals: {\n activeProjects: projects.length,\n activeClients: new Set(clientRecords.map(processKeyOf)).size,\n activeSessions: liveSessions.length,\n activeSubagents: totalSubagents,\n unreadMailboxMessages: unread,\n incompleteMailboxMessages: incomplete,\n totalCostUsd,\n activeMachines: machines.length,\n activeAgents: totalAgents,\n ...(options?.tokenStats !== undefined ? { tokenStats: options.tokenStats } : {}),\n },\n };\n}\n\n// \u2500\u2500 Snapshot broadcaster \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function createSnapshotBroadcaster(\n clients: Map<WebSocket, ConnectedClient>,\n browsers: Set<WebSocket>,\n persistence?: HqPersistence,\n): HqSnapshotBroadcaster {\n let cached = '';\n let dirty = true;\n let timer: NodeJS.Timeout | null = null;\n let closed = false;\n let lastPersistAt = 0;\n\n const persistCheckpoint = (snapshot: HqSnapshot): void => {\n if (persistence === undefined) return;\n const now = Date.now();\n if (now - lastPersistAt < HQ_SNAPSHOT_PERSIST_MIN_INTERVAL_MS) return;\n lastPersistAt = now;\n // Best-effort, fire-and-forget so a restarted HQ can re-seed from disk.\n persistence.snapshotStore.save(snapshot);\n };\n\n const serialize = (): string => {\n if (!dirty && cached.length > 0) return cached;\n const snapshot = buildSnapshot(clients);\n const msg: HqBrowserMessage = { type: 'hq.snapshot', snapshot };\n cached = JSON.stringify(msg);\n dirty = false;\n persistCheckpoint(snapshot);\n return cached;\n };\n\n const flush = (): void => {\n timer = null;\n if (browsers.size === 0) {\n // No dashboard viewer: skip the browser (de)serialize entirely \u2014 the\n // expensive full-tree JSON.stringify is wasted with no recipient. Keep the\n // on-disk checkpoint fresh only on the slow throttled cadence.\n if (\n persistence !== undefined &&\n Date.now() - lastPersistAt >= HQ_SNAPSHOT_PERSIST_MIN_INTERVAL_MS\n ) {\n persistCheckpoint(buildSnapshot(clients));\n }\n return;\n }\n const data = serialize();\n for (const ws of browsers) sendGuarded(ws, data);\n };\n\n return {\n currentSerialized: serialize,\n broadcast: () => {\n // Socket close callbacks can arrive after the HQ handle has begun\n // shutting down. Do not let those callbacks recreate the debounce\n // timer and write snapshot.json after close() has already drained it.\n if (closed) return;\n dirty = true;\n if (timer !== null) return;\n timer = setTimeout(flush, HQ_SNAPSHOT_BROADCAST_DEBOUNCE_MS);\n timer.unref?.();\n },\n close: () => {\n closed = true;\n if (timer !== null) {\n clearTimeout(timer);\n timer = null;\n }\n },\n };\n}\n\n// \u2500\u2500 Project detail \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function buildProjectDetail(\n clients: Map<WebSocket, ConnectedClient>,\n projectId: string,\n): ProjectDetail | null {\n const projectClients: ConnectedClient[] = [];\n for (const c of clients.values()) {\n if (c.projectId === projectId) projectClients.push(c);\n }\n if (projectClients.length === 0) return null;\n\n const now = new Date().toISOString();\n const clientRecords: HqClientRecord[] = projectClients.map((c) => ({\n clientId: c.clientId,\n kind: c.kind as HqClientRecord['kind'],\n machineId: '',\n ...(c.hostname ? { hostname: c.hostname } : {}),\n ...(c.pid ? { pid: c.pid } : {}),\n ...(c.version ? { version: c.version } : {}),\n connected: true,\n connectedAt: c.connectedAt,\n lastSeenAt: c.lastSeenAt,\n projectId: c.projectId,\n capabilities: c.capabilities as readonly HqClientCapability[],\n }));\n\n const mailboxPayloads: HqMailboxSnapshotPayload[] = [];\n let latestActivity = now;\n for (const c of projectClients) {\n for (const snap of c.mailboxes.values()) {\n mailboxPayloads.push(snap);\n if (snap.totals.messages > 0) latestActivity = now;\n }\n }\n\n const primaryProject = projectClients[0]!.project;\n const machineIds = Array.from(new Set(projectClients.map((client) => client.project.machineId)));\n const project: HqProjectRecord = {\n projectId,\n projectName: primaryProject.projectName || projectId,\n projectRootDisplay: primaryProject.projectRoot,\n machineIds,\n ...(primaryProject.gitBranch ? { gitBranch: primaryProject.gitBranch } : {}),\n activeClients: projectClients.length,\n activeSessions: 0,\n activeSubagents: 0,\n totalCostUsd: 0,\n lastActivityAt: latestActivity,\n status: 'active',\n };\n\n return {\n generatedAt: now,\n project,\n clients: clientRecords,\n mailboxes: mailboxPayloads,\n };\n}\n\n// \u2500\u2500 Event broadcast \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function broadcastEvent(event: HqEventEnvelope, browsers: Set<WebSocket>): void {\n const msg: HqBrowserMessage = { type: 'hq.event', event };\n const data = JSON.stringify(msg);\n for (const ws of browsers) sendGuarded(ws, data);\n}\n\n/** Push one control command's lifecycle to every authenticated HQ browser. */\nexport function broadcastCommandStatus(\n command: HqCommandAuditEntry,\n browsers: Set<WebSocket>,\n): void {\n const data = JSON.stringify({ type: 'hq.command_status', command } satisfies HqBrowserMessage);\n for (const ws of browsers) sendGuarded(ws, data);\n}\n", "/**\n * HQ server \u2014 general utility functions.\n *\n * @module hq-server/utils\n */\n\nimport * as fs from 'node:fs/promises';\nimport type * as http from 'node:http';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport type { HqEventEnvelope, HqPersistence, HqTranscriptEntry } from '@wrongstack/core/hq';\nimport { resolveHqDataDir } from '@wrongstack/core/hq';\n\n// \u2500\u2500 Constants \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const TRANSCRIPT_RING_MAX = 4000;\nexport const MAX_TRANSCRIPT_SESSIONS = 400;\nexport const MAX_AGENT_RINGS = 800;\n\n// \u2500\u2500 Map eviction (LRU-by-insertion-order) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Evict oldest entries from a Map until its size \u2264 max.\n * Maps are insertion-ordered, so iterating keys() gives the oldest first.\n */\nexport function evictOldest(map: Map<string, unknown>, max: number): void {\n while (map.size > max) {\n const oldest = map.keys().next().value;\n if (oldest === undefined) break;\n map.delete(oldest);\n }\n}\n\n// \u2500\u2500 Transcript helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Ring key for one subagent's transcript. Scoped by session so same-named\n * agents in different sessions (every leader is id 'leader') stay separate.\n * Falls back to the bare subId when no session id is known (legacy clients).\n */\nexport function agentRingKey(sessionId: string | undefined, subId: string): string {\n return sessionId ? `${sessionId}::${subId}` : subId;\n}\n\n/**\n * Convert an `agent.message` payload record into a `HqTranscriptEntry` that\n * is compact and viewable in the HQ session timeline. Mirrors the mapping the\n * TUI-side buffered-transcript writer applies so the HQ stream looks\n * identically to the live stream (thinking\u2192thinking, system/status\u2192system).\n */\nexport function agentMessageToEntry(p: Record<string, unknown>): HqTranscriptEntry {\n const kind = typeof p['kind'] === 'string' ? p['kind'] : 'text';\n const role: HqTranscriptEntry['role'] =\n kind === 'thinking'\n ? 'thinking'\n : kind === 'tool_use' || kind === 'tool_result'\n ? 'tool'\n : kind === 'error'\n ? 'error'\n : kind === 'status' || kind === 'system'\n ? 'system'\n : 'assistant';\n return {\n ts: typeof p['ts'] === 'string' ? p['ts'] : new Date().toISOString(),\n role,\n text: typeof p['content'] === 'string' ? p['content'] : '',\n ...(typeof p['toolName'] === 'string' ? { tool: p['toolName'] } : {}),\n ...(kind === 'error' ? { isError: true } : {}),\n };\n}\n\n/**\n * Read one local subagent's FULL conversation from disk. The agent monitor\n * writes every timeline entry to\n * <projectSessions>/<sessionId>/subagents/transcripts/<subId>/transcript.jsonl\n * so for sessions on THIS machine we can serve the complete history \u2014 not\n * just the \u22644000-entry live ring. Returns null when the session isn't local\n * or the file is absent (caller falls back to the ring).\n */\nexport async function readLocalSubagentTranscript(\n sessionId: string,\n subagentId: string,\n): Promise<HqTranscriptEntry[] | null> {\n try {\n const { SessionRegistry } = await import('@wrongstack/core/storage');\n const { resolveWstackPaths, sessionScopedPath } = await import('@wrongstack/core/utils');\n const globalRoot = path.dirname(resolveHqDataDir());\n const registry = new SessionRegistry(globalRoot);\n const entry = await registry.get(sessionId).catch(() => null);\n if (!entry) return null; // remote session \u2014 no local disk to read\n const paths = resolveWstackPaths({ projectRoot: entry.projectRoot, globalRoot });\n const sessionDir = sessionScopedPath(paths.projectSessions, sessionId, '');\n const file = path.join(sessionDir, 'subagents', 'transcripts', subagentId, 'transcript.jsonl');\n const raw = await fs.readFile(file, 'utf8').catch(() => null);\n if (raw === null) return null;\n const out: HqTranscriptEntry[] = [];\n for (const line of raw.split('\\n')) {\n const trimmed = line.trim();\n if (trimmed.length === 0) continue;\n try {\n out.push(agentMessageToEntry(JSON.parse(trimmed) as Record<string, unknown>));\n } catch {\n // Skip a torn/partial trailing line \u2014 best-effort replay.\n }\n }\n return out;\n } catch {\n return null;\n }\n}\n\n// \u2500\u2500 String/path utilities \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Safe URL-decoding \u2014 returns null on malformed input. */\nexport function decodePathSegment(value: string): string | null {\n try {\n return decodeURIComponent(value);\n } catch {\n return null;\n }\n}\n\n/** Normalize display host \u2014 \"0.0.0.0\" prints as \"127.0.0.1\" for user-facing URLs. */\nexport function displayHost(host: string): string {\n return host === '0.0.0.0' ? '127.0.0.1' : host;\n}\n\n// \u2500\u2500 HTTP body helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nclass RequestBodyTooLargeError extends Error {}\n\n/** Read the full body of an HTTP request as a UTF-8 string (capped at 1 MB). */\nexport function readRequestBody(req: http.IncomingMessage, maxBytes = 1_000_000): Promise<string> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n let size = 0;\n let settled = false;\n req.on('data', (chunk: Buffer) => {\n if (settled) return;\n size += chunk.length;\n if (size > maxBytes) {\n settled = true;\n chunks.length = 0;\n reject(new RequestBodyTooLargeError('request body too large'));\n return;\n }\n chunks.push(chunk);\n });\n req.on('end', () => {\n if (!settled) resolve(Buffer.concat(chunks).toString('utf8'));\n });\n req.on('error', (error) => {\n if (!settled) reject(error);\n });\n });\n}\n\nexport function writeInvalidBody(res: http.ServerResponse, error: unknown): void {\n const tooLarge = error instanceof RequestBodyTooLargeError;\n res.writeHead(tooLarge ? 413 : 400, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: tooLarge ? 'request body too large' : 'invalid json body' }));\n}\n\n// \u2500\u2500 URL builders \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function buildHttpUrl(host: string, port: number, token?: string): string {\n const url = new URL(`http://${displayHost(host)}:${port}/`);\n if (token) url.searchParams.set('token', token);\n return url.toString();\n}\n\n/**\n * Build the browser startup URL with a one-time bootstrap code in the\n * fragment (`#bootstrap=\u2026`). Fragments never reach HTTP access logs,\n * Referer headers, or proxy caches \u2014 unlike query-string tokens. The\n * SPA extracts the fragment, POSTs it to `/api/auth/bootstrap`, and\n * receives only an HttpOnly session cookie.\n */\nexport function buildBootstrapHttpUrl(host: string, port: number, bootstrapCode: string): string {\n const url = new URL(`http://${displayHost(host)}:${port}/`);\n url.hash = `bootstrap=${bootstrapCode}`;\n return url.toString();\n}\n\nexport function buildClientWsUrl(host: string, port: number, token?: string): string {\n const url = new URL(`ws://${displayHost(host)}:${port}/ws/client`);\n if (token) url.searchParams.set('token', token);\n return url.toString();\n}\n\n// \u2500\u2500 Runtime marker \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function hqRuntimeMarkerPath(dataDir: string): string {\n return path.join(dataDir, 'runtime.json');\n}\n\n// \u2500\u2500 LAN addresses \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Non-internal IPv4 addresses, so we can print URLs reachable from other machines. */\nexport function lanIPv4Addresses(): string[] {\n const out: string[] = [];\n try {\n const ifaces = os.networkInterfaces();\n for (const name of Object.keys(ifaces)) {\n for (const ni of ifaces[name] ?? []) {\n if (ni.family === 'IPv4' && !ni.internal) out.push(ni.address);\n }\n }\n } catch {\n // best-effort\n }\n return out;\n}\n\n// \u2500\u2500 String truncation (safe for summaries) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function truncateHqSummary(value: unknown, maxLength: number): string | undefined {\n if (typeof value !== 'string' || value.length === 0) return undefined;\n if (value.length <= maxLength) return value;\n return `${value.slice(0, maxLength)}\u2026[truncated:${value.length - maxLength}]`;\n}\n\n// \u2500\u2500 Machine key \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Stable per-machine key. Prefers hostname so the same physical computer maps\n * to one machine even when clients report different per-process machineIds\n * (older builds hashed `hostname:pid`). Falls back to machineId.\n */\nexport function hqMachineKey(hostname: string | undefined, machineId: string | undefined): string {\n const hn = hostname?.trim();\n return hn ? `host:${hn.toLowerCase()}` : `mid:${machineId || 'local'}`;\n}\n\n// \u2500\u2500 Timeseries signal extraction \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Fold a cost/tool signal from an event envelope into the timeseries store.\n * Recognizes `session.usage` (cost/tokens, plus model/provider/cache\n * dimensions) and `tool.completed` (tool call). Best-effort, never throws.\n */\nexport function recordTimeseriesSignal(persistence: HqPersistence, event: HqEventEnvelope): void {\n try {\n if (event.type === 'session.usage') {\n const p = event.payload as {\n costUsd?: number;\n inputTokens?: number;\n outputTokens?: number;\n model?: string;\n provider?: string;\n cacheRead?: number;\n cacheWrite?: number;\n };\n persistence.timeseries.record({\n ts: Date.parse(event.timestamp) || Date.now(),\n ...(typeof p.costUsd === 'number' ? { costUsd: p.costUsd } : {}),\n ...(typeof p.inputTokens === 'number' ? { inputTokens: p.inputTokens } : {}),\n ...(typeof p.outputTokens === 'number' ? { outputTokens: p.outputTokens } : {}),\n ...(typeof p.model === 'string' && p.model.length > 0 ? { model: p.model } : {}),\n ...(typeof p.provider === 'string' && p.provider.length > 0 ? { provider: p.provider } : {}),\n ...(typeof p.cacheRead === 'number' ? { cacheRead: p.cacheRead } : {}),\n ...(typeof p.cacheWrite === 'number' ? { cacheWrite: p.cacheWrite } : {}),\n });\n } else if (event.type === 'tool.completed') {\n persistence.timeseries.record({\n ts: Date.parse(event.timestamp) || Date.now(),\n toolCalls: 1,\n });\n }\n } catch {\n /* best-effort */\n }\n}\n\n// \u2500\u2500 API error sanitization \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Coerce a thrown error into a safe, opaque message for HTTP/JSON API\n * responses. Raw error strings (file paths, environment details, stack\n * fragments) are never forwarded to the browser \u2014 only a stable category.\n * The original error is logged server-side by the caller.\n */\nexport function sanitizeApiError(err: unknown): string {\n const message = err instanceof Error ? err.message : String(err);\n // Classify a few well-known shapes without echoing their text verbatim.\n const lower = message.toLowerCase();\n if (lower.includes('enoent') || lower.includes('no such file')) {\n return 'resource not found';\n }\n if (lower.includes('eacces') || lower.includes('permission')) {\n return 'permission denied';\n }\n if (lower.includes('json') && (lower.includes('parse') || lower.includes('unexpected'))) {\n return 'malformed data';\n }\n // Default: a generic label \u2014 the detail stays server-side.\n return 'internal error';\n}\n", "import type { HqCommand } from '@wrongstack/core/hq';\nimport { isTrustDecisionAllowed, type TrustBoundary, type TrustBoundaryRequest } from '@wrongstack/core/security';\nimport type { ConnectedClient } from './types.js';\n\nexport async function authorizeHqCommand(input: {\n boundary: TrustBoundary;\n command: HqCommand;\n commandId: string;\n enqueuedBy: string;\n authMethod: 'session' | 'bearer-token';\n target: ConnectedClient;\n}): Promise<{ allowed: boolean; reason: string }> {\n const { boundary, command, commandId, enqueuedBy, authMethod, target } = input;\n const subject =\n command.type === 'run-command'\n ? {\n kind: 'command' as const,\n id: command.command,\n attributes: { targetClientId: target.clientId },\n }\n : {\n kind: 'custom' as const,\n id: command.type,\n attributes: { targetClientId: target.clientId },\n };\n const request: TrustBoundaryRequest = {\n version: 1,\n requestId: commandId,\n // This request is initiated by the authenticated HQ operator. Browser and\n // target-client capability checks have already passed before this adapter\n // is called, so classifying it as an unauthenticated remote client would\n // make the compatibility policy deny every legitimate run-command.\n actor: { kind: 'user', id: enqueuedBy },\n surface: 'hq',\n capability: command.type === 'run-command' ? 'hq.control.execute' : 'hq.control.enqueue',\n subject,\n risk: command.type === 'run-command' ? 'critical' : 'high',\n scope: { projectId: target.projectId },\n authContext: { method: authMethod, principalId: enqueuedBy },\n metadata: { commandType: command.type, targetKind: target.kind },\n };\n const decision = await boundary.evaluate(request);\n console.warn(\n JSON.stringify({\n level: 'info',\n event: 'hq.trust_boundary.decision',\n requestId: commandId,\n capability: request.capability,\n decision: decision.kind,\n policyId: decision.policyId,\n actor: enqueuedBy,\n clientId: target.clientId,\n timestamp: new Date().toISOString(),\n }),\n );\n return { allowed: isTrustDecisionAllowed(decision), reason: decision.reason };\n}\n", "import { randomUUID } from 'node:crypto';\nimport type * as http from 'node:http';\nimport {\n DEFAULT_HQ_REDACTION_POLICY,\n hashHqPassword,\n isLoopbackHost,\n mintHqCookieSecret,\n mutateHqAuthFile,\n verifyHqPassword,\n type HqAlertRuleConfig,\n type HqRedactionPolicy,\n type HqToken,\n} from '@wrongstack/core/hq';\nimport {\n authenticateBrowserRequest,\n clearHqSessionCookie,\n HQ_SESSION_COOKIE,\n isCookieAuth,\n isTokenAuth,\n parseCookieHeader,\n parseHqSessionCookie,\n serializeHqSessionCookie,\n setHqSessionCookie,\n} from '../auth.js';\nimport type { HqRouterMutableAuth, HqSessionEntry } from '../types.js';\nimport { readRequestBody, writeInvalidBody } from '../utils.js';\n\nfunction isLoopbackRequest(req: http.IncomingMessage): boolean {\n const address = req.socket.remoteAddress?.replace(/^::ffff:/, '');\n return address !== undefined && isLoopbackHost(address);\n}\n\nexport async function handleApiAuthStatus(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n url: URL,\n mutableAuth: HqRouterMutableAuth,\n sessions: Map<string, HqSessionEntry>,\n requireBrowserAuth: boolean | undefined,\n trustedPublicOrigins: Set<string>,\n secureCookies: boolean | undefined,\n): Promise<void> {\n const auth = authenticateBrowserRequest(req, url, mutableAuth, sessions);\n const openMode =\n mutableAuth.browserTokens.size === 0 && mutableAuth.passwordHash === undefined;\n const localOpenMode = openMode && !requireBrowserAuth && isLoopbackRequest(req);\n const publicOrigin = trustedPublicOrigins.values().next().value;\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n tokenMode: mutableAuth.browserTokens.size > 0,\n passwordMode: mutableAuth.passwordHash !== undefined,\n publicRelay: requireBrowserAuth === true || publicOrigin !== undefined,\n ...(publicOrigin !== undefined ? { publicOrigin } : {}),\n secureCookies: secureCookies === true,\n loggedIn: auth !== undefined || localOpenMode,\n authKind:\n isCookieAuth(auth)\n ? 'password'\n : isTokenAuth(auth)\n ? 'token'\n : localOpenMode\n ? 'open'\n : undefined,\n }),\n );\n}\n\nexport async function handleApiLogin(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n mutableAuth: HqRouterMutableAuth,\n sessions: Map<string, HqSessionEntry>,\n loginAttempts: Map<string, { count: number; blockedUntil: number; lastAttempt: number }>,\n secureCookies: boolean | undefined,\n): Promise<void> {\n if (!mutableAuth.passwordHash) {\n res.writeHead(403, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n error: {\n code: 'PASSWORD_NOT_CONFIGURED',\n message: 'Password login is not enabled on this HQ server.',\n },\n }),\n );\n return;\n }\n\n const clientIp = req.socket.remoteAddress ?? 'unknown';\n const existing = loginAttempts.get(clientIp);\n if (existing && existing.blockedUntil > Date.now()) {\n const retryAfter = Math.ceil((existing.blockedUntil - Date.now()) / 1000);\n res.writeHead(429, {\n 'Content-Type': 'application/json',\n 'Retry-After': String(retryAfter),\n });\n res.end(\n JSON.stringify({\n error: {\n code: 'RATE_LIMITED',\n message: `Too many failed login attempts. Retry after ${retryAfter} seconds.`,\n },\n }),\n );\n return;\n }\n\n let body: { password?: unknown };\n try {\n body = JSON.parse(await readRequestBody(req)) as { password?: unknown };\n } catch (error) {\n writeInvalidBody(res, error);\n return;\n }\n\n if (typeof body.password !== 'string' || body.password.length === 0) {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({ error: { code: 'BAD_REQUEST', message: 'password is required' } }),\n );\n return;\n }\n\n const ok = await verifyHqPassword(body.password, mutableAuth.passwordHash);\n if (!ok || !mutableAuth.cookieSecret) {\n const prev = loginAttempts.get(clientIp);\n const count = (prev?.count ?? 0) + 1;\n const backoffMs = Math.min(2 ** count * 1000, 16_000);\n loginAttempts.set(clientIp, {\n count,\n blockedUntil: Date.now() + backoffMs,\n lastAttempt: Date.now(),\n });\n res.writeHead(401, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({ error: { code: 'INVALID_PASSWORD', message: 'Invalid password.' } }),\n );\n return;\n }\n\n loginAttempts.delete(clientIp);\n const sessionId = randomUUID();\n sessions.set(sessionId, { createdAt: Date.now(), kind: 'password' });\n setHqSessionCookie(\n res,\n serializeHqSessionCookie(sessionId, mutableAuth.cookieSecret),\n secureCookies,\n );\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ loggedIn: true }));\n}\n\nexport async function handleApiLogout(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n mutableAuth: HqRouterMutableAuth,\n sessions: Map<string, HqSessionEntry>,\n secureCookies: boolean | undefined,\n): Promise<void> {\n const auth = authenticateBrowserRequest(\n req,\n new URL(req.url ?? '/', 'http://localhost'),\n mutableAuth,\n sessions,\n );\n if (isCookieAuth(auth)) {\n const cookies = parseCookieHeader(req.headers.cookie);\n const raw = cookies[HQ_SESSION_COOKIE];\n if (raw) {\n const sessionId = parseHqSessionCookie(raw, mutableAuth.cookieSecret ?? '');\n if (sessionId) sessions.delete(sessionId);\n }\n }\n clearHqSessionCookie(res, secureCookies);\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ loggedIn: false }));\n}\n\nexport async function handleApiPassword(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n mutableAuth: HqRouterMutableAuth,\n sessions: Map<string, HqSessionEntry>,\n dataDir: string,\n secureCookies: boolean | undefined,\n requireBrowserAuth: boolean | undefined,\n): Promise<void> {\n const auth = authenticateBrowserRequest(\n req,\n new URL(req.url ?? '/', 'http://localhost'),\n mutableAuth,\n sessions,\n );\n const localOpenBootstrap =\n auth === undefined &&\n req.method === 'POST' &&\n mutableAuth.browserTokens.size === 0 &&\n mutableAuth.passwordHash === undefined &&\n isLoopbackRequest(req);\n if (auth === undefined && !localOpenBootstrap) {\n res.writeHead(401, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n error: {\n code: 'AUTH_REQUIRED',\n message: 'A browser token or password session is required to manage the password.',\n },\n }),\n );\n return;\n }\n\n let body: { currentPassword?: unknown; newPassword?: unknown } = {};\n try {\n body = JSON.parse(await readRequestBody(req)) as typeof body;\n } catch {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({ error: { code: 'BAD_REQUEST', message: 'Invalid JSON body.' } }),\n );\n return;\n }\n\n if (isCookieAuth(auth) && mutableAuth.passwordHash !== undefined) {\n const currentPassword = typeof body.currentPassword === 'string' ? body.currentPassword : '';\n if (\n !currentPassword ||\n !(await verifyHqPassword(currentPassword, mutableAuth.passwordHash))\n ) {\n res.writeHead(403, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n error: { code: 'INVALID_CURRENT_PASSWORD', message: 'Current password is invalid.' },\n }),\n );\n return;\n }\n }\n\n if (req.method === 'DELETE') {\n if (requireBrowserAuth && mutableAuth.browserTokens.size === 0) {\n res.writeHead(409, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n error: {\n code: 'BROWSER_AUTH_REQUIRED',\n message:\n 'Cannot remove the only browser authentication method while a public relay is active.',\n },\n }),\n );\n return;\n }\n const next = await mutateHqAuthFile(dataDir, (current) => {\n const updated = { ...current };\n delete updated.passwordHash;\n delete updated.cookieSecret;\n return updated;\n });\n applyAuthFile(mutableAuth, next);\n sessions.clear();\n clearHqSessionCookie(res, secureCookies);\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n passwordMode: false,\n tokenMode: mutableAuth.browserTokens.size > 0,\n loggedIn: !isCookieAuth(auth) && isTokenAuth(auth),\n }),\n );\n return;\n }\n\n const newPassword = typeof body.newPassword === 'string' ? body.newPassword : '';\n if (newPassword.length < 8 || newPassword.length > 1024) {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n error: { code: 'INVALID_PASSWORD', message: 'New password must be between 8 and 1024 characters.' },\n }),\n );\n return;\n }\n\n const passwordHash = await hashHqPassword(newPassword);\n const cookieSecret = mintHqCookieSecret();\n const next = await mutateHqAuthFile(dataDir, (current) => ({\n ...current,\n passwordHash,\n cookieSecret,\n }));\n applyAuthFile(mutableAuth, next);\n sessions.clear();\n\n if (isCookieAuth(auth) || localOpenBootstrap) {\n const sessionId = randomUUID();\n sessions.set(sessionId, { createdAt: Date.now(), kind: 'password' });\n setHqSessionCookie(\n res,\n serializeHqSessionCookie(sessionId, cookieSecret),\n secureCookies,\n );\n }\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n passwordMode: true,\n tokenMode: mutableAuth.browserTokens.size > 0,\n loggedIn: true,\n }),\n );\n}\n\nexport function applyAuthFile(\n mutableAuth: HqRouterMutableAuth,\n next: {\n browserTokens?: Array<{ token: string; id: string; capabilities?: string[] }>;\n clientTokens?: Array<HqToken>;\n redactionPolicy?: Partial<HqRedactionPolicy>;\n passwordHash?: string;\n cookieSecret?: string;\n alertRules?: HqAlertRuleConfig;\n },\n): void {\n mutableAuth.operatorPolicy = {\n ...DEFAULT_HQ_REDACTION_POLICY,\n ...(next.redactionPolicy ?? {}),\n };\n mutableAuth.operatorPolicyOverride = next.redactionPolicy;\n mutableAuth.browserTokens = new Set((next.browserTokens ?? []).map((t) => t.token));\n mutableAuth.clientTokens = new Set((next.clientTokens ?? []).map((t) => t.token));\n mutableAuth.browserTokenObjs = new Map(\n (next.browserTokens ?? []).map((t) => [\n t.token,\n { id: t.id, ...(t.capabilities !== undefined ? { capabilities: t.capabilities } : {}) },\n ]),\n );\n mutableAuth.clientTokenObjs = new Map(\n (next.clientTokens ?? []).map((token: HqToken) => [token.token, token]),\n );\n mutableAuth.passwordHash = next.passwordHash;\n mutableAuth.cookieSecret = next.cookieSecret;\n mutableAuth.alertRules = next.alertRules;\n}\n\n// \u2500\u2500 Bootstrap exchange \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport async function handleApiBootstrap(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n mutableAuth: HqRouterMutableAuth,\n sessions: Map<string, HqSessionEntry>,\n secureCookies: boolean | undefined,\n bootstrapStore: import('@wrongstack/core/hq').HqBootstrapCodeStore,\n): Promise<void> {\n if (!mutableAuth.cookieSecret) {\n res.writeHead(503, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n error: {\n code: 'BOOTSTRAP_UNAVAILABLE',\n message: 'Cookie signing is not configured on this HQ server.',\n },\n }),\n );\n return;\n }\n\n let body: { code?: unknown };\n try {\n body = JSON.parse(await readRequestBody(req)) as { code?: unknown };\n } catch (error) {\n writeInvalidBody(res, error);\n return;\n }\n\n if (typeof body.code !== 'string' || body.code.length === 0) {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({ error: { code: 'BAD_REQUEST', message: 'code is required' } }),\n );\n return;\n }\n\n const entry = bootstrapStore.consume(body.code);\n if (!entry) {\n res.writeHead(401, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n error: {\n code: 'INVALID_OR_EXPIRED_CODE',\n message: 'The bootstrap code is invalid, already used, or expired.',\n },\n }),\n );\n return;\n }\n\n // Verify the originating token is still live.\n const tokenLive = [...mutableAuth.browserTokenObjs.values()].some(\n (obj) => obj.id === entry.tokenId,\n );\n if (!tokenLive) {\n res.writeHead(401, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n error: {\n code: 'TOKEN_REVOKED',\n message: 'The token that issued this bootstrap code has been revoked.',\n },\n }),\n );\n return;\n }\n\n const sessionId = randomUUID();\n sessions.set(sessionId, {\n createdAt: Date.now(),\n kind: 'token',\n tokenId: entry.tokenId,\n ...(entry.capabilities !== undefined ? { capabilities: entry.capabilities } : {}),\n });\n setHqSessionCookie(\n res,\n serializeHqSessionCookie(sessionId, mutableAuth.cookieSecret),\n secureCookies,\n );\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ loggedIn: true }));\n}\n", "/**\n * HQ server \u2014 System route handlers.\n *\n * Extracted from the monolithic routes.ts for maintainability.\n * Covers: system update check, system health, command audit log, alerts.\n */\n\nimport type * as http from 'node:http';\nimport type { WebSocket } from 'ws';\nimport type { HqCommandAuditLog, HqEventEnvelope, HqPersistence } from '@wrongstack/core/hq';\nimport type { HqAlertEngine } from '@wrongstack/core/hq';\nimport type { ConnectedClient } from '../types.js';\n\nexport async function handleApiSystemUpdate(res: http.ServerResponse): Promise<void> {\n const [{ checkForUpdate }, { detectUpdatePackageName }] = await Promise.all([\n import('../../update-check.js'),\n import('../../subcommands/handlers/update.js'),\n ]);\n const packageName = detectUpdatePackageName();\n const info = await checkForUpdate({ packageName });\n res.writeHead(200, {\n 'Content-Type': 'application/json',\n 'Cache-Control': 'no-store',\n });\n res.end(\n JSON.stringify({\n ...info,\n packageName,\n command: 'wstack update',\n }),\n );\n}\n\nexport async function handleApiSystemHealth(\n res: http.ServerResponse,\n clients: Map<WebSocket, ConnectedClient>,\n persistence: HqPersistence,\n eventLog: HqEventEnvelope[],\n): Promise<void> {\n const now = Date.now();\n const eventCount = eventLog.length;\n\n let timeseriesStoreStatus: 'ok' | 'degraded' | 'unknown' = 'unknown';\n let kanbanStoreStatus: 'ok' | 'degraded' | 'unknown' = 'unknown';\n\n try {\n const tsOk = await persistence.timeseries.read(now - 300_000);\n timeseriesStoreStatus = Array.isArray(tsOk) ? 'ok' : 'degraded';\n } catch {\n timeseriesStoreStatus = 'degraded';\n }\n\n try {\n await persistence.kanban.load('__hq_health_probe__');\n kanbanStoreStatus = 'ok';\n } catch {\n kanbanStoreStatus = 'degraded';\n }\n\n const inMemoryEventLogActive = true;\n const allOk = inMemoryEventLogActive && timeseriesStoreStatus === 'ok' && kanbanStoreStatus === 'ok';\n\n const clientCount = clients.size;\n const connectedClients = [...clients.values()].filter(\n (c) => Date.now() - new Date(c.lastSeenAt).getTime() < 60_000,\n ).length;\n\n res.writeHead(200, {\n 'Content-Type': 'application/json',\n 'Cache-Control': 'no-store',\n });\n res.end(\n JSON.stringify({\n status: allOk ? 'healthy' : 'degraded',\n uptime: {\n serverTime: new Date().toISOString(),\n eventLogSize: eventCount,\n },\n stores: {\n events: 'ok',\n timeseries: timeseriesStoreStatus,\n kanban: kanbanStoreStatus,\n },\n connections: {\n total: clientCount,\n active: connectedClients,\n stale: clientCount - connectedClients,\n },\n }),\n );\n}\n\nexport async function handleApiCommandsAudit(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n auditLog: HqCommandAuditLog,\n): Promise<void> {\n const url = new URL(req.url ?? '/', 'http://localhost');\n const rawLimit = Number.parseInt(url.searchParams.get('limit') ?? '200', 10);\n const limit = Math.min(1000, Math.max(1, Number.isFinite(rawLimit) ? rawLimit : 200));\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ commands: auditLog.recent(limit) }));\n}\n\nexport async function handleApiAlerts(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n alertEngine: HqAlertEngine,\n): Promise<void> {\n const url = new URL(req.url ?? '/', 'http://localhost');\n const rawLimit = Number.parseInt(url.searchParams.get('limit') ?? '100', 10);\n const limit = Math.min(500, Math.max(1, Number.isFinite(rawLimit) ? rawLimit : 100));\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n active: alertEngine.activeAlerts(),\n history: alertEngine.recentAlerts(limit),\n }),\n );\n}\n", "import * as path from 'node:path';\nimport type * as http from 'node:http';\nimport {\n buildTranscriptFromEvents,\n resolveHqDataDir,\n type HqTranscriptEntry,\n} from '@wrongstack/core/hq';\nimport type { TranscriptRing } from '../types.js';\nimport {\n agentRingKey,\n decodePathSegment,\n readLocalSubagentTranscript,\n sanitizeApiError,\n} from '../utils.js';\n\nexport async function handleApiSessions(res: http.ServerResponse): Promise<void> {\n const { SessionRegistry } = await import('@wrongstack/core/storage');\n const globalRoot = path.dirname(resolveHqDataDir());\n try {\n const registry = new SessionRegistry(globalRoot);\n const sessions = (await registry.list()) as unknown as Array<Record<string, unknown>>;\n const result = sessions\n .filter((s: { status?: string }) => s.status !== 'stale')\n .map((s: Record<string, unknown>) => ({\n sessionId: s.sessionId,\n projectSlug: s.projectSlug,\n projectName: s.projectName,\n projectRoot: s.projectRoot,\n workingDir: s.workingDir,\n status: s.status,\n pid: s.pid,\n startedAt: s.startedAt,\n lastHeartbeatAt: s.lastHeartbeatAt,\n agentCount: s.agentCount,\n agents: (s.agents as Array<Record<string, unknown>>).map((a) => ({\n id: a.id,\n name: a.name,\n status: a.status,\n currentTool: a.currentTool,\n iterations: a.iterations,\n toolCalls: a.toolCalls,\n lastActivityAt: a.lastActivityAt,\n })),\n }));\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify(result));\n } catch (err) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: sanitizeApiError(err) }));\n }\n}\n\nexport async function handleApiSessionEvents(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n match: RegExpMatchArray,\n transcripts: Map<string, TranscriptRing>,\n): Promise<void> {\n const { SessionRegistry, DefaultSessionStore } = await import('@wrongstack/core/storage');\n const { resolveWstackPaths } = await import('@wrongstack/core/utils');\n const url = new URL(req.url ?? '/', 'http://localhost');\n const full = url.searchParams.get('full') === '1';\n const rawLimit = Number.parseInt(url.searchParams.get('limit') ?? '200', 10);\n const limit = Math.min(5000, Math.max(1, Number.isFinite(rawLimit) ? rawLimit : 200));\n const sessionId = decodePathSegment(match[1]!);\n if (sessionId === null) {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'invalid sessionId encoding' }));\n return;\n }\n\n const globalRoot = path.dirname(resolveHqDataDir());\n try {\n const registry = new SessionRegistry(globalRoot);\n const entry = await registry.get(sessionId).catch(() => null);\n\n let entries: HqTranscriptEntry[] = [];\n let source: 'disk' | 'stream' = 'stream';\n let status: string | undefined;\n let clientType: string | undefined;\n let projectName: string | undefined;\n\n if (entry && 'projectRoot' in entry) {\n const paths = resolveWstackPaths({\n projectRoot: (entry as { projectRoot: string }).projectRoot,\n globalRoot,\n });\n const store = new DefaultSessionStore({ dir: paths.projectSessions });\n const data = await store.load(sessionId).catch(() => null);\n if (data) {\n entries = buildTranscriptFromEvents(\n (data.events as unknown[]).map((e) => e as Record<string, unknown>),\n );\n source = 'disk';\n status = (entry as { status?: string }).status;\n clientType = (entry as { clientType?: string }).clientType;\n projectName = (entry as { projectName?: string }).projectName;\n }\n }\n\n if (entries.length === 0) {\n const ring = transcripts.get(sessionId);\n if (!ring && !entry) {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Session not found' }));\n return;\n }\n entries = ring ? ring.entries : [];\n source = 'stream';\n if (entry) {\n status = (entry as { status?: string }).status;\n clientType = (entry as { clientType?: string }).clientType;\n projectName = (entry as { projectName?: string }).projectName;\n }\n }\n\n const total = entries.length;\n const tail = full ? entries : entries.slice(-limit);\n\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n sessionId,\n source,\n ...(status !== undefined ? { status } : {}),\n ...(clientType !== undefined ? { clientType } : {}),\n ...(projectName !== undefined ? { projectName } : {}),\n total,\n entries: tail,\n }),\n );\n } catch (err) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: sanitizeApiError(err) }));\n }\n}\n\nexport async function handleApiSessionAgentMessages(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n match: RegExpMatchArray,\n agentMessages: Map<string, HqTranscriptEntry[]>,\n): Promise<void> {\n const url = new URL(req.url ?? '/', 'http://localhost');\n const sid = decodePathSegment(match[1]!);\n const aid = decodePathSegment(match[2]!);\n if (sid === null || aid === null) {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'invalid session or agent id encoding' }));\n return;\n }\n const full = url.searchParams.get('full') === '1';\n const disk = await readLocalSubagentTranscript(sid, aid);\n const source: 'disk' | 'stream' = disk !== null ? 'disk' : 'stream';\n const all =\n disk !== null ? disk : (agentMessages.get(agentRingKey(sid, aid)) ?? agentMessages.get(aid) ?? []);\n const entries = full ? all : all.slice(-200);\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ subagentId: aid, sessionId: sid, source, total: all.length, entries }));\n}\n\nexport async function handleApiAgentMessages(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n match: RegExpMatchArray,\n agentMessages: Map<string, HqTranscriptEntry[]>,\n): Promise<void> {\n const url = new URL(req.url ?? '/', 'http://localhost');\n const id = decodePathSegment(match[1]!);\n if (id === null) {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'invalid agent id encoding' }));\n return;\n }\n const full = url.searchParams.get('full') === '1';\n const merged: HqTranscriptEntry[] = [];\n for (const [key, ring] of agentMessages) {\n if (key === id || key.endsWith(`::${id}`)) merged.push(...ring);\n }\n merged.sort((a, b) => a.ts.localeCompare(b.ts));\n const entries = full ? merged : merged.slice(-200);\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ subagentId: id, total: merged.length, entries }));\n}\n", "import { deriveHqProjectId } from '@wrongstack/core/hq';\n\nexport function resolveHqProjectRoot(\n globalRoot: string,\n ids: { sessionId?: string | undefined; projectId?: string | undefined },\n): Promise<string | undefined> {\n // Dynamic import to avoid pulling in SessionRegistry at module level.\n const fn = async (): Promise<string | undefined> => {\n const { SessionRegistry } = await import('@wrongstack/core/storage');\n try {\n const registry = new SessionRegistry(globalRoot);\n if (typeof ids.sessionId === 'string') {\n const entry = await registry.get(ids.sessionId).catch(() => null);\n if (entry?.projectRoot) return entry.projectRoot;\n }\n if (typeof ids.projectId === 'string') {\n const { createHash } = await import('node:crypto');\n const all = await registry.list().catch(() => []);\n const projectIds = new Map<string, string>();\n const projectIdForRoot = (projectRoot: string): string => {\n const cached = projectIds.get(projectRoot);\n if (cached !== undefined) return cached;\n const derived = deriveHqProjectId(projectRoot);\n projectIds.set(projectRoot, derived);\n return derived;\n };\n const match = all.find(\n (e: { projectSlug?: string; projectRoot: string }) =>\n e.projectSlug === ids.projectId ||\n projectIdForRoot(e.projectRoot) === ids.projectId ||\n createHash('sha256').update(e.projectRoot).digest('hex').slice(0, 12) === ids.projectId,\n );\n if (match) return match.projectRoot;\n }\n } catch {\n /* fall through */\n }\n return undefined;\n };\n return fn();\n}\n", "/**\n * HQ server \u2014 runtime marker and startup info printing.\n *\n * Writes/clears the `<dataDir>/runtime.json` marker and prints the\n * operator-facing startup banner with LAN endpoints.\n *\n * @module hq-server/startup\n */\n\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport * as HqServerUtils from './utils.js';\n\n// \u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface HqRuntimeMarker {\n url?: string;\n pid?: number;\n updatedAt?: string;\n}\n\n// \u2500\u2500 Runtime marker \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const hqRuntimeMarkerPath = HqServerUtils.hqRuntimeMarkerPath;\n\n/**\n * Write `<dataDir>/runtime.json` so auto-discovering clients on this machine\n * can find this HQ instance. Overwrites any previous marker.\n */\nexport async function writeHqRuntimeMarker(dataDir: string, url: string): Promise<void> {\n const file = hqRuntimeMarkerPath(dataDir);\n const payload = JSON.stringify(\n { url, pid: process.pid, updatedAt: new Date().toISOString() },\n null,\n 2,\n );\n await fs.mkdir(path.dirname(file), { recursive: true });\n await fs.writeFile(file, `${payload}\\n`, { encoding: 'utf8', mode: 0o600 });\n}\n\n/**\n * Remove `<dataDir>/runtime.json` only when it belongs to this process\n * (same URL and PID). Best-effort \u2014 never throws.\n */\nexport async function clearHqRuntimeMarker(dataDir: string, url: string): Promise<void> {\n const file = hqRuntimeMarkerPath(dataDir);\n try {\n const raw = await fs.readFile(file, 'utf8');\n const parsed = JSON.parse(raw) as HqRuntimeMarker;\n if (parsed.url === url && parsed.pid === process.pid) {\n await fs.rm(file, { force: true });\n }\n } catch {\n // Best-effort cleanup only.\n }\n}\n\n// \u2500\u2500 Startup info \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface HqStartupInfoHandle {\n host: string;\n port: number;\n firstRunSetup?: {\n dataDir: string;\n browserUrl: string;\n clientUrl: string;\n clientEnv: {\n WRONGSTACK_HQ_URL: string;\n WRONGSTACK_HQ_TOKEN?: string;\n };\n createdAuth: boolean;\n browserTokenMode: boolean;\n passwordMode: boolean;\n };\n}\n\n/**\n * Print the operator-facing startup banner. When firstRunSetup is present,\n * print richer first-run instructions with credentials; otherwise a minimal\n * endpoint listing.\n */\nexport function writeHqStartupInfo(\n write: (line: string) => void,\n handle: HqStartupInfoHandle,\n): void {\n const startup = handle.firstRunSetup;\n write(`WrongStack HQ listening on http://${handle.host}:${handle.port}\\n`);\n if (!startup) {\n write(`Browser endpoint: ${HqServerUtils.buildHttpUrl(handle.host, handle.port)}\\n`);\n write(`Client endpoint: ${HqServerUtils.buildClientWsUrl(handle.host, handle.port)}\\n`);\n writeHqLanEndpoints(write, handle, undefined);\n return;\n }\n\n write(`Browser endpoint: ${startup.browserUrl}\\n`);\n write(`Client endpoint: ${startup.clientUrl}\\n`);\n if (startup.createdAuth) {\n write(`\\nFirst-run HQ auth created in ${startup.dataDir}\\n`);\n } else {\n write(`\\nHQ auth loaded from ${startup.dataDir}\\n`);\n }\n write('Start clients with:\\n');\n write(` WRONGSTACK_HQ_URL=${startup.clientEnv.WRONGSTACK_HQ_URL}\\n`);\n if (startup.clientEnv.WRONGSTACK_HQ_TOKEN) {\n write(` WRONGSTACK_HQ_TOKEN=${startup.clientEnv.WRONGSTACK_HQ_TOKEN}\\n`);\n write(`Credentials are stored in ${path.join(startup.dataDir, 'auth.json')}\\n`);\n }\n writeHqLanEndpoints(write, handle, undefined);\n}\n\n/** When bound to all interfaces, print LAN URLs so other machines can reach HQ. */\nexport function writeHqLanEndpoints(\n write: (line: string) => void,\n handle: HqStartupInfoHandle,\n browserToken: string | undefined,\n): void {\n if (handle.host !== '0.0.0.0' && handle.host !== '::') return;\n const ips = HqServerUtils.lanIPv4Addresses();\n if (ips.length === 0) return;\n write('\\nReachable from other machines on your network:\\n');\n for (const ip of ips) {\n write(` ${HqServerUtils.buildHttpUrl(ip, handle.port, browserToken)}\\n`);\n }\n write(` On another machine, set WRONGSTACK_HQ_URL=http://${ips[0]}:${handle.port}\\n`);\n}\n", "/**\n * HQ server \u2014 WebSocket handlers for browser and client connections.\n *\n * @module hq-server/ws\n */\n\nimport { randomUUID } from 'node:crypto';\nimport type {\n HqCommandAuditLog,\n HqEventEnvelope,\n HqFleetSnapshotPayload,\n HqKanbanSnapshotPayload,\n HqMailboxEventPayload,\n HqMailboxSnapshotPayload,\n HqMcpHealthSnapshotPayload,\n HqPersistence,\n HqQueuedCommand,\n HqRedactionPolicy,\n HqSessionEndedPayload,\n HqSessionSnapshotPayload,\n HqToken,\n HqTranscriptAppendPayload,\n HqTranscriptEntry,\n HqWelcomePayload,\n} from '@wrongstack/core/hq';\nimport {\n HQ_PROTOCOL_VERSION,\n HQ_TRANSCRIPT_TEXT_CAP,\n parseHqEventPayload,\n parseHqFrame,\n redactHqEvent,\n resolveHqRedactionPolicy,\n tightenHqRedactionPolicy,\n tokenHasCapability,\n} from '@wrongstack/core/hq';\nimport { WebSocket } from 'ws';\nimport { broadcastCommandStatus, broadcastEvent, sendGuarded } from './snapshot.js';\nimport type { ConnectedClient, HqSnapshotBroadcaster, TranscriptRing } from './types.js';\nimport {\n agentMessageToEntry,\n agentRingKey,\n evictOldest,\n MAX_AGENT_RINGS,\n MAX_TRANSCRIPT_SESSIONS,\n recordTimeseriesSignal,\n TRANSCRIPT_RING_MAX,\n truncateHqSummary,\n} from './utils.js';\n\n// \u2500\u2500 Constants \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst MAX_EVENT_LOG = 5000;\n\n// \u2500\u2500 handleBrowser \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function handleBrowser(\n ws: WebSocket,\n snapshotBroadcaster: HqSnapshotBroadcaster,\n browsers: Set<WebSocket>,\n): void {\n browsers.add(ws);\n\n // Per-connection error handler. An oversized inbound frame makes the `ws`\n // receiver throw (`RangeError: Max payload size exceeded`, close 1009) and\n // emit 'error' on this socket \u2014 unhandled, that crashes the whole process.\n ws.on('error', (err) => {\n console.warn(\n JSON.stringify({\n level: 'warn',\n event: 'hq.browser_socket_error',\n message: err instanceof Error ? err.message : String(err),\n timestamp: new Date().toISOString(),\n }),\n );\n });\n\n sendGuarded(ws, snapshotBroadcaster.currentSerialized());\n\n ws.on('close', () => {\n browsers.delete(ws);\n });\n}\n\n// \u2500\u2500 handleClient \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function handleClient(\n ws: WebSocket,\n clients: Map<WebSocket, ConnectedClient>,\n browsers: Set<WebSocket>,\n eventLog: HqEventEnvelope[],\n auth: {\n token?: HqToken | undefined;\n getOperatorPolicy: () => Partial<HqRedactionPolicy> | undefined;\n },\n snapshotBroadcaster: HqSnapshotBroadcaster,\n transcripts: Map<string, TranscriptRing>,\n agentMessages: Map<string, HqTranscriptEntry[]>,\n persistence?: HqPersistence,\n auditLog?: HqCommandAuditLog,\n): void {\n let registered = false;\n\n /**\n * Record an event into both the in-memory ring and the persistent log, and\n * fold any cost/tool signal into the timeseries store. Best-effort: never\n * throws into the message handler.\n */\n function persistEvent(event: HqEventEnvelope): void {\n eventLog.push(event);\n if (eventLog.length > MAX_EVENT_LOG) eventLog.splice(0, eventLog.length - MAX_EVENT_LOG);\n if (persistence !== undefined) {\n persistence.eventLog.append(event);\n recordTimeseriesSignal(persistence, event);\n }\n }\n\n // Per-connection error handler. An oversized inbound frame makes the `ws`\n // receiver throw (`RangeError: Max payload size exceeded`, close 1009) and\n // emit 'error' on this socket \u2014 unhandled, that crashes the whole process.\n ws.on('error', (err) => {\n console.warn(\n JSON.stringify({\n level: 'warn',\n event: 'hq.client_socket_error',\n message: err instanceof Error ? err.message : String(err),\n timestamp: new Date().toISOString(),\n }),\n );\n });\n\n ws.on('message', (data: Buffer | ArrayBuffer | Buffer[]) => {\n const raw =\n typeof data === 'string'\n ? data\n : Buffer.isBuffer(data)\n ? data\n : new TextDecoder().decode(data as ArrayBuffer);\n const parsed = parseHqFrame(raw);\n if (!parsed.ok) {\n // RFC 6455 \u00A77.4.1: 1003 = invalid payload (not processable),\n // 1008 = policy violation (unknown type or malformed shape).\n const code = parsed.reason === 'invalid-json' ? 1003 : 1008;\n ws.close(code, `invalid frame: ${parsed.reason}`);\n return;\n }\n const frame = parsed.frame;\n\n if (frame.type === 'client.hello') {\n if (registered) {\n ws.close(1008, 'duplicate client.hello');\n return;\n }\n const payload = frame.payload;\n if (payload.protocolVersion !== HQ_PROTOCOL_VERSION) {\n ws.close(1008, 'protocol version mismatch');\n return;\n }\n\n const canPublishTelemetry =\n auth.token === undefined || tokenHasCapability(auth.token, 'telemetry.publish');\n const acceptedCapabilities = payload.capabilities.filter(\n (capability: string) => capability === 'control.receive' || canPublishTelemetry,\n );\n const declaredRedactionPolicy = resolveHqRedactionPolicy(payload.redactionPolicy);\n\n // A reconnect reuses the SAME clientId (the publisher identity is fixed\n // at construction), so an exact clientId match always supersedes the old\n // zombie socket. Same-process/same-kind duplicates with a DIFFERENT\n // clientId are distinct publisher instances (one process legitimately\n // holds a telemetry socket plus auxiliary mailbox sockets) \u2014 those are\n // only superseded while they hold no live session telemetry. Killing a\n // socket that is actively refreshing session snapshots would drop the\n // terminal from the fleet tree and ping-pong forever (both sides\n // auto-reconnect and re-hello), which showed up as agents/terminals\n // flapping in the HQ map.\n for (const [otherWs, otherClient] of clients) {\n const samePublisher =\n otherClient.projectId === payload.project.projectId &&\n otherClient.kind === payload.client.kind &&\n otherClient.pid !== undefined &&\n payload.client.pid !== undefined &&\n otherClient.pid === payload.client.pid &&\n (otherClient.machineId || otherClient.project.machineId) ===\n (payload.client.machineId || payload.project.machineId);\n if (\n otherWs !== ws &&\n (otherClient.clientId === payload.client.clientId ||\n (samePublisher && otherClient.sessions.size === 0))\n ) {\n clients.delete(otherWs);\n otherWs.close(4001, 'superseded by a newer HQ connection');\n }\n }\n\n const client: ConnectedClient = {\n ws,\n clientId: payload.client.clientId,\n projectId: payload.project.projectId,\n project: payload.project,\n kind: payload.client.kind,\n connectedAt: new Date().toISOString(),\n lastSeenAt: new Date().toISOString(),\n ...(payload.client.hostname ? { hostname: payload.client.hostname } : {}),\n ...(payload.client.pid ? { pid: payload.client.pid } : {}),\n ...(payload.client.version ? { version: payload.client.version } : {}),\n capabilities: acceptedCapabilities,\n ...(auth.token !== undefined ? { authToken: auth.token } : {}),\n declaredRedactionPolicy,\n lastEventSeq: 0,\n mailboxes: new Map(),\n machineId: payload.client.machineId || payload.project.machineId,\n sessions: new Map(),\n fleets: new Map(),\n mcpSnapshots: new Map(),\n commandQueue: [],\n };\n clients.set(ws, client);\n registered = true;\n\n // Server-to-client acknowledgement: the client learns which capabilities\n // the server accepted and the active redaction policy. Command delivery\n // happens later over `client.command_poll` frames on this same socket.\n const welcome: HqWelcomePayload = {\n type: 'hq.welcome',\n protocolVersion: HQ_PROTOCOL_VERSION,\n serverTime: new Date().toISOString(),\n acceptedCapabilities,\n // The operator-configured override (from <dataDir>/auth.json) wins\n // over the default. The client learns the *effective* policy.\n redactionPolicy: tightenHqRedactionPolicy(\n declaredRedactionPolicy,\n auth.getOperatorPolicy(),\n ),\n };\n ws.send(JSON.stringify(welcome));\n if (persistence !== undefined) {\n void persistence.kanban\n .load(client.projectId)\n .then((payload) => {\n sendGuarded(ws, JSON.stringify({ type: 'hq.kanban_snapshot', payload }));\n })\n .catch(() => undefined);\n }\n\n const event: HqEventEnvelope = {\n id: randomUUID(),\n type: 'client.hello',\n schemaVersion: HQ_PROTOCOL_VERSION,\n timestamp: new Date().toISOString(),\n clientId: payload.client.clientId,\n projectId: payload.project.projectId,\n seq: 0,\n payload: { client: payload.client, project: payload.project },\n };\n persistEvent(event);\n snapshotBroadcaster.broadcast();\n broadcastEvent(event, browsers);\n return;\n }\n\n if (!registered) return;\n\n // \u2500\u2500 Phase 3 control plane: client polls for commands & acks them \u2500\u2500\u2500\u2500\u2500\u2500\n // The client SDK (HqPublisher) polls every ~500ms with an `afterCommandId`\n // cursor; we drain the per-client queue back to it as a `hq.command_batch`.\n if (frame.type === 'client.command_poll') {\n const client = clients.get(ws);\n if (client) {\n if (frame.clientId !== client.clientId || frame.projectId !== client.projectId) {\n ws.close(1008, 'command poll identity mismatch');\n return;\n }\n client.lastSeenAt = new Date().toISOString();\n const afterId = frame.afterCommandId;\n const limit = frame.limit ?? 25;\n let toSend: HqQueuedCommand[];\n if (afterId === undefined) {\n toSend = client.commandQueue.slice(0, limit);\n } else {\n const idx = client.commandQueue.findIndex((c) => c.commandId === afterId);\n toSend = (idx >= 0 ? client.commandQueue.slice(idx + 1) : client.commandQueue).slice(\n 0,\n limit,\n );\n }\n if (toSend.length > 0) {\n const batch = JSON.stringify({ type: 'hq.command_batch', commands: toSend });\n if (ws.readyState === WebSocket.OPEN) ws.send(batch);\n for (const cmd of toSend) {\n auditLog?.update(cmd.commandId, { status: 'delivered' });\n const updated = auditLog?.get(cmd.commandId);\n if (updated !== undefined) broadcastCommandStatus(updated, browsers);\n }\n }\n }\n return;\n }\n\n if (frame.type === 'client.command_ack') {\n const client = clients.get(ws);\n if (client) {\n if (frame.clientId !== client.clientId || frame.projectId !== client.projectId) {\n ws.close(1008, 'command ack identity mismatch');\n return;\n }\n client.lastSeenAt = new Date().toISOString();\n }\n if (client) {\n const updated = auditLog?.updateForClient(frame.commandId, client.clientId, {\n status: 'acked',\n ackStatus: frame.status,\n ...(frame.message !== undefined ? { ackMessage: frame.message } : {}),\n ackedAt: new Date().toISOString(),\n });\n if (updated === true) {\n const entry = auditLog?.get(frame.commandId);\n if (entry !== undefined) broadcastCommandStatus(entry, browsers);\n }\n }\n return;\n }\n\n if (frame.type === 'client.event') {\n const client = clients.get(ws);\n if (!client) return;\n const incomingEvent = frame.event;\n if (\n incomingEvent.clientId !== client.clientId ||\n incomingEvent.projectId !== client.projectId\n ) {\n ws.close(1008, 'event identity mismatch');\n return;\n }\n if (!tokenHasCapability(client.authToken, 'telemetry.publish') && auth.token !== undefined) {\n ws.close(1008, 'client token lacks telemetry.publish capability');\n return;\n }\n if (incomingEvent.seq <= client.lastEventSeq) {\n ws.close(1008, 'event sequence must increase monotonically');\n return;\n }\n const parsedPayload = parseHqEventPayload(incomingEvent.type, incomingEvent.payload);\n if (!parsedPayload.ok) {\n // A single malformed telemetry payload must not take down an otherwise\n // healthy publisher connection. Drop it before sequence advancement;\n // identity/auth violations above still close the socket.\n return;\n }\n client.lastEventSeq = incomingEvent.seq;\n client.lastSeenAt = new Date().toISOString();\n const event = redactHqEvent(\n { ...incomingEvent, payload: parsedPayload.payload },\n {\n policy: tightenHqRedactionPolicy(\n client.declaredRedactionPolicy,\n auth.getOperatorPolicy(),\n ),\n projectRoot: client.project.projectRoot,\n // Chat-transcript events carry full turns \u2014 the generic 500-char\n // summary cap would truncate them a second time after the\n // publisher already applied the transcript cap.\n ...(incomingEvent.type === 'session.transcript' || incomingEvent.type === 'agent.message'\n ? { maxSummaryLength: HQ_TRANSCRIPT_TEXT_CAP }\n : {}),\n },\n ).value;\n\n if (event.type === 'client.heartbeat') {\n return;\n }\n\n if (event.type === 'kanban.snapshot') {\n const payload = event.payload as HqKanbanSnapshotPayload;\n if (payload.projectId !== client.projectId || persistence === undefined) return;\n void persistence.kanban\n .merge(payload)\n .then((merged) => {\n // Broadcast only the post-merge authoritative records for the\n // boards this delta touched \u2014 NEVER the full merged project set.\n // A project accumulates thousands of boards (run mirrors), so the\n // full set grows into multi-MB JSON; re-broadcasting it to every\n // same-project client on every delta was a broadcast storm that\n // drove connected TUIs into V8 heap exhaustion. Clients apply\n // snapshots per-record by revision, so a touched-only payload is\n // semantically identical; the full set still goes out once per\n // connection at hello time.\n const touched = new Set<string>();\n for (const record of payload.boards) touched.add(record.boardId);\n for (const record of payload.tombstones) touched.add(record.boardId);\n const delta: HqKanbanSnapshotPayload = {\n projectId: merged.projectId,\n generatedAt: merged.generatedAt,\n boards: merged.boards.filter((record) => touched.has(record.boardId)),\n tombstones: merged.tombstones.filter((record) => touched.has(record.boardId)),\n };\n const message = JSON.stringify({ type: 'hq.kanban_snapshot', payload: delta });\n for (const peer of clients.values()) {\n if (peer.projectId === client.projectId) sendGuarded(peer.ws, message);\n }\n })\n .catch((error: unknown) => {\n console.warn(\n JSON.stringify({\n level: 'warn',\n event: 'hq.kanban_merge_failed',\n message: error instanceof Error ? error.message : String(error),\n timestamp: new Date().toISOString(),\n }),\n );\n });\n persistEvent(event);\n broadcastEvent(event, browsers);\n return;\n }\n\n // Mailbox snapshots are authoritative rollups \u2014 adopt them into the\n // per-client mailbox map and re-broadcast the global snapshot so the\n // browser counters reflect the latest rollup. We validate the\n // payload via `parseHqEventPayload` so a malformed snapshot cannot\n // poison the per-client mailbox map; other event types are not\n // validated yet and pass through unchanged.\n if (event.type === 'mailbox.snapshot' && client !== undefined) {\n const payloadResult = parseHqEventPayload(event.type, event.payload);\n if (payloadResult.ok) {\n const payload = payloadResult.payload as HqMailboxSnapshotPayload;\n client.mailboxes.set(client.projectId + ':' + payload.mailboxId, payload);\n persistEvent(event);\n snapshotBroadcaster.broadcast();\n broadcastEvent(event, browsers);\n return;\n }\n // Malformed mailbox.snapshot: drop without logging or broadcasting so\n // it cannot poison the per-client mailbox map.\n return;\n }\n\n // Mailbox events are transient \u2014 validate the payload so a malformed\n // envelope cannot leak garbage to the browser live feed, and truncate\n // the optional `summary` preview before storing it in the event log and\n // broadcasting to browsers.\n if (event.type === 'mailbox.event') {\n const payloadResult = parseHqEventPayload(event.type, event.payload);\n if (!payloadResult.ok) {\n return;\n }\n const payload = payloadResult.payload as HqMailboxEventPayload;\n const sanitizedSummary = truncateHqSummary(payload.summary, 280);\n const sanitizedEvent =\n sanitizedSummary === undefined\n ? event\n : { ...event, payload: { ...payload, summary: sanitizedSummary } };\n persistEvent(sanitizedEvent);\n broadcastEvent(sanitizedEvent, browsers);\n return;\n }\n\n // \u2500\u2500 Session telemetry \u2014 the spine of the fleet tree \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (event.type === 'session.snapshot' && client !== undefined) {\n const result = parseHqEventPayload(event.type, event.payload);\n if (result.ok) {\n const payload = result.payload as HqSessionSnapshotPayload;\n client.sessions.set(payload.sessionId, { payload, receivedAt: Date.now() });\n snapshotBroadcaster.broadcast();\n }\n return;\n }\n\n if (event.type === 'session.ended' && client !== undefined) {\n const result = parseHqEventPayload(event.type, event.payload);\n if (result.ok) {\n const payload = result.payload as HqSessionEndedPayload;\n client.sessions.delete(payload.sessionId);\n client.mcpSnapshots.delete(payload.sessionId);\n for (const [runId, fleet] of client.fleets) {\n if (fleet.sessionId === payload.sessionId) client.fleets.delete(runId);\n }\n snapshotBroadcaster.broadcast();\n }\n return;\n }\n\n // Fleet snapshots \u2014 authoritative coordinator rollups. Store per\n // (client, runId) so buildSnapshot can populate fleets[] the same way\n // it folds sessions. Validate via parseHqEventPayload so a malformed\n // snapshot cannot poison the map.\n if (event.type === 'fleet.snapshot' && client !== undefined) {\n const result = parseHqEventPayload(event.type, event.payload);\n if (result.ok) {\n const payload = result.payload as HqFleetSnapshotPayload;\n client.fleets.set(payload.runId, {\n payload,\n ...(event.sessionId !== undefined ? { sessionId: event.sessionId } : {}),\n receivedAt: Date.now(),\n });\n snapshotBroadcaster.broadcast();\n }\n return;\n }\n\n // MCP health snapshots \u2014 authoritative per-session rollups. Store per\n // (client, sessionId) so buildSnapshot can populate mcpServers[].\n if (event.type === 'mcp.health.snapshot' && client !== undefined) {\n const result = parseHqEventPayload(event.type, event.payload);\n if (result.ok) {\n const payload = result.payload as HqMcpHealthSnapshotPayload;\n const sessionId = event.sessionId || 'unknown';\n const stamped = payload.servers.map((s) => ({\n ...s,\n projectId: client.projectId,\n clientId: client.clientId,\n }));\n client.mcpSnapshots.set(sessionId, { servers: stamped, receivedAt: Date.now() });\n snapshotBroadcaster.broadcast();\n }\n return;\n }\n\n if (event.type === 'session.transcript' && client !== undefined) {\n const result = parseHqEventPayload(event.type, event.payload);\n if (result.ok) {\n const payload = result.payload as HqTranscriptAppendPayload;\n let ring = transcripts.get(payload.sessionId);\n if (!ring) {\n ring = { entries: [], ...(client.machineId ? { machineId: client.machineId } : {}) };\n }\n for (const entry of payload.entries) ring.entries.push(entry);\n if (ring.entries.length > TRANSCRIPT_RING_MAX) {\n ring.entries.splice(0, ring.entries.length - TRANSCRIPT_RING_MAX);\n }\n // Re-insert to keep LRU order, then bound the number of sessions kept.\n transcripts.delete(payload.sessionId);\n transcripts.set(payload.sessionId, ring);\n evictOldest(transcripts, MAX_TRANSCRIPT_SESSIONS);\n // Forward to browsers so an open history pane streams live.\n broadcastEvent(event, browsers);\n }\n return;\n }\n\n // Subagent conversation \u2014 buffer per (sessionId, subagentId) so\n // late-connecting browsers (incl. on other machines) can replay the\n // full history. Scoping by session is essential: every session's\n // leader uses the default id 'leader', so a bare-subId key would merge\n // every leader's transcript into one shared ring.\n if (event.type === 'agent.message') {\n const p = event.payload as Record<string, unknown> | undefined;\n const subId =\n p && typeof p['subagentId'] === 'string' ? (p['subagentId'] as string) : undefined;\n if (subId) {\n const key = agentRingKey(event.sessionId, subId);\n let ring = agentMessages.get(key);\n if (!ring) ring = [];\n ring.push(agentMessageToEntry(p as Record<string, unknown>));\n if (ring.length > TRANSCRIPT_RING_MAX) ring.splice(0, ring.length - TRANSCRIPT_RING_MAX);\n agentMessages.delete(key);\n agentMessages.set(key, ring);\n evictOldest(agentMessages, MAX_AGENT_RINGS);\n }\n persistEvent(event);\n broadcastEvent(event, browsers);\n return;\n }\n\n // Other event types pass through unchanged.\n persistEvent(event);\n broadcastEvent(event, browsers);\n }\n });\n\n ws.on('close', () => {\n clients.delete(ws);\n snapshotBroadcaster.broadcast();\n });\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["randomUUID", "fs", "path", "mintHqCookieSecret", "mutateHqAuthFile", "WebSocket", "randomUUID", "path", "fs", "path", "resolveHqDataDir", "DEFAULT_HQ_REDACTION_POLICY", "next", "DEFAULT_HQ_REDACTION_POLICY", "path", "resolveHqDataDir", "resolveHqDataDir", "setHqSecurityHeaders", "hasTrustedBrowserOrigin", "authenticateBrowserRequest", "isTokenAuth", "isCookieAuth", "parseHqSessionCookie", "parseCookieHeader", "HQ_SESSION_COOKIE", "decodePathSegment", "readRequestBody", "writeInvalidBody", "sanitizeApiError", "buildHttpUrl", "buildBootstrapHttpUrl", "buildClientWsUrl", "agentRingKey", "agentMessageToEntry", "readLocalSubagentTranscript", "setHqSecurityHeaders", "hasTrustedBrowserOrigin", "authenticateBrowserRequest", "decodePathSegment", "isCookieAuth", "isTokenAuth", "readRequestBody", "writeInvalidBody", "randomUUID", "sanitizeApiError", "fs", "path", "hqRuntimeMarkerPath", "randomUUID", "tokenHasCapability", "WebSocket", "tokenHasCapability", "payload", "randomUUID", "WebSocket", "HqInsecureExposureError", "MAX_EVENT_LOG", "mintHqCookieSecret", "mutateHqAuthFile", "HQ_SESSION_MAX_AGE_MS", "randomUUID", "authenticateBrowserRequest", "isTokenAuth", "isCookieAuth", "WebSocket", "MAX_EVENT_LOG", "hasTrustedBrowserOrigin", "parseCookieHeader", "HQ_SESSION_COOKIE", "parseHqSessionCookie", "buildBootstrapHttpUrl", "buildHttpUrl", "buildClientWsUrl"]
|
|
7
|
+
}
|