@wrongstack/webui 0.274.0 → 0.275.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/server/index.ts","../../src/server/ws-payload-validation.ts","../../src/server/handlers/worklist-handlers.ts","../../src/server/http-server.ts","../../src/server/http-server/api-handlers.ts","../../src/server/ws-auth.ts","../../src/server/codebase-indexing.ts","../../src/server/file-handlers.ts","../../src/server/file-picker.ts","../../src/server/path-containment.ts","../../src/server/ws-utils.ts","../../src/server/completion-handlers.ts","../../src/server/memory-handlers.ts","../../src/server/mcp-handlers.ts","../../src/server/skills-handlers.ts","../../src/server/boot.ts","../../src/server/autophase-ws-handler.ts","../../src/server/specs-ws-handler.ts","../../src/server/sdd-board-ws-handler.ts","../../src/server/sdd-wizard-ws-handler.ts","../../src/server/sdd-wizard-wiring.ts","../../src/server/sdd-wizard-routes.ts","../../src/server/collaboration-ws-handler.ts","../../src/server/projects-manifest.ts","../../src/server/terminal-ws-handler.ts","../../src/server/worktree-ws-handler.ts","../../src/server/mailbox-handlers.ts","../../src/server/lifecycle.ts","../../src/server/instance-registry.ts","../../src/server/port-utils.ts","../../src/server/open-browser.ts","../../src/server/usage-cost.ts","../../src/server/provider-handlers.ts","../../src/server/provider-config-io.ts","../../src/server/provider-keys.ts","../../src/server/mode-handlers.ts","../../src/server/project-handlers.ts","../../src/server/session-handlers.ts","../../src/server/token-estimator.ts","../../src/server/provider-routes.ts","../../src/server/session-routes.ts","../../src/server/project-routes.ts","../../src/server/mode-routes.ts","../../src/server/prefs-routes.ts","../../src/server/shell-git-routes.ts","../../src/server/mailbox-routes.ts","../../src/server/mcp-routes.ts","../../src/server/brain-routes.ts","../../src/server/autophase-routes.ts","../../src/server/specs-routes.ts","../../src/server/sdd-board-routes.ts","../../src/server/setup-events.ts","../../src/server/custom-context-modes.ts","../../src/server/eternal-iteration-broadcast.ts","../../src/server/shell-open.ts","../../src/server/git-handlers.ts","../../src/server/process-handlers.ts","../../src/server/goal-handlers.ts"],"sourcesContent":["import { expectDefined, GlobalMailbox, getSessionRegistry, AgentStatusTracker, FleetNotifier } from '@wrongstack/core';\nimport {\n handleWorklistMessage,\n type WorklistContext,\n type WorklistMessage,\n} from './handlers/index.js';\nimport { makeMailboxTool, makeMailSendTool, makeMailInboxTool, mailboxSessionTag } from '@wrongstack/core';\nimport { toErrorMessage, wstackGlobalRoot, projectHash } from '@wrongstack/core/utils';\nimport { SkillInstaller } from '@wrongstack/core/skills';\nimport {\n BrainMonitor,\n DefaultBrainArbiter,\n ObservableBrainArbiter,\n createAutonomyBrain,\n createTieredBrainArbiter,\n type BrainArbiter,\n type BrainAutoRisk,\n} from '@wrongstack/core';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { createHttpServer } from './http-server.js';\nimport { setupWebUICodebaseIndexing } from './codebase-indexing.js';\nimport {\n handleFilesTree,\n handleFilesRead,\n handleFilesWrite,\n handleFilesList,\n} from './file-handlers.js';\nimport { createToolLspCompletionSource, handleCompletionRequest } from './completion-handlers.js';\nimport {\n validateMailboxAgentsPayload,\n validateMailboxMessagesPayload,\n validateMailboxPurgePayload,\n validateModelSwitchPayload,\n validatePrefsUpdatePayload,\n validateShellOpenPayload,\n validateGitDiffPayload,\n validateAutonomySwitchPayload,\n validateBrainAskPayload,\n validateBrainRiskPayload,\n} from './ws-payload-validation.js';\nimport {\n handleMemoryList,\n handleMemoryRemember,\n handleMemoryForget,\n} from './memory-handlers.js';\nimport {\n handleMcpList,\n handleMcpAdd,\n handleMcpRemove,\n handleMcpUpdate,\n handleMcpWake,\n handleMcpSleep,\n handleMcpDiscover,\n handleMcpEnable,\n handleMcpDisable,\n handleMcpRestart,\n} from './mcp-handlers.js';\nimport {\n handleSkillsList,\n handleSkillsContent,\n handleSkillsInstall,\n handleSkillsUninstall,\n handleSkillsUpdate,\n handleSkillsCreate,\n handleSkillsEdit,\n handleSkillsExport,\n} from './skills-handlers.js';\nimport {\n Agent,\n AutoCompactionMiddleware,\n Context,\n DefaultMemoryStore,\n DefaultModeStore,\n DefaultModelsRegistry,\n DefaultSessionReader,\n DefaultSessionStore,\n DefaultSkillLoader,\n DefaultSystemPromptBuilder,\n DefaultTokenCounter,\n AnnotationsStore,\n CollaborationBus,\n collabPauseMiddleware,\n collabInjectMiddleware,\n estimateRequestTokensCalibrated,\n EventBus,\n createStrategyCompactor,\n type Provider,\n ProviderRegistry,\n TOKENS,\n ToolRegistry,\n atomicWrite,\n createDefaultPipelines,\n createSessionEventBridge,\n resolveSessionLoggingConfig,\n DEFAULT_CONTEXT_WINDOW_MODE_ID,\n DEFAULT_SESSION_PRUNE_DAYS,\n DEFAULT_TOOLS_CONFIG,\n applyToolDescriptionModes,\n resolveContextWindowPolicy,\n enhanceUserPrompt,\n gatedEnhancerReasoning,\n recentTextTurns,\n resolveProviderModelList,\n} from '@wrongstack/core';\nimport { ToolExecutor } from '@wrongstack/core/execution';\nimport { decryptConfigSecrets, encryptConfigSecrets } from '@wrongstack/core/security';\nimport { buildProviderFactoriesFromRegistry, makeProviderFromConfig } from '@wrongstack/providers';\nimport { builtinToolsPack, configureExecPolicy, ensureSessionShell, forgetTool, rememberTool, searchMemoryTool, relatedMemoryTool } from '@wrongstack/tools';\nimport { MCPRegistry } from '@wrongstack/mcp';\nimport { WebSocket, WebSocketServer } from 'ws';\nimport { createDefaultContainer, makeLightSubagentFactory } from '@wrongstack/runtime';\nimport { bootConfig, patchConfig } from './boot.js';\nimport { AutoPhaseWebSocketHandler } from './autophase-ws-handler.js';\nimport { SpecsWebSocketHandler } from './specs-ws-handler.js';\nimport { SddBoardWebSocketHandler } from './sdd-board-ws-handler.js';\nimport { SddWizardWebSocketHandler } from './sdd-wizard-ws-handler.js';\nimport { buildSddWizardDeps } from './sdd-wizard-wiring.js';\nimport { handleSddWizardRoute, type SddWizardRouteHandlers } from './sdd-wizard-routes.js';\nimport { CollaborationWebSocketHandler } from './collaboration-ws-handler.js';\nimport {\n ensureProjectDataDir,\n generateProjectSlug,\n loadManifest,\n saveManifest,\n} from './projects-manifest.js';\nimport { TerminalWebSocketHandler } from './terminal-ws-handler.js';\nimport { WorktreeWebSocketHandler } from './worktree-ws-handler.js';\nimport { handleMailboxMessages, handleMailboxAgents, handleMailboxClear, handleMailboxPurge } from './mailbox-handlers.js';\nimport { verifyClient as verifyWsClient } from './ws-auth.js';\nimport { registerShutdownHandlers } from './lifecycle.js';\nimport { registerInstance, unregisterInstance } from './instance-registry.js';\nimport { findFreePort } from './port-utils.js';\nimport { openBrowser } from './open-browser.js';\nimport { computeUsageCost, getCostRates } from './usage-cost.js';\nimport { createProviderHandlers, projectSavedProviders } from './provider-handlers.js';\nimport { createModeHandlers } from './mode-handlers.js';\nimport { createProjectHandlers } from './project-handlers.js';\nimport { createSessionHandlers } from './session-handlers.js';\nimport { handleProviderRoute, type ProviderRouteHandlers } from './provider-routes.js';\nimport { handleSessionRoute, type SessionRouteHandlers } from './session-routes.js';\nimport { handleProjectRoute, type ProjectRouteHandlers } from './project-routes.js';\nimport { handleModeRoute, type ModeRouteHandlers } from './mode-routes.js';\nimport { handlePrefsRoute, type PrefsRouteHandlers } from './prefs-routes.js';\nimport { handleShellGitRoute, type ShellGitRouteHandlers } from './shell-git-routes.js';\nimport { handleMailboxRoute, type MailboxRouteHandlers } from './mailbox-routes.js';\nimport { handleMcpRoute, type McpRouteHandlers } from './mcp-routes.js';\nimport { handleBrainRoute, type BrainRouteHandlers } from './brain-routes.js';\nimport { handleAutoPhaseRoute, type AutoPhaseRouteHandlers } from './autophase-routes.js';\nimport { handleSpecsRoute, type SpecsRouteHandlers } from './specs-routes.js';\nimport { handleSddBoardRoute, type SddBoardRouteHandlers } from './sdd-board-routes.js';\nimport { setupEvents, type FileWatcherMetrics } from './setup-events.js';\nimport { createCustomModeStore } from './custom-context-modes.js';\nimport { maskedKey, normalizeKeys } from './provider-keys.js';\nimport {\n send,\n broadcast,\n sendResult,\n errMessage,\n resolveAuthToken,\n buildWebUIAccessUrl,\n envFlag,\n} from './ws-utils.js';\nimport { createEternalSubscription } from './eternal-iteration-broadcast.js';\nimport { handleShellOpen, type ShellOpenRequest, type ShellOpenResult } from './shell-open.js';\nimport { handleGitChanges, handleGitDiff, handleGitInfo } from './git-handlers.js';\nimport {\n handleProcessKill,\n handleProcessKillAll,\n handleProcessList,\n} from './process-handlers.js';\nimport { handleGoalGet } from './goal-handlers.js';\n// Re-export types — shared message shapes and options used by both the\n// standalone server and the CLI's `--webui` embedded mode.\nexport type { WebUIOptions, BackendServices } from './types.js';\nexport type { WSServerMessage, WSClientMessage, ConnectedClient } from './types.js';\n\n// Re-export the static-serve + multi-instance building blocks so other packages\n// (the CLI's `--webui` mode) can serve the same React frontend, inject the live\n// WS port, pick free ports, and register in the shared instance registry —\n// without duplicating any of that logic.\nexport { createHttpServer, buildCspHeader, injectWsPort } from './http-server.js';\nexport type { CreateHttpServerOptions } from './http-server.js';\nexport { findFreePort, isPortFree } from './port-utils.js';\nexport { openBrowser, browserOpenCommand } from './open-browser.js';\nexport { WorktreeWebSocketHandler } from './worktree-ws-handler.js';\n// Token estimator primitives — exposed for the CLI's embedded webui\n// (which historically inlined its own copy and let it drift). Now\n// there's exactly one definition. See\n// packages/cli/src/webui-server.ts Phase 2 of the refactor plan.\nexport {\n estimateTokens,\n messageTokens,\n messagePreview,\n stringifyContent,\n type ContextBreakdown,\n type MessageTokenEntry,\n type ToolTokenEntry,\n} from './token-estimator.js';\nexport {\n registerInstance,\n unregisterInstance,\n listInstances,\n formatInstances,\n registryPath,\n defaultBaseDir,\n type WebUIInstanceRecord,\n} from './instance-registry.js';\n\n// WebSocket utilities shared with CLI\nexport {\n createEternalSubscription,\n type EternalSubscribe,\n type EternalBroadcast,\n type EternalSubscription,\n} from './eternal-iteration-broadcast.js';\nexport {\n handleShellOpen,\n type ShellOpenRequest,\n type ShellOpenResult,\n type ShellOpenTarget,\n} from './shell-open.js';\nexport {\n send,\n broadcast,\n sendResult,\n errMessage,\n generateAuthToken,\n resolveAuthToken,\n hostForBrowserUrl,\n buildWebUIAccessUrl,\n envFlag,\n} from './ws-utils.js';\n\n// File operation handlers shared with CLI (files.tree, files.read, files.write, files.list)\nexport {\n handleFilesTree,\n handleFilesRead,\n handleFilesWrite,\n handleFilesList,\n} from './file-handlers.js';\nexport {\n createToolLspCompletionSource,\n handleCompletionRequest,\n type CompletionHandlerOptions,\n type CompletionItemKind,\n type CompletionSuggestion,\n type LspCompletionSource,\n type LspCompletionSourceRequest,\n} from './completion-handlers.js';\n\n// Git info handler shared with CLI (git.info) — single source so the two\n// servers can't drift on ahead/behind / insertion-deletion parsing.\nexport { handleGitChanges, handleGitDiff, handleGitInfo } from './git-handlers.js';\n\n// Memory operation handlers shared with CLI (memory.list, memory.remember, memory.forget)\nexport {\n handleMemoryList,\n handleMemoryRemember,\n handleMemoryForget,\n} from './memory-handlers.js';\n\n// MCP operation handlers shared with CLI (mcp.list, mcp.add, mcp.remove, etc.)\nexport {\n handleMcpList,\n handleMcpAdd,\n handleMcpRemove,\n handleMcpUpdate,\n handleMcpWake,\n handleMcpSleep,\n handleMcpDiscover,\n handleMcpEnable,\n handleMcpDisable,\n handleMcpRestart,\n} from './mcp-handlers.js';\n\n// Custom context-mode store shared with the CLI's embedded server\n// (context.mode.create/update/delete + custom-aware list/switch).\nexport {\n createCustomModeStore,\n type CustomModeStore,\n type CustomContextMode,\n} from './custom-context-modes.js';\n\n// WS auth — pure functions for verifying WebSocket connections\nexport {\n verifyClient,\n isLoopbackHostname,\n isLoopbackBind,\n tokenMatches,\n extractToken,\n hostHeaderOk,\n type VerifyClientInput,\n} from './ws-auth.js';\n\n// Provider/API-key record transforms (pure functions, testable without I/O)\nexport {\n normalizeKeys,\n writeKeysBack,\n maskedKey,\n upsertKey,\n deleteKey,\n setActiveKey,\n addProvider,\n removeProvider,\n type KeyOpResult,\n type ProvidersRecord,\n} from './provider-keys.js';\n\n// Provider config load/save (decrypt from / encrypt to global config)\nexport {\n loadSavedProviders,\n saveProviders,\n createProviderConfigIO,\n} from './provider-config-io.js';\n\n// AutoPhase WebSocket handler — manages AutoPhase lifecycle via WS messages.\n// Exported so the CLI's embedded webui-server can also handle autophase.*\n// messages when running in --webui mode.\nexport { AutoPhaseWebSocketHandler } from './autophase-ws-handler.js';\nexport { SpecsWebSocketHandler } from './specs-ws-handler.js';\nexport { SddBoardWebSocketHandler } from './sdd-board-ws-handler.js';\nexport { SddWizardWebSocketHandler, type SddWizardDeps } from './sdd-wizard-ws-handler.js';\nexport { buildSddWizardDeps, type SddWizardWiringOptions } from './sdd-wizard-wiring.js';\n\n// Shared skills WebSocket handlers — one source of truth for both this\n// standalone server and the CLI's embedded --webui server. The CLI imports\n// these so skills.content / install / uninstall / update / create / edit /\n// export are handled there too (they previously fell through to the\n// \"Unhandled message type\" warning).\nexport {\n type SkillsContext,\n handleSkillsContent,\n handleSkillsInstall,\n handleSkillsUninstall,\n handleSkillsUpdate,\n handleSkillsCreate,\n handleSkillsEdit,\n handleSkillsExport,\n} from './skills-handlers.js';\n\n// Message + client shapes now live in ./types.ts (shared with the CLI's\n// embedded server). Imported here for internal use; re-exported above for\n// external consumers. The previous local copies shadowed these and made the\n// `Map<WebSocket, ConnectedClient>` passed to the extracted ws-utils helpers\n// nominally distinct, which TS rejected.\nimport type { ConnectedClient, WSClientMessage, WebUIOptions } from './types.js';\n\nexport async function startWebUI(\n opts: WebUIOptions & {\n wsPort?: number | undefined;\n wsHost?: string | undefined;\n httpPort?: number | undefined;\n accessToken?: string | undefined;\n publicUrl?: string | undefined;\n publicWsUrl?: string | undefined;\n requireToken?: boolean | undefined;\n open?: boolean | undefined;\n } = {},\n): Promise<void> {\n // Pin one stable shell for the session on Windows (PowerShell by default) via\n // WRONGSTACK_SHELL before the system-prompt builder is constructed below, so\n // the model is told exactly which shell + syntax to use. No-op on POSIX / when\n // the user already set WRONGSTACK_SHELL.\n ensureSessionShell();\n\n const requestedWsPort = opts.wsPort ?? 3457;\n // Bind to loopback IP by default (not the string \"localhost\", which on some\n // hosts resolves to IPv6 ::1 and surprises older WS clients). Set WS_HOST or\n // pass opts.wsHost to override (e.g. \"0.0.0.0\" for LAN access).\n const wsHost = opts.wsHost ?? process.env['WEBUI_HOST'] ?? process.env['WS_HOST'] ?? '127.0.0.1';\n const requestedHttpPort =\n opts.httpPort ??\n opts.webuiPort ??\n opts.port ??\n Number.parseInt(process.env['WEBUI_PORT'] ?? process.env['PORT'] ?? '3456', 10);\n const publicUrl = opts.publicUrl ?? process.env['WEBUI_PUBLIC_URL'];\n const publicWsUrl = opts.publicWsUrl ?? process.env['WEBUI_PUBLIC_WS_URL'];\n const requireToken = opts.requireToken ?? envFlag('WEBUI_REQUIRE_TOKEN');\n\n // Port resolution. Unless WEBUI_STRICT_PORT is set, auto-advance past any port\n // already taken by another instance so running `wstackui` several times \"just\n // works\" — the real ports are then stamped into the served HTML and the\n // instance registry. Strict mode keeps the requested ports and lets bind fail\n // loudly (useful behind a reverse proxy that expects fixed ports).\n const strictPort =\n process.env['WEBUI_STRICT_PORT'] === '1' || process.env['WEBUI_STRICT_PORT'] === 'true';\n let wsPort = requestedWsPort;\n let httpPort = requestedHttpPort;\n if (!strictPort) {\n // Resolve HTTP first, then WS excluding it, so successive instances land on\n // tidy adjacent pairs (3456/3457, 3458/3459, …) instead of interleaving.\n httpPort = await findFreePort(wsHost, requestedHttpPort);\n wsPort = await findFreePort(wsHost, requestedWsPort, { exclude: new Set([httpPort]) });\n if (httpPort !== requestedHttpPort) {\n console.warn(JSON.stringify({\n level: 'warn',\n event: 'webui.port_reassigned',\n protocol: 'HTTP',\n requested: requestedHttpPort,\n assigned: httpPort,\n timestamp: new Date().toISOString(),\n }));\n }\n if (wsPort !== requestedWsPort) {\n console.warn(JSON.stringify({\n level: 'warn',\n event: 'webui.port_reassigned',\n protocol: 'WS',\n requested: requestedWsPort,\n assigned: wsPort,\n timestamp: new Date().toISOString(),\n }));\n }\n }\n\n console.log('[WebUI] Starting backend services...');\n\n // Boot configuration\n const boot = await bootConfig();\n const { config: baseConfig, globalConfigPath, wpaths, logger } = boot;\n // PR 5 of Phase 2: when the caller (typically the CLI) supplies a\n // pre-built `BackendServices`, prefer its `vault` over the one the\n // default boot would construct. This lets `runWebUI` keep owning the\n // vault lifecycle (so it can decrypt/encrypt its own config writes\n // in lockstep with the rest of the CLI session) instead of having\n // the webui build a parallel vault it can never see.\n const vault = opts.services?.vault ?? boot.vault;\n let config = baseConfig;\n\n /** Mutable project root — updated on `projects.select`. File handlers,\n * sessionStartPayload, and session store use this value. */\n let projectRoot = boot.projectRoot;\n /** Mutable working directory — starts at projectRoot, changeable via\n * `working_dir.set` WS message. Must always stay inside projectRoot. */\n let workingDir = projectRoot;\n\n // Serialize concurrent config writes to prevent races between model.switch\n // and key.add/key.update handlers that both read-modify-write globalConfigPath.\n let configWriteLock: Promise<void> = Promise.resolve();\n\n /**\n * Unified global config mutation: read → decrypt → mutate → encrypt → write.\n * All config writes MUST go through this helper so encryption is always\n * preserved and writes are serialized behind configWriteLock.\n * The `mutate` callback receives the decrypted config and mutates it in place.\n * Failures log but never break the caller (non-poisoning lock).\n */\n const updateGlobalConfig = async (\n mutate: (config: Record<string, unknown>) => void,\n errorLabel: string,\n ): Promise<void> => {\n const write = async (): Promise<void> => {\n let raw: string;\n try {\n raw = await fs.readFile(globalConfigPath, 'utf8');\n } catch {\n raw = '{}';\n }\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(raw) as Record<string, unknown>;\n } catch {\n logger.warn(`${errorLabel}: refusing to overwrite corrupt config at ${globalConfigPath}`);\n return;\n }\n const decrypted = decryptConfigSecrets(parsed, vault) as Record<string, unknown>;\n mutate(decrypted);\n const encrypted = encryptConfigSecrets(decrypted, vault);\n await atomicWrite(globalConfigPath, JSON.stringify(encrypted, null, 2), { mode: 0o600 });\n };\n const next = configWriteLock.then(write);\n configWriteLock = next.then(\n () => undefined,\n () => undefined,\n );\n try {\n await next;\n } catch (err) {\n logger.warn(`${errorLabel}: failed to persist to config: ${errMessage(err)}`);\n }\n };\n\n console.log('[WebUI] Config loaded:', config.provider ?? '(none)', '/', config.model ?? '(none)');\n\n // If no active provider is set but there are saved providers, pick the first one.\n // This handles configs written in older formats or by external tools.\n // Guard against config.providers being a string or other non-object value\n // (e.g., from a corrupted config or YAML parser misreading the value).\n if (\n !config.provider &&\n config.providers &&\n typeof config.providers === 'object' &&\n config.providers !== null &&\n !Array.isArray(config.providers) &&\n Object.keys(config.providers).length > 0\n ) {\n const firstKey = expectDefined(Object.keys(config.providers)[0]);\n config = patchConfig(config, { provider: firstKey });\n console.log('[WebUI] No active provider — auto-selected:', firstKey);\n }\n\n // If still no provider, the frontend will show a no-provider welcome screen.\n // We still start the HTTP/WS servers so the user can configure via the UI.\n const needsProvider = !config.provider || !config.model;\n\n // ModelsRegistry — use injected one if `services.modelsRegistry` was passed,\n // otherwise build a fresh one. The injected path lets the CLI's `runWebUI`\n // share a single registry across its own runtime and the webui surface.\n const modelsRegistry =\n opts.services?.modelsRegistry ??\n new DefaultModelsRegistry({\n cacheFile: wpaths.modelsCache,\n ttlSeconds: 24 * 3600,\n });\n\n // Container via shared factory\n const container = createDefaultContainer({ config, wpaths, logger, modelsRegistry });\n // PR 5 of Phase 2: when the caller (typically the CLI) supplies a\n // pre-built `BackendServices`, prefer its `configStore` over the one\n // the default container would resolve. This is the read+write\n // counterpart of the `vault` injection above: together they let\n // `runWebUI` own the global config lifecycle and have the webui\n // operate on the *same* in-memory store, so a `provider.switch`\n // from the webui is visible to the CLI's next call without a disk\n // round-trip in between.\n const configStore = opts.services?.configStore ?? container.resolve(TOKENS.ConfigStore);\n\n // Provider registry\n const providerRegistry = new ProviderRegistry();\n try {\n const factories = await buildProviderFactoriesFromRegistry({\n registry: modelsRegistry,\n log: logger,\n });\n for (const f of factories) providerRegistry.register(f);\n console.log('[WebUI] Provider registry loaded:', providerRegistry.list().length, 'providers');\n } catch (err) {\n console.warn(JSON.stringify({\n level: 'warn',\n event: 'webui.provider_registry_load_failed',\n message: toErrorMessage(err),\n timestamp: new Date().toISOString(),\n }));\n }\n\n // Tool registry — use injected one if `services.toolRegistry` was passed.\n // When injected, the caller has already registered the tools they want\n // (the CLI's runWebUI registers its own runtime tools); startWebUI just\n // uses the registry as-is.\n const toolRegistry =\n opts.services?.toolRegistry ??\n (() => {\n const r = new ToolRegistry();\n r.registerAllOrThrow([...(builtinToolsPack.tools ?? [])], builtinToolsPack.name);\n return r;\n })();\n\n // Memory tools\n const memoryStore = new DefaultMemoryStore({ paths: wpaths });\n if (config.features.memory) {\n toolRegistry.register(rememberTool(memoryStore));\n toolRegistry.register(forgetTool(memoryStore));\n toolRegistry.register(searchMemoryTool(memoryStore));\n toolRegistry.register(relatedMemoryTool(memoryStore));\n }\n\n // Event bus — use injected one if `services.events` was passed. The CLI's\n // runWebUI owns the agent's EventBus so it can wire sub-agents onto the\n // same bus the webui dashboard reads from. When injected, we just\n // attach the logger and reuse the existing instance.\n const events = opts.services?.events ?? new EventBus();\n events.setLogger(logger);\n\n // Inter-agent mailbox tools — same project-level GlobalMailbox the CLI\n // registers, keyed by wpaths.projectDir so WebUI agents and terminal\n // agents on the same project share one inbox and can chat/broadcast.\n // mail_send/mail_inbox are the high-affordance thin wrappers.\n toolRegistry.register(makeMailboxTool({ projectDir: wpaths.projectDir, events }));\n toolRegistry.register(makeMailSendTool({ projectDir: wpaths.projectDir, events }));\n toolRegistry.register(makeMailInboxTool({ projectDir: wpaths.projectDir, events }));\n applyToolDescriptionModes(toolRegistry, config.tools?.descriptionMode);\n // Apply the configured exec command policy (DEFAULT ∪ allow − deny). `allow`\n // is trusted-config-only; the config loader strips `tools.exec.allow` from\n // any in-project repo config before it reaches here.\n configureExecPolicy(config.tools?.exec ?? {});\n console.log('[WebUI] Tool registry loaded:', toolRegistry.list().length, 'tools');\n\n // ── MCP registry — the live counterpart to config.mcpServers. ────────────\n // The standalone WebUI server now owns a real registry (the CLI's embedded\n // server reuses the agent's), so the MCP settings panel can actually\n // start/stop servers and surface live status + tool names, not just edit\n // config. Enabled servers are connected at boot, mirroring the CLI host.\n const mcpRegistry = new MCPRegistry({\n toolRegistry,\n events,\n log: logger,\n // Lazy-connect (per-server `lazy`) manifest cache + default idle auto-sleep.\n cacheDir: wpaths.cacheDir,\n });\n if (config.features.mcp && config.mcpServers) {\n for (const [name, cfg] of Object.entries(config.mcpServers)) {\n if (cfg.enabled === false) continue;\n void mcpRegistry.start({ ...cfg, name }).catch((err) => {\n logger.warn(`MCP server \"${name}\" failed to start at boot`, err);\n });\n }\n }\n\n // Session store — mutable so projects.select can swap it to the new project's dir.\n // Use the injected one if `services.session` was passed. The CLI's\n // runWebUI already has its own session store pointing at the\n // right per-project dir; we reuse it here so the webui reads\n // the same history the CLI is writing.\n let sessionStore = opts.services?.session ?? new DefaultSessionStore({ dir: wpaths.projectSessions });\n // Prune old sessions on server start (non-blocking). Skipped when\n // an injected store is in use — the CLI's eternal loop is\n // responsible for its own lifecycle and pruning an in-use store\n // would race with the CLI's own prune policy.\n if (!opts.services?.session) {\n sessionStore\n .prune(DEFAULT_SESSION_PRUNE_DAYS)\n .then((count) => {\n if (count > 0) logger.info(`Pruned ${count} old session${count === 1 ? '' : 's'}.`);\n })\n .catch(() => undefined);\n }\n // Session reader — same on-disk store, read-only access. Used by the\n // collaboration handler to replay the last N events to late-joining\n // observers (Phase 1.5 of idea #13).\n const sessionReader = new DefaultSessionReader({ store: sessionStore });\n // Annotations store — sidecar files for collaboration notes (Phase 2\n // of idea #13). Living under `projectSessions` so all per-session\n // data is colocated and travels with the project.\n const annotationsStore = new AnnotationsStore({ dir: wpaths.projectSessions, events });\n let session = await sessionStore.create({\n id: '',\n title: '',\n model: config.model,\n provider: config.provider,\n });\n // Wall-clock when the *current* session started. Updated on /new and on\n // /resume so /stats can report accurate elapsed time per the active\n // session, not the daemon process uptime.\n let sessionStartedAt = Date.now();\n console.log('[WebUI] Session created:', session.id);\n\n // ── Cross-surface discovery ──────────────────────────────────────────\n // (1) Register/refresh this project in ~/.wrongstack/projects.json so\n // pickers and other surfaces see it regardless of which interface\n // opened it first. (2) Register this session in the cross-process\n // SessionRegistry so terminals' `/sessions status` lists this WebUI\n // (and vice versa). Both best-effort — discovery must not block boot.\n try {\n await touchProjectEntry(projectRoot, workingDir);\n } catch { /* best-effort */ }\n let statusTracker: AgentStatusTracker | undefined;\n try {\n const registry = getSessionRegistry(wpaths.globalRoot);\n await registry.register({\n sessionId: session.id,\n projectSlug: wpaths.projectSlug,\n projectRoot,\n projectName: path.basename(projectRoot),\n workingDir,\n clientType: 'webui',\n pid: process.pid,\n startedAt: new Date().toISOString(),\n });\n // Push-on-write: nudge OTHER same-project WebUIs when our agents advance,\n // so a fleet of WebUI windows stays in lockstep without watch/poll lag.\n const fleetNotifier = new FleetNotifier({\n baseDir: wpaths.globalRoot,\n projectRoot,\n selfPid: process.pid,\n });\n statusTracker = new AgentStatusTracker({ events, registry, onUpdate: () => fleetNotifier.notify() });\n statusTracker.start();\n\n // ── HQ session telemetry — stream live state + full transcript to HQ ──\n let stopHqSessionBridge: (() => void) | undefined;\n let hqTelemetryPublisher: { close(): void } | undefined;\n try {\n const { createHqPublisherFromEnv, startSessionTelemetryBridge } = await import('@wrongstack/core');\n const hqTelemetry = createHqPublisherFromEnv({\n clientKind: 'webui',\n projectRoot,\n projectName: path.basename(projectRoot),\n appConfig: config as never as Parameters<typeof createHqPublisherFromEnv>[0]['appConfig'],\n socketFactory: (url: string) => new WebSocket(url) as unknown as import('@wrongstack/core').HqSocketLike,\n });\n if (hqTelemetry) {\n hqTelemetry.connect();\n hqTelemetryPublisher = hqTelemetry;\n stopHqSessionBridge = startSessionTelemetryBridge({\n publisher: hqTelemetry,\n events,\n sessionId: session.id,\n projectRoot,\n projectName: path.basename(projectRoot),\n globalRoot: wpaths.globalRoot,\n initialAgents: statusTracker?.getAgents(),\n startedAt: new Date().toISOString(),\n });\n }\n } catch { /* telemetry optional */ }\n\n const stopTracking = async () => {\n try {\n fleetNotifier.dispose();\n await registry.markClosing();\n statusTracker?.stop();\n stopHqSessionBridge?.();\n hqTelemetryPublisher?.close();\n } catch { /* ignore */ }\n };\n process.once('beforeExit', () => { void stopTracking(); });\n process.once('SIGINT', () => { void stopTracking(); });\n process.once('SIGTERM', () => { void stopTracking(); });\n } catch { /* best-effort — discovery degrades gracefully */ }\n\n // Token counter\n const tokenCounter = new DefaultTokenCounter({\n registry: modelsRegistry,\n providerId: config.provider,\n });\n\n // Mode store\n const modeStore = new DefaultModeStore({ directory: wpaths.configDir });\n const activeMode = await modeStore.getActiveMode();\n let modeId = activeMode?.id ?? 'default';\n const modePrompt = activeMode?.prompt ?? '';\n\n // Custom context modes store — user-defined presets persisted to disk.\n // Loaded once on startup; merges with built-in modes in the list handler.\n const customModeStore = createCustomModeStore(wpaths.configDir);\n await customModeStore.load();\n console.log(\n '[WebUI] Custom context modes loaded:',\n customModeStore.list().filter((m) => (m as { custom?: boolean }).custom).length,\n 'custom',\n );\n\n // System prompt builder\n const resolvedModel = await modelsRegistry.getModel(config.provider, config.model);\n const modelCapabilities = resolvedModel?.capabilities\n ? {\n maxContextTokens: resolvedModel.capabilities.maxContext,\n supportsTools: resolvedModel.capabilities.tools,\n supportsVision: resolvedModel.capabilities.vision,\n supportsReasoning: resolvedModel.capabilities.reasoning,\n }\n : undefined;\n const modelCapabilitiesRef: { current: typeof modelCapabilities } = {\n current: modelCapabilities,\n };\n\n const skillLoader = config.features.skills\n ? new DefaultSkillLoader({ paths: wpaths })\n : undefined;\n const skillInstaller = config.features.skills\n ? new SkillInstaller({\n manifestPath: path.join(wstackGlobalRoot(), 'installed-skills.json'),\n projectSkillsDir: path.join(projectRoot, '.wrongstack', 'skills'),\n globalSkillsDir: path.join(wstackGlobalRoot(), 'skills'),\n projectHash: projectHash(projectRoot),\n skillLoader,\n })\n : undefined;\n const systemPromptBuilder = new DefaultSystemPromptBuilder({\n memoryStore,\n skillLoader,\n modeStore,\n modeId,\n modePrompt,\n modelCapabilities: () => modelCapabilitiesRef.current,\n });\n\n // Fetch online agents from the shared mailbox to include in system prompt\n let onlineAgents: import('@wrongstack/core').MailboxAgentStatus[] = [];\n try {\n const systemMailbox = new GlobalMailbox(wpaths.projectDir);\n onlineAgents = await systemMailbox.getAgentStatuses();\n } catch {\n // Non-fatal — mailbox errors should not block prompt building\n }\n\n const systemPrompt = await systemPromptBuilder.build({\n cwd: projectRoot,\n projectRoot,\n tools: toolRegistry.list(),\n provider: config.provider,\n model: config.model,\n onlineAgents,\n });\n\n // Build provider (only if provider is configured)\n let provider: ReturnType<ProviderRegistry['create']>;\n if (!needsProvider) {\n const providerConfig = config.providers?.[config.provider] ?? {\n type: config.provider,\n apiKey: config.apiKey,\n baseUrl: config.baseUrl,\n };\n try {\n const cfgWithType = { ...providerConfig, type: config.provider };\n if (config.features.modelsRegistry && providerRegistry.has(config.provider)) {\n provider = providerRegistry.create(cfgWithType);\n } else {\n provider = makeProviderFromConfig(config.provider, cfgWithType);\n }\n } catch (err) {\n console.error(JSON.stringify({\n level: 'error',\n event: 'webui.provider_create_failed',\n message: toErrorMessage(err),\n timestamp: new Date().toISOString(),\n }));\n throw err;\n }\n } else {\n // No provider is actively selected, but saved providers exist.\n // Re-read the config to find one with a usable encrypted API key\n // and create a real provider from it (the vault is already initialized).\n const savedProviders = config.providers ?? {};\n const firstKey = Object.keys(savedProviders)[0];\n if (firstKey) {\n const firstProvider = expectDefined(savedProviders[firstKey]);\n try {\n provider = makeProviderFromConfig(firstKey, {\n ...firstProvider,\n type: firstKey,\n family: firstProvider.family,\n apiKey: firstProvider.apiKey,\n });\n console.log('[WebUI] Using saved provider:', firstKey);\n } catch (err) {\n console.error(JSON.stringify({\n level: 'error',\n event: 'webui.provider_stub_create_failed',\n message: toErrorMessage(err),\n timestamp: new Date().toISOString(),\n }));\n throw err;\n }\n } else {\n throw new Error(\n 'No provider configured. Run `wrongstack auth` to set up, or configure via the WebUI.',\n );\n }\n }\n\n // Context\n const context = new Context({\n systemPrompt,\n provider,\n session,\n signal: new AbortController().signal,\n tokenCounter,\n cwd: workingDir,\n projectRoot,\n model: config.model,\n });\n const initialContextPolicy = resolveContextWindowPolicy(config.context);\n context.meta['contextWindowMode'] = initialContextPolicy.id;\n context.meta['contextWindowPolicy'] = initialContextPolicy;\n\n // ── Seed runtime prefs from config ──────────────────────────────────────\n // The settings panel reads prefs via `prefs.get` → context.meta. Without\n // this seed the snapshot is empty and every browser shows localStorage\n // defaults (autonomy \"off\", etc.) regardless of what config.json says.\n // Mirrors the CLI's getSettings() mapping so TUI and WebUI agree.\n {\n const autonomyCfg = (config.autonomy ?? {}) as Record<string, unknown>;\n const rawMode = autonomyCfg['defaultMode'];\n context.meta['autonomy'] =\n rawMode === 'suggest' || rawMode === 'auto' ? rawMode : 'off';\n context.meta['autonomyDelayMs'] = (autonomyCfg['autoProceedDelayMs'] as number) ?? 45_000;\n context.meta['autoProceedMaxIterations'] =\n (autonomyCfg['autoProceedMaxIterations'] as number) ?? 50;\n context.meta['yolo'] = (autonomyCfg['yolo'] as boolean) ?? config.yolo ?? false;\n context.meta['chime'] = (autonomyCfg['chime'] as boolean) ?? false;\n context.meta['confirmExit'] = autonomyCfg['confirmExit'] !== false;\n context.meta['streamFleet'] = autonomyCfg['streamFleet'] !== false;\n context.meta['enhanceEnabled'] = (autonomyCfg['enhance'] as boolean) ?? true;\n context.meta['enhanceDelayMs'] = (autonomyCfg['enhanceDelayMs'] as number) ?? 60_000;\n context.meta['enhanceLanguage'] = (autonomyCfg['enhanceLanguage'] as string) ?? 'original';\n context.meta['nextPrediction'] = config.nextPrediction ?? false;\n context.meta['fallbackModels'] = config.fallbackModels ?? [];\n context.meta['fallbackAuto'] = config.fallbackAuto !== false;\n context.meta['featureMcp'] = config.features.mcp !== false;\n context.meta['featurePlugins'] = config.features.plugins !== false;\n context.meta['featureMemory'] = config.features.memory !== false;\n context.meta['featureSkills'] = config.features.skills !== false;\n context.meta['featureModelsRegistry'] = config.features.modelsRegistry !== false;\n context.meta['indexOnStart'] = config.indexing?.onSessionStart !== false;\n context.meta['contextAutoCompact'] = config.context?.autoCompact !== false;\n context.meta['contextStrategy'] = config.context?.strategy ?? 'hybrid';\n context.meta['logLevel'] = config.log?.level ?? 'info';\n context.meta['auditLevel'] = config.session?.auditLevel ?? 'standard';\n context.meta['maxIterations'] = config.tools?.maxIterations ?? 500;\n const hqConfig = (config as { hq?: { enabled?: boolean; url?: string; token?: string; rawContent?: boolean } }).hq;\n context.meta['hqEnabled'] = hqConfig?.enabled === true;\n context.meta['hqUrl'] = hqConfig?.url ?? '';\n context.meta['hqToken'] = hqConfig?.token ?? '';\n context.meta['hqRawContent'] = hqConfig?.rawContent === true;\n\n // Telegram plugin notification settings live under\n // extensions.telegram — same path the CLI's /telegram-settings writes.\n // Seed the meta so the SettingsPanel reflects the persisted config on\n // first connect, before any prefs.update arrives.\n const tgExt = (config.extensions as Record<string, Record<string, unknown>> | undefined)?.['telegram'];\n context.meta['tgConfigured'] = typeof tgExt?.['botToken'] === 'string' && tgExt['botToken'].length > 0;\n context.meta['tgSessionEnd'] = tgExt?.['notifyOnSessionEnd'] === true;\n context.meta['tgDelegate'] = tgExt?.['notifyOnDelegate'] !== false; // default true\n const tgMs = tgExt?.['longToolThresholdMs'];\n context.meta['tgLongToolMs'] = typeof tgMs === 'number' ? tgMs : 30_000;\n }\n\n /** Pref keys exposed to the settings panel via prefs.get / prefs.updated. */\n const PREF_KEYS = [\n 'autonomy', 'autonomyDelayMs', 'autoProceedMaxIterations', 'yolo', 'maxIterations',\n 'chime', 'confirmExit', 'streamFleet', 'nextPrediction',\n 'enhanceEnabled', 'enhanceDelayMs', 'enhanceLanguage',\n 'featureMcp', 'featurePlugins', 'featureMemory', 'featureSkills',\n 'featureModelsRegistry', 'indexOnStart',\n 'contextAutoCompact', 'contextStrategy', 'logLevel', 'auditLevel',\n 'hqEnabled', 'hqUrl', 'hqToken', 'hqRawContent',\n 'tgConfigured', 'tgSessionEnd', 'tgDelegate', 'tgLongToolMs',\n 'reasoningMode', 'reasoningEffort', 'reasoningPreserve', 'cacheTtl',\n 'fallbackModels', 'fallbackAuto',\n ] as const;\n\n const prefSnapshot = (): Record<string, unknown> => {\n const snapshot: Record<string, unknown> = {};\n for (const k of PREF_KEYS) {\n if (k in context.meta) snapshot[k] = context.meta[k];\n }\n return snapshot;\n };\n\n /**\n * Persist pref changes into the global config.json — the SAME keys the\n * TUI settings picker writes — so a toggle made in the browser survives\n * restarts and is visible to the CLI/TUI (and vice versa on next boot).\n * Best-effort and serialized behind configWriteLock (shared with the\n * provider/key handlers); failures log but never break the WS reply.\n */\n const persistPrefsToConfig = async (payload: Record<string, unknown>): Promise<void> => {\n await updateGlobalConfig((decrypted) => {\n const autonomyCfg = (decrypted.autonomy as Record<string, unknown>) ?? {};\n let autonomyTouched = false;\n const setAutonomy = (key: string, val: unknown): void => {\n autonomyCfg[key] = val;\n autonomyTouched = true;\n };\n if (\n typeof payload['autonomy'] === 'string' &&\n ['off', 'suggest', 'auto'].includes(payload['autonomy'])\n ) {\n setAutonomy('defaultMode', payload['autonomy']);\n }\n if (typeof payload['autonomyDelayMs'] === 'number') setAutonomy('autoProceedDelayMs', payload['autonomyDelayMs']);\n if (typeof payload['autoProceedMaxIterations'] === 'number') setAutonomy('autoProceedMaxIterations', payload['autoProceedMaxIterations']);\n if (typeof payload['yolo'] === 'boolean') setAutonomy('yolo', payload['yolo']);\n if (typeof payload['chime'] === 'boolean') setAutonomy('chime', payload['chime']);\n if (typeof payload['confirmExit'] === 'boolean') setAutonomy('confirmExit', payload['confirmExit']);\n if (typeof payload['streamFleet'] === 'boolean') setAutonomy('streamFleet', payload['streamFleet']);\n if (typeof payload['enhanceEnabled'] === 'boolean') setAutonomy('enhance', payload['enhanceEnabled']);\n if (typeof payload['enhanceDelayMs'] === 'number') setAutonomy('enhanceDelayMs', payload['enhanceDelayMs']);\n if (typeof payload['enhanceLanguage'] === 'string') setAutonomy('enhanceLanguage', payload['enhanceLanguage']);\n if (autonomyTouched) decrypted.autonomy = autonomyCfg;\n\n if (typeof payload['nextPrediction'] === 'boolean') decrypted.nextPrediction = payload['nextPrediction'];\n\n // Global fallback model chain (top-level config). Read live by the leader's\n // fallback extension each turn (effectiveFallbackChain), so it takes effect\n // without a restart.\n if (Array.isArray(payload['fallbackModels'])) decrypted.fallbackModels = payload['fallbackModels'];\n if (typeof payload['fallbackAuto'] === 'boolean') decrypted.fallbackAuto = payload['fallbackAuto'];\n\n const FEATURE_MAP: Record<string, string> = {\n featureMcp: 'mcp',\n featurePlugins: 'plugins',\n featureMemory: 'memory',\n featureSkills: 'skills',\n featureModelsRegistry: 'modelsRegistry',\n };\n for (const [prefKey, cfgKey] of Object.entries(FEATURE_MAP)) {\n if (typeof payload[prefKey] === 'boolean') {\n const feats = (decrypted.features as Record<string, unknown>) ?? {};\n feats[cfgKey] = payload[prefKey];\n decrypted.features = feats;\n }\n }\n\n if (typeof payload['contextAutoCompact'] === 'boolean' || typeof payload['contextStrategy'] === 'string') {\n const ctxCfg = (decrypted.context as Record<string, unknown>) ?? {};\n if (typeof payload['contextAutoCompact'] === 'boolean') ctxCfg.autoCompact = payload['contextAutoCompact'];\n if (typeof payload['contextStrategy'] === 'string') ctxCfg.strategy = payload['contextStrategy'];\n decrypted.context = ctxCfg;\n }\n if (typeof payload['logLevel'] === 'string') {\n const logCfg = (decrypted.log as Record<string, unknown>) ?? {};\n logCfg.level = payload['logLevel'];\n decrypted.log = logCfg;\n }\n if (typeof payload['auditLevel'] === 'string') {\n const sessionCfg = (decrypted.session as Record<string, unknown>) ?? {};\n sessionCfg.auditLevel = payload['auditLevel'];\n decrypted.session = sessionCfg;\n }\n if (typeof payload['indexOnStart'] === 'boolean') {\n const indexingCfg = (decrypted.indexing as Record<string, unknown>) ?? {};\n indexingCfg.onSessionStart = payload['indexOnStart'];\n decrypted.indexing = indexingCfg;\n }\n if (typeof payload['maxIterations'] === 'number') {\n const toolsCfg = (decrypted.tools as Record<string, unknown>) ?? {};\n toolsCfg.maxIterations = payload['maxIterations'];\n decrypted.tools = toolsCfg;\n }\n\n const hqTouched =\n typeof payload['hqEnabled'] === 'boolean' ||\n typeof payload['hqUrl'] === 'string' ||\n typeof payload['hqToken'] === 'string' ||\n typeof payload['hqRawContent'] === 'boolean';\n if (hqTouched) {\n const hqCfg = (decrypted.hq as Record<string, unknown>) ?? {};\n if (typeof payload['hqEnabled'] === 'boolean') hqCfg.enabled = payload['hqEnabled'];\n if (typeof payload['hqUrl'] === 'string') hqCfg.url = payload['hqUrl'];\n if (typeof payload['hqToken'] === 'string') hqCfg.token = payload['hqToken'];\n if (typeof payload['hqRawContent'] === 'boolean') hqCfg.rawContent = payload['hqRawContent'];\n decrypted.hq = hqCfg;\n }\n\n const tgTouched =\n typeof payload['tgSessionEnd'] === 'boolean' ||\n typeof payload['tgDelegate'] === 'boolean' ||\n typeof payload['tgLongToolMs'] === 'number';\n if (tgTouched) {\n const ext = (decrypted.extensions as Record<string, Record<string, unknown>>) ?? {};\n const tg = ext['telegram'] ?? {};\n if (typeof payload['tgSessionEnd'] === 'boolean') {\n tg['notifyOnSessionEnd'] = payload['tgSessionEnd'];\n }\n if (typeof payload['tgDelegate'] === 'boolean') {\n tg['notifyOnDelegate'] = payload['tgDelegate'];\n }\n if (typeof payload['tgLongToolMs'] === 'number') {\n tg['longToolThresholdMs'] = payload['tgLongToolMs'];\n }\n ext['telegram'] = tg;\n decrypted.extensions = ext;\n }\n\n // Reasoning / cache runtime controls → Config.modelRuntime\n const modelRuntimeTouched =\n typeof payload['reasoningMode'] === 'string' ||\n typeof payload['reasoningEffort'] === 'string' ||\n typeof payload['reasoningPreserve'] === 'boolean' ||\n typeof payload['cacheTtl'] === 'string';\n if (modelRuntimeTouched) {\n const mr = (decrypted.modelRuntime as Record<string, unknown>) ?? {};\n const reasoning = (mr.reasoning as Record<string, unknown>) ?? {};\n if (typeof payload['reasoningMode'] === 'string') reasoning.mode = payload['reasoningMode'];\n if (typeof payload['reasoningEffort'] === 'string') reasoning.effort = payload['reasoningEffort'];\n if (typeof payload['reasoningPreserve'] === 'boolean') reasoning.preserve = payload['reasoningPreserve'];\n mr.reasoning = reasoning;\n if (typeof payload['cacheTtl'] === 'string' && payload['cacheTtl'] !== 'default') {\n mr.cache = { ttl: payload['cacheTtl'] };\n } else if (payload['cacheTtl'] === 'default') {\n delete mr.cache;\n }\n decrypted.modelRuntime = mr;\n }\n }, 'prefs');\n };\n\n // Pipelines\n const pipelines = createDefaultPipelines();\n // Collaboration bus — process-singleton pause/resume signal. The\n // middleware below hooks it into the toolCall pipeline so a\n // `controller` participant can halt the agent before the next tool\n // call (Phase 3 of idea #13). The same bus instance is shared with\n // the CollaborationWebSocketHandler so client pause/resume requests\n // are routed to the kernel.\n const collabBus = new CollaborationBus();\n // prepend (not use) — the pause check must run first, before any\n // permission/retry middleware that would otherwise proceed.\n const collabPause = collabPauseMiddleware(collabBus, { logger });\n Object.defineProperty(collabPause, 'name', { value: 'collab-pause' });\n pipelines.toolCall.prepend(collabPause as never);\n // Phase 4 — collab-inject. Installed AFTER collab-pause so the\n // controller can pause + inject before the next tool runs. The\n // middleware checks the bus's injection queue and splices a\n // synthetic tool_result when a controller has queued one for\n // the current toolUse.id.\n const collabInject = collabInjectMiddleware(collabBus, { logger });\n Object.defineProperty(collabInject, 'name', { value: 'collab-inject' });\n pipelines.toolCall.prepend(collabInject as never);\n const codebaseIndexing = setupWebUICodebaseIndexing({\n config,\n context,\n projectRoot,\n logger,\n });\n // Compactor — honors config.context.strategy ('hybrid' default, lossless\n // rules; 'intelligent'/'selective' resolve their provider from ctx at\n // compact()-time). eliseThreshold is a TOKEN COUNT (not a fraction).\n const compactor = createStrategyCompactor({\n strategy: config.context?.strategy,\n preserveK: config.context?.preserveK ?? 10,\n eliseThreshold: config.context?.eliseThreshold ?? 2000,\n summarizerModel: config.context?.summarizerModel,\n llmSelector: config.context?.llmSelector,\n });\n\n // Auto-compaction\n let autoCompactor: AutoCompactionMiddleware | undefined;\n if (config.context?.autoCompact !== false) {\n // Priority: explicit override → models.dev per-model window → family default.\n // The catalog lookup matters for openai-compatible providers (OpenRouter,\n // Groq, …) whose family default is 0; without it auto-compaction would be\n // disabled even though the model has a real published window. Mirrors\n // updateAutoCompactionMaxContext below.\n let effectiveMaxContext = config.context?.effectiveMaxContext ?? 0;\n if (!effectiveMaxContext) {\n try {\n const m = await modelsRegistry.getModel(provider.id, context.model);\n effectiveMaxContext = m?.capabilities?.maxContext ?? 0;\n } catch {\n // best-effort: fall through to provider capability\n }\n }\n if (!effectiveMaxContext) effectiveMaxContext = provider.capabilities.maxContext;\n autoCompactor = new AutoCompactionMiddleware(\n compactor,\n effectiveMaxContext,\n (ctx) =>\n estimateRequestTokensCalibrated(\n ctx.messages,\n ctx.systemPrompt,\n ctx.tools ?? [],\n `${ctx.provider?.id ?? 'unknown'}/${ctx.model}`,\n ).total,\n {\n warn: initialContextPolicy.thresholds.warn,\n soft: initialContextPolicy.thresholds.soft,\n hard: initialContextPolicy.thresholds.hard,\n },\n {\n events,\n aggressiveOn: initialContextPolicy.aggressiveOn,\n policyProvider: (ctx) => {\n const policy = ctx.meta['contextWindowPolicy'];\n return policy && typeof policy === 'object'\n ? (policy as ReturnType<typeof resolveContextWindowPolicy>)\n : initialContextPolicy;\n },\n },\n );\n pipelines.contextWindow.use({ name: 'AutoCompaction', handler: autoCompactor.handler() });\n }\n\n /** Refresh AutoCompactionMiddleware denominator when the active model changes. */\n async function updateAutoCompactionMaxContext(newProvider: Provider): Promise<void> {\n await modelsRegistry.refresh().catch((err) => {\n logger.warn(\n `models.dev refresh failed for ${newProvider.id}/${context.model}: ${toErrorMessage(err)}; using cached catalog`,\n );\n });\n let newMaxContext = config.context?.effectiveMaxContext ?? newProvider.capabilities.maxContext;\n try {\n const m = await modelsRegistry.getModel(newProvider.id, context.model);\n newMaxContext = m?.capabilities?.maxContext ?? newMaxContext;\n } catch {\n // best-effort: use provider capability\n }\n newProvider.capabilities.maxContext = newMaxContext;\n modelCapabilitiesRef.current =\n newMaxContext > 0\n ? {\n maxContextTokens: newMaxContext,\n supportsTools: !!newProvider.capabilities.tools,\n supportsVision: !!newProvider.capabilities.vision,\n supportsReasoning: !!newProvider.capabilities.reasoning,\n }\n : undefined;\n if (newMaxContext > 0) {\n context.meta['effectiveMaxContext'] = newMaxContext;\n autoCompactor?.setMaxContext(newMaxContext);\n autoCompactor?.setEnabled(config.context?.autoCompact !== false);\n } else {\n delete context.meta['effectiveMaxContext'];\n autoCompactor?.setEnabled(false);\n }\n events.emit('ctx.max_context', {\n providerId: newProvider.id,\n modelId: context.model,\n maxContext: newMaxContext,\n });\n }\n\n // Agent\n const secretScrubber = container.resolve(TOKENS.SecretScrubber);\n const renderer = container.has(TOKENS.Renderer) ? container.resolve(TOKENS.Renderer) : undefined;\n const permissionPolicy = container.resolve(TOKENS.PermissionPolicy);\n const toolExecutor = new ToolExecutor(toolRegistry, {\n permissionPolicy,\n secretScrubber,\n renderer,\n events,\n confirmAwaiter: undefined,\n iterationTimeoutMs: config.tools?.iterationTimeoutMs ?? DEFAULT_TOOLS_CONFIG.iterationTimeoutMs,\n perIterationOutputCapBytes:\n config.tools?.perIterationOutputCapBytes ?? DEFAULT_TOOLS_CONFIG.perIterationOutputCapBytes,\n tracer: undefined,\n });\n\n const agent = new Agent({\n container,\n tools: toolRegistry,\n providers: providerRegistry,\n events,\n pipelines,\n context,\n maxIterations: config.tools?.maxIterations ?? DEFAULT_TOOLS_CONFIG.maxIterations,\n iterationTimeoutMs: config.tools?.iterationTimeoutMs ?? DEFAULT_TOOLS_CONFIG.iterationTimeoutMs,\n executionStrategy:\n config.tools?.defaultExecutionStrategy ?? DEFAULT_TOOLS_CONFIG.defaultExecutionStrategy,\n perIterationOutputCapBytes:\n config.tools?.perIterationOutputCapBytes ?? DEFAULT_TOOLS_CONFIG.perIterationOutputCapBytes,\n confirmAwaiter: undefined,\n toolExecutor,\n });\n console.log('[WebUI] Agent initialized');\n\n // ── Brain — policy → LLM tiered decision layer ─────────────────────────\n // Same positioning as the CLI: one Brain per process at\n // TOKENS.BrainArbiter. The WebUI has no human-escalation prompt yet, so\n // the chain stops at the LLM tier — `ask_human` decisions surface to the\n // browser as `brain.event` WS messages and the caller's fallback applies.\n const brainSettings: { maxAutoRisk: BrainAutoRisk } = { maxAutoRisk: 'medium' };\n // Lazy wrapper so the LLM tier always sees the LIVE provider/model —\n // both are swapped at runtime via the settings panel.\n const autonomousBrain: BrainArbiter = {\n decide: (request) =>\n createAutonomyBrain({\n provider,\n model: context.model,\n maxAutoRisk: 'all', // the tiered ceiling gates risk — keep inner permissive\n }).decide(request),\n };\n const brain = new ObservableBrainArbiter(\n createTieredBrainArbiter({\n policy: new DefaultBrainArbiter(),\n autonomous: autonomousBrain,\n getMaxAutoRisk: () => brainSettings.maxAutoRisk,\n }),\n events,\n );\n container.bind(TOKENS.BrainArbiter, () => brain);\n\n // Self-activation: watch for tool-failure streaks / error storms and\n // steer this session's leader via the shared project mailbox. `session`\n // is mutable (swapped on /new and resume) — read it at send time so the\n // steer always targets the LIVE session's leader identity.\n const brainMailbox = new GlobalMailbox(wpaths.projectDir, events);\n const brainMonitor = new BrainMonitor({\n events,\n brain,\n intervene: async ({ subject, body }) => {\n const tag = mailboxSessionTag(session.id);\n await brainMailbox.send({\n from: `brain@${tag}`,\n to: `leader@${tag}`,\n type: 'steer',\n subject,\n body,\n priority: 'high',\n });\n },\n });\n brainMonitor.start();\n console.log('[WebUI] Brain initialized (tiered policy → LLM, monitor active)');\n\n // Decision log for the /brain command — last 20 decisions, newest last.\n const brainLog: Array<{ at: number; kind: string; question: string; outcome: string }> = [];\n const pushBrainLog = (entry: (typeof brainLog)[number]) => {\n brainLog.push(entry);\n if (brainLog.length > 20) brainLog.shift();\n };\n events.on('brain.decision_answered', (e) =>\n pushBrainLog({\n at: e.at,\n kind: 'answered',\n question: e.request.question,\n outcome: e.decision.type === 'answer' ? (e.decision.optionId ?? e.decision.text) : '',\n }),\n );\n events.on('brain.decision_ask_human', (e) =>\n pushBrainLog({ at: e.at, kind: 'ask_human', question: e.request.question, outcome: 'needs human judgement' }),\n );\n events.on('brain.decision_denied', (e) =>\n pushBrainLog({\n at: e.at,\n kind: 'denied',\n question: e.request.question,\n outcome: e.decision.type === 'deny' ? e.decision.reason : '',\n }),\n );\n events.on('brain.intervention', (e) =>\n pushBrainLog({\n at: e.at,\n kind: 'intervention',\n question: e.request.question,\n outcome: e.intervened ? 'steered the agent' : 'observed (no action)',\n }),\n );\n\n // AutoPhase handler — manages AutoPhaseRunner lifecycle via WS messages.\n // Stored under the per-project autophase dir (not the shared SDD task-graphs).\n const autoPhaseHandler = new AutoPhaseWebSocketHandler(\n agent,\n context,\n logger,\n wpaths.projectAutophase,\n events,\n projectRoot,\n );\n\n // Specs handler — FORGE-style browser of persisted SDD specs + their task\n // graphs (dependency board). Reads the shared per-project SDD stores.\n const specsHandler = new SpecsWebSocketHandler(wpaths.projectSpecs, wpaths.projectTaskGraphs);\n\n // SDD live board handler — observes a CLI-owned multi-agent run. Standalone\n // server is a different process from the run, so it polls the on-disk\n // snapshot (no shared EventBus) and steers via the control file.\n const sddBoardHandler = new SddBoardWebSocketHandler(wpaths.projectSddBoards);\n\n // SDD wizard — the interactive \"New SDD Project\" flow (goal → Q&A → spec →\n // task graph → start run). The standalone server runs the real fleet in-process\n // via the runtime light subagent factory (no @wrongstack/cli MultiAgentHost —\n // layer rule). The interview turns + run subagents share one factory.\n const sddWizardHandler = new SddWizardWebSocketHandler(\n buildSddWizardDeps({\n agent,\n events,\n projectRoot,\n brain,\n subagentFactory: makeLightSubagentFactory({\n container,\n providerRegistry,\n toolRegistry,\n session,\n projectRoot,\n }),\n paths: {\n projectSpecs: wpaths.projectSpecs,\n projectTaskGraphs: wpaths.projectTaskGraphs,\n projectSddBoards: wpaths.projectSddBoards,\n projectDir: wpaths.projectDir,\n },\n }),\n );\n\n // Worktree handler — subscribes to the shared EventBus `worktree.*` events\n // and streams live swim-lane / DAG state to connected clients.\n const worktreeHandler = new WorktreeWebSocketHandler(events, logger);\n\n // Integrated terminal handler — per-client node-pty sessions backing the\n // WebUI terminal panel. New terminals open in the live working directory.\n const terminalHandler = new TerminalWebSocketHandler(() => workingDir, logger);\n\n // Collaboration handler — Phase 1 of idea #13. Lets a second client\n // (e.g. a senior dev) join an active agent run as a read-only\n // observer and watch a live mirror of kernel events. Annotated and\n // controller roles land in Phase 2/3. The session reader enables\n // replay-on-join for late observers.\n const collabHandler = new CollaborationWebSocketHandler(\n events,\n logger,\n sessionReader,\n annotationsStore,\n collabBus,\n );\n\n // Helper: build the rich session.start payload from current runtime state.\n // Centralised so initial connect, post-/new, and post-model.switch all\n // broadcast the same shape — frontend treats this as the single source of\n // truth for everything in the status bar (model, context window, project).\n async function sessionStartPayload(): Promise<{\n sessionId: string;\n model: string;\n provider: string;\n maxContext: number;\n /** USD per 1M input tokens (0 if unknown / free). */\n inputCost: number;\n /** USD per 1M output tokens. */\n outputCost: number;\n /** USD per 1M cache-read tokens. */\n cacheReadCost: number;\n projectName: string;\n projectRoot: string;\n cwd: string;\n mode: string;\n contextMode: string;\n }> {\n let maxContext = 0;\n let inputCost = 0;\n let outputCost = 0;\n let cacheReadCost = 0;\n try {\n const m = await modelsRegistry.getModel(config.provider, config.model);\n maxContext = m?.capabilities?.maxContext ?? 0;\n // Fall back to the provider's raw model data from the registry when the\n // resolved model has no maxContext (e.g. a user-defined or API-proxied\n // model that wasn't in the models.dev catalog). DefaultModelsRegistry\n // exposes getProvider() which gives us the model's limit.context directly.\n if (!maxContext) {\n try {\n const provider = await (\n modelsRegistry as { getProvider(id: string): Promise<{ models: Array<{ id: string; limit?: { context?: number } }> } | undefined> }\n ).getProvider(config.provider);\n const rawModel = provider?.models.find((mod) => mod.id === config.model);\n maxContext = rawModel?.limit?.context ?? 0;\n } catch {\n /* best-effort — leave maxContext at whatever the registry set it */\n }\n }\n // models.dev pricing is dollars per 1M tokens; some providers omit the\n // field for free/unmetered plans (e.g. minimax-coding-plan) — in that\n // case we report 0 and the cost chip just stays at $0.\n const rates = getCostRates(m);\n inputCost = rates.input;\n outputCost = rates.output;\n cacheReadCost = rates.cacheRead;\n } catch {\n // best-effort\n }\n return {\n sessionId: session.id,\n model: config.model,\n provider: config.provider,\n maxContext,\n inputCost,\n outputCost,\n cacheReadCost,\n projectName: path.basename(projectRoot) || projectRoot,\n projectRoot,\n cwd: workingDir,\n mode: modeId,\n contextMode: String(context.meta['contextWindowMode'] ?? DEFAULT_CONTEXT_WINDOW_MODE_ID),\n };\n }\n\n // WebSocket server(s).\n //\n // When the user keeps the default loopback bind (127.0.0.1), we ALSO open a\n // second listener on ::1 (IPv6 loopback). Reason: Chrome/Edge on Windows\n // resolve `localhost` to `[::1]` before `127.0.0.1`, so a single v4-only\n // bind causes \"ws disconnect hep\" — clients hammer the v6 socket, get\n // ECONNREFUSED, fall back to v4 inconsistently. Listening on both v4 and v6\n // loopback keeps the connection scope \"this machine only\" while removing\n // the resolution-order coin flip.\n //\n // When the user explicitly sets WS_HOST (e.g. 0.0.0.0 or a LAN IP), we\n // respect that choice exactly and don't add a second listener.\n // Generate a random WS auth token so only callers that know the token\n // can connect. Printed to console on startup; the frontend reads it from\n // the URL query param `?token=...`. Without a token, any client on the\n // network can connect and send `user_message`/`key.add`/`model.switch`.\n const wsToken = resolveAuthToken(opts.accessToken);\n // Token is delivered through the printed first-load URL and then exchanged\n // for an HttpOnly cookie by /ws-auth.\n console.log('[WebUI] WS auth token ready');\n const publicHostnames = [publicUrl, publicWsUrl]\n .map((value) => {\n if (!value) return undefined;\n try {\n return new URL(value).hostname;\n } catch {\n return undefined;\n }\n })\n .filter((value): value is string => Boolean(value));\n\n // CSWSH guard + token auth: when the user exposes the socket beyond loopback,\n // require the shared token; loopback connections bootstrap without one. The\n // policy (DNS-rebinding Host guard, constant-time token compare, loopback\n // bootstrap) lives in ./ws-auth.ts as pure functions — this closure just\n // pulls the relevant fields off the incoming request and delegates.\n const verifyClient = (info: {\n origin: string;\n secure: boolean;\n req: import('node:http').IncomingMessage;\n }) =>\n verifyWsClient({\n origin: info.origin,\n url: info.req.url ?? '',\n hostHeader: info.req.headers.host,\n remoteAddress: info.req.socket.remoteAddress,\n // C-2 fix: accept the token via the HttpOnly cookie set by\n // `/ws-auth` (preferred) OR the URL query param (non-browser\n // fallback). The cookie path closes the C-598 query-string\n // exposure class.\n cookieHeader: info.req.headers.cookie,\n wsHost,\n expectedToken: wsToken,\n requireToken,\n allowedHostnames: publicHostnames,\n allowBrowserUrlToken: Boolean(publicWsUrl),\n });\n // Cap inbound frame size (8 MiB) so a single oversized message can't exhaust\n // memory. Agent messages are small; large pastes/attachments stay well under.\n const WS_MAX_PAYLOAD = 8 * 1024 * 1024;\n const wssPrimary = new WebSocketServer({\n port: wsPort,\n host: wsHost,\n verifyClient,\n maxPayload: WS_MAX_PAYLOAD,\n } as ConstructorParameters<typeof WebSocketServer>[0]);\n const wssSecondary =\n wsHost === '127.0.0.1'\n ? new WebSocketServer({\n port: wsPort,\n host: '::1',\n verifyClient,\n maxPayload: WS_MAX_PAYLOAD,\n } as ConstructorParameters<typeof WebSocketServer>[0])\n : null;\n const clients = new Map<WebSocket, ConnectedClient>();\n\n // ── Subscribe to working directory changes from the CLI ──────────────\n // When ctx.setWorkingDir() is called from the CLI (e.g. /wd, /cd, or\n // the set_working_dir tool), update the server's workingDir reference\n // and broadcast to all connected WebUI clients so the file explorer\n // and the WorkingDirChip UI stay in sync.\n context.onWorkingDirChanged((newDir) => {\n workingDir = newDir;\n broadcast(clients, {\n type: 'working_dir.changed',\n payload: { cwd: newDir, projectRoot },\n });\n });\n\n // ── Eternal-autonomy iteration broadcast (PR 4 of Phase 2) ─────────\n // When the CLI passes `opts.subscribeEternalIteration`, hook the\n // returned observer into a WS broadcast so every connected client\n // gets a live stream of `JournalEntry` items as the engine ticks.\n // The disposer is captured and invoked on shutdown() so the CLI's\n // engine subscription is properly torn down with the webui.\n let eternalSubscription: { dispose: () => void } | null = null;\n if (opts.subscribeEternalIteration) {\n eternalSubscription = createEternalSubscription(\n opts.subscribeEternalIteration,\n broadcast,\n () => clients,\n );\n }\n\n // Per-connection message rate limiting: 60 messages per 60-second window.\n // Exceeding clients are temporarily blocked to prevent flooding.\n // Uses sessionId as the key once connected, falling back to ws for\n // pre-auth messages — prevents connection-reuse bypass.\n // Rate limit OFF by default (counted pings/list calls too and tripped during\n // normal use). Opt in via WEBUI_RATE_LIMIT=<messages-per-60s> for LAN exposure.\n const RATE_LIMIT_MESSAGES = Number.parseInt(process.env['WEBUI_RATE_LIMIT'] ?? '0', 10);\n const RATE_LIMIT_WINDOW_MS = 60_000;\n const rateLimits = new Map<string, { count: number; resetAt: number }>();\n // Per-connection id sequence. The rate-limit bucket must be keyed per\n // connection, not per sessionId (every client is created with the same\n // live `session.id`, so a sessionId key would share one bucket across all\n // tabs) and not by `String(ws)` (which is `\"[object Object]\"` for every\n // socket — identical for all connections and never matching on cleanup).\n let connSeq = 0;\n\n function checkRateLimit(_ws: WebSocket, client: ConnectedClient): boolean {\n if (RATE_LIMIT_MESSAGES <= 0) return true; // disabled\n const now = Date.now();\n const key = client.connId;\n const limit = rateLimits.get(key);\n if (!limit || now > limit.resetAt) {\n rateLimits.set(key, { count: 1, resetAt: now + RATE_LIMIT_WINDOW_MS });\n return true;\n }\n if (limit.count >= RATE_LIMIT_MESSAGES) return false;\n limit.count++;\n return true;\n }\n\n /** Holds the AbortController for the currently in-flight agent.run().\n * Non-null while the agent is running; guarded at the user_message\n * handler to prevent concurrent runs that would corrupt shared state\n * (context, agent, tokenCounter). A second user_message while running\n * is answered with an inline error instead of being queued — the\n * caller should wait for run.result. */\n let runLock: AbortController | null = null;\n\n console.log(\n `[WebUI] WebSocket server running on ws://${wsHost}:${wsPort}` +\n (wssSecondary ? ` (and ws://[::1]:${wsPort})` : ''),\n );\n\n // Pending permission confirmations. When the agent emits\n // tool.confirm_needed, we store the resolve function here keyed by\n // toolUseId. When the client sends tool.confirm_result back, we look\n // it up and resolve — unblocking the agent loop.\n const pendingConfirms = new Map<string, (d: 'yes' | 'no' | 'always' | 'deny') => void>();\n\n const handleConnection = (ws: WebSocket): void => {\n const client: ConnectedClient = {\n ws,\n sessionId: session.id,\n connectedAt: Date.now(),\n connId: `c${++connSeq}`,\n };\n clients.set(ws, client);\n\n // sessionStartPayload handles errors internally; no explicit catch needed.\n // Adding a catch would be defensive but sessionStartPayload already has try-catch.\n void sessionStartPayload()\n .then((payload) => {\n send(ws, { type: 'session.start', payload });\n })\n .catch((err) => {\n // Log at warn level since sessionStartPayload should rarely fail.\n // This prevents silent failures if internal error handling changes.\n console.warn(JSON.stringify({\n level: 'warn',\n event: 'webui.session_start_payload_failed',\n message: toErrorMessage(err),\n timestamp: new Date().toISOString(),\n }));\n });\n\n // Register this client with the AutoPhase handler so it receives phase events\n autoPhaseHandler.addClient(ws);\n // …and the specs handler for the FORGE dependency board.\n specsHandler.addClient(ws);\n // …and the live SDD multi-agent board handler.\n sddBoardHandler.addClient(ws);\n sddWizardHandler.addClient(ws);\n // …and the worktree handler for live isolation lanes.\n worktreeHandler.addClient(ws);\n // …and the collaboration handler for read-only session observation.\n collabHandler.addClient(ws);\n // …and the terminal handler for the integrated terminal panel.\n terminalHandler.addClient(ws);\n\n ws.on('message', async (data) => {\n if (!checkRateLimit(ws, client)) {\n send(ws, {\n type: 'error',\n payload: {\n phase: 'rate_limit',\n message: 'Too many messages. Please wait before sending more.',\n },\n });\n return;\n }\n try {\n // Prototype pollution guard: reject messages whose root-level payload\n // contains __proto__, constructor, or prototype keys. These could\n // cause prototype pollution via Object.assign({}, payload) or\n // spread {...payload}. The top-level check below catches the\n // dangerous keys; nested payload sub-objects are low-risk since\n // handlers don't do deep property merges.\n const rawObj = JSON.parse(data.toString());\n if (typeof rawObj === 'object' && rawObj !== null) {\n const obj = rawObj as Record<string, unknown>;\n // Own-property check only: the `in` operator walks the prototype\n // chain, so `'constructor' in obj` / `'__proto__' in obj` are true\n // for EVERY plain object and would reject all legitimate messages.\n // A malicious JSON payload surfaces these as OWN keys (V8 materializes\n // a literal \"__proto__\" data property from JSON), which Object.hasOwn\n // detects without the false positives.\n if (\n Object.hasOwn(obj, '__proto__') ||\n Object.hasOwn(obj, 'constructor') ||\n Object.hasOwn(obj, 'prototype')\n ) {\n send(ws, {\n type: 'error',\n payload: { phase: 'parse', message: 'Invalid message object' },\n });\n } else {\n await handleMessage(ws, client, rawObj as never as WSClientMessage);\n }\n } else {\n // Non-object JSON (array, string, number…) — pass through\n await handleMessage(ws, client, rawObj as WSClientMessage);\n }\n } catch (err) {\n console.error(JSON.stringify({\n level: 'error',\n event: 'webui.ws_message_parse_failed',\n message: toErrorMessage(err),\n timestamp: new Date().toISOString(),\n }));\n }\n });\n\n ws.on('close', () => {\n const closing = clients.get(ws);\n clients.delete(ws);\n if (closing) rateLimits.delete(closing.connId);\n // If the client disconnects while a permission prompt is pending,\n // resolve all pending confirms with 'no' so the agent loop doesn't\n // hang forever waiting for a response that will never come.\n if (pendingConfirms.size > 0) {\n for (const [id, resolve] of pendingConfirms) {\n resolve('no');\n pendingConfirms.delete(id);\n }\n }\n });\n\n ws.on('error', (err) => {\n // Without this handler an errored socket would crash the process.\n console.warn(JSON.stringify({\n level: 'warn',\n event: 'webui.client_socket_error',\n message: err.message,\n timestamp: new Date().toISOString(),\n }));\n });\n };\n\n // Audit-level-aware session log bridge — persists tool/error/provider\n // events to the session JSONL with the same contract as the CLI. The\n // getter form resolves the CURRENT writer on every append so events\n // follow session.new / session.resume / projects.select swaps.\n const sessionLogging = resolveSessionLoggingConfig(\n config as never as Parameters<typeof resolveSessionLoggingConfig>[0],\n );\n const sessionBridge = createSessionEventBridge(\n () => context.session ?? session,\n sessionLogging.auditLevel,\n { sampling: sessionLogging.sampling },\n );\n\n let eventsArmed = false;\n let disposeEvents: (() => void) | null = null;\n // Captured from setupEvents so `POST /api/fleet/ping` can trigger an\n // immediate fleet re-broadcast (push-on-write from a TUI/REPL).\n let fleetBroadcast: (() => Promise<void>) | null = null;\n const armOnce = (label: string): void => {\n if (eventsArmed) return;\n eventsArmed = true;\n console.log(`[WebUI] Backend ready (${label})`);\n disposeEvents = setupEvents({\n events, broadcast, clients, config, context, pendingConfirms, globalConfigPath, sessionBridge, wpaths, watcherMetrics,\n onFleetBroadcaster: (fn) => { fleetBroadcast = fn; },\n });\n };\n\n wssPrimary.on('listening', () => armOnce(`${wsHost}:${wsPort}`));\n wssPrimary.on('connection', handleConnection);\n wssPrimary.on('error', (err) => {\n console.error(JSON.stringify({\n level: 'error',\n event: 'webui.ws_server_error',\n host: wsHost,\n message: toErrorMessage(err),\n timestamp: new Date().toISOString(),\n }));\n });\n\n if (wssSecondary) {\n wssSecondary.on('listening', () => armOnce(`::1:${wsPort}`));\n wssSecondary.on('connection', handleConnection);\n wssSecondary.on('error', (err: NodeJS.ErrnoException) => {\n // Best-effort secondary: if IPv6 loopback isn't available on this host\n // (e.g. disabled in OS), just log and continue. Primary v4 is enough.\n if (err.code === 'EAFNOSUPPORT' || err.code === 'EADDRNOTAVAIL') {\n console.warn(JSON.stringify({\n level: 'warn',\n event: 'webui.ipv6_unavailable',\n code: err.code,\n message: err.message,\n timestamp: new Date().toISOString(),\n }));\n } else {\n console.error(JSON.stringify({\n level: 'error',\n event: 'webui.ws_server_error',\n host: '::1',\n message: err.message,\n timestamp: new Date().toISOString(),\n }));\n }\n });\n }\n\n // ── Project manifest helpers ──────────────────────────────────────────\n\n /**\n * Idempotent manifest registration (mirrors the CLI's\n * touchProjectInManifest): create the projects.json entry when missing,\n * refresh lastSeen/lastWorkingDir when present.\n */\n async function touchProjectEntry(root: string, workDir?: string): Promise<void> {\n const resolved = path.resolve(root);\n const manifest = await loadManifest(globalConfigPath);\n const now = new Date().toISOString();\n const existing = manifest.projects.find((p) => path.resolve(p.root) === resolved);\n if (existing) {\n existing.lastSeen = now;\n if (workDir) existing.lastWorkingDir = path.resolve(workDir);\n } else {\n manifest.projects.push({\n name: path.basename(resolved),\n root: resolved,\n slug: generateProjectSlug(resolved),\n createdAt: now,\n lastSeen: now,\n lastWorkingDir: workDir ? path.resolve(workDir) : undefined,\n });\n }\n await saveManifest(manifest, globalConfigPath);\n await ensureProjectDataDir(generateProjectSlug(resolved), globalConfigPath);\n }\n\n function makeWorklistContext(): WorklistContext {\n return {\n context: {\n todos: context.todos,\n meta: context.meta as Record<string, unknown>,\n session: context.session ? { id: context.session.id } : null,\n state: context.state,\n },\n send: (w, m) => send(w, m),\n broadcast: (m) => broadcast(clients, m),\n };\n }\n\n let providerRoutes: ProviderRouteHandlers;\n let sessionRoutes: SessionRouteHandlers;\n let projectRoutes: ProjectRouteHandlers;\n let modeRoutes: ModeRouteHandlers;\n let prefsRoutes: PrefsRouteHandlers;\n let shellGitRoutes: ShellGitRouteHandlers;\n let mailboxRoutes: MailboxRouteHandlers;\n let mcpRoutes: McpRouteHandlers;\n let brainRoutes: BrainRouteHandlers;\n let autoPhaseRoutes: AutoPhaseRouteHandlers;\n let specsRoutes: SpecsRouteHandlers;\n let sddBoardRoutes: SddBoardRouteHandlers;\n let sddWizardRoutes: SddWizardRouteHandlers;\n\n async function handleMessage(\n ws: WebSocket,\n _client: ConnectedClient,\n msg: WSClientMessage,\n ): Promise<void> {\n if (await handleProviderRoute(ws, msg, providerRoutes)) return;\n if (await handleSessionRoute(ws, msg, sessionRoutes)) return;\n if (await handleProjectRoute(ws, msg, projectRoutes)) return;\n if (await handleModeRoute(ws, msg, modeRoutes)) return;\n if (await handlePrefsRoute(ws, msg, prefsRoutes)) return;\n if (await handleShellGitRoute(ws, msg, shellGitRoutes)) return;\n if (await handleMailboxRoute(ws, msg, mailboxRoutes)) return;\n if (await handleMcpRoute(ws, msg, mcpRoutes)) return;\n if (await handleBrainRoute(ws, msg, brainRoutes)) return;\n if (await handleAutoPhaseRoute(ws, msg, autoPhaseRoutes)) return;\n if (await handleSpecsRoute(ws, msg, specsRoutes)) return;\n if (await handleSddBoardRoute(ws, msg, sddBoardRoutes)) return;\n if (await handleSddWizardRoute(ws, msg, sddWizardRoutes)) return;\n\n switch (msg.type) {\n // Collaboration messages short-circuit the user/agent flow.\n // They don't touch runLock, the agent loop, or the message queue —\n // they're pure transport for the live observer mirror.\n case 'collab.join':\n case 'collab.leave':\n case 'collab.annotate':\n case 'collab.resolve':\n case 'collab.request_pause':\n case 'collab.resume':\n case 'collab.grant_control':\n case 'collab.inject_tool': {\n collabHandler.handleMessage(ws, msg as { type: string; payload?: unknown | undefined });\n return;\n }\n // Integrated terminal — interactive pty transport, bypasses the agent loop.\n case 'terminal.create':\n case 'terminal.input':\n case 'terminal.resize':\n case 'terminal.close': {\n terminalHandler.handleMessage(ws, msg);\n return;\n }\n case 'user_message': {\n const content = (msg as { payload: { content: string } }).payload.content;\n\n // Guard against concurrent agent runs — a second user_message while\n // the agent is already processing would kick off two agent.run()\n // calls on the same shared context/agent, leading to corrupted\n // state (duplicate tool bubbles, mixed text_delta streams, token\n // counter undercount). Reject with an inline error; the frontend\n // should wait for run.result before sending the next message.\n if (runLock) {\n send(ws, {\n type: 'error',\n payload: {\n phase: 'user_message',\n message: 'Agent is already processing a request. Wait for the current run to finish.',\n },\n });\n break;\n }\n\n runLock = new AbortController();\n // Capture so the finally block only clears its own lock — a\n // second race could set a new runLock between await and finally.\n const thisRun = runLock;\n\n try {\n // Read maxIterations from context.meta so the webui settings\n // panel can adjust the cap dynamically without restarting.\n const maxIt = typeof context.meta['maxIterations'] === 'number'\n ? context.meta['maxIterations']\n : undefined;\n const result = await agent.run(content, { signal: thisRun.signal, maxIterations: maxIt });\n send(ws, {\n type: 'run.result',\n payload: {\n status: result.status,\n iterations: result.iterations,\n finalText: result.finalText,\n error: result.error\n ? {\n code: result.error.code,\n message: result.error.message,\n recoverable: result.error.recoverable,\n }\n : undefined,\n },\n });\n } catch (err) {\n send(ws, {\n type: 'error',\n payload: {\n phase: 'agent.run',\n message: errMessage(err),\n },\n });\n } finally {\n // Only clear runLock if it's still ours — otherwise we'd wipe a\n // newer run's controller set after we returned.\n if (runLock === thisRun) {\n runLock = null;\n }\n }\n break;\n }\n\n case 'tool.confirm_result': {\n const { id, decision } = (\n msg as { payload: { id: string; decision: 'yes' | 'no' | 'always' | 'deny' } }\n ).payload;\n const resolve = pendingConfirms.get(id);\n if (resolve) {\n pendingConfirms.delete(id);\n resolve(decision);\n }\n break;\n }\n\n case 'abort':\n runLock?.abort();\n broadcast(clients, { type: 'error', payload: { phase: 'abort', message: 'User aborted' } });\n break;\n\n case 'ping':\n send(ws, { type: 'pong', payload: {} });\n break;\n\n case 'tools.list': {\n // Full tool registry dump for the /tools inspect view. We surface\n // name, description, and schema-derived param names so the user\n // can tell at a glance which tools the model can call right now.\n const list = toolRegistry.list().map((t) => {\n const schema =\n (t as { inputSchema?: { properties?: Record<string, unknown> } }).inputSchema ?? {};\n const params = schema.properties ? Object.keys(schema.properties) : [];\n return {\n name: t.name,\n description: (t as { description?: string | undefined }).description ?? '',\n params,\n };\n });\n send(ws, { type: 'tools.list', payload: { tools: list } });\n break;\n }\n\n // ── Memory operations — delegated to shared handlers (memory-handlers.ts) ──\n case 'memory.list':\n return handleMemoryList(ws, memoryStore);\n case 'memory.remember':\n return handleMemoryRemember(ws, msg, memoryStore);\n case 'memory.forget':\n return handleMemoryForget(ws, msg, memoryStore);\n\n // ── MCP operations — delegated to shared handlers (mcp-handlers.ts),\n // backed by the live MCPRegistry constructed above. Routed via\n // handleMcpRoute (see mcpRoutes = { ... } below). These case arms\n // are unreachable but left as tripwires for any future regression\n // where the route chain stops claiming 'mcp.*'. If you see one\n // fire, fix the dispatch order in the handleMessage chain above.\n case 'mcp.list':\n throw new Error('handleMcpRoute did not claim mcp.list — check chain order');\n case 'mcp.add':\n throw new Error('handleMcpRoute did not claim mcp.add — check chain order');\n case 'mcp.update':\n throw new Error('handleMcpRoute did not claim mcp.update — check chain order');\n case 'mcp.remove':\n throw new Error('handleMcpRoute did not claim mcp.remove — check chain order');\n case 'mcp.enable':\n throw new Error('handleMcpRoute did not claim mcp.enable — check chain order');\n case 'mcp.disable':\n throw new Error('handleMcpRoute did not claim mcp.disable — check chain order');\n case 'mcp.sleep':\n throw new Error('handleMcpRoute did not claim mcp.sleep — check chain order');\n case 'mcp.wake':\n throw new Error('handleMcpRoute did not claim mcp.wake — check chain order');\n case 'mcp.restart':\n throw new Error('handleMcpRoute did not claim mcp.restart — check chain order');\n case 'mcp.discover':\n throw new Error('handleMcpRoute did not claim mcp.discover — check chain order');\n\n // Skills — full request→response cycle lives in skills-handlers.ts\n // (shared with the CLI's embedded server). skillsCtx is the closed-over\n // loader/installer/projectRoot the handlers need.\n case 'skills.list':\n await handleSkillsList(ws, { skillLoader, skillInstaller, projectRoot });\n break;\n case 'skills.content':\n await handleSkillsContent(ws, { skillLoader, skillInstaller, projectRoot }, msg);\n break;\n case 'skills.install':\n await handleSkillsInstall(ws, { skillLoader, skillInstaller, projectRoot }, msg);\n break;\n case 'skills.uninstall':\n await handleSkillsUninstall(ws, { skillLoader, skillInstaller, projectRoot }, msg);\n break;\n case 'skills.update':\n await handleSkillsUpdate(ws, { skillLoader, skillInstaller, projectRoot }, msg);\n break;\n case 'skills.create':\n await handleSkillsCreate(ws, { skillLoader, skillInstaller, projectRoot }, msg);\n break;\n case 'skills.edit':\n await handleSkillsEdit(ws, { skillLoader, skillInstaller, projectRoot }, msg);\n break;\n case 'skills.export':\n await handleSkillsExport(ws, { skillLoader, skillInstaller, projectRoot });\n break;\n\n case 'diag.get': {\n // Snapshot of the moving parts so the user can debug \"why is X\n // not working?\" without diving into the server logs.\n const usage = tokenCounter.total();\n send(ws, {\n type: 'diag.get',\n payload: {\n provider: config.provider,\n model: config.model,\n cwd: projectRoot,\n sessionId: session.id,\n tools: {\n count: toolRegistry.list().length,\n names: toolRegistry.list().map((t) => t.name),\n },\n features: {\n memory: !!config.features?.memory,\n skills: !!config.features?.skills,\n modelsRegistry: !!config.features?.modelsRegistry,\n },\n mode: modeId ?? 'default',\n usage,\n messages: context.messages.length,\n todos: context.todos.length,\n },\n });\n break;\n }\n\n // ── Worklist (todos / tasks / plan) — delegated to the shared dispatcher ──\n // The nine worklist message types share one context factory; the dispatcher\n // in handlers/worklist-handlers.ts narrows each payload and routes it.\n case 'todos.get':\n case 'todos.clear':\n case 'todos.remove':\n case 'tasks.get':\n case 'plan.get':\n case 'plan.template_use':\n case 'todo.update':\n case 'task.update':\n case 'plan.item.update': {\n await handleWorklistMessage(makeWorklistContext(), ws, msg as WorklistMessage);\n break;\n }\n\n // ── File operations — delegated to shared handlers (file-handlers.ts) ──\n // These handlers are also used by the CLI's webui-server.ts. When\n // adding or modifying file-operation WebSocket messages, update\n // file-handlers.ts — NOT these case blocks individually.\n case 'files.list':\n return handleFilesList(ws, msg, projectRoot);\n case 'files.tree':\n return handleFilesTree(ws, msg, projectRoot);\n case 'files.read':\n return handleFilesRead(ws, msg, projectRoot);\n case 'files.write':\n return handleFilesWrite(ws, msg, projectRoot, {\n onWritten: (filePath) => codebaseIndexing.onFileWritten(filePath),\n });\n case 'completion.request':\n return handleCompletionRequest(ws, msg, {\n projectRoot,\n provider: context.provider,\n model: context.model,\n indexDir: typeof context.meta['codebaseIndexDir'] === 'string'\n ? context.meta['codebaseIndexDir']\n : undefined,\n lspCompletion: createToolLspCompletionSource(toolRegistry.get('lsp_completion'), context),\n });\n\n case 'stats.get': {\n // Mirror of the CLI's /stats: detailed session report.\n const usage = tokenCounter.total();\n const cacheStats = tokenCounter.cacheStats();\n const m = await modelsRegistry.getModel(config.provider, config.model).catch(() => null);\n const cost = computeUsageCost(usage, getCostRates(m));\n send(ws, {\n type: 'stats.get',\n payload: {\n sessionId: session.id,\n provider: config.provider,\n model: config.model,\n usage,\n cache: cacheStats,\n cost,\n messages: context.messages.length,\n readFiles: context.readFiles.size,\n tools: toolRegistry.list().length,\n elapsedMs: Date.now() - sessionStartedAt,\n },\n });\n break;\n }\n\n case 'process.list': {\n await handleProcessList(ws);\n break;\n }\n\n case 'process.kill': {\n await handleProcessKill(ws, msg.payload);\n break;\n }\n\n case 'process.killAll': {\n await handleProcessKillAll(ws);\n break;\n }\n\n case 'webui.shutdown': {\n // `/exit` from the client. Trigger the same graceful teardown the\n // CLI-hosted server does — route through SIGINT so the registered\n // shutdown handlers (session flush, disposers, registry unregister)\n // all run. Previously this fell through to the unknown-type error.\n console.log('[WebUI] Shutdown requested from client');\n process.kill(process.pid, 'SIGINT');\n break;\n }\n\n case 'goal.get': {\n await handleGoalGet(projectRoot, (m) => broadcast(clients, m));\n break;\n }\n\n case 'autonomy.switch': {\n // Autonomy mode switch — forwarded to the agent context.\n // The mode is stored in context.meta for the permission policy to read.\n const parsed = validateAutonomySwitchPayload(msg.payload);\n if (!parsed.ok) {\n sendResult(ws, false, parsed.message);\n break;\n }\n const { mode } = parsed.value;\n context.meta['autonomy'] = mode;\n sendResult(ws, true, `Autonomy mode set to \"${mode}\"`);\n // Keep every browser tab + the settings panel in sync, and persist\n // the durable modes (eternal/eternal-parallel are session-level).\n broadcast(clients, { type: 'prefs.updated', payload: { autonomy: mode } });\n void persistPrefsToConfig({ autonomy: mode });\n break;\n }\n\n case 'prefs.update': {\n // Routed via handlePrefsRoute (see prefsRoutes = { ... } below) —\n // the actual handler is `updatePrefs`. This case is unreachable but\n // left as a tripwire for any future regression where the route\n // chain stops claiming 'prefs.*'. If you see this fire, fix the\n // dispatch order in the handleMessage chain above.\n void ws;\n throw new Error('handlePrefsRoute did not claim prefs.update — check chain order');\n }\n\n case 'prefs.get': {\n // Routed via handlePrefsRoute (see prefsRoutes = { ... } below).\n throw new Error('handlePrefsRoute did not claim prefs.get — check chain order');\n }\n\n default:\n send(ws, {\n type: 'error',\n payload: { phase: 'handleMessage', message: `Unknown message type: ${msg.type}` },\n });\n }\n }\n\n // ---- Provider/Key management helpers (extracted to provider-handlers.ts) ----\n const providerHandlers = createProviderHandlers({\n globalConfigPath,\n vault,\n getConfigWriteLock: () => configWriteLock,\n setConfigWriteLock: (p) => {\n configWriteLock = p;\n },\n broadcast,\n clients,\n });\n\n providerRoutes = {\n providerHandlers,\n listProviders: async (ws) => {\n const providers = await modelsRegistry.listProviders();\n // \"Configured\" should mean *any* working credential, not just env vars.\n // Users register keys with `wstack auth`, which writes apiKey/apiKeys\n // into config.providers[<id>] — those are decrypted in memory here.\n const savedIds = new Set(Object.keys(config.providers ?? {}));\n send(ws, {\n type: 'provider.catalog',\n payload: {\n providers: providers.map((p: { id: string; name: string; family: unknown; apiBase?: unknown; envVars: string[]; models: readonly unknown[] }) => ({\n id: p.id,\n name: p.name,\n family: p.family,\n apiBase: p.apiBase,\n envVars: p.envVars,\n modelCount: p.models.length,\n hasApiKey: savedIds.has(p.id) || p.envVars.some((v: string) => !!process.env[v]),\n })),\n },\n });\n },\n listSavedProviders: async (ws) => {\n const saved = await providerHandlers.loadConfigProviders();\n send(ws, {\n type: 'providers.saved',\n payload: { providers: projectSavedProviders(saved) },\n });\n },\n listProviderModels: async (ws, msg) => {\n const providerId = (msg as { payload: { providerId: string } }).payload.providerId;\n // Merge catalog + saved config so OAuth / subscription providers\n // (github-copilot, anthropic-oauth, openai-codex, …) that models.dev\n // doesn't list still resolve to their saved model allowlist. Always\n // reply (possibly empty) — the switcher lazy-loads every saved provider.\n const saved = await providerHandlers.loadConfigProviders();\n const cfg = saved[providerId];\n const catalogId = cfg?.type && cfg.type !== providerId ? cfg.type : providerId;\n const provider = await modelsRegistry.getProvider(catalogId);\n send(ws, {\n type: 'provider.models',\n payload: {\n provider: providerId,\n models: resolveProviderModelList(cfg?.models, provider),\n },\n });\n },\n switchModel: async (ws, msg) => {\n const parsed = validateModelSwitchPayload(msg.payload);\n if (!parsed.ok) {\n sendResult(ws, false, parsed.message);\n return;\n }\n const { provider: newProvider, model: newModel } = parsed.value;\n try {\n // Update config\n config = patchConfig(config, { provider: newProvider, model: newModel });\n configStore.update({ provider: newProvider, model: newModel });\n context.model = newModel;\n\n // Create new provider instance — fail loudly if the user picks a\n // provider with no creds rather than silently keeping the old one.\n const providerCfg = config.providers?.[newProvider] ?? { type: newProvider };\n const newProv = providerRegistry.has(newProvider)\n ? providerRegistry.create({ ...providerCfg, type: newProvider })\n : makeProviderFromConfig(newProvider, providerCfg);\n context.provider = newProv;\n\n // Update AutoCompactionMiddleware with the new model's maxContext so\n // backend threshold triggers (warn/soft/hard) use the correct denominator.\n // sessionStartPayload is called below (after this block) and uses\n // the new provider for its modelsRegistry lookup.\n await updateAutoCompactionMaxContext(newProv);\n\n // Persist to global config file via the unified config mutation helper.\n await updateGlobalConfig((cfg) => {\n cfg.provider = newProvider;\n cfg.model = newModel;\n }, 'model.switch');\n\n // Toast for the SettingsPanel\n send(ws, {\n type: 'key.operation_result',\n payload: { success: true, message: `Switched to ${newProvider} / ${newModel}` },\n });\n } catch (err) {\n send(ws, {\n type: 'key.operation_result',\n payload: {\n success: false,\n message: `Switch failed: ${errMessage(err)}`,\n },\n });\n return;\n }\n\n broadcast(clients, { type: 'session.start', payload: await sessionStartPayload() });\n },\n refineModel: async (ws, msg) => {\n const { text } = (msg as { payload: { text: string } }).payload;\n if (!text?.trim()) {\n send(ws, {\n type: 'model.refine_result',\n payload: { refined: '', english: '', error: 'Empty text' },\n });\n return;\n }\n try {\n const history = recentTextTurns(context.messages);\n // Gate a low-effort reasoning hint to the active model's capabilities\n // (config is patched live on model.switch). Refinement is a shallow\n // rewrite, so this trims wasted thinking on reasoning models; resolves\n // to undefined → no reasoning field, as before.\n const resolved = await modelsRegistry\n .getModel(config.provider, config.model)\n .catch(() => undefined);\n const reasoning = gatedEnhancerReasoning(resolved?.capabilities.reasoningConfig);\n const result = await enhanceUserPrompt({\n provider: context.provider,\n model: context.model,\n text,\n history,\n timeoutMs: 90000,\n ...(reasoning ? { reasoning } : {}),\n onError: (reason: unknown) => {\n console.warn(JSON.stringify({\n level: 'warn',\n event: 'model.refine_failed',\n reason,\n timestamp: new Date().toISOString(),\n }));\n },\n });\n if (result) {\n send(ws, {\n type: 'model.refine_result',\n payload: { refined: result.refined, english: result.english },\n });\n } else {\n send(ws, {\n type: 'model.refine_result',\n payload: { refined: text, english: text, error: 'Refinement returned no result' },\n });\n }\n } catch (err) {\n console.error(JSON.stringify({\n level: 'error',\n event: 'model.refine.error',\n error: errMessage(err),\n timestamp: new Date().toISOString(),\n }));\n send(ws, {\n type: 'model.refine_result',\n payload: { refined: text, english: text, error: errMessage(err) },\n });\n }\n },\n };\n\n\n\n sessionRoutes = createSessionHandlers({\n config,\n clients,\n context,\n toolRegistry,\n compactor,\n customModeStore,\n tokenCounter,\n getProjectRoot: () => projectRoot,\n getSession: () => session,\n getSessionStore: () => sessionStore,\n setSession: (s) => {\n session = s;\n },\n setSessionStartedAt: (t) => {\n sessionStartedAt = t;\n },\n sessionStartPayload,\n });\n\n projectRoutes = createProjectHandlers({\n globalConfigPath,\n wpaths,\n clients,\n context,\n modeStore,\n memoryStore,\n skillLoader,\n modelCapabilities: () => modelCapabilitiesRef.current,\n toolRegistry,\n tokenCounter,\n config,\n getModeId: () => modeId,\n getProjectRoot: () => projectRoot,\n getSession: () => session,\n setProjectRoot: (p) => {\n projectRoot = p;\n },\n setWorkingDir: (p) => {\n workingDir = p;\n },\n setSession: (s) => {\n session = s;\n },\n setSessionStore: (s) => {\n sessionStore = s;\n },\n setSessionStartedAt: (t) => {\n sessionStartedAt = t;\n },\n abortRunLock: () => {\n if (runLock) {\n runLock.abort();\n runLock = null;\n }\n },\n sessionStartPayload,\n });\n\n modeRoutes = createModeHandlers({\n modeStore,\n memoryStore,\n skillLoader,\n modelCapabilities: () => modelCapabilitiesRef.current,\n context,\n toolRegistry,\n config,\n projectRoot,\n clients,\n setModeId: (id) => {\n modeId = id;\n },\n sessionStartPayload,\n });\n\n // ---- Prefs route (handlePrefsRoute) ----\n // The standalone server's pref surface is richer than the CLI's embedded\n // prefs.ts (issue #31 follow-on to #94–#110). We own the full set of\n // runtime effects: YOLO toggle on permissionPolicy, feature-flag mutation\n // on config.features, fallback chain update on config, AutoCompaction\n // pipeline add/remove, logger.level mutation, and config.json persistence.\n // Closure-captured dependencies stay here in index.ts; the dispatch layer\n // (prefs-routes.ts) just calls these two functions.\n prefsRoutes = {\n getPrefs: async (ws) => {\n // Return the current pref snapshot so a freshly-connected client\n // can seed its local-prefs store from the server's truth.\n send(ws, { type: 'prefs.updated', payload: prefSnapshot() });\n },\n updatePrefs: async (ws, msgPayload) => {\n // Batch preference update from the webui. Merges arbitrary key/value\n // pairs into context.meta so the runtime can read them immediately,\n // broadcasts the full pref snapshot to every connected client so all\n // browser tabs stay in sync, and persists the durable keys to\n // config.json (same keys the TUI settings picker writes).\n const parsed = validatePrefsUpdatePayload(msgPayload);\n if (!parsed.ok) {\n sendResult(ws, false, parsed.message);\n return;\n }\n const payload = parsed.value.prefs;\n // Write each pref into context.meta\n for (const [key, val] of Object.entries(payload)) {\n context.meta[key] = val;\n }\n void persistPrefsToConfig(payload);\n // YOLO mode: toggle the permission policy so tool confirmations\n // are auto-approved instead of prompting the user. Uses the live\n // reference resolved from the container at startup.\n if (typeof payload['yolo'] === 'boolean') {\n permissionPolicy.setYolo?.(payload['yolo']);\n }\n // Also update config.features for feature flags that affect tool/skill\n // initialisation (these were read at startup but can be changed at runtime\n // by the agent's permission middleware or tool guards).\n if (typeof payload['featureMcp'] === 'boolean')\n config.features.mcp = payload['featureMcp'];\n if (typeof payload['featurePlugins'] === 'boolean')\n config.features.plugins = payload['featurePlugins'];\n if (typeof payload['featureMemory'] === 'boolean')\n config.features.memory = payload['featureMemory'];\n if (typeof payload['featureSkills'] === 'boolean')\n config.features.skills = payload['featureSkills'];\n if (typeof payload['featureModelsRegistry'] === 'boolean')\n config.features.modelsRegistry = payload['featureModelsRegistry'];\n\n // Global fallback chain: mutate the live config so the leader's fallback\n // extension (which reads config each turn) honours it without a restart.\n if (Array.isArray(payload['fallbackModels']))\n config.fallbackModels = payload['fallbackModels'] as string[];\n if (typeof payload['fallbackAuto'] === 'boolean')\n config.fallbackAuto = payload['fallbackAuto'];\n\n // Runtime effects: apply prefs that change server behaviour immediately.\n\n // contextAutoCompact — toggle AutoCompactionMiddleware in/out of the\n // contextWindow pipeline. When off, the pipeline skips the compaction\n // step entirely (zero overhead). When on, re-adds the middleware.\n if (typeof payload['contextAutoCompact'] === 'boolean') {\n if (payload['contextAutoCompact'] && autoCompactor) {\n // Re-add: remove first (idempotent via optional), then insert.\n pipelines.contextWindow.remove('AutoCompaction', { optional: true });\n pipelines.contextWindow.use({ name: 'AutoCompaction', handler: autoCompactor.handler() });\n } else {\n pipelines.contextWindow.remove('AutoCompaction', { optional: true });\n }\n }\n\n // logLevel — the DefaultLogger.level property is a public mutable\n // field. Setting it at runtime changes the log threshold immediately\n // (the log() method checks LEVEL_RANK on every call).\n if (typeof payload['logLevel'] === 'string') {\n const valid = ['debug', 'info', 'warn', 'error'] as const;\n if ((valid as readonly string[]).includes(payload['logLevel'])) {\n logger.level = payload['logLevel'] as typeof valid[number];\n }\n }\n\n // auditLevel — stored in context.meta by the generic loop above.\n // Consumed by the session audit log system at session-close time.\n\n // Broadcast the full current prefs snapshot to ALL clients.\n broadcast(clients, { type: 'prefs.updated', payload: prefSnapshot() });\n },\n };\n\n shellGitRoutes = {\n gitInfo: async (ws) => {\n await handleGitInfo(ws, projectRoot);\n },\n gitChanges: async (ws) => {\n await handleGitChanges(ws, projectRoot);\n },\n gitDiff: async (ws, msg) => {\n const parsed = validateGitDiffPayload(msg.payload);\n if (!parsed.ok) {\n sendResult(ws, false, parsed.message);\n return;\n }\n await handleGitDiff(ws, projectRoot, parsed.value.path);\n },\n shellOpen: async (ws, msg) => {\n const parsed = validateShellOpenPayload(msg.payload);\n if (!parsed.ok) {\n sendResult(ws, false, parsed.message);\n return;\n }\n const result: ShellOpenResult = await handleShellOpen(parsed.value as ShellOpenRequest, logger);\n sendResult(ws, result.success, result.message);\n },\n };\n\n mailboxRoutes = {\n messages: (ws, msg) => {\n const parsed = validateMailboxMessagesPayload(msg.payload);\n if (!parsed.ok) {\n sendResult(ws, false, parsed.message);\n return;\n }\n return handleMailboxMessages(ws, { projectRoot, globalRoot: path.dirname(globalConfigPath) }, parsed.value);\n },\n agents: (ws, msg) => {\n const parsed = validateMailboxAgentsPayload(msg.payload);\n if (!parsed.ok) {\n sendResult(ws, false, parsed.message);\n return;\n }\n return handleMailboxAgents(ws, { projectRoot, globalRoot: path.dirname(globalConfigPath) }, parsed.value);\n },\n clear: (ws) =>\n handleMailboxClear(ws, { projectRoot, globalRoot: path.dirname(globalConfigPath) }),\n purge: (ws, msg) => {\n const parsed = validateMailboxPurgePayload(msg.payload);\n if (!parsed.ok) {\n sendResult(ws, false, parsed.message);\n return;\n }\n return handleMailboxPurge(ws, { projectRoot, globalRoot: path.dirname(globalConfigPath) }, parsed.value);\n },\n };\n\n // ---- MCP route (handleMcpRoute) ----\n // Issue #31 follow-on (after #118 PR 0 baseline, #119 prefs extraction).\n // Each callback delegates to the matching handleMcpXxx in mcp-handlers.ts\n // — that module already owns the WS-message logic, this is just the\n // chain-of-responsibility wiring. The 10 cases were pure delegations\n // inside the residual switch before this PR; now they're an explicit\n // sibling in the chain.\n mcpRoutes = {\n list: (ws, msg) => handleMcpList(ws, msg, globalConfigPath, mcpRegistry),\n add: (ws, msg) => handleMcpAdd(ws, msg, globalConfigPath, mcpRegistry),\n update: (ws, msg) => handleMcpUpdate(ws, msg, globalConfigPath, mcpRegistry),\n remove: (ws, msg) => handleMcpRemove(ws, msg, globalConfigPath, mcpRegistry),\n enable: (ws, msg) => handleMcpEnable(ws, msg, globalConfigPath, mcpRegistry),\n disable: (ws, msg) => handleMcpDisable(ws, msg, globalConfigPath, mcpRegistry),\n sleep: (ws, msg) => handleMcpSleep(ws, msg, globalConfigPath, mcpRegistry),\n wake: (ws, msg) => handleMcpWake(ws, msg, globalConfigPath, mcpRegistry),\n restart: (ws, msg) => handleMcpRestart(ws, msg, globalConfigPath, mcpRegistry),\n discover: (ws, msg) => handleMcpDiscover(ws, msg, globalConfigPath, mcpRegistry),\n };\n\n brainRoutes = {\n status: (ws) => {\n send(ws, {\n type: 'brain.status',\n payload: { maxAutoRisk: brainSettings.maxAutoRisk, log: brainLog },\n });\n },\n risk: (ws, msg) => {\n const parsed = validateBrainRiskPayload(msg.payload);\n if (!parsed.ok) {\n sendResult(ws, false, parsed.message);\n return;\n }\n const { level } = parsed.value;\n brainSettings.maxAutoRisk = level as BrainAutoRisk;\n send(ws, {\n type: 'brain.status',\n payload: { maxAutoRisk: brainSettings.maxAutoRisk, log: brainLog },\n });\n },\n ask: async (ws, msg) => {\n const parsed = validateBrainAskPayload(msg.payload);\n if (!parsed.ok) {\n sendResult(ws, false, parsed.message);\n return;\n }\n const { question } = parsed.value;\n try {\n const decision = await brain.decide({\n id: `brain-ask-${Date.now().toString(36)}`,\n source: 'user',\n question,\n risk: 'medium',\n fallback: 'ask_human',\n });\n send(ws, { type: 'brain.answer', payload: { question, decision } });\n } catch (err) {\n sendResult(ws, false, `Brain consultation failed: ${errMessage(err)}`);\n }\n },\n };\n\n autoPhaseRoutes = {\n handleMessage: (msg) => autoPhaseHandler.handleMessage(msg),\n };\n\n specsRoutes = {\n handleMessage: (msg) => specsHandler.handleMessage(msg),\n };\n\n sddBoardRoutes = {\n handleMessage: (msg) => sddBoardHandler.handleMessage(msg),\n };\n\n sddWizardRoutes = {\n handleMessage: (msg) => sddWizardHandler.handleMessage(msg),\n };\n\n // HTTP server for the React frontend (port 3456) — see `http-server.ts`\n // for the static-serve, MIME matching, path-traversal guard, and CSP\n // header logic. Constructed here, listen()d below alongside the WS server.\n // `globalRoot` powers the /api/sessions and /api/sessions/:id/agents\n // handlers (read the cross-process SessionRegistry); `apiToken` is the\n // shared auth token the HTTP API requires when bound to a non-loopback\n // host (LAN exposure). Loopback binds skip the token check, mirroring\n // the WS verifyClient loopback-bootstrap policy.\n\n // Shared metrics object for file watcher — populated by setupEvents and\n // exposed via the /debug/watcher-metrics HTTP endpoint.\n const watcherMetrics: FileWatcherMetrics = {\n fileChangesDetected: 0,\n filesProcessed: 0,\n broadcastsSent: 0,\n debounceResets: 0,\n totalDebounceDelayMs: 0,\n activeProjects: 0,\n averageDebounceDelayMs: 0,\n watcherActive: false,\n };\n\n const httpServer = createHttpServer({\n host: wsHost,\n distDir: path.resolve(import.meta.dirname, '../../dist'),\n wsPort,\n publicWsUrl,\n globalRoot: wpaths.globalRoot,\n apiToken: wsToken,\n requireToken,\n watcherMetrics,\n onFleetPing: () => { void fleetBroadcast?.(); },\n });\n // httpPort/wsPort were resolved (and possibly auto-advanced) at the top.\n // Base dir for the running-instance registry — keep it next to the rest of\n // the wstack home state (config.json lives here too).\n const registryBaseDir = path.dirname(globalConfigPath);\n httpServer.listen(httpPort, wsHost, () => {\n const openUrl = buildWebUIAccessUrl({\n host: wsHost,\n port: httpPort,\n token: wsToken,\n publicUrl,\n });\n console.log(`[WebUI] HTTP server running on ${openUrl}`);\n // Optionally pop the browser open (best-effort; the URL is always printed).\n if (opts.open) openBrowser(openUrl);\n // Record this instance so `wstackui --list` (and `~/.wrongstack/\n // webui-instances.json`) show which ports are open for which project.\n // Best-effort: a registry write failure must not affect serving.\n void registerInstance(\n {\n pid: process.pid,\n httpPort,\n wsPort,\n host: wsHost,\n projectRoot,\n projectName: path.basename(projectRoot) || projectRoot,\n startedAt: new Date().toISOString(),\n url: buildWebUIAccessUrl({ host: wsHost, port: httpPort, publicUrl }),\n },\n registryBaseDir,\n ).catch((err) => console.warn(JSON.stringify({\n level: 'warn',\n event: 'webui.instance_record_failed',\n message: errMessage(err),\n timestamp: new Date().toISOString(),\n })));\n });\n\n // Graceful shutdown on SIGINT/SIGTERM — see `lifecycle.ts`. The session\n // flush (session_end + close) is passed as a thunk so lifecycle stays\n // decoupled from the session/tokenCounter types.\n registerShutdownHandlers({\n flushSession: async () => {\n await session.append({\n type: 'session_end',\n ts: new Date().toISOString(),\n usage: tokenCounter.total(),\n });\n await session.close();\n },\n clients: () => clients.keys(),\n servers: [httpServer, wssPrimary, wssSecondary],\n // Drop this instance from the registry on a clean exit so the file reflects\n // reality. Crash exits are healed by the next register()/list() prune pass.\n onShutdown: () => {\n brainMonitor.stop();\n void mcpRegistry.stopAll().catch(() => undefined);\n if (disposeEvents) {\n disposeEvents();\n disposeEvents = null;\n }\n if (eternalSubscription) {\n eternalSubscription.dispose();\n eternalSubscription = null;\n }\n codebaseIndexing.dispose();\n return unregisterInstance(process.pid, registryBaseDir);\n },\n });\n}\n","export type PayloadValidationResult<T> = { ok: true; value: T } | { ok: false; message: string };\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport interface ModelSwitchPayload {\n provider: string;\n model: string;\n}\n\nexport function validateModelSwitchPayload(\n payload: unknown,\n): PayloadValidationResult<ModelSwitchPayload> {\n if (!isRecord(payload)) {\n return {\n ok: false,\n message: 'model.switch payload must be an object with string provider and model',\n };\n }\n const provider = payload['provider'];\n const model = payload['model'];\n if (typeof provider !== 'string' || provider.trim().length === 0) {\n return { ok: false, message: 'model.switch payload.provider must be a non-empty string' };\n }\n if (typeof model !== 'string' || model.trim().length === 0) {\n return { ok: false, message: 'model.switch payload.model must be a non-empty string' };\n }\n return { ok: true, value: { provider, model } };\n}\n\nexport interface PrefsUpdatePayload {\n prefs: Record<string, unknown>;\n}\n\nconst AUTONOMY_VALUES = new Set(['off', 'suggest', 'auto', 'eternal', 'eternal-parallel']);\n\nexport interface MailboxMessagesPayload {\n limit?: number;\n agentId?: string;\n unreadOnly?: boolean;\n}\n\nexport function validateMailboxMessagesPayload(\n payload: unknown,\n): PayloadValidationResult<MailboxMessagesPayload | undefined> {\n if (payload === undefined) return { ok: true, value: undefined };\n if (!isRecord(payload)) {\n return { ok: false, message: 'mailbox.messages payload must be an object when provided' };\n }\n const limit = payload['limit'];\n const agentId = payload['agentId'];\n const unreadOnly = payload['unreadOnly'];\n if (limit !== undefined && (typeof limit !== 'number' || !Number.isFinite(limit) || limit < 1)) {\n return {\n ok: false,\n message: 'mailbox.messages payload.limit must be a positive number when provided',\n };\n }\n if (agentId !== undefined && typeof agentId !== 'string') {\n return {\n ok: false,\n message: 'mailbox.messages payload.agentId must be a string when provided',\n };\n }\n if (unreadOnly !== undefined && typeof unreadOnly !== 'boolean') {\n return {\n ok: false,\n message: 'mailbox.messages payload.unreadOnly must be a boolean when provided',\n };\n }\n return { ok: true, value: { limit, agentId, unreadOnly } };\n}\n\nexport interface MailboxAgentsPayload {\n onlineOnly?: boolean;\n}\n\nexport function validateMailboxAgentsPayload(\n payload: unknown,\n): PayloadValidationResult<MailboxAgentsPayload | undefined> {\n if (payload === undefined) return { ok: true, value: undefined };\n if (!isRecord(payload)) {\n return { ok: false, message: 'mailbox.agents payload must be an object when provided' };\n }\n const onlineOnly = payload['onlineOnly'];\n if (onlineOnly !== undefined && typeof onlineOnly !== 'boolean') {\n return {\n ok: false,\n message: 'mailbox.agents payload.onlineOnly must be a boolean when provided',\n };\n }\n return { ok: true, value: { onlineOnly } };\n}\n\nexport interface MailboxPurgePayload {\n completedMaxAgeMs?: number;\n incompleteMaxAgeMs?: number;\n}\n\nexport function validateMailboxPurgePayload(\n payload: unknown,\n): PayloadValidationResult<MailboxPurgePayload | undefined> {\n if (payload === undefined) return { ok: true, value: undefined };\n if (!isRecord(payload)) {\n return { ok: false, message: 'mailbox.purge payload must be an object when provided' };\n }\n const completedMaxAgeMs = payload['completedMaxAgeMs'];\n const incompleteMaxAgeMs = payload['incompleteMaxAgeMs'];\n if (\n completedMaxAgeMs !== undefined &&\n (typeof completedMaxAgeMs !== 'number' ||\n !Number.isFinite(completedMaxAgeMs) ||\n completedMaxAgeMs < 0)\n ) {\n return {\n ok: false,\n message:\n 'mailbox.purge payload.completedMaxAgeMs must be a non-negative number when provided',\n };\n }\n if (\n incompleteMaxAgeMs !== undefined &&\n (typeof incompleteMaxAgeMs !== 'number' ||\n !Number.isFinite(incompleteMaxAgeMs) ||\n incompleteMaxAgeMs < 0)\n ) {\n return {\n ok: false,\n message:\n 'mailbox.purge payload.incompleteMaxAgeMs must be a non-negative number when provided',\n };\n }\n return { ok: true, value: { completedMaxAgeMs, incompleteMaxAgeMs } };\n}\n\nexport interface BrainRiskPayload {\n level: string;\n}\n\nconst BRAIN_RISK_VALUES = new Set(['off', 'low', 'medium', 'high', 'all']);\n\nexport function validateBrainRiskPayload(\n payload: unknown,\n): PayloadValidationResult<BrainRiskPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'brain.risk payload must be an object with string level' };\n }\n const level = payload['level'];\n if (typeof level !== 'string' || !BRAIN_RISK_VALUES.has(level)) {\n return {\n ok: false,\n message: 'brain.risk payload.level must be one of off, low, medium, high, all',\n };\n }\n return { ok: true, value: { level } };\n}\n\nexport interface BrainAskPayload {\n question: string;\n}\n\nexport function validateBrainAskPayload(\n payload: unknown,\n): PayloadValidationResult<BrainAskPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'brain.ask payload must be an object with string question' };\n }\n const question = payload['question'];\n if (typeof question !== 'string' || question.trim().length === 0) {\n return { ok: false, message: 'brain.ask payload.question must be a non-empty string' };\n }\n return { ok: true, value: { question: question.trim() } };\n}\n\nexport interface AutonomySwitchPayload {\n mode: string;\n}\n\nexport function validateAutonomySwitchPayload(\n payload: unknown,\n): PayloadValidationResult<AutonomySwitchPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'autonomy.switch payload must be an object with string mode' };\n }\n const mode = payload['mode'];\n if (typeof mode !== 'string' || !AUTONOMY_VALUES.has(mode)) {\n return { ok: false, message: 'autonomy.switch payload.mode must be a valid autonomy mode' };\n }\n return { ok: true, value: { mode } };\n}\n\nexport interface PlanTemplateUsePayload {\n template: string;\n}\n\nexport function validatePlanTemplateUsePayload(\n payload: unknown,\n): PayloadValidationResult<PlanTemplateUsePayload> {\n if (!isRecord(payload)) {\n return {\n ok: false,\n message: 'plan.template_use payload must be an object with string template',\n };\n }\n const template = payload['template'];\n if (typeof template !== 'string' || template.trim().length === 0) {\n return { ok: false, message: 'plan.template_use payload.template must be a non-empty string' };\n }\n return { ok: true, value: { template } };\n}\nconst CONTEXT_STRATEGY_VALUES = new Set(['hybrid', 'intelligent', 'selective']);\nconst CONTEXT_MODE_VALUES = new Set(['balanced', 'frugal', 'deep', 'archival']);\nconst TOKEN_SAVING_TIER_VALUES = new Set(['off', 'minimal', 'light', 'medium', 'aggressive']);\nconst ENHANCE_LANGUAGE_VALUES = new Set(['original', 'english']);\nconst LOG_LEVEL_VALUES = new Set(['debug', 'info', 'warn', 'error']);\nconst AUDIT_LEVEL_VALUES = new Set(['minimal', 'standard', 'full']);\nconst REASONING_MODE_VALUES = new Set(['auto', 'on', 'off']);\nconst REASONING_EFFORT_VALUES = new Set([\n 'none',\n 'minimal',\n 'low',\n 'medium',\n 'high',\n 'xhigh',\n 'max',\n]);\nconst CACHE_TTL_VALUES = new Set(['default', '5m', '1h']);\n\nconst BOOLEAN_PREF_KEYS = new Set([\n 'yolo',\n 'chime',\n 'confirmExit',\n 'streamFleet',\n 'nextPrediction',\n 'titleAnimation',\n 'enhanceEnabled',\n 'featureMcp',\n 'featurePlugins',\n 'featureMemory',\n 'featureSkills',\n 'featureModelsRegistry',\n 'indexOnStart',\n 'contextAutoCompact',\n 'tgSessionEnd',\n 'tgDelegate',\n 'reasoningPreserve',\n 'hqEnabled',\n 'hqRawContent',\n 'fallbackAuto',\n]);\n\n/** Keys whose value must be an array of strings (e.g. an ordered model list). */\nconst STRING_ARRAY_PREF_KEYS = new Set(['fallbackModels']);\n\nconst NUMBER_PREF_KEYS = new Set([\n 'autonomyDelayMs',\n 'autoProceedMaxIterations',\n 'maxIterations',\n 'maxConcurrent',\n 'enhanceDelayMs',\n 'tgLongToolMs',\n]);\n\nconst STRING_PREF_KEYS = new Set(['hqUrl', 'hqToken']);\n\nconst ENUM_PREF_KEYS: Record<string, Set<string>> = {\n autonomy: AUTONOMY_VALUES,\n contextStrategy: CONTEXT_STRATEGY_VALUES,\n contextMode: CONTEXT_MODE_VALUES,\n tokenSavingTier: TOKEN_SAVING_TIER_VALUES,\n enhanceLanguage: ENHANCE_LANGUAGE_VALUES,\n logLevel: LOG_LEVEL_VALUES,\n auditLevel: AUDIT_LEVEL_VALUES,\n reasoningMode: REASONING_MODE_VALUES,\n reasoningEffort: REASONING_EFFORT_VALUES,\n cacheTtl: CACHE_TTL_VALUES,\n};\n\nfunction validatePreferenceValue(key: string, value: unknown): string | null {\n if (BOOLEAN_PREF_KEYS.has(key)) {\n return typeof value === 'boolean' ? null : `prefs.update payload.${key} must be a boolean`;\n }\n if (NUMBER_PREF_KEYS.has(key)) {\n return typeof value === 'number' && Number.isFinite(value)\n ? null\n : `prefs.update payload.${key} must be a finite number`;\n }\n if (STRING_PREF_KEYS.has(key)) {\n return typeof value === 'string' ? null : `prefs.update payload.${key} must be a string`;\n }\n if (STRING_ARRAY_PREF_KEYS.has(key)) {\n return Array.isArray(value) && value.every((v) => typeof v === 'string')\n ? null\n : `prefs.update payload.${key} must be an array of strings`;\n }\n const allowed = ENUM_PREF_KEYS[key];\n if (allowed) {\n return typeof value === 'string' && allowed.has(value)\n ? null\n : `prefs.update payload.${key} must be one of: ${Array.from(allowed).join(', ')}`;\n }\n return `prefs.update payload contains unknown preference key: ${key}`;\n}\n\nexport function validatePrefsUpdatePayload(\n payload: unknown,\n): PayloadValidationResult<PrefsUpdatePayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'prefs.update payload must be an object' };\n }\n for (const [key, value] of Object.entries(payload)) {\n const error = validatePreferenceValue(key, value);\n if (error) return { ok: false, message: error };\n }\n return { ok: true, value: { prefs: payload } };\n}\n\nexport interface SkillsCreatePayload {\n name: string;\n description: string;\n scope: 'project' | 'global';\n}\n\nexport function validateSkillsCreatePayload(\n payload: unknown,\n): PayloadValidationResult<SkillsCreatePayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'skills.create payload must be an object' };\n }\n const name = payload['name'];\n const description = payload['description'];\n const scope = payload['scope'];\n if (typeof name !== 'string' || name.trim().length === 0) {\n return { ok: false, message: 'Skill name is required' };\n }\n if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(name.trim())) {\n return { ok: false, message: 'Skill name must be kebab-case (e.g. my-new-skill)' };\n }\n if (typeof description !== 'string' || description.trim().length === 0) {\n return { ok: false, message: 'Description/trigger is required' };\n }\n if (scope !== 'project' && scope !== 'global') {\n return { ok: false, message: 'skills.create payload.scope must be project or global' };\n }\n return { ok: true, value: { name, description, scope } };\n}\n\nexport interface SkillsEditPayload {\n name: string;\n body: string;\n}\n\nexport function validateSkillsEditPayload(\n payload: unknown,\n): PayloadValidationResult<SkillsEditPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'skills.edit payload must be an object' };\n }\n const name = payload['name'];\n const body = payload['body'];\n if (typeof name !== 'string' || name.trim().length === 0) {\n return { ok: false, message: 'Skill name is required' };\n }\n if (typeof body !== 'string' || body.length === 0) {\n return { ok: false, message: 'Skill body is required' };\n }\n return { ok: true, value: { name, body } };\n}\n\nexport interface ProcessKillPayload {\n pid: number;\n}\n\nexport function validateProcessKillPayload(\n payload: unknown,\n): PayloadValidationResult<ProcessKillPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'process.kill payload must be an object with numeric pid' };\n }\n const pid = payload['pid'];\n if (typeof pid !== 'number' || !Number.isInteger(pid) || pid <= 0) {\n return { ok: false, message: 'process.kill payload.pid must be a positive integer' };\n }\n return { ok: true, value: { pid } };\n}\n\nexport interface WorkingDirSetPayload {\n path: string;\n}\n\nexport function validateWorkingDirSetPayload(\n payload: unknown,\n): PayloadValidationResult<WorkingDirSetPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'working_dir.set payload must be an object with string path' };\n }\n const newPath = payload['path'];\n if (typeof newPath !== 'string' || newPath.trim().length === 0) {\n return { ok: false, message: 'working_dir.set payload.path must be a non-empty string' };\n }\n return { ok: true, value: { path: newPath } };\n}\n\nexport interface ModeSwitchPayload {\n id: string;\n}\n\nexport function validateModeSwitchPayload(\n payload: unknown,\n): PayloadValidationResult<ModeSwitchPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'mode.switch payload must be an object with string id' };\n }\n const id = payload['id'];\n if (typeof id !== 'string' || id.trim().length === 0) {\n return { ok: false, message: 'mode.switch payload.id must be a non-empty string' };\n }\n return { ok: true, value: { id } };\n}\n\nexport interface ContextModeIdPayload {\n id: string;\n}\n\nfunction validateContextModeIdPayload(\n payload: unknown,\n type: 'context.mode.switch' | 'context.mode.delete',\n): PayloadValidationResult<ContextModeIdPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: `${type} payload must be an object with string id` };\n }\n const id = payload['id'];\n if (typeof id !== 'string' || id.trim().length === 0) {\n return { ok: false, message: `${type} payload.id must be a non-empty string` };\n }\n return { ok: true, value: { id } };\n}\n\nexport function validateContextModeSwitchPayload(\n payload: unknown,\n): PayloadValidationResult<ContextModeIdPayload> {\n return validateContextModeIdPayload(payload, 'context.mode.switch');\n}\n\nexport function validateContextModeDeletePayload(\n payload: unknown,\n): PayloadValidationResult<ContextModeIdPayload> {\n return validateContextModeIdPayload(payload, 'context.mode.delete');\n}\n\nexport interface ContextModeCreatePayload {\n id: string;\n name: string;\n description: string;\n thresholds: { warn: number; soft: number; hard: number };\n preserveK: number;\n eliseThreshold: number;\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value);\n}\n\nexport function validateContextModeCreatePayload(\n payload: unknown,\n): PayloadValidationResult<ContextModeCreatePayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'context.mode.create payload must be an object' };\n }\n const id = payload['id'];\n const name = payload['name'];\n const description = payload['description'];\n const thresholds = payload['thresholds'];\n const preserveK = payload['preserveK'];\n const eliseThreshold = payload['eliseThreshold'];\n\n if (typeof id !== 'string' || id.trim().length === 0) {\n return { ok: false, message: 'context.mode.create payload.id must be a non-empty string' };\n }\n if (typeof name !== 'string' || name.trim().length === 0) {\n return { ok: false, message: 'context.mode.create payload.name must be a non-empty string' };\n }\n if (typeof description !== 'string') {\n return { ok: false, message: 'context.mode.create payload.description must be a string' };\n }\n if (!isRecord(thresholds)) {\n return {\n ok: false,\n message:\n 'context.mode.create payload.thresholds must be an object with warn/soft/hard numbers',\n };\n }\n if (\n !isFiniteNumber(thresholds['warn']) ||\n !isFiniteNumber(thresholds['soft']) ||\n !isFiniteNumber(thresholds['hard'])\n ) {\n return {\n ok: false,\n message: 'context.mode.create payload.thresholds.warn/soft/hard must be finite numbers',\n };\n }\n if (!isFiniteNumber(preserveK)) {\n return { ok: false, message: 'context.mode.create payload.preserveK must be a finite number' };\n }\n if (!isFiniteNumber(eliseThreshold)) {\n return {\n ok: false,\n message: 'context.mode.create payload.eliseThreshold must be a finite number',\n };\n }\n return {\n ok: true,\n value: {\n id,\n name,\n description,\n thresholds: { warn: thresholds['warn'], soft: thresholds['soft'], hard: thresholds['hard'] },\n preserveK,\n eliseThreshold,\n },\n };\n}\n\nexport interface ContextModeUpdatePayload {\n id: string;\n name?: string;\n description?: string;\n thresholds?: { warn?: number; soft?: number; hard?: number };\n preserveK?: number;\n eliseThreshold?: number;\n}\n\nexport function validateContextModeUpdatePayload(\n payload: unknown,\n): PayloadValidationResult<ContextModeUpdatePayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'context.mode.update payload must be an object' };\n }\n const id = payload['id'];\n if (typeof id !== 'string' || id.trim().length === 0) {\n return { ok: false, message: 'context.mode.update payload.id must be a non-empty string' };\n }\n\n const name = payload['name'];\n if (name !== undefined && typeof name !== 'string') {\n return {\n ok: false,\n message: 'context.mode.update payload.name must be a string when provided',\n };\n }\n\n const description = payload['description'];\n if (description !== undefined && typeof description !== 'string') {\n return {\n ok: false,\n message: 'context.mode.update payload.description must be a string when provided',\n };\n }\n\n const thresholds = payload['thresholds'];\n let validatedThresholds: ContextModeUpdatePayload['thresholds'];\n if (thresholds !== undefined) {\n if (!isRecord(thresholds)) {\n return {\n ok: false,\n message: 'context.mode.update payload.thresholds must be an object when provided',\n };\n }\n for (const key of ['warn', 'soft', 'hard'] as const) {\n const val = thresholds[key];\n if (val !== undefined && !isFiniteNumber(val)) {\n return {\n ok: false,\n message: `context.mode.update payload.thresholds.${key} must be a finite number when provided`,\n };\n }\n }\n validatedThresholds = {\n warn: typeof thresholds['warn'] === 'number' ? thresholds['warn'] : undefined,\n soft: typeof thresholds['soft'] === 'number' ? thresholds['soft'] : undefined,\n hard: typeof thresholds['hard'] === 'number' ? thresholds['hard'] : undefined,\n };\n }\n\n const preserveK = payload['preserveK'];\n if (preserveK !== undefined && !isFiniteNumber(preserveK)) {\n return {\n ok: false,\n message: 'context.mode.update payload.preserveK must be a finite number when provided',\n };\n }\n\n const eliseThreshold = payload['eliseThreshold'];\n if (eliseThreshold !== undefined && !isFiniteNumber(eliseThreshold)) {\n return {\n ok: false,\n message: 'context.mode.update payload.eliseThreshold must be a finite number when provided',\n };\n }\n\n return {\n ok: true,\n value: {\n id,\n name: typeof name === 'string' ? name : undefined,\n description: typeof description === 'string' ? description : undefined,\n thresholds: validatedThresholds,\n preserveK: typeof preserveK === 'number' ? preserveK : undefined,\n eliseThreshold: typeof eliseThreshold === 'number' ? eliseThreshold : undefined,\n },\n };\n}\n\nexport interface ShellOpenPayload {\n path: string;\n target?: 'file' | 'terminal';\n}\n\nexport function validateShellOpenPayload(\n payload: unknown,\n): PayloadValidationResult<ShellOpenPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'shell.open payload must be an object with string path' };\n }\n const path = payload['path'];\n if (typeof path !== 'string' || path.trim().length === 0) {\n return { ok: false, message: 'shell.open payload.path must be a non-empty string' };\n }\n const target = payload['target'];\n if (target !== undefined && target !== 'file' && target !== 'terminal') {\n return {\n ok: false,\n message: 'shell.open payload.target must be \"file\" or \"terminal\" when provided',\n };\n }\n return { ok: true, value: { path, target: target as ShellOpenPayload['target'] } };\n}\n\nexport interface GitDiffPayload {\n path: string;\n}\n\nexport function validateGitDiffPayload(payload: unknown): PayloadValidationResult<GitDiffPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'git.diff payload must be an object' };\n }\n const path = payload['path'];\n if (path === undefined || path === null) {\n return { ok: true, value: { path: '' } };\n }\n if (typeof path !== 'string') {\n return { ok: false, message: 'git.diff payload.path must be a string when provided' };\n }\n return { ok: true, value: { path } };\n}\n\nexport interface ProjectsAddPayload {\n root: string;\n name?: string;\n}\n\nexport function validateProjectsAddPayload(\n payload: unknown,\n): PayloadValidationResult<ProjectsAddPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'projects.add payload must be an object with string root' };\n }\n const root = payload['root'];\n if (typeof root !== 'string' || root.trim().length === 0) {\n return { ok: false, message: 'projects.add payload.root must be a non-empty string' };\n }\n const name = payload['name'];\n if (name !== undefined && typeof name !== 'string') {\n return { ok: false, message: 'projects.add payload.name must be a string when provided' };\n }\n return { ok: true, value: { root, name: typeof name === 'string' ? name : undefined } };\n}\n\nexport interface ProjectsSelectPayload {\n root: string;\n name?: string;\n}\n\nexport function validateProjectsSelectPayload(\n payload: unknown,\n): PayloadValidationResult<ProjectsSelectPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'projects.select payload must be an object with string root' };\n }\n const root = payload['root'];\n if (typeof root !== 'string' || root.trim().length === 0) {\n return { ok: false, message: 'projects.select payload.root must be a non-empty string' };\n }\n const name = payload['name'];\n if (name !== undefined && typeof name !== 'string') {\n return { ok: false, message: 'projects.select payload.name must be a string when provided' };\n }\n return { ok: true, value: { root, name: typeof name === 'string' ? name : undefined } };\n}\n","// ── Shared Worklist Handlers ─────────────────────────────────────────────────\n// Extracted from standalone server (packages/webui/src/server/index.ts) and CLI\n// embedded server (packages/cli/src/webui-server/). Both servers use these\n// handlers for todos, tasks, and plan operations. Keep them in sync.\n//\n// Message types handled here:\n// todos.get | todos.clear | todos.remove | todo.update\n// tasks.get | task.update\n// plan.get | plan.template_use | plan.item.update\n// ─────────────────────────────────────────────────────────────────────────────\n\nimport type { WebSocket } from 'ws';\nimport type { TodoItem } from '@wrongstack/core';\nimport { validatePlanTemplateUsePayload } from '../ws-payload-validation.js';\n\n// ── Shared result helper ───────────────────────────────────────────────────────\n\nfunction sendResult(\n ws: WebSocket,\n ctx: WorklistContext,\n ok: boolean,\n message: string,\n): void {\n ctx.send(ws, { type: ok ? 'ok' : 'error', message });\n}\n\n// ── Context interface ─────────────────────────────────────────────────────────\n// Both servers satisfy this with their own local state.\n\nexport interface WorklistContext {\n context: {\n todos: TodoItem[];\n meta: Record<string, unknown>;\n session: { id: string } | null;\n state?: unknown;\n };\n send: (ws: WebSocket, msg: object) => void;\n broadcast: (msg: object) => void;\n /**\n * Optional mutator for in-memory todo state. Servers that manage live\n * agent state (e.g. the CLI embedded server) provide this so handlers\n * can update the agent's todo list directly. Standalone server may omit.\n */\n replaceTodos?: (todos: TodoItem[]) => void;\n}\n\n// ── Todos ─────────────────────────────────────────────────────────────────────\n\nexport function handleTodosGet(ctx: WorklistContext, ws: WebSocket): void {\n ctx.send(ws, { type: 'todos.updated', payload: { todos: ctx.context.todos } });\n}\n\nexport function handleTodosClear(ctx: WorklistContext, ws: WebSocket): void {\n ctx.replaceTodos?.([]);\n ctx.broadcast({ type: 'todos.cleared' });\n sendResult(ws, ctx, true, 'Todo board cleared.');\n}\n\nexport function handleTodosRemove(\n ctx: WorklistContext,\n ws: WebSocket,\n payload: { id?: string; index?: number } | undefined,\n): void {\n if (!payload || (payload.id === undefined && payload.index === undefined)) {\n sendResult(ws, ctx, false, 'todos.remove requires id or index.');\n return;\n }\n const next =\n payload.id !== undefined\n ? ctx.context.todos.filter((t) => t.id !== payload.id)\n : ctx.context.todos.filter((_, i) => i !== (payload.index as number));\n ctx.replaceTodos?.(next);\n ctx.broadcast({ type: 'todos.updated', payload: { todos: next } });\n sendResult(ws, ctx, true, 'Todo item removed.');\n}\n\nexport function handleTodoUpdate(\n ctx: WorklistContext,\n ws: WebSocket,\n payload: { id: string; status?: TodoItem['status']; activeForm?: string },\n): void {\n const todo = ctx.context.todos.find((t) => t.id === payload.id);\n if (!todo) {\n sendResult(ws, ctx, false, `No todo with id \"${payload.id}\".`);\n return;\n }\n const next = ctx.context.todos.map((t) =>\n t.id === payload.id\n ? { ...t, ...(payload.status !== undefined && { status: payload.status }), ...(payload.activeForm !== undefined && { activeForm: payload.activeForm }) }\n : t,\n );\n ctx.replaceTodos?.(next);\n ctx.broadcast({ type: 'todos.updated', payload: { todos: next } });\n sendResult(ws, ctx, true, `Todo \"${todo.content}\" updated.`);\n}\n\n// ── Tasks ─────────────────────────────────────────────────────────────────────\n\nexport async function handleTasksGet(ctx: WorklistContext, ws: WebSocket): Promise<void> {\n const taskPath = ctx.context.meta['task.path'];\n if (typeof taskPath === 'string' && taskPath) {\n try {\n const { loadTasks } = await import('@wrongstack/core');\n const file = await loadTasks(taskPath);\n ctx.send(ws, { type: 'tasks.updated', payload: { tasks: file?.tasks ?? [] } });\n } catch {\n ctx.send(ws, { type: 'tasks.updated', payload: { tasks: [] } });\n }\n } else {\n ctx.send(ws, {\n type: 'tasks.updated',\n payload: { tasks: [], error: 'Task storage not configured.' },\n });\n }\n}\n\nexport async function handleTaskUpdate(\n ctx: WorklistContext,\n ws: WebSocket,\n payload: {\n id: string;\n status: 'pending' | 'in_progress' | 'blocked' | 'failed' | 'review' | 'completed';\n },\n): Promise<void> {\n const taskPath = ctx.context.meta['task.path'];\n if (typeof taskPath !== 'string' || !taskPath) {\n sendResult(ws, ctx, false, 'Task storage is not configured for this session.');\n return;\n }\n try {\n const { loadTasks, saveTasks } = await import('@wrongstack/core');\n const file = await loadTasks(taskPath);\n if (!file) {\n sendResult(ws, ctx, false, 'No task file found.');\n return;\n }\n const idx = file.tasks.findIndex((t) => t.id === payload.id);\n if (idx === -1) {\n sendResult(ws, ctx, false, `Task \"${payload.id}\" not found.`);\n return;\n }\n file.tasks[idx] = { ...file.tasks[idx], status: payload.status };\n await saveTasks(taskPath, file);\n ctx.broadcast({ type: 'tasks.updated', payload: { tasks: file.tasks } });\n sendResult(ws, ctx, true, `Task \"${payload.id}\" marked ${payload.status}.`);\n } catch (err) {\n sendResult(ws, ctx, false, String(err));\n }\n}\n\n// ── Plan ───────────────────────────────────────────────────────────────────────\n\nexport async function handlePlanGet(ctx: WorklistContext, ws: WebSocket): Promise<void> {\n const planPath = ctx.context.meta['plan.path'];\n const sessionId = ctx.context.session?.id ?? '';\n if (typeof planPath === 'string' && planPath) {\n try {\n const { loadPlan } = await import('@wrongstack/core');\n const plan = await loadPlan(planPath);\n ctx.send(ws, {\n type: 'plan.updated',\n payload: {\n plan: plan ?? {\n version: 1,\n sessionId,\n updatedAt: new Date().toISOString(),\n items: [],\n },\n },\n });\n } catch {\n ctx.send(ws, {\n type: 'plan.updated',\n payload: {\n plan: {\n version: 1,\n sessionId,\n updatedAt: new Date().toISOString(),\n items: [],\n },\n },\n });\n }\n } else {\n ctx.send(ws, {\n type: 'plan.updated',\n payload: { plan: null, error: 'Plan storage is not configured for this session.' },\n });\n }\n}\n\nexport async function handlePlanTemplateUse(ctx: WorklistContext, ws: WebSocket, template: string): Promise<void> {\n const planPath = ctx.context.meta['plan.path'];\n const sessionId = ctx.context.session?.id ?? '';\n if (typeof planPath !== 'string' || !planPath) {\n sendResult(ws, ctx, false, 'Plan storage is not configured for this session.');\n return;\n }\n try {\n const { getPlanTemplate, loadPlan, savePlan, emptyPlan, addPlanItem } = await import('@wrongstack/core');\n const tpl = getPlanTemplate(template);\n if (!tpl) {\n sendResult(ws, ctx, false, `Unknown template \"${template}\".`);\n return;\n }\n let plan = (await loadPlan(planPath)) ?? emptyPlan(sessionId);\n for (const item of tpl.items) {\n ({ plan } = addPlanItem(plan, item.title, item.details));\n }\n await savePlan(planPath, plan);\n sendResult(ws, ctx, true, `Applied template \"${tpl.name}\" — ${tpl.items.length} items added.`);\n ctx.broadcast({ type: 'plan.updated', payload: { plan } });\n } catch (err) {\n sendResult(ws, ctx, false, String(err));\n }\n}\n\nexport async function handlePlanItemUpdate(\n ctx: WorklistContext,\n ws: WebSocket,\n payload: { target: string; status: 'open' | 'in_progress' | 'done' },\n): Promise<void> {\n const planPath = ctx.context.meta['plan.path'];\n const sessionId = ctx.context.session?.id ?? '';\n if (typeof planPath !== 'string' || !planPath) {\n sendResult(ws, ctx, false, 'Plan storage is not configured for this session.');\n return;\n }\n try {\n const { mutatePlan, setPlanItemStatus } = await import('@wrongstack/core');\n let changed = false;\n const plan = await mutatePlan(planPath, sessionId, async (p) => {\n const before = p.updatedAt;\n const updated = setPlanItemStatus(p, payload.target, payload.status);\n changed = updated.updatedAt !== before;\n return updated;\n });\n if (!changed) {\n sendResult(ws, ctx, false, `No plan item matched \"${payload.target}\".`);\n return;\n }\n sendResult(ws, ctx, true, `Plan item status updated to \"${payload.status}\".`);\n ctx.broadcast({ type: 'plan.updated', payload: { plan } });\n } catch (err) {\n sendResult(ws, ctx, false, String(err));\n }\n}\n\n// ── Dispatcher ──────────────────────────────────────────────────────────────────\n// Single entry point for the nine worklist message types, so the host server's\n// switch delegates one grouped case here instead of repeating the per-type\n// `makeWorklistContext()` boilerplate. Unknown types are a no-op (the caller\n// only routes worklist types to this function).\n\n/** Loosely-typed worklist WS message — payload shapes are narrowed per case. */\nexport interface WorklistMessage {\n type: string;\n payload?: unknown;\n}\n\nexport async function handleWorklistMessage(\n ctx: WorklistContext,\n ws: WebSocket,\n msg: WorklistMessage,\n): Promise<void> {\n switch (msg.type) {\n case 'todos.get':\n handleTodosGet(ctx, ws);\n return;\n case 'todos.clear':\n handleTodosClear(ctx, ws);\n return;\n case 'todos.remove':\n handleTodosRemove(ctx, ws, msg.payload as { id?: string; index?: number } | undefined);\n return;\n case 'todo.update':\n handleTodoUpdate(\n ctx,\n ws,\n msg.payload as { id: string; status?: TodoItem['status']; activeForm?: string },\n );\n return;\n case 'tasks.get':\n await handleTasksGet(ctx, ws);\n return;\n case 'task.update':\n await handleTaskUpdate(\n ctx,\n ws,\n msg.payload as {\n id: string;\n status: 'pending' | 'in_progress' | 'blocked' | 'failed' | 'review' | 'completed';\n },\n );\n return;\n case 'plan.get':\n await handlePlanGet(ctx, ws);\n return;\n case 'plan.template_use': {\n const parsed = validatePlanTemplateUsePayload(msg.payload);\n if (!parsed.ok) {\n sendResult(ws, ctx, false, parsed.message);\n return;\n }\n await handlePlanTemplateUse(ctx, ws, parsed.value.template);\n return;\n }\n case 'plan.item.update':\n await handlePlanItemUpdate(\n ctx,\n ws,\n msg.payload as { target: string; status: 'open' | 'in_progress' | 'done' },\n );\n return;\n }\n}\n","/**\n * Static-file HTTP server for the WebUI React frontend.\n *\n * - Serves files from `distDir` (typically `<webui>/dist`).\n * - Returns `index.html` for any unknown path so client-side routing works\n * (SPA fallback) — and applies the same Content-Security-Policy to that\n * fallback as to a direct `.html` response, so deep-linked routes are\n * not unprotected.\n * - **Path-traversal guard**: `path.join` alone does NOT prevent\n * `%2e%2e%2f` escapes (the `URL` constructor decodes percent-encoding\n * before we see the path). We re-`resolve` the candidate and verify it\n * stays under `distDir`.\n * - **CSP**: `connect-src` uses explicit loopback addresses for the WS\n * server (not bare `ws:` / `wss:`) so a malicious page script cannot\n * dial an attacker-controlled WebSocket. Combined with the\n * cookie-based WS auth delivery (`/ws-auth` → `Set-Cookie: ws_token=\n * …; HttpOnly; SameSite=Strict; Path=/`), this prevents cross-origin\n * WS abuse.\n * - **Access auth**: on non-loopback binds, all HTTP routes require the same\n * shared token as the WS upgrade, accepted via `?token=...`, `X-WS-Token`,\n * or the `ws_token` HttpOnly cookie. This protects the React UI and the\n * `/api/*` control/read endpoints when `WS_HOST=0.0.0.0`.\n *\n * Extracted from `index.ts` so the static-serve concern can be tested\n * with a tiny fake `distDir` and asserted on path-traversal, MIME\n * matching, and CSP header presence.\n */\nimport * as fs from 'node:fs/promises';\nimport * as http from 'node:http';\nimport * as path from 'node:path';\nimport {\n handleApiFleetBroadcast,\n handleApiSessionAgents,\n handleApiSessionEvents,\n handleApiSessionInterrupt,\n handleApiSessionMailbox,\n handleApiSessionMessage,\n handleApiSessions,\n} from './http-server/api-handlers.js';\nimport { extractTokenFromCookie, isLoopbackBind, tokenMatches } from './ws-auth.js';\nimport type { FileWatcherMetrics } from './setup-events.js';\n\nexport interface CreateHttpServerOptions {\n /** Port to listen on. Defaults to 3456 (or the `PORT` env var). */\n port?: number | undefined;\n /** Host/interface to bind. Typically the loopback for the WebUI. */\n host: string;\n /** Resolved path to the directory containing the built React assets. */\n distDir: string;\n /**\n * WS port — appears in the CSP `connect-src` directive so the browser\n * is allowed to open a WebSocket back to the local server.\n */\n wsPort: number;\n /**\n * Public WebSocket URL injected into the frontend. Use this behind tunnels or\n * reverse proxies where the browser-facing WS URL differs from host:wsPort.\n */\n publicWsUrl?: string | undefined;\n /**\n * Path to the global WrongStack root (~/.wrongstack). Used by the\n * /api/sessions and /api/sessions/:id/agents endpoints to read the\n * cross-process SessionRegistry.\n */\n globalRoot?: string | undefined;\n /**\n * Shared auth token for HTTP and WS access. Required for non-loopback\n * binds (LAN exposure). Loopback binds accept local browser access without\n * a token (the WS path's loopback-bootstrap policy — see ws-auth.ts).\n */\n apiToken?: string | undefined;\n /** Force HTTP token auth even on loopback binds, useful behind public tunnels. */\n requireToken?: boolean | undefined;\n /**\n * If true, the `/ws-auth` endpoint exchanges a `?token=` query param (or\n * `X-WS-Token` header) for an `HttpOnly` auth cookie. The cookie is then\n * sent automatically on the WS upgrade, closing the C-598 query-string\n * token exposure class. Default: true. Set to false to keep the legacy\n * URL-token-only flow (e.g. in tests that don't want cookie state).\n */\n enableWsCookie?: boolean | undefined;\n /**\n * Optional file watcher metrics object. When provided, the\n * /debug/watcher-metrics endpoint will be enabled to expose these metrics.\n */\n watcherMetrics?: FileWatcherMetrics | undefined;\n /**\n * Push-on-write hook. `POST /api/fleet/ping` (loopback only) invokes this to\n * trigger an immediate fleet re-broadcast, so a TUI/REPL's registry write\n * reaches the map without waiting on the file-watch/poll. Best-effort.\n */\n onFleetPing?: (() => void) | undefined;\n}\n\nconst MIME_TYPES: Record<string, string> = {\n '.html': 'text/html',\n '.js': 'application/javascript',\n '.css': 'text/css',\n '.json': 'application/json',\n '.svg': 'image/svg+xml',\n '.png': 'image/png',\n '.ico': 'image/x-icon',\n};\n\n/**\n * Inject the live WS port into the served HTML so the frontend connects to\n * THIS instance's backend instead of a hardcoded default. Enables running\n * several WebUI instances simultaneously on different PORT/WS_PORT pairs\n * (e.g. one per project) — each instance serves HTML stamped with its own\n * WS port.\n *\n * A `<meta>` tag is used deliberately rather than an inline `<script>`: the\n * CSP sets `script-src 'self'`, which would block an inline script, but meta\n * tags are not subject to script-src. The frontend reads\n * `meta[name=\"wrongstack-ws-port\"]` (see ws-client.ts `defaultWsUrl`).\n */\nexport function injectWsPort(html: string, wsPort: number): string {\n const tag = `<meta name=\"wrongstack-ws-port\" content=\"${wsPort}\" />`;\n // Idempotent: never inject twice if the source HTML already carries one.\n if (html.includes('name=\"wrongstack-ws-port\"')) return html;\n if (html.includes('</head>')) {\n return html.replace('</head>', ` ${tag}\\n </head>`);\n }\n // No <head> (unexpected) — prepend so the tag is still in the document.\n return `${tag}\\n${html}`;\n}\n\nfunction escapeHtmlAttr(value: string): string {\n return value\n .replace(/&/g, '&amp;')\n .replace(/\"/g, '&quot;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;');\n}\n\nexport function injectWsConfig(\n html: string,\n opts: { wsPort: number; publicWsUrl?: string | undefined },\n): string {\n let out = injectWsPort(html, opts.wsPort);\n if (!opts.publicWsUrl || out.includes('name=\"wrongstack-ws-url\"')) return out;\n const tag = `<meta name=\"wrongstack-ws-url\" content=\"${escapeHtmlAttr(opts.publicWsUrl)}\" />`;\n if (out.includes('</head>')) {\n return out.replace('</head>', ` ${tag}\\n </head>`);\n }\n return `${tag}\\n${out}`;\n}\n\nfunction firstHeader(value: string | string[] | undefined): string | undefined {\n return Array.isArray(value) ? value[0] : value;\n}\n\nfunction wsTokenCookie(token: string): string {\n return `ws_token=${encodeURIComponent(token)}; HttpOnly; SameSite=Strict; Path=/; Max-Age=3600`;\n}\n\nfunction requestToken(req: http.IncomingMessage, url: URL): string | undefined {\n return (\n url.searchParams.get('token') ??\n firstHeader(req.headers['x-ws-token']) ??\n extractTokenFromCookie(req.headers.cookie)\n );\n}\n\nfunction requestHostForCsp(hostHeader: string | string[] | undefined): string | undefined {\n const raw = firstHeader(hostHeader)?.trim();\n if (!raw) return undefined;\n try {\n return new URL(`http://${raw}`).hostname;\n } catch {\n return undefined;\n }\n}\n\nfunction formatCspHostname(hostname: string): string {\n return hostname.includes(':') && !hostname.startsWith('[') ? `[${hostname}]` : hostname;\n}\n\nfunction cspSourceFromUrl(rawUrl: string): string | undefined {\n try {\n const url = new URL(rawUrl);\n if (url.protocol !== 'ws:' && url.protocol !== 'wss:') return undefined;\n return `${url.protocol}//${formatCspHostname(url.hostname)}${url.port ? `:${url.port}` : ''}`;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Inline-script hashes allow-listed in the production CSP.\n *\n * `script-src 'self'` blocks every inline `<script>`, including those Chrome\n * extensions inject as their content-script bootstrap (the browser reports\n * them from `content.js:74:196`). The hash list reported in the CSP violation\n * message is exactly the script bytes Chrome computed — adding those hashes\n * as `'sha256-…'` sources lets only those two extension bootstraps through\n * (and any future hash we add here), without re-enabling `'unsafe-inline'`\n * for the whole app. The WrongStack frontend itself ships no inline scripts,\n * so the policy stays strict for our own code.\n */\nconst ALLOWED_INLINE_SCRIPT_HASHES: readonly string[] = [\n \"'sha256-6PXDy0zrpXa6mvYOl11bZ8nubNUL7ushPUhGDZtaexg='\",\n \"'sha256-6sIdwbEBx7jj0drqSHHm7MqvmoYD3CQ4lp8Zp8blcb0='\",\n];\n\n/** Build the Content-Security-Policy value for the given WS port. */\nexport function buildCspHeader(\n wsPort: number,\n requestHost?: string | undefined,\n publicWsUrl?: string | undefined,\n): string {\n const connect = new Set([\n \"'self'\",\n `ws://127.0.0.1:${wsPort}`,\n `wss://127.0.0.1:${wsPort}`,\n ]);\n if (requestHost && requestHost !== '127.0.0.1') {\n const host = formatCspHostname(requestHost);\n connect.add(`ws://${host}:${wsPort}`);\n connect.add(`wss://${host}:${wsPort}`);\n }\n const publicWsSource = publicWsUrl ? cspSourceFromUrl(publicWsUrl) : undefined;\n if (publicWsSource) connect.add(publicWsSource);\n const scriptSrc = [\"'self'\", ...ALLOWED_INLINE_SCRIPT_HASHES].join(' ');\n return (\n `default-src 'self'; script-src ${scriptSrc}; style-src 'self' 'unsafe-inline'; ` +\n `connect-src ${Array.from(connect).join(' ')}; ` +\n `img-src 'self' data:; font-src 'self' data:; worker-src 'self' blob:; object-src 'none'; ` +\n `base-uri 'self'; frame-ancestors 'none'; form-action 'self'`\n );\n}\n\n/**\n * Returns true when `candidate` (a fully-resolved absolute path) lies\n * strictly inside `distDir` (or equals it). Used to reject path-traversal\n * attempts after `path.resolve` has normalised any `..` segments.\n *\n * Exported so tests can assert the guard's contract without having to\n * also defeat the WHATWG URL normaliser (which strips `..` from the\n * path string *before* the request even reaches the server, making a\n * black-box test via fetch impossible).\n */\nexport function isInsideDist(candidate: string, distDir: string): boolean {\n const root = path.resolve(distDir);\n const resolved = path.resolve(candidate);\n return resolved === root || resolved.startsWith(root + path.sep);\n}\n\n/**\n * Decode a `:id` path segment captured by the `/api/sessions/:id/*` routes.\n *\n * Session ids are `YYYY-MM-DD/HH-MM-SSZ_model_hash` — they contain a literal\n * `/`. The frontend builds the URL with `encodeURIComponent(sessionId)`, so\n * that slash arrives as `%2F`. The route regex `([^/]+)` correctly captures\n * the whole percent-encoded segment (there is no real `/` in `%2F`), but the\n * SessionRegistry is keyed by the *decoded* id — so the capture must be\n * `decodeURIComponent`d before lookup. Without this, every\n * `/api/sessions/:id/{events,message,agents}` request 404s (the registry has\n * `2026-…/…` but we looked up `2026-…%2F…`), which broke the Fleet HQ\n * watch-stream and the steer-message composer.\n *\n * Malformed percent-encoding (a lone `%`) makes `decodeURIComponent` throw;\n * fall back to the raw segment so the caller still gets a clean 404 rather\n * than a 500.\n */\nexport function decodeSessionId(segment: string): string {\n try {\n return decodeURIComponent(segment);\n } catch {\n return segment;\n }\n}\n\n/**\n * Create the static-file HTTP server. Returns the `http.Server` (not\n * listening yet) so the caller can attach to a `shutdown()` hook and\n * coordinate the listen() with the WebSocket bootstrap.\n */\nexport function createHttpServer(opts: CreateHttpServerOptions): http.Server {\n const port = opts.port ?? Number.parseInt(process.env['PORT'] ?? '3456', 10);\n const distDir = path.resolve(opts.distDir);\n const wsPort = opts.wsPort;\n // Loopback bind: no HTTP token required (mirrors WS loopback-bootstrap).\n // LAN bind: caller MUST supply a token; fail closed if it is absent.\n const requireAccessToken = Boolean(opts.requireToken) || !isLoopbackBind(opts.host);\n\n return http.createServer(async (req, res) => {\n try {\n const url = new URL(req.url ?? '/', `http://127.0.0.1:${port}`);\n const providedAccessToken = requestToken(req, url);\n const accessTokenOk =\n Boolean(opts.apiToken) && tokenMatches(providedAccessToken, opts.apiToken ?? '');\n const shouldSetAuthCookie =\n Boolean(opts.apiToken) &&\n tokenMatches(url.searchParams.get('token') ?? undefined, opts.apiToken ?? '');\n\n // ── API routes ──────────────────────────────────────────────────\n // /ws-auth — exchange a one-shot token (header or query) for an\n // HttpOnly cookie. The browser then sends the cookie on the WS\n // upgrade automatically, closing C-598 (token-in-URL). Disabled\n // when `enableWsCookie: false` (tests, or operators who prefer\n // the URL-token flow for explicit dev).\n if (url.pathname === '/ws-auth' && req.method === 'GET' && (opts.enableWsCookie ?? true)) {\n // Accept the token from `?token=` query (browser navigation\n // from the server-printed URL) OR the `X-WS-Token` header\n // (scripted client).\n const provided = requestToken(req, url);\n if (!provided || !opts.apiToken || !tokenMatches(provided, opts.apiToken)) {\n res.writeHead(401, { 'Content-Type': 'text/plain' });\n res.end('Unauthorized');\n return;\n }\n // HttpOnly + SameSite=Strict + Path=/ — the cookie is immune to\n // XSS exfiltration (no JS access), cross-origin Referer leakage\n // (Strict blocks cross-site), and is scoped to this origin only.\n // No `Secure` flag: the dev server is plain HTTP on loopback,\n // and a Secure cookie over HTTP would not be sent by the browser.\n res.writeHead(200, {\n 'Content-Type': 'text/plain',\n 'Set-Cookie': wsTokenCookie(opts.apiToken),\n // Belt-and-braces: tell any caches the cookie response itself\n // is sensitive.\n 'Cache-Control': 'no-store',\n });\n res.end('ok');\n return;\n }\n\n if (requireAccessToken && !accessTokenOk) {\n res.writeHead(401, {\n 'Content-Type': 'text/plain',\n 'Cache-Control': 'no-store',\n });\n res.end('Unauthorized');\n return;\n }\n\n if (shouldSetAuthCookie && opts.apiToken) {\n res.setHeader('Set-Cookie', wsTokenCookie(opts.apiToken));\n res.setHeader('Cache-Control', 'no-store');\n }\n\n // /api/fleet/ping — push-on-write nudge from a same-project TUI/REPL.\n // Triggers an immediate fleet re-broadcast of data the WS clients already\n // receive (no new disclosure, no persistent mutation). Same auth posture\n // as /api/sessions: open on loopback, token-gated on a LAN bind.\n if (url.pathname === '/api/fleet/ping' && req.method === 'POST') {\n if (requireAccessToken && !accessTokenOk) {\n res.writeHead(401, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Unauthorized' }));\n return;\n }\n try {\n opts.onFleetPing?.();\n } catch {\n /* best-effort */\n }\n res.writeHead(204);\n res.end();\n return;\n }\n\n if (url.pathname === '/api/sessions' && req.method === 'GET') {\n if (requireAccessToken && !accessTokenOk) {\n res.writeHead(401, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Unauthorized' }));\n return;\n }\n await handleApiSessions(res, opts.globalRoot);\n return;\n }\n\n const agentsMatch = url.pathname.match(/^\\/api\\/sessions\\/([^/]+)\\/agents$/);\n if (agentsMatch && req.method === 'GET') {\n if (requireAccessToken && !accessTokenOk) {\n res.writeHead(401, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Unauthorized' }));\n return;\n }\n await handleApiSessionAgents(res, opts.globalRoot, decodeSessionId(agentsMatch[1]!));\n return;\n }\n\n // /api/sessions/:id/events — replay another session's conversation +\n // tool stream (read-only) so the WebUI can *watch* a TUI/REPL running in\n // the same project. Reads that session's JSONL via the core session\n // reader; the browser re-fetches to tail it live.\n const eventsMatch = url.pathname.match(/^\\/api\\/sessions\\/([^/]+)\\/events$/);\n if (eventsMatch && req.method === 'GET') {\n if (requireAccessToken && !accessTokenOk) {\n res.writeHead(401, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Unauthorized' }));\n return;\n }\n const rawLimit = Number.parseInt(url.searchParams.get('limit') ?? '200', 10);\n const limit = Math.min(500, Math.max(1, Number.isFinite(rawLimit) ? rawLimit : 200));\n await handleApiSessionEvents(res, opts.globalRoot, decodeSessionId(eventsMatch[1]!), limit);\n return;\n }\n\n // /api/sessions/:id/message — send a steering message into another\n // session's mailbox. Its running agent injects pending mailbox messages\n // before each LLM call, so this is two-way control: the WebUI steers a\n // TUI/REPL working in the same project. Loopback-open, token-gated on LAN.\n const msgMatch = url.pathname.match(/^\\/api\\/sessions\\/([^/]+)\\/message$/);\n if (msgMatch && req.method === 'POST') {\n if (requireAccessToken && !accessTokenOk) {\n res.writeHead(401, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Unauthorized' }));\n return;\n }\n await handleApiSessionMessage(res, req, opts.globalRoot, decodeSessionId(msgMatch[1]!));\n return;\n }\n\n // /api/sessions/:id/mailbox — the human<->leader thread (read-receipts +\n // replies). Makes the two-way loop visible in Fleet HQ.\n const mailboxMatch = url.pathname.match(/^\\/api\\/sessions\\/([^/]+)\\/mailbox$/);\n if (mailboxMatch && req.method === 'GET') {\n if (requireAccessToken && !accessTokenOk) {\n res.writeHead(401, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Unauthorized' }));\n return;\n }\n await handleApiSessionMailbox(res, opts.globalRoot, decodeSessionId(mailboxMatch[1]!));\n return;\n }\n\n // /api/sessions/:id/interrupt — cooperative stop (control message).\n const interruptMatch = url.pathname.match(/^\\/api\\/sessions\\/([^/]+)\\/interrupt$/);\n if (interruptMatch && req.method === 'POST') {\n if (requireAccessToken && !accessTokenOk) {\n res.writeHead(401, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Unauthorized' }));\n return;\n }\n await handleApiSessionInterrupt(\n res,\n req,\n opts.globalRoot,\n decodeSessionId(interruptMatch[1]!),\n );\n return;\n }\n\n // /api/fleet/broadcast — one message to every live session's leader.\n if (url.pathname === '/api/fleet/broadcast' && req.method === 'POST') {\n if (requireAccessToken && !accessTokenOk) {\n res.writeHead(401, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Unauthorized' }));\n return;\n }\n await handleApiFleetBroadcast(res, req, opts.globalRoot);\n return;\n }\n\n // Debug endpoint: /debug/watcher-metrics\n // Returns file watcher metrics as JSON. Protected by the same HTTP access\n // token when the server is bound beyond loopback.\n if (url.pathname === '/debug/watcher-metrics' && req.method === 'GET') {\n if (opts.watcherMetrics) {\n // Update computed fields before returning\n const avgDelay = opts.watcherMetrics.broadcastsSent > 0\n ? opts.watcherMetrics.totalDebounceDelayMs / opts.watcherMetrics.broadcastsSent\n : 0;\n const response = {\n ...opts.watcherMetrics,\n averageDebounceDelayMs: avgDelay,\n timestamp: Date.now(),\n };\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify(response));\n } else {\n res.writeHead(503, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'File watcher metrics not available' }));\n }\n return;\n }\n\n let filePath: string;\n\n if (url.pathname === '/' || url.pathname === '') {\n filePath = path.join(distDir, 'index.html');\n } else if (url.pathname.startsWith('/assets/')) {\n filePath = path.join(distDir, url.pathname);\n } else if (url.pathname.startsWith('/')) {\n filePath = path.join(distDir, url.pathname);\n } else {\n filePath = path.join(distDir, 'index.html');\n }\n\n // Path traversal guard: the resolved path must stay inside distDir.\n // WHATWG URL leaves percent-encoding alone in `url.pathname` (it\n // does not decode `%2e%2e` to `..`), so percent-encoded escapes\n // are *not* a concern here — but unencoded `..` segments are\n // normalised by `path.resolve` and would walk the candidate up\n // out of distDir. `isInsideDist` catches that.\n const resolvedPath = path.resolve(filePath);\n if (!isInsideDist(resolvedPath, distDir)) {\n res.writeHead(403, { 'Content-Type': 'text/plain' });\n res.end('Forbidden');\n return;\n }\n\n const ext = path.extname(resolvedPath);\n const contentType = MIME_TYPES[ext] ?? 'application/octet-stream';\n res.setHeader('Content-Type', contentType);\n res.setHeader('X-Content-Type-Options', 'nosniff');\n res.setHeader('X-Frame-Options', 'DENY');\n res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');\n\n if (ext === '.html') {\n if (!shouldSetAuthCookie) res.setHeader('Cache-Control', 'no-cache');\n res.setHeader(\n 'Content-Security-Policy',\n buildCspHeader(wsPort, requestHostForCsp(req.headers.host), opts.publicWsUrl),\n );\n // Stamp the live WS port into the HTML so the frontend dials this\n // instance's backend (not the hardcoded default) — required for\n // running multiple WebUI instances on different ports.\n const html = await fs.readFile(resolvedPath, 'utf8');\n res.writeHead(200);\n res.end(injectWsConfig(html, { wsPort, publicWsUrl: opts.publicWsUrl }));\n return;\n }\n\n const fileContent = await fs.readFile(resolvedPath);\n res.writeHead(200);\n res.end(fileContent);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n // SPA fallback: serve index.html so client-side routing still works.\n try {\n const html = await fs.readFile(path.join(distDir, 'index.html'), 'utf8');\n res.writeHead(200, {\n 'Content-Type': 'text/html',\n 'X-Content-Type-Options': 'nosniff',\n 'X-Frame-Options': 'DENY',\n 'Referrer-Policy': 'strict-origin-when-cross-origin',\n 'Content-Security-Policy': buildCspHeader(\n wsPort,\n requestHostForCsp(req.headers.host),\n opts.publicWsUrl,\n ),\n });\n res.end(injectWsConfig(html, { wsPort, publicWsUrl: opts.publicWsUrl }));\n } catch {\n res.writeHead(404);\n res.end('Not found');\n }\n } else {\n res.writeHead(500);\n res.end('Server error');\n }\n }\n });\n}\n","/**\n * HTTP /api/* request handlers for the WebUI server — extracted from\n * http-server.ts to keep the static-serve/routing concern separate from the\n * (substantial) Fleet-HQ session/mailbox API. Every handler is a pure,\n * param-based function: it takes the Node req/res plus the globalRoot and reads\n * the cross-process SessionRegistry / GlobalMailbox via dynamic core imports.\n * createHttpServer() in http-server.ts dispatches to these.\n */\nimport type * as http from 'node:http';\n\nexport async function handleApiSessions(\n res: http.ServerResponse,\n globalRoot: string | undefined,\n): Promise<void> {\n if (!globalRoot) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'SessionRegistry not available' }));\n return;\n }\n\n try {\n const { SessionRegistry } = await import('@wrongstack/core');\n const registry = new SessionRegistry(globalRoot);\n const sessions = await registry.list();\n\n const result = sessions.map((s) => ({\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.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\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: String(err) }));\n }\n}\n\nexport async function handleApiSessionAgents(\n res: http.ServerResponse,\n globalRoot: string | undefined,\n sessionId: string,\n): Promise<void> {\n if (!globalRoot) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'SessionRegistry not available' }));\n return;\n }\n\n try {\n const { SessionRegistry } = await import('@wrongstack/core');\n const registry = new SessionRegistry(globalRoot);\n const entry = await registry.get(sessionId);\n\n if (!entry) {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Session not found' }));\n return;\n }\n\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({\n sessionId: entry.sessionId,\n projectName: entry.projectName,\n status: entry.status,\n agents: entry.agents.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 } catch (err) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: String(err) }));\n }\n}\n\n/** One line in the session \"watch\" stream sent to the browser.\n * Rich enough for the frontend to render full tool call details,\n * markdown, and structured data — not just pre-clipped text. */\ninterface WatchEntry {\n ts: string;\n role: 'user' | 'assistant' | 'tool' | 'system' | 'error';\n /** Human-readable text summary (may be clipped for tool input/output). */\n text: string;\n /** Tool name (for tool-role entries). */\n tool?: string;\n /** Structured tool input (object or array — rendered by ToolInputView). */\n input?: unknown;\n /** Structured tool output (rendered as pre-formatted text / markdown). */\n output?: unknown;\n /** Wall-clock duration in ms (tool call / response). */\n durationMs?: number;\n /** Whether the tool/response had an error. */\n isError?: boolean;\n /** Tool use correlation id — pairs tool_call_start with tool_call_end. */\n toolUseId?: string;\n}\n\n/** Join the text blocks of a message content value into a single string. */\nfunction blocksToText(content: unknown): string {\n if (typeof content === 'string') return content;\n if (Array.isArray(content)) {\n return content\n .filter(\n (b): b is { type: string; text: string } =>\n !!b && typeof b === 'object' && (b as { type?: unknown }).type === 'text' &&\n typeof (b as { text?: unknown }).text === 'string',\n )\n .map((b) => b.text)\n .join('\\n');\n }\n return '';\n}\n\nfunction asString(v: unknown): string {\n if (typeof v === 'string') return v;\n try {\n return JSON.stringify(v, null, 2);\n } catch {\n return String(v);\n }\n}\n\n/** Map a raw session event to a watch entry. Returns rich structured data\n * for tool calls (input + output + duration) so the frontend can render\n * full detail via WatchMessageBubble — matching the main ChatView. */\nfunction mapWatchEntry(ev: Record<string, unknown>): WatchEntry | null {\n const ts = typeof ev['ts'] === 'string' ? (ev['ts'] as string) : '';\n switch (ev['type']) {\n case 'user_input': {\n const text = blocksToText(ev['content']);\n return text.trim() ? { ts, role: 'user', text } : null;\n }\n case 'llm_response': {\n const text = blocksToText(ev['content']);\n return text.trim() ? { ts, role: 'assistant', text } : null;\n }\n case 'tool_use':\n case 'tool_call_start': {\n const toolName = String(ev['name'] ?? 'tool');\n const input = ev['input'] ?? ev['args'];\n const text = input !== undefined && input !== null ? asString(input) : '';\n const toolUseId = typeof ev['id'] === 'string' ? ev['id'] : undefined;\n return { ts, role: 'tool', tool: toolName, text, input, toolUseId };\n }\n case 'tool_call_end':\n case 'tool_result': {\n const isError = ev['isError'] === true;\n const content = ev['output'] ?? ev['content'];\n const outStr = content !== undefined && content !== null ? asString(content) : '';\n const durationMs = typeof ev['durationMs'] === 'number' ? ev['durationMs'] : undefined;\n const toolUseId = typeof ev['id'] === 'string' ? ev['id'] : undefined;\n const toolName = typeof ev['name'] === 'string' ? String(ev['name']) : '↳ result';\n if (!outStr.trim() && !isError) return null;\n return { ts, role: isError ? 'error' : 'tool', tool: toolName, text: outStr, output: content, durationMs, isError, toolUseId };\n }\n case 'error':\n case 'provider_error':\n return { ts, role: 'error', text: String(ev['message'] ?? 'error') };\n case 'agent_spawned':\n return { ts, role: 'system', text: `spawned ${String(ev['role'] ?? 'agent')}` };\n case 'task_completed':\n return { ts, role: 'system', text: `task done: ${String(ev['title'] ?? '')}` };\n case 'task_failed':\n return { ts, role: 'system', text: `task failed: ${String(ev['title'] ?? '')}` };\n default:\n return null;\n }\n}\n\n/** Correlate tool_call_start + tool_call_end events by id and merge them\n * into unified WatchEntry entries with full input+output+duration.\n * Standalone events (unpaired) pass through as-is. */\nfunction correlateToolEvents(entries: WatchEntry[]): WatchEntry[] {\n const pending = new Map<string, WatchEntry>(); // toolUseId → start entry\n const result: WatchEntry[] = [];\n for (const e of entries) {\n if (e.role === 'tool' && e.toolUseId && e.output === undefined && e.durationMs === undefined) {\n // This is a tool_call_start with no result yet — stash it\n pending.set(e.toolUseId, e);\n continue;\n }\n if (e.toolUseId && pending.has(e.toolUseId)) {\n const start = pending.get(e.toolUseId)!;\n pending.delete(e.toolUseId);\n // Merge: keep the start's ts, tool name, and input; add the end's output/duration/error\n result.push({\n ts: start.ts,\n role: e.isError ? 'error' : 'tool',\n text: e.text || start.text,\n tool: start.tool,\n input: start.input,\n output: e.output,\n durationMs: e.durationMs,\n isError: e.isError,\n toolUseId: e.toolUseId,\n });\n continue;\n }\n result.push(e);\n }\n // Unpaired start events: flush at the end\n for (const e of pending.values()) result.push(e);\n return result;\n}\n\nexport async function handleApiSessionEvents(\n res: http.ServerResponse,\n globalRoot: string | undefined,\n sessionId: string,\n limit: number,\n): Promise<void> {\n if (!globalRoot) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'SessionRegistry not available' }));\n return;\n }\n\n try {\n const { SessionRegistry, resolveWstackPaths, DefaultSessionStore, DefaultSessionReader } =\n await import('@wrongstack/core');\n const registry = new SessionRegistry(globalRoot);\n const entry = await registry.get(sessionId);\n if (!entry) {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Session not found' }));\n return;\n }\n\n const paths = resolveWstackPaths({ projectRoot: entry.projectRoot, globalRoot });\n const store = new DefaultSessionStore({ dir: paths.projectSessions });\n const reader = new DefaultSessionReader({ store });\n\n const rawEntries: WatchEntry[] = [];\n for await (const ev of reader.replay(sessionId)) {\n const mapped = mapWatchEntry(ev as never as Record<string, unknown>);\n if (mapped) rawEntries.push(mapped);\n }\n // Correlate paired tool call start+end events for rich combined rendering\n const all = correlateToolEvents(rawEntries);\n const tail = all.slice(-limit);\n\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n sessionId,\n status: entry.status,\n clientType: entry.clientType,\n projectName: entry.projectName,\n total: all.length,\n entries: tail,\n }),\n );\n } catch (err) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: String(err) }));\n }\n}\n\n/** Read and JSON-parse a request body, capped at 64 KiB. */\nfunction readJsonBody(req: http.IncomingMessage): Promise<Record<string, unknown>> {\n return new Promise((resolve, reject) => {\n let data = '';\n req.on('data', (chunk) => {\n data += chunk;\n if (data.length > 64_000) {\n reject(new Error('Request body too large'));\n req.destroy();\n }\n });\n req.on('end', () => {\n try {\n resolve(data ? (JSON.parse(data) as Record<string, unknown>) : {});\n } catch (err) {\n reject(err instanceof Error ? err : new Error(String(err)));\n }\n });\n req.on('error', reject);\n });\n}\n\nexport async function handleApiSessionMessage(\n res: http.ServerResponse,\n req: http.IncomingMessage,\n globalRoot: string | undefined,\n sessionId: string,\n): Promise<void> {\n if (!globalRoot) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'SessionRegistry not available' }));\n return;\n }\n\n let body: Record<string, unknown>;\n try {\n body = await readJsonBody(req);\n } catch {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Invalid request body' }));\n return;\n }\n\n const text = typeof body['text'] === 'string' ? (body['text'] as string).trim() : '';\n if (!text) {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'text is required' }));\n return;\n }\n const from =\n typeof body['from'] === 'string' && (body['from'] as string).trim()\n ? (body['from'] as string).trim()\n : 'human@webui';\n\n // Message kind from Fleet HQ's composer. The agent-loop injects every type\n // before its next LLM call; 'ask'/'assign' carry a stronger call-to-action\n // in the injected block (see buildMailboxBlock). Default 'steer'.\n const ALLOWED = new Set(['steer', 'ask', 'assign', 'note', 'btw']);\n const rawType = typeof body['type'] === 'string' ? (body['type'] as string) : 'steer';\n const type = (ALLOWED.has(rawType) ? rawType : 'steer') as\n | 'steer'\n | 'ask'\n | 'assign'\n | 'note'\n | 'btw';\n const rawPriority = typeof body['priority'] === 'string' ? (body['priority'] as string) : '';\n const priority = (['low', 'normal', 'high'].includes(rawPriority) ? rawPriority : 'high') as\n | 'low'\n | 'normal'\n | 'high';\n const subject =\n typeof body['subject'] === 'string' && (body['subject'] as string).trim()\n ? (body['subject'] as string).trim()\n : 'Message from Fleet HQ';\n\n try {\n const { SessionRegistry, resolveWstackPaths, GlobalMailbox, mailboxSessionTag } =\n await import('@wrongstack/core');\n const registry = new SessionRegistry(globalRoot);\n const entry = await registry.get(sessionId);\n if (!entry) {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Session not found' }));\n return;\n }\n\n const paths = resolveWstackPaths({ projectRoot: entry.projectRoot, globalRoot });\n const mailbox = new GlobalMailbox(paths.projectDir);\n // The target session's leader answers to `leader@<sessionTag>` — its\n // agent-loop checker queries exactly this address before each LLM call.\n const to = `leader@${mailboxSessionTag(sessionId)}`;\n const sent = await mailbox.send({ from, to, type, subject, body: text, priority });\n\n // Return the message id so the caller can poll the thread for read-receipt\n // (readBy) and the agent's reply — the visible two-way feedback loop.\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ ok: true, id: sent.id, to, type, delivered: entry.status }));\n } catch (err) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: String(err) }));\n }\n}\n\n/**\n * GET /api/sessions/:id/mailbox — the human↔leader thread for a session.\n *\n * Returns the messages exchanged between the operator (human@webui) and this\n * session's leader, newest last, with read-receipts (readBy) and completion/\n * outcome. This is what makes the WebUI's two-way loop *visible*: after Fleet\n * HQ sends a steer/ask, the panel shows whether the target read it (✓) and any\n * reply the agent posted back.\n */\nexport async function handleApiSessionMailbox(\n res: http.ServerResponse,\n globalRoot: string | undefined,\n sessionId: string,\n): Promise<void> {\n if (!globalRoot) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'SessionRegistry not available' }));\n return;\n }\n try {\n const { SessionRegistry, resolveWstackPaths, GlobalMailbox, mailboxSessionTag } =\n await import('@wrongstack/core');\n const registry = new SessionRegistry(globalRoot);\n const entry = await registry.get(sessionId);\n if (!entry) {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Session not found' }));\n return;\n }\n const paths = resolveWstackPaths({ projectRoot: entry.projectRoot, globalRoot });\n const mailbox = new GlobalMailbox(paths.projectDir);\n const leaderAddr = `leader@${mailboxSessionTag(sessionId)}`;\n // Messages TO the leader (operator → agent) and FROM the leader (replies).\n const [inbound, outbound] = await Promise.all([\n mailbox.query({ to: leaderAddr, limit: 50 }),\n mailbox.query({ from: leaderAddr, limit: 50 }),\n ]);\n const seen = new Set<string>();\n const thread = [...inbound, ...outbound]\n .filter((m) => {\n if (seen.has(m.id)) return false;\n seen.add(m.id);\n return true;\n })\n .sort((a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp))\n .map((m) => ({\n id: m.id,\n from: m.from,\n to: m.to,\n type: m.type,\n subject: m.subject,\n body: m.body,\n priority: m.priority,\n // Whether the leader has read it, and when.\n readByLeader: m.readBy?.[leaderAddr] ?? null,\n readByCount: Object.keys(m.readBy ?? {}).length,\n completed: m.completed,\n outcome: m.outcome ?? null,\n timestamp: m.timestamp,\n replyTo: m.replyTo ?? null,\n fromLeader: m.from === leaderAddr,\n }));\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ sessionId, leader: leaderAddr, status: entry.status, thread }));\n } catch (err) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: String(err) }));\n }\n}\n\n/**\n * POST /api/sessions/:id/interrupt — cooperatively halt a running session.\n *\n * Sends a high-priority `control` mailbox message. The target's agent-loop\n * checks the mailbox before each LLM call; on seeing a fresh control:interrupt\n * it stops gracefully at the next iteration boundary (it does NOT kill the\n * process — for a hard stop use the process panel's PID kill). Cross-process\n * interrupt is necessarily cooperative: the WebUI server can't reach another\n * process's AbortController, only its mailbox.\n */\nexport async function handleApiSessionInterrupt(\n res: http.ServerResponse,\n req: http.IncomingMessage,\n globalRoot: string | undefined,\n sessionId: string,\n): Promise<void> {\n if (!globalRoot) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'SessionRegistry not available' }));\n return;\n }\n let body: Record<string, unknown> = {};\n try {\n body = await readJsonBody(req);\n } catch {\n /* interrupt needs no body — ignore parse errors */\n }\n const reason =\n typeof body['reason'] === 'string' && (body['reason'] as string).trim()\n ? (body['reason'] as string).trim()\n : 'Operator requested stop from Fleet HQ';\n const from =\n typeof body['from'] === 'string' && (body['from'] as string).trim()\n ? (body['from'] as string).trim()\n : 'human@webui';\n try {\n const { SessionRegistry, resolveWstackPaths, GlobalMailbox, mailboxSessionTag } =\n await import('@wrongstack/core');\n const registry = new SessionRegistry(globalRoot);\n const entry = await registry.get(sessionId);\n if (!entry) {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Session not found' }));\n return;\n }\n const paths = resolveWstackPaths({ projectRoot: entry.projectRoot, globalRoot });\n const mailbox = new GlobalMailbox(paths.projectDir);\n const to = `leader@${mailboxSessionTag(sessionId)}`;\n const sent = await mailbox.send({\n from,\n to,\n type: 'control',\n subject: 'interrupt',\n body: reason,\n priority: 'high',\n });\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ ok: true, id: sent.id, to, delivered: entry.status }));\n } catch (err) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: String(err) }));\n }\n}\n\n/**\n * POST /api/fleet/broadcast — send one message to every live session's leader.\n *\n * Resolves all non-stale sessions in the same project as the WebUI host and\n * sends the message to each session's `leader@<tag>` (a true per-leader fan-out\n * rather than the bare '*' broadcast, so every live leader's mailbox loop —\n * which queries its session-bound id — actually receives it).\n */\nexport async function handleApiFleetBroadcast(\n res: http.ServerResponse,\n req: http.IncomingMessage,\n globalRoot: string | undefined,\n): Promise<void> {\n if (!globalRoot) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'SessionRegistry not available' }));\n return;\n }\n let body: Record<string, unknown>;\n try {\n body = await readJsonBody(req);\n } catch {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Invalid request body' }));\n return;\n }\n const text = typeof body['text'] === 'string' ? (body['text'] as string).trim() : '';\n if (!text) {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'text is required' }));\n return;\n }\n const from =\n typeof body['from'] === 'string' && (body['from'] as string).trim()\n ? (body['from'] as string).trim()\n : 'human@webui';\n try {\n const { SessionRegistry, resolveWstackPaths, GlobalMailbox, mailboxSessionTag } =\n await import('@wrongstack/core');\n const registry = new SessionRegistry(globalRoot);\n const all = await registry.list();\n // Scope to the WebUI host's own project (its pid's entry), like the live\n // status poll does. Fall back to every non-stale session if not found.\n const mySlug = all.find((s) => s.pid === process.pid)?.projectSlug;\n const targets = all\n .filter((s) => s.status !== 'stale')\n .filter((s) => (mySlug ? s.projectSlug === mySlug : true));\n if (targets.length === 0) {\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ ok: true, delivered: 0 }));\n return;\n }\n // Cache one mailbox per project dir (targets here share a slug).\n const mbByDir = new Map<string, InstanceType<typeof GlobalMailbox>>();\n const mailboxFor = (projectRoot: string): InstanceType<typeof GlobalMailbox> => {\n const dir = resolveWstackPaths({ projectRoot, globalRoot }).projectDir;\n let mb = mbByDir.get(dir);\n if (!mb) {\n mb = new GlobalMailbox(dir);\n mbByDir.set(dir, mb);\n }\n return mb;\n };\n let delivered = 0;\n await Promise.all(\n targets.map(async (s) => {\n try {\n const mb = mailboxFor(s.projectRoot);\n await mb.send({\n from,\n to: `leader@${mailboxSessionTag(s.sessionId)}`,\n type: 'steer',\n subject: 'Broadcast from Fleet HQ',\n body: text,\n priority: 'high',\n });\n delivered++;\n } catch {\n /* best-effort per target */\n }\n }),\n );\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ ok: true, delivered, targets: targets.length }));\n } catch (err) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: String(err) }));\n }\n}\n","/**\n * WebSocket connection authentication for the WebUI server.\n *\n * Three layered defenses, all enforced in {@link verifyClient}:\n * 1. **DNS-rebinding guard** ({@link hostHeaderOk}) — on a loopback bind the\n * `Host` header must itself be a loopback name, so a rebound attacker page\n * (`Host: evil.com`) is rejected even though its TCP peer is 127.0.0.1.\n * 2. **Shared-token auth** ({@link tokenMatches}, constant-time) — required for\n * any non-loopback origin and for non-browser clients reaching a publicly\n * bound socket. Tokens are accepted via `Cookie: ws_token=…` (preferred;\n * set by the `/ws-auth` HTTP endpoint with HttpOnly+SameSite=Strict) OR\n * `?token=…` URL query param (non-browser fallback).\n * 3. **Loopback bootstrap** — same-machine browser origins are allowed without\n * a token; the Host-header guard above already blocks cross-site pages.\n *\n * Browser clients (those that send an `Origin` header) authenticate via the\n * HttpOnly cookie by default — the URL `?token=` path is rejected for them,\n * closing the C-598 (Information Exposure Through Query String) class (token in\n * browser history / referrer / proxy logs). The only browser URL-token exception\n * is an explicit public-WS tunnel URL whose origin is allowlisted by the server;\n * that covers separate HTTP/WS hostnames where cookies cannot cross hosts.\n * Non-browser clients (no `Origin`: curl, scripts, tests) keep the URL-token\n * path for ergonomics — query-string exposure is a browser-only concern.\n *\n * Extracted from `index.ts` as pure functions so the auth contract can be unit\n * tested without standing up a real `http.Server`/`WebSocketServer`. `index.ts`\n * builds a thin closure that pulls the fields below off the incoming request.\n */\nimport { Buffer } from 'node:buffer';\nimport { timingSafeEqual } from 'node:crypto';\n\n/** A hostname that refers to the local machine. */\nexport function isLoopbackHostname(hostname: string): boolean {\n return (\n hostname === 'localhost' ||\n hostname === '127.0.0.1' ||\n hostname === '::1' ||\n hostname === '[::1]'\n );\n}\n\n/**\n * Check if an origin is a trusted loopback browser origin.\n * Defense-in-depth: when wsHost=0.0.0.0, only accept explicit localhost origins,\n * not arbitrary loopback hostnames that could be spoofed by local malware.\n */\nfunction isTrustedLoopbackOrigin(origin: string): boolean {\n try {\n const url = new URL(origin);\n // Only allow explicit loopback http(s) origins.\n // Reject file://, data://, and other schemes even on loopback.\n if (url.protocol !== 'http:' && url.protocol !== 'https:') return false;\n return (\n url.hostname === 'localhost' ||\n url.hostname === '127.0.0.1' ||\n url.hostname === '::1' ||\n url.hostname === '[::1]'\n );\n } catch {\n return false;\n }\n}\n\n/** True when the server is bound to a loopback interface (vs. LAN/0.0.0.0). */\nexport function isLoopbackBind(wsHost: string): boolean {\n return wsHost === '127.0.0.1' || wsHost === '::1' || wsHost === 'localhost';\n}\n\n/**\n * True when the server is bound to a wildcard address that exposes it on every\n * interface — IPv4 `0.0.0.0` OR IPv6 `::` (and its bracketed form). The\n * \"LAN exposure = deny\" guards below must treat both families identically; a\n * `::` bind is exactly as exposed as `0.0.0.0` and previously slipped past the\n * `wsHost === '0.0.0.0'` string check.\n */\nexport function isWildcardBind(wsHost: string): boolean {\n return wsHost === '0.0.0.0' || wsHost === '::' || wsHost === '[::]';\n}\n\nfunction normalizeHostname(hostname: string): string {\n const h = hostname.trim().toLowerCase();\n return h.startsWith('[') && h.endsWith(']') ? h.slice(1, -1) : h;\n}\n\nfunction allowedHostname(hostname: string, allowedHostnames?: readonly string[]): boolean {\n const normalized = normalizeHostname(hostname);\n return (allowedHostnames ?? []).some((candidate) => normalizeHostname(candidate) === normalized);\n}\n\n/**\n * Constant-time comparison of a provided token against the expected one.\n * A length mismatch short-circuits (lengths aren't secret); equal-length\n * inputs are compared with `timingSafeEqual` so the token can't be recovered\n * byte-by-byte via response timing.\n */\nexport function tokenMatches(provided: string | undefined, expected: string): boolean {\n if (!provided) return false;\n const a = Buffer.from(provided);\n const b = Buffer.from(expected);\n if (a.length !== b.length) return false;\n return timingSafeEqual(a, b);\n}\n\n/** Pull the `token` query param out of a request URL (`/?token=…`). */\nexport function extractToken(url: string): string | undefined {\n const match = url.match(/[?&]token=([^&]+)/);\n return match ? match[1] : undefined;\n}\n\n/**\n * Pull the `ws_token` value out of a Cookie header (`Cookie: ws_token=…`).\n * The WebUI's auth-token cookie is set via `Set-Cookie: ws_token=<token>;\n * HttpOnly; SameSite=Strict; Path=/` from the `/ws-auth` HTTP endpoint. The\n * browser then sends it back automatically on the WS upgrade request —\n * closing the C-598 (Information Exposure Through Query String) class\n * because the token never appears in the URL, browser history, or\n * reverse-proxy access logs.\n *\n * Returns `undefined` if the cookie header is absent or malformed.\n */\nexport function extractTokenFromCookie(cookieHeader: string | string[] | undefined): string | undefined {\n if (!cookieHeader) return undefined;\n const raw = Array.isArray(cookieHeader) ? cookieHeader.join('; ') : cookieHeader;\n for (const part of raw.split(';')) {\n const eq = part.indexOf('=');\n if (eq < 0) continue;\n const name = part.slice(0, eq).trim();\n if (name === 'ws_token') {\n // Cookie values are url-encoded in spec; decode for the constant-time\n // compare downstream. Trim trailing whitespace defensively.\n try {\n return decodeURIComponent(part.slice(eq + 1).trim());\n } catch {\n return part.slice(eq + 1).trim();\n }\n }\n }\n return undefined;\n}\n\n/**\n * DNS-rebinding defense. On a loopback bind, the `Host` header must resolve to\n * a loopback name. When the operator deliberately exposes the socket (wsHost is\n * a LAN/0.0.0.0 address) the Host is legitimately non-loopback, so the guard is\n * skipped and connection auth falls to the token check.\n */\nexport function hostHeaderOk(input: {\n hostHeader: string | undefined;\n wsHost: string;\n allowedHostnames?: readonly string[] | undefined;\n}): boolean {\n if (!isLoopbackBind(input.wsHost)) return true; // operator opted into wider exposure\n const hostHeader = (input.hostHeader ?? '').trim();\n if (!hostHeader) return false;\n // Strip the port (handle bare host, host:port, and [::1]:port).\n let hostname: string;\n try {\n hostname = new URL(`http://${hostHeader}`).hostname;\n } catch {\n return false;\n }\n return isLoopbackHostname(hostname) || allowedHostname(hostname, input.allowedHostnames);\n}\n\nexport interface VerifyClientInput {\n /** Browser `Origin` header, or undefined for non-browser clients. */\n origin?: string | undefined;\n /** Request URL (`req.url`) — carries the `?token=…` query param. */\n url: string;\n /** `Host` header (`req.headers.host`). */\n hostHeader?: string | undefined;\n /** Peer address (`req.socket.remoteAddress`). */\n remoteAddress?: string | undefined;\n /** `Cookie` header (`req.headers.cookie`). Carries `ws_token=…` when the\n * browser went through `/ws-auth` to set the HttpOnly auth cookie. */\n cookieHeader?: string | string[] | undefined;\n /** Host/interface the WS server is bound to. */\n wsHost: string;\n /** The server's generated auth token. */\n expectedToken: string;\n /** Force token auth even for loopback binds, useful behind public tunnels. */\n requireToken?: boolean | undefined;\n /** Extra Host header names allowed on loopback binds, e.g. a tunnel hostname. */\n allowedHostnames?: readonly string[] | undefined;\n /** Allow browser WS URL tokens for explicit public WS URLs where cookies cannot cross hostnames. */\n allowBrowserUrlToken?: boolean | undefined;\n}\n\n/**\n * Decide whether to accept an incoming WebSocket handshake. Pure mirror of the\n * closure previously inlined in `index.ts`; see the module doc for the layered\n * policy. Returns `true` to accept, `false` to reject.\n *\n * Token sources, in priority order:\n * 1. `Cookie: ws_token=…` (browser clients that went through `/ws-auth`)\n * 2. `?token=…` URL query param (non-browser clients: curl, scripts)\n *\n * Browser clients (with an `Origin` header) are restricted to the cookie path —\n * URL token is rejected for them, closing the C-598 query-string token\n * exposure class. Non-browser clients keep the URL-token fallback so curl\n * and tests continue to work.\n */\nexport function verifyClient(input: VerifyClientInput): boolean {\n const {\n origin,\n url,\n hostHeader,\n remoteAddress,\n cookieHeader,\n wsHost,\n expectedToken,\n requireToken,\n allowedHostnames,\n allowBrowserUrlToken,\n } = input;\n const urlTokenOk = tokenMatches(extractToken(url ?? ''), expectedToken);\n const cookieTokenOk = tokenMatches(extractTokenFromCookie(cookieHeader), expectedToken);\n\n // DNS-rebinding guard runs first on a loopback bind — independent of token\n // and Origin. Blocks a rebound attacker page (Host = attacker domain) even\n // though the TCP peer is 127.0.0.1.\n if (!hostHeaderOk({ hostHeader, wsHost, allowedHostnames })) return false;\n\n if (!origin) {\n // Non-browser clients (curl, scripts): require token unless on loopback.\n // The URL `?token=` path stays valid here for ergonomics (curl/tests have\n // no cookie jar) — query-string token exposure (C-598) is a *browser*\n // history/log concern, which non-browser clients don't have.\n // When wsHost=0.0.0.0 the server accepts connections from any network\n // interface — a non-loopback peer is denied outright.\n const remoteIp = remoteAddress ?? '';\n const isRemoteLoopback = remoteIp === '127.0.0.1' || remoteIp === '::1';\n if (!isRemoteLoopback && isWildcardBind(wsHost)) return false; // LAN exposure = deny\n return urlTokenOk || cookieTokenOk || (isLoopbackBind(wsHost) && !requireToken);\n }\n try {\n const { hostname: originHostname } = new URL(origin);\n // Loopback browser origins: allow without token only if the origin is\n // explicitly http://localhost or http://127.0.0.1 (defense-in-depth).\n // Reject file://, data://, and other schemes even on loopback.\n if (isLoopbackHostname(originHostname)) {\n if (requireToken || !isLoopbackBind(wsHost)) return cookieTokenOk;\n return isTrustedLoopbackOrigin(origin);\n }\n // Non-loopback browser origins normally authenticate via the HttpOnly cookie\n // set by `/ws-auth`. When an operator supplies a separate public WS URL, the\n // cookie may not cross hostnames, so an explicit opt-in keeps URL-token auth\n // available for that tunnel endpoint.\n return (\n cookieTokenOk ||\n (Boolean(allowBrowserUrlToken) &&\n urlTokenOk &&\n allowedHostname(originHostname, allowedHostnames))\n );\n } catch {\n return false;\n }\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { Context, IndexingConfig, Logger } from '@wrongstack/core';\nimport {\n cancelPendingReindexes,\n enqueueReindex,\n isIndexableFile,\n runStartupIndex,\n shutdownCodebaseIndexHost,\n} from '@wrongstack/tools';\n\nconst IGNORE_DIRS = new Set([\n 'node_modules',\n '.git',\n 'dist',\n 'build',\n '.next',\n 'coverage',\n '.turbo',\n '__snapshots__',\n '.nyc_output',\n]);\n\nexport interface WebUICodebaseIndexingDeps {\n config: { indexing?: IndexingConfig | undefined };\n context: Context;\n projectRoot: string;\n logger: Logger;\n}\n\nexport interface WebUICodebaseIndexing {\n onFileWritten(filePath: string): void;\n dispose(): void;\n}\n\nexport function setupWebUICodebaseIndexing(\n deps: WebUICodebaseIndexingDeps,\n): WebUICodebaseIndexing {\n const indexing = deps.config.indexing;\n if (!indexing) return noopIndexing();\n const idx: IndexingConfig = indexing;\n\n const indexDir = typeof deps.context.meta['codebaseIndexDir'] === 'string'\n ? deps.context.meta['codebaseIndexDir']\n : undefined;\n const debounceMs = idx.debounceMs ?? 400;\n const onError = (err: unknown) => {\n deps.logger.debug(\n `webui codebase auto-index failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n };\n\n if (idx.onSessionStart) {\n void runStartupIndex({\n projectRoot: deps.projectRoot,\n indexDir,\n signal: deps.context.signal,\n timeoutMs: idx.indexTimeoutMs,\n })\n .then((result) => {\n deps.logger.info(\n `webui codebase index ready: ${result.symbolsIndexed} symbols · ${result.filesIndexed} files · ${result.durationMs}ms`,\n );\n })\n .catch((err) => {\n deps.logger.warn(\n `webui codebase index (startup) failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n });\n }\n\n let watcher: fs.FSWatcher | undefined;\n if (idx.watchExternal) {\n try {\n watcher = fs.watch(deps.projectRoot, { recursive: true }, (_event, filename) => {\n if (!filename) return;\n const rel = filename.toString();\n if (isIgnored(rel)) return;\n const abs = path.resolve(deps.projectRoot, rel);\n enqueueFile(abs);\n });\n watcher.on('error', (err) => deps.logger.debug(`webui codebase index watcher error: ${err}`));\n watcher.unref?.();\n } catch (err) {\n deps.logger.debug(\n `webui codebase index watcher unavailable: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n function enqueueFile(filePath: string): void {\n if (!idx.onEdit && !idx.watchExternal) return;\n const abs = path.isAbsolute(filePath)\n ? path.normalize(filePath)\n : path.resolve(deps.projectRoot, filePath);\n if (!isInside(deps.projectRoot, abs) || !isIndexableFile(abs)) return;\n enqueueReindex({\n projectRoot: deps.projectRoot,\n files: [abs],\n indexDir,\n debounceMs,\n timeoutMs: idx.indexTimeoutMs,\n onError,\n });\n }\n\n return {\n onFileWritten(filePath) {\n if (idx.onEdit) enqueueFile(filePath);\n },\n dispose() {\n try {\n watcher?.close();\n } catch {\n /* ignore */\n }\n cancelPendingReindexes();\n shutdownCodebaseIndexHost();\n },\n };\n}\n\nfunction noopIndexing(): WebUICodebaseIndexing {\n return {\n onFileWritten() {},\n dispose() {},\n };\n}\n\nfunction isIgnored(rel: string): boolean {\n return rel.split(/[/\\\\]/).some((seg) => IGNORE_DIRS.has(seg));\n}\n\nfunction isInside(root: string, target: string): boolean {\n const normalizedRoot = path.resolve(root);\n const normalizedTarget = path.resolve(target);\n return normalizedTarget === normalizedRoot || normalizedTarget.startsWith(normalizedRoot + path.sep);\n}\n","/**\n * Shared file-operation WebSocket handlers for both the standalone WebUI\n * server and the CLI's `--webui` embedded server. Extracted from the\n * duplicated switch cases in `index.ts` and `cli/src/webui-server.ts`.\n *\n * Each function handles the full request→response cycle for one message\n * type. Callers drop them into their switch statement:\n *\n * case 'files.tree': return handleFilesTree(ws, msg, projectRoot);\n */\n\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { WebSocket } from 'ws';\nimport { atomicWrite } from '@wrongstack/core';\nimport { SKIP_DIRS, isHiddenEntry, rankFiles } from './file-picker.js';\nimport { isPathInside, resolveWorkingDirInsideProject } from './path-containment.js';\nimport { send, errMessage } from './ws-utils.js';\n\n/**\n * Resolve a user-supplied file path against `projectRoot` and verify the\n * canonical (real) path stays inside the canonical project root. This\n * rejects:\n * - lexical escapes (`../../etc/passwd`)\n * - in-project symlinks that point outside the project root\n * - absolute paths outside the project root\n *\n * The target file does not need to exist; we `realpath` the parent\n * directory and re-attach the basename. This matches the behavior of\n * `realpath(3)` once the file is later created.\n */\nasync function resolveFileInsideProject(\n projectRoot: string,\n filePath: string,\n): Promise<string> {\n // Lexical containment check first — cheap, and avoids calling realpath\n // on a path we already know is bogus. This also blocks `..` segments.\n const resolved = path.resolve(projectRoot, filePath);\n if (!isPathInside(projectRoot, resolved)) {\n throw new Error('Path outside project root');\n }\n\n // Canonical containment: walk the parent directory's real path and\n // re-attach the basename. If the parent doesn't exist yet, walk up\n // until we find an existing ancestor and verify the rest of the path\n // is still inside the real project root.\n const { parent, base } = splitParentAndBase(resolved);\n const realProjectRoot = await fs.realpath(projectRoot);\n const realParent = await realpathAllowMissing(parent);\n const realFull = path.join(realParent, base);\n if (!isPathInside(realProjectRoot, realFull)) {\n throw new Error('Path outside project root');\n }\n return realFull;\n}\n\nfunction splitParentAndBase(p: string): { parent: string; base: string } {\n const base = path.basename(p);\n const parent = path.dirname(p);\n return { parent, base };\n}\n\n/**\n * `realpath` that does not throw when the path doesn't exist. Walks up\n * until an existing ancestor is found, realpaths that ancestor, then\n * re-attaches the missing tail. This is what we need for write targets\n * that don't exist yet, and for read targets whose parent may have\n * been deleted between check and use.\n */\nasync function realpathAllowMissing(p: string): Promise<string> {\n // Existing path — normal realpath, canonicalizing any symlinks.\n try {\n return await fs.realpath(p);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n }\n // Walk up to the first existing ancestor, realpath that, and reattach.\n const segments: string[] = [];\n let cursor = p;\n while (true) {\n const parent = path.dirname(cursor);\n if (parent === cursor) {\n // Hit a filesystem root and still nothing exists. The lexical\n // check above already kept us inside projectRoot, so this should\n // be unreachable; bail out conservatively.\n throw new Error('Path outside project root');\n }\n segments.unshift(path.basename(cursor));\n try {\n const realParent = await fs.realpath(parent);\n return path.join(realParent, ...segments);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n cursor = parent;\n }\n }\n}\n\n// ── Type helpers (inlined, no dependence on types.ts) ──\n\ninterface FilesListPayload {\n query?: string | undefined;\n limit?: number | undefined;\n /** Optional directory root for the file list (relative to projectRoot).\n * When set, only files under this directory are returned. */\n path?: string | undefined;\n}\n\ninterface FilesReadPayload {\n filePath: string;\n}\n\ninterface FilesWritePayload {\n filePath: string;\n content: string;\n}\n\nexport interface FilesWriteOptions {\n onWritten?: ((filePath: string) => void | Promise<void>) | undefined;\n}\n\n// ── Shared handlers ───────────────────────────────────────────────────\n\n/**\n * Build and send a nested directory tree for the File Explorer.\n *\n * Walks `projectRoot` to depth 10 max, skipping heavyweight dirs\n * (node_modules, .git, dist, …) and dot-entries. Responds with\n * `{ type: 'files.tree', payload: { root, tree } }`.\n */\nexport async function handleFilesTree(\n ws: WebSocket,\n msg: unknown,\n projectRoot: string,\n): Promise<void> {\n interface TreeNode {\n name: string;\n path: string;\n type: 'file' | 'directory';\n children?: TreeNode[];\n }\n\n // Use the optional `path` from the message payload as the tree root.\n // When absent, empty, or \".\", fall back to projectRoot (backward compatible).\n const payload = (msg as { payload?: { path?: string | undefined } }).payload;\n const rawPath = payload?.path?.trim();\n\n // Guard: the requested tree root must be both lexically AND via\n // realpath() inside the project root. A symlinked subdirectory that\n // points outside the project would otherwise expose arbitrary\n // directory structure to a connected client.\n let treeRoot: string;\n let realProjectRoot: string;\n try {\n if (rawPath && rawPath !== '.') {\n treeRoot = await resolveWorkingDirInsideProject(projectRoot, rawPath);\n } else {\n treeRoot = projectRoot;\n }\n realProjectRoot = await fs.realpath(projectRoot);\n } catch {\n send(ws, {\n type: 'files.tree',\n payload: { root: projectRoot, tree: [], error: 'Path outside project root' },\n });\n return;\n }\n\n // Compute the path prefix so tree paths are always relative to\n // projectRoot (not treeRoot). This ensures double-clicking a file in\n // the explorer sends the correct path to files.read/files.write.\n const pathPrefix = treeRoot === projectRoot\n ? ''\n : (path.relative(projectRoot, treeRoot) + '/').replace(/\\\\/g, '/');\n\n async function buildTree(dir: string, rel: string, depth: number): Promise<TreeNode[]> {\n if (depth > 10) return [];\n let entries: import('node:fs').Dirent[] = [];\n try {\n entries = await fs.readdir(dir, { withFileTypes: true });\n } catch {\n return [];\n }\n entries.sort((a, b) => {\n if (a.isDirectory() !== b.isDirectory()) return a.isDirectory() ? -1 : 1;\n return a.name.localeCompare(b.name);\n });\n const nodes: TreeNode[] = [];\n for (const e of entries) {\n if (isHiddenEntry(e.name)) continue;\n const childRel = rel ? `${rel}/${e.name}` : e.name;\n const childAbs = path.join(dir, e.name);\n // Prepend the workingDir prefix so the path is projectRoot-relative\n const childPath = pathPrefix + childRel;\n if (e.isDirectory()) {\n if (SKIP_DIRS.has(e.name)) continue;\n // Reject symlinked directories whose real path escapes the\n // real project root. A symlink to an in-project directory is\n // fine and recursed into normally.\n let realChild: string;\n try {\n realChild = await fs.realpath(childAbs);\n } catch {\n continue;\n }\n if (!isPathInside(realProjectRoot, realChild)) {\n continue;\n }\n const children = await buildTree(realChild, childRel, depth + 1);\n nodes.push({ name: e.name, path: childPath, type: 'directory', children });\n } else if (e.isFile()) {\n nodes.push({ name: e.name, path: childPath, type: 'file' });\n }\n }\n return nodes;\n }\n\n try {\n const tree = await buildTree(treeRoot, '', 0);\n const rootLabel = treeRoot === projectRoot\n ? projectRoot\n : path.relative(projectRoot, treeRoot) || '.';\n send(ws, { type: 'files.tree', payload: { root: rootLabel, tree } });\n } catch (err) {\n const rootLabel = treeRoot === projectRoot\n ? projectRoot\n : path.relative(projectRoot, treeRoot) || '.';\n send(ws, {\n type: 'files.tree',\n payload: { root: rootLabel, tree: [], error: errMessage(err) },\n });\n }\n}\n\n/**\n * Read a file's content for the Monaco editor.\n *\n * Guards against path traversal (`../` escapes). Responds with\n * `{ type: 'files.read', payload: { filePath, content } }`.\n */\nexport async function handleFilesRead(\n ws: WebSocket,\n msg: unknown,\n projectRoot: string,\n): Promise<void> {\n const { filePath } = (msg as { payload: FilesReadPayload }).payload;\n\n // Path traversal guard: resolve and verify both lexically AND via\n // realpath() that the file stays inside the canonical project root.\n // A string-prefix check is not enough — an in-project symlink to\n // an external file would otherwise escape the project root.\n let realResolved: string;\n try {\n realResolved = await resolveFileInsideProject(projectRoot, filePath);\n } catch {\n send(ws, { type: 'files.read', payload: { filePath, content: '', error: 'Forbidden' } });\n return;\n }\n\n try {\n const content = await fs.readFile(realResolved, 'utf8');\n send(ws, { type: 'files.read', payload: { filePath, content } });\n } catch (err) {\n send(ws, {\n type: 'files.read',\n payload: { filePath, content: '', error: errMessage(err) },\n });\n }\n}\n\n/**\n * Write file content back to disk (atomic write via tmp + rename).\n *\n * Guards against path traversal. Responds with\n * `{ type: 'files.written', payload: { filePath, success } }`.\n */\nexport async function handleFilesWrite(\n ws: WebSocket,\n msg: unknown,\n projectRoot: string,\n opts: FilesWriteOptions = {},\n): Promise<void> {\n const { filePath, content } = (msg as { payload: FilesWritePayload }).payload;\n\n // Path traversal guard: resolve and verify both lexically AND via\n // realpath() that the parent directory stays inside the canonical\n // project root. A string-prefix check is not enough — an in-project\n // symlink to an external directory would let a write escape the\n // project root and clobber files elsewhere on disk.\n let realResolved: string;\n try {\n realResolved = await resolveFileInsideProject(projectRoot, filePath);\n } catch {\n send(ws, { type: 'files.written', payload: { filePath, success: false, error: 'Forbidden' } });\n return;\n }\n\n try {\n await atomicWrite(realResolved, content);\n send(ws, { type: 'files.written', payload: { filePath, success: true } });\n if (opts.onWritten) {\n void Promise.resolve(opts.onWritten(realResolved)).catch(() => undefined);\n }\n } catch (err) {\n send(ws, {\n type: 'files.written',\n payload: { filePath, success: false, error: errMessage(err) },\n });\n }\n}\n\n/**\n * Lightweight project file picker for the chat `@` mention popup.\n *\n * Walks `projectRoot` (max depth 8), skipping hidden and heavyweight\n * dirs, then fuzzy-ranks results against `query`. Responds with\n * `{ type: 'files.list', payload: { files } }`.\n */\nexport async function handleFilesList(\n ws: WebSocket,\n msg: unknown,\n projectRoot: string,\n): Promise<void> {\n const payload = (msg as { payload?: FilesListPayload }).payload ?? {};\n const limit = payload.limit ?? 50;\n\n // Guard: the requested list root must be both lexically AND via\n // realpath() inside the project root. A symlinked subdirectory that\n // points outside the project would otherwise expose arbitrary\n // filenames to a connected client.\n let listRoot: string;\n let realProjectRoot: string;\n try {\n if (payload.path) {\n listRoot = await resolveWorkingDirInsideProject(projectRoot, payload.path);\n } else {\n listRoot = projectRoot;\n }\n realProjectRoot = await fs.realpath(projectRoot);\n } catch {\n send(ws, { type: 'files.list', payload: { files: [] } });\n return;\n }\n\n const results: string[] = [];\n\n async function walk(dir: string, rel: string, depth: number): Promise<void> {\n if (depth > 8 || results.length >= 600) return;\n let entries: import('node:fs').Dirent[] = [];\n try {\n entries = await fs.readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const e of entries) {\n if (results.length >= 600) return;\n if (isHiddenEntry(e.name)) continue;\n const childRel = rel ? `${rel}/${e.name}` : e.name;\n if (e.isDirectory()) {\n if (SKIP_DIRS.has(e.name)) continue;\n // Reject symlinked directories whose real path escapes the\n // real project root. A symlink to an in-project directory is\n // fine and recursed into normally.\n let realChild: string;\n try {\n realChild = await fs.realpath(path.join(dir, e.name));\n } catch {\n continue;\n }\n if (!isPathInside(realProjectRoot, realChild)) {\n continue;\n }\n await walk(realChild, childRel, depth + 1);\n } else if (e.isFile()) {\n results.push(childRel);\n }\n }\n }\n\n await walk(listRoot, '', 0);\n send(ws, {\n type: 'files.list',\n payload: { files: rankFiles(results, payload.query ?? '', limit) },\n });\n}\n","/**\n * Pure filtering + ranking for the `files.list` project file picker (the chat\n * `@`-mention popup). The directory *walk* stays in index.ts (it's I/O), but\n * the two decisions that shape the result — which entries to hide and how to\n * rank matches — are pure and live here so the scoring weights, depth penalty,\n * and tie-break order can be unit tested. A silently-flipped weight would make\n * the picker feel subtly wrong with nothing to catch it.\n */\n/** Heavyweight build/vcs/dependency dirs the picker never descends into. */\nexport const SKIP_DIRS: ReadonlySet<string> = new Set([\n '.git',\n 'node_modules',\n 'dist',\n 'build',\n '.next',\n '.turbo',\n '.cache',\n 'target',\n 'coverage',\n '.nyc_output',\n 'out',\n '.pnpm-store',\n '.parcel-cache',\n]);\n\n/** Dotfiles/dirs kept despite the hide-dotfiles-by-default rule. */\nconst KEEP_DOTFILES: ReadonlySet<string> = new Set([\n '.wrongstack',\n '.env.example',\n '.gitignore',\n '.eslintrc',\n '.prettierrc',\n]);\n\n/**\n * Whether a directory entry should be hidden from the picker by its name.\n * Dotfiles are hidden by default, except a few commonly-wanted ones.\n */\nexport function isHiddenEntry(name: string): boolean {\n return name.startsWith('.') && !KEEP_DOTFILES.has(name);\n}\n\n/**\n * Rank `paths` against `query` and return up to `limit` paths, best first.\n *\n * Scoring (cheap heuristic, good enough for a picker): exact basename match\n * (100) > basename prefix (60) > path substring (20); non-matches are dropped.\n * Each match is penalized by its path depth so root files sort first. Ties\n * break by lexicographic path. An empty query keeps every path (score 0), so\n * the result is the paths sorted lexicographically, capped to `limit`.\n */\nexport function rankFiles(paths: readonly string[], query: string, limit: number): string[] {\n const q = query.toLowerCase();\n const scored: Array<{ path: string; score: number }> = [];\n for (const p of paths) {\n if (!q) {\n scored.push({ path: p, score: 0 });\n continue;\n }\n const lower = p.toLowerCase();\n const base = lower.split('/').pop() ?? lower;\n let score = 0;\n if (base === q) score = 100;\n else if (base.startsWith(q)) score = 60;\n else if (lower.includes(q)) score = 20;\n else continue;\n // Penalise depth so root files come first.\n score -= p.split('/').length;\n scored.push({ path: p, score });\n }\n scored.sort((a, b) => b.score - a.score || a.path.localeCompare(b.path));\n return scored.slice(0, limit).map((s) => s.path);\n}\n","import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\n\nexport function isPathInside(root: string, target: string): boolean {\n const relative = path.relative(root, target);\n return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));\n}\n\nexport async function resolveWorkingDirInsideProject(projectRoot: string, inputPath: string): Promise<string> {\n const resolved = path.resolve(projectRoot, inputPath);\n\n let stat;\n try {\n stat = await fs.stat(resolved);\n } catch {\n throw new Error(`Directory not found or not accessible: ${resolved}`);\n }\n if (!stat.isDirectory()) {\n throw new Error(`Directory not found or not accessible: ${resolved}`);\n }\n\n const [realProjectRoot, realResolved] = await Promise.all([\n fs.realpath(projectRoot),\n fs.realpath(resolved),\n ]);\n\n if (!isPathInside(realProjectRoot, realResolved)) {\n throw new Error(`Path must stay inside the project root: ${projectRoot}`);\n }\n\n return resolved;\n}\n","/**\n * Shared WebSocket utilities for both the standalone WebUI server and the\n * CLI's `--webui` embedded server. Extracted from the duplicated `send` /\n * `broadcast` / `sendResult` / `generateAuthToken` patterns that were\n * copy-pasted between `packages/webui/src/server/index.ts` and\n * `packages/cli/src/webui-server.ts`.\n */\nimport { randomBytes } from 'node:crypto';\n// Value import (not `import type`): we reference `WebSocket.OPEN` below, which\n// is a runtime value, not just a type.\nimport { WebSocket } from 'ws';\nimport type { ConnectedClient } from './types.js';\n\n/**\n * Send a JSON message to a single WebSocket client.\n * No-op when the socket is not in OPEN state (disconnected / closing).\n */\nexport function send(ws: WebSocket, msg: object): void {\n if (ws.readyState === WebSocket.OPEN) {\n ws.send(JSON.stringify(msg));\n }\n}\n\n/**\n * Broadcast a JSON message to every connected client.\n * Swallows per-socket send errors — a client that disconnected between the\n * readyState check and `ws.send()` is cleaned up by its own `close` handler.\n */\nexport function broadcast(\n clients: Map<WebSocket, ConnectedClient>,\n msg: object,\n): void {\n const data = JSON.stringify(msg);\n for (const [ws] of clients) {\n if (ws.readyState === WebSocket.OPEN) {\n try {\n ws.send(data);\n } catch {\n // Client disconnected between the readyState check and the send —\n // let the 'close' handler remove it from the map naturally.\n }\n }\n }\n}\n\n/**\n * Send a success/failure result message (used by key.* and provider.* handlers).\n * The frontend expects `key.operation_result` with `{ success, message }`.\n */\nexport function sendResult(ws: WebSocket, success: boolean, message: string): void {\n send(ws, { type: 'key.operation_result', payload: { success, message } });\n}\n\n/**\n * Extract a human-readable message from an unknown thrown value.\n */\nexport function errMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\n/**\n * Generate a cryptographically random WebSocket auth token (hex string).\n * Shared between standalone and CLI-embedded WebUI servers.\n */\nexport function generateAuthToken(): string {\n return randomBytes(16).toString('hex');\n}\n\nexport function resolveAuthToken(explicit?: string | undefined): string {\n const configured =\n explicit?.trim() ||\n process.env['WEBUI_TOKEN']?.trim() ||\n process.env['WEBUI_AUTH_TOKEN']?.trim();\n return configured || generateAuthToken();\n}\n\nexport function hostForBrowserUrl(bindHost: string): string {\n if (bindHost === '0.0.0.0') return '127.0.0.1';\n if (bindHost === '::' || bindHost === '[::]') return '[::1]';\n if (bindHost.includes(':') && !bindHost.startsWith('[')) return `[${bindHost}]`;\n return bindHost;\n}\n\nexport function buildWebUIAccessUrl(opts: {\n host: string;\n port: number;\n token?: string | undefined;\n protocol?: 'http' | 'https' | undefined;\n publicUrl?: string | undefined;\n}): string {\n const protocol = opts.protocol ?? 'http';\n const base = opts.publicUrl?.trim() || `${protocol}://${hostForBrowserUrl(opts.host)}:${opts.port}`;\n if (!opts.token) return base;\n try {\n const url = new URL(base);\n url.searchParams.set('token', opts.token);\n const rendered = url.toString();\n const afterOrigin = base.slice(url.origin.length);\n if (url.pathname === '/' && !afterOrigin.startsWith('/')) {\n return `${url.origin}${url.search}${url.hash}`;\n }\n return rendered;\n } catch {\n return `${base}${base.includes('?') ? '&' : '?'}token=${encodeURIComponent(opts.token)}`;\n }\n}\n\nexport function envFlag(name: string): boolean {\n const value = process.env[name]?.trim().toLowerCase();\n return value === '1' || value === 'true' || value === 'yes' || value === 'on';\n}\n","/**\n * Context-aware editor completion for the WebUI Monaco surface.\n *\n * The handler combines fast symbol-index hits with a short, JSON-only LLM call.\n * It is intentionally side-effect free: it never writes files and only reads the\n * existing codebase index when available.\n */\n\nimport * as path from 'node:path';\nimport type { WebSocket } from 'ws';\nimport type { Context, Provider, Request, Tool } from '@wrongstack/core';\nimport { searchCodebaseIndex, type SearchResult } from '@wrongstack/tools/codebase-index/index';\nimport { send, errMessage } from './ws-utils.js';\n\nexport type CompletionItemKind =\n | 'text'\n | 'method'\n | 'function'\n | 'constructor'\n | 'field'\n | 'variable'\n | 'class'\n | 'interface'\n | 'module'\n | 'property'\n | 'unit'\n | 'value'\n | 'enum'\n | 'keyword'\n | 'snippet'\n | 'file'\n | 'reference';\n\nexport interface CompletionSuggestion {\n label: string;\n insertText: string;\n kind?: CompletionItemKind | undefined;\n detail?: string | undefined;\n documentation?: string | undefined;\n sortText?: string | undefined;\n source?: 'llm' | 'index' | 'lsp' | undefined;\n}\n\ninterface CompletionRequestPayload {\n requestId: string;\n filePath: string;\n language: string;\n lineNumber: number;\n column: number;\n content?: string | undefined;\n prefix: string;\n suffix?: string | undefined;\n triggerCharacter?: string | undefined;\n triggerKind?: number | undefined;\n allowLlm?: boolean | undefined;\n}\n\nexport interface CompletionHandlerOptions {\n projectRoot: string;\n provider?: Provider | undefined;\n model?: string | undefined;\n indexDir?: string | undefined;\n lspCompletion?: LspCompletionSource | undefined;\n timeoutMs?: number | undefined;\n}\n\nexport interface LspCompletionSourceRequest {\n filePath: string;\n lineNumber: number;\n column: number;\n content?: string | undefined;\n triggerCharacter?: string | undefined;\n signal: AbortSignal;\n}\n\nexport type LspCompletionSource = (\n request: LspCompletionSourceRequest,\n) => Promise<CompletionSuggestion[]>;\n\nconst MAX_PREFIX_CHARS = 12_000;\nconst MAX_SUFFIX_CHARS = 4_000;\nconst MAX_CONTENT_CHARS = 500_000;\nconst INDEX_LIMIT = 8;\nconst LLM_LIMIT = 8;\nconst DEFAULT_TIMEOUT_MS = 4_500;\n\nconst COMPLETION_SYSTEM_PROMPT = [\n 'You are a code completion engine for an IDE.',\n 'Return only JSON. No markdown, prose, or code fences.',\n 'Suggest context-aware completions that fit the cursor location.',\n 'Prefer project-local names, repository conventions, and type-safe APIs.',\n 'Do not invent large code blocks; keep insertText small and directly insertable.',\n].join('\\n');\n\nconst COMPLETION_JSON_SCHEMA = {\n type: 'object',\n additionalProperties: false,\n properties: {\n items: {\n type: 'array',\n maxItems: LLM_LIMIT,\n items: {\n type: 'object',\n additionalProperties: false,\n properties: {\n label: { type: 'string' },\n insertText: { type: 'string' },\n kind: {\n type: 'string',\n enum: [\n 'text',\n 'method',\n 'function',\n 'constructor',\n 'field',\n 'variable',\n 'class',\n 'interface',\n 'module',\n 'property',\n 'unit',\n 'value',\n 'enum',\n 'keyword',\n 'snippet',\n 'file',\n 'reference',\n ],\n },\n detail: { type: 'string' },\n documentation: { type: 'string' },\n sortText: { type: 'string' },\n },\n required: ['label', 'insertText'],\n },\n },\n },\n required: ['items'],\n};\n\nexport async function handleCompletionRequest(\n ws: WebSocket,\n msg: unknown,\n opts: CompletionHandlerOptions,\n): Promise<void> {\n const parsed = parsePayload(msg);\n if (!parsed.ok) {\n send(ws, {\n type: 'completion.result',\n payload: {\n requestId: parsed.requestId ?? '',\n filePath: parsed.filePath ?? '',\n items: [],\n error: parsed.error,\n },\n });\n return;\n }\n\n const payload = parsed.payload;\n const projectRoot = path.resolve(opts.projectRoot);\n const resolved = path.resolve(projectRoot, payload.filePath);\n if (!isInside(projectRoot, resolved)) {\n send(ws, {\n type: 'completion.result',\n payload: {\n requestId: payload.requestId,\n filePath: payload.filePath,\n items: [],\n error: 'Forbidden',\n },\n });\n return;\n }\n\n const prefix = tail(payload.prefix, MAX_PREFIX_CHARS);\n const suffix = head(payload.suffix ?? '', MAX_SUFFIX_CHARS);\n const linePrefix = currentLinePrefix(prefix);\n const query = buildSearchQuery(linePrefix, payload.filePath);\n\n const [lspItems, indexItems] = await Promise.all([\n loadLspSuggestions(opts.lspCompletion, payload, resolved)\n .catch(() => [] as CompletionSuggestion[]),\n loadIndexSuggestions({\n projectRoot,\n indexDir: opts.indexDir,\n query,\n }).catch(() => [] as CompletionSuggestion[]),\n ]);\n\n const llmResult = shouldUseLlm(payload, linePrefix, query)\n ? await loadLlmSuggestions({\n provider: opts.provider,\n model: opts.model,\n payload,\n prefix,\n suffix,\n linePrefix,\n query,\n relatedSymbols: indexItems,\n timeoutMs: opts.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n }).catch((err) => ({ error: errMessage(err), items: [] as CompletionSuggestion[] }))\n : ([] as CompletionSuggestion[]);\n\n const llmItems = Array.isArray(llmResult) ? llmResult : llmResult.items;\n const error = Array.isArray(llmResult) ? undefined : llmResult.error;\n const items = mergeSuggestions([...lspItems, ...llmItems, ...indexItems]).slice(\n 0,\n LLM_LIMIT + INDEX_LIMIT,\n );\n\n send(ws, {\n type: 'completion.result',\n payload: {\n requestId: payload.requestId,\n filePath: payload.filePath,\n items,\n error: items.length === 0 ? error : undefined,\n },\n });\n}\n\nexport function createToolLspCompletionSource(\n tool: Tool | undefined,\n ctx: Context,\n): LspCompletionSource | undefined {\n if (!tool) return undefined;\n return async (request) => {\n const output = await tool.execute(\n {\n path: request.filePath,\n line: request.lineNumber,\n character: request.column,\n content: request.content,\n limit: 8,\n trigger_character: request.triggerCharacter,\n format: 'json',\n },\n ctx,\n { signal: request.signal },\n );\n return parseLspToolOutput(String(output));\n };\n}\n\nfunction parsePayload(msg: unknown):\n | { ok: true; payload: CompletionRequestPayload }\n | { ok: false; error: string; requestId?: string | undefined; filePath?: string | undefined } {\n const payload = (msg as { payload?: Partial<CompletionRequestPayload> | undefined }).payload;\n const requestId = typeof payload?.requestId === 'string' ? payload.requestId : undefined;\n const filePath = typeof payload?.filePath === 'string' ? payload.filePath : undefined;\n if (!payload || typeof payload !== 'object') {\n return { ok: false, error: 'Missing payload' };\n }\n if (!requestId) {\n return { ok: false, error: 'Missing requestId', filePath };\n }\n if (!filePath) {\n return { ok: false, error: 'Missing filePath', requestId };\n }\n if (typeof payload.language !== 'string') {\n return { ok: false, error: 'Missing language', requestId, filePath };\n }\n if (typeof payload.prefix !== 'string') {\n return { ok: false, error: 'Missing prefix', requestId, filePath };\n }\n if (!isValidPositionValue(payload.lineNumber) || !isValidPositionValue(payload.column)) {\n return { ok: false, error: 'Invalid cursor position', requestId, filePath };\n }\n const content = typeof payload.content === 'string' && payload.content.length <= MAX_CONTENT_CHARS\n ? payload.content\n : undefined;\n return {\n ok: true,\n payload: {\n requestId,\n filePath,\n language: payload.language,\n lineNumber: payload.lineNumber,\n column: payload.column,\n content,\n prefix: payload.prefix,\n suffix: typeof payload.suffix === 'string' ? payload.suffix : undefined,\n triggerCharacter: typeof payload.triggerCharacter === 'string'\n ? payload.triggerCharacter\n : undefined,\n triggerKind: typeof payload.triggerKind === 'number' ? payload.triggerKind : undefined,\n allowLlm: typeof payload.allowLlm === 'boolean' ? payload.allowLlm : undefined,\n },\n };\n}\n\nfunction shouldUseLlm(\n payload: CompletionRequestPayload,\n linePrefix: string,\n query: string,\n): boolean {\n if (payload.allowLlm !== undefined) return payload.allowLlm;\n if (payload.triggerCharacter === '.') return true;\n if (payload.triggerCharacter) return false;\n const token = linePrefix.match(/([A-Za-z_$][\\w$]*)$/)?.[1] ?? query;\n return /^(findBy|findAllBy|create|update|delete|remove|get[A-Z_]|set[A-Z_]|use[A-Z_])/.test(\n token,\n );\n}\n\nasync function loadIndexSuggestions(opts: {\n projectRoot: string;\n indexDir?: string | undefined;\n query: string;\n}): Promise<CompletionSuggestion[]> {\n const query = opts.query.trim();\n if (query.length < 2) return [];\n const result = await searchCodebaseIndex(\n {\n projectRoot: opts.projectRoot,\n indexDir: opts.indexDir,\n query,\n limit: INDEX_LIMIT,\n },\n { timeoutMs: 1_500 },\n );\n\n return result.results.map(indexResultToSuggestion);\n}\n\nasync function loadLspSuggestions(\n source: LspCompletionSource | undefined,\n payload: CompletionRequestPayload,\n resolvedFilePath: string,\n): Promise<CompletionSuggestion[]> {\n if (!source) return [];\n const timer = new AbortController();\n const to = setTimeout(() => timer.abort(new Error('lsp completion timeout')), 2_000);\n to.unref?.();\n try {\n return await source({\n filePath: resolvedFilePath,\n lineNumber: payload.lineNumber,\n column: payload.column,\n content: payload.content,\n triggerCharacter: payload.triggerCharacter,\n signal: timer.signal,\n });\n } finally {\n timer.abort();\n clearTimeout(to);\n }\n}\n\nasync function loadLlmSuggestions(opts: {\n provider?: Provider | undefined;\n model?: string | undefined;\n payload: CompletionRequestPayload;\n prefix: string;\n suffix: string;\n linePrefix: string;\n query: string;\n relatedSymbols: CompletionSuggestion[];\n timeoutMs: number;\n}): Promise<CompletionSuggestion[]> {\n if (!opts.provider || !opts.model) return [];\n\n const req: Request = {\n model: opts.model,\n system: [{ type: 'text', text: COMPLETION_SYSTEM_PROMPT }],\n messages: [\n {\n role: 'user',\n content: buildCompletionPrompt(opts),\n },\n ],\n maxTokens: 700,\n };\n\n if (opts.provider.capabilities.structuredOutput) {\n req.responseFormat = {\n type: 'json_schema',\n jsonSchema: {\n name: 'code_completion_suggestions',\n strict: false,\n schema: COMPLETION_JSON_SCHEMA,\n },\n };\n } else if (opts.provider.capabilities.jsonMode) {\n req.responseFormat = { type: 'json_object' };\n }\n\n const timer = new AbortController();\n const to = setTimeout(() => timer.abort(new Error('completion timeout')), opts.timeoutMs);\n to.unref?.();\n try {\n const res = await opts.provider.complete(req, { signal: timer.signal });\n const text = res.content\n .filter((block) => block.type === 'text')\n .map((block) => block.text)\n .join('\\n')\n .trim();\n return parseCompletionJson(text).slice(0, LLM_LIMIT);\n } finally {\n timer.abort();\n clearTimeout(to);\n }\n}\n\nfunction buildCompletionPrompt(opts: {\n payload: CompletionRequestPayload;\n prefix: string;\n suffix: string;\n linePrefix: string;\n query: string;\n relatedSymbols: CompletionSuggestion[];\n}): string {\n const related = opts.relatedSymbols.length > 0\n ? opts.relatedSymbols\n .slice(0, INDEX_LIMIT)\n .map((item) => `- ${item.label}: ${item.detail ?? item.documentation ?? item.kind ?? 'symbol'}`)\n .join('\\n')\n : '(none)';\n\n return [\n `File: ${opts.payload.filePath}`,\n `Language: ${opts.payload.language}`,\n `Cursor: line ${opts.payload.lineNumber}, column ${opts.payload.column}`,\n `Trigger: ${opts.payload.triggerCharacter ?? 'manual'}`,\n `Current line prefix: ${opts.linePrefix}`,\n `Search/query hint: ${opts.query}`,\n '',\n 'Relevant project symbols from the codebase index:',\n related,\n '',\n 'Return JSON shaped exactly as:',\n '{\"items\":[{\"label\":\"name\",\"insertText\":\"text\",\"kind\":\"function\",\"detail\":\"short optional detail\",\"documentation\":\"short optional docs\",\"sortText\":\"optional\"}]}',\n '',\n '<prefix>',\n opts.prefix,\n '</prefix>',\n '<suffix>',\n opts.suffix,\n '</suffix>',\n ].join('\\n');\n}\n\nfunction parseCompletionJson(text: string): CompletionSuggestion[] {\n const parsed = JSON.parse(extractJson(text)) as { items?: unknown };\n if (!Array.isArray(parsed.items)) return [];\n return parsed.items\n .map(normalizeSuggestion)\n .filter((item): item is CompletionSuggestion => item !== null);\n}\n\nfunction normalizeSuggestion(value: unknown): CompletionSuggestion | null {\n if (!value || typeof value !== 'object') return null;\n const raw = value as Record<string, unknown>;\n const label = typeof raw.label === 'string' ? raw.label.trim() : '';\n const insertText = typeof raw.insertText === 'string' ? raw.insertText : '';\n if (!label || !insertText) return null;\n return {\n label,\n insertText,\n kind: normalizeKind(raw.kind),\n detail: optionalString(raw.detail),\n documentation: optionalString(raw.documentation),\n sortText: optionalString(raw.sortText),\n source: 'llm',\n };\n}\n\nfunction indexResultToSuggestion(result: SearchResult): CompletionSuggestion {\n return {\n label: result.name,\n insertText: result.name,\n kind: mapIndexKind(result.kind),\n detail: result.signature || `${result.kind} ${relativeDisplayPath(result.file, result.line)}`,\n documentation: result.docComment || result.snippet || undefined,\n sortText: `z-${String(Math.round(10_000 - result.score)).padStart(5, '0')}-${result.name}`,\n source: 'index',\n };\n}\n\nfunction parseLspToolOutput(output: string): CompletionSuggestion[] {\n if (!output || output.startsWith('No completions') || output.startsWith('[LSP_')) return [];\n const jsonItems = parseLspToolJson(output);\n if (jsonItems) return jsonItems;\n return output\n .split(/\\r?\\n/)\n .map((line) => line.match(/^\\d+\\.\\s+(.+?)\\s+\\[([^\\]]+)](?:\\s+—\\s+(.+))?$/))\n .filter((match): match is RegExpMatchArray => match !== null)\n .map((match, index): CompletionSuggestion => {\n const label = match[1]?.trim() ?? '';\n const detail = match[3]?.trim();\n return {\n label,\n insertText: label,\n kind: mapLspKindName(match[2]),\n detail: detail || undefined,\n sortText: `a-${String(index).padStart(3, '0')}-${label}`,\n source: 'lsp',\n };\n })\n .filter((item) => item.label);\n}\n\nfunction parseLspToolJson(output: string): CompletionSuggestion[] | null {\n try {\n const parsed = JSON.parse(output) as { items?: unknown };\n if (!Array.isArray(parsed.items)) return [];\n return parsed.items\n .map((value, index): CompletionSuggestion | null => {\n if (!value || typeof value !== 'object') return null;\n const raw = value as Record<string, unknown>;\n const label = typeof raw.label === 'string' ? raw.label.trim() : '';\n const insertText = typeof raw.insertText === 'string' && raw.insertText\n ? raw.insertText\n : label;\n if (!label || !insertText) return null;\n return {\n label,\n insertText,\n kind: mapLspKindName(typeof raw.kind === 'string' ? raw.kind : undefined),\n detail: optionalString(raw.detail),\n documentation: optionalString(raw.documentation),\n sortText: `a-${String(index).padStart(3, '0')}-${label}`,\n source: 'lsp',\n };\n })\n .filter((item): item is CompletionSuggestion => item !== null);\n } catch {\n return null;\n }\n}\n\nfunction mapLspKindName(kind: string | undefined): CompletionItemKind {\n switch (kind?.toLowerCase()) {\n case 'method':\n return 'method';\n case 'function':\n return 'function';\n case 'constructor':\n return 'constructor';\n case 'field':\n return 'field';\n case 'variable':\n case 'constant':\n return 'variable';\n case 'class':\n case 'struct':\n return 'class';\n case 'interface':\n case 'typeparameter':\n return 'interface';\n case 'module':\n return 'module';\n case 'property':\n return 'property';\n case 'unit':\n return 'unit';\n case 'value':\n case 'enummember':\n return 'value';\n case 'enum':\n return 'enum';\n case 'keyword':\n return 'keyword';\n case 'snippet':\n return 'snippet';\n case 'file':\n return 'file';\n case 'reference':\n return 'reference';\n default:\n return 'text';\n }\n}\n\nfunction mapIndexKind(kind: SearchResult['kind']): CompletionItemKind {\n switch (kind) {\n case 'class':\n case 'struct':\n return 'class';\n case 'interface':\n case 'trait':\n case 'type':\n return 'interface';\n case 'enum':\n return 'enum';\n case 'function':\n return 'function';\n case 'method':\n return 'method';\n case 'property':\n case 'parameter':\n return 'property';\n case 'var':\n case 'let':\n case 'const':\n case 'static':\n return 'variable';\n case 'namespace':\n case 'mod':\n return 'module';\n default:\n return 'reference';\n }\n}\n\nfunction normalizeKind(value: unknown): CompletionItemKind | undefined {\n if (typeof value !== 'string') return undefined;\n const allowed: CompletionItemKind[] = [\n 'text',\n 'method',\n 'function',\n 'constructor',\n 'field',\n 'variable',\n 'class',\n 'interface',\n 'module',\n 'property',\n 'unit',\n 'value',\n 'enum',\n 'keyword',\n 'snippet',\n 'file',\n 'reference',\n ];\n return allowed.includes(value as CompletionItemKind)\n ? value as CompletionItemKind\n : undefined;\n}\n\nfunction mergeSuggestions(items: CompletionSuggestion[]): CompletionSuggestion[] {\n const seen = new Set<string>();\n const merged: CompletionSuggestion[] = [];\n for (const item of items) {\n const key = `${item.label}\\0${item.insertText}`;\n if (seen.has(key)) continue;\n seen.add(key);\n merged.push(item);\n }\n return merged;\n}\n\nfunction buildSearchQuery(linePrefix: string, filePath: string): string {\n const memberMatch = linePrefix.match(/([A-Za-z_$][\\w$]*)\\.\\s*([A-Za-z_$][\\w$]*)?$/);\n if (memberMatch?.[2]) return memberMatch[2];\n if (memberMatch?.[1]) return memberMatch[1];\n const token = linePrefix.match(/([A-Za-z_$][\\w$]*)$/)?.[1];\n if (token && token.length >= 2) return token;\n return path.basename(filePath, path.extname(filePath));\n}\n\nfunction currentLinePrefix(prefix: string): string {\n const idx = Math.max(prefix.lastIndexOf('\\n'), prefix.lastIndexOf('\\r'));\n return idx === -1 ? prefix : prefix.slice(idx + 1);\n}\n\nfunction extractJson(text: string): string {\n const trimmed = text.trim();\n if (trimmed.startsWith('{')) return trimmed;\n const start = trimmed.indexOf('{');\n const end = trimmed.lastIndexOf('}');\n if (start !== -1 && end > start) return trimmed.slice(start, end + 1);\n return trimmed;\n}\n\nfunction optionalString(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim() ? value.trim() : undefined;\n}\n\nfunction isValidPositionValue(value: unknown): value is number {\n return typeof value === 'number' && Number.isInteger(value) && value >= 1;\n}\n\nfunction relativeDisplayPath(file: string, line: number): string {\n return `${file.replace(/\\\\/g, '/')}:${line}`;\n}\n\nfunction tail(value: string, max: number): string {\n return value.length <= max ? value : value.slice(value.length - max);\n}\n\nfunction head(value: string, max: number): string {\n return value.length <= max ? value : value.slice(0, max);\n}\n\nfunction isInside(root: string, target: string): boolean {\n return target === root || target.startsWith(root + path.sep);\n}\n","/**\n * Shared memory-operation WebSocket handlers for both the standalone WebUI\n * server and the CLI's `--webui` embedded server. Extracted from the\n * duplicated switch cases in `index.ts` and `cli/src/webui-server.ts`.\n *\n * Each function handles the full request→response cycle for one message\n * type. Callers drop them into their switch statement:\n *\n * case 'memory.list': return handleMemoryList(ws, memoryStore);\n */\n\nimport type { WebSocket } from 'ws';\nimport type { MemoryStore } from '@wrongstack/core';\nimport { send, sendResult, errMessage } from './ws-utils.js';\n\n// ── Shared handlers ───────────────────────────────────────────────────\n\n/**\n * List all memory entries across all scopes.\n * Responds with `{ type: 'memory.list', payload: { text } }`.\n */\nexport async function handleMemoryList(\n ws: WebSocket,\n memoryStore: MemoryStore,\n): Promise<void> {\n try {\n const text = await memoryStore.readAll();\n send(ws, { type: 'memory.list', payload: { text } });\n } catch (err) {\n send(ws, {\n type: 'memory.list',\n payload: { text: '', error: errMessage(err) },\n });\n }\n}\n\n/**\n * Persist a new memory entry.\n * Responds with `{ type: 'key.operation_result', payload: { success, message } }`.\n */\nexport async function handleMemoryRemember(\n ws: WebSocket,\n msg: unknown,\n memoryStore: MemoryStore,\n): Promise<void> {\n const { text, scope } = (\n msg as {\n payload: {\n text: string;\n scope?: 'project-agents' | 'project-memory' | 'user-memory' | undefined;\n };\n }\n ).payload;\n try {\n await memoryStore.remember(text, scope ?? 'project-memory');\n sendResult(ws, true, 'Saved to memory');\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n}\n\n/**\n * Remove memory entries matching the given text.\n * Responds with `{ type: 'key.operation_result', payload: { success, message } }`.\n */\nexport async function handleMemoryForget(\n ws: WebSocket,\n msg: unknown,\n memoryStore: MemoryStore,\n): Promise<void> {\n const { text, scope } = (\n msg as {\n payload: {\n text: string;\n scope?: 'project-agents' | 'project-memory' | 'user-memory' | undefined;\n };\n }\n ).payload;\n try {\n const removed = await memoryStore.forget(text, scope ?? 'project-memory');\n sendResult(\n ws,\n removed > 0,\n removed > 0\n ? `Removed ${removed} entr${removed === 1 ? 'y' : 'ies'}`\n : 'No matching entries',\n );\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n}\n","/**\n * MCP management handlers for the WebUI server (both the standalone\n * `wstackui` server and the CLI's embedded `--webui` server).\n *\n * These are thin WebSocket translators over the shared, surface-agnostic\n * management core in `@wrongstack/mcp` (`manage.ts`) — the SAME core the REPL\n * `/mcp` command writes against (same config.json, same MCPRegistry). All the\n * config IO, url/header persistence, and live registry start/stop logic lives\n * there; here we only map structured results to WS events the browser expects.\n */\n\nimport { allServers } from '@wrongstack/core';\nimport {\n addMcp,\n disableMcp,\n discoverMcp,\n enableMcp,\n listMcp,\n type MCPRegistry,\n type McpManageDeps,\n type McpServerInfo,\n type McpServerInput,\n removeMcp,\n restartMcp,\n updateMcp,\n} from '@wrongstack/mcp';\nimport type { WebSocket } from 'ws';\nimport type { WSClientMessage } from './types.js';\nimport { send } from './ws-utils.js';\n\n/** Wire view of a server as the browser MCP panel consumes it. */\nexport interface MCPServerView {\n name: string;\n transport: string;\n status: 'stopped' | 'connecting' | 'connected' | 'sleeping' | 'discovering' | 'error';\n enabled: boolean;\n description?: string;\n tools?: string[];\n error?: string;\n pid?: number;\n lazy?: boolean;\n}\n\n/** Map a raw registry state to the UI status union. */\nfunction mapStatus(raw: string): MCPServerView['status'] {\n switch (raw) {\n case 'connected':\n return 'connected';\n case 'connecting':\n case 'reconnecting':\n return 'connecting';\n case 'failed':\n return 'error';\n case 'dormant':\n // Lazy server registered from cache, process not spawned — show as sleeping.\n return 'sleeping';\n default:\n // idle / disconnected / stopped\n return 'stopped';\n }\n}\n\n/** Project the shared {@link McpServerInfo} into the browser wire shape. */\nfunction toView(info: McpServerInfo): MCPServerView {\n const view: MCPServerView = {\n name: info.name,\n transport: info.transport,\n // A dormant lazy server is \"asleep\", not stopped — preserve that even when\n // it's enabled in config.\n status: info.status === 'dormant' ? 'sleeping' : info.enabled === false ? 'stopped' : mapStatus(info.status),\n enabled: info.enabled,\n tools: info.tools,\n };\n if (info.description !== undefined) view.description = info.description;\n if (info.lazy !== undefined) view.lazy = info.lazy;\n return view;\n}\n\n/**\n * Build the shared management deps. Returns null (and sends a failure result)\n * when the live registry isn't wired — both WebUI servers now pass one, so this\n * is a defensive guard rather than the normal path.\n */\nfunction deps(\n ws: WebSocket,\n globalConfigPath: string | undefined,\n registry: MCPRegistry | undefined,\n): McpManageDeps | null {\n if (!registry || !globalConfigPath) {\n send(ws, {\n type: 'mcp.operation_result',\n payload: { success: false, message: 'MCP registry is not available in this session.' },\n });\n return null;\n }\n return { configPath: globalConfigPath, registry, presets: allServers() };\n}\n\nfunction name(msg: WSClientMessage): string {\n return (msg.payload as { name?: string } | undefined)?.name ?? '';\n}\n\n/** mcp.list — configured servers merged with live registry status + tools. */\nexport async function handleMcpList(\n ws: WebSocket,\n _msg: WSClientMessage,\n globalConfigPath: string,\n mcpRegistry?: MCPRegistry,\n): Promise<void> {\n if (!mcpRegistry || !globalConfigPath) {\n send(ws, { type: 'mcp.list', payload: { servers: [] } });\n return;\n }\n const servers = await listMcp({\n configPath: globalConfigPath,\n registry: mcpRegistry,\n presets: allServers(),\n });\n send(ws, { type: 'mcp.list', payload: { servers: servers.map(toView) } });\n}\n\n/** mcp.add — persist a new server (incl. url/headers) and start it if enabled. */\nexport async function handleMcpAdd(\n ws: WebSocket,\n msg: WSClientMessage,\n globalConfigPath: string,\n mcpRegistry?: MCPRegistry,\n): Promise<void> {\n const d = deps(ws, globalConfigPath, mcpRegistry);\n if (!d) return;\n const result = await addMcp(msg.payload as McpServerInput, d);\n if (result.ok && result.server) {\n send(ws, { type: 'mcp.server.added', payload: { server: toView(result.server) } });\n if (result.registryError) {\n send(ws, {\n type: 'mcp.server.error',\n payload: { name: result.server.name, error: result.registryError },\n });\n } else if (result.server.enabled) {\n send(ws, { type: 'mcp.server.connected', payload: { name: result.server.name } });\n }\n }\n send(ws, {\n type: 'mcp.operation_result',\n payload: { success: result.ok, message: result.message },\n });\n}\n\n/** mcp.update — re-persist config (incl. url/headers) and re-apply to registry. */\nexport async function handleMcpUpdate(\n ws: WebSocket,\n msg: WSClientMessage,\n globalConfigPath: string,\n mcpRegistry?: MCPRegistry,\n): Promise<void> {\n const d = deps(ws, globalConfigPath, mcpRegistry);\n if (!d) return;\n const result = await updateMcp(msg.payload as McpServerInput, d);\n if (result.ok && result.server) {\n send(ws, { type: 'mcp.server.updated', payload: { server: toView(result.server) } });\n }\n send(ws, {\n type: 'mcp.operation_result',\n payload: { success: result.ok, message: result.message },\n });\n}\n\n/** mcp.remove — stop the server and delete it from config. */\nexport async function handleMcpRemove(\n ws: WebSocket,\n msg: WSClientMessage,\n globalConfigPath: string,\n mcpRegistry?: MCPRegistry,\n): Promise<void> {\n const d = deps(ws, globalConfigPath, mcpRegistry);\n if (!d) return;\n const result = await removeMcp(name(msg), d);\n if (result.ok) {\n send(ws, { type: 'mcp.server.removed', payload: { name: name(msg) } });\n }\n send(ws, {\n type: 'mcp.operation_result',\n payload: { success: result.ok, message: result.message },\n });\n}\n\n/** mcp.enable — flip enabled:true in config and start the server. */\nexport async function handleMcpEnable(\n ws: WebSocket,\n msg: WSClientMessage,\n globalConfigPath: string,\n mcpRegistry?: MCPRegistry,\n): Promise<void> {\n const d = deps(ws, globalConfigPath, mcpRegistry);\n if (!d) return;\n const result = await enableMcp(name(msg), d);\n if (result.ok && result.server) {\n send(ws, { type: 'mcp.server.updated', payload: { server: toView(result.server) } });\n if (result.registryError) {\n send(ws, {\n type: 'mcp.server.error',\n payload: { name: name(msg), error: result.registryError },\n });\n } else {\n send(ws, { type: 'mcp.server.connected', payload: { name: name(msg) } });\n }\n }\n send(ws, {\n type: 'mcp.operation_result',\n payload: { success: result.ok, message: result.message },\n });\n}\n\n/** mcp.disable — stop the server and flip enabled:false in config. */\nexport async function handleMcpDisable(\n ws: WebSocket,\n msg: WSClientMessage,\n globalConfigPath: string,\n mcpRegistry?: MCPRegistry,\n): Promise<void> {\n const d = deps(ws, globalConfigPath, mcpRegistry);\n if (!d) return;\n const result = await disableMcp(name(msg), d);\n if (result.ok) {\n send(ws, { type: 'mcp.server.sleeping', payload: { name: name(msg) } });\n if (result.server) {\n send(ws, { type: 'mcp.server.updated', payload: { server: toView(result.server) } });\n }\n }\n send(ws, {\n type: 'mcp.operation_result',\n payload: { success: result.ok, message: result.message },\n });\n}\n\n/** mcp.sleep — stop a running server (config stays enabled). */\nexport async function handleMcpSleep(\n ws: WebSocket,\n msg: WSClientMessage,\n globalConfigPath: string,\n mcpRegistry?: MCPRegistry,\n): Promise<void> {\n const d = deps(ws, globalConfigPath, mcpRegistry);\n if (!d) return;\n // Sleep == disable the live process but keep config enabled — use the\n // registry directly so the persisted `enabled` flag is untouched.\n try {\n await d.registry.stop(name(msg));\n send(ws, { type: 'mcp.server.sleeping', payload: { name: name(msg) } });\n send(ws, {\n type: 'mcp.operation_result',\n payload: { success: true, message: `Server \"${name(msg)}\" stopped` },\n });\n } catch (err) {\n const error = err instanceof Error ? err.message : String(err);\n send(ws, { type: 'mcp.server.error', payload: { name: name(msg), error } });\n send(ws, {\n type: 'mcp.operation_result',\n payload: { success: false, message: `Failed to stop \"${name(msg)}\": ${error}` },\n });\n }\n}\n\n/** mcp.wake — restart a sleeping/stopped server from config. */\nexport async function handleMcpWake(\n ws: WebSocket,\n msg: WSClientMessage,\n globalConfigPath: string,\n mcpRegistry?: MCPRegistry,\n): Promise<void> {\n const d = deps(ws, globalConfigPath, mcpRegistry);\n if (!d) return;\n send(ws, { type: 'mcp.server.waking', payload: { name: name(msg) } });\n const result = await restartMcp(name(msg), d);\n if (result.ok && !result.registryError) {\n send(ws, { type: 'mcp.server.connected', payload: { name: name(msg) } });\n } else if (result.registryError) {\n send(ws, {\n type: 'mcp.server.error',\n payload: { name: name(msg), error: result.registryError },\n });\n }\n send(ws, {\n type: 'mcp.operation_result',\n payload: { success: result.ok, message: result.message },\n });\n}\n\n/** mcp.restart — stop + start a server. */\nexport async function handleMcpRestart(\n ws: WebSocket,\n msg: WSClientMessage,\n globalConfigPath: string,\n mcpRegistry?: MCPRegistry,\n): Promise<void> {\n const d = deps(ws, globalConfigPath, mcpRegistry);\n if (!d) return;\n const result = await restartMcp(name(msg), d);\n if (result.ok && !result.registryError) {\n send(ws, { type: 'mcp.server.connected', payload: { name: name(msg) } });\n } else if (result.registryError) {\n send(ws, {\n type: 'mcp.server.error',\n payload: { name: name(msg), error: result.registryError },\n });\n }\n send(ws, {\n type: 'mcp.operation_result',\n payload: { success: result.ok, message: result.message },\n });\n}\n\n/** mcp.discover — ensure the server is running and report its live tools. */\nexport async function handleMcpDiscover(\n ws: WebSocket,\n msg: WSClientMessage,\n globalConfigPath: string,\n mcpRegistry?: MCPRegistry,\n): Promise<void> {\n const d = deps(ws, globalConfigPath, mcpRegistry);\n if (!d) return;\n const result = await discoverMcp(name(msg), d);\n if (result.ok) {\n send(ws, {\n type: 'mcp.server.discovered',\n payload: { name: name(msg), tools: result.tools ?? [] },\n });\n }\n send(ws, {\n type: 'mcp.operation_result',\n payload: { success: result.ok, message: result.message },\n });\n}\n","/**\n * Shared skills WebSocket handlers for both the standalone WebUI server\n * (`packages/webui/src/server/index.ts`) and the CLI's `--webui` embedded\n * server (`packages/cli/src/webui-server.ts`).\n *\n * These were previously inlined in BOTH servers, and the CLI copy had\n * drifted — it only wired `skills.list`, so `skills.content` /\n * `skills.export` / `skills.update` (and install/uninstall/create/edit)\n * fell through to the \"Unhandled message type\" warning even though the\n * SkillsPanel sends them. Extracting the full set here gives both servers\n * one source of truth. Each function handles the full request→response\n * cycle for one message type; callers drop them into their switch:\n *\n * case 'skills.content': return handleSkillsContent(ws, skillsCtx, msg);\n *\n * The logic is a verbatim lift of the standalone's inline cases — only the\n * dependency references changed (`skillLoader`/`skillInstaller`/\n * `projectRoot` → `ctx.*`, local `send`/`errMessage` → imported helpers).\n */\n\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport type { WebSocket } from 'ws';\nimport JSZip from 'jszip';\nimport type { SkillLoader } from '@wrongstack/core';\nimport { atomicWrite } from '@wrongstack/core';\nimport type { SkillInstaller } from '@wrongstack/core/skills';\nimport { wstackGlobalRoot } from '@wrongstack/core/utils';\nimport { send, errMessage } from './ws-utils.js';\nimport { validateSkillsCreatePayload, validateSkillsEditPayload } from './ws-payload-validation.js';\n\nexport interface SkillsContext {\n /** Backs skills.list/content/edit/export. Absent ⇒ feature disabled. */\n skillLoader: SkillLoader | undefined;\n /** Backs skills.install/uninstall/update. Absent ⇒ those ops disabled. */\n skillInstaller: SkillInstaller | undefined;\n /** Project root — used by skills.create to write `.wrongstack/skills/…`. */\n projectRoot: string;\n}\n\n// ── Shared handlers ───────────────────────────────────────────────────\n\n/**\n * List installed skills. Enriches each manifest with the source URL + git\n * ref recorded by the installer (when present), so the panel can show\n * provenance and offer update/uninstall.\n */\nexport async function handleSkillsList(ws: WebSocket, ctx: SkillsContext): Promise<void> {\n if (!ctx.skillLoader) {\n send(ws, { type: 'skills.list', payload: { skills: [], enabled: false } });\n return;\n }\n try {\n const manifests = await ctx.skillLoader.list();\n const entries = await ctx.skillLoader.listEntries();\n const byName = new Map(entries.map((e) => [e.name, e]));\n\n // Fetch source URLs and commit refs from the manifest (installed-skills.json)\n const sourceUrlsByName = new Map<string, string>();\n const refsByName = new Map<string, string>();\n if (ctx.skillInstaller) {\n try {\n const installed = await ctx.skillInstaller.listInstalled();\n for (const entry of installed) {\n sourceUrlsByName.set(entry.name, entry.source);\n refsByName.set(entry.name, entry.ref);\n }\n } catch {\n // Non-fatal — source URLs just won't be shown\n }\n }\n\n send(ws, {\n type: 'skills.list',\n payload: {\n enabled: true,\n skills: manifests.map((m) => ({\n name: m.name,\n description: m.description,\n version: m.version ?? '',\n source: m.source,\n sourceUrl: sourceUrlsByName.get(m.name) ?? '',\n ref: refsByName.get(m.name) ?? '',\n path: m.path,\n trigger: byName.get(m.name)?.trigger ?? '',\n scope: byName.get(m.name)?.scope ?? [],\n })),\n },\n });\n } catch (err) {\n send(ws, {\n type: 'skills.list',\n payload: {\n skills: [],\n enabled: true,\n error: errMessage(err),\n },\n });\n }\n}\n\n/**\n * Read a single skill's body + its directory's related files + which other\n * skills reference it by name. Powers the skill detail/preview view.\n */\nexport async function handleSkillsContent(\n ws: WebSocket,\n ctx: SkillsContext,\n msg: unknown,\n): Promise<void> {\n if (!ctx.skillLoader) {\n send(ws, { type: 'skills.content', payload: { name: '', body: '', path: '', source: '', relatedFiles: [], references: [], error: 'Skills not enabled' } });\n return;\n }\n const contentPayload = (msg as { payload: { name: string; source: string } }).payload;\n if (!contentPayload?.name) {\n send(ws, { type: 'skills.content', payload: { name: '', body: '', path: '', source: '', relatedFiles: [], references: [], error: 'Skill name is required' } });\n return;\n }\n try {\n const { name, source } = contentPayload;\n const entries = await ctx.skillLoader.listEntries();\n const entry = entries.find((e) => e.name.toLowerCase() === name.toLowerCase());\n if (!entry) {\n send(ws, { type: 'skills.content', payload: { name, body: '', path: '', source, relatedFiles: [], references: [], error: `Skill \"${name}\" not found` } });\n return;\n }\n // Read body directly from path — avoids re-running find() which re-reads all SKILL.md files\n const body = await fs.readFile(entry.path, 'utf8');\n const skillDir = path.dirname(entry.path);\n\n // Related files — other files in the same skill directory\n let relatedFiles: string[] = [];\n try {\n const files = await fs.readdir(skillDir);\n relatedFiles = files\n .filter((f) => f !== path.basename(entry.path))\n .map((f) => path.join(skillDir, f));\n } catch {\n // Non-fatal\n }\n\n // References — which other skills reference this one (by name)\n // Read all other skill bodies in parallel, keyed by name for O(1) lookup\n const nameLower = name.toLowerCase();\n const refResults = await Promise.all(\n entries\n .filter((e) => e.name.toLowerCase() !== nameLower)\n .map(async (e): Promise<[string, boolean]> => {\n try {\n // Use entry.path directly to skip find() overhead\n const content = await fs.readFile(e.path, 'utf8');\n return [e.name, content.toLowerCase().includes(nameLower)];\n } catch {\n return [e.name, false];\n }\n }),\n );\n const refs = refResults.filter(([, hasRef]) => hasRef).map(([n]) => n);\n\n send(ws, { type: 'skills.content', payload: { name, body, path: entry.path, source, relatedFiles, references: refs } });\n } catch (err) {\n send(ws, { type: 'skills.content', payload: { name: contentPayload.name, body: '', path: '', source: contentPayload.source, relatedFiles: [], references: [], error: errMessage(err) } });\n }\n}\n\n/**\n * Install a skill from a git ref (`owner/repo` or URL). Optional `global`\n * installs into the user-wide skills dir instead of the project's.\n */\nexport async function handleSkillsInstall(\n ws: WebSocket,\n ctx: SkillsContext,\n msg: unknown,\n): Promise<void> {\n if (!ctx.skillInstaller) {\n send(ws, { type: 'skills.installed', payload: { success: false, error: 'Skills not enabled' } });\n return;\n }\n const installPayload = (msg as { payload: { ref: string; global?: boolean } }).payload;\n if (!installPayload?.ref?.trim()) {\n send(ws, { type: 'skills.installed', payload: { success: false, error: 'Skill reference is required (e.g. owner/repo or https://github.com/owner/repo)' } });\n return;\n }\n try {\n const results = await ctx.skillInstaller.install(installPayload.ref.trim(), { global: installPayload.global });\n send(ws, {\n type: 'skills.installed',\n payload: {\n success: true,\n results,\n error: null,\n },\n });\n } catch (err) {\n send(ws, {\n type: 'skills.installed',\n payload: {\n success: false,\n error: errMessage(err),\n },\n });\n }\n}\n\n/**\n * Uninstall a skill by name. Optional `global` restricts/Targets the\n * user-wide install.\n */\nexport async function handleSkillsUninstall(\n ws: WebSocket,\n ctx: SkillsContext,\n msg: unknown,\n): Promise<void> {\n if (!ctx.skillInstaller) {\n send(ws, { type: 'skills.uninstalled', payload: { success: false, error: 'Skills not enabled' } });\n return;\n }\n const uninstallPayload = (msg as { payload: { name: string; global?: boolean } }).payload;\n if (!uninstallPayload?.name?.trim()) {\n send(ws, { type: 'skills.uninstalled', payload: { success: false, error: 'Skill name is required' } });\n return;\n }\n try {\n await ctx.skillInstaller.uninstall(uninstallPayload.name.trim(), { global: uninstallPayload.global });\n send(ws, { type: 'skills.uninstalled', payload: { success: true, error: null } });\n } catch (err) {\n send(ws, { type: 'skills.uninstalled', payload: { success: false, error: errMessage(err) } });\n }\n}\n\n/**\n * Update one skill (`name`) or all installed skills (when `name` is\n * omitted). Reports per-skill updated/unchanged/error tallies.\n */\nexport async function handleSkillsUpdate(\n ws: WebSocket,\n ctx: SkillsContext,\n msg: unknown,\n): Promise<void> {\n if (!ctx.skillInstaller) {\n send(ws, { type: 'skills.updated', payload: { success: false, error: 'Skills not enabled' } });\n return;\n }\n const updatePayload = (msg as { payload?: { name?: string; global?: boolean } | undefined }).payload;\n try {\n const result = await ctx.skillInstaller.update(updatePayload?.name, { global: updatePayload?.global });\n send(ws, {\n type: 'skills.updated',\n payload: {\n success: true,\n error: null,\n updated: result.updated,\n unchanged: result.unchanged,\n errors: result.errors,\n },\n });\n } catch (err) {\n send(ws, { type: 'skills.updated', payload: { success: false, error: errMessage(err) } });\n }\n}\n\n/**\n * Scaffold a new project- or global-scoped skill from a name + description.\n * Writes a templated `SKILL.md` under `.wrongstack/skills/<name>/` (project)\n * or the user-wide skills dir (global).\n */\nexport async function handleSkillsCreate(\n ws: WebSocket,\n ctx: SkillsContext,\n msg: unknown,\n): Promise<void> {\n const parsed = validateSkillsCreatePayload((msg as { payload?: unknown }).payload);\n if (!parsed.ok) {\n send(ws, { type: 'skills.created', payload: { success: false, error: parsed.message } });\n return;\n }\n const createPayload = parsed.value;\n try {\n const targetDir =\n createPayload.scope === 'global'\n ? path.join(wstackGlobalRoot(), 'skills', createPayload.name.trim())\n : path.join(ctx.projectRoot, '.wrongstack', 'skills', createPayload.name.trim());\n\n // Check if directory already exists\n try {\n await fs.access(targetDir);\n send(ws, { type: 'skills.created', payload: { success: false, error: `Skill \"${createPayload.name}\" already exists` } });\n return;\n } catch {\n // Directory does not exist — good\n }\n\n await fs.mkdir(targetDir, { recursive: true });\n\n // Parse description lines to build the skill content\n const lines = createPayload.description.trim().split('\\n');\n const firstLine = lines[0].trim();\n const bodyLines = lines.slice(1).map((l) => l.trim()).filter(Boolean);\n const descriptionText = firstLine + (bodyLines.length > 0 ? `\\n${bodyLines.join('\\n')}` : '');\n const trigger = bodyLines.find((l) => l.toLowerCase().startsWith('triggers:')) ?? '';\n\n const skillContent = [\n '---',\n `name: ${createPayload.name.trim()}`,\n 'description: |',\n ` ${descriptionText.replace(/\\n/g, '\\n ')}`,\n `version: 1.0.0`,\n '---',\n '',\n `# ${createPayload.name.trim().split('-').map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(' ')}`,\n '',\n '## Overview',\n '',\n firstLine,\n '',\n ...(bodyLines.length > 0 ? bodyLines.filter((l) => !l.toLowerCase().startsWith('triggers:')) : []),\n '',\n '## Rules',\n '- TODO: add your first rule',\n '',\n '## Patterns',\n '### Do',\n '```ts',\n '// TODO: add a good example',\n '```',\n '',\n '### Don\\'t',\n '```ts',\n '// TODO: add a bad example',\n '```',\n '',\n '## Workflow',\n '1. TODO: describe step one',\n '2. TODO: describe step two',\n '',\n trigger ? `\\n${trigger}\\n` : '',\n '## Skills in scope',\n '- `bug-hunter` — for systematic bug detection patterns',\n '- `output-standards` — for standardized `<next_steps>` formatting',\n ].join('\\n');\n\n await atomicWrite(path.join(targetDir, 'SKILL.md'), skillContent);\n\n send(ws, {\n type: 'skills.created',\n payload: {\n success: true,\n error: null,\n skill: { name: createPayload.name.trim(), path: path.join(targetDir, 'SKILL.md'), scope: createPayload.scope },\n },\n });\n } catch (err) {\n send(ws, { type: 'skills.created', payload: { success: false, error: errMessage(err) } });\n }\n}\n\n/**\n * Overwrite a skill's body. Refuses bundled skills (read-only) and unknown\n * names.\n */\nexport async function handleSkillsEdit(\n ws: WebSocket,\n ctx: SkillsContext,\n msg: unknown,\n): Promise<void> {\n if (!ctx.skillLoader) {\n send(ws, { type: 'skills.edited', payload: { success: false, error: 'Skills not enabled' } });\n return;\n }\n const parsed = validateSkillsEditPayload((msg as { payload?: unknown }).payload);\n if (!parsed.ok) {\n send(ws, { type: 'skills.edited', payload: { success: false, error: parsed.message } });\n return;\n }\n const editPayload = parsed.value;\n try {\n const entries = await ctx.skillLoader.listEntries();\n const entry = entries.find((e) => e.name.toLowerCase() === editPayload.name.toLowerCase());\n if (!entry) {\n send(ws, { type: 'skills.edited', payload: { success: false, error: `Skill \"${editPayload.name}\" not found` } });\n return;\n }\n // Only allow editing project/user skills (not bundled)\n if (entry.scope.includes('bundled')) {\n send(ws, { type: 'skills.edited', payload: { success: false, error: 'Bundled skills cannot be edited' } });\n return;\n }\n await atomicWrite(entry.path, editPayload.body);\n send(ws, { type: 'skills.edited', payload: { success: true, error: null } });\n } catch (err) {\n send(ws, { type: 'skills.edited', payload: { success: false, error: errMessage(err) } });\n }\n}\n\n/**\n * Export every readable skill as a base64-encoded zip (one folder per skill,\n * each with its `SKILL.md`). Powers the panel's \"Export all\" button.\n */\nexport async function handleSkillsExport(ws: WebSocket, ctx: SkillsContext): Promise<void> {\n if (!ctx.skillLoader) {\n send(ws, { type: 'skills.exported', payload: { zipBase64: '', skillCount: 0, error: 'Skills not enabled' } });\n return;\n }\n try {\n const entries = await ctx.skillLoader.listEntries();\n const zip = new JSZip();\n for (const entry of entries) {\n try {\n const body = await ctx.skillLoader!.readBody(entry.name);\n const safeName = entry.name.replace(/\\//g, '_');\n zip.file(`${safeName}/SKILL.md`, body);\n } catch {\n // Skip skills we can't read\n }\n }\n const zipBuffer = await zip.generateAsync({ type: 'nodebuffer', compression: 'DEFLATE' });\n const zipBase64 = zipBuffer.toString('base64');\n send(ws, { type: 'skills.exported', payload: { zipBase64, skillCount: entries.length, error: undefined } });\n } catch (err) {\n send(ws, { type: 'skills.exported', payload: { zipBase64: '', skillCount: 0, error: errMessage(err) } });\n }\n}\n","import {\n type Config,\n type DefaultLogger,\n type DefaultSecretVault,\n type WstackPaths,\n bootConfig as coreBootConfig,\n} from '@wrongstack/core';\n\nexport interface BootResult {\n config: Config;\n vault: DefaultSecretVault;\n globalConfigPath: string;\n projectRoot: string;\n wpaths: WstackPaths;\n logger: InstanceType<typeof DefaultLogger>;\n}\n\n/**\n * Thin WebUI wrapper over the canonical `bootConfig` in `@wrongstack/core`\n * (mirrors packages/cli/src/boot-config.ts). All real boot behavior — wstack\n * path resolution, the AES-GCM `DefaultSecretVault`, plaintext-secret\n * migration, and config load/merge — lives in core so the WebUI server and the\n * CLI can't drift. Only the secret-migration notice label (`WebUI`) differs.\n */\nexport async function bootConfig(): Promise<BootResult> {\n const { config, vault, globalConfigPath, projectRoot, wpaths, logger } = await coreBootConfig({\n appLabel: 'WebUI',\n });\n return { config, vault, globalConfigPath, projectRoot, wpaths, logger };\n}\n\nexport function patchConfig(config: Config, updates: Partial<Config>): Config {\n return Object.freeze({ ...config, ...updates });\n}\n","import { spawnSync } from 'node:child_process';\nimport type { WebSocket } from 'ws';\nimport { toErrorMessage } from '@wrongstack/core/utils';\nimport {\n assignNickname,\n AutoPhasePlanner,\n PhaseGraphBuilder,\n PhaseOrchestrator,\n PhaseStore,\n WorktreeManager,\n type PhaseGraph,\n type PhaseTemplate,\n} from '@wrongstack/core';\nimport type { Agent, Context, EventBus, Logger } from '@wrongstack/core';\n\n/**\n * Derive a short, single-line heading from a (possibly multi-paragraph) goal\n * prompt. Takes the first non-empty line, trims to its first sentence, and caps\n * the length so AutoPhase headers stay readable. The full prompt is preserved\n * separately as the graph description.\n */\nfunction deriveTitle(goal: string): string {\n const firstLine = goal\n .split('\\n')\n .map((l) => l.trim())\n .find(Boolean);\n if (!firstLine) return 'AutoPhase';\n const sentence = firstLine.split(/(?<=[.!?])\\s/)[0] ?? firstLine;\n const trimmed = sentence.length <= 64 ? sentence : `${sentence.slice(0, 63).trimEnd()}…`;\n return trimmed || 'AutoPhase';\n}\n\nfunction isGitRepo(cwd: string): boolean {\n try {\n const r = spawnSync('git', ['rev-parse', '--is-inside-work-tree'], { cwd, encoding: 'utf8', windowsHide: true });\n return r.status === 0 && r.stdout.trim() === 'true';\n } catch {\n return false;\n }\n}\n\n/**\n * List the commits on `branch` since `baseSha` (oldest → newest, the order they\n * landed). Used by `autophase.revert` to feed WorktreeManager.revertCommits,\n * which reverses them. Returns [] on any git error.\n */\nfunction commitsSince(cwd: string, baseSha: string, branch: string): string[] {\n try {\n const r = spawnSync('git', ['log', '--reverse', '--format=%H', `${baseSha}..${branch}`], {\n cwd,\n encoding: 'utf8',\n windowsHide: true,\n });\n if (r.status !== 0) return [];\n return r.stdout.split('\\n').map((s) => s.trim()).filter(Boolean);\n } catch {\n return [];\n }\n}\n\ninterface WSClient {\n ws: WebSocket;\n id: string;\n}\n\ninterface AutoPhaseWSMessage {\n type: string;\n payload?: Record<string, unknown>;\n}\n\n/**\n * AutoPhaseWebSocketHandler — WebSocket-based AutoPhase control.\n *\n * Message types:\n * autophase.start → { title, phases?, autonomous? }\n * autophase.pause → {}\n * autophase.resume → {}\n * autophase.stop → {}\n * autophase.status → {}\n * autophase.selectPhase → { phaseId }\n * autophase.taskStatus → { taskId, status }\n */\nexport class AutoPhaseWebSocketHandler {\n private orchestrator: PhaseOrchestrator | null = null;\n private graph: PhaseGraph | null = null;\n private store: PhaseStore;\n private clients = new Set<WSClient>();\n private broadcastInterval: ReturnType<typeof setInterval> | null = null;\n /** Aborts in-flight task agents AND the planning turn when the run is stopped. */\n private abort: AbortController | null = null;\n /** Set the instant a stop/clear/revert is requested, so a planning turn that\n * resolves afterwards never launches the orchestrator (the abort alone can't\n * cover the window between the LLM call resolving and the orchestrator start). */\n private stopping = false;\n /** Optional per-phase git-worktree isolation (lazily created at start). */\n private worktrees: WorktreeManager | null = null;\n /** Base branch + tip SHA captured at run start so a revert can git-revert the\n * run's squash commits (history-preserving) instead of a destructive reset. */\n private runBase: { branch: string; sha: string } | null = null;\n /** Per-run worker identities so the board can show \"who is on what\". */\n private usedNicknames = new Set<string>();\n\n constructor(\n private agent: Agent,\n private context: Context,\n private logger: Logger,\n storeDir: string,\n private events?: EventBus | undefined,\n private projectRoot?: string | undefined,\n ) {\n this.store = new PhaseStore({ baseDir: storeDir });\n }\n\n addClient(ws: WebSocket): void {\n const client: WSClient = { ws, id: crypto.randomUUID() };\n this.clients.add(client);\n\n ws.on('close', () => this.clients.delete(client));\n ws.on('error', () => this.clients.delete(client));\n\n // Send current state\n this.sendState(client);\n }\n\n async handleMessage(msg: AutoPhaseWSMessage): Promise<void> {\n switch (msg.type) {\n case 'autophase.start':\n await this.handleStart(msg.payload);\n break;\n case 'autophase.pause':\n this.orchestrator?.pause();\n this.broadcast({ type: 'autophase.paused', payload: {} });\n break;\n case 'autophase.resume':\n this.orchestrator?.resume();\n this.broadcast({ type: 'autophase.resumed', payload: {} });\n break;\n case 'autophase.stop':\n await this.handleStop();\n break;\n case 'autophase.clear':\n await this.handleClear();\n break;\n case 'autophase.revert':\n await this.handleRevert();\n break;\n case 'autophase.status':\n this.broadcastState();\n break;\n case 'autophase.selectPhase': {\n const phaseId = msg.payload?.phaseId as string;\n if (phaseId && this.graph) {\n this.broadcastState(phaseId);\n }\n break;\n }\n case 'autophase.taskStatus': {\n const { taskId, status } = msg.payload as { taskId: string; status: string };\n await this.handleTaskStatusChange(taskId, status);\n break;\n }\n case 'autophase.moveTask': {\n const { taskId, toPhaseId } = msg.payload as { taskId: string; toPhaseId: string };\n if (this.orchestrator?.moveTask(taskId, toPhaseId)) this.afterBoardMutation();\n break;\n }\n case 'autophase.assignTask': {\n const { taskId, agentId, agentName } = msg.payload as {\n taskId: string;\n agentId?: string;\n agentName?: string;\n };\n if (this.orchestrator?.setTaskAssignee(taskId, agentId, agentName)) this.afterBoardMutation();\n break;\n }\n case 'autophase.addTask': {\n const { phaseId, title, description, type, priority } = msg.payload as {\n phaseId: string;\n title: string;\n description?: string;\n type?: import('@wrongstack/core').TaskNode['type'];\n priority?: import('@wrongstack/core').TaskNode['priority'];\n };\n if (title?.trim() && this.orchestrator?.addTask(phaseId, { title: title.trim(), description, type, priority })) {\n this.afterBoardMutation();\n }\n break;\n }\n case 'autophase.retryTask':\n case 'autophase.runTask': {\n const { taskId } = msg.payload as { taskId: string };\n if (this.orchestrator?.requeueTask(taskId)) this.afterBoardMutation();\n break;\n }\n case 'autophase.toggleAutonomous': {\n const autonomous = (msg.payload?.autonomous as boolean) ?? !this.graph?.autonomous;\n if (this.graph) {\n this.graph.autonomous = autonomous;\n await this.store.save(this.graph);\n this.broadcast({ type: 'autophase.state', payload: this.buildState() });\n }\n break;\n }\n case 'autophase.save': {\n if (this.graph) {\n await this.store.save(this.graph);\n this.broadcast({ type: 'autophase.saved', payload: { graphId: this.graph.id } });\n }\n break;\n }\n case 'autophase.list': {\n const graphs = await this.store.list();\n this.broadcast({ type: 'autophase.list', payload: { graphs } });\n break;\n }\n case 'autophase.load': {\n const graphId = msg.payload?.graphId as string | undefined;\n if (graphId) {\n const graph = await this.store.load(graphId);\n if (graph) {\n this.graph = graph;\n this.broadcast({ type: 'autophase.state', payload: this.buildState() });\n } else {\n this.broadcast({ type: 'autophase.error', payload: { message: `Graph not found: ${graphId}` } });\n }\n }\n break;\n }\n }\n }\n\n private async handleStart(payload?: Record<string, unknown>): Promise<void> {\n // The caller sends the operator's full prompt as the goal. We keep it intact\n // as the graph `description` and derive a short, human-readable `title` for\n // headers / the board switcher — pasting the whole prompt as the title made\n // the AutoPhase header unreadable.\n const goal = (payload?.goal as string) || (payload?.title as string) || 'Untitled Project';\n const title = deriveTitle(goal);\n const autonomous = (payload?.autonomous as boolean) ?? true;\n\n // Fresh abort for THIS run, created BEFORE planning so a stop pressed during\n // the (long) planning turn actually cancels it. Previously the controller was\n // created only after planning, so a stop while \"starting\" was a no-op and the\n // run launched anyway.\n this.abort = new AbortController();\n this.stopping = false;\n\n // Phase plan resolution:\n // 1. explicit phases in the payload win (caller override);\n // 2. otherwise the LLM plans phases+todos for the goal;\n // 3. failing that, fall back to the generic default phases.\n const phases = Array.isArray(payload?.phases)\n ? (payload.phases as PhaseTemplate[])\n : await this.planPhases(goal, this.abort.signal);\n\n // Stop requested during planning → never launch the orchestrator. The abort\n // may not have interrupted the in-flight LLM call promptly, so the `stopping`\n // flag is the authoritative guard for the resolve-after-stop window.\n if (this.stopping || this.abort.signal.aborted) {\n this.broadcast({ type: 'autophase.stopped', payload: { title } });\n return;\n }\n\n this.logger.info(`[AutoPhase] Starting: ${title}`);\n\n // Build the graph up-front so we have a reference for live broadcasts and\n // persistence *before* the (long-running) build begins.\n const graph = await new PhaseGraphBuilder({ title, description: goal, phases, autonomous }).build();\n this.graph = graph;\n await this.store.save(graph);\n\n // Per-phase git-worktree isolation, when enabled and inside a git repo.\n // The shared agent/context means we can't run phases in parallel here\n // (we swap a single context.cwd per task), so phases stay sequential —\n // but each phase still commits + squash-merges back through its own\n // worktree, and the lifecycle events drive the live swim-lane/DAG view.\n // Per-run worktree-isolation override from the UI wins; omitted → env default\n // (disable with WRONGSTACK_AUTOPHASE_WORKTREES=0). false → run on the current branch.\n const useWorktrees =\n (payload?.worktrees as boolean | undefined) ??\n process.env['WRONGSTACK_AUTOPHASE_WORKTREES'] !== '0';\n if (\n !this.worktrees &&\n this.events &&\n this.projectRoot &&\n useWorktrees &&\n isGitRepo(this.projectRoot)\n ) {\n this.worktrees = new WorktreeManager({ projectRoot: this.projectRoot, events: this.events });\n }\n // Capture the pre-run base tip so `autophase.revert` can git-revert exactly\n // the commits this run lands on the base branch.\n if (this.worktrees) {\n this.runBase = await this.worktrees.currentBase();\n }\n\n // NOTE: this interactive-board orchestrator deliberately omits the CLI host's\n // `verifyPhase`/`repairPhase`/`resolveConflict` hooks. The WebUI run is\n // human-supervised (live kanban + manual task moves), so it trusts the task\n // agents + the operator rather than running an autonomous typecheck/lint gate\n // and repair/conflict-resolver subagents. Worktree isolation + squash-merge\n // still happen (above); an unresolved merge conflict simply parks the worktree\n // for review (mergeOne's default). The fully-autonomous gate lives in the CLI\n // host (`packages/cli/src/autophase-host.ts`). Keep these two in mind when\n // changing phase-completion semantics.\n this.orchestrator = new PhaseOrchestrator({\n graph,\n ctx: {\n executeTask: async (task, phaseId, env) => {\n this.logger.info(`[AutoPhase] [${phaseId}] Executing: ${task.title}`);\n const result = await this.executeTaskWithAgent(task, phaseId, env);\n this.logger.info(`[AutoPhase] [${phaseId}] Completed: ${task.title}`);\n return result;\n },\n onPhaseComplete: (phase) => {\n this.logger.info(`[AutoPhase] Phase completed: ${phase.name}`);\n void this.store.save(graph);\n this.broadcastState();\n },\n onPhaseFail: (phase, error) => {\n this.logger.error(`[AutoPhase] Phase failed: ${phase.name} — ${error.message}`);\n void this.store.save(graph);\n this.broadcastState();\n },\n },\n worktrees: this.worktrees ?? undefined,\n autonomous,\n // Must stay 1: phase tasks run on the single shared context whose cwd we\n // swap per phase, so parallel phases would race on context.cwd.\n maxConcurrentPhases: 1,\n // Sequential within a phase: each todo is a full-tool agent editing the\n // phase worktree, so running two at once risks concurrent writes.\n maxConcurrentTasks: 1,\n });\n\n // Start the live broadcast immediately, then run the orchestrator in the\n // background. Awaiting start() would block until the *entire* build\n // finishes — the periodic broadcast (below) reads the mutating graph, so\n // clients see live progress while it runs.\n this.startBroadcast();\n this.broadcastState();\n\n void this.orchestrator\n .start()\n .then(() => {\n this.orchestrator?.stop(); // clear the autonomous tick interval\n void this.store.save(graph);\n this.stopBroadcast();\n const failed = graph.failedPhaseIds.length > 0;\n this.broadcast(\n failed\n ? { type: 'autophase.failed', payload: { title } }\n : { type: 'autophase.completed', payload: { title } },\n );\n this.broadcastState();\n })\n .catch((err: unknown) => {\n this.logger.error(`[AutoPhase] Aborted: ${toErrorMessage(err)}`);\n this.stopBroadcast();\n this.broadcast({ type: 'autophase.failed', payload: { title, error: String(err) } });\n });\n }\n\n /**\n * Halt the run NOW — at any phase. Sets `stopping` (so a planning turn that\n * resolves afterwards bails), aborts in-flight agents, stops the orchestrator\n * tick, and ends the live broadcast. The board is kept for review; use\n * `autophase.clear` to reset or `autophase.revert` to undo the changes.\n */\n private async handleStop(): Promise<void> {\n this.stopping = true;\n this.abort?.abort();\n this.orchestrator?.stop();\n this.stopBroadcast();\n if (this.graph) await this.store.save(this.graph).catch(() => undefined);\n this.broadcast({ type: 'autophase.stopped', payload: { title: this.graph?.title } });\n }\n\n /**\n * Stop + wipe: tear down phase worktrees and reset to an empty board so the UI\n * returns to the start screen (\"new one\"). Does NOT touch already-merged commits\n * on the base branch — that is `autophase.revert`.\n */\n private async handleClear(): Promise<void> {\n await this.handleStop();\n if (this.worktrees) await this.worktrees.cleanupAllManaged().catch(() => undefined);\n this.orchestrator = null;\n this.graph = null;\n this.runBase = null;\n this.usedNicknames.clear();\n this.broadcast({ type: 'autophase.cleared', payload: {} });\n // Empty state → board/wizard falls back to the goal-entry screen.\n this.broadcast({ type: 'autophase.state', payload: this.buildState() });\n }\n\n /**\n * Stop + undo: remove phase worktrees, then history-preservingly `git revert`\n * every commit this run landed on the base branch (captured `runBase`..HEAD),\n * then reset to an empty board. Refuses (reports a reason) on a dirty tree or a\n * conflicting revert rather than leaving the tree half-reverted.\n */\n private async handleRevert(): Promise<void> {\n await this.handleStop();\n if (!this.worktrees || !this.runBase || !this.projectRoot) {\n this.broadcast({\n type: 'autophase.reverted',\n payload: { ok: false, reverted: 0, reason: 'no git baseline was captured for this run' },\n });\n return;\n }\n await this.worktrees.cleanupAllManaged().catch(() => undefined);\n const shas = commitsSince(this.projectRoot, this.runBase.sha, this.runBase.branch);\n const res = await this.worktrees.revertCommits(this.runBase.branch, shas);\n this.broadcast({ type: 'autophase.reverted', payload: res });\n if (res.ok) {\n this.orchestrator = null;\n this.graph = null;\n this.runBase = null;\n this.broadcast({ type: 'autophase.cleared', payload: {} });\n this.broadcast({ type: 'autophase.state', payload: this.buildState() });\n }\n }\n\n /** Generic fallback phases when the LLM planner produces nothing usable. */\n private defaultPhases(): PhaseTemplate[] {\n return [\n { name: 'Discovery', description: 'Requirements gathering', priority: 'high', estimateHours: 2, parallelizable: false },\n { name: 'Design', description: 'Architecture and design', priority: 'critical', estimateHours: 4, parallelizable: false },\n { name: 'Implementation', description: 'Core development', priority: 'critical', estimateHours: 12, parallelizable: false },\n { name: 'Testing', description: 'Unit and integration tests', priority: 'high', estimateHours: 6, parallelizable: true },\n { name: 'Deployment', description: 'Deploy to production', priority: 'medium', estimateHours: 2, parallelizable: false },\n ];\n }\n\n /** Plan phases+todos for the goal via the LLM; fall back to defaults on failure.\n * The caller passes the run's abort signal so a stop during planning cancels\n * the LLM turn (the previous fresh, never-aborted controller made planning\n * uninterruptible). */\n private async planPhases(goal: string, signal?: AbortSignal): Promise<PhaseTemplate[]> {\n try {\n const planner = new AutoPhasePlanner({\n goal,\n runOnce: async (prompt) => {\n const result = (await this.agent.run(prompt, {\n signal: signal ?? new AbortController().signal,\n })) as {\n status: string;\n finalText?: string | undefined;\n };\n return result.status === 'done' ? (result.finalText ?? '') : '';\n },\n });\n const { phases, parseFailed } = await planner.plan();\n if (!parseFailed && phases.length > 0) {\n const todos = phases.reduce((n, p) => n + (p.taskTemplates?.length ?? 0), 0);\n this.logger.info(`[AutoPhase] Planned ${phases.length} phases / ${todos} todos for: ${goal}`);\n return phases;\n }\n this.logger.info(`[AutoPhase] Planner produced no phases; using defaults for: ${goal}`);\n } catch (err) {\n this.logger.error(`[AutoPhase] Planning failed, using defaults: ${toErrorMessage(err)}`);\n }\n return this.defaultPhases();\n }\n\n private async executeTaskWithAgent(\n task: import('@wrongstack/core').TaskNode,\n phaseId: string,\n env?: { cwd?: string | undefined; branch?: string | undefined },\n ): Promise<unknown> {\n // Give the task a human worker identity (reuse a manual assignment if one\n // exists) so the board shows who is running it; reflect it on the node and\n // push a live state update before the (long) run begins.\n if (!task.assignee) {\n const nick = assignNickname('executor', this.usedNicknames);\n this.usedNicknames.add(nick.key);\n task.assignee = nick.display.replace(/\\s*\\([^)]*\\)\\s*$/, '');\n task.updatedAt = Date.now();\n this.broadcastState();\n }\n\n // Execute task with agent\n const prompt = `Execute task: ${task.title}\\n\\nDescription: ${task.description}\\nPhase: ${phaseId}\\nPriority: ${task.priority}\\nType: ${task.type}`;\n const signal = this.abort?.signal ?? new AbortController().signal;\n // Redirect the shared context's cwd at the phase worktree for the duration\n // of this task. Safe because phases/tasks run strictly sequentially here;\n // tools read `ctx.cwd` live, so the agent operates inside the worktree.\n const prevCwd = this.context.cwd;\n if (env?.cwd) this.context.cwd = env.cwd;\n try {\n return await this.agent.run(prompt, { signal });\n } finally {\n this.context.cwd = prevCwd;\n }\n }\n\n /** Persist + broadcast after an interactive board mutation. */\n private afterBoardMutation(): void {\n if (this.graph) void this.store.save(this.graph);\n this.broadcastState();\n }\n\n private async handleTaskStatusChange(taskId: string, status: string): Promise<void> {\n if (!this.graph) return;\n\n for (const phase of this.graph.phases.values()) {\n const task = phase.taskGraph.nodes.get(taskId);\n if (task) {\n task.status = status as import('@wrongstack/core').TaskStatus;\n task.updatedAt = Date.now();\n this.broadcastState();\n return;\n }\n }\n }\n\n private startBroadcast(): void {\n if (this.broadcastInterval) return;\n this.broadcastInterval = setInterval(() => {\n const progress = this.orchestrator?.getProgress();\n if (progress) this.broadcast({ type: 'autophase.progress', payload: progress });\n this.broadcastState();\n }, 2000);\n }\n\n private stopBroadcast(): void {\n if (this.broadcastInterval) {\n clearInterval(this.broadcastInterval);\n this.broadcastInterval = null;\n }\n }\n\n private broadcastState(activePhaseId?: string): void {\n if (!this.graph) return;\n\n const state = this.buildState(activePhaseId);\n this.broadcast({ type: 'autophase.state', payload: state });\n }\n\n private buildState(activePhaseId?: string): Record<string, unknown> {\n if (!this.graph) {\n return { phases: [], tasks: [], overallPercent: 0, autonomous: true, title: '' };\n }\n\n const phases = Array.from(this.graph.phases.values());\n const currentActiveId = activePhaseId || phases.find((p) => p.status === 'running')?.id || phases[0]?.id || '';\n const activePhase = this.graph.phases.get(currentActiveId);\n\n const totalTasks = phases.reduce((sum, p) => sum + p.taskGraph.nodes.size, 0);\n const completedTasks = phases.reduce(\n (sum, p) => sum + Array.from(p.taskGraph.nodes.values()).filter((t) => t.status === 'completed').length,\n 0,\n );\n\n // Shared task → board-card mapper. Carries assignee/timestamps so the kanban\n // can show who is on each card and how long it has been running.\n const mapTask = (t: import('@wrongstack/core').TaskNode) => ({\n id: t.id,\n title: t.title,\n description: t.description,\n status: t.status,\n priority: t.priority,\n type: t.type,\n estimateHours: t.estimateHours,\n actualHours: t.actualHours,\n assignee: t.assignee,\n tags: t.tags || [],\n startedAt: t.startedAt,\n completedAt: t.completedAt,\n });\n\n const phaseItems = phases.map((p) => {\n const nodes = Array.from(p.taskGraph.nodes.values());\n const done = nodes.filter((t) => t.status === 'completed').length;\n return {\n id: p.id,\n name: p.name,\n description: p.description,\n status: p.status,\n priority: p.priority,\n estimateHours: p.estimateHours,\n actualDurationMs: p.actualDurationMs,\n startedAt: p.startedAt,\n completedAt: p.completedAt,\n progressPercent: nodes.length > 0 ? Math.round((done / nodes.length) * 100) : 0,\n taskCount: nodes.length,\n completedTasks: done,\n assignedAgents: p.assignedAgents,\n isActive: p.id === currentActiveId,\n // Every phase carries its full task list so the board can render each\n // phase as a column (not just the selected one).\n tasks: nodes.map(mapTask),\n };\n });\n\n // Back-compat: the chat-area TaskBoard still reads the flat active-phase list.\n const taskItems = activePhase ? Array.from(activePhase.taskGraph.nodes.values()).map(mapTask) : [];\n\n const completedPhases = phases.filter((p) => p.status === 'completed').length;\n const failedPhases = phases.filter((p) => p.status === 'failed').length;\n const failedTasks = phases.reduce(\n (sum, p) => sum + Array.from(p.taskGraph.nodes.values()).filter((t) => t.status === 'failed').length,\n 0,\n );\n\n // Surface the most recent failure so the board can show it (the store keeps a\n // `lastError` field the UI renders). Prefer the worktree integration error,\n // else a generic phase-failure note.\n const lastFailed = phases.filter((p) => p.status === 'failed').sort((a, b) => (b.updatedAt ?? 0) - (a.updatedAt ?? 0))[0];\n const lastError = lastFailed\n ? `${lastFailed.name}: ${(lastFailed.metadata?.integrationError as string | undefined) ?? 'phase failed'}`\n : null;\n\n return {\n title: this.graph.title,\n // Full operator prompt, shown verbatim in a dedicated goal block (the\n // title is only a short derived heading). Fall back to the title for\n // legacy boards saved before the title/goal split.\n goal: this.graph.description || this.graph.title,\n phases: phaseItems,\n tasks: taskItems,\n activePhaseId: currentActiveId,\n overallPercent: phases.length > 0 ? Math.round((completedPhases / phases.length) * 100) : 0,\n autonomous: this.graph.autonomous,\n totalTasks,\n completedTasks,\n // Structured progress + lastError consumed by the autophase store (were\n // defined client-side but never sent, so they stayed null on the board).\n progress: {\n totalPhases: phases.length,\n completed: completedPhases,\n failed: failedPhases,\n totalTasks,\n completedTasks,\n failedTasks,\n },\n lastError,\n };\n }\n\n private sendState(client: WSClient): void {\n if (!this.graph) return;\n const state = this.buildState();\n this.send(client, { type: 'autophase.state', payload: state });\n }\n\n private broadcast(msg: { type: string; payload: unknown }): void {\n const data = JSON.stringify(msg);\n for (const client of this.clients) {\n if (client.ws.readyState === 1) { // OPEN\n client.ws.send(data);\n }\n }\n }\n\n private send(client: WSClient, msg: { type: string; payload: unknown }): void {\n if (client.ws.readyState === 1) {\n client.ws.send(JSON.stringify(msg));\n }\n }\n}\n","import type { WebSocket } from 'ws';\nimport {\n computeTaskProgress,\n SpecStore,\n TaskGraphStore,\n type Specification,\n type TaskGraph,\n type TaskNode,\n} from '@wrongstack/core';\n\ninterface WSClient {\n ws: WebSocket;\n id: string;\n}\n\ninterface SpecsWSMessage {\n type: string;\n payload?: Record<string, unknown>;\n}\n\n/** A task as rendered on the FORGE-style dependency board. */\ninterface BoardTask {\n id: string;\n shortId: string;\n title: string;\n description: string;\n priority: TaskNode['priority'];\n type: TaskNode['type'];\n status: TaskNode['status'];\n /** Derived label for the legend: 'queued' = pending with all blockers done. */\n displayStatus: TaskNode['status'] | 'queued';\n deps: string[];\n}\n\n/**\n * SpecsWebSocketHandler — read-only-ish browser of persisted SDD specs and their\n * task graphs, rendered as a FORGE-style dependency board (topological phase\n * columns + dependency refs). Shared by both webui servers via specs-routes.\n *\n * Message types:\n * specs.list → all specs + progress\n * specs.get { specId } → one spec's dependency board\n * specs.taskStatus { graphId, taskId, status } → update + rebroadcast\n */\nexport class SpecsWebSocketHandler {\n private specStore: SpecStore;\n private graphStore: TaskGraphStore;\n private clients = new Set<WSClient>();\n\n constructor(specsDir: string, taskGraphsDir: string) {\n this.specStore = new SpecStore({ baseDir: specsDir });\n this.graphStore = new TaskGraphStore({ baseDir: taskGraphsDir });\n }\n\n addClient(ws: WebSocket): void {\n const client: WSClient = { ws, id: crypto.randomUUID() };\n this.clients.add(client);\n ws.on('close', () => this.clients.delete(client));\n ws.on('error', () => this.clients.delete(client));\n void this.sendList(client);\n }\n\n async handleMessage(msg: SpecsWSMessage): Promise<void> {\n switch (msg.type) {\n case 'specs.list':\n await this.broadcastList();\n break;\n case 'specs.get': {\n const specId = msg.payload?.specId as string | undefined;\n if (specId) await this.broadcastDetail(specId);\n break;\n }\n case 'specs.taskStatus': {\n const { graphId, taskId, status } = msg.payload as {\n graphId: string;\n taskId: string;\n status: TaskNode['status'];\n };\n await this.updateTaskStatus(graphId, taskId, status);\n break;\n }\n }\n }\n\n // ── List ──────────────────────────────────────────────────────────────────\n\n private async buildList(): Promise<unknown[]> {\n const [specs, graphs] = await Promise.all([this.specStore.list(), this.graphStore.list()]);\n return specs.map((s, i) => {\n const graph = graphs.find((g) => g.specId === s.id);\n return {\n id: s.id,\n // FORGE-style display id (spec-001…). The real UUID stays in `id`.\n displayId: `spec-${String(i + 1).padStart(3, '0')}`,\n title: s.title,\n status: s.status,\n graphId: graph?.id,\n total: graph?.nodeCount ?? 0,\n completed: graph?.completedCount ?? 0,\n };\n });\n }\n\n private async broadcastList(): Promise<void> {\n this.broadcast({ type: 'specs.list', payload: { specs: await this.buildList() } });\n }\n\n private async sendList(client: WSClient): Promise<void> {\n this.send(client, { type: 'specs.list', payload: { specs: await this.buildList() } });\n }\n\n // ── Detail (dependency board) ───────────────────────────────────────────────\n\n private async broadcastDetail(specId: string): Promise<void> {\n const spec = await this.specStore.load(specId);\n const graph = await this.findGraphForSpec(specId);\n if (!spec || !graph) {\n this.broadcast({ type: 'specs.detail', payload: { specId, columns: [], notFound: true } });\n return;\n }\n this.broadcast({ type: 'specs.detail', payload: this.buildDetail(spec, graph) });\n }\n\n private async findGraphForSpec(specId: string): Promise<TaskGraph | null> {\n const entry = (await this.graphStore.list()).find((g) => g.specId === specId);\n if (!entry) return null;\n return this.graphStore.load(entry.id);\n }\n\n private buildDetail(spec: Specification, graph: TaskGraph): Record<string, unknown> {\n const nodes = Array.from(graph.nodes.values()).sort((a, b) => a.createdAt - b.createdAt);\n // Stable short ids (t01, t02, …) in creation order, FORGE-style.\n const shortId = new Map<string, string>();\n nodes.forEach((n, i) => {\n shortId.set(n.id, `t${String(i + 1).padStart(2, '0')}`);\n });\n\n // Blockers per node (depends_on edges pointing at the node).\n const blockers = new Map<string, string[]>();\n for (const n of nodes) blockers.set(n.id, []);\n for (const e of graph.edges) {\n if (e.type === 'depends_on') blockers.get(e.to)?.push(e.from);\n }\n\n const statusOf = (id: string) => graph.nodes.get(id)?.status;\n const depthCache = new Map<string, number>();\n const depthOf = (id: string, seen = new Set<string>()): number => {\n const cached = depthCache.get(id);\n if (cached !== undefined) return cached;\n if (seen.has(id)) return 0; // cycle guard\n seen.add(id);\n const deps = blockers.get(id) ?? [];\n const d = deps.length === 0 ? 0 : 1 + Math.max(...deps.map((b) => depthOf(b, seen)));\n depthCache.set(id, d);\n return d;\n };\n\n const toBoardTask = (n: TaskNode): BoardTask => {\n const deps = blockers.get(n.id) ?? [];\n const allDepsDone = deps.every((b) => statusOf(b) === 'completed');\n const displayStatus = n.status === 'pending' && deps.length > 0 && allDepsDone ? 'queued' : n.status;\n return {\n id: n.id,\n shortId: shortId.get(n.id) ?? n.id.slice(0, 6),\n title: n.title,\n description: n.description,\n priority: n.priority,\n type: n.type,\n status: n.status,\n displayStatus,\n deps: deps.map((b) => shortId.get(b) ?? b.slice(0, 6)),\n };\n };\n\n // Group into topological columns: depth 0 → \"Start\", depth k → \"Phase k\".\n const byDepth = new Map<number, BoardTask[]>();\n for (const n of nodes) {\n const d = depthOf(n.id);\n if (!byDepth.has(d)) byDepth.set(d, []);\n byDepth.get(d)?.push(toBoardTask(n));\n }\n const columns = [...byDepth.keys()]\n .sort((a, b) => a - b)\n .map((d) => ({ label: d === 0 ? 'Start' : `Phase ${d}`, tasks: byDepth.get(d) ?? [] }));\n\n const progress = computeTaskProgress(graph);\n return {\n specId: spec.id,\n graphId: graph.id,\n title: spec.title,\n overview: spec.overview,\n status: spec.status,\n total: progress.total,\n completed: progress.completed,\n running: progress.inProgress,\n pending: progress.pending,\n columns,\n };\n }\n\n private async updateTaskStatus(\n graphId: string,\n taskId: string,\n status: TaskNode['status'],\n ): Promise<void> {\n const graph = await this.graphStore.load(graphId);\n const node = graph?.nodes.get(taskId);\n if (!graph || !node) return;\n node.status = status;\n node.updatedAt = Date.now();\n graph.updatedAt = Date.now();\n await this.graphStore.save(graph);\n this.broadcastDetail(graph.specId).catch(() => {});\n await this.broadcastList();\n }\n\n // ── Transport ───────────────────────────────────────────────────────────────\n\n private broadcast(msg: { type: string; payload: unknown }): void {\n const data = JSON.stringify(msg);\n for (const client of this.clients) {\n if (client.ws.readyState === 1) client.ws.send(data);\n }\n }\n\n private send(client: WSClient, msg: { type: string; payload: unknown }): void {\n if (client.ws.readyState === 1) client.ws.send(JSON.stringify(msg));\n }\n}\n","import type { WebSocket } from 'ws';\nimport type { EventBus, SddBoardSnapshot } from '@wrongstack/core';\nimport { SddBoardStore } from '@wrongstack/core';\n\ninterface WSClient {\n ws: WebSocket;\n id: string;\n}\n\ninterface SddBoardWSMessage {\n type: string;\n payload?: Record<string, unknown>;\n}\n\nconst CONTROL_TYPES = new Set([\n 'pause',\n 'resume',\n 'stop',\n 'retry',\n 'retry_all_failed',\n 'reassign',\n // Per-task model / fallback / verification assignment + stop/delete (drained by start-sdd-run).\n 'set_task_model',\n 'set_task_fallbacks',\n 'set_task_verification',\n 'cancel_task',\n 'delete_task',\n 'split_task',\n // Lifecycle (pair with a prior `stop`): sweep worktrees / revert merged commits.\n 'cleanup_worktrees',\n 'rollback',\n]);\n\n/**\n * SddBoardWebSocketHandler — streams the live SDD multi-agent board to clients\n * and relays control commands back to the CLI-owned run.\n *\n * Two observe modes (one class, shared by both webui servers):\n * • in-process (CLI-hosted): subscribe the shared EventBus `sdd.board.snapshot`\n * for instant updates;\n * • standalone (separate process): poll the on-disk snapshot store (the CLI\n * run persists JSON every change).\n *\n * Control is uniform + cross-process: every command is appended to the run's\n * `<runId>.control.jsonl`, which the CLI run drains and applies — so the run\n * stays the single driver and nothing races on shared state.\n */\nexport class SddBoardWebSocketHandler {\n private readonly store: SddBoardStore;\n private readonly clients = new Set<WSClient>();\n private latest: SddBoardSnapshot | null = null;\n private poll: ReturnType<typeof setInterval> | null = null;\n private unsub: (() => void) | null = null;\n\n constructor(boardsDir: string, events?: EventBus) {\n this.store = new SddBoardStore({ baseDir: boardsDir });\n\n if (events) {\n // Instant updates in the CLI-hosted server (shared bus).\n const handler = (e: { runId: string; snapshot: SddBoardSnapshot }) => {\n this.latest = e.snapshot;\n this.broadcast({ type: 'sdd.board.snapshot', payload: e.snapshot });\n };\n this.unsub = events.on('sdd.board.snapshot', handler as (p: unknown) => void);\n } else {\n // Standalone server (other process): poll the persisted snapshot.\n this.poll = setInterval(() => void this.pollLatest(), 1000);\n }\n }\n\n addClient(ws: WebSocket): void {\n const client: WSClient = { ws, id: crypto.randomUUID() };\n this.clients.add(client);\n ws.on('close', () => this.clients.delete(client));\n ws.on('error', () => this.clients.delete(client));\n // Send the current board immediately (from memory or disk).\n void this.sendCurrent(client);\n }\n\n async handleMessage(msg: SddBoardWSMessage): Promise<void> {\n if (msg.type === 'sdd.board.get') {\n await this.broadcastCurrent();\n return;\n }\n if (msg.type === 'sdd.board.list') {\n const boards = await this.store.list();\n this.broadcast({ type: 'sdd.board.list', payload: { boards } });\n return;\n }\n const action = msg.type.replace(/^sdd\\.board\\./, '');\n if (CONTROL_TYPES.has(action)) {\n const runId =\n (msg.payload?.runId as string | undefined) ??\n this.latest?.runId ??\n (await this.store.list())[0]?.runId;\n if (runId) {\n await this.store.appendControl(runId, {\n ts: Date.now(),\n type: action,\n payload: msg.payload,\n });\n }\n }\n }\n\n dispose(): void {\n if (this.poll) clearInterval(this.poll);\n this.unsub?.();\n this.poll = null;\n this.unsub = null;\n }\n\n // ── internal ────────────────────────────────────────────────────────────\n\n private async pollLatest(): Promise<void> {\n const entry = (await this.store.list())[0];\n if (!entry) return;\n if (this.latest && this.latest.updatedAt >= entry.updatedAt && this.latest.runId === entry.runId) {\n return; // nothing newer\n }\n const snap = await this.store.load(entry.runId);\n if (snap) {\n this.latest = snap;\n this.broadcast({ type: 'sdd.board.snapshot', payload: snap });\n }\n }\n\n private async sendCurrent(client: WSClient): Promise<void> {\n const snap = this.latest ?? (await this.loadLatestFromDisk());\n if (snap) this.send(client, { type: 'sdd.board.snapshot', payload: snap });\n }\n\n private async broadcastCurrent(): Promise<void> {\n const snap = this.latest ?? (await this.loadLatestFromDisk());\n if (snap) this.broadcast({ type: 'sdd.board.snapshot', payload: snap });\n }\n\n private async loadLatestFromDisk(): Promise<SddBoardSnapshot | null> {\n const entry = (await this.store.list())[0];\n return entry ? this.store.load(entry.runId) : null;\n }\n\n private broadcast(msg: { type: string; payload: unknown }): void {\n const data = JSON.stringify(msg);\n for (const client of this.clients) {\n if (client.ws.readyState === 1) client.ws.send(data);\n }\n }\n\n private send(client: WSClient, msg: { type: string; payload: unknown }): void {\n if (client.ws.readyState === 1) client.ws.send(JSON.stringify(msg));\n }\n}\n","import type { WebSocket } from 'ws';\nimport type { SddInterviewDriver, SddInterviewSnapshot } from '@wrongstack/core';\n\ninterface WSClient {\n ws: WebSocket;\n id: string;\n}\n\ninterface WizardMessage {\n type: string;\n payload?: Record<string, unknown>;\n}\n\n/** Short, single-line heading derived from a (possibly long) goal prompt. */\nfunction deriveTitle(goal: string): string {\n const firstLine = goal\n .split('\\n')\n .map((l) => l.trim())\n .find(Boolean);\n if (!firstLine) return 'New SDD Project';\n const sentence = firstLine.split(/(?<=[.!?])\\s/)[0] ?? firstLine;\n return sentence.length <= 64 ? sentence : `${sentence.slice(0, 63).trimEnd()}…`;\n}\n\n/**\n * Dependencies each webui server supplies. The handler is deliberately\n * agent-agnostic: every surface decides how to build a driver, how to run an\n * interview turn (on an isolated agent, off the main chat bus), and how to\n * start the real multi-agent run (CLI's director-backed factory vs the runtime\n * light factory). This keeps the wizard protocol identical across both servers.\n */\nexport interface SddWizardDeps {\n /** Build a fresh interview driver (disk spec/graph stores + session path). */\n makeDriver: () => SddInterviewDriver;\n /**\n * Run one interview turn: feed the AI prompt to an isolated agent and return\n * its final text. MUST NOT run on the main chat agent's bus — the wizard owns\n * this conversation, separate from the user's chat.\n */\n runInterviewTurn: (prompt: string) => Promise<string>;\n /**\n * Start the real multi-agent SDD run for the driver's task graph. Returns the\n * runId; the live board flows through the existing board handler.\n */\n startRun: (\n driver: SddInterviewDriver,\n opts: {\n parallelSlots?: number | undefined;\n defaultModel?: string | undefined;\n defaultProvider?: string | undefined;\n fallbackModels?: string[] | undefined;\n /** Per-run worktree-isolation override; undefined → env default. */\n worktrees?: boolean | undefined;\n },\n ) => Promise<{ runId: string }>;\n}\n\n/**\n * SddWizardWebSocketHandler — drives the interactive \"New SDD Project\" wizard\n * (goal → Q&A → spec → task graph → start run) over WebSocket. Shared by both\n * webui servers; server-specific construction (agent, factory) is injected via\n * {@link SddWizardDeps}.\n */\nexport class SddWizardWebSocketHandler {\n private readonly clients = new Set<WSClient>();\n private driver: SddInterviewDriver | null = null;\n /** The agent's most recent question — paired with the next user answer. */\n private lastAgentText = '';\n /** Guards against overlapping interview turns (one in flight at a time). */\n private busy = false;\n\n constructor(private readonly deps: SddWizardDeps) {}\n\n addClient(ws: WebSocket): void {\n const client: WSClient = { ws, id: crypto.randomUUID() };\n this.clients.add(client);\n ws.on('close', () => this.clients.delete(client));\n ws.on('error', () => this.clients.delete(client));\n // Send the current interview state (if any) so a reconnecting client catches up.\n if (this.driver) this.send(client, this.snapshotMsg());\n }\n\n async handleMessage(msg: WizardMessage): Promise<void> {\n try {\n switch (msg.type) {\n case 'sdd.spec.start':\n await this.onStart(String(msg.payload?.goal ?? '').trim());\n break;\n case 'sdd.spec.message':\n await this.onMessage(String(msg.payload?.text ?? ''));\n break;\n case 'sdd.spec.approve':\n await this.onApprove();\n break;\n case 'sdd.spec.get':\n if (this.driver) this.broadcast(this.snapshotMsg());\n break;\n case 'sdd.run.start':\n await this.onRunStart({\n parallelSlots: msg.payload?.parallelSlots as number | undefined,\n defaultModel: msg.payload?.model as string | undefined,\n defaultProvider: msg.payload?.provider as string | undefined,\n fallbackModels: Array.isArray(msg.payload?.fallbackModels)\n ? (msg.payload?.fallbackModels as string[])\n : undefined,\n worktrees: typeof msg.payload?.worktrees === 'boolean' ? msg.payload.worktrees : undefined,\n });\n break;\n }\n } catch (err) {\n this.busy = false;\n this.broadcast({\n type: 'sdd.spec.error',\n payload: { message: err instanceof Error ? err.message : String(err) },\n });\n }\n }\n\n // ── message handlers ──────────────────────────────────────────────────────\n\n private async onStart(goal: string): Promise<void> {\n if (!goal) {\n this.broadcast({ type: 'sdd.spec.error', payload: { message: 'A goal is required.' } });\n return;\n }\n if (this.busy) return;\n this.driver = this.deps.makeDriver();\n // Keep the operator's full prompt as the interview's intent/goal, but give\n // the session a short readable title — pasting the whole prompt as the title\n // made the wizard header unreadable.\n const prompt = this.driver.start(deriveTitle(goal), goal);\n await this.runTurn(prompt);\n }\n\n private async onMessage(text: string): Promise<void> {\n if (!this.driver || this.busy) return;\n // In the questioning phase, the user's message answers the agent's last\n // question. In review phases a free-form message is fed back as context.\n if (this.driver.phase() === 'questioning' && this.lastAgentText) {\n this.driver.submitAnswer(this.lastAgentText, text);\n } else {\n this.driver.submitAnswer(this.lastAgentText || '(feedback)', text);\n }\n await this.runTurn(this.driver.currentPrompt());\n }\n\n private async onApprove(): Promise<void> {\n if (!this.driver || this.busy) return;\n const { phase, prompt } = await this.driver.approve();\n // Executing phase needs no further AI turn — the graph is ready to run.\n if (phase === 'executing') {\n this.broadcast(this.snapshotMsg());\n return;\n }\n await this.runTurn(prompt);\n }\n\n private async onRunStart(opts: {\n parallelSlots?: number | undefined;\n defaultModel?: string | undefined;\n defaultProvider?: string | undefined;\n fallbackModels?: string[] | undefined;\n worktrees?: boolean | undefined;\n }): Promise<void> {\n if (!this.driver) {\n this.broadcast({ type: 'sdd.spec.error', payload: { message: 'No active spec session.' } });\n return;\n }\n // Guarantee a graph exists (deterministic fallback if the agent never\n // emitted a task array).\n const graph = await this.driver.ensureTaskGraph();\n if (!graph) {\n this.broadcast({\n type: 'sdd.spec.error',\n payload: { message: 'No spec yet — finish the interview before starting a run.' },\n });\n return;\n }\n const { runId } = await this.deps.startRun(this.driver, opts);\n this.broadcast({ type: 'sdd.run.started', payload: { runId } });\n }\n\n // ── internals ───────────────────────────────────────────────────────────\n\n /** Run one interview turn against the isolated agent, then ingest + broadcast. */\n private async runTurn(prompt: string): Promise<void> {\n this.busy = true;\n this.broadcast(this.snapshotMsg());\n try {\n const text = await this.deps.runInterviewTurn(prompt);\n this.lastAgentText = text;\n if (this.driver) await this.driver.ingestAgentOutput(text);\n this.broadcast({ type: 'sdd.spec.agent_text', payload: { text } });\n } finally {\n this.busy = false;\n this.broadcast(this.snapshotMsg());\n }\n }\n\n private snapshotMsg(): { type: string; payload: SddInterviewSnapshot & { busy: boolean } } {\n const snap = this.driver?.snapshot();\n return {\n type: 'sdd.spec.snapshot',\n payload: { ...(snap as SddInterviewSnapshot), busy: this.busy },\n };\n }\n\n private broadcast(msg: { type: string; payload: unknown }): void {\n const data = JSON.stringify(msg);\n for (const client of this.clients) {\n if (client.ws.readyState === 1) client.ws.send(data);\n }\n }\n\n private send(client: WSClient, msg: { type: string; payload: unknown }): void {\n if (client.ws.readyState === 1) client.ws.send(JSON.stringify(msg));\n }\n}\n","import * as path from 'node:path';\nimport { spawnSync } from 'node:child_process';\nimport {\n type Agent,\n type AgentFactory,\n type BrainArbiter,\n type EventBus,\n makeCommandVerifier,\n makeLlmSubtaskGenerator,\n SddBoardStore,\n SddInterviewDriver,\n SddRunRegistry,\n SddSupervisor,\n SpecStore,\n startSddRun,\n TaskGraphStore,\n WorktreeManager,\n} from '@wrongstack/core';\nimport type { SddWizardDeps } from './sdd-wizard-ws-handler.js';\n\nexport interface SddWizardWiringOptions {\n /** Leader agent — seeds the run's default factory + project context. */\n agent: Agent;\n /** Shared EventBus — the board projector emits sdd.board.snapshot on it. */\n events: EventBus;\n projectRoot: string;\n /** Per-task agent factory: CLI's director-backed one, or the runtime light one. */\n subagentFactory: AgentFactory;\n /**\n * Decision authority for the failure supervisor (the server's bound\n * TOKENS.BrainArbiter). Omit to run without a supervisor (plain terminal-fail,\n * matching a bare run) — but parity with the CLI wants it wired.\n */\n brain?: BrainArbiter | undefined;\n /** Persisted-store directories (from resolveWstackPaths). */\n paths: {\n projectSpecs: string;\n projectTaskGraphs: string;\n projectSddBoards: string;\n projectDir: string;\n };\n}\n\n/**\n * Build the {@link SddWizardDeps} shared by both webui servers from a single\n * per-task `subagentFactory`. The factory drives BOTH the interview agent (an\n * isolated turn off the main chat bus) and the real multi-agent run, so each\n * server only has to supply the right factory for its process.\n */\n/**\n * Prepended to every isolated interview/splitter turn. Keeps the spec interview\n * a pure planning conversation — no file writes, no shell — regardless of how\n * \"implement\"-flavoured the underlying phase prompt reads.\n */\nconst PLANNING_ONLY_GUARD =\n 'SYSTEM: You are running a PLANNING-ONLY specification interview. Do NOT write, ' +\n 'create, or edit any files, and do NOT run shell/terminal commands or use any ' +\n 'code-editing tools — they are disabled here and any attempt will fail and waste ' +\n 'the turn. Respond with TEXT ONLY: ask your question, or emit the requested spec / ' +\n 'plan / task JSON. All code is written later, automatically, once the plan is ' +\n 'approved and the multi-agent run starts.\\n\\n---\\n\\n';\n\nexport function buildSddWizardDeps(opts: SddWizardWiringOptions): SddWizardDeps {\n const registry = new SddRunRegistry();\n let isolatedSeq = 0;\n\n /**\n * Run one self-contained, read-only LLM turn on a fresh isolated agent (off the\n * main chat bus). Shared by the interview and the supervisor's subtask splitter:\n * both feed a self-embedding prompt, want no shared context, and must NOT edit\n * the repo (restricted to the read-only capability floor; the execute phase is\n * where writes happen). The factory's per-turn cleanup is invoked here because\n * we drive it directly, not via makeAgentSubagentRunner.\n *\n * The interview is PLANNING-ONLY: it must never write code. The read-only\n * capability floor already denies fs.write/shell, but a capable model will\n * still *attempt* a write/bash call when the implementation-planning prompt\n * mentions \"implement\" — the call then fails and derails the turn. So we belt-\n * and-suspenders it: (1) disable the mutating tools by name, and (2) prepend an\n * explicit text guard so the agent never even tries. Code is written later, by\n * the real run, after the plan is approved.\n */\n const runIsolatedTurn = async (prompt: string, name: string): Promise<string> => {\n const result = await opts.subagentFactory({\n id: `sdd-${name.toLowerCase().replace(/\\s+/g, '-')}-${isolatedSeq++}`,\n role: 'executor',\n name,\n disabledTools: ['delegate', 'write', 'edit', 'patch', 'bash', 'exec'],\n allowedCapabilities: ['fs.read', 'net.outbound'],\n });\n try {\n const res = await result.agent.run([{ type: 'text', text: PLANNING_ONLY_GUARD + prompt }]);\n return res.finalText ?? '';\n } finally {\n await result.dispose?.();\n }\n };\n\n return {\n makeDriver: () =>\n new SddInterviewDriver({\n specStore: new SpecStore({ baseDir: opts.paths.projectSpecs }),\n graphStore: new TaskGraphStore({ baseDir: opts.paths.projectTaskGraphs }),\n sessionPath: path.join(opts.paths.projectDir, 'sdd-wizard-session.json'),\n }),\n\n runInterviewTurn: (prompt: string): Promise<string> => runIsolatedTurn(prompt, 'Spec Architect'),\n\n startRun: async (\n driver,\n { parallelSlots, defaultModel, defaultProvider, fallbackModels, worktrees: useWorktrees },\n ) => {\n const graph = driver.getGraph();\n const tracker = driver.getTracker();\n if (!graph || !tracker) {\n throw new Error('No task graph to run — finish the interview first.');\n }\n\n // Per-task git-worktree isolation. The per-run UI toggle wins; when it is\n // omitted we fall back to the env default (disable with\n // WRONGSTACK_SDD_WORKTREES=0). Mirrors the CLI /sdd execute path.\n const worktreesEnabled = useWorktrees ?? process.env['WRONGSTACK_SDD_WORKTREES'] !== '0';\n let worktrees: WorktreeManager | undefined;\n if (worktreesEnabled) {\n const inGit =\n spawnSync('git', ['rev-parse', '--is-inside-work-tree'], {\n cwd: opts.projectRoot,\n encoding: 'utf8',\n windowsHide: true,\n }).stdout?.trim() === 'true';\n if (inGit) worktrees = new WorktreeManager({ projectRoot: opts.projectRoot, events: opts.events });\n }\n\n const boardStore = new SddBoardStore({ baseDir: opts.paths.projectSddBoards });\n\n // Parity with the CLI `/sdd parallel` path: gate completion on a per-task\n // verificationCommand and let the Brain rescue a retry-exhausted task\n // instead of dead-ending. Both are shared with cli-main.ts.\n const verifyTask = makeCommandVerifier();\n const superviseFailure = opts.brain\n ? new SddSupervisor({\n brain: opts.brain,\n // The run-level fallback chain (chosen in the wizard) doubles as the\n // supervisor's reassign options — a `reassign` verdict rotates the\n // worker model on retry. Empty/undefined → reassign option dropped.\n reassignModels: fallbackModels,\n // LLM auto-split: decompose a retry-exhausted task into smaller\n // sub-tasks on an isolated read-only turn. Heavily validated +\n // bounded; an empty result degrades the split into a retry.\n generateSubtasks: makeLlmSubtaskGenerator({\n run: (prompt) => runIsolatedTurn(prompt, 'Task Splitter'),\n }),\n // The standalone brain is a tiered policy→LLM arbiter with NO\n // human-escalation wrapper (see index.ts), so it never blocks on a\n // human prompt — an unresolved verdict degrades to a bounded retry.\n // Safe to let the LLM layer actually pick reassign/split.\n requestLlmVerdict: true,\n }).superviseFailure\n : undefined;\n\n const handle = startSddRun({\n tracker,\n graph,\n agent: opts.agent,\n projectRoot: opts.projectRoot,\n events: opts.events,\n subagentFactory: opts.subagentFactory,\n worktrees,\n boardStore,\n registry,\n parallelSlots,\n defaultModel,\n defaultProvider,\n fallbackModels,\n verifyTask,\n superviseFailure,\n });\n // The board surfaces progress (events + disk); we don't block the wizard\n // on completion. Swallow rejections so a failed run can't crash the server.\n void handle.completion.catch(() => {});\n return { runId: handle.runId };\n },\n };\n}\n","import type { WebSocket } from 'ws';\nimport type { WSClientMessage } from './types.js';\n\nexport interface SddWizardRouteHandlers {\n handleMessage: (msg: { type: string; payload?: Record<string, unknown> }) => Promise<void>;\n}\n\n/**\n * Forward the SDD wizard messages (`sdd.spec.*` and `sdd.run.start`) to the\n * SddWizardWebSocketHandler. Note `sdd.board.*` is handled separately by the\n * board route — the wizard owns spec-building + run kickoff, the board owns\n * live observation/control.\n */\nexport async function handleSddWizardRoute(\n _ws: WebSocket,\n msg: WSClientMessage,\n handlers: SddWizardRouteHandlers,\n): Promise<boolean> {\n if (!(msg.type.startsWith('sdd.spec.') || msg.type.startsWith('sdd.run.'))) return false;\n await handlers.handleMessage(msg as { type: string; payload?: Record<string, unknown> });\n return true;\n}\n","import { randomUUID } from 'node:crypto';\nimport type { WebSocket } from 'ws';\nimport type { CollaborationBus, ConsumedInjectionInfo, EventBus, Logger } from '@wrongstack/core';\nimport type { AnnotationsStore, SessionReader } from '@wrongstack/core/storage';\nimport { toErrorMessage } from '@wrongstack/core/utils';\nimport type {\n CollabRole,\n WSCollabState,\n WSServerMessage,\n} from '../types.js';\n\n/** How many historical events to replay to a late-joining observer. */\nconst REPLAY_LIMIT = 50;\n\n/** How long the middleware waits before auto-resuming (mirrors the middleware default). */\nconst PAUSE_TIMEOUT_MS = 60_000;\n\n/**\n * CollaborationWebSocketHandler — passive read-only session observer (Phase 1\n * of idea #13 from IDEAS.md). Mirrors `WorktreeWebSocketHandler` and\n * `AutoPhaseWebSocketHandler`.\n *\n * Capabilities in this phase:\n * - A second human (or any client) joins an active agent run as an\n * `observer` and receives a live mirror of the kernel's iteration /\n * tool / subagent events.\n * - The observer declares a `sessionId` on join (used for state scoping\n * and future replay-on-join). Live event routing is session-agnostic\n * for now — see the limitation note below.\n * - The observer can leave at any time; cleanup runs on WS close/error.\n * - The observer CANNOT modify the agent's state, pause it, or inject\n * tool calls. Those capabilities land in Phase 2/3.\n *\n * Limitation (documented, acceptable for Phase 1):\n * The webui server multiplexes every active session onto a single\n * EventBus, and most event payloads (`tool.started`, `iteration.*`,\n * `subagent.*`) do NOT carry a `sessionId` field. The webui's primary\n * WS path works because it is the only consumer and assumes one\n * active session at a time. We mirror that assumption here. When a\n * future multi-session \"session router\" lands, this handler will be\n * upgraded to filter by sessionId.\n *\n * Protocol additions (see `packages/webui/src/types.ts`):\n * client → server: collab.join { sessionId, role: 'observer' }\n * collab.leave { sessionId }\n * server → client: collab.state (initial + 2s periodic)\n * collab.participant.joined\n * collab.participant.left\n * collab.event (live kernel event mirror)\n */\nexport class CollaborationWebSocketHandler {\n private readonly clients = new Set<WebSocket>();\n /** sessionId → participants currently watching it. */\n private readonly bySession = new Map<string, Set<Participant>>();\n private broadcastInterval: ReturnType<typeof setInterval> | null = null;\n private readonly offs: Array<() => void> = [];\n\n constructor(\n private readonly events: EventBus,\n private readonly logger: Logger,\n /**\n * Optional reader over the on-disk session log. When provided, late\n * joiners receive the last `REPLAY_LIMIT` events of the joined\n * session before live mirroring begins. Without a reader, joining\n * is still allowed — the observer simply starts from \"now\" with no\n * historical context.\n */\n private readonly reader?: SessionReader | undefined,\n /**\n * Optional sidecar store for collaboration annotations. Required\n * for the `annotator` role — without it, `collab.annotate` messages\n * are rejected with an error.\n */\n private readonly annotations?: AnnotationsStore | undefined,\n /**\n * Optional kernel-level pause/resume bus. Required for the\n * `controller` role — without it, `collab.request_pause` is rejected\n * with an error. Wired to the agent's `toolCall` pipeline via\n * `collabPauseMiddleware` in the webui server boot.\n */\n private readonly bus?: CollaborationBus | undefined,\n ) {\n this.subscribe();\n // Phase 4 feedback loop: when the inject middleware applies a queued\n // injection, broadcast a `consumed` grant so observers see it landed.\n this.bus?.onInjectionConsumed((info) => this.broadcastInjectionConsumed(info));\n }\n\n // ── Public API (called by server/index.ts per WS connection) ───────────\n\n addClient(ws: WebSocket): void {\n this.clients.add(ws);\n this.ensureBroadcast();\n ws.on('close', () => this.handleDisconnect(ws));\n ws.on('error', () => this.handleDisconnect(ws));\n }\n\n dispose(): void {\n for (const off of this.offs) off();\n this.offs.length = 0;\n this.stopBroadcast();\n }\n\n // ── Inbound client messages ────────────────────────────────────────────\n\n /**\n * Dispatch a parsed client message. Returns true when the message was\n * recognized and handled; false when the caller should ignore / log.\n * Phase 1 only knows `collab.join` and `collab.leave`; unknown types\n * return false so the upstream router can decide.\n */\n handleMessage(\n ws: WebSocket,\n msg: { type: string; payload?: unknown | undefined },\n ): boolean {\n if (msg.type === 'collab.join') {\n const payload = msg.payload as { sessionId?: string | undefined; role?: CollabRole | undefined } | undefined;\n if (!payload?.sessionId) {\n this.send(ws, this.errorMessage('collab.join requires sessionId'));\n return true;\n }\n // The `role` field is accepted on the wire for forward-compat;\n // 'controller' (Phase 3) is not yet wired and is rejected here.\n this.join(ws, payload.sessionId, payload.role ?? 'observer');\n return true;\n }\n if (msg.type === 'collab.leave') {\n this.leave(ws);\n return true;\n }\n if (msg.type === 'collab.annotate') {\n void this.handleAnnotate(ws, msg.payload);\n return true;\n }\n if (msg.type === 'collab.resolve') {\n void this.handleResolve(ws, msg.payload);\n return true;\n }\n if (msg.type === 'collab.request_pause') {\n void this.handleRequestPause(ws, msg.payload);\n return true;\n }\n if (msg.type === 'collab.resume') {\n void this.handleResume(ws, msg.payload);\n return true;\n }\n if (msg.type === 'collab.grant_control') {\n void this.handleGrantControl(ws, msg.payload);\n return true;\n }\n if (msg.type === 'collab.inject_tool') {\n void this.handleInjectTool(ws, msg.payload);\n return true;\n }\n return false;\n }\n\n // ── Join / leave flow ──────────────────────────────────────────────────\n\n private join(ws: WebSocket, sessionId: string, role: CollabRole): void {\n if (role === 'controller' && !this.bus) {\n this.send(\n ws,\n this.errorMessage(\n `role 'controller' is not available: server has no CollaborationBus`,\n ),\n );\n return;\n }\n if (role === 'annotator' && !this.annotations) {\n this.send(\n ws,\n this.errorMessage(\n `role 'annotator' is not available: server has no annotations store`,\n ),\n );\n return;\n }\n const participant: Participant = {\n participantId: randomUUID(),\n ws,\n sessionId,\n role,\n joinedAt: new Date().toISOString(),\n };\n let bucket = this.bySession.get(sessionId);\n if (!bucket) {\n bucket = new Set();\n this.bySession.set(sessionId, bucket);\n }\n bucket.add(participant);\n\n // Per-participant hello: send the current state snapshot immediately\n // so the new observer knows who else is watching. Then broadcast the\n // join event AND a fresh state to every participant (including the\n // newcomer) so existing observers see the updated count without\n // waiting for the 2s timer.\n this.send(ws, this.stateMessage(sessionId));\n this.broadcast(sessionId, {\n type: 'collab.participant.joined',\n payload: {\n participantId: participant.participantId,\n sessionId,\n role,\n joinedAt: participant.joinedAt,\n },\n });\n this.broadcast(sessionId, this.stateMessage(sessionId));\n\n // Replay last N events to give the late joiner historical context.\n // Best-effort: failures are logged and silently ignored — the live\n // mirror continues regardless.\n if (this.reader) {\n this.replayHistory(ws, sessionId).catch((err) => {\n this.logger.debug?.(\n `collab: replay failed for ${sessionId}: ${\n toErrorMessage(err)\n }`,\n );\n });\n }\n this.logger.debug?.(\n `collab: participant ${participant.participantId} joined ${sessionId}`,\n );\n }\n\n private leave(ws: WebSocket): void {\n this.handleDisconnect(ws);\n }\n\n private handleDisconnect(ws: WebSocket): void {\n this.clients.delete(ws);\n // Remove from every session bucket the WS may have joined (a single\n // WS is in at most one bucket in Phase 1, but the loop is cheap and\n // future-proofs multi-session observers).\n //\n // Order matters:\n // 1. Send `participant.left` to the leaving ws so they get a\n // confirmation that their leave registered.\n // 2. Delete from bucket.\n // 3. Broadcast the fresh state to remaining observers so they\n // see the updated count without waiting for the 2s timer.\n for (const [sessionId, bucket] of this.bySession) {\n for (const p of bucket) {\n if (p.ws === ws) {\n const leftEvent = {\n type: 'collab.participant.left' as const,\n payload: { participantId: p.participantId, sessionId },\n };\n // Send directly to the leaving ws first so they get an\n // immediate confirmation, then broadcast to the rest of the\n // bucket (which is still inclusive of the leaving ws here —\n // the per-iteration below strips it out).\n this.send(ws, leftEvent);\n bucket.delete(p);\n if (bucket.size === 0) {\n this.bySession.delete(sessionId);\n } else {\n this.broadcast(sessionId, leftEvent);\n this.broadcast(sessionId, this.stateMessage(sessionId));\n }\n break;\n }\n }\n }\n if (this.bySession.size === 0) this.stopBroadcast();\n }\n\n // ── Annotation flow (Phase 2) ───────────────────────────────────────────\n\n /**\n * Look up the participant record for a given WS across all sessions.\n * Returns null when the WS hasn't joined (e.g. the client sent a\n * `collab.annotate` before `collab.join`).\n */\n private findParticipant(ws: WebSocket): Participant | null {\n for (const bucket of this.bySession.values()) {\n for (const p of bucket) {\n if (p.ws === ws) return p;\n }\n }\n return null;\n }\n\n private findParticipantById(sessionId: string, participantId: string): Participant | null {\n const bucket = this.bySession.get(sessionId);\n if (!bucket) return null;\n for (const p of bucket) {\n if (p.participantId === participantId) return p;\n }\n return null;\n }\n\n private async handleAnnotate(ws: WebSocket, raw: unknown): Promise<void> {\n if (!this.annotations) {\n this.send(ws, this.errorMessage('annotations store is not configured'));\n return;\n }\n const participant = this.findParticipant(ws);\n if (!participant) {\n this.send(ws, this.errorMessage('annotate requires an active join'));\n return;\n }\n if (participant.role !== 'annotator') {\n this.send(\n ws,\n this.errorMessage(\n `annotate requires the 'annotator' role (current: '${participant.role}')`,\n ),\n );\n return;\n }\n const payload = raw as\n | { sessionId?: string | undefined; atEventIndex?: number | undefined; text?: string | undefined }\n | undefined;\n if (\n !payload?.sessionId ||\n typeof payload.atEventIndex !== 'number' ||\n typeof payload.text !== 'string'\n ) {\n this.send(\n ws,\n this.errorMessage('annotate requires { sessionId, atEventIndex, text }'),\n );\n return;\n }\n if (payload.sessionId !== participant.sessionId) {\n this.send(\n ws,\n this.errorMessage(\n `annotate sessionId mismatch (joined: ${participant.sessionId})`,\n ),\n );\n return;\n }\n try {\n const annotation = await this.annotations.add({\n sessionId: payload.sessionId,\n atEventIndex: payload.atEventIndex,\n authorId: participant.participantId,\n text: payload.text,\n });\n this.broadcast(payload.sessionId, {\n type: 'collab.annotation.added',\n payload: {\n sessionId: payload.sessionId,\n annotation: {\n id: annotation.id,\n atEventIndex: annotation.atEventIndex,\n authorId: annotation.authorId,\n authorRole: annotation.authorRole,\n text: annotation.text,\n createdAt: annotation.createdAt,\n resolved: annotation.resolved,\n },\n },\n });\n } catch (err) {\n this.send(\n ws,\n this.errorMessage(\n `annotation rejected: ${\n toErrorMessage(err)\n }`,\n ),\n );\n }\n }\n\n private async handleResolve(ws: WebSocket, raw: unknown): Promise<void> {\n if (!this.annotations) {\n this.send(ws, this.errorMessage('annotations store is not configured'));\n return;\n }\n const participant = this.findParticipant(ws);\n if (!participant) {\n this.send(ws, this.errorMessage('resolve requires an active join'));\n return;\n }\n if (participant.role !== 'annotator') {\n this.send(\n ws,\n this.errorMessage(\n `resolve requires the 'annotator' role (current: '${participant.role}')`,\n ),\n );\n return;\n }\n const payload = raw as\n | { sessionId?: string | undefined; annotationId?: string | undefined }\n | undefined;\n if (!payload?.sessionId || !payload.annotationId) {\n this.send(\n ws,\n this.errorMessage('resolve requires { sessionId, annotationId }'),\n );\n return;\n }\n if (payload.sessionId !== participant.sessionId) {\n this.send(\n ws,\n this.errorMessage(\n `resolve sessionId mismatch (joined: ${participant.sessionId})`,\n ),\n );\n return;\n }\n try {\n const updated = await this.annotations.resolve({\n sessionId: payload.sessionId,\n annotationId: payload.annotationId,\n resolvedBy: participant.participantId,\n });\n if (!updated) {\n this.send(\n ws,\n this.errorMessage(`annotation not found: ${payload.annotationId}`),\n );\n return;\n }\n this.broadcast(payload.sessionId, {\n type: 'collab.annotation.resolved',\n payload: {\n sessionId: payload.sessionId,\n annotationId: updated.id,\n resolvedBy: updated.resolvedBy ?? participant.participantId,\n resolvedAt: updated.resolvedAt ?? new Date().toISOString(),\n },\n });\n } catch (err) {\n this.send(\n ws,\n this.errorMessage(\n `resolve failed: ${\n toErrorMessage(err)\n }`,\n ),\n );\n }\n }\n\n // ── Event subscription (live mirror) ───────────────────────────────────\n\n private subscribe(): void {\n // Same trick as WorktreeWebSocketHandler: bind a single typed-on helper\n // to a string-keyed signature so we can register many handlers.\n const on = this.events.on.bind(this.events) as never as (\n ev: string,\n fn: (p: unknown) => void,\n ) => () => void;\n\n // Mirror every event an observer would care about. Each is forwarded\n // to all joined participants as a generic `collab.event` envelope so\n // the client can render a flowing activity strip. Filtering /\n // denormalization happens on the client.\n const forwarded: Array<[string, string]> = [\n ['iteration.started', 'iteration.started'],\n ['iteration.completed', 'iteration.completed'],\n ['tool.started', 'tool.started'],\n ['tool.progress', 'tool.progress'],\n ['tool.executed', 'tool.executed'],\n ['tool.confirm_needed', 'tool.confirm_needed'],\n ['subagent.spawned', 'subagent.spawned'],\n ['subagent.task_started', 'subagent.task_started'],\n ['subagent.iteration_summary', 'subagent.iteration_summary'],\n ['subagent.task_completed', 'subagent.task_completed'],\n ['subagent.done', 'subagent.done'],\n ];\n for (const [kernelEvent, kind] of forwarded) {\n this.offs.push(\n on(kernelEvent, (raw) => {\n // Best-effort payload shape: we don't deeply validate, but we\n // make sure it's serializable. Observers must never receive\n // non-serializable objects (Functions, circular refs).\n let payload: unknown = raw;\n try {\n payload = JSON.parse(JSON.stringify(raw));\n } catch {\n // Skip unserializable payloads — better to drop than to crash\n // the broadcast loop.\n return;\n }\n this.broadcastEvent(kind, payload);\n }),\n );\n }\n }\n\n private broadcastEvent(kind: string, payload: unknown): void {\n if (this.bySession.size === 0) return; // nobody watching — no-op\n const msg: WSServerMessage = {\n type: 'collab.event',\n payload: { kind, payload, at: new Date().toISOString() },\n };\n const data = JSON.stringify(msg);\n for (const bucket of this.bySession.values()) {\n for (const p of bucket) {\n try {\n if (p.ws.readyState === 1) p.ws.send(data);\n } catch (err) {\n this.logger.debug?.(\n `collab broadcast failed: ${\n toErrorMessage(err)\n }`,\n );\n }\n }\n }\n }\n\n /**\n * Replay the last `REPLAY_LIMIT` events from the on-disk session log\n * to a single observer (the late joiner). Each event is forwarded as\n * a `collab.event` with `replay: true` so the client can distinguish\n * history from the live stream.\n *\n * The session log stores typed `SessionEvent`s (`user_input`,\n * `llm_response`, `tool_result`, etc.) — different from the kernel's\n * bus events. We translate the most useful subset (`tool.*` and\n * `iteration.*`-shaped ones) into the same `kind` namespace the live\n * mirror uses, so the client can render a single activity strip.\n */\n private async replayHistory(ws: WebSocket, sessionId: string): Promise<void> {\n if (!this.reader) return;\n const all: unknown[] = [];\n try {\n for await (const ev of this.reader.replay(sessionId)) {\n all.push(ev);\n }\n } catch (err) {\n this.logger.debug?.(\n `collab: session reader rejected ${sessionId}: ${\n toErrorMessage(err)\n }`,\n );\n return;\n }\n const tail = all.slice(-REPLAY_LIMIT);\n if (tail.length === 0) return; // nothing to replay\n for (const raw of tail) {\n const ev = raw as { type?: string | undefined; ts?: string | undefined; [k: string]: unknown };\n const kind = this.historyEventToKind(ev);\n if (!kind) continue; // skip events we don't know how to mirror\n this.send(ws, {\n type: 'collab.event',\n payload: {\n kind,\n payload: ev,\n at: ev.ts ?? new Date().toISOString(),\n replay: true,\n },\n });\n }\n }\n\n /**\n * Map a stored `SessionEvent` to a `collab.event.kind` so the live\n * strip and the history strip can share a single rendering path.\n * Returns null for events that don't have a meaningful live analog\n * (e.g. `session_start`, file-snapshot bookkeeping, rewind markers).\n */\n private historyEventToKind(ev: { type?: string | undefined }): string | null {\n switch (ev.type) {\n case 'user_input':\n return 'user_input';\n case 'llm_response':\n return 'llm_response';\n case 'tool_result':\n return 'tool.executed';\n case 'compaction':\n return 'compaction';\n case 'error':\n return 'error';\n default:\n return null;\n }\n }\n\n // ── State snapshot + periodic broadcast ────────────────────────────────\n\n private stateMessage(sessionId: string): WSCollabState {\n const bucket = this.bySession.get(sessionId);\n return {\n type: 'collab.state',\n payload: {\n sessionId,\n participants: bucket\n ? [...bucket].map((p) => ({\n participantId: p.participantId,\n role: p.role,\n joinedAt: p.joinedAt,\n }))\n : [],\n },\n };\n }\n\n private ensureBroadcast(): void {\n if (this.broadcastInterval) return;\n this.broadcastInterval = setInterval(() => {\n for (const sessionId of this.bySession.keys()) {\n this.broadcast(sessionId, this.stateMessage(sessionId));\n }\n }, 2000);\n }\n\n private stopBroadcast(): void {\n if (this.broadcastInterval) {\n clearInterval(this.broadcastInterval);\n this.broadcastInterval = null;\n }\n }\n\n private broadcast(sessionId: string, msg: WSServerMessage): void {\n const data = JSON.stringify(msg);\n const bucket = this.bySession.get(sessionId);\n if (!bucket) return;\n for (const p of bucket) {\n try {\n if (p.ws.readyState === 1) p.ws.send(data);\n } catch (err) {\n this.logger.debug?.(\n `collab broadcast failed: ${\n toErrorMessage(err)\n }`,\n );\n }\n }\n }\n\n private send(ws: WebSocket, msg: WSServerMessage): void {\n try {\n if (ws.readyState === 1) ws.send(JSON.stringify(msg));\n } catch {\n /* client gone */\n }\n }\n\n private errorMessage(detail: string): WSServerMessage {\n return { type: 'error', payload: { phase: 'collab', message: detail } };\n }\n\n // ── Controller flow (Phase 3) ───────────────────────────────────────────\n\n private async handleRequestPause(ws: WebSocket, raw: unknown): Promise<void> {\n if (!this.bus) {\n this.send(ws, this.errorMessage('pause requires a CollaborationBus'));\n return;\n }\n const participant = this.findParticipant(ws);\n if (!participant) {\n this.send(ws, this.errorMessage('pause requires an active join'));\n return;\n }\n if (participant.role !== 'controller') {\n this.send(\n ws,\n this.errorMessage(\n `pause requires the 'controller' role (current: '${participant.role}')`,\n ),\n );\n return;\n }\n const payload = raw as { sessionId?: string | undefined } | undefined;\n if (!payload?.sessionId || payload.sessionId !== participant.sessionId) {\n this.send(ws, this.errorMessage('pause sessionId mismatch'));\n return;\n }\n const transitioned = this.bus.requestPause(participant.participantId);\n if (!transitioned) {\n // Already paused — surface the current state to the requester.\n const s = this.bus.getState();\n this.send(ws, {\n type: 'error',\n payload: {\n phase: 'collab',\n message: `bus already paused by ${s.pausedBy ?? '?'} at ${s.pausedAt ?? '?'}`,\n },\n });\n return;\n }\n const s = this.bus.getState();\n this.broadcast(payload.sessionId, {\n type: 'collab.pause.granted',\n payload: {\n sessionId: payload.sessionId,\n pausedBy: s.pausedBy ?? participant.participantId,\n pausedAt: s.pausedAt ?? new Date().toISOString(),\n autoResumeInMs: PAUSE_TIMEOUT_MS,\n },\n });\n }\n\n private async handleResume(ws: WebSocket, raw: unknown): Promise<void> {\n if (!this.bus) {\n this.send(ws, this.errorMessage('resume requires a CollaborationBus'));\n return;\n }\n const participant = this.findParticipant(ws);\n if (!participant) {\n this.send(ws, this.errorMessage('resume requires an active join'));\n return;\n }\n // Permission: controller OR the original pauser. We do a simple\n // \"any controller can release\" check — fine for Phase 3, can be\n // tightened to \"only the pauser\" later.\n if (participant.role !== 'controller') {\n this.send(\n ws,\n this.errorMessage(\n `resume requires the 'controller' role (current: '${participant.role}')`,\n ),\n );\n return;\n }\n const payload = raw as { sessionId?: string | undefined } | undefined;\n if (!payload?.sessionId || payload.sessionId !== participant.sessionId) {\n this.send(ws, this.errorMessage('resume sessionId mismatch'));\n return;\n }\n const transitioned = this.bus.resume();\n if (!transitioned) {\n this.send(ws, this.errorMessage('bus is not currently paused'));\n return;\n }\n this.broadcast(payload.sessionId, {\n type: 'collab.pause.released',\n payload: {\n sessionId: payload.sessionId,\n reason: 'controller',\n at: new Date().toISOString(),\n },\n });\n }\n\n private async handleGrantControl(ws: WebSocket, raw: unknown): Promise<void> {\n // Promote a target participant to `controller` so the pause/resume and\n // inject_tool checks (which gate on role === 'controller') accept it. Only\n // a current controller may grant; the granter itself already passed the\n // bus requirement when it joined as controller, so no extra bus check is\n // needed here. The new roster is broadcast so every client reflects it.\n const participant = this.findParticipant(ws);\n if (!participant) {\n this.send(ws, this.errorMessage('grant_control requires an active join'));\n return;\n }\n if (participant.role !== 'controller') {\n this.send(\n ws,\n this.errorMessage(\n `grant_control requires the 'controller' role (current: '${participant.role}')`,\n ),\n );\n return;\n }\n const payload = raw as\n | { sessionId?: string | undefined; toParticipant?: string | undefined }\n | undefined;\n if (\n !payload?.sessionId ||\n !payload.toParticipant ||\n payload.sessionId !== participant.sessionId\n ) {\n this.send(ws, this.errorMessage('grant_control requires { sessionId, toParticipant }'));\n return;\n }\n const target = this.findParticipantById(payload.sessionId, payload.toParticipant);\n if (!target) {\n this.send(\n ws,\n this.errorMessage(\n `grant_control: no participant '${payload.toParticipant}' in this session`,\n ),\n );\n return;\n }\n target.role = 'controller';\n this.logger.debug?.(\n `collab: control granted from ${participant.participantId} to ${target.participantId} in ${payload.sessionId}`,\n );\n this.broadcast(payload.sessionId, this.stateMessage(payload.sessionId));\n }\n\n /**\n * Phase 4 — handle a controller's manual tool-call injection.\n * Validates the payload, queues it on the bus, and broadcasts\n * the grant so observers see what just happened. The actual\n * splice into the agent's pipeline is performed by the\n * `collabInjectMiddleware` on the next tool call.\n */\n private async handleInjectTool(ws: WebSocket, raw: unknown): Promise<void> {\n if (!this.bus) {\n this.send(ws, this.errorMessage('inject_tool requires a CollaborationBus'));\n return;\n }\n const participant = this.findParticipant(ws);\n if (!participant) {\n this.send(ws, this.errorMessage('inject_tool requires an active join'));\n return;\n }\n if (participant.role !== 'controller') {\n this.send(\n ws,\n this.errorMessage(\n `inject_tool requires the 'controller' role (current: '${participant.role}')`,\n ),\n );\n return;\n }\n const payload = raw as\n | {\n sessionId?: string | undefined;\n toolUseId?: string | undefined;\n content?: unknown | undefined;\n isError?: boolean | undefined;\n reason?: string | undefined;\n }\n | undefined;\n if (\n !payload?.sessionId ||\n !payload.toolUseId ||\n typeof payload.isError !== 'boolean' ||\n typeof payload.reason !== 'string' ||\n payload.content === undefined\n ) {\n this.send(\n ws,\n this.errorMessage(\n 'inject_tool requires { sessionId, toolUseId, content, isError, reason }',\n ),\n );\n return;\n }\n if (payload.sessionId !== participant.sessionId) {\n this.send(\n ws,\n this.errorMessage(\n `inject_tool sessionId mismatch (joined: ${participant.sessionId})`,\n ),\n );\n return;\n }\n const queued = this.bus.injectToolResult({\n toolUseId: payload.toolUseId,\n content: payload.content,\n isError: payload.isError,\n reason: payload.reason,\n authorId: participant.participantId,\n });\n if (!queued) {\n this.send(\n ws,\n this.errorMessage(\n `an injection for toolUseId ${payload.toolUseId} is already queued`,\n ),\n );\n return;\n }\n this.broadcast(payload.sessionId, {\n type: 'collab.injection.granted',\n payload: {\n sessionId: payload.sessionId,\n toolUseId: payload.toolUseId,\n // The tool name is unknown here (the injection is queued\n // before the model produces the tool call). We surface a\n // placeholder; the middleware will emit a `consumed` event\n // with the real name on match.\n toolName: '(pending match)',\n authorId: participant.participantId,\n reason: payload.reason,\n isError: payload.isError,\n phase: 'queued',\n at: new Date().toISOString(),\n },\n });\n }\n\n /**\n * Bus callback: a queued injection was spliced into a real tool call. Re-emit\n * `collab.injection.granted` with phase `'consumed'` and the now-known tool\n * name. The injection carries no sessionId, so resolve it from the author's\n * current session; if they've already left, fall back to every live session.\n */\n private broadcastInjectionConsumed(info: ConsumedInjectionInfo): void {\n let sessionId: string | null = null;\n for (const [sid, bucket] of this.bySession) {\n for (const p of bucket) {\n if (p.participantId === info.authorId) {\n sessionId = sid;\n break;\n }\n }\n if (sessionId) break;\n }\n const message = (sid: string): WSServerMessage => ({\n type: 'collab.injection.granted',\n payload: {\n sessionId: sid,\n toolUseId: info.toolUseId,\n toolName: info.toolName,\n authorId: info.authorId,\n reason: info.reason,\n isError: info.isError,\n phase: 'consumed',\n at: new Date().toISOString(),\n },\n });\n if (sessionId) {\n this.broadcast(sessionId, message(sessionId));\n } else {\n for (const sid of this.bySession.keys()) this.broadcast(sid, message(sid));\n }\n }\n}\n\ninterface Participant {\n participantId: string;\n ws: WebSocket;\n sessionId: string;\n role: CollabRole;\n joinedAt: string;\n}\n","/**\n * Projects manifest (~/.wrongstack/projects.json) helpers — extracted from the\n * giant startWebUI closure in index.ts. Pure, param-based file IO: each fn\n * takes the global config path explicitly, so they close over nothing. Mirrors\n * the CLI's project-manifest registration (touchProjectInManifest).\n */\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { projectSlug } from '@wrongstack/core';\n\nexport interface ProjectEntry {\n name: string;\n root: string;\n slug: string;\n lastSeen?: string | undefined;\n createdAt?: string | undefined;\n /** Working directory of the most recent session (may differ from root). */\n lastWorkingDir?: string | undefined;\n}\n\nexport interface ProjectsManifest {\n projects: ProjectEntry[];\n}\n\nexport function projectsJsonPath(globalConfigPath: string): string {\n const base = path.dirname(globalConfigPath);\n return path.join(base, 'projects.json');\n}\n\nexport async function loadManifest(globalConfigPath: string): Promise<ProjectsManifest> {\n try {\n const raw = await fs.readFile(projectsJsonPath(globalConfigPath), 'utf8');\n const parsed = JSON.parse(raw) as ProjectsManifest;\n return { projects: parsed.projects ?? [] };\n } catch {\n return { projects: [] };\n }\n}\n\nexport async function saveManifest(\n manifest: ProjectsManifest,\n globalConfigPath: string,\n): Promise<void> {\n const file = projectsJsonPath(globalConfigPath);\n await fs.mkdir(path.dirname(file), { recursive: true });\n await fs.writeFile(file, JSON.stringify(manifest, null, 2), 'utf8');\n}\n\nexport function generateProjectSlug(rootPath: string): string {\n // Canonical derivation — must match wstack-paths/projectSlug exactly or\n // the WebUI and CLI would key the same project under different dirs.\n return projectSlug(rootPath);\n}\n\nexport async function ensureProjectDataDir(\n slug: string,\n globalConfigPath: string,\n): Promise<string> {\n const base = path.dirname(globalConfigPath);\n const dir = path.join(base, 'projects', slug);\n await fs.mkdir(dir, { recursive: true });\n return dir;\n}\n","import { createRequire } from 'node:module';\nimport type { WebSocket } from 'ws';\nimport type { Logger } from '@wrongstack/core';\nimport { toErrorMessage } from '@wrongstack/core/utils';\nimport type { WSServerMessage } from '../types.js';\n\n/** Loose inbound shape — matches the server's internal WSClientMessage. */\ntype IncomingMessage = { type: string; payload?: unknown };\ntype PtyExit = { exitCode: number; signal?: number | undefined };\ninterface PtyProcess {\n write(data: string): void;\n resize(cols: number, rows: number): void;\n kill(): void;\n onData(cb: (data: string) => void): unknown;\n onExit(cb: (event: PtyExit) => void): unknown;\n}\ninterface NodePtyApi {\n spawn(\n file: string,\n args: string[],\n opts: {\n name: string;\n cols: number;\n rows: number;\n cwd: string;\n env: Record<string, string>;\n },\n ): PtyProcess;\n}\ntype LoadNodePty = () => NodePtyApi | null;\n\n/** Hard cap on concurrent PTYs per connected client — a runaway-spawn backstop. */\nconst MAX_SESSIONS_PER_CLIENT = 8;\nconst DEFAULT_COLS = 80;\nconst DEFAULT_ROWS = 24;\nconst requireFromHere = createRequire(import.meta.url);\nlet cachedNodePty: NodePtyApi | null | undefined;\n\n/**\n * TerminalWebSocketHandler — backs the WebUI's integrated terminal panel.\n *\n * Mirrors the lifecycle shape of WorktreeWebSocketHandler but is *per-client*\n * and *interactive*: each connected WebSocket owns a map of real node-pty\n * sessions keyed by a client-chosen id. Browser xterm.js ⇄ pty wiring:\n * - `terminal.create` → spawn a shell pty, stream its output back\n * - `terminal.input` → write keystrokes to the pty\n * - `terminal.resize` → propagate xterm's fit dimensions\n * - `terminal.close` → kill the pty\n * When a client disconnects, every pty it owns is killed (no orphan shells).\n */\nexport class TerminalWebSocketHandler {\n /** ws → (terminalId → pty). */\n private readonly sessions = new Map<WebSocket, Map<string, PtyProcess>>();\n\n constructor(\n /** Resolves the cwd new terminals open in — tracks the live working dir. */\n private readonly getCwd: () => string,\n private readonly logger: Logger,\n private readonly loadNodePty: LoadNodePty = defaultLoadNodePty,\n ) {}\n\n addClient(ws: WebSocket): void {\n if (!this.sessions.has(ws)) this.sessions.set(ws, new Map());\n ws.on('close', () => this.disposeClient(ws));\n ws.on('error', () => this.disposeClient(ws));\n }\n\n /** Kill every pty owned by every client (server shutdown). */\n dispose(): void {\n for (const ws of [...this.sessions.keys()]) this.disposeClient(ws);\n }\n\n /** True if this message was a terminal.* message (handled here). */\n handleMessage(ws: WebSocket, msg: IncomingMessage): boolean {\n const p = (msg.payload ?? {}) as Record<string, unknown>;\n switch (msg.type) {\n case 'terminal.create':\n if (isStr(p.id))\n this.create(ws, { id: p.id, cols: numOrUndef(p.cols), rows: numOrUndef(p.rows) });\n return true;\n case 'terminal.input':\n if (isStr(p.id) && isStr(p.data)) this.input(ws, { id: p.id, data: p.data });\n return true;\n case 'terminal.resize':\n if (isStr(p.id)) this.resize(ws, { id: p.id, cols: Number(p.cols), rows: Number(p.rows) });\n return true;\n case 'terminal.close':\n if (isStr(p.id)) this.close(ws, p.id);\n return true;\n default:\n return false;\n }\n }\n\n // ── internals ───────────────────────────────────────────────────────────\n\n private create(\n ws: WebSocket,\n payload: { id: string; cols?: number | undefined; rows?: number | undefined },\n ): void {\n const map = this.sessions.get(ws) ?? new Map<string, PtyProcess>();\n this.sessions.set(ws, map);\n\n if (map.has(payload.id)) return; // idempotent — already running\n if (map.size >= MAX_SESSIONS_PER_CLIENT) {\n this.send(ws, {\n type: 'terminal.exit',\n payload: { id: payload.id, exitCode: -1 },\n });\n return;\n }\n\n const shell =\n process.platform === 'win32'\n ? process.env.COMSPEC || 'cmd.exe'\n : process.env.SHELL || '/bin/bash';\n\n const nodePty = this.loadNodePty();\n if (!nodePty) {\n const msg =\n 'Integrated terminal unavailable: optional dependency node-pty is not installed. ' +\n 'Install node-pty to enable WebUI terminal sessions.';\n this.logger.warn?.(msg);\n this.send(ws, { type: 'terminal.output', payload: { id: payload.id, data: `${msg}\\r\\n` } });\n this.send(ws, { type: 'terminal.exit', payload: { id: payload.id, exitCode: -1 } });\n return;\n }\n\n let pty: PtyProcess;\n try {\n pty = nodePty.spawn(shell, [], {\n name: 'xterm-color',\n cols: clampDim(payload.cols, DEFAULT_COLS),\n rows: clampDim(payload.rows, DEFAULT_ROWS),\n cwd: this.getCwd(),\n env: process.env as Record<string, string>,\n });\n } catch (err) {\n this.logger.warn?.(`terminal spawn failed: ${toErrorMessage(err)}`);\n this.send(ws, { type: 'terminal.exit', payload: { id: payload.id, exitCode: -1 } });\n return;\n }\n\n map.set(payload.id, pty);\n\n pty.onData((data) => {\n this.send(ws, { type: 'terminal.output', payload: { id: payload.id, data } });\n });\n pty.onExit(({ exitCode, signal }) => {\n map.delete(payload.id);\n this.send(ws, {\n type: 'terminal.exit',\n payload: { id: payload.id, exitCode, signal: signal ?? undefined },\n });\n });\n }\n\n private input(ws: WebSocket, payload: { id: string; data: string }): void {\n const pty = this.sessions.get(ws)?.get(payload.id);\n if (pty) pty.write(payload.data);\n }\n\n private resize(ws: WebSocket, payload: { id: string; cols: number; rows: number }): void {\n const pty = this.sessions.get(ws)?.get(payload.id);\n if (!pty) return;\n try {\n pty.resize(clampDim(payload.cols, DEFAULT_COLS), clampDim(payload.rows, DEFAULT_ROWS));\n } catch {\n /* pty already gone */\n }\n }\n\n private close(ws: WebSocket, id: string): void {\n const map = this.sessions.get(ws);\n const pty = map?.get(id);\n if (!pty) return;\n map?.delete(id);\n try {\n pty.kill();\n } catch {\n /* already dead */\n }\n }\n\n private disposeClient(ws: WebSocket): void {\n const map = this.sessions.get(ws);\n if (!map) return;\n for (const pty of map.values()) {\n try {\n pty.kill();\n } catch {\n /* already dead */\n }\n }\n this.sessions.delete(ws);\n }\n\n private send(ws: WebSocket, msg: WSServerMessage): void {\n try {\n if (ws.readyState === 1) ws.send(JSON.stringify(msg));\n } catch {\n /* client gone */\n }\n }\n}\n\nfunction defaultLoadNodePty(): NodePtyApi | null {\n if (cachedNodePty !== undefined) return cachedNodePty;\n try {\n cachedNodePty = requireFromHere('node-pty') as NodePtyApi;\n } catch {\n cachedNodePty = null;\n }\n return cachedNodePty;\n}\n\nfunction isStr(v: unknown): v is string {\n return typeof v === 'string';\n}\n\nfunction numOrUndef(v: unknown): number | undefined {\n return typeof v === 'number' && Number.isFinite(v) ? v : undefined;\n}\n\n/** Clamp a terminal dimension into a sane range; fall back to a default. */\nfunction clampDim(value: number | undefined, fallback: number): number {\n if (typeof value !== 'number' || !Number.isFinite(value)) return fallback;\n return Math.max(1, Math.min(1000, Math.floor(value)));\n}\n","import type { WebSocket } from 'ws';\nimport type { EventBus, Logger } from '@wrongstack/core';\nimport type { WorktreeHandleView, WSServerMessage } from '../types.js';\nimport { toErrorMessage } from '@wrongstack/core/utils';\n\nconst MAX_ACTIVITY = 6;\n\n/**\n * WorktreeWebSocketHandler — mirrors AutoPhaseWebSocketHandler. Subscribes to\n * the shared EventBus `worktree.*` lifecycle events, keeps a live snapshot of\n * every worktree, and broadcasts:\n * - `worktree.event` incrementally (drives the flowing activity strip)\n * - `worktree.state` on connect + on a 2s timer (drives swim-lanes/DAG)\n */\nexport class WorktreeWebSocketHandler {\n private readonly clients = new Set<WebSocket>();\n private readonly handles = new Map<string, WorktreeHandleView>();\n private baseBranch = '';\n private broadcastInterval: ReturnType<typeof setInterval> | null = null;\n private readonly offs: Array<() => void> = [];\n\n constructor(\n private readonly events: EventBus,\n private readonly logger: Logger,\n ) {\n this.subscribe();\n }\n\n addClient(ws: WebSocket): void {\n this.clients.add(ws);\n ws.on('close', () => this.clients.delete(ws));\n ws.on('error', () => this.clients.delete(ws));\n this.send(ws, this.stateMessage());\n }\n\n dispose(): void {\n for (const off of this.offs) off();\n this.offs.length = 0;\n this.stopBroadcast();\n }\n\n // ── internals ───────────────────────────────────────────────────────────\n\n private subscribe(): void {\n const on = this.events.on.bind(this.events) as never as (\n ev: string,\n fn: (p: unknown) => void,\n ) => () => void;\n\n this.offs.push(\n on('worktree.allocated', (p) => {\n const e = p as { handleId: string; ownerId: string; ownerLabel: string; branch: string; baseBranch: string };\n this.baseBranch = e.baseBranch || this.baseBranch;\n this.upsert(e.handleId, {\n handleId: e.handleId,\n ownerId: e.ownerId,\n ownerLabel: e.ownerLabel,\n branch: e.branch,\n baseBranch: e.baseBranch,\n status: 'active',\n insertions: 0,\n deletions: 0,\n files: 0,\n allocatedAt: Date.now(),\n lastEventAt: Date.now(),\n recentActivity: [],\n });\n this.activity(e.handleId, 'allocated', `branch ${e.branch}`);\n this.ensureBroadcast();\n }),\n on('worktree.committed', (p) => {\n const e = p as { handleId: string; insertions: number; deletions: number; files: number; committed: boolean };\n this.patch(e.handleId, { status: 'committing', insertions: e.insertions, deletions: e.deletions, files: e.files });\n if (e.committed) this.activity(e.handleId, 'committed', `+${e.insertions}/-${e.deletions} (${e.files}f)`);\n this.broadcastState();\n }),\n on('worktree.merged', (p) => {\n const e = p as { handleId: string; baseBranch: string };\n this.patch(e.handleId, { status: 'merged' });\n this.activity(e.handleId, 'merged', `→ ${e.baseBranch}`);\n this.broadcastState();\n }),\n on('worktree.conflict', (p) => {\n const e = p as { handleId: string; conflictFiles: string[] };\n this.patch(e.handleId, { status: 'needs-review', conflictFiles: e.conflictFiles });\n this.activity(e.handleId, 'conflict', e.conflictFiles.join(', '));\n this.broadcastState();\n }),\n on('worktree.failed', (p) => {\n const e = p as { handleId: string; error: string };\n this.patch(e.handleId, { status: 'failed' });\n this.activity(e.handleId, 'failed', e.error);\n this.broadcastState();\n }),\n on('worktree.released', (p) => {\n const e = p as { handleId: string; kept: boolean };\n if (!e.kept) this.handles.delete(e.handleId);\n this.activity(e.handleId, 'released', e.kept ? 'kept for review' : 'removed');\n if (this.handles.size === 0) this.stopBroadcast();\n else this.broadcastState();\n }),\n );\n }\n\n private upsert(id: string, view: WorktreeHandleView): void {\n this.handles.set(id, view);\n }\n\n private patch(id: string, patch: Partial<WorktreeHandleView>): void {\n const cur = this.handles.get(id);\n if (!cur) return;\n this.handles.set(id, { ...cur, ...patch, lastEventAt: Date.now() });\n }\n\n private activity(id: string, kind: string, text: string): void {\n const cur = this.handles.get(id);\n if (cur) {\n const recentActivity = [...cur.recentActivity, { kind, text, at: Date.now() }].slice(-MAX_ACTIVITY);\n this.handles.set(id, { ...cur, recentActivity });\n }\n this.broadcast({ type: 'worktree.event', payload: { kind, handleId: id, text, at: Date.now() } });\n }\n\n private stateMessage(): WSServerMessage {\n return {\n type: 'worktree.state',\n payload: { worktrees: [...this.handles.values()], baseBranch: this.baseBranch },\n };\n }\n\n private broadcastState(): void {\n this.broadcast(this.stateMessage());\n }\n\n private ensureBroadcast(): void {\n this.broadcast(this.stateMessage());\n if (this.broadcastInterval) return;\n this.broadcastInterval = setInterval(() => this.broadcast(this.stateMessage()), 2000);\n }\n\n private stopBroadcast(): void {\n this.broadcast(this.stateMessage());\n if (this.broadcastInterval) {\n clearInterval(this.broadcastInterval);\n this.broadcastInterval = null;\n }\n }\n\n private broadcast(msg: WSServerMessage): void {\n const data = JSON.stringify(msg);\n for (const ws of this.clients) {\n try {\n if (ws.readyState === 1) ws.send(data);\n } catch (err) {\n this.logger.debug?.(`worktree broadcast failed: ${toErrorMessage(err)}`);\n }\n }\n }\n\n private send(ws: WebSocket, msg: WSServerMessage): void {\n try {\n if (ws.readyState === 1) ws.send(JSON.stringify(msg));\n } catch {\n /* client gone */\n }\n }\n}\n","/**\n * Mailbox WebSocket handlers for the WebUI.\n *\n * Handles `mailbox.messages` and `mailbox.agents` message types.\n * The frontend sends these to populate the mailbox panel; the server\n * reads from the project-level GlobalMailbox and responds.\n */\n\nimport type { WebSocket } from 'ws';\nimport { GlobalMailbox, resolveProjectDir } from '@wrongstack/core';\nimport { send, errMessage } from './ws-utils.js';\n\nexport interface MailboxHandlerDeps {\n /** Absolute project root. */\n projectRoot: string;\n /** Global WrongStack root (~/.wrongstack). */\n globalRoot: string;\n}\n\n// ── Handlers ──────────────────────────────────────────────────────────\n\n/**\n * List recent mailbox messages. Frontend sends:\n * { type: 'mailbox.messages', limit?: number, incompleteOnly?: boolean }\n *\n * Uses `incompleteOnly` so the server filters to active/unread messages,\n * making readByCount === 0 a reliable \"unread to all agents\" signal for\n * the ActivityBar badge count.\n */\nexport async function handleMailboxMessages(\n ws: WebSocket,\n deps: MailboxHandlerDeps,\n payload: { limit?: number; incompleteOnly?: boolean } | undefined,\n): Promise<void> {\n try {\n const dir = resolveProjectDir(deps.projectRoot, deps.globalRoot);\n const mb = new GlobalMailbox(dir);\n const messages = await mb.query({\n limit: payload?.limit ?? 30,\n incompleteOnly: payload?.incompleteOnly ?? false,\n });\n send(ws, {\n type: 'mailbox.messages',\n payload: {\n messages: messages.map((m) => ({\n id: m.id, from: m.from, to: m.to, type: m.type,\n subject: m.subject, body: m.body, priority: m.priority,\n readBy: m.readBy, readByCount: Object.keys(m.readBy).length,\n completed: m.completed, completedBy: m.completedBy,\n completedAt: m.completedAt, outcome: m.outcome, timestamp: m.timestamp,\n replyTo: m.replyTo, senderSessionId: m.senderSessionId,\n taskContext: m.taskContext,\n })),\n },\n });\n } catch (err) {\n send(ws, { type: 'mailbox.messages', payload: { messages: [], error: errMessage(err) } });\n }\n}\n\n/**\n * List registered agents. Frontend sends:\n * { type: 'mailbox.agents', onlineOnly?: boolean }\n */\nexport async function handleMailboxAgents(\n ws: WebSocket,\n deps: MailboxHandlerDeps,\n payload: { onlineOnly?: boolean } | undefined,\n): Promise<void> {\n try {\n const dir = resolveProjectDir(deps.projectRoot, deps.globalRoot);\n const mb = new GlobalMailbox(dir);\n const agents = payload?.onlineOnly\n ? await mb.getOnlineAgents()\n : await mb.getAgentStatuses();\n send(ws, {\n type: 'mailbox.agents',\n payload: {\n agents: agents.map((a) => ({\n agentId: a.agentId, name: a.name, role: a.role,\n sessionId: a.sessionId, status: a.status,\n currentTool: a.currentTool, currentTask: a.currentTask,\n iterations: a.iterations, toolCalls: a.toolCalls,\n lastSeenAt: a.lastSeenAt, online: a.online,\n pid: a.pid, source: a.source,\n })),\n },\n });\n } catch (err) {\n send(ws, { type: 'mailbox.agents', payload: { agents: [], error: errMessage(err) } });\n }\n}\n\n/**\n * Delete all messages from the mailbox. Frontend sends:\n * { type: 'mailbox.clear' }\n * Server responds with 'mailbox.cleared'.\n */\nexport async function handleMailboxClear(\n ws: WebSocket,\n deps: MailboxHandlerDeps,\n): Promise<void> {\n try {\n const dir = resolveProjectDir(deps.projectRoot, deps.globalRoot);\n const mb = new GlobalMailbox(dir);\n await mb.clearAll();\n send(ws, { type: 'mailbox.cleared', payload: {} });\n } catch (err) {\n send(ws, { type: 'mailbox.cleared', payload: { error: errMessage(err) } });\n }\n}\n\n/**\n * Purge stale/orphaned messages from the mailbox. Frontend sends:\n * { type: 'mailbox.purge', payload?: { completedMaxAgeMs?: number; incompleteMaxAgeMs?: number } }\n * Server responds with 'mailbox.purged'.\n */\nexport async function handleMailboxPurge(\n ws: WebSocket,\n deps: MailboxHandlerDeps,\n opts?: { completedMaxAgeMs?: number; incompleteMaxAgeMs?: number },\n): Promise<void> {\n try {\n const dir = resolveProjectDir(deps.projectRoot, deps.globalRoot);\n const mb = new GlobalMailbox(dir);\n const result = await mb.purgeStale(opts);\n send(ws, { type: 'mailbox.purged', payload: result });\n } catch (err) {\n send(ws, { type: 'mailbox.purged', payload: { error: errMessage(err) } });\n }\n}\n","/**\n * Process lifecycle for the WebUI server: graceful shutdown and the\n * SIGINT/SIGTERM wiring that triggers it.\n *\n * On a termination signal we (best-effort) flush + close the active session,\n * close every connected WebSocket, stop the HTTP and WS servers, then exit.\n * A re-entrancy guard makes a second signal during shutdown a no-op (rapid\n * double Ctrl+C no longer runs the teardown twice).\n *\n * Extracted from `index.ts` as a parameterized factory so the teardown\n * sequence can be unit tested without a real process signal, server, or\n * `process.exit` — `log` and `exit` are injectable seams.\n */\n\nexport interface LifecycleResources {\n /** Persist + close the active session (best-effort; errors are logged). */\n flushSession: () => Promise<void>;\n /**\n * Returns the currently-connected client sockets to close. A thunk (not a\n * snapshot) so shutdown closes whoever is connected *at signal time*, not\n * whoever was connected when the handler was registered.\n */\n clients: () => Iterable<{ close: () => void }>;\n /** Servers to stop (HTTP + WS). `null`/`undefined` entries are skipped. */\n servers: Array<{ close: () => void } | null | undefined>;\n /**\n * Optional best-effort cleanup run after the session flush and before exit\n * (e.g. removing this process from the running-instance registry). Errors are\n * logged, never thrown — cleanup must not block a clean shutdown.\n */\n onShutdown?: (() => Promise<void> | void) | undefined;\n /** Output sink. Defaults to `console.log`. */\n log?: ((msg: string) => void) | undefined;\n /** Process exit. Defaults to `process.exit`. Injectable for tests. */\n exit?: ((code: number) => void) | undefined;\n}\n\n/**\n * Build the graceful-shutdown handler. Returns an idempotent async function:\n * the first call runs the teardown, subsequent calls (e.g. a second SIGINT)\n * return immediately.\n */\nexport function createShutdown(res: LifecycleResources): () => Promise<void> {\n const log = res.log ?? ((m: string) => console.log(m));\n const exit = res.exit ?? ((code: number) => process.exit(code));\n let shuttingDown = false;\n\n return async () => {\n if (shuttingDown) return; // a second signal during teardown is a no-op\n shuttingDown = true;\n\n log('[WebUI] Shutting down...');\n try {\n await res.flushSession();\n } catch (e) {\n log(`[WebUI] Error closing session: ${e instanceof Error ? e.message : String(e)}`);\n }\n for (const ws of res.clients()) ws.close();\n for (const server of res.servers) server?.close();\n if (res.onShutdown) {\n try {\n await res.onShutdown();\n } catch (e) {\n log(`[WebUI] Error during shutdown cleanup: ${e instanceof Error ? e.message : String(e)}`);\n }\n }\n exit(0);\n };\n}\n\n/**\n * Register the shutdown handler on SIGINT and SIGTERM. Returns an unregister\n * function that detaches both listeners (useful for tests and clean restarts).\n */\nexport function registerShutdownHandlers(res: LifecycleResources): () => void {\n const shutdown = createShutdown(res);\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n return () => {\n process.off('SIGINT', shutdown);\n process.off('SIGTERM', shutdown);\n };\n}\n","/**\n * Running-instance registry for the standalone WebUI server.\n *\n * Every live `wstackui` process records itself in a single JSON file under the\n * wstack home dir (`~/.wrongstack/webui-instances.json`) so a user running\n * several instances (one per project, or several per project on different\n * ports) can see at a glance which ports are open for which path.\n *\n * Design notes:\n * - **Self-healing**: every register/unregister/list prunes entries whose PID\n * is no longer alive (`process.kill(pid, 0)`), so a crashed instance that\n * never got to unregister doesn't leave a ghost behind.\n * - **Atomic writes**: the file is rewritten via `atomicWrite` (tmp + rename),\n * so a concurrent reader never sees a half-written file. Two instances\n * starting at the *exact* same millisecond could still race the\n * read-modify-write — acceptable for a best-effort tracking file, and the\n * next register() heals any dropped entry.\n * - **Best-effort**: a failure to read/write the registry must NEVER take the\n * server down. Callers wrap these in `.catch()`.\n */\n\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport * as fs from 'node:fs/promises';\nimport { atomicWrite } from '@wrongstack/core';\n\n/** One running WebUI process. */\nexport interface WebUIInstanceRecord {\n /** OS process id — also the liveness key. */\n pid: number;\n /** HTTP port serving the React frontend. */\n httpPort: number;\n /** WebSocket port for the agent backend. */\n wsPort: number;\n /** Bind host (e.g. 127.0.0.1 or 0.0.0.0). */\n host: string;\n /** Absolute project root the instance booted against. */\n projectRoot: string;\n /** Display name (basename of projectRoot). */\n projectName: string;\n /** ISO timestamp when the instance registered. */\n startedAt: string;\n /** Convenience open-in-browser URL. */\n url: string;\n}\n\ninterface RegistryFile {\n version: 1;\n instances: WebUIInstanceRecord[];\n}\n\n/** Default wstack home dir (`~/.wrongstack`). Callers may override the base. */\nexport function defaultBaseDir(): string {\n return path.join(os.homedir(), '.wrongstack');\n}\n\n/** Resolve the registry file path for a given base dir. */\nexport function registryPath(baseDir: string = defaultBaseDir()): string {\n return path.join(baseDir, 'webui-instances.json');\n}\n\n/**\n * Liveness probe. `process.kill(pid, 0)` sends no signal — it only checks the\n * process exists. ESRCH ⇒ dead; EPERM ⇒ alive but owned by another user (still\n * counts as alive). Any other error is treated conservatively as \"alive\" so we\n * never prune an instance we simply failed to probe.\n */\nexport function isPidAlive(pid: number): boolean {\n if (!Number.isInteger(pid) || pid <= 0) return false;\n try {\n process.kill(pid, 0);\n return true;\n } catch (err) {\n return (err as NodeJS.ErrnoException).code !== 'ESRCH';\n }\n}\n\nasync function load(file: string): Promise<RegistryFile> {\n try {\n const raw = await fs.readFile(file, 'utf8');\n const parsed = JSON.parse(raw) as RegistryFile;\n if (parsed?.version === 1 && Array.isArray(parsed.instances)) {\n return parsed;\n }\n } catch {\n // Missing or corrupt → start fresh.\n }\n return { version: 1, instances: [] };\n}\n\nasync function save(file: string, instances: WebUIInstanceRecord[]): Promise<void> {\n await atomicWrite(file, `${JSON.stringify({ version: 1, instances }, null, 2)}\\n`, {\n mode: 0o600,\n });\n}\n\n/** Drop dead processes and (optionally) one specific pid. */\nfunction prune(instances: WebUIInstanceRecord[], excludePid?: number): WebUIInstanceRecord[] {\n return instances.filter((i) => i.pid !== excludePid && isPidAlive(i.pid));\n}\n\n/**\n * Register (or refresh) this instance. Prunes dead entries and any stale entry\n * for our own PID before adding the current record. Best-effort — rejects only\n * on a hard fs error, which callers swallow.\n */\nexport async function registerInstance(\n record: WebUIInstanceRecord,\n baseDir: string = defaultBaseDir(),\n): Promise<void> {\n const file = registryPath(baseDir);\n const data = await load(file);\n const instances = prune(data.instances, record.pid);\n instances.push(record);\n await save(file, instances);\n}\n\n/** Remove this instance (called on graceful shutdown). Also prunes dead pids. */\nexport async function unregisterInstance(\n pid: number,\n baseDir: string = defaultBaseDir(),\n): Promise<void> {\n const file = registryPath(baseDir);\n const data = await load(file);\n const instances = prune(data.instances, pid);\n await save(file, instances);\n}\n\n/** List live instances, pruning any dead entries encountered. */\nexport async function listInstances(\n baseDir: string = defaultBaseDir(),\n): Promise<WebUIInstanceRecord[]> {\n const file = registryPath(baseDir);\n const data = await load(file);\n const live = prune(data.instances);\n // Persist the pruned view so `cat`-ing the file also shows reality, but never\n // fail the list on a write error.\n if (live.length !== data.instances.length) {\n await save(file, live).catch(() => {});\n }\n return live;\n}\n\n/** Human-readable table of running instances for `wstackui --list`. */\nexport function formatInstances(instances: WebUIInstanceRecord[]): string {\n if (instances.length === 0) {\n return 'No WebUI instances are currently running.';\n }\n const lines = [`Running WebUI instances (${instances.length}):`, ''];\n for (const i of instances) {\n lines.push(\n ` • ${i.url} · ws:${i.wsPort} · pid ${i.pid}`,\n ` project: ${i.projectName} (${i.projectRoot})`,\n ` since: ${i.startedAt}`,\n );\n }\n return lines.join('\\n');\n}\n","/**\n * Free-port discovery for the standalone WebUI server.\n *\n * When a user runs several instances, the default ports (HTTP 3456 / WS 3457)\n * are taken by the first one. Rather than make the user hand-pick `PORT` /\n * `WS_PORT` for every extra instance, the server probes upward from the\n * requested port and binds the first free one — then stamps that real port into\n * the served HTML and the instance registry so everything stays consistent.\n *\n * The probe binds a throwaway `net.Server`, then closes it, so there is a tiny\n * TOCTOU window between \"found free\" and \"the real server binds it\". For local\n * single-user multi-instance use that race is negligible; if it ever loses, the\n * real bind fails loudly with EADDRINUSE exactly as before.\n */\n\nimport * as net from 'node:net';\n\n/** Resolve true when `port` can be bound on `host`, false on EADDRINUSE/EACCES. */\nexport function isPortFree(host: string, port: number): Promise<boolean> {\n return new Promise((resolve) => {\n const srv = net.createServer();\n srv.once('error', () => resolve(false));\n srv.once('listening', () => {\n srv.close(() => resolve(true));\n });\n try {\n srv.listen(port, host);\n } catch {\n resolve(false);\n }\n });\n}\n\nexport interface FindFreePortOptions {\n /** Ports to skip even if free (e.g. one already chosen for the sibling server). */\n exclude?: Set<number> | undefined;\n /** How many consecutive ports to try before giving up. Default 200. */\n maxTries?: number | undefined;\n}\n\n/**\n * Find the first free port at or above `startPort` on `host`, skipping any in\n * `exclude`. Throws if nothing is free within `maxTries` steps.\n */\nexport async function findFreePort(\n host: string,\n startPort: number,\n opts: FindFreePortOptions = {},\n): Promise<number> {\n const exclude = opts.exclude ?? new Set<number>();\n const maxTries = opts.maxTries ?? 200;\n let port = startPort;\n for (let i = 0; i < maxTries; i++) {\n // Stay inside the valid TCP range; wrap into the high ephemeral band if a\n // pathological startPort pushes us past the ceiling.\n if (port > 65535) port = 1024 + (port % 50000);\n if (!exclude.has(port) && (await isPortFree(host, port))) {\n return port;\n }\n port++;\n }\n throw new Error(\n `No free port found near ${startPort} on ${host} after ${maxTries} attempts.`,\n );\n}\n","/**\n * Best-effort \"open this URL in the default browser\" for `--webui --open`.\n *\n * Cross-platform via the OS opener (`start` / `open` / `xdg-open`). Fully\n * fire-and-forget: a missing opener, a headless box, or a spawn failure must\n * NEVER take the server down — the URL is always also printed to the console.\n */\n\nimport { spawn } from 'node:child_process';\n\n/** Resolve the platform's URL-opener command + args. */\nexport function browserOpenCommand(\n url: string,\n platform: NodeJS.Platform = process.platform,\n): { command: string; args: string[] } {\n if (platform === 'win32') {\n // `start` is a cmd builtin; the empty \"\" is the window title slot so URLs\n // containing `&` / spaces are passed through intact.\n return { command: 'cmd', args: ['/c', 'start', '', url] };\n }\n if (platform === 'darwin') {\n return { command: 'open', args: [url] };\n }\n return { command: 'xdg-open', args: [url] };\n}\n\n/** Spawn the OS browser-opener for `url` and register it as a protected\n * process so it survives kill/killAll. Never throws. */\nexport function openBrowser(url: string, platform: NodeJS.Platform = process.platform): void {\n try {\n const { command, args } = browserOpenCommand(url, platform);\n const child = spawn(command, args, { stdio: 'ignore', detached: true, windowsHide: true });\n // A missing opener (e.g. xdg-open absent on a headless box) surfaces as an\n // async 'error' event — swallow it so it doesn't crash the process.\n child.on('error', () => {});\n child.unref();\n\n // Register the browser process as protected so process.kill / killAll\n // never accidentally terminates it — that would crash the webui session.\n // The registry is imported lazily to avoid a circular dependency with\n // @wrongstack/tools (which the webui server does not directly depend on).\n if (child.pid) {\n try {\n // Dynamic import to avoid hard dependency on @wrongstack/tools from\n // this module (the webui server may not have tools installed).\n import('@wrongstack/tools').then(({ getProcessRegistry }) => {\n const pid = child.pid;\n if (pid === undefined) return;\n getProcessRegistry().register({\n pid,\n name: 'browser',\n command: `${command} ${args.join(' ')}`,\n startedAt: Date.now(),\n child,\n protected: true,\n });\n // Auto-unregister on exit so the process list stays accurate.\n child.on('exit', () => {\n getProcessRegistry().unregister(pid);\n });\n }).catch(() => {\n // @wrongstack/tools may not be available — silently skip registration.\n });\n } catch {\n // Module resolution failure — silently skip.\n }\n }\n } catch {\n // Synchronous spawn failure — best-effort, ignore.\n }\n}\n","/**\n * Token-usage cost math for the WebUI server.\n *\n * models.dev pricing is expressed in **dollars per 1,000,000 tokens**, and\n * providers omit the field entirely for free/unmetered plans. Both the\n * `session.start` payload (which ships the per-token rates to the client) and\n * `stats.get` (which reports an actual dollar figure) repeated the same\n * \"read `model.cost.*` with a `?? 0` fallback, then divide by 1e6\" logic\n * inline. Pulling it here keeps the rate normalization and the cost formula in\n * one tested place — a wrong field name or a missing `/ 1e6` silently produces\n * a plausible-but-wrong number, which is exactly what a unit test should pin.\n */\n\n/** Per-1,000,000-token pricing, normalized to numbers (0 when unpriced). */\nexport interface CostRates {\n /** $ per 1M input tokens. */\n input: number;\n /** $ per 1M output tokens. */\n output: number;\n /** $ per 1M cache-read tokens. */\n cacheRead: number;\n}\n\n/** Token counts for a turn/session. `cacheRead` is optional (older counters). */\nexport interface TokenUsage {\n input: number;\n output: number;\n cacheRead?: number | undefined;\n}\n\n/**\n * Normalize a models.dev model object's pricing into {@link CostRates}.\n * Missing model, missing `cost`, or missing individual fields all yield 0 —\n * free/unmetered plans report `$0` rather than crashing.\n */\nexport function getCostRates(model: unknown): CostRates {\n const cost = (\n model as { cost?: { input?: number | undefined; output?: number | undefined; cache_read?: number | undefined } } | null | undefined\n )?.cost;\n return {\n input: cost?.input ?? 0,\n output: cost?.output ?? 0,\n cacheRead: cost?.cache_read ?? 0,\n };\n}\n\n/**\n * Dollar cost of `usage` at the given per-1M-token `rates`. Returns 0 when all\n * rates are 0 (unpriced plan).\n */\nexport function computeUsageCost(usage: TokenUsage, rates: CostRates): number {\n return (\n (usage.input * rates.input +\n usage.output * rates.output +\n (usage.cacheRead ?? 0) * rates.cacheRead) /\n 1_000_000\n );\n}\n","import type { WebSocket } from 'ws';\nimport type { ProviderConfig } from '@wrongstack/core';\nimport { DefaultSecretScrubber } from '@wrongstack/core';\nimport { probeLocalLlm } from '@wrongstack/runtime/probe';\nimport { loadSavedProviders, saveProviders } from './provider-config-io.js';\nimport { toErrorMessage } from '@wrongstack/core/utils';\nimport {\n upsertKey as upsertKeyRecord,\n deleteKey as deleteKeyRecord,\n setActiveKey as setActiveKeyRecord,\n addProvider as addProviderRecord,\n removeProvider as removeProviderRecord,\n maskedKey,\n normalizeKeys,\n} from './provider-keys.js';\nimport type { ConnectedClient, WSServerMessage } from './types.js';\nimport { send, sendResult, errMessage } from './ws-utils.js';\n\n/**\n * Wire shape of one saved provider as broadcast over `providers.saved`.\n * The WebUI's `<ProviderModelsPanel>` consumes this — when\n * `pickedModelId` / `models` is missing, the panel renders the empty\n * state.\n */\nexport interface SavedProviderView {\n id: string;\n family?: string | undefined;\n baseUrl?: string | undefined;\n /** Saved model allowlist, verbatim (undefined / [] both possible). */\n models?: string[] | undefined;\n /** First entry of `models`, or undefined when the list is empty/unset. */\n pickedModelId?: string | undefined;\n apiKeys: Array<{\n label: string;\n maskedKey: string;\n isActive: boolean;\n createdAt: string;\n }>;\n}\n\n/**\n * Canonical projection from in-memory `ProviderConfig` to the\n * `providers.saved` wire shape. Pure (no I/O) so it's unit-tested in\n * isolation — see `tests/server/provider-handlers-projection.test.ts`.\n *\n * Secrets never leave: every key is run through `maskedKey` before it\n * reaches the wire.\n */\nexport function projectSavedProviders(\n providers: Record<string, ProviderConfig>,\n): SavedProviderView[] {\n return Object.entries(providers).map(([id, cfg]) => {\n const keys = normalizeKeys(cfg);\n const models = cfg.models;\n const view: SavedProviderView = {\n id,\n family: cfg.family ?? id,\n baseUrl: cfg.baseUrl,\n models,\n apiKeys: keys.map((k) => ({\n label: k.label,\n maskedKey: maskedKey(k.apiKey),\n isActive: k.label === cfg.activeKey,\n createdAt: k.createdAt,\n })),\n };\n const picked = models && models.length > 0 ? models[0] : undefined;\n if (picked !== undefined) view.pickedModelId = picked;\n return view;\n });\n}\n\n/** Shared scrubber for probe error/body redaction. */\nconst probeScrubber = new DefaultSecretScrubber();\n\nexport interface ProviderHandlerDeps {\n globalConfigPath: string;\n vault: import('@wrongstack/core').SecretVault;\n /** Shared config write lock — serialized via chained promises */\n setConfigWriteLock: (lock: Promise<void>) => void;\n getConfigWriteLock: () => Promise<void>;\n /** Broadcast a message to all connected WebUI clients */\n broadcast: (clients: Map<WebSocket, ConnectedClient>, msg: WSServerMessage) => void;\n /** Connected WebUI clients map */\n clients: Map<WebSocket, ConnectedClient>;\n}\n\nexport function createProviderHandlers(deps: ProviderHandlerDeps) {\n const { globalConfigPath, vault, broadcast, clients } = deps;\n let configWriteLock = deps.getConfigWriteLock();\n\n async function loadConfigProviders(): Promise<Record<string, ProviderConfig>> {\n return loadSavedProviders(globalConfigPath, vault);\n }\n\n async function saveConfigProviders(providers: Record<string, ProviderConfig>): Promise<void> {\n const next = configWriteLock\n .then(() => saveProviders(globalConfigPath, vault, providers))\n .catch((err) => {\n const msg = toErrorMessage(err);\n console.error(JSON.stringify({\n level: 'error',\n event: 'webui.provider_save_failed',\n message: msg,\n timestamp: new Date().toISOString(),\n }));\n });\n configWriteLock = next;\n deps.setConfigWriteLock(next);\n await next;\n }\n\n async function handleKeyUpsert(ws: WebSocket, providerId: string, label: string, apiKey: string): Promise<void> {\n try {\n const providers = await loadConfigProviders();\n const result = upsertKeyRecord(providers, providerId, label, apiKey, new Date().toISOString());\n if (result.ok) {\n await saveConfigProviders(providers);\n broadcastSaved(providers);\n }\n sendResult(ws, result.ok, result.message);\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n }\n\n async function handleKeyDelete(ws: WebSocket, providerId: string, label: string): Promise<void> {\n try {\n const providers = await loadConfigProviders();\n const result = deleteKeyRecord(providers, providerId, label);\n if (result.ok) {\n await saveConfigProviders(providers);\n broadcastSaved(providers);\n }\n sendResult(ws, result.ok, result.message);\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n }\n\n async function handleKeySetActive(ws: WebSocket, providerId: string, label: string): Promise<void> {\n try {\n const providers = await loadConfigProviders();\n const result = setActiveKeyRecord(providers, providerId, label);\n if (result.ok) {\n await saveConfigProviders(providers);\n broadcastSaved(providers);\n }\n sendResult(ws, result.ok, result.message);\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n }\n\n async function handleProviderAdd(ws: WebSocket, payload: { id: string; family: string; baseUrl?: string | undefined; apiKey?: string | undefined }): Promise<void> {\n try {\n const providers = await loadConfigProviders();\n const result = addProviderRecord(providers, payload, new Date().toISOString());\n if (result.ok) {\n await saveConfigProviders(providers);\n broadcastSaved(providers);\n }\n sendResult(ws, result.ok, result.message);\n if (result.ok) {\n console.log(`[WebUI] Provider \"${payload.id}\" added via provider.add`);\n }\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n }\n\n async function handleProviderRemove(ws: WebSocket, providerId: string): Promise<void> {\n try {\n const providers = await loadConfigProviders();\n const result = removeProviderRecord(providers, providerId);\n if (result.ok) {\n await saveConfigProviders(providers);\n broadcastSaved(providers);\n }\n sendResult(ws, result.ok, result.message);\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n }\n\n /** Broadcast the current saved-provider list to every connected client. */\n function broadcastSaved(providers: Record<string, ProviderConfig>): void {\n broadcast(clients, {\n type: 'providers.saved',\n payload: { providers: projectSavedProviders(providers) },\n });\n }\n\n /** Remove the saved model allowlist for a provider. */\n async function handleProviderClearModels(ws: WebSocket, providerId: string): Promise<void> {\n try {\n const providers = await loadConfigProviders();\n const cfg = providers[providerId];\n if (!cfg) {\n sendResult(ws, false, `Unknown provider \"${providerId}\"`);\n return;\n }\n delete cfg.models;\n await saveConfigProviders(providers);\n sendResult(ws, true, `Cleared model allowlist for ${providerId}`);\n broadcastSaved(providers);\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n }\n\n /** Restore a previously-cleared model allowlist (pairs with clear). */\n async function handleProviderUndoClear(\n ws: WebSocket,\n providerId: string,\n previousModels: string[],\n ): Promise<void> {\n try {\n const providers = await loadConfigProviders();\n const cfg = providers[providerId];\n if (!cfg) {\n sendResult(ws, false, `Unknown provider \"${providerId}\"`);\n return;\n }\n cfg.models = [...previousModels];\n await saveConfigProviders(providers);\n sendResult(ws, true, `Restored ${previousModels.length} model(s) for ${providerId}`);\n broadcastSaved(providers);\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n }\n\n /** Update a saved provider's wire config (family / baseUrl / envVars / models). */\n async function handleProviderUpdate(\n ws: WebSocket,\n payload: {\n id: string;\n family?: string | undefined;\n baseUrl?: string | undefined;\n envVars?: string[] | undefined;\n models?: string[] | undefined;\n },\n ): Promise<void> {\n try {\n const providers = await loadConfigProviders();\n const cfg = providers[payload.id];\n if (!cfg) {\n sendResult(ws, false, `Unknown provider \"${payload.id}\"`);\n return;\n }\n if (payload.family !== undefined) cfg.family = payload.family as ProviderConfig['family'];\n if (payload.baseUrl !== undefined) cfg.baseUrl = payload.baseUrl;\n if (payload.envVars !== undefined) cfg.envVars = payload.envVars;\n if (payload.models !== undefined) cfg.models = payload.models;\n await saveConfigProviders(providers);\n sendResult(ws, true, `Updated ${payload.id}`);\n broadcastSaved(providers);\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n }\n\n /**\n * Run a health probe against a saved provider's `/v1/models` and\n * reply with a `provider.probe` message. Never throws — the\n * `ProbeResult` carries the failure mode in its `status`.\n */\n async function handleProviderProbe(\n ws: WebSocket,\n providerId: string,\n timeoutMs?: number,\n ): Promise<void> {\n const reply = (payload: Record<string, unknown>): void =>\n send(ws, { type: 'provider.probe', payload: { providerId, ...payload } });\n try {\n const providers = await loadConfigProviders();\n const cfg = providers[providerId];\n if (!cfg) {\n reply({ ok: false, status: 'no_provider' });\n return;\n }\n if (!cfg.baseUrl) {\n reply({ ok: false, status: 'no_base_url' });\n return;\n }\n const keys = normalizeKeys(cfg);\n const active = keys.find((k) => k.label === cfg.activeKey) ?? keys[0];\n const result = await probeLocalLlm({\n baseUrl: cfg.baseUrl,\n apiKey: active?.apiKey,\n noAuth: false,\n scrubber: probeScrubber,\n ...(timeoutMs !== undefined ? { timeoutMs } : {}),\n });\n reply(result as never as Record<string, unknown>);\n } catch (err) {\n reply({ ok: false, status: 'unreachable', detail: errMessage(err) });\n }\n }\n\n return {\n handleKeyUpsert,\n handleKeyDelete,\n handleKeySetActive,\n handleProviderAdd,\n handleProviderRemove,\n handleProviderClearModels,\n handleProviderUndoClear,\n handleProviderUpdate,\n handleProviderProbe,\n loadConfigProviders,\n };\n}\n","/**\n * Shared config I/O helpers for the `providers` map inside the global config.\n *\n * Extracted from both `packages/webui/src/server/index.ts` and\n * `packages/cli/src/webui-server.ts` so the CLI's `--webui` mode doesn't\n * duplicate the read-merge-decrypt / encrypt-write cycle. Callers supply\n * their own vault (already booted) and config path — this module is pure I/O\n * with no side-channel state.\n */\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { type ProviderConfig, type SecretVault, atomicWrite } from '@wrongstack/core';\nimport { decryptConfigSecrets, encryptConfigSecrets } from '@wrongstack/core/security';\n\n/**\n * Read the `providers` section from the global config, decrypting\n * secret-bearing fields. Returns an empty record when the config file\n * doesn't exist or has no `providers` key.\n */\nexport async function loadSavedProviders(\n configPath: string,\n vault: SecretVault,\n): Promise<Record<string, ProviderConfig>> {\n let raw: string;\n try {\n raw = await fs.readFile(configPath, 'utf8');\n } catch {\n return {};\n }\n let parsed: { providers?: Record<string, ProviderConfig> } = {};\n try {\n parsed = JSON.parse(raw) as { providers?: Record<string, ProviderConfig> };\n } catch {\n return {};\n }\n if (!parsed.providers) return {};\n return decryptConfigSecrets(parsed.providers, vault);\n}\n\n/**\n * Write `providers` back into the global config, encrypting secrets first.\n * Refuses to overwrite a corrupt-but-existing config file (the operator\n * should fix it manually). When the config file is missing (ENOENT), starts\n * from an empty object.\n */\nexport async function saveProviders(\n configPath: string,\n vault: SecretVault,\n providers: Record<string, ProviderConfig>,\n): Promise<void> {\n let raw: string;\n let fileExists = true;\n try {\n raw = await fs.readFile(configPath, 'utf8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n throw new Error(\n `Refusing to mutate ${configPath}: ${(err as Error).message}`,\n { cause: err },\n );\n }\n fileExists = false;\n raw = '{}';\n }\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(raw) as Record<string, unknown>;\n } catch (err) {\n if (fileExists) {\n throw new Error(\n `Refusing to overwrite corrupt config at ${configPath} ` +\n `(${(err as Error).message}). Fix or move the file aside before retrying.`,\n { cause: err },\n );\n }\n parsed = {};\n }\n parsed.providers = providers;\n const encrypted = encryptConfigSecrets(parsed, vault);\n await atomicWrite(configPath, JSON.stringify(encrypted, null, 2), { mode: 0o600 });\n}\n\n// ---------------------------------------------------------------------------\n// Standalone WebUI server helpers (boot phase — not WS-connected)\n// ---------------------------------------------------------------------------\n\nimport { DefaultSecretVault } from '@wrongstack/core';\n\n/**\n * Small helper for the standalone WebUI entry point: create a\n * `{ load, save }` pair from a config path alone (uses the\n * config-directory-relative `.key` file for the vault). The `--webui`\n * CLI mode and the standalone server both need to read/write the\n * `providers` map identically.\n */\nexport function createProviderConfigIO(configPath: string) {\n const keyFile = path.join(path.dirname(configPath), '.key');\n const vault = new DefaultSecretVault({ keyFile });\n\n return {\n load: () => loadSavedProviders(configPath, vault),\n save: (providers: Record<string, ProviderConfig>) =>\n saveProviders(configPath, vault, providers),\n };\n}\n","import { expectDefined } from '@wrongstack/core';\n/**\n * Pure provider/API-key record transforms for the WebUI server's `key.*` and\n * `provider.*` WebSocket handlers.\n *\n * These operate on an in-memory `providers` record (the decrypted\n * `config.providers` map) and return a `{ ok, message }` result mirroring the\n * status string the handler sends back to the client. All persistence\n * (load/decrypt, encrypt/atomic-write) and WS messaging stays in `index.ts` —\n * keeping this layer pure means the security-sensitive key bookkeeping (which\n * key is active, when a provider is dropped, how legacy single-key configs are\n * normalized) is unit-testable without a vault or a socket.\n *\n * Extracted from `index.ts`; transforms mutate the passed record in place, the\n * same way the original handlers did before calling `saveProviders`.\n */\nimport type { ProviderApiKey, ProviderConfig } from '@wrongstack/core';\nexport type ProvidersRecord = Record<string, ProviderConfig>;\n\nexport interface KeyOpResult {\n ok: boolean;\n message: string;\n}\n\n/**\n * Normalize a provider's keys to the array form, upgrading a legacy single\n * `apiKey` string to a one-element `[{ label: 'default', ... }]` list. Returns\n * fresh copies so callers can mutate without aliasing the stored config.\n */\nexport function normalizeKeys(cfg: ProviderConfig): ProviderApiKey[] {\n if (Array.isArray(cfg.apiKeys) && cfg.apiKeys.length > 0) {\n return cfg.apiKeys.map((k) => ({ ...k }));\n }\n if (typeof cfg.apiKey === 'string' && cfg.apiKey.length > 0) {\n return [{ label: 'default', apiKey: cfg.apiKey, createdAt: '' }];\n }\n return [];\n}\n\n/**\n * Write a normalized key list back onto a provider config: drop all key fields\n * when empty, otherwise sync `apiKeys` and re-point `activeKey` if it no longer\n * names a present key. Does NOT mirror the plaintext key to the legacy `apiKey`\n * field — that would leak the secret on accidental serialization. Consumers\n * that need the real key should read from `apiKeys[]` directly.\n */\nexport function writeKeysBack(cfg: ProviderConfig, keys: ProviderApiKey[]): void {\n if (keys.length === 0) {\n delete cfg.apiKeys;\n delete cfg.apiKey;\n delete cfg.activeKey;\n return;\n }\n cfg.apiKeys = keys;\n const active = keys.find((k) => k.label === cfg.activeKey) ?? expectDefined(keys[0]);\n // Do NOT mirror plaintext to cfg.apiKey — cleared to prevent serialization leaks.\n delete cfg.apiKey;\n if (!cfg.activeKey || !keys.some((k) => k.label === cfg.activeKey)) {\n cfg.activeKey = active.label;\n }\n}\n\n/** Mask a secret for display: `••••` for short keys, `abcd…wxyz` otherwise. */\nexport function maskedKey(key: string | undefined): string {\n if (!key) return '—';\n if (key.length <= 8) return '•'.repeat(key.length);\n return `${key.slice(0, 4)}…${key.slice(-4)}`;\n}\n\n/** Add or replace a labeled key for a provider, creating the provider if new. */\nexport function upsertKey(\n providers: ProvidersRecord,\n providerId: string,\n label: string,\n apiKey: string,\n nowIso: string,\n): KeyOpResult {\n const existing: ProviderConfig = providers[providerId] ?? { type: providerId };\n const keys = normalizeKeys(existing);\n const idx = keys.findIndex((k) => k.label === label);\n if (idx >= 0) {\n keys[idx] = { ...expectDefined(keys[idx]), apiKey, createdAt: nowIso };\n } else {\n keys.push({ label, apiKey, createdAt: nowIso });\n }\n writeKeysBack(existing, keys);\n if (!existing.activeKey) existing.activeKey = label;\n providers[providerId] = existing;\n return { ok: true, message: `Key \"${label}\" saved for ${providerId}` };\n}\n\n/** Remove a labeled key; drops the provider entirely when its last key goes. */\nexport function deleteKey(\n providers: ProvidersRecord,\n providerId: string,\n label: string,\n): KeyOpResult {\n const existing = providers[providerId];\n if (!existing) {\n return { ok: false, message: `Provider \"${providerId}\" not found` };\n }\n const keys = normalizeKeys(existing).filter((k) => k.label !== label);\n if (keys.length === 0) {\n delete providers[providerId];\n } else {\n writeKeysBack(existing, keys);\n if (existing.activeKey === label) existing.activeKey = keys[0]?.label;\n providers[providerId] = existing;\n }\n return { ok: true, message: `Key \"${label}\" deleted from ${providerId}` };\n}\n\n/** Point a provider's active key at the given label. */\nexport function setActiveKey(\n providers: ProvidersRecord,\n providerId: string,\n label: string,\n): KeyOpResult {\n const existing = providers[providerId];\n if (!existing) {\n return { ok: false, message: `Provider \"${providerId}\" not found` };\n }\n existing.activeKey = label;\n writeKeysBack(existing, normalizeKeys(existing));\n providers[providerId] = existing;\n return { ok: true, message: `Active key for ${providerId} set to \"${label}\"` };\n}\n\n/** Register a brand-new provider (optionally with an initial `default` key). */\nexport function addProvider(\n providers: ProvidersRecord,\n payload: { id: string; family: string; baseUrl?: string | undefined; apiKey?: string | undefined },\n nowIso: string,\n): KeyOpResult {\n if (providers[payload.id]) {\n return {\n ok: false,\n message: `Provider \"${payload.id}\" already exists. Use key.add to add a key.`,\n };\n }\n const newProv: ProviderConfig = {\n type: payload.id,\n family: payload.family as ProviderConfig['family'],\n baseUrl: payload.baseUrl,\n };\n if (payload.apiKey) {\n newProv.apiKeys = [{ label: 'default', apiKey: payload.apiKey, createdAt: nowIso }];\n newProv.activeKey = 'default';\n }\n providers[payload.id] = newProv;\n return { ok: true, message: `Provider \"${payload.id}\" added` };\n}\n\n/** Remove an entire provider and all its keys. */\nexport function removeProvider(providers: ProvidersRecord, providerId: string): KeyOpResult {\n if (!providers[providerId]) {\n return { ok: false, message: `Provider \"${providerId}\" not found` };\n }\n delete providers[providerId];\n return { ok: true, message: `Provider \"${providerId}\" removed` };\n}\n","/**\n * Mode route handlers — extracted from the startWebUI closure in index.ts.\n * Mirrors createProviderHandlers: a factory that closes the handler bodies over\n * an explicit context object instead of the giant startWebUI scope. The one\n * piece of outer mutable state (the `modeId` let) is threaded in as a setter so\n * the factory stays a pure function of its context.\n */\nimport type { WebSocket } from 'ws';\nimport {\n type Context,\n DefaultSystemPromptBuilder,\n type DefaultMemoryStore,\n type DefaultModeStore,\n type SkillLoader,\n type ToolRegistry,\n} from '@wrongstack/core';\nimport type { ConnectedClient } from './types.js';\nimport type { ModeRouteHandlers } from './mode-routes.js';\nimport { broadcast, errMessage, send, sendResult } from './ws-utils.js';\nimport { validateModeSwitchPayload } from './ws-payload-validation.js';\n\n/** The rich payload startWebUI's sessionStartPayload() resolves to. Matches the\n * WSSessionStart wire shape; broadcast() accepts it for a 'session.start' msg. */\ntype SessionStartPayload = {\n sessionId: string;\n model: string;\n provider: string;\n maxContext: number;\n inputCost: number;\n outputCost: number;\n cacheReadCost: number;\n projectName: string;\n projectRoot: string;\n cwd: string;\n mode: string;\n contextMode: string;\n};\ntype ModelCapabilities = NonNullable<\n ConstructorParameters<typeof DefaultSystemPromptBuilder>[0]\n>['modelCapabilities'];\n\nexport interface ModeHandlersContext {\n modeStore: DefaultModeStore;\n memoryStore: DefaultMemoryStore;\n skillLoader: SkillLoader | undefined;\n modelCapabilities: ModelCapabilities;\n context: Context;\n toolRegistry: ToolRegistry;\n config: { provider: string; model: string };\n projectRoot: string;\n clients: Map<WebSocket, ConnectedClient>;\n /** Update the outer `modeId` binding on a successful switch. */\n setModeId: (id: string) => void;\n /** Rebuilds the rich session.start payload broadcast after a mode switch. */\n sessionStartPayload: () => Promise<SessionStartPayload>;\n}\n\nexport function createModeHandlers(ctx: ModeHandlersContext): ModeRouteHandlers {\n return {\n listModes: async (ws) => {\n try {\n const modes = await ctx.modeStore.listModes();\n const active = await ctx.modeStore.getActiveMode();\n send(ws, {\n type: 'modes.list',\n payload: {\n modes: modes.map((m) => ({\n id: m.id,\n name: m.name,\n description: m.description,\n isActive: m.id === (active?.id ?? 'default'),\n })),\n activeId: active?.id ?? 'default',\n },\n });\n } catch (err) {\n send(ws, {\n type: 'modes.list',\n payload: {\n modes: [],\n activeId: 'default',\n error: errMessage(err),\n },\n });\n }\n },\n switchMode: async (ws, msg) => {\n const parsed = validateModeSwitchPayload(msg.payload);\n if (!parsed.ok) {\n sendResult(ws, false, parsed.message);\n return;\n }\n const { id } = parsed.value;\n try {\n if (id === 'default') {\n await ctx.modeStore.setActiveMode(null);\n } else {\n const found = await ctx.modeStore.getMode(id);\n if (!found) throw new Error(`Unknown mode \"${id}\"`);\n await ctx.modeStore.setActiveMode(id);\n }\n ctx.setModeId(id);\n const modePrompt = id === 'default' ? '' : ((await ctx.modeStore.getMode(id))?.prompt ?? '');\n const freshBuilder = new DefaultSystemPromptBuilder({\n memoryStore: ctx.memoryStore,\n skillLoader: ctx.skillLoader,\n modeStore: ctx.modeStore,\n modeId: id,\n modePrompt,\n modelCapabilities: ctx.modelCapabilities,\n });\n ctx.context.systemPrompt = await freshBuilder.build({\n cwd: ctx.projectRoot,\n projectRoot: ctx.projectRoot,\n tools: ctx.toolRegistry.list(),\n provider: ctx.config.provider,\n model: ctx.config.model,\n });\n sendResult(ws, true, `Switched to mode \"${id}\"`);\n broadcast(ctx.clients, {\n type: 'session.start',\n payload: { ...(await ctx.sessionStartPayload()) },\n });\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n },\n };\n}\n","/**\n * Project route handlers — extracted from the startWebUI closure in index.ts.\n * Mirrors createProviderHandlers/createModeHandlers. selectProject is the heavy\n * one: it tears down the current session and re-initialises for the chosen\n * project, mutating several startWebUI `let` bindings. Those are threaded in as\n * getters/setters so the factory stays a pure function of its context — the\n * handler bodies are a verbatim lift, only the dependency references changed.\n */\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { WebSocket } from 'ws';\nimport {\n type Context,\n DefaultSessionStore,\n DefaultSystemPromptBuilder,\n type DefaultMemoryStore,\n type DefaultModeStore,\n type DefaultTokenCounter,\n getSessionRegistry,\n type SkillLoader,\n type ToolRegistry,\n} from '@wrongstack/core';\nimport type { ConnectedClient } from './types.js';\nimport type { ProjectRouteHandlers } from './project-routes.js';\nimport { broadcast, errMessage, send, sendResult } from './ws-utils.js';\nimport {\n validateProjectsAddPayload,\n validateProjectsSelectPayload,\n validateWorkingDirSetPayload,\n} from './ws-payload-validation.js';\nimport { ensureProjectDataDir, generateProjectSlug, loadManifest, saveManifest } from './projects-manifest.js';\nimport { resolveWorkingDirInsideProject } from './path-containment.js';\n\ntype Session = Awaited<ReturnType<DefaultSessionStore['create']>>;\ntype SessionStartPayload = {\n sessionId: string;\n model: string;\n provider: string;\n maxContext: number;\n inputCost: number;\n outputCost: number;\n cacheReadCost: number;\n projectName: string;\n projectRoot: string;\n cwd: string;\n mode: string;\n contextMode: string;\n};\ntype ModelCapabilities = NonNullable<\n ConstructorParameters<typeof DefaultSystemPromptBuilder>[0]\n>['modelCapabilities'];\n\nexport interface ProjectHandlersContext {\n globalConfigPath: string;\n wpaths: { globalRoot: string };\n clients: Map<WebSocket, ConnectedClient>;\n context: Context;\n modeStore: DefaultModeStore;\n memoryStore: DefaultMemoryStore;\n skillLoader: SkillLoader | undefined;\n modelCapabilities: ModelCapabilities;\n toolRegistry: ToolRegistry;\n tokenCounter: DefaultTokenCounter;\n config: { provider: string; model: string };\n // Live reads of the mutable startWebUI bindings.\n getModeId: () => string;\n getProjectRoot: () => string;\n getSession: () => Session;\n // Mutations of the startWebUI bindings.\n setProjectRoot: (p: string) => void;\n setWorkingDir: (p: string) => void;\n setSession: (s: Session) => void;\n setSessionStore: (s: DefaultSessionStore) => void;\n setSessionStartedAt: (t: number) => void;\n /** Abort + clear any in-flight runLock before switching projects. */\n abortRunLock: () => void;\n sessionStartPayload: () => Promise<SessionStartPayload>;\n}\n\nexport function createProjectHandlers(ctx: ProjectHandlersContext): ProjectRouteHandlers {\n return {\n listProjects: async (ws) => {\n try {\n const manifest = await loadManifest(ctx.globalConfigPath);\n send(ws, { type: 'projects.list', payload: { projects: manifest.projects } });\n } catch (err) {\n send(ws, { type: 'projects.list', payload: { projects: [], error: errMessage(err) } });\n }\n },\n addProject: async (ws, msg) => {\n const parsed = validateProjectsAddPayload(msg.payload);\n if (!parsed.ok) {\n send(ws, {\n type: 'projects.added',\n payload: { name: '', root: '', slug: '', message: parsed.message },\n });\n return;\n }\n const { root: addRoot, name: displayName } = parsed.value;\n try {\n const resolved = path.resolve(addRoot);\n await fs.access(resolved);\n const stat = await fs.stat(resolved);\n if (!stat.isDirectory()) throw new Error(`Not a directory: ${resolved}`);\n\n const manifest = await loadManifest(ctx.globalConfigPath);\n const existing = manifest.projects.find((p) => p.root === resolved);\n if (existing) {\n send(ws, {\n type: 'projects.added',\n payload: {\n name: existing.name,\n root: existing.root,\n slug: existing.slug,\n message: `Already registered as \"${existing.name}\"`,\n },\n });\n return;\n }\n\n const name = displayName?.trim() || path.basename(resolved);\n const slug = generateProjectSlug(resolved);\n await ensureProjectDataDir(slug, ctx.globalConfigPath);\n const now = new Date().toISOString();\n manifest.projects.push({ name, root: resolved, slug, lastSeen: now, createdAt: now });\n await saveManifest(manifest, ctx.globalConfigPath);\n\n send(ws, {\n type: 'projects.added',\n payload: { name, root: resolved, slug, message: `Registered project \"${name}\"` },\n });\n } catch (err) {\n send(ws, {\n type: 'projects.added',\n payload: { name: path.basename(addRoot), root: addRoot, slug: '', message: errMessage(err) },\n });\n }\n },\n selectProject: async (ws, msg) => {\n const parsed = validateProjectsSelectPayload(msg.payload);\n if (!parsed.ok) {\n send(ws, {\n type: 'projects.selected',\n payload: { root: '', name: '', message: parsed.message },\n });\n return;\n }\n const { root: selRoot, name: selName } = parsed.value;\n try {\n const resolved = path.resolve(selRoot);\n\n try {\n await fs.access(resolved);\n const stat = await fs.stat(resolved);\n if (!stat.isDirectory()) throw new Error(`Not a directory: ${resolved}`);\n } catch (err) {\n send(ws, {\n type: 'projects.selected',\n payload: {\n root: selRoot,\n name: selName || path.basename(selRoot),\n message: `Cannot switch: ${errMessage(err)}`,\n },\n });\n return;\n }\n\n const manifest = await loadManifest(ctx.globalConfigPath);\n const entry = manifest.projects.find((p) => p.root === resolved);\n if (entry) {\n entry.lastSeen = new Date().toISOString();\n entry.lastWorkingDir = resolved;\n } else {\n const name = selName?.trim() || path.basename(resolved);\n const slug = generateProjectSlug(resolved);\n manifest.projects.push({\n name,\n root: resolved,\n slug,\n lastSeen: new Date().toISOString(),\n createdAt: new Date().toISOString(),\n lastWorkingDir: resolved,\n });\n await ensureProjectDataDir(slug, ctx.globalConfigPath);\n }\n await saveManifest(manifest, ctx.globalConfigPath);\n\n ctx.abortRunLock();\n\n ctx.setProjectRoot(resolved);\n ctx.setWorkingDir(resolved);\n ctx.context.cwd = resolved;\n ctx.context.projectRoot = resolved;\n\n const switchSlug = entry?.slug ?? generateProjectSlug(resolved);\n\n try {\n const modeId = ctx.getModeId();\n const switchMode = modeId === 'default' ? undefined : await ctx.modeStore.getMode(modeId);\n const switchBuilder = new DefaultSystemPromptBuilder({\n memoryStore: ctx.memoryStore,\n skillLoader: ctx.skillLoader,\n modeStore: ctx.modeStore,\n modeId,\n modePrompt: switchMode?.prompt ?? '',\n modelCapabilities: ctx.modelCapabilities,\n });\n ctx.context.systemPrompt = await switchBuilder.build({\n cwd: resolved,\n projectRoot: resolved,\n tools: ctx.toolRegistry.list(),\n provider: ctx.config.provider,\n model: ctx.config.model,\n });\n } catch {\n /* best-effort */\n }\n\n const newSessionsDir = path.join(\n path.dirname(ctx.globalConfigPath),\n 'projects',\n switchSlug,\n 'sessions',\n );\n await fs.mkdir(newSessionsDir, { recursive: true });\n const newSessionStore = new DefaultSessionStore({ dir: newSessionsDir });\n\n const oldSession = ctx.getSession();\n const oldSessionId = oldSession.id;\n try {\n await oldSession.append({\n type: 'session_end',\n ts: new Date().toISOString(),\n usage: ctx.tokenCounter.total(),\n });\n await oldSession.close();\n } catch {\n // best-effort\n }\n\n ctx.setSessionStore(newSessionStore);\n const newSession = await newSessionStore.create({\n id: '',\n title: '',\n model: ctx.config.model,\n provider: ctx.config.provider,\n });\n ctx.setSession(newSession);\n ctx.context.session = newSession;\n ctx.context.state.replaceMessages([]);\n ctx.context.state.replaceTodos([]);\n ctx.context.readFiles.clear();\n ctx.context.fileMtimes.clear();\n ctx.tokenCounter.reset();\n ctx.setSessionStartedAt(Date.now());\n\n try {\n const registry = getSessionRegistry(ctx.wpaths.globalRoot);\n await registry.register({\n sessionId: newSession.id,\n projectSlug: switchSlug,\n projectRoot: resolved,\n projectName: path.basename(resolved),\n workingDir: resolved,\n clientType: 'webui',\n pid: process.pid,\n startedAt: new Date().toISOString(),\n });\n } catch {\n /* best-effort */\n }\n\n send(ws, {\n type: 'projects.selected',\n payload: {\n root: resolved,\n name: selName || path.basename(resolved),\n message: `Switched to ${selName || path.basename(resolved)}`,\n },\n });\n\n broadcast(ctx.clients, {\n type: 'subagent.event',\n payload: { kind: 'session_stopped', sessionId: oldSessionId },\n });\n\n broadcast(ctx.clients, {\n type: 'session.start',\n payload: {\n ...(await ctx.sessionStartPayload()),\n reset: true,\n clearedSessionId: oldSessionId,\n },\n });\n } catch (err) {\n send(ws, {\n type: 'projects.selected',\n payload: {\n root: selRoot,\n name: selName || path.basename(selRoot),\n message: errMessage(err),\n },\n });\n }\n },\n setWorkingDir: async (ws, msg) => {\n const parsed = validateWorkingDirSetPayload(msg.payload);\n if (!parsed.ok) {\n sendResult(ws, false, parsed.message);\n return;\n }\n const { path: newPath } = parsed.value;\n try {\n const projectRoot = ctx.getProjectRoot();\n const resolved = await resolveWorkingDirInsideProject(projectRoot, newPath);\n\n ctx.setWorkingDir(resolved);\n ctx.context.cwd = resolved;\n\n broadcast(ctx.clients, {\n type: 'working_dir.changed',\n payload: { cwd: resolved, projectRoot },\n });\n\n sendResult(ws, true, `Working directory set to ${resolved}`);\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n },\n };\n}\n","/**\n * Session route handlers — extracted from the startWebUI closure in index.ts.\n * The largest builder: session lifecycle (new/clear/resume/save), context ops\n * (debug/compact/repair), context-mode CRUD, and checkpoint list/rewind.\n *\n * Mirrors createProviderHandlers/createModeHandlers/createProjectHandlers. The\n * mutable startWebUI bindings the handlers touch (`session`, `sessionStartedAt`,\n * and the project-switch-mutable `sessionStore`/`projectRoot`) are threaded in\n * as getters/setters so this stays a pure function of its context. Handler\n * bodies are a verbatim lift — only dependency references changed.\n */\nimport * as path from 'node:path';\nimport type { WebSocket } from 'ws';\nimport {\n type Context,\n DEFAULT_CONTEXT_WINDOW_MODE_ID,\n type DefaultTokenCounter,\n type SessionStore,\n type ToolRegistry,\n type createStrategyCompactor,\n repairToolUseAdjacency,\n resolveContextWindowPolicy,\n} from '@wrongstack/core';\nimport type { ConnectedClient } from './types.js';\nimport type { SessionRouteHandlers } from './session-routes.js';\nimport type { CustomModeStore } from './custom-context-modes.js';\nimport { broadcast, errMessage, send, sendResult } from './ws-utils.js';\nimport { estimateContextBreakdown } from './token-estimator.js';\nimport {\n validateContextModeCreatePayload,\n validateContextModeDeletePayload,\n validateContextModeSwitchPayload,\n validateContextModeUpdatePayload,\n} from './ws-payload-validation.js';\n\ntype Session = Awaited<ReturnType<SessionStore['create']>>;\ntype SessionStartPayload = {\n sessionId: string;\n model: string;\n provider: string;\n maxContext: number;\n inputCost: number;\n outputCost: number;\n cacheReadCost: number;\n projectName: string;\n projectRoot: string;\n cwd: string;\n mode: string;\n contextMode: string;\n};\n\nexport interface SessionHandlersContext {\n config: { provider: string; model: string };\n clients: Map<WebSocket, ConnectedClient>;\n context: Context;\n toolRegistry: ToolRegistry;\n compactor: ReturnType<typeof createStrategyCompactor>;\n customModeStore: CustomModeStore;\n tokenCounter: DefaultTokenCounter;\n /** Live reads of the mutable startWebUI bindings. */\n getProjectRoot: () => string;\n getSession: () => Session;\n getSessionStore: () => SessionStore;\n /** Mutations of the startWebUI bindings. */\n setSession: (s: Session) => void;\n setSessionStartedAt: (t: number) => void;\n sessionStartPayload: () => Promise<SessionStartPayload>;\n}\n\nexport function createSessionHandlers(ctx: SessionHandlersContext): SessionRouteHandlers {\n return {\n newSession: async () => {\n const session = ctx.getSession();\n try {\n await session.append({\n type: 'session_end',\n ts: new Date().toISOString(),\n usage: ctx.tokenCounter.total(),\n });\n await session.close();\n } catch {\n // best-effort\n }\n const next = await ctx.getSessionStore().create({\n id: '',\n title: '',\n model: ctx.config.model,\n provider: ctx.config.provider,\n });\n ctx.setSession(next);\n ctx.context.session = next;\n ctx.context.state.replaceMessages([]);\n ctx.context.state.replaceTodos([]);\n ctx.context.readFiles.clear();\n ctx.context.fileMtimes.clear();\n ctx.tokenCounter.reset();\n ctx.setSessionStartedAt(Date.now());\n broadcast(ctx.clients, { type: 'session.start', payload: await ctx.sessionStartPayload() });\n },\n clearContext: async (ws) => {\n ctx.context.state.replaceMessages([]);\n ctx.context.state.replaceTodos([]);\n ctx.context.readFiles.clear();\n ctx.context.fileMtimes.clear();\n ctx.tokenCounter.reset();\n sendResult(ws, true, 'Context cleared');\n broadcast(ctx.clients, {\n type: 'session.start',\n payload: { ...(await ctx.sessionStartPayload()), reset: true },\n });\n },\n debugContext: async (ws) => {\n const breakdown = estimateContextBreakdown({\n systemPrompt: ctx.context.systemPrompt,\n tools: ctx.toolRegistry.list(),\n messages: ctx.context.messages,\n });\n send(ws, {\n type: 'context.debug',\n payload: {\n ...breakdown,\n mode: ctx.context.meta['contextWindowMode'] ?? DEFAULT_CONTEXT_WINDOW_MODE_ID,\n policy: ctx.context.meta['contextWindowPolicy'],\n },\n });\n },\n compactContext: async (ws, msg) => {\n const aggressive = !!(msg as { payload?: { aggressive?: boolean | undefined } }).payload?.aggressive;\n try {\n const report = await ctx.compactor.compact(ctx.context, { aggressive });\n send(ws, {\n type: 'context.compacted',\n payload: {\n before: report.before,\n after: report.after,\n saved: Math.max(0, report.before - report.after),\n reductions: report.reductions,\n repaired: report.repaired,\n },\n });\n sendResult(\n ws,\n true,\n `Compacted: ${report.before} → ${report.after} tokens (saved ~${Math.max(0, report.before - report.after)})`,\n );\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n },\n repairContext: async (ws) => {\n const beforeMessages = ctx.context.messages.length;\n const repaired = repairToolUseAdjacency(ctx.context.messages);\n if (repaired.report.changed) {\n ctx.context.state.replaceMessages(repaired.messages);\n }\n const payload = {\n removedToolUses: repaired.report.removedToolUses,\n removedToolResults: repaired.report.removedToolResults,\n removedMessages: repaired.report.removedMessages,\n beforeMessages,\n afterMessages: ctx.context.messages.length,\n };\n broadcast(ctx.clients, { type: 'context.repaired', payload });\n const removed =\n payload.removedToolUses.length + payload.removedToolResults.length + payload.removedMessages;\n sendResult(\n ws,\n true,\n removed > 0\n ? `Context repaired: removed ${removed} orphan protocol item(s)`\n : 'Context repair found no orphan protocol blocks',\n );\n },\n listContextModes: async (ws) => {\n const active = String(ctx.context.meta['contextWindowMode'] ?? DEFAULT_CONTEXT_WINDOW_MODE_ID);\n const allModes = ctx.customModeStore.list().map((m) => ({\n id: m.id,\n name: m.name,\n description: m.description,\n isActive: m.id === active,\n thresholds: m.thresholds,\n preserveK: m.preserveK,\n eliseThreshold: m.eliseThreshold,\n custom: (m as { custom?: boolean }).custom === true,\n }));\n send(ws, { type: 'context.modes.list', payload: { activeId: active, modes: allModes } });\n },\n switchContextMode: async (ws, msg) => {\n const parsed = validateContextModeSwitchPayload(msg.payload);\n if (!parsed.ok) {\n sendResult(ws, false, parsed.message);\n return;\n }\n const { id } = parsed.value;\n let policy = resolveContextWindowPolicy({}, id);\n if (policy.id !== id) {\n const customModes = ctx.customModeStore.list().filter((m) => (m as { custom?: boolean }).custom === true);\n const custom = customModes.find((m) => m.id === id);\n if (!custom) {\n sendResult(ws, false, `Unknown context mode \"${id}\"`);\n return;\n }\n policy = custom as never as typeof policy;\n }\n ctx.context.meta['contextWindowMode'] = policy.id;\n ctx.context.meta['contextWindowPolicy'] = policy;\n sendResult(ws, true, `Context mode switched to ${policy.id}`);\n broadcast(ctx.clients, {\n type: 'context.mode.changed',\n payload: { id: policy.id, name: policy.name, policy },\n });\n },\n createContextMode: async (ws, msg) => {\n const parsed = validateContextModeCreatePayload(msg.payload);\n if (!parsed.ok) {\n sendResult(ws, false, parsed.message);\n return;\n }\n const payload = parsed.value;\n const result = ctx.customModeStore.create({\n id: payload.id,\n name: payload.name,\n description: payload.description,\n thresholds: payload.thresholds,\n preserveK: payload.preserveK,\n eliseThreshold: payload.eliseThreshold,\n custom: true,\n aggressiveOn: 'soft',\n targetLoad: 0.65,\n });\n sendResult(ws, result.ok, result.error ?? `Mode \"${payload.id}\" created`);\n },\n updateContextMode: async (ws, msg) => {\n const parsed = validateContextModeUpdatePayload(msg.payload);\n if (!parsed.ok) {\n sendResult(ws, false, parsed.message);\n return;\n }\n const payload = parsed.value;\n const result = ctx.customModeStore.update(payload.id, {\n name: payload.name,\n description: payload.description,\n thresholds: payload.thresholds\n ? {\n warn: payload.thresholds.warn ?? 0.6,\n soft: payload.thresholds.soft ?? 0.75,\n hard: payload.thresholds.hard ?? 0.9,\n }\n : undefined,\n preserveK: payload.preserveK,\n eliseThreshold: payload.eliseThreshold,\n });\n sendResult(ws, result.ok, result.error ?? `Mode \"${payload.id}\" updated`);\n },\n deleteContextMode: async (ws, msg) => {\n const parsed = validateContextModeDeletePayload(msg.payload);\n if (!parsed.ok) {\n sendResult(ws, false, parsed.message);\n return;\n }\n const { id } = parsed.value;\n if (String(ctx.context.meta['contextWindowMode'] ?? '') === id) {\n ctx.context.meta['contextWindowMode'] = DEFAULT_CONTEXT_WINDOW_MODE_ID;\n ctx.context.meta['contextWindowPolicy'] = resolveContextWindowPolicy({}, DEFAULT_CONTEXT_WINDOW_MODE_ID);\n }\n const result = ctx.customModeStore.remove(id);\n sendResult(ws, result.ok, result.error ?? `Mode \"${id}\" deleted`);\n },\n listSessions: async (ws, msg) => {\n const limit = (msg as { payload?: { limit?: number | undefined } }).payload?.limit ?? 50;\n try {\n const list = await ctx.getSessionStore().list(limit);\n const currentId = ctx.getSession().id;\n send(ws, {\n type: 'sessions.list',\n payload: {\n sessions: list.map((s) => ({\n id: s.id,\n title: s.title,\n startedAt: s.startedAt,\n model: s.model,\n provider: s.provider,\n tokenTotal: s.tokenTotal,\n isCurrent: s.id === currentId,\n })),\n },\n });\n } catch (err) {\n send(ws, { type: 'sessions.list', payload: { sessions: [], error: errMessage(err) } });\n }\n },\n deleteSession: async (ws, msg) => {\n const { id } = (msg as { payload: { id: string } }).payload;\n try {\n if (id === ctx.getSession().id) {\n sendResult(ws, false, 'Cannot delete the active session');\n return;\n }\n await ctx.getSessionStore().delete(id);\n sendResult(ws, true, `Session ${id} deleted`);\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n },\n resumeSession: async (ws, msg) => {\n const { id } = (msg as { payload: { id: string } }).payload;\n try {\n const current = ctx.getSession();\n if (id === current.id) {\n sendResult(ws, false, 'Session is already active');\n return;\n }\n const resumed = await ctx.getSessionStore().resume(id);\n try {\n await current.append({\n type: 'session_end',\n ts: new Date().toISOString(),\n usage: ctx.tokenCounter.total(),\n });\n await current.close();\n } catch {\n /* noop */\n }\n ctx.setSession(resumed.writer);\n ctx.context.session = resumed.writer;\n ctx.context.state.replaceMessages(resumed.data.messages);\n ctx.context.readFiles.clear();\n ctx.context.fileMtimes.clear();\n ctx.tokenCounter.reset();\n ctx.tokenCounter.account(resumed.data.usage, ctx.config.model);\n ctx.setSessionStartedAt(Date.now());\n broadcast(ctx.clients, {\n type: 'session.start',\n payload: {\n ...(await ctx.sessionStartPayload()),\n reset: true,\n replayMessages: resumed.data.messages,\n replayUsage: resumed.data.usage,\n },\n });\n sendResult(ws, true, `Resumed session ${id}`);\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n },\n saveSession: async (ws) => {\n sendResult(ws, true, `Session ${ctx.getSession().id} is auto-saved`);\n },\n listCheckpoints: async (ws) => {\n try {\n const { DefaultSessionRewinder } = await import('@wrongstack/core');\n const projectRoot = ctx.getProjectRoot();\n const rewinder = new DefaultSessionRewinder(\n path.join(projectRoot, '.wrongstack', 'sessions'),\n projectRoot,\n );\n const checkpoints = await rewinder.listCheckpoints(ctx.getSession().id);\n send(ws, { type: 'session.checkpoints', payload: { checkpoints } });\n } catch {\n send(ws, { type: 'session.checkpoints', payload: { checkpoints: [] } });\n }\n },\n rewindSession: async (ws, msg) => {\n const { checkpointIndex } = (msg as { payload: { checkpointIndex: number } }).payload;\n try {\n const { DefaultSessionRewinder } = await import('@wrongstack/core');\n const projectRoot = ctx.getProjectRoot();\n const rewinder = new DefaultSessionRewinder(\n path.join(projectRoot, '.wrongstack', 'sessions'),\n projectRoot,\n );\n await rewinder.rewindToCheckpoint(ctx.getSession().id, checkpointIndex);\n await ctx.context.session.truncateToCheckpoint(checkpointIndex);\n sendResult(ws, true, `Rewound to checkpoint ${checkpointIndex}`);\n broadcast(ctx.clients, {\n type: 'session.start',\n payload: { ...(await ctx.sessionStartPayload()), reset: true },\n });\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n },\n };\n}\n","/**\n * Per-section context-window token estimate for the `context.debug` command.\n *\n * Uses the simple 4-chars-per-token heuristic — not exact, but close enough to\n * spot which section (system prompt, tool schemas, or message history) is\n * eating the context window. Tool schemas in particular are easy to overlook:\n * each tool ships its full JSON schema to the model every turn, so 20+ builtins\n * can cost 10-20k tokens on their own.\n *\n * Extracted from `index.ts` as a pure function so the breakdown maths can be\n * unit tested without standing up a Context/ToolRegistry.\n */\n\n/** 4-chars-per-token heuristic estimate for a string. */\nexport function estimateTokens(s: string): number {\n return Math.ceil(s.length / 4);\n}\n\n/** Stringify arbitrary content for length estimation (JSON, with fallbacks). */\nexport function stringifyContent(c: unknown): string {\n if (typeof c === 'string') return c;\n try {\n return JSON.stringify(c);\n } catch {\n return String(c);\n }\n}\n\ninterface PromptBlock {\n text?: string | undefined;\n}\ninterface ToolLike {\n name: string;\n inputSchema?: unknown | undefined;\n description?: string | undefined;\n}\ninterface ContentBlock {\n type?: string | undefined;\n text?: string | undefined;\n input?: unknown | undefined;\n content?: unknown | undefined;\n name?: string | undefined;\n}\ninterface MessageLike {\n role: string;\n content: unknown;\n}\n\nexport interface ToolTokenEntry {\n name: string;\n tokens: number;\n}\nexport interface MessageTokenEntry {\n index: number;\n role: string;\n tokens: number;\n preview: string;\n}\n\nexport interface ContextBreakdown {\n total: number;\n systemPrompt: number;\n tools: { total: number; count: number; breakdown: ToolTokenEntry[] };\n messages: { total: number; count: number; breakdown: MessageTokenEntry[] };\n}\n\nexport function messageTokens(content: unknown): number {\n if (typeof content === 'string') return estimateTokens(content);\n if (!Array.isArray(content)) return 0;\n let tk = 0;\n for (const b of content as ContentBlock[]) {\n if (b.type === 'text') tk += estimateTokens(b.text ?? '');\n else if (b.type === 'tool_use') tk += estimateTokens(stringifyContent(b.input));\n else if (b.type === 'tool_result') tk += estimateTokens(stringifyContent(b.content));\n else tk += estimateTokens(stringifyContent(b));\n }\n return tk;\n}\n\nexport function messagePreview(content: unknown): string {\n if (typeof content === 'string') return content.slice(0, 60);\n if (!Array.isArray(content)) return '';\n return (content as ContentBlock[])\n .map((b) =>\n b.type === 'text'\n ? (b.text ?? '').slice(0, 40)\n : b.type === 'tool_use'\n ? `[tool_use: ${b.name}]`\n : b.type === 'tool_result'\n ? '[tool_result]'\n : `[${b.type}]`,\n )\n .join(' ')\n .slice(0, 60);\n}\n\n/**\n * Compute the per-section token breakdown for the active context. Mirrors the\n * shape the `context.debug` WS reply expects (minus the `mode`/`policy` fields,\n * which the caller layers on from `context.meta`).\n */\nexport function estimateContextBreakdown(input: {\n systemPrompt: ReadonlyArray<PromptBlock>;\n tools: ReadonlyArray<ToolLike>;\n messages: ReadonlyArray<MessageLike>;\n}): ContextBreakdown {\n const sysTokens = input.systemPrompt.reduce((acc, b) => acc + estimateTokens(b.text ?? ''), 0);\n\n const toolBreakdown: ToolTokenEntry[] = input.tools.map((t) => {\n const schema = t.inputSchema ?? {};\n const desc = t.description ?? '';\n return {\n name: t.name,\n tokens:\n estimateTokens(t.name) + estimateTokens(desc) + estimateTokens(stringifyContent(schema)),\n };\n });\n const toolTokens = toolBreakdown.reduce((a, b) => a + b.tokens, 0);\n\n const messageBreakdown: MessageTokenEntry[] = input.messages.map((m, i) => ({\n index: i,\n role: m.role,\n tokens: messageTokens(m.content),\n preview: messagePreview(m.content),\n }));\n const msgTokens = messageBreakdown.reduce((a, b) => a + b.tokens, 0);\n\n return {\n total: sysTokens + toolTokens + msgTokens,\n systemPrompt: sysTokens,\n tools: { total: toolTokens, count: input.tools.length, breakdown: toolBreakdown },\n messages: { total: msgTokens, count: input.messages.length, breakdown: messageBreakdown },\n };\n}\n","import type { WebSocket } from 'ws';\nimport type { createProviderHandlers } from './provider-handlers.js';\nimport type { WSClientMessage } from './types.js';\nimport { sendResult } from './ws-utils.js';\n\nexport interface ProviderRouteHandlers {\n listProviders: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n listSavedProviders: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n listProviderModels: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n switchModel: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n refineModel: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n providerHandlers: ReturnType<typeof createProviderHandlers>;\n}\n\nfunction asPayloadRecord(msg: WSClientMessage): Record<string, unknown> | null {\n const payload = msg.payload;\n return typeof payload === 'object' && payload !== null && !Array.isArray(payload)\n ? (payload as Record<string, unknown>)\n : null;\n}\n\nfunction requiredString(payload: Record<string, unknown>, key: string): string | null {\n const value = payload[key];\n return typeof value === 'string' && value.trim().length > 0 ? value : null;\n}\n\nfunction optionalNumber(payload: Record<string, unknown>, key: string): number | undefined | null {\n const value = payload[key];\n if (value === undefined) return undefined;\n return typeof value === 'number' && Number.isFinite(value) ? value : null;\n}\n\nfunction optionalStringArray(payload: Record<string, unknown>, key: string): string[] | undefined | null {\n const value = payload[key];\n if (value === undefined) return undefined;\n return Array.isArray(value) && value.every((item) => typeof item === 'string') ? value : null;\n}\n\nfunction invalidPayload(ws: WebSocket, type: string): true {\n sendResult(ws, false, `${type} payload is invalid`);\n return true;\n}\n\nexport async function handleProviderRoute(\n ws: WebSocket,\n msg: WSClientMessage,\n routes: ProviderRouteHandlers,\n): Promise<boolean> {\n switch (msg.type) {\n case 'providers.list':\n await routes.listProviders(ws, msg);\n return true;\n case 'providers.saved':\n await routes.listSavedProviders(ws, msg);\n return true;\n case 'provider.models':\n await routes.listProviderModels(ws, msg);\n return true;\n case 'model.switch':\n await routes.switchModel(ws, msg);\n return true;\n case 'model.refine':\n await routes.refineModel(ws, msg);\n return true;\n\n case 'key.add':\n case 'key.update': {\n const payload = asPayloadRecord(msg);\n const providerId = payload ? requiredString(payload, 'providerId') : null;\n const label = payload ? requiredString(payload, 'label') : null;\n const apiKey = payload ? requiredString(payload, 'apiKey') : null;\n if (!providerId || !label || !apiKey) return invalidPayload(ws, msg.type);\n await routes.providerHandlers.handleKeyUpsert(ws, providerId, label, apiKey);\n return true;\n }\n\n case 'key.delete': {\n const payload = asPayloadRecord(msg);\n const providerId = payload ? requiredString(payload, 'providerId') : null;\n const label = payload ? requiredString(payload, 'label') : null;\n if (!providerId || !label) return invalidPayload(ws, msg.type);\n await routes.providerHandlers.handleKeyDelete(ws, providerId, label);\n return true;\n }\n\n case 'key.set_active': {\n const payload = asPayloadRecord(msg);\n const providerId = payload ? requiredString(payload, 'providerId') : null;\n const label = payload ? requiredString(payload, 'label') : null;\n if (!providerId || !label) return invalidPayload(ws, msg.type);\n await routes.providerHandlers.handleKeySetActive(ws, providerId, label);\n return true;\n }\n\n case 'provider.add': {\n const payload = asPayloadRecord(msg);\n const id = payload ? requiredString(payload, 'id') : null;\n const family = payload ? requiredString(payload, 'family') : null;\n const baseUrl = payload?.['baseUrl'];\n const apiKey = payload?.['apiKey'];\n if (!id || !family) return invalidPayload(ws, msg.type);\n if (baseUrl !== undefined && typeof baseUrl !== 'string') return invalidPayload(ws, msg.type);\n if (apiKey !== undefined && typeof apiKey !== 'string') return invalidPayload(ws, msg.type);\n await routes.providerHandlers.handleProviderAdd(ws, {\n id,\n family,\n baseUrl: baseUrl as string | undefined,\n apiKey: apiKey as string | undefined,\n });\n return true;\n }\n\n case 'provider.remove': {\n const payload = asPayloadRecord(msg);\n const providerId = payload ? requiredString(payload, 'providerId') : null;\n if (!providerId) return invalidPayload(ws, msg.type);\n await routes.providerHandlers.handleProviderRemove(ws, providerId);\n return true;\n }\n\n case 'provider.clear_models': {\n const payload = asPayloadRecord(msg);\n const providerId = payload ? requiredString(payload, 'providerId') : null;\n if (!providerId) return invalidPayload(ws, msg.type);\n await routes.providerHandlers.handleProviderClearModels(ws, providerId);\n return true;\n }\n\n case 'provider.undo_clear': {\n const payload = asPayloadRecord(msg);\n const providerId = payload ? requiredString(payload, 'providerId') : null;\n const previousModels = payload ? optionalStringArray(payload, 'previousModels') : null;\n if (!providerId || !previousModels) return invalidPayload(ws, msg.type);\n await routes.providerHandlers.handleProviderUndoClear(ws, providerId, previousModels);\n return true;\n }\n\n case 'provider.update': {\n const payload = asPayloadRecord(msg);\n const id = payload ? requiredString(payload, 'id') : null;\n const envVars = payload ? optionalStringArray(payload, 'envVars') : null;\n const models = payload ? optionalStringArray(payload, 'models') : null;\n if (!payload || !id || envVars === null || models === null) return invalidPayload(ws, msg.type);\n for (const key of ['family', 'baseUrl'] as const) {\n if (payload[key] !== undefined && typeof payload[key] !== 'string') return invalidPayload(ws, msg.type);\n }\n await routes.providerHandlers.handleProviderUpdate(ws, {\n id,\n family: payload['family'] as string | undefined,\n baseUrl: payload['baseUrl'] as string | undefined,\n envVars,\n models,\n });\n return true;\n }\n\n case 'provider.probe': {\n const payload = asPayloadRecord(msg);\n const providerId = payload ? requiredString(payload, 'providerId') : null;\n const timeoutMs = payload ? optionalNumber(payload, 'timeoutMs') : null;\n if (!providerId || timeoutMs === null) return invalidPayload(ws, msg.type);\n await routes.providerHandlers.handleProviderProbe(ws, providerId, timeoutMs);\n return true;\n }\n\n default:\n return false;\n }\n}\n","import type { WebSocket } from 'ws';\nimport type { WSClientMessage } from './types.js';\n\nexport interface SessionRouteHandlers {\n newSession: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n clearContext: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n debugContext: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n compactContext: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n repairContext: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n listContextModes: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n switchContextMode: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n createContextMode: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n updateContextMode: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n deleteContextMode: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n listSessions: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n deleteSession: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n resumeSession: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n saveSession: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n listCheckpoints: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n rewindSession: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n}\n\nexport async function handleSessionRoute(\n ws: WebSocket,\n msg: WSClientMessage,\n handlers: SessionRouteHandlers,\n): Promise<boolean> {\n switch (msg.type) {\n case 'session.new':\n await handlers.newSession(ws, msg);\n return true;\n case 'context.clear':\n await handlers.clearContext(ws, msg);\n return true;\n case 'context.debug':\n await handlers.debugContext(ws, msg);\n return true;\n case 'context.compact':\n await handlers.compactContext(ws, msg);\n return true;\n case 'context.repair':\n await handlers.repairContext(ws, msg);\n return true;\n case 'context.modes.list':\n await handlers.listContextModes(ws, msg);\n return true;\n case 'context.mode.switch':\n await handlers.switchContextMode(ws, msg);\n return true;\n case 'context.mode.create':\n await handlers.createContextMode(ws, msg);\n return true;\n case 'context.mode.update':\n await handlers.updateContextMode(ws, msg);\n return true;\n case 'context.mode.delete':\n await handlers.deleteContextMode(ws, msg);\n return true;\n case 'sessions.list':\n await handlers.listSessions(ws, msg);\n return true;\n case 'session.delete':\n await handlers.deleteSession(ws, msg);\n return true;\n case 'session.resume':\n await handlers.resumeSession(ws, msg);\n return true;\n case 'session.save':\n await handlers.saveSession(ws, msg);\n return true;\n case 'session.checkpoints':\n await handlers.listCheckpoints(ws, msg);\n return true;\n case 'session.rewind':\n await handlers.rewindSession(ws, msg);\n return true;\n default:\n return false;\n }\n}\n","import type { WebSocket } from 'ws';\nimport type { WSClientMessage } from './types.js';\n\nexport interface ProjectRouteHandlers {\n listProjects: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n addProject: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n selectProject: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n setWorkingDir: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n}\n\nexport async function handleProjectRoute(\n ws: WebSocket,\n msg: WSClientMessage,\n handlers: ProjectRouteHandlers,\n): Promise<boolean> {\n switch (msg.type) {\n case 'projects.list':\n await handlers.listProjects(ws, msg);\n return true;\n case 'projects.add':\n await handlers.addProject(ws, msg);\n return true;\n case 'projects.select':\n await handlers.selectProject(ws, msg);\n return true;\n case 'working_dir.set':\n await handlers.setWorkingDir(ws, msg);\n return true;\n default:\n return false;\n }\n}\n","import type { WebSocket } from 'ws';\nimport type { WSClientMessage } from './types.js';\n\nexport interface ModeRouteHandlers {\n listModes: (ws: WebSocket) => Promise<void>;\n switchMode: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n}\n\nexport async function handleModeRoute(\n ws: WebSocket,\n msg: WSClientMessage,\n handlers: ModeRouteHandlers,\n): Promise<boolean> {\n switch (msg.type) {\n case 'modes.list':\n await handlers.listModes(ws);\n return true;\n case 'mode.switch':\n await handlers.switchMode(ws, msg);\n return true;\n default:\n return false;\n }\n}\n","// Prefs WS-message routing — extracted from packages/webui/src/server/index.ts\n// (issue #31, follow-on to PRs #94–#110). The standalone server owns a richer\n// pref surface than the CLI's embedded ws-handlers/prefs.ts (which only knows\n// about YOLO/autonomy), so this module is a thin dispatch layer — the actual\n// logic stays in the index.ts closures (getPrefs/updatePrefs) that close over\n// the live boot context (config, context.meta, permissionPolicy, pipelines,\n// autoCompactor, logger). Mirrors the shape of the 11 sibling route handlers\n// already wired through `handleMessage`.\n//\n// Why callback injection (not the CLI's context-object style): the standalone\n// server has ~10 closure-captured dependencies the prefs handler reads (config\n// for feature-flag mutation, pipelines for AutoCompaction add/remove, logger\n// for runtime level, etc.) — bundling them into a PrefsContext interface\n// would duplicate state already living on index.ts. Two callbacks (one per\n// message type) keeps the contract minimal and avoids drift if any new\n// closure dependency is added.\n\nimport type { WebSocket } from 'ws';\nimport type { WSClientMessage } from './types.js';\n\nexport interface PrefsRouteHandlers {\n /** Respond to the WS client with the current pref snapshot. */\n getPrefs: (ws: WebSocket) => Promise<void>;\n /**\n * Merge the supplied pref payload into context.meta, persist the durable\n * keys to config.json, apply any runtime effects (YOLO toggle, feature-flag\n * mutation, fallback chain update, AutoCompaction pipeline add/remove,\n * logger.level), then broadcast the full current snapshot to all clients.\n */\n updatePrefs: (ws: WebSocket, payload: Record<string, unknown>) => Promise<void>;\n}\n\n/**\n * Chain-of-responsibility dispatcher for the `prefs.*` WS message family.\n * Returns `true` if the message was handled by this layer (so the caller's\n * chain short-circuits), `false` if it should fall through to the next layer\n * or the residual switch.\n *\n * Owned prefixes:\n * - `prefs.get`\n * - `prefs.update`\n *\n * Regression-tested by packages/webui/tests/server/dispatcher-routing.test.ts.\n */\nexport async function handlePrefsRoute(\n ws: WebSocket,\n msg: WSClientMessage,\n handlers: PrefsRouteHandlers,\n): Promise<boolean> {\n switch (msg.type) {\n case 'prefs.get': {\n await handlers.getPrefs(ws);\n return true;\n }\n case 'prefs.update': {\n await handlers.updatePrefs(ws, (msg.payload ?? {}) as Record<string, unknown>);\n return true;\n }\n default:\n return false;\n }\n}\n","import type { WebSocket } from 'ws';\nimport type { WSClientMessage } from './types.js';\n\nexport interface ShellGitRouteHandlers {\n gitInfo: (ws: WebSocket) => Promise<void>;\n gitChanges: (ws: WebSocket) => Promise<void>;\n gitDiff: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n shellOpen: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n}\n\nexport async function handleShellGitRoute(\n ws: WebSocket,\n msg: WSClientMessage,\n handlers: ShellGitRouteHandlers,\n): Promise<boolean> {\n switch (msg.type) {\n case 'git.info':\n await handlers.gitInfo(ws);\n return true;\n case 'git.changes':\n await handlers.gitChanges(ws);\n return true;\n case 'git.diff':\n await handlers.gitDiff(ws, msg);\n return true;\n case 'shell.open':\n await handlers.shellOpen(ws, msg);\n return true;\n default:\n return false;\n }\n}\n","import type { WebSocket } from 'ws';\nimport type { WSClientMessage } from './types.js';\n\nexport interface MailboxRouteHandlers {\n messages: (ws: WebSocket, msg: WSClientMessage) => Promise<void> | void;\n agents: (ws: WebSocket, msg: WSClientMessage) => Promise<void> | void;\n clear: (ws: WebSocket, msg: WSClientMessage) => Promise<void> | void;\n purge: (ws: WebSocket, msg: WSClientMessage) => Promise<void> | void;\n}\n\nexport async function handleMailboxRoute(\n ws: WebSocket,\n msg: WSClientMessage,\n handlers: MailboxRouteHandlers,\n): Promise<boolean> {\n switch (msg.type) {\n case 'mailbox.messages':\n await handlers.messages(ws, msg);\n return true;\n case 'mailbox.agents':\n await handlers.agents(ws, msg);\n return true;\n case 'mailbox.clear':\n await handlers.clear(ws, msg);\n return true;\n case 'mailbox.purge':\n await handlers.purge(ws, msg);\n return true;\n default:\n return false;\n }\n}\n","// MCP WS-message routing — extracted from packages/webui/src/server/index.ts\n// (issue #31, follow-on to PRs #94–#110, #118, #119). The handler logic was\n// already in mcp-handlers.ts; this module is the chain-of-responsibility\n// dispatcher that mirrors the shape of the other 12 sibling route handlers\n// already wired through `handleMessage`.\n//\n// Why a thin dispatcher instead of importing handleMcpXxx directly into\n// index.ts: every other sibling uses the handleXxxRoute(ws, msg, handlers)\n// callback-injection pattern, which lets the test surface stub individual\n// callbacks (dispatcher-routing.test.ts covers 13 of these now). Bypassing\n// the pattern for MCP would mean the dispatcher-routing test for mcp.*\n// would have to spin up a real MCPRegistry — high cost for low value.\n//\n// Why 10 callbacks (one per case) instead of a McpContext interface: each\n// handleMcpXxx already takes the same (ws, msg, globalConfigPath,\n// mcpRegistry) signature. Bundling those 4 params into a single\n// McpContext object would be churn for no behavior change. The two-callback\n// (prefs) vs ten-callback (mcp) asymmetry is fine — the contract is\n// \"one callback per owned message type\", not \"smallest possible surface\".\n\nimport type { WebSocket } from 'ws';\nimport type { WSClientMessage } from './types.js';\n\nexport interface McpRouteHandlers {\n list: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n add: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n update: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n remove: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n enable: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n disable: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n sleep: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n wake: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n restart: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n discover: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n}\n\n/**\n * Chain-of-responsibility dispatcher for the `mcp.*` WS message family.\n * Returns `true` if the message was handled by this layer (so the caller's\n * chain short-circuits), `false` if it should fall through to the next layer\n * or the residual switch.\n *\n * Owned prefixes (10 message types — full coverage of the MCP management\n * surface; the WebUI MCP panel only ever talks to the server through these):\n * - mcp.list\n * - mcp.add\n * - mcp.update\n * - mcp.remove\n * - mcp.enable\n * - mcp.disable\n * - mcp.sleep\n * - mcp.wake\n * - mcp.restart\n * - mcp.discover\n *\n * Regression-tested by packages/webui/tests/server/dispatcher-routing.test.ts.\n */\nexport async function handleMcpRoute(\n ws: WebSocket,\n msg: WSClientMessage,\n handlers: McpRouteHandlers,\n): Promise<boolean> {\n switch (msg.type) {\n case 'mcp.list':\n await handlers.list(ws, msg);\n return true;\n case 'mcp.add':\n await handlers.add(ws, msg);\n return true;\n case 'mcp.update':\n await handlers.update(ws, msg);\n return true;\n case 'mcp.remove':\n await handlers.remove(ws, msg);\n return true;\n case 'mcp.enable':\n await handlers.enable(ws, msg);\n return true;\n case 'mcp.disable':\n await handlers.disable(ws, msg);\n return true;\n case 'mcp.sleep':\n await handlers.sleep(ws, msg);\n return true;\n case 'mcp.wake':\n await handlers.wake(ws, msg);\n return true;\n case 'mcp.restart':\n await handlers.restart(ws, msg);\n return true;\n case 'mcp.discover':\n await handlers.discover(ws, msg);\n return true;\n default:\n return false;\n }\n}\n","import type { WebSocket } from 'ws';\nimport type { WSClientMessage } from './types.js';\n\nexport interface BrainRouteHandlers {\n status: (ws: WebSocket, msg: WSClientMessage) => Promise<void> | void;\n risk: (ws: WebSocket, msg: WSClientMessage) => Promise<void> | void;\n ask: (ws: WebSocket, msg: WSClientMessage) => Promise<void> | void;\n}\n\nexport async function handleBrainRoute(\n ws: WebSocket,\n msg: WSClientMessage,\n handlers: BrainRouteHandlers,\n): Promise<boolean> {\n switch (msg.type) {\n case 'brain.status':\n await handlers.status(ws, msg);\n return true;\n case 'brain.risk':\n await handlers.risk(ws, msg);\n return true;\n case 'brain.ask':\n await handlers.ask(ws, msg);\n return true;\n default:\n return false;\n }\n}\n","import type { WebSocket } from 'ws';\nimport type { WSClientMessage } from './types.js';\n\nexport interface AutoPhaseRouteHandlers {\n handleMessage: (msg: { type: string; payload?: Record<string, unknown> }) => Promise<void>;\n}\n\nexport async function handleAutoPhaseRoute(\n _ws: WebSocket,\n msg: WSClientMessage,\n handlers: AutoPhaseRouteHandlers,\n): Promise<boolean> {\n if (!msg.type.startsWith('autophase.')) return false;\n await handlers.handleMessage(msg as { type: string; payload?: Record<string, unknown> });\n return true;\n}\n","import type { WebSocket } from 'ws';\nimport type { WSClientMessage } from './types.js';\n\nexport interface SpecsRouteHandlers {\n handleMessage: (msg: { type: string; payload?: Record<string, unknown> }) => Promise<void>;\n}\n\n/** Forward any `specs.*` message to the SpecsWebSocketHandler. */\nexport async function handleSpecsRoute(\n _ws: WebSocket,\n msg: WSClientMessage,\n handlers: SpecsRouteHandlers,\n): Promise<boolean> {\n if (!msg.type.startsWith('specs.')) return false;\n await handlers.handleMessage(msg as { type: string; payload?: Record<string, unknown> });\n return true;\n}\n","import type { WebSocket } from 'ws';\nimport type { WSClientMessage } from './types.js';\n\nexport interface SddBoardRouteHandlers {\n handleMessage: (msg: { type: string; payload?: Record<string, unknown> }) => Promise<void>;\n}\n\n/** Forward any `sdd.board.*` message to the SddBoardWebSocketHandler. */\nexport async function handleSddBoardRoute(\n _ws: WebSocket,\n msg: WSClientMessage,\n handlers: SddBoardRouteHandlers,\n): Promise<boolean> {\n if (!msg.type.startsWith('sdd.board.')) return false;\n await handlers.handleMessage(msg as { type: string; payload?: Record<string, unknown> });\n return true;\n}\n","import type { EventBus, Context, SessionEventBridge, WstackPaths } from '@wrongstack/core';\nimport type { WebSocket } from 'ws';\nimport type { ConnectedClient, WSServerMessage } from './types.js';\n\nimport * as fs from 'node:fs/promises';\nimport { watch as fsWatch } from 'node:fs';\nimport * as path from 'node:path';\n\n/** Metrics for the file watcher that watches status.json files. */\nexport interface FileWatcherMetrics {\n fileChangesDetected: number;\n filesProcessed: number;\n broadcastsSent: number;\n debounceResets: number;\n totalDebounceDelayMs: number;\n activeProjects: number;\n /** Average debounce delay in ms across all broadcasts. */\n averageDebounceDelayMs: number;\n /** Whether the file watcher is currently active. */\n watcherActive: boolean;\n}\n\nexport interface SetupEventsDeps {\n events: EventBus;\n broadcast: (clients: Map<WebSocket, ConnectedClient>, msg: WSServerMessage) => void;\n clients: Map<WebSocket, ConnectedClient>;\n config: { tools?: { maxIterations?: number | undefined } };\n context: Context;\n pendingConfirms: Map<string, (d: 'yes' | 'no' | 'always' | 'deny') => void>;\n /** Optional global config dir (~/.wrongstack) — enables SessionRegistry poll for fleet view. */\n globalConfigPath?: string | undefined;\n /**\n * Audit-level-aware session log bridge. When provided, tool/error/provider\n * events are persisted to the session JSONL (same contract as the CLI) —\n * without it, standalone-WebUI sessions carry no audit events and resume\n * with no tool history.\n */\n sessionBridge?: SessionEventBridge | undefined;\n /** Optional wpaths for writing status.json file. */\n wpaths?: WstackPaths | undefined;\n /**\n * Optional object to populate with file watcher metrics.\n * When provided, the setupEvents function will populate this object\n * with real-time metrics from the file watcher.\n */\n watcherMetrics?: FileWatcherMetrics | undefined;\n /**\n * Receives the internal `broadcastSessions` fn so the HTTP layer can trigger\n * an immediate fleet re-broadcast on `POST /api/fleet/ping` (push-on-write\n * from a TUI/REPL), instead of waiting on the registry file-watch/poll.\n */\n onFleetBroadcaster?: ((fn: () => Promise<void>) => void) | undefined;\n}\n\n/**\n * Wire kernel events to WS broadcasts and (when wpaths/globalConfigPath are\n * given) start the status-file watcher and session-poll interval.\n *\n * Returns a disposer that stops the watcher, clears the metrics/poll\n * intervals, and flushes pending debounce timers. Callers MUST invoke it on\n * shutdown — the watcher is `persistent: true` and the metrics interval is not\n * `unref`'d, so without disposal they keep the process alive and leak across\n * server restarts. (Previously this was hung off a non-existent\n * `process.on('cleanup')` event that never fired.)\n */\nexport function setupEvents(deps: SetupEventsDeps): () => void {\n const { events, broadcast, clients, config, context, pendingConfirms, globalConfigPath, sessionBridge, wpaths, watcherMetrics, onFleetBroadcaster } = deps;\n const disposers: Array<() => void> = [];\n\n events.on('iteration.started', (e) => {\n // Read maxIterations from context.meta so the UI reflects the\n // webui setting, falling back to the startup config default.\n const maxIt = typeof context.meta['maxIterations'] === 'number'\n ? context.meta['maxIterations']\n : config.tools?.maxIterations ?? 100;\n broadcast(clients, {\n type: 'iteration.started',\n payload: { index: e.index, maxIterations: maxIt },\n });\n });\n\n events.on('iteration.completed', (e) => {\n broadcast(clients, {\n type: 'iteration.completed',\n payload: { index: e.index, totalIterations: e.index + 1 },\n });\n });\n\n events.on('iteration.limit_reached', (e) => {\n broadcast(clients, {\n type: 'iteration.limit_reached',\n payload: {\n currentIterations: e.currentIterations,\n currentLimit: e.currentLimit,\n },\n });\n });\n\n events.on('provider.text_delta', (e) => {\n broadcast(clients, { type: 'provider.text_delta', payload: { text: e.text, messageId: 'current' } });\n });\n\n events.on('provider.thinking_delta', (e) => {\n broadcast(clients, { type: 'provider.thinking_delta', payload: { text: e.text } });\n });\n\n events.on('provider.stream_error', (e) => {\n broadcast(clients, {\n type: 'provider.stream_error',\n payload: { eventType: e.eventType, message: e.msg },\n });\n });\n\n events.on('tool.started', (e) => {\n broadcast(clients, {\n type: 'tool.started',\n payload: { id: e.id, name: e.name, input: e.input, messageId: `tool_${e.id}` },\n });\n // Persist for audit + resume tool history (respects auditLevel).\n sessionBridge\n ?.append({\n type: 'tool_call_start',\n ts: new Date().toISOString(),\n name: e.name,\n id: e.id,\n input: e.input,\n })\n .catch(() => { /* best-effort */ });\n });\n\n events.on('tool.progress', (e) => {\n broadcast(clients, {\n type: 'tool.progress',\n // Nested `event` shape — the client handler reads `payload.event?.text`\n // and early-returns on a falsy text, so a flat { eventType, text } payload\n // makes live tool progress (bash streaming, partial_output, warnings)\n // never render. Must match WSToolProgress and the CLI server.\n payload: { id: e.id, name: e.name, event: { type: e.event.type, text: e.event.text, data: e.event.data } },\n });\n sessionBridge\n ?.append({\n type: 'tool_progress',\n ts: new Date().toISOString(),\n name: e.name,\n id: e.id,\n event: { type: e.event.type, text: e.event.text, data: e.event.data },\n })\n .catch(() => { /* best-effort */ });\n });\n\n events.on('tool.executed', (e) => {\n broadcast(clients, {\n type: 'tool.executed',\n payload: { id: e.id, name: e.name, durationMs: e.durationMs, ok: e.ok, input: e.input, output: e.output },\n });\n sessionBridge\n ?.append({\n type: 'tool_call_end',\n ts: new Date().toISOString(),\n name: e.name,\n id: e.id ?? '',\n durationMs: e.durationMs,\n outputSize: e.outputBytes ?? 0,\n ok: e.ok,\n outputBytes: e.outputBytes,\n outputTokens: e.outputTokens,\n outputLines: e.outputLines,\n })\n .catch(() => { /* best-effort */ });\n broadcast(clients, { type: 'todos.updated', payload: { todos: [...context.todos] } });\n\n // Broadcast task/plan updates after task/plan/todo tool executions.\n if (e.name === 'task' || e.name === 'plan' || e.name === 'todo') {\n void (async () => {\n try {\n const taskPath = (context.meta as Record<string, unknown>)['task.path'];\n if (typeof taskPath === 'string' && taskPath) {\n const { loadTasks } = await import('@wrongstack/core');\n const file = await loadTasks(taskPath);\n broadcast(clients, { type: 'tasks.updated', payload: { tasks: file?.tasks ?? [] } });\n }\n } catch { /* best-effort */ }\n try {\n const planPath = (context.meta as Record<string, unknown>)['plan.path'];\n if (typeof planPath === 'string' && planPath) {\n const { loadPlan } = await import('@wrongstack/core');\n const plan = await loadPlan(planPath);\n broadcast(clients, { type: 'plan.updated', payload: { plan: plan ?? { version: 1, sessionId: context.session?.id ?? '', updatedAt: new Date().toISOString(), items: [] } } });\n }\n } catch { /* best-effort */ }\n })();\n }\n });\n\n events.on('tool.loop_detected', (e) => {\n broadcast(clients, {\n type: 'tool.loop_detected',\n payload: {\n tools: e.tools,\n repeatCount: e.repeatCount,\n iteration: e.iteration,\n kind: e.kind,\n },\n });\n });\n\n events.on('trust.persisted', (e) => {\n broadcast(clients, {\n type: 'trust.persisted',\n payload: { tool: e.tool, pattern: e.pattern, decision: e.decision },\n });\n });\n\n events.on('delegate.started', (e) => {\n broadcast(clients, {\n type: 'delegate.started',\n payload: { target: e.target, task: e.task },\n });\n });\n\n events.on('delegate.completed', (e) => {\n broadcast(clients, {\n type: 'delegate.completed',\n payload: {\n target: e.target,\n task: e.task,\n ok: e.ok,\n status: e.status,\n summary: e.summary,\n durationMs: e.durationMs,\n iterations: e.iterations,\n toolCalls: e.toolCalls,\n costUsd: e.costUsd,\n subagentId: e.subagentId,\n },\n });\n });\n\n events.on('provider.response', (e) => {\n broadcast(clients, { type: 'provider.response', payload: { usage: e.usage, stopReason: e.stopReason, messageId: 'current' } });\n });\n\n events.on('ctx.pct', (e) => {\n broadcast(clients, {\n type: 'ctx.pct',\n payload: { load: e.load, tokens: e.tokens, maxContext: e.maxContext },\n });\n broadcast(clients, {\n type: 'subagent.event',\n payload: {\n kind: 'ctx_pct',\n subagentId: 'leader',\n load: e.load,\n tokens: e.tokens,\n maxContext: e.maxContext,\n },\n });\n });\n\n events.on('ctx.max_context', (e) => {\n broadcast(clients, {\n type: 'ctx.max_context',\n payload: { providerId: e.providerId, modelId: e.modelId, maxContext: e.maxContext },\n });\n });\n\n events.on('token.threshold', (e) => {\n broadcast(clients, {\n type: 'token.threshold',\n payload: { used: e.used, limit: e.limit },\n });\n });\n\n events.on('token.cost_estimate_unavailable', (e) => {\n broadcast(clients, {\n type: 'token.cost_estimate_unavailable',\n payload: { model: e.model },\n });\n });\n\n events.on('context.repaired', (e) => {\n broadcast(clients, { type: 'context.repaired', payload: { removedToolUses: e.removedToolUses, removedToolResults: e.removedToolResults, removedMessages: e.removedMessages } });\n });\n\n events.on('tool.confirm_needed', (e) => {\n const id = e.toolUseId ?? `confirm_${Date.now()}`;\n pendingConfirms.set(id, e.resolve);\n broadcast(clients, { type: 'tool.confirm_needed', payload: { id, toolName: e.tool?.name ?? 'unknown', input: e.input, suggestedPattern: e.suggestedPattern } });\n });\n\n events.on('error', (e) => {\n broadcast(clients, { type: 'error', payload: { phase: e.phase, message: e.err instanceof Error ? e.err.message : String(e.err) } });\n sessionBridge\n ?.append({\n type: 'error',\n ts: new Date().toISOString(),\n message: e.err instanceof Error ? e.err.message : String(e.err),\n phase: e.phase,\n })\n .catch(() => { /* best-effort */ });\n });\n\n events.on('session.damaged', (e) => {\n broadcast(clients, {\n type: 'session.damaged',\n payload: { sessionId: e.sessionId, detail: e.detail },\n });\n });\n\n events.on('session.rewound', (e) => {\n broadcast(clients, {\n type: 'session.rewound',\n payload: {\n toPromptIndex: e.toPromptIndex,\n revertedFiles: e.revertedFiles,\n removedEvents: e.removedEvents,\n },\n });\n });\n\n events.on('checkpoint.written', (e) => {\n broadcast(clients, {\n type: 'checkpoint.written',\n payload: {\n promptIndex: e.promptIndex,\n promptPreview: e.promptPreview,\n ts: e.ts,\n fileCount: e.fileCount,\n },\n });\n });\n\n events.on('in_flight.started', (e) => {\n broadcast(clients, {\n type: 'in_flight.started',\n payload: { context: e.context, ts: e.ts },\n });\n });\n\n events.on('in_flight.ended', (e) => {\n broadcast(clients, {\n type: 'in_flight.ended',\n payload: { reason: e.reason, ts: e.ts },\n });\n });\n\n // Provider visibility — retry storms and provider failures in the JSONL\n // for forensics, mirroring the CLI's bridge wiring.\n events.on('provider.retry', (e) => {\n broadcast(clients, {\n type: 'provider.retry',\n payload: {\n providerId: e.providerId,\n attempt: e.attempt,\n delayMs: e.delayMs,\n status: e.status,\n description: e.description,\n },\n });\n sessionBridge\n ?.append({\n type: 'provider_retry',\n ts: new Date().toISOString(),\n providerId: e.providerId,\n attempt: e.attempt,\n delayMs: e.delayMs,\n status: e.status,\n description: e.description,\n })\n .catch(() => { /* best-effort */ });\n });\n\n events.on('provider.error', (e) => {\n broadcast(clients, {\n type: 'provider.error',\n payload: {\n providerId: e.providerId,\n status: e.status,\n description: e.description,\n retryable: e.retryable,\n },\n });\n sessionBridge\n ?.append({\n type: 'provider_error',\n ts: new Date().toISOString(),\n providerId: e.providerId,\n status: e.status,\n description: e.description,\n retryable: e.retryable,\n })\n .catch(() => { /* best-effort */ });\n });\n\n events.on('provider.fallback', (e) => {\n broadcast(clients, {\n type: 'provider.fallback',\n payload: {\n from: e.from,\n to: e.to,\n status: e.status,\n providerSwitched: e.providerSwitched,\n },\n });\n });\n\n events.on('compaction.fired', (e) => {\n broadcast(clients, {\n type: 'context.compacted',\n payload: {\n before: e.report.before,\n after: e.report.after,\n saved: Math.max(0, e.report.before - e.report.after),\n reductions: e.report.reductions,\n },\n });\n });\n\n events.on('compaction.failed', (e) => {\n broadcast(clients, {\n type: 'compaction.failed',\n payload: {\n message: e.err.message,\n aggressive: e.aggressive,\n level: e.level,\n tokens: e.tokens,\n maxContext: e.maxContext,\n load: e.load,\n fatal: e.fatal,\n },\n });\n });\n\n events.on('mcp.server.connected', (e) => {\n broadcast(clients, {\n type: 'mcp.server.connected',\n payload: { name: e.name, toolCount: e.toolCount },\n });\n });\n\n events.on('mcp.server.reconnected', (e) => {\n broadcast(clients, {\n type: 'mcp.server.reconnected',\n payload: { name: e.name, toolCount: e.toolCount },\n });\n });\n\n events.on('mcp.server.disconnected', (e) => {\n broadcast(clients, {\n type: 'mcp.server.disconnected',\n payload: { name: e.name, reason: e.reason },\n });\n });\n\n events.on('coordinator.stats', (e) => {\n broadcast(clients, {\n type: 'coordinator.stats',\n payload: {\n total: e.total,\n running: e.running,\n idle: e.idle,\n stopped: e.stopped,\n inFlight: e.inFlight,\n pending: e.pending,\n completed: e.completed,\n subagentStatuses: e.subagentStatuses.map((s) => ({\n id: s.subagentId,\n name: s.subagentId,\n status: s.status,\n currentTask: s.taskId,\n })),\n },\n });\n });\n\n // ── Inter-agent mailbox visibility ───────────────────────────────────\n // Forward cross-session mailbox activity (messages received by this\n // process's agents, new agent registrations on the project) to the\n // browser so the user sees multi-terminal/multi-surface chatter live.\n // These events are emitted via emit() with untyped names (GlobalMailbox\n // + mailbox-loop), so subscribe by pattern like the TUI does.\n events.onPattern('mailbox.received', (_e, payload) => {\n broadcast(clients, { type: 'mailbox.received', payload } as never as WSServerMessage);\n });\n events.onPattern('mailbox.agent_registered', (_e, payload) => {\n broadcast(clients, { type: 'mailbox.agent_registered', payload } as never as WSServerMessage);\n });\n\n // Subagent fleet lifecycle\n const forwardSubagent = (kind: string, payload: Record<string, unknown>) =>\n broadcast(clients, { type: 'subagent.event', payload: { kind, sessionId: context.session.id, ...payload } });\n\n events.on('subagent.spawned', (e) => forwardSubagent('spawned', { subagentId: e.subagentId, taskId: e.taskId, name: e.name, provider: e.provider, model: e.model, description: e.description }));\n events.on('subagent.task_started', (e) => forwardSubagent('task_started', { subagentId: e.subagentId, taskId: e.taskId, description: e.description }));\n events.on('subagent.tool_executed', (e) => forwardSubagent('tool_executed', { subagentId: e.subagentId, toolName: e.name, durationMs: e.durationMs, ok: e.ok }));\n events.on('subagent.iteration_summary', (e) => forwardSubagent('iteration_summary', { subagentId: e.subagentId, iteration: e.iteration, toolCalls: e.toolCalls, costUsd: e.costUsd, currentTool: e.currentTool, partialText: e.partialText }));\n events.on('subagent.budget_warning', (e) => forwardSubagent('budget_warning', { subagentId: e.subagentId, budgetKind: e.kind, used: e.used, limit: e.limit }));\n events.on('subagent.budget_extended', (e) => forwardSubagent('budget_extended', { subagentId: e.subagentId, budgetKind: e.kind, newLimit: e.newLimit, totalExtensions: e.totalExtensions }));\n events.on('subagent.ctx_pct', (e) => forwardSubagent('ctx_pct', { subagentId: e.subagentId, load: e.load, tokens: e.tokens, maxContext: e.maxContext }));\n events.on('subagent.task_completed', (e) => forwardSubagent('task_completed', { subagentId: e.subagentId, status: e.status, iterations: e.iterations, toolCalls: e.toolCalls, finalText: (e as Record<string, unknown>).finalText as string | undefined, failureReason: e.error?.kind, error: e.error ? { kind: e.error.kind, message: e.error.message } : undefined }));\n\n events.on('agent.timeline.message', (e) => {\n broadcast(clients, {\n type: 'agent.timeline.message',\n payload: {\n subagentId: e.subagentId,\n agentName: e.agentName,\n content: e.content,\n kind: e.kind,\n iteration: e.iteration,\n ts: e.ts,\n toolName: e.toolName,\n costUsd: e.costUsd,\n },\n });\n });\n events.on('agent.status_changed', (e) => {\n broadcast(clients, {\n type: 'agent.status_changed',\n payload: {\n subagentId: e.subagentId,\n agentName: e.agentName,\n status: e.status,\n ts: e.ts,\n summary: e.summary,\n task: e.task,\n },\n });\n });\n\n // ── Leader (main session) events — forwarded as subagent.event with subagentId 'leader' ──\n // These give the AgentsPage a live leader row with real-time tool tracking,\n // context pressure — matching the TUI's leader entry.\n // Iteration counts, cost, and overall status come from the sessionStore on the frontend.\n\n // Leader spawned: sent on first iteration so the frontend creates the leader row.\n let leaderSpawned = false;\n events.on('iteration.started', () => {\n if (!leaderSpawned) {\n leaderSpawned = true;\n const provider = (context.provider as { id?: string } | undefined)?.id ?? 'unknown';\n forwardSubagent('spawned', {\n subagentId: 'leader',\n name: 'LEADER',\n provider,\n model: context.model,\n description: `Main agent session (${context.session.id})`,\n });\n }\n });\n\n // Leader tool execution: emitted on every tool.executed in the main session.\n events.on('tool.executed', (e) => {\n forwardSubagent('tool_executed', {\n subagentId: 'leader',\n toolName: e.name,\n durationMs: e.durationMs,\n ok: e.ok,\n });\n });\n\n // Leader context pressure + cost: emitted on every provider response.\n events.on('provider.response', (e) => {\n if (e.usage?.input != null) {\n const maxCtx = context.provider.capabilities.maxContext;\n const rawLoad = maxCtx > 0 ? e.usage.input / maxCtx : 0;\n const load = Math.max(0, Math.min(1, rawLoad));\n const costUsd = context.tokenCounter.estimateCost().total;\n forwardSubagent('ctx_pct', {\n subagentId: 'leader',\n load,\n rawLoad,\n tokens: e.usage.input,\n maxContext: maxCtx,\n costUsd,\n });\n }\n });\n\n // Leader iteration updates: we already track iteration started above.\n // The frontend uses sessionStore for accurate cost/iteration counts.\n // When the run completes, the frontend's run.result handler resets isLoading,\n // making the leader go idle. We reset leader state on iteration.started.\n events.on('iteration.completed', () => {\n // Respawn leader if it was cleared (e.g., on session resume).\n if (!leaderSpawned) {\n leaderSpawned = true;\n const provider = (context.provider as { id?: string } | undefined)?.id ?? 'unknown';\n forwardSubagent('spawned', {\n subagentId: 'leader',\n name: 'LEADER',\n provider,\n model: context.model,\n description: `Main agent session (${context.session.id})`,\n });\n }\n });\n\n // ── Mailbox events — broadcast to WebUI for real-time per-project visibility ──\n events.onPattern('mailbox.*', (eventName, payload) => {\n broadcast(clients, { type: 'mailbox.event', payload: { event: eventName, ...payload as Record<string, unknown> } });\n });\n\n // ── Brain events — decisions + proactive interventions, live in the browser ──\n events.onPattern('brain.*', (eventName, payload) => {\n broadcast(clients, { type: 'brain.event', payload: { event: eventName, ...payload as Record<string, unknown> } } as never as WSServerMessage);\n });\n\n // ── Client status events — immediate broadcast to WebUI + write to status.json ──\n // Emitted by TUI/CLI/WebUI when significant status changes occur (tool calls, tokens, etc.)\n events.on('client.status', async (e) => {\n // Immediately broadcast to all connected WebUI clients\n broadcast(clients, { type: 'client.status_update', payload: e });\n\n // Write to status.json file for external watchers (e.g., other tools monitoring this project)\n if (wpaths?.projectStatus) {\n try {\n const statusFile = wpaths.projectStatus(e.projectHash);\n const dir = path.dirname(statusFile);\n await fs.mkdir(dir, { recursive: true });\n await fs.writeFile(statusFile, JSON.stringify(e, null, 2), 'utf-8');\n } catch (err) {\n console.error('[setup-events] Failed to write status.json:', err);\n }\n }\n });\n\n // ── File watcher for external status.json changes ──\n // Watches ~/.wrongstack/projects/<hash>/status.json files for external tool changes.\n // Uses project hash filtering and debouncing to handle rapid writes efficiently.\n if (wpaths?.projectStatus && wpaths.configDir) {\n // projectsDir = ~/.wrongstack/projects/\n const projectsDir = path.join(wpaths.configDir, 'projects');\n\n // Track known project hashes (populated from incoming client.status events)\n const knownProjectHashes = new Set<string>();\n\n // Debounce state: map of projectHash -> timer\n const debounceTimers = new Map<string, ReturnType<typeof setTimeout>>();\n const DEBOUNCE_MS = 150; // Wait 150ms after last write before broadcasting\n\n // Track pending status updates for debouncing (with write timestamps for delay calculation)\n const pendingStatuses = new Map<string, { data: unknown; firstWriteAt: number }>();\n\n // Initialize the external watcher metrics object if provided\n if (watcherMetrics) {\n watcherMetrics.fileChangesDetected = 0;\n watcherMetrics.filesProcessed = 0;\n watcherMetrics.broadcastsSent = 0;\n watcherMetrics.debounceResets = 0;\n watcherMetrics.totalDebounceDelayMs = 0;\n watcherMetrics.activeProjects = 0;\n watcherMetrics.averageDebounceDelayMs = 0;\n watcherMetrics.watcherActive = true;\n }\n\n const getAverageDebounceDelay = (): number => {\n if (!watcherMetrics || watcherMetrics.broadcastsSent === 0) return 0;\n return watcherMetrics.totalDebounceDelayMs / watcherMetrics.broadcastsSent;\n };\n\n const logWatcherMetrics = () => {\n if (!watcherMetrics) return;\n // Update computed field\n watcherMetrics.averageDebounceDelayMs = getAverageDebounceDelay();\n console.log(\n `[setup-events] File watcher stats: ` +\n `${watcherMetrics.broadcastsSent} broadcasts, ` +\n `${watcherMetrics.fileChangesDetected} file changes, ` +\n `${watcherMetrics.debounceResets} debounce resets, ` +\n `avg delay: ${watcherMetrics.averageDebounceDelayMs.toFixed(1)}ms, ` +\n `${watcherMetrics.activeProjects} active projects`\n );\n };\n\n // Log metrics every 60 seconds\n const metricsInterval = setInterval(logWatcherMetrics, 60_000);\n\n const broadcastStatus = (_projectHash: string, statusData: unknown, actualDelayMs: number) => {\n broadcast(clients, { type: 'client.status_update', payload: statusData });\n if (watcherMetrics) {\n watcherMetrics.broadcastsSent++;\n watcherMetrics.totalDebounceDelayMs += actualDelayMs;\n watcherMetrics.averageDebounceDelayMs = getAverageDebounceDelay();\n }\n };\n\n const scheduleBroadcast = (projectHash: string, statusData: unknown) => {\n const now = Date.now();\n const existing = pendingStatuses.get(projectHash);\n\n // Track if this is a debounce reset (rapid successive write)\n if (existing && watcherMetrics) {\n watcherMetrics.debounceResets++;\n }\n\n // Store latest status data with first write timestamp\n pendingStatuses.set(projectHash, {\n data: statusData,\n firstWriteAt: existing ? existing.firstWriteAt : now,\n });\n\n // Clear existing timer for this project\n const existingTimer = debounceTimers.get(projectHash);\n if (existingTimer) {\n clearTimeout(existingTimer);\n }\n\n // Set new debounce timer\n const timer = setTimeout(() => {\n debounceTimers.delete(projectHash);\n const pending = pendingStatuses.get(projectHash);\n if (pending) {\n const actualDelay = Date.now() - pending.firstWriteAt;\n broadcastStatus(projectHash, pending.data, actualDelay);\n pendingStatuses.delete(projectHash);\n }\n }, DEBOUNCE_MS);\n\n debounceTimers.set(projectHash, timer);\n };\n\n let watcher: import('fs').FSWatcher | undefined;\n\n const startWatcher = async () => {\n try {\n // Ensure directory exists before watching\n await fs.mkdir(projectsDir, { recursive: true });\n\n // Use fs.watch for efficient file change detection\n // Watch the projects directory for changes to status.json files\n // recursive:true so nested `<hash>/status.json` writes are delivered —\n // a non-recursive watch on the parent dir does not reliably fire for\n // changes inside subdirectories. filename can be null on some platforms.\n watcher = fsWatch(projectsDir, { persistent: true, recursive: true }, async (eventType, filename) => {\n if (eventType === 'change') {\n if (filename == null) return;\n if (watcherMetrics) watcherMetrics.fileChangesDetected++;\n\n // filename is the path relative to projectsDir, e.g. '<hash>/status.json'\n const targetFile = path.join(projectsDir, String(filename));\n if (targetFile.endsWith('status.json')) {\n // Extract project hash from path: .../projects/<hash>/status.json\n const projectHash = path.basename(path.dirname(targetFile));\n\n // Only process if this is a known project hash\n if (knownProjectHashes.size > 0 && !knownProjectHashes.has(projectHash)) {\n return; // Skip unknown project directories\n }\n\n if (watcherMetrics) watcherMetrics.filesProcessed++;\n\n try {\n const content = await fs.readFile(targetFile, 'utf-8');\n const statusData = JSON.parse(content);\n\n // Add to known hashes if not present\n if (statusData.projectHash) {\n const hash = String(statusData.projectHash);\n if (!knownProjectHashes.has(hash)) {\n knownProjectHashes.add(hash);\n if (watcherMetrics) watcherMetrics.activeProjects = knownProjectHashes.size;\n }\n }\n\n // Debounce the broadcast\n scheduleBroadcast(projectHash, statusData);\n } catch {\n // File may not exist, be readable yet, or invalid JSON\n }\n }\n }\n });\n\n console.log(`[setup-events] Watching ${projectsDir} for status.json changes (hash-filtered, debounced)`);\n } catch (err) {\n console.error('[setup-events] Failed to start status file watcher:', err);\n }\n };\n\n // Register incoming client.status events to build known project hashes\n // This ensures we only watch directories that have emitted status before\n events.on('client.status', (e) => {\n if (e.projectHash) {\n const hash = String(e.projectHash);\n if (!knownProjectHashes.has(hash)) {\n knownProjectHashes.add(hash);\n if (watcherMetrics) watcherMetrics.activeProjects = knownProjectHashes.size;\n }\n }\n });\n\n // Start watcher asynchronously without blocking setup\n startWatcher();\n\n // Clean up watcher and timers on shutdown. Registered as a disposer so it\n // actually runs (the previous `process.on('cleanup')` event never fires).\n disposers.push(() => {\n clearInterval(metricsInterval);\n logWatcherMetrics(); // Final metrics log on shutdown\n\n // Mark watcher as inactive\n if (watcherMetrics) watcherMetrics.watcherActive = false;\n\n // Flush any pending broadcasts before cleanup\n for (const [projectHash, pending] of pendingStatuses) {\n const timer = debounceTimers.get(projectHash);\n if (timer) {\n clearTimeout(timer);\n // Broadcast pending status immediately on shutdown\n broadcastStatus(projectHash, pending.data, 0);\n }\n }\n\n // Clear all debounce timers\n for (const timer of debounceTimers.values()) {\n clearTimeout(timer);\n }\n debounceTimers.clear();\n pendingStatuses.clear();\n\n if (watcher) {\n watcher.close();\n console.log('[setup-events] Closed status file watcher');\n }\n });\n }\n\n // ── Cross-process session / fleet status ──\n // Read the SessionRegistry and broadcast live session+agent status to all\n // connected clients. Three triggers, from fastest to slowest: a push-on-write\n // `POST /api/fleet/ping` (via onFleetBroadcaster, ~ms), an `fs.watch` on the\n // registry file (~150ms), and a 5s fallback poll that also prunes stale\n // entries via `list()`.\n const globalRoot = globalConfigPath ? path.dirname(globalConfigPath) : undefined;\n if (globalRoot) {\n const broadcastSessions = async () => {\n try {\n const { SessionRegistry } = await import('@wrongstack/core');\n const registry = new SessionRegistry(globalRoot);\n const sessions = await registry.list();\n // Scope Fleet HQ to the *same project* as this server. The registry lists\n // every project's sessions, so derive our current project from our own\n // entry (matched by pid — survives in-place project switches, unlike the\n // launch-time `wpaths.projectSlug`). Fall back to all sessions if our\n // entry isn't found yet (first tick before registration settles).\n const mySlug = sessions.find((s) => s.pid === process.pid)?.projectSlug;\n const live = sessions\n .filter((s) => s.status !== 'stale')\n .filter((s) => (mySlug ? s.projectSlug === mySlug : true))\n .map((s) => ({\n sessionId: s.sessionId,\n projectName: s.projectName,\n projectSlug: s.projectSlug,\n projectRoot: s.projectRoot,\n workingDir: s.workingDir,\n gitBranch: s.gitBranch,\n // Surface (tui/webui/cli) so Fleet HQ can label each live client node.\n clientType: s.clientType,\n status: s.status,\n pid: s.pid,\n startedAt: s.startedAt,\n agentCount: s.agentCount,\n agents: (s.agents ?? []).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 costUsd: a.costUsd,\n tokensIn: a.tokensIn,\n tokensOut: a.tokensOut,\n ctxPct: a.ctxPct,\n model: a.model,\n partialText: a.partialText,\n lastActivityAt: a.lastActivityAt,\n })),\n }));\n broadcast(clients, { type: 'sessions.status_update', payload: { sessions: live } });\n } catch {\n // Best-effort — never crash for status broadcasting errors\n }\n };\n\n // Hand the broadcaster to the HTTP layer for push-on-write (/api/fleet/ping).\n onFleetBroadcaster?.(broadcastSessions);\n\n // Fallback poll (also prunes stale entries on read).\n const statusInterval = setInterval(() => void broadcastSessions(), 5_000);\n if (statusInterval.unref) statusInterval.unref();\n disposers.push(() => clearInterval(statusInterval));\n\n // Event-driven: watch the registry file so a TUI/REPL agent's write reaches\n // the map in ~150ms. Atomic writes go via `<file>.<uuid>.tmp` → rename, so\n // watch the dir and match any `session-registry.json*` change (ignore .lock).\n let regDebounce: ReturnType<typeof setTimeout> | undefined;\n try {\n const regWatcher = fsWatch(globalRoot, { persistent: false }, (_event, filename) => {\n const name = filename ? String(filename) : '';\n if (!name.startsWith('session-registry.json') || name.endsWith('.lock')) return;\n if (regDebounce) clearTimeout(regDebounce);\n regDebounce = setTimeout(() => void broadcastSessions(), 150);\n });\n disposers.push(() => {\n if (regDebounce) clearTimeout(regDebounce);\n regWatcher.close();\n });\n } catch {\n // Watch unsupported on this platform — the 5s poll still covers it.\n }\n\n // Push an immediate snapshot so a freshly-connected client doesn't wait.\n void broadcastSessions();\n }\n\n return () => {\n for (const dispose of disposers) {\n try {\n dispose();\n } catch {\n /* best-effort teardown */\n }\n }\n };\n}\n","import { listContextWindowModes, atomicWrite } from '@wrongstack/core';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\n\n/**\n * Custom context modes — user-defined presets that are loaded from disk,\n * merged with the built-in modes, and managed via WebSocket CRUD handlers.\n *\n * Stored in: ~/.wrongstack/custom-context-modes.json\n * Format: { \"modes\": ContextWindowMode[] }\n */\n\nexport interface CustomContextMode {\n id: string;\n name: string;\n description: string;\n thresholds: { warn: number; soft: number; hard: number };\n aggressiveOn: string;\n preserveK: number;\n eliseThreshold: number;\n targetLoad: number;\n /** Whether this is a user-defined (custom) or built-in mode. */\n custom: boolean;\n}\n\nexport interface CustomModeStore {\n modes: Map<string, CustomContextMode>;\n load: () => Promise<void>;\n save: () => Promise<void>;\n create: (mode: CustomContextMode) => { ok: boolean; error?: string | undefined };\n update: (id: string, patch: Partial<CustomContextMode>) => { ok: boolean; error?: string | undefined };\n remove: (id: string) => { ok: boolean; error?: string | undefined };\n list: () => CustomContextMode[];\n}\n\nconst STORE_FILENAME = 'custom-context-modes.json';\n\nfunction storePath(wrongstackDir: string): string {\n return path.join(wrongstackDir, STORE_FILENAME);\n}\n\nconst BUILTIN_IDS = new Set(['balanced', 'frugal', 'deep', 'archival']);\n\nexport function createCustomModeStore(wrongstackDir: string): CustomModeStore {\n const modes = new Map<string, CustomContextMode>();\n\n const load = async (): Promise<void> => {\n modes.clear();\n try {\n const raw = await fs.readFile(storePath(wrongstackDir), 'utf8');\n const parsed = JSON.parse(raw) as { modes?: CustomContextMode[] };\n if (Array.isArray(parsed.modes)) {\n for (const m of parsed.modes) {\n if (m.id && !BUILTIN_IDS.has(m.id)) {\n modes.set(m.id, { ...m, custom: true });\n }\n }\n }\n } catch {\n // File missing or corrupt — start with empty custom modes.\n }\n };\n\n const save = async (): Promise<void> => {\n const arr = [...modes.values()];\n const json = JSON.stringify({ modes: arr }, null, 2);\n await atomicWrite(storePath(wrongstackDir), json);\n };\n\n const create = (\n mode: CustomContextMode,\n ): { ok: boolean; error?: string | undefined } => {\n if (!mode.id || typeof mode.id !== 'string') {\n return { ok: false, error: 'id is required' };\n }\n if (BUILTIN_IDS.has(mode.id)) {\n return { ok: false, error: `Cannot override built-in mode \"${mode.id}\"` };\n }\n if (modes.has(mode.id)) {\n return { ok: false, error: `Mode \"${mode.id}\" already exists` };\n }\n if (!mode.name) {\n return { ok: false, error: 'name is required' };\n }\n const entry: CustomContextMode = {\n id: mode.id,\n name: mode.name,\n description: mode.description || '',\n thresholds: {\n warn: mode.thresholds?.warn ?? 0.6,\n soft: mode.thresholds?.soft ?? 0.75,\n hard: mode.thresholds?.hard ?? 0.9,\n },\n aggressiveOn: mode.aggressiveOn || 'soft',\n preserveK: mode.preserveK ?? 10,\n eliseThreshold: mode.eliseThreshold ?? 2000,\n targetLoad: mode.targetLoad ?? 0.65,\n custom: true,\n };\n modes.set(mode.id, entry);\n void save();\n return { ok: true };\n };\n\n const update = (\n id: string,\n patch: Partial<CustomContextMode>,\n ): { ok: boolean; error?: string | undefined } => {\n if (BUILTIN_IDS.has(id)) {\n return { ok: false, error: `Cannot modify built-in mode \"${id}\"` };\n }\n const existing = modes.get(id);\n if (!existing) {\n return { ok: false, error: `Mode \"${id}\" not found` };\n }\n const next: CustomContextMode = { ...existing };\n if (patch.name !== undefined) next.name = patch.name;\n if (patch.description !== undefined) next.description = patch.description;\n if (patch.thresholds) {\n next.thresholds = {\n warn: patch.thresholds.warn ?? existing.thresholds.warn,\n soft: patch.thresholds.soft ?? existing.thresholds.soft,\n hard: patch.thresholds.hard ?? existing.thresholds.hard,\n };\n }\n if (patch.preserveK !== undefined) next.preserveK = patch.preserveK;\n if (patch.eliseThreshold !== undefined) next.eliseThreshold = patch.eliseThreshold;\n if (patch.targetLoad !== undefined) next.targetLoad = patch.targetLoad;\n if (patch.aggressiveOn !== undefined) next.aggressiveOn = patch.aggressiveOn;\n modes.set(id, next);\n void save();\n return { ok: true };\n };\n\n const remove = (\n id: string,\n ): { ok: boolean; error?: string | undefined } => {\n if (BUILTIN_IDS.has(id)) {\n return { ok: false, error: `Cannot delete built-in mode \"${id}\"` };\n }\n if (!modes.delete(id)) {\n return { ok: false, error: `Mode \"${id}\" not found` };\n }\n void save();\n return { ok: true };\n };\n\n const list = (): CustomContextMode[] => {\n const builtins = listContextWindowModes().map((m) => ({\n id: m.id as string,\n name: m.name,\n description: m.description,\n thresholds: { ...m.thresholds },\n aggressiveOn: m.aggressiveOn as string,\n preserveK: m.preserveK,\n eliseThreshold: m.eliseThreshold,\n targetLoad: m.targetLoad,\n custom: false as const,\n }));\n const custom = [...modes.values()];\n return [...builtins, ...custom];\n };\n\n return { modes, load, save, create, update, remove, list };\n}\n","// Eternal-autonomy iteration broadcast wiring.\n//\n// The CLI's `runWebUI` owns the eternal-autonomy engine and exposes a\n// `subscribeEternalIteration` callback that lets the webui hook into\n// the journal-entry stream. This module extracts the wiring in\n// isolation so it can be unit-tested without spinning up the full\n// server (clients, WS, HTTP bring-up).\n//\n// `createEternalSubscription` is the helper that:\n// 1. Calls the caller-supplied `subscribe` function with a broadcast\n// closure bound to the current `clients` Map.\n// 2. Captures the returned disposer so `tearDown` can invoke it on\n// server shutdown.\n//\n// Both the disposer and the `JournalEntry` are projected by the caller\n// — this module intentionally knows nothing about the engine itself.\n\nimport type { WebSocket } from 'ws';\nimport type { WSServerMessage } from './types.js';\nimport type { JournalEntry } from '@wrongstack/core';\n\nexport type EternalSubscribe = (\n fn: (entry: JournalEntry) => void,\n) => () => void;\n\n// `clients` is generic so callers that use a structurally-similar\n// `ConnectedClient` (the CLI's own Map<WebSocket, { ws; sessionId }>,\n// for example) don't have to alias their type to webui's\n// `ConnectedClient`. The helper doesn't read the value at all —\n// `broadcast` gets to decide whether to use the map or not — so we\n// only need the key type (WebSocket) to be present, which is\n// enforced by the constraint.\nexport type EternalBroadcast<C> = (clients: Map<WebSocket, C>, msg: WSServerMessage) => void;\n\nexport interface EternalSubscription {\n /** Tear down the underlying engine subscription. Idempotent. */\n dispose: () => void;\n}\n\nexport function createEternalSubscription<C>(\n subscribe: EternalSubscribe,\n broadcast: EternalBroadcast<C>,\n clientsRef: () => Map<WebSocket, C>,\n): EternalSubscription {\n let disposed = false;\n const dispose = subscribe((entry) => {\n if (disposed) return;\n broadcast(clientsRef(), {\n type: 'eternal.iteration',\n payload: { entry },\n });\n });\n return {\n dispose() {\n if (disposed) return;\n disposed = true;\n dispose();\n },\n };\n}\n","// Open the OS file manager or a terminal at a given path (the\n// `shell.open` WS message handler).\n//\n// Both the standalone `startWebUI` and the CLI's `runWebUI` needed\n// the same logic \\u2014 metacharacter guard, `path.resolve` to fold\n// any `..` traversal, and a cross-platform `spawn()` for the\n// platform's file manager (`explorer`/`open`/`xdg-open`) or\n// terminal (`cmd /c start cmd /k` / `open -a Terminal` /\n// `x-terminal-emulator` \\u2192 `gnome-terminal` \\u2192 `xterm` fallback chain).\n// Phase 1.2 added the `spawn`-based version on the CLI side; the\n// standalone got it shortly after. The two implementations have\n// drifted slightly (CLI lacks the `logger.warn` on spawn failure),\n// which is exactly the class of bug extraction prevents.\n//\n// This module returns a `ShellOpenResult` so the caller (the WS\n// router in either entry point) can pipe it through `sendResult`\n// with the same `success`/`message` shape both sides already use.\n// Spawn is async + detached + unref'd so a missing terminal\n// emulator (which fires `error` async) never crashes the server\n// \\u2014 the fallback chain tries the next one, the file-manager\n// branch just logs.\n//\n// SECURITY: the path arrives over the WebSocket. The\n// metacharacter guard (`/[&|<>^\\\"'`\\n\\r]/`) closes the cmd.exe\n// re-parsing injection class (`\"foo\" && calc.exe`,\n// `'$(...)'`, backticks, redirections) before anything reaches\n// the argv array. The `path.resolve` then folds any\n// `..` traversal, and `fs.access(resolved)` enforces that the\n// target exists \\u2014 callers can't ask us to open a non-existent\n// path. Defense in depth: the spawn below uses an argv array\n// (no string concatenation), and `windowsHide` keeps the\n// launcher console out of the way.\n\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { spawn } from 'node:child_process';\nimport type { Logger } from '@wrongstack/core';\n\nexport type ShellOpenTarget = 'terminal' | 'file-manager';\n\nexport interface ShellOpenRequest {\n path: string;\n target: ShellOpenTarget;\n}\n\nexport interface ShellOpenResult {\n success: boolean;\n message: string;\n}\n\n/** Metacharacters that would let a path slip past an argv-array\n * spawn and into a shell re-parse on Windows. Real directory\n * paths virtually never contain these. */\nconst METACHAR_REGEX = /[&|<>^\"'`\\n\\r]/;\n\nexport async function handleShellOpen(\n req: ShellOpenRequest,\n logger: Logger,\n): Promise<ShellOpenResult> {\n try {\n const resolved = path.resolve(req.path);\n await fs.access(resolved);\n if (METACHAR_REGEX.test(resolved)) {\n return { success: false, message: 'Path contains unsupported characters.' };\n }\n\n const platform = process.platform;\n const launch = (cmd: string, args: string[], onError?: () => void) => {\n const child = spawn(cmd, args, {\n detached: true,\n stdio: 'ignore',\n windowsHide: true,\n });\n // `error` fires when the binary is missing (e.g. xterm not\n // installed) \\u2014 log it, but never block the WS caller. The\n // fallback chain in the terminal branch uses onError to try\n // the next emulator.\n child.on('error', (err) => {\n logger.warn(`shell.open spawn failed: ${err.message}`);\n onError?.();\n });\n child.unref();\n };\n\n if (req.target === 'file-manager') {\n if (platform === 'win32') launch('explorer', [resolved]);\n else if (platform === 'darwin') launch('open', [resolved]);\n else launch('xdg-open', [resolved]);\n } else if (req.target === 'terminal') {\n if (platform === 'win32') {\n // `start` is a cmd builtin; each token is a separate argv\n // entry (Node quotes them individually \\u2014 no string\n // concatenation). This replaces the previous\n // `start cmd /k cd /d \"...\"` exec() call that was\n // shell-injectable.\n launch('cmd', ['/c', 'start', 'cmd', '/k', 'cd', '/d', resolved]);\n } else if (platform === 'darwin') {\n launch('open', ['-a', 'Terminal', resolved]);\n } else {\n // Try several terminal emulators\n launch('x-terminal-emulator', [`--working-directory=${resolved}`], () =>\n launch('gnome-terminal', [`--working-directory=${resolved}`], () =>\n launch('xterm', ['-e', `cd '${resolved}' && ${process.env['SHELL'] ?? 'sh'}`]),\n ),\n );\n }\n } else {\n return { success: false, message: `Unknown shell.open target: ${String(req.target)}` };\n }\n return { success: true, message: `Opened ${req.target} at ${resolved}` };\n } catch (err) {\n return { success: false, message: err instanceof Error ? err.message : String(err) };\n }\n}\n","/**\n * Shared `git.info` WebSocket handler for both the standalone WebUI server and\n * the CLI's `--webui` embedded server. Extracted from the duplicated switch\n * cases in `index.ts` and `cli/src/webui-server.ts`, which had drifted (the\n * standalone copy transposed ahead/behind and never matched deletions). One\n * implementation here keeps both surfaces in lockstep.\n *\n * case 'git.info': return handleGitInfo(ws, projectRoot);\n */\n\nimport type { WebSocket } from 'ws';\nimport nodePath from 'node:path';\nimport { send } from './ws-utils.js';\n\n/**\n * Read git branch, change stats, and upstream sync status from `projectRoot`\n * and broadcast a `git.info` message. Never throws — a non-repo / missing-git\n * directory yields an empty-but-valid payload.\n */\nexport async function handleGitInfo(ws: WebSocket, projectRoot: string): Promise<void> {\n const cwd = projectRoot || undefined;\n try {\n const { execFile: ef } = await import('node:child_process');\n const git = (args: string[]): Promise<string> =>\n new Promise((resolve) => {\n ef('git', args, { cwd, timeout: 3000 }, (err: Error | null, stdout: string) => {\n resolve(err ? '' : stdout.trim());\n });\n });\n\n const [branchRaw, diffRaw, statusRaw, upstreamRaw] = await Promise.all([\n git(['branch', '--show-current']),\n git(['diff', '--stat']),\n git(['status', '--porcelain']),\n git(['rev-list', '--left-right', '--count', '@{upstream}...HEAD']),\n ]);\n\n const branch = branchRaw || '(detached)';\n\n // `git diff --stat` summary line: \"N files changed, X insertions(+), Y deletions(-)\".\n // Deletions are formatted \"Y deletions(-)\" — the `+` only ever precedes\n // INSERTIONS, so a `\\+`-anchored deletion regex never matches.\n const addMatch = /(\\d+)\\s+insertion/i.exec(diffRaw);\n const delMatch = /(\\d+)\\s+deletion/i.exec(diffRaw);\n const added = addMatch ? Number(addMatch[1]) : 0;\n const deleted = delMatch ? Number(delMatch[1]) : 0;\n\n // Untracked files from `git status --porcelain` (lines starting with \"??\").\n const untracked = statusRaw.split('\\n').filter((l) => l.startsWith('??')).length;\n\n // `git rev-list --left-right --count @{upstream}...HEAD` prints \"<behind>\\t<ahead>\":\n // left = commits in upstream not in HEAD (BEHIND), right = HEAD-only (AHEAD).\n const [behindRaw, aheadRaw] = (upstreamRaw || '0\\t0').split('\\t');\n const behind = Number(behindRaw) || 0;\n const ahead = Number(aheadRaw) || 0;\n\n send(ws, { type: 'git.info', payload: { branch, added, deleted, untracked, ahead, behind } });\n } catch {\n // Git not available or not a repo — send empty info silently.\n send(ws, { type: 'git.info', payload: { branch: '', added: 0, deleted: 0, untracked: 0, ahead: 0, behind: 0 } });\n }\n}\n\n/** One changed file in the working tree (vs HEAD). */\nexport interface GitChangedFile {\n /** Repo-relative path (POSIX separators, as git reports). */\n path: string;\n /**\n * Single-letter change kind for the badge:\n * `M` modified, `A` added/staged-new, `D` deleted, `R` renamed,\n * `?` untracked, `C` copied, `U` unmerged/conflict.\n */\n status: string;\n /** Lines added (best-effort; 0 for untracked-binary / unknown). */\n added: number;\n /** Lines removed (best-effort). */\n deleted: number;\n /** True when the change is at least partly staged. */\n staged: boolean;\n}\n\n/** Spawn `git` in `cwd` and resolve its trimmed stdout ('' on any error). */\nfunction makeGit(cwd: string | undefined) {\n return async (args: string[]): Promise<string> => {\n const { execFile: ef } = await import('node:child_process');\n return new Promise((resolve) => {\n ef(\n 'git',\n args,\n { cwd, timeout: 5000, maxBuffer: 1024 * 1024 * 16 },\n (err: Error | null, stdout: string) => resolve(err ? '' : stdout),\n );\n });\n };\n}\n\n/**\n * Read the working-tree change set (everything that differs from HEAD:\n * staged, unstaged, and untracked) and broadcast a `git.changes` message.\n *\n * The file list comes from `git status --porcelain -z` (NUL-delimited so\n * paths with spaces/unicode survive intact, and renames are unambiguous).\n * Per-file line counts come from `--numstat` of both the unstaged and the\n * staged diff, summed. Untracked files intentionally report 0/0 here so the\n * list view does not read every untracked file; `git.diff` loads a selected\n * file lazily on demand.\n * Never throws — a non-repo yields an empty list.\n */\nexport async function handleGitChanges(ws: WebSocket, projectRoot: string): Promise<void> {\n const cwd = projectRoot || undefined;\n try {\n const git = makeGit(cwd);\n const [statusRaw, unstagedNumstat, stagedNumstat] = await Promise.all([\n git(['status', '--porcelain', '-z']),\n git(['diff', '--numstat', '-z']),\n git(['diff', '--cached', '--numstat', '-z']),\n ]);\n\n // numstat -z format: \"<added>\\t<deleted>\\t<path>\\0\" per entry. For a rename\n // git emits \"<added>\\t<deleted>\\0<oldpath>\\0<newpath>\\0\" (path field empty,\n // two extra NUL records). Parse defensively, keying counts by final path.\n const counts = new Map<string, { added: number; deleted: number }>();\n const parseNumstat = (raw: string): void => {\n const parts = raw.split('\\0');\n for (let i = 0; i < parts.length; i++) {\n const entry = parts[i];\n if (!entry) continue;\n const m = /^(\\d+|-)\\t(\\d+|-)\\t(.*)$/.exec(entry);\n if (!m) continue;\n const added = m[1] === '-' ? 0 : Number(m[1]);\n const deleted = m[2] === '-' ? 0 : Number(m[2]);\n let path = m[3] ?? '';\n if (path === '') {\n // Rename: next two records are old, then new path.\n i += 1;\n path = parts[i + 1] ?? parts[i] ?? '';\n i += 1;\n }\n if (!path) continue;\n const prev = counts.get(path) ?? { added: 0, deleted: 0 };\n counts.set(path, { added: prev.added + added, deleted: prev.deleted + deleted });\n }\n };\n parseNumstat(unstagedNumstat);\n parseNumstat(stagedNumstat);\n\n // `git status --porcelain -z`: each record is \"XY <path>\" (no separator\n // after the 2-char code beyond the single space). Rename/copy records are\n // followed by a separate NUL record carrying the original path.\n const records = statusRaw.split('\\0').filter((r) => r.length > 0);\n const files: GitChangedFile[] = [];\n for (let i = 0; i < records.length; i++) {\n const rec = records[i];\n if (!rec || rec.length < 3) continue;\n const x = rec[0] ?? ' ';\n const y = rec[1] ?? ' ';\n const path = rec.slice(3);\n const isRename = x === 'R' || x === 'C' || y === 'R' || y === 'C';\n if (isRename) i += 1; // consume the original-path record that follows\n\n let status: string;\n if (x === '?' && y === '?') status = '?';\n else if (x === 'U' || y === 'U' || (x === 'A' && y === 'A') || (x === 'D' && y === 'D')) status = 'U';\n else if (x === 'R' || y === 'R') status = 'R';\n else if (x === 'C' || y === 'C') status = 'C';\n else if (x === 'A' || y === 'A') status = 'A';\n else if (x === 'D' || y === 'D') status = 'D';\n else status = 'M';\n\n const staged = x !== ' ' && x !== '?';\n\n let added = counts.get(path)?.added ?? 0;\n let deleted = counts.get(path)?.deleted ?? 0;\n if (status === '?') {\n // Untracked files are not present in numstat. Do not read every file\n // here: large generated/untracked trees made git.changes an N+1 file\n // scan. The diff endpoint loads a selected file on demand.\n added = 0;\n deleted = 0;\n }\n files.push({ path, status, added, deleted, staged });\n }\n\n send(ws, { type: 'git.changes', payload: { files } });\n } catch (err) {\n send(ws, {\n type: 'git.changes',\n payload: { files: [], error: err instanceof Error ? err.message : String(err) },\n });\n }\n}\n\nconst MAX_DIFF_BYTES = 2 * 1024 * 1024; // 2 MB per side — guard the renderer\n\n/**\n * Resolve the before/after text for a single file and broadcast a `git.diff`\n * message. `oldText` is the file at HEAD (`git show HEAD:<path>`), `newText`\n * is the current working-tree content. New/untracked files have empty\n * `oldText`; deleted files have empty `newText`. Binary or oversized files\n * are reported with a flag instead of content so the client can show a notice.\n */\nexport async function handleGitDiff(\n ws: WebSocket,\n projectRoot: string,\n path: string,\n): Promise<void> {\n const cwd = projectRoot || undefined;\n const reply = (extra: Record<string, unknown>): void =>\n send(ws, { type: 'git.diff', payload: { path, ...extra } });\n\n if (!path || path.includes('\\0') || path.includes('..') || nodePath.isAbsolute(path)) {\n reply({ oldText: '', newText: '', error: 'invalid path' });\n return;\n }\n\n try {\n const git = makeGit(cwd);\n const { readFile } = await import('node:fs/promises');\n const { join } = await import('node:path');\n\n // HEAD version. `git show` writes nothing for a path absent at HEAD.\n const oldText = await git(['show', `HEAD:${path}`]);\n\n // Working-tree version (absent → deleted file → empty).\n let newText = '';\n try {\n const abs = cwd ? join(cwd, path) : path;\n const buf = await readFile(abs);\n if (buf.includes(0)) {\n reply({ oldText: '', newText: '', binary: true });\n return;\n }\n if (buf.length > MAX_DIFF_BYTES) {\n reply({ oldText: '', newText: '', tooLarge: true });\n return;\n }\n newText = buf.toString('utf8');\n } catch {\n newText = '';\n }\n\n if ((oldText.length || 0) > MAX_DIFF_BYTES) {\n reply({ oldText: '', newText: '', tooLarge: true });\n return;\n }\n if (oldText.includes('\\0')) {\n reply({ oldText: '', newText: '', binary: true });\n return;\n }\n\n reply({ oldText, newText });\n } catch (err) {\n reply({ oldText: '', newText: '', error: err instanceof Error ? err.message : String(err) });\n }\n}\n","/**\n * Process-registry WebSocket handlers for the WebUI server, extracted from the\n * `handleMessage` switch in `index.ts` as part of splitting that file (#31).\n *\n * case 'process.list': return handleProcessList(ws);\n * case 'process.kill': return handleProcessKill(ws, msg.payload);\n * case 'process.killAll': return handleProcessKillAll(ws);\n *\n * All three reach the registry via a dynamic `@wrongstack/tools` import so the\n * server starts even when that package is unavailable, and never throw — a\n * failure is reported back over the socket instead.\n */\n\nimport type { WebSocket } from 'ws';\nimport { errMessage, send, sendResult } from './ws-utils.js';\nimport { validateProcessKillPayload } from './ws-payload-validation.js';\n\n/** Broadcast the tracked-process list; an empty list on any registry failure. */\nexport async function handleProcessList(ws: WebSocket): Promise<void> {\n try {\n const { getProcessRegistry } = await import('@wrongstack/tools');\n const procs = getProcessRegistry().list();\n send(ws, {\n type: 'process.list',\n payload: {\n processes: procs.map((p) => ({\n pid: p.pid,\n command: p.command,\n tool: p.name,\n startedAt: p.startedAt,\n status: p.killed ? ('killed' as const) : ('running' as const),\n protected: p.protected,\n })),\n },\n });\n } catch {\n send(ws, { type: 'process.list', payload: { processes: [] } });\n }\n}\n\n/** Kill one tracked PID. Rejects invalid payloads and protected processes. */\nexport async function handleProcessKill(ws: WebSocket, payload: unknown): Promise<void> {\n const parsed = validateProcessKillPayload(payload);\n if (!parsed.ok) {\n sendResult(ws, false, parsed.message);\n return;\n }\n const { pid } = parsed.value;\n try {\n const { getProcessRegistry } = await import('@wrongstack/tools');\n const proc = getProcessRegistry().get(pid);\n if (proc?.protected) {\n sendResult(ws, false, `Cannot kill protected process (PID ${pid})`);\n return;\n }\n getProcessRegistry().kill(pid);\n sendResult(ws, true, `Killed PID ${pid}`);\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n}\n\n/** Kill every tracked process. */\nexport async function handleProcessKillAll(ws: WebSocket): Promise<void> {\n try {\n const { getProcessRegistry } = await import('@wrongstack/tools');\n getProcessRegistry().killAll();\n sendResult(ws, true, 'All processes killed');\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n}\n","/**\n * Goal-state WebSocket handler for the WebUI server, extracted from the\n * `handleMessage` switch in `index.ts` as part of splitting that file (#31).\n *\n * case 'goal.get': return handleGoalGet(projectRoot, (m) => broadcast(clients, m));\n *\n * Reads the canonical goal.json and broadcasts it to every connected client so\n * all browser tabs share one goal snapshot. Never throws — a missing or\n * unparseable file broadcasts `null` so clients clear stale goal state.\n */\n\nimport { resolveWstackPaths } from '@wrongstack/core/utils';\n\n/**\n * Read `goal.json` for `projectRoot` and broadcast a `goal.updated` message.\n * The path must match /goal, the autonomy engines, and TUI F9, which all\n * resolve via `resolveWstackPaths().projectGoal`\n * (`~/.wrongstack/projects/<slug>/goal.json`) — NOT the repo-local\n * `.wrongstack/goal.json`.\n */\nexport async function handleGoalGet(\n projectRoot: string,\n broadcast: (msg: object) => void,\n): Promise<void> {\n try {\n const goalPath = resolveWstackPaths({ projectRoot }).projectGoal;\n const { readFile } = await import('node:fs/promises');\n const raw = await readFile(goalPath, 'utf8');\n const goal = JSON.parse(raw);\n broadcast({ type: 'goal.updated', payload: goal });\n } catch {\n broadcast({ type: 'goal.updated', payload: null });\n }\n}\n"],"mappings":"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","names":["expectDefined","GlobalMailbox","getSessionRegistry","name","path","toErrorMessage","wstackGlobalRoot","fs","path","resolveWstackPaths","DefaultSessionStore","DefaultSessionReader","tail","resolve","GlobalMailbox","mailboxSessionTag","name","fs","path","deps","fs","path","name","fs","path","relative","stat","sendResult","name","path","isInside","sendResult","fs","path","atomicWrite","name","fs","path","atomicWrite","DefaultSessionStore","DefaultSystemPromptBuilder","atomicWrite","DEFAULT_CONTEXT_WINDOW_MODE_ID","resolveContextWindowPolicy","decryptConfigSecrets","encryptConfigSecrets","WebSocket","deps","deriveTitle","deps","path","spawnSync","SddBoardStore","SpecStore","TaskGraphStore","WorktreeManager","name","toErrorMessage","tail","s","fs","path","toErrorMessage","toErrorMessage","deps","path","fs","atomicWrite","resolve","fs","path","atomicWrite","toErrorMessage","deps","broadcast","toErrorMessage","sendResult","sendResult","fs","path","DefaultSystemPromptBuilder","stat","name","DefaultSystemPromptBuilder","sendResult","path","sendResult","sendResult","fs","path","deps","broadcast","load","projectHash","name","atomicWrite","fs","path","load","save","broadcast","fs","path","spawn","resolve","path","readFile","join","sendResult","broadcast","readFile","decryptConfigSecrets","encryptConfigSecrets","atomicWrite","expectDefined","toErrorMessage","name","DefaultSessionStore","getSessionRegistry","WebSocket","wstackGlobalRoot","DefaultSystemPromptBuilder","GlobalMailbox","resolveContextWindowPolicy","provider","DEFAULT_CONTEXT_WINDOW_MODE_ID","verifyClient","resolve","sendResult"]}
1
+ {"version":3,"sources":["../../src/server/index.ts","../../src/server/ws-payload-validation.ts","../../src/server/handlers/worklist-handlers.ts","../../src/server/discover-mailbox-bridge.ts","../../src/server/http-server.ts","../../src/server/http-server/api-handlers.ts","../../src/server/ws-auth.ts","../../src/server/codebase-indexing.ts","../../src/server/file-handlers.ts","../../src/server/file-picker.ts","../../src/server/path-containment.ts","../../src/server/ws-utils.ts","../../src/server/completion-handlers.ts","../../src/server/memory-handlers.ts","../../src/server/mcp-handlers.ts","../../src/server/skills-handlers.ts","../../src/server/prompts-handlers.ts","../../src/server/design-handlers.ts","../../src/server/boot.ts","../../src/server/autophase-ws-handler.ts","../../src/server/specs-ws-handler.ts","../../src/server/sdd-board-ws-handler.ts","../../src/server/sdd-wizard-ws-handler.ts","../../src/server/sdd-wizard-wiring.ts","../../src/server/sdd-wizard-routes.ts","../../src/server/collaboration-ws-handler.ts","../../src/server/projects-manifest.ts","../../src/server/terminal-ws-handler.ts","../../src/server/worktree-ws-handler.ts","../../src/server/mailbox-handlers.ts","../../src/server/lifecycle.ts","../../src/server/instance-registry.ts","../../src/server/port-utils.ts","../../src/server/open-browser.ts","../../src/server/usage-cost.ts","../../src/server/provider-handlers.ts","../../src/server/provider-config-io.ts","../../src/server/provider-keys.ts","../../src/server/mode-handlers.ts","../../src/server/project-handlers.ts","../../src/server/session-handlers.ts","../../src/server/token-estimator.ts","../../src/server/provider-routes.ts","../../src/server/session-routes.ts","../../src/server/project-routes.ts","../../src/server/mode-routes.ts","../../src/server/prefs-routes.ts","../../src/server/shell-git-routes.ts","../../src/server/mailbox-routes.ts","../../src/server/mcp-routes.ts","../../src/server/brain-routes.ts","../../src/server/autophase-routes.ts","../../src/server/specs-routes.ts","../../src/server/sdd-board-routes.ts","../../src/server/setup-events.ts","../../src/server/custom-context-modes.ts","../../src/server/eternal-iteration-broadcast.ts","../../src/server/shell-open.ts","../../src/server/git-handlers.ts","../../src/server/process-handlers.ts","../../src/server/goal-handlers.ts"],"sourcesContent":["import { expectDefined, GlobalMailbox, getSessionRegistry, AgentStatusTracker, FleetNotifier, resolveProjectDir } from '@wrongstack/core';\nimport { readLiveLock } from '@wrongstack/core/coordination';\nimport {\n handleWorklistMessage,\n type WorklistContext,\n type WorklistMessage,\n} from './handlers/index.js';\nimport { makeMailboxTool, makeMailSendTool, makeMailInboxTool, mailboxSessionTag } from '@wrongstack/core';\nimport { toErrorMessage, wstackGlobalRoot, projectHash } from '@wrongstack/core/utils';\nimport { SkillInstaller } from '@wrongstack/core/skills';\nimport { discoverMailboxBridgeForWebui } from './discover-mailbox-bridge.js';\nimport {\n BrainMonitor,\n DefaultBrainArbiter,\n ObservableBrainArbiter,\n createAutonomyBrain,\n createTieredBrainArbiter,\n type BrainArbiter,\n type BrainAutoRisk,\n} from '@wrongstack/core';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { createRequire } from 'node:module';\nimport { createHttpServer } from './http-server.js';\nimport { setupWebUICodebaseIndexing } from './codebase-indexing.js';\nimport {\n handleFilesTree,\n handleFilesRead,\n handleFilesWrite,\n handleFilesList,\n} from './file-handlers.js';\nimport { createToolLspCompletionSource, handleCompletionRequest } from './completion-handlers.js';\nimport {\n validateMailboxAgentsPayload,\n validateMailboxMessagesPayload,\n validateMailboxPurgePayload,\n validateModelSwitchPayload,\n validatePrefsUpdatePayload,\n validateShellOpenPayload,\n validateGitDiffPayload,\n validateAutonomySwitchPayload,\n validateBrainAskPayload,\n validateBrainRiskPayload,\n} from './ws-payload-validation.js';\nimport {\n handleMemoryList,\n handleMemoryRemember,\n handleMemoryForget,\n} from './memory-handlers.js';\nimport {\n handleMcpList,\n handleMcpAdd,\n handleMcpRemove,\n handleMcpUpdate,\n handleMcpWake,\n handleMcpSleep,\n handleMcpDiscover,\n handleMcpEnable,\n handleMcpDisable,\n handleMcpRestart,\n} from './mcp-handlers.js';\nimport {\n handleSkillsList,\n handleSkillsContent,\n handleSkillsInstall,\n handleSkillsUninstall,\n handleSkillsUpdate,\n handleSkillsCreate,\n handleSkillsEdit,\n handleSkillsExport,\n} from './skills-handlers.js';\nimport {\n handlePromptsList,\n handlePromptsSearch,\n handlePromptsContent,\n handlePromptsFavorite,\n handlePromptsCreate,\n handlePromptsUsed,\n handlePromptsRecent,\n} from './prompts-handlers.js';\nimport {\n handleDesignList,\n handleDesignMaterialize,\n handleDesignSet,\n handleDesignUse,\n handleDesignState,\n handleDesignVerify,\n} from './design-handlers.js';\nimport {\n Agent,\n AutoCompactionMiddleware,\n Context,\n DefaultMemoryStore,\n DefaultModeStore,\n DefaultModelsRegistry,\n DefaultSessionReader,\n DefaultSessionStore,\n DefaultSkillLoader,\n DefaultPromptLoader,\n PromptUsageStore,\n DefaultSystemPromptBuilder,\n DefaultTokenCounter,\n AnnotationsStore,\n CollaborationBus,\n collabPauseMiddleware,\n collabInjectMiddleware,\n estimateRequestTokensCalibrated,\n EventBus,\n createStrategyCompactor,\n type Provider,\n ProviderRegistry,\n TOKENS,\n ToolRegistry,\n atomicWrite,\n createDefaultPipelines,\n installDesignStudioMiddleware,\n createSessionEventBridge,\n resolveSessionLoggingConfig,\n DEFAULT_CONTEXT_WINDOW_MODE_ID,\n DEFAULT_SESSION_PRUNE_DAYS,\n DEFAULT_TOOLS_CONFIG,\n applyToolDescriptionModes,\n applyToolResultRenderModes,\n resolveContextWindowPolicy,\n enhanceUserPrompt,\n gatedEnhancerReasoning,\n recentTextTurns,\n resolveProviderModelList,\n cleanupStaleSddWorktrees,\n} from '@wrongstack/core';\nimport { ToolExecutor } from '@wrongstack/core/execution';\nimport { decryptConfigSecrets, encryptConfigSecrets } from '@wrongstack/core/security';\nimport { buildProviderFactoriesFromRegistry, makeProviderFromConfig } from '@wrongstack/providers';\nimport { builtinToolsPack, configureExecPolicy, ensureSessionShell, forgetTool, rememberTool, searchMemoryTool, relatedMemoryTool } from '@wrongstack/tools';\nimport { MCPRegistry } from '@wrongstack/mcp';\nimport { WebSocket, WebSocketServer } from 'ws';\nimport { createDefaultContainer, makeLightSubagentFactory } from '@wrongstack/runtime';\nimport { bootConfig, patchConfig } from './boot.js';\nimport { AutoPhaseWebSocketHandler } from './autophase-ws-handler.js';\nimport { SpecsWebSocketHandler } from './specs-ws-handler.js';\nimport { SddBoardWebSocketHandler } from './sdd-board-ws-handler.js';\nimport { SddWizardWebSocketHandler } from './sdd-wizard-ws-handler.js';\nimport { buildSddWizardDeps } from './sdd-wizard-wiring.js';\nimport { handleSddWizardRoute, type SddWizardRouteHandlers } from './sdd-wizard-routes.js';\nimport { CollaborationWebSocketHandler } from './collaboration-ws-handler.js';\nimport {\n ensureProjectDataDir,\n generateProjectSlug,\n loadManifest,\n saveManifest,\n} from './projects-manifest.js';\nimport { TerminalWebSocketHandler } from './terminal-ws-handler.js';\nimport { WorktreeWebSocketHandler } from './worktree-ws-handler.js';\nimport { handleMailboxMessages, handleMailboxAgents, handleMailboxClear, handleMailboxPurge } from './mailbox-handlers.js';\nimport { verifyClient as verifyWsClient } from './ws-auth.js';\nimport { registerShutdownHandlers } from './lifecycle.js';\nimport { registerInstance, unregisterInstance } from './instance-registry.js';\nimport { findFreePort } from './port-utils.js';\nimport { openBrowser } from './open-browser.js';\nimport { computeUsageCost, getCostRates } from './usage-cost.js';\nimport { createProviderHandlers, projectSavedProviders } from './provider-handlers.js';\nimport { createModeHandlers } from './mode-handlers.js';\nimport { createProjectHandlers } from './project-handlers.js';\nimport { createSessionHandlers } from './session-handlers.js';\nimport { handleProviderRoute, type ProviderRouteHandlers } from './provider-routes.js';\nimport { handleSessionRoute, type SessionRouteHandlers } from './session-routes.js';\nimport { handleProjectRoute, type ProjectRouteHandlers } from './project-routes.js';\nimport { handleModeRoute, type ModeRouteHandlers } from './mode-routes.js';\nimport { handlePrefsRoute, type PrefsRouteHandlers } from './prefs-routes.js';\nimport { handleShellGitRoute, type ShellGitRouteHandlers } from './shell-git-routes.js';\nimport { handleMailboxRoute, type MailboxRouteHandlers } from './mailbox-routes.js';\nimport { handleMcpRoute, type McpRouteHandlers } from './mcp-routes.js';\nimport { handleBrainRoute, type BrainRouteHandlers } from './brain-routes.js';\nimport { handleAutoPhaseRoute, type AutoPhaseRouteHandlers } from './autophase-routes.js';\nimport { handleSpecsRoute, type SpecsRouteHandlers } from './specs-routes.js';\nimport { handleSddBoardRoute, type SddBoardRouteHandlers } from './sdd-board-routes.js';\nimport { setupEvents, type FileWatcherMetrics } from './setup-events.js';\nimport { createCustomModeStore } from './custom-context-modes.js';\nimport { maskedKey, normalizeKeys } from './provider-keys.js';\nimport {\n send,\n broadcast,\n sendResult,\n errMessage,\n resolveAuthToken,\n buildWebUIAccessUrl,\n envFlag,\n} from './ws-utils.js';\nimport { createEternalSubscription } from './eternal-iteration-broadcast.js';\nimport { handleShellOpen, type ShellOpenRequest, type ShellOpenResult } from './shell-open.js';\nimport { handleGitChanges, handleGitDiff, handleGitInfo } from './git-handlers.js';\nimport {\n handleProcessKill,\n handleProcessKillAll,\n handleProcessList,\n} from './process-handlers.js';\nimport { handleGoalGet } from './goal-handlers.js';\n// Re-export types — shared message shapes and options used by both the\n// standalone server and the CLI's `--webui` embedded mode.\nexport type { WebUIOptions, BackendServices } from './types.js';\nexport type { WSServerMessage, WSClientMessage, ConnectedClient } from './types.js';\n\n// Re-export the static-serve + multi-instance building blocks so other packages\n// (the CLI's `--webui` mode) can serve the same React frontend, inject the live\n// WS port, pick free ports, and register in the shared instance registry —\n// without duplicating any of that logic.\nexport { createHttpServer, buildCspHeader, injectWsPort } from './http-server.js';\nexport type { CreateHttpServerOptions } from './http-server.js';\nexport { findFreePort, isPortFree } from './port-utils.js';\nexport { openBrowser, browserOpenCommand } from './open-browser.js';\nexport { WorktreeWebSocketHandler } from './worktree-ws-handler.js';\n// Token estimator primitives — exposed for the CLI's embedded webui\n// (which historically inlined its own copy and let it drift). Now\n// there's exactly one definition. See\n// packages/cli/src/webui-server.ts Phase 2 of the refactor plan.\nexport {\n estimateTokens,\n messageTokens,\n messagePreview,\n stringifyContent,\n type ContextBreakdown,\n type MessageTokenEntry,\n type ToolTokenEntry,\n} from './token-estimator.js';\nexport {\n registerInstance,\n unregisterInstance,\n listInstances,\n formatInstances,\n registryPath,\n defaultBaseDir,\n type WebUIInstanceRecord,\n} from './instance-registry.js';\n\n// WebSocket utilities shared with CLI\nexport {\n createEternalSubscription,\n type EternalSubscribe,\n type EternalBroadcast,\n type EternalSubscription,\n} from './eternal-iteration-broadcast.js';\nexport {\n handleShellOpen,\n type ShellOpenRequest,\n type ShellOpenResult,\n type ShellOpenTarget,\n} from './shell-open.js';\nexport {\n send,\n broadcast,\n sendResult,\n errMessage,\n generateAuthToken,\n resolveAuthToken,\n hostForBrowserUrl,\n buildWebUIAccessUrl,\n envFlag,\n} from './ws-utils.js';\n\n// File operation handlers shared with CLI (files.tree, files.read, files.write, files.list)\nexport {\n handleFilesTree,\n handleFilesRead,\n handleFilesWrite,\n handleFilesList,\n} from './file-handlers.js';\nexport {\n createToolLspCompletionSource,\n handleCompletionRequest,\n type CompletionHandlerOptions,\n type CompletionItemKind,\n type CompletionSuggestion,\n type LspCompletionSource,\n type LspCompletionSourceRequest,\n} from './completion-handlers.js';\n\n// Git info handler shared with CLI (git.info) — single source so the two\n// servers can't drift on ahead/behind / insertion-deletion parsing.\nexport { handleGitChanges, handleGitDiff, handleGitInfo } from './git-handlers.js';\n\n// Memory operation handlers shared with CLI (memory.list, memory.remember, memory.forget)\nexport {\n handleMemoryList,\n handleMemoryRemember,\n handleMemoryForget,\n} from './memory-handlers.js';\n\n// MCP operation handlers shared with CLI (mcp.list, mcp.add, mcp.remove, etc.)\nexport {\n handleMcpList,\n handleMcpAdd,\n handleMcpRemove,\n handleMcpUpdate,\n handleMcpWake,\n handleMcpSleep,\n handleMcpDiscover,\n handleMcpEnable,\n handleMcpDisable,\n handleMcpRestart,\n} from './mcp-handlers.js';\n\n// Custom context-mode store shared with the CLI's embedded server\n// (context.mode.create/update/delete + custom-aware list/switch).\nexport {\n createCustomModeStore,\n type CustomModeStore,\n type CustomContextMode,\n} from './custom-context-modes.js';\n\n// WS auth — pure functions for verifying WebSocket connections\nexport {\n verifyClient,\n isLoopbackHostname,\n isLoopbackBind,\n tokenMatches,\n extractToken,\n hostHeaderOk,\n type VerifyClientInput,\n} from './ws-auth.js';\n\n// Provider/API-key record transforms (pure functions, testable without I/O)\nexport {\n normalizeKeys,\n writeKeysBack,\n maskedKey,\n upsertKey,\n deleteKey,\n setActiveKey,\n addProvider,\n removeProvider,\n type KeyOpResult,\n type ProvidersRecord,\n} from './provider-keys.js';\n\n// Provider config load/save (decrypt from / encrypt to global config)\nexport {\n loadSavedProviders,\n saveProviders,\n createProviderConfigIO,\n} from './provider-config-io.js';\n\n// AutoPhase WebSocket handler — manages AutoPhase lifecycle via WS messages.\n// Exported so the CLI's embedded webui-server can also handle autophase.*\n// messages when running in --webui mode.\nexport { AutoPhaseWebSocketHandler } from './autophase-ws-handler.js';\nexport { SpecsWebSocketHandler } from './specs-ws-handler.js';\nexport { SddBoardWebSocketHandler } from './sdd-board-ws-handler.js';\nexport { SddWizardWebSocketHandler, type SddWizardDeps } from './sdd-wizard-ws-handler.js';\nexport { buildSddWizardDeps, type SddWizardWiringOptions } from './sdd-wizard-wiring.js';\n\n// Shared skills WebSocket handlers — one source of truth for both this\n// standalone server and the CLI's embedded --webui server. The CLI imports\n// these so skills.content / install / uninstall / update / create / edit /\n// export are handled there too (they previously fell through to the\n// \"Unhandled message type\" warning).\nexport {\n type SkillsContext,\n handleSkillsContent,\n handleSkillsInstall,\n handleSkillsUninstall,\n handleSkillsUpdate,\n handleSkillsCreate,\n handleSkillsEdit,\n handleSkillsExport,\n} from './skills-handlers.js';\n// Shared prompt-library handlers — one source of truth for both servers.\nexport {\n type PromptsContext,\n handlePromptsList,\n handlePromptsSearch,\n handlePromptsContent,\n handlePromptsFavorite,\n handlePromptsCreate,\n handlePromptsUsed,\n handlePromptsRecent,\n} from './prompts-handlers.js';\n// Design Studio handlers — shared so the CLI's embedded server reaches parity.\nexport {\n type DesignContext,\n handleDesignList,\n handleDesignMaterialize,\n handleDesignSet,\n handleDesignUse,\n handleDesignState,\n handleDesignVerify,\n} from './design-handlers.js';\n\n// Message + client shapes now live in ./types.ts (shared with the CLI's\n// embedded server). Imported here for internal use; re-exported above for\n// external consumers. The previous local copies shadowed these and made the\n// `Map<WebSocket, ConnectedClient>` passed to the extracted ws-utils helpers\n// nominally distinct, which TS rejected.\nimport type { ConnectedClient, WSClientMessage, WebUIOptions } from './types.js';\n\nexport async function startWebUI(\n opts: WebUIOptions & {\n wsPort?: number | undefined;\n wsHost?: string | undefined;\n httpPort?: number | undefined;\n accessToken?: string | undefined;\n publicUrl?: string | undefined;\n publicWsUrl?: string | undefined;\n requireToken?: boolean | undefined;\n open?: boolean | undefined;\n } = {},\n): Promise<void> {\n // Pin one stable shell for the session on Windows (PowerShell by default) via\n // WRONGSTACK_SHELL before the system-prompt builder is constructed below, so\n // the model is told exactly which shell + syntax to use. No-op on POSIX / when\n // the user already set WRONGSTACK_SHELL.\n ensureSessionShell();\n\n const requestedWsPort = opts.wsPort ?? 3457;\n // Bind to loopback IP by default (not the string \"localhost\", which on some\n // hosts resolves to IPv6 ::1 and surprises older WS clients). Set WS_HOST or\n // pass opts.wsHost to override (e.g. \"0.0.0.0\" for LAN access).\n const wsHost = opts.wsHost ?? process.env['WEBUI_HOST'] ?? process.env['WS_HOST'] ?? '127.0.0.1';\n const requestedHttpPort =\n opts.httpPort ??\n opts.webuiPort ??\n opts.port ??\n Number.parseInt(process.env['WEBUI_PORT'] ?? process.env['PORT'] ?? '3456', 10);\n const publicUrl = opts.publicUrl ?? process.env['WEBUI_PUBLIC_URL'];\n const publicWsUrl = opts.publicWsUrl ?? process.env['WEBUI_PUBLIC_WS_URL'];\n const requireToken = opts.requireToken ?? envFlag('WEBUI_REQUIRE_TOKEN');\n\n // Port resolution. Unless WEBUI_STRICT_PORT is set, auto-advance past any port\n // already taken by another instance so running `wstackui` several times \"just\n // works\" — the real ports are then stamped into the served HTML and the\n // instance registry. Strict mode keeps the requested ports and lets bind fail\n // loudly (useful behind a reverse proxy that expects fixed ports).\n const strictPort =\n process.env['WEBUI_STRICT_PORT'] === '1' || process.env['WEBUI_STRICT_PORT'] === 'true';\n let wsPort = requestedWsPort;\n let httpPort = requestedHttpPort;\n if (!strictPort) {\n // Resolve HTTP first, then WS excluding it, so successive instances land on\n // tidy adjacent pairs (3456/3457, 3458/3459, …) instead of interleaving.\n httpPort = await findFreePort(wsHost, requestedHttpPort);\n wsPort = await findFreePort(wsHost, requestedWsPort, { exclude: new Set([httpPort]) });\n if (httpPort !== requestedHttpPort) {\n console.warn(JSON.stringify({\n level: 'warn',\n event: 'webui.port_reassigned',\n protocol: 'HTTP',\n requested: requestedHttpPort,\n assigned: httpPort,\n timestamp: new Date().toISOString(),\n }));\n }\n if (wsPort !== requestedWsPort) {\n console.warn(JSON.stringify({\n level: 'warn',\n event: 'webui.port_reassigned',\n protocol: 'WS',\n requested: requestedWsPort,\n assigned: wsPort,\n timestamp: new Date().toISOString(),\n }));\n }\n }\n\n console.log('[WebUI] Starting backend services...');\n\n // Boot configuration\n const boot = await bootConfig();\n const { config: baseConfig, globalConfigPath, wpaths, logger } = boot;\n // PR 5 of Phase 2: when the caller (typically the CLI) supplies a\n // pre-built `BackendServices`, prefer its `vault` over the one the\n // default boot would construct. This lets `runWebUI` keep owning the\n // vault lifecycle (so it can decrypt/encrypt its own config writes\n // in lockstep with the rest of the CLI session) instead of having\n // the webui build a parallel vault it can never see.\n const vault = opts.services?.vault ?? boot.vault;\n let config = baseConfig;\n\n /** Mutable project root — updated on `projects.select`. File handlers,\n * sessionStartPayload, and session store use this value. */\n let projectRoot = boot.projectRoot;\n /** Mutable working directory — starts at projectRoot, changeable via\n * `working_dir.set` WS message. Must always stay inside projectRoot. */\n let workingDir = projectRoot;\n\n // Serialize concurrent config writes to prevent races between model.switch\n // and key.add/key.update handlers that both read-modify-write globalConfigPath.\n let configWriteLock: Promise<void> = Promise.resolve();\n\n /**\n * Unified global config mutation: read → decrypt → mutate → encrypt → write.\n * All config writes MUST go through this helper so encryption is always\n * preserved and writes are serialized behind configWriteLock.\n * The `mutate` callback receives the decrypted config and mutates it in place.\n * Failures log but never break the caller (non-poisoning lock).\n */\n const updateGlobalConfig = async (\n mutate: (config: Record<string, unknown>) => void,\n errorLabel: string,\n ): Promise<void> => {\n const write = async (): Promise<void> => {\n let raw: string;\n try {\n raw = await fs.readFile(globalConfigPath, 'utf8');\n } catch {\n raw = '{}';\n }\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(raw) as Record<string, unknown>;\n } catch {\n logger.warn(`${errorLabel}: refusing to overwrite corrupt config at ${globalConfigPath}`);\n return;\n }\n const decrypted = decryptConfigSecrets(parsed, vault) as Record<string, unknown>;\n mutate(decrypted);\n const encrypted = encryptConfigSecrets(decrypted, vault);\n await atomicWrite(globalConfigPath, JSON.stringify(encrypted, null, 2), { mode: 0o600 });\n };\n const next = configWriteLock.then(write);\n configWriteLock = next.then(\n () => undefined,\n () => undefined,\n );\n try {\n await next;\n } catch (err) {\n logger.warn(`${errorLabel}: failed to persist to config: ${errMessage(err)}`);\n }\n };\n\n console.log('[WebUI] Config loaded:', config.provider ?? '(none)', '/', config.model ?? '(none)');\n\n // If no active provider is set but there are saved providers, pick the first one.\n // This handles configs written in older formats or by external tools.\n // Guard against config.providers being a string or other non-object value\n // (e.g., from a corrupted config or YAML parser misreading the value).\n if (\n !config.provider &&\n config.providers &&\n typeof config.providers === 'object' &&\n config.providers !== null &&\n !Array.isArray(config.providers) &&\n Object.keys(config.providers).length > 0\n ) {\n const firstKey = expectDefined(Object.keys(config.providers)[0]);\n config = patchConfig(config, { provider: firstKey });\n console.log('[WebUI] No active provider — auto-selected:', firstKey);\n }\n\n // If still no provider, the frontend will show a no-provider welcome screen.\n // We still start the HTTP/WS servers so the user can configure via the UI.\n const needsProvider = !config.provider || !config.model;\n\n // ModelsRegistry — use injected one if `services.modelsRegistry` was passed,\n // otherwise build a fresh one. The injected path lets the CLI's `runWebUI`\n // share a single registry across its own runtime and the webui surface.\n const modelsRegistry =\n opts.services?.modelsRegistry ??\n new DefaultModelsRegistry({\n cacheFile: wpaths.modelsCache,\n ttlSeconds: 24 * 3600,\n });\n\n // Container via shared factory\n const container = createDefaultContainer({ config, wpaths, logger, modelsRegistry });\n // PR 5 of Phase 2: when the caller (typically the CLI) supplies a\n // pre-built `BackendServices`, prefer its `configStore` over the one\n // the default container would resolve. This is the read+write\n // counterpart of the `vault` injection above: together they let\n // `runWebUI` own the global config lifecycle and have the webui\n // operate on the *same* in-memory store, so a `provider.switch`\n // from the webui is visible to the CLI's next call without a disk\n // round-trip in between.\n const configStore = opts.services?.configStore ?? container.resolve(TOKENS.ConfigStore);\n\n // Provider registry\n const providerRegistry = new ProviderRegistry();\n try {\n const factories = await buildProviderFactoriesFromRegistry({\n registry: modelsRegistry,\n log: logger,\n });\n for (const f of factories) providerRegistry.register(f);\n console.log('[WebUI] Provider registry loaded:', providerRegistry.list().length, 'providers');\n } catch (err) {\n console.warn(JSON.stringify({\n level: 'warn',\n event: 'webui.provider_registry_load_failed',\n message: toErrorMessage(err),\n timestamp: new Date().toISOString(),\n }));\n }\n\n // Tool registry — use injected one if `services.toolRegistry` was passed.\n // When injected, the caller has already registered the tools they want\n // (the CLI's runWebUI registers its own runtime tools); startWebUI just\n // uses the registry as-is.\n const toolRegistry =\n opts.services?.toolRegistry ??\n (() => {\n const r = new ToolRegistry();\n r.registerAllOrThrow([...(builtinToolsPack.tools ?? [])], builtinToolsPack.name);\n return r;\n })();\n\n // Memory tools\n const memoryStore = new DefaultMemoryStore({ paths: wpaths });\n if (config.features.memory) {\n toolRegistry.register(rememberTool(memoryStore));\n toolRegistry.register(forgetTool(memoryStore));\n toolRegistry.register(searchMemoryTool(memoryStore));\n toolRegistry.register(relatedMemoryTool(memoryStore));\n }\n\n // Event bus — use injected one if `services.events` was passed. The CLI's\n // runWebUI owns the agent's EventBus so it can wire sub-agents onto the\n // same bus the webui dashboard reads from. When injected, we just\n // attach the logger and reuse the existing instance.\n const events = opts.services?.events ?? new EventBus();\n events.setLogger(logger);\n\n // Inter-agent mailbox tools — same project-level GlobalMailbox the CLI\n // registers, keyed by wpaths.projectDir so WebUI agents and terminal\n // agents on the same project share one inbox and can chat/broadcast.\n // mail_send/mail_inbox are the high-affordance thin wrappers.\n toolRegistry.register(makeMailboxTool({ projectDir: wpaths.projectDir, events }));\n toolRegistry.register(makeMailSendTool({ projectDir: wpaths.projectDir, events }));\n toolRegistry.register(makeMailInboxTool({ projectDir: wpaths.projectDir, events }));\n applyToolDescriptionModes(toolRegistry, config.tools?.descriptionMode);\n applyToolResultRenderModes(toolRegistry, config.tools?.resultRenderMode);\n // Apply the configured exec command policy (DEFAULT ∪ allow − deny). `allow`\n // is trusted-config-only; the config loader strips `tools.exec.allow` from\n // any in-project repo config before it reaches here.\n configureExecPolicy(config.tools?.exec ?? {});\n console.log('[WebUI] Tool registry loaded:', toolRegistry.list().length, 'tools');\n\n // ── MCP registry — the live counterpart to config.mcpServers. ────────────\n // The standalone WebUI server now owns a real registry (the CLI's embedded\n // server reuses the agent's), so the MCP settings panel can actually\n // start/stop servers and surface live status + tool names, not just edit\n // config. Enabled servers are connected at boot, mirroring the CLI host.\n const mcpRegistry = new MCPRegistry({\n toolRegistry,\n events,\n log: logger,\n // Lazy-connect (per-server `lazy`) manifest cache + default idle auto-sleep.\n cacheDir: wpaths.cacheDir,\n });\n if (config.features.mcp && config.mcpServers) {\n for (const [name, cfg] of Object.entries(config.mcpServers)) {\n if (cfg.enabled === false) continue;\n void mcpRegistry.start({ ...cfg, name }).catch((err) => {\n logger.warn(`MCP server \"${name}\" failed to start at boot`, err);\n });\n }\n }\n\n // Session store — mutable so projects.select can swap it to the new project's dir.\n // Use the injected one if `services.session` was passed. The CLI's\n // runWebUI already has its own session store pointing at the\n // right per-project dir; we reuse it here so the webui reads\n // the same history the CLI is writing.\n let sessionStore = opts.services?.session ?? new DefaultSessionStore({ dir: wpaths.projectSessions });\n // Prune old sessions on server start (non-blocking). Skipped when\n // an injected store is in use — the CLI's eternal loop is\n // responsible for its own lifecycle and pruning an in-use store\n // would race with the CLI's own prune policy.\n if (!opts.services?.session) {\n sessionStore\n .prune(DEFAULT_SESSION_PRUNE_DAYS)\n .then((count) => {\n if (count > 0) logger.info(`Pruned ${count} old session${count === 1 ? '' : 's'}.`);\n })\n .catch(() => undefined);\n }\n // Session reader — same on-disk store, read-only access. Used by the\n // collaboration handler to replay the last N events to late-joining\n // observers (Phase 1.5 of idea #13).\n const sessionReader = new DefaultSessionReader({ store: sessionStore });\n // Annotations store — sidecar files for collaboration notes (Phase 2\n // of idea #13). Living under `projectSessions` so all per-session\n // data is colocated and travels with the project.\n const annotationsStore = new AnnotationsStore({ dir: wpaths.projectSessions, events });\n let session = await sessionStore.create({\n id: '',\n title: '',\n model: config.model,\n provider: config.provider,\n });\n // Wall-clock when the *current* session started. Updated on /new and on\n // /resume so /stats can report accurate elapsed time per the active\n // session, not the daemon process uptime.\n let sessionStartedAt = Date.now();\n console.log('[WebUI] Session created:', session.id);\n\n // ── Cross-surface discovery ──────────────────────────────────────────\n // (1) Register/refresh this project in ~/.wrongstack/projects.json so\n // pickers and other surfaces see it regardless of which interface\n // opened it first. (2) Register this session in the cross-process\n // SessionRegistry so terminals' `/sessions status` lists this WebUI\n // (and vice versa). Both best-effort — discovery must not block boot.\n try {\n await touchProjectEntry(projectRoot, workingDir);\n } catch { /* best-effort */ }\n let statusTracker: AgentStatusTracker | undefined;\n try {\n const registry = getSessionRegistry(wpaths.globalRoot);\n await registry.register({\n sessionId: session.id,\n projectSlug: wpaths.projectSlug,\n projectRoot,\n projectName: path.basename(projectRoot),\n workingDir,\n clientType: 'webui',\n pid: process.pid,\n startedAt: new Date().toISOString(),\n });\n // Push-on-write: nudge OTHER same-project WebUIs when our agents advance,\n // so a fleet of WebUI windows stays in lockstep without watch/poll lag.\n const fleetNotifier = new FleetNotifier({\n baseDir: wpaths.globalRoot,\n projectRoot,\n selfPid: process.pid,\n });\n statusTracker = new AgentStatusTracker({ events, registry, onUpdate: () => fleetNotifier.notify() });\n statusTracker.start();\n\n // ── HQ session telemetry — stream live state + full transcript to HQ ──\n let stopHqSessionBridge: (() => void) | undefined;\n let hqTelemetryPublisher: { close(): void } | undefined;\n try {\n const { createHqPublisherFromEnv, startSessionTelemetryBridge } = await import('@wrongstack/core');\n const hqTelemetry = createHqPublisherFromEnv({\n clientKind: 'webui',\n projectRoot,\n projectName: path.basename(projectRoot),\n appConfig: config as never as Parameters<typeof createHqPublisherFromEnv>[0]['appConfig'],\n socketFactory: (url: string) => new WebSocket(url) as unknown as import('@wrongstack/core').HqSocketLike,\n });\n if (hqTelemetry) {\n hqTelemetry.connect();\n hqTelemetryPublisher = hqTelemetry;\n stopHqSessionBridge = startSessionTelemetryBridge({\n publisher: hqTelemetry,\n events,\n sessionId: session.id,\n projectRoot,\n projectName: path.basename(projectRoot),\n globalRoot: wpaths.globalRoot,\n initialAgents: statusTracker?.getAgents(),\n startedAt: new Date().toISOString(),\n });\n }\n } catch { /* telemetry optional */ }\n\n const stopTracking = async () => {\n try {\n fleetNotifier.dispose();\n await registry.markClosing();\n statusTracker?.stop();\n stopHqSessionBridge?.();\n hqTelemetryPublisher?.close();\n } catch { /* ignore */ }\n };\n process.once('beforeExit', () => { void stopTracking(); });\n process.once('SIGINT', () => { void stopTracking(); });\n process.once('SIGTERM', () => { void stopTracking(); });\n } catch { /* best-effort — discovery degrades gracefully */ }\n\n // Token counter\n const tokenCounter = new DefaultTokenCounter({\n registry: modelsRegistry,\n providerId: config.provider,\n });\n\n // Mode store\n const modeStore = new DefaultModeStore({ directory: wpaths.configDir });\n const activeMode = await modeStore.getActiveMode();\n let modeId = activeMode?.id ?? 'default';\n const modePrompt = activeMode?.prompt ?? '';\n\n // Custom context modes store — user-defined presets persisted to disk.\n // Loaded once on startup; merges with built-in modes in the list handler.\n const customModeStore = createCustomModeStore(wpaths.configDir);\n await customModeStore.load();\n console.log(\n '[WebUI] Custom context modes loaded:',\n customModeStore.list().filter((m) => (m as { custom?: boolean }).custom).length,\n 'custom',\n );\n\n // System prompt builder\n const resolvedModel = await modelsRegistry.getModel(config.provider, config.model);\n const modelCapabilities = resolvedModel?.capabilities\n ? {\n maxContextTokens: resolvedModel.capabilities.maxContext,\n supportsTools: resolvedModel.capabilities.tools,\n supportsVision: resolvedModel.capabilities.vision,\n supportsReasoning: resolvedModel.capabilities.reasoning,\n }\n : undefined;\n const modelCapabilitiesRef: { current: typeof modelCapabilities } = {\n current: modelCapabilities,\n };\n\n const skillLoader = config.features.skills\n ? new DefaultSkillLoader({ paths: wpaths })\n : undefined;\n const skillInstaller = config.features.skills\n ? new SkillInstaller({\n manifestPath: path.join(wstackGlobalRoot(), 'installed-skills.json'),\n projectSkillsDir: path.join(projectRoot, '.wrongstack', 'skills'),\n globalSkillsDir: path.join(wstackGlobalRoot(), 'skills'),\n projectHash: projectHash(projectRoot),\n skillLoader,\n })\n : undefined;\n // Prompt library — on by default; `features.prompts: false` disables it\n // (the loader is withheld so handlers report it unavailable). Resolve the\n // bundled dataset shipped with @wrongstack/core (sibling of dist) so the\n // builtin prompts show up.\n const promptsEnabled = config.features.prompts !== false;\n const bundledPromptsDir = promptsEnabled\n ? (() => {\n try {\n const req = createRequire(import.meta.url);\n return path.join(\n path.dirname(req.resolve('@wrongstack/core/package.json')),\n 'data',\n 'prompts',\n );\n } catch {\n return undefined;\n }\n })()\n : undefined;\n const promptLoader = promptsEnabled\n ? new DefaultPromptLoader({ paths: wpaths, bundledDir: bundledPromptsDir })\n : undefined;\n const promptUsage = new PromptUsageStore(wpaths.promptUsage);\n const promptsCtx = { promptLoader, promptUsage };\n const systemPromptBuilder = new DefaultSystemPromptBuilder({\n memoryStore,\n skillLoader,\n modeStore,\n modeId,\n modePrompt,\n modelCapabilities: () => modelCapabilitiesRef.current,\n instructionPaths: {\n globalDir: wpaths.globalInstructions,\n projectDir: wpaths.inProjectInstructions,\n },\n });\n\n // Fetch online agents from the shared mailbox to include in system prompt\n let onlineAgents: import('@wrongstack/core').MailboxAgentStatus[] = [];\n try {\n const systemMailbox = new GlobalMailbox(wpaths.projectDir);\n onlineAgents = await systemMailbox.getAgentStatuses();\n } catch {\n // Non-fatal — mailbox errors should not block prompt building\n }\n\n const systemPrompt = await systemPromptBuilder.build({\n cwd: projectRoot,\n projectRoot,\n tools: toolRegistry.list(),\n provider: config.provider,\n model: config.model,\n onlineAgents,\n });\n\n // Build provider (only if provider is configured)\n let provider: ReturnType<ProviderRegistry['create']>;\n if (!needsProvider) {\n const providerConfig = config.providers?.[config.provider] ?? {\n type: config.provider,\n apiKey: config.apiKey,\n baseUrl: config.baseUrl,\n };\n try {\n const cfgWithType = { ...providerConfig, type: config.provider };\n if (config.features.modelsRegistry && providerRegistry.has(config.provider)) {\n provider = providerRegistry.create(cfgWithType);\n } else {\n provider = makeProviderFromConfig(config.provider, cfgWithType);\n }\n } catch (err) {\n console.error(JSON.stringify({\n level: 'error',\n event: 'webui.provider_create_failed',\n message: toErrorMessage(err),\n timestamp: new Date().toISOString(),\n }));\n throw err;\n }\n } else {\n // No provider is actively selected, but saved providers exist.\n // Re-read the config to find one with a usable encrypted API key\n // and create a real provider from it (the vault is already initialized).\n const savedProviders = config.providers ?? {};\n const firstKey = Object.keys(savedProviders)[0];\n if (firstKey) {\n const firstProvider = expectDefined(savedProviders[firstKey]);\n try {\n provider = makeProviderFromConfig(firstKey, {\n ...firstProvider,\n type: firstKey,\n family: firstProvider.family,\n apiKey: firstProvider.apiKey,\n });\n console.log('[WebUI] Using saved provider:', firstKey);\n } catch (err) {\n console.error(JSON.stringify({\n level: 'error',\n event: 'webui.provider_stub_create_failed',\n message: toErrorMessage(err),\n timestamp: new Date().toISOString(),\n }));\n throw err;\n }\n } else {\n throw new Error(\n 'No provider configured. Run `wrongstack auth` to set up, or configure via the WebUI.',\n );\n }\n }\n\n // Context\n const context = new Context({\n systemPrompt,\n provider,\n session,\n signal: new AbortController().signal,\n tokenCounter,\n cwd: workingDir,\n projectRoot,\n model: config.model,\n });\n const initialContextPolicy = resolveContextWindowPolicy(config.context);\n context.meta['contextWindowMode'] = initialContextPolicy.id;\n context.meta['contextWindowPolicy'] = initialContextPolicy;\n\n // ── Seed runtime prefs from config ──────────────────────────────────────\n // The settings panel reads prefs via `prefs.get` → context.meta. Without\n // this seed the snapshot is empty and every browser shows localStorage\n // defaults (autonomy \"off\", etc.) regardless of what config.json says.\n // Mirrors the CLI's getSettings() mapping so TUI and WebUI agree.\n {\n const autonomyCfg = (config.autonomy ?? {}) as Record<string, unknown>;\n const rawMode = autonomyCfg['defaultMode'];\n context.meta['autonomy'] =\n rawMode === 'suggest' || rawMode === 'auto' ? rawMode : 'off';\n context.meta['autonomyDelayMs'] = (autonomyCfg['autoProceedDelayMs'] as number) ?? 45_000;\n context.meta['autoProceedMaxIterations'] =\n (autonomyCfg['autoProceedMaxIterations'] as number) ?? 50;\n context.meta['yolo'] = (autonomyCfg['yolo'] as boolean) ?? config.yolo ?? false;\n context.meta['chime'] = (autonomyCfg['chime'] as boolean) ?? false;\n context.meta['confirmExit'] = autonomyCfg['confirmExit'] !== false;\n context.meta['streamFleet'] = autonomyCfg['streamFleet'] !== false;\n context.meta['enhanceEnabled'] = (autonomyCfg['enhance'] as boolean) ?? true;\n context.meta['enhanceDelayMs'] = (autonomyCfg['enhanceDelayMs'] as number) ?? 60_000;\n context.meta['enhanceLanguage'] = (autonomyCfg['enhanceLanguage'] as string) ?? 'original';\n context.meta['nextPrediction'] = config.nextPrediction ?? false;\n context.meta['fallbackModels'] = config.fallbackModels ?? [];\n context.meta['fallbackProfiles'] = config.fallbackProfiles ?? {};\n context.meta['favoriteModels'] = config.favoriteModels ?? [];\n context.meta['favoriteModelsOnly'] = config.favoriteModelsOnly === true;\n context.meta['modelMatrix'] = config.modelMatrix ?? {};\n context.meta['fallbackAuto'] = config.fallbackAuto !== false;\n context.meta['featureMcp'] = config.features.mcp !== false;\n context.meta['featurePlugins'] = config.features.plugins !== false;\n context.meta['featureMemory'] = config.features.memory !== false;\n context.meta['featureSkills'] = config.features.skills !== false;\n context.meta['featureModelsRegistry'] = config.features.modelsRegistry !== false;\n context.meta['indexOnStart'] = config.indexing?.onSessionStart !== false;\n context.meta['contextAutoCompact'] = config.context?.autoCompact !== false;\n context.meta['contextStrategy'] = config.context?.strategy ?? 'hybrid';\n context.meta['logLevel'] = config.log?.level ?? 'info';\n context.meta['auditLevel'] = config.session?.auditLevel ?? 'standard';\n context.meta['maxIterations'] = config.tools?.maxIterations ?? 500;\n context.meta['contextMode'] = config.context?.mode ?? 'balanced';\n {\n const tsm = config.features?.tokenSavingMode;\n context.meta['tokenSavingTier'] =\n typeof tsm === 'string' ? tsm : tsm ? 'medium' : 'off';\n }\n context.meta['maxConcurrent'] =\n typeof config.maxConcurrent === 'number' ? config.maxConcurrent : 10;\n context.meta['titleAnimation'] = autonomyCfg['terminalTitleAnimation'] !== false;\n {\n const mr = (config.modelRuntime ?? {}) as {\n reasoning?: { mode?: string; effort?: string; preserve?: boolean };\n cache?: { ttl?: string };\n };\n context.meta['reasoningMode'] = mr.reasoning?.mode ?? 'auto';\n context.meta['reasoningEffort'] = mr.reasoning?.effort ?? 'high';\n context.meta['reasoningPreserve'] = mr.reasoning?.preserve === true;\n context.meta['cacheTtl'] = mr.cache?.ttl ?? 'default';\n }\n const hqConfig = (config as { hq?: { enabled?: boolean; url?: string; token?: string; rawContent?: boolean } }).hq;\n context.meta['hqEnabled'] = hqConfig?.enabled === true;\n context.meta['hqUrl'] = hqConfig?.url ?? '';\n context.meta['hqToken'] = hqConfig?.token ?? '';\n context.meta['hqRawContent'] = hqConfig?.rawContent === true;\n\n // Telegram plugin notification settings live under\n // extensions.telegram — same path the CLI's /telegram-settings writes.\n // Seed the meta so the SettingsPanel reflects the persisted config on\n // first connect, before any prefs.update arrives.\n const tgExt = (config.extensions as Record<string, Record<string, unknown>> | undefined)?.['telegram'];\n context.meta['tgConfigured'] = typeof tgExt?.['botToken'] === 'string' && tgExt['botToken'].length > 0;\n context.meta['tgSessionEnd'] = tgExt?.['notifyOnSessionEnd'] === true;\n context.meta['tgDelegate'] = tgExt?.['notifyOnDelegate'] !== false; // default true\n const tgMs = tgExt?.['longToolThresholdMs'];\n context.meta['tgLongToolMs'] = typeof tgMs === 'number' ? tgMs : 30_000;\n }\n\n /** Pref keys exposed to the settings panel via prefs.get / prefs.updated. */\n const PREF_KEYS = [\n 'autonomy', 'autonomyDelayMs', 'autoProceedMaxIterations', 'yolo', 'maxIterations',\n 'chime', 'confirmExit', 'streamFleet', 'nextPrediction',\n 'enhanceEnabled', 'enhanceDelayMs', 'enhanceLanguage',\n 'featureMcp', 'featurePlugins', 'featureMemory', 'featureSkills',\n 'featureModelsRegistry', 'indexOnStart',\n 'contextAutoCompact', 'contextStrategy', 'contextMode', 'tokenSavingTier',\n 'maxConcurrent', 'titleAnimation', 'logLevel', 'auditLevel',\n 'hqEnabled', 'hqUrl', 'hqToken', 'hqRawContent',\n 'tgConfigured', 'tgSessionEnd', 'tgDelegate', 'tgLongToolMs',\n 'reasoningMode', 'reasoningEffort', 'reasoningPreserve', 'cacheTtl',\n 'fallbackModels', 'fallbackProfiles', 'favoriteModels', 'favoriteModelsOnly', 'modelMatrix', 'fallbackAuto',\n ] as const;\n\n const prefSnapshot = (): Record<string, unknown> => {\n const snapshot: Record<string, unknown> = {};\n for (const k of PREF_KEYS) {\n if (k in context.meta) snapshot[k] = context.meta[k];\n }\n return snapshot;\n };\n\n /**\n * Persist pref changes into the global config.json — the SAME keys the\n * TUI settings picker writes — so a toggle made in the browser survives\n * restarts and is visible to the CLI/TUI (and vice versa on next boot).\n * Best-effort and serialized behind configWriteLock (shared with the\n * provider/key handlers); failures log but never break the WS reply.\n */\n const persistPrefsToConfig = async (payload: Record<string, unknown>): Promise<void> => {\n await updateGlobalConfig((decrypted) => {\n const autonomyCfg = (decrypted.autonomy as Record<string, unknown>) ?? {};\n let autonomyTouched = false;\n const setAutonomy = (key: string, val: unknown): void => {\n autonomyCfg[key] = val;\n autonomyTouched = true;\n };\n if (\n typeof payload['autonomy'] === 'string' &&\n ['off', 'suggest', 'auto'].includes(payload['autonomy'])\n ) {\n setAutonomy('defaultMode', payload['autonomy']);\n }\n if (typeof payload['autonomyDelayMs'] === 'number') setAutonomy('autoProceedDelayMs', payload['autonomyDelayMs']);\n if (typeof payload['autoProceedMaxIterations'] === 'number') setAutonomy('autoProceedMaxIterations', payload['autoProceedMaxIterations']);\n if (typeof payload['yolo'] === 'boolean') setAutonomy('yolo', payload['yolo']);\n if (typeof payload['chime'] === 'boolean') setAutonomy('chime', payload['chime']);\n if (typeof payload['confirmExit'] === 'boolean') setAutonomy('confirmExit', payload['confirmExit']);\n if (typeof payload['streamFleet'] === 'boolean') setAutonomy('streamFleet', payload['streamFleet']);\n if (typeof payload['enhanceEnabled'] === 'boolean') setAutonomy('enhance', payload['enhanceEnabled']);\n if (typeof payload['enhanceDelayMs'] === 'number') setAutonomy('enhanceDelayMs', payload['enhanceDelayMs']);\n if (typeof payload['enhanceLanguage'] === 'string') setAutonomy('enhanceLanguage', payload['enhanceLanguage']);\n if (autonomyTouched) decrypted.autonomy = autonomyCfg;\n\n if (typeof payload['nextPrediction'] === 'boolean') decrypted.nextPrediction = payload['nextPrediction'];\n\n // Global fallback model chain (top-level config). Read live by the leader's\n // fallback extension each turn (effectiveFallbackChain), so it takes effect\n // without a restart.\n if (Array.isArray(payload['fallbackModels'])) decrypted.fallbackModels = payload['fallbackModels'];\n if (\n payload['fallbackProfiles'] &&\n typeof payload['fallbackProfiles'] === 'object' &&\n !Array.isArray(payload['fallbackProfiles'])\n ) {\n decrypted.fallbackProfiles = payload['fallbackProfiles'] as Record<string, string[]>;\n }\n if (Array.isArray(payload['favoriteModels'])) decrypted.favoriteModels = payload['favoriteModels'];\n if (typeof payload['favoriteModelsOnly'] === 'boolean')\n decrypted.favoriteModelsOnly = payload['favoriteModelsOnly'];\n if (\n payload['modelMatrix'] &&\n typeof payload['modelMatrix'] === 'object' &&\n !Array.isArray(payload['modelMatrix'])\n ) {\n decrypted.modelMatrix = payload['modelMatrix'] as typeof decrypted.modelMatrix;\n }\n if (typeof payload['fallbackAuto'] === 'boolean') decrypted.fallbackAuto = payload['fallbackAuto'];\n\n const FEATURE_MAP: Record<string, string> = {\n featureMcp: 'mcp',\n featurePlugins: 'plugins',\n featureMemory: 'memory',\n featureSkills: 'skills',\n featureModelsRegistry: 'modelsRegistry',\n };\n for (const [prefKey, cfgKey] of Object.entries(FEATURE_MAP)) {\n if (typeof payload[prefKey] === 'boolean') {\n const feats = (decrypted.features as Record<string, unknown>) ?? {};\n feats[cfgKey] = payload[prefKey];\n decrypted.features = feats;\n }\n }\n\n if (\n typeof payload['contextAutoCompact'] === 'boolean' ||\n typeof payload['contextStrategy'] === 'string' ||\n typeof payload['contextMode'] === 'string'\n ) {\n const ctxCfg = (decrypted.context as Record<string, unknown>) ?? {};\n if (typeof payload['contextAutoCompact'] === 'boolean') ctxCfg.autoCompact = payload['contextAutoCompact'];\n if (typeof payload['contextStrategy'] === 'string') ctxCfg.strategy = payload['contextStrategy'];\n if (typeof payload['contextMode'] === 'string') ctxCfg.mode = payload['contextMode'];\n decrypted.context = ctxCfg;\n }\n if (typeof payload['tokenSavingTier'] === 'string') {\n const featsCfg = (decrypted.features as Record<string, unknown>) ?? {};\n featsCfg.tokenSavingMode = payload['tokenSavingTier'];\n decrypted.features = featsCfg;\n }\n if (typeof payload['maxConcurrent'] === 'number') {\n decrypted.maxConcurrent = payload['maxConcurrent'];\n }\n if (typeof payload['titleAnimation'] === 'boolean') {\n const autoCfg = (decrypted.autonomy as Record<string, unknown>) ?? {};\n autoCfg.terminalTitleAnimation = payload['titleAnimation'];\n decrypted.autonomy = autoCfg;\n }\n if (typeof payload['logLevel'] === 'string') {\n const logCfg = (decrypted.log as Record<string, unknown>) ?? {};\n logCfg.level = payload['logLevel'];\n decrypted.log = logCfg;\n }\n if (typeof payload['auditLevel'] === 'string') {\n const sessionCfg = (decrypted.session as Record<string, unknown>) ?? {};\n sessionCfg.auditLevel = payload['auditLevel'];\n decrypted.session = sessionCfg;\n }\n if (typeof payload['indexOnStart'] === 'boolean') {\n const indexingCfg = (decrypted.indexing as Record<string, unknown>) ?? {};\n indexingCfg.onSessionStart = payload['indexOnStart'];\n decrypted.indexing = indexingCfg;\n }\n if (typeof payload['maxIterations'] === 'number') {\n const toolsCfg = (decrypted.tools as Record<string, unknown>) ?? {};\n toolsCfg.maxIterations = payload['maxIterations'];\n decrypted.tools = toolsCfg;\n }\n\n const hqTouched =\n typeof payload['hqEnabled'] === 'boolean' ||\n typeof payload['hqUrl'] === 'string' ||\n typeof payload['hqToken'] === 'string' ||\n typeof payload['hqRawContent'] === 'boolean';\n if (hqTouched) {\n const hqCfg = (decrypted.hq as Record<string, unknown>) ?? {};\n if (typeof payload['hqEnabled'] === 'boolean') hqCfg.enabled = payload['hqEnabled'];\n if (typeof payload['hqUrl'] === 'string') hqCfg.url = payload['hqUrl'];\n if (typeof payload['hqToken'] === 'string') hqCfg.token = payload['hqToken'];\n if (typeof payload['hqRawContent'] === 'boolean') hqCfg.rawContent = payload['hqRawContent'];\n decrypted.hq = hqCfg;\n }\n\n const tgTouched =\n typeof payload['tgSessionEnd'] === 'boolean' ||\n typeof payload['tgDelegate'] === 'boolean' ||\n typeof payload['tgLongToolMs'] === 'number';\n if (tgTouched) {\n const ext = (decrypted.extensions as Record<string, Record<string, unknown>>) ?? {};\n const tg = ext['telegram'] ?? {};\n if (typeof payload['tgSessionEnd'] === 'boolean') {\n tg['notifyOnSessionEnd'] = payload['tgSessionEnd'];\n }\n if (typeof payload['tgDelegate'] === 'boolean') {\n tg['notifyOnDelegate'] = payload['tgDelegate'];\n }\n if (typeof payload['tgLongToolMs'] === 'number') {\n tg['longToolThresholdMs'] = payload['tgLongToolMs'];\n }\n ext['telegram'] = tg;\n decrypted.extensions = ext;\n }\n\n // Reasoning / cache runtime controls → Config.modelRuntime\n const modelRuntimeTouched =\n typeof payload['reasoningMode'] === 'string' ||\n typeof payload['reasoningEffort'] === 'string' ||\n typeof payload['reasoningPreserve'] === 'boolean' ||\n typeof payload['cacheTtl'] === 'string';\n if (modelRuntimeTouched) {\n const mr = (decrypted.modelRuntime as Record<string, unknown>) ?? {};\n const reasoning = (mr.reasoning as Record<string, unknown>) ?? {};\n if (typeof payload['reasoningMode'] === 'string') reasoning.mode = payload['reasoningMode'];\n if (typeof payload['reasoningEffort'] === 'string') reasoning.effort = payload['reasoningEffort'];\n if (typeof payload['reasoningPreserve'] === 'boolean') reasoning.preserve = payload['reasoningPreserve'];\n mr.reasoning = reasoning;\n if (typeof payload['cacheTtl'] === 'string' && payload['cacheTtl'] !== 'default') {\n mr.cache = { ttl: payload['cacheTtl'] };\n } else if (payload['cacheTtl'] === 'default') {\n delete mr.cache;\n }\n decrypted.modelRuntime = mr;\n }\n }, 'prefs');\n };\n\n // Pipelines\n const pipelines = createDefaultPipelines();\n // Collaboration bus — process-singleton pause/resume signal. The\n // middleware below hooks it into the toolCall pipeline so a\n // `controller` participant can halt the agent before the next tool\n // call (Phase 3 of idea #13). The same bus instance is shared with\n // the CollaborationWebSocketHandler so client pause/resume requests\n // are routed to the kernel.\n const collabBus = new CollaborationBus();\n // prepend (not use) — the pause check must run first, before any\n // permission/retry middleware that would otherwise proceed.\n const collabPause = collabPauseMiddleware(collabBus, { logger });\n Object.defineProperty(collabPause, 'name', { value: 'collab-pause' });\n pipelines.toolCall.prepend(collabPause as never);\n // Phase 4 — collab-inject. Installed AFTER collab-pause so the\n // controller can pause + inject before the next tool runs. The\n // middleware checks the bus's injection queue and splices a\n // synthetic tool_result when a controller has queued one for\n // the current toolUse.id.\n const collabInject = collabInjectMiddleware(collabBus, { logger });\n Object.defineProperty(collabInject, 'name', { value: 'collab-inject' });\n pipelines.toolCall.prepend(collabInject as never);\n // Design Studio — per-turn UI-intent detection + kit-menu injection, so the\n // WebUI host gets the same auto-trigger behavior as the CLI/TUI.\n installDesignStudioMiddleware({ pipelines, ctx: context });\n const codebaseIndexing = setupWebUICodebaseIndexing({\n config,\n context,\n projectRoot,\n logger,\n });\n // Compactor — honors config.context.strategy ('hybrid' default, lossless\n // rules; 'intelligent'/'selective' resolve their provider from ctx at\n // compact()-time). eliseThreshold is a TOKEN COUNT (not a fraction).\n const compactor = createStrategyCompactor({\n strategy: config.context?.strategy,\n preserveK: config.context?.preserveK ?? 10,\n eliseThreshold: config.context?.eliseThreshold ?? 2000,\n summarizerModel: config.context?.summarizerModel,\n llmSelector: config.context?.llmSelector,\n });\n\n // Auto-compaction\n let autoCompactor: AutoCompactionMiddleware | undefined;\n if (config.context?.autoCompact !== false) {\n // Priority: explicit override → models.dev per-model window → family default.\n // The catalog lookup matters for openai-compatible providers (OpenRouter,\n // Groq, …) whose family default is 0; without it auto-compaction would be\n // disabled even though the model has a real published window. Mirrors\n // updateAutoCompactionMaxContext below.\n let effectiveMaxContext = config.context?.effectiveMaxContext ?? 0;\n if (!effectiveMaxContext) {\n try {\n const m = await modelsRegistry.getModel(provider.id, context.model);\n effectiveMaxContext = m?.capabilities?.maxContext ?? 0;\n } catch {\n // best-effort: fall through to provider capability\n }\n }\n if (!effectiveMaxContext) effectiveMaxContext = provider.capabilities.maxContext;\n autoCompactor = new AutoCompactionMiddleware(\n compactor,\n effectiveMaxContext,\n (ctx) =>\n estimateRequestTokensCalibrated(\n ctx.messages,\n ctx.systemPrompt,\n ctx.tools ?? [],\n `${ctx.provider?.id ?? 'unknown'}/${ctx.model}`,\n ).total,\n {\n warn: initialContextPolicy.thresholds.warn,\n soft: initialContextPolicy.thresholds.soft,\n hard: initialContextPolicy.thresholds.hard,\n },\n {\n events,\n aggressiveOn: initialContextPolicy.aggressiveOn,\n policyProvider: (ctx) => {\n const policy = ctx.meta['contextWindowPolicy'];\n return policy && typeof policy === 'object'\n ? (policy as ReturnType<typeof resolveContextWindowPolicy>)\n : initialContextPolicy;\n },\n },\n );\n pipelines.contextWindow.use({ name: 'AutoCompaction', handler: autoCompactor.handler() });\n }\n\n /** Refresh AutoCompactionMiddleware denominator when the active model changes. */\n async function updateAutoCompactionMaxContext(newProvider: Provider): Promise<void> {\n await modelsRegistry.refresh().catch((err) => {\n logger.warn(\n `models.dev refresh failed for ${newProvider.id}/${context.model}: ${toErrorMessage(err)}; using cached catalog`,\n );\n });\n let newMaxContext = config.context?.effectiveMaxContext ?? newProvider.capabilities.maxContext;\n try {\n const m = await modelsRegistry.getModel(newProvider.id, context.model);\n newMaxContext = m?.capabilities?.maxContext ?? newMaxContext;\n } catch {\n // best-effort: use provider capability\n }\n newProvider.capabilities.maxContext = newMaxContext;\n modelCapabilitiesRef.current =\n newMaxContext > 0\n ? {\n maxContextTokens: newMaxContext,\n supportsTools: !!newProvider.capabilities.tools,\n supportsVision: !!newProvider.capabilities.vision,\n supportsReasoning: !!newProvider.capabilities.reasoning,\n }\n : undefined;\n if (newMaxContext > 0) {\n context.meta['effectiveMaxContext'] = newMaxContext;\n autoCompactor?.setMaxContext(newMaxContext);\n autoCompactor?.setEnabled(config.context?.autoCompact !== false);\n } else {\n delete context.meta['effectiveMaxContext'];\n autoCompactor?.setEnabled(false);\n }\n events.emit('ctx.max_context', {\n providerId: newProvider.id,\n modelId: context.model,\n maxContext: newMaxContext,\n });\n }\n\n // Agent\n const secretScrubber = container.resolve(TOKENS.SecretScrubber);\n const renderer = container.has(TOKENS.Renderer) ? container.resolve(TOKENS.Renderer) : undefined;\n const permissionPolicy = container.resolve(TOKENS.PermissionPolicy);\n const toolExecutor = new ToolExecutor(toolRegistry, {\n permissionPolicy,\n secretScrubber,\n renderer,\n events,\n confirmAwaiter: undefined,\n iterationTimeoutMs: config.tools?.iterationTimeoutMs ?? DEFAULT_TOOLS_CONFIG.iterationTimeoutMs,\n perIterationOutputCapBytes:\n config.tools?.perIterationOutputCapBytes ?? DEFAULT_TOOLS_CONFIG.perIterationOutputCapBytes,\n tracer: undefined,\n });\n\n // Mailbox bridge discovery — fire-and-forget. Now that the lock\n // primitives live in `@wrongstack/core` (see commit after\n // `f1720ed0`), the webui can read the per-project\n // `.mailbox-bridge.lock` directly without a cli dependency. We\n // don't spawn a bridge here — the cli surface (REPL/TUI) does that\n // via the auto-bootstrap wiring; we just join whatever's running\n // for this project and stash the handle on ctx.meta so downstream\n // HTTP surfaces (mailbox routes, external-agent proxy) can find it.\n //\n // Best-effort: a failed discovery never blocks the WebUI from\n // starting. If no bridge is running, we log a breadcrumb so the\n // user knows to start `wstack mailbox serve` (or any CLI surface)\n // to enable external-agent connectivity.\n const webuiLogger = container.resolve(TOKENS.Logger);\n void discoverMailboxBridgeForWebui({\n projectRoot,\n config,\n logger: webuiLogger,\n ctx: context,\n }).catch((err: unknown) => {\n webuiLogger.warn('mailbox bridge discovery threw on webui boot', {\n err: err instanceof Error ? err.message : String(err),\n });\n });\n\n const agent = new Agent({\n container,\n tools: toolRegistry,\n providers: providerRegistry,\n events,\n pipelines,\n context,\n maxIterations: config.tools?.maxIterations ?? DEFAULT_TOOLS_CONFIG.maxIterations,\n iterationTimeoutMs: config.tools?.iterationTimeoutMs ?? DEFAULT_TOOLS_CONFIG.iterationTimeoutMs,\n executionStrategy:\n config.tools?.defaultExecutionStrategy ?? DEFAULT_TOOLS_CONFIG.defaultExecutionStrategy,\n perIterationOutputCapBytes:\n config.tools?.perIterationOutputCapBytes ?? DEFAULT_TOOLS_CONFIG.perIterationOutputCapBytes,\n confirmAwaiter: undefined,\n toolExecutor,\n });\n console.log('[WebUI] Agent initialized');\n\n // ── Brain — policy → LLM tiered decision layer ─────────────────────────\n // Same positioning as the CLI: one Brain per process at\n // TOKENS.BrainArbiter. The WebUI has no human-escalation prompt yet, so\n // the chain stops at the LLM tier — `ask_human` decisions surface to the\n // browser as `brain.event` WS messages and the caller's fallback applies.\n const brainSettings: { maxAutoRisk: BrainAutoRisk } = { maxAutoRisk: 'medium' };\n // Lazy wrapper so the LLM tier always sees the LIVE provider/model —\n // both are swapped at runtime via the settings panel.\n const autonomousBrain: BrainArbiter = {\n decide: (request) =>\n createAutonomyBrain({\n provider,\n model: context.model,\n maxAutoRisk: 'all', // the tiered ceiling gates risk — keep inner permissive\n }).decide(request),\n };\n const brain = new ObservableBrainArbiter(\n createTieredBrainArbiter({\n policy: new DefaultBrainArbiter(),\n autonomous: autonomousBrain,\n getMaxAutoRisk: () => brainSettings.maxAutoRisk,\n }),\n events,\n );\n container.bind(TOKENS.BrainArbiter, () => brain);\n\n // Self-activation: watch for tool-failure streaks / error storms and\n // steer this session's leader via the shared project mailbox. `session`\n // is mutable (swapped on /new and resume) — read it at send time so the\n // steer always targets the LIVE session's leader identity.\n const brainMailbox = new GlobalMailbox(wpaths.projectDir, events);\n const brainMonitor = new BrainMonitor({\n events,\n brain,\n intervene: async ({ subject, body }) => {\n const tag = mailboxSessionTag(session.id);\n await brainMailbox.send({\n from: `brain@${tag}`,\n to: `leader@${tag}`,\n type: 'steer',\n subject,\n body,\n priority: 'high',\n });\n },\n });\n brainMonitor.start();\n console.log('[WebUI] Brain initialized (tiered policy → LLM, monitor active)');\n\n // Decision log for the /brain command — last 20 decisions, newest last.\n const brainLog: Array<{ at: number; kind: string; question: string; outcome: string }> = [];\n const pushBrainLog = (entry: (typeof brainLog)[number]) => {\n brainLog.push(entry);\n if (brainLog.length > 20) brainLog.shift();\n };\n events.on('brain.decision_answered', (e) =>\n pushBrainLog({\n at: e.at,\n kind: 'answered',\n question: e.request.question,\n outcome: e.decision.type === 'answer' ? (e.decision.optionId ?? e.decision.text) : '',\n }),\n );\n events.on('brain.decision_ask_human', (e) =>\n pushBrainLog({ at: e.at, kind: 'ask_human', question: e.request.question, outcome: 'needs human judgement' }),\n );\n events.on('brain.decision_denied', (e) =>\n pushBrainLog({\n at: e.at,\n kind: 'denied',\n question: e.request.question,\n outcome: e.decision.type === 'deny' ? e.decision.reason : '',\n }),\n );\n events.on('brain.intervention', (e) =>\n pushBrainLog({\n at: e.at,\n kind: 'intervention',\n question: e.request.question,\n outcome: e.intervened ? 'steered the agent' : 'observed (no action)',\n }),\n );\n\n // AutoPhase handler — manages AutoPhaseRunner lifecycle via WS messages.\n // Stored under the per-project autophase dir (not the shared SDD task-graphs).\n const autoPhaseHandler = new AutoPhaseWebSocketHandler(\n agent,\n context,\n logger,\n wpaths.projectAutophase,\n events,\n projectRoot,\n );\n\n // Specs handler — FORGE-style browser of persisted SDD specs + their task\n // graphs (dependency board). Reads the shared per-project SDD stores.\n const specsHandler = new SpecsWebSocketHandler(wpaths.projectSpecs, wpaths.projectTaskGraphs);\n\n // SDD live board handler — observes a CLI-owned multi-agent run. Standalone\n // server is a different process from the run, so it polls the on-disk\n // snapshot (no shared EventBus) and steers via the control file.\n const sddBoardHandler = new SddBoardWebSocketHandler(wpaths.projectSddBoards, undefined, {\n projectRoot,\n paths: {\n projectSpecs: wpaths.projectSpecs,\n projectTaskGraphs: wpaths.projectTaskGraphs,\n projectSddSession: wpaths.projectSddSession,\n projectSddBoards: wpaths.projectSddBoards,\n },\n });\n\n // One-shot orphan sweep on boot: remove worktrees/branches a crashed or\n // abandoned SDD run left behind so they never accumulate across sessions.\n // Liveness-guarded (skips if a run is live, incl. one in another process) and\n // best-effort — fire-and-forget so it never delays server startup.\n void cleanupStaleSddWorktrees({ projectRoot, boardsDir: wpaths.projectSddBoards }).catch(\n () => undefined,\n );\n\n // SDD wizard — the interactive \"New SDD Project\" flow (goal → Q&A → spec →\n // task graph → start run). The standalone server runs the real fleet in-process\n // via the runtime light subagent factory (no @wrongstack/cli MultiAgentHost —\n // layer rule). The interview turns + run subagents share one factory.\n const sddWizardHandler = new SddWizardWebSocketHandler(\n buildSddWizardDeps({\n agent,\n events,\n projectRoot,\n brain,\n subagentFactory: makeLightSubagentFactory({\n container,\n providerRegistry,\n toolRegistry,\n session,\n projectRoot,\n }),\n paths: {\n projectSpecs: wpaths.projectSpecs,\n projectTaskGraphs: wpaths.projectTaskGraphs,\n projectSddBoards: wpaths.projectSddBoards,\n projectDir: wpaths.projectDir,\n },\n }),\n );\n\n // Worktree handler — subscribes to the shared EventBus `worktree.*` events\n // and streams live swim-lane / DAG state to connected clients. The management\n // deps add a disk-orphan scan + guarded \"clean orphans\" control.\n const worktreeHandler = new WorktreeWebSocketHandler(events, logger, {\n projectRoot,\n boardsDir: wpaths.projectSddBoards,\n });\n\n // Integrated terminal handler — per-client node-pty sessions backing the\n // WebUI terminal panel. New terminals open in the live working directory.\n const terminalHandler = new TerminalWebSocketHandler(() => workingDir, logger);\n\n // Collaboration handler — Phase 1 of idea #13. Lets a second client\n // (e.g. a senior dev) join an active agent run as a read-only\n // observer and watch a live mirror of kernel events. Annotated and\n // controller roles land in Phase 2/3. The session reader enables\n // replay-on-join for late observers.\n const collabHandler = new CollaborationWebSocketHandler(\n events,\n logger,\n sessionReader,\n annotationsStore,\n collabBus,\n );\n\n // Helper: build the rich session.start payload from current runtime state.\n // Centralised so initial connect, post-/new, and post-model.switch all\n // broadcast the same shape — frontend treats this as the single source of\n // truth for everything in the status bar (model, context window, project).\n async function sessionStartPayload(): Promise<{\n sessionId: string;\n model: string;\n provider: string;\n maxContext: number;\n /** USD per 1M input tokens (0 if unknown / free). */\n inputCost: number;\n /** USD per 1M output tokens. */\n outputCost: number;\n /** USD per 1M cache-read tokens. */\n cacheReadCost: number;\n projectName: string;\n projectRoot: string;\n cwd: string;\n mode: string;\n contextMode: string;\n }> {\n let maxContext = 0;\n let inputCost = 0;\n let outputCost = 0;\n let cacheReadCost = 0;\n try {\n const m = await modelsRegistry.getModel(config.provider, config.model);\n maxContext = m?.capabilities?.maxContext ?? 0;\n // Fall back to the provider's raw model data from the registry when the\n // resolved model has no maxContext (e.g. a user-defined or API-proxied\n // model that wasn't in the models.dev catalog). DefaultModelsRegistry\n // exposes getProvider() which gives us the model's limit.context directly.\n if (!maxContext) {\n try {\n const provider = await (\n modelsRegistry as { getProvider(id: string): Promise<{ models: Array<{ id: string; limit?: { context?: number } }> } | undefined> }\n ).getProvider(config.provider);\n const rawModel = provider?.models.find((mod) => mod.id === config.model);\n maxContext = rawModel?.limit?.context ?? 0;\n } catch {\n /* best-effort — leave maxContext at whatever the registry set it */\n }\n }\n // models.dev pricing is dollars per 1M tokens; some providers omit the\n // field for free/unmetered plans (e.g. minimax-coding-plan) — in that\n // case we report 0 and the cost chip just stays at $0.\n const rates = getCostRates(m);\n inputCost = rates.input;\n outputCost = rates.output;\n cacheReadCost = rates.cacheRead;\n } catch {\n // best-effort\n }\n return {\n sessionId: session.id,\n model: config.model,\n provider: config.provider,\n maxContext,\n inputCost,\n outputCost,\n cacheReadCost,\n projectName: path.basename(projectRoot) || projectRoot,\n projectRoot,\n cwd: workingDir,\n mode: modeId,\n contextMode: String(context.meta['contextWindowMode'] ?? DEFAULT_CONTEXT_WINDOW_MODE_ID),\n };\n }\n\n // WebSocket server(s).\n //\n // When the user keeps the default loopback bind (127.0.0.1), we ALSO open a\n // second listener on ::1 (IPv6 loopback). Reason: Chrome/Edge on Windows\n // resolve `localhost` to `[::1]` before `127.0.0.1`, so a single v4-only\n // bind causes \"ws disconnect hep\" — clients hammer the v6 socket, get\n // ECONNREFUSED, fall back to v4 inconsistently. Listening on both v4 and v6\n // loopback keeps the connection scope \"this machine only\" while removing\n // the resolution-order coin flip.\n //\n // When the user explicitly sets WS_HOST (e.g. 0.0.0.0 or a LAN IP), we\n // respect that choice exactly and don't add a second listener.\n // Generate a random WS auth token so only callers that know the token\n // can connect. Printed to console on startup; the frontend reads it from\n // the URL query param `?token=...`. Without a token, any client on the\n // network can connect and send `user_message`/`key.add`/`model.switch`.\n const wsToken = resolveAuthToken(opts.accessToken);\n // Token is delivered through the printed first-load URL and then exchanged\n // for an HttpOnly cookie by /ws-auth.\n console.log('[WebUI] WS auth token ready');\n const publicHostnames = [publicUrl, publicWsUrl]\n .map((value) => {\n if (!value) return undefined;\n try {\n return new URL(value).hostname;\n } catch {\n return undefined;\n }\n })\n .filter((value): value is string => Boolean(value));\n\n // CSWSH guard + token auth: when the user exposes the socket beyond loopback,\n // require the shared token; loopback connections bootstrap without one. The\n // policy (DNS-rebinding Host guard, constant-time token compare, loopback\n // bootstrap) lives in ./ws-auth.ts as pure functions — this closure just\n // pulls the relevant fields off the incoming request and delegates.\n const verifyClient = (info: {\n origin: string;\n secure: boolean;\n req: import('node:http').IncomingMessage;\n }) =>\n verifyWsClient({\n origin: info.origin,\n url: info.req.url ?? '',\n hostHeader: info.req.headers.host,\n remoteAddress: info.req.socket.remoteAddress,\n // C-2 fix: accept the token via the HttpOnly cookie set by\n // `/ws-auth` (preferred) OR the URL query param (non-browser\n // fallback). The cookie path closes the C-598 query-string\n // exposure class.\n cookieHeader: info.req.headers.cookie,\n wsHost,\n expectedToken: wsToken,\n requireToken,\n allowedHostnames: publicHostnames,\n allowBrowserUrlToken: Boolean(publicWsUrl),\n });\n // Cap inbound frame size (8 MiB) so a single oversized message can't exhaust\n // memory. Agent messages are small; large pastes/attachments stay well under.\n const WS_MAX_PAYLOAD = 8 * 1024 * 1024;\n const wssPrimary = new WebSocketServer({\n port: wsPort,\n host: wsHost,\n verifyClient,\n maxPayload: WS_MAX_PAYLOAD,\n } as ConstructorParameters<typeof WebSocketServer>[0]);\n const wssSecondary =\n wsHost === '127.0.0.1'\n ? new WebSocketServer({\n port: wsPort,\n host: '::1',\n verifyClient,\n maxPayload: WS_MAX_PAYLOAD,\n } as ConstructorParameters<typeof WebSocketServer>[0])\n : null;\n const clients = new Map<WebSocket, ConnectedClient>();\n\n // ── Subscribe to working directory changes from the CLI ──────────────\n // When ctx.setWorkingDir() is called from the CLI (e.g. /wd, /cd, or\n // the set_working_dir tool), update the server's workingDir reference\n // and broadcast to all connected WebUI clients so the file explorer\n // and the WorkingDirChip UI stay in sync.\n context.onWorkingDirChanged((newDir) => {\n workingDir = newDir;\n broadcast(clients, {\n type: 'working_dir.changed',\n payload: { cwd: newDir, projectRoot },\n });\n });\n\n // ── Eternal-autonomy iteration broadcast (PR 4 of Phase 2) ─────────\n // When the CLI passes `opts.subscribeEternalIteration`, hook the\n // returned observer into a WS broadcast so every connected client\n // gets a live stream of `JournalEntry` items as the engine ticks.\n // The disposer is captured and invoked on shutdown() so the CLI's\n // engine subscription is properly torn down with the webui.\n let eternalSubscription: { dispose: () => void } | null = null;\n if (opts.subscribeEternalIteration) {\n eternalSubscription = createEternalSubscription(\n opts.subscribeEternalIteration,\n broadcast,\n () => clients,\n );\n }\n\n // Per-connection message rate limiting: 60 messages per 60-second window.\n // Exceeding clients are temporarily blocked to prevent flooding.\n // Uses sessionId as the key once connected, falling back to ws for\n // pre-auth messages — prevents connection-reuse bypass.\n // Rate limit OFF by default (counted pings/list calls too and tripped during\n // normal use). Opt in via WEBUI_RATE_LIMIT=<messages-per-60s> for LAN exposure.\n const RATE_LIMIT_MESSAGES = Number.parseInt(process.env['WEBUI_RATE_LIMIT'] ?? '0', 10);\n const RATE_LIMIT_WINDOW_MS = 60_000;\n const rateLimits = new Map<string, { count: number; resetAt: number }>();\n // Per-connection id sequence. The rate-limit bucket must be keyed per\n // connection, not per sessionId (every client is created with the same\n // live `session.id`, so a sessionId key would share one bucket across all\n // tabs) and not by `String(ws)` (which is `\"[object Object]\"` for every\n // socket — identical for all connections and never matching on cleanup).\n let connSeq = 0;\n\n function checkRateLimit(_ws: WebSocket, client: ConnectedClient): boolean {\n if (RATE_LIMIT_MESSAGES <= 0) return true; // disabled\n const now = Date.now();\n const key = client.connId;\n const limit = rateLimits.get(key);\n if (!limit || now > limit.resetAt) {\n rateLimits.set(key, { count: 1, resetAt: now + RATE_LIMIT_WINDOW_MS });\n return true;\n }\n if (limit.count >= RATE_LIMIT_MESSAGES) return false;\n limit.count++;\n return true;\n }\n\n /** Holds the AbortController for the currently in-flight agent.run().\n * Non-null while the agent is running; guarded at the user_message\n * handler to prevent concurrent runs that would corrupt shared state\n * (context, agent, tokenCounter). A second user_message while running\n * is answered with an inline error instead of being queued — the\n * caller should wait for run.result. */\n let runLock: AbortController | null = null;\n\n console.log(\n `[WebUI] WebSocket server running on ws://${wsHost}:${wsPort}` +\n (wssSecondary ? ` (and ws://[::1]:${wsPort})` : ''),\n );\n\n // Pending permission confirmations. When the agent emits\n // tool.confirm_needed, we store the resolve function here keyed by\n // toolUseId. When the client sends tool.confirm_result back, we look\n // it up and resolve — unblocking the agent loop.\n const pendingConfirms = new Map<string, (d: 'yes' | 'no' | 'always' | 'deny') => void>();\n\n const handleConnection = (ws: WebSocket): void => {\n const client: ConnectedClient = {\n ws,\n sessionId: session.id,\n connectedAt: Date.now(),\n connId: `c${++connSeq}`,\n };\n clients.set(ws, client);\n\n // sessionStartPayload handles errors internally; no explicit catch needed.\n // Adding a catch would be defensive but sessionStartPayload already has try-catch.\n void sessionStartPayload()\n .then((payload) => {\n send(ws, { type: 'session.start', payload });\n })\n .catch((err) => {\n // Log at warn level since sessionStartPayload should rarely fail.\n // This prevents silent failures if internal error handling changes.\n console.warn(JSON.stringify({\n level: 'warn',\n event: 'webui.session_start_payload_failed',\n message: toErrorMessage(err),\n timestamp: new Date().toISOString(),\n }));\n });\n\n // Register this client with the AutoPhase handler so it receives phase events\n autoPhaseHandler.addClient(ws);\n // …and the specs handler for the FORGE dependency board.\n specsHandler.addClient(ws);\n // …and the live SDD multi-agent board handler.\n sddBoardHandler.addClient(ws);\n sddWizardHandler.addClient(ws);\n // …and the worktree handler for live isolation lanes.\n worktreeHandler.addClient(ws);\n // …and the collaboration handler for read-only session observation.\n collabHandler.addClient(ws);\n // …and the terminal handler for the integrated terminal panel.\n terminalHandler.addClient(ws);\n\n ws.on('message', async (data) => {\n if (!checkRateLimit(ws, client)) {\n send(ws, {\n type: 'error',\n payload: {\n phase: 'rate_limit',\n message: 'Too many messages. Please wait before sending more.',\n },\n });\n return;\n }\n try {\n // Prototype pollution guard: reject messages whose root-level payload\n // contains __proto__, constructor, or prototype keys. These could\n // cause prototype pollution via Object.assign({}, payload) or\n // spread {...payload}. The top-level check below catches the\n // dangerous keys; nested payload sub-objects are low-risk since\n // handlers don't do deep property merges.\n const rawObj = JSON.parse(data.toString());\n if (typeof rawObj === 'object' && rawObj !== null) {\n const obj = rawObj as Record<string, unknown>;\n // Own-property check only: the `in` operator walks the prototype\n // chain, so `'constructor' in obj` / `'__proto__' in obj` are true\n // for EVERY plain object and would reject all legitimate messages.\n // A malicious JSON payload surfaces these as OWN keys (V8 materializes\n // a literal \"__proto__\" data property from JSON), which Object.hasOwn\n // detects without the false positives.\n if (\n Object.hasOwn(obj, '__proto__') ||\n Object.hasOwn(obj, 'constructor') ||\n Object.hasOwn(obj, 'prototype')\n ) {\n send(ws, {\n type: 'error',\n payload: { phase: 'parse', message: 'Invalid message object' },\n });\n } else {\n await handleMessage(ws, client, rawObj as never as WSClientMessage);\n }\n } else {\n // Non-object JSON (array, string, number…) — pass through\n await handleMessage(ws, client, rawObj as WSClientMessage);\n }\n } catch (err) {\n console.error(JSON.stringify({\n level: 'error',\n event: 'webui.ws_message_parse_failed',\n message: toErrorMessage(err),\n timestamp: new Date().toISOString(),\n }));\n }\n });\n\n ws.on('close', () => {\n const closing = clients.get(ws);\n clients.delete(ws);\n if (closing) rateLimits.delete(closing.connId);\n // If the client disconnects while a permission prompt is pending,\n // resolve all pending confirms with 'no' so the agent loop doesn't\n // hang forever waiting for a response that will never come.\n if (pendingConfirms.size > 0) {\n for (const [id, resolve] of pendingConfirms) {\n resolve('no');\n pendingConfirms.delete(id);\n }\n }\n });\n\n ws.on('error', (err) => {\n // Without this handler an errored socket would crash the process.\n console.warn(JSON.stringify({\n level: 'warn',\n event: 'webui.client_socket_error',\n message: err.message,\n timestamp: new Date().toISOString(),\n }));\n });\n };\n\n // Audit-level-aware session log bridge — persists tool/error/provider\n // events to the session JSONL with the same contract as the CLI. The\n // getter form resolves the CURRENT writer on every append so events\n // follow session.new / session.resume / projects.select swaps.\n const sessionLogging = resolveSessionLoggingConfig(\n config as never as Parameters<typeof resolveSessionLoggingConfig>[0],\n );\n const sessionBridge = createSessionEventBridge(\n () => context.session ?? session,\n sessionLogging.auditLevel,\n { sampling: sessionLogging.sampling },\n );\n\n let eventsArmed = false;\n let disposeEvents: (() => void) | null = null;\n // Captured from setupEvents so `POST /api/fleet/ping` can trigger an\n // immediate fleet re-broadcast (push-on-write from a TUI/REPL).\n let fleetBroadcast: (() => Promise<void>) | null = null;\n const armOnce = (label: string): void => {\n if (eventsArmed) return;\n eventsArmed = true;\n console.log(`[WebUI] Backend ready (${label})`);\n disposeEvents = setupEvents({\n events, broadcast, clients, config, context, pendingConfirms, globalConfigPath, sessionBridge, wpaths, watcherMetrics,\n onFleetBroadcaster: (fn) => { fleetBroadcast = fn; },\n });\n };\n\n wssPrimary.on('listening', () => armOnce(`${wsHost}:${wsPort}`));\n wssPrimary.on('connection', handleConnection);\n wssPrimary.on('error', (err) => {\n console.error(JSON.stringify({\n level: 'error',\n event: 'webui.ws_server_error',\n host: wsHost,\n message: toErrorMessage(err),\n timestamp: new Date().toISOString(),\n }));\n });\n\n if (wssSecondary) {\n wssSecondary.on('listening', () => armOnce(`::1:${wsPort}`));\n wssSecondary.on('connection', handleConnection);\n wssSecondary.on('error', (err: NodeJS.ErrnoException) => {\n // Best-effort secondary: if IPv6 loopback isn't available on this host\n // (e.g. disabled in OS), just log and continue. Primary v4 is enough.\n if (err.code === 'EAFNOSUPPORT' || err.code === 'EADDRNOTAVAIL') {\n console.warn(JSON.stringify({\n level: 'warn',\n event: 'webui.ipv6_unavailable',\n code: err.code,\n message: err.message,\n timestamp: new Date().toISOString(),\n }));\n } else {\n console.error(JSON.stringify({\n level: 'error',\n event: 'webui.ws_server_error',\n host: '::1',\n message: err.message,\n timestamp: new Date().toISOString(),\n }));\n }\n });\n }\n\n // ── Project manifest helpers ──────────────────────────────────────────\n\n /**\n * Idempotent manifest registration (mirrors the CLI's\n * touchProjectInManifest): create the projects.json entry when missing,\n * refresh lastSeen/lastWorkingDir when present.\n */\n async function touchProjectEntry(root: string, workDir?: string): Promise<void> {\n const resolved = path.resolve(root);\n const manifest = await loadManifest(globalConfigPath);\n const now = new Date().toISOString();\n const existing = manifest.projects.find((p) => path.resolve(p.root) === resolved);\n if (existing) {\n existing.lastSeen = now;\n if (workDir) existing.lastWorkingDir = path.resolve(workDir);\n } else {\n manifest.projects.push({\n name: path.basename(resolved),\n root: resolved,\n slug: generateProjectSlug(resolved),\n createdAt: now,\n lastSeen: now,\n lastWorkingDir: workDir ? path.resolve(workDir) : undefined,\n });\n }\n await saveManifest(manifest, globalConfigPath);\n await ensureProjectDataDir(generateProjectSlug(resolved), globalConfigPath);\n }\n\n function makeWorklistContext(): WorklistContext {\n return {\n context: {\n todos: context.todos,\n meta: context.meta as Record<string, unknown>,\n session: context.session ? { id: context.session.id } : null,\n state: context.state,\n },\n send: (w, m) => send(w, m),\n broadcast: (m) => broadcast(clients, m),\n };\n }\n\n let providerRoutes: ProviderRouteHandlers;\n let sessionRoutes: SessionRouteHandlers;\n let projectRoutes: ProjectRouteHandlers;\n let modeRoutes: ModeRouteHandlers;\n let prefsRoutes: PrefsRouteHandlers;\n let shellGitRoutes: ShellGitRouteHandlers;\n let mailboxRoutes: MailboxRouteHandlers;\n let mcpRoutes: McpRouteHandlers;\n let brainRoutes: BrainRouteHandlers;\n let autoPhaseRoutes: AutoPhaseRouteHandlers;\n let specsRoutes: SpecsRouteHandlers;\n let sddBoardRoutes: SddBoardRouteHandlers;\n let sddWizardRoutes: SddWizardRouteHandlers;\n\n async function handleMessage(\n ws: WebSocket,\n _client: ConnectedClient,\n msg: WSClientMessage,\n ): Promise<void> {\n if (await handleProviderRoute(ws, msg, providerRoutes)) return;\n if (await handleSessionRoute(ws, msg, sessionRoutes)) return;\n if (await handleProjectRoute(ws, msg, projectRoutes)) return;\n if (await handleModeRoute(ws, msg, modeRoutes)) return;\n if (await handlePrefsRoute(ws, msg, prefsRoutes)) return;\n if (await handleShellGitRoute(ws, msg, shellGitRoutes)) return;\n if (await handleMailboxRoute(ws, msg, mailboxRoutes)) return;\n if (await handleMcpRoute(ws, msg, mcpRoutes)) return;\n if (await handleBrainRoute(ws, msg, brainRoutes)) return;\n if (await handleAutoPhaseRoute(ws, msg, autoPhaseRoutes)) return;\n if (await handleSpecsRoute(ws, msg, specsRoutes)) return;\n if (await handleSddBoardRoute(ws, msg, sddBoardRoutes)) return;\n if (await handleSddWizardRoute(ws, msg, sddWizardRoutes)) return;\n if (\n msg.type.startsWith('worktree.') &&\n (await worktreeHandler.handleMessage(msg as { type: string; payload?: Record<string, unknown> }))\n )\n return;\n\n switch (msg.type) {\n // Collaboration messages short-circuit the user/agent flow.\n // They don't touch runLock, the agent loop, or the message queue —\n // they're pure transport for the live observer mirror.\n case 'collab.join':\n case 'collab.leave':\n case 'collab.annotate':\n case 'collab.resolve':\n case 'collab.request_pause':\n case 'collab.resume':\n case 'collab.grant_control':\n case 'collab.inject_tool': {\n collabHandler.handleMessage(ws, msg as { type: string; payload?: unknown | undefined });\n return;\n }\n // Integrated terminal — interactive pty transport, bypasses the agent loop.\n case 'terminal.create':\n case 'terminal.input':\n case 'terminal.resize':\n case 'terminal.close': {\n terminalHandler.handleMessage(ws, msg);\n return;\n }\n case 'user_message': {\n const content = (msg as { payload: { content: string } }).payload.content;\n\n // Guard against concurrent agent runs — a second user_message while\n // the agent is already processing would kick off two agent.run()\n // calls on the same shared context/agent, leading to corrupted\n // state (duplicate tool bubbles, mixed text_delta streams, token\n // counter undercount). Reject with an inline error; the frontend\n // should wait for run.result before sending the next message.\n if (runLock) {\n send(ws, {\n type: 'error',\n payload: {\n phase: 'user_message',\n message: 'Agent is already processing a request. Wait for the current run to finish.',\n },\n });\n break;\n }\n\n runLock = new AbortController();\n // Capture so the finally block only clears its own lock — a\n // second race could set a new runLock between await and finally.\n const thisRun = runLock;\n\n try {\n // Read maxIterations from context.meta so the webui settings\n // panel can adjust the cap dynamically without restarting.\n const maxIt = typeof context.meta['maxIterations'] === 'number'\n ? context.meta['maxIterations']\n : undefined;\n const result = await agent.run(content, { signal: thisRun.signal, maxIterations: maxIt });\n send(ws, {\n type: 'run.result',\n payload: {\n status: result.status,\n iterations: result.iterations,\n finalText: result.finalText,\n error: result.error\n ? {\n code: result.error.code,\n message: result.error.message,\n recoverable: result.error.recoverable,\n }\n : undefined,\n },\n });\n } catch (err) {\n send(ws, {\n type: 'error',\n payload: {\n phase: 'agent.run',\n message: errMessage(err),\n },\n });\n } finally {\n // Only clear runLock if it's still ours — otherwise we'd wipe a\n // newer run's controller set after we returned.\n if (runLock === thisRun) {\n runLock = null;\n }\n }\n break;\n }\n\n case 'tool.confirm_result': {\n const { id, decision } = (\n msg as { payload: { id: string; decision: 'yes' | 'no' | 'always' | 'deny' } }\n ).payload;\n const resolve = pendingConfirms.get(id);\n if (resolve) {\n pendingConfirms.delete(id);\n resolve(decision);\n }\n break;\n }\n\n case 'abort':\n runLock?.abort();\n broadcast(clients, { type: 'error', payload: { phase: 'abort', message: 'User aborted' } });\n break;\n\n case 'ping':\n send(ws, { type: 'pong', payload: {} });\n break;\n\n case 'tools.list': {\n // Full tool registry dump for the /tools inspect view. We surface\n // name, description, and schema-derived param names so the user\n // can tell at a glance which tools the model can call right now.\n const list = toolRegistry.list().map((t) => {\n const schema =\n (t as { inputSchema?: { properties?: Record<string, unknown> } }).inputSchema ?? {};\n const params = schema.properties ? Object.keys(schema.properties) : [];\n return {\n name: t.name,\n description: (t as { description?: string | undefined }).description ?? '',\n params,\n };\n });\n send(ws, { type: 'tools.list', payload: { tools: list } });\n break;\n }\n\n // ── Memory operations — delegated to shared handlers (memory-handlers.ts) ──\n case 'memory.list':\n return handleMemoryList(ws, memoryStore);\n case 'memory.remember':\n return handleMemoryRemember(ws, msg, memoryStore);\n case 'memory.forget':\n return handleMemoryForget(ws, msg, memoryStore);\n\n // ── MCP operations — delegated to shared handlers (mcp-handlers.ts),\n // backed by the live MCPRegistry constructed above. Routed via\n // handleMcpRoute (see mcpRoutes = { ... } below). These case arms\n // are unreachable but left as tripwires for any future regression\n // where the route chain stops claiming 'mcp.*'. If you see one\n // fire, fix the dispatch order in the handleMessage chain above.\n case 'mcp.list':\n throw new Error('handleMcpRoute did not claim mcp.list — check chain order');\n case 'mcp.add':\n throw new Error('handleMcpRoute did not claim mcp.add — check chain order');\n case 'mcp.update':\n throw new Error('handleMcpRoute did not claim mcp.update — check chain order');\n case 'mcp.remove':\n throw new Error('handleMcpRoute did not claim mcp.remove — check chain order');\n case 'mcp.enable':\n throw new Error('handleMcpRoute did not claim mcp.enable — check chain order');\n case 'mcp.disable':\n throw new Error('handleMcpRoute did not claim mcp.disable — check chain order');\n case 'mcp.sleep':\n throw new Error('handleMcpRoute did not claim mcp.sleep — check chain order');\n case 'mcp.wake':\n throw new Error('handleMcpRoute did not claim mcp.wake — check chain order');\n case 'mcp.restart':\n throw new Error('handleMcpRoute did not claim mcp.restart — check chain order');\n case 'mcp.discover':\n throw new Error('handleMcpRoute did not claim mcp.discover — check chain order');\n\n // Skills — full request→response cycle lives in skills-handlers.ts\n // (shared with the CLI's embedded server). skillsCtx is the closed-over\n // loader/installer/projectRoot the handlers need.\n case 'skills.list':\n await handleSkillsList(ws, { skillLoader, skillInstaller, projectRoot });\n break;\n case 'skills.content':\n await handleSkillsContent(ws, { skillLoader, skillInstaller, projectRoot }, msg);\n break;\n case 'skills.install':\n await handleSkillsInstall(ws, { skillLoader, skillInstaller, projectRoot }, msg);\n break;\n case 'skills.uninstall':\n await handleSkillsUninstall(ws, { skillLoader, skillInstaller, projectRoot }, msg);\n break;\n case 'skills.update':\n await handleSkillsUpdate(ws, { skillLoader, skillInstaller, projectRoot }, msg);\n break;\n case 'skills.create':\n await handleSkillsCreate(ws, { skillLoader, skillInstaller, projectRoot }, msg);\n break;\n case 'skills.edit':\n await handleSkillsEdit(ws, { skillLoader, skillInstaller, projectRoot }, msg);\n break;\n case 'skills.export':\n await handleSkillsExport(ws, { skillLoader, skillInstaller, projectRoot });\n break;\n\n // Prompt library — shared handlers (prompts-handlers.ts).\n case 'prompts.list':\n await handlePromptsList(ws, promptsCtx);\n break;\n case 'prompts.search':\n await handlePromptsSearch(ws, promptsCtx, msg);\n break;\n case 'prompts.content':\n await handlePromptsContent(ws, promptsCtx, msg);\n break;\n case 'prompts.favorite':\n await handlePromptsFavorite(ws, promptsCtx, msg);\n break;\n case 'prompts.create':\n await handlePromptsCreate(ws, promptsCtx, msg);\n break;\n case 'prompts.used':\n await handlePromptsUsed(ws, promptsCtx, msg);\n break;\n case 'prompts.recent':\n await handlePromptsRecent(ws, promptsCtx);\n break;\n\n // Design Studio — shared handlers (design-handlers.ts). agentMeta is the\n // live context so design.use pins the active kit for the next turn.\n case 'design.list':\n await handleDesignList(ws, { projectRoot, agentMeta: context });\n break;\n case 'design.use':\n await handleDesignUse(ws, { projectRoot, agentMeta: context }, msg);\n break;\n case 'design.state':\n await handleDesignState(ws, { projectRoot, agentMeta: context });\n break;\n case 'design.set':\n await handleDesignSet(ws, { projectRoot, agentMeta: context }, msg);\n break;\n case 'design.materialize':\n await handleDesignMaterialize(ws, { projectRoot, agentMeta: context }, msg);\n break;\n case 'design.verify':\n await handleDesignVerify(ws, { projectRoot, agentMeta: context });\n break;\n\n case 'diag.get': {\n // Snapshot of the moving parts so the user can debug \"why is X\n // not working?\" without diving into the server logs.\n const usage = tokenCounter.total();\n send(ws, {\n type: 'diag.get',\n payload: {\n provider: config.provider,\n model: config.model,\n cwd: projectRoot,\n sessionId: session.id,\n tools: {\n count: toolRegistry.list().length,\n names: toolRegistry.list().map((t) => t.name),\n },\n features: {\n memory: !!config.features?.memory,\n skills: !!config.features?.skills,\n modelsRegistry: !!config.features?.modelsRegistry,\n },\n mode: modeId ?? 'default',\n usage,\n messages: context.messages.length,\n todos: context.todos.length,\n },\n });\n break;\n }\n\n // ── Worklist (todos / tasks / plan) — delegated to the shared dispatcher ──\n // The nine worklist message types share one context factory; the dispatcher\n // in handlers/worklist-handlers.ts narrows each payload and routes it.\n case 'todos.get':\n case 'todos.clear':\n case 'todos.remove':\n case 'tasks.get':\n case 'plan.get':\n case 'plan.template_use':\n case 'todo.update':\n case 'task.update':\n case 'plan.item.update': {\n await handleWorklistMessage(makeWorklistContext(), ws, msg as WorklistMessage);\n break;\n }\n\n // ── File operations — delegated to shared handlers (file-handlers.ts) ──\n // These handlers are also used by the CLI's webui-server.ts. When\n // adding or modifying file-operation WebSocket messages, update\n // file-handlers.ts — NOT these case blocks individually.\n case 'files.list':\n return handleFilesList(ws, msg, projectRoot);\n case 'files.tree':\n return handleFilesTree(ws, msg, projectRoot);\n case 'files.read':\n return handleFilesRead(ws, msg, projectRoot);\n case 'files.write':\n return handleFilesWrite(ws, msg, projectRoot, {\n onWritten: (filePath) => codebaseIndexing.onFileWritten(filePath),\n });\n case 'completion.request':\n return handleCompletionRequest(ws, msg, {\n projectRoot,\n provider: context.provider,\n model: context.model,\n indexDir: typeof context.meta['codebaseIndexDir'] === 'string'\n ? context.meta['codebaseIndexDir']\n : undefined,\n lspCompletion: createToolLspCompletionSource(toolRegistry.get('lsp_completion'), context),\n });\n\n case 'stats.get': {\n // Mirror of the CLI's /stats: detailed session report.\n const usage = tokenCounter.total();\n const cacheStats = tokenCounter.cacheStats();\n const m = await modelsRegistry.getModel(config.provider, config.model).catch(() => null);\n const cost = computeUsageCost(usage, getCostRates(m));\n send(ws, {\n type: 'stats.get',\n payload: {\n sessionId: session.id,\n provider: config.provider,\n model: config.model,\n usage,\n cache: cacheStats,\n cost,\n messages: context.messages.length,\n readFiles: context.readFiles.size,\n tools: toolRegistry.list().length,\n sideEffectCount: context.sideEffects?.length ?? 0,\n elapsedMs: Date.now() - sessionStartedAt,\n },\n });\n break;\n }\n\n case 'side_effects.list': {\n // P2 #5 Phase 4: return the in-memory side-effect audit trail.\n const sideEffects = context.sideEffects ?? [];\n send(ws, {\n type: 'side_effects',\n payload: {\n sideEffects: sideEffects.slice(-50).map((se) => ({\n toolUseId: se.toolUseId,\n toolName: se.toolName,\n ts: se.ts,\n input: se.input,\n outcome: se.outcome,\n risk: se.risk,\n })),\n },\n });\n break;\n }\n\n case 'process.list': {\n await handleProcessList(ws);\n break;\n }\n\n case 'process.kill': {\n await handleProcessKill(ws, msg.payload);\n break;\n }\n\n case 'process.killAll': {\n await handleProcessKillAll(ws);\n break;\n }\n\n case 'webui.shutdown': {\n // `/exit` from the client. Trigger the same graceful teardown the\n // CLI-hosted server does — route through SIGINT so the registered\n // shutdown handlers (session flush, disposers, registry unregister)\n // all run. Previously this fell through to the unknown-type error.\n console.log('[WebUI] Shutdown requested from client');\n process.kill(process.pid, 'SIGINT');\n break;\n }\n\n case 'goal.get': {\n await handleGoalGet(projectRoot, (m) => broadcast(clients, m));\n break;\n }\n\n case 'autonomy.switch': {\n // Autonomy mode switch — forwarded to the agent context.\n // The mode is stored in context.meta for the permission policy to read.\n const parsed = validateAutonomySwitchPayload(msg.payload);\n if (!parsed.ok) {\n sendResult(ws, false, parsed.message);\n break;\n }\n const { mode } = parsed.value;\n context.meta['autonomy'] = mode;\n sendResult(ws, true, `Autonomy mode set to \"${mode}\"`);\n // Keep every browser tab + the settings panel in sync, and persist\n // the durable modes (eternal/eternal-parallel are session-level).\n broadcast(clients, { type: 'prefs.updated', payload: { autonomy: mode } });\n void persistPrefsToConfig({ autonomy: mode });\n break;\n }\n\n case 'prefs.update': {\n // Routed via handlePrefsRoute (see prefsRoutes = { ... } below) —\n // the actual handler is `updatePrefs`. This case is unreachable but\n // left as a tripwire for any future regression where the route\n // chain stops claiming 'prefs.*'. If you see this fire, fix the\n // dispatch order in the handleMessage chain above.\n void ws;\n throw new Error('handlePrefsRoute did not claim prefs.update — check chain order');\n }\n\n case 'prefs.get': {\n // Routed via handlePrefsRoute (see prefsRoutes = { ... } below).\n throw new Error('handlePrefsRoute did not claim prefs.get — check chain order');\n }\n\n default:\n send(ws, {\n type: 'error',\n payload: { phase: 'handleMessage', message: `Unknown message type: ${msg.type}` },\n });\n }\n }\n\n // ---- Provider/Key management helpers (extracted to provider-handlers.ts) ----\n const providerHandlers = createProviderHandlers({\n globalConfigPath,\n vault,\n getConfigWriteLock: () => configWriteLock,\n setConfigWriteLock: (p) => {\n configWriteLock = p;\n },\n broadcast,\n clients,\n });\n\n providerRoutes = {\n providerHandlers,\n listProviders: async (ws) => {\n const providers = await modelsRegistry.listProviders();\n // \"Configured\" should mean *any* working credential, not just env vars.\n // Users register keys with `wstack auth`, which writes apiKey/apiKeys\n // into config.providers[<id>] — those are decrypted in memory here.\n const savedIds = new Set(Object.keys(config.providers ?? {}));\n send(ws, {\n type: 'provider.catalog',\n payload: {\n providers: providers.map((p: { id: string; name: string; family: unknown; apiBase?: unknown; envVars: string[]; models: readonly unknown[] }) => ({\n id: p.id,\n name: p.name,\n family: p.family,\n apiBase: p.apiBase,\n envVars: p.envVars,\n modelCount: p.models.length,\n hasApiKey: savedIds.has(p.id) || p.envVars.some((v: string) => !!process.env[v]),\n })),\n },\n });\n },\n listSavedProviders: async (ws) => {\n const saved = await providerHandlers.loadConfigProviders();\n send(ws, {\n type: 'providers.saved',\n payload: { providers: projectSavedProviders(saved) },\n });\n },\n listProviderModels: async (ws, msg) => {\n const providerId = (msg as { payload: { providerId: string } }).payload.providerId;\n // Merge catalog + saved config so OAuth / subscription providers\n // (github-copilot, anthropic-oauth, openai-codex, …) that models.dev\n // doesn't list still resolve to their saved model allowlist. Always\n // reply (possibly empty) — the switcher lazy-loads every saved provider.\n const saved = await providerHandlers.loadConfigProviders();\n const cfg = saved[providerId];\n const catalogId = cfg?.type && cfg.type !== providerId ? cfg.type : providerId;\n const provider = await modelsRegistry.getProvider(catalogId);\n send(ws, {\n type: 'provider.models',\n payload: {\n provider: providerId,\n models: resolveProviderModelList(cfg?.models, provider),\n },\n });\n },\n switchModel: async (ws, msg) => {\n const parsed = validateModelSwitchPayload(msg.payload);\n if (!parsed.ok) {\n sendResult(ws, false, parsed.message);\n return;\n }\n const { provider: newProvider, model: newModel } = parsed.value;\n try {\n // Update config\n config = patchConfig(config, { provider: newProvider, model: newModel });\n configStore.update({ provider: newProvider, model: newModel });\n context.model = newModel;\n\n // Create new provider instance — fail loudly if the user picks a\n // provider with no creds rather than silently keeping the old one.\n const providerCfg = config.providers?.[newProvider] ?? { type: newProvider };\n const newProv = providerRegistry.has(newProvider)\n ? providerRegistry.create({ ...providerCfg, type: newProvider })\n : makeProviderFromConfig(newProvider, providerCfg);\n context.provider = newProv;\n\n // Update AutoCompactionMiddleware with the new model's maxContext so\n // backend threshold triggers (warn/soft/hard) use the correct denominator.\n // sessionStartPayload is called below (after this block) and uses\n // the new provider for its modelsRegistry lookup.\n await updateAutoCompactionMaxContext(newProv);\n\n // Persist to global config file via the unified config mutation helper.\n await updateGlobalConfig((cfg) => {\n cfg.provider = newProvider;\n cfg.model = newModel;\n }, 'model.switch');\n\n // Toast for the SettingsPanel\n send(ws, {\n type: 'key.operation_result',\n payload: { success: true, message: `Switched to ${newProvider} / ${newModel}` },\n });\n } catch (err) {\n send(ws, {\n type: 'key.operation_result',\n payload: {\n success: false,\n message: `Switch failed: ${errMessage(err)}`,\n },\n });\n return;\n }\n\n broadcast(clients, { type: 'session.start', payload: await sessionStartPayload() });\n },\n refineModel: async (ws, msg) => {\n const { text } = (msg as { payload: { text: string } }).payload;\n if (!text?.trim()) {\n send(ws, {\n type: 'model.refine_result',\n payload: { refined: '', english: '', error: 'Empty text' },\n });\n return;\n }\n try {\n const history = recentTextTurns(context.messages);\n // Gate a low-effort reasoning hint to the active model's capabilities\n // (config is patched live on model.switch). Refinement is a shallow\n // rewrite, so this trims wasted thinking on reasoning models; resolves\n // to undefined → no reasoning field, as before.\n const resolved = await modelsRegistry\n .getModel(config.provider, config.model)\n .catch(() => undefined);\n const reasoning = gatedEnhancerReasoning(resolved?.capabilities.reasoningConfig);\n const result = await enhanceUserPrompt({\n provider: context.provider,\n model: context.model,\n text,\n history,\n timeoutMs: 90000,\n ...(reasoning ? { reasoning } : {}),\n onError: (reason: unknown) => {\n console.warn(JSON.stringify({\n level: 'warn',\n event: 'model.refine_failed',\n reason,\n timestamp: new Date().toISOString(),\n }));\n },\n });\n if (result) {\n send(ws, {\n type: 'model.refine_result',\n payload: { refined: result.refined, english: result.english },\n });\n } else {\n send(ws, {\n type: 'model.refine_result',\n payload: { refined: text, english: text, error: 'Refinement returned no result' },\n });\n }\n } catch (err) {\n console.error(JSON.stringify({\n level: 'error',\n event: 'model.refine.error',\n error: errMessage(err),\n timestamp: new Date().toISOString(),\n }));\n send(ws, {\n type: 'model.refine_result',\n payload: { refined: text, english: text, error: errMessage(err) },\n });\n }\n },\n };\n\n\n\n sessionRoutes = createSessionHandlers({\n config,\n clients,\n context,\n toolRegistry,\n compactor,\n customModeStore,\n tokenCounter,\n getProjectRoot: () => projectRoot,\n getSession: () => session,\n getSessionStore: () => sessionStore,\n setSession: (s) => {\n session = s;\n },\n setSessionStartedAt: (t) => {\n sessionStartedAt = t;\n },\n sessionStartPayload,\n });\n\n projectRoutes = createProjectHandlers({\n globalConfigPath,\n wpaths,\n clients,\n context,\n modeStore,\n memoryStore,\n skillLoader,\n modelCapabilities: () => modelCapabilitiesRef.current,\n toolRegistry,\n tokenCounter,\n config,\n getModeId: () => modeId,\n getProjectRoot: () => projectRoot,\n getSession: () => session,\n setProjectRoot: (p) => {\n projectRoot = p;\n },\n setWorkingDir: (p) => {\n workingDir = p;\n },\n setSession: (s) => {\n session = s;\n },\n setSessionStore: (s) => {\n sessionStore = s;\n },\n setSessionStartedAt: (t) => {\n sessionStartedAt = t;\n },\n abortRunLock: () => {\n if (runLock) {\n runLock.abort();\n runLock = null;\n }\n },\n sessionStartPayload,\n });\n\n modeRoutes = createModeHandlers({\n modeStore,\n memoryStore,\n skillLoader,\n modelCapabilities: () => modelCapabilitiesRef.current,\n context,\n toolRegistry,\n config,\n projectRoot,\n globalRoot: wpaths.globalRoot,\n clients,\n setModeId: (id) => {\n modeId = id;\n },\n sessionStartPayload,\n });\n\n // ---- Prefs route (handlePrefsRoute) ----\n // The standalone server's pref surface is richer than the CLI's embedded\n // prefs.ts (issue #31 follow-on to #94–#110). We own the full set of\n // runtime effects: YOLO toggle on permissionPolicy, feature-flag mutation\n // on config.features, fallback chain update on config, AutoCompaction\n // pipeline add/remove, logger.level mutation, and config.json persistence.\n // Closure-captured dependencies stay here in index.ts; the dispatch layer\n // (prefs-routes.ts) just calls these two functions.\n prefsRoutes = {\n getPrefs: async (ws) => {\n // Return the current pref snapshot so a freshly-connected client\n // can seed its local-prefs store from the server's truth.\n send(ws, { type: 'prefs.updated', payload: prefSnapshot() });\n },\n updatePrefs: async (ws, msgPayload) => {\n // Batch preference update from the webui. Merges arbitrary key/value\n // pairs into context.meta so the runtime can read them immediately,\n // broadcasts the full pref snapshot to every connected client so all\n // browser tabs stay in sync, and persists the durable keys to\n // config.json (same keys the TUI settings picker writes).\n const parsed = validatePrefsUpdatePayload(msgPayload);\n if (!parsed.ok) {\n sendResult(ws, false, parsed.message);\n return;\n }\n const payload = parsed.value.prefs;\n // Write each pref into context.meta\n for (const [key, val] of Object.entries(payload)) {\n context.meta[key] = val;\n }\n void persistPrefsToConfig(payload);\n // YOLO mode: toggle the permission policy so tool confirmations\n // are auto-approved instead of prompting the user. Uses the live\n // reference resolved from the container at startup.\n if (typeof payload['yolo'] === 'boolean') {\n permissionPolicy.setYolo?.(payload['yolo']);\n }\n // Also update config.features for feature flags that affect tool/skill\n // initialisation (these were read at startup but can be changed at runtime\n // by the agent's permission middleware or tool guards).\n if (typeof payload['featureMcp'] === 'boolean')\n config.features.mcp = payload['featureMcp'];\n if (typeof payload['featurePlugins'] === 'boolean')\n config.features.plugins = payload['featurePlugins'];\n if (typeof payload['featureMemory'] === 'boolean')\n config.features.memory = payload['featureMemory'];\n if (typeof payload['featureSkills'] === 'boolean')\n config.features.skills = payload['featureSkills'];\n if (typeof payload['featureModelsRegistry'] === 'boolean')\n config.features.modelsRegistry = payload['featureModelsRegistry'];\n\n // Global fallback chain: mutate the live config so the leader's fallback\n // extension (which reads config each turn) honours it without a restart.\n if (Array.isArray(payload['fallbackModels']))\n config.fallbackModels = payload['fallbackModels'] as string[];\n if (\n payload['fallbackProfiles'] &&\n typeof payload['fallbackProfiles'] === 'object' &&\n !Array.isArray(payload['fallbackProfiles'])\n ) {\n config.fallbackProfiles = payload['fallbackProfiles'] as Record<string, string[]>;\n }\n if (Array.isArray(payload['favoriteModels']))\n config.favoriteModels = payload['favoriteModels'] as string[];\n if (typeof payload['favoriteModelsOnly'] === 'boolean')\n config.favoriteModelsOnly = payload['favoriteModelsOnly'];\n if (\n payload['modelMatrix'] &&\n typeof payload['modelMatrix'] === 'object' &&\n !Array.isArray(payload['modelMatrix'])\n ) {\n config.modelMatrix = payload['modelMatrix'] as typeof config.modelMatrix;\n }\n if (typeof payload['fallbackAuto'] === 'boolean')\n config.fallbackAuto = payload['fallbackAuto'];\n\n // Runtime effects: apply prefs that change server behaviour immediately.\n\n // contextAutoCompact — toggle AutoCompactionMiddleware in/out of the\n // contextWindow pipeline. When off, the pipeline skips the compaction\n // step entirely (zero overhead). When on, re-adds the middleware.\n if (typeof payload['contextAutoCompact'] === 'boolean') {\n if (payload['contextAutoCompact'] && autoCompactor) {\n // Re-add: remove first (idempotent via optional), then insert.\n pipelines.contextWindow.remove('AutoCompaction', { optional: true });\n pipelines.contextWindow.use({ name: 'AutoCompaction', handler: autoCompactor.handler() });\n } else {\n pipelines.contextWindow.remove('AutoCompaction', { optional: true });\n }\n }\n\n // logLevel — the DefaultLogger.level property is a public mutable\n // field. Setting it at runtime changes the log threshold immediately\n // (the log() method checks LEVEL_RANK on every call).\n if (typeof payload['logLevel'] === 'string') {\n const valid = ['debug', 'info', 'warn', 'error'] as const;\n if ((valid as readonly string[]).includes(payload['logLevel'])) {\n logger.level = payload['logLevel'] as typeof valid[number];\n }\n }\n\n // auditLevel — stored in context.meta by the generic loop above.\n // Consumed by the session audit log system at session-close time.\n\n // Broadcast the full current prefs snapshot to ALL clients.\n broadcast(clients, { type: 'prefs.updated', payload: prefSnapshot() });\n },\n };\n\n shellGitRoutes = {\n gitInfo: async (ws) => {\n await handleGitInfo(ws, projectRoot);\n },\n gitChanges: async (ws) => {\n await handleGitChanges(ws, projectRoot);\n },\n gitDiff: async (ws, msg) => {\n const parsed = validateGitDiffPayload(msg.payload);\n if (!parsed.ok) {\n sendResult(ws, false, parsed.message);\n return;\n }\n await handleGitDiff(ws, projectRoot, parsed.value.path);\n },\n shellOpen: async (ws, msg) => {\n const parsed = validateShellOpenPayload(msg.payload);\n if (!parsed.ok) {\n sendResult(ws, false, parsed.message);\n return;\n }\n const result: ShellOpenResult = await handleShellOpen(parsed.value as ShellOpenRequest, logger);\n sendResult(ws, result.success, result.message);\n },\n };\n\n mailboxRoutes = {\n messages: (ws, msg) => {\n const parsed = validateMailboxMessagesPayload(msg.payload);\n if (!parsed.ok) {\n sendResult(ws, false, parsed.message);\n return;\n }\n return handleMailboxMessages(ws, { projectRoot, globalRoot: path.dirname(globalConfigPath) }, parsed.value);\n },\n agents: (ws, msg) => {\n const parsed = validateMailboxAgentsPayload(msg.payload);\n if (!parsed.ok) {\n sendResult(ws, false, parsed.message);\n return;\n }\n return handleMailboxAgents(ws, { projectRoot, globalRoot: path.dirname(globalConfigPath) }, parsed.value);\n },\n clear: (ws) =>\n handleMailboxClear(ws, { projectRoot, globalRoot: path.dirname(globalConfigPath) }),\n purge: (ws, msg) => {\n const parsed = validateMailboxPurgePayload(msg.payload);\n if (!parsed.ok) {\n sendResult(ws, false, parsed.message);\n return;\n }\n return handleMailboxPurge(ws, { projectRoot, globalRoot: path.dirname(globalConfigPath) }, parsed.value);\n },\n };\n\n // ---- MCP route (handleMcpRoute) ----\n // Issue #31 follow-on (after #118 PR 0 baseline, #119 prefs extraction).\n // Each callback delegates to the matching handleMcpXxx in mcp-handlers.ts\n // — that module already owns the WS-message logic, this is just the\n // chain-of-responsibility wiring. The 10 cases were pure delegations\n // inside the residual switch before this PR; now they're an explicit\n // sibling in the chain.\n mcpRoutes = {\n list: (ws, msg) => handleMcpList(ws, msg, globalConfigPath, mcpRegistry),\n add: (ws, msg) => handleMcpAdd(ws, msg, globalConfigPath, mcpRegistry),\n update: (ws, msg) => handleMcpUpdate(ws, msg, globalConfigPath, mcpRegistry),\n remove: (ws, msg) => handleMcpRemove(ws, msg, globalConfigPath, mcpRegistry),\n enable: (ws, msg) => handleMcpEnable(ws, msg, globalConfigPath, mcpRegistry),\n disable: (ws, msg) => handleMcpDisable(ws, msg, globalConfigPath, mcpRegistry),\n sleep: (ws, msg) => handleMcpSleep(ws, msg, globalConfigPath, mcpRegistry),\n wake: (ws, msg) => handleMcpWake(ws, msg, globalConfigPath, mcpRegistry),\n restart: (ws, msg) => handleMcpRestart(ws, msg, globalConfigPath, mcpRegistry),\n discover: (ws, msg) => handleMcpDiscover(ws, msg, globalConfigPath, mcpRegistry),\n };\n\n brainRoutes = {\n status: (ws) => {\n send(ws, {\n type: 'brain.status',\n payload: { maxAutoRisk: brainSettings.maxAutoRisk, log: brainLog },\n });\n },\n risk: (ws, msg) => {\n const parsed = validateBrainRiskPayload(msg.payload);\n if (!parsed.ok) {\n sendResult(ws, false, parsed.message);\n return;\n }\n const { level } = parsed.value;\n brainSettings.maxAutoRisk = level as BrainAutoRisk;\n send(ws, {\n type: 'brain.status',\n payload: { maxAutoRisk: brainSettings.maxAutoRisk, log: brainLog },\n });\n },\n ask: async (ws, msg) => {\n const parsed = validateBrainAskPayload(msg.payload);\n if (!parsed.ok) {\n sendResult(ws, false, parsed.message);\n return;\n }\n const { question } = parsed.value;\n try {\n const decision = await brain.decide({\n id: `brain-ask-${Date.now().toString(36)}`,\n source: 'user',\n question,\n risk: 'medium',\n fallback: 'ask_human',\n });\n send(ws, { type: 'brain.answer', payload: { question, decision } });\n } catch (err) {\n sendResult(ws, false, `Brain consultation failed: ${errMessage(err)}`);\n }\n },\n };\n\n autoPhaseRoutes = {\n handleMessage: (msg) => autoPhaseHandler.handleMessage(msg),\n };\n\n specsRoutes = {\n handleMessage: (msg) => specsHandler.handleMessage(msg),\n };\n\n sddBoardRoutes = {\n handleMessage: (msg) => sddBoardHandler.handleMessage(msg),\n };\n\n sddWizardRoutes = {\n handleMessage: (msg) => sddWizardHandler.handleMessage(msg),\n };\n\n // HTTP server for the React frontend (port 3456) — see `http-server.ts`\n // for the static-serve, MIME matching, path-traversal guard, and CSP\n // header logic. Constructed here, listen()d below alongside the WS server.\n // `globalRoot` powers the /api/sessions and /api/sessions/:id/agents\n // handlers (read the cross-process SessionRegistry); `apiToken` is the\n // shared auth token the HTTP API requires when bound to a non-loopback\n // host (LAN exposure). Loopback binds skip the token check, mirroring\n // the WS verifyClient loopback-bootstrap policy.\n\n // Shared metrics object for file watcher — populated by setupEvents and\n // exposed via the /debug/watcher-metrics HTTP endpoint.\n const watcherMetrics: FileWatcherMetrics = {\n fileChangesDetected: 0,\n filesProcessed: 0,\n broadcastsSent: 0,\n debounceResets: 0,\n totalDebounceDelayMs: 0,\n activeProjects: 0,\n averageDebounceDelayMs: 0,\n watcherActive: false,\n };\n\n const httpServer = createHttpServer({\n host: wsHost,\n distDir: path.resolve(import.meta.dirname, '../../dist'),\n wsPort,\n publicWsUrl,\n globalRoot: wpaths.globalRoot,\n apiToken: wsToken,\n requireToken,\n watcherMetrics,\n onFleetPing: () => { void fleetBroadcast?.(); },\n });\n // httpPort/wsPort were resolved (and possibly auto-advanced) at the top.\n // Base dir for the running-instance registry — keep it next to the rest of\n // the wstack home state (config.json lives here too).\n const registryBaseDir = path.dirname(globalConfigPath);\n httpServer.listen(httpPort, wsHost, () => {\n const openUrl = buildWebUIAccessUrl({\n host: wsHost,\n port: httpPort,\n token: wsToken,\n publicUrl,\n });\n console.log(`[WebUI] HTTP server running on ${openUrl}`);\n // Optionally pop the browser open (best-effort; the URL is always printed).\n if (opts.open) openBrowser(openUrl);\n // Record this instance so `wstackui --list` (and `~/.wrongstack/\n // webui-instances.json`) show which ports are open for which project.\n // Best-effort: a registry write failure must not affect serving.\n void registerInstance(\n {\n pid: process.pid,\n httpPort,\n wsPort,\n host: wsHost,\n projectRoot,\n projectName: path.basename(projectRoot) || projectRoot,\n startedAt: new Date().toISOString(),\n url: buildWebUIAccessUrl({ host: wsHost, port: httpPort, publicUrl }),\n },\n registryBaseDir,\n ).catch((err) => console.warn(JSON.stringify({\n level: 'warn',\n event: 'webui.instance_record_failed',\n message: errMessage(err),\n timestamp: new Date().toISOString(),\n })));\n });\n\n // Graceful shutdown on SIGINT/SIGTERM — see `lifecycle.ts`. The session\n // flush (session_end + close) is passed as a thunk so lifecycle stays\n // decoupled from the session/tokenCounter types.\n registerShutdownHandlers({\n flushSession: async () => {\n await session.append({\n type: 'session_end',\n ts: new Date().toISOString(),\n usage: tokenCounter.total(),\n });\n await session.close();\n },\n clients: () => clients.keys(),\n servers: [httpServer, wssPrimary, wssSecondary],\n // Drop this instance from the registry on a clean exit so the file reflects\n // reality. Crash exits are healed by the next register()/list() prune pass.\n onShutdown: () => {\n brainMonitor.stop();\n void mcpRegistry.stopAll().catch(() => undefined);\n if (disposeEvents) {\n disposeEvents();\n disposeEvents = null;\n }\n if (eternalSubscription) {\n eternalSubscription.dispose();\n eternalSubscription = null;\n }\n codebaseIndexing.dispose();\n return unregisterInstance(process.pid, registryBaseDir);\n },\n });\n}\n\n/**\n * Webui-side mailbox bridge discovery.\n *\n * The webui doesn't spawn a bridge — the bridge (`wstack mailbox serve`)\n * is spawned by any CLI surface via the auto-bootstrap wiring. We just\n * probe the per-project lock for an already-running instance and stash\n * the discovered handle on `ctx.meta['mailboxBridge']` so any later\n * code (the `/mailbox` HTTP surface, agent-status broadcasters,\n * external-agent proxy) can find it without re-running discovery.\n *\n * If no bridge is running, we log a breadcrumb so the user knows\n * to start one (`wstack --repl`, `wstack --webui`, or\n * `wstack mailbox serve` standalone).\n *\n * Best-effort: never throws. A failure (missing lock dir, ENOENT,\n * etc.) logs at warn level and returns — the webui keeps running.\n */\n// discoverMailboxBridgeForWebui extracted → ./discover-mailbox-bridge.ts\n","export type PayloadValidationResult<T> = { ok: true; value: T } | { ok: false; message: string };\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport interface ModelSwitchPayload {\n provider: string;\n model: string;\n}\n\nexport function validateModelSwitchPayload(\n payload: unknown,\n): PayloadValidationResult<ModelSwitchPayload> {\n if (!isRecord(payload)) {\n return {\n ok: false,\n message: 'model.switch payload must be an object with string provider and model',\n };\n }\n const provider = payload['provider'];\n const model = payload['model'];\n if (typeof provider !== 'string' || provider.trim().length === 0) {\n return { ok: false, message: 'model.switch payload.provider must be a non-empty string' };\n }\n if (typeof model !== 'string' || model.trim().length === 0) {\n return { ok: false, message: 'model.switch payload.model must be a non-empty string' };\n }\n return { ok: true, value: { provider, model } };\n}\n\nexport interface PrefsUpdatePayload {\n prefs: Record<string, unknown>;\n}\n\nconst AUTONOMY_VALUES = new Set(['off', 'suggest', 'auto', 'eternal', 'eternal-parallel']);\n\nexport interface MailboxMessagesPayload {\n limit?: number;\n agentId?: string;\n unreadOnly?: boolean;\n}\n\nexport function validateMailboxMessagesPayload(\n payload: unknown,\n): PayloadValidationResult<MailboxMessagesPayload | undefined> {\n if (payload === undefined) return { ok: true, value: undefined };\n if (!isRecord(payload)) {\n return { ok: false, message: 'mailbox.messages payload must be an object when provided' };\n }\n const limit = payload['limit'];\n const agentId = payload['agentId'];\n const unreadOnly = payload['unreadOnly'];\n if (limit !== undefined && (typeof limit !== 'number' || !Number.isFinite(limit) || limit < 1)) {\n return {\n ok: false,\n message: 'mailbox.messages payload.limit must be a positive number when provided',\n };\n }\n if (agentId !== undefined && typeof agentId !== 'string') {\n return {\n ok: false,\n message: 'mailbox.messages payload.agentId must be a string when provided',\n };\n }\n if (unreadOnly !== undefined && typeof unreadOnly !== 'boolean') {\n return {\n ok: false,\n message: 'mailbox.messages payload.unreadOnly must be a boolean when provided',\n };\n }\n return { ok: true, value: { limit, agentId, unreadOnly } };\n}\n\nexport interface MailboxAgentsPayload {\n onlineOnly?: boolean;\n}\n\nexport function validateMailboxAgentsPayload(\n payload: unknown,\n): PayloadValidationResult<MailboxAgentsPayload | undefined> {\n if (payload === undefined) return { ok: true, value: undefined };\n if (!isRecord(payload)) {\n return { ok: false, message: 'mailbox.agents payload must be an object when provided' };\n }\n const onlineOnly = payload['onlineOnly'];\n if (onlineOnly !== undefined && typeof onlineOnly !== 'boolean') {\n return {\n ok: false,\n message: 'mailbox.agents payload.onlineOnly must be a boolean when provided',\n };\n }\n return { ok: true, value: { onlineOnly } };\n}\n\nexport interface MailboxPurgePayload {\n completedMaxAgeMs?: number;\n incompleteMaxAgeMs?: number;\n}\n\nexport function validateMailboxPurgePayload(\n payload: unknown,\n): PayloadValidationResult<MailboxPurgePayload | undefined> {\n if (payload === undefined) return { ok: true, value: undefined };\n if (!isRecord(payload)) {\n return { ok: false, message: 'mailbox.purge payload must be an object when provided' };\n }\n const completedMaxAgeMs = payload['completedMaxAgeMs'];\n const incompleteMaxAgeMs = payload['incompleteMaxAgeMs'];\n if (\n completedMaxAgeMs !== undefined &&\n (typeof completedMaxAgeMs !== 'number' ||\n !Number.isFinite(completedMaxAgeMs) ||\n completedMaxAgeMs < 0)\n ) {\n return {\n ok: false,\n message:\n 'mailbox.purge payload.completedMaxAgeMs must be a non-negative number when provided',\n };\n }\n if (\n incompleteMaxAgeMs !== undefined &&\n (typeof incompleteMaxAgeMs !== 'number' ||\n !Number.isFinite(incompleteMaxAgeMs) ||\n incompleteMaxAgeMs < 0)\n ) {\n return {\n ok: false,\n message:\n 'mailbox.purge payload.incompleteMaxAgeMs must be a non-negative number when provided',\n };\n }\n return { ok: true, value: { completedMaxAgeMs, incompleteMaxAgeMs } };\n}\n\nexport interface BrainRiskPayload {\n level: string;\n}\n\nconst BRAIN_RISK_VALUES = new Set(['off', 'low', 'medium', 'high', 'all']);\n\nexport function validateBrainRiskPayload(\n payload: unknown,\n): PayloadValidationResult<BrainRiskPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'brain.risk payload must be an object with string level' };\n }\n const level = payload['level'];\n if (typeof level !== 'string' || !BRAIN_RISK_VALUES.has(level)) {\n return {\n ok: false,\n message: 'brain.risk payload.level must be one of off, low, medium, high, all',\n };\n }\n return { ok: true, value: { level } };\n}\n\nexport interface BrainAskPayload {\n question: string;\n}\n\nexport function validateBrainAskPayload(\n payload: unknown,\n): PayloadValidationResult<BrainAskPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'brain.ask payload must be an object with string question' };\n }\n const question = payload['question'];\n if (typeof question !== 'string' || question.trim().length === 0) {\n return { ok: false, message: 'brain.ask payload.question must be a non-empty string' };\n }\n return { ok: true, value: { question: question.trim() } };\n}\n\nexport interface AutonomySwitchPayload {\n mode: string;\n}\n\nexport function validateAutonomySwitchPayload(\n payload: unknown,\n): PayloadValidationResult<AutonomySwitchPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'autonomy.switch payload must be an object with string mode' };\n }\n const mode = payload['mode'];\n if (typeof mode !== 'string' || !AUTONOMY_VALUES.has(mode)) {\n return { ok: false, message: 'autonomy.switch payload.mode must be a valid autonomy mode' };\n }\n return { ok: true, value: { mode } };\n}\n\nexport interface PlanTemplateUsePayload {\n template: string;\n}\n\nexport function validatePlanTemplateUsePayload(\n payload: unknown,\n): PayloadValidationResult<PlanTemplateUsePayload> {\n if (!isRecord(payload)) {\n return {\n ok: false,\n message: 'plan.template_use payload must be an object with string template',\n };\n }\n const template = payload['template'];\n if (typeof template !== 'string' || template.trim().length === 0) {\n return { ok: false, message: 'plan.template_use payload.template must be a non-empty string' };\n }\n return { ok: true, value: { template } };\n}\nconst CONTEXT_STRATEGY_VALUES = new Set(['hybrid', 'intelligent', 'selective']);\nconst CONTEXT_MODE_VALUES = new Set(['balanced', 'frugal', 'deep', 'archival']);\nconst TOKEN_SAVING_TIER_VALUES = new Set(['off', 'minimal', 'light', 'medium', 'aggressive']);\nconst ENHANCE_LANGUAGE_VALUES = new Set(['original', 'english']);\nconst LOG_LEVEL_VALUES = new Set(['debug', 'info', 'warn', 'error']);\nconst AUDIT_LEVEL_VALUES = new Set(['minimal', 'standard', 'full']);\nconst REASONING_MODE_VALUES = new Set(['auto', 'on', 'off']);\nconst REASONING_EFFORT_VALUES = new Set([\n 'none',\n 'minimal',\n 'low',\n 'medium',\n 'high',\n 'xhigh',\n 'max',\n]);\nconst CACHE_TTL_VALUES = new Set(['default', '5m', '1h']);\n\nconst BOOLEAN_PREF_KEYS = new Set([\n 'yolo',\n 'chime',\n 'confirmExit',\n 'streamFleet',\n 'nextPrediction',\n 'titleAnimation',\n 'enhanceEnabled',\n 'featureMcp',\n 'featurePlugins',\n 'featureMemory',\n 'featureSkills',\n 'featureModelsRegistry',\n 'indexOnStart',\n 'contextAutoCompact',\n 'tgSessionEnd',\n 'tgDelegate',\n 'reasoningPreserve',\n 'hqEnabled',\n 'hqRawContent',\n 'fallbackAuto',\n 'favoriteModelsOnly',\n]);\n\n/** Keys whose value must be an array of strings (e.g. an ordered model list). */\nconst STRING_ARRAY_PREF_KEYS = new Set(['fallbackModels', 'favoriteModels']);\nconst STRING_ARRAY_RECORD_PREF_KEYS = new Set(['fallbackProfiles']);\nconst MODEL_MATRIX_PREF_KEYS = new Set(['modelMatrix']);\n\nconst NUMBER_PREF_KEYS = new Set([\n 'autonomyDelayMs',\n 'autoProceedMaxIterations',\n 'maxIterations',\n 'maxConcurrent',\n 'enhanceDelayMs',\n 'tgLongToolMs',\n]);\n\nconst STRING_PREF_KEYS = new Set(['hqUrl', 'hqToken']);\n\nconst ENUM_PREF_KEYS: Record<string, Set<string>> = {\n autonomy: AUTONOMY_VALUES,\n contextStrategy: CONTEXT_STRATEGY_VALUES,\n contextMode: CONTEXT_MODE_VALUES,\n tokenSavingTier: TOKEN_SAVING_TIER_VALUES,\n enhanceLanguage: ENHANCE_LANGUAGE_VALUES,\n logLevel: LOG_LEVEL_VALUES,\n auditLevel: AUDIT_LEVEL_VALUES,\n reasoningMode: REASONING_MODE_VALUES,\n reasoningEffort: REASONING_EFFORT_VALUES,\n cacheTtl: CACHE_TTL_VALUES,\n};\n\nfunction validatePreferenceValue(key: string, value: unknown): string | null {\n if (BOOLEAN_PREF_KEYS.has(key)) {\n return typeof value === 'boolean' ? null : `prefs.update payload.${key} must be a boolean`;\n }\n if (NUMBER_PREF_KEYS.has(key)) {\n return typeof value === 'number' && Number.isFinite(value)\n ? null\n : `prefs.update payload.${key} must be a finite number`;\n }\n if (STRING_PREF_KEYS.has(key)) {\n return typeof value === 'string' ? null : `prefs.update payload.${key} must be a string`;\n }\n if (STRING_ARRAY_PREF_KEYS.has(key)) {\n return Array.isArray(value) && value.every((v) => typeof v === 'string')\n ? null\n : `prefs.update payload.${key} must be an array of strings`;\n }\n if (STRING_ARRAY_RECORD_PREF_KEYS.has(key)) {\n return isRecord(value) &&\n Object.values(value).every(\n (v) => Array.isArray(v) && v.every((item) => typeof item === 'string'),\n )\n ? null\n : `prefs.update payload.${key} must be an object of string arrays`;\n }\n if (MODEL_MATRIX_PREF_KEYS.has(key)) {\n if (!isRecord(value)) return `prefs.update payload.${key} must be an object`;\n for (const entry of Object.values(value)) {\n if (!isRecord(entry)) return `prefs.update payload.${key} entries must be objects`;\n const provider = entry['provider'];\n const model = entry['model'];\n const fallbackProfile = entry['fallbackProfile'];\n if (provider !== undefined && typeof provider !== 'string') {\n return `prefs.update payload.${key}.provider must be a string when provided`;\n }\n if (model !== undefined && typeof model !== 'string') {\n return `prefs.update payload.${key}.model must be a string when provided`;\n }\n if (fallbackProfile !== undefined && typeof fallbackProfile !== 'string') {\n return `prefs.update payload.${key}.fallbackProfile must be a string when provided`;\n }\n if (model === undefined && fallbackProfile === undefined) {\n return `prefs.update payload.${key} entries require model or fallbackProfile`;\n }\n }\n return null;\n }\n const allowed = ENUM_PREF_KEYS[key];\n if (allowed) {\n return typeof value === 'string' && allowed.has(value)\n ? null\n : `prefs.update payload.${key} must be one of: ${Array.from(allowed).join(', ')}`;\n }\n return `prefs.update payload contains unknown preference key: ${key}`;\n}\n\nexport function validatePrefsUpdatePayload(\n payload: unknown,\n): PayloadValidationResult<PrefsUpdatePayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'prefs.update payload must be an object' };\n }\n for (const [key, value] of Object.entries(payload)) {\n const error = validatePreferenceValue(key, value);\n if (error) return { ok: false, message: error };\n }\n return { ok: true, value: { prefs: payload } };\n}\n\nexport interface SkillsCreatePayload {\n name: string;\n description: string;\n scope: 'project' | 'global';\n}\n\nexport function validateSkillsCreatePayload(\n payload: unknown,\n): PayloadValidationResult<SkillsCreatePayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'skills.create payload must be an object' };\n }\n const name = payload['name'];\n const description = payload['description'];\n const scope = payload['scope'];\n if (typeof name !== 'string' || name.trim().length === 0) {\n return { ok: false, message: 'Skill name is required' };\n }\n if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(name.trim())) {\n return { ok: false, message: 'Skill name must be kebab-case (e.g. my-new-skill)' };\n }\n if (typeof description !== 'string' || description.trim().length === 0) {\n return { ok: false, message: 'Description/trigger is required' };\n }\n if (scope !== 'project' && scope !== 'global') {\n return { ok: false, message: 'skills.create payload.scope must be project or global' };\n }\n return { ok: true, value: { name, description, scope } };\n}\n\nexport interface SkillsEditPayload {\n name: string;\n body: string;\n}\n\nexport function validateSkillsEditPayload(\n payload: unknown,\n): PayloadValidationResult<SkillsEditPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'skills.edit payload must be an object' };\n }\n const name = payload['name'];\n const body = payload['body'];\n if (typeof name !== 'string' || name.trim().length === 0) {\n return { ok: false, message: 'Skill name is required' };\n }\n if (typeof body !== 'string' || body.length === 0) {\n return { ok: false, message: 'Skill body is required' };\n }\n return { ok: true, value: { name, body } };\n}\n\nexport interface ProcessKillPayload {\n pid: number;\n}\n\nexport function validateProcessKillPayload(\n payload: unknown,\n): PayloadValidationResult<ProcessKillPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'process.kill payload must be an object with numeric pid' };\n }\n const pid = payload['pid'];\n if (typeof pid !== 'number' || !Number.isInteger(pid) || pid <= 0) {\n return { ok: false, message: 'process.kill payload.pid must be a positive integer' };\n }\n return { ok: true, value: { pid } };\n}\n\nexport interface WorkingDirSetPayload {\n path: string;\n}\n\nexport function validateWorkingDirSetPayload(\n payload: unknown,\n): PayloadValidationResult<WorkingDirSetPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'working_dir.set payload must be an object with string path' };\n }\n const newPath = payload['path'];\n if (typeof newPath !== 'string' || newPath.trim().length === 0) {\n return { ok: false, message: 'working_dir.set payload.path must be a non-empty string' };\n }\n return { ok: true, value: { path: newPath } };\n}\n\nexport interface ModeSwitchPayload {\n id: string;\n}\n\nexport function validateModeSwitchPayload(\n payload: unknown,\n): PayloadValidationResult<ModeSwitchPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'mode.switch payload must be an object with string id' };\n }\n const id = payload['id'];\n if (typeof id !== 'string' || id.trim().length === 0) {\n return { ok: false, message: 'mode.switch payload.id must be a non-empty string' };\n }\n return { ok: true, value: { id } };\n}\n\nexport interface ContextModeIdPayload {\n id: string;\n}\n\nfunction validateContextModeIdPayload(\n payload: unknown,\n type: 'context.mode.switch' | 'context.mode.delete',\n): PayloadValidationResult<ContextModeIdPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: `${type} payload must be an object with string id` };\n }\n const id = payload['id'];\n if (typeof id !== 'string' || id.trim().length === 0) {\n return { ok: false, message: `${type} payload.id must be a non-empty string` };\n }\n return { ok: true, value: { id } };\n}\n\nexport function validateContextModeSwitchPayload(\n payload: unknown,\n): PayloadValidationResult<ContextModeIdPayload> {\n return validateContextModeIdPayload(payload, 'context.mode.switch');\n}\n\nexport function validateContextModeDeletePayload(\n payload: unknown,\n): PayloadValidationResult<ContextModeIdPayload> {\n return validateContextModeIdPayload(payload, 'context.mode.delete');\n}\n\nexport interface ContextModeCreatePayload {\n id: string;\n name: string;\n description: string;\n thresholds: { warn: number; soft: number; hard: number };\n preserveK: number;\n eliseThreshold: number;\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value);\n}\n\nexport function validateContextModeCreatePayload(\n payload: unknown,\n): PayloadValidationResult<ContextModeCreatePayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'context.mode.create payload must be an object' };\n }\n const id = payload['id'];\n const name = payload['name'];\n const description = payload['description'];\n const thresholds = payload['thresholds'];\n const preserveK = payload['preserveK'];\n const eliseThreshold = payload['eliseThreshold'];\n\n if (typeof id !== 'string' || id.trim().length === 0) {\n return { ok: false, message: 'context.mode.create payload.id must be a non-empty string' };\n }\n if (typeof name !== 'string' || name.trim().length === 0) {\n return { ok: false, message: 'context.mode.create payload.name must be a non-empty string' };\n }\n if (typeof description !== 'string') {\n return { ok: false, message: 'context.mode.create payload.description must be a string' };\n }\n if (!isRecord(thresholds)) {\n return {\n ok: false,\n message:\n 'context.mode.create payload.thresholds must be an object with warn/soft/hard numbers',\n };\n }\n if (\n !isFiniteNumber(thresholds['warn']) ||\n !isFiniteNumber(thresholds['soft']) ||\n !isFiniteNumber(thresholds['hard'])\n ) {\n return {\n ok: false,\n message: 'context.mode.create payload.thresholds.warn/soft/hard must be finite numbers',\n };\n }\n if (!isFiniteNumber(preserveK)) {\n return { ok: false, message: 'context.mode.create payload.preserveK must be a finite number' };\n }\n if (!isFiniteNumber(eliseThreshold)) {\n return {\n ok: false,\n message: 'context.mode.create payload.eliseThreshold must be a finite number',\n };\n }\n return {\n ok: true,\n value: {\n id,\n name,\n description,\n thresholds: { warn: thresholds['warn'], soft: thresholds['soft'], hard: thresholds['hard'] },\n preserveK,\n eliseThreshold,\n },\n };\n}\n\nexport interface ContextModeUpdatePayload {\n id: string;\n name?: string;\n description?: string;\n thresholds?: { warn?: number; soft?: number; hard?: number };\n preserveK?: number;\n eliseThreshold?: number;\n}\n\nexport function validateContextModeUpdatePayload(\n payload: unknown,\n): PayloadValidationResult<ContextModeUpdatePayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'context.mode.update payload must be an object' };\n }\n const id = payload['id'];\n if (typeof id !== 'string' || id.trim().length === 0) {\n return { ok: false, message: 'context.mode.update payload.id must be a non-empty string' };\n }\n\n const name = payload['name'];\n if (name !== undefined && typeof name !== 'string') {\n return {\n ok: false,\n message: 'context.mode.update payload.name must be a string when provided',\n };\n }\n\n const description = payload['description'];\n if (description !== undefined && typeof description !== 'string') {\n return {\n ok: false,\n message: 'context.mode.update payload.description must be a string when provided',\n };\n }\n\n const thresholds = payload['thresholds'];\n let validatedThresholds: ContextModeUpdatePayload['thresholds'];\n if (thresholds !== undefined) {\n if (!isRecord(thresholds)) {\n return {\n ok: false,\n message: 'context.mode.update payload.thresholds must be an object when provided',\n };\n }\n for (const key of ['warn', 'soft', 'hard'] as const) {\n const val = thresholds[key];\n if (val !== undefined && !isFiniteNumber(val)) {\n return {\n ok: false,\n message: `context.mode.update payload.thresholds.${key} must be a finite number when provided`,\n };\n }\n }\n validatedThresholds = {\n warn: typeof thresholds['warn'] === 'number' ? thresholds['warn'] : undefined,\n soft: typeof thresholds['soft'] === 'number' ? thresholds['soft'] : undefined,\n hard: typeof thresholds['hard'] === 'number' ? thresholds['hard'] : undefined,\n };\n }\n\n const preserveK = payload['preserveK'];\n if (preserveK !== undefined && !isFiniteNumber(preserveK)) {\n return {\n ok: false,\n message: 'context.mode.update payload.preserveK must be a finite number when provided',\n };\n }\n\n const eliseThreshold = payload['eliseThreshold'];\n if (eliseThreshold !== undefined && !isFiniteNumber(eliseThreshold)) {\n return {\n ok: false,\n message: 'context.mode.update payload.eliseThreshold must be a finite number when provided',\n };\n }\n\n return {\n ok: true,\n value: {\n id,\n name: typeof name === 'string' ? name : undefined,\n description: typeof description === 'string' ? description : undefined,\n thresholds: validatedThresholds,\n preserveK: typeof preserveK === 'number' ? preserveK : undefined,\n eliseThreshold: typeof eliseThreshold === 'number' ? eliseThreshold : undefined,\n },\n };\n}\n\nexport interface ShellOpenPayload {\n path: string;\n target?: 'file' | 'terminal';\n}\n\nexport function validateShellOpenPayload(\n payload: unknown,\n): PayloadValidationResult<ShellOpenPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'shell.open payload must be an object with string path' };\n }\n const path = payload['path'];\n if (typeof path !== 'string' || path.trim().length === 0) {\n return { ok: false, message: 'shell.open payload.path must be a non-empty string' };\n }\n const target = payload['target'];\n if (target !== undefined && target !== 'file' && target !== 'terminal') {\n return {\n ok: false,\n message: 'shell.open payload.target must be \"file\" or \"terminal\" when provided',\n };\n }\n return { ok: true, value: { path, target: target as ShellOpenPayload['target'] } };\n}\n\nexport interface GitDiffPayload {\n path: string;\n}\n\nexport function validateGitDiffPayload(payload: unknown): PayloadValidationResult<GitDiffPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'git.diff payload must be an object' };\n }\n const path = payload['path'];\n if (path === undefined || path === null) {\n return { ok: true, value: { path: '' } };\n }\n if (typeof path !== 'string') {\n return { ok: false, message: 'git.diff payload.path must be a string when provided' };\n }\n return { ok: true, value: { path } };\n}\n\nexport interface ProjectsAddPayload {\n root: string;\n name?: string;\n}\n\nexport function validateProjectsAddPayload(\n payload: unknown,\n): PayloadValidationResult<ProjectsAddPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'projects.add payload must be an object with string root' };\n }\n const root = payload['root'];\n if (typeof root !== 'string' || root.trim().length === 0) {\n return { ok: false, message: 'projects.add payload.root must be a non-empty string' };\n }\n const name = payload['name'];\n if (name !== undefined && typeof name !== 'string') {\n return { ok: false, message: 'projects.add payload.name must be a string when provided' };\n }\n return { ok: true, value: { root, name: typeof name === 'string' ? name : undefined } };\n}\n\nexport interface ProjectsSelectPayload {\n root: string;\n name?: string;\n}\n\nexport function validateProjectsSelectPayload(\n payload: unknown,\n): PayloadValidationResult<ProjectsSelectPayload> {\n if (!isRecord(payload)) {\n return { ok: false, message: 'projects.select payload must be an object with string root' };\n }\n const root = payload['root'];\n if (typeof root !== 'string' || root.trim().length === 0) {\n return { ok: false, message: 'projects.select payload.root must be a non-empty string' };\n }\n const name = payload['name'];\n if (name !== undefined && typeof name !== 'string') {\n return { ok: false, message: 'projects.select payload.name must be a string when provided' };\n }\n return { ok: true, value: { root, name: typeof name === 'string' ? name : undefined } };\n}\n","// ── Shared Worklist Handlers ─────────────────────────────────────────────────\n// Extracted from standalone server (packages/webui/src/server/index.ts) and CLI\n// embedded server (packages/cli/src/webui-server/). Both servers use these\n// handlers for todos, tasks, and plan operations. Keep them in sync.\n//\n// Message types handled here:\n// todos.get | todos.clear | todos.remove | todo.update\n// tasks.get | task.update\n// plan.get | plan.template_use | plan.item.update\n// ─────────────────────────────────────────────────────────────────────────────\n\nimport type { WebSocket } from 'ws';\nimport type { TodoItem } from '@wrongstack/core';\nimport { validatePlanTemplateUsePayload } from '../ws-payload-validation.js';\n\n// ── Shared result helper ───────────────────────────────────────────────────────\n\nfunction sendResult(\n ws: WebSocket,\n ctx: WorklistContext,\n ok: boolean,\n message: string,\n): void {\n ctx.send(ws, { type: ok ? 'ok' : 'error', message });\n}\n\n// ── Context interface ─────────────────────────────────────────────────────────\n// Both servers satisfy this with their own local state.\n\nexport interface WorklistContext {\n context: {\n todos: TodoItem[];\n meta: Record<string, unknown>;\n session: { id: string } | null;\n state?: unknown;\n };\n send: (ws: WebSocket, msg: object) => void;\n broadcast: (msg: object) => void;\n /**\n * Optional mutator for in-memory todo state. Servers that manage live\n * agent state (e.g. the CLI embedded server) provide this so handlers\n * can update the agent's todo list directly. Standalone server may omit.\n */\n replaceTodos?: (todos: TodoItem[]) => void;\n}\n\n// ── Todos ─────────────────────────────────────────────────────────────────────\n\nexport function handleTodosGet(ctx: WorklistContext, ws: WebSocket): void {\n ctx.send(ws, { type: 'todos.updated', payload: { todos: ctx.context.todos } });\n}\n\nexport function handleTodosClear(ctx: WorklistContext, ws: WebSocket): void {\n ctx.replaceTodos?.([]);\n ctx.broadcast({ type: 'todos.cleared' });\n sendResult(ws, ctx, true, 'Todo board cleared.');\n}\n\nexport function handleTodosRemove(\n ctx: WorklistContext,\n ws: WebSocket,\n payload: { id?: string; index?: number } | undefined,\n): void {\n if (!payload || (payload.id === undefined && payload.index === undefined)) {\n sendResult(ws, ctx, false, 'todos.remove requires id or index.');\n return;\n }\n const next =\n payload.id !== undefined\n ? ctx.context.todos.filter((t) => t.id !== payload.id)\n : ctx.context.todos.filter((_, i) => i !== (payload.index as number));\n ctx.replaceTodos?.(next);\n ctx.broadcast({ type: 'todos.updated', payload: { todos: next } });\n sendResult(ws, ctx, true, 'Todo item removed.');\n}\n\nexport function handleTodoUpdate(\n ctx: WorklistContext,\n ws: WebSocket,\n payload: { id: string; status?: TodoItem['status']; activeForm?: string },\n): void {\n const todo = ctx.context.todos.find((t) => t.id === payload.id);\n if (!todo) {\n sendResult(ws, ctx, false, `No todo with id \"${payload.id}\".`);\n return;\n }\n const next = ctx.context.todos.map((t) =>\n t.id === payload.id\n ? { ...t, ...(payload.status !== undefined && { status: payload.status }), ...(payload.activeForm !== undefined && { activeForm: payload.activeForm }) }\n : t,\n );\n ctx.replaceTodos?.(next);\n ctx.broadcast({ type: 'todos.updated', payload: { todos: next } });\n sendResult(ws, ctx, true, `Todo \"${todo.content}\" updated.`);\n}\n\n// ── Tasks ─────────────────────────────────────────────────────────────────────\n\nexport async function handleTasksGet(ctx: WorklistContext, ws: WebSocket): Promise<void> {\n const taskPath = ctx.context.meta['task.path'];\n if (typeof taskPath === 'string' && taskPath) {\n try {\n const { loadTasks } = await import('@wrongstack/core');\n const file = await loadTasks(taskPath);\n ctx.send(ws, { type: 'tasks.updated', payload: { tasks: file?.tasks ?? [] } });\n } catch {\n ctx.send(ws, { type: 'tasks.updated', payload: { tasks: [] } });\n }\n } else {\n ctx.send(ws, {\n type: 'tasks.updated',\n payload: { tasks: [], error: 'Task storage not configured.' },\n });\n }\n}\n\nexport async function handleTaskUpdate(\n ctx: WorklistContext,\n ws: WebSocket,\n payload: {\n id: string;\n status: 'pending' | 'in_progress' | 'blocked' | 'failed' | 'review' | 'completed';\n },\n): Promise<void> {\n const taskPath = ctx.context.meta['task.path'];\n if (typeof taskPath !== 'string' || !taskPath) {\n sendResult(ws, ctx, false, 'Task storage is not configured for this session.');\n return;\n }\n try {\n const { loadTasks, saveTasks } = await import('@wrongstack/core');\n const file = await loadTasks(taskPath);\n if (!file) {\n sendResult(ws, ctx, false, 'No task file found.');\n return;\n }\n const idx = file.tasks.findIndex((t) => t.id === payload.id);\n if (idx === -1) {\n sendResult(ws, ctx, false, `Task \"${payload.id}\" not found.`);\n return;\n }\n file.tasks[idx] = { ...file.tasks[idx], status: payload.status };\n await saveTasks(taskPath, file);\n ctx.broadcast({ type: 'tasks.updated', payload: { tasks: file.tasks } });\n sendResult(ws, ctx, true, `Task \"${payload.id}\" marked ${payload.status}.`);\n } catch (err) {\n sendResult(ws, ctx, false, String(err));\n }\n}\n\n// ── Plan ───────────────────────────────────────────────────────────────────────\n\nexport async function handlePlanGet(ctx: WorklistContext, ws: WebSocket): Promise<void> {\n const planPath = ctx.context.meta['plan.path'];\n const sessionId = ctx.context.session?.id ?? '';\n if (typeof planPath === 'string' && planPath) {\n try {\n const { loadPlan } = await import('@wrongstack/core');\n const plan = await loadPlan(planPath);\n ctx.send(ws, {\n type: 'plan.updated',\n payload: {\n plan: plan ?? {\n version: 1,\n sessionId,\n updatedAt: new Date().toISOString(),\n items: [],\n },\n },\n });\n } catch {\n ctx.send(ws, {\n type: 'plan.updated',\n payload: {\n plan: {\n version: 1,\n sessionId,\n updatedAt: new Date().toISOString(),\n items: [],\n },\n },\n });\n }\n } else {\n ctx.send(ws, {\n type: 'plan.updated',\n payload: { plan: null, error: 'Plan storage is not configured for this session.' },\n });\n }\n}\n\nexport async function handlePlanTemplateUse(ctx: WorklistContext, ws: WebSocket, template: string): Promise<void> {\n const planPath = ctx.context.meta['plan.path'];\n const sessionId = ctx.context.session?.id ?? '';\n if (typeof planPath !== 'string' || !planPath) {\n sendResult(ws, ctx, false, 'Plan storage is not configured for this session.');\n return;\n }\n try {\n const { getPlanTemplate, loadPlan, savePlan, emptyPlan, addPlanItem } = await import('@wrongstack/core');\n const tpl = getPlanTemplate(template);\n if (!tpl) {\n sendResult(ws, ctx, false, `Unknown template \"${template}\".`);\n return;\n }\n let plan = (await loadPlan(planPath)) ?? emptyPlan(sessionId);\n for (const item of tpl.items) {\n ({ plan } = addPlanItem(plan, item.title, item.details));\n }\n await savePlan(planPath, plan);\n sendResult(ws, ctx, true, `Applied template \"${tpl.name}\" — ${tpl.items.length} items added.`);\n ctx.broadcast({ type: 'plan.updated', payload: { plan } });\n } catch (err) {\n sendResult(ws, ctx, false, String(err));\n }\n}\n\nexport async function handlePlanItemUpdate(\n ctx: WorklistContext,\n ws: WebSocket,\n payload: { target: string; status: 'open' | 'in_progress' | 'done' },\n): Promise<void> {\n const planPath = ctx.context.meta['plan.path'];\n const sessionId = ctx.context.session?.id ?? '';\n if (typeof planPath !== 'string' || !planPath) {\n sendResult(ws, ctx, false, 'Plan storage is not configured for this session.');\n return;\n }\n try {\n const { mutatePlan, setPlanItemStatus } = await import('@wrongstack/core');\n let changed = false;\n const plan = await mutatePlan(planPath, sessionId, async (p) => {\n const before = p.updatedAt;\n const updated = setPlanItemStatus(p, payload.target, payload.status);\n changed = updated.updatedAt !== before;\n return updated;\n });\n if (!changed) {\n sendResult(ws, ctx, false, `No plan item matched \"${payload.target}\".`);\n return;\n }\n sendResult(ws, ctx, true, `Plan item status updated to \"${payload.status}\".`);\n ctx.broadcast({ type: 'plan.updated', payload: { plan } });\n } catch (err) {\n sendResult(ws, ctx, false, String(err));\n }\n}\n\n// ── Dispatcher ──────────────────────────────────────────────────────────────────\n// Single entry point for the nine worklist message types, so the host server's\n// switch delegates one grouped case here instead of repeating the per-type\n// `makeWorklistContext()` boilerplate. Unknown types are a no-op (the caller\n// only routes worklist types to this function).\n\n/** Loosely-typed worklist WS message — payload shapes are narrowed per case. */\nexport interface WorklistMessage {\n type: string;\n payload?: unknown;\n}\n\nexport async function handleWorklistMessage(\n ctx: WorklistContext,\n ws: WebSocket,\n msg: WorklistMessage,\n): Promise<void> {\n switch (msg.type) {\n case 'todos.get':\n handleTodosGet(ctx, ws);\n return;\n case 'todos.clear':\n handleTodosClear(ctx, ws);\n return;\n case 'todos.remove':\n handleTodosRemove(ctx, ws, msg.payload as { id?: string; index?: number } | undefined);\n return;\n case 'todo.update':\n handleTodoUpdate(\n ctx,\n ws,\n msg.payload as { id: string; status?: TodoItem['status']; activeForm?: string },\n );\n return;\n case 'tasks.get':\n await handleTasksGet(ctx, ws);\n return;\n case 'task.update':\n await handleTaskUpdate(\n ctx,\n ws,\n msg.payload as {\n id: string;\n status: 'pending' | 'in_progress' | 'blocked' | 'failed' | 'review' | 'completed';\n },\n );\n return;\n case 'plan.get':\n await handlePlanGet(ctx, ws);\n return;\n case 'plan.template_use': {\n const parsed = validatePlanTemplateUsePayload(msg.payload);\n if (!parsed.ok) {\n sendResult(ws, ctx, false, parsed.message);\n return;\n }\n await handlePlanTemplateUse(ctx, ws, parsed.value.template);\n return;\n }\n case 'plan.item.update':\n await handlePlanItemUpdate(\n ctx,\n ws,\n msg.payload as { target: string; status: 'open' | 'in_progress' | 'done' },\n );\n return;\n }\n}\n","import { resolveProjectDir, wstackGlobalRoot } from '@wrongstack/core';\nimport { readLiveLock } from '@wrongstack/core/coordination';\n\nexport interface MailboxBridgeParams {\n projectRoot: string;\n config: { features?: { mailboxBridge?: 'auto' | 'off' | undefined } } | undefined;\n logger: {\n debug: (msg: string, meta?: Record<string, unknown>) => void;\n warn: (msg: string, meta?: Record<string, unknown>) => void;\n info: (msg: string, meta?: Record<string, unknown>) => void;\n };\n ctx: { meta: Record<string, unknown> };\n}\n\n/**\n * Attempt to discover and join a running mailbox bridge server.\n *\n * Checks the project's live-lock file for an active bridge instance.\n * When found, stores the bridge URL and token in ctx.meta so the\n * backend services can use it. When absent or unhealthy, logs a\n * message and continues without external-agent connectivity.\n */\nexport async function discoverMailboxBridgeForWebui(params: MailboxBridgeParams): Promise<void> {\n const mode = params.config?.features?.mailboxBridge ?? 'auto';\n if (mode === 'off') return;\n\n const projectDir = resolveProjectDir(params.projectRoot, wstackGlobalRoot());\n const result = await readLiveLock(projectDir);\n switch (result.kind) {\n case 'live': {\n params.logger.debug('webui joined existing mailbox bridge', {\n url: result.lock.url,\n lockPath: projectDir,\n });\n params.ctx.meta['mailboxBridge'] = {\n url: result.lock.url,\n token: result.lock.token,\n lockPath: projectDir,\n childPid: null,\n source: 'joined',\n };\n break;\n }\n case 'probe-failed': {\n params.logger.warn(\n 'mailbox bridge present but /healthz unreachable; webui will start without external-agent connectivity',\n { url: result.lock.url, lockPath: projectDir },\n );\n params.ctx.meta['mailboxBridge'] = {\n url: result.lock.url,\n token: result.lock.token,\n lockPath: projectDir,\n childPid: null,\n source: 'unhealthy',\n };\n break;\n }\n case 'absent': {\n params.logger.info(\n 'no mailbox bridge running; webui will start without external-agent connectivity. Run `wstack mailbox serve` or a CLI surface to bring one up.',\n { projectDir },\n );\n break;\n }\n }\n}\n","/**\n * Static-file HTTP server for the WebUI React frontend.\n *\n * - Serves files from `distDir` (typically `<webui>/dist`).\n * - Returns `index.html` for any unknown path so client-side routing works\n * (SPA fallback) — and applies the same Content-Security-Policy to that\n * fallback as to a direct `.html` response, so deep-linked routes are\n * not unprotected.\n * - **Path-traversal guard**: `path.join` alone does NOT prevent\n * `%2e%2e%2f` escapes (the `URL` constructor decodes percent-encoding\n * before we see the path). We re-`resolve` the candidate and verify it\n * stays under `distDir`.\n * - **CSP**: `connect-src` uses explicit loopback addresses for the WS\n * server (not bare `ws:` / `wss:`) so a malicious page script cannot\n * dial an attacker-controlled WebSocket. Combined with the\n * cookie-based WS auth delivery (`/ws-auth` → `Set-Cookie: ws_token=\n * …; HttpOnly; SameSite=Strict; Path=/`), this prevents cross-origin\n * WS abuse.\n * - **Access auth**: on non-loopback binds, all HTTP routes require the same\n * shared token as the WS upgrade, accepted via `?token=...`, `X-WS-Token`,\n * or the `ws_token` HttpOnly cookie. This protects the React UI and the\n * `/api/*` control/read endpoints when `WS_HOST=0.0.0.0`.\n *\n * Extracted from `index.ts` so the static-serve concern can be tested\n * with a tiny fake `distDir` and asserted on path-traversal, MIME\n * matching, and CSP header presence.\n */\nimport * as fs from 'node:fs/promises';\nimport * as http from 'node:http';\nimport * as path from 'node:path';\nimport {\n handleApiFleetBroadcast,\n handleApiSessionAgents,\n handleApiSessionEvents,\n handleApiSessionInterrupt,\n handleApiSessionMailbox,\n handleApiSessionMessage,\n handleApiSessions,\n} from './http-server/api-handlers.js';\nimport { extractTokenFromCookie, isLoopbackBind, tokenMatches } from './ws-auth.js';\nimport type { FileWatcherMetrics } from './setup-events.js';\n\nexport interface CreateHttpServerOptions {\n /** Port to listen on. Defaults to 3456 (or the `PORT` env var). */\n port?: number | undefined;\n /** Host/interface to bind. Typically the loopback for the WebUI. */\n host: string;\n /** Resolved path to the directory containing the built React assets. */\n distDir: string;\n /**\n * WS port — appears in the CSP `connect-src` directive so the browser\n * is allowed to open a WebSocket back to the local server.\n */\n wsPort: number;\n /**\n * Public WebSocket URL injected into the frontend. Use this behind tunnels or\n * reverse proxies where the browser-facing WS URL differs from host:wsPort.\n */\n publicWsUrl?: string | undefined;\n /**\n * Path to the global WrongStack root (~/.wrongstack). Used by the\n * /api/sessions and /api/sessions/:id/agents endpoints to read the\n * cross-process SessionRegistry.\n */\n globalRoot?: string | undefined;\n /**\n * Shared auth token for HTTP and WS access. Required for non-loopback\n * binds (LAN exposure). Loopback binds accept local browser access without\n * a token (the WS path's loopback-bootstrap policy — see ws-auth.ts).\n */\n apiToken?: string | undefined;\n /** Force HTTP token auth even on loopback binds, useful behind public tunnels. */\n requireToken?: boolean | undefined;\n /**\n * If true, the `/ws-auth` endpoint exchanges a `?token=` query param (or\n * `X-WS-Token` header) for an `HttpOnly` auth cookie. The cookie is then\n * sent automatically on the WS upgrade, closing the C-598 query-string\n * token exposure class. Default: true. Set to false to keep the legacy\n * URL-token-only flow (e.g. in tests that don't want cookie state).\n */\n enableWsCookie?: boolean | undefined;\n /**\n * Optional file watcher metrics object. When provided, the\n * /debug/watcher-metrics endpoint will be enabled to expose these metrics.\n */\n watcherMetrics?: FileWatcherMetrics | undefined;\n /**\n * Push-on-write hook. `POST /api/fleet/ping` (loopback only) invokes this to\n * trigger an immediate fleet re-broadcast, so a TUI/REPL's registry write\n * reaches the map without waiting on the file-watch/poll. Best-effort.\n */\n onFleetPing?: (() => void) | undefined;\n}\n\nconst MIME_TYPES: Record<string, string> = {\n '.html': 'text/html',\n '.js': 'application/javascript',\n '.css': 'text/css',\n '.json': 'application/json',\n '.svg': 'image/svg+xml',\n '.png': 'image/png',\n '.ico': 'image/x-icon',\n};\n\n/**\n * Inject the live WS port into the served HTML so the frontend connects to\n * THIS instance's backend instead of a hardcoded default. Enables running\n * several WebUI instances simultaneously on different PORT/WS_PORT pairs\n * (e.g. one per project) — each instance serves HTML stamped with its own\n * WS port.\n *\n * A `<meta>` tag is used deliberately rather than an inline `<script>`: the\n * CSP sets `script-src 'self'`, which would block an inline script, but meta\n * tags are not subject to script-src. The frontend reads\n * `meta[name=\"wrongstack-ws-port\"]` (see ws-client.ts `defaultWsUrl`).\n */\nexport function injectWsPort(html: string, wsPort: number): string {\n const tag = `<meta name=\"wrongstack-ws-port\" content=\"${wsPort}\" />`;\n // Idempotent: never inject twice if the source HTML already carries one.\n if (html.includes('name=\"wrongstack-ws-port\"')) return html;\n if (html.includes('</head>')) {\n return html.replace('</head>', ` ${tag}\\n </head>`);\n }\n // No <head> (unexpected) — prepend so the tag is still in the document.\n return `${tag}\\n${html}`;\n}\n\nfunction escapeHtmlAttr(value: string): string {\n return value\n .replace(/&/g, '&amp;')\n .replace(/\"/g, '&quot;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;');\n}\n\nexport function injectWsConfig(\n html: string,\n opts: { wsPort: number; publicWsUrl?: string | undefined },\n): string {\n let out = injectWsPort(html, opts.wsPort);\n if (!opts.publicWsUrl || out.includes('name=\"wrongstack-ws-url\"')) return out;\n const tag = `<meta name=\"wrongstack-ws-url\" content=\"${escapeHtmlAttr(opts.publicWsUrl)}\" />`;\n if (out.includes('</head>')) {\n return out.replace('</head>', ` ${tag}\\n </head>`);\n }\n return `${tag}\\n${out}`;\n}\n\nfunction firstHeader(value: string | string[] | undefined): string | undefined {\n return Array.isArray(value) ? value[0] : value;\n}\n\nfunction wsTokenCookie(token: string): string {\n return `ws_token=${encodeURIComponent(token)}; HttpOnly; SameSite=Strict; Path=/; Max-Age=3600`;\n}\n\nfunction requestToken(req: http.IncomingMessage, url: URL): string | undefined {\n return (\n url.searchParams.get('token') ??\n firstHeader(req.headers['x-ws-token']) ??\n extractTokenFromCookie(req.headers.cookie)\n );\n}\n\nfunction requestHostForCsp(hostHeader: string | string[] | undefined): string | undefined {\n const raw = firstHeader(hostHeader)?.trim();\n if (!raw) return undefined;\n try {\n return new URL(`http://${raw}`).hostname;\n } catch {\n return undefined;\n }\n}\n\nfunction formatCspHostname(hostname: string): string {\n return hostname.includes(':') && !hostname.startsWith('[') ? `[${hostname}]` : hostname;\n}\n\nfunction cspSourceFromUrl(rawUrl: string): string | undefined {\n try {\n const url = new URL(rawUrl);\n if (url.protocol !== 'ws:' && url.protocol !== 'wss:') return undefined;\n return `${url.protocol}//${formatCspHostname(url.hostname)}${url.port ? `:${url.port}` : ''}`;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Inline-script hashes allow-listed in the production CSP.\n *\n * `script-src 'self'` blocks every inline `<script>`, including those Chrome\n * extensions inject as their content-script bootstrap (the browser reports\n * them from `content.js:74:196`). The hash list reported in the CSP violation\n * message is exactly the script bytes Chrome computed — adding those hashes\n * as `'sha256-…'` sources lets only those two extension bootstraps through\n * (and any future hash we add here), without re-enabling `'unsafe-inline'`\n * for the whole app. The WrongStack frontend itself ships no inline scripts,\n * so the policy stays strict for our own code.\n */\nconst ALLOWED_INLINE_SCRIPT_HASHES: readonly string[] = [\n \"'sha256-6PXDy0zrpXa6mvYOl11bZ8nubNUL7ushPUhGDZtaexg='\",\n \"'sha256-6sIdwbEBx7jj0drqSHHm7MqvmoYD3CQ4lp8Zp8blcb0='\",\n];\n\n/** Build the Content-Security-Policy value for the given WS port. */\nexport function buildCspHeader(\n wsPort: number,\n requestHost?: string | undefined,\n publicWsUrl?: string | undefined,\n): string {\n const connect = new Set([\n \"'self'\",\n `ws://127.0.0.1:${wsPort}`,\n `wss://127.0.0.1:${wsPort}`,\n ]);\n if (requestHost && requestHost !== '127.0.0.1' && requestHost !== '::1' && requestHost !== '[::1]') {\n const host = formatCspHostname(requestHost);\n connect.add(`ws://${host}:${wsPort}`);\n connect.add(`wss://${host}:${wsPort}`);\n }\n const publicWsSource = publicWsUrl ? cspSourceFromUrl(publicWsUrl) : undefined;\n if (publicWsSource) connect.add(publicWsSource);\n const scriptSrc = [\"'self'\", ...ALLOWED_INLINE_SCRIPT_HASHES].join(' ');\n return (\n `default-src 'self'; script-src ${scriptSrc}; style-src 'self' 'unsafe-inline'; ` +\n `connect-src ${Array.from(connect).join(' ')}; ` +\n `img-src 'self' data:; font-src 'self' data:; worker-src 'self' blob:; object-src 'none'; ` +\n `base-uri 'self'; frame-ancestors 'none'; form-action 'self'`\n );\n}\n\n/**\n * Returns true when `candidate` (a fully-resolved absolute path) lies\n * strictly inside `distDir` (or equals it). Used to reject path-traversal\n * attempts after `path.resolve` has normalised any `..` segments.\n *\n * Exported so tests can assert the guard's contract without having to\n * also defeat the WHATWG URL normaliser (which strips `..` from the\n * path string *before* the request even reaches the server, making a\n * black-box test via fetch impossible).\n */\nexport function isInsideDist(candidate: string, distDir: string): boolean {\n const root = path.resolve(distDir);\n const resolved = path.resolve(candidate);\n return resolved === root || resolved.startsWith(root + path.sep);\n}\n\n/**\n * Decode a `:id` path segment captured by the `/api/sessions/:id/*` routes.\n *\n * Session ids are `YYYY-MM-DD/HH-MM-SSZ_model_hash` — they contain a literal\n * `/`. The frontend builds the URL with `encodeURIComponent(sessionId)`, so\n * that slash arrives as `%2F`. The route regex `([^/]+)` correctly captures\n * the whole percent-encoded segment (there is no real `/` in `%2F`), but the\n * SessionRegistry is keyed by the *decoded* id — so the capture must be\n * `decodeURIComponent`d before lookup. Without this, every\n * `/api/sessions/:id/{events,message,agents}` request 404s (the registry has\n * `2026-…/…` but we looked up `2026-…%2F…`), which broke the Fleet HQ\n * watch-stream and the steer-message composer.\n *\n * Malformed percent-encoding (a lone `%`) makes `decodeURIComponent` throw;\n * fall back to the raw segment so the caller still gets a clean 404 rather\n * than a 500.\n */\nexport function decodeSessionId(segment: string): string {\n try {\n return decodeURIComponent(segment);\n } catch {\n return segment;\n }\n}\n\n/**\n * Create the static-file HTTP server. Returns the `http.Server` (not\n * listening yet) so the caller can attach to a `shutdown()` hook and\n * coordinate the listen() with the WebSocket bootstrap.\n */\nexport function createHttpServer(opts: CreateHttpServerOptions): http.Server {\n const port = opts.port ?? Number.parseInt(process.env['PORT'] ?? '3456', 10);\n const distDir = path.resolve(opts.distDir);\n const wsPort = opts.wsPort;\n // Loopback bind: no HTTP token required (mirrors WS loopback-bootstrap).\n // LAN bind: caller MUST supply a token; fail closed if it is absent.\n const requireAccessToken = Boolean(opts.requireToken) || !isLoopbackBind(opts.host);\n\n return http.createServer(async (req, res) => {\n try {\n const url = new URL(req.url ?? '/', `http://127.0.0.1:${port}`);\n const providedAccessToken = requestToken(req, url);\n const accessTokenOk =\n Boolean(opts.apiToken) && tokenMatches(providedAccessToken, opts.apiToken ?? '');\n const shouldSetAuthCookie =\n Boolean(opts.apiToken) &&\n tokenMatches(url.searchParams.get('token') ?? undefined, opts.apiToken ?? '');\n\n // ── API routes ──────────────────────────────────────────────────\n // /ws-auth — exchange a one-shot token (header or query) for an\n // HttpOnly cookie. The browser then sends the cookie on the WS\n // upgrade automatically, closing C-598 (token-in-URL). Disabled\n // when `enableWsCookie: false` (tests, or operators who prefer\n // the URL-token flow for explicit dev).\n if (url.pathname === '/ws-auth' && req.method === 'GET' && (opts.enableWsCookie ?? true)) {\n // Accept the token from `?token=` query (browser navigation\n // from the server-printed URL) OR the `X-WS-Token` header\n // (scripted client).\n const provided = requestToken(req, url);\n if (!provided || !opts.apiToken || !tokenMatches(provided, opts.apiToken)) {\n res.writeHead(401, { 'Content-Type': 'text/plain' });\n res.end('Unauthorized');\n return;\n }\n // HttpOnly + SameSite=Strict + Path=/ — the cookie is immune to\n // XSS exfiltration (no JS access), cross-origin Referer leakage\n // (Strict blocks cross-site), and is scoped to this origin only.\n // No `Secure` flag: the dev server is plain HTTP on loopback,\n // and a Secure cookie over HTTP would not be sent by the browser.\n res.writeHead(200, {\n 'Content-Type': 'text/plain',\n 'Set-Cookie': wsTokenCookie(opts.apiToken),\n // Belt-and-braces: tell any caches the cookie response itself\n // is sensitive.\n 'Cache-Control': 'no-store',\n });\n res.end('ok');\n return;\n }\n\n if (requireAccessToken && !accessTokenOk) {\n res.writeHead(401, {\n 'Content-Type': 'text/plain',\n 'Cache-Control': 'no-store',\n });\n res.end('Unauthorized');\n return;\n }\n\n if (shouldSetAuthCookie && opts.apiToken) {\n res.setHeader('Set-Cookie', wsTokenCookie(opts.apiToken));\n res.setHeader('Cache-Control', 'no-store');\n }\n\n // /api/fleet/ping — push-on-write nudge from a same-project TUI/REPL.\n // Triggers an immediate fleet re-broadcast of data the WS clients already\n // receive (no new disclosure, no persistent mutation). Same auth posture\n // as /api/sessions: open on loopback, token-gated on a LAN bind.\n if (url.pathname === '/api/fleet/ping' && req.method === 'POST') {\n if (requireAccessToken && !accessTokenOk) {\n res.writeHead(401, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Unauthorized' }));\n return;\n }\n try {\n opts.onFleetPing?.();\n } catch {\n /* best-effort */\n }\n res.writeHead(204);\n res.end();\n return;\n }\n\n if (url.pathname === '/api/sessions' && req.method === 'GET') {\n if (requireAccessToken && !accessTokenOk) {\n res.writeHead(401, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Unauthorized' }));\n return;\n }\n await handleApiSessions(res, opts.globalRoot);\n return;\n }\n\n const agentsMatch = url.pathname.match(/^\\/api\\/sessions\\/([^/]+)\\/agents$/);\n if (agentsMatch && req.method === 'GET') {\n if (requireAccessToken && !accessTokenOk) {\n res.writeHead(401, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Unauthorized' }));\n return;\n }\n await handleApiSessionAgents(res, opts.globalRoot, decodeSessionId(agentsMatch[1]!));\n return;\n }\n\n // /api/sessions/:id/events — replay another session's conversation +\n // tool stream (read-only) so the WebUI can *watch* a TUI/REPL running in\n // the same project. Reads that session's JSONL via the core session\n // reader; the browser re-fetches to tail it live.\n const eventsMatch = url.pathname.match(/^\\/api\\/sessions\\/([^/]+)\\/events$/);\n if (eventsMatch && req.method === 'GET') {\n if (requireAccessToken && !accessTokenOk) {\n res.writeHead(401, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Unauthorized' }));\n return;\n }\n const rawLimit = Number.parseInt(url.searchParams.get('limit') ?? '200', 10);\n const limit = Math.min(500, Math.max(1, Number.isFinite(rawLimit) ? rawLimit : 200));\n await handleApiSessionEvents(res, opts.globalRoot, decodeSessionId(eventsMatch[1]!), limit);\n return;\n }\n\n // /api/sessions/:id/message — send a steering message into another\n // session's mailbox. Its running agent injects pending mailbox messages\n // before each LLM call, so this is two-way control: the WebUI steers a\n // TUI/REPL working in the same project. Loopback-open, token-gated on LAN.\n const msgMatch = url.pathname.match(/^\\/api\\/sessions\\/([^/]+)\\/message$/);\n if (msgMatch && req.method === 'POST') {\n if (requireAccessToken && !accessTokenOk) {\n res.writeHead(401, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Unauthorized' }));\n return;\n }\n await handleApiSessionMessage(res, req, opts.globalRoot, decodeSessionId(msgMatch[1]!));\n return;\n }\n\n // /api/sessions/:id/mailbox — the human<->leader thread (read-receipts +\n // replies). Makes the two-way loop visible in Fleet HQ.\n const mailboxMatch = url.pathname.match(/^\\/api\\/sessions\\/([^/]+)\\/mailbox$/);\n if (mailboxMatch && req.method === 'GET') {\n if (requireAccessToken && !accessTokenOk) {\n res.writeHead(401, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Unauthorized' }));\n return;\n }\n await handleApiSessionMailbox(res, opts.globalRoot, decodeSessionId(mailboxMatch[1]!));\n return;\n }\n\n // /api/sessions/:id/interrupt — cooperative stop (control message).\n const interruptMatch = url.pathname.match(/^\\/api\\/sessions\\/([^/]+)\\/interrupt$/);\n if (interruptMatch && req.method === 'POST') {\n if (requireAccessToken && !accessTokenOk) {\n res.writeHead(401, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Unauthorized' }));\n return;\n }\n await handleApiSessionInterrupt(\n res,\n req,\n opts.globalRoot,\n decodeSessionId(interruptMatch[1]!),\n );\n return;\n }\n\n // /api/fleet/broadcast — one message to every live session's leader.\n if (url.pathname === '/api/fleet/broadcast' && req.method === 'POST') {\n if (requireAccessToken && !accessTokenOk) {\n res.writeHead(401, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Unauthorized' }));\n return;\n }\n await handleApiFleetBroadcast(res, req, opts.globalRoot);\n return;\n }\n\n // Debug endpoint: /debug/watcher-metrics\n // Returns file watcher metrics as JSON. Protected by the same HTTP access\n // token when the server is bound beyond loopback.\n if (url.pathname === '/debug/watcher-metrics' && req.method === 'GET') {\n if (opts.watcherMetrics) {\n // Update computed fields before returning\n const avgDelay = opts.watcherMetrics.broadcastsSent > 0\n ? opts.watcherMetrics.totalDebounceDelayMs / opts.watcherMetrics.broadcastsSent\n : 0;\n const response = {\n ...opts.watcherMetrics,\n averageDebounceDelayMs: avgDelay,\n timestamp: Date.now(),\n };\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify(response));\n } else {\n res.writeHead(503, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'File watcher metrics not available' }));\n }\n return;\n }\n\n let filePath: string;\n\n if (url.pathname === '/' || url.pathname === '') {\n filePath = path.join(distDir, 'index.html');\n } else if (url.pathname.startsWith('/assets/')) {\n filePath = path.join(distDir, url.pathname);\n } else if (url.pathname.startsWith('/')) {\n filePath = path.join(distDir, url.pathname);\n } else {\n filePath = path.join(distDir, 'index.html');\n }\n\n // Path traversal guard: the resolved path must stay inside distDir.\n // WHATWG URL leaves percent-encoding alone in `url.pathname` (it\n // does not decode `%2e%2e` to `..`), so percent-encoded escapes\n // are *not* a concern here — but unencoded `..` segments are\n // normalised by `path.resolve` and would walk the candidate up\n // out of distDir. `isInsideDist` catches that.\n const resolvedPath = path.resolve(filePath);\n if (!isInsideDist(resolvedPath, distDir)) {\n res.writeHead(403, { 'Content-Type': 'text/plain' });\n res.end('Forbidden');\n return;\n }\n\n const ext = path.extname(resolvedPath);\n const contentType = MIME_TYPES[ext] ?? 'application/octet-stream';\n res.setHeader('Content-Type', contentType);\n res.setHeader('X-Content-Type-Options', 'nosniff');\n res.setHeader('X-Frame-Options', 'DENY');\n res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');\n\n if (ext === '.html') {\n if (!shouldSetAuthCookie) res.setHeader('Cache-Control', 'no-cache');\n res.setHeader(\n 'Content-Security-Policy',\n buildCspHeader(wsPort, requestHostForCsp(req.headers.host), opts.publicWsUrl),\n );\n // Stamp the live WS port into the HTML so the frontend dials this\n // instance's backend (not the hardcoded default) — required for\n // running multiple WebUI instances on different ports.\n const html = await fs.readFile(resolvedPath, 'utf8');\n res.writeHead(200);\n res.end(injectWsConfig(html, { wsPort, publicWsUrl: opts.publicWsUrl }));\n return;\n }\n\n const fileContent = await fs.readFile(resolvedPath);\n res.writeHead(200);\n res.end(fileContent);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n // SPA fallback: serve index.html so client-side routing still works.\n try {\n const html = await fs.readFile(path.join(distDir, 'index.html'), 'utf8');\n res.writeHead(200, {\n 'Content-Type': 'text/html',\n 'X-Content-Type-Options': 'nosniff',\n 'X-Frame-Options': 'DENY',\n 'Referrer-Policy': 'strict-origin-when-cross-origin',\n 'Content-Security-Policy': buildCspHeader(\n wsPort,\n requestHostForCsp(req.headers.host),\n opts.publicWsUrl,\n ),\n });\n res.end(injectWsConfig(html, { wsPort, publicWsUrl: opts.publicWsUrl }));\n } catch {\n res.writeHead(404);\n res.end('Not found');\n }\n } else {\n res.writeHead(500);\n res.end('Server error');\n }\n }\n });\n}\n","/**\n * HTTP /api/* request handlers for the WebUI server — extracted from\n * http-server.ts to keep the static-serve/routing concern separate from the\n * (substantial) Fleet-HQ session/mailbox API. Every handler is a pure,\n * param-based function: it takes the Node req/res plus the globalRoot and reads\n * the cross-process SessionRegistry / GlobalMailbox via dynamic core imports.\n * createHttpServer() in http-server.ts dispatches to these.\n */\nimport type * as http from 'node:http';\n\nexport async function handleApiSessions(\n res: http.ServerResponse,\n globalRoot: string | undefined,\n): Promise<void> {\n if (!globalRoot) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'SessionRegistry not available' }));\n return;\n }\n\n try {\n const { SessionRegistry } = await import('@wrongstack/core');\n const registry = new SessionRegistry(globalRoot);\n const sessions = await registry.list();\n\n const result = sessions.map((s) => ({\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.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\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: String(err) }));\n }\n}\n\nexport async function handleApiSessionAgents(\n res: http.ServerResponse,\n globalRoot: string | undefined,\n sessionId: string,\n): Promise<void> {\n if (!globalRoot) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'SessionRegistry not available' }));\n return;\n }\n\n try {\n const { SessionRegistry } = await import('@wrongstack/core');\n const registry = new SessionRegistry(globalRoot);\n const entry = await registry.get(sessionId);\n\n if (!entry) {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Session not found' }));\n return;\n }\n\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({\n sessionId: entry.sessionId,\n projectName: entry.projectName,\n status: entry.status,\n agents: entry.agents.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 } catch (err) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: String(err) }));\n }\n}\n\n/** One line in the session \"watch\" stream sent to the browser.\n * Rich enough for the frontend to render full tool call details,\n * markdown, and structured data — not just pre-clipped text. */\ninterface WatchEntry {\n ts: string;\n role: 'user' | 'assistant' | 'tool' | 'system' | 'error';\n /** Human-readable text summary (may be clipped for tool input/output). */\n text: string;\n /** Tool name (for tool-role entries). */\n tool?: string;\n /** Structured tool input (object or array — rendered by ToolInputView). */\n input?: unknown;\n /** Structured tool output (rendered as pre-formatted text / markdown). */\n output?: unknown;\n /** Wall-clock duration in ms (tool call / response). */\n durationMs?: number;\n /** Whether the tool/response had an error. */\n isError?: boolean;\n /** Tool use correlation id — pairs tool_call_start with tool_call_end. */\n toolUseId?: string;\n}\n\n/** Join the text blocks of a message content value into a single string. */\nfunction blocksToText(content: unknown): string {\n if (typeof content === 'string') return content;\n if (Array.isArray(content)) {\n return content\n .filter(\n (b): b is { type: string; text: string } =>\n !!b && typeof b === 'object' && (b as { type?: unknown }).type === 'text' &&\n typeof (b as { text?: unknown }).text === 'string',\n )\n .map((b) => b.text)\n .join('\\n');\n }\n return '';\n}\n\nfunction asString(v: unknown): string {\n if (typeof v === 'string') return v;\n try {\n return JSON.stringify(v, null, 2);\n } catch {\n return String(v);\n }\n}\n\n/** Map a raw session event to a watch entry. Returns rich structured data\n * for tool calls (input + output + duration) so the frontend can render\n * full detail via WatchMessageBubble — matching the main ChatView. */\nfunction mapWatchEntry(ev: Record<string, unknown>): WatchEntry | null {\n const ts = typeof ev['ts'] === 'string' ? (ev['ts'] as string) : '';\n switch (ev['type']) {\n case 'user_input': {\n const text = blocksToText(ev['content']);\n return text.trim() ? { ts, role: 'user', text } : null;\n }\n case 'llm_response': {\n const text = blocksToText(ev['content']);\n return text.trim() ? { ts, role: 'assistant', text } : null;\n }\n case 'tool_use':\n case 'tool_call_start': {\n const toolName = String(ev['name'] ?? 'tool');\n const input = ev['input'] ?? ev['args'];\n const text = input !== undefined && input !== null ? asString(input) : '';\n const toolUseId = typeof ev['id'] === 'string' ? ev['id'] : undefined;\n return { ts, role: 'tool', tool: toolName, text, input, toolUseId };\n }\n case 'tool_call_end':\n case 'tool_result': {\n const isError = ev['isError'] === true;\n const content = ev['output'] ?? ev['content'];\n const outStr = content !== undefined && content !== null ? asString(content) : '';\n const durationMs = typeof ev['durationMs'] === 'number' ? ev['durationMs'] : undefined;\n const toolUseId = typeof ev['id'] === 'string' ? ev['id'] : undefined;\n const toolName = typeof ev['name'] === 'string' ? String(ev['name']) : '↳ result';\n if (!outStr.trim() && !isError) return null;\n return { ts, role: isError ? 'error' : 'tool', tool: toolName, text: outStr, output: content, durationMs, isError, toolUseId };\n }\n case 'error':\n case 'provider_error':\n return { ts, role: 'error', text: String(ev['message'] ?? 'error') };\n case 'agent_spawned':\n return { ts, role: 'system', text: `spawned ${String(ev['role'] ?? 'agent')}` };\n case 'task_completed':\n return { ts, role: 'system', text: `task done: ${String(ev['title'] ?? '')}` };\n case 'task_failed':\n return { ts, role: 'system', text: `task failed: ${String(ev['title'] ?? '')}` };\n default:\n return null;\n }\n}\n\n/** Correlate tool_call_start + tool_call_end events by id and merge them\n * into unified WatchEntry entries with full input+output+duration.\n * Standalone events (unpaired) pass through as-is. */\nfunction correlateToolEvents(entries: WatchEntry[]): WatchEntry[] {\n const pending = new Map<string, WatchEntry>(); // toolUseId → start entry\n const result: WatchEntry[] = [];\n for (const e of entries) {\n if (e.role === 'tool' && e.toolUseId && e.output === undefined && e.durationMs === undefined) {\n // This is a tool_call_start with no result yet — stash it\n pending.set(e.toolUseId, e);\n continue;\n }\n if (e.toolUseId && pending.has(e.toolUseId)) {\n const start = pending.get(e.toolUseId)!;\n pending.delete(e.toolUseId);\n // Merge: keep the start's ts, tool name, and input; add the end's output/duration/error\n result.push({\n ts: start.ts,\n role: e.isError ? 'error' : 'tool',\n text: e.text || start.text,\n tool: start.tool,\n input: start.input,\n output: e.output,\n durationMs: e.durationMs,\n isError: e.isError,\n toolUseId: e.toolUseId,\n });\n continue;\n }\n result.push(e);\n }\n // Unpaired start events: flush at the end\n for (const e of pending.values()) result.push(e);\n return result;\n}\n\nexport async function handleApiSessionEvents(\n res: http.ServerResponse,\n globalRoot: string | undefined,\n sessionId: string,\n limit: number,\n): Promise<void> {\n if (!globalRoot) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'SessionRegistry not available' }));\n return;\n }\n\n try {\n const { SessionRegistry, resolveWstackPaths, DefaultSessionStore, DefaultSessionReader } =\n await import('@wrongstack/core');\n const registry = new SessionRegistry(globalRoot);\n const entry = await registry.get(sessionId);\n if (!entry) {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Session not found' }));\n return;\n }\n\n const paths = resolveWstackPaths({ projectRoot: entry.projectRoot, globalRoot });\n const store = new DefaultSessionStore({ dir: paths.projectSessions });\n const reader = new DefaultSessionReader({ store });\n\n const rawEntries: WatchEntry[] = [];\n for await (const ev of reader.replay(sessionId)) {\n const mapped = mapWatchEntry(ev as never as Record<string, unknown>);\n if (mapped) rawEntries.push(mapped);\n }\n // Correlate paired tool call start+end events for rich combined rendering\n const all = correlateToolEvents(rawEntries);\n const tail = all.slice(-limit);\n\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n sessionId,\n status: entry.status,\n clientType: entry.clientType,\n projectName: entry.projectName,\n total: all.length,\n entries: tail,\n }),\n );\n } catch (err) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: String(err) }));\n }\n}\n\n/** Read and JSON-parse a request body, capped at 64 KiB. */\nfunction readJsonBody(req: http.IncomingMessage): Promise<Record<string, unknown>> {\n return new Promise((resolve, reject) => {\n let data = '';\n req.on('data', (chunk) => {\n data += chunk;\n if (data.length > 64_000) {\n reject(new Error('Request body too large'));\n req.destroy();\n }\n });\n req.on('end', () => {\n try {\n resolve(data ? (JSON.parse(data) as Record<string, unknown>) : {});\n } catch (err) {\n reject(err instanceof Error ? err : new Error(String(err)));\n }\n });\n req.on('error', reject);\n });\n}\n\nexport async function handleApiSessionMessage(\n res: http.ServerResponse,\n req: http.IncomingMessage,\n globalRoot: string | undefined,\n sessionId: string,\n): Promise<void> {\n if (!globalRoot) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'SessionRegistry not available' }));\n return;\n }\n\n let body: Record<string, unknown>;\n try {\n body = await readJsonBody(req);\n } catch {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Invalid request body' }));\n return;\n }\n\n const text = typeof body['text'] === 'string' ? (body['text'] as string).trim() : '';\n if (!text) {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'text is required' }));\n return;\n }\n const from =\n typeof body['from'] === 'string' && (body['from'] as string).trim()\n ? (body['from'] as string).trim()\n : 'human@webui';\n\n // Message kind from Fleet HQ's composer. The agent-loop injects every type\n // before its next LLM call; 'ask'/'assign' carry a stronger call-to-action\n // in the injected block (see buildMailboxBlock). Default 'steer'.\n const ALLOWED = new Set(['steer', 'ask', 'assign', 'note', 'btw']);\n const rawType = typeof body['type'] === 'string' ? (body['type'] as string) : 'steer';\n const type = (ALLOWED.has(rawType) ? rawType : 'steer') as\n | 'steer'\n | 'ask'\n | 'assign'\n | 'note'\n | 'btw';\n const rawPriority = typeof body['priority'] === 'string' ? (body['priority'] as string) : '';\n const priority = (['low', 'normal', 'high'].includes(rawPriority) ? rawPriority : 'high') as\n | 'low'\n | 'normal'\n | 'high';\n const subject =\n typeof body['subject'] === 'string' && (body['subject'] as string).trim()\n ? (body['subject'] as string).trim()\n : 'Message from Fleet HQ';\n\n try {\n const { SessionRegistry, resolveWstackPaths, GlobalMailbox, mailboxSessionTag } =\n await import('@wrongstack/core');\n const registry = new SessionRegistry(globalRoot);\n const entry = await registry.get(sessionId);\n if (!entry) {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Session not found' }));\n return;\n }\n\n const paths = resolveWstackPaths({ projectRoot: entry.projectRoot, globalRoot });\n const mailbox = new GlobalMailbox(paths.projectDir);\n // The target session's leader answers to `leader@<sessionTag>` — its\n // agent-loop checker queries exactly this address before each LLM call.\n const to = `leader@${mailboxSessionTag(sessionId)}`;\n const sent = await mailbox.send({ from, to, type, subject, body: text, priority });\n\n // Return the message id so the caller can poll the thread for read-receipt\n // (readBy) and the agent's reply — the visible two-way feedback loop.\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ ok: true, id: sent.id, to, type, delivered: entry.status }));\n } catch (err) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: String(err) }));\n }\n}\n\n/**\n * GET /api/sessions/:id/mailbox — the human↔leader thread for a session.\n *\n * Returns the messages exchanged between the operator (human@webui) and this\n * session's leader, newest last, with read-receipts (readBy) and completion/\n * outcome. This is what makes the WebUI's two-way loop *visible*: after Fleet\n * HQ sends a steer/ask, the panel shows whether the target read it (✓) and any\n * reply the agent posted back.\n */\nexport async function handleApiSessionMailbox(\n res: http.ServerResponse,\n globalRoot: string | undefined,\n sessionId: string,\n): Promise<void> {\n if (!globalRoot) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'SessionRegistry not available' }));\n return;\n }\n try {\n const { SessionRegistry, resolveWstackPaths, GlobalMailbox, mailboxSessionTag } =\n await import('@wrongstack/core');\n const registry = new SessionRegistry(globalRoot);\n const entry = await registry.get(sessionId);\n if (!entry) {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Session not found' }));\n return;\n }\n const paths = resolveWstackPaths({ projectRoot: entry.projectRoot, globalRoot });\n const mailbox = new GlobalMailbox(paths.projectDir);\n const leaderAddr = `leader@${mailboxSessionTag(sessionId)}`;\n // Messages TO the leader (operator → agent) and FROM the leader (replies).\n const [inbound, outbound] = await Promise.all([\n mailbox.query({ to: leaderAddr, limit: 50 }),\n mailbox.query({ from: leaderAddr, limit: 50 }),\n ]);\n const seen = new Set<string>();\n const thread = [...inbound, ...outbound]\n .filter((m) => {\n if (seen.has(m.id)) return false;\n seen.add(m.id);\n return true;\n })\n .sort((a, b) => Date.parse(a.timestamp) - Date.parse(b.timestamp))\n .map((m) => ({\n id: m.id,\n from: m.from,\n to: m.to,\n type: m.type,\n subject: m.subject,\n body: m.body,\n priority: m.priority,\n // Whether the leader has read it, and when.\n readByLeader: m.readBy?.[leaderAddr] ?? null,\n readByCount: Object.keys(m.readBy ?? {}).length,\n completed: m.completed,\n outcome: m.outcome ?? null,\n timestamp: m.timestamp,\n replyTo: m.replyTo ?? null,\n fromLeader: m.from === leaderAddr,\n }));\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ sessionId, leader: leaderAddr, status: entry.status, thread }));\n } catch (err) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: String(err) }));\n }\n}\n\n/**\n * POST /api/sessions/:id/interrupt — cooperatively halt a running session.\n *\n * Sends a high-priority `control` mailbox message. The target's agent-loop\n * checks the mailbox before each LLM call; on seeing a fresh control:interrupt\n * it stops gracefully at the next iteration boundary (it does NOT kill the\n * process — for a hard stop use the process panel's PID kill). Cross-process\n * interrupt is necessarily cooperative: the WebUI server can't reach another\n * process's AbortController, only its mailbox.\n */\nexport async function handleApiSessionInterrupt(\n res: http.ServerResponse,\n req: http.IncomingMessage,\n globalRoot: string | undefined,\n sessionId: string,\n): Promise<void> {\n if (!globalRoot) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'SessionRegistry not available' }));\n return;\n }\n let body: Record<string, unknown> = {};\n try {\n body = await readJsonBody(req);\n } catch {\n /* interrupt needs no body — ignore parse errors */\n }\n const reason =\n typeof body['reason'] === 'string' && (body['reason'] as string).trim()\n ? (body['reason'] as string).trim()\n : 'Operator requested stop from Fleet HQ';\n const from =\n typeof body['from'] === 'string' && (body['from'] as string).trim()\n ? (body['from'] as string).trim()\n : 'human@webui';\n try {\n const { SessionRegistry, resolveWstackPaths, GlobalMailbox, mailboxSessionTag } =\n await import('@wrongstack/core');\n const registry = new SessionRegistry(globalRoot);\n const entry = await registry.get(sessionId);\n if (!entry) {\n res.writeHead(404, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Session not found' }));\n return;\n }\n const paths = resolveWstackPaths({ projectRoot: entry.projectRoot, globalRoot });\n const mailbox = new GlobalMailbox(paths.projectDir);\n const to = `leader@${mailboxSessionTag(sessionId)}`;\n const sent = await mailbox.send({\n from,\n to,\n type: 'control',\n subject: 'interrupt',\n body: reason,\n priority: 'high',\n });\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ ok: true, id: sent.id, to, delivered: entry.status }));\n } catch (err) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: String(err) }));\n }\n}\n\n/**\n * POST /api/fleet/broadcast — send one message to every live session's leader.\n *\n * Resolves all non-stale sessions in the same project as the WebUI host and\n * sends the message to each session's `leader@<tag>` (a true per-leader fan-out\n * rather than the bare '*' broadcast, so every live leader's mailbox loop —\n * which queries its session-bound id — actually receives it).\n */\nexport async function handleApiFleetBroadcast(\n res: http.ServerResponse,\n req: http.IncomingMessage,\n globalRoot: string | undefined,\n): Promise<void> {\n if (!globalRoot) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'SessionRegistry not available' }));\n return;\n }\n let body: Record<string, unknown>;\n try {\n body = await readJsonBody(req);\n } catch {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'Invalid request body' }));\n return;\n }\n const text = typeof body['text'] === 'string' ? (body['text'] as string).trim() : '';\n if (!text) {\n res.writeHead(400, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: 'text is required' }));\n return;\n }\n const from =\n typeof body['from'] === 'string' && (body['from'] as string).trim()\n ? (body['from'] as string).trim()\n : 'human@webui';\n try {\n const { SessionRegistry, resolveWstackPaths, GlobalMailbox, mailboxSessionTag } =\n await import('@wrongstack/core');\n const registry = new SessionRegistry(globalRoot);\n const all = await registry.list();\n // Scope to the WebUI host's own project (its pid's entry), like the live\n // status poll does. Fall back to every non-stale session if not found.\n const mySlug = all.find((s) => s.pid === process.pid)?.projectSlug;\n const targets = all\n .filter((s) => s.status !== 'stale')\n .filter((s) => (mySlug ? s.projectSlug === mySlug : true));\n if (targets.length === 0) {\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ ok: true, delivered: 0 }));\n return;\n }\n // Cache one mailbox per project dir (targets here share a slug).\n const mbByDir = new Map<string, InstanceType<typeof GlobalMailbox>>();\n const mailboxFor = (projectRoot: string): InstanceType<typeof GlobalMailbox> => {\n const dir = resolveWstackPaths({ projectRoot, globalRoot }).projectDir;\n let mb = mbByDir.get(dir);\n if (!mb) {\n mb = new GlobalMailbox(dir);\n mbByDir.set(dir, mb);\n }\n return mb;\n };\n let delivered = 0;\n await Promise.all(\n targets.map(async (s) => {\n try {\n const mb = mailboxFor(s.projectRoot);\n await mb.send({\n from,\n to: `leader@${mailboxSessionTag(s.sessionId)}`,\n type: 'steer',\n subject: 'Broadcast from Fleet HQ',\n body: text,\n priority: 'high',\n });\n delivered++;\n } catch {\n /* best-effort per target */\n }\n }),\n );\n res.writeHead(200, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ ok: true, delivered, targets: targets.length }));\n } catch (err) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(JSON.stringify({ error: String(err) }));\n }\n}\n","/**\n * WebSocket connection authentication for the WebUI server.\n *\n * Three layered defenses, all enforced in {@link verifyClient}:\n * 1. **DNS-rebinding guard** ({@link hostHeaderOk}) — on a loopback bind the\n * `Host` header must itself be a loopback name, so a rebound attacker page\n * (`Host: evil.com`) is rejected even though its TCP peer is 127.0.0.1.\n * 2. **Shared-token auth** ({@link tokenMatches}, constant-time) — required for\n * any non-loopback origin and for non-browser clients reaching a publicly\n * bound socket. Tokens are accepted via `Cookie: ws_token=…` (preferred;\n * set by the `/ws-auth` HTTP endpoint with HttpOnly+SameSite=Strict) OR\n * `?token=…` URL query param (non-browser fallback).\n * 3. **Loopback bootstrap** — same-machine browser origins are allowed without\n * a token; the Host-header guard above already blocks cross-site pages.\n *\n * Browser clients (those that send an `Origin` header) authenticate via the\n * HttpOnly cookie by default — the URL `?token=` path is rejected for them,\n * closing the C-598 (Information Exposure Through Query String) class (token in\n * browser history / referrer / proxy logs). The only browser URL-token exception\n * is an explicit public-WS tunnel URL whose origin is allowlisted by the server;\n * that covers separate HTTP/WS hostnames where cookies cannot cross hosts.\n * Non-browser clients (no `Origin`: curl, scripts, tests) keep the URL-token\n * path for ergonomics — query-string exposure is a browser-only concern.\n *\n * Extracted from `index.ts` as pure functions so the auth contract can be unit\n * tested without standing up a real `http.Server`/`WebSocketServer`. `index.ts`\n * builds a thin closure that pulls the fields below off the incoming request.\n */\nimport { Buffer } from 'node:buffer';\nimport { timingSafeEqual } from 'node:crypto';\n\n/** A hostname that refers to the local machine. */\nexport function isLoopbackHostname(hostname: string): boolean {\n return (\n hostname === 'localhost' ||\n hostname === '127.0.0.1' ||\n hostname === '::1' ||\n hostname === '[::1]'\n );\n}\n\n/**\n * Check if an origin is a trusted loopback browser origin.\n * Defense-in-depth: when wsHost=0.0.0.0, only accept explicit localhost origins,\n * not arbitrary loopback hostnames that could be spoofed by local malware.\n */\nfunction isTrustedLoopbackOrigin(origin: string): boolean {\n try {\n const url = new URL(origin);\n // Only allow explicit loopback http(s) origins.\n // Reject file://, data://, and other schemes even on loopback.\n if (url.protocol !== 'http:' && url.protocol !== 'https:') return false;\n return (\n url.hostname === 'localhost' ||\n url.hostname === '127.0.0.1' ||\n url.hostname === '::1' ||\n url.hostname === '[::1]'\n );\n } catch {\n return false;\n }\n}\n\n/** True when the server is bound to a loopback interface (vs. LAN/0.0.0.0). */\nexport function isLoopbackBind(wsHost: string): boolean {\n return wsHost === '127.0.0.1' || wsHost === '::1' || wsHost === 'localhost';\n}\n\n/**\n * True when the server is bound to a wildcard address that exposes it on every\n * interface — IPv4 `0.0.0.0` OR IPv6 `::` (and its bracketed form). The\n * \"LAN exposure = deny\" guards below must treat both families identically; a\n * `::` bind is exactly as exposed as `0.0.0.0` and previously slipped past the\n * `wsHost === '0.0.0.0'` string check.\n */\nexport function isWildcardBind(wsHost: string): boolean {\n return wsHost === '0.0.0.0' || wsHost === '::' || wsHost === '[::]';\n}\n\nfunction normalizeHostname(hostname: string): string {\n const h = hostname.trim().toLowerCase();\n return h.startsWith('[') && h.endsWith(']') ? h.slice(1, -1) : h;\n}\n\nfunction allowedHostname(hostname: string, allowedHostnames?: readonly string[]): boolean {\n const normalized = normalizeHostname(hostname);\n return (allowedHostnames ?? []).some((candidate) => normalizeHostname(candidate) === normalized);\n}\n\n/**\n * Constant-time comparison of a provided token against the expected one.\n * A length mismatch short-circuits (lengths aren't secret); equal-length\n * inputs are compared with `timingSafeEqual` so the token can't be recovered\n * byte-by-byte via response timing.\n */\nexport function tokenMatches(provided: string | undefined, expected: string): boolean {\n if (!provided) return false;\n const a = Buffer.from(provided);\n const b = Buffer.from(expected);\n if (a.length !== b.length) return false;\n return timingSafeEqual(a, b);\n}\n\n/** Pull the `token` query param out of a request URL (`/?token=…`). */\nexport function extractToken(url: string): string | undefined {\n const match = url.match(/[?&]token=([^&]+)/);\n return match ? match[1] : undefined;\n}\n\n/**\n * Pull the `ws_token` value out of a Cookie header (`Cookie: ws_token=…`).\n * The WebUI's auth-token cookie is set via `Set-Cookie: ws_token=<token>;\n * HttpOnly; SameSite=Strict; Path=/` from the `/ws-auth` HTTP endpoint. The\n * browser then sends it back automatically on the WS upgrade request —\n * closing the C-598 (Information Exposure Through Query String) class\n * because the token never appears in the URL, browser history, or\n * reverse-proxy access logs.\n *\n * Returns `undefined` if the cookie header is absent or malformed.\n */\nexport function extractTokenFromCookie(cookieHeader: string | string[] | undefined): string | undefined {\n if (!cookieHeader) return undefined;\n const raw = Array.isArray(cookieHeader) ? cookieHeader.join('; ') : cookieHeader;\n for (const part of raw.split(';')) {\n const eq = part.indexOf('=');\n if (eq < 0) continue;\n const name = part.slice(0, eq).trim();\n if (name === 'ws_token') {\n // Cookie values are url-encoded in spec; decode for the constant-time\n // compare downstream. Trim trailing whitespace defensively.\n try {\n return decodeURIComponent(part.slice(eq + 1).trim());\n } catch {\n return part.slice(eq + 1).trim();\n }\n }\n }\n return undefined;\n}\n\n/**\n * DNS-rebinding defense. On a loopback bind, the `Host` header must resolve to\n * a loopback name. When the operator deliberately exposes the socket (wsHost is\n * a LAN/0.0.0.0 address) the Host is legitimately non-loopback, so the guard is\n * skipped and connection auth falls to the token check.\n */\nexport function hostHeaderOk(input: {\n hostHeader: string | undefined;\n wsHost: string;\n allowedHostnames?: readonly string[] | undefined;\n}): boolean {\n if (!isLoopbackBind(input.wsHost)) return true; // operator opted into wider exposure\n const hostHeader = (input.hostHeader ?? '').trim();\n if (!hostHeader) return false;\n // Strip the port (handle bare host, host:port, and [::1]:port).\n let hostname: string;\n try {\n hostname = new URL(`http://${hostHeader}`).hostname;\n } catch {\n return false;\n }\n return isLoopbackHostname(hostname) || allowedHostname(hostname, input.allowedHostnames);\n}\n\nexport interface VerifyClientInput {\n /** Browser `Origin` header, or undefined for non-browser clients. */\n origin?: string | undefined;\n /** Request URL (`req.url`) — carries the `?token=…` query param. */\n url: string;\n /** `Host` header (`req.headers.host`). */\n hostHeader?: string | undefined;\n /** Peer address (`req.socket.remoteAddress`). */\n remoteAddress?: string | undefined;\n /** `Cookie` header (`req.headers.cookie`). Carries `ws_token=…` when the\n * browser went through `/ws-auth` to set the HttpOnly auth cookie. */\n cookieHeader?: string | string[] | undefined;\n /** Host/interface the WS server is bound to. */\n wsHost: string;\n /** The server's generated auth token. */\n expectedToken: string;\n /** Force token auth even for loopback binds, useful behind public tunnels. */\n requireToken?: boolean | undefined;\n /** Extra Host header names allowed on loopback binds, e.g. a tunnel hostname. */\n allowedHostnames?: readonly string[] | undefined;\n /** Allow browser WS URL tokens for explicit public WS URLs where cookies cannot cross hostnames. */\n allowBrowserUrlToken?: boolean | undefined;\n}\n\n/**\n * Decide whether to accept an incoming WebSocket handshake. Pure mirror of the\n * closure previously inlined in `index.ts`; see the module doc for the layered\n * policy. Returns `true` to accept, `false` to reject.\n *\n * Token sources, in priority order:\n * 1. `Cookie: ws_token=…` (browser clients that went through `/ws-auth`)\n * 2. `?token=…` URL query param (non-browser clients: curl, scripts)\n *\n * Browser clients (with an `Origin` header) are restricted to the cookie path —\n * URL token is rejected for them, closing the C-598 query-string token\n * exposure class. Non-browser clients keep the URL-token fallback so curl\n * and tests continue to work.\n */\nexport function verifyClient(input: VerifyClientInput): boolean {\n const {\n origin,\n url,\n hostHeader,\n remoteAddress,\n cookieHeader,\n wsHost,\n expectedToken,\n requireToken,\n allowedHostnames,\n allowBrowserUrlToken,\n } = input;\n const urlTokenOk = tokenMatches(extractToken(url ?? ''), expectedToken);\n const cookieTokenOk = tokenMatches(extractTokenFromCookie(cookieHeader), expectedToken);\n\n // DNS-rebinding guard runs first on a loopback bind — independent of token\n // and Origin. Blocks a rebound attacker page (Host = attacker domain) even\n // though the TCP peer is 127.0.0.1.\n if (!hostHeaderOk({ hostHeader, wsHost, allowedHostnames })) return false;\n\n if (!origin) {\n // Non-browser clients (curl, scripts): require token unless on loopback.\n // The URL `?token=` path stays valid here for ergonomics (curl/tests have\n // no cookie jar) — query-string token exposure (C-598) is a *browser*\n // history/log concern, which non-browser clients don't have.\n // When wsHost=0.0.0.0 the server accepts connections from any network\n // interface — a non-loopback peer is denied outright.\n const remoteIp = remoteAddress ?? '';\n const isRemoteLoopback = remoteIp === '127.0.0.1' || remoteIp === '::1';\n if (!isRemoteLoopback && isWildcardBind(wsHost)) return false; // LAN exposure = deny\n return urlTokenOk || cookieTokenOk || (isLoopbackBind(wsHost) && !requireToken);\n }\n try {\n const { hostname: originHostname } = new URL(origin);\n // Loopback browser origins: allow without token only if the origin is\n // explicitly http://localhost or http://127.0.0.1 (defense-in-depth).\n // Reject file://, data://, and other schemes even on loopback.\n if (isLoopbackHostname(originHostname)) {\n if (requireToken || !isLoopbackBind(wsHost)) return cookieTokenOk;\n return isTrustedLoopbackOrigin(origin);\n }\n // Non-loopback browser origins normally authenticate via the HttpOnly cookie\n // set by `/ws-auth`. When an operator supplies a separate public WS URL, the\n // cookie may not cross hostnames, so an explicit opt-in keeps URL-token auth\n // available for that tunnel endpoint.\n return (\n cookieTokenOk ||\n (Boolean(allowBrowserUrlToken) &&\n urlTokenOk &&\n allowedHostname(originHostname, allowedHostnames))\n );\n } catch {\n return false;\n }\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport type { Context, IndexingConfig, Logger } from '@wrongstack/core';\nimport {\n cancelPendingReindexes,\n enqueueReindex,\n isIndexableFile,\n runStartupIndex,\n shutdownCodebaseIndexHost,\n} from '@wrongstack/tools';\n\nconst IGNORE_DIRS = new Set([\n 'node_modules',\n '.git',\n 'dist',\n 'build',\n '.next',\n 'coverage',\n '.turbo',\n '__snapshots__',\n '.nyc_output',\n]);\n\nexport interface WebUICodebaseIndexingDeps {\n config: { indexing?: IndexingConfig | undefined };\n context: Context;\n projectRoot: string;\n logger: Logger;\n}\n\nexport interface WebUICodebaseIndexing {\n onFileWritten(filePath: string): void;\n dispose(): void;\n}\n\nexport function setupWebUICodebaseIndexing(\n deps: WebUICodebaseIndexingDeps,\n): WebUICodebaseIndexing {\n const indexing = deps.config.indexing;\n if (!indexing) return noopIndexing();\n const idx: IndexingConfig = indexing;\n\n const indexDir = typeof deps.context.meta['codebaseIndexDir'] === 'string'\n ? deps.context.meta['codebaseIndexDir']\n : undefined;\n const debounceMs = idx.debounceMs ?? 400;\n const onError = (err: unknown) => {\n deps.logger.debug(\n `webui codebase auto-index failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n };\n\n if (idx.onSessionStart) {\n void runStartupIndex({\n projectRoot: deps.projectRoot,\n indexDir,\n signal: deps.context.signal,\n timeoutMs: idx.indexTimeoutMs,\n })\n .then((result) => {\n deps.logger.info(\n `webui codebase index ready: ${result.symbolsIndexed} symbols · ${result.filesIndexed} files · ${result.durationMs}ms`,\n );\n })\n .catch((err) => {\n deps.logger.warn(\n `webui codebase index (startup) failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n });\n }\n\n let watcher: fs.FSWatcher | undefined;\n if (idx.watchExternal) {\n try {\n watcher = fs.watch(deps.projectRoot, { recursive: true }, (_event, filename) => {\n if (!filename) return;\n const rel = filename.toString();\n if (isIgnored(rel)) return;\n const abs = path.resolve(deps.projectRoot, rel);\n enqueueFile(abs);\n });\n watcher.on('error', (err) => deps.logger.debug(`webui codebase index watcher error: ${err}`));\n watcher.unref?.();\n } catch (err) {\n deps.logger.debug(\n `webui codebase index watcher unavailable: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n function enqueueFile(filePath: string): void {\n if (!idx.onEdit && !idx.watchExternal) return;\n const abs = path.isAbsolute(filePath)\n ? path.normalize(filePath)\n : path.resolve(deps.projectRoot, filePath);\n if (!isInside(deps.projectRoot, abs) || !isIndexableFile(abs)) return;\n enqueueReindex({\n projectRoot: deps.projectRoot,\n files: [abs],\n indexDir,\n debounceMs,\n timeoutMs: idx.indexTimeoutMs,\n onError,\n });\n }\n\n return {\n onFileWritten(filePath) {\n if (idx.onEdit) enqueueFile(filePath);\n },\n dispose() {\n try {\n watcher?.close();\n } catch {\n /* ignore */\n }\n cancelPendingReindexes();\n shutdownCodebaseIndexHost();\n },\n };\n}\n\nfunction noopIndexing(): WebUICodebaseIndexing {\n return {\n onFileWritten() {},\n dispose() {},\n };\n}\n\nfunction isIgnored(rel: string): boolean {\n return rel.split(/[/\\\\]/).some((seg) => IGNORE_DIRS.has(seg));\n}\n\nfunction isInside(root: string, target: string): boolean {\n const normalizedRoot = path.resolve(root);\n const normalizedTarget = path.resolve(target);\n return normalizedTarget === normalizedRoot || normalizedTarget.startsWith(normalizedRoot + path.sep);\n}\n","/**\n * Shared file-operation WebSocket handlers for both the standalone WebUI\n * server and the CLI's `--webui` embedded server. Extracted from the\n * duplicated switch cases in `index.ts` and `cli/src/webui-server.ts`.\n *\n * Each function handles the full request→response cycle for one message\n * type. Callers drop them into their switch statement:\n *\n * case 'files.tree': return handleFilesTree(ws, msg, projectRoot);\n */\n\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { WebSocket } from 'ws';\nimport { atomicWrite } from '@wrongstack/core';\nimport { SKIP_DIRS, isHiddenEntry, rankFiles } from './file-picker.js';\nimport { isPathInside, resolveWorkingDirInsideProject } from './path-containment.js';\nimport { send, errMessage } from './ws-utils.js';\n\n/**\n * Resolve a user-supplied file path against `projectRoot` and verify the\n * canonical (real) path stays inside the canonical project root. This\n * rejects:\n * - lexical escapes (`../../etc/passwd`)\n * - in-project symlinks that point outside the project root\n * - absolute paths outside the project root\n *\n * The target file does not need to exist; we `realpath` the parent\n * directory and re-attach the basename. This matches the behavior of\n * `realpath(3)` once the file is later created.\n */\nasync function resolveFileInsideProject(\n projectRoot: string,\n filePath: string,\n): Promise<string> {\n // Lexical containment check first — cheap, and avoids calling realpath\n // on a path we already know is bogus. This also blocks `..` segments.\n const resolved = path.resolve(projectRoot, filePath);\n if (!isPathInside(projectRoot, resolved)) {\n throw new Error('Path outside project root');\n }\n\n // Canonical containment: walk the parent directory's real path and\n // re-attach the basename. If the parent doesn't exist yet, walk up\n // until we find an existing ancestor and verify the rest of the path\n // is still inside the real project root.\n const { parent, base } = splitParentAndBase(resolved);\n const realProjectRoot = await fs.realpath(projectRoot);\n const realParent = await realpathAllowMissing(parent);\n const realFull = path.join(realParent, base);\n if (!isPathInside(realProjectRoot, realFull)) {\n throw new Error('Path outside project root');\n }\n return realFull;\n}\n\nfunction splitParentAndBase(p: string): { parent: string; base: string } {\n const base = path.basename(p);\n const parent = path.dirname(p);\n return { parent, base };\n}\n\n/**\n * `realpath` that does not throw when the path doesn't exist. Walks up\n * until an existing ancestor is found, realpaths that ancestor, then\n * re-attaches the missing tail. This is what we need for write targets\n * that don't exist yet, and for read targets whose parent may have\n * been deleted between check and use.\n */\nasync function realpathAllowMissing(p: string): Promise<string> {\n // Existing path — normal realpath, canonicalizing any symlinks.\n try {\n return await fs.realpath(p);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n }\n // Walk up to the first existing ancestor, realpath that, and reattach.\n const segments: string[] = [];\n let cursor = p;\n while (true) {\n const parent = path.dirname(cursor);\n if (parent === cursor) {\n // Hit a filesystem root and still nothing exists. The lexical\n // check above already kept us inside projectRoot, so this should\n // be unreachable; bail out conservatively.\n throw new Error('Path outside project root');\n }\n segments.unshift(path.basename(cursor));\n try {\n const realParent = await fs.realpath(parent);\n return path.join(realParent, ...segments);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n cursor = parent;\n }\n }\n}\n\n// ── Type helpers (inlined, no dependence on types.ts) ──\n\ninterface FilesListPayload {\n query?: string | undefined;\n limit?: number | undefined;\n /** Optional directory root for the file list (relative to projectRoot).\n * When set, only files under this directory are returned. */\n path?: string | undefined;\n}\n\ninterface FilesReadPayload {\n filePath: string;\n}\n\ninterface FilesWritePayload {\n filePath: string;\n content: string;\n}\n\n/** Guard: ensure msg is an object with a payload of the expected shape.\n * Throws TypeError if the shape is wrong so callers catch it explicitly. */\nfunction validatedPayload<T>(msg: unknown, label: string): T {\n if (msg == null || typeof msg !== 'object') {\n throw new TypeError(`Expected object for ${label}, got ${msg}`);\n }\n const payload = (msg as { payload?: unknown }).payload;\n if (payload == null || typeof payload !== 'object') {\n throw new TypeError(`Expected payload object for ${label}, got ${payload}`);\n }\n return payload as T;\n}\n\nexport interface FilesWriteOptions {\n onWritten?: ((filePath: string) => void | Promise<void>) | undefined;\n}\n\n// ── Shared handlers ───────────────────────────────────────────────────\n\n/**\n * Build and send a nested directory tree for the File Explorer.\n *\n * Walks `projectRoot` to depth 10 max, skipping heavyweight dirs\n * (node_modules, .git, dist, …) and dot-entries. Responds with\n * `{ type: 'files.tree', payload: { root, tree } }`.\n */\nexport async function handleFilesTree(\n ws: WebSocket,\n msg: unknown,\n projectRoot: string,\n): Promise<void> {\n interface TreeNode {\n name: string;\n path: string;\n type: 'file' | 'directory';\n children?: TreeNode[];\n }\n\n // Use the optional `path` from the message payload as the tree root.\n // When absent, empty, or \".\", fall back to projectRoot (backward compatible).\n const payload = (msg as { payload?: { path?: string | undefined } }).payload;\n const rawPath = payload?.path?.trim();\n\n // Guard: the requested tree root must be both lexically AND via\n // realpath() inside the project root. A symlinked subdirectory that\n // points outside the project would otherwise expose arbitrary\n // directory structure to a connected client.\n let treeRoot: string;\n let realProjectRoot: string;\n try {\n if (rawPath && rawPath !== '.') {\n treeRoot = await resolveWorkingDirInsideProject(projectRoot, rawPath);\n } else {\n treeRoot = projectRoot;\n }\n realProjectRoot = await fs.realpath(projectRoot);\n } catch {\n send(ws, {\n type: 'files.tree',\n payload: { root: projectRoot, tree: [], error: 'Path outside project root' },\n });\n return;\n }\n\n // Compute the path prefix so tree paths are always relative to\n // projectRoot (not treeRoot). This ensures double-clicking a file in\n // the explorer sends the correct path to files.read/files.write.\n const pathPrefix = treeRoot === projectRoot\n ? ''\n : (path.relative(projectRoot, treeRoot) + '/').replace(/\\\\/g, '/');\n\n async function buildTree(dir: string, rel: string, depth: number): Promise<TreeNode[]> {\n if (depth > 10) return [];\n let entries: import('node:fs').Dirent[] = [];\n try {\n entries = await fs.readdir(dir, { withFileTypes: true });\n } catch {\n return [];\n }\n entries.sort((a, b) => {\n if (a.isDirectory() !== b.isDirectory()) return a.isDirectory() ? -1 : 1;\n return a.name.localeCompare(b.name);\n });\n const nodes: TreeNode[] = [];\n for (const e of entries) {\n if (isHiddenEntry(e.name)) continue;\n const childRel = rel ? `${rel}/${e.name}` : e.name;\n const childAbs = path.join(dir, e.name);\n // Prepend the workingDir prefix so the path is projectRoot-relative\n const childPath = pathPrefix + childRel;\n if (e.isDirectory()) {\n if (SKIP_DIRS.has(e.name)) continue;\n // Reject symlinked directories whose real path escapes the\n // real project root. A symlink to an in-project directory is\n // fine and recursed into normally.\n let realChild: string;\n try {\n realChild = await fs.realpath(childAbs);\n } catch {\n continue;\n }\n if (!isPathInside(realProjectRoot, realChild)) {\n continue;\n }\n const children = await buildTree(realChild, childRel, depth + 1);\n nodes.push({ name: e.name, path: childPath, type: 'directory', children });\n } else if (e.isFile()) {\n nodes.push({ name: e.name, path: childPath, type: 'file' });\n }\n }\n return nodes;\n }\n\n try {\n const tree = await buildTree(treeRoot, '', 0);\n const rootLabel = treeRoot === projectRoot\n ? projectRoot\n : path.relative(projectRoot, treeRoot) || '.';\n send(ws, { type: 'files.tree', payload: { root: rootLabel, tree } });\n } catch (err) {\n const rootLabel = treeRoot === projectRoot\n ? projectRoot\n : path.relative(projectRoot, treeRoot) || '.';\n send(ws, {\n type: 'files.tree',\n payload: { root: rootLabel, tree: [], error: errMessage(err) },\n });\n }\n}\n\n/**\n * Read a file's content for the Monaco editor.\n *\n * Guards against path traversal (`../` escapes). Responds with\n * `{ type: 'files.read', payload: { filePath, content } }`.\n */\nexport async function handleFilesRead(\n ws: WebSocket,\n msg: unknown,\n projectRoot: string,\n): Promise<void> {\n let filePath: string;\n try {\n ({ filePath } = validatedPayload<FilesReadPayload>(msg, 'files.read'));\n } catch {\n send(ws, { type: 'files.read', payload: { filePath: '', content: '', error: 'Malformed request' } });\n return;\n }\n\n // Path traversal guard: resolve and verify both lexically AND via\n // realpath() that the file stays inside the canonical project root.\n // A string-prefix check is not enough — an in-project symlink to\n // an external file would otherwise escape the project root.\n let realResolved: string;\n try {\n realResolved = await resolveFileInsideProject(projectRoot, filePath);\n } catch {\n send(ws, { type: 'files.read', payload: { filePath, content: '', error: 'Forbidden' } });\n return;\n }\n\n try {\n const content = await fs.readFile(realResolved, 'utf8');\n send(ws, { type: 'files.read', payload: { filePath, content } });\n } catch (err) {\n send(ws, {\n type: 'files.read',\n payload: { filePath, content: '', error: errMessage(err) },\n });\n }\n}\n\n/**\n * Write file content back to disk (atomic write via tmp + rename).\n *\n * Guards against path traversal. Responds with\n * `{ type: 'files.written', payload: { filePath, success } }`.\n */\nexport async function handleFilesWrite(\n ws: WebSocket,\n msg: unknown,\n projectRoot: string,\n opts: FilesWriteOptions = {},\n): Promise<void> {\n let filePath: string;\n let content: string;\n try {\n ({ filePath, content } = validatedPayload<FilesWritePayload>(msg, 'files.write'));\n } catch {\n send(ws, { type: 'files.written', payload: { filePath: '', success: false, error: 'Malformed request' } });\n return;\n }\n\n // Path traversal guard: resolve and verify both lexically AND via\n // realpath() that the parent directory stays inside the canonical\n // project root. A string-prefix check is not enough — an in-project\n // symlink to an external directory would let a write escape the\n // project root and clobber files elsewhere on disk.\n let realResolved: string;\n try {\n realResolved = await resolveFileInsideProject(projectRoot, filePath);\n } catch {\n send(ws, { type: 'files.written', payload: { filePath, success: false, error: 'Forbidden' } });\n return;\n }\n\n try {\n await atomicWrite(realResolved, content);\n send(ws, { type: 'files.written', payload: { filePath, success: true } });\n if (opts.onWritten) {\n void Promise.resolve(opts.onWritten(realResolved)).catch(() => undefined);\n }\n } catch (err) {\n send(ws, {\n type: 'files.written',\n payload: { filePath, success: false, error: errMessage(err) },\n });\n }\n}\n\n/**\n * Lightweight project file picker for the chat `@` mention popup.\n *\n * Walks `projectRoot` (max depth 8), skipping hidden and heavyweight\n * dirs, then fuzzy-ranks results against `query`. Responds with\n * `{ type: 'files.list', payload: { files } }`.\n */\nexport async function handleFilesList(\n ws: WebSocket,\n msg: unknown,\n projectRoot: string,\n): Promise<void> {\n const payload = (msg as { payload?: FilesListPayload }).payload ?? {};\n const limit = payload.limit ?? 50;\n\n // Guard: the requested list root must be both lexically AND via\n // realpath() inside the project root. A symlinked subdirectory that\n // points outside the project would otherwise expose arbitrary\n // filenames to a connected client.\n let listRoot: string;\n let realProjectRoot: string;\n try {\n if (payload.path) {\n listRoot = await resolveWorkingDirInsideProject(projectRoot, payload.path);\n } else {\n listRoot = projectRoot;\n }\n realProjectRoot = await fs.realpath(projectRoot);\n } catch {\n send(ws, { type: 'files.list', payload: { files: [] } });\n return;\n }\n\n const results: string[] = [];\n\n async function walk(dir: string, rel: string, depth: number): Promise<void> {\n if (depth > 8 || results.length >= 600) return;\n let entries: import('node:fs').Dirent[] = [];\n try {\n entries = await fs.readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const e of entries) {\n if (results.length >= 600) return;\n if (isHiddenEntry(e.name)) continue;\n const childRel = rel ? `${rel}/${e.name}` : e.name;\n if (e.isDirectory()) {\n if (SKIP_DIRS.has(e.name)) continue;\n // Reject symlinked directories whose real path escapes the\n // real project root. A symlink to an in-project directory is\n // fine and recursed into normally.\n let realChild: string;\n try {\n realChild = await fs.realpath(path.join(dir, e.name));\n } catch {\n continue;\n }\n if (!isPathInside(realProjectRoot, realChild)) {\n continue;\n }\n await walk(realChild, childRel, depth + 1);\n } else if (e.isFile()) {\n results.push(childRel);\n }\n }\n }\n\n await walk(listRoot, '', 0);\n send(ws, {\n type: 'files.list',\n payload: { files: rankFiles(results, payload.query ?? '', limit) },\n });\n}\n","/**\n * Pure filtering + ranking for the `files.list` project file picker (the chat\n * `@`-mention popup). The directory *walk* stays in index.ts (it's I/O), but\n * the two decisions that shape the result — which entries to hide and how to\n * rank matches — are pure and live here so the scoring weights, depth penalty,\n * and tie-break order can be unit tested. A silently-flipped weight would make\n * the picker feel subtly wrong with nothing to catch it.\n */\n/** Heavyweight build/vcs/dependency dirs the picker never descends into. */\nexport const SKIP_DIRS: ReadonlySet<string> = new Set([\n '.git',\n 'node_modules',\n 'dist',\n 'build',\n '.next',\n '.turbo',\n '.cache',\n 'target',\n 'coverage',\n '.nyc_output',\n 'out',\n '.pnpm-store',\n '.parcel-cache',\n]);\n\n/** Dotfiles/dirs kept despite the hide-dotfiles-by-default rule. */\nconst KEEP_DOTFILES: ReadonlySet<string> = new Set([\n '.wrongstack',\n '.env.example',\n '.gitignore',\n '.eslintrc',\n '.prettierrc',\n]);\n\n/**\n * Whether a directory entry should be hidden from the picker by its name.\n * Dotfiles are hidden by default, except a few commonly-wanted ones.\n */\nexport function isHiddenEntry(name: string): boolean {\n return name.startsWith('.') && !KEEP_DOTFILES.has(name);\n}\n\n/**\n * Rank `paths` against `query` and return up to `limit` paths, best first.\n *\n * Scoring (cheap heuristic, good enough for a picker): exact basename match\n * (100) > basename prefix (60) > path substring (20); non-matches are dropped.\n * Each match is penalized by its path depth so root files sort first. Ties\n * break by lexicographic path. An empty query keeps every path (score 0), so\n * the result is the paths sorted lexicographically, capped to `limit`.\n */\nexport function rankFiles(paths: readonly string[], query: string, limit: number): string[] {\n const q = query.toLowerCase();\n const scored: Array<{ path: string; score: number }> = [];\n for (const p of paths) {\n if (!q) {\n scored.push({ path: p, score: 0 });\n continue;\n }\n const lower = p.toLowerCase();\n const base = lower.split('/').pop() ?? lower;\n let score = 0;\n if (base === q) score = 100;\n else if (base.startsWith(q)) score = 60;\n else if (lower.includes(q)) score = 20;\n else continue;\n // Penalise depth so root files come first.\n score -= p.split('/').length;\n scored.push({ path: p, score });\n }\n scored.sort((a, b) => b.score - a.score || a.path.localeCompare(b.path));\n return scored.slice(0, limit).map((s) => s.path);\n}\n","import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\n\nexport function isPathInside(root: string, target: string): boolean {\n const relative = path.relative(root, target);\n return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));\n}\n\nexport async function resolveWorkingDirInsideProject(projectRoot: string, inputPath: string): Promise<string> {\n const resolved = path.resolve(projectRoot, inputPath);\n\n let stat;\n try {\n stat = await fs.stat(resolved);\n } catch {\n throw new Error(`Directory not found or not accessible: ${resolved}`);\n }\n if (!stat.isDirectory()) {\n throw new Error(`Directory not found or not accessible: ${resolved}`);\n }\n\n const [realProjectRoot, realResolved] = await Promise.all([\n fs.realpath(projectRoot),\n fs.realpath(resolved),\n ]);\n\n if (!isPathInside(realProjectRoot, realResolved)) {\n throw new Error(`Path must stay inside the project root: ${projectRoot}`);\n }\n\n return resolved;\n}\n","/**\n * Shared WebSocket utilities for both the standalone WebUI server and the\n * CLI's `--webui` embedded server. Extracted from the duplicated `send` /\n * `broadcast` / `sendResult` / `generateAuthToken` patterns that were\n * copy-pasted between `packages/webui/src/server/index.ts` and\n * `packages/cli/src/webui-server.ts`.\n */\nimport { randomBytes } from 'node:crypto';\n// Value import (not `import type`): we reference `WebSocket.OPEN` below, which\n// is a runtime value, not just a type.\nimport { WebSocket } from 'ws';\nimport type { ConnectedClient } from './types.js';\n\n/**\n * Send a JSON message to a single WebSocket client.\n * No-op when the socket is not in OPEN state (disconnected / closing).\n */\nexport function send(ws: WebSocket, msg: object): void {\n if (ws.readyState === WebSocket.OPEN) {\n ws.send(JSON.stringify(msg));\n }\n}\n\n/**\n * Broadcast a JSON message to every connected client.\n * Swallows per-socket send errors — a client that disconnected between the\n * readyState check and `ws.send()` is cleaned up by its own `close` handler.\n */\nexport function broadcast(\n clients: Map<WebSocket, ConnectedClient>,\n msg: object,\n): void {\n const data = JSON.stringify(msg);\n for (const [ws] of clients) {\n if (ws.readyState === WebSocket.OPEN) {\n try {\n ws.send(data);\n } catch {\n // Client disconnected between the readyState check and the send —\n // let the 'close' handler remove it from the map naturally.\n }\n }\n }\n}\n\n/**\n * Send a success/failure result message (used by key.* and provider.* handlers).\n * The frontend expects `key.operation_result` with `{ success, message }`.\n */\nexport function sendResult(ws: WebSocket, success: boolean, message: string): void {\n send(ws, { type: 'key.operation_result', payload: { success, message } });\n}\n\n/**\n * Extract a human-readable message from an unknown thrown value.\n */\nexport function errMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\n/**\n * Generate a cryptographically random WebSocket auth token (hex string).\n * Shared between standalone and CLI-embedded WebUI servers.\n */\nexport function generateAuthToken(): string {\n return randomBytes(16).toString('hex');\n}\n\nexport function resolveAuthToken(explicit?: string | undefined): string {\n const configured =\n explicit?.trim() ||\n process.env['WEBUI_TOKEN']?.trim() ||\n process.env['WEBUI_AUTH_TOKEN']?.trim();\n return configured || generateAuthToken();\n}\n\nexport function hostForBrowserUrl(bindHost: string): string {\n if (bindHost === '0.0.0.0') return '127.0.0.1';\n if (bindHost === '::' || bindHost === '[::]') return '[::1]';\n if (bindHost.includes(':') && !bindHost.startsWith('[')) return `[${bindHost}]`;\n return bindHost;\n}\n\nexport function buildWebUIAccessUrl(opts: {\n host: string;\n port: number;\n token?: string | undefined;\n protocol?: 'http' | 'https' | undefined;\n publicUrl?: string | undefined;\n}): string {\n const protocol = opts.protocol ?? 'http';\n const base = opts.publicUrl?.trim() || `${protocol}://${hostForBrowserUrl(opts.host)}:${opts.port}`;\n if (!opts.token) return base;\n try {\n const url = new URL(base);\n url.searchParams.set('token', opts.token);\n const rendered = url.toString();\n const afterOrigin = base.slice(url.origin.length);\n if (url.pathname === '/' && !afterOrigin.startsWith('/')) {\n return `${url.origin}${url.search}${url.hash}`;\n }\n return rendered;\n } catch {\n return `${base}${base.includes('?') ? '&' : '?'}token=${encodeURIComponent(opts.token)}`;\n }\n}\n\nexport function envFlag(name: string): boolean {\n const value = process.env[name]?.trim().toLowerCase();\n return value === '1' || value === 'true' || value === 'yes' || value === 'on';\n}\n","/**\n * Context-aware editor completion for the WebUI Monaco surface.\n *\n * The handler combines fast symbol-index hits with a short, JSON-only LLM call.\n * It is intentionally side-effect free: it never writes files and only reads the\n * existing codebase index when available.\n */\n\nimport * as path from 'node:path';\nimport type { WebSocket } from 'ws';\nimport type { Context, Provider, Request, Tool } from '@wrongstack/core';\nimport { searchCodebaseIndex, type SearchResult } from '@wrongstack/tools/codebase-index/index';\nimport { send, errMessage } from './ws-utils.js';\n\nexport type CompletionItemKind =\n | 'text'\n | 'method'\n | 'function'\n | 'constructor'\n | 'field'\n | 'variable'\n | 'class'\n | 'interface'\n | 'module'\n | 'property'\n | 'unit'\n | 'value'\n | 'enum'\n | 'keyword'\n | 'snippet'\n | 'file'\n | 'reference';\n\nexport interface CompletionSuggestion {\n label: string;\n insertText: string;\n kind?: CompletionItemKind | undefined;\n detail?: string | undefined;\n documentation?: string | undefined;\n sortText?: string | undefined;\n source?: 'llm' | 'index' | 'lsp' | undefined;\n}\n\ninterface CompletionRequestPayload {\n requestId: string;\n filePath: string;\n language: string;\n lineNumber: number;\n column: number;\n content?: string | undefined;\n prefix: string;\n suffix?: string | undefined;\n triggerCharacter?: string | undefined;\n triggerKind?: number | undefined;\n allowLlm?: boolean | undefined;\n}\n\nexport interface CompletionHandlerOptions {\n projectRoot: string;\n provider?: Provider | undefined;\n model?: string | undefined;\n indexDir?: string | undefined;\n lspCompletion?: LspCompletionSource | undefined;\n timeoutMs?: number | undefined;\n}\n\nexport interface LspCompletionSourceRequest {\n filePath: string;\n lineNumber: number;\n column: number;\n content?: string | undefined;\n triggerCharacter?: string | undefined;\n signal: AbortSignal;\n}\n\nexport type LspCompletionSource = (\n request: LspCompletionSourceRequest,\n) => Promise<CompletionSuggestion[]>;\n\nconst MAX_PREFIX_CHARS = 12_000;\nconst MAX_SUFFIX_CHARS = 4_000;\nconst MAX_CONTENT_CHARS = 500_000;\nconst INDEX_LIMIT = 8;\nconst LLM_LIMIT = 8;\nconst DEFAULT_TIMEOUT_MS = 4_500;\n\nconst COMPLETION_SYSTEM_PROMPT = [\n 'You are a code completion engine for an IDE.',\n 'Return only JSON. No markdown, prose, or code fences.',\n 'Suggest context-aware completions that fit the cursor location.',\n 'Prefer project-local names, repository conventions, and type-safe APIs.',\n 'Do not invent large code blocks; keep insertText small and directly insertable.',\n].join('\\n');\n\nconst COMPLETION_JSON_SCHEMA = {\n type: 'object',\n additionalProperties: false,\n properties: {\n items: {\n type: 'array',\n maxItems: LLM_LIMIT,\n items: {\n type: 'object',\n additionalProperties: false,\n properties: {\n label: { type: 'string' },\n insertText: { type: 'string' },\n kind: {\n type: 'string',\n enum: [\n 'text',\n 'method',\n 'function',\n 'constructor',\n 'field',\n 'variable',\n 'class',\n 'interface',\n 'module',\n 'property',\n 'unit',\n 'value',\n 'enum',\n 'keyword',\n 'snippet',\n 'file',\n 'reference',\n ],\n },\n detail: { type: 'string' },\n documentation: { type: 'string' },\n sortText: { type: 'string' },\n },\n required: ['label', 'insertText'],\n },\n },\n },\n required: ['items'],\n};\n\nexport async function handleCompletionRequest(\n ws: WebSocket,\n msg: unknown,\n opts: CompletionHandlerOptions,\n): Promise<void> {\n const parsed = parsePayload(msg);\n if (!parsed.ok) {\n send(ws, {\n type: 'completion.result',\n payload: {\n requestId: parsed.requestId ?? '',\n filePath: parsed.filePath ?? '',\n items: [],\n error: parsed.error,\n },\n });\n return;\n }\n\n const payload = parsed.payload;\n const projectRoot = path.resolve(opts.projectRoot);\n const resolved = path.resolve(projectRoot, payload.filePath);\n if (!isInside(projectRoot, resolved)) {\n send(ws, {\n type: 'completion.result',\n payload: {\n requestId: payload.requestId,\n filePath: payload.filePath,\n items: [],\n error: 'Forbidden',\n },\n });\n return;\n }\n\n const prefix = tail(payload.prefix, MAX_PREFIX_CHARS);\n const suffix = head(payload.suffix ?? '', MAX_SUFFIX_CHARS);\n const linePrefix = currentLinePrefix(prefix);\n const query = buildSearchQuery(linePrefix, payload.filePath);\n\n const [lspItems, indexItems] = await Promise.all([\n loadLspSuggestions(opts.lspCompletion, payload, resolved)\n .catch(() => [] as CompletionSuggestion[]),\n loadIndexSuggestions({\n projectRoot,\n indexDir: opts.indexDir,\n query,\n }).catch(() => [] as CompletionSuggestion[]),\n ]);\n\n const llmResult = shouldUseLlm(payload, linePrefix, query)\n ? await loadLlmSuggestions({\n provider: opts.provider,\n model: opts.model,\n payload,\n prefix,\n suffix,\n linePrefix,\n query,\n relatedSymbols: indexItems,\n timeoutMs: opts.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n }).catch((err) => ({ error: errMessage(err), items: [] as CompletionSuggestion[] }))\n : ([] as CompletionSuggestion[]);\n\n const llmItems = Array.isArray(llmResult) ? llmResult : llmResult.items;\n const error = Array.isArray(llmResult) ? undefined : llmResult.error;\n const items = mergeSuggestions([...lspItems, ...llmItems, ...indexItems]).slice(\n 0,\n LLM_LIMIT + INDEX_LIMIT,\n );\n\n send(ws, {\n type: 'completion.result',\n payload: {\n requestId: payload.requestId,\n filePath: payload.filePath,\n items,\n error: items.length === 0 ? error : undefined,\n },\n });\n}\n\nexport function createToolLspCompletionSource(\n tool: Tool | undefined,\n ctx: Context,\n): LspCompletionSource | undefined {\n if (!tool) return undefined;\n return async (request) => {\n const output = await tool.execute(\n {\n path: request.filePath,\n line: request.lineNumber,\n character: request.column,\n content: request.content,\n limit: 8,\n trigger_character: request.triggerCharacter,\n format: 'json',\n },\n ctx,\n { signal: request.signal },\n );\n return parseLspToolOutput(String(output));\n };\n}\n\nfunction parsePayload(msg: unknown):\n | { ok: true; payload: CompletionRequestPayload }\n | { ok: false; error: string; requestId?: string | undefined; filePath?: string | undefined } {\n const payload = (msg as { payload?: Partial<CompletionRequestPayload> | undefined }).payload;\n const requestId = typeof payload?.requestId === 'string' ? payload.requestId : undefined;\n const filePath = typeof payload?.filePath === 'string' ? payload.filePath : undefined;\n if (!payload || typeof payload !== 'object') {\n return { ok: false, error: 'Missing payload' };\n }\n if (!requestId) {\n return { ok: false, error: 'Missing requestId', filePath };\n }\n if (!filePath) {\n return { ok: false, error: 'Missing filePath', requestId };\n }\n if (typeof payload.language !== 'string') {\n return { ok: false, error: 'Missing language', requestId, filePath };\n }\n if (typeof payload.prefix !== 'string') {\n return { ok: false, error: 'Missing prefix', requestId, filePath };\n }\n if (!isValidPositionValue(payload.lineNumber) || !isValidPositionValue(payload.column)) {\n return { ok: false, error: 'Invalid cursor position', requestId, filePath };\n }\n const content = typeof payload.content === 'string' && payload.content.length <= MAX_CONTENT_CHARS\n ? payload.content\n : undefined;\n return {\n ok: true,\n payload: {\n requestId,\n filePath,\n language: payload.language,\n lineNumber: payload.lineNumber,\n column: payload.column,\n content,\n prefix: payload.prefix,\n suffix: typeof payload.suffix === 'string' ? payload.suffix : undefined,\n triggerCharacter: typeof payload.triggerCharacter === 'string'\n ? payload.triggerCharacter\n : undefined,\n triggerKind: typeof payload.triggerKind === 'number' ? payload.triggerKind : undefined,\n allowLlm: typeof payload.allowLlm === 'boolean' ? payload.allowLlm : undefined,\n },\n };\n}\n\nfunction shouldUseLlm(\n payload: CompletionRequestPayload,\n linePrefix: string,\n query: string,\n): boolean {\n if (payload.allowLlm !== undefined) return payload.allowLlm;\n if (payload.triggerCharacter === '.') return true;\n if (payload.triggerCharacter) return false;\n const token = linePrefix.match(/([A-Za-z_$][\\w$]*)$/)?.[1] ?? query;\n return /^(findBy|findAllBy|create|update|delete|remove|get[A-Z_]|set[A-Z_]|use[A-Z_])/.test(\n token,\n );\n}\n\nasync function loadIndexSuggestions(opts: {\n projectRoot: string;\n indexDir?: string | undefined;\n query: string;\n}): Promise<CompletionSuggestion[]> {\n const query = opts.query.trim();\n if (query.length < 2) return [];\n const result = await searchCodebaseIndex(\n {\n projectRoot: opts.projectRoot,\n indexDir: opts.indexDir,\n query,\n limit: INDEX_LIMIT,\n },\n { timeoutMs: 1_500 },\n );\n\n return result.results.map(indexResultToSuggestion);\n}\n\nasync function loadLspSuggestions(\n source: LspCompletionSource | undefined,\n payload: CompletionRequestPayload,\n resolvedFilePath: string,\n): Promise<CompletionSuggestion[]> {\n if (!source) return [];\n const timer = new AbortController();\n const to = setTimeout(() => timer.abort(new Error('lsp completion timeout')), 2_000);\n to.unref?.();\n try {\n return await source({\n filePath: resolvedFilePath,\n lineNumber: payload.lineNumber,\n column: payload.column,\n content: payload.content,\n triggerCharacter: payload.triggerCharacter,\n signal: timer.signal,\n });\n } finally {\n timer.abort();\n clearTimeout(to);\n }\n}\n\nasync function loadLlmSuggestions(opts: {\n provider?: Provider | undefined;\n model?: string | undefined;\n payload: CompletionRequestPayload;\n prefix: string;\n suffix: string;\n linePrefix: string;\n query: string;\n relatedSymbols: CompletionSuggestion[];\n timeoutMs: number;\n}): Promise<CompletionSuggestion[]> {\n if (!opts.provider || !opts.model) return [];\n\n const req: Request = {\n model: opts.model,\n system: [{ type: 'text', text: COMPLETION_SYSTEM_PROMPT }],\n messages: [\n {\n role: 'user',\n content: buildCompletionPrompt(opts),\n },\n ],\n maxTokens: 700,\n };\n\n if (opts.provider.capabilities.structuredOutput) {\n req.responseFormat = {\n type: 'json_schema',\n jsonSchema: {\n name: 'code_completion_suggestions',\n strict: false,\n schema: COMPLETION_JSON_SCHEMA,\n },\n };\n } else if (opts.provider.capabilities.jsonMode) {\n req.responseFormat = { type: 'json_object' };\n }\n\n const timer = new AbortController();\n const to = setTimeout(() => timer.abort(new Error('completion timeout')), opts.timeoutMs);\n to.unref?.();\n try {\n const res = await opts.provider.complete(req, { signal: timer.signal });\n const text = res.content\n .filter((block) => block.type === 'text')\n .map((block) => block.text)\n .join('\\n')\n .trim();\n return parseCompletionJson(text).slice(0, LLM_LIMIT);\n } finally {\n timer.abort();\n clearTimeout(to);\n }\n}\n\nfunction buildCompletionPrompt(opts: {\n payload: CompletionRequestPayload;\n prefix: string;\n suffix: string;\n linePrefix: string;\n query: string;\n relatedSymbols: CompletionSuggestion[];\n}): string {\n const related = opts.relatedSymbols.length > 0\n ? opts.relatedSymbols\n .slice(0, INDEX_LIMIT)\n .map((item) => `- ${item.label}: ${item.detail ?? item.documentation ?? item.kind ?? 'symbol'}`)\n .join('\\n')\n : '(none)';\n\n return [\n `File: ${opts.payload.filePath}`,\n `Language: ${opts.payload.language}`,\n `Cursor: line ${opts.payload.lineNumber}, column ${opts.payload.column}`,\n `Trigger: ${opts.payload.triggerCharacter ?? 'manual'}`,\n `Current line prefix: ${opts.linePrefix}`,\n `Search/query hint: ${opts.query}`,\n '',\n 'Relevant project symbols from the codebase index:',\n related,\n '',\n 'Return JSON shaped exactly as:',\n '{\"items\":[{\"label\":\"name\",\"insertText\":\"text\",\"kind\":\"function\",\"detail\":\"short optional detail\",\"documentation\":\"short optional docs\",\"sortText\":\"optional\"}]}',\n '',\n '<prefix>',\n opts.prefix,\n '</prefix>',\n '<suffix>',\n opts.suffix,\n '</suffix>',\n ].join('\\n');\n}\n\nfunction parseCompletionJson(text: string): CompletionSuggestion[] {\n const parsed = JSON.parse(extractJson(text)) as { items?: unknown };\n if (!Array.isArray(parsed.items)) return [];\n return parsed.items\n .map(normalizeSuggestion)\n .filter((item): item is CompletionSuggestion => item !== null);\n}\n\nfunction normalizeSuggestion(value: unknown): CompletionSuggestion | null {\n if (!value || typeof value !== 'object') return null;\n const raw = value as Record<string, unknown>;\n const label = typeof raw.label === 'string' ? raw.label.trim() : '';\n const insertText = typeof raw.insertText === 'string' ? raw.insertText : '';\n if (!label || !insertText) return null;\n return {\n label,\n insertText,\n kind: normalizeKind(raw.kind),\n detail: optionalString(raw.detail),\n documentation: optionalString(raw.documentation),\n sortText: optionalString(raw.sortText),\n source: 'llm',\n };\n}\n\nfunction indexResultToSuggestion(result: SearchResult): CompletionSuggestion {\n return {\n label: result.name,\n insertText: result.name,\n kind: mapIndexKind(result.kind),\n detail: result.signature || `${result.kind} ${relativeDisplayPath(result.file, result.line)}`,\n documentation: result.docComment || result.snippet || undefined,\n sortText: `z-${String(Math.round(10_000 - result.score)).padStart(5, '0')}-${result.name}`,\n source: 'index',\n };\n}\n\nfunction parseLspToolOutput(output: string): CompletionSuggestion[] {\n if (!output || output.startsWith('No completions') || output.startsWith('[LSP_')) return [];\n const jsonItems = parseLspToolJson(output);\n if (jsonItems) return jsonItems;\n return output\n .split(/\\r?\\n/)\n .map((line) => line.match(/^\\d+\\.\\s+(.+?)\\s+\\[([^\\]]+)](?:\\s+—\\s+(.+))?$/))\n .filter((match): match is RegExpMatchArray => match !== null)\n .map((match, index): CompletionSuggestion => {\n const label = match[1]?.trim() ?? '';\n const detail = match[3]?.trim();\n return {\n label,\n insertText: label,\n kind: mapLspKindName(match[2]),\n detail: detail || undefined,\n sortText: `a-${String(index).padStart(3, '0')}-${label}`,\n source: 'lsp',\n };\n })\n .filter((item) => item.label);\n}\n\nfunction parseLspToolJson(output: string): CompletionSuggestion[] | null {\n try {\n const parsed = JSON.parse(output) as { items?: unknown };\n if (!Array.isArray(parsed.items)) return [];\n return parsed.items\n .map((value, index): CompletionSuggestion | null => {\n if (!value || typeof value !== 'object') return null;\n const raw = value as Record<string, unknown>;\n const label = typeof raw.label === 'string' ? raw.label.trim() : '';\n const insertText = typeof raw.insertText === 'string' && raw.insertText\n ? raw.insertText\n : label;\n if (!label || !insertText) return null;\n return {\n label,\n insertText,\n kind: mapLspKindName(typeof raw.kind === 'string' ? raw.kind : undefined),\n detail: optionalString(raw.detail),\n documentation: optionalString(raw.documentation),\n sortText: `a-${String(index).padStart(3, '0')}-${label}`,\n source: 'lsp',\n };\n })\n .filter((item): item is CompletionSuggestion => item !== null);\n } catch {\n return null;\n }\n}\n\nfunction mapLspKindName(kind: string | undefined): CompletionItemKind {\n switch (kind?.toLowerCase()) {\n case 'method':\n return 'method';\n case 'function':\n return 'function';\n case 'constructor':\n return 'constructor';\n case 'field':\n return 'field';\n case 'variable':\n case 'constant':\n return 'variable';\n case 'class':\n case 'struct':\n return 'class';\n case 'interface':\n case 'typeparameter':\n return 'interface';\n case 'module':\n return 'module';\n case 'property':\n return 'property';\n case 'unit':\n return 'unit';\n case 'value':\n case 'enummember':\n return 'value';\n case 'enum':\n return 'enum';\n case 'keyword':\n return 'keyword';\n case 'snippet':\n return 'snippet';\n case 'file':\n return 'file';\n case 'reference':\n return 'reference';\n default:\n return 'text';\n }\n}\n\nfunction mapIndexKind(kind: SearchResult['kind']): CompletionItemKind {\n switch (kind) {\n case 'class':\n case 'struct':\n return 'class';\n case 'interface':\n case 'trait':\n case 'type':\n return 'interface';\n case 'enum':\n return 'enum';\n case 'function':\n return 'function';\n case 'method':\n return 'method';\n case 'property':\n case 'parameter':\n return 'property';\n case 'var':\n case 'let':\n case 'const':\n case 'static':\n return 'variable';\n case 'namespace':\n case 'mod':\n return 'module';\n default:\n return 'reference';\n }\n}\n\nfunction normalizeKind(value: unknown): CompletionItemKind | undefined {\n if (typeof value !== 'string') return undefined;\n const allowed: CompletionItemKind[] = [\n 'text',\n 'method',\n 'function',\n 'constructor',\n 'field',\n 'variable',\n 'class',\n 'interface',\n 'module',\n 'property',\n 'unit',\n 'value',\n 'enum',\n 'keyword',\n 'snippet',\n 'file',\n 'reference',\n ];\n return allowed.includes(value as CompletionItemKind)\n ? value as CompletionItemKind\n : undefined;\n}\n\nfunction mergeSuggestions(items: CompletionSuggestion[]): CompletionSuggestion[] {\n const seen = new Set<string>();\n const merged: CompletionSuggestion[] = [];\n for (const item of items) {\n const key = `${item.label}\\0${item.insertText}`;\n if (seen.has(key)) continue;\n seen.add(key);\n merged.push(item);\n }\n return merged;\n}\n\nfunction buildSearchQuery(linePrefix: string, filePath: string): string {\n const memberMatch = linePrefix.match(/([A-Za-z_$][\\w$]*)\\.\\s*([A-Za-z_$][\\w$]*)?$/);\n if (memberMatch?.[2]) return memberMatch[2];\n if (memberMatch?.[1]) return memberMatch[1];\n const token = linePrefix.match(/([A-Za-z_$][\\w$]*)$/)?.[1];\n if (token && token.length >= 2) return token;\n return path.basename(filePath, path.extname(filePath));\n}\n\nfunction currentLinePrefix(prefix: string): string {\n const idx = Math.max(prefix.lastIndexOf('\\n'), prefix.lastIndexOf('\\r'));\n return idx === -1 ? prefix : prefix.slice(idx + 1);\n}\n\nfunction extractJson(text: string): string {\n const trimmed = text.trim();\n if (trimmed.startsWith('{')) return trimmed;\n const start = trimmed.indexOf('{');\n const end = trimmed.lastIndexOf('}');\n if (start !== -1 && end > start) return trimmed.slice(start, end + 1);\n return trimmed;\n}\n\nfunction optionalString(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim() ? value.trim() : undefined;\n}\n\nfunction isValidPositionValue(value: unknown): value is number {\n return typeof value === 'number' && Number.isInteger(value) && value >= 1;\n}\n\nfunction relativeDisplayPath(file: string, line: number): string {\n return `${file.replace(/\\\\/g, '/')}:${line}`;\n}\n\nfunction tail(value: string, max: number): string {\n return value.length <= max ? value : value.slice(value.length - max);\n}\n\nfunction head(value: string, max: number): string {\n return value.length <= max ? value : value.slice(0, max);\n}\n\nfunction isInside(root: string, target: string): boolean {\n return target === root || target.startsWith(root + path.sep);\n}\n","/**\n * Shared memory-operation WebSocket handlers for both the standalone WebUI\n * server and the CLI's `--webui` embedded server. Extracted from the\n * duplicated switch cases in `index.ts` and `cli/src/webui-server.ts`.\n *\n * Each function handles the full request→response cycle for one message\n * type. Callers drop them into their switch statement:\n *\n * case 'memory.list': return handleMemoryList(ws, memoryStore);\n */\n\nimport type { WebSocket } from 'ws';\nimport type { MemoryStore } from '@wrongstack/core';\nimport { send, sendResult, errMessage } from './ws-utils.js';\n\n// ── Shared handlers ───────────────────────────────────────────────────\n\n/**\n * List all memory entries across all scopes.\n * Responds with `{ type: 'memory.list', payload: { text } }`.\n */\nexport async function handleMemoryList(\n ws: WebSocket,\n memoryStore: MemoryStore,\n): Promise<void> {\n try {\n const text = await memoryStore.readAll();\n send(ws, { type: 'memory.list', payload: { text } });\n } catch (err) {\n send(ws, {\n type: 'memory.list',\n payload: { text: '', error: errMessage(err) },\n });\n }\n}\n\n/**\n * Persist a new memory entry.\n * Responds with `{ type: 'key.operation_result', payload: { success, message } }`.\n */\nexport async function handleMemoryRemember(\n ws: WebSocket,\n msg: unknown,\n memoryStore: MemoryStore,\n): Promise<void> {\n const { text, scope } = (\n msg as {\n payload: {\n text: string;\n scope?: 'project-agents' | 'project-memory' | 'user-memory' | undefined;\n };\n }\n ).payload;\n try {\n await memoryStore.remember(text, scope ?? 'project-memory');\n sendResult(ws, true, 'Saved to memory');\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n}\n\n/**\n * Remove memory entries matching the given text.\n * Responds with `{ type: 'key.operation_result', payload: { success, message } }`.\n */\nexport async function handleMemoryForget(\n ws: WebSocket,\n msg: unknown,\n memoryStore: MemoryStore,\n): Promise<void> {\n const { text, scope } = (\n msg as {\n payload: {\n text: string;\n scope?: 'project-agents' | 'project-memory' | 'user-memory' | undefined;\n };\n }\n ).payload;\n try {\n const removed = await memoryStore.forget(text, scope ?? 'project-memory');\n sendResult(\n ws,\n removed > 0,\n removed > 0\n ? `Removed ${removed} entr${removed === 1 ? 'y' : 'ies'}`\n : 'No matching entries',\n );\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n}\n","/**\n * MCP management handlers for the WebUI server (both the standalone\n * `wstackui` server and the CLI's embedded `--webui` server).\n *\n * These are thin WebSocket translators over the shared, surface-agnostic\n * management core in `@wrongstack/mcp` (`manage.ts`) — the SAME core the REPL\n * `/mcp` command writes against (same config.json, same MCPRegistry). All the\n * config IO, url/header persistence, and live registry start/stop logic lives\n * there; here we only map structured results to WS events the browser expects.\n */\n\nimport { allServers } from '@wrongstack/core';\nimport {\n addMcp,\n disableMcp,\n discoverMcp,\n enableMcp,\n listMcp,\n type MCPRegistry,\n type McpManageDeps,\n type McpServerInfo,\n type McpServerInput,\n removeMcp,\n restartMcp,\n updateMcp,\n} from '@wrongstack/mcp';\nimport type { WebSocket } from 'ws';\nimport type { WSClientMessage } from './types.js';\nimport { send } from './ws-utils.js';\n\n/** Wire view of a server as the browser MCP panel consumes it. */\nexport interface MCPServerView {\n name: string;\n transport: string;\n status: 'stopped' | 'connecting' | 'connected' | 'sleeping' | 'discovering' | 'error';\n enabled: boolean;\n description?: string;\n tools?: string[];\n error?: string;\n pid?: number;\n lazy?: boolean;\n}\n\n/** Map a raw registry state to the UI status union. */\nfunction mapStatus(raw: string): MCPServerView['status'] {\n switch (raw) {\n case 'connected':\n return 'connected';\n case 'connecting':\n case 'reconnecting':\n return 'connecting';\n case 'failed':\n return 'error';\n case 'dormant':\n // Lazy server registered from cache, process not spawned — show as sleeping.\n return 'sleeping';\n default:\n // idle / disconnected / stopped\n return 'stopped';\n }\n}\n\n/** Project the shared {@link McpServerInfo} into the browser wire shape. */\nfunction toView(info: McpServerInfo): MCPServerView {\n const view: MCPServerView = {\n name: info.name,\n transport: info.transport,\n // A dormant lazy server is \"asleep\", not stopped — preserve that even when\n // it's enabled in config.\n status: info.status === 'dormant' ? 'sleeping' : info.enabled === false ? 'stopped' : mapStatus(info.status),\n enabled: info.enabled,\n tools: info.tools,\n };\n if (info.description !== undefined) view.description = info.description;\n if (info.lazy !== undefined) view.lazy = info.lazy;\n return view;\n}\n\n/**\n * Build the shared management deps. Returns null (and sends a failure result)\n * when the live registry isn't wired — both WebUI servers now pass one, so this\n * is a defensive guard rather than the normal path.\n */\nfunction deps(\n ws: WebSocket,\n globalConfigPath: string | undefined,\n registry: MCPRegistry | undefined,\n): McpManageDeps | null {\n if (!registry || !globalConfigPath) {\n send(ws, {\n type: 'mcp.operation_result',\n payload: { success: false, message: 'MCP registry is not available in this session.' },\n });\n return null;\n }\n return { configPath: globalConfigPath, registry, presets: allServers() };\n}\n\nfunction name(msg: WSClientMessage): string {\n return (msg.payload as { name?: string } | undefined)?.name ?? '';\n}\n\n/** mcp.list — configured servers merged with live registry status + tools. */\nexport async function handleMcpList(\n ws: WebSocket,\n _msg: WSClientMessage,\n globalConfigPath: string,\n mcpRegistry?: MCPRegistry,\n): Promise<void> {\n if (!mcpRegistry || !globalConfigPath) {\n send(ws, { type: 'mcp.list', payload: { servers: [] } });\n return;\n }\n const servers = await listMcp({\n configPath: globalConfigPath,\n registry: mcpRegistry,\n presets: allServers(),\n });\n send(ws, { type: 'mcp.list', payload: { servers: servers.map(toView) } });\n}\n\n/** mcp.add — persist a new server (incl. url/headers) and start it if enabled. */\nexport async function handleMcpAdd(\n ws: WebSocket,\n msg: WSClientMessage,\n globalConfigPath: string,\n mcpRegistry?: MCPRegistry,\n): Promise<void> {\n const d = deps(ws, globalConfigPath, mcpRegistry);\n if (!d) return;\n const result = await addMcp(msg.payload as McpServerInput, d);\n if (result.ok && result.server) {\n send(ws, { type: 'mcp.server.added', payload: { server: toView(result.server) } });\n if (result.registryError) {\n send(ws, {\n type: 'mcp.server.error',\n payload: { name: result.server.name, error: result.registryError },\n });\n } else if (result.server.enabled) {\n send(ws, { type: 'mcp.server.connected', payload: { name: result.server.name } });\n }\n }\n send(ws, {\n type: 'mcp.operation_result',\n payload: { success: result.ok, message: result.message },\n });\n}\n\n/** mcp.update — re-persist config (incl. url/headers) and re-apply to registry. */\nexport async function handleMcpUpdate(\n ws: WebSocket,\n msg: WSClientMessage,\n globalConfigPath: string,\n mcpRegistry?: MCPRegistry,\n): Promise<void> {\n const d = deps(ws, globalConfigPath, mcpRegistry);\n if (!d) return;\n const result = await updateMcp(msg.payload as McpServerInput, d);\n if (result.ok && result.server) {\n send(ws, { type: 'mcp.server.updated', payload: { server: toView(result.server) } });\n }\n send(ws, {\n type: 'mcp.operation_result',\n payload: { success: result.ok, message: result.message },\n });\n}\n\n/** mcp.remove — stop the server and delete it from config. */\nexport async function handleMcpRemove(\n ws: WebSocket,\n msg: WSClientMessage,\n globalConfigPath: string,\n mcpRegistry?: MCPRegistry,\n): Promise<void> {\n const d = deps(ws, globalConfigPath, mcpRegistry);\n if (!d) return;\n const result = await removeMcp(name(msg), d);\n if (result.ok) {\n send(ws, { type: 'mcp.server.removed', payload: { name: name(msg) } });\n }\n send(ws, {\n type: 'mcp.operation_result',\n payload: { success: result.ok, message: result.message },\n });\n}\n\n/** mcp.enable — flip enabled:true in config and start the server. */\nexport async function handleMcpEnable(\n ws: WebSocket,\n msg: WSClientMessage,\n globalConfigPath: string,\n mcpRegistry?: MCPRegistry,\n): Promise<void> {\n const d = deps(ws, globalConfigPath, mcpRegistry);\n if (!d) return;\n const result = await enableMcp(name(msg), d);\n if (result.ok && result.server) {\n send(ws, { type: 'mcp.server.updated', payload: { server: toView(result.server) } });\n if (result.registryError) {\n send(ws, {\n type: 'mcp.server.error',\n payload: { name: name(msg), error: result.registryError },\n });\n } else {\n send(ws, { type: 'mcp.server.connected', payload: { name: name(msg) } });\n }\n }\n send(ws, {\n type: 'mcp.operation_result',\n payload: { success: result.ok, message: result.message },\n });\n}\n\n/** mcp.disable — stop the server and flip enabled:false in config. */\nexport async function handleMcpDisable(\n ws: WebSocket,\n msg: WSClientMessage,\n globalConfigPath: string,\n mcpRegistry?: MCPRegistry,\n): Promise<void> {\n const d = deps(ws, globalConfigPath, mcpRegistry);\n if (!d) return;\n const result = await disableMcp(name(msg), d);\n if (result.ok) {\n send(ws, { type: 'mcp.server.sleeping', payload: { name: name(msg) } });\n if (result.server) {\n send(ws, { type: 'mcp.server.updated', payload: { server: toView(result.server) } });\n }\n }\n send(ws, {\n type: 'mcp.operation_result',\n payload: { success: result.ok, message: result.message },\n });\n}\n\n/** mcp.sleep — stop a running server (config stays enabled). */\nexport async function handleMcpSleep(\n ws: WebSocket,\n msg: WSClientMessage,\n globalConfigPath: string,\n mcpRegistry?: MCPRegistry,\n): Promise<void> {\n const d = deps(ws, globalConfigPath, mcpRegistry);\n if (!d) return;\n // Sleep == disable the live process but keep config enabled — use the\n // registry directly so the persisted `enabled` flag is untouched.\n try {\n await d.registry.stop(name(msg));\n send(ws, { type: 'mcp.server.sleeping', payload: { name: name(msg) } });\n send(ws, {\n type: 'mcp.operation_result',\n payload: { success: true, message: `Server \"${name(msg)}\" stopped` },\n });\n } catch (err) {\n const error = err instanceof Error ? err.message : String(err);\n send(ws, { type: 'mcp.server.error', payload: { name: name(msg), error } });\n send(ws, {\n type: 'mcp.operation_result',\n payload: { success: false, message: `Failed to stop \"${name(msg)}\": ${error}` },\n });\n }\n}\n\n/** mcp.wake — restart a sleeping/stopped server from config. */\nexport async function handleMcpWake(\n ws: WebSocket,\n msg: WSClientMessage,\n globalConfigPath: string,\n mcpRegistry?: MCPRegistry,\n): Promise<void> {\n const d = deps(ws, globalConfigPath, mcpRegistry);\n if (!d) return;\n send(ws, { type: 'mcp.server.waking', payload: { name: name(msg) } });\n const result = await restartMcp(name(msg), d);\n if (result.ok && !result.registryError) {\n send(ws, { type: 'mcp.server.connected', payload: { name: name(msg) } });\n } else if (result.registryError) {\n send(ws, {\n type: 'mcp.server.error',\n payload: { name: name(msg), error: result.registryError },\n });\n }\n send(ws, {\n type: 'mcp.operation_result',\n payload: { success: result.ok, message: result.message },\n });\n}\n\n/** mcp.restart — stop + start a server. */\nexport async function handleMcpRestart(\n ws: WebSocket,\n msg: WSClientMessage,\n globalConfigPath: string,\n mcpRegistry?: MCPRegistry,\n): Promise<void> {\n const d = deps(ws, globalConfigPath, mcpRegistry);\n if (!d) return;\n const result = await restartMcp(name(msg), d);\n if (result.ok && !result.registryError) {\n send(ws, { type: 'mcp.server.connected', payload: { name: name(msg) } });\n } else if (result.registryError) {\n send(ws, {\n type: 'mcp.server.error',\n payload: { name: name(msg), error: result.registryError },\n });\n }\n send(ws, {\n type: 'mcp.operation_result',\n payload: { success: result.ok, message: result.message },\n });\n}\n\n/** mcp.discover — ensure the server is running and report its live tools. */\nexport async function handleMcpDiscover(\n ws: WebSocket,\n msg: WSClientMessage,\n globalConfigPath: string,\n mcpRegistry?: MCPRegistry,\n): Promise<void> {\n const d = deps(ws, globalConfigPath, mcpRegistry);\n if (!d) return;\n const result = await discoverMcp(name(msg), d);\n if (result.ok) {\n send(ws, {\n type: 'mcp.server.discovered',\n payload: { name: name(msg), tools: result.tools ?? [] },\n });\n }\n send(ws, {\n type: 'mcp.operation_result',\n payload: { success: result.ok, message: result.message },\n });\n}\n","/**\n * Shared skills WebSocket handlers for both the standalone WebUI server\n * (`packages/webui/src/server/index.ts`) and the CLI's `--webui` embedded\n * server (`packages/cli/src/webui-server.ts`).\n *\n * These were previously inlined in BOTH servers, and the CLI copy had\n * drifted — it only wired `skills.list`, so `skills.content` /\n * `skills.export` / `skills.update` (and install/uninstall/create/edit)\n * fell through to the \"Unhandled message type\" warning even though the\n * SkillsPanel sends them. Extracting the full set here gives both servers\n * one source of truth. Each function handles the full request→response\n * cycle for one message type; callers drop them into their switch:\n *\n * case 'skills.content': return handleSkillsContent(ws, skillsCtx, msg);\n *\n * The logic is a verbatim lift of the standalone's inline cases — only the\n * dependency references changed (`skillLoader`/`skillInstaller`/\n * `projectRoot` → `ctx.*`, local `send`/`errMessage` → imported helpers).\n */\n\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport type { WebSocket } from 'ws';\nimport JSZip from 'jszip';\nimport type { SkillLoader } from '@wrongstack/core';\nimport { atomicWrite } from '@wrongstack/core';\nimport type { SkillInstaller } from '@wrongstack/core/skills';\nimport { wstackGlobalRoot } from '@wrongstack/core/utils';\nimport { send, errMessage } from './ws-utils.js';\nimport { validateSkillsCreatePayload, validateSkillsEditPayload } from './ws-payload-validation.js';\n\nexport interface SkillsContext {\n /** Backs skills.list/content/edit/export. Absent ⇒ feature disabled. */\n skillLoader: SkillLoader | undefined;\n /** Backs skills.install/uninstall/update. Absent ⇒ those ops disabled. */\n skillInstaller: SkillInstaller | undefined;\n /** Project root — used by skills.create to write `.wrongstack/skills/…`. */\n projectRoot: string;\n}\n\n// ── Shared handlers ───────────────────────────────────────────────────\n\n/**\n * List installed skills. Enriches each manifest with the source URL + git\n * ref recorded by the installer (when present), so the panel can show\n * provenance and offer update/uninstall.\n */\nexport async function handleSkillsList(ws: WebSocket, ctx: SkillsContext): Promise<void> {\n if (!ctx.skillLoader) {\n send(ws, { type: 'skills.list', payload: { skills: [], enabled: false } });\n return;\n }\n try {\n const manifests = await ctx.skillLoader.list();\n const entries = await ctx.skillLoader.listEntries();\n const byName = new Map(entries.map((e) => [e.name, e]));\n\n // Fetch source URLs and commit refs from the manifest (installed-skills.json)\n const sourceUrlsByName = new Map<string, string>();\n const refsByName = new Map<string, string>();\n if (ctx.skillInstaller) {\n try {\n const installed = await ctx.skillInstaller.listInstalled();\n for (const entry of installed) {\n sourceUrlsByName.set(entry.name, entry.source);\n refsByName.set(entry.name, entry.ref);\n }\n } catch {\n // Non-fatal — source URLs just won't be shown\n }\n }\n\n send(ws, {\n type: 'skills.list',\n payload: {\n enabled: true,\n skills: manifests.map((m) => ({\n name: m.name,\n description: m.description,\n version: m.version ?? '',\n source: m.source,\n sourceUrl: sourceUrlsByName.get(m.name) ?? '',\n ref: refsByName.get(m.name) ?? '',\n path: m.path,\n trigger: byName.get(m.name)?.trigger ?? '',\n scope: byName.get(m.name)?.scope ?? [],\n })),\n },\n });\n } catch (err) {\n send(ws, {\n type: 'skills.list',\n payload: {\n skills: [],\n enabled: true,\n error: errMessage(err),\n },\n });\n }\n}\n\n/**\n * Read a single skill's body + its directory's related files + which other\n * skills reference it by name. Powers the skill detail/preview view.\n */\nexport async function handleSkillsContent(\n ws: WebSocket,\n ctx: SkillsContext,\n msg: unknown,\n): Promise<void> {\n if (!ctx.skillLoader) {\n send(ws, { type: 'skills.content', payload: { name: '', body: '', path: '', source: '', relatedFiles: [], references: [], error: 'Skills not enabled' } });\n return;\n }\n const contentPayload = (msg as { payload: { name: string; source: string } }).payload;\n if (!contentPayload?.name) {\n send(ws, { type: 'skills.content', payload: { name: '', body: '', path: '', source: '', relatedFiles: [], references: [], error: 'Skill name is required' } });\n return;\n }\n try {\n const { name, source } = contentPayload;\n const entries = await ctx.skillLoader.listEntries();\n const entry = entries.find((e) => e.name.toLowerCase() === name.toLowerCase());\n if (!entry) {\n send(ws, { type: 'skills.content', payload: { name, body: '', path: '', source, relatedFiles: [], references: [], error: `Skill \"${name}\" not found` } });\n return;\n }\n // Read body directly from path — avoids re-running find() which re-reads all SKILL.md files\n const body = await fs.readFile(entry.path, 'utf8');\n const skillDir = path.dirname(entry.path);\n\n // Related files — other files in the same skill directory\n let relatedFiles: string[] = [];\n try {\n const files = await fs.readdir(skillDir);\n relatedFiles = files\n .filter((f) => f !== path.basename(entry.path))\n .map((f) => path.join(skillDir, f));\n } catch {\n // Non-fatal\n }\n\n // References — which other skills reference this one (by name)\n // Read all other skill bodies in parallel, keyed by name for O(1) lookup\n const nameLower = name.toLowerCase();\n const refResults = await Promise.all(\n entries\n .filter((e) => e.name.toLowerCase() !== nameLower)\n .map(async (e): Promise<[string, boolean]> => {\n try {\n // Use entry.path directly to skip find() overhead\n const content = await fs.readFile(e.path, 'utf8');\n return [e.name, content.toLowerCase().includes(nameLower)];\n } catch {\n return [e.name, false];\n }\n }),\n );\n const refs = refResults.filter(([, hasRef]) => hasRef).map(([n]) => n);\n\n send(ws, { type: 'skills.content', payload: { name, body, path: entry.path, source, relatedFiles, references: refs } });\n } catch (err) {\n send(ws, { type: 'skills.content', payload: { name: contentPayload.name, body: '', path: '', source: contentPayload.source, relatedFiles: [], references: [], error: errMessage(err) } });\n }\n}\n\n/**\n * Install a skill from a git ref (`owner/repo` or URL). Optional `global`\n * installs into the user-wide skills dir instead of the project's.\n */\nexport async function handleSkillsInstall(\n ws: WebSocket,\n ctx: SkillsContext,\n msg: unknown,\n): Promise<void> {\n if (!ctx.skillInstaller) {\n send(ws, { type: 'skills.installed', payload: { success: false, error: 'Skills not enabled' } });\n return;\n }\n const installPayload = (msg as { payload: { ref: string; global?: boolean } }).payload;\n if (!installPayload?.ref?.trim()) {\n send(ws, { type: 'skills.installed', payload: { success: false, error: 'Skill reference is required (e.g. owner/repo or https://github.com/owner/repo)' } });\n return;\n }\n try {\n const results = await ctx.skillInstaller.install(installPayload.ref.trim(), { global: installPayload.global });\n send(ws, {\n type: 'skills.installed',\n payload: {\n success: true,\n results,\n error: null,\n },\n });\n } catch (err) {\n send(ws, {\n type: 'skills.installed',\n payload: {\n success: false,\n error: errMessage(err),\n },\n });\n }\n}\n\n/**\n * Uninstall a skill by name. Optional `global` restricts/Targets the\n * user-wide install.\n */\nexport async function handleSkillsUninstall(\n ws: WebSocket,\n ctx: SkillsContext,\n msg: unknown,\n): Promise<void> {\n if (!ctx.skillInstaller) {\n send(ws, { type: 'skills.uninstalled', payload: { success: false, error: 'Skills not enabled' } });\n return;\n }\n const uninstallPayload = (msg as { payload: { name: string; global?: boolean } }).payload;\n if (!uninstallPayload?.name?.trim()) {\n send(ws, { type: 'skills.uninstalled', payload: { success: false, error: 'Skill name is required' } });\n return;\n }\n try {\n await ctx.skillInstaller.uninstall(uninstallPayload.name.trim(), { global: uninstallPayload.global });\n send(ws, { type: 'skills.uninstalled', payload: { success: true, error: null } });\n } catch (err) {\n send(ws, { type: 'skills.uninstalled', payload: { success: false, error: errMessage(err) } });\n }\n}\n\n/**\n * Update one skill (`name`) or all installed skills (when `name` is\n * omitted). Reports per-skill updated/unchanged/error tallies.\n */\nexport async function handleSkillsUpdate(\n ws: WebSocket,\n ctx: SkillsContext,\n msg: unknown,\n): Promise<void> {\n if (!ctx.skillInstaller) {\n send(ws, { type: 'skills.updated', payload: { success: false, error: 'Skills not enabled' } });\n return;\n }\n const updatePayload = (msg as { payload?: { name?: string; global?: boolean } | undefined }).payload;\n try {\n const result = await ctx.skillInstaller.update(updatePayload?.name, { global: updatePayload?.global });\n send(ws, {\n type: 'skills.updated',\n payload: {\n success: true,\n error: null,\n updated: result.updated,\n unchanged: result.unchanged,\n errors: result.errors,\n },\n });\n } catch (err) {\n send(ws, { type: 'skills.updated', payload: { success: false, error: errMessage(err) } });\n }\n}\n\n/**\n * Scaffold a new project- or global-scoped skill from a name + description.\n * Writes a templated `SKILL.md` under `.wrongstack/skills/<name>/` (project)\n * or the user-wide skills dir (global).\n */\nexport async function handleSkillsCreate(\n ws: WebSocket,\n ctx: SkillsContext,\n msg: unknown,\n): Promise<void> {\n const parsed = validateSkillsCreatePayload((msg as { payload?: unknown }).payload);\n if (!parsed.ok) {\n send(ws, { type: 'skills.created', payload: { success: false, error: parsed.message } });\n return;\n }\n const createPayload = parsed.value;\n try {\n const targetDir =\n createPayload.scope === 'global'\n ? path.join(wstackGlobalRoot(), 'skills', createPayload.name.trim())\n : path.join(ctx.projectRoot, '.wrongstack', 'skills', createPayload.name.trim());\n\n // Check if directory already exists\n try {\n await fs.access(targetDir);\n send(ws, { type: 'skills.created', payload: { success: false, error: `Skill \"${createPayload.name}\" already exists` } });\n return;\n } catch {\n // Directory does not exist — good\n }\n\n await fs.mkdir(targetDir, { recursive: true });\n\n // Parse description lines to build the skill content\n const lines = createPayload.description.trim().split('\\n');\n const firstLine = lines[0].trim();\n const bodyLines = lines.slice(1).map((l) => l.trim()).filter(Boolean);\n const descriptionText = firstLine + (bodyLines.length > 0 ? `\\n${bodyLines.join('\\n')}` : '');\n const trigger = bodyLines.find((l) => l.toLowerCase().startsWith('triggers:')) ?? '';\n\n const skillContent = [\n '---',\n `name: ${createPayload.name.trim()}`,\n 'description: |',\n ` ${descriptionText.replace(/\\n/g, '\\n ')}`,\n `version: 1.0.0`,\n '---',\n '',\n `# ${createPayload.name.trim().split('-').map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(' ')}`,\n '',\n '## Overview',\n '',\n firstLine,\n '',\n ...(bodyLines.length > 0 ? bodyLines.filter((l) => !l.toLowerCase().startsWith('triggers:')) : []),\n '',\n '## Rules',\n '- TODO: add your first rule',\n '',\n '## Patterns',\n '### Do',\n '```ts',\n '// TODO: add a good example',\n '```',\n '',\n '### Don\\'t',\n '```ts',\n '// TODO: add a bad example',\n '```',\n '',\n '## Workflow',\n '1. TODO: describe step one',\n '2. TODO: describe step two',\n '',\n trigger ? `\\n${trigger}\\n` : '',\n '## Skills in scope',\n '- `bug-hunter` — for systematic bug detection patterns',\n '- `output-standards` — for standardized `<next_steps>` formatting',\n ].join('\\n');\n\n await atomicWrite(path.join(targetDir, 'SKILL.md'), skillContent);\n\n send(ws, {\n type: 'skills.created',\n payload: {\n success: true,\n error: null,\n skill: { name: createPayload.name.trim(), path: path.join(targetDir, 'SKILL.md'), scope: createPayload.scope },\n },\n });\n } catch (err) {\n send(ws, { type: 'skills.created', payload: { success: false, error: errMessage(err) } });\n }\n}\n\n/**\n * Overwrite a skill's body. Refuses bundled skills (read-only) and unknown\n * names.\n */\nexport async function handleSkillsEdit(\n ws: WebSocket,\n ctx: SkillsContext,\n msg: unknown,\n): Promise<void> {\n if (!ctx.skillLoader) {\n send(ws, { type: 'skills.edited', payload: { success: false, error: 'Skills not enabled' } });\n return;\n }\n const parsed = validateSkillsEditPayload((msg as { payload?: unknown }).payload);\n if (!parsed.ok) {\n send(ws, { type: 'skills.edited', payload: { success: false, error: parsed.message } });\n return;\n }\n const editPayload = parsed.value;\n try {\n const entries = await ctx.skillLoader.listEntries();\n const entry = entries.find((e) => e.name.toLowerCase() === editPayload.name.toLowerCase());\n if (!entry) {\n send(ws, { type: 'skills.edited', payload: { success: false, error: `Skill \"${editPayload.name}\" not found` } });\n return;\n }\n // Only allow editing project/user skills (not bundled)\n if (entry.scope.includes('bundled')) {\n send(ws, { type: 'skills.edited', payload: { success: false, error: 'Bundled skills cannot be edited' } });\n return;\n }\n await atomicWrite(entry.path, editPayload.body);\n send(ws, { type: 'skills.edited', payload: { success: true, error: null } });\n } catch (err) {\n send(ws, { type: 'skills.edited', payload: { success: false, error: errMessage(err) } });\n }\n}\n\n/**\n * Export every readable skill as a base64-encoded zip (one folder per skill,\n * each with its `SKILL.md`). Powers the panel's \"Export all\" button.\n */\nexport async function handleSkillsExport(ws: WebSocket, ctx: SkillsContext): Promise<void> {\n if (!ctx.skillLoader) {\n send(ws, { type: 'skills.exported', payload: { zipBase64: '', skillCount: 0, error: 'Skills not enabled' } });\n return;\n }\n try {\n const entries = await ctx.skillLoader.listEntries();\n const zip = new JSZip();\n for (const entry of entries) {\n try {\n const body = await ctx.skillLoader!.readBody(entry.name);\n const safeName = entry.name.replace(/\\//g, '_');\n zip.file(`${safeName}/SKILL.md`, body);\n } catch {\n // Skip skills we can't read\n }\n }\n const zipBuffer = await zip.generateAsync({ type: 'nodebuffer', compression: 'DEFLATE' });\n const zipBase64 = zipBuffer.toString('base64');\n send(ws, { type: 'skills.exported', payload: { zipBase64, skillCount: entries.length, error: undefined } });\n } catch (err) {\n send(ws, { type: 'skills.exported', payload: { zipBase64: '', skillCount: 0, error: errMessage(err) } });\n }\n}\n","/**\n * Shared prompt-library WebSocket handlers for BOTH the standalone WebUI server\n * (`packages/webui/src/server/index.ts`) and the CLI's `--webui` embedded server\n * (`packages/cli/src/webui-server.ts`). One source of truth so the two servers\n * never drift (the lesson from skills-handlers).\n *\n * Each function handles one request→response cycle; callers drop them into their\n * switch:\n *\n * case 'prompts.search': return handlePromptsSearch(ws, promptsCtx, msg);\n *\n * The prompt library is read across three layers (builtin + user + project) by\n * the injected `PromptLoader`; writes (create/favorite) go to the user layer\n * with copy-on-write for builtins. Treat synced/builtin content as DATA — these\n * handlers never execute it; the client inserts a chosen prompt into the chat\n * input as an ordinary user turn.\n */\n\nimport type { PromptEntry, PromptLoader, PromptUsageStore, PromptVariable } from '@wrongstack/core';\nimport { errMessage, send } from './ws-utils.js';\n\n/**\n * Normalize a client-supplied `variables` array into clean PromptVariable[].\n * Drops entries without a string `name`; carries description/required/multiline\n * and a string-only `enum`. Returns undefined when nothing valid is present so\n * the entry omits the field entirely.\n */\nfunction parseVariablesPayload(raw: unknown): PromptVariable[] | undefined {\n if (!Array.isArray(raw)) return undefined;\n const out: PromptVariable[] = [];\n for (const item of raw) {\n if (!item || typeof item !== 'object') continue;\n const o = item as Record<string, unknown>;\n if (typeof o['name'] !== 'string' || !o['name'].trim()) continue;\n const enumVals =\n Array.isArray(o['enum']) && o['enum'].every((x) => typeof x === 'string')\n ? (o['enum'] as string[]).map((s) => s.trim()).filter(Boolean)\n : undefined;\n const v: PromptVariable = { name: o['name'].trim() };\n if (typeof o['description'] === 'string' && o['description'].trim()) {\n v.description = o['description'].trim();\n }\n if (o['required'] === true) v.required = true;\n if (o['multiline'] === true) v.multiline = true;\n if (enumVals && enumVals.length > 0) v.enum = enumVals;\n out.push(v);\n }\n return out.length > 0 ? out : undefined;\n}\n\nexport interface PromptsContext {\n /** Backs all prompt ops. Absent ⇒ feature unavailable. */\n promptLoader: PromptLoader | undefined;\n /** Records per-slug insert counts (shared with CLI `/prompt recent`). */\n promptUsage?: PromptUsageStore | undefined;\n}\n\n/** Project-relative, content-free metadata for list/search results. */\nfunction toMeta(e: PromptEntry) {\n return {\n id: e.id,\n slug: e.slug,\n title: e.title,\n description: e.description,\n category: e.category,\n tags: e.tags,\n source: e.source,\n favorite: e.favorite,\n variables: e.variables ?? [],\n };\n}\n\nexport async function handlePromptsList(ws: WSLike, ctx: PromptsContext): Promise<void> {\n if (!ctx.promptLoader) {\n send(ws, { type: 'prompts.list', payload: { enabled: false, prompts: [], categories: [] } });\n return;\n }\n try {\n const [all, categories] = await Promise.all([\n ctx.promptLoader.list(),\n ctx.promptLoader.categories(),\n ]);\n send(ws, {\n type: 'prompts.list',\n payload: { enabled: true, prompts: all.map(toMeta), categories },\n });\n } catch (err) {\n send(ws, {\n type: 'prompts.list',\n payload: { enabled: true, prompts: [], categories: [], error: errMessage(err) },\n });\n }\n}\n\nexport async function handlePromptsSearch(\n ws: WSLike,\n ctx: PromptsContext,\n msg: unknown,\n): Promise<void> {\n if (!ctx.promptLoader) {\n send(ws, { type: 'prompts.search', payload: { enabled: false, prompts: [] } });\n return;\n }\n const payload = (msg as { payload?: { query?: string; category?: string } }).payload ?? {};\n try {\n const results = await ctx.promptLoader.search(payload.query ?? '', {\n ...(payload.category ? { category: payload.category } : {}),\n limit: 50,\n });\n send(ws, { type: 'prompts.search', payload: { enabled: true, prompts: results.map(toMeta) } });\n } catch (err) {\n send(ws, {\n type: 'prompts.search',\n payload: { enabled: true, prompts: [], error: errMessage(err) },\n });\n }\n}\n\nexport async function handlePromptsContent(\n ws: WSLike,\n ctx: PromptsContext,\n msg: unknown,\n): Promise<void> {\n const slug = (msg as { payload?: { slug?: string } }).payload?.slug;\n if (!ctx.promptLoader || !slug) {\n send(ws, {\n type: 'prompts.content',\n payload: { slug: slug ?? '', found: false, content: '', variables: [] },\n });\n return;\n }\n try {\n const entry = await ctx.promptLoader.find(slug);\n if (!entry) {\n send(ws, {\n type: 'prompts.content',\n payload: { slug, found: false, content: '', variables: [] },\n });\n return;\n }\n send(ws, {\n type: 'prompts.content',\n payload: {\n slug: entry.slug,\n found: true,\n title: entry.title,\n content: entry.content,\n variables: entry.variables ?? [],\n category: entry.category,\n source: entry.source,\n },\n });\n } catch (err) {\n send(ws, {\n type: 'prompts.content',\n payload: { slug, found: false, content: '', variables: [], error: errMessage(err) },\n });\n }\n}\n\nexport async function handlePromptsFavorite(\n ws: WSLike,\n ctx: PromptsContext,\n msg: unknown,\n): Promise<void> {\n const payload = (msg as { payload?: { slug?: string; favorite?: boolean } }).payload;\n if (!ctx.promptLoader || !payload?.slug) {\n send(ws, {\n type: 'prompts.favorite',\n payload: { success: false, error: 'Prompt library unavailable' },\n });\n return;\n }\n try {\n const updated = await ctx.promptLoader.setFavorite(payload.slug, payload.favorite !== false);\n if (!updated) {\n send(ws, {\n type: 'prompts.favorite',\n payload: { success: false, error: 'Prompt not found' },\n });\n return;\n }\n send(ws, {\n type: 'prompts.favorite',\n payload: { success: true, slug: updated.slug, favorite: updated.favorite },\n });\n } catch (err) {\n send(ws, { type: 'prompts.favorite', payload: { success: false, error: errMessage(err) } });\n }\n}\n\nexport async function handlePromptsCreate(\n ws: WSLike,\n ctx: PromptsContext,\n msg: unknown,\n): Promise<void> {\n const p = (msg as { payload?: Record<string, unknown> }).payload;\n if (!ctx.promptLoader || !p) {\n send(ws, {\n type: 'prompts.created',\n payload: { success: false, error: 'Prompt library unavailable' },\n });\n return;\n }\n const title = typeof p['title'] === 'string' ? p['title'].trim() : '';\n const content = typeof p['content'] === 'string' ? p['content'] : '';\n if (!title || !content) {\n send(ws, {\n type: 'prompts.created',\n payload: { success: false, error: 'Title and content are required' },\n });\n return;\n }\n try {\n const now = new Date().toISOString();\n const tags = Array.isArray(p['tags'])\n ? (p['tags'].filter((t) => typeof t === 'string') as string[])\n : [];\n const slug =\n title\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 64) || 'prompt';\n const variables = parseVariablesPayload(p['variables']);\n const entry: PromptEntry = {\n id: slug,\n slug,\n title,\n description: typeof p['description'] === 'string' ? p['description'] : '',\n content,\n category:\n typeof p['category'] === 'string' && p['category']\n ? (p['category'] as string)\n : 'uncategorized',\n tags,\n source: 'user',\n favorite: false,\n ...(variables ? { variables } : {}),\n createdAt: now,\n updatedAt: now,\n };\n await ctx.promptLoader.save(entry);\n send(ws, { type: 'prompts.created', payload: { success: true, slug } });\n } catch (err) {\n send(ws, { type: 'prompts.created', payload: { success: false, error: errMessage(err) } });\n }\n}\n\n/** Record that a prompt was inserted (best-effort; feeds CLI `/prompt recent`). */\nexport async function handlePromptsUsed(ws: WSLike, ctx: PromptsContext, msg: unknown): Promise<void> {\n const slug = (msg as { payload?: { slug?: string } }).payload?.slug;\n if (!ctx.promptUsage || !slug) {\n send(ws, { type: 'prompts.used', payload: { success: false } });\n return;\n }\n try {\n await ctx.promptUsage.record(slug);\n send(ws, { type: 'prompts.used', payload: { success: true, slug } });\n } catch {\n send(ws, { type: 'prompts.used', payload: { success: false } });\n }\n}\n\n/** Return recently-inserted prompt slugs (most-recent first) for the modal's Recent view. */\nexport async function handlePromptsRecent(ws: WSLike, ctx: PromptsContext): Promise<void> {\n if (!ctx.promptUsage) {\n send(ws, { type: 'prompts.recent', payload: { slugs: [] } });\n return;\n }\n try {\n const recent = await ctx.promptUsage.recent(50);\n send(ws, { type: 'prompts.recent', payload: { slugs: recent.map((r) => r.slug) } });\n } catch (err) {\n send(ws, { type: 'prompts.recent', payload: { slugs: [], error: errMessage(err) } });\n }\n}\n\n/** Minimal structural type for the ws.send sink (matches `ws` WebSocket). */\ntype WSLike = Parameters<typeof send>[0];\n","/**\n * Shared Design Studio WebSocket handlers for both the standalone WebUI server\n * (`packages/webui/src/server/index.ts`) and the CLI's `--webui` embedded\n * server (`packages/cli/src/webui-server.ts`). One source of truth keeps the two\n * servers at parity (enforced by ws-handler-parity.test.ts).\n *\n * case 'design.list': return handleDesignList(ws, designCtx);\n * case 'design.use': return handleDesignUse(ws, designCtx, msg);\n * case 'design.state': return handleDesignState(ws, designCtx);\n * case 'design.set': return handleDesignSet(ws, designCtx, msg);\n * case 'design.materialize': return handleDesignMaterialize(ws, designCtx, msg);\n *\n * Browsing + customization of curated UI design kits; `design.use` pins the\n * active kit, `design.set` records color/token overrides, `design.materialize`\n * writes the (override-applied) tokens to a real theme file on disk.\n */\n\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { DesignStack } from '@wrongstack/core';\nimport {\n applyTokenOverrides,\n getDesignKitLoader,\n getDesignState,\n isDesignStack,\n loadActiveKit,\n materializeTokens,\n recordKitChoice,\n recordOverrides,\n runDesignVerify,\n setActiveKit,\n setDesignOverrides,\n} from '@wrongstack/core';\nimport type { WebSocket } from 'ws';\nimport { send } from './ws-utils.js';\n\n/** Coerce a loose payload value into a string→string override map. */\nfunction readOverrides(value: unknown): Record<string, string> {\n const out: Record<string, string> = {};\n if (value && typeof value === 'object') {\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n if (typeof v === 'string') out[k] = v;\n }\n }\n return out;\n}\n\nexport interface DesignContext {\n projectRoot: string;\n /** Live agent context whose `meta.designStudio` we read/pin. Optional. */\n agentMeta?: { meta: Record<string, unknown> } | undefined;\n}\n\nconst FOUNDATIONS_ID = '_foundations';\n\nasync function buildListPayload(ctx: DesignContext): Promise<{\n kits: Array<{\n id: string;\n name: string;\n aesthetic: string;\n bestFor: string;\n stacks: string[];\n tags: string[];\n light: Record<string, string>;\n dark: Record<string, string>;\n }>;\n activeKit: string | null;\n stack: string | null;\n overrides: Record<string, string>;\n}> {\n const loader = getDesignKitLoader(ctx.projectRoot);\n const manifests = (await loader.list()).filter((k) => k.id !== FOUNDATIONS_ID);\n const kits = [];\n for (const m of manifests) {\n const tokens = await loader.readTokens(m.id);\n kits.push({\n id: m.id,\n name: m.name,\n aesthetic: m.aesthetic,\n bestFor: m.bestFor,\n stacks: m.stacks,\n tags: m.tags,\n light: tokens?.light ?? {},\n dark: tokens?.dark ?? {},\n });\n }\n const state = ctx.agentMeta ? getDesignState(ctx.agentMeta) : undefined;\n const persisted = await loadActiveKit(ctx.projectRoot).catch(() => undefined);\n return {\n kits,\n activeKit: state?.activeKit ?? persisted?.kit ?? null,\n stack: state?.stack ?? persisted?.stack ?? null,\n overrides: state?.overrides ?? persisted?.overrides ?? {},\n };\n}\n\nexport async function handleDesignList(ws: WebSocket, ctx: DesignContext): Promise<void> {\n try {\n send(ws, { type: 'design.list', payload: await buildListPayload(ctx) });\n } catch (err) {\n send(ws, {\n type: 'design.list',\n payload: { kits: [], activeKit: null, stack: null, error: String(err) },\n });\n }\n}\n\nexport async function handleDesignState(ws: WebSocket, ctx: DesignContext): Promise<void> {\n const state = ctx.agentMeta ? getDesignState(ctx.agentMeta) : undefined;\n send(ws, {\n type: 'design.state',\n payload: {\n activeKit: state?.activeKit ?? null,\n stack: state?.stack ?? null,\n overrides: state?.overrides ?? {},\n },\n });\n}\n\nexport async function handleDesignUse(\n ws: WebSocket,\n ctx: DesignContext,\n msg: { payload?: unknown },\n): Promise<void> {\n const payload = (msg.payload ?? {}) as { kit?: unknown; stack?: unknown };\n const kitId = typeof payload.kit === 'string' ? payload.kit.trim() : '';\n if (!kitId) {\n send(ws, { type: 'design.use', payload: { ok: false, error: 'No kit id provided' } });\n return;\n }\n try {\n const loader = getDesignKitLoader(ctx.projectRoot);\n const kit = await loader.find(kitId);\n if (!kit) {\n send(ws, { type: 'design.use', payload: { ok: false, kit: kitId, error: 'Kit not found' } });\n return;\n }\n const stackArg = typeof payload.stack === 'string' ? payload.stack : undefined;\n const stack: DesignStack =\n stackArg && isDesignStack(stackArg) ? stackArg : (kit.stacks[0] ?? 'web');\n // Preserve persisted overrides for this kit; merge any passed with `use`.\n const persisted = await loadActiveKit(ctx.projectRoot).catch(() => undefined);\n const keep = persisted?.kit === kit.id ? (persisted.overrides ?? {}) : {};\n const overrides = { ...keep, ...readOverrides((payload as { overrides?: unknown }).overrides) };\n if (ctx.agentMeta) setActiveKit(ctx.agentMeta, kit.id, stack, overrides);\n await recordKitChoice(\n ctx.projectRoot,\n kit.id,\n stack,\n 'webui',\n new Date().toISOString(),\n Object.keys(overrides).length ? overrides : undefined,\n );\n const body = await loader.readBody(kit.id, stack);\n const rawTokens = await loader.readTokens(kit.id);\n const tokens = rawTokens ? applyTokenOverrides(rawTokens, overrides) : rawTokens;\n send(ws, {\n type: 'design.use',\n payload: {\n ok: true,\n kit: kit.id,\n name: kit.name,\n aesthetic: kit.aesthetic,\n stack,\n body,\n overrides,\n light: tokens?.light ?? {},\n dark: tokens?.dark ?? {},\n },\n });\n } catch (err) {\n send(ws, { type: 'design.use', payload: { ok: false, kit: kitId, error: String(err) } });\n }\n}\n\n/** Record structured color/token overrides without changing the pinned kit. */\nexport async function handleDesignSet(\n ws: WebSocket,\n ctx: DesignContext,\n msg: { payload?: unknown },\n): Promise<void> {\n const patch = readOverrides((msg.payload as { overrides?: unknown })?.overrides);\n if (Object.keys(patch).length === 0) {\n send(ws, { type: 'design.set', payload: { ok: false, error: 'No overrides provided' } });\n return;\n }\n try {\n const merged = await recordOverrides(ctx.projectRoot, patch, new Date().toISOString());\n if (!merged) {\n send(ws, { type: 'design.set', payload: { ok: false, error: 'No active kit' } });\n return;\n }\n if (ctx.agentMeta) setDesignOverrides(ctx.agentMeta, merged);\n send(ws, { type: 'design.set', payload: { ok: true, overrides: merged } });\n } catch (err) {\n send(ws, { type: 'design.set', payload: { ok: false, error: String(err) } });\n }\n}\n\n/** Write the active kit's (override-applied) tokens to a real theme file. */\nexport async function handleDesignMaterialize(\n ws: WebSocket,\n ctx: DesignContext,\n msg: { payload?: unknown },\n): Promise<void> {\n const payload = (msg.payload ?? {}) as { stack?: unknown; out?: unknown };\n try {\n const active = await loadActiveKit(ctx.projectRoot);\n if (!active) {\n send(ws, { type: 'design.materialize', payload: { ok: false, error: 'No active kit' } });\n return;\n }\n const loader = getDesignKitLoader(ctx.projectRoot);\n const stackArg = typeof payload.stack === 'string' ? payload.stack : undefined;\n const stack: DesignStack =\n stackArg && isDesignStack(stackArg)\n ? stackArg\n : active.stack && isDesignStack(active.stack)\n ? active.stack\n : 'web';\n const raw = await loader.readTokens(active.kit);\n if (!raw) {\n send(ws, { type: 'design.materialize', payload: { ok: false, error: 'Kit has no tokens' } });\n return;\n }\n const tokens = applyTokenOverrides(raw, active.overrides);\n const result = materializeTokens({\n tokens,\n stack,\n kitId: active.kit,\n outPath: typeof payload.out === 'string' ? payload.out : undefined,\n });\n const abs = path.join(ctx.projectRoot, result.path);\n await fs.mkdir(path.dirname(abs), { recursive: true });\n await fs.writeFile(abs, result.content);\n send(ws, {\n type: 'design.materialize',\n payload: { ok: true, path: result.path, format: result.format, stack },\n });\n } catch (err) {\n send(ws, { type: 'design.materialize', payload: { ok: false, error: String(err) } });\n }\n}\n\n/** Scan project UI files for off-palette colors against the active kit. */\nexport async function handleDesignVerify(ws: WebSocket, ctx: DesignContext): Promise<void> {\n try {\n const active = await loadActiveKit(ctx.projectRoot);\n if (!active) {\n send(ws, { type: 'design.verify', payload: { ok: false, error: 'No active kit' } });\n return;\n }\n const loader = getDesignKitLoader(ctx.projectRoot);\n const raw = await loader.readTokens(active.kit);\n if (!raw) {\n send(ws, { type: 'design.verify', payload: { ok: false, error: 'Kit has no tokens' } });\n return;\n }\n const tokens = applyTokenOverrides(raw, active.overrides);\n const report = await runDesignVerify(ctx.projectRoot, tokens);\n send(ws, {\n type: 'design.verify',\n payload: {\n ok: true,\n kit: active.kit,\n filesScanned: report.filesScanned,\n score: report.score,\n violations: report.violations.slice(0, 50),\n violationCount: report.violations.length,\n },\n });\n } catch (err) {\n send(ws, { type: 'design.verify', payload: { ok: false, error: String(err) } });\n }\n}\n","import {\n type Config,\n type DefaultLogger,\n type DefaultSecretVault,\n type WstackPaths,\n bootConfig as coreBootConfig,\n} from '@wrongstack/core';\n\nexport interface BootResult {\n config: Config;\n vault: DefaultSecretVault;\n globalConfigPath: string;\n projectRoot: string;\n wpaths: WstackPaths;\n logger: InstanceType<typeof DefaultLogger>;\n}\n\n/**\n * Thin WebUI wrapper over the canonical `bootConfig` in `@wrongstack/core`\n * (mirrors packages/cli/src/boot-config.ts). All real boot behavior — wstack\n * path resolution, the AES-GCM `DefaultSecretVault`, plaintext-secret\n * migration, and config load/merge — lives in core so the WebUI server and the\n * CLI can't drift. Only the secret-migration notice label (`WebUI`) differs.\n */\nexport async function bootConfig(): Promise<BootResult> {\n const { config, vault, globalConfigPath, projectRoot, wpaths, logger } = await coreBootConfig({\n appLabel: 'WebUI',\n });\n return { config, vault, globalConfigPath, projectRoot, wpaths, logger };\n}\n\nexport function patchConfig(config: Config, updates: Partial<Config>): Config {\n return Object.freeze({ ...config, ...updates });\n}\n","import { spawnSync } from 'node:child_process';\nimport type { WebSocket } from 'ws';\nimport { toErrorMessage } from '@wrongstack/core/utils';\nimport {\n assignNickname,\n AutoPhasePlanner,\n PhaseGraphBuilder,\n PhaseOrchestrator,\n PhaseStore,\n WorktreeManager,\n type PhaseGraph,\n type PhaseTemplate,\n} from '@wrongstack/core';\nimport type { Agent, Context, EventBus, Logger } from '@wrongstack/core';\n\n/**\n * Derive a short, single-line heading from a (possibly multi-paragraph) goal\n * prompt. Takes the first non-empty line, trims to its first sentence, and caps\n * the length so AutoPhase headers stay readable. The full prompt is preserved\n * separately as the graph description.\n */\nfunction deriveTitle(goal: string): string {\n const firstLine = goal\n .split('\\n')\n .map((l) => l.trim())\n .find(Boolean);\n if (!firstLine) return 'AutoPhase';\n const sentence = firstLine.split(/(?<=[.!?])\\s/)[0] ?? firstLine;\n const trimmed = sentence.length <= 64 ? sentence : `${sentence.slice(0, 63).trimEnd()}…`;\n return trimmed || 'AutoPhase';\n}\n\nfunction isGitRepo(cwd: string): boolean {\n try {\n const r = spawnSync('git', ['rev-parse', '--is-inside-work-tree'], { cwd, encoding: 'utf8', windowsHide: true });\n return r.status === 0 && r.stdout.trim() === 'true';\n } catch {\n return false;\n }\n}\n\n/**\n * List the commits on `branch` since `baseSha` (oldest → newest, the order they\n * landed). Used by `autophase.revert` to feed WorktreeManager.revertCommits,\n * which reverses them. Returns [] on any git error.\n */\nfunction commitsSince(cwd: string, baseSha: string, branch: string): string[] {\n try {\n const r = spawnSync('git', ['log', '--reverse', '--format=%H', `${baseSha}..${branch}`], {\n cwd,\n encoding: 'utf8',\n windowsHide: true,\n });\n if (r.status !== 0) return [];\n return r.stdout.split('\\n').map((s) => s.trim()).filter(Boolean);\n } catch {\n return [];\n }\n}\n\ninterface WSClient {\n ws: WebSocket;\n id: string;\n}\n\ninterface AutoPhaseWSMessage {\n type: string;\n payload?: Record<string, unknown>;\n}\n\n/**\n * AutoPhaseWebSocketHandler — WebSocket-based AutoPhase control.\n *\n * Message types:\n * autophase.start → { title, phases?, autonomous? }\n * autophase.pause → {}\n * autophase.resume → {}\n * autophase.stop → {}\n * autophase.status → {}\n * autophase.selectPhase → { phaseId }\n * autophase.taskStatus → { taskId, status }\n */\nexport class AutoPhaseWebSocketHandler {\n private orchestrator: PhaseOrchestrator | null = null;\n private graph: PhaseGraph | null = null;\n private store: PhaseStore;\n private clients = new Set<WSClient>();\n private broadcastInterval: ReturnType<typeof setInterval> | null = null;\n /** Aborts in-flight task agents AND the planning turn when the run is stopped. */\n private abort: AbortController | null = null;\n /** Set the instant a stop/clear/revert is requested, so a planning turn that\n * resolves afterwards never launches the orchestrator (the abort alone can't\n * cover the window between the LLM call resolving and the orchestrator start). */\n private stopping = false;\n /** Optional per-phase git-worktree isolation (lazily created at start). */\n private worktrees: WorktreeManager | null = null;\n /** Base branch + tip SHA captured at run start so a revert can git-revert the\n * run's squash commits (history-preserving) instead of a destructive reset. */\n private runBase: { branch: string; sha: string } | null = null;\n /** Per-run worker identities so the board can show \"who is on what\". */\n private usedNicknames = new Set<string>();\n\n constructor(\n private agent: Agent,\n private context: Context,\n private logger: Logger,\n storeDir: string,\n private events?: EventBus | undefined,\n private projectRoot?: string | undefined,\n ) {\n this.store = new PhaseStore({ baseDir: storeDir });\n }\n\n addClient(ws: WebSocket): void {\n const client: WSClient = { ws, id: crypto.randomUUID() };\n this.clients.add(client);\n\n ws.on('close', () => this.clients.delete(client));\n ws.on('error', () => this.clients.delete(client));\n\n // Send current state\n this.sendState(client);\n }\n\n async handleMessage(msg: AutoPhaseWSMessage): Promise<void> {\n switch (msg.type) {\n case 'autophase.start':\n await this.handleStart(msg.payload);\n break;\n case 'autophase.pause':\n this.orchestrator?.pause();\n this.broadcast({ type: 'autophase.paused', payload: {} });\n break;\n case 'autophase.resume':\n this.orchestrator?.resume();\n this.broadcast({ type: 'autophase.resumed', payload: {} });\n break;\n case 'autophase.stop':\n await this.handleStop();\n break;\n case 'autophase.clear':\n await this.handleClear();\n break;\n case 'autophase.revert':\n await this.handleRevert();\n break;\n case 'autophase.status':\n this.broadcastState();\n break;\n case 'autophase.selectPhase': {\n const phaseId = msg.payload?.phaseId as string;\n if (phaseId && this.graph) {\n this.broadcastState(phaseId);\n }\n break;\n }\n case 'autophase.taskStatus': {\n const { taskId, status } = msg.payload as { taskId: string; status: string };\n await this.handleTaskStatusChange(taskId, status);\n break;\n }\n case 'autophase.moveTask': {\n const { taskId, toPhaseId } = msg.payload as { taskId: string; toPhaseId: string };\n if (this.orchestrator?.moveTask(taskId, toPhaseId)) this.afterBoardMutation();\n break;\n }\n case 'autophase.assignTask': {\n const { taskId, agentId, agentName } = msg.payload as {\n taskId: string;\n agentId?: string;\n agentName?: string;\n };\n if (this.orchestrator?.setTaskAssignee(taskId, agentId, agentName)) this.afterBoardMutation();\n break;\n }\n case 'autophase.addTask': {\n const { phaseId, title, description, type, priority } = msg.payload as {\n phaseId: string;\n title: string;\n description?: string;\n type?: import('@wrongstack/core').TaskNode['type'];\n priority?: import('@wrongstack/core').TaskNode['priority'];\n };\n if (title?.trim() && this.orchestrator?.addTask(phaseId, { title: title.trim(), description, type, priority })) {\n this.afterBoardMutation();\n }\n break;\n }\n case 'autophase.retryTask':\n case 'autophase.runTask': {\n const { taskId } = msg.payload as { taskId: string };\n if (this.orchestrator?.requeueTask(taskId)) this.afterBoardMutation();\n break;\n }\n case 'autophase.toggleAutonomous': {\n const autonomous = (msg.payload?.autonomous as boolean) ?? !this.graph?.autonomous;\n if (this.graph) {\n this.graph.autonomous = autonomous;\n await this.store.save(this.graph);\n this.broadcast({ type: 'autophase.state', payload: this.buildState() });\n }\n break;\n }\n case 'autophase.save': {\n if (this.graph) {\n await this.store.save(this.graph);\n this.broadcast({ type: 'autophase.saved', payload: { graphId: this.graph.id } });\n }\n break;\n }\n case 'autophase.list': {\n const graphs = await this.store.list();\n this.broadcast({ type: 'autophase.list', payload: { graphs } });\n break;\n }\n case 'autophase.load': {\n const graphId = msg.payload?.graphId as string | undefined;\n if (graphId) {\n const graph = await this.store.load(graphId);\n if (graph) {\n this.graph = graph;\n this.broadcast({ type: 'autophase.state', payload: this.buildState() });\n } else {\n this.broadcast({ type: 'autophase.error', payload: { message: `Graph not found: ${graphId}` } });\n }\n }\n break;\n }\n }\n }\n\n private async handleStart(payload?: Record<string, unknown>): Promise<void> {\n // The caller sends the operator's full prompt as the goal. We keep it intact\n // as the graph `description` and derive a short, human-readable `title` for\n // headers / the board switcher — pasting the whole prompt as the title made\n // the AutoPhase header unreadable.\n const goal = (payload?.goal as string) || (payload?.title as string) || 'Untitled Project';\n const title = deriveTitle(goal);\n const autonomous = (payload?.autonomous as boolean) ?? true;\n\n // Fresh abort for THIS run, created BEFORE planning so a stop pressed during\n // the (long) planning turn actually cancels it. Previously the controller was\n // created only after planning, so a stop while \"starting\" was a no-op and the\n // run launched anyway.\n this.abort = new AbortController();\n this.stopping = false;\n\n // Phase plan resolution:\n // 1. explicit phases in the payload win (caller override);\n // 2. otherwise the LLM plans phases+todos for the goal;\n // 3. failing that, fall back to the generic default phases.\n const phases = Array.isArray(payload?.phases)\n ? (payload.phases as PhaseTemplate[])\n : await this.planPhases(goal, this.abort.signal);\n\n // Stop requested during planning → never launch the orchestrator. The abort\n // may not have interrupted the in-flight LLM call promptly, so the `stopping`\n // flag is the authoritative guard for the resolve-after-stop window.\n if (this.stopping || this.abort.signal.aborted) {\n this.broadcast({ type: 'autophase.stopped', payload: { title } });\n return;\n }\n\n this.logger.info(`[AutoPhase] Starting: ${title}`);\n\n // Build the graph up-front so we have a reference for live broadcasts and\n // persistence *before* the (long-running) build begins.\n const graph = await new PhaseGraphBuilder({ title, description: goal, phases, autonomous }).build();\n this.graph = graph;\n await this.store.save(graph);\n\n // Per-phase git-worktree isolation, when enabled and inside a git repo.\n // The shared agent/context means we can't run phases in parallel here\n // (we swap a single context.cwd per task), so phases stay sequential —\n // but each phase still commits + squash-merges back through its own\n // worktree, and the lifecycle events drive the live swim-lane/DAG view.\n // Per-run worktree-isolation override from the UI wins; omitted → env default\n // (disable with WRONGSTACK_AUTOPHASE_WORKTREES=0). false → run on the current branch.\n const useWorktrees =\n (payload?.worktrees as boolean | undefined) ??\n process.env['WRONGSTACK_AUTOPHASE_WORKTREES'] !== '0';\n if (\n !this.worktrees &&\n this.events &&\n this.projectRoot &&\n useWorktrees &&\n isGitRepo(this.projectRoot)\n ) {\n this.worktrees = new WorktreeManager({ projectRoot: this.projectRoot, events: this.events });\n }\n // Capture the pre-run base tip so `autophase.revert` can git-revert exactly\n // the commits this run lands on the base branch.\n if (this.worktrees) {\n this.runBase = await this.worktrees.currentBase();\n }\n\n // NOTE: this interactive-board orchestrator deliberately omits the CLI host's\n // `verifyPhase`/`repairPhase`/`resolveConflict` hooks. The WebUI run is\n // human-supervised (live kanban + manual task moves), so it trusts the task\n // agents + the operator rather than running an autonomous typecheck/lint gate\n // and repair/conflict-resolver subagents. Worktree isolation + squash-merge\n // still happen (above); an unresolved merge conflict simply parks the worktree\n // for review (mergeOne's default). The fully-autonomous gate lives in the CLI\n // host (`packages/cli/src/autophase-host.ts`). Keep these two in mind when\n // changing phase-completion semantics.\n this.orchestrator = new PhaseOrchestrator({\n graph,\n ctx: {\n executeTask: async (task, phaseId, env) => {\n this.logger.info(`[AutoPhase] [${phaseId}] Executing: ${task.title}`);\n const result = await this.executeTaskWithAgent(task, phaseId, env);\n this.logger.info(`[AutoPhase] [${phaseId}] Completed: ${task.title}`);\n return result;\n },\n onPhaseComplete: (phase) => {\n this.logger.info(`[AutoPhase] Phase completed: ${phase.name}`);\n void this.store.save(graph);\n this.broadcastState();\n },\n onPhaseFail: (phase, error) => {\n this.logger.error(`[AutoPhase] Phase failed: ${phase.name} — ${error.message}`);\n void this.store.save(graph);\n this.broadcastState();\n },\n },\n worktrees: this.worktrees ?? undefined,\n autonomous,\n // Must stay 1: phase tasks run on the single shared context whose cwd we\n // swap per phase, so parallel phases would race on context.cwd.\n maxConcurrentPhases: 1,\n // Sequential within a phase: each todo is a full-tool agent editing the\n // phase worktree, so running two at once risks concurrent writes.\n maxConcurrentTasks: 1,\n });\n\n // Start the live broadcast immediately, then run the orchestrator in the\n // background. Awaiting start() would block until the *entire* build\n // finishes — the periodic broadcast (below) reads the mutating graph, so\n // clients see live progress while it runs.\n this.startBroadcast();\n this.broadcastState();\n\n void this.orchestrator\n .start()\n .then(() => {\n this.orchestrator?.stop(); // clear the autonomous tick interval\n void this.store.save(graph);\n this.stopBroadcast();\n const failed = graph.failedPhaseIds.length > 0;\n this.broadcast(\n failed\n ? { type: 'autophase.failed', payload: { title } }\n : { type: 'autophase.completed', payload: { title } },\n );\n this.broadcastState();\n })\n .catch((err: unknown) => {\n this.logger.error(`[AutoPhase] Aborted: ${toErrorMessage(err)}`);\n this.stopBroadcast();\n this.broadcast({ type: 'autophase.failed', payload: { title, error: String(err) } });\n });\n }\n\n /**\n * Halt the run NOW — at any phase. Sets `stopping` (so a planning turn that\n * resolves afterwards bails), aborts in-flight agents, stops the orchestrator\n * tick, and ends the live broadcast. The board is kept for review; use\n * `autophase.clear` to reset or `autophase.revert` to undo the changes.\n */\n private async handleStop(): Promise<void> {\n this.stopping = true;\n this.abort?.abort();\n this.orchestrator?.stop();\n this.stopBroadcast();\n if (this.graph) await this.store.save(this.graph).catch(() => undefined);\n this.broadcast({ type: 'autophase.stopped', payload: { title: this.graph?.title } });\n }\n\n /**\n * Stop + wipe: tear down phase worktrees and reset to an empty board so the UI\n * returns to the start screen (\"new one\"). Does NOT touch already-merged commits\n * on the base branch — that is `autophase.revert`.\n */\n private async handleClear(): Promise<void> {\n await this.handleStop();\n if (this.worktrees) await this.worktrees.cleanupAllManaged().catch(() => undefined);\n this.orchestrator = null;\n this.graph = null;\n this.runBase = null;\n this.usedNicknames.clear();\n this.broadcast({ type: 'autophase.cleared', payload: {} });\n // Empty state → board/wizard falls back to the goal-entry screen.\n this.broadcast({ type: 'autophase.state', payload: this.buildState() });\n }\n\n /**\n * Stop + undo: remove phase worktrees, then history-preservingly `git revert`\n * every commit this run landed on the base branch (captured `runBase`..HEAD),\n * then reset to an empty board. Refuses (reports a reason) on a dirty tree or a\n * conflicting revert rather than leaving the tree half-reverted.\n */\n private async handleRevert(): Promise<void> {\n await this.handleStop();\n if (!this.worktrees || !this.runBase || !this.projectRoot) {\n this.broadcast({\n type: 'autophase.reverted',\n payload: { ok: false, reverted: 0, reason: 'no git baseline was captured for this run' },\n });\n return;\n }\n await this.worktrees.cleanupAllManaged().catch(() => undefined);\n const shas = commitsSince(this.projectRoot, this.runBase.sha, this.runBase.branch);\n const res = await this.worktrees.revertCommits(this.runBase.branch, shas);\n this.broadcast({ type: 'autophase.reverted', payload: res });\n if (res.ok) {\n this.orchestrator = null;\n this.graph = null;\n this.runBase = null;\n this.broadcast({ type: 'autophase.cleared', payload: {} });\n this.broadcast({ type: 'autophase.state', payload: this.buildState() });\n }\n }\n\n /** Generic fallback phases when the LLM planner produces nothing usable. */\n private defaultPhases(): PhaseTemplate[] {\n return [\n { name: 'Discovery', description: 'Requirements gathering', priority: 'high', estimateHours: 2, parallelizable: false },\n { name: 'Design', description: 'Architecture and design', priority: 'critical', estimateHours: 4, parallelizable: false },\n { name: 'Implementation', description: 'Core development', priority: 'critical', estimateHours: 12, parallelizable: false },\n { name: 'Testing', description: 'Unit and integration tests', priority: 'high', estimateHours: 6, parallelizable: true },\n { name: 'Deployment', description: 'Deploy to production', priority: 'medium', estimateHours: 2, parallelizable: false },\n ];\n }\n\n /** Plan phases+todos for the goal via the LLM; fall back to defaults on failure.\n * The caller passes the run's abort signal so a stop during planning cancels\n * the LLM turn (the previous fresh, never-aborted controller made planning\n * uninterruptible). */\n private async planPhases(goal: string, signal?: AbortSignal): Promise<PhaseTemplate[]> {\n try {\n const planner = new AutoPhasePlanner({\n goal,\n runOnce: async (prompt) => {\n const result = (await this.agent.run(prompt, {\n signal: signal ?? new AbortController().signal,\n })) as {\n status: string;\n finalText?: string | undefined;\n };\n return result.status === 'done' ? (result.finalText ?? '') : '';\n },\n });\n const { phases, parseFailed } = await planner.plan();\n if (!parseFailed && phases.length > 0) {\n const todos = phases.reduce((n, p) => n + (p.taskTemplates?.length ?? 0), 0);\n this.logger.info(`[AutoPhase] Planned ${phases.length} phases / ${todos} todos for: ${goal}`);\n return phases;\n }\n this.logger.info(`[AutoPhase] Planner produced no phases; using defaults for: ${goal}`);\n } catch (err) {\n this.logger.error(`[AutoPhase] Planning failed, using defaults: ${toErrorMessage(err)}`);\n }\n return this.defaultPhases();\n }\n\n private async executeTaskWithAgent(\n task: import('@wrongstack/core').TaskNode,\n phaseId: string,\n env?: { cwd?: string | undefined; branch?: string | undefined },\n ): Promise<unknown> {\n // Give the task a human worker identity (reuse a manual assignment if one\n // exists) so the board shows who is running it; reflect it on the node and\n // push a live state update before the (long) run begins.\n if (!task.assignee) {\n const nick = assignNickname('executor', this.usedNicknames);\n this.usedNicknames.add(nick.key);\n task.assignee = nick.display.replace(/\\s*\\([^)]*\\)\\s*$/, '');\n task.updatedAt = Date.now();\n this.broadcastState();\n }\n\n // Execute task with agent\n const prompt = `Execute task: ${task.title}\\n\\nDescription: ${task.description}\\nPhase: ${phaseId}\\nPriority: ${task.priority}\\nType: ${task.type}`;\n const signal = this.abort?.signal ?? new AbortController().signal;\n // Redirect the shared context's cwd at the phase worktree for the duration\n // of this task. Safe because phases/tasks run strictly sequentially here;\n // tools read `ctx.cwd` live, so the agent operates inside the worktree.\n const prevCwd = this.context.cwd;\n if (env?.cwd) this.context.cwd = env.cwd;\n try {\n return await this.agent.run(prompt, { signal });\n } finally {\n this.context.cwd = prevCwd;\n }\n }\n\n /** Persist + broadcast after an interactive board mutation. */\n private afterBoardMutation(): void {\n if (this.graph) void this.store.save(this.graph);\n this.broadcastState();\n }\n\n private async handleTaskStatusChange(taskId: string, status: string): Promise<void> {\n if (!this.graph) return;\n\n for (const phase of this.graph.phases.values()) {\n const task = phase.taskGraph.nodes.get(taskId);\n if (task) {\n task.status = status as import('@wrongstack/core').TaskStatus;\n task.updatedAt = Date.now();\n this.broadcastState();\n return;\n }\n }\n }\n\n private startBroadcast(): void {\n if (this.broadcastInterval) return;\n this.broadcastInterval = setInterval(() => {\n const progress = this.orchestrator?.getProgress();\n if (progress) this.broadcast({ type: 'autophase.progress', payload: progress });\n this.broadcastState();\n }, 2000);\n }\n\n private stopBroadcast(): void {\n if (this.broadcastInterval) {\n clearInterval(this.broadcastInterval);\n this.broadcastInterval = null;\n }\n }\n\n private broadcastState(activePhaseId?: string): void {\n if (!this.graph) return;\n\n const state = this.buildState(activePhaseId);\n this.broadcast({ type: 'autophase.state', payload: state });\n }\n\n private buildState(activePhaseId?: string): Record<string, unknown> {\n if (!this.graph) {\n return { phases: [], tasks: [], overallPercent: 0, autonomous: true, title: '' };\n }\n\n const phases = Array.from(this.graph.phases.values());\n const currentActiveId = activePhaseId || phases.find((p) => p.status === 'running')?.id || phases[0]?.id || '';\n const activePhase = this.graph.phases.get(currentActiveId);\n\n const totalTasks = phases.reduce((sum, p) => sum + p.taskGraph.nodes.size, 0);\n const completedTasks = phases.reduce(\n (sum, p) => sum + Array.from(p.taskGraph.nodes.values()).filter((t) => t.status === 'completed').length,\n 0,\n );\n\n // Shared task → board-card mapper. Carries assignee/timestamps so the kanban\n // can show who is on each card and how long it has been running.\n const mapTask = (t: import('@wrongstack/core').TaskNode) => ({\n id: t.id,\n title: t.title,\n description: t.description,\n status: t.status,\n priority: t.priority,\n type: t.type,\n estimateHours: t.estimateHours,\n actualHours: t.actualHours,\n assignee: t.assignee,\n tags: t.tags || [],\n startedAt: t.startedAt,\n completedAt: t.completedAt,\n });\n\n const phaseItems = phases.map((p) => {\n const nodes = Array.from(p.taskGraph.nodes.values());\n const done = nodes.filter((t) => t.status === 'completed').length;\n return {\n id: p.id,\n name: p.name,\n description: p.description,\n status: p.status,\n priority: p.priority,\n estimateHours: p.estimateHours,\n actualDurationMs: p.actualDurationMs,\n startedAt: p.startedAt,\n completedAt: p.completedAt,\n progressPercent: nodes.length > 0 ? Math.round((done / nodes.length) * 100) : 0,\n taskCount: nodes.length,\n completedTasks: done,\n assignedAgents: p.assignedAgents,\n isActive: p.id === currentActiveId,\n // Every phase carries its full task list so the board can render each\n // phase as a column (not just the selected one).\n tasks: nodes.map(mapTask),\n };\n });\n\n // Back-compat: the chat-area TaskBoard still reads the flat active-phase list.\n const taskItems = activePhase ? Array.from(activePhase.taskGraph.nodes.values()).map(mapTask) : [];\n\n const completedPhases = phases.filter((p) => p.status === 'completed').length;\n const failedPhases = phases.filter((p) => p.status === 'failed').length;\n const failedTasks = phases.reduce(\n (sum, p) => sum + Array.from(p.taskGraph.nodes.values()).filter((t) => t.status === 'failed').length,\n 0,\n );\n\n // Surface the most recent failure so the board can show it (the store keeps a\n // `lastError` field the UI renders). Prefer the worktree integration error,\n // else a generic phase-failure note.\n const lastFailed = phases.filter((p) => p.status === 'failed').sort((a, b) => (b.updatedAt ?? 0) - (a.updatedAt ?? 0))[0];\n const lastError = lastFailed\n ? `${lastFailed.name}: ${(lastFailed.metadata?.integrationError as string | undefined) ?? 'phase failed'}`\n : null;\n\n return {\n title: this.graph.title,\n // Full operator prompt, shown verbatim in a dedicated goal block (the\n // title is only a short derived heading). Fall back to the title for\n // legacy boards saved before the title/goal split.\n goal: this.graph.description || this.graph.title,\n phases: phaseItems,\n tasks: taskItems,\n activePhaseId: currentActiveId,\n overallPercent: phases.length > 0 ? Math.round((completedPhases / phases.length) * 100) : 0,\n autonomous: this.graph.autonomous,\n totalTasks,\n completedTasks,\n // Structured progress + lastError consumed by the autophase store (were\n // defined client-side but never sent, so they stayed null on the board).\n progress: {\n totalPhases: phases.length,\n completed: completedPhases,\n failed: failedPhases,\n totalTasks,\n completedTasks,\n failedTasks,\n },\n lastError,\n };\n }\n\n private sendState(client: WSClient): void {\n if (!this.graph) return;\n const state = this.buildState();\n this.send(client, { type: 'autophase.state', payload: state });\n }\n\n private broadcast(msg: { type: string; payload: unknown }): void {\n const data = JSON.stringify(msg);\n for (const client of this.clients) {\n if (client.ws.readyState === 1) { // OPEN\n client.ws.send(data);\n }\n }\n }\n\n private send(client: WSClient, msg: { type: string; payload: unknown }): void {\n if (client.ws.readyState === 1) {\n client.ws.send(JSON.stringify(msg));\n }\n }\n}\n","import type { WebSocket } from 'ws';\nimport {\n computeTaskProgress,\n SpecStore,\n TaskGraphStore,\n type Specification,\n type TaskGraph,\n type TaskNode,\n} from '@wrongstack/core';\n\ninterface WSClient {\n ws: WebSocket;\n id: string;\n}\n\ninterface SpecsWSMessage {\n type: string;\n payload?: Record<string, unknown>;\n}\n\n/** A task as rendered on the FORGE-style dependency board. */\ninterface BoardTask {\n id: string;\n shortId: string;\n title: string;\n description: string;\n priority: TaskNode['priority'];\n type: TaskNode['type'];\n status: TaskNode['status'];\n /** Derived label for the legend: 'queued' = pending with all blockers done. */\n displayStatus: TaskNode['status'] | 'queued';\n deps: string[];\n}\n\n/**\n * SpecsWebSocketHandler — read-only-ish browser of persisted SDD specs and their\n * task graphs, rendered as a FORGE-style dependency board (topological phase\n * columns + dependency refs). Shared by both webui servers via specs-routes.\n *\n * Message types:\n * specs.list → all specs + progress\n * specs.get { specId } → one spec's dependency board\n * specs.taskStatus { graphId, taskId, status } → update + rebroadcast\n */\nexport class SpecsWebSocketHandler {\n private specStore: SpecStore;\n private graphStore: TaskGraphStore;\n private clients = new Set<WSClient>();\n\n constructor(specsDir: string, taskGraphsDir: string) {\n this.specStore = new SpecStore({ baseDir: specsDir });\n this.graphStore = new TaskGraphStore({ baseDir: taskGraphsDir });\n }\n\n addClient(ws: WebSocket): void {\n const client: WSClient = { ws, id: crypto.randomUUID() };\n this.clients.add(client);\n ws.on('close', () => this.clients.delete(client));\n ws.on('error', () => this.clients.delete(client));\n void this.sendList(client);\n }\n\n async handleMessage(msg: SpecsWSMessage): Promise<void> {\n switch (msg.type) {\n case 'specs.list':\n await this.broadcastList();\n break;\n case 'specs.get': {\n const specId = msg.payload?.specId as string | undefined;\n if (specId) await this.broadcastDetail(specId);\n break;\n }\n case 'specs.taskStatus': {\n const { graphId, taskId, status } = msg.payload as {\n graphId: string;\n taskId: string;\n status: TaskNode['status'];\n };\n await this.updateTaskStatus(graphId, taskId, status);\n break;\n }\n }\n }\n\n // ── List ──────────────────────────────────────────────────────────────────\n\n private async buildList(): Promise<unknown[]> {\n const [specs, graphs] = await Promise.all([this.specStore.list(), this.graphStore.list()]);\n return specs.map((s, i) => {\n const graph = graphs.find((g) => g.specId === s.id);\n return {\n id: s.id,\n // FORGE-style display id (spec-001…). The real UUID stays in `id`.\n displayId: `spec-${String(i + 1).padStart(3, '0')}`,\n title: s.title,\n status: s.status,\n graphId: graph?.id,\n total: graph?.nodeCount ?? 0,\n completed: graph?.completedCount ?? 0,\n };\n });\n }\n\n private async broadcastList(): Promise<void> {\n this.broadcast({ type: 'specs.list', payload: { specs: await this.buildList() } });\n }\n\n private async sendList(client: WSClient): Promise<void> {\n this.send(client, { type: 'specs.list', payload: { specs: await this.buildList() } });\n }\n\n // ── Detail (dependency board) ───────────────────────────────────────────────\n\n private async broadcastDetail(specId: string): Promise<void> {\n const spec = await this.specStore.load(specId);\n const graph = await this.findGraphForSpec(specId);\n if (!spec || !graph) {\n this.broadcast({ type: 'specs.detail', payload: { specId, columns: [], notFound: true } });\n return;\n }\n this.broadcast({ type: 'specs.detail', payload: this.buildDetail(spec, graph) });\n }\n\n private async findGraphForSpec(specId: string): Promise<TaskGraph | null> {\n const entry = (await this.graphStore.list()).find((g) => g.specId === specId);\n if (!entry) return null;\n return this.graphStore.load(entry.id);\n }\n\n private buildDetail(spec: Specification, graph: TaskGraph): Record<string, unknown> {\n const nodes = Array.from(graph.nodes.values()).sort((a, b) => a.createdAt - b.createdAt);\n // Stable short ids (t01, t02, …) in creation order, FORGE-style.\n const shortId = new Map<string, string>();\n nodes.forEach((n, i) => {\n shortId.set(n.id, `t${String(i + 1).padStart(2, '0')}`);\n });\n\n // Blockers per node (depends_on edges pointing at the node).\n const blockers = new Map<string, string[]>();\n for (const n of nodes) blockers.set(n.id, []);\n for (const e of graph.edges) {\n if (e.type === 'depends_on') blockers.get(e.to)?.push(e.from);\n }\n\n const statusOf = (id: string) => graph.nodes.get(id)?.status;\n const depthCache = new Map<string, number>();\n const depthOf = (id: string, seen = new Set<string>()): number => {\n const cached = depthCache.get(id);\n if (cached !== undefined) return cached;\n if (seen.has(id)) return 0; // cycle guard\n seen.add(id);\n const deps = blockers.get(id) ?? [];\n const d = deps.length === 0 ? 0 : 1 + Math.max(...deps.map((b) => depthOf(b, seen)));\n depthCache.set(id, d);\n return d;\n };\n\n const toBoardTask = (n: TaskNode): BoardTask => {\n const deps = blockers.get(n.id) ?? [];\n const allDepsDone = deps.every((b) => statusOf(b) === 'completed');\n const displayStatus = n.status === 'pending' && deps.length > 0 && allDepsDone ? 'queued' : n.status;\n return {\n id: n.id,\n shortId: shortId.get(n.id) ?? n.id.slice(0, 6),\n title: n.title,\n description: n.description,\n priority: n.priority,\n type: n.type,\n status: n.status,\n displayStatus,\n deps: deps.map((b) => shortId.get(b) ?? b.slice(0, 6)),\n };\n };\n\n // Group into topological columns: depth 0 → \"Start\", depth k → \"Phase k\".\n const byDepth = new Map<number, BoardTask[]>();\n for (const n of nodes) {\n const d = depthOf(n.id);\n if (!byDepth.has(d)) byDepth.set(d, []);\n byDepth.get(d)?.push(toBoardTask(n));\n }\n const columns = [...byDepth.keys()]\n .sort((a, b) => a - b)\n .map((d) => ({ label: d === 0 ? 'Start' : `Phase ${d}`, tasks: byDepth.get(d) ?? [] }));\n\n const progress = computeTaskProgress(graph);\n return {\n specId: spec.id,\n graphId: graph.id,\n title: spec.title,\n overview: spec.overview,\n status: spec.status,\n total: progress.total,\n completed: progress.completed,\n running: progress.inProgress,\n pending: progress.pending,\n columns,\n };\n }\n\n private async updateTaskStatus(\n graphId: string,\n taskId: string,\n status: TaskNode['status'],\n ): Promise<void> {\n const graph = await this.graphStore.load(graphId);\n const node = graph?.nodes.get(taskId);\n if (!graph || !node) return;\n node.status = status;\n node.updatedAt = Date.now();\n graph.updatedAt = Date.now();\n await this.graphStore.save(graph);\n this.broadcastDetail(graph.specId).catch(() => {});\n await this.broadcastList();\n }\n\n // ── Transport ───────────────────────────────────────────────────────────────\n\n private broadcast(msg: { type: string; payload: unknown }): void {\n const data = JSON.stringify(msg);\n for (const client of this.clients) {\n if (client.ws.readyState === 1) client.ws.send(data);\n }\n }\n\n private send(client: WSClient, msg: { type: string; payload: unknown }): void {\n if (client.ws.readyState === 1) client.ws.send(JSON.stringify(msg));\n }\n}\n","import type { WebSocket } from 'ws';\nimport type { EventBus, SddBoardSnapshot, SddLifecycleOp } from '@wrongstack/core';\nimport { applySddLifecycle, SddBoardStore } from '@wrongstack/core';\n\ninterface WSClient {\n ws: WebSocket;\n id: string;\n}\n\ninterface SddBoardWSMessage {\n type: string;\n payload?: Record<string, unknown>;\n}\n\n/**\n * Commands appended to `<runId>.control.jsonl` and drained by the live run\n * (start-sdd-run's in-process timer). Only meaningful while the run is active —\n * the drain timer is gone once it finishes.\n */\nconst CONTROL_TYPES = new Set([\n 'pause',\n 'resume',\n 'stop',\n 'retry',\n 'retry_all_failed',\n 'reassign',\n // Per-task model / fallback / verification assignment + stop/delete (drained by start-sdd-run).\n 'set_task_model',\n 'set_task_fallbacks',\n 'set_task_verification',\n 'cancel_task',\n 'delete_task',\n 'split_task',\n]);\n\n/**\n * Post-run lifecycle ops applied DIRECTLY from disk by this handler (not via the\n * control file — nothing drains it once the run settles). Each operates on git +\n * on-disk state and is gated on \"no active run\". `destroy` accepts a\n * `revertMerged` flag to also undo merged commits.\n */\nconst LIFECYCLE_TYPES = new Set<SddLifecycleOp>(['cleanup_worktrees', 'rollback', 'destroy']);\n\n/** Project paths the handler needs to apply lifecycle ops directly. */\nexport interface SddBoardLifecycleDeps {\n projectRoot: string;\n paths: {\n projectSpecs: string;\n projectTaskGraphs: string;\n projectSddSession: string;\n projectSddBoards: string;\n };\n}\n\n/**\n * SddBoardWebSocketHandler — streams the live SDD multi-agent board to clients\n * and relays control commands back to the CLI-owned run.\n *\n * Two observe modes (one class, shared by both webui servers):\n * • in-process (CLI-hosted): subscribe the shared EventBus `sdd.board.snapshot`\n * for instant updates;\n * • standalone (separate process): poll the on-disk snapshot store (the CLI\n * run persists JSON every change).\n *\n * Control is uniform + cross-process: every command is appended to the run's\n * `<runId>.control.jsonl`, which the CLI run drains and applies — so the run\n * stays the single driver and nothing races on shared state.\n */\nexport class SddBoardWebSocketHandler {\n private readonly store: SddBoardStore;\n private readonly clients = new Set<WSClient>();\n private readonly lifecycle?: SddBoardLifecycleDeps | undefined;\n private latest: SddBoardSnapshot | null = null;\n private poll: ReturnType<typeof setInterval> | null = null;\n private unsub: (() => void) | null = null;\n\n constructor(boardsDir: string, events?: EventBus, lifecycle?: SddBoardLifecycleDeps) {\n this.store = new SddBoardStore({ baseDir: boardsDir });\n this.lifecycle = lifecycle;\n\n if (events) {\n // Instant updates in the CLI-hosted server (shared bus).\n const handler = (e: { runId: string; snapshot: SddBoardSnapshot }) => {\n this.latest = e.snapshot;\n this.broadcast({ type: 'sdd.board.snapshot', payload: e.snapshot });\n };\n this.unsub = events.on('sdd.board.snapshot', handler as (p: unknown) => void);\n } else {\n // Standalone server (other process): poll the persisted snapshot.\n this.poll = setInterval(() => void this.pollLatest(), 1000);\n }\n }\n\n addClient(ws: WebSocket): void {\n const client: WSClient = { ws, id: crypto.randomUUID() };\n this.clients.add(client);\n ws.on('close', () => this.clients.delete(client));\n ws.on('error', () => this.clients.delete(client));\n // Send the current board immediately (from memory or disk).\n void this.sendCurrent(client);\n }\n\n async handleMessage(msg: SddBoardWSMessage): Promise<void> {\n if (msg.type === 'sdd.board.get') {\n await this.broadcastCurrent();\n return;\n }\n if (msg.type === 'sdd.board.list') {\n const boards = await this.store.list();\n this.broadcast({ type: 'sdd.board.list', payload: { boards } });\n return;\n }\n const action = msg.type.replace(/^sdd\\.board\\./, '');\n\n // Post-run lifecycle ops are applied here, directly from disk — the run's\n // control-file drain timer is gone once it finishes, so routing these\n // through control.jsonl (as the old Clean/Rollback buttons did) was a no-op.\n if (LIFECYCLE_TYPES.has(action as SddLifecycleOp)) {\n await this.applyLifecycle(action as SddLifecycleOp, msg.payload);\n return;\n }\n\n if (CONTROL_TYPES.has(action)) {\n const runId =\n (msg.payload?.runId as string | undefined) ??\n this.latest?.runId ??\n (await this.store.list())[0]?.runId;\n if (runId) {\n await this.store.appendControl(runId, {\n ts: Date.now(),\n type: action,\n payload: msg.payload,\n });\n }\n }\n }\n\n /**\n * Apply a cleanup/rollback/destroy from disk and broadcast a structured\n * `sdd.board.lifecycle_result`. Refuses (no-op) while a run is still active —\n * the user must stop it first; the UI gates the buttons on `!active` and the\n * Destroy flow auto-stops then waits before sending `destroy`.\n */\n private async applyLifecycle(op: SddLifecycleOp, payload?: Record<string, unknown>): Promise<void> {\n if (!this.lifecycle) {\n this.broadcast({\n type: 'sdd.board.lifecycle_result',\n payload: { op, ok: false, reason: 'Lifecycle operations are not available in this session.' },\n });\n return;\n }\n // Refuse while live — these force-remove worktrees / rewrite the base branch.\n if (this.latest && (this.latest.status === 'running' || this.latest.status === 'paused')) {\n this.broadcast({\n type: 'sdd.board.lifecycle_result',\n payload: { op, ok: false, reason: 'Stop the run first, then retry.' },\n });\n return;\n }\n\n const runId = (payload?.runId as string | undefined) ?? this.latest?.runId;\n const result = await applySddLifecycle(op, {\n projectRoot: this.lifecycle.projectRoot,\n paths: this.lifecycle.paths,\n runId,\n revertMerged: payload?.revertMerged === true,\n });\n\n this.broadcast({ type: 'sdd.board.lifecycle_result', payload: result });\n\n // A destroy wipes the board; clear the in-memory snapshot and push an empty\n // board so every client returns to the \"No active SDD run\" state.\n if (op === 'destroy' && result.ok) {\n this.latest = null;\n this.broadcast({ type: 'sdd.board.snapshot', payload: null });\n }\n }\n\n dispose(): void {\n if (this.poll) clearInterval(this.poll);\n this.unsub?.();\n this.poll = null;\n this.unsub = null;\n }\n\n // ── internal ────────────────────────────────────────────────────────────\n\n private async pollLatest(): Promise<void> {\n const entry = (await this.store.list())[0];\n if (!entry) return;\n if (this.latest && this.latest.updatedAt >= entry.updatedAt && this.latest.runId === entry.runId) {\n return; // nothing newer\n }\n const snap = await this.store.load(entry.runId);\n if (snap) {\n this.latest = snap;\n this.broadcast({ type: 'sdd.board.snapshot', payload: snap });\n }\n }\n\n private async sendCurrent(client: WSClient): Promise<void> {\n const snap = this.latest ?? (await this.loadLatestFromDisk());\n if (snap) this.send(client, { type: 'sdd.board.snapshot', payload: snap });\n }\n\n private async broadcastCurrent(): Promise<void> {\n const snap = this.latest ?? (await this.loadLatestFromDisk());\n if (snap) this.broadcast({ type: 'sdd.board.snapshot', payload: snap });\n }\n\n private async loadLatestFromDisk(): Promise<SddBoardSnapshot | null> {\n const entry = (await this.store.list())[0];\n return entry ? this.store.load(entry.runId) : null;\n }\n\n private broadcast(msg: { type: string; payload: unknown }): void {\n const data = JSON.stringify(msg);\n for (const client of this.clients) {\n if (client.ws.readyState === 1) client.ws.send(data);\n }\n }\n\n private send(client: WSClient, msg: { type: string; payload: unknown }): void {\n if (client.ws.readyState === 1) client.ws.send(JSON.stringify(msg));\n }\n}\n","import type { WebSocket } from 'ws';\nimport type { SddInterviewDriver, SddInterviewSnapshot } from '@wrongstack/core';\n\ninterface WSClient {\n ws: WebSocket;\n id: string;\n}\n\ninterface WizardMessage {\n type: string;\n payload?: Record<string, unknown>;\n}\n\n/** Short, single-line heading derived from a (possibly long) goal prompt. */\nfunction deriveTitle(goal: string): string {\n const firstLine = goal\n .split('\\n')\n .map((l) => l.trim())\n .find(Boolean);\n if (!firstLine) return 'New SDD Project';\n const sentence = firstLine.split(/(?<=[.!?])\\s/)[0] ?? firstLine;\n return sentence.length <= 64 ? sentence : `${sentence.slice(0, 63).trimEnd()}…`;\n}\n\n/**\n * Dependencies each webui server supplies. The handler is deliberately\n * agent-agnostic: every surface decides how to build a driver, how to run an\n * interview turn (on an isolated agent, off the main chat bus), and how to\n * start the real multi-agent run (CLI's director-backed factory vs the runtime\n * light factory). This keeps the wizard protocol identical across both servers.\n */\nexport interface SddWizardDeps {\n /** Build a fresh interview driver (disk spec/graph stores + session path). */\n makeDriver: () => SddInterviewDriver;\n /**\n * Run one interview turn: feed the AI prompt to an isolated agent and return\n * its final text. MUST NOT run on the main chat agent's bus — the wizard owns\n * this conversation, separate from the user's chat.\n */\n runInterviewTurn: (prompt: string) => Promise<string>;\n /**\n * Start the real multi-agent SDD run for the driver's task graph. Returns the\n * runId; the live board flows through the existing board handler.\n */\n startRun: (\n driver: SddInterviewDriver,\n opts: {\n parallelSlots?: number | undefined;\n defaultModel?: string | undefined;\n defaultProvider?: string | undefined;\n fallbackModels?: string[] | undefined;\n /** Per-run worktree-isolation override; undefined → env default. */\n worktrees?: boolean | undefined;\n },\n ) => Promise<{ runId: string }>;\n}\n\n/**\n * SddWizardWebSocketHandler — drives the interactive \"New SDD Project\" wizard\n * (goal → Q&A → spec → task graph → start run) over WebSocket. Shared by both\n * webui servers; server-specific construction (agent, factory) is injected via\n * {@link SddWizardDeps}.\n */\nexport class SddWizardWebSocketHandler {\n private readonly clients = new Set<WSClient>();\n private driver: SddInterviewDriver | null = null;\n /** The agent's most recent question — paired with the next user answer. */\n private lastAgentText = '';\n /** Guards against overlapping interview turns (one in flight at a time). */\n private busy = false;\n\n constructor(private readonly deps: SddWizardDeps) {}\n\n addClient(ws: WebSocket): void {\n const client: WSClient = { ws, id: crypto.randomUUID() };\n this.clients.add(client);\n ws.on('close', () => this.clients.delete(client));\n ws.on('error', () => this.clients.delete(client));\n // Send the current interview state (if any) so a reconnecting client catches up.\n if (this.driver) this.send(client, this.snapshotMsg());\n }\n\n async handleMessage(msg: WizardMessage): Promise<void> {\n try {\n switch (msg.type) {\n case 'sdd.spec.start':\n await this.onStart(String(msg.payload?.goal ?? '').trim());\n break;\n case 'sdd.spec.message':\n await this.onMessage(String(msg.payload?.text ?? ''));\n break;\n case 'sdd.spec.approve':\n await this.onApprove();\n break;\n case 'sdd.spec.get':\n if (this.driver) this.broadcast(this.snapshotMsg());\n break;\n case 'sdd.run.start':\n await this.onRunStart({\n parallelSlots: msg.payload?.parallelSlots as number | undefined,\n defaultModel: msg.payload?.model as string | undefined,\n defaultProvider: msg.payload?.provider as string | undefined,\n fallbackModels: Array.isArray(msg.payload?.fallbackModels)\n ? (msg.payload?.fallbackModels as string[])\n : undefined,\n worktrees: typeof msg.payload?.worktrees === 'boolean' ? msg.payload.worktrees : undefined,\n });\n break;\n }\n } catch (err) {\n this.busy = false;\n this.broadcast({\n type: 'sdd.spec.error',\n payload: { message: err instanceof Error ? err.message : String(err) },\n });\n }\n }\n\n // ── message handlers ──────────────────────────────────────────────────────\n\n private async onStart(goal: string): Promise<void> {\n if (!goal) {\n this.broadcast({ type: 'sdd.spec.error', payload: { message: 'A goal is required.' } });\n return;\n }\n if (this.busy) return;\n this.driver = this.deps.makeDriver();\n // Keep the operator's full prompt as the interview's intent/goal, but give\n // the session a short readable title — pasting the whole prompt as the title\n // made the wizard header unreadable.\n const prompt = this.driver.start(deriveTitle(goal), goal);\n await this.runTurn(prompt);\n }\n\n private async onMessage(text: string): Promise<void> {\n if (!this.driver || this.busy) return;\n // In the questioning phase, the user's message answers the agent's last\n // question. In review phases a free-form message is fed back as context.\n if (this.driver.phase() === 'questioning' && this.lastAgentText) {\n this.driver.submitAnswer(this.lastAgentText, text);\n } else {\n this.driver.submitAnswer(this.lastAgentText || '(feedback)', text);\n }\n await this.runTurn(this.driver.currentPrompt());\n }\n\n private async onApprove(): Promise<void> {\n if (!this.driver || this.busy) return;\n const { phase, prompt } = await this.driver.approve();\n // Executing phase needs no further AI turn — the graph is ready to run.\n if (phase === 'executing') {\n this.broadcast(this.snapshotMsg());\n return;\n }\n await this.runTurn(prompt);\n }\n\n private async onRunStart(opts: {\n parallelSlots?: number | undefined;\n defaultModel?: string | undefined;\n defaultProvider?: string | undefined;\n fallbackModels?: string[] | undefined;\n worktrees?: boolean | undefined;\n }): Promise<void> {\n if (!this.driver) {\n this.broadcast({ type: 'sdd.spec.error', payload: { message: 'No active spec session.' } });\n return;\n }\n // Guarantee a graph exists (deterministic fallback if the agent never\n // emitted a task array).\n const graph = await this.driver.ensureTaskGraph();\n if (!graph) {\n this.broadcast({\n type: 'sdd.spec.error',\n payload: { message: 'No spec yet — finish the interview before starting a run.' },\n });\n return;\n }\n const { runId } = await this.deps.startRun(this.driver, opts);\n this.broadcast({ type: 'sdd.run.started', payload: { runId } });\n }\n\n // ── internals ───────────────────────────────────────────────────────────\n\n /** Run one interview turn against the isolated agent, then ingest + broadcast. */\n private async runTurn(prompt: string): Promise<void> {\n this.busy = true;\n this.broadcast(this.snapshotMsg());\n try {\n const text = await this.deps.runInterviewTurn(prompt);\n this.lastAgentText = text;\n if (this.driver) await this.driver.ingestAgentOutput(text);\n this.broadcast({ type: 'sdd.spec.agent_text', payload: { text } });\n } finally {\n this.busy = false;\n this.broadcast(this.snapshotMsg());\n }\n }\n\n private snapshotMsg(): { type: string; payload: SddInterviewSnapshot & { busy: boolean } } {\n const snap = this.driver?.snapshot();\n return {\n type: 'sdd.spec.snapshot',\n payload: { ...(snap as SddInterviewSnapshot), busy: this.busy },\n };\n }\n\n private broadcast(msg: { type: string; payload: unknown }): void {\n const data = JSON.stringify(msg);\n for (const client of this.clients) {\n if (client.ws.readyState === 1) client.ws.send(data);\n }\n }\n\n private send(client: WSClient, msg: { type: string; payload: unknown }): void {\n if (client.ws.readyState === 1) client.ws.send(JSON.stringify(msg));\n }\n}\n","import * as path from 'node:path';\nimport { spawnSync } from 'node:child_process';\nimport {\n type Agent,\n type AgentFactory,\n type BrainArbiter,\n cleanupStaleSddWorktrees,\n type EventBus,\n makeCommandVerifier,\n makeLlmSubtaskGenerator,\n SddBoardStore,\n SddInterviewDriver,\n SddRunRegistry,\n SddSupervisor,\n SpecStore,\n startSddRun,\n TaskGraphStore,\n WorktreeManager,\n} from '@wrongstack/core';\nimport type { SddWizardDeps } from './sdd-wizard-ws-handler.js';\n\nexport interface SddWizardWiringOptions {\n /** Leader agent — seeds the run's default factory + project context. */\n agent: Agent;\n /** Shared EventBus — the board projector emits sdd.board.snapshot on it. */\n events: EventBus;\n projectRoot: string;\n /** Per-task agent factory: CLI's director-backed one, or the runtime light one. */\n subagentFactory: AgentFactory;\n /**\n * Decision authority for the failure supervisor (the server's bound\n * TOKENS.BrainArbiter). Omit to run without a supervisor (plain terminal-fail,\n * matching a bare run) — but parity with the CLI wants it wired.\n */\n brain?: BrainArbiter | undefined;\n /** Persisted-store directories (from resolveWstackPaths). */\n paths: {\n projectSpecs: string;\n projectTaskGraphs: string;\n projectSddBoards: string;\n projectDir: string;\n };\n}\n\n/**\n * Build the {@link SddWizardDeps} shared by both webui servers from a single\n * per-task `subagentFactory`. The factory drives BOTH the interview agent (an\n * isolated turn off the main chat bus) and the real multi-agent run, so each\n * server only has to supply the right factory for its process.\n */\n/**\n * Prepended to every isolated interview/splitter turn. Keeps the spec interview\n * a pure planning conversation — no file writes, no shell — regardless of how\n * \"implement\"-flavoured the underlying phase prompt reads.\n */\nconst PLANNING_ONLY_GUARD =\n 'SYSTEM: You are running a PLANNING-ONLY specification interview. Do NOT write, ' +\n 'create, or edit any files, and do NOT run shell/terminal commands or use any ' +\n 'code-editing tools — they are disabled here and any attempt will fail and waste ' +\n 'the turn. Respond with TEXT ONLY: ask your question, or emit the requested spec / ' +\n 'plan / task JSON. All code is written later, automatically, once the plan is ' +\n 'approved and the multi-agent run starts.\\n\\n---\\n\\n';\n\nexport function buildSddWizardDeps(opts: SddWizardWiringOptions): SddWizardDeps {\n const registry = new SddRunRegistry();\n let isolatedSeq = 0;\n\n /**\n * Run one self-contained, read-only LLM turn on a fresh isolated agent (off the\n * main chat bus). Shared by the interview and the supervisor's subtask splitter:\n * both feed a self-embedding prompt, want no shared context, and must NOT edit\n * the repo (restricted to the read-only capability floor; the execute phase is\n * where writes happen). The factory's per-turn cleanup is invoked here because\n * we drive it directly, not via makeAgentSubagentRunner.\n *\n * The interview is PLANNING-ONLY: it must never write code. The read-only\n * capability floor already denies fs.write/shell, but a capable model will\n * still *attempt* a write/bash call when the implementation-planning prompt\n * mentions \"implement\" — the call then fails and derails the turn. So we belt-\n * and-suspenders it: (1) disable the mutating tools by name, and (2) prepend an\n * explicit text guard so the agent never even tries. Code is written later, by\n * the real run, after the plan is approved.\n */\n const runIsolatedTurn = async (prompt: string, name: string): Promise<string> => {\n const result = await opts.subagentFactory({\n id: `sdd-${name.toLowerCase().replace(/\\s+/g, '-')}-${isolatedSeq++}`,\n role: 'executor',\n name,\n disabledTools: ['delegate', 'write', 'edit', 'patch', 'bash', 'exec'],\n allowedCapabilities: ['fs.read', 'net.outbound'],\n });\n try {\n const res = await result.agent.run([{ type: 'text', text: PLANNING_ONLY_GUARD + prompt }]);\n return res.finalText ?? '';\n } finally {\n await result.dispose?.();\n }\n };\n\n return {\n makeDriver: () =>\n new SddInterviewDriver({\n specStore: new SpecStore({ baseDir: opts.paths.projectSpecs }),\n graphStore: new TaskGraphStore({ baseDir: opts.paths.projectTaskGraphs }),\n sessionPath: path.join(opts.paths.projectDir, 'sdd-wizard-session.json'),\n }),\n\n runInterviewTurn: (prompt: string): Promise<string> => runIsolatedTurn(prompt, 'Spec Architect'),\n\n startRun: async (\n driver,\n { parallelSlots, defaultModel, defaultProvider, fallbackModels, worktrees: useWorktrees },\n ) => {\n const graph = driver.getGraph();\n const tracker = driver.getTracker();\n if (!graph || !tracker) {\n throw new Error('No task graph to run — finish the interview first.');\n }\n\n // Per-task git-worktree isolation. The per-run UI toggle wins; when it is\n // omitted we fall back to the env default (disable with\n // WRONGSTACK_SDD_WORKTREES=0). Mirrors the CLI /sdd execute path.\n const worktreesEnabled = useWorktrees ?? process.env['WRONGSTACK_SDD_WORKTREES'] !== '0';\n let worktrees: WorktreeManager | undefined;\n if (worktreesEnabled) {\n const inGit =\n spawnSync('git', ['rev-parse', '--is-inside-work-tree'], {\n cwd: opts.projectRoot,\n encoding: 'utf8',\n windowsHide: true,\n }).stdout?.trim() === 'true';\n if (inGit) {\n // Clean slate: sweep any orphaned worktrees/branches a prior crashed or\n // abandoned run left behind BEFORE this run allocates. Liveness-guarded\n // so it never touches a run that is still live in another process.\n await cleanupStaleSddWorktrees({\n projectRoot: opts.projectRoot,\n boardsDir: opts.paths.projectSddBoards,\n }).catch(() => undefined);\n worktrees = new WorktreeManager({ projectRoot: opts.projectRoot, events: opts.events });\n }\n }\n\n const boardStore = new SddBoardStore({ baseDir: opts.paths.projectSddBoards });\n\n // Parity with the CLI `/sdd parallel` path: gate completion on a per-task\n // verificationCommand and let the Brain rescue a retry-exhausted task\n // instead of dead-ending. Both are shared with cli-main.ts.\n const verifyTask = makeCommandVerifier();\n const superviseFailure = opts.brain\n ? new SddSupervisor({\n brain: opts.brain,\n // The run-level fallback chain (chosen in the wizard) doubles as the\n // supervisor's reassign options — a `reassign` verdict rotates the\n // worker model on retry. Empty/undefined → reassign option dropped.\n reassignModels: fallbackModels,\n // LLM auto-split: decompose a retry-exhausted task into smaller\n // sub-tasks on an isolated read-only turn. Heavily validated +\n // bounded; an empty result degrades the split into a retry.\n generateSubtasks: makeLlmSubtaskGenerator({\n run: (prompt) => runIsolatedTurn(prompt, 'Task Splitter'),\n }),\n // The standalone brain is a tiered policy→LLM arbiter with NO\n // human-escalation wrapper (see index.ts), so it never blocks on a\n // human prompt — an unresolved verdict degrades to a bounded retry.\n // Safe to let the LLM layer actually pick reassign/split.\n requestLlmVerdict: true,\n }).superviseFailure\n : undefined;\n\n const handle = startSddRun({\n tracker,\n graph,\n agent: opts.agent,\n projectRoot: opts.projectRoot,\n events: opts.events,\n subagentFactory: opts.subagentFactory,\n worktrees,\n boardStore,\n registry,\n parallelSlots,\n defaultModel,\n defaultProvider,\n fallbackModels,\n verifyTask,\n superviseFailure,\n });\n // The board surfaces progress (events + disk); we don't block the wizard\n // on completion. Swallow rejections so a failed run can't crash the server.\n void handle.completion.catch(() => {});\n return { runId: handle.runId };\n },\n };\n}\n","import type { WebSocket } from 'ws';\nimport type { WSClientMessage } from './types.js';\n\nexport interface SddWizardRouteHandlers {\n handleMessage: (msg: { type: string; payload?: Record<string, unknown> }) => Promise<void>;\n}\n\n/**\n * Forward the SDD wizard messages (`sdd.spec.*` and `sdd.run.start`) to the\n * SddWizardWebSocketHandler. Note `sdd.board.*` is handled separately by the\n * board route — the wizard owns spec-building + run kickoff, the board owns\n * live observation/control.\n */\nexport async function handleSddWizardRoute(\n _ws: WebSocket,\n msg: WSClientMessage,\n handlers: SddWizardRouteHandlers,\n): Promise<boolean> {\n if (!(msg.type.startsWith('sdd.spec.') || msg.type.startsWith('sdd.run.'))) return false;\n await handlers.handleMessage(msg as { type: string; payload?: Record<string, unknown> });\n return true;\n}\n","import { randomUUID } from 'node:crypto';\nimport type { WebSocket } from 'ws';\nimport type { CollaborationBus, ConsumedInjectionInfo, EventBus, Logger } from '@wrongstack/core';\nimport type { AnnotationsStore, SessionReader } from '@wrongstack/core/storage';\nimport { toErrorMessage } from '@wrongstack/core/utils';\nimport type {\n CollabRole,\n WSCollabState,\n WSServerMessage,\n} from '../types.js';\n\n/** How many historical events to replay to a late-joining observer. */\nconst REPLAY_LIMIT = 50;\n\n/** How long the middleware waits before auto-resuming (mirrors the middleware default). */\nconst PAUSE_TIMEOUT_MS = 60_000;\n\n/**\n * CollaborationWebSocketHandler — passive read-only session observer (Phase 1\n * of idea #13 from IDEAS.md). Mirrors `WorktreeWebSocketHandler` and\n * `AutoPhaseWebSocketHandler`.\n *\n * Capabilities in this phase:\n * - A second human (or any client) joins an active agent run as an\n * `observer` and receives a live mirror of the kernel's iteration /\n * tool / subagent events.\n * - The observer declares a `sessionId` on join (used for state scoping\n * and future replay-on-join). Live event routing is session-agnostic\n * for now — see the limitation note below.\n * - The observer can leave at any time; cleanup runs on WS close/error.\n * - The observer CANNOT modify the agent's state, pause it, or inject\n * tool calls. Those capabilities land in Phase 2/3.\n *\n * Limitation (documented, acceptable for Phase 1):\n * The webui server multiplexes every active session onto a single\n * EventBus, and most event payloads (`tool.started`, `iteration.*`,\n * `subagent.*`) do NOT carry a `sessionId` field. The webui's primary\n * WS path works because it is the only consumer and assumes one\n * active session at a time. We mirror that assumption here. When a\n * future multi-session \"session router\" lands, this handler will be\n * upgraded to filter by sessionId.\n *\n * Protocol additions (see `packages/webui/src/types.ts`):\n * client → server: collab.join { sessionId, role: 'observer' }\n * collab.leave { sessionId }\n * server → client: collab.state (initial + 2s periodic)\n * collab.participant.joined\n * collab.participant.left\n * collab.event (live kernel event mirror)\n */\nexport class CollaborationWebSocketHandler {\n private readonly clients = new Set<WebSocket>();\n /** sessionId → participants currently watching it. */\n private readonly bySession = new Map<string, Set<Participant>>();\n private broadcastInterval: ReturnType<typeof setInterval> | null = null;\n private readonly offs: Array<() => void> = [];\n\n constructor(\n private readonly events: EventBus,\n private readonly logger: Logger,\n /**\n * Optional reader over the on-disk session log. When provided, late\n * joiners receive the last `REPLAY_LIMIT` events of the joined\n * session before live mirroring begins. Without a reader, joining\n * is still allowed — the observer simply starts from \"now\" with no\n * historical context.\n */\n private readonly reader?: SessionReader | undefined,\n /**\n * Optional sidecar store for collaboration annotations. Required\n * for the `annotator` role — without it, `collab.annotate` messages\n * are rejected with an error.\n */\n private readonly annotations?: AnnotationsStore | undefined,\n /**\n * Optional kernel-level pause/resume bus. Required for the\n * `controller` role — without it, `collab.request_pause` is rejected\n * with an error. Wired to the agent's `toolCall` pipeline via\n * `collabPauseMiddleware` in the webui server boot.\n */\n private readonly bus?: CollaborationBus | undefined,\n ) {\n this.subscribe();\n // Phase 4 feedback loop: when the inject middleware applies a queued\n // injection, broadcast a `consumed` grant so observers see it landed.\n this.bus?.onInjectionConsumed((info) => this.broadcastInjectionConsumed(info));\n }\n\n // ── Public API (called by server/index.ts per WS connection) ───────────\n\n addClient(ws: WebSocket): void {\n this.clients.add(ws);\n this.ensureBroadcast();\n ws.on('close', () => this.handleDisconnect(ws));\n ws.on('error', () => this.handleDisconnect(ws));\n }\n\n dispose(): void {\n for (const off of this.offs) off();\n this.offs.length = 0;\n this.stopBroadcast();\n }\n\n // ── Inbound client messages ────────────────────────────────────────────\n\n /**\n * Dispatch a parsed client message. Returns true when the message was\n * recognized and handled; false when the caller should ignore / log.\n * Phase 1 only knows `collab.join` and `collab.leave`; unknown types\n * return false so the upstream router can decide.\n */\n handleMessage(\n ws: WebSocket,\n msg: { type: string; payload?: unknown | undefined },\n ): boolean {\n if (msg.type === 'collab.join') {\n const payload = msg.payload as { sessionId?: string | undefined; role?: CollabRole | undefined } | undefined;\n if (!payload?.sessionId) {\n this.send(ws, this.errorMessage('collab.join requires sessionId'));\n return true;\n }\n // The `role` field is accepted on the wire for forward-compat;\n // 'controller' (Phase 3) is not yet wired and is rejected here.\n this.join(ws, payload.sessionId, payload.role ?? 'observer');\n return true;\n }\n if (msg.type === 'collab.leave') {\n this.leave(ws);\n return true;\n }\n if (msg.type === 'collab.annotate') {\n void this.handleAnnotate(ws, msg.payload);\n return true;\n }\n if (msg.type === 'collab.resolve') {\n void this.handleResolve(ws, msg.payload);\n return true;\n }\n if (msg.type === 'collab.request_pause') {\n void this.handleRequestPause(ws, msg.payload);\n return true;\n }\n if (msg.type === 'collab.resume') {\n void this.handleResume(ws, msg.payload);\n return true;\n }\n if (msg.type === 'collab.grant_control') {\n void this.handleGrantControl(ws, msg.payload);\n return true;\n }\n if (msg.type === 'collab.inject_tool') {\n void this.handleInjectTool(ws, msg.payload);\n return true;\n }\n return false;\n }\n\n // ── Join / leave flow ──────────────────────────────────────────────────\n\n private join(ws: WebSocket, sessionId: string, role: CollabRole): void {\n if (role === 'controller' && !this.bus) {\n this.send(\n ws,\n this.errorMessage(\n `role 'controller' is not available: server has no CollaborationBus`,\n ),\n );\n return;\n }\n if (role === 'annotator' && !this.annotations) {\n this.send(\n ws,\n this.errorMessage(\n `role 'annotator' is not available: server has no annotations store`,\n ),\n );\n return;\n }\n const participant: Participant = {\n participantId: randomUUID(),\n ws,\n sessionId,\n role,\n joinedAt: new Date().toISOString(),\n };\n let bucket = this.bySession.get(sessionId);\n if (!bucket) {\n bucket = new Set();\n this.bySession.set(sessionId, bucket);\n }\n bucket.add(participant);\n\n // Per-participant hello: send the current state snapshot immediately\n // so the new observer knows who else is watching. Then broadcast the\n // join event AND a fresh state to every participant (including the\n // newcomer) so existing observers see the updated count without\n // waiting for the 2s timer.\n this.send(ws, this.stateMessage(sessionId));\n this.broadcast(sessionId, {\n type: 'collab.participant.joined',\n payload: {\n participantId: participant.participantId,\n sessionId,\n role,\n joinedAt: participant.joinedAt,\n },\n });\n this.broadcast(sessionId, this.stateMessage(sessionId));\n\n // Replay last N events to give the late joiner historical context.\n // Best-effort: failures are logged and silently ignored — the live\n // mirror continues regardless.\n if (this.reader) {\n this.replayHistory(ws, sessionId).catch((err) => {\n this.logger.debug?.(\n `collab: replay failed for ${sessionId}: ${\n toErrorMessage(err)\n }`,\n );\n });\n }\n this.logger.debug?.(\n `collab: participant ${participant.participantId} joined ${sessionId}`,\n );\n }\n\n private leave(ws: WebSocket): void {\n this.handleDisconnect(ws);\n }\n\n private handleDisconnect(ws: WebSocket): void {\n this.clients.delete(ws);\n // Remove from every session bucket the WS may have joined (a single\n // WS is in at most one bucket in Phase 1, but the loop is cheap and\n // future-proofs multi-session observers).\n //\n // Order matters:\n // 1. Send `participant.left` to the leaving ws so they get a\n // confirmation that their leave registered.\n // 2. Delete from bucket.\n // 3. Broadcast the fresh state to remaining observers so they\n // see the updated count without waiting for the 2s timer.\n for (const [sessionId, bucket] of this.bySession) {\n for (const p of bucket) {\n if (p.ws === ws) {\n const leftEvent = {\n type: 'collab.participant.left' as const,\n payload: { participantId: p.participantId, sessionId },\n };\n // Send directly to the leaving ws first so they get an\n // immediate confirmation, then broadcast to the rest of the\n // bucket (which is still inclusive of the leaving ws here —\n // the per-iteration below strips it out).\n this.send(ws, leftEvent);\n bucket.delete(p);\n if (bucket.size === 0) {\n this.bySession.delete(sessionId);\n } else {\n this.broadcast(sessionId, leftEvent);\n this.broadcast(sessionId, this.stateMessage(sessionId));\n }\n break;\n }\n }\n }\n if (this.bySession.size === 0) this.stopBroadcast();\n }\n\n // ── Annotation flow (Phase 2) ───────────────────────────────────────────\n\n /**\n * Look up the participant record for a given WS across all sessions.\n * Returns null when the WS hasn't joined (e.g. the client sent a\n * `collab.annotate` before `collab.join`).\n */\n private findParticipant(ws: WebSocket): Participant | null {\n for (const bucket of this.bySession.values()) {\n for (const p of bucket) {\n if (p.ws === ws) return p;\n }\n }\n return null;\n }\n\n private findParticipantById(sessionId: string, participantId: string): Participant | null {\n const bucket = this.bySession.get(sessionId);\n if (!bucket) return null;\n for (const p of bucket) {\n if (p.participantId === participantId) return p;\n }\n return null;\n }\n\n private async handleAnnotate(ws: WebSocket, raw: unknown): Promise<void> {\n if (!this.annotations) {\n this.send(ws, this.errorMessage('annotations store is not configured'));\n return;\n }\n const participant = this.findParticipant(ws);\n if (!participant) {\n this.send(ws, this.errorMessage('annotate requires an active join'));\n return;\n }\n if (participant.role !== 'annotator') {\n this.send(\n ws,\n this.errorMessage(\n `annotate requires the 'annotator' role (current: '${participant.role}')`,\n ),\n );\n return;\n }\n const payload = raw as\n | { sessionId?: string | undefined; atEventIndex?: number | undefined; text?: string | undefined }\n | undefined;\n if (\n !payload?.sessionId ||\n typeof payload.atEventIndex !== 'number' ||\n typeof payload.text !== 'string'\n ) {\n this.send(\n ws,\n this.errorMessage('annotate requires { sessionId, atEventIndex, text }'),\n );\n return;\n }\n if (payload.sessionId !== participant.sessionId) {\n this.send(\n ws,\n this.errorMessage(\n `annotate sessionId mismatch (joined: ${participant.sessionId})`,\n ),\n );\n return;\n }\n try {\n const annotation = await this.annotations.add({\n sessionId: payload.sessionId,\n atEventIndex: payload.atEventIndex,\n authorId: participant.participantId,\n text: payload.text,\n });\n this.broadcast(payload.sessionId, {\n type: 'collab.annotation.added',\n payload: {\n sessionId: payload.sessionId,\n annotation: {\n id: annotation.id,\n atEventIndex: annotation.atEventIndex,\n authorId: annotation.authorId,\n authorRole: annotation.authorRole,\n text: annotation.text,\n createdAt: annotation.createdAt,\n resolved: annotation.resolved,\n },\n },\n });\n } catch (err) {\n this.send(\n ws,\n this.errorMessage(\n `annotation rejected: ${\n toErrorMessage(err)\n }`,\n ),\n );\n }\n }\n\n private async handleResolve(ws: WebSocket, raw: unknown): Promise<void> {\n if (!this.annotations) {\n this.send(ws, this.errorMessage('annotations store is not configured'));\n return;\n }\n const participant = this.findParticipant(ws);\n if (!participant) {\n this.send(ws, this.errorMessage('resolve requires an active join'));\n return;\n }\n if (participant.role !== 'annotator') {\n this.send(\n ws,\n this.errorMessage(\n `resolve requires the 'annotator' role (current: '${participant.role}')`,\n ),\n );\n return;\n }\n const payload = raw as\n | { sessionId?: string | undefined; annotationId?: string | undefined }\n | undefined;\n if (!payload?.sessionId || !payload.annotationId) {\n this.send(\n ws,\n this.errorMessage('resolve requires { sessionId, annotationId }'),\n );\n return;\n }\n if (payload.sessionId !== participant.sessionId) {\n this.send(\n ws,\n this.errorMessage(\n `resolve sessionId mismatch (joined: ${participant.sessionId})`,\n ),\n );\n return;\n }\n try {\n const updated = await this.annotations.resolve({\n sessionId: payload.sessionId,\n annotationId: payload.annotationId,\n resolvedBy: participant.participantId,\n });\n if (!updated) {\n this.send(\n ws,\n this.errorMessage(`annotation not found: ${payload.annotationId}`),\n );\n return;\n }\n this.broadcast(payload.sessionId, {\n type: 'collab.annotation.resolved',\n payload: {\n sessionId: payload.sessionId,\n annotationId: updated.id,\n resolvedBy: updated.resolvedBy ?? participant.participantId,\n resolvedAt: updated.resolvedAt ?? new Date().toISOString(),\n },\n });\n } catch (err) {\n this.send(\n ws,\n this.errorMessage(\n `resolve failed: ${\n toErrorMessage(err)\n }`,\n ),\n );\n }\n }\n\n // ── Event subscription (live mirror) ───────────────────────────────────\n\n private subscribe(): void {\n // Same trick as WorktreeWebSocketHandler: bind a single typed-on helper\n // to a string-keyed signature so we can register many handlers.\n const on = this.events.on.bind(this.events) as never as (\n ev: string,\n fn: (p: unknown) => void,\n ) => () => void;\n\n // Mirror every event an observer would care about. Each is forwarded\n // to all joined participants as a generic `collab.event` envelope so\n // the client can render a flowing activity strip. Filtering /\n // denormalization happens on the client.\n const forwarded: Array<[string, string]> = [\n ['iteration.started', 'iteration.started'],\n ['iteration.completed', 'iteration.completed'],\n ['tool.started', 'tool.started'],\n ['tool.progress', 'tool.progress'],\n ['tool.executed', 'tool.executed'],\n ['tool.confirm_needed', 'tool.confirm_needed'],\n ['subagent.spawned', 'subagent.spawned'],\n ['subagent.task_started', 'subagent.task_started'],\n ['subagent.iteration_summary', 'subagent.iteration_summary'],\n ['subagent.task_completed', 'subagent.task_completed'],\n ['subagent.done', 'subagent.done'],\n ];\n for (const [kernelEvent, kind] of forwarded) {\n this.offs.push(\n on(kernelEvent, (raw) => {\n // Best-effort payload shape: we don't deeply validate, but we\n // make sure it's serializable. Observers must never receive\n // non-serializable objects (Functions, circular refs).\n let payload: unknown = raw;\n try {\n payload = JSON.parse(JSON.stringify(raw));\n } catch {\n // Skip unserializable payloads — better to drop than to crash\n // the broadcast loop.\n return;\n }\n this.broadcastEvent(kind, payload);\n }),\n );\n }\n }\n\n private broadcastEvent(kind: string, payload: unknown): void {\n if (this.bySession.size === 0) return; // nobody watching — no-op\n const msg: WSServerMessage = {\n type: 'collab.event',\n payload: { kind, payload, at: new Date().toISOString() },\n };\n const data = JSON.stringify(msg);\n for (const bucket of this.bySession.values()) {\n for (const p of bucket) {\n try {\n if (p.ws.readyState === 1) p.ws.send(data);\n } catch (err) {\n this.logger.debug?.(\n `collab broadcast failed: ${\n toErrorMessage(err)\n }`,\n );\n }\n }\n }\n }\n\n /**\n * Replay the last `REPLAY_LIMIT` events from the on-disk session log\n * to a single observer (the late joiner). Each event is forwarded as\n * a `collab.event` with `replay: true` so the client can distinguish\n * history from the live stream.\n *\n * The session log stores typed `SessionEvent`s (`user_input`,\n * `llm_response`, `tool_result`, etc.) — different from the kernel's\n * bus events. We translate the most useful subset (`tool.*` and\n * `iteration.*`-shaped ones) into the same `kind` namespace the live\n * mirror uses, so the client can render a single activity strip.\n */\n private async replayHistory(ws: WebSocket, sessionId: string): Promise<void> {\n if (!this.reader) return;\n const all: unknown[] = [];\n try {\n for await (const ev of this.reader.replay(sessionId)) {\n all.push(ev);\n }\n } catch (err) {\n this.logger.debug?.(\n `collab: session reader rejected ${sessionId}: ${\n toErrorMessage(err)\n }`,\n );\n return;\n }\n const tail = all.slice(-REPLAY_LIMIT);\n if (tail.length === 0) return; // nothing to replay\n for (const raw of tail) {\n const ev = raw as { type?: string | undefined; ts?: string | undefined; [k: string]: unknown };\n const kind = this.historyEventToKind(ev);\n if (!kind) continue; // skip events we don't know how to mirror\n this.send(ws, {\n type: 'collab.event',\n payload: {\n kind,\n payload: ev,\n at: ev.ts ?? new Date().toISOString(),\n replay: true,\n },\n });\n }\n }\n\n /**\n * Map a stored `SessionEvent` to a `collab.event.kind` so the live\n * strip and the history strip can share a single rendering path.\n * Returns null for events that don't have a meaningful live analog\n * (e.g. `session_start`, file-snapshot bookkeeping, rewind markers).\n */\n private historyEventToKind(ev: { type?: string | undefined }): string | null {\n switch (ev.type) {\n case 'user_input':\n return 'user_input';\n case 'llm_response':\n return 'llm_response';\n case 'tool_result':\n return 'tool.executed';\n case 'compaction':\n return 'compaction';\n case 'error':\n return 'error';\n default:\n return null;\n }\n }\n\n // ── State snapshot + periodic broadcast ────────────────────────────────\n\n private stateMessage(sessionId: string): WSCollabState {\n const bucket = this.bySession.get(sessionId);\n return {\n type: 'collab.state',\n payload: {\n sessionId,\n participants: bucket\n ? [...bucket].map((p) => ({\n participantId: p.participantId,\n role: p.role,\n joinedAt: p.joinedAt,\n }))\n : [],\n },\n };\n }\n\n private ensureBroadcast(): void {\n if (this.broadcastInterval) return;\n this.broadcastInterval = setInterval(() => {\n for (const sessionId of this.bySession.keys()) {\n this.broadcast(sessionId, this.stateMessage(sessionId));\n }\n }, 2000);\n }\n\n private stopBroadcast(): void {\n if (this.broadcastInterval) {\n clearInterval(this.broadcastInterval);\n this.broadcastInterval = null;\n }\n }\n\n private broadcast(sessionId: string, msg: WSServerMessage): void {\n const data = JSON.stringify(msg);\n const bucket = this.bySession.get(sessionId);\n if (!bucket) return;\n for (const p of bucket) {\n try {\n if (p.ws.readyState === 1) p.ws.send(data);\n } catch (err) {\n this.logger.debug?.(\n `collab broadcast failed: ${\n toErrorMessage(err)\n }`,\n );\n }\n }\n }\n\n private send(ws: WebSocket, msg: WSServerMessage): void {\n try {\n if (ws.readyState === 1) ws.send(JSON.stringify(msg));\n } catch {\n /* client gone */\n }\n }\n\n private errorMessage(detail: string): WSServerMessage {\n return { type: 'error', payload: { phase: 'collab', message: detail } };\n }\n\n // ── Controller flow (Phase 3) ───────────────────────────────────────────\n\n private async handleRequestPause(ws: WebSocket, raw: unknown): Promise<void> {\n if (!this.bus) {\n this.send(ws, this.errorMessage('pause requires a CollaborationBus'));\n return;\n }\n const participant = this.findParticipant(ws);\n if (!participant) {\n this.send(ws, this.errorMessage('pause requires an active join'));\n return;\n }\n if (participant.role !== 'controller') {\n this.send(\n ws,\n this.errorMessage(\n `pause requires the 'controller' role (current: '${participant.role}')`,\n ),\n );\n return;\n }\n const payload = raw as { sessionId?: string | undefined } | undefined;\n if (!payload?.sessionId || payload.sessionId !== participant.sessionId) {\n this.send(ws, this.errorMessage('pause sessionId mismatch'));\n return;\n }\n const transitioned = this.bus.requestPause(participant.participantId);\n if (!transitioned) {\n // Already paused — surface the current state to the requester.\n const s = this.bus.getState();\n this.send(ws, {\n type: 'error',\n payload: {\n phase: 'collab',\n message: `bus already paused by ${s.pausedBy ?? '?'} at ${s.pausedAt ?? '?'}`,\n },\n });\n return;\n }\n const s = this.bus.getState();\n this.broadcast(payload.sessionId, {\n type: 'collab.pause.granted',\n payload: {\n sessionId: payload.sessionId,\n pausedBy: s.pausedBy ?? participant.participantId,\n pausedAt: s.pausedAt ?? new Date().toISOString(),\n autoResumeInMs: PAUSE_TIMEOUT_MS,\n },\n });\n }\n\n private async handleResume(ws: WebSocket, raw: unknown): Promise<void> {\n if (!this.bus) {\n this.send(ws, this.errorMessage('resume requires a CollaborationBus'));\n return;\n }\n const participant = this.findParticipant(ws);\n if (!participant) {\n this.send(ws, this.errorMessage('resume requires an active join'));\n return;\n }\n // Permission: controller OR the original pauser. We do a simple\n // \"any controller can release\" check — fine for Phase 3, can be\n // tightened to \"only the pauser\" later.\n if (participant.role !== 'controller') {\n this.send(\n ws,\n this.errorMessage(\n `resume requires the 'controller' role (current: '${participant.role}')`,\n ),\n );\n return;\n }\n const payload = raw as { sessionId?: string | undefined } | undefined;\n if (!payload?.sessionId || payload.sessionId !== participant.sessionId) {\n this.send(ws, this.errorMessage('resume sessionId mismatch'));\n return;\n }\n const transitioned = this.bus.resume();\n if (!transitioned) {\n this.send(ws, this.errorMessage('bus is not currently paused'));\n return;\n }\n this.broadcast(payload.sessionId, {\n type: 'collab.pause.released',\n payload: {\n sessionId: payload.sessionId,\n reason: 'controller',\n at: new Date().toISOString(),\n },\n });\n }\n\n private async handleGrantControl(ws: WebSocket, raw: unknown): Promise<void> {\n // Promote a target participant to `controller` so the pause/resume and\n // inject_tool checks (which gate on role === 'controller') accept it. Only\n // a current controller may grant; the granter itself already passed the\n // bus requirement when it joined as controller, so no extra bus check is\n // needed here. The new roster is broadcast so every client reflects it.\n const participant = this.findParticipant(ws);\n if (!participant) {\n this.send(ws, this.errorMessage('grant_control requires an active join'));\n return;\n }\n if (participant.role !== 'controller') {\n this.send(\n ws,\n this.errorMessage(\n `grant_control requires the 'controller' role (current: '${participant.role}')`,\n ),\n );\n return;\n }\n const payload = raw as\n | { sessionId?: string | undefined; toParticipant?: string | undefined }\n | undefined;\n if (\n !payload?.sessionId ||\n !payload.toParticipant ||\n payload.sessionId !== participant.sessionId\n ) {\n this.send(ws, this.errorMessage('grant_control requires { sessionId, toParticipant }'));\n return;\n }\n const target = this.findParticipantById(payload.sessionId, payload.toParticipant);\n if (!target) {\n this.send(\n ws,\n this.errorMessage(\n `grant_control: no participant '${payload.toParticipant}' in this session`,\n ),\n );\n return;\n }\n target.role = 'controller';\n this.logger.debug?.(\n `collab: control granted from ${participant.participantId} to ${target.participantId} in ${payload.sessionId}`,\n );\n this.broadcast(payload.sessionId, this.stateMessage(payload.sessionId));\n }\n\n /**\n * Phase 4 — handle a controller's manual tool-call injection.\n * Validates the payload, queues it on the bus, and broadcasts\n * the grant so observers see what just happened. The actual\n * splice into the agent's pipeline is performed by the\n * `collabInjectMiddleware` on the next tool call.\n */\n private async handleInjectTool(ws: WebSocket, raw: unknown): Promise<void> {\n if (!this.bus) {\n this.send(ws, this.errorMessage('inject_tool requires a CollaborationBus'));\n return;\n }\n const participant = this.findParticipant(ws);\n if (!participant) {\n this.send(ws, this.errorMessage('inject_tool requires an active join'));\n return;\n }\n if (participant.role !== 'controller') {\n this.send(\n ws,\n this.errorMessage(\n `inject_tool requires the 'controller' role (current: '${participant.role}')`,\n ),\n );\n return;\n }\n const payload = raw as\n | {\n sessionId?: string | undefined;\n toolUseId?: string | undefined;\n content?: unknown | undefined;\n isError?: boolean | undefined;\n reason?: string | undefined;\n }\n | undefined;\n if (\n !payload?.sessionId ||\n !payload.toolUseId ||\n typeof payload.isError !== 'boolean' ||\n typeof payload.reason !== 'string' ||\n payload.content === undefined\n ) {\n this.send(\n ws,\n this.errorMessage(\n 'inject_tool requires { sessionId, toolUseId, content, isError, reason }',\n ),\n );\n return;\n }\n if (payload.sessionId !== participant.sessionId) {\n this.send(\n ws,\n this.errorMessage(\n `inject_tool sessionId mismatch (joined: ${participant.sessionId})`,\n ),\n );\n return;\n }\n const queued = this.bus.injectToolResult({\n toolUseId: payload.toolUseId,\n content: payload.content,\n isError: payload.isError,\n reason: payload.reason,\n authorId: participant.participantId,\n });\n if (!queued) {\n this.send(\n ws,\n this.errorMessage(\n `an injection for toolUseId ${payload.toolUseId} is already queued`,\n ),\n );\n return;\n }\n this.broadcast(payload.sessionId, {\n type: 'collab.injection.granted',\n payload: {\n sessionId: payload.sessionId,\n toolUseId: payload.toolUseId,\n // The tool name is unknown here (the injection is queued\n // before the model produces the tool call). We surface a\n // placeholder; the middleware will emit a `consumed` event\n // with the real name on match.\n toolName: '(pending match)',\n authorId: participant.participantId,\n reason: payload.reason,\n isError: payload.isError,\n phase: 'queued',\n at: new Date().toISOString(),\n },\n });\n }\n\n /**\n * Bus callback: a queued injection was spliced into a real tool call. Re-emit\n * `collab.injection.granted` with phase `'consumed'` and the now-known tool\n * name. The injection carries no sessionId, so resolve it from the author's\n * current session; if they've already left, fall back to every live session.\n */\n private broadcastInjectionConsumed(info: ConsumedInjectionInfo): void {\n let sessionId: string | null = null;\n for (const [sid, bucket] of this.bySession) {\n for (const p of bucket) {\n if (p.participantId === info.authorId) {\n sessionId = sid;\n break;\n }\n }\n if (sessionId) break;\n }\n const message = (sid: string): WSServerMessage => ({\n type: 'collab.injection.granted',\n payload: {\n sessionId: sid,\n toolUseId: info.toolUseId,\n toolName: info.toolName,\n authorId: info.authorId,\n reason: info.reason,\n isError: info.isError,\n phase: 'consumed',\n at: new Date().toISOString(),\n },\n });\n if (sessionId) {\n this.broadcast(sessionId, message(sessionId));\n } else {\n for (const sid of this.bySession.keys()) this.broadcast(sid, message(sid));\n }\n }\n}\n\ninterface Participant {\n participantId: string;\n ws: WebSocket;\n sessionId: string;\n role: CollabRole;\n joinedAt: string;\n}\n","/**\n * Projects manifest (~/.wrongstack/projects.json) helpers — extracted from the\n * giant startWebUI closure in index.ts. Pure, param-based file IO: each fn\n * takes the global config path explicitly, so they close over nothing. Mirrors\n * the CLI's project-manifest registration (touchProjectInManifest).\n */\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { projectSlug } from '@wrongstack/core';\n\nexport interface ProjectEntry {\n name: string;\n root: string;\n slug: string;\n lastSeen?: string | undefined;\n createdAt?: string | undefined;\n /** Working directory of the most recent session (may differ from root). */\n lastWorkingDir?: string | undefined;\n}\n\nexport interface ProjectsManifest {\n projects: ProjectEntry[];\n}\n\nexport function projectsJsonPath(globalConfigPath: string): string {\n const base = path.dirname(globalConfigPath);\n return path.join(base, 'projects.json');\n}\n\nexport async function loadManifest(globalConfigPath: string): Promise<ProjectsManifest> {\n try {\n const raw = await fs.readFile(projectsJsonPath(globalConfigPath), 'utf8');\n const parsed = JSON.parse(raw) as ProjectsManifest;\n return { projects: parsed.projects ?? [] };\n } catch {\n return { projects: [] };\n }\n}\n\nexport async function saveManifest(\n manifest: ProjectsManifest,\n globalConfigPath: string,\n): Promise<void> {\n const file = projectsJsonPath(globalConfigPath);\n await fs.mkdir(path.dirname(file), { recursive: true });\n await fs.writeFile(file, JSON.stringify(manifest, null, 2), 'utf8');\n}\n\nexport function generateProjectSlug(rootPath: string): string {\n // Canonical derivation — must match wstack-paths/projectSlug exactly or\n // the WebUI and CLI would key the same project under different dirs.\n return projectSlug(rootPath);\n}\n\nexport async function ensureProjectDataDir(\n slug: string,\n globalConfigPath: string,\n): Promise<string> {\n const base = path.dirname(globalConfigPath);\n const dir = path.join(base, 'projects', slug);\n await fs.mkdir(dir, { recursive: true });\n return dir;\n}\n","import { createRequire } from 'node:module';\nimport type { WebSocket } from 'ws';\nimport type { Logger } from '@wrongstack/core';\nimport { toErrorMessage } from '@wrongstack/core/utils';\nimport type { WSServerMessage } from '../types.js';\n\n/** Loose inbound shape — matches the server's internal WSClientMessage. */\ntype IncomingMessage = { type: string; payload?: unknown };\ntype PtyExit = { exitCode: number; signal?: number | undefined };\ninterface PtyProcess {\n write(data: string): void;\n resize(cols: number, rows: number): void;\n kill(): void;\n onData(cb: (data: string) => void): unknown;\n onExit(cb: (event: PtyExit) => void): unknown;\n}\ninterface NodePtyApi {\n spawn(\n file: string,\n args: string[],\n opts: {\n name: string;\n cols: number;\n rows: number;\n cwd: string;\n env: Record<string, string>;\n },\n ): PtyProcess;\n}\ntype LoadNodePty = () => NodePtyApi | null;\n\n/** Hard cap on concurrent PTYs per connected client — a runaway-spawn backstop. */\nconst MAX_SESSIONS_PER_CLIENT = 8;\nconst DEFAULT_COLS = 80;\nconst DEFAULT_ROWS = 24;\nconst requireFromHere = createRequire(import.meta.url);\nlet cachedNodePty: NodePtyApi | null | undefined;\n\n/**\n * TerminalWebSocketHandler — backs the WebUI's integrated terminal panel.\n *\n * Mirrors the lifecycle shape of WorktreeWebSocketHandler but is *per-client*\n * and *interactive*: each connected WebSocket owns a map of real node-pty\n * sessions keyed by a client-chosen id. Browser xterm.js ⇄ pty wiring:\n * - `terminal.create` → spawn a shell pty, stream its output back\n * - `terminal.input` → write keystrokes to the pty\n * - `terminal.resize` → propagate xterm's fit dimensions\n * - `terminal.close` → kill the pty\n * When a client disconnects, every pty it owns is killed (no orphan shells).\n */\nexport class TerminalWebSocketHandler {\n /** ws → (terminalId → pty). */\n private readonly sessions = new Map<WebSocket, Map<string, PtyProcess>>();\n\n constructor(\n /** Resolves the cwd new terminals open in — tracks the live working dir. */\n private readonly getCwd: () => string,\n private readonly logger: Logger,\n private readonly loadNodePty: LoadNodePty = defaultLoadNodePty,\n ) {}\n\n addClient(ws: WebSocket): void {\n if (!this.sessions.has(ws)) this.sessions.set(ws, new Map());\n ws.on('close', () => this.disposeClient(ws));\n ws.on('error', () => this.disposeClient(ws));\n }\n\n /** Kill every pty owned by every client (server shutdown). */\n dispose(): void {\n for (const ws of [...this.sessions.keys()]) this.disposeClient(ws);\n }\n\n /** True if this message was a terminal.* message (handled here). */\n handleMessage(ws: WebSocket, msg: IncomingMessage): boolean {\n const p = (msg.payload ?? {}) as Record<string, unknown>;\n switch (msg.type) {\n case 'terminal.create':\n if (isStr(p.id))\n this.create(ws, { id: p.id, cols: numOrUndef(p.cols), rows: numOrUndef(p.rows) });\n return true;\n case 'terminal.input':\n if (isStr(p.id) && isStr(p.data)) this.input(ws, { id: p.id, data: p.data });\n return true;\n case 'terminal.resize':\n if (isStr(p.id)) this.resize(ws, { id: p.id, cols: Number(p.cols), rows: Number(p.rows) });\n return true;\n case 'terminal.close':\n if (isStr(p.id)) this.close(ws, p.id);\n return true;\n default:\n return false;\n }\n }\n\n // ── internals ───────────────────────────────────────────────────────────\n\n private create(\n ws: WebSocket,\n payload: { id: string; cols?: number | undefined; rows?: number | undefined },\n ): void {\n const map = this.sessions.get(ws) ?? new Map<string, PtyProcess>();\n this.sessions.set(ws, map);\n\n if (map.has(payload.id)) return; // idempotent — already running\n if (map.size >= MAX_SESSIONS_PER_CLIENT) {\n this.send(ws, {\n type: 'terminal.exit',\n payload: { id: payload.id, exitCode: -1 },\n });\n return;\n }\n\n const shell =\n process.platform === 'win32'\n ? process.env.COMSPEC || 'cmd.exe'\n : process.env.SHELL || '/bin/bash';\n\n const nodePty = this.loadNodePty();\n if (!nodePty) {\n const msg =\n 'Integrated terminal unavailable: optional dependency node-pty is not installed. ' +\n 'Install node-pty to enable WebUI terminal sessions.';\n this.logger.warn?.(msg);\n this.send(ws, { type: 'terminal.output', payload: { id: payload.id, data: `${msg}\\r\\n` } });\n this.send(ws, { type: 'terminal.exit', payload: { id: payload.id, exitCode: -1 } });\n return;\n }\n\n let pty: PtyProcess;\n try {\n pty = nodePty.spawn(shell, [], {\n name: 'xterm-color',\n cols: clampDim(payload.cols, DEFAULT_COLS),\n rows: clampDim(payload.rows, DEFAULT_ROWS),\n cwd: this.getCwd(),\n env: process.env as Record<string, string>,\n });\n } catch (err) {\n this.logger.warn?.(`terminal spawn failed: ${toErrorMessage(err)}`);\n this.send(ws, { type: 'terminal.exit', payload: { id: payload.id, exitCode: -1 } });\n return;\n }\n\n map.set(payload.id, pty);\n\n pty.onData((data) => {\n this.send(ws, { type: 'terminal.output', payload: { id: payload.id, data } });\n });\n pty.onExit(({ exitCode, signal }) => {\n map.delete(payload.id);\n this.send(ws, {\n type: 'terminal.exit',\n payload: { id: payload.id, exitCode, signal: signal ?? undefined },\n });\n });\n }\n\n private input(ws: WebSocket, payload: { id: string; data: string }): void {\n const pty = this.sessions.get(ws)?.get(payload.id);\n if (pty) pty.write(payload.data);\n }\n\n private resize(ws: WebSocket, payload: { id: string; cols: number; rows: number }): void {\n const pty = this.sessions.get(ws)?.get(payload.id);\n if (!pty) return;\n try {\n pty.resize(clampDim(payload.cols, DEFAULT_COLS), clampDim(payload.rows, DEFAULT_ROWS));\n } catch {\n /* pty already gone */\n }\n }\n\n private close(ws: WebSocket, id: string): void {\n const map = this.sessions.get(ws);\n const pty = map?.get(id);\n if (!pty) return;\n map?.delete(id);\n try {\n pty.kill();\n } catch {\n /* already dead */\n }\n }\n\n private disposeClient(ws: WebSocket): void {\n const map = this.sessions.get(ws);\n if (!map) return;\n for (const pty of map.values()) {\n try {\n pty.kill();\n } catch {\n /* already dead */\n }\n }\n this.sessions.delete(ws);\n }\n\n private send(ws: WebSocket, msg: WSServerMessage): void {\n try {\n if (ws.readyState === 1) ws.send(JSON.stringify(msg));\n } catch {\n /* client gone */\n }\n }\n}\n\nfunction defaultLoadNodePty(): NodePtyApi | null {\n if (cachedNodePty !== undefined) return cachedNodePty;\n try {\n cachedNodePty = requireFromHere('node-pty') as NodePtyApi;\n } catch {\n cachedNodePty = null;\n }\n return cachedNodePty;\n}\n\nfunction isStr(v: unknown): v is string {\n return typeof v === 'string';\n}\n\nfunction numOrUndef(v: unknown): number | undefined {\n return typeof v === 'number' && Number.isFinite(v) ? v : undefined;\n}\n\n/** Clamp a terminal dimension into a sane range; fall back to a default. */\nfunction clampDim(value: number | undefined, fallback: number): number {\n if (typeof value !== 'number' || !Number.isFinite(value)) return fallback;\n return Math.max(1, Math.min(1000, Math.floor(value)));\n}\n","import { join, resolve, sep } from 'node:path';\nimport type { WebSocket } from 'ws';\nimport type { EventBus, Logger } from '@wrongstack/core';\nimport { cleanupStaleSddWorktrees, WorktreeManager } from '@wrongstack/core';\nimport type { WorktreeHandleView, WorktreeOrphanView, WSServerMessage } from '../types.js';\nimport { toErrorMessage } from '@wrongstack/core/utils';\n\nconst MAX_ACTIVITY = 6;\n\n/** Statuses that mean a worktree is actively owned by a live in-session run. */\nconst ACTIVE_STATUSES = new Set(['allocating', 'active', 'committing', 'merging']);\n\n/**\n * Only this project's own managed branches are operable from the panel — both a\n * safety scope (never touch `main`/arbitrary refs) AND an argv-injection guard:\n * the strict charset forbids a leading `-`, so a client can't smuggle a value\n * that git would parse as a flag. Mirrors `WorktreeManager`'s `wstack/ap/<slug>`.\n */\nconst MANAGED_BRANCH_RE = /^wstack\\/ap\\/[A-Za-z0-9._/-]+$/;\n\nexport interface WorktreeManagementDeps {\n projectRoot: string;\n /** Board snapshot dir — powers the cross-process liveness guard on cleanup. */\n boardsDir: string;\n}\n\n/**\n * WorktreeWebSocketHandler — mirrors AutoPhaseWebSocketHandler. Subscribes to\n * the shared EventBus `worktree.*` lifecycle events, keeps a live snapshot of\n * every worktree, and broadcasts:\n * - `worktree.event` incrementally (drives the flowing activity strip)\n * - `worktree.state` on connect + on a 2s timer (drives swim-lanes/DAG)\n */\nexport class WorktreeWebSocketHandler {\n private readonly clients = new Set<WebSocket>();\n private readonly handles = new Map<string, WorktreeHandleView>();\n private baseBranch = '';\n private broadcastInterval: ReturnType<typeof setInterval> | null = null;\n private readonly offs: Array<() => void> = [];\n\n constructor(\n private readonly events: EventBus,\n private readonly logger: Logger,\n private readonly management?: WorktreeManagementDeps | undefined,\n ) {\n this.subscribe();\n }\n\n addClient(ws: WebSocket): void {\n this.clients.add(ws);\n ws.on('close', () => this.clients.delete(ws));\n ws.on('error', () => this.clients.delete(ws));\n this.send(ws, this.stateMessage());\n // Push the current orphan inventory to the freshly-connected client.\n void this.scanAndBroadcast();\n }\n\n /** Handle worktree-panel control messages (scan / clean / per-row ops). */\n async handleMessage(msg: { type: string; payload?: Record<string, unknown> }): Promise<boolean> {\n if (msg.type === 'worktree.scan') {\n await this.scanAndBroadcast();\n return true;\n }\n if (msg.type === 'worktree.cleanup') {\n await this.cleanupOrphans();\n return true;\n }\n if (msg.type === 'worktree.remove') {\n await this.removeOne(msg.payload?.['dir'] as string | undefined, msg.payload?.['branch'] as string | undefined);\n return true;\n }\n if (msg.type === 'worktree.merge') {\n await this.mergeBranch(msg.payload?.['branch'] as string | undefined);\n return true;\n }\n if (msg.type === 'worktree.diff') {\n await this.diffOne(msg.payload?.['dir'] as string | undefined, msg.payload?.['baseBranch'] as string | undefined);\n return true;\n }\n return false;\n }\n\n dispose(): void {\n for (const off of this.offs) off();\n this.offs.length = 0;\n this.stopBroadcast();\n }\n\n // ── orphan management ─────────────────────────────────────────────────────\n\n /** Absolute managed-worktrees root for this project. */\n private worktreesRoot(): string {\n return resolve(join(this.management!.projectRoot, '.wrongstack', 'worktrees'));\n }\n\n /** True iff `dir` resolves strictly inside the managed worktrees root. */\n private underRoot(dir: string): boolean {\n const abs = resolve(dir);\n const root = this.worktreesRoot();\n return abs !== root && abs.startsWith(root + sep);\n }\n\n /** Branches of worktrees a live in-session run currently owns. */\n private liveActiveBranches(): Set<string> {\n const live = new Set<string>();\n for (const h of this.handles.values()) {\n if (ACTIVE_STATUSES.has(h.status) && h.branch) live.add(h.branch);\n }\n return live;\n }\n\n /**\n * Scan the disk for managed worktrees/branches NOT owned by a live in-session\n * run and broadcast them as orphans, with whether it is safe to clean now.\n * No-op (empty inventory) when management deps were not wired.\n */\n private async scanAndBroadcast(): Promise<void> {\n if (!this.management) {\n this.broadcast({ type: 'worktree.orphans', payload: { orphans: [], canClean: false } });\n return;\n }\n try {\n const wt = new WorktreeManager({ projectRoot: this.management.projectRoot });\n const { worktrees, branches } = await wt.listManaged();\n const live = this.liveActiveBranches();\n const orphans: WorktreeOrphanView[] = [];\n const seenBranches = new Set<string>();\n for (const w of worktrees) {\n if (w.branch && live.has(w.branch)) continue; // owned by a live run\n if (w.branch) seenBranches.add(w.branch);\n orphans.push({ kind: 'worktree', dir: w.dir, branch: w.branch });\n }\n // Branch-only orphans (no checkout) — skip those a live run owns or that a\n // listed worktree already covers.\n for (const b of branches) {\n if (live.has(b) || seenBranches.has(b)) continue;\n orphans.push({ kind: 'branch', branch: b });\n }\n // Safe to clean when no live in-session worktree exists. (The cross-process\n // board guard is additionally enforced at cleanup time.)\n const canClean = this.liveActiveBranches().size === 0;\n this.broadcast({\n type: 'worktree.orphans',\n payload: {\n orphans,\n canClean,\n reason: canClean ? undefined : 'a run is live in this session',\n },\n });\n } catch (err) {\n this.logger.debug?.(`worktree orphan scan failed: ${toErrorMessage(err)}`);\n this.broadcast({ type: 'worktree.orphans', payload: { orphans: [], canClean: false } });\n }\n }\n\n /**\n * Force-remove every orphaned worktree + branch. Refused while a run is live —\n * in this session (active handles) OR another process (the SDD board liveness\n * guard inside cleanupStaleSddWorktrees). Best-effort; reports the outcome.\n */\n private async cleanupOrphans(): Promise<void> {\n if (!this.management) {\n this.broadcast({\n type: 'worktree.cleanup_result',\n payload: { ok: false, removed: 0, reason: 'cleanup is not available in this session' },\n });\n return;\n }\n if (this.liveActiveBranches().size > 0) {\n this.broadcast({\n type: 'worktree.cleanup_result',\n payload: { ok: false, removed: 0, reason: 'a run is live in this session — stop it first' },\n });\n return;\n }\n const res = await cleanupStaleSddWorktrees({\n projectRoot: this.management.projectRoot,\n boardsDir: this.management.boardsDir,\n });\n if (res.skippedReason) {\n this.broadcast({\n type: 'worktree.cleanup_result',\n payload: { ok: false, removed: 0, reason: res.skippedReason },\n });\n await this.scanAndBroadcast();\n return;\n }\n // Drop any kept-for-review handles we held — their checkouts are gone now.\n for (const [id, h] of [...this.handles]) {\n if (!ACTIVE_STATUSES.has(h.status)) this.handles.delete(id);\n }\n this.broadcast({ type: 'worktree.cleanup_result', payload: { ok: true, removed: res.removed } });\n this.broadcastState();\n await this.scanAndBroadcast();\n }\n\n /** Remove/discard ONE worktree + branch. Refused while a live run owns it. */\n private async removeOne(dir?: string, branch?: string): Promise<void> {\n if (!this.management || (!dir && !branch)) {\n this.broadcast({ type: 'worktree.cleanup_result', payload: { ok: false, removed: 0, reason: 'nothing to remove' } });\n return;\n }\n // Validate the client-supplied targets: a branch must be one of ours (the\n // regex also blocks argv flag-smuggling) and a dir must be inside the\n // managed worktrees root (no path traversal to arbitrary checkouts).\n if (branch && !MANAGED_BRANCH_RE.test(branch)) {\n this.broadcast({ type: 'worktree.cleanup_result', payload: { ok: false, removed: 0, reason: 'not a managed worktree branch' } });\n return;\n }\n if (dir && !this.underRoot(dir)) {\n this.broadcast({ type: 'worktree.cleanup_result', payload: { ok: false, removed: 0, reason: 'path is outside the managed worktrees root' } });\n return;\n }\n if (branch && this.liveActiveBranches().has(branch)) {\n this.broadcast({ type: 'worktree.cleanup_result', payload: { ok: false, removed: 0, reason: 'a run is live on this worktree — stop it first' } });\n return;\n }\n let removed = false;\n if (dir) {\n const wt = new WorktreeManager({ projectRoot: this.management.projectRoot });\n ({ removed } = await wt.removeOne(dir, branch));\n }\n // Drop our handle for this branch/dir.\n for (const [id, h] of [...this.handles]) {\n if ((branch && h.branch === branch) || (dir && h.handleId && dir.endsWith(h.handleId))) this.handles.delete(id);\n }\n this.broadcast({ type: 'worktree.cleanup_result', payload: { ok: removed, removed: removed ? 1 : 0, reason: removed ? undefined : 'remove failed (not a managed worktree?)' } });\n this.broadcastState();\n await this.scanAndBroadcast();\n }\n\n /** Squash-merge ONE branch into base. Refused while a live run owns it. */\n private async mergeBranch(branch?: string): Promise<void> {\n if (!this.management || !branch) {\n this.broadcast({ type: 'worktree.merge_result', payload: { ok: false, branch: branch ?? '', reason: 'no branch' } });\n return;\n }\n if (!MANAGED_BRANCH_RE.test(branch)) {\n this.broadcast({ type: 'worktree.merge_result', payload: { ok: false, branch, reason: 'not a managed worktree branch' } });\n return;\n }\n if (this.liveActiveBranches().has(branch)) {\n this.broadcast({ type: 'worktree.merge_result', payload: { ok: false, branch, reason: 'a run is live on this worktree — stop it first' } });\n return;\n }\n const wt = new WorktreeManager({ projectRoot: this.management.projectRoot });\n const res = await wt.mergeBranch(branch);\n this.broadcast({\n type: 'worktree.merge_result',\n payload: { ok: res.ok, branch, conflict: res.conflict, conflictFiles: res.conflictFiles, reason: res.reason },\n });\n await this.scanAndBroadcast();\n }\n\n /** Compact change summary for one worktree checkout. */\n private async diffOne(dir?: string, baseBranch?: string): Promise<void> {\n // Same path guard as removeOne — never run git in an arbitrary directory.\n if (!this.management || !dir || !this.underRoot(dir)) {\n this.broadcast({ type: 'worktree.diff_result', payload: { dir: dir ?? '', summary: null } });\n return;\n }\n // A baseBranch is only ever a managed branch or omitted (→ detected base);\n // reject anything that could smuggle a git flag.\n const base = baseBranch && MANAGED_BRANCH_RE.test(baseBranch) ? baseBranch : undefined;\n const wt = new WorktreeManager({ projectRoot: this.management.projectRoot });\n const summary = await wt.diffSummary(resolve(dir), base);\n this.broadcast({ type: 'worktree.diff_result', payload: { dir, summary } });\n }\n\n // ── internals ───────────────────────────────────────────────────────────\n\n private subscribe(): void {\n const on = this.events.on.bind(this.events) as never as (\n ev: string,\n fn: (p: unknown) => void,\n ) => () => void;\n\n this.offs.push(\n on('worktree.allocated', (p) => {\n const e = p as { handleId: string; ownerId: string; ownerLabel: string; dir?: string; branch: string; baseBranch: string };\n this.baseBranch = e.baseBranch || this.baseBranch;\n this.upsert(e.handleId, {\n handleId: e.handleId,\n ownerId: e.ownerId,\n ownerLabel: e.ownerLabel,\n dir: e.dir,\n branch: e.branch,\n baseBranch: e.baseBranch,\n status: 'active',\n insertions: 0,\n deletions: 0,\n files: 0,\n allocatedAt: Date.now(),\n lastEventAt: Date.now(),\n recentActivity: [],\n });\n this.activity(e.handleId, 'allocated', `branch ${e.branch}`);\n this.ensureBroadcast();\n }),\n on('worktree.committed', (p) => {\n const e = p as { handleId: string; insertions: number; deletions: number; files: number; committed: boolean };\n this.patch(e.handleId, { status: 'committing', insertions: e.insertions, deletions: e.deletions, files: e.files });\n if (e.committed) this.activity(e.handleId, 'committed', `+${e.insertions}/-${e.deletions} (${e.files}f)`);\n this.broadcastState();\n }),\n on('worktree.merged', (p) => {\n const e = p as { handleId: string; baseBranch: string };\n this.patch(e.handleId, { status: 'merged' });\n this.activity(e.handleId, 'merged', `→ ${e.baseBranch}`);\n this.broadcastState();\n }),\n on('worktree.conflict', (p) => {\n const e = p as { handleId: string; conflictFiles: string[] };\n this.patch(e.handleId, { status: 'needs-review', conflictFiles: e.conflictFiles });\n this.activity(e.handleId, 'conflict', e.conflictFiles.join(', '));\n this.broadcastState();\n }),\n on('worktree.failed', (p) => {\n const e = p as { handleId: string; error: string };\n this.patch(e.handleId, { status: 'failed' });\n this.activity(e.handleId, 'failed', e.error);\n this.broadcastState();\n }),\n on('worktree.released', (p) => {\n const e = p as { handleId: string; kept: boolean };\n if (!e.kept) this.handles.delete(e.handleId);\n this.activity(e.handleId, 'released', e.kept ? 'kept for review' : 'removed');\n if (this.handles.size === 0) this.stopBroadcast();\n else this.broadcastState();\n }),\n );\n }\n\n private upsert(id: string, view: WorktreeHandleView): void {\n this.handles.set(id, view);\n }\n\n private patch(id: string, patch: Partial<WorktreeHandleView>): void {\n const cur = this.handles.get(id);\n if (!cur) return;\n this.handles.set(id, { ...cur, ...patch, lastEventAt: Date.now() });\n }\n\n private activity(id: string, kind: string, text: string): void {\n const cur = this.handles.get(id);\n if (cur) {\n const recentActivity = [...cur.recentActivity, { kind, text, at: Date.now() }].slice(-MAX_ACTIVITY);\n this.handles.set(id, { ...cur, recentActivity });\n }\n this.broadcast({ type: 'worktree.event', payload: { kind, handleId: id, text, at: Date.now() } });\n }\n\n private stateMessage(): WSServerMessage {\n return {\n type: 'worktree.state',\n payload: { worktrees: [...this.handles.values()], baseBranch: this.baseBranch },\n };\n }\n\n private broadcastState(): void {\n this.broadcast(this.stateMessage());\n }\n\n private ensureBroadcast(): void {\n this.broadcast(this.stateMessage());\n if (this.broadcastInterval) return;\n this.broadcastInterval = setInterval(() => this.broadcast(this.stateMessage()), 2000);\n }\n\n private stopBroadcast(): void {\n this.broadcast(this.stateMessage());\n if (this.broadcastInterval) {\n clearInterval(this.broadcastInterval);\n this.broadcastInterval = null;\n }\n }\n\n private broadcast(msg: WSServerMessage): void {\n const data = JSON.stringify(msg);\n for (const ws of this.clients) {\n try {\n if (ws.readyState === 1) ws.send(data);\n } catch (err) {\n this.logger.debug?.(`worktree broadcast failed: ${toErrorMessage(err)}`);\n }\n }\n }\n\n private send(ws: WebSocket, msg: WSServerMessage): void {\n try {\n if (ws.readyState === 1) ws.send(JSON.stringify(msg));\n } catch {\n /* client gone */\n }\n }\n}\n","/**\n * Mailbox WebSocket handlers for the WebUI.\n *\n * Handles `mailbox.messages` and `mailbox.agents` message types.\n * The frontend sends these to populate the mailbox panel; the server\n * reads from the project-level GlobalMailbox and responds.\n */\n\nimport type { WebSocket } from 'ws';\nimport { GlobalMailbox, resolveProjectDir } from '@wrongstack/core';\nimport { send, errMessage } from './ws-utils.js';\n\nexport interface MailboxHandlerDeps {\n /** Absolute project root. */\n projectRoot: string;\n /** Global WrongStack root (~/.wrongstack). */\n globalRoot: string;\n}\n\n// ── Handlers ──────────────────────────────────────────────────────────\n\n/**\n * List recent mailbox messages. Frontend sends:\n * { type: 'mailbox.messages', limit?: number, incompleteOnly?: boolean }\n *\n * Uses `incompleteOnly` so the server filters to active/unread messages,\n * making readByCount === 0 a reliable \"unread to all agents\" signal for\n * the ActivityBar badge count.\n */\nexport async function handleMailboxMessages(\n ws: WebSocket,\n deps: MailboxHandlerDeps,\n payload: { limit?: number; incompleteOnly?: boolean } | undefined,\n): Promise<void> {\n try {\n const dir = resolveProjectDir(deps.projectRoot, deps.globalRoot);\n const mb = new GlobalMailbox(dir);\n const messages = await mb.query({\n limit: payload?.limit ?? 30,\n incompleteOnly: payload?.incompleteOnly ?? false,\n });\n send(ws, {\n type: 'mailbox.messages',\n payload: {\n messages: messages.map((m) => ({\n id: m.id, from: m.from, to: m.to, type: m.type,\n subject: m.subject, body: m.body, priority: m.priority,\n readBy: m.readBy, readByCount: Object.keys(m.readBy).length,\n completed: m.completed, completedBy: m.completedBy,\n completedAt: m.completedAt, outcome: m.outcome, timestamp: m.timestamp,\n replyTo: m.replyTo, senderSessionId: m.senderSessionId,\n taskContext: m.taskContext,\n })),\n },\n });\n } catch (err) {\n send(ws, { type: 'mailbox.messages', payload: { messages: [], error: errMessage(err) } });\n }\n}\n\n/**\n * List registered agents. Frontend sends:\n * { type: 'mailbox.agents', onlineOnly?: boolean }\n */\nexport async function handleMailboxAgents(\n ws: WebSocket,\n deps: MailboxHandlerDeps,\n payload: { onlineOnly?: boolean } | undefined,\n): Promise<void> {\n try {\n const dir = resolveProjectDir(deps.projectRoot, deps.globalRoot);\n const mb = new GlobalMailbox(dir);\n const agents = payload?.onlineOnly\n ? await mb.getOnlineAgents()\n : await mb.getAgentStatuses();\n send(ws, {\n type: 'mailbox.agents',\n payload: {\n agents: agents.map((a) => ({\n agentId: a.agentId, name: a.name, role: a.role,\n sessionId: a.sessionId, status: a.status,\n currentTool: a.currentTool, currentTask: a.currentTask,\n iterations: a.iterations, toolCalls: a.toolCalls,\n lastSeenAt: a.lastSeenAt, online: a.online,\n pid: a.pid, source: a.source,\n })),\n },\n });\n } catch (err) {\n send(ws, { type: 'mailbox.agents', payload: { agents: [], error: errMessage(err) } });\n }\n}\n\n/**\n * Delete all messages from the mailbox. Frontend sends:\n * { type: 'mailbox.clear' }\n * Server responds with 'mailbox.cleared'.\n */\nexport async function handleMailboxClear(\n ws: WebSocket,\n deps: MailboxHandlerDeps,\n): Promise<void> {\n try {\n const dir = resolveProjectDir(deps.projectRoot, deps.globalRoot);\n const mb = new GlobalMailbox(dir);\n await mb.clearAll();\n send(ws, { type: 'mailbox.cleared', payload: {} });\n } catch (err) {\n send(ws, { type: 'mailbox.cleared', payload: { error: errMessage(err) } });\n }\n}\n\n/**\n * Purge stale/orphaned messages from the mailbox. Frontend sends:\n * { type: 'mailbox.purge', payload?: { completedMaxAgeMs?: number; incompleteMaxAgeMs?: number } }\n * Server responds with 'mailbox.purged'.\n */\nexport async function handleMailboxPurge(\n ws: WebSocket,\n deps: MailboxHandlerDeps,\n opts?: { completedMaxAgeMs?: number; incompleteMaxAgeMs?: number },\n): Promise<void> {\n try {\n const dir = resolveProjectDir(deps.projectRoot, deps.globalRoot);\n const mb = new GlobalMailbox(dir);\n const result = await mb.purgeStale(opts);\n send(ws, { type: 'mailbox.purged', payload: result });\n } catch (err) {\n send(ws, { type: 'mailbox.purged', payload: { error: errMessage(err) } });\n }\n}\n","/**\n * Process lifecycle for the WebUI server: graceful shutdown and the\n * SIGINT/SIGTERM wiring that triggers it.\n *\n * On a termination signal we (best-effort) flush + close the active session,\n * close every connected WebSocket, stop the HTTP and WS servers, then exit.\n * A re-entrancy guard makes a second signal during shutdown a no-op (rapid\n * double Ctrl+C no longer runs the teardown twice).\n *\n * Extracted from `index.ts` as a parameterized factory so the teardown\n * sequence can be unit tested without a real process signal, server, or\n * `process.exit` — `log` and `exit` are injectable seams.\n */\n\nexport interface LifecycleResources {\n /** Persist + close the active session (best-effort; errors are logged). */\n flushSession: () => Promise<void>;\n /**\n * Returns the currently-connected client sockets to close. A thunk (not a\n * snapshot) so shutdown closes whoever is connected *at signal time*, not\n * whoever was connected when the handler was registered.\n */\n clients: () => Iterable<{ close: () => void }>;\n /** Servers to stop (HTTP + WS). `null`/`undefined` entries are skipped. */\n servers: Array<{ close: () => void } | null | undefined>;\n /**\n * Optional best-effort cleanup run after the session flush and before exit\n * (e.g. removing this process from the running-instance registry). Errors are\n * logged, never thrown — cleanup must not block a clean shutdown.\n */\n onShutdown?: (() => Promise<void> | void) | undefined;\n /** Output sink. Defaults to `console.log`. */\n log?: ((msg: string) => void) | undefined;\n /** Process exit. Defaults to `process.exit`. Injectable for tests. */\n exit?: ((code: number) => void) | undefined;\n}\n\n/**\n * Build the graceful-shutdown handler. Returns an idempotent async function:\n * the first call runs the teardown, subsequent calls (e.g. a second SIGINT)\n * return immediately.\n */\nexport function createShutdown(res: LifecycleResources): () => Promise<void> {\n const log = res.log ?? ((m: string) => console.log(m));\n const exit = res.exit ?? ((code: number) => process.exit(code));\n let shuttingDown = false;\n\n return async () => {\n if (shuttingDown) return; // a second signal during teardown is a no-op\n shuttingDown = true;\n\n log('[WebUI] Shutting down...');\n try {\n await res.flushSession();\n } catch (e) {\n log(`[WebUI] Error closing session: ${e instanceof Error ? e.message : String(e)}`);\n }\n for (const ws of res.clients()) ws.close();\n for (const server of res.servers) server?.close();\n if (res.onShutdown) {\n try {\n await res.onShutdown();\n } catch (e) {\n log(`[WebUI] Error during shutdown cleanup: ${e instanceof Error ? e.message : String(e)}`);\n }\n }\n exit(0);\n };\n}\n\n/**\n * Register the shutdown handler on SIGINT and SIGTERM. Returns an unregister\n * function that detaches both listeners (useful for tests and clean restarts).\n */\nexport function registerShutdownHandlers(res: LifecycleResources): () => void {\n const shutdown = createShutdown(res);\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n return () => {\n process.off('SIGINT', shutdown);\n process.off('SIGTERM', shutdown);\n };\n}\n","/**\n * Running-instance registry for the standalone WebUI server.\n *\n * Every live `wstackui` process records itself in a single JSON file under the\n * wstack home dir (`~/.wrongstack/webui-instances.json`) so a user running\n * several instances (one per project, or several per project on different\n * ports) can see at a glance which ports are open for which path.\n *\n * Design notes:\n * - **Self-healing**: every register/unregister/list prunes entries whose PID\n * is no longer alive (`process.kill(pid, 0)`), so a crashed instance that\n * never got to unregister doesn't leave a ghost behind.\n * - **Atomic writes**: the file is rewritten via `atomicWrite` (tmp + rename),\n * so a concurrent reader never sees a half-written file. Two instances\n * starting at the *exact* same millisecond could still race the\n * read-modify-write — acceptable for a best-effort tracking file, and the\n * next register() heals any dropped entry.\n * - **Best-effort**: a failure to read/write the registry must NEVER take the\n * server down. Callers wrap these in `.catch()`.\n */\n\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport * as fs from 'node:fs/promises';\nimport { atomicWrite } from '@wrongstack/core';\n\n/** One running WebUI process. */\nexport interface WebUIInstanceRecord {\n /** OS process id — also the liveness key. */\n pid: number;\n /** HTTP port serving the React frontend. */\n httpPort: number;\n /** WebSocket port for the agent backend. */\n wsPort: number;\n /** Bind host (e.g. 127.0.0.1 or 0.0.0.0). */\n host: string;\n /** Absolute project root the instance booted against. */\n projectRoot: string;\n /** Display name (basename of projectRoot). */\n projectName: string;\n /** ISO timestamp when the instance registered. */\n startedAt: string;\n /** Convenience open-in-browser URL. */\n url: string;\n}\n\ninterface RegistryFile {\n version: 1;\n instances: WebUIInstanceRecord[];\n}\n\n/** Default wstack home dir (`~/.wrongstack`). Callers may override the base. */\nexport function defaultBaseDir(): string {\n return path.join(os.homedir(), '.wrongstack');\n}\n\n/** Resolve the registry file path for a given base dir. */\nexport function registryPath(baseDir: string = defaultBaseDir()): string {\n return path.join(baseDir, 'webui-instances.json');\n}\n\n/**\n * Liveness probe. `process.kill(pid, 0)` sends no signal — it only checks the\n * process exists. ESRCH ⇒ dead; EPERM ⇒ alive but owned by another user (still\n * counts as alive). Any other error is treated conservatively as \"alive\" so we\n * never prune an instance we simply failed to probe.\n */\nexport function isPidAlive(pid: number): boolean {\n if (!Number.isInteger(pid) || pid <= 0) return false;\n try {\n process.kill(pid, 0);\n return true;\n } catch (err) {\n return (err as NodeJS.ErrnoException).code !== 'ESRCH';\n }\n}\n\nasync function load(file: string): Promise<RegistryFile> {\n try {\n const raw = await fs.readFile(file, 'utf8');\n const parsed = JSON.parse(raw) as RegistryFile;\n if (parsed?.version === 1 && Array.isArray(parsed.instances)) {\n return parsed;\n }\n } catch {\n // Missing or corrupt → start fresh.\n }\n return { version: 1, instances: [] };\n}\n\nasync function save(file: string, instances: WebUIInstanceRecord[]): Promise<void> {\n await atomicWrite(file, `${JSON.stringify({ version: 1, instances }, null, 2)}\\n`, {\n mode: 0o600,\n });\n}\n\n/** Drop dead processes and (optionally) one specific pid. */\nfunction prune(instances: WebUIInstanceRecord[], excludePid?: number): WebUIInstanceRecord[] {\n return instances.filter((i) => i.pid !== excludePid && isPidAlive(i.pid));\n}\n\n/**\n * Register (or refresh) this instance. Prunes dead entries and any stale entry\n * for our own PID before adding the current record. Best-effort — rejects only\n * on a hard fs error, which callers swallow.\n */\nexport async function registerInstance(\n record: WebUIInstanceRecord,\n baseDir: string = defaultBaseDir(),\n): Promise<void> {\n const file = registryPath(baseDir);\n const data = await load(file);\n const instances = prune(data.instances, record.pid);\n instances.push(record);\n await save(file, instances);\n}\n\n/** Remove this instance (called on graceful shutdown). Also prunes dead pids. */\nexport async function unregisterInstance(\n pid: number,\n baseDir: string = defaultBaseDir(),\n): Promise<void> {\n const file = registryPath(baseDir);\n const data = await load(file);\n const instances = prune(data.instances, pid);\n await save(file, instances);\n}\n\n/** List live instances, pruning any dead entries encountered. */\nexport async function listInstances(\n baseDir: string = defaultBaseDir(),\n): Promise<WebUIInstanceRecord[]> {\n const file = registryPath(baseDir);\n const data = await load(file);\n const live = prune(data.instances);\n // Persist the pruned view so `cat`-ing the file also shows reality, but never\n // fail the list on a write error.\n if (live.length !== data.instances.length) {\n await save(file, live).catch(() => {});\n }\n return live;\n}\n\n/** Human-readable table of running instances for `wstackui --list`. */\nexport function formatInstances(instances: WebUIInstanceRecord[]): string {\n if (instances.length === 0) {\n return 'No WebUI instances are currently running.';\n }\n const lines = [`Running WebUI instances (${instances.length}):`, ''];\n for (const i of instances) {\n lines.push(\n ` • ${i.url} · ws:${i.wsPort} · pid ${i.pid}`,\n ` project: ${i.projectName} (${i.projectRoot})`,\n ` since: ${i.startedAt}`,\n );\n }\n return lines.join('\\n');\n}\n","/**\n * Free-port discovery for the standalone WebUI server.\n *\n * When a user runs several instances, the default ports (HTTP 3456 / WS 3457)\n * are taken by the first one. Rather than make the user hand-pick `PORT` /\n * `WS_PORT` for every extra instance, the server probes upward from the\n * requested port and binds the first free one — then stamps that real port into\n * the served HTML and the instance registry so everything stays consistent.\n *\n * The probe binds a throwaway `net.Server`, then closes it, so there is a tiny\n * TOCTOU window between \"found free\" and \"the real server binds it\". For local\n * single-user multi-instance use that race is negligible; if it ever loses, the\n * real bind fails loudly with EADDRINUSE exactly as before.\n */\n\nimport * as net from 'node:net';\n\n/** Resolve true when `port` can be bound on `host`, false on EADDRINUSE/EACCES. */\nexport function isPortFree(host: string, port: number): Promise<boolean> {\n return new Promise((resolve) => {\n const srv = net.createServer();\n srv.once('error', () => resolve(false));\n srv.once('listening', () => {\n srv.close(() => resolve(true));\n });\n try {\n srv.listen(port, host);\n } catch {\n resolve(false);\n }\n });\n}\n\nexport interface FindFreePortOptions {\n /** Ports to skip even if free (e.g. one already chosen for the sibling server). */\n exclude?: Set<number> | undefined;\n /** How many consecutive ports to try before giving up. Default 200. */\n maxTries?: number | undefined;\n}\n\n/**\n * Find the first free port at or above `startPort` on `host`, skipping any in\n * `exclude`. Throws if nothing is free within `maxTries` steps.\n */\nexport async function findFreePort(\n host: string,\n startPort: number,\n opts: FindFreePortOptions = {},\n): Promise<number> {\n const exclude = opts.exclude ?? new Set<number>();\n const maxTries = opts.maxTries ?? 200;\n let port = startPort;\n for (let i = 0; i < maxTries; i++) {\n // Stay inside the valid TCP range; wrap into the high ephemeral band if a\n // pathological startPort pushes us past the ceiling.\n if (port > 65535) port = 1024 + (port % 50000);\n if (!exclude.has(port) && (await isPortFree(host, port))) {\n return port;\n }\n port++;\n }\n throw new Error(\n `No free port found near ${startPort} on ${host} after ${maxTries} attempts.`,\n );\n}\n","/**\n * Best-effort \"open this URL in the default browser\" for `--webui --open`.\n *\n * Cross-platform via the OS opener (`start` / `open` / `xdg-open`). Fully\n * fire-and-forget: a missing opener, a headless box, or a spawn failure must\n * NEVER take the server down — the URL is always also printed to the console.\n */\n\nimport { spawn } from 'node:child_process';\n\n/** Resolve the platform's URL-opener command + args. */\nexport function browserOpenCommand(\n url: string,\n platform: NodeJS.Platform = process.platform,\n): { command: string; args: string[] } {\n if (platform === 'win32') {\n // `start` is a cmd builtin; the empty \"\" is the window title slot so URLs\n // containing `&` / spaces are passed through intact.\n return { command: 'cmd', args: ['/c', 'start', '', url] };\n }\n if (platform === 'darwin') {\n return { command: 'open', args: [url] };\n }\n return { command: 'xdg-open', args: [url] };\n}\n\n/** Spawn the OS browser-opener for `url` and register it as a protected\n * process so it survives kill/killAll. Never throws. */\nexport function openBrowser(url: string, platform: NodeJS.Platform = process.platform): void {\n try {\n const { command, args } = browserOpenCommand(url, platform);\n const child = spawn(command, args, { stdio: 'ignore', detached: true, windowsHide: true });\n // A missing opener (e.g. xdg-open absent on a headless box) surfaces as an\n // async 'error' event — swallow it so it doesn't crash the process.\n child.on('error', () => {});\n child.unref();\n\n // Register the browser process as protected so process.kill / killAll\n // never accidentally terminates it — that would crash the webui session.\n // The registry is imported lazily to avoid a circular dependency with\n // @wrongstack/tools (which the webui server does not directly depend on).\n if (child.pid) {\n try {\n // Dynamic import to avoid hard dependency on @wrongstack/tools from\n // this module (the webui server may not have tools installed).\n import('@wrongstack/tools').then(({ getProcessRegistry }) => {\n const pid = child.pid;\n if (pid === undefined) return;\n getProcessRegistry().register({\n pid,\n name: 'browser',\n command: `${command} ${args.join(' ')}`,\n startedAt: Date.now(),\n child,\n protected: true,\n });\n // Auto-unregister on exit so the process list stays accurate.\n child.on('exit', () => {\n getProcessRegistry().unregister(pid);\n });\n }).catch(() => {\n // @wrongstack/tools may not be available — silently skip registration.\n });\n } catch {\n // Module resolution failure — silently skip.\n }\n }\n } catch {\n // Synchronous spawn failure — best-effort, ignore.\n }\n}\n","/**\n * Token-usage cost math for the WebUI server.\n *\n * models.dev pricing is expressed in **dollars per 1,000,000 tokens**, and\n * providers omit the field entirely for free/unmetered plans. Both the\n * `session.start` payload (which ships the per-token rates to the client) and\n * `stats.get` (which reports an actual dollar figure) repeated the same\n * \"read `model.cost.*` with a `?? 0` fallback, then divide by 1e6\" logic\n * inline. Pulling it here keeps the rate normalization and the cost formula in\n * one tested place — a wrong field name or a missing `/ 1e6` silently produces\n * a plausible-but-wrong number, which is exactly what a unit test should pin.\n */\n\n/** Per-1,000,000-token pricing, normalized to numbers (0 when unpriced). */\nexport interface CostRates {\n /** $ per 1M input tokens. */\n input: number;\n /** $ per 1M output tokens. */\n output: number;\n /** $ per 1M cache-read tokens. */\n cacheRead: number;\n}\n\n/** Token counts for a turn/session. `cacheRead` is optional (older counters). */\nexport interface TokenUsage {\n input: number;\n output: number;\n cacheRead?: number | undefined;\n}\n\n/**\n * Normalize a models.dev model object's pricing into {@link CostRates}.\n * Missing model, missing `cost`, or missing individual fields all yield 0 —\n * free/unmetered plans report `$0` rather than crashing.\n */\nexport function getCostRates(model: unknown): CostRates {\n const cost = (\n model as { cost?: { input?: number | undefined; output?: number | undefined; cache_read?: number | undefined } } | null | undefined\n )?.cost;\n return {\n input: cost?.input ?? 0,\n output: cost?.output ?? 0,\n cacheRead: cost?.cache_read ?? 0,\n };\n}\n\n/**\n * Dollar cost of `usage` at the given per-1M-token `rates`. Returns 0 when all\n * rates are 0 (unpriced plan).\n */\nexport function computeUsageCost(usage: TokenUsage, rates: CostRates): number {\n return (\n (usage.input * rates.input +\n usage.output * rates.output +\n (usage.cacheRead ?? 0) * rates.cacheRead) /\n 1_000_000\n );\n}\n","import type { WebSocket } from 'ws';\nimport type { ProviderConfig } from '@wrongstack/core';\nimport { DefaultSecretScrubber } from '@wrongstack/core';\nimport { probeLocalLlm } from '@wrongstack/runtime/probe';\nimport { loadSavedProviders, saveProviders } from './provider-config-io.js';\nimport { toErrorMessage } from '@wrongstack/core/utils';\nimport {\n upsertKey as upsertKeyRecord,\n deleteKey as deleteKeyRecord,\n setActiveKey as setActiveKeyRecord,\n addProvider as addProviderRecord,\n removeProvider as removeProviderRecord,\n maskedKey,\n normalizeKeys,\n} from './provider-keys.js';\nimport type { ConnectedClient, WSServerMessage } from './types.js';\nimport { send, sendResult, errMessage } from './ws-utils.js';\n\n/**\n * Wire shape of one saved provider as broadcast over `providers.saved`.\n * The WebUI's `<ProviderModelsPanel>` consumes this — when\n * `pickedModelId` / `models` is missing, the panel renders the empty\n * state.\n */\nexport interface SavedProviderView {\n id: string;\n family?: string | undefined;\n baseUrl?: string | undefined;\n /** Saved model allowlist, verbatim (undefined / [] both possible). */\n models?: string[] | undefined;\n /** First entry of `models`, or undefined when the list is empty/unset. */\n pickedModelId?: string | undefined;\n apiKeys: Array<{\n label: string;\n maskedKey: string;\n isActive: boolean;\n createdAt: string;\n }>;\n}\n\n/**\n * Canonical projection from in-memory `ProviderConfig` to the\n * `providers.saved` wire shape. Pure (no I/O) so it's unit-tested in\n * isolation — see `tests/server/provider-handlers-projection.test.ts`.\n *\n * Secrets never leave: every key is run through `maskedKey` before it\n * reaches the wire.\n */\nexport function projectSavedProviders(\n providers: Record<string, ProviderConfig>,\n): SavedProviderView[] {\n return Object.entries(providers).map(([id, cfg]) => {\n const keys = normalizeKeys(cfg);\n const models = cfg.models;\n const view: SavedProviderView = {\n id,\n family: cfg.family ?? id,\n baseUrl: cfg.baseUrl,\n models,\n apiKeys: keys.map((k) => ({\n label: k.label,\n maskedKey: maskedKey(k.apiKey),\n isActive: k.label === cfg.activeKey,\n createdAt: k.createdAt,\n })),\n };\n const picked = models && models.length > 0 ? models[0] : undefined;\n if (picked !== undefined) view.pickedModelId = picked;\n return view;\n });\n}\n\n/** Shared scrubber for probe error/body redaction. */\nconst probeScrubber = new DefaultSecretScrubber();\n\nexport interface ProviderHandlerDeps {\n globalConfigPath: string;\n vault: import('@wrongstack/core').SecretVault;\n /** Shared config write lock — serialized via chained promises */\n setConfigWriteLock: (lock: Promise<void>) => void;\n getConfigWriteLock: () => Promise<void>;\n /** Broadcast a message to all connected WebUI clients */\n broadcast: (clients: Map<WebSocket, ConnectedClient>, msg: WSServerMessage) => void;\n /** Connected WebUI clients map */\n clients: Map<WebSocket, ConnectedClient>;\n}\n\nexport function createProviderHandlers(deps: ProviderHandlerDeps) {\n const { globalConfigPath, vault, broadcast, clients } = deps;\n let configWriteLock = deps.getConfigWriteLock();\n\n async function loadConfigProviders(): Promise<Record<string, ProviderConfig>> {\n return loadSavedProviders(globalConfigPath, vault);\n }\n\n async function saveConfigProviders(providers: Record<string, ProviderConfig>): Promise<void> {\n const next = configWriteLock\n .then(() => saveProviders(globalConfigPath, vault, providers))\n .catch((err) => {\n const msg = toErrorMessage(err);\n console.error(JSON.stringify({\n level: 'error',\n event: 'webui.provider_save_failed',\n message: msg,\n timestamp: new Date().toISOString(),\n }));\n });\n configWriteLock = next;\n deps.setConfigWriteLock(next);\n await next;\n }\n\n async function handleKeyUpsert(ws: WebSocket, providerId: string, label: string, apiKey: string): Promise<void> {\n try {\n const providers = await loadConfigProviders();\n const result = upsertKeyRecord(providers, providerId, label, apiKey, new Date().toISOString());\n if (result.ok) {\n await saveConfigProviders(providers);\n broadcastSaved(providers);\n }\n sendResult(ws, result.ok, result.message);\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n }\n\n async function handleKeyDelete(ws: WebSocket, providerId: string, label: string): Promise<void> {\n try {\n const providers = await loadConfigProviders();\n const result = deleteKeyRecord(providers, providerId, label);\n if (result.ok) {\n await saveConfigProviders(providers);\n broadcastSaved(providers);\n }\n sendResult(ws, result.ok, result.message);\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n }\n\n async function handleKeySetActive(ws: WebSocket, providerId: string, label: string): Promise<void> {\n try {\n const providers = await loadConfigProviders();\n const result = setActiveKeyRecord(providers, providerId, label);\n if (result.ok) {\n await saveConfigProviders(providers);\n broadcastSaved(providers);\n }\n sendResult(ws, result.ok, result.message);\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n }\n\n async function handleProviderAdd(ws: WebSocket, payload: { id: string; family: string; baseUrl?: string | undefined; apiKey?: string | undefined }): Promise<void> {\n try {\n const providers = await loadConfigProviders();\n const result = addProviderRecord(providers, payload, new Date().toISOString());\n if (result.ok) {\n await saveConfigProviders(providers);\n broadcastSaved(providers);\n }\n sendResult(ws, result.ok, result.message);\n if (result.ok) {\n console.log(`[WebUI] Provider \"${payload.id}\" added via provider.add`);\n }\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n }\n\n async function handleProviderRemove(ws: WebSocket, providerId: string): Promise<void> {\n try {\n const providers = await loadConfigProviders();\n const result = removeProviderRecord(providers, providerId);\n if (result.ok) {\n await saveConfigProviders(providers);\n broadcastSaved(providers);\n }\n sendResult(ws, result.ok, result.message);\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n }\n\n /** Broadcast the current saved-provider list to every connected client. */\n function broadcastSaved(providers: Record<string, ProviderConfig>): void {\n broadcast(clients, {\n type: 'providers.saved',\n payload: { providers: projectSavedProviders(providers) },\n });\n }\n\n /** Remove the saved model allowlist for a provider. */\n async function handleProviderClearModels(ws: WebSocket, providerId: string): Promise<void> {\n try {\n const providers = await loadConfigProviders();\n const cfg = providers[providerId];\n if (!cfg) {\n sendResult(ws, false, `Unknown provider \"${providerId}\"`);\n return;\n }\n delete cfg.models;\n await saveConfigProviders(providers);\n sendResult(ws, true, `Cleared model allowlist for ${providerId}`);\n broadcastSaved(providers);\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n }\n\n /** Restore a previously-cleared model allowlist (pairs with clear). */\n async function handleProviderUndoClear(\n ws: WebSocket,\n providerId: string,\n previousModels: string[],\n ): Promise<void> {\n try {\n const providers = await loadConfigProviders();\n const cfg = providers[providerId];\n if (!cfg) {\n sendResult(ws, false, `Unknown provider \"${providerId}\"`);\n return;\n }\n cfg.models = [...previousModels];\n await saveConfigProviders(providers);\n sendResult(ws, true, `Restored ${previousModels.length} model(s) for ${providerId}`);\n broadcastSaved(providers);\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n }\n\n /** Update a saved provider's wire config (family / baseUrl / envVars / models). */\n async function handleProviderUpdate(\n ws: WebSocket,\n payload: {\n id: string;\n family?: string | undefined;\n baseUrl?: string | undefined;\n envVars?: string[] | undefined;\n models?: string[] | undefined;\n },\n ): Promise<void> {\n try {\n const providers = await loadConfigProviders();\n const cfg = providers[payload.id];\n if (!cfg) {\n sendResult(ws, false, `Unknown provider \"${payload.id}\"`);\n return;\n }\n if (payload.family !== undefined) cfg.family = payload.family as ProviderConfig['family'];\n if (payload.baseUrl !== undefined) cfg.baseUrl = payload.baseUrl;\n if (payload.envVars !== undefined) cfg.envVars = payload.envVars;\n if (payload.models !== undefined) cfg.models = payload.models;\n await saveConfigProviders(providers);\n sendResult(ws, true, `Updated ${payload.id}`);\n broadcastSaved(providers);\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n }\n\n /**\n * Run a health probe against a saved provider's `/v1/models` and\n * reply with a `provider.probe` message. Never throws — the\n * `ProbeResult` carries the failure mode in its `status`.\n */\n async function handleProviderProbe(\n ws: WebSocket,\n providerId: string,\n timeoutMs?: number,\n ): Promise<void> {\n const reply = (payload: Record<string, unknown>): void =>\n send(ws, { type: 'provider.probe', payload: { providerId, ...payload } });\n try {\n const providers = await loadConfigProviders();\n const cfg = providers[providerId];\n if (!cfg) {\n reply({ ok: false, status: 'no_provider' });\n return;\n }\n if (!cfg.baseUrl) {\n reply({ ok: false, status: 'no_base_url' });\n return;\n }\n const keys = normalizeKeys(cfg);\n const active = keys.find((k) => k.label === cfg.activeKey) ?? keys[0];\n const result = await probeLocalLlm({\n baseUrl: cfg.baseUrl,\n apiKey: active?.apiKey,\n noAuth: false,\n scrubber: probeScrubber,\n ...(timeoutMs !== undefined ? { timeoutMs } : {}),\n });\n reply(result as never as Record<string, unknown>);\n } catch (err) {\n reply({ ok: false, status: 'unreachable', detail: errMessage(err) });\n }\n }\n\n return {\n handleKeyUpsert,\n handleKeyDelete,\n handleKeySetActive,\n handleProviderAdd,\n handleProviderRemove,\n handleProviderClearModels,\n handleProviderUndoClear,\n handleProviderUpdate,\n handleProviderProbe,\n loadConfigProviders,\n };\n}\n","/**\n * Shared config I/O helpers for the `providers` map inside the global config.\n *\n * Extracted from both `packages/webui/src/server/index.ts` and\n * `packages/cli/src/webui-server.ts` so the CLI's `--webui` mode doesn't\n * duplicate the read-merge-decrypt / encrypt-write cycle. Callers supply\n * their own vault (already booted) and config path — this module is pure I/O\n * with no side-channel state.\n */\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { type ProviderConfig, type SecretVault, atomicWrite } from '@wrongstack/core';\nimport { decryptConfigSecrets, encryptConfigSecrets } from '@wrongstack/core/security';\n\n/**\n * Read the `providers` section from the global config, decrypting\n * secret-bearing fields. Returns an empty record when the config file\n * doesn't exist or has no `providers` key.\n */\nexport async function loadSavedProviders(\n configPath: string,\n vault: SecretVault,\n): Promise<Record<string, ProviderConfig>> {\n let raw: string;\n try {\n raw = await fs.readFile(configPath, 'utf8');\n } catch {\n return {};\n }\n let parsed: { providers?: Record<string, ProviderConfig> } = {};\n try {\n parsed = JSON.parse(raw) as { providers?: Record<string, ProviderConfig> };\n } catch {\n return {};\n }\n if (!parsed.providers) return {};\n return decryptConfigSecrets(parsed.providers, vault);\n}\n\n/**\n * Write `providers` back into the global config, encrypting secrets first.\n * Refuses to overwrite a corrupt-but-existing config file (the operator\n * should fix it manually). When the config file is missing (ENOENT), starts\n * from an empty object.\n */\nexport async function saveProviders(\n configPath: string,\n vault: SecretVault,\n providers: Record<string, ProviderConfig>,\n): Promise<void> {\n let raw: string;\n let fileExists = true;\n try {\n raw = await fs.readFile(configPath, 'utf8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n throw new Error(\n `Refusing to mutate ${configPath}: ${(err as Error).message}`,\n { cause: err },\n );\n }\n fileExists = false;\n raw = '{}';\n }\n let parsed: Record<string, unknown>;\n try {\n parsed = JSON.parse(raw) as Record<string, unknown>;\n } catch (err) {\n if (fileExists) {\n throw new Error(\n `Refusing to overwrite corrupt config at ${configPath} ` +\n `(${(err as Error).message}). Fix or move the file aside before retrying.`,\n { cause: err },\n );\n }\n parsed = {};\n }\n parsed.providers = providers;\n const encrypted = encryptConfigSecrets(parsed, vault);\n await atomicWrite(configPath, JSON.stringify(encrypted, null, 2), { mode: 0o600 });\n}\n\n// ---------------------------------------------------------------------------\n// Standalone WebUI server helpers (boot phase — not WS-connected)\n// ---------------------------------------------------------------------------\n\nimport { DefaultSecretVault } from '@wrongstack/core';\n\n/**\n * Small helper for the standalone WebUI entry point: create a\n * `{ load, save }` pair from a config path alone (uses the\n * config-directory-relative `.key` file for the vault). The `--webui`\n * CLI mode and the standalone server both need to read/write the\n * `providers` map identically.\n */\nexport function createProviderConfigIO(configPath: string) {\n const keyFile = path.join(path.dirname(configPath), '.key');\n const vault = new DefaultSecretVault({ keyFile });\n\n return {\n load: () => loadSavedProviders(configPath, vault),\n save: (providers: Record<string, ProviderConfig>) =>\n saveProviders(configPath, vault, providers),\n };\n}\n","import { expectDefined } from '@wrongstack/core';\n/**\n * Pure provider/API-key record transforms for the WebUI server's `key.*` and\n * `provider.*` WebSocket handlers.\n *\n * These operate on an in-memory `providers` record (the decrypted\n * `config.providers` map) and return a `{ ok, message }` result mirroring the\n * status string the handler sends back to the client. All persistence\n * (load/decrypt, encrypt/atomic-write) and WS messaging stays in `index.ts` —\n * keeping this layer pure means the security-sensitive key bookkeeping (which\n * key is active, when a provider is dropped, how legacy single-key configs are\n * normalized) is unit-testable without a vault or a socket.\n *\n * Extracted from `index.ts`; transforms mutate the passed record in place, the\n * same way the original handlers did before calling `saveProviders`.\n */\nimport type { ProviderApiKey, ProviderConfig } from '@wrongstack/core';\nexport type ProvidersRecord = Record<string, ProviderConfig>;\n\nexport interface KeyOpResult {\n ok: boolean;\n message: string;\n}\n\n/**\n * Normalize a provider's keys to the array form, upgrading a legacy single\n * `apiKey` string to a one-element `[{ label: 'default', ... }]` list. Returns\n * fresh copies so callers can mutate without aliasing the stored config.\n */\nexport function normalizeKeys(cfg: ProviderConfig): ProviderApiKey[] {\n if (Array.isArray(cfg.apiKeys) && cfg.apiKeys.length > 0) {\n return cfg.apiKeys.map((k) => ({ ...k }));\n }\n if (typeof cfg.apiKey === 'string' && cfg.apiKey.length > 0) {\n return [{ label: 'default', apiKey: cfg.apiKey, createdAt: '' }];\n }\n return [];\n}\n\n/**\n * Write a normalized key list back onto a provider config: drop all key fields\n * when empty, otherwise sync `apiKeys` and re-point `activeKey` if it no longer\n * names a present key. Does NOT mirror the plaintext key to the legacy `apiKey`\n * field — that would leak the secret on accidental serialization. Consumers\n * that need the real key should read from `apiKeys[]` directly.\n */\nexport function writeKeysBack(cfg: ProviderConfig, keys: ProviderApiKey[]): void {\n if (keys.length === 0) {\n delete cfg.apiKeys;\n delete cfg.apiKey;\n delete cfg.activeKey;\n return;\n }\n cfg.apiKeys = keys;\n const active = keys.find((k) => k.label === cfg.activeKey) ?? expectDefined(keys[0]);\n // Do NOT mirror plaintext to cfg.apiKey — cleared to prevent serialization leaks.\n delete cfg.apiKey;\n if (!cfg.activeKey || !keys.some((k) => k.label === cfg.activeKey)) {\n cfg.activeKey = active.label;\n }\n}\n\n/** Mask a secret for display: `••••` for short keys, `abcd…wxyz` otherwise. */\nexport function maskedKey(key: string | undefined): string {\n if (!key) return '—';\n if (key.length <= 8) return '•'.repeat(key.length);\n return `${key.slice(0, 4)}…${key.slice(-4)}`;\n}\n\n/** Add or replace a labeled key for a provider, creating the provider if new. */\nexport function upsertKey(\n providers: ProvidersRecord,\n providerId: string,\n label: string,\n apiKey: string,\n nowIso: string,\n): KeyOpResult {\n const existing: ProviderConfig = providers[providerId] ?? { type: providerId };\n const keys = normalizeKeys(existing);\n const idx = keys.findIndex((k) => k.label === label);\n if (idx >= 0) {\n keys[idx] = { ...expectDefined(keys[idx]), apiKey, createdAt: nowIso };\n } else {\n keys.push({ label, apiKey, createdAt: nowIso });\n }\n writeKeysBack(existing, keys);\n if (!existing.activeKey) existing.activeKey = label;\n providers[providerId] = existing;\n return { ok: true, message: `Key \"${label}\" saved for ${providerId}` };\n}\n\n/** Remove a labeled key; drops the provider entirely when its last key goes. */\nexport function deleteKey(\n providers: ProvidersRecord,\n providerId: string,\n label: string,\n): KeyOpResult {\n const existing = providers[providerId];\n if (!existing) {\n return { ok: false, message: `Provider \"${providerId}\" not found` };\n }\n const keys = normalizeKeys(existing).filter((k) => k.label !== label);\n if (keys.length === 0) {\n delete providers[providerId];\n } else {\n writeKeysBack(existing, keys);\n if (existing.activeKey === label) existing.activeKey = keys[0]?.label;\n providers[providerId] = existing;\n }\n return { ok: true, message: `Key \"${label}\" deleted from ${providerId}` };\n}\n\n/** Point a provider's active key at the given label. */\nexport function setActiveKey(\n providers: ProvidersRecord,\n providerId: string,\n label: string,\n): KeyOpResult {\n const existing = providers[providerId];\n if (!existing) {\n return { ok: false, message: `Provider \"${providerId}\" not found` };\n }\n existing.activeKey = label;\n writeKeysBack(existing, normalizeKeys(existing));\n providers[providerId] = existing;\n return { ok: true, message: `Active key for ${providerId} set to \"${label}\"` };\n}\n\n/** Register a brand-new provider (optionally with an initial `default` key). */\nexport function addProvider(\n providers: ProvidersRecord,\n payload: { id: string; family: string; baseUrl?: string | undefined; apiKey?: string | undefined },\n nowIso: string,\n): KeyOpResult {\n if (providers[payload.id]) {\n return {\n ok: false,\n message: `Provider \"${payload.id}\" already exists. Use key.add to add a key.`,\n };\n }\n const newProv: ProviderConfig = {\n type: payload.id,\n family: payload.family as ProviderConfig['family'],\n baseUrl: payload.baseUrl,\n };\n if (payload.apiKey) {\n newProv.apiKeys = [{ label: 'default', apiKey: payload.apiKey, createdAt: nowIso }];\n newProv.activeKey = 'default';\n }\n providers[payload.id] = newProv;\n return { ok: true, message: `Provider \"${payload.id}\" added` };\n}\n\n/** Remove an entire provider and all its keys. */\nexport function removeProvider(providers: ProvidersRecord, providerId: string): KeyOpResult {\n if (!providers[providerId]) {\n return { ok: false, message: `Provider \"${providerId}\" not found` };\n }\n delete providers[providerId];\n return { ok: true, message: `Provider \"${providerId}\" removed` };\n}\n","/**\n * Mode route handlers — extracted from the startWebUI closure in index.ts.\n * Mirrors createProviderHandlers: a factory that closes the handler bodies over\n * an explicit context object instead of the giant startWebUI scope. The one\n * piece of outer mutable state (the `modeId` let) is threaded in as a setter so\n * the factory stays a pure function of its context.\n */\nimport type { WebSocket } from 'ws';\nimport {\n type Context,\n DefaultSystemPromptBuilder,\n resolveWstackPaths,\n type DefaultMemoryStore,\n type DefaultModeStore,\n type SkillLoader,\n type ToolRegistry,\n} from '@wrongstack/core';\nimport type { ConnectedClient } from './types.js';\nimport type { ModeRouteHandlers } from './mode-routes.js';\nimport { broadcast, errMessage, send, sendResult } from './ws-utils.js';\nimport { validateModeSwitchPayload } from './ws-payload-validation.js';\n\n/** The rich payload startWebUI's sessionStartPayload() resolves to. Matches the\n * WSSessionStart wire shape; broadcast() accepts it for a 'session.start' msg. */\ntype SessionStartPayload = {\n sessionId: string;\n model: string;\n provider: string;\n maxContext: number;\n inputCost: number;\n outputCost: number;\n cacheReadCost: number;\n projectName: string;\n projectRoot: string;\n cwd: string;\n mode: string;\n contextMode: string;\n};\ntype ModelCapabilities = NonNullable<\n ConstructorParameters<typeof DefaultSystemPromptBuilder>[0]\n>['modelCapabilities'];\n\nexport interface ModeHandlersContext {\n modeStore: DefaultModeStore;\n memoryStore: DefaultMemoryStore;\n skillLoader: SkillLoader | undefined;\n modelCapabilities: ModelCapabilities;\n context: Context;\n toolRegistry: ToolRegistry;\n config: { provider: string; model: string };\n projectRoot: string;\n globalRoot: string;\n clients: Map<WebSocket, ConnectedClient>;\n /** Update the outer `modeId` binding on a successful switch. */\n setModeId: (id: string) => void;\n /** Rebuilds the rich session.start payload broadcast after a mode switch. */\n sessionStartPayload: () => Promise<SessionStartPayload>;\n}\n\nexport function createModeHandlers(ctx: ModeHandlersContext): ModeRouteHandlers {\n return {\n listModes: async (ws) => {\n try {\n const modes = await ctx.modeStore.listModes();\n const active = await ctx.modeStore.getActiveMode();\n send(ws, {\n type: 'modes.list',\n payload: {\n modes: modes.map((m) => ({\n id: m.id,\n name: m.name,\n description: m.description,\n isActive: m.id === (active?.id ?? 'default'),\n })),\n activeId: active?.id ?? 'default',\n },\n });\n } catch (err) {\n send(ws, {\n type: 'modes.list',\n payload: {\n modes: [],\n activeId: 'default',\n error: errMessage(err),\n },\n });\n }\n },\n switchMode: async (ws, msg) => {\n const parsed = validateModeSwitchPayload(msg.payload);\n if (!parsed.ok) {\n sendResult(ws, false, parsed.message);\n return;\n }\n const { id } = parsed.value;\n try {\n if (id === 'default') {\n await ctx.modeStore.setActiveMode(null);\n } else {\n const found = await ctx.modeStore.getMode(id);\n if (!found) throw new Error(`Unknown mode \"${id}\"`);\n await ctx.modeStore.setActiveMode(id);\n }\n ctx.setModeId(id);\n const modePrompt = id === 'default' ? '' : ((await ctx.modeStore.getMode(id))?.prompt ?? '');\n const paths = resolveWstackPaths({ projectRoot: ctx.projectRoot, globalRoot: ctx.globalRoot });\n const freshBuilder = new DefaultSystemPromptBuilder({\n memoryStore: ctx.memoryStore,\n skillLoader: ctx.skillLoader,\n modeStore: ctx.modeStore,\n modeId: id,\n modePrompt,\n modelCapabilities: ctx.modelCapabilities,\n instructionPaths: {\n globalDir: paths.globalInstructions,\n projectDir: paths.inProjectInstructions,\n },\n });\n ctx.context.systemPrompt = await freshBuilder.build({\n cwd: ctx.projectRoot,\n projectRoot: ctx.projectRoot,\n tools: ctx.toolRegistry.list(),\n provider: ctx.config.provider,\n model: ctx.config.model,\n });\n sendResult(ws, true, `Switched to mode \"${id}\"`);\n broadcast(ctx.clients, {\n type: 'session.start',\n payload: { ...(await ctx.sessionStartPayload()) },\n });\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n },\n };\n}\n","/**\n * Project route handlers — extracted from the startWebUI closure in index.ts.\n * Mirrors createProviderHandlers/createModeHandlers. selectProject is the heavy\n * one: it tears down the current session and re-initialises for the chosen\n * project, mutating several startWebUI `let` bindings. Those are threaded in as\n * getters/setters so the factory stays a pure function of its context — the\n * handler bodies are a verbatim lift, only the dependency references changed.\n */\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { WebSocket } from 'ws';\nimport {\n type Context,\n DefaultSessionStore,\n DefaultSystemPromptBuilder,\n type DefaultMemoryStore,\n type DefaultModeStore,\n type DefaultTokenCounter,\n getSessionRegistry,\n resolveWstackPaths,\n type SkillLoader,\n type ToolRegistry,\n} from '@wrongstack/core';\nimport type { ConnectedClient } from './types.js';\nimport type { ProjectRouteHandlers } from './project-routes.js';\nimport { broadcast, errMessage, send, sendResult } from './ws-utils.js';\nimport {\n validateProjectsAddPayload,\n validateProjectsSelectPayload,\n validateWorkingDirSetPayload,\n} from './ws-payload-validation.js';\nimport { ensureProjectDataDir, generateProjectSlug, loadManifest, saveManifest } from './projects-manifest.js';\nimport { resolveWorkingDirInsideProject } from './path-containment.js';\n\ntype Session = Awaited<ReturnType<DefaultSessionStore['create']>>;\ntype SessionStartPayload = {\n sessionId: string;\n model: string;\n provider: string;\n maxContext: number;\n inputCost: number;\n outputCost: number;\n cacheReadCost: number;\n projectName: string;\n projectRoot: string;\n cwd: string;\n mode: string;\n contextMode: string;\n};\ntype ModelCapabilities = NonNullable<\n ConstructorParameters<typeof DefaultSystemPromptBuilder>[0]\n>['modelCapabilities'];\n\nexport interface ProjectHandlersContext {\n globalConfigPath: string;\n wpaths: { globalRoot: string };\n clients: Map<WebSocket, ConnectedClient>;\n context: Context;\n modeStore: DefaultModeStore;\n memoryStore: DefaultMemoryStore;\n skillLoader: SkillLoader | undefined;\n modelCapabilities: ModelCapabilities;\n toolRegistry: ToolRegistry;\n tokenCounter: DefaultTokenCounter;\n config: { provider: string; model: string };\n // Live reads of the mutable startWebUI bindings.\n getModeId: () => string;\n getProjectRoot: () => string;\n getSession: () => Session;\n // Mutations of the startWebUI bindings.\n setProjectRoot: (p: string) => void;\n setWorkingDir: (p: string) => void;\n setSession: (s: Session) => void;\n setSessionStore: (s: DefaultSessionStore) => void;\n setSessionStartedAt: (t: number) => void;\n /** Abort + clear any in-flight runLock before switching projects. */\n abortRunLock: () => void;\n sessionStartPayload: () => Promise<SessionStartPayload>;\n}\n\nexport function createProjectHandlers(ctx: ProjectHandlersContext): ProjectRouteHandlers {\n return {\n listProjects: async (ws) => {\n try {\n const manifest = await loadManifest(ctx.globalConfigPath);\n send(ws, { type: 'projects.list', payload: { projects: manifest.projects } });\n } catch (err) {\n send(ws, { type: 'projects.list', payload: { projects: [], error: errMessage(err) } });\n }\n },\n addProject: async (ws, msg) => {\n const parsed = validateProjectsAddPayload(msg.payload);\n if (!parsed.ok) {\n send(ws, {\n type: 'projects.added',\n payload: { name: '', root: '', slug: '', message: parsed.message },\n });\n return;\n }\n const { root: addRoot, name: displayName } = parsed.value;\n try {\n const resolved = path.resolve(addRoot);\n await fs.access(resolved);\n const stat = await fs.stat(resolved);\n if (!stat.isDirectory()) throw new Error(`Not a directory: ${resolved}`);\n\n const manifest = await loadManifest(ctx.globalConfigPath);\n const existing = manifest.projects.find((p) => p.root === resolved);\n if (existing) {\n send(ws, {\n type: 'projects.added',\n payload: {\n name: existing.name,\n root: existing.root,\n slug: existing.slug,\n message: `Already registered as \"${existing.name}\"`,\n },\n });\n return;\n }\n\n const name = displayName?.trim() || path.basename(resolved);\n const slug = generateProjectSlug(resolved);\n await ensureProjectDataDir(slug, ctx.globalConfigPath);\n const now = new Date().toISOString();\n manifest.projects.push({ name, root: resolved, slug, lastSeen: now, createdAt: now });\n await saveManifest(manifest, ctx.globalConfigPath);\n\n send(ws, {\n type: 'projects.added',\n payload: { name, root: resolved, slug, message: `Registered project \"${name}\"` },\n });\n } catch (err) {\n send(ws, {\n type: 'projects.added',\n payload: { name: path.basename(addRoot), root: addRoot, slug: '', message: errMessage(err) },\n });\n }\n },\n selectProject: async (ws, msg) => {\n const parsed = validateProjectsSelectPayload(msg.payload);\n if (!parsed.ok) {\n send(ws, {\n type: 'projects.selected',\n payload: { root: '', name: '', message: parsed.message },\n });\n return;\n }\n const { root: selRoot, name: selName } = parsed.value;\n try {\n const resolved = path.resolve(selRoot);\n\n try {\n await fs.access(resolved);\n const stat = await fs.stat(resolved);\n if (!stat.isDirectory()) throw new Error(`Not a directory: ${resolved}`);\n } catch (err) {\n send(ws, {\n type: 'projects.selected',\n payload: {\n root: selRoot,\n name: selName || path.basename(selRoot),\n message: `Cannot switch: ${errMessage(err)}`,\n },\n });\n return;\n }\n\n const manifest = await loadManifest(ctx.globalConfigPath);\n const entry = manifest.projects.find((p) => p.root === resolved);\n if (entry) {\n entry.lastSeen = new Date().toISOString();\n entry.lastWorkingDir = resolved;\n } else {\n const name = selName?.trim() || path.basename(resolved);\n const slug = generateProjectSlug(resolved);\n manifest.projects.push({\n name,\n root: resolved,\n slug,\n lastSeen: new Date().toISOString(),\n createdAt: new Date().toISOString(),\n lastWorkingDir: resolved,\n });\n await ensureProjectDataDir(slug, ctx.globalConfigPath);\n }\n await saveManifest(manifest, ctx.globalConfigPath);\n\n ctx.abortRunLock();\n\n ctx.setProjectRoot(resolved);\n ctx.setWorkingDir(resolved);\n ctx.context.cwd = resolved;\n ctx.context.projectRoot = resolved;\n\n const switchSlug = entry?.slug ?? generateProjectSlug(resolved);\n\n try {\n const modeId = ctx.getModeId();\n const switchMode = modeId === 'default' ? undefined : await ctx.modeStore.getMode(modeId);\n const switchPaths = resolveWstackPaths({\n projectRoot: resolved,\n globalRoot: ctx.wpaths.globalRoot,\n });\n const switchBuilder = new DefaultSystemPromptBuilder({\n memoryStore: ctx.memoryStore,\n skillLoader: ctx.skillLoader,\n modeStore: ctx.modeStore,\n modeId,\n modePrompt: switchMode?.prompt ?? '',\n modelCapabilities: ctx.modelCapabilities,\n instructionPaths: {\n globalDir: switchPaths.globalInstructions,\n projectDir: switchPaths.inProjectInstructions,\n },\n });\n ctx.context.systemPrompt = await switchBuilder.build({\n cwd: resolved,\n projectRoot: resolved,\n tools: ctx.toolRegistry.list(),\n provider: ctx.config.provider,\n model: ctx.config.model,\n });\n } catch {\n /* best-effort */\n }\n\n const newSessionsDir = path.join(\n path.dirname(ctx.globalConfigPath),\n 'projects',\n switchSlug,\n 'sessions',\n );\n await fs.mkdir(newSessionsDir, { recursive: true });\n const newSessionStore = new DefaultSessionStore({ dir: newSessionsDir });\n\n const oldSession = ctx.getSession();\n const oldSessionId = oldSession.id;\n try {\n await oldSession.append({\n type: 'session_end',\n ts: new Date().toISOString(),\n usage: ctx.tokenCounter.total(),\n });\n await oldSession.close();\n } catch {\n // best-effort\n }\n\n ctx.setSessionStore(newSessionStore);\n const newSession = await newSessionStore.create({\n id: '',\n title: '',\n model: ctx.config.model,\n provider: ctx.config.provider,\n });\n ctx.setSession(newSession);\n ctx.context.session = newSession;\n ctx.context.state.replaceMessages([]);\n ctx.context.state.replaceTodos([]);\n ctx.context.readFiles.clear();\n ctx.context.fileMtimes.clear();\n ctx.tokenCounter.reset();\n ctx.setSessionStartedAt(Date.now());\n\n try {\n const registry = getSessionRegistry(ctx.wpaths.globalRoot);\n await registry.register({\n sessionId: newSession.id,\n projectSlug: switchSlug,\n projectRoot: resolved,\n projectName: path.basename(resolved),\n workingDir: resolved,\n clientType: 'webui',\n pid: process.pid,\n startedAt: new Date().toISOString(),\n });\n } catch {\n /* best-effort */\n }\n\n send(ws, {\n type: 'projects.selected',\n payload: {\n root: resolved,\n name: selName || path.basename(resolved),\n message: `Switched to ${selName || path.basename(resolved)}`,\n },\n });\n\n broadcast(ctx.clients, {\n type: 'subagent.event',\n payload: { kind: 'session_stopped', sessionId: oldSessionId },\n });\n\n broadcast(ctx.clients, {\n type: 'session.start',\n payload: {\n ...(await ctx.sessionStartPayload()),\n reset: true,\n clearedSessionId: oldSessionId,\n },\n });\n } catch (err) {\n send(ws, {\n type: 'projects.selected',\n payload: {\n root: selRoot,\n name: selName || path.basename(selRoot),\n message: errMessage(err),\n },\n });\n }\n },\n setWorkingDir: async (ws, msg) => {\n const parsed = validateWorkingDirSetPayload(msg.payload);\n if (!parsed.ok) {\n sendResult(ws, false, parsed.message);\n return;\n }\n const { path: newPath } = parsed.value;\n try {\n const projectRoot = ctx.getProjectRoot();\n const resolved = await resolveWorkingDirInsideProject(projectRoot, newPath);\n\n ctx.setWorkingDir(resolved);\n ctx.context.cwd = resolved;\n\n broadcast(ctx.clients, {\n type: 'working_dir.changed',\n payload: { cwd: resolved, projectRoot },\n });\n\n sendResult(ws, true, `Working directory set to ${resolved}`);\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n },\n };\n}\n","/**\n * Session route handlers — extracted from the startWebUI closure in index.ts.\n * The largest builder: session lifecycle (new/clear/resume/save), context ops\n * (debug/compact/repair), context-mode CRUD, and checkpoint list/rewind.\n *\n * Mirrors createProviderHandlers/createModeHandlers/createProjectHandlers. The\n * mutable startWebUI bindings the handlers touch (`session`, `sessionStartedAt`,\n * and the project-switch-mutable `sessionStore`/`projectRoot`) are threaded in\n * as getters/setters so this stays a pure function of its context. Handler\n * bodies are a verbatim lift — only dependency references changed.\n */\nimport * as path from 'node:path';\nimport type { WebSocket } from 'ws';\nimport {\n type Context,\n DEFAULT_CONTEXT_WINDOW_MODE_ID,\n type DefaultTokenCounter,\n type SessionStore,\n type ToolRegistry,\n type createStrategyCompactor,\n repairToolUseAdjacency,\n resolveContextWindowPolicy,\n} from '@wrongstack/core';\nimport type { ConnectedClient } from './types.js';\nimport type { SessionRouteHandlers } from './session-routes.js';\nimport type { CustomModeStore } from './custom-context-modes.js';\nimport { broadcast, errMessage, send, sendResult } from './ws-utils.js';\nimport { estimateContextBreakdown } from './token-estimator.js';\nimport {\n validateContextModeCreatePayload,\n validateContextModeDeletePayload,\n validateContextModeSwitchPayload,\n validateContextModeUpdatePayload,\n} from './ws-payload-validation.js';\n\ntype Session = Awaited<ReturnType<SessionStore['create']>>;\ntype SessionStartPayload = {\n sessionId: string;\n model: string;\n provider: string;\n maxContext: number;\n inputCost: number;\n outputCost: number;\n cacheReadCost: number;\n projectName: string;\n projectRoot: string;\n cwd: string;\n mode: string;\n contextMode: string;\n};\n\nexport interface SessionHandlersContext {\n config: { provider: string; model: string };\n clients: Map<WebSocket, ConnectedClient>;\n context: Context;\n toolRegistry: ToolRegistry;\n compactor: ReturnType<typeof createStrategyCompactor>;\n customModeStore: CustomModeStore;\n tokenCounter: DefaultTokenCounter;\n /** Live reads of the mutable startWebUI bindings. */\n getProjectRoot: () => string;\n getSession: () => Session;\n getSessionStore: () => SessionStore;\n /** Mutations of the startWebUI bindings. */\n setSession: (s: Session) => void;\n setSessionStartedAt: (t: number) => void;\n sessionStartPayload: () => Promise<SessionStartPayload>;\n}\n\nexport function createSessionHandlers(ctx: SessionHandlersContext): SessionRouteHandlers {\n return {\n newSession: async () => {\n const session = ctx.getSession();\n try {\n await session.append({\n type: 'session_end',\n ts: new Date().toISOString(),\n usage: ctx.tokenCounter.total(),\n });\n await session.close();\n } catch {\n // best-effort\n }\n const next = await ctx.getSessionStore().create({\n id: '',\n title: '',\n model: ctx.config.model,\n provider: ctx.config.provider,\n });\n ctx.setSession(next);\n ctx.context.session = next;\n ctx.context.state.replaceMessages([]);\n ctx.context.state.replaceTodos([]);\n ctx.context.readFiles.clear();\n ctx.context.fileMtimes.clear();\n ctx.tokenCounter.reset();\n ctx.setSessionStartedAt(Date.now());\n broadcast(ctx.clients, { type: 'session.start', payload: await ctx.sessionStartPayload() });\n },\n clearContext: async (ws) => {\n ctx.context.state.replaceMessages([]);\n ctx.context.state.replaceTodos([]);\n ctx.context.readFiles.clear();\n ctx.context.fileMtimes.clear();\n ctx.tokenCounter.reset();\n sendResult(ws, true, 'Context cleared');\n broadcast(ctx.clients, {\n type: 'session.start',\n payload: { ...(await ctx.sessionStartPayload()), reset: true },\n });\n },\n debugContext: async (ws) => {\n const breakdown = estimateContextBreakdown({\n systemPrompt: ctx.context.systemPrompt,\n tools: ctx.toolRegistry.list(),\n messages: ctx.context.messages,\n });\n send(ws, {\n type: 'context.debug',\n payload: {\n ...breakdown,\n mode: ctx.context.meta['contextWindowMode'] ?? DEFAULT_CONTEXT_WINDOW_MODE_ID,\n policy: ctx.context.meta['contextWindowPolicy'],\n },\n });\n },\n compactContext: async (ws, msg) => {\n const aggressive = !!(msg as { payload?: { aggressive?: boolean | undefined } }).payload?.aggressive;\n try {\n const report = await ctx.compactor.compact(ctx.context, { aggressive });\n send(ws, {\n type: 'context.compacted',\n payload: {\n before: report.before,\n after: report.after,\n saved: Math.max(0, report.before - report.after),\n reductions: report.reductions,\n repaired: report.repaired,\n },\n });\n sendResult(\n ws,\n true,\n `Compacted: ${report.before} → ${report.after} tokens (saved ~${Math.max(0, report.before - report.after)})`,\n );\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n },\n repairContext: async (ws) => {\n const beforeMessages = ctx.context.messages.length;\n const repaired = repairToolUseAdjacency(ctx.context.messages);\n if (repaired.report.changed) {\n ctx.context.state.replaceMessages(repaired.messages);\n }\n const payload = {\n removedToolUses: repaired.report.removedToolUses,\n removedToolResults: repaired.report.removedToolResults,\n removedMessages: repaired.report.removedMessages,\n beforeMessages,\n afterMessages: ctx.context.messages.length,\n };\n broadcast(ctx.clients, { type: 'context.repaired', payload });\n const removed =\n payload.removedToolUses.length + payload.removedToolResults.length + payload.removedMessages;\n sendResult(\n ws,\n true,\n removed > 0\n ? `Context repaired: removed ${removed} orphan protocol item(s)`\n : 'Context repair found no orphan protocol blocks',\n );\n },\n listContextModes: async (ws) => {\n const active = String(ctx.context.meta['contextWindowMode'] ?? DEFAULT_CONTEXT_WINDOW_MODE_ID);\n const allModes = ctx.customModeStore.list().map((m) => ({\n id: m.id,\n name: m.name,\n description: m.description,\n isActive: m.id === active,\n thresholds: m.thresholds,\n preserveK: m.preserveK,\n eliseThreshold: m.eliseThreshold,\n custom: (m as { custom?: boolean }).custom === true,\n }));\n send(ws, { type: 'context.modes.list', payload: { activeId: active, modes: allModes } });\n },\n switchContextMode: async (ws, msg) => {\n const parsed = validateContextModeSwitchPayload(msg.payload);\n if (!parsed.ok) {\n sendResult(ws, false, parsed.message);\n return;\n }\n const { id } = parsed.value;\n let policy = resolveContextWindowPolicy({}, id);\n if (policy.id !== id) {\n const customModes = ctx.customModeStore.list().filter((m) => (m as { custom?: boolean }).custom === true);\n const custom = customModes.find((m) => m.id === id);\n if (!custom) {\n sendResult(ws, false, `Unknown context mode \"${id}\"`);\n return;\n }\n policy = custom as never as typeof policy;\n }\n ctx.context.meta['contextWindowMode'] = policy.id;\n ctx.context.meta['contextWindowPolicy'] = policy;\n sendResult(ws, true, `Context mode switched to ${policy.id}`);\n broadcast(ctx.clients, {\n type: 'context.mode.changed',\n payload: { id: policy.id, name: policy.name, policy },\n });\n },\n createContextMode: async (ws, msg) => {\n const parsed = validateContextModeCreatePayload(msg.payload);\n if (!parsed.ok) {\n sendResult(ws, false, parsed.message);\n return;\n }\n const payload = parsed.value;\n const result = ctx.customModeStore.create({\n id: payload.id,\n name: payload.name,\n description: payload.description,\n thresholds: payload.thresholds,\n preserveK: payload.preserveK,\n eliseThreshold: payload.eliseThreshold,\n custom: true,\n aggressiveOn: 'soft',\n targetLoad: 0.65,\n });\n sendResult(ws, result.ok, result.error ?? `Mode \"${payload.id}\" created`);\n },\n updateContextMode: async (ws, msg) => {\n const parsed = validateContextModeUpdatePayload(msg.payload);\n if (!parsed.ok) {\n sendResult(ws, false, parsed.message);\n return;\n }\n const payload = parsed.value;\n const result = ctx.customModeStore.update(payload.id, {\n name: payload.name,\n description: payload.description,\n thresholds: payload.thresholds\n ? {\n warn: payload.thresholds.warn ?? 0.6,\n soft: payload.thresholds.soft ?? 0.75,\n hard: payload.thresholds.hard ?? 0.9,\n }\n : undefined,\n preserveK: payload.preserveK,\n eliseThreshold: payload.eliseThreshold,\n });\n sendResult(ws, result.ok, result.error ?? `Mode \"${payload.id}\" updated`);\n },\n deleteContextMode: async (ws, msg) => {\n const parsed = validateContextModeDeletePayload(msg.payload);\n if (!parsed.ok) {\n sendResult(ws, false, parsed.message);\n return;\n }\n const { id } = parsed.value;\n if (String(ctx.context.meta['contextWindowMode'] ?? '') === id) {\n ctx.context.meta['contextWindowMode'] = DEFAULT_CONTEXT_WINDOW_MODE_ID;\n ctx.context.meta['contextWindowPolicy'] = resolveContextWindowPolicy({}, DEFAULT_CONTEXT_WINDOW_MODE_ID);\n }\n const result = ctx.customModeStore.remove(id);\n sendResult(ws, result.ok, result.error ?? `Mode \"${id}\" deleted`);\n },\n listSessions: async (ws, msg) => {\n const limit = (msg as { payload?: { limit?: number | undefined } }).payload?.limit ?? 50;\n try {\n const list = await ctx.getSessionStore().list(limit);\n const currentId = ctx.getSession().id;\n send(ws, {\n type: 'sessions.list',\n payload: {\n sessions: list.map((s) => ({\n id: s.id,\n title: s.title,\n startedAt: s.startedAt,\n model: s.model,\n provider: s.provider,\n tokenTotal: s.tokenTotal,\n isCurrent: s.id === currentId,\n })),\n },\n });\n } catch (err) {\n send(ws, { type: 'sessions.list', payload: { sessions: [], error: errMessage(err) } });\n }\n },\n deleteSession: async (ws, msg) => {\n const { id } = (msg as { payload: { id: string } }).payload;\n try {\n if (id === ctx.getSession().id) {\n sendResult(ws, false, 'Cannot delete the active session');\n return;\n }\n await ctx.getSessionStore().delete(id);\n sendResult(ws, true, `Session ${id} deleted`);\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n },\n resumeSession: async (ws, msg) => {\n const { id } = (msg as { payload: { id: string } }).payload;\n try {\n const current = ctx.getSession();\n if (id === current.id) {\n sendResult(ws, false, 'Session is already active');\n return;\n }\n const resumed = await ctx.getSessionStore().resume(id);\n try {\n await current.append({\n type: 'session_end',\n ts: new Date().toISOString(),\n usage: ctx.tokenCounter.total(),\n });\n await current.close();\n } catch {\n /* noop */\n }\n ctx.setSession(resumed.writer);\n ctx.context.session = resumed.writer;\n ctx.context.state.replaceMessages(resumed.data.messages);\n ctx.context.readFiles.clear();\n ctx.context.fileMtimes.clear();\n ctx.tokenCounter.reset();\n ctx.tokenCounter.account(resumed.data.usage, ctx.config.model);\n ctx.setSessionStartedAt(Date.now());\n broadcast(ctx.clients, {\n type: 'session.start',\n payload: {\n ...(await ctx.sessionStartPayload()),\n reset: true,\n replayMessages: resumed.data.messages,\n replayUsage: resumed.data.usage,\n },\n });\n sendResult(ws, true, `Resumed session ${id}`);\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n },\n saveSession: async (ws) => {\n sendResult(ws, true, `Session ${ctx.getSession().id} is auto-saved`);\n },\n listCheckpoints: async (ws) => {\n try {\n const { DefaultSessionRewinder } = await import('@wrongstack/core');\n const projectRoot = ctx.getProjectRoot();\n const rewinder = new DefaultSessionRewinder(\n path.join(projectRoot, '.wrongstack', 'sessions'),\n projectRoot,\n );\n const checkpoints = await rewinder.listCheckpoints(ctx.getSession().id);\n send(ws, { type: 'session.checkpoints', payload: { checkpoints } });\n } catch {\n send(ws, { type: 'session.checkpoints', payload: { checkpoints: [] } });\n }\n },\n rewindSession: async (ws, msg) => {\n const { checkpointIndex } = (msg as { payload: { checkpointIndex: number } }).payload;\n try {\n const { DefaultSessionRewinder } = await import('@wrongstack/core');\n const projectRoot = ctx.getProjectRoot();\n const rewinder = new DefaultSessionRewinder(\n path.join(projectRoot, '.wrongstack', 'sessions'),\n projectRoot,\n );\n await rewinder.rewindToCheckpoint(ctx.getSession().id, checkpointIndex);\n await ctx.context.session.truncateToCheckpoint(checkpointIndex);\n sendResult(ws, true, `Rewound to checkpoint ${checkpointIndex}`);\n broadcast(ctx.clients, {\n type: 'session.start',\n payload: { ...(await ctx.sessionStartPayload()), reset: true },\n });\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n },\n };\n}\n","/**\n * Per-section context-window token estimate for the `context.debug` command.\n *\n * Uses the simple 4-chars-per-token heuristic — not exact, but close enough to\n * spot which section (system prompt, tool schemas, or message history) is\n * eating the context window. Tool schemas in particular are easy to overlook:\n * each tool ships its full JSON schema to the model every turn, so 20+ builtins\n * can cost 10-20k tokens on their own.\n *\n * Extracted from `index.ts` as a pure function so the breakdown maths can be\n * unit tested without standing up a Context/ToolRegistry.\n */\n\n/** 4-chars-per-token heuristic estimate for a string. */\nexport function estimateTokens(s: string): number {\n return Math.ceil(s.length / 4);\n}\n\n/** Stringify arbitrary content for length estimation (JSON, with fallbacks). */\nexport function stringifyContent(c: unknown): string {\n if (typeof c === 'string') return c;\n try {\n return JSON.stringify(c);\n } catch {\n return String(c);\n }\n}\n\ninterface PromptBlock {\n text?: string | undefined;\n}\ninterface ToolLike {\n name: string;\n inputSchema?: unknown | undefined;\n description?: string | undefined;\n}\ninterface ContentBlock {\n type?: string | undefined;\n text?: string | undefined;\n input?: unknown | undefined;\n content?: unknown | undefined;\n name?: string | undefined;\n}\ninterface MessageLike {\n role: string;\n content: unknown;\n}\n\nexport interface ToolTokenEntry {\n name: string;\n tokens: number;\n}\nexport interface MessageTokenEntry {\n index: number;\n role: string;\n tokens: number;\n preview: string;\n}\n\nexport interface ContextBreakdown {\n total: number;\n systemPrompt: number;\n tools: { total: number; count: number; breakdown: ToolTokenEntry[] };\n messages: { total: number; count: number; breakdown: MessageTokenEntry[] };\n}\n\nexport function messageTokens(content: unknown): number {\n if (typeof content === 'string') return estimateTokens(content);\n if (!Array.isArray(content)) return 0;\n let tk = 0;\n for (const b of content as ContentBlock[]) {\n if (b.type === 'text') tk += estimateTokens(b.text ?? '');\n else if (b.type === 'tool_use') tk += estimateTokens(stringifyContent(b.input));\n else if (b.type === 'tool_result') tk += estimateTokens(stringifyContent(b.content));\n else tk += estimateTokens(stringifyContent(b));\n }\n return tk;\n}\n\nexport function messagePreview(content: unknown): string {\n if (typeof content === 'string') return content.slice(0, 60);\n if (!Array.isArray(content)) return '';\n return (content as ContentBlock[])\n .map((b) =>\n b.type === 'text'\n ? (b.text ?? '').slice(0, 40)\n : b.type === 'tool_use'\n ? `[tool_use: ${b.name}]`\n : b.type === 'tool_result'\n ? '[tool_result]'\n : `[${b.type}]`,\n )\n .join(' ')\n .slice(0, 60);\n}\n\n/**\n * Compute the per-section token breakdown for the active context. Mirrors the\n * shape the `context.debug` WS reply expects (minus the `mode`/`policy` fields,\n * which the caller layers on from `context.meta`).\n */\nexport function estimateContextBreakdown(input: {\n systemPrompt: ReadonlyArray<PromptBlock>;\n tools: ReadonlyArray<ToolLike>;\n messages: ReadonlyArray<MessageLike>;\n}): ContextBreakdown {\n const sysTokens = input.systemPrompt.reduce((acc, b) => acc + estimateTokens(b.text ?? ''), 0);\n\n const toolBreakdown: ToolTokenEntry[] = input.tools.map((t) => {\n const schema = t.inputSchema ?? {};\n const desc = t.description ?? '';\n return {\n name: t.name,\n tokens:\n estimateTokens(t.name) + estimateTokens(desc) + estimateTokens(stringifyContent(schema)),\n };\n });\n const toolTokens = toolBreakdown.reduce((a, b) => a + b.tokens, 0);\n\n const messageBreakdown: MessageTokenEntry[] = input.messages.map((m, i) => ({\n index: i,\n role: m.role,\n tokens: messageTokens(m.content),\n preview: messagePreview(m.content),\n }));\n const msgTokens = messageBreakdown.reduce((a, b) => a + b.tokens, 0);\n\n return {\n total: sysTokens + toolTokens + msgTokens,\n systemPrompt: sysTokens,\n tools: { total: toolTokens, count: input.tools.length, breakdown: toolBreakdown },\n messages: { total: msgTokens, count: input.messages.length, breakdown: messageBreakdown },\n };\n}\n","import type { WebSocket } from 'ws';\nimport type { createProviderHandlers } from './provider-handlers.js';\nimport type { WSClientMessage } from './types.js';\nimport { sendResult } from './ws-utils.js';\n\nexport interface ProviderRouteHandlers {\n listProviders: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n listSavedProviders: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n listProviderModels: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n switchModel: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n refineModel: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n providerHandlers: ReturnType<typeof createProviderHandlers>;\n}\n\nfunction asPayloadRecord(msg: WSClientMessage): Record<string, unknown> | null {\n const payload = msg.payload;\n return typeof payload === 'object' && payload !== null && !Array.isArray(payload)\n ? (payload as Record<string, unknown>)\n : null;\n}\n\nfunction requiredString(payload: Record<string, unknown>, key: string): string | null {\n const value = payload[key];\n return typeof value === 'string' && value.trim().length > 0 ? value : null;\n}\n\nfunction optionalNumber(payload: Record<string, unknown>, key: string): number | undefined | null {\n const value = payload[key];\n if (value === undefined) return undefined;\n return typeof value === 'number' && Number.isFinite(value) ? value : null;\n}\n\nfunction optionalStringArray(payload: Record<string, unknown>, key: string): string[] | undefined | null {\n const value = payload[key];\n if (value === undefined) return undefined;\n return Array.isArray(value) && value.every((item) => typeof item === 'string') ? value : null;\n}\n\nfunction invalidPayload(ws: WebSocket, type: string): true {\n sendResult(ws, false, `${type} payload is invalid`);\n return true;\n}\n\nexport async function handleProviderRoute(\n ws: WebSocket,\n msg: WSClientMessage,\n routes: ProviderRouteHandlers,\n): Promise<boolean> {\n switch (msg.type) {\n case 'providers.list':\n await routes.listProviders(ws, msg);\n return true;\n case 'providers.saved':\n await routes.listSavedProviders(ws, msg);\n return true;\n case 'provider.models':\n await routes.listProviderModels(ws, msg);\n return true;\n case 'model.switch':\n await routes.switchModel(ws, msg);\n return true;\n case 'model.refine':\n await routes.refineModel(ws, msg);\n return true;\n\n case 'key.add':\n case 'key.update': {\n const payload = asPayloadRecord(msg);\n const providerId = payload ? requiredString(payload, 'providerId') : null;\n const label = payload ? requiredString(payload, 'label') : null;\n const apiKey = payload ? requiredString(payload, 'apiKey') : null;\n if (!providerId || !label || !apiKey) return invalidPayload(ws, msg.type);\n await routes.providerHandlers.handleKeyUpsert(ws, providerId, label, apiKey);\n return true;\n }\n\n case 'key.delete': {\n const payload = asPayloadRecord(msg);\n const providerId = payload ? requiredString(payload, 'providerId') : null;\n const label = payload ? requiredString(payload, 'label') : null;\n if (!providerId || !label) return invalidPayload(ws, msg.type);\n await routes.providerHandlers.handleKeyDelete(ws, providerId, label);\n return true;\n }\n\n case 'key.set_active': {\n const payload = asPayloadRecord(msg);\n const providerId = payload ? requiredString(payload, 'providerId') : null;\n const label = payload ? requiredString(payload, 'label') : null;\n if (!providerId || !label) return invalidPayload(ws, msg.type);\n await routes.providerHandlers.handleKeySetActive(ws, providerId, label);\n return true;\n }\n\n case 'provider.add': {\n const payload = asPayloadRecord(msg);\n const id = payload ? requiredString(payload, 'id') : null;\n const family = payload ? requiredString(payload, 'family') : null;\n const baseUrl = payload?.['baseUrl'];\n const apiKey = payload?.['apiKey'];\n if (!id || !family) return invalidPayload(ws, msg.type);\n if (baseUrl !== undefined && typeof baseUrl !== 'string') return invalidPayload(ws, msg.type);\n if (apiKey !== undefined && typeof apiKey !== 'string') return invalidPayload(ws, msg.type);\n await routes.providerHandlers.handleProviderAdd(ws, {\n id,\n family,\n baseUrl: baseUrl as string | undefined,\n apiKey: apiKey as string | undefined,\n });\n return true;\n }\n\n case 'provider.remove': {\n const payload = asPayloadRecord(msg);\n const providerId = payload ? requiredString(payload, 'providerId') : null;\n if (!providerId) return invalidPayload(ws, msg.type);\n await routes.providerHandlers.handleProviderRemove(ws, providerId);\n return true;\n }\n\n case 'provider.clear_models': {\n const payload = asPayloadRecord(msg);\n const providerId = payload ? requiredString(payload, 'providerId') : null;\n if (!providerId) return invalidPayload(ws, msg.type);\n await routes.providerHandlers.handleProviderClearModels(ws, providerId);\n return true;\n }\n\n case 'provider.undo_clear': {\n const payload = asPayloadRecord(msg);\n const providerId = payload ? requiredString(payload, 'providerId') : null;\n const previousModels = payload ? optionalStringArray(payload, 'previousModels') : null;\n if (!providerId || !previousModels) return invalidPayload(ws, msg.type);\n await routes.providerHandlers.handleProviderUndoClear(ws, providerId, previousModels);\n return true;\n }\n\n case 'provider.update': {\n const payload = asPayloadRecord(msg);\n const id = payload ? requiredString(payload, 'id') : null;\n const envVars = payload ? optionalStringArray(payload, 'envVars') : null;\n const models = payload ? optionalStringArray(payload, 'models') : null;\n if (!payload || !id || envVars === null || models === null) return invalidPayload(ws, msg.type);\n for (const key of ['family', 'baseUrl'] as const) {\n if (payload[key] !== undefined && typeof payload[key] !== 'string') return invalidPayload(ws, msg.type);\n }\n await routes.providerHandlers.handleProviderUpdate(ws, {\n id,\n family: payload['family'] as string | undefined,\n baseUrl: payload['baseUrl'] as string | undefined,\n envVars,\n models,\n });\n return true;\n }\n\n case 'provider.probe': {\n const payload = asPayloadRecord(msg);\n const providerId = payload ? requiredString(payload, 'providerId') : null;\n const timeoutMs = payload ? optionalNumber(payload, 'timeoutMs') : null;\n if (!providerId || timeoutMs === null) return invalidPayload(ws, msg.type);\n await routes.providerHandlers.handleProviderProbe(ws, providerId, timeoutMs);\n return true;\n }\n\n default:\n return false;\n }\n}\n","import type { WebSocket } from 'ws';\nimport type { WSClientMessage } from './types.js';\n\nexport interface SessionRouteHandlers {\n newSession: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n clearContext: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n debugContext: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n compactContext: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n repairContext: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n listContextModes: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n switchContextMode: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n createContextMode: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n updateContextMode: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n deleteContextMode: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n listSessions: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n deleteSession: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n resumeSession: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n saveSession: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n listCheckpoints: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n rewindSession: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n}\n\nexport async function handleSessionRoute(\n ws: WebSocket,\n msg: WSClientMessage,\n handlers: SessionRouteHandlers,\n): Promise<boolean> {\n switch (msg.type) {\n case 'session.new':\n await handlers.newSession(ws, msg);\n return true;\n case 'context.clear':\n await handlers.clearContext(ws, msg);\n return true;\n case 'context.debug':\n await handlers.debugContext(ws, msg);\n return true;\n case 'context.compact':\n await handlers.compactContext(ws, msg);\n return true;\n case 'context.repair':\n await handlers.repairContext(ws, msg);\n return true;\n case 'context.modes.list':\n await handlers.listContextModes(ws, msg);\n return true;\n case 'context.mode.switch':\n await handlers.switchContextMode(ws, msg);\n return true;\n case 'context.mode.create':\n await handlers.createContextMode(ws, msg);\n return true;\n case 'context.mode.update':\n await handlers.updateContextMode(ws, msg);\n return true;\n case 'context.mode.delete':\n await handlers.deleteContextMode(ws, msg);\n return true;\n case 'sessions.list':\n await handlers.listSessions(ws, msg);\n return true;\n case 'session.delete':\n await handlers.deleteSession(ws, msg);\n return true;\n case 'session.resume':\n await handlers.resumeSession(ws, msg);\n return true;\n case 'session.save':\n await handlers.saveSession(ws, msg);\n return true;\n case 'session.checkpoints':\n await handlers.listCheckpoints(ws, msg);\n return true;\n case 'session.rewind':\n await handlers.rewindSession(ws, msg);\n return true;\n default:\n return false;\n }\n}\n","import type { WebSocket } from 'ws';\nimport type { WSClientMessage } from './types.js';\n\nexport interface ProjectRouteHandlers {\n listProjects: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n addProject: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n selectProject: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n setWorkingDir: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n}\n\nexport async function handleProjectRoute(\n ws: WebSocket,\n msg: WSClientMessage,\n handlers: ProjectRouteHandlers,\n): Promise<boolean> {\n switch (msg.type) {\n case 'projects.list':\n await handlers.listProjects(ws, msg);\n return true;\n case 'projects.add':\n await handlers.addProject(ws, msg);\n return true;\n case 'projects.select':\n await handlers.selectProject(ws, msg);\n return true;\n case 'working_dir.set':\n await handlers.setWorkingDir(ws, msg);\n return true;\n default:\n return false;\n }\n}\n","import type { WebSocket } from 'ws';\nimport type { WSClientMessage } from './types.js';\n\nexport interface ModeRouteHandlers {\n listModes: (ws: WebSocket) => Promise<void>;\n switchMode: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n}\n\nexport async function handleModeRoute(\n ws: WebSocket,\n msg: WSClientMessage,\n handlers: ModeRouteHandlers,\n): Promise<boolean> {\n switch (msg.type) {\n case 'modes.list':\n await handlers.listModes(ws);\n return true;\n case 'mode.switch':\n await handlers.switchMode(ws, msg);\n return true;\n default:\n return false;\n }\n}\n","// Prefs WS-message routing — extracted from packages/webui/src/server/index.ts\n// (issue #31, follow-on to PRs #94–#110). The standalone server owns a richer\n// pref surface than the CLI's embedded ws-handlers/prefs.ts (which only knows\n// about YOLO/autonomy), so this module is a thin dispatch layer — the actual\n// logic stays in the index.ts closures (getPrefs/updatePrefs) that close over\n// the live boot context (config, context.meta, permissionPolicy, pipelines,\n// autoCompactor, logger). Mirrors the shape of the 11 sibling route handlers\n// already wired through `handleMessage`.\n//\n// Why callback injection (not the CLI's context-object style): the standalone\n// server has ~10 closure-captured dependencies the prefs handler reads (config\n// for feature-flag mutation, pipelines for AutoCompaction add/remove, logger\n// for runtime level, etc.) — bundling them into a PrefsContext interface\n// would duplicate state already living on index.ts. Two callbacks (one per\n// message type) keeps the contract minimal and avoids drift if any new\n// closure dependency is added.\n\nimport type { WebSocket } from 'ws';\nimport type { WSClientMessage } from './types.js';\n\nexport interface PrefsRouteHandlers {\n /** Respond to the WS client with the current pref snapshot. */\n getPrefs: (ws: WebSocket) => Promise<void>;\n /**\n * Merge the supplied pref payload into context.meta, persist the durable\n * keys to config.json, apply any runtime effects (YOLO toggle, feature-flag\n * mutation, fallback chain update, AutoCompaction pipeline add/remove,\n * logger.level), then broadcast the full current snapshot to all clients.\n */\n updatePrefs: (ws: WebSocket, payload: Record<string, unknown>) => Promise<void>;\n}\n\n/**\n * Chain-of-responsibility dispatcher for the `prefs.*` WS message family.\n * Returns `true` if the message was handled by this layer (so the caller's\n * chain short-circuits), `false` if it should fall through to the next layer\n * or the residual switch.\n *\n * Owned prefixes:\n * - `prefs.get`\n * - `prefs.update`\n *\n * Regression-tested by packages/webui/tests/server/dispatcher-routing.test.ts.\n */\nexport async function handlePrefsRoute(\n ws: WebSocket,\n msg: WSClientMessage,\n handlers: PrefsRouteHandlers,\n): Promise<boolean> {\n switch (msg.type) {\n case 'prefs.get': {\n await handlers.getPrefs(ws);\n return true;\n }\n case 'prefs.update': {\n await handlers.updatePrefs(ws, (msg.payload ?? {}) as Record<string, unknown>);\n return true;\n }\n default:\n return false;\n }\n}\n","import type { WebSocket } from 'ws';\nimport type { WSClientMessage } from './types.js';\n\nexport interface ShellGitRouteHandlers {\n gitInfo: (ws: WebSocket) => Promise<void>;\n gitChanges: (ws: WebSocket) => Promise<void>;\n gitDiff: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n shellOpen: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n}\n\nexport async function handleShellGitRoute(\n ws: WebSocket,\n msg: WSClientMessage,\n handlers: ShellGitRouteHandlers,\n): Promise<boolean> {\n switch (msg.type) {\n case 'git.info':\n await handlers.gitInfo(ws);\n return true;\n case 'git.changes':\n await handlers.gitChanges(ws);\n return true;\n case 'git.diff':\n await handlers.gitDiff(ws, msg);\n return true;\n case 'shell.open':\n await handlers.shellOpen(ws, msg);\n return true;\n default:\n return false;\n }\n}\n","import type { WebSocket } from 'ws';\nimport type { WSClientMessage } from './types.js';\n\nexport interface MailboxRouteHandlers {\n messages: (ws: WebSocket, msg: WSClientMessage) => Promise<void> | void;\n agents: (ws: WebSocket, msg: WSClientMessage) => Promise<void> | void;\n clear: (ws: WebSocket, msg: WSClientMessage) => Promise<void> | void;\n purge: (ws: WebSocket, msg: WSClientMessage) => Promise<void> | void;\n}\n\nexport async function handleMailboxRoute(\n ws: WebSocket,\n msg: WSClientMessage,\n handlers: MailboxRouteHandlers,\n): Promise<boolean> {\n switch (msg.type) {\n case 'mailbox.messages':\n await handlers.messages(ws, msg);\n return true;\n case 'mailbox.agents':\n await handlers.agents(ws, msg);\n return true;\n case 'mailbox.clear':\n await handlers.clear(ws, msg);\n return true;\n case 'mailbox.purge':\n await handlers.purge(ws, msg);\n return true;\n default:\n return false;\n }\n}\n","// MCP WS-message routing — extracted from packages/webui/src/server/index.ts\n// (issue #31, follow-on to PRs #94–#110, #118, #119). The handler logic was\n// already in mcp-handlers.ts; this module is the chain-of-responsibility\n// dispatcher that mirrors the shape of the other 12 sibling route handlers\n// already wired through `handleMessage`.\n//\n// Why a thin dispatcher instead of importing handleMcpXxx directly into\n// index.ts: every other sibling uses the handleXxxRoute(ws, msg, handlers)\n// callback-injection pattern, which lets the test surface stub individual\n// callbacks (dispatcher-routing.test.ts covers 13 of these now). Bypassing\n// the pattern for MCP would mean the dispatcher-routing test for mcp.*\n// would have to spin up a real MCPRegistry — high cost for low value.\n//\n// Why 10 callbacks (one per case) instead of a McpContext interface: each\n// handleMcpXxx already takes the same (ws, msg, globalConfigPath,\n// mcpRegistry) signature. Bundling those 4 params into a single\n// McpContext object would be churn for no behavior change. The two-callback\n// (prefs) vs ten-callback (mcp) asymmetry is fine — the contract is\n// \"one callback per owned message type\", not \"smallest possible surface\".\n\nimport type { WebSocket } from 'ws';\nimport type { WSClientMessage } from './types.js';\n\nexport interface McpRouteHandlers {\n list: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n add: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n update: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n remove: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n enable: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n disable: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n sleep: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n wake: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n restart: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n discover: (ws: WebSocket, msg: WSClientMessage) => Promise<void>;\n}\n\n/**\n * Chain-of-responsibility dispatcher for the `mcp.*` WS message family.\n * Returns `true` if the message was handled by this layer (so the caller's\n * chain short-circuits), `false` if it should fall through to the next layer\n * or the residual switch.\n *\n * Owned prefixes (10 message types — full coverage of the MCP management\n * surface; the WebUI MCP panel only ever talks to the server through these):\n * - mcp.list\n * - mcp.add\n * - mcp.update\n * - mcp.remove\n * - mcp.enable\n * - mcp.disable\n * - mcp.sleep\n * - mcp.wake\n * - mcp.restart\n * - mcp.discover\n *\n * Regression-tested by packages/webui/tests/server/dispatcher-routing.test.ts.\n */\nexport async function handleMcpRoute(\n ws: WebSocket,\n msg: WSClientMessage,\n handlers: McpRouteHandlers,\n): Promise<boolean> {\n switch (msg.type) {\n case 'mcp.list':\n await handlers.list(ws, msg);\n return true;\n case 'mcp.add':\n await handlers.add(ws, msg);\n return true;\n case 'mcp.update':\n await handlers.update(ws, msg);\n return true;\n case 'mcp.remove':\n await handlers.remove(ws, msg);\n return true;\n case 'mcp.enable':\n await handlers.enable(ws, msg);\n return true;\n case 'mcp.disable':\n await handlers.disable(ws, msg);\n return true;\n case 'mcp.sleep':\n await handlers.sleep(ws, msg);\n return true;\n case 'mcp.wake':\n await handlers.wake(ws, msg);\n return true;\n case 'mcp.restart':\n await handlers.restart(ws, msg);\n return true;\n case 'mcp.discover':\n await handlers.discover(ws, msg);\n return true;\n default:\n return false;\n }\n}\n","import type { WebSocket } from 'ws';\nimport type { WSClientMessage } from './types.js';\n\nexport interface BrainRouteHandlers {\n status: (ws: WebSocket, msg: WSClientMessage) => Promise<void> | void;\n risk: (ws: WebSocket, msg: WSClientMessage) => Promise<void> | void;\n ask: (ws: WebSocket, msg: WSClientMessage) => Promise<void> | void;\n}\n\nexport async function handleBrainRoute(\n ws: WebSocket,\n msg: WSClientMessage,\n handlers: BrainRouteHandlers,\n): Promise<boolean> {\n switch (msg.type) {\n case 'brain.status':\n await handlers.status(ws, msg);\n return true;\n case 'brain.risk':\n await handlers.risk(ws, msg);\n return true;\n case 'brain.ask':\n await handlers.ask(ws, msg);\n return true;\n default:\n return false;\n }\n}\n","import type { WebSocket } from 'ws';\nimport type { WSClientMessage } from './types.js';\n\nexport interface AutoPhaseRouteHandlers {\n handleMessage: (msg: { type: string; payload?: Record<string, unknown> }) => Promise<void>;\n}\n\nexport async function handleAutoPhaseRoute(\n _ws: WebSocket,\n msg: WSClientMessage,\n handlers: AutoPhaseRouteHandlers,\n): Promise<boolean> {\n if (!msg.type.startsWith('autophase.')) return false;\n await handlers.handleMessage(msg as { type: string; payload?: Record<string, unknown> });\n return true;\n}\n","import type { WebSocket } from 'ws';\nimport type { WSClientMessage } from './types.js';\n\nexport interface SpecsRouteHandlers {\n handleMessage: (msg: { type: string; payload?: Record<string, unknown> }) => Promise<void>;\n}\n\n/** Forward any `specs.*` message to the SpecsWebSocketHandler. */\nexport async function handleSpecsRoute(\n _ws: WebSocket,\n msg: WSClientMessage,\n handlers: SpecsRouteHandlers,\n): Promise<boolean> {\n if (!msg.type.startsWith('specs.')) return false;\n await handlers.handleMessage(msg as { type: string; payload?: Record<string, unknown> });\n return true;\n}\n","import type { WebSocket } from 'ws';\nimport type { WSClientMessage } from './types.js';\n\nexport interface SddBoardRouteHandlers {\n handleMessage: (msg: { type: string; payload?: Record<string, unknown> }) => Promise<void>;\n}\n\n/** Forward any `sdd.board.*` message to the SddBoardWebSocketHandler. */\nexport async function handleSddBoardRoute(\n _ws: WebSocket,\n msg: WSClientMessage,\n handlers: SddBoardRouteHandlers,\n): Promise<boolean> {\n if (!msg.type.startsWith('sdd.board.')) return false;\n await handlers.handleMessage(msg as { type: string; payload?: Record<string, unknown> });\n return true;\n}\n","import type { EventBus, Context, SessionEventBridge, WstackPaths } from '@wrongstack/core';\nimport type { WebSocket } from 'ws';\nimport type { ConnectedClient, WSServerMessage } from './types.js';\n\nimport * as fs from 'node:fs/promises';\nimport { watch as fsWatch } from 'node:fs';\nimport * as path from 'node:path';\n\n/** Metrics for the file watcher that watches status.json files. */\nexport interface FileWatcherMetrics {\n fileChangesDetected: number;\n filesProcessed: number;\n broadcastsSent: number;\n debounceResets: number;\n totalDebounceDelayMs: number;\n activeProjects: number;\n /** Average debounce delay in ms across all broadcasts. */\n averageDebounceDelayMs: number;\n /** Whether the file watcher is currently active. */\n watcherActive: boolean;\n}\n\nexport interface SetupEventsDeps {\n events: EventBus;\n broadcast: (clients: Map<WebSocket, ConnectedClient>, msg: WSServerMessage) => void;\n clients: Map<WebSocket, ConnectedClient>;\n config: { tools?: { maxIterations?: number | undefined } };\n context: Context;\n pendingConfirms: Map<string, (d: 'yes' | 'no' | 'always' | 'deny') => void>;\n /** Optional global config dir (~/.wrongstack) — enables SessionRegistry poll for fleet view. */\n globalConfigPath?: string | undefined;\n /**\n * Audit-level-aware session log bridge. When provided, tool/error/provider\n * events are persisted to the session JSONL (same contract as the CLI) —\n * without it, standalone-WebUI sessions carry no audit events and resume\n * with no tool history.\n */\n sessionBridge?: SessionEventBridge | undefined;\n /** Optional wpaths for writing status.json file. */\n wpaths?: WstackPaths | undefined;\n /**\n * Optional object to populate with file watcher metrics.\n * When provided, the setupEvents function will populate this object\n * with real-time metrics from the file watcher.\n */\n watcherMetrics?: FileWatcherMetrics | undefined;\n /**\n * Receives the internal `broadcastSessions` fn so the HTTP layer can trigger\n * an immediate fleet re-broadcast on `POST /api/fleet/ping` (push-on-write\n * from a TUI/REPL), instead of waiting on the registry file-watch/poll.\n */\n onFleetBroadcaster?: ((fn: () => Promise<void>) => void) | undefined;\n}\n\n/**\n * Wire kernel events to WS broadcasts and (when wpaths/globalConfigPath are\n * given) start the status-file watcher and session-poll interval.\n *\n * Returns a disposer that stops the watcher, clears the metrics/poll\n * intervals, and flushes pending debounce timers. Callers MUST invoke it on\n * shutdown — the watcher is `persistent: true` and the metrics interval is not\n * `unref`'d, so without disposal they keep the process alive and leak across\n * server restarts. (Previously this was hung off a non-existent\n * `process.on('cleanup')` event that never fired.)\n */\nexport function setupEvents(deps: SetupEventsDeps): () => void {\n const { events, broadcast, clients, config, context, pendingConfirms, globalConfigPath, sessionBridge, wpaths, watcherMetrics, onFleetBroadcaster } = deps;\n const disposers: Array<() => void> = [];\n\n events.on('iteration.started', (e) => {\n // Read maxIterations from context.meta so the UI reflects the\n // webui setting, falling back to the startup config default.\n const maxIt = typeof context.meta['maxIterations'] === 'number'\n ? context.meta['maxIterations']\n : config.tools?.maxIterations ?? 100;\n broadcast(clients, {\n type: 'iteration.started',\n payload: { index: e.index, maxIterations: maxIt },\n });\n });\n\n events.on('iteration.completed', (e) => {\n broadcast(clients, {\n type: 'iteration.completed',\n payload: { index: e.index, totalIterations: e.index + 1 },\n });\n });\n\n events.on('iteration.limit_reached', (e) => {\n broadcast(clients, {\n type: 'iteration.limit_reached',\n payload: {\n currentIterations: e.currentIterations,\n currentLimit: e.currentLimit,\n },\n });\n });\n\n events.on('provider.text_delta', (e) => {\n broadcast(clients, { type: 'provider.text_delta', payload: { text: e.text, messageId: 'current' } });\n });\n\n events.on('provider.thinking_delta', (e) => {\n broadcast(clients, { type: 'provider.thinking_delta', payload: { text: e.text } });\n });\n\n events.on('provider.stream_error', (e) => {\n broadcast(clients, {\n type: 'provider.stream_error',\n payload: { eventType: e.eventType, message: e.msg },\n });\n });\n\n events.on('tool.started', (e) => {\n broadcast(clients, {\n type: 'tool.started',\n payload: { id: e.id, name: e.name, input: e.input, messageId: `tool_${e.id}` },\n });\n // Persist for audit + resume tool history (respects auditLevel).\n sessionBridge\n ?.append({\n type: 'tool_call_start',\n ts: new Date().toISOString(),\n name: e.name,\n id: e.id,\n input: e.input,\n })\n .catch(() => { /* best-effort */ });\n });\n\n events.on('tool.progress', (e) => {\n broadcast(clients, {\n type: 'tool.progress',\n // Nested `event` shape — the client handler reads `payload.event?.text`\n // and early-returns on a falsy text, so a flat { eventType, text } payload\n // makes live tool progress (bash streaming, partial_output, warnings)\n // never render. Must match WSToolProgress and the CLI server.\n payload: { id: e.id, name: e.name, event: { type: e.event.type, text: e.event.text, data: e.event.data } },\n });\n sessionBridge\n ?.append({\n type: 'tool_progress',\n ts: new Date().toISOString(),\n name: e.name,\n id: e.id,\n event: { type: e.event.type, text: e.event.text, data: e.event.data },\n })\n .catch(() => { /* best-effort */ });\n });\n\n events.on('tool.executed', (e) => {\n broadcast(clients, {\n type: 'tool.executed',\n payload: { id: e.id, name: e.name, durationMs: e.durationMs, ok: e.ok, input: e.input, output: e.output },\n });\n sessionBridge\n ?.append({\n type: 'tool_call_end',\n ts: new Date().toISOString(),\n name: e.name,\n id: e.id ?? '',\n durationMs: e.durationMs,\n outputSize: e.outputBytes ?? 0,\n ok: e.ok,\n outputBytes: e.outputBytes,\n outputTokens: e.outputTokens,\n outputLines: e.outputLines,\n })\n .catch(() => { /* best-effort */ });\n broadcast(clients, { type: 'todos.updated', payload: { todos: [...context.todos] } });\n\n // P2 #5: push updated side effects after every tool execution so the\n // Audit tab refreshes automatically — no manual refresh needed.\n const sideEffects = context.sideEffects ?? [];\n if (sideEffects.length > 0) {\n broadcast(clients, {\n type: 'side_effects',\n payload: {\n sideEffects: sideEffects.slice(-50).map((se) => ({\n toolUseId: se.toolUseId,\n toolName: se.toolName,\n ts: se.ts,\n input: se.input,\n outcome: se.outcome,\n risk: se.risk,\n })),\n },\n });\n }\n\n // Broadcast task/plan updates after task/plan/todo tool executions.\n if (e.name === 'task' || e.name === 'plan' || e.name === 'todo') {\n void (async () => {\n try {\n const taskPath = (context.meta as Record<string, unknown>)['task.path'];\n if (typeof taskPath === 'string' && taskPath) {\n const { loadTasks } = await import('@wrongstack/core');\n const file = await loadTasks(taskPath);\n broadcast(clients, { type: 'tasks.updated', payload: { tasks: file?.tasks ?? [] } });\n }\n } catch { /* best-effort */ }\n try {\n const planPath = (context.meta as Record<string, unknown>)['plan.path'];\n if (typeof planPath === 'string' && planPath) {\n const { loadPlan } = await import('@wrongstack/core');\n const plan = await loadPlan(planPath);\n broadcast(clients, { type: 'plan.updated', payload: { plan: plan ?? { version: 1, sessionId: context.session?.id ?? '', updatedAt: new Date().toISOString(), items: [] } } });\n }\n } catch { /* best-effort */ }\n })();\n }\n });\n\n events.on('tool.loop_detected', (e) => {\n broadcast(clients, {\n type: 'tool.loop_detected',\n payload: {\n tools: e.tools,\n repeatCount: e.repeatCount,\n iteration: e.iteration,\n kind: e.kind,\n },\n });\n });\n\n events.on('trust.persisted', (e) => {\n broadcast(clients, {\n type: 'trust.persisted',\n payload: { tool: e.tool, pattern: e.pattern, decision: e.decision },\n });\n });\n\n events.on('delegate.started', (e) => {\n broadcast(clients, {\n type: 'delegate.started',\n payload: { target: e.target, task: e.task },\n });\n });\n\n events.on('delegate.completed', (e) => {\n broadcast(clients, {\n type: 'delegate.completed',\n payload: {\n target: e.target,\n task: e.task,\n ok: e.ok,\n status: e.status,\n summary: e.summary,\n durationMs: e.durationMs,\n iterations: e.iterations,\n toolCalls: e.toolCalls,\n costUsd: e.costUsd,\n subagentId: e.subagentId,\n },\n });\n });\n\n events.on('provider.response', (e) => {\n broadcast(clients, { type: 'provider.response', payload: { usage: e.usage, stopReason: e.stopReason, messageId: 'current' } });\n });\n\n events.on('ctx.pct', (e) => {\n broadcast(clients, {\n type: 'ctx.pct',\n payload: { load: e.load, tokens: e.tokens, maxContext: e.maxContext },\n });\n broadcast(clients, {\n type: 'subagent.event',\n payload: {\n kind: 'ctx_pct',\n subagentId: 'leader',\n load: e.load,\n tokens: e.tokens,\n maxContext: e.maxContext,\n },\n });\n });\n\n events.on('ctx.max_context', (e) => {\n broadcast(clients, {\n type: 'ctx.max_context',\n payload: { providerId: e.providerId, modelId: e.modelId, maxContext: e.maxContext },\n });\n });\n\n events.on('token.threshold', (e) => {\n broadcast(clients, {\n type: 'token.threshold',\n payload: { used: e.used, limit: e.limit },\n });\n });\n\n events.on('token.cost_estimate_unavailable', (e) => {\n broadcast(clients, {\n type: 'token.cost_estimate_unavailable',\n payload: { model: e.model },\n });\n });\n\n events.on('context.repaired', (e) => {\n broadcast(clients, { type: 'context.repaired', payload: { removedToolUses: e.removedToolUses, removedToolResults: e.removedToolResults, removedMessages: e.removedMessages } });\n });\n\n events.on('tool.confirm_needed', (e) => {\n const id = e.toolUseId ?? `confirm_${Date.now()}`;\n pendingConfirms.set(id, e.resolve);\n broadcast(clients, { type: 'tool.confirm_needed', payload: { id, toolName: e.tool?.name ?? 'unknown', input: e.input, suggestedPattern: e.suggestedPattern } });\n });\n\n events.on('error', (e) => {\n broadcast(clients, { type: 'error', payload: { phase: e.phase, message: e.err instanceof Error ? e.err.message : String(e.err) } });\n sessionBridge\n ?.append({\n type: 'error',\n ts: new Date().toISOString(),\n message: e.err instanceof Error ? e.err.message : String(e.err),\n phase: e.phase,\n })\n .catch(() => { /* best-effort */ });\n });\n\n events.on('session.damaged', (e) => {\n broadcast(clients, {\n type: 'session.damaged',\n payload: { sessionId: e.sessionId, detail: e.detail },\n });\n });\n\n events.on('session.rewound', (e) => {\n broadcast(clients, {\n type: 'session.rewound',\n payload: {\n toPromptIndex: e.toPromptIndex,\n revertedFiles: e.revertedFiles,\n removedEvents: e.removedEvents,\n },\n });\n });\n\n events.on('checkpoint.written', (e) => {\n broadcast(clients, {\n type: 'checkpoint.written',\n payload: {\n promptIndex: e.promptIndex,\n promptPreview: e.promptPreview,\n ts: e.ts,\n fileCount: e.fileCount,\n },\n });\n });\n\n events.on('in_flight.started', (e) => {\n broadcast(clients, {\n type: 'in_flight.started',\n payload: { context: e.context, ts: e.ts },\n });\n });\n\n events.on('in_flight.ended', (e) => {\n broadcast(clients, {\n type: 'in_flight.ended',\n payload: { reason: e.reason, ts: e.ts },\n });\n });\n\n // Provider visibility — retry storms and provider failures in the JSONL\n // for forensics, mirroring the CLI's bridge wiring.\n events.on('provider.retry', (e) => {\n broadcast(clients, {\n type: 'provider.retry',\n payload: {\n providerId: e.providerId,\n attempt: e.attempt,\n delayMs: e.delayMs,\n status: e.status,\n description: e.description,\n },\n });\n sessionBridge\n ?.append({\n type: 'provider_retry',\n ts: new Date().toISOString(),\n providerId: e.providerId,\n attempt: e.attempt,\n delayMs: e.delayMs,\n status: e.status,\n description: e.description,\n })\n .catch(() => { /* best-effort */ });\n });\n\n events.on('provider.error', (e) => {\n broadcast(clients, {\n type: 'provider.error',\n payload: {\n providerId: e.providerId,\n status: e.status,\n description: e.description,\n retryable: e.retryable,\n },\n });\n sessionBridge\n ?.append({\n type: 'provider_error',\n ts: new Date().toISOString(),\n providerId: e.providerId,\n status: e.status,\n description: e.description,\n retryable: e.retryable,\n })\n .catch(() => { /* best-effort */ });\n });\n\n events.on('provider.fallback', (e) => {\n broadcast(clients, {\n type: 'provider.fallback',\n payload: {\n from: e.from,\n to: e.to,\n status: e.status,\n providerSwitched: e.providerSwitched,\n },\n });\n });\n\n events.on('compaction.fired', (e) => {\n broadcast(clients, {\n type: 'context.compacted',\n payload: {\n before: e.report.before,\n after: e.report.after,\n saved: Math.max(0, e.report.before - e.report.after),\n reductions: e.report.reductions,\n },\n });\n });\n\n events.on('compaction.failed', (e) => {\n broadcast(clients, {\n type: 'compaction.failed',\n payload: {\n message: e.err.message,\n aggressive: e.aggressive,\n level: e.level,\n tokens: e.tokens,\n maxContext: e.maxContext,\n load: e.load,\n fatal: e.fatal,\n },\n });\n });\n\n events.on('mcp.server.connected', (e) => {\n broadcast(clients, {\n type: 'mcp.server.connected',\n payload: { name: e.name, toolCount: e.toolCount },\n });\n });\n\n events.on('mcp.server.reconnected', (e) => {\n broadcast(clients, {\n type: 'mcp.server.reconnected',\n payload: { name: e.name, toolCount: e.toolCount },\n });\n });\n\n events.on('mcp.server.disconnected', (e) => {\n broadcast(clients, {\n type: 'mcp.server.disconnected',\n payload: { name: e.name, reason: e.reason },\n });\n });\n\n events.on('coordinator.stats', (e) => {\n broadcast(clients, {\n type: 'coordinator.stats',\n payload: {\n total: e.total,\n running: e.running,\n idle: e.idle,\n stopped: e.stopped,\n inFlight: e.inFlight,\n pending: e.pending,\n completed: e.completed,\n subagentStatuses: e.subagentStatuses.map((s) => ({\n id: s.subagentId,\n name: s.subagentId,\n status: s.status,\n currentTask: s.taskId,\n })),\n },\n });\n });\n\n // ── Inter-agent mailbox visibility ───────────────────────────────────\n // Forward cross-session mailbox activity (messages received by this\n // process's agents, new agent registrations on the project) to the\n // browser so the user sees multi-terminal/multi-surface chatter live.\n // These events are emitted via emit() with untyped names (GlobalMailbox\n // + mailbox-loop), so subscribe by pattern like the TUI does.\n events.onPattern('mailbox.received', (_e, payload) => {\n broadcast(clients, { type: 'mailbox.received', payload } as never as WSServerMessage);\n });\n events.onPattern('mailbox.agent_registered', (_e, payload) => {\n broadcast(clients, { type: 'mailbox.agent_registered', payload } as never as WSServerMessage);\n });\n\n // Subagent fleet lifecycle\n const forwardSubagent = (kind: string, payload: Record<string, unknown>) =>\n broadcast(clients, { type: 'subagent.event', payload: { kind, sessionId: context.session.id, ...payload } });\n\n events.on('subagent.spawned', (e) => forwardSubagent('spawned', { subagentId: e.subagentId, taskId: e.taskId, name: e.name, provider: e.provider, model: e.model, description: e.description }));\n events.on('subagent.task_started', (e) => forwardSubagent('task_started', { subagentId: e.subagentId, taskId: e.taskId, description: e.description }));\n events.on('subagent.tool_executed', (e) => forwardSubagent('tool_executed', { subagentId: e.subagentId, toolName: e.name, durationMs: e.durationMs, ok: e.ok }));\n events.on('subagent.iteration_summary', (e) => forwardSubagent('iteration_summary', { subagentId: e.subagentId, iteration: e.iteration, toolCalls: e.toolCalls, costUsd: e.costUsd, currentTool: e.currentTool, partialText: e.partialText }));\n events.on('subagent.budget_warning', (e) => forwardSubagent('budget_warning', { subagentId: e.subagentId, budgetKind: e.kind, used: e.used, limit: e.limit }));\n events.on('subagent.budget_extended', (e) => forwardSubagent('budget_extended', { subagentId: e.subagentId, budgetKind: e.kind, newLimit: e.newLimit, totalExtensions: e.totalExtensions }));\n events.on('subagent.ctx_pct', (e) => forwardSubagent('ctx_pct', { subagentId: e.subagentId, load: e.load, tokens: e.tokens, maxContext: e.maxContext }));\n events.on('subagent.task_completed', (e) => forwardSubagent('task_completed', { subagentId: e.subagentId, status: e.status, iterations: e.iterations, toolCalls: e.toolCalls, finalText: (e as Record<string, unknown>).finalText as string | undefined, failureReason: e.error?.kind, error: e.error ? { kind: e.error.kind, message: e.error.message } : undefined }));\n\n events.on('agent.timeline.message', (e) => {\n broadcast(clients, {\n type: 'agent.timeline.message',\n payload: {\n subagentId: e.subagentId,\n agentName: e.agentName,\n content: e.content,\n kind: e.kind,\n iteration: e.iteration,\n ts: e.ts,\n toolName: e.toolName,\n costUsd: e.costUsd,\n },\n });\n });\n events.on('agent.status_changed', (e) => {\n broadcast(clients, {\n type: 'agent.status_changed',\n payload: {\n subagentId: e.subagentId,\n agentName: e.agentName,\n status: e.status,\n ts: e.ts,\n summary: e.summary,\n task: e.task,\n },\n });\n });\n\n // ── Leader (main session) events — forwarded as subagent.event with subagentId 'leader' ──\n // These give the AgentsPage a live leader row with real-time tool tracking,\n // context pressure — matching the TUI's leader entry.\n // Iteration counts, cost, and overall status come from the sessionStore on the frontend.\n\n // Leader spawned: sent on first iteration so the frontend creates the leader row.\n let leaderSpawned = false;\n events.on('iteration.started', () => {\n if (!leaderSpawned) {\n leaderSpawned = true;\n const provider = (context.provider as { id?: string } | undefined)?.id ?? 'unknown';\n forwardSubagent('spawned', {\n subagentId: 'leader',\n name: 'LEADER',\n provider,\n model: context.model,\n description: `Main agent session (${context.session.id})`,\n });\n }\n });\n\n // Leader tool execution: emitted on every tool.executed in the main session.\n events.on('tool.executed', (e) => {\n forwardSubagent('tool_executed', {\n subagentId: 'leader',\n toolName: e.name,\n durationMs: e.durationMs,\n ok: e.ok,\n });\n });\n\n // Leader context pressure + cost: emitted on every provider response.\n events.on('provider.response', (e) => {\n if (e.usage?.input != null) {\n const maxCtx = context.provider.capabilities.maxContext;\n const rawLoad = maxCtx > 0 ? e.usage.input / maxCtx : 0;\n const load = Math.max(0, Math.min(1, rawLoad));\n const costUsd = context.tokenCounter.estimateCost().total;\n forwardSubagent('ctx_pct', {\n subagentId: 'leader',\n load,\n rawLoad,\n tokens: e.usage.input,\n maxContext: maxCtx,\n costUsd,\n });\n }\n });\n\n // Leader iteration updates: we already track iteration started above.\n // The frontend uses sessionStore for accurate cost/iteration counts.\n // When the run completes, the frontend's run.result handler resets isLoading,\n // making the leader go idle. We reset leader state on iteration.started.\n events.on('iteration.completed', () => {\n // Respawn leader if it was cleared (e.g., on session resume).\n if (!leaderSpawned) {\n leaderSpawned = true;\n const provider = (context.provider as { id?: string } | undefined)?.id ?? 'unknown';\n forwardSubagent('spawned', {\n subagentId: 'leader',\n name: 'LEADER',\n provider,\n model: context.model,\n description: `Main agent session (${context.session.id})`,\n });\n }\n });\n\n // ── Mailbox events — broadcast to WebUI for real-time per-project visibility ──\n events.onPattern('mailbox.*', (eventName, payload) => {\n broadcast(clients, { type: 'mailbox.event', payload: { event: eventName, ...payload as Record<string, unknown> } });\n });\n\n // ── Brain events — decisions + proactive interventions, live in the browser ──\n events.onPattern('brain.*', (eventName, payload) => {\n broadcast(clients, { type: 'brain.event', payload: { event: eventName, ...payload as Record<string, unknown> } } as never as WSServerMessage);\n });\n\n // ── Client status events — immediate broadcast to WebUI + write to status.json ──\n // Emitted by TUI/CLI/WebUI when significant status changes occur (tool calls, tokens, etc.)\n events.on('client.status', async (e) => {\n // Immediately broadcast to all connected WebUI clients\n broadcast(clients, { type: 'client.status_update', payload: e });\n\n // Write to status.json file for external watchers (e.g., other tools monitoring this project)\n if (wpaths?.projectStatus) {\n try {\n const statusFile = wpaths.projectStatus(e.projectHash);\n const dir = path.dirname(statusFile);\n await fs.mkdir(dir, { recursive: true });\n await fs.writeFile(statusFile, JSON.stringify(e, null, 2), 'utf-8');\n } catch (err) {\n console.error('[setup-events] Failed to write status.json:', err);\n }\n }\n });\n\n // ── File watcher for external status.json changes ──\n // Watches ~/.wrongstack/projects/<hash>/status.json files for external tool changes.\n // Uses project hash filtering and debouncing to handle rapid writes efficiently.\n if (wpaths?.projectStatus && wpaths.configDir) {\n // projectsDir = ~/.wrongstack/projects/\n const projectsDir = path.join(wpaths.configDir, 'projects');\n\n // Track known project hashes (populated from incoming client.status events)\n const knownProjectHashes = new Set<string>();\n\n // Debounce state: map of projectHash -> timer\n const debounceTimers = new Map<string, ReturnType<typeof setTimeout>>();\n const DEBOUNCE_MS = 150; // Wait 150ms after last write before broadcasting\n\n // Track pending status updates for debouncing (with write timestamps for delay calculation)\n const pendingStatuses = new Map<string, { data: unknown; firstWriteAt: number }>();\n\n // Initialize the external watcher metrics object if provided\n if (watcherMetrics) {\n watcherMetrics.fileChangesDetected = 0;\n watcherMetrics.filesProcessed = 0;\n watcherMetrics.broadcastsSent = 0;\n watcherMetrics.debounceResets = 0;\n watcherMetrics.totalDebounceDelayMs = 0;\n watcherMetrics.activeProjects = 0;\n watcherMetrics.averageDebounceDelayMs = 0;\n watcherMetrics.watcherActive = true;\n }\n\n const getAverageDebounceDelay = (): number => {\n if (!watcherMetrics || watcherMetrics.broadcastsSent === 0) return 0;\n return watcherMetrics.totalDebounceDelayMs / watcherMetrics.broadcastsSent;\n };\n\n const logWatcherMetrics = () => {\n if (!watcherMetrics) return;\n // Update computed field\n watcherMetrics.averageDebounceDelayMs = getAverageDebounceDelay();\n console.log(\n `[setup-events] File watcher stats: ` +\n `${watcherMetrics.broadcastsSent} broadcasts, ` +\n `${watcherMetrics.fileChangesDetected} file changes, ` +\n `${watcherMetrics.debounceResets} debounce resets, ` +\n `avg delay: ${watcherMetrics.averageDebounceDelayMs.toFixed(1)}ms, ` +\n `${watcherMetrics.activeProjects} active projects`\n );\n };\n\n // Log metrics every 60 seconds\n const metricsInterval = setInterval(logWatcherMetrics, 60_000);\n\n const broadcastStatus = (_projectHash: string, statusData: unknown, actualDelayMs: number) => {\n broadcast(clients, { type: 'client.status_update', payload: statusData });\n if (watcherMetrics) {\n watcherMetrics.broadcastsSent++;\n watcherMetrics.totalDebounceDelayMs += actualDelayMs;\n watcherMetrics.averageDebounceDelayMs = getAverageDebounceDelay();\n }\n };\n\n const scheduleBroadcast = (projectHash: string, statusData: unknown) => {\n const now = Date.now();\n const existing = pendingStatuses.get(projectHash);\n\n // Track if this is a debounce reset (rapid successive write)\n if (existing && watcherMetrics) {\n watcherMetrics.debounceResets++;\n }\n\n // Store latest status data with first write timestamp\n pendingStatuses.set(projectHash, {\n data: statusData,\n firstWriteAt: existing ? existing.firstWriteAt : now,\n });\n\n // Clear existing timer for this project\n const existingTimer = debounceTimers.get(projectHash);\n if (existingTimer) {\n clearTimeout(existingTimer);\n }\n\n // Set new debounce timer\n const timer = setTimeout(() => {\n debounceTimers.delete(projectHash);\n const pending = pendingStatuses.get(projectHash);\n if (pending) {\n const actualDelay = Date.now() - pending.firstWriteAt;\n broadcastStatus(projectHash, pending.data, actualDelay);\n pendingStatuses.delete(projectHash);\n }\n }, DEBOUNCE_MS);\n\n debounceTimers.set(projectHash, timer);\n };\n\n let watcher: import('fs').FSWatcher | undefined;\n\n const startWatcher = async () => {\n try {\n // Ensure directory exists before watching\n await fs.mkdir(projectsDir, { recursive: true });\n\n // Use fs.watch for efficient file change detection\n // Watch the projects directory for changes to status.json files\n // recursive:true so nested `<hash>/status.json` writes are delivered —\n // a non-recursive watch on the parent dir does not reliably fire for\n // changes inside subdirectories. filename can be null on some platforms.\n watcher = fsWatch(projectsDir, { persistent: true, recursive: true }, async (eventType, filename) => {\n if (eventType === 'change') {\n if (filename == null) return;\n if (watcherMetrics) watcherMetrics.fileChangesDetected++;\n\n // filename is the path relative to projectsDir, e.g. '<hash>/status.json'\n const targetFile = path.join(projectsDir, String(filename));\n if (targetFile.endsWith('status.json')) {\n // Extract project hash from path: .../projects/<hash>/status.json\n const projectHash = path.basename(path.dirname(targetFile));\n\n // Only process if this is a known project hash\n if (knownProjectHashes.size > 0 && !knownProjectHashes.has(projectHash)) {\n return; // Skip unknown project directories\n }\n\n if (watcherMetrics) watcherMetrics.filesProcessed++;\n\n try {\n const content = await fs.readFile(targetFile, 'utf-8');\n const statusData = JSON.parse(content);\n\n // Add to known hashes if not present\n if (statusData.projectHash) {\n const hash = String(statusData.projectHash);\n if (!knownProjectHashes.has(hash)) {\n knownProjectHashes.add(hash);\n if (watcherMetrics) watcherMetrics.activeProjects = knownProjectHashes.size;\n }\n }\n\n // Debounce the broadcast\n scheduleBroadcast(projectHash, statusData);\n } catch {\n // File may not exist, be readable yet, or invalid JSON\n }\n }\n }\n });\n\n console.log(`[setup-events] Watching ${projectsDir} for status.json changes (hash-filtered, debounced)`);\n } catch (err) {\n console.error('[setup-events] Failed to start status file watcher:', err);\n }\n };\n\n // Register incoming client.status events to build known project hashes\n // This ensures we only watch directories that have emitted status before\n events.on('client.status', (e) => {\n if (e.projectHash) {\n const hash = String(e.projectHash);\n if (!knownProjectHashes.has(hash)) {\n knownProjectHashes.add(hash);\n if (watcherMetrics) watcherMetrics.activeProjects = knownProjectHashes.size;\n }\n }\n });\n\n // Start watcher asynchronously without blocking setup\n startWatcher();\n\n // Clean up watcher and timers on shutdown. Registered as a disposer so it\n // actually runs (the previous `process.on('cleanup')` event never fires).\n disposers.push(() => {\n clearInterval(metricsInterval);\n logWatcherMetrics(); // Final metrics log on shutdown\n\n // Mark watcher as inactive\n if (watcherMetrics) watcherMetrics.watcherActive = false;\n\n // Flush any pending broadcasts before cleanup\n for (const [projectHash, pending] of pendingStatuses) {\n const timer = debounceTimers.get(projectHash);\n if (timer) {\n clearTimeout(timer);\n // Broadcast pending status immediately on shutdown\n broadcastStatus(projectHash, pending.data, 0);\n }\n }\n\n // Clear all debounce timers\n for (const timer of debounceTimers.values()) {\n clearTimeout(timer);\n }\n debounceTimers.clear();\n pendingStatuses.clear();\n\n if (watcher) {\n watcher.close();\n console.log('[setup-events] Closed status file watcher');\n }\n });\n }\n\n // ── Cross-process session / fleet status ──\n // Read the SessionRegistry and broadcast live session+agent status to all\n // connected clients. Three triggers, from fastest to slowest: a push-on-write\n // `POST /api/fleet/ping` (via onFleetBroadcaster, ~ms), an `fs.watch` on the\n // registry file (~150ms), and a 5s fallback poll that also prunes stale\n // entries via `list()`.\n const globalRoot = globalConfigPath ? path.dirname(globalConfigPath) : undefined;\n if (globalRoot) {\n const broadcastSessions = async () => {\n try {\n const { SessionRegistry } = await import('@wrongstack/core');\n const registry = new SessionRegistry(globalRoot);\n const sessions = await registry.list();\n // Scope Fleet HQ to the *same project* as this server. The registry lists\n // every project's sessions, so derive our current project from our own\n // entry (matched by pid — survives in-place project switches, unlike the\n // launch-time `wpaths.projectSlug`). Fall back to all sessions if our\n // entry isn't found yet (first tick before registration settles).\n const mySlug = sessions.find((s) => s.pid === process.pid)?.projectSlug;\n const live = sessions\n .filter((s) => s.status !== 'stale')\n .filter((s) => (mySlug ? s.projectSlug === mySlug : true))\n .map((s) => ({\n sessionId: s.sessionId,\n projectName: s.projectName,\n projectSlug: s.projectSlug,\n projectRoot: s.projectRoot,\n workingDir: s.workingDir,\n gitBranch: s.gitBranch,\n // Surface (tui/webui/cli) so Fleet HQ can label each live client node.\n clientType: s.clientType,\n status: s.status,\n pid: s.pid,\n startedAt: s.startedAt,\n agentCount: s.agentCount,\n agents: (s.agents ?? []).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 costUsd: a.costUsd,\n tokensIn: a.tokensIn,\n tokensOut: a.tokensOut,\n ctxPct: a.ctxPct,\n model: a.model,\n partialText: a.partialText,\n lastActivityAt: a.lastActivityAt,\n })),\n }));\n broadcast(clients, { type: 'sessions.status_update', payload: { sessions: live } });\n } catch {\n // Best-effort — never crash for status broadcasting errors\n }\n };\n\n // Hand the broadcaster to the HTTP layer for push-on-write (/api/fleet/ping).\n onFleetBroadcaster?.(broadcastSessions);\n\n // Fallback poll (also prunes stale entries on read).\n const statusInterval = setInterval(() => void broadcastSessions(), 5_000);\n if (statusInterval.unref) statusInterval.unref();\n disposers.push(() => clearInterval(statusInterval));\n\n // Event-driven: watch the registry file so a TUI/REPL agent's write reaches\n // the map in ~150ms. Atomic writes go via `<file>.<uuid>.tmp` → rename, so\n // watch the dir and match any `session-registry.json*` change (ignore .lock).\n let regDebounce: ReturnType<typeof setTimeout> | undefined;\n try {\n const regWatcher = fsWatch(globalRoot, { persistent: false }, (_event, filename) => {\n const name = filename ? String(filename) : '';\n if (!name.startsWith('session-registry.json') || name.endsWith('.lock')) return;\n if (regDebounce) clearTimeout(regDebounce);\n regDebounce = setTimeout(() => void broadcastSessions(), 150);\n });\n disposers.push(() => {\n if (regDebounce) clearTimeout(regDebounce);\n regWatcher.close();\n });\n } catch {\n // Watch unsupported on this platform — the 5s poll still covers it.\n }\n\n // Push an immediate snapshot so a freshly-connected client doesn't wait.\n void broadcastSessions();\n }\n\n return () => {\n for (const dispose of disposers) {\n try {\n dispose();\n } catch {\n /* best-effort teardown */\n }\n }\n };\n}\n","import { listContextWindowModes, atomicWrite } from '@wrongstack/core';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\n\n/**\n * Custom context modes — user-defined presets that are loaded from disk,\n * merged with the built-in modes, and managed via WebSocket CRUD handlers.\n *\n * Stored in: ~/.wrongstack/custom-context-modes.json\n * Format: { \"modes\": ContextWindowMode[] }\n */\n\nexport interface CustomContextMode {\n id: string;\n name: string;\n description: string;\n thresholds: { warn: number; soft: number; hard: number };\n aggressiveOn: string;\n preserveK: number;\n eliseThreshold: number;\n targetLoad: number;\n /** Whether this is a user-defined (custom) or built-in mode. */\n custom: boolean;\n}\n\nexport interface CustomModeStore {\n modes: Map<string, CustomContextMode>;\n load: () => Promise<void>;\n save: () => Promise<void>;\n create: (mode: CustomContextMode) => { ok: boolean; error?: string | undefined };\n update: (id: string, patch: Partial<CustomContextMode>) => { ok: boolean; error?: string | undefined };\n remove: (id: string) => { ok: boolean; error?: string | undefined };\n list: () => CustomContextMode[];\n}\n\nconst STORE_FILENAME = 'custom-context-modes.json';\n\nfunction storePath(wrongstackDir: string): string {\n return path.join(wrongstackDir, STORE_FILENAME);\n}\n\nconst BUILTIN_IDS = new Set(['balanced', 'frugal', 'deep', 'archival']);\n\nexport function createCustomModeStore(wrongstackDir: string): CustomModeStore {\n const modes = new Map<string, CustomContextMode>();\n\n const load = async (): Promise<void> => {\n modes.clear();\n try {\n const raw = await fs.readFile(storePath(wrongstackDir), 'utf8');\n const parsed = JSON.parse(raw) as { modes?: CustomContextMode[] };\n if (Array.isArray(parsed.modes)) {\n for (const m of parsed.modes) {\n if (m.id && !BUILTIN_IDS.has(m.id)) {\n modes.set(m.id, { ...m, custom: true });\n }\n }\n }\n } catch {\n // File missing or corrupt — start with empty custom modes.\n }\n };\n\n const save = async (): Promise<void> => {\n const arr = [...modes.values()];\n const json = JSON.stringify({ modes: arr }, null, 2);\n await atomicWrite(storePath(wrongstackDir), json);\n };\n\n const create = (\n mode: CustomContextMode,\n ): { ok: boolean; error?: string | undefined } => {\n if (!mode.id || typeof mode.id !== 'string') {\n return { ok: false, error: 'id is required' };\n }\n if (BUILTIN_IDS.has(mode.id)) {\n return { ok: false, error: `Cannot override built-in mode \"${mode.id}\"` };\n }\n if (modes.has(mode.id)) {\n return { ok: false, error: `Mode \"${mode.id}\" already exists` };\n }\n if (!mode.name) {\n return { ok: false, error: 'name is required' };\n }\n const entry: CustomContextMode = {\n id: mode.id,\n name: mode.name,\n description: mode.description || '',\n thresholds: {\n warn: mode.thresholds?.warn ?? 0.6,\n soft: mode.thresholds?.soft ?? 0.75,\n hard: mode.thresholds?.hard ?? 0.9,\n },\n aggressiveOn: mode.aggressiveOn || 'soft',\n preserveK: mode.preserveK ?? 10,\n eliseThreshold: mode.eliseThreshold ?? 2000,\n targetLoad: mode.targetLoad ?? 0.65,\n custom: true,\n };\n modes.set(mode.id, entry);\n void save().catch(() => {});\n return { ok: true };\n };\n\n const update = (\n id: string,\n patch: Partial<CustomContextMode>,\n ): { ok: boolean; error?: string | undefined } => {\n if (BUILTIN_IDS.has(id)) {\n return { ok: false, error: `Cannot modify built-in mode \"${id}\"` };\n }\n const existing = modes.get(id);\n if (!existing) {\n return { ok: false, error: `Mode \"${id}\" not found` };\n }\n const next: CustomContextMode = { ...existing };\n if (patch.name !== undefined) next.name = patch.name;\n if (patch.description !== undefined) next.description = patch.description;\n if (patch.thresholds) {\n next.thresholds = {\n warn: patch.thresholds.warn ?? existing.thresholds.warn,\n soft: patch.thresholds.soft ?? existing.thresholds.soft,\n hard: patch.thresholds.hard ?? existing.thresholds.hard,\n };\n }\n if (patch.preserveK !== undefined) next.preserveK = patch.preserveK;\n if (patch.eliseThreshold !== undefined) next.eliseThreshold = patch.eliseThreshold;\n if (patch.targetLoad !== undefined) next.targetLoad = patch.targetLoad;\n if (patch.aggressiveOn !== undefined) next.aggressiveOn = patch.aggressiveOn;\n modes.set(id, next);\n void save().catch(() => {});\n return { ok: true };\n };\n\n const remove = (\n id: string,\n ): { ok: boolean; error?: string | undefined } => {\n if (BUILTIN_IDS.has(id)) {\n return { ok: false, error: `Cannot delete built-in mode \"${id}\"` };\n }\n if (!modes.delete(id)) {\n return { ok: false, error: `Mode \"${id}\" not found` };\n }\n void save().catch(() => {});\n return { ok: true };\n };\n\n const list = (): CustomContextMode[] => {\n const builtins = listContextWindowModes().map((m) => ({\n id: m.id as string,\n name: m.name,\n description: m.description,\n thresholds: { ...m.thresholds },\n aggressiveOn: m.aggressiveOn as string,\n preserveK: m.preserveK,\n eliseThreshold: m.eliseThreshold,\n targetLoad: m.targetLoad,\n custom: false as const,\n }));\n const custom = [...modes.values()];\n return [...builtins, ...custom];\n };\n\n return { modes, load, save, create, update, remove, list };\n}\n","// Eternal-autonomy iteration broadcast wiring.\n//\n// The CLI's `runWebUI` owns the eternal-autonomy engine and exposes a\n// `subscribeEternalIteration` callback that lets the webui hook into\n// the journal-entry stream. This module extracts the wiring in\n// isolation so it can be unit-tested without spinning up the full\n// server (clients, WS, HTTP bring-up).\n//\n// `createEternalSubscription` is the helper that:\n// 1. Calls the caller-supplied `subscribe` function with a broadcast\n// closure bound to the current `clients` Map.\n// 2. Captures the returned disposer so `tearDown` can invoke it on\n// server shutdown.\n//\n// Both the disposer and the `JournalEntry` are projected by the caller\n// — this module intentionally knows nothing about the engine itself.\n\nimport type { WebSocket } from 'ws';\nimport type { WSServerMessage } from './types.js';\nimport type { JournalEntry } from '@wrongstack/core';\n\nexport type EternalSubscribe = (\n fn: (entry: JournalEntry) => void,\n) => () => void;\n\n// `clients` is generic so callers that use a structurally-similar\n// `ConnectedClient` (the CLI's own Map<WebSocket, { ws; sessionId }>,\n// for example) don't have to alias their type to webui's\n// `ConnectedClient`. The helper doesn't read the value at all —\n// `broadcast` gets to decide whether to use the map or not — so we\n// only need the key type (WebSocket) to be present, which is\n// enforced by the constraint.\nexport type EternalBroadcast<C> = (clients: Map<WebSocket, C>, msg: WSServerMessage) => void;\n\nexport interface EternalSubscription {\n /** Tear down the underlying engine subscription. Idempotent. */\n dispose: () => void;\n}\n\nexport function createEternalSubscription<C>(\n subscribe: EternalSubscribe,\n broadcast: EternalBroadcast<C>,\n clientsRef: () => Map<WebSocket, C>,\n): EternalSubscription {\n let disposed = false;\n const dispose = subscribe((entry) => {\n if (disposed) return;\n broadcast(clientsRef(), {\n type: 'eternal.iteration',\n payload: { entry },\n });\n });\n return {\n dispose() {\n if (disposed) return;\n disposed = true;\n dispose();\n },\n };\n}\n","// Open the OS file manager or a terminal at a given path (the\n// `shell.open` WS message handler).\n//\n// Both the standalone `startWebUI` and the CLI's `runWebUI` needed\n// the same logic \\u2014 metacharacter guard, `path.resolve` to fold\n// any `..` traversal, and a cross-platform `spawn()` for the\n// platform's file manager (`explorer`/`open`/`xdg-open`) or\n// terminal (`cmd /c start cmd /k` / `open -a Terminal` /\n// `x-terminal-emulator` \\u2192 `gnome-terminal` \\u2192 `xterm` fallback chain).\n// Phase 1.2 added the `spawn`-based version on the CLI side; the\n// standalone got it shortly after. The two implementations have\n// drifted slightly (CLI lacks the `logger.warn` on spawn failure),\n// which is exactly the class of bug extraction prevents.\n//\n// This module returns a `ShellOpenResult` so the caller (the WS\n// router in either entry point) can pipe it through `sendResult`\n// with the same `success`/`message` shape both sides already use.\n// Spawn is async + detached + unref'd so a missing terminal\n// emulator (which fires `error` async) never crashes the server\n// \\u2014 the fallback chain tries the next one, the file-manager\n// branch just logs.\n//\n// SECURITY: the path arrives over the WebSocket. The\n// metacharacter guard (`/[&|<>^\\\"'`\\n\\r]/`) closes the cmd.exe\n// re-parsing injection class (`\"foo\" && calc.exe`,\n// `'$(...)'`, backticks, redirections) before anything reaches\n// the argv array. The `path.resolve` then folds any\n// `..` traversal, and `fs.access(resolved)` enforces that the\n// target exists \\u2014 callers can't ask us to open a non-existent\n// path. Defense in depth: the spawn below uses an argv array\n// (no string concatenation), and `windowsHide` keeps the\n// launcher console out of the way.\n\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { spawn } from 'node:child_process';\nimport type { Logger } from '@wrongstack/core';\n\nexport type ShellOpenTarget = 'terminal' | 'file-manager';\n\nexport interface ShellOpenRequest {\n path: string;\n target: ShellOpenTarget;\n}\n\nexport interface ShellOpenResult {\n success: boolean;\n message: string;\n}\n\n/** Metacharacters that would let a path slip past an argv-array\n * spawn and into a shell re-parse on Windows. Real directory\n * paths virtually never contain these. Single-quote is included\n * because an unescaped ' inside a single-quoted shell string\n * (e.g. cd '$path') breaks the literal and enables injection. */\nconst METACHAR_REGEX = /[&|<>^\"'`'\\n\\r]/;\n\n/** Escape a string for safe use as a single-quoted shell argument.\n * Replaces ' -> '\\'' (end quote, escaped quote, restart quote). */\nfunction shellQuote(s: string): string {\n return s.replaceAll(\"'\", \"'\\\"'\\\"'\");\n}\n\nexport async function handleShellOpen(\n req: ShellOpenRequest,\n logger: Logger,\n): Promise<ShellOpenResult> {\n try {\n const resolved = path.resolve(req.path);\n await fs.access(resolved);\n if (METACHAR_REGEX.test(resolved)) {\n return { success: false, message: 'Path contains unsupported characters.' };\n }\n\n const platform = process.platform;\n const launch = (cmd: string, args: string[], onError?: () => void) => {\n const child = spawn(cmd, args, {\n detached: true,\n stdio: 'ignore',\n windowsHide: true,\n });\n // `error` fires when the binary is missing (e.g. xterm not\n // installed) \\u2014 log it, but never block the WS caller. The\n // fallback chain in the terminal branch uses onError to try\n // the next emulator.\n child.on('error', (err) => {\n logger.warn(`shell.open spawn failed: ${err.message}`);\n onError?.();\n });\n child.unref();\n };\n\n if (req.target === 'file-manager') {\n if (platform === 'win32') launch('explorer', [resolved]);\n else if (platform === 'darwin') launch('open', [resolved]);\n else launch('xdg-open', [resolved]);\n } else if (req.target === 'terminal') {\n if (platform === 'win32') {\n // `start` is a cmd builtin; each token is a separate argv\n // entry (Node quotes them individually \\u2014 no string\n // concatenation). This replaces the previous\n // `start cmd /k cd /d \"...\"` exec() call that was\n // shell-injectable.\n launch('cmd', ['/c', 'start', 'cmd', '/k', 'cd', '/d', resolved]);\n } else if (platform === 'darwin') {\n launch('open', ['-a', 'Terminal', resolved]);\n } else {\n // Try several terminal emulators\n launch('x-terminal-emulator', [`--working-directory=${resolved}`], () =>\n launch('gnome-terminal', [`--working-directory=${resolved}`], () =>\n // Pass argv array so sh -c sees a literal string, not an interpolated one.\n // shellQuote() guards against paths that somehow slipped the METACHAR_REGEX.\n launch('xterm', ['-e', 'sh', '-c', `cd ${shellQuote(resolved)} && ${process.env['SHELL'] ?? 'sh'}`]),\n ),\n );\n }\n } else {\n return { success: false, message: `Unknown shell.open target: ${String(req.target)}` };\n }\n return { success: true, message: `Opened ${req.target} at ${resolved}` };\n } catch (err) {\n return { success: false, message: err instanceof Error ? err.message : String(err) };\n }\n}\n","/**\n * Shared `git.info` WebSocket handler for both the standalone WebUI server and\n * the CLI's `--webui` embedded server. Extracted from the duplicated switch\n * cases in `index.ts` and `cli/src/webui-server.ts`, which had drifted (the\n * standalone copy transposed ahead/behind and never matched deletions). One\n * implementation here keeps both surfaces in lockstep.\n *\n * case 'git.info': return handleGitInfo(ws, projectRoot);\n */\n\nimport type { WebSocket } from 'ws';\nimport nodePath from 'node:path';\nimport { send } from './ws-utils.js';\n\n/**\n * Read git branch, change stats, and upstream sync status from `projectRoot`\n * and broadcast a `git.info` message. Never throws — a non-repo / missing-git\n * directory yields an empty-but-valid payload.\n */\nexport async function handleGitInfo(ws: WebSocket, projectRoot: string): Promise<void> {\n const cwd = projectRoot || undefined;\n try {\n const { execFile: ef } = await import('node:child_process');\n const git = (args: string[]): Promise<string> =>\n new Promise((resolve) => {\n ef('git', args, { cwd, timeout: 3000 }, (err: Error | null, stdout: string) => {\n resolve(err ? '' : stdout.trim());\n });\n });\n\n const [branchRaw, diffRaw, statusRaw, upstreamRaw] = await Promise.all([\n git(['branch', '--show-current']),\n git(['diff', '--stat']),\n git(['status', '--porcelain']),\n git(['rev-list', '--left-right', '--count', '@{upstream}...HEAD']),\n ]);\n\n const branch = branchRaw || '(detached)';\n\n // `git diff --stat` summary line: \"N files changed, X insertions(+), Y deletions(-)\".\n // Deletions are formatted \"Y deletions(-)\" — the `+` only ever precedes\n // INSERTIONS, so a `\\+`-anchored deletion regex never matches.\n const addMatch = /(\\d+)\\s+insertion/i.exec(diffRaw);\n const delMatch = /(\\d+)\\s+deletion/i.exec(diffRaw);\n const added = addMatch ? Number(addMatch[1]) : 0;\n const deleted = delMatch ? Number(delMatch[1]) : 0;\n\n // Untracked files from `git status --porcelain` (lines starting with \"??\").\n const untracked = statusRaw.split('\\n').filter((l) => l.startsWith('??')).length;\n\n // `git rev-list --left-right --count @{upstream}...HEAD` prints \"<behind>\\t<ahead>\":\n // left = commits in upstream not in HEAD (BEHIND), right = HEAD-only (AHEAD).\n const [behindRaw, aheadRaw] = (upstreamRaw || '0\\t0').split('\\t');\n const behind = Number(behindRaw) || 0;\n const ahead = Number(aheadRaw) || 0;\n\n send(ws, { type: 'git.info', payload: { branch, added, deleted, untracked, ahead, behind } });\n } catch {\n // Git not available or not a repo — send empty info silently.\n send(ws, { type: 'git.info', payload: { branch: '', added: 0, deleted: 0, untracked: 0, ahead: 0, behind: 0 } });\n }\n}\n\n/** One changed file in the working tree (vs HEAD). */\nexport interface GitChangedFile {\n /** Repo-relative path (POSIX separators, as git reports). */\n path: string;\n /**\n * Single-letter change kind for the badge:\n * `M` modified, `A` added/staged-new, `D` deleted, `R` renamed,\n * `?` untracked, `C` copied, `U` unmerged/conflict.\n */\n status: string;\n /** Lines added (best-effort; 0 for untracked-binary / unknown). */\n added: number;\n /** Lines removed (best-effort). */\n deleted: number;\n /** True when the change is at least partly staged. */\n staged: boolean;\n}\n\n/** Spawn `git` in `cwd` and resolve its trimmed stdout ('' on any error). */\nfunction makeGit(cwd: string | undefined) {\n return async (args: string[]): Promise<string> => {\n const { execFile: ef } = await import('node:child_process');\n return new Promise((resolve) => {\n ef(\n 'git',\n args,\n { cwd, timeout: 5000, maxBuffer: 1024 * 1024 * 16 },\n (err: Error | null, stdout: string) => resolve(err ? '' : stdout),\n );\n });\n };\n}\n\n/**\n * Read the working-tree change set (everything that differs from HEAD:\n * staged, unstaged, and untracked) and broadcast a `git.changes` message.\n *\n * The file list comes from `git status --porcelain -z` (NUL-delimited so\n * paths with spaces/unicode survive intact, and renames are unambiguous).\n * Per-file line counts come from `--numstat` of both the unstaged and the\n * staged diff, summed. Untracked files intentionally report 0/0 here so the\n * list view does not read every untracked file; `git.diff` loads a selected\n * file lazily on demand.\n * Never throws — a non-repo yields an empty list.\n */\nexport async function handleGitChanges(ws: WebSocket, projectRoot: string): Promise<void> {\n const cwd = projectRoot || undefined;\n try {\n const git = makeGit(cwd);\n const [statusRaw, unstagedNumstat, stagedNumstat] = await Promise.all([\n git(['status', '--porcelain', '-z']),\n git(['diff', '--numstat', '-z']),\n git(['diff', '--cached', '--numstat', '-z']),\n ]);\n\n // numstat -z format: \"<added>\\t<deleted>\\t<path>\\0\" per entry. For a rename\n // git emits \"<added>\\t<deleted>\\0<oldpath>\\0<newpath>\\0\" (path field empty,\n // two extra NUL records). Parse defensively, keying counts by final path.\n const counts = new Map<string, { added: number; deleted: number }>();\n const parseNumstat = (raw: string): void => {\n const parts = raw.split('\\0');\n for (let i = 0; i < parts.length; i++) {\n const entry = parts[i];\n if (!entry) continue;\n const m = /^(\\d+|-)\\t(\\d+|-)\\t(.*)$/.exec(entry);\n if (!m) continue;\n const added = m[1] === '-' ? 0 : Number(m[1]);\n const deleted = m[2] === '-' ? 0 : Number(m[2]);\n let path = m[3] ?? '';\n if (path === '') {\n // Rename: next two records are old, then new path.\n i += 1;\n path = parts[i + 1] ?? parts[i] ?? '';\n i += 1;\n }\n if (!path) continue;\n const prev = counts.get(path) ?? { added: 0, deleted: 0 };\n counts.set(path, { added: prev.added + added, deleted: prev.deleted + deleted });\n }\n };\n parseNumstat(unstagedNumstat);\n parseNumstat(stagedNumstat);\n\n // `git status --porcelain -z`: each record is \"XY <path>\" (no separator\n // after the 2-char code beyond the single space). Rename/copy records are\n // followed by a separate NUL record carrying the original path.\n const records = statusRaw.split('\\0').filter((r) => r.length > 0);\n const files: GitChangedFile[] = [];\n for (let i = 0; i < records.length; i++) {\n const rec = records[i];\n if (!rec || rec.length < 3) continue;\n const x = rec[0] ?? ' ';\n const y = rec[1] ?? ' ';\n const path = rec.slice(3);\n const isRename = x === 'R' || x === 'C' || y === 'R' || y === 'C';\n if (isRename) i += 1; // consume the original-path record that follows\n\n let status: string;\n if (x === '?' && y === '?') status = '?';\n else if (x === 'U' || y === 'U' || (x === 'A' && y === 'A') || (x === 'D' && y === 'D')) status = 'U';\n else if (x === 'R' || y === 'R') status = 'R';\n else if (x === 'C' || y === 'C') status = 'C';\n else if (x === 'A' || y === 'A') status = 'A';\n else if (x === 'D' || y === 'D') status = 'D';\n else status = 'M';\n\n const staged = x !== ' ' && x !== '?';\n\n let added = counts.get(path)?.added ?? 0;\n let deleted = counts.get(path)?.deleted ?? 0;\n if (status === '?') {\n // Untracked files are not present in numstat. Do not read every file\n // here: large generated/untracked trees made git.changes an N+1 file\n // scan. The diff endpoint loads a selected file on demand.\n added = 0;\n deleted = 0;\n }\n files.push({ path, status, added, deleted, staged });\n }\n\n send(ws, { type: 'git.changes', payload: { files } });\n } catch (err) {\n send(ws, {\n type: 'git.changes',\n payload: { files: [], error: err instanceof Error ? err.message : String(err) },\n });\n }\n}\n\nconst MAX_DIFF_BYTES = 2 * 1024 * 1024; // 2 MB per side — guard the renderer\n\n/**\n * Resolve the before/after text for a single file and broadcast a `git.diff`\n * message. `oldText` is the file at HEAD (`git show HEAD:<path>`), `newText`\n * is the current working-tree content. New/untracked files have empty\n * `oldText`; deleted files have empty `newText`. Binary or oversized files\n * are reported with a flag instead of content so the client can show a notice.\n */\nexport async function handleGitDiff(\n ws: WebSocket,\n projectRoot: string,\n path: string,\n): Promise<void> {\n const cwd = projectRoot || undefined;\n const reply = (extra: Record<string, unknown>): void =>\n send(ws, { type: 'git.diff', payload: { path, ...extra } });\n\n if (!path || path.includes('\\0') || path.includes('..') || nodePath.isAbsolute(path)) {\n reply({ oldText: '', newText: '', error: 'invalid path' });\n return;\n }\n\n try {\n const git = makeGit(cwd);\n const { readFile } = await import('node:fs/promises');\n const { join } = await import('node:path');\n\n // HEAD version. `git show` writes nothing for a path absent at HEAD.\n const oldText = await git(['show', `HEAD:${path}`]);\n\n // Working-tree version (absent → deleted file → empty).\n let newText = '';\n try {\n const abs = cwd ? join(cwd, path) : path;\n const buf = await readFile(abs);\n if (buf.includes(0)) {\n reply({ oldText: '', newText: '', binary: true });\n return;\n }\n if (buf.length > MAX_DIFF_BYTES) {\n reply({ oldText: '', newText: '', tooLarge: true });\n return;\n }\n newText = buf.toString('utf8');\n } catch {\n newText = '';\n }\n\n if ((oldText.length || 0) > MAX_DIFF_BYTES) {\n reply({ oldText: '', newText: '', tooLarge: true });\n return;\n }\n if (oldText.includes('\\0')) {\n reply({ oldText: '', newText: '', binary: true });\n return;\n }\n\n reply({ oldText, newText });\n } catch (err) {\n reply({ oldText: '', newText: '', error: err instanceof Error ? err.message : String(err) });\n }\n}\n","/**\n * Process-registry WebSocket handlers for the WebUI server, extracted from the\n * `handleMessage` switch in `index.ts` as part of splitting that file (#31).\n *\n * case 'process.list': return handleProcessList(ws);\n * case 'process.kill': return handleProcessKill(ws, msg.payload);\n * case 'process.killAll': return handleProcessKillAll(ws);\n *\n * All three reach the registry via a dynamic `@wrongstack/tools` import so the\n * server starts even when that package is unavailable, and never throw — a\n * failure is reported back over the socket instead.\n */\n\nimport type { WebSocket } from 'ws';\nimport { errMessage, send, sendResult } from './ws-utils.js';\nimport { validateProcessKillPayload } from './ws-payload-validation.js';\n\n/** Broadcast the tracked-process list; an empty list on any registry failure. */\nexport async function handleProcessList(ws: WebSocket): Promise<void> {\n try {\n const { getProcessRegistry } = await import('@wrongstack/tools');\n const procs = getProcessRegistry().list();\n send(ws, {\n type: 'process.list',\n payload: {\n processes: procs.map((p) => ({\n pid: p.pid,\n command: p.command,\n tool: p.name,\n startedAt: p.startedAt,\n status: p.killed ? ('killed' as const) : ('running' as const),\n protected: p.protected,\n })),\n },\n });\n } catch {\n send(ws, { type: 'process.list', payload: { processes: [] } });\n }\n}\n\n/** Kill one tracked PID. Rejects invalid payloads and protected processes. */\nexport async function handleProcessKill(ws: WebSocket, payload: unknown): Promise<void> {\n const parsed = validateProcessKillPayload(payload);\n if (!parsed.ok) {\n sendResult(ws, false, parsed.message);\n return;\n }\n const { pid } = parsed.value;\n try {\n const { getProcessRegistry } = await import('@wrongstack/tools');\n const proc = getProcessRegistry().get(pid);\n if (proc?.protected) {\n sendResult(ws, false, `Cannot kill protected process (PID ${pid})`);\n return;\n }\n getProcessRegistry().kill(pid);\n sendResult(ws, true, `Killed PID ${pid}`);\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n}\n\n/** Kill every tracked process. */\nexport async function handleProcessKillAll(ws: WebSocket): Promise<void> {\n try {\n const { getProcessRegistry } = await import('@wrongstack/tools');\n getProcessRegistry().killAll();\n sendResult(ws, true, 'All processes killed');\n } catch (err) {\n sendResult(ws, false, errMessage(err));\n }\n}\n","/**\n * Goal-state WebSocket handler for the WebUI server, extracted from the\n * `handleMessage` switch in `index.ts` as part of splitting that file (#31).\n *\n * case 'goal.get': return handleGoalGet(projectRoot, (m) => broadcast(clients, m));\n *\n * Reads the canonical goal.json and broadcasts it to every connected client so\n * all browser tabs share one goal snapshot. Never throws — a missing or\n * unparseable file broadcasts `null` so clients clear stale goal state.\n */\n\nimport { resolveWstackPaths } from '@wrongstack/core/utils';\n\n/**\n * Read `goal.json` for `projectRoot` and broadcast a `goal.updated` message.\n * The path must match /goal, the autonomy engines, and TUI F9, which all\n * resolve via `resolveWstackPaths().projectGoal`\n * (`~/.wrongstack/projects/<slug>/goal.json`) — NOT the repo-local\n * `.wrongstack/goal.json`.\n */\nexport async function handleGoalGet(\n projectRoot: string,\n broadcast: (msg: object) => void,\n): Promise<void> {\n try {\n const goalPath = resolveWstackPaths({ projectRoot }).projectGoal;\n const { readFile } = await import('node:fs/promises');\n const raw = await readFile(goalPath, 'utf8');\n const goal = JSON.parse(raw);\n broadcast({ type: 'goal.updated', payload: goal });\n } catch {\n broadcast({ type: 'goal.updated', payload: null });\n }\n}\n"],"mappings":"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","names":["expectDefined","GlobalMailbox","getSessionRegistry","name","path","toErrorMessage","wstackGlobalRoot","fs","path","createRequire","resolveWstackPaths","DefaultSessionStore","DefaultSessionReader","tail","resolve","GlobalMailbox","mailboxSessionTag","name","fs","path","deps","fs","path","name","fs","path","relative","stat","sendResult","name","path","isInside","sendResult","fs","path","atomicWrite","wstackGlobalRoot","name","fs","path","wstackGlobalRoot","atomicWrite","fs","path","DefaultSessionStore","DefaultSystemPromptBuilder","atomicWrite","DEFAULT_CONTEXT_WINDOW_MODE_ID","resolveContextWindowPolicy","cleanupStaleSddWorktrees","decryptConfigSecrets","encryptConfigSecrets","WebSocket","deps","deriveTitle","deps","path","spawnSync","SddBoardStore","SpecStore","TaskGraphStore","WorktreeManager","name","toErrorMessage","tail","s","fs","path","toErrorMessage","join","resolve","sep","cleanupStaleSddWorktrees","WorktreeManager","toErrorMessage","resolveProjectDir","deps","resolveProjectDir","path","fs","atomicWrite","resolve","fs","path","atomicWrite","toErrorMessage","deps","broadcast","toErrorMessage","sendResult","sendResult","fs","path","DefaultSystemPromptBuilder","resolveWstackPaths","stat","name","resolveWstackPaths","DefaultSystemPromptBuilder","sendResult","path","sendResult","sendResult","fs","path","deps","broadcast","load","projectHash","name","atomicWrite","fs","path","load","save","broadcast","fs","path","spawn","resolve","path","readFile","join","sendResult","resolveWstackPaths","broadcast","readFile","decryptConfigSecrets","encryptConfigSecrets","atomicWrite","expectDefined","toErrorMessage","name","DefaultSessionStore","getSessionRegistry","WebSocket","wstackGlobalRoot","createRequire","DefaultSystemPromptBuilder","GlobalMailbox","resolveContextWindowPolicy","cleanupStaleSddWorktrees","provider","DEFAULT_CONTEXT_WINDOW_MODE_ID","verifyClient","resolve","sendResult"]}