@wrongstack/core 0.292.0 → 0.292.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/types/blocks.ts", "../../src/types/tool.ts", "../../src/types/tool-executor.ts", "../../src/types/tool-markers.ts", "../../src/utils/string.ts", "../../src/utils/error.ts", "../../src/utils/expect-defined.ts", "../../src/types/config.ts", "../../src/types/system-prompt.ts", "../../src/utils/regex-guard.ts", "../../src/utils/session-scoped-path.ts", "../../src/types/errors.ts", "../../src/types/provider.ts", "../../src/types/default-config.ts", "../../src/types/memory.ts", "../../src/types/prompt.ts", "../../src/types/prompt-registry.ts", "../../src/types/design-kit.ts", "../../src/types/mode-prompts.ts", "../../src/types/mode.ts", "../../src/types/context-window.ts", "../../src/types/spec.ts", "../../src/types/task-graph.ts", "../../src/storage/session-reader.ts"],
4
- "sourcesContent": ["export interface TextBlock {\n type: 'text';\n text: string;\n cache_control?: { type: 'ephemeral' | undefined };\n}\n\nexport interface ToolUseBlock {\n type: 'tool_use';\n id: string;\n name: string;\n input: Record<string, unknown>;\n /**\n * Provider-specific opaque metadata captured from the wire response.\n * Echoed back verbatim in the next request so providers that bind\n * extra state to function calls keep working. Example: Gemini's\n * `thoughtSignature` \u2014 required for tool-use turns with thinking\n * models, otherwise the next request fails with 400 \"Function call\n * is missing a thought_signature in functionCall parts\".\n *\n * Keys are namespaced by intent so multiple wires can coexist:\n * - `google.thoughtSignature` \u2014 Gemini signed-thought blob\n * Other providers can add their own keys without colliding.\n */\n providerMeta?: Record<string, unknown>;\n}\n\nexport interface ToolResultBlock {\n type: 'tool_result';\n tool_use_id: string;\n /**\n * The original tool name. Useful for providers like Google Gemini that\n * need the tool name in `functionResponse.name` \u2014 the tool_use_id is\n * only a session-local identifier and is not stable across replays.\n * Always set by ToolExecutor; may be absent on manually-constructed blocks.\n */\n name?: string | undefined;\n content: string;\n is_error?: boolean | undefined;\n}\n\nexport interface ImageBlock {\n type: 'image';\n source: {\n type: 'base64' | 'url';\n media_type?: string | undefined;\n data?: string | undefined;\n url?: string | undefined;\n };\n}\n\n/**\n * Chain-of-thought / extended-thinking content emitted by the model.\n *\n * Both Anthropic extended thinking (`{type:'thinking', thinking, signature}`)\n * and DeepSeek reasoning mode (top-level `reasoning_content` on the assistant\n * message) require this content to be echoed back verbatim on the next\n * request, otherwise the provider returns 400:\n * - Anthropic: \"The `content[].thinking` in the thinking mode must be passed back\"\n * - DeepSeek: \"The `reasoning_content` in the thinking mode must be passed back\"\n *\n * `signature` is Anthropic-specific (an opaque integrity blob). DeepSeek\n * doesn't issue a signature \u2014 the field is absent for that provider.\n *\n * Per Anthropic, thinking blocks MUST appear before any text/tool_use blocks\n * in an assistant message. Stream builders preserve that order.\n */\nexport interface ThinkingBlock {\n type: 'thinking';\n thinking: string;\n signature?: string | undefined;\n providerMeta?: Record<string, unknown>;\n}\n\nexport type ContentBlock = TextBlock | ToolUseBlock | ToolResultBlock | ImageBlock | ThinkingBlock;\n\nexport function isTextBlock(b: ContentBlock): b is TextBlock {\n return b.type === 'text';\n}\nexport function isToolUseBlock(b: ContentBlock): b is ToolUseBlock {\n return b.type === 'tool_use';\n}\nexport function isToolResultBlock(b: ContentBlock): b is ToolResultBlock {\n return b.type === 'tool_result';\n}\nexport function isImageBlock(b: ContentBlock): b is ImageBlock {\n return b.type === 'image';\n}\n", "import type { Context } from '../core/context.js';\n\nexport type Permission = 'auto' | 'confirm' | 'deny';\n\n/**\n * Risk tier for tools in UI/audit surfaces. YOLO auto-approves non-denied\n * calls regardless of risk tier; when YOLO is off, risk can inform prompts.\n *\n * - `safe` \u2014 read-only, no side effects (read, glob, grep, etc.)\n * - `standard` \u2014 non-destructive writes and mutations (write, edit, safe shell commands)\n * - `destructive` \u2014 irreversible or broadside effects (recursive deletes, db drops, etc.)\n */\nexport type RiskTier = 'safe' | 'standard' | 'destructive';\n\n/**\n * Icon identifiers for tools \u2014 each UI (WebUI/TUI/REPL) maps these to its own icon library.\n * Add the icon directly on each Tool so all UIs consume the same canonical value.\n */\nexport type ToolIconId =\n | 'file' // read, write \u2014 document operations\n | 'edit' // edit, patch \u2014 modifying files\n | 'search' // grep, search \u2014 searching content\n | 'folder' // glob \u2014 file discovery\n | 'terminal' // bash, exec \u2014 shell commands\n | 'web' // fetch \u2014 HTTP requests\n | 'git' // git \u2014 version control\n | 'tree' // tree \u2014 directory structure\n | 'code' // lint, format, typecheck \u2014 code quality\n | 'test' // test \u2014 testing\n | 'package' // install, audit, outdated \u2014 package management\n | 'document' // document \u2014 documentation\n | 'scaffold' // scaffold \u2014 project generation\n | 'todo' // todo \u2014 task tracking\n | 'plan' // plan \u2014 planning\n | 'task' // task \u2014 structured work items\n | 'meta' // tool-use, batch-tool-use, tool-search, tool-help \u2014 meta tools\n | 'index' // codebase-index, codebase-search, codebase-stats \u2014 code indexing\n | 'json' // json \u2014 JSON operations\n | 'diff' // diff \u2014 comparing changes\n | 'logs' // logs \u2014 log viewing\n | 'settings' // set-working-dir \u2014 configuration\n | 'fallback'; // unknown tool \u2014 fallback icon\n\nexport interface JSONSchema {\n type?: string | undefined;\n properties?: Record<string, JSONSchema>;\n required?: string[] | undefined;\n items?: JSONSchema | undefined;\n enum?: unknown[] | undefined;\n description?: string | undefined;\n [k: string]: unknown;\n}\n\n/**\n * Tool progress event \u2014 yielded by `Tool.executeStream` to give the UI\n * something to render while a long-running tool works. The executor\n * publishes each event via EventBus as `tool.progress` so the TUI, logger,\n * and observability layer can consume them uniformly.\n *\n * Keep events small. They are buffered through the EventBus synchronously\n * and rendered on the main thread.\n */\nexport interface ToolProgressEvent {\n /**\n * - `log` \u2014 verbose informational message (e.g. \"scanning\u2026\")\n * - `warning` \u2014 non-fatal issue (e.g. \"skipped X due to ENOENT\")\n * - `metric` \u2014 numeric data (e.g. files scanned so far)\n * - `file_changed` \u2014 a tool that mutates the workspace announces a write\n * - `partial_output` \u2014 stream of textual output (bash stdout, fetch body)\n */\n type: 'log' | 'warning' | 'metric' | 'file_changed' | 'partial_output';\n text?: string | undefined;\n data?: Record<string, unknown>;\n /** Canonical or project-relative target for file_changed events. */\n path?: string | undefined;\n operation?: 'write' | 'edit' | 'delete' | 'rename' | undefined;\n line?: number | undefined;\n endLine?: number | undefined;\n}\n\n/**\n * Terminal event for `executeStream`. The output must match the tool's\n * declared output type \u2014 the executor unwraps `output` and treats it like\n * a normal `execute` return value.\n */\nexport interface ToolFinalEvent<O> {\n type: 'final';\n output: O;\n}\n\nexport type ToolStreamEvent<O = unknown> = ToolProgressEvent | ToolFinalEvent<O>;\n\nexport interface Tool<I = unknown, O = unknown> {\n name: string;\n description: string;\n /**\n * Pre-computed token estimate for this tool's definition (name +\n * description + JSON-serialized inputSchema). Set by ToolRegistry on\n * registration; consumed by estimateToolDefTokens / estimateRequestTokens\n * to skip redundant JSON.stringify on every context-pressure check.\n */\n _estDefTokens?: number | undefined;\n usageHint?: string | undefined;\n /** Structured guidance for choosing between similar tools. */\n selection?:\n | {\n /** A concise boundary where this tool should not be selected. */\n doNotUseWhen: string;\n /** Tool names the model should prefer for that boundary. */\n useInstead?: readonly string[] | undefined;\n }\n | undefined;\n /** Optional category for grouping in help lists and system prompts. */\n category?: string | undefined;\n inputSchema: JSONSchema;\n permission: Permission;\n mutating: boolean;\n /**\n * Risk tier for selective YOLO gating. When YOLO is active, clearly\n * destructive calls still emit `confirm`. Defaults to `standard` when\n * omitted \u2014 callers should always check `riskTier` after the basic\n * permission decision.\n */\n riskTier?: RiskTier | undefined;\n /**\n * Input-field name that the permission policy should match trust rules\n * against. Without this, the policy falls back to a heuristic\n * (`command` / `path` / `url` / `name`) that can collide across tools \u2014\n * e.g. an HTTP tool whose `path` means \"request path\" would be checked\n * against filesystem-path trust rules. Set explicitly to avoid the\n * cross-tool subject collision.\n *\n * The named field's value must be a string at runtime; non-string values\n * fall back to the heuristic.\n */\n subjectKey?: string | undefined;\n maxOutputBytes?: number | undefined;\n timeoutMs?: number | undefined;\n /**\n * The tool owns its timeout/idle policy and only needs the executor to\n * propagate the parent abort signal. Use this sparingly for orchestration\n * tools such as `delegate` that already enforce a heartbeat-aware timeout;\n * otherwise the executor's fixed max-tool timeout can kill healthy work.\n */\n managesOwnTimeout?: boolean | undefined;\n /**\n * Hint for the TUI spinner \u2014 does NOT affect actual timeout enforcement.\n * Use `timeoutMs` for hard limits. Leave undefined when duration varies\n * unpredictably.\n */\n estimatedDurationMs?: number | undefined;\n\n /**\n * Declarative security capabilities granted by this tool.\n *\n * Examples: \"shell.arbitrary\", \"fs.write\", \"fs.write.outside-project\",\n * \"net.outbound\", \"mcp.proxy\", \"subagent.spawn\", \"config.mutate\".\n *\n * These are used by permission policies (especially subagent guards) and\n * future capability-based allowlists. Prefer well-known values over ad-hoc strings.\n *\n * This field is optional for backward compatibility. Tools without it are\n * treated conservatively by guards.\n */\n capabilities?: readonly string[] | undefined;\n /**\n * Icon identifier for this tool \u2014 consumed by all UIs (WebUI/TUI/REPL) to\n * render a tool-specific icon instead of a generic fallback.\n * Each UI maps this id to its own icon library.\n */\n icon?: ToolIconId | undefined;\n execute(input: I, ctx: Context, opts: { signal: AbortSignal }): Promise<O>;\n /**\n * Optional cross-field validation hook. Called by the executor AFTER\n * JSON Schema validation passes and AFTER PreToolUse hooks may have\n * rewritten the input, but BEFORE permission checks and execution.\n *\n * Use this for invariants the JSON Schema cannot express \u2014 e.g.\n * `old_string !== new_string` in edit, or `end > start` in a range tool.\n * Return an array of validation errors (empty = valid). The executor\n * surfaces them to the model just like schema validation errors, so the\n * model can self-correct without the tool's `execute()` running.\n *\n * P3 #16 (before-release.md): tools that implement cross-field checks\n * inside `execute()` can migrate them here for earlier rejection and\n * consistent error formatting.\n */\n validate?(input: I): string[];\n /**\n * Optional streaming variant. When defined, the executor prefers this\n * over `execute` \u2014 yielded events become `tool.progress` EventBus events\n * and the terminal `final` event provides the output. Tools that don't\n * have intermediate state shouldn't implement this; the default `execute`\n * path is more efficient.\n */\n executeStream?(\n input: I,\n ctx: Context,\n opts: { signal: AbortSignal },\n ): AsyncIterable<ToolStreamEvent<O>>;\n /**\n * Optional teardown hook fired by the executor when the tool's run is\n * aborted (signal triggered). Errors thrown here are swallowed so they\n * never mask the originating failure.\n *\n * **When to use `cleanup` vs `ctx.registerAbortHook`:**\n *\n * - Use `cleanup` for resources **owned by the tool author** that are\n * established at execute-time: child processes spawned by the tool,\n * file handles opened by the tool, network connections initiated by\n * the tool. The lifecycle is co-located with the tool definition, so\n * readers see the resource and its teardown in one place.\n *\n * ```ts\n * async execute(input, ctx, opts) {\n * const child = spawn(...);\n * // \u2026 tool work \u2026\n * },\n * async cleanup(_input, _ctx) {\n * // best-effort kill of any child still running\n * }\n * ```\n *\n * - Use `ctx.registerAbortHook` for **context-scoped teardown** registered\n * dynamically inside `execute`: when the tool delegates to a library\n * that needs cancellation, or when the resource is created lazily\n * somewhere down the call stack and the natural cleanup point isn't\n * at the tool boundary. The hook fires when the **agent run** ends,\n * not when this specific tool call aborts.\n *\n * ```ts\n * async execute(input, ctx, opts) {\n * const handle = openHelper();\n * ctx.registerAbortHook(() => handle.dispose());\n * // \u2026 work \u2026\n * }\n * ```\n *\n * If both are registered for the same resource, `cleanup` fires first\n * (on tool abort) and the abort-hook fires after on the wider run abort.\n * Avoid double-free by gating one on the other's effect, or pick a single\n * teardown channel per resource.\n */\n cleanup?(input: I, ctx: Context): Promise<void>;\n /**\n * Optional custom output serializer. When present, the executor's output\n * serializer calls this INSTEAD of the central `renderToolObject()` switch\n * \u2014 the tool owns its own pretty-printing.\n *\n * Return a string representation of the output that the model will see in\n * its tool_result block. The serializer applies the iteration output cap\n * AFTER this runs, so don't worry about truncation.\n *\n * P3 #21 (before-release.md): `renderToolObject()` is a god function with\n * 30+ per-tool branches, far from each tool's definition. New tools that\n * want custom output no longer need to add a branch there \u2014 they implement\n * this method instead. Existing branches stay until migrated incrementally.\n */\n serialize?(output: O, input: I): string;\n}\n\nexport interface ToolCallContext {\n tool: Tool;\n input: unknown;\n callId: string;\n ctx: Context;\n signal: AbortSignal;\n}\n\n/**\n * Error categories for tool execution failures.\n * Used by the executor to classify errors and determine retry strategy.\n */\nexport enum ToolErrorCategory {\n TRANSIENT = 'transient', // ETIMEDOUT, ECONNRESET, network timeout, HTTP 429/503\n NOT_FOUND = 'not_found', // ENOENT, ENOTDIR, HTTP 404\n PERMISSION = 'permission', // EACCES, EPERM, HTTP 401/403\n VALIDATION = 'validation', // schema validation error, HTTP 400\n FATAL = 'fatal', // unhandled exception, crash, invariant violation\n}\n\n/**\n * Structured tool error information for the LLM and retry logic.\n */\nexport interface ToolErrorInfo {\n readonly category: ToolErrorCategory;\n /** Whether the operation can be retried automatically. */\n readonly retryable: boolean;\n /** User-facing message describing the error. */\n readonly userMessage: string;\n /** Optional technical detail for debugging. */\n readonly detail?: string;\n}\n", "import type { ToolResultBlock, ToolUseBlock } from '../types/blocks.js';\nimport type { Tool } from '../types/tool.js';\n\n/** Context.meta key installed by ToolExecutor for governed calls made by meta-tools. */\nexport const GOVERNED_TOOL_EXECUTOR_META_KEY = 'toolExecutor.executeGoverned';\n\n/** Result returned to meta-tools after a nested call traverses the normal executor. */\nexport interface GovernedToolExecutionResult {\n success: boolean;\n result?: unknown | undefined;\n error?: string | undefined;\n}\n\n/** Governed execution bridge exposed to meta-tools through Context.meta. */\nexport type GovernedToolExecutor = (\n toolName: string,\n input: Record<string, unknown>,\n) => Promise<GovernedToolExecutionResult>;\n\n/**\n * Input for a single tool execution, scoped to a single iteration's budget.\n */\nexport interface ToolExecution {\n toolUse: ToolUseBlock;\n result: ToolResultBlock;\n /** True if the tool was not found in the registry. */\n unknownTool?: boolean | undefined;\n /** True if the tool execution threw an exception. */\n threw?: boolean | undefined;\n}\n\n/**\n * Output from a single tool execution.\n */\nexport interface ToolExecutionOutput {\n result: ToolResultBlock | ToolConfirmPendingResult;\n tool?: Tool | undefined;\n durationMs: number;\n}\n\n/**\n * Result of running a batch of tools for a single agent iteration.\n */\nexport interface ToolBatchResult {\n outputs: ToolExecutionOutput[];\n remainingBudget: number;\n}\n\nexport type ConfirmAwaiter = (\n tool: Tool,\n input: unknown,\n toolUseId: string,\n suggestedPattern: string,\n) => Promise<'yes' | 'no' | 'always' | 'deny'>;\n\nexport interface ToolExecutorOptions {\n permissionPolicy: import('../types/permission.js').PermissionPolicy;\n secretScrubber: import('../types/secret-scrubber.js').SecretScrubber;\n renderer?: import('../types/renderer.js').Renderer | undefined;\n /**\n * Optional event bus. When provided, the executor emits `tool.started`\n * before invoking each tool's `execute()`. Closes the observability gap\n * between \"model decided to call tool\" and \"tool finished\".\n */\n events?: import('../kernel/events.js').EventBus | undefined;\n /**\n * Optional tracer. When provided, every tool execution opens a\n * `tool.<name>` span with attributes for tool name, permission decision,\n * input size, output size, and outcome. Spans are no-op by default.\n */\n tracer?: import('../types/observability.js').Tracer | undefined;\n /**\n * Optional structured logger for production diagnostics. Tool execution logs\n * include correlation IDs and metadata only \u2014 never raw tool inputs or output.\n */\n logger?: import('../types/logger.js').Logger | undefined;\n /**\n * Async callback invoked when a tool needs user confirmation.\n * When omitted and confirmation is required, the executor returns a\n * failure result immediately (TUI path). When provided (CLI path),\n * the callback handles the interactive prompt and returns a decision.\n */\n confirmAwaiter?: ConfirmAwaiter | undefined;\n iterationTimeoutMs?: number | undefined;\n /** Hard upper bound for a single tool call timeout. Defaults to 5 minutes. */\n maxToolTimeoutMs?: number | undefined;\n perIterationOutputCapBytes?: number | undefined;\n /**\n * Optional lifecycle hook runner. When present, `PreToolUse` hooks run\n * before the permission check (and can block the call or rewrite its input)\n * and `PostToolUse` hooks run after the tool returns (and can append context\n * to the result the model sees).\n */\n hookRunner?: import('../hooks/runner.js').HookRunner | undefined;\n /**\n * Per-tool on-screen result render mode map (`tools.resultRenderMode[name]`).\n * When set, the executor reads this map to decide whether the next\n * `writeToolResult` call should render in `simple` (meta only) or `extend`\n * (full preview) mode. Independent of the LLM-side `descriptionMode`.\n */\n resultRenderModes?: import('./config.js').ToolResultRenderModeConfig | undefined;\n}\n\nexport interface ToolExecutorInit {\n registry: import('../registry/tool-registry.js').ToolRegistry;\n options: ToolExecutorOptions;\n}\n\n/**\n * Result returned by executeBatch when a tool needs confirmation and\n * no confirmAwaiter is available. The TUI catches this and surfaces a\n * confirmation dialog; once resolved the tool is re-executed.\n * The string tag identifies it as a \"pending confirm\" result so callers\n * can distinguish it from an error without inspecting content strings.\n */\nexport interface ToolConfirmPendingResult {\n type: 'tool_confirm_pending';\n toolUseId: string;\n toolName: string;\n input: unknown;\n suggestedPattern: string;\n decisionSource?: import('./permission.js').PermissionDecision['source'] | undefined;\n riskTier?: import('./tool.js').RiskTier | undefined;\n /** Present when approval is required specifically by a Kanban scope. */\n boundaryReason?: string | undefined;\n}\n\nexport type ToolExecutorStrategy = 'parallel' | 'sequential' | 'smart';\n\n/**\n * Minimal contract for tool execution.\n *\n * Defined here (in `types/`) so `core/` does not need to import the\n * concrete `ToolExecutor` class from `execution/`. Callers that create\n * the executor (e.g. CLI wiring) implement this interface.\n *\n * Only the methods actually called by `Agent` are included \u2014 keeping the\n * interface narrow prevents unnecessary coupling.\n */\nexport interface ToolExecutorLike {\n /**\n * Execute a batch of tool uses. The strategy controls whether tools run\n * sequentially, in parallel, or smart (parallel non-mutating + sequential mutating).\n */\n executeBatch(\n toolUses: import('./blocks.js').ToolUseBlock[],\n ctx: import('../core/context.js').Context,\n strategy: ToolExecutorStrategy,\n ): Promise<ToolBatchResult>;\n\n /**\n * Clear the interactive confirm awaiter so the executor returns\n * `ToolConfirmPendingResult` instead of blocking.\n */\n clearConfirmAwaiter(): void;\n\n /**\n * Execute a single tool with timeout and output capping.\n * Used by the agent when it needs to run one tool at a time.\n *\n * Returns the rendered `ToolResultBlock` plus the exact byte count it\n * consumed against the iteration output cap. The caller subtracts\n * `bytes` from the running budget \u2014 no second `Buffer.byteLength`\n * walk, and no `JSON.stringify` fallback for structured results.\n */\n executeTool(\n tool: Tool,\n use: ToolUseBlock,\n ctx: import('../core/context.js').Context,\n budget: number,\n ): Promise<{ block: ToolResultBlock; bytes: number }>;\n}\n", "/**\n * Sentinel keys provider adapters use to wrap tool-call arguments that could\n * not be parsed into a proper JSON object. Single source of truth \u2014 the core\n * tool executor (which DETECTS these markers to surface a friendly error)\n * defines them here, and the providers package (which PRODUCES them when\n * wrapping) imports from `@wrongstack/core`.\n *\n * P3 #14 (before-release.md): the list was duplicated in tool-executor.ts with\n * a \"Keep this list in sync\" comment \u2014 a manual rule that will eventually be\n * forgotten. Centralizing it removes the sync burden.\n *\n * Layering note: this lives in core (not providers) because the dependency\n * direction is providers \u2192 core, not the reverse. Putting it in providers\n * would force core into a forbidden upward dependency.\n *\n * Current markers:\n * - `__raw` \u2014 produced by `parseToolInput` (Anthropic / shared)\n * - `__raw_arguments` \u2014 produced by `contentFromOpenAI` (OpenAI / compatible)\n * - `_raw` \u2014 produced by the streaming response builder's\n * `safeJsonOrRaw` (legacy fallback)\n */\nexport const MALFORMED_ARG_MARKERS = ['__raw', '__raw_arguments', '_raw'] as const;\n", "/**\n * String utilities shared across the WrongStack codebase.\n */\n\n/**\n * Truncate a string to at most `max` characters, appending an ellipsis if it\n * was longer. Returns the original string unchanged when it fits.\n */\nexport function truncate(s: string, max: number): string {\n return s.length <= max ? s : `${s.slice(0, max - 1)}\u2026`;\n}\n", "/**\n * Converts an unknown error value to a human-readable string.\n * Used in 40+ files across the codebase to normalize error messaging.\n */\nexport function toErrorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n", "/** Assert a value is neither null nor undefined. Throws if it is.\n * Useful after optional chaining and indexed access when the\n * control flow guarantees the value exists but TypeScript can't\n * prove it (e.g. after a check on a related field). */\nexport function expectDefined<T>(value: T | null | undefined, label?: string): T {\n if (value === null || value === undefined) {\n const err = new Error(label ? `Expected ${label} to be defined` : 'Expected value to be defined');\n err.name = 'ExpectDefinedError';\n throw err;\n }\n return value;\n}\n", "import type { ContextWindowModeId } from './context-window.js';\nimport type { ConfiguredHook, HookEvent } from './hooks.js';\nimport type { WireFamily } from './models-registry.js';\nimport type { CacheTtl, Capabilities, ReasoningEffort } from './provider.js';\nimport type { Permission } from './tool.js';\n\n/**\n * Runtime reasoning controls the user can set per-session/project. Mapped into\n * the provider `Request.reasoning` field by the model-runtime request\n * middleware, gated by the active model's `reasoningConfig` capabilities so\n * unsupported values are omitted (and warned) instead of triggering provider\n * 400s. See `resolveReasoningForRequest()` in packages/core.\n */\nexport interface ModelRuntimeReasoningConfig {\n /**\n * Whether to send explicit reasoning enable/disable.\n * - 'auto' \u2192 do not send explicit fields; provider/model default wins\n * - 'on' \u2192 send `reasoning.enabled = true`\n * - 'off' \u2192 send `reasoning.enabled = false` only when the model supports disable\n */\n mode?: 'auto' | 'on' | 'off' | undefined;\n /** Reasoning effort. Only sent when the model advertises `effortSupported`. */\n effort?: ReasoningEffort | undefined;\n /** Preserve thinking across turns. Only sent when `preserveThinking !== 'unsupported'`. */\n preserve?: boolean | undefined;\n}\n\n/**\n * Runtime prompt-cache controls mapped into `Request.cache`. Currently only the\n * Anthropic TTL toggle (5m vs 1h) is exposed; other providers ignore it.\n */\nexport interface ModelRuntimeCacheConfig {\n ttl?: CacheTtl | undefined;\n /**\n * Opt-in explicit Gemini context caching. When true, the Google provider\n * creates a server-side `cachedContents` resource for the stable system\n * prefix (system instruction + tool defs) and references it by name instead\n * of resending it every turn. Default false: Gemini's automatic *implicit*\n * caching already covers a byte-stable prefix with no setup. Ignored by every\n * non-Google provider. Any failure in the create flow falls back to the\n * normal inline request, so enabling it can never break a request.\n */\n geminiExplicit?: boolean | undefined;\n}\n\n/**\n * Shared runtime controls applied to every provider request, regardless of host\n * (REPL / TUI / WebUI). The CLI installs a single request-pipeline middleware\n * that reads these and mutates the outgoing `Request`.\n */\nexport interface ModelRuntimeConfig {\n reasoning?: ModelRuntimeReasoningConfig | undefined;\n cache?: ModelRuntimeCacheConfig | undefined;\n /**\n * Generic generation parameters mapped directly onto `Request` fields.\n * Only sent when the active model's `Capabilities` advertise support.\n */\n parameters?: ModelRuntimeParametersConfig | undefined;\n}\n\n/**\n * Generic generation parameters the user can set per-session / per-project.\n * Each field maps to a `Request` field of the same name and is gated by the\n * corresponding `Capabilities` flag so unsupported models don't receive\n * parameters they'd reject.\n */\nexport interface ModelRuntimeParametersConfig {\n /** Top-K sampling (Anthropic, Gemini). Gated by `capabilities.topK`. */\n topK?: number | undefined;\n /** Frequency penalty (OpenAI, Gemini). Gated by `capabilities.frequencyPenalty`. */\n frequencyPenalty?: number | undefined;\n /** Presence penalty (OpenAI, Gemini). Gated by `capabilities.presencePenalty`. */\n presencePenalty?: number | undefined;\n /** Random seed (OpenAI, Gemini). Gated by `capabilities.seed`. */\n seed?: number | undefined;\n /** End-user identifier for abuse monitoring. */\n user?: string | undefined;\n /** Log probabilities (OpenAI, Gemini). Gated by `capabilities.logprobs`. */\n logprobs?: boolean | undefined;\n /** Number of top logprobs to return (OpenAI). Only when `logprobs` is true. */\n topLogprobs?: number | undefined;\n}\n\n/**\n * HQ client connection settings. Same-machine clients can auto-discover the\n * local HQ auth file; remote clients use this config-backed URL/token pair.\n */\nexport interface HqClientConfig {\n /** Enable HQ publishing. Env WRONGSTACK_HQ_ENABLED still overrides at runtime. */\n enabled?: boolean | undefined;\n /** HQ HTTP base URL, e.g. http://host:3499. */\n url?: string | undefined;\n /** Client token for /ws/client. Stored encrypted by SecretVault when persisted. */\n token?: string | undefined;\n /** Optional HQ data dir for same-machine auth.json discovery. */\n dataDir?: string | undefined;\n /** Send raw content previews to HQ instead of redacted previews. */\n rawContent?: boolean | undefined;\n /** Override project display name in HQ. */\n projectAlias?: string | undefined;\n}\n\n/**\n * Token-saving mode tier levels. Controls how aggressively the system prompt\n * is compacted to reduce per-request token consumption.\n *\n * - 'off' \u2014 Full prompt, all tools, complete guidance (no reduction)\n * - 'minimal' \u2014 TIER1 tools (13, including codebase index lifecycle), stripped guidance\n * - 'light' \u2014 Same Tier 1 tool surface, common patterns, minimal guidance\n * - 'medium' \u2014 TIER1 + TIER2 development tools, some guidance (default when `true`)\n * - 'aggressive' \u2014 Maximum savings before tools become unusable (~4-5k tokens saved)\n */\n/**\n * Prompt token-saving tiers. `'auto'` is an INPUT-only sentinel meaning \"pick a\n * concrete tier from the model's context window\" \u2014 it is resolved to one of the\n * concrete tiers by {@link resolveTokenSavingTier} before reaching the prompt\n * builder (which never sees `'auto'`; if it somehow does, it behaves as `'off'`,\n * i.e. the full prompt \u2014 the safe fallback).\n */\nexport type TokenSavingTier = 'off' | 'auto' | 'minimal' | 'light' | 'medium' | 'aggressive';\n\n/** Concrete tiers the prompt builder actually consumes ('auto' excluded). */\nexport type ConcreteTokenSavingTier = Exclude<TokenSavingTier, 'auto'>;\n\n/**\n * Normalize a TokenSavingTier value, handling backward-compatible boolean inputs.\n * - `true` \u2192 'medium' (existing behavior)\n * - `false` \u2192 'off'\n * - `'auto'` \u2192 `'off'` \u2014 the `'auto'` sentinel is window-dependent, so EVERY\n * consumer that isn't the prompt builder (tool selection, lazy-load gate, TUI\n * display) must treat it as the safe no-op `'off'`: it must NOT reduce the\n * registered tool set or enable lazy loading on its own. Only the prompt\n * builder expands `'auto'` \u2014 via {@link resolveTokenSavingTier} \u2014 and only for\n * the (cache-stable) prompt prose. This keeps auto-tiering capability-neutral.\n * - other valid strings are returned as-is; `undefined`/invalid \u2192 'off'\n */\nexport function normalizeTokenSavingTier(val?: TokenSavingTier | boolean): ConcreteTokenSavingTier {\n if (val === undefined) return 'off';\n if (typeof val === 'boolean') return val ? 'medium' : 'off';\n const validTiers = new Set<ConcreteTokenSavingTier>([\n 'off',\n 'minimal',\n 'light',\n 'medium',\n 'aggressive',\n ]);\n // 'auto' is deliberately absent \u2192 collapses to 'off' for non-prompt consumers.\n return validTiers.has(val as ConcreteTokenSavingTier) ? (val as ConcreteTokenSavingTier) : 'off';\n}\n\n/**\n * Resolve the effective (concrete) token-saving tier for the **prompt builder**,\n * expanding the `'auto'` sentinel from the model's context window. This is\n * **cache-safe**: the window is stable for a session, so it resolves to the same\n * tier every turn \u2014 the system-prompt prefix stays byte-stable and the provider\n * prompt cache is never busted by a shifting tier (unlike a per-turn\n * pressure-driven tier). It re-resolves only on `/model` switch, which busts the\n * cache anyway.\n *\n * Conservative thresholds (small windows only; large windows keep the full\n * prompt so nothing changes for the common 200k+/1M case):\n * - `< 32k` \u2192 `'medium'` (identity + tool prose is a big fraction \u2014 trim it)\n * - `< 96k` \u2192 `'light'`\n * - `>= 96k` \u2192 `'off'` (room to spare; favour cache stability + capability)\n * - unknown window \u2192 `'off'` (never guess a lean prompt without evidence)\n *\n * Explicit concrete tiers (a user who set `'medium'`, `'off'`, \u2026) are always\n * respected verbatim \u2014 `'auto'` is the only value that consults the window.\n */\nexport function resolveTokenSavingTier(\n val: TokenSavingTier | boolean | undefined,\n maxContext: number | undefined,\n): ConcreteTokenSavingTier {\n if (val === 'auto') {\n if (typeof maxContext !== 'number' || !Number.isFinite(maxContext) || maxContext <= 0) {\n return 'off';\n }\n if (maxContext < 32_000) return 'medium';\n if (maxContext < 96_000) return 'light';\n return 'off';\n }\n return normalizeTokenSavingTier(val);\n}\n\n/**\n * Verbosity of fleet/subagent activity streamed into the main TUI chat.\n * See {@link AutonomyConfig.fleetChatVerbosity}.\n */\nexport type FleetChatVerbosity = 'off' | 'full';\n\nexport const FLEET_CHAT_VERBOSITY_VALUES: readonly FleetChatVerbosity[] = ['off', 'full'];\n\n/**\n * Resolve the effective fleet-chat verbosity from autonomy config.\n * An explicit `fleetChatVerbosity` wins; otherwise the legacy `streamFleet`\n * boolean is honored (`false` \u2192 'off'); absence of both means 'off'.\n * `fleetChatVerbosity` must never be given a merge-time default \u2014 the\n * absence of the field is what lets legacy `streamFleet: false` configs\n * keep their intent.\n */\nexport function resolveFleetChatVerbosity(\n autonomy?: Pick<AutonomyConfig, 'fleetChatVerbosity' | 'streamFleet'>,\n): FleetChatVerbosity {\n const explicit = autonomy?.fleetChatVerbosity;\n if (explicit && (FLEET_CHAT_VERBOSITY_VALUES as readonly string[]).includes(explicit)) {\n return explicit;\n }\n if (autonomy?.streamFleet === false) return 'off';\n return 'off';\n}\n\nexport const DEFAULT_TUI_THINKING_WORD = 'thinking';\nexport const MAX_TUI_THINKING_WORD_LENGTH = 16;\n\n/**\n * Normalize the configurable statusline word shown while the TUI is working.\n * The value must be a single short word; invalid values fall back to the default.\n */\nexport function normalizeTuiThinkingWord(value: unknown): string {\n if (typeof value !== 'string') return DEFAULT_TUI_THINKING_WORD;\n const word = value.trim();\n if (word.length === 0 || word.length > MAX_TUI_THINKING_WORD_LENGTH) {\n return DEFAULT_TUI_THINKING_WORD;\n }\n if (!/^[\\p{L}\\p{N}_-]+$/u.test(word)) return DEFAULT_TUI_THINKING_WORD;\n return word;\n}\n\nexport interface ContextConfig {\n /** Context-window policy mode. Controls compaction thresholds and preservation depth. */\n mode?: ContextWindowModeId | undefined;\n warnThreshold: number;\n softThreshold: number;\n hardThreshold: number;\n /** Enable automatic compaction when thresholds are crossed (default: true). */\n autoCompact?: boolean | undefined;\n /**\n * Model used for LLM-assisted summarization in IntelligentCompactor.\n * Falls back to the main model when omitted.\n */\n summarizerModel?: string | undefined;\n /**\n * Override the effective context window size (in tokens). Use this when\n * you want the compactor to trigger earlier than the provider's actual\n * maxContext. Defaults to the provider's reported maxContext.\n */\n effectiveMaxContext?: number | undefined;\n maxSessionTokens?: number | undefined;\n maxDailyTokens?: number | undefined;\n preserveK: number;\n eliseThreshold: number;\n /** Compactor strategy: 'hybrid' (default, fast rules), 'intelligent' (LLM summarization), 'selective' (LLM-driven selection). */\n strategy?: 'hybrid' | 'intelligent' | 'selective' | undefined;\n /** Enable LLM-driven selective compaction (default: false for backward compat). */\n llmSelector?: boolean | undefined;\n}\n\n/**\n * Runtime configuration for the process circuit breaker (the one owned by the\n * ProcessRegistry that gates `bash`/`exec`). Toggle via `/settings breaker`.\n *\n * The breaker itself is a low-level primitive (`packages/tools/.../circuit-breaker.ts`)\n * that is on by default; this section controls whether the registry actually\n * participates in it and how it auto-recovers.\n */\nexport interface CircuitBreakerRuntimeConfig {\n /**\n * Enable circuit-breaker protection. When false (the default), the breaker\n * is bypassed \u2014 `bash`/`exec` calls always proceed regardless of failure\n * history. When true, the breaker trips on repeated failures / slow calls /\n * bursts and blocks further calls until it recovers.\n */\n enabled?: boolean | undefined;\n /**\n * When the breaker trips, automatically kill all tracked processes AND\n * reset the breaker to closed after this delay (ms). 0 = disabled (manual\n * recovery only via `/kill reset`). Only effective when `enabled` is true.\n * While armed, the statusline shows a live countdown to the kill/reset.\n */\n autoKillResetMs?: number | undefined;\n}\n\n/**\n * Adaptive concurrency controller configuration. When enabled, the controller\n * automatically adjusts `maxConcurrent` based on rate-limit (429) errors:\n * - On 429: halves `maxConcurrent` (floor at 1)\n * - On sustained success (no 429 for `recoveryIntervalMs`): increases `maxConcurrent` by 1\n */\nexport interface AdaptiveConcurrencyConfig {\n /** Enable adaptive concurrency. Default: false (disabled). */\n enabled?: boolean | undefined;\n /**\n * Minimum concurrency floor. The controller never drops below this.\n * Default: 1.\n */\n minConcurrent?: number | undefined;\n /**\n * Maximum concurrency ceiling. The controller never exceeds this.\n * Default: 16 (matches MultiAgentCoordinator default).\n */\n maxConcurrent?: number | undefined;\n /**\n * Multiplicative decrease factor when a 429 is hit.\n * `newConcurrency = floor(currentConcurrency * decreaseFactor)`.\n * Default: 0.5 (halves concurrency).\n */\n decreaseFactor?: number | undefined;\n /**\n * Number of consecutive successful requests before increasing concurrency by 1.\n * Default: 10.\n */\n successThreshold?: number | undefined;\n /**\n * How often (ms) to check for recovery and bump concurrency.\n * Default: 30_000 (30 seconds).\n */\n recoveryIntervalMs?: number | undefined;\n}\n\nexport interface ToolsConfig {\n defaultExecutionStrategy: 'parallel' | 'sequential' | 'smart';\n maxIterations: number;\n iterationTimeoutMs: number;\n /** Hard upper bound for a single tool call timeout. Defaults to 5 minutes. */\n maxToolTimeoutMs?: number | undefined;\n sessionTimeoutMs: number;\n perIterationOutputCapBytes: number;\n /**\n * Per-tool prose budget for the tool's top-level description and usage hint.\n * Missing entries default to \"extend\".\n */\n descriptionMode?: ToolDescriptionModeConfig | undefined;\n /**\n * Per-tool on-screen result rendering mode (terminal / WebUI / TUI).\n * Missing entries default to \"extend\". Independent of `descriptionMode`:\n * `/tool <name> result simple` toggles this without touching the\n * LLM-side description length.\n */\n resultRenderMode?: ToolResultRenderModeConfig | undefined;\n /**\n * Tool names to disable. Disabled tools are excluded from the tool registry\n * (`ToolRegistry.list()` / `get()`), so they do NOT appear in the system\n * prompt's \"## Tool usage\" block \u2014 reducing per-request token consumption.\n * Override per-session with `/tool enable <name>` or re-enable all via\n * `/tool enable-all`.\n */\n disabledTools?: string[] | undefined;\n /**\n * When true (default), the agent automatically extends its iteration\n * limit by 100 when hit. Set to false to require user confirmation.\n */\n autoExtendLimit?: boolean | undefined;\n /**\n * When true, file tools (read/write/edit/grep/glob/install) are confined to\n * the project root and `set_working_dir` may not leave it. Default: false \u2014\n * tools may access paths outside the project root, still subject to each\n * tool's permission tier (writes/edits prompt for confirmation). Toggle via\n * `/settings` (\"Filesystem access\").\n */\n restrictToProjectRoot?: boolean | undefined;\n /**\n * Per-command policy for the `exec` tool's allowlist. The tool ships a\n * curated default allowlist of dev/build commands; this extends or trims it.\n *\n * SECURITY: `allow` EXPANDS what the agent may execute, so it is honored only\n * from the trusted active-profile config \u2014 the config loader\n * strips `tools.exec.allow` from the untrusted, repo-committed\n * `<project>/.wrongstack/config.json`. `deny` only ever REMOVES commands, so\n * it is honored from any source.\n */\n exec?: ExecToolConfig | undefined;\n /**\n * Agent-loop repetition detector tuning. The detector watches two signals:\n * consecutive effectively-identical iterations (same tool-name set + inputs\n * + text) and per-call repeats (the same tool invoked with identical\n * arguments N times within a sliding window, even when interleaved with\n * other calls). In the default `steer-then-cut` mode the first detection\n * folds a corrective note into the conversation and lets the run continue;\n * only persistent repetition cuts the turn. Omitted fields use built-in\n * defaults (see DEFAULT_TOOLS_CONFIG.loopDetection).\n */\n loopDetection?: LoopDetectionConfig | undefined;\n}\n\n/** Tuning for the agent-loop repetition detector (`tools.loopDetection`). */\nexport interface LoopDetectionConfig {\n /**\n * `steer-then-cut` (default): inject a corrective note at the steer\n * threshold, cut the turn only if repetition persists to the cut threshold.\n * `cut`: legacy behavior \u2014 hard-stop at the steer threshold, per-call\n * detector disabled. `off`: disable loop detection entirely.\n */\n mode?: 'steer-then-cut' | 'cut' | 'off' | undefined;\n /** Consecutive identical iterations before the detector acts (default 3, min 2). */\n steerThreshold?: number | undefined;\n /**\n * Consecutive identical iterations at which the turn is cut in\n * `steer-then-cut` mode (default steerThreshold + 2, min steerThreshold + 1).\n */\n cutThreshold?: number | undefined;\n /** Sliding window of recent tool calls for per-call repeat detection (default 12, min 4). */\n windowSize?: number | undefined;\n /**\n * Identical (name + canonicalized args) calls within the window that\n * trigger a steer note (default 4, min 2).\n */\n callRepeatThreshold?: number | undefined;\n}\n\n/** Allow/deny extension of the `exec` tool's built-in command allowlist. */\nexport interface ExecToolConfig {\n /**\n * Extra command names to add to the allowlist (e.g. `[\"make\", \"dotnet\"]`).\n * Trusted sources only \u2014 stripped from in-project repo config.\n */\n allow?: string[] | undefined;\n /**\n * Command names to remove from the allowlist. Honored from any source \u2014\n * removing a command can only narrow what runs, so it is always safe.\n */\n deny?: string[] | undefined;\n /**\n * Per-rule bypass for the heuristic danger detector. Each entry is a\n * stable `matchedRule` id (e.g. `rm-recursive`, `git-push-force`); a\n * matched rule whose id is in this list is suppressed.\n *\n * Use case: a project that legitimately runs `rm -rf ./build` on every\n * CI run can add `\"rm-recursive\"` to bypass so the detector stops\n * emitting banners for that one rule \u2014 without disabling it for every\n * other `rm -rf` invocation.\n *\n * **Trusted sources only.** Bypassing a danger rule means the user\n * agreed to a specific destructive pattern; in-project repo config\n * could otherwise be used to silently opt everyone in. The boot path\n * strips this field from `<project>/.wrongstack/config.json` the\n * same way it strips `allow`.\n */\n danger?: ExecDangerConfig | undefined;\n}\n\nexport interface ExecDangerConfig {\n /**\n * List of danger rule ids to skip. Each id corresponds to a rule in\n * `@wrongstack/tools/src/_danger-detect.ts` (e.g. `rm-recursive`,\n * `git-push-force`, `inline-eval`, `sudo`). Unknown ids are ignored\n * (forward-compat: a rule added in a future version can be referenced\n * before the user upgrades).\n */\n bypass?: string[] | undefined;\n}\n\nexport type ToolDescriptionMode = 'extend' | 'simple';\nexport type ToolDescriptionModeConfig = Record<string, ToolDescriptionMode | undefined>;\n\n/**\n * Per-tool on-screen result rendering mode. Independent of\n * {@link ToolDescriptionMode}: `descriptionMode` controls the prose the\n * model sees in the system prompt, `resultRenderMode` controls how the\n * tool's RESULT is printed to the user (terminal / WebUI / TUI).\n *\n * - `simple` \u2014 meta only (filename, line count, exit code). Body is hidden\n * by default; the user can still expand on demand where the renderer\n * supports it.\n * - `extend` \u2014 full preview, up to 10 lines for read-like tools.\n *\n * The two modes are toggled independently via `/tool <name> desc simple`\n * and `/tool <name> result simple`. The legacy `/tool <name> simple`\n * command sets BOTH at once for backward compatibility.\n */\nexport type ToolResultRenderMode = 'extend' | 'simple';\nexport type ToolResultRenderModeConfig = Record<string, ToolResultRenderMode | undefined>;\n\nexport interface ProviderApiKey {\n /** Short human-readable label (e.g. \"personal\", \"work\", \"rate-limit-backup\"). */\n label: string;\n /**\n * The key itself. The field name contains `apiKey` so the secret-vault\n * walker will encrypt it on write and decrypt it on read.\n */\n apiKey: string;\n /** ISO-8601 timestamp the key was added. */\n createdAt: string;\n /**\n * How this credential was obtained.\n * - `api_key` \u2014 manually pasted API key (default)\n * - `oauth` \u2014 OAuth 2.0 device-code / authorization-code flow\n * - `session_token` \u2014 extracted from browser session (ChatGPT web, etc.)\n */\n authMethod?: 'api_key' | 'oauth' | 'session_token' | undefined;\n /** ISO-8601 expiry. When set, the token manager will refresh before this time. */\n expiresAt?: string | undefined;\n /**\n * OAuth refresh token. Stored encrypted by the secret-vault walker because\n * the field name contains `Token` (case-insensitive match by vault).\n */\n refreshToken?: string | undefined;\n /** Token type as returned by the OAuth endpoint (e.g. \"bearer\"). */\n tokenType?: string | undefined;\n /** OAuth scope string (e.g. \"openai.models.read openai.models.use\"). */\n scope?: string | undefined;\n /**\n * ChatGPT account id, extracted from the OAuth access-token JWT\n * (`https://api.openai.com/auth`.chatgpt_account_id). Sent as the\n * `chatgpt-account-id` header by the `openai-codex` wire family. Cached\n * here for display/diagnostics; the provider re-derives it from the live\n * token at request time so it can never go stale after a refresh.\n */\n accountId?: string | undefined;\n}\n\nexport interface ProviderConfig {\n type: string;\n /**\n * Legacy single-key field. Still honored as a read fallback when `apiKeys`\n * is empty (for configs not yet migrated to multi-key format). After key\n * management operations (`writeKeysBack`), this field is **cleared** to\n * prevent accidental serialization of the plaintext key. Consumers that\n * need the active API key should use `resolveActiveApiKey()` (cli) or\n * resolve from `apiKeys[]` directly \u2014 never read `cfg.apiKey` in new code.\n */\n apiKey?: string | undefined;\n /** Multiple keys for the same provider \u2014 pick one with `activeKey`. */\n apiKeys?: ProviderApiKey[] | undefined;\n /** Label of the entry in `apiKeys` to use. Defaults to the first one. */\n activeKey?: string | undefined;\n baseUrl?: string | undefined;\n headers?: Record<string, string>;\n model?: string | undefined;\n quirks?: Record<string, unknown>;\n capabilities?: Record<string, unknown>;\n /**\n * Optional wire-family override. When present, the provider can be\n * constructed without consulting the models.dev catalog \u2014 useful for\n * self-hosted endpoints, internal proxies, or for working offline.\n */\n family?: WireFamily | undefined;\n /** Custom env var names to probe when `apiKey` is missing. */\n envVars?: string[] | undefined;\n /** Optional list of models the user wants visible for this provider. */\n models?: string[] | undefined;\n /**\n * Fetch this provider's model list + per-model capabilities from its\n * `{baseUrl}/models` endpoint at startup and inject them into the catalog.\n * For openai-compatible gateways/proxies (omniroute, LiteLLM, vLLM, \u2026) that\n * expose rich metadata there. Defaults on for presets that set it (omniroute).\n * Discovery is best-effort: a down server or missing key is a no-op.\n */\n autoDiscoverModels?: boolean | undefined;\n /**\n * Provider-relative custom model definitions (maps modelId \u2192 definition).\n * Each entry adds/overrides a model for this provider with optional\n * capability overrides. The model id is the key, not a fully qualified id.\n */\n customModels?: Record<string, CustomModelDefinition>;\n /**\n * Per-provider OAuth configuration. When present, `wstack auth login <id>`\n * uses this instead of prompting for a raw API key. Set by the catalog or\n * by the user via `/settings`.\n */\n oauthConfig?:\n | {\n /** OAuth client id registered with the provider. */\n clientId?: string | undefined;\n /** Device authorization endpoint (RFC 8628). */\n deviceCodeEndpoint?: string | undefined;\n /** Token endpoint for code exchange and refresh. */\n tokenEndpoint?: string | undefined;\n /** Authorization server URL shown to the user for opening in browser. */\n authorizationEndpoint?: string | undefined;\n /** Default OAuth scopes to request. */\n scopes?: string[] | undefined;\n }\n | undefined;\n}\n\n/**\n * One entry in the per-task model matrix. Pins a catalog role, a phase, or\n * the `*` default to a specific model (and, optionally, a specific provider).\n * Resolved at subagent-spawn time so e.g. `security-scanner` can run a\n * different model than `documentation` while the leader stays on its own.\n */\nexport interface ModelMatrixEntry {\n /** Provider registry id (e.g. \"anthropic\", \"minimax\", \"zai\"). When omitted,\n * the leader's provider is used with this entry's model. */\n provider?: string | undefined;\n /** Model id to run for the matched role/phase/default. */\n model?: string | undefined;\n /**\n * Runtime request overrides for subagents matched by this entry. This is\n * intentionally scoped to subagents: leader requests keep using top-level\n * `Config.modelRuntime`, while a role/phase can opt into its own reasoning\n * effort, cache TTL, or gated generation parameters.\n */\n modelRuntime?: ModelRuntimeConfig | undefined;\n /**\n * Named fallback profile to use for the matched role/phase/default. When\n * `model` is omitted, the first model in the profile becomes the primary and\n * the remaining entries become that subagent's fallback chain.\n */\n fallbackProfile?: string | undefined;\n}\n\nexport interface MCPServerConfig {\n /** Human-readable description shown in `wstack mcp list`. */\n description?: string | undefined;\n name: string;\n transport: 'stdio' | 'sse' | 'streamable-http';\n command?: string | undefined;\n args?: string[] | undefined;\n env?: Record<string, string>;\n url?: string | undefined;\n headers?: Record<string, string>;\n enabled?: boolean | undefined;\n allowedTools?: string[] | undefined;\n permission?: Permission | undefined;\n startupTimeoutMs?: number | undefined;\n requestTimeoutMs?: number | undefined;\n /**\n * Lazy connect: when true, the server process is NOT spawned at boot. Its\n * tools are registered from a cached manifest (discovered on the first ever\n * connect) and the server only spawns when one of its tools is actually\n * called, then auto-sleeps after an idle period. Default (false/undefined) =\n * eager connect at boot.\n */\n lazy?: boolean | undefined;\n /**\n * Allowlist of environment variable names to forward from the parent process\n * to this MCP server's child process. The values are resolved from\n * `process.env` at spawn time, NOT stored in the config file.\n *\n * Why this exists: WrongStack's `buildChildEnv()` security filter scrubs\n * env vars whose names look like secrets (TOKEN, SECRET, AUTH, KEY, ...)\n * from all child processes \u2014 this prevents a compromised MCP server from\n * exfiltrating provider API keys. But most MCP servers (GitHub, Slack,\n * Brave Search, ...) need their own API tokens from the environment.\n * `passthroughEnv` is the explicit bypass: only vars listed here survive\n * the filter, and they go through the `extra` path (unfiltered merge).\n *\n * Built-in presets declare their required env vars here so they work\n * out of the box when the user has the corresponding env vars exported\n * in their shell. Users can also add entries for custom servers.\n *\n * Example: passthroughEnv: ['GITHUB_PERSONAL_ACCESS_TOKEN', 'GITHUB_TOKEN']\n */\n passthroughEnv?: string[] | undefined;\n /**\n * Operational-health settings for this MCP server. Thresholds are optional;\n * when omitted the server is considered healthy as long as its connection\n * lifecycle succeeds. Latency thresholds compare against the rolling p95 of\n * the bounded sample buffer; the in-flight threshold compares against the\n * observed peak in-flight call count.\n */\n health?: MCPHealthConfig | undefined;\n}\n\n/** Per-server operational-health knobs. */\nexport interface MCPHealthConfig {\n thresholds?: MCPHealthThresholds | undefined;\n}\n\n/**\n * Configurable thresholds that can push an otherwise-healthy MCP server into\n * the `degraded` health state. All thresholds are optional and disabled when\n * omitted so existing behaviour is preserved.\n */\nexport interface MCPHealthThresholds {\n /** Connection latency p95 above this value marks the server degraded. */\n connectionLatencyP95Ms?: number | undefined;\n /** Discovery (capability listing) latency p95 above this marks degraded. */\n discoveryLatencyP95Ms?: number | undefined;\n /** Tool-call latency p95 above this marks degraded. */\n callLatencyP95Ms?: number | undefined;\n /** Peak in-flight calls above this marks the server saturated/degraded. */\n inFlightCalls?: number | undefined;\n}\n\nexport interface LogConfig {\n level: 'error' | 'warn' | 'info' | 'debug' | 'trace';\n file?: string | undefined;\n}\n\nexport interface PluginConfig {\n name: string;\n enabled?: boolean | undefined;\n options?: Record<string, unknown>;\n}\n\n/**\n * Optional subsystems that the CLI can boot without. The core flow\n * (provider + agent loop + bundled tools + session) always works; these\n * just add capabilities. `--no-features` flips all of these off, which\n * is the minimum viable WrongStack: a single provider, a fixed config,\n * no network calls at startup.\n */\nexport interface FeaturesConfig {\n /** Load MCP servers declared in `mcpServers`. */\n mcp: boolean;\n /** Load + initialise npm plugins declared in `plugins`. */\n plugins: boolean;\n /** Register `remember` / `forget` tools backed by memory store. */\n memory: boolean;\n /**\n * Automatically consolidate session learnings into long-term memory\n * after each completed run. The agent extracts key facts, conventions,\n * and decisions via a lightweight LLM call and persists them.\n * Enabled by default when `memory` is on; set to false to opt out.\n */\n memoryConsolidation?: boolean | undefined;\n /** Fetch the models.dev catalog at startup. When false, the provider\n * must declare its `family` explicitly in `providers[<id>]`. */\n modelsRegistry: boolean;\n /** Discover + load skills from disk. */\n skills: boolean;\n /**\n * Enable the prompt library (`/prompt`, `/prompts`, `/prompt-gen`, the WebUI\n * modal and the bundled 168-prompt dataset). Defaults to on; set to false to\n * disable the subsystem entirely (the loader is withheld so every surface\n * reports it unavailable).\n */\n prompts?: boolean | undefined;\n /**\n * Token-saving mode tier. Controls how aggressively the system prompt\n * is compacted to reduce per-request token consumption.\n *\n * - 'off' \u2014 Full prompt, all tools, complete guidance\n * - 'minimal' \u2014 TIER1 tools only, stripped guidance (~3-4k tokens saved)\n * - 'light' \u2014 Core + memory tools, common patterns, minimal guidance\n * - 'medium' \u2014 Most development tools, some guidance\n * - 'aggressive' \u2014 Maximum savings before tools become unusable (~4-5k tokens)\n *\n * Boolean values are accepted for backward compatibility:\n * - `true` \u2192 'medium'\n * - `false` \u2192 'off'\n *\n * Enable via CLI: `--token-saving-tier <level>` or `--token-saving-mode` (maps to 'medium').\n * Configure via: `features.tokenSavingMode: \"minimal\"` in config.\n */\n tokenSavingMode?: TokenSavingTier | boolean | undefined;\n /**\n * Enable the autonomous-coordination toolkit (AutonomousCoordinator +\n * KnowledgeGraph + ConsensusProtocol + TaskAuctioneer + ChangeManager +\n * TaskDAG). When true (the default), the TUI boot wires the coordinator\n * lazily on the first Director spawn. When false, the coordinator is\n * never constructed and the `/coordinator` slash command reports it\n * unavailable \u2014 reducing the coordination domain's runtime surface for\n * users who only use the simpler Director/Fleet path.\n */\n autonomousCoordination?: boolean | undefined;\n /**\n * Allow tools to read/write paths outside the project root directory.\n * When true (default), tools can access any path on the filesystem.\n * When false, tools are restricted to the project root directory.\n */\n allowOutsideProjectRoot?: boolean | undefined;\n /**\n * Auto-bootstrap the mailbox HTTP bridge from any WrongStack surface\n * (REPL/TUI/WebUI/eternal). When 'auto' (the default), the first\n * surface to come up for a given project joins or spawns the bridge\n * so external agents can connect without the user running\n * `wstack mailbox serve` themselves. 'off' disables this \u2014 operators\n * must start the bridge explicitly (e.g. via the `/mailbox-serve`\n * slash command or the standalone `wstack mailbox serve` subcommand).\n * The per-project lock + token-persistence model means a second\n * surface on the same project joins the first's bridge rather than\n * spawning a duplicate.\n */\n mailboxBridge?: 'auto' | 'off' | undefined;\n}\n\nexport interface SuperMemoryConfig {\n /**\n * Default: true. Super Memory is the ONLY memory backend \u2014 this flag no longer\n * swaps the store. When `false`, the backend is still Super Memory (explicit\n * `/memory`, agent memory tools, and WebUI all keep working); only automatic\n * context injection and session-end hygiene are turned off.\n */\n enabled?: boolean | undefined;\n storage?:\n | {\n /** Store memory inside the project under a gitignored directory. Default: true. */\n projectLocal?: boolean | undefined;\n /** Project-relative directory. Default: \".wrongstack/memories\". */\n directory?: string | undefined;\n /** Storage engine: 'jsonl' (default, append-only JSONL) or 'sqlite' (indexed + FTS5 search, auto-migrates from JSONL). */\n engine?: 'jsonl' | 'sqlite' | undefined;\n }\n | undefined;\n inject?:\n | {\n /** Add relevant memory to ordinary turn-level context. Default: false (opt-in). */\n turnContext?: boolean | undefined;\n /** Add relevant memory to read/tree/grep/bash/edit tool results. Default: true. */\n toolResults?: boolean | undefined;\n /** Enrich tool retrieval with live todo/Kanban task state and context-pressure budgeting. Default: true. */\n taskAware?: boolean | undefined;\n /** Maximum diverse, structurally related hints appended to a single tool result. Default: 8. */\n maxHintsPerTool?: number | undefined;\n /** Maximum characters appended to a single tool result. Default: 2800. */\n maxCharsPerTool?: number | undefined;\n /** Maximum memories appended to ordinary turn context. Default: 8. */\n maxTurnMemories?: number | undefined;\n /** Maximum characters appended to ordinary turn context. Default: 2400. */\n maxCharsPerTurn?: number | undefined;\n /** Minimum retrieval score for ordinary hints. Default: 0.65. */\n minScore?: number | undefined;\n /** Cooldown before the same memory can be injected again. Default: 30 minutes. */\n repeatCooldownMs?: number | undefined;\n triggers?:\n | Partial<\n Record<\n | 'read'\n | 'tree'\n | 'grep'\n | 'glob'\n | 'codebase_search'\n | 'bash'\n | 'write'\n | 'edit'\n | 'patch',\n boolean\n >\n >\n | undefined;\n }\n | undefined;\n retrieval?:\n | {\n /**\n * Weight given to the metadata score floor (0\u20131) in the relevance-blended\n * scoring formula: `metadataScore * (metadataWeight + relevance * (1 - metadataWeight))`.\n * At 0.0, relevance fully gates injection. At 1.0, metadata alone decides.\n * Default: 0.3 \u2014 validated against 148 real query-memory pairs.\n */\n metadataWeight?: number | undefined;\n }\n | undefined;\n hygiene?:\n | {\n /** Run hygiene after successful sessions. Default: true. */\n autoAfterSession?: boolean | undefined;\n /** Re-check anchored memories when files are edited. Default: true. */\n autoOnFileChange?: boolean | undefined;\n /** Archive stale/low-value memories after this many days. Default: 90. */\n retentionDays?: number | undefined;\n /** Archive low-confidence memories after this many days. Default: 30. */\n archiveLowConfidenceAfterDays?: number | undefined;\n /**\n * Archive active memories that were injected at least `unusedMinInjections`\n * times but never referenced by the assistant, this many days after their\n * last content update. Default: 30.\n */\n archiveUnusedAfterDays?: number | undefined;\n /** Minimum injection count before a never-used memory is archived. Default: 10. */\n unusedMinInjections?: number | undefined;\n }\n | undefined;\n embeddings?:\n | {\n /** Optional future semantic layer. Disabled by default and never required. */\n enabled?: boolean | undefined;\n }\n | undefined;\n}\n\nexport interface AutonomyConfig {\n /** Default autonomy mode at startup. Default: \"auto\". */\n defaultMode?: 'off' | 'suggest' | 'auto' | undefined;\n /** ms to wait before auto-proceeding in 'auto' mode. Default: 45000. */\n autoProceedDelayMs?: number | undefined;\n /** Maximum consecutive auto-proceed turns before pausing. 0 = unlimited. Default: 50. */\n autoProceedMaxIterations?: number | undefined;\n /** Template used for YOLO+auto suggestions. Must include {{suggestion}}. */\n autonomyNextPrompt?: string | undefined;\n /** Animate the terminal/window title while the agent is active. Default: true. */\n terminalTitleAnimation?: boolean | undefined;\n /** Persisted YOLO preference mirrored into top-level config.yolo at runtime. Default: false. */\n yolo?: boolean | undefined;\n /**\n * @deprecated Mirror of `fleetChatVerbosity !== 'off'`, kept for readers that\n * still expect a boolean (webui prefs). Writers must keep it in sync.\n */\n streamFleet?: boolean | undefined;\n /**\n * How much fleet/subagent activity is streamed into the main TUI chat.\n * - 'off': no subagent lines (failures/errors still surface); F2/F3 stay live.\n * - 'full': every subagent tool call and interim message (legacy behavior).\n * Resolved via {@link resolveFleetChatVerbosity}. Default: 'off'.\n */\n fleetChatVerbosity?: FleetChatVerbosity | undefined;\n /** Ring terminal bell when an agent run completes. Default: false. */\n chime?: boolean | undefined;\n /** Ask for confirmation before interrupt/exit. Default: true. */\n confirmExit?: boolean | undefined;\n /** Terminal mouse tracking preference. Default: false. */\n mouseMode?: boolean | undefined;\n /** Enable prompt refinement before sending. Default: true. */\n enhance?: boolean | undefined;\n /**\n * Provider id to use for goal refinement (`/goal set`). When set,\n * the refiner uses this provider's model (see `refinerModel`)\n * instead of the session's main provider/model. Falls back to the\n * main session provider when unset or when the provider is unavailable.\n * Default: unset (uses the main session provider).\n */\n refinerProvider?: string | undefined;\n /**\n * Model id to use for goal refinement. When `refinerProvider` is\n * also set, the refiner uses this specific model on that provider.\n * When only `refinerModel` is set (without a provider), the model\n * is used on the session's main provider. When both are unset, the\n * session's main model is used. Falls back to heuristic on failure.\n * Default: unset (uses the main session model).\n */\n refinerModel?: string | undefined;\n /**\n * Named fallback profile to use for goal refinement. When set, the\n * refiner uses the first valid entry from the named chain (stored in\n * top-level `fallbackProfiles`) instead of `refinerProvider`+`refinerModel`.\n * Falls back to the session model when the profile is empty or missing.\n * Default: unset (uses refinerProvider+refinerModel, or session defaults).\n */\n refinerFallbackProfile?: string | undefined;\n /** Prompt-refinement preview countdown in ms. Default: 60000. */\n enhanceDelayMs?: number | undefined;\n /** Prompt-refinement language mode. Default: \"original\". */\n enhanceLanguage?: 'original' | 'english' | undefined;\n /**\n * `provider/model` ref used for the one-key \"retry with another model\" action\n * offered when a refinement fails. When unset, the recovery UI falls back to\n * the first entry of the effective fallback chain (see\n * `resolveEnhanceFallbackRef`). Default: unset.\n */\n enhanceFallbackModel?: string | undefined;\n /**\n * Timeout (ms) used when RETRYING a refinement after the first attempt timed\n * out \u2014 the \"extra time\" retry. When unset, the retry uses\n * `max(baseTimeout * 2, 180000)`. Default: unset.\n */\n enhanceRetryTimeoutMs?: number | undefined;\n /** TUI statusline density. Default: \"detailed\". */\n statuslineMode?: 'minimum' | 'detailed' | 'no-color' | undefined;\n /** Single short word shown in the TUI rainbow working-state chip. Default: \"thinking\". */\n thinkingWord?: string | undefined;\n /**\n * Show the \"Model Reasoning\" collapsible blocks in chat history that display\n * the LLM's structured reasoning / COT output. Separate from the `thinkingWord`\n * status-bar chip and from model-provisioning `reasoning` settings.\n * Default: true.\n */\n showModelReasoning?: boolean | undefined;\n /**\n * Persist the TUI prompt input history to disk per project so Up/Down\n * navigation recalls prompts across sessions. Secrets are scrubbed before\n * they reach disk. Default: enabled, 100 entries.\n */\n inputHistory?: InputHistoryConfig | undefined;\n}\n\n/**\n * Per-project TUI input history persistence options. Lives under\n * `config.autonomy.inputHistory` because the TUI-specific knobs on Config\n * are grouped there.\n */\nexport interface InputHistoryConfig {\n /** Persist history to ~/.wrongstack/projects/<slug>/input-history.json. Default: true. */\n enabled?: boolean | undefined;\n /** Max entries kept on disk (and in memory). Default: 100. */\n maxEntries?: number | undefined;\n}\n\n/**\n * Automatic codebase symbol-index maintenance. Keeps the `codebase-search`\n * index (SQLite, `~/.wrongstack/projects/<hash>/codebase-index/index.db`) fresh\n * without the user having to call `codebase-index` by hand.\n */\nexport interface IndexingConfig {\n /** Run a blocking incremental index at session start (with a visible summary). Default: true. */\n onSessionStart: boolean;\n /** Reindex files the agent writes/edits via tools, in the background. Default: true. */\n onEdit: boolean;\n /** Watch the project root for external editor changes and reindex them. Default: true. */\n watchExternal: boolean;\n /** Debounce window (ms) coalescing rapid edits to the same file. Default: 400. */\n debounceMs: number;\n /**\n * Watchdog timeout (ms) for a full index run. A run exceeding this is\n * aborted (so it can never wedge the indexing mutex or freeze the terminal)\n * and counts toward the indexing circuit breaker. Default: 240000.\n */\n indexTimeoutMs?: number | undefined;\n}\n\n/**\n * Saved launch preferences \u2014 restored on next boot so the pre-launch prompt\n * can offer a one-line \"Continue with last settings? [Y/n]\" instead of\n * re-asking every question from scratch.\n */\nexport interface LaunchConfig {\n /** Interactive mode: 'tui' (Ink TUI) or 'repl' (readline REPL). */\n mode?: 'tui' | 'repl' | undefined;\n // (removed: director \u2014 Director Mode is permanently on)\n /**\n * Launch-time autonomy mode (binary choice from pre-launch prompt).\n * 'off' = stops after each turn; 'auto' = self-driving.\n * Distinct from `AutonomyConfig.defaultMode` which also supports 'suggest'.\n */\n autonomy?: 'off' | 'auto' | undefined;\n /**\n * Last mode chosen from the interactive launch menu\n * (`packages/cli/src/boot/launch-menu.ts`).\n *\n * Stored so the menu can offer a one-line \"Continue with last\n * settings? [Y/n/q]\" summary on the next boot instead of re-asking\n * the same 1-of-4 question. Distinct from `mode` (tui/repl) \u2014 that\n * field is set by the inner pre-launch prompts that run AFTER the\n * user has chosen \"TUI/REPL\" here.\n *\n * Default port per mode is owned by the launcher (HQ=3499, WebUI=3456,\n * SimpleUI=3466). Storing an explicit override here makes\n * `wstack --no-menu` keep the user's last port too.\n */\n menuChoice?: LaunchMenuChoice | undefined;\n}\n\n/**\n * Persisted record of the user's last interactive launch-menu choice.\n * Distinct from {@link LaunchConfig} above because it survives a\n * `wstack --webui` \u2192 `wstack` round-trip without overwriting the\n * inner pre-launch `mode` (tui/repl) preference.\n */\nexport interface LaunchMenuChoice {\n /** Which top-level surface the user picked from the menu. */\n mode: 'tui-repl' | 'webui' | 'simpleui' | 'hq';\n /** Port override the user typed (defaults to the surface's default). */\n port?: number | undefined;\n /** Host override the user typed (defaults to 127.0.0.1). */\n host?: string | undefined;\n}\n\n/**\n * Controls how much detail is persisted to the per-session JSONL log\n * (`~/.wrongstack/projects/<hash>/sessions/<date>/sess_<ULID>.jsonl`).\n */\nexport interface SessionLoggingConfig {\n /**\n * How much detail to write to the persistent session log.\n *\n * - \"minimal\" \u2192 Only events required for resume/rewind/recovery\n * - \"standard\" \u2192 (default) + high-value lightweight audit events\n * (compaction, tool timing, retries, errors, etc.)\n * - \"full\" \u2192 Also persist full request payloads (very large).\n * Consider enabling a separate replay log instead.\n */\n auditLevel?: 'minimal' | 'standard' | 'full' | undefined;\n\n /**\n * Sampling configuration for high-volume events (especially relevant at\n * `auditLevel: \"full\"`).\n */\n sampling?: {\n /** Controls sampling of `tool_progress` events. */\n toolProgress?: {\n /**\n * Sample rate for noisy progress events (`log`, `partial_output`).\n * - 1 = no sampling (every message is logged)\n * - 8 = default (first message + every 8th)\n */\n sampleRate?: number | undefined;\n };\n };\n}\n\nexport type SyncCategory = 'settings' | 'skills' | 'prompts' | 'memory' | 'history';\n\nexport interface SyncConfig {\n enabled: boolean;\n repo: string;\n /** GitHub token (fine-grained PAT). Encrypted at rest via SecretVault. */\n githubToken: string;\n categories: SyncCategory[];\n lastSyncedAt?: string | undefined;\n}\n\n/**\n * Per-model capability overrides the user can define in their config.\n * Used to add models not in the models.dev catalog, or override catalog\n * facts when the real backend differs (e.g. local Ollama models, proxies).\n */\nexport interface CustomModelDefinition {\n /** Provider this model belongs to. Defaults to the owning ProviderConfig. */\n provider?: string | undefined;\n /** Optional display name. */\n name?: string | undefined;\n /** Capability overrides \u2014 only specified fields are overlaid. */\n capabilities?: Partial<Capabilities> | undefined;\n /**\n * Max output tokens. If not specified, the provider family default\n * or catalog entry is used.\n */\n maxOutput?: number | undefined;\n}\n\n/**\n * Skill subsystem configuration. All fields optional; the subsystem itself is\n * gated by `features.skills`. Honored from the user's active-profile config;\n * in the repo-committed in-project config the `extraDirs` field is stripped\n * (arbitrary directories are a prompt-injection vector) \u2014 only `readClaudeSkills`\n * and `mode` survive there.\n */\nexport interface SkillsConfig {\n /**\n * Read skills from foreign coding-agent directories (`<project>/.claude/skills`\n * and `~/.claude/skills`). Default `true`. Lets Claude Code / Codex / Gemini /\n * `asm` / `gh skill` skills be used without copying them.\n */\n readClaudeSkills?: boolean | undefined;\n /**\n * Scan OTHER coding agents' skill directories (`~/.codex/skills`,\n * `~/.cursor/skills`, `~/.agents/skills`, `~/.qwen/skills`,\n * `~/.trae/skills`, \u2026 + their `<project>/.<tool>/\u2026` equivalents). Default\n * `true` (all known tools); pass a tool-id list to restrict, or `false` to\n * disable. Non-existent dirs are skipped. Unknown ids in the list (likely\n * typos) are dropped and surfaced via a config warning.\n */\n foreignSources?: boolean | string[] | undefined;\n /**\n * How skill bodies reach the system prompt.\n * - `'eager'` (default): inject every discovered skill body into the prompt.\n * - `'progressive'`: inject only the metadata manifest; the agent loads a\n * skill body on demand via the `skill` tool (the agentskills.io model).\n */\n mode?: 'eager' | 'progressive' | undefined;\n /**\n * Extra skill directories to scan (lowest priority, after the `.claude`\n * layers). Honored only from the user config; stripped from in-project config.\n */\n extraDirs?: string[] | undefined;\n /**\n * In eager mode, the maximum total chars of skill bodies injected into the\n * prompt (highest-priority skills first; the rest are listed as a manifest the\n * agent loads via the `skill` tool). Bounds prompt cost when many skills are\n * discovered. Default 24000 (~6k tokens). Set very high to disable. Ignored in\n * progressive mode (which injects only the manifest anyway).\n */\n eagerMaxChars?: number | undefined;\n /**\n * Base URL of the skill registry used by `/skill-search` and\n * `/skill-install <registry>:<id>`. Default `https://skills.sh` (the open\n * marketplace backed by mastra-ai/skills-api). Honored only from the user\n * config; stripped from in-project config (a repo-committed override would be\n * an SSRF / prompt-injection vector \u2014 the registry response is parsed into the\n * prompt). Set to a self-hosted skills-api instance to use a private catalog.\n */\n registryUrl?: string | undefined;\n}\n\n/**\n * Fleet peer-awareness + supervision settings. All sub-features are\n * enabled-by-default with conservative throttles; each has its own kill\n * switch. See `FleetSupervisor` (coordination/fleet-supervisor.ts) for the\n * supervisor semantics.\n */\nexport interface FleetConfig {\n /** Subagent process/registry lifecycle after it is no longer doing work. */\n lifecycle?:\n | {\n /**\n * Remove a spawned or between-task subagent after this much idle time.\n * This is separate from the in-task activity watchdog. Default 30000.\n */\n idleTimeoutMs?: number | undefined;\n /**\n * Retire a subagent as soon as its final task result is delivered and\n * no queued task reused it in the same dispatch cycle. Default true.\n */\n retireOnTaskComplete?: boolean | undefined;\n }\n | undefined;\n /** Fleet-wide hard ceilings. In-flight work may finish; new spawns are refused at the cap. */\n budget?:\n | {\n /** Maximum subagents spawned during one Director lifetime. Default 64 in CLI. */\n maxSpawns?: number | undefined;\n /** Maximum cumulative input+output tokens across all fleet subagents. */\n maxTokens?: number | undefined;\n /** Maximum cumulative estimated USD cost across all fleet subagents. */\n maxCostUsd?: number | undefined;\n }\n | undefined;\n /** Periodic \"[FLEET PULSE]\" peer-status digest folded into each agent's context. */\n pulse?:\n | {\n /** Default true. */\n enabled?: boolean | undefined;\n /** Inject at most every N agent iterations. Default 5. */\n everyNIterations?: number | undefined;\n /** Hard cap on digest characters. Default 900. */\n maxChars?: number | undefined;\n /** Max peers listed per digest. Default 15. */\n maxAgents?: number | undefined;\n }\n | undefined;\n /** Broadcast `type:'status'` mails on meaningful subagent transitions. */\n statusBroadcasts?:\n | {\n /** Default true. */\n enabled?: boolean | undefined;\n /** Min interval between broadcasts about the same subagent. Default 15000. */\n minIntervalMsPerAgent?: number | undefined;\n /** Global cap on broadcasts per minute (excess dropped + counted). Default 20. */\n globalPerMinuteCap?: number | undefined;\n /**\n * Broadcast recoverable soft-budget warnings to every project agent.\n * Default false: the local fleet UI still tracks warnings/extensions,\n * but routine preemption and auto-extension do not flood peer mailboxes.\n */\n budgetWarnings?: boolean | undefined;\n }\n | undefined;\n /**\n * Per-subagent git-worktree isolation for Director fleets. The default is\n * `auto`: mutating/build-capable subagents run in isolated checkouts and are\n * squash-merged back on success; read-only review agents usually stay on the\n * shared checkout. Set `enabled:false` or `mode:'off'` when a workflow cannot\n * use worktrees.\n */\n worktrees?:\n | {\n /** Kill switch. Default true. */\n enabled?: boolean | undefined;\n /**\n * `auto` (default): isolate only side-effectful subagents.\n * `required`: side-effectful subagents must get a worktree or fail.\n * `off`: never allocate worktrees.\n */\n mode?: 'auto' | 'required' | 'off' | undefined;\n /**\n * Merge successful task branches back into the base checkout. Default\n * true. When false, successful worktrees are committed and kept for\n * manual `/worktree merge`.\n */\n autoMerge?: boolean | undefined;\n /** Keep failed/timeout worktrees when they contain changes. Default true. */\n keepFailed?: boolean | undefined;\n }\n | undefined;\n /** Brain-gated fleet supervisor (rebalance/steer/spawn-helper). */\n supervisor?: FleetSupervisorConfig | undefined;\n}\n\n/** Config surface for the brain-gated FleetSupervisor. */\nexport interface FleetSupervisorConfig {\n /** Kill switch. Default true (active whenever a Director is running). */\n enabled?: boolean | undefined;\n /** Evaluation tick. Default 20000. */\n intervalMs?: number | undefined;\n /** Per-(signal,subject) re-engagement cooldown. Default 120000. */\n cooldownMs?: number | undefined;\n /** Hard cap on interventions touching one subagent per run. Default 3. */\n maxInterventionsPerSubagent?: number | undefined;\n /** Pending task pinned to a busy worker longer than this \u2192 starvation signal. Default 60000. */\n pinnedWaitMs?: number | undefined;\n /** \u2265 this many pending tasks pinned to one worker (with an idle sibling) \u2192 overload signal. Default 2. */\n overloadPinnedThreshold?: number | undefined;\n /** pending > backlogFactor \u00D7 live workers (sustained) \u2192 spawn-helper signal. Default 2. */\n backlogFactor?: number | undefined;\n /** Running subagent with no observable fleet activity for this long \u2192 stuck signal. Default 180000. */\n stuckMs?: number | undefined;\n /** Consecutive failed/timeout results from one subagent \u2192 failure-streak signal. Default 2. */\n failureStreak?: number | undefined;\n /** Allow the supervisor to spawn helper subagents. Default true. */\n allowSpawn?: boolean | undefined;\n /** Allow the supervisor to terminate subagents (highest risk). Default false. */\n allowTerminate?: boolean | undefined;\n}\n\n/**\n * One member of the Brain's LLM pool or council. String entries elsewhere\n * (`Config.brain.models`, council voters) parse with the same `parseModelRef`\n * grammar as `fallbackModels`: bare `model`, `provider/model`, or\n * `provider model`.\n */\nexport interface BrainModelEntry {\n /** Provider id (a key of `Config.providers` or a catalog id). Defaults to the session provider. */\n provider?: string | undefined;\n /** Model id, required. */\n model: string;\n}\n\n/** One voting seat on the Brain council. */\nexport interface BrainCouncilVoterConfig extends BrainModelEntry {\n /**\n * Decision lens for this seat. Built-ins: 'executor' (progress-biased),\n * 'skeptic' (risk-hunting), 'auditor' (cost/waste-focused). Any other\n * string is injected verbatim as the persona description.\n */\n persona?: string | undefined;\n /** Vote weight in the tally. Default 1. */\n weight?: number | undefined;\n /** When true, this seat's explicit refusal denies the request outright. */\n veto?: boolean | undefined;\n}\n\n/** Multi-LLM council configuration for high-stakes Brain decisions. */\nexport interface BrainCouncilConfig {\n /** Kill switch. Default: enabled when `voters` is non-empty or \u22652 pool models exist. */\n enabled?: boolean | undefined;\n /**\n * Minimum request risk that convenes the council instead of the single-LLM\n * tier. Default 'high'. 'critical' = council only for critical questions;\n * 'medium' = council for most non-trivial questions (slow + expensive).\n */\n minRisk?: 'medium' | 'high' | 'critical' | undefined;\n /**\n * Voting seats. String entries use the `parseModelRef` grammar and get\n * default personas (executor, skeptic w/ veto, auditor) assigned in order.\n * When omitted, seats are derived from `brain.models` (up to 3).\n */\n voters?: Array<string | BrainCouncilVoterConfig> | undefined;\n /** Fraction of seats that must return a valid vote. Default 0.5. */\n quorum?: number | undefined;\n /** Fraction of cast vote weight the winning option must exceed. Default 0.5. */\n approval?: number | undefined;\n /**\n * Tie-breaker / synthesizer model (`parseModelRef` grammar or entry).\n * Sees every vote's rationale and issues the final structured decision.\n * Default: the first pool/voter model.\n */\n judge?: string | BrainModelEntry | undefined;\n}\n\n/**\n * Brain decision-layer configuration. SECURITY: in the in-project config\n * DENY list \u2014 a repo-committed config must not be able to raise the\n * autonomy ceiling, remove the human tier, or point Brain decisions at an\n * attacker-chosen provider. Only honoured from the active-profile config.\n */\nexport interface BrainConfig {\n /**\n * 'headless' \u2014 the Brain NEVER blocks on a human. Escalations resolve\n * via the terminal policy (recommended option for low/medium\n * risk, request fallback semantics, otherwise deny).\n * 'interactive' \u2014 escalations prompt the human in the TUI/WebUI.\n * Default (resolved at boot by `resolveBrainConfigDefaults`): 'headless' \u2014\n * minimum-human out of the box. Switch live with `/brain mode <m>`.\n */\n mode?: 'headless' | 'interactive' | undefined;\n /**\n * Initial autonomy ceiling for the LLM tier. Default (resolved at boot):\n * adaptive \u2014 'all' when a council can convene (\u22652 voters/pool models),\n * otherwise 'high'. Live-set via `/brain risk`.\n */\n maxAutoRisk?: 'off' | 'low' | 'medium' | 'high' | 'all' | undefined;\n /**\n * Ordered LLM pool for Brain decisions (`parseModelRef` grammar or\n * entries). With `strategy: 'fallback'` the first entry is primary and the\n * rest are tried in order when it fails; with 'round-robin' calls rotate\n * across the pool. Default (resolved at boot): the user's `fallbackModels`\n * chain; with none configured, the session provider/model is used.\n */\n models?: Array<string | BrainModelEntry> | undefined;\n /** Pool selection strategy. Default 'fallback'. */\n strategy?: 'fallback' | 'round-robin' | undefined;\n /** Per-LLM-call decision timeout (ms). Default 15000. */\n decisionTimeoutMs?: number | undefined;\n /**\n * Interactive mode only: how long an ask-human prompt may stay unanswered\n * before it resolves through the terminal policy instead of blocking\n * forever. Default (resolved at boot): 120000. Set 0 to wait indefinitely\n * (legacy behavior).\n */\n humanTimeoutMs?: number | undefined;\n /** Multi-LLM council for high-stakes decisions. */\n council?: BrainCouncilConfig | undefined;\n /**\n * Persistent decision ledger (`<project>/.wrongstack/brain-ledger.jsonl`):\n * every decision + observed outcome is appended, and outcome stats for\n * similar past decisions are fed back into the LLM/council prompts.\n * Default: enabled.\n */\n ledger?:\n | {\n enabled?: boolean | undefined;\n /**\n * Deterministic guard: once this many consecutive approvals of a\n * decision group ended in observed failures, deny outright without\n * consulting any LLM (a later success lifts the guard). Default 3.\n * 0 disables.\n */\n autoDenyAfterFailures?: number | undefined;\n }\n | undefined;\n /**\n * BrainMonitor distress-signal thresholds (self-activation). All optional;\n * defaults match `BrainMonitorOptions`.\n */\n monitor?:\n | {\n /** Consecutive failures of the same tool before engaging. Default 3. */\n toolFailureStreak?: number | undefined;\n /** Errors within 60s before engaging. Default 4. */\n errorStormCount?: number | undefined;\n /** Active run with no progress for this long \u2192 stall signal (ms). Default 300000. 0 disables. */\n stallMs?: number | undefined;\n /** Edits to the same file within the churn window before engaging. Default 5. */\n fileChurnThreshold?: number | undefined;\n /** Sliding window for the file-churn signal (ms). Default 600000. */\n fileChurnWindowMs?: number | undefined;\n /** Per-signal re-engagement cooldown (ms). Default 120000. */\n cooldownMs?: number | undefined;\n }\n | undefined;\n}\n\n/** Git behavior overrides for agent-run git commands. See `Config.git`. */\nexport interface GitBehaviorConfig {\n /**\n * Commit identity injected as `GIT_AUTHOR_NAME/EMAIL` +\n * `GIT_COMMITTER_NAME/EMAIL` into every child process. Either field may be\n * set alone; the missing one falls back to git's own config.\n */\n identity?:\n | {\n name?: string | undefined;\n email?: string | undefined;\n }\n | undefined;\n}\n\nexport interface Config {\n /** Recurring provider/model blackout windows used by autonomous routing. */\n modelAvailabilitySchedule?:\n | import('../core/model-availability-calendar.js').ModelBlackoutRule[]\n | undefined;\n version: 1;\n provider: string;\n model: string;\n apiKey?: string | undefined;\n baseUrl?: string | undefined;\n /**\n * Maximum number of subagent tasks the fleet coordinator dispatches\n * simultaneously. Extra tasks queue until a slot frees. Default: 4.\n * Overridden by WRONGSTACK_MAX_CONCURRENT env var and --max-concurrent\n * CLI flag. Change at runtime with /fleet concurrency <n>.\n */\n maxConcurrent?: number | undefined;\n /**\n * Display language for the UI chrome (WebUI + desktop shell). A BCP-47-ish\n * code from SUPPORTED_LOCALES (en/tr/de/fr/it/es/pt-BR). Persisted here so a\n * change in one surface propagates to all others via the shared machine\n * config; each surface may keep a local cache for instant reactivity. When\n * unset, surfaces fall back to their own browser/system detection.\n */\n uiLocale?: string | undefined;\n providers?: Record<string, ProviderConfig>;\n /**\n * Top-level custom models (maps modelId \u2192 definition). Merged with\n * per-provider `customModels` at resolution time. The key is the\n * model id \u2014 not a fully qualified name. When the same model id\n * appears in both places, the top-level one wins.\n */\n models?: Record<string, CustomModelDefinition>;\n /**\n * Per-task model matrix. Keys are catalog roles (e.g. \"security-scanner\"),\n * phase names (e.g. \"review\"), or the `*` default. Resolution precedence at\n * subagent spawn: exact role \u2192 the role's phase \u2192 `*` \u2192 leader model. Set via\n * the `/setmodel` slash command; persisted to the active-profile config.\n */\n modelMatrix?: Record<string, ModelMatrixEntry>;\n /**\n * User-curated model references shown/prioritized by model commands and used\n * by smart fallback derivation. Entries are `model`, `provider/model`, or\n * `provider model`.\n */\n favoriteModels?: string[] | undefined;\n /**\n * When true, auto-derived fallback chains are restricted to `favoriteModels`.\n * Explicit fallback profiles/chains are always honored as written.\n */\n favoriteModelsOnly?: boolean | undefined;\n context: ContextConfig;\n tools: ToolsConfig;\n mcpServers?: Record<string, MCPServerConfig>;\n /**\n * Per-agent ACP invocation overrides, keyed by catalog agent id\n * (`claude-code`, `codex-cli`, `gemini-cli`, \u2026). Lets a user correct an\n * agent's ACP entry command \u2014 e.g. point `claude-code` at the right\n * adapter \u2014 without a code change. Consumed by `/acp`, `/ensemble`, and\n * `wstack acp`. SECURITY: this is an arbitrary-command exec surface, so it\n * is in the in-project config DENY list \u2014 only honoured from the user's\n * active-profile config, never from a repo-committed config.\n */\n acp?: {\n agents?: Record<string, { command: string; args?: string[]; env?: Record<string, string> }>;\n };\n /**\n * Ordered list of fallback model references tried, in order, when the\n * primary model is overloaded (HTTP 429/529/5xx) and its own retries are\n * exhausted. Each entry is a model reference: a bare model id (same\n * provider), `provider/model`, or `provider model`. After a fallback hop,\n * the primary is retried only after its cooldown expires. See\n * `createFallbackModelExtension`.\n */\n fallbackModels?: string[] | undefined;\n /**\n * Named fallback chains. A profile's first entry can be used as a primary\n * model by `/setmodel`, while the whole ordered list is used for failover.\n */\n fallbackProfiles?: Record<string, string[]> | undefined;\n /**\n * When `true` (the default) and `fallbackModels` is empty, a fallback chain\n * is derived automatically from the other keyed providers/models so 429s\n * recover out of the box. Set `false` to disable the smart default and only\n * use an explicit `fallbackModels` list. Toggle via `/fallback auto on|off`.\n */\n fallbackAuto?: boolean | undefined;\n /**\n * Lifecycle command/HTTP hooks, keyed by event. Commands receive HookInput\n * JSON on stdin; HTTP hooks receive the same object as a POST body. A typed\n * outcome can allow, deny, or mutate. `policy: true` enforcement hooks remain\n * active under `--no-hooks`; ordinary automation is disabled.\n */\n hooks?: Partial<Record<HookEvent, ConfiguredHook[]>>;\n plugins?: (string | PluginConfig)[] | undefined;\n log: LogConfig;\n features: FeaturesConfig;\n /** Project-local structured memory, graph-ready anchors, retrieval, and hygiene. */\n superMemory?: SuperMemoryConfig | undefined;\n /** Skill subsystem options (readClaudeSkills / mode / extraDirs). */\n skills?: SkillsConfig | undefined;\n yolo?: boolean | undefined;\n /** When true, show lightweight LLM-predicted next steps after each turn (/next). */\n nextPrediction?: boolean | undefined;\n cwd?: string | undefined;\n /**\n * Active profile name selected by the root bootstrap config. Settings load\n * from ~/.wrongstack/profiles/<name>/config.json. Default: 'default'.\n */\n activeProfile?: string | undefined;\n /** Autonomy mode configuration (auto-proceed delay, etc.). */\n autonomy?: AutonomyConfig | undefined;\n /** Show rotating launch hints on startup. Default: true. Set to false to suppress. */\n hints?: boolean | undefined;\n /** Raw SSE stream debugging \u2014 hex-dump every byte received from providers to stderr. */\n debugStream?: boolean | undefined;\n /**\n * Where settings are persisted. 'global' \u2192 the active profile config\n * (default). 'project' \u2192 <project>/.wrongstack/config.json.\n * When 'project', safe settings are saved per-project.\n */\n configScope?: 'global' | 'project' | undefined;\n /** Automatic codebase symbol-index maintenance (session-start + live updates). */\n indexing?: IndexingConfig | undefined;\n /**\n * Process circuit-breaker protection (gates `bash`/`exec` on repeated\n * failures). Default off \u2014 toggle with `/settings breaker on|off`.\n */\n circuitBreaker?: CircuitBreakerRuntimeConfig | undefined;\n /**\n * Adaptive concurrency controller \u2014 automatically adjusts `maxConcurrent` based on\n * rate-limit (429) errors. On 429: decreases concurrency. On sustained success:\n * gradually increases concurrency back up. Default off.\n */\n adaptiveConcurrency?: AdaptiveConcurrencyConfig | undefined;\n /** Saved launch preferences \u2014 restored on next boot for one-line confirmation. */\n launch?: LaunchConfig | undefined;\n\n /**\n * Session logging & audit configuration.\n * Controls what gets written to the persistent JSONL transcript.\n */\n session?: SessionLoggingConfig | undefined;\n /**\n * Runtime reasoning / cache controls applied to every provider request\n * (REPL/TUI/WebUI). Mapped into `Request.reasoning` and `Request.cache` by a\n * single request-pipeline middleware, gated by the active model's\n * capabilities. See `ModelRuntimeConfig`.\n */\n modelRuntime?: ModelRuntimeConfig | undefined;\n /** HQ client publishing settings, used by CLI/REPL/TUI/WebUI consistently. */\n hq?: HqClientConfig | undefined;\n /**\n * Fleet awareness + supervision settings (peer-status pulse digests,\n * status-broadcast mails, and the brain-gated FleetSupervisor). SECURITY:\n * in the in-project config DENY list \u2014 a repo-committed config must not be\n * able to enable autonomous spawning/steering or mailbox traffic. Only\n * honoured from the user's active-profile config.\n */\n fleet?: FleetConfig | undefined;\n /**\n * Brain decision-layer settings: escalation mode (headless = never block\n * on a human), LLM pool with fallback/round-robin, autonomy ceiling, and\n * the multi-LLM council. SECURITY: in the in-project config DENY list \u2014\n * a repo-committed config must not be able to raise the autonomy ceiling\n * or reroute Brain decisions. Only honoured from the active-profile config.\n */\n brain?: BrainConfig | undefined;\n /**\n * Cloud sync configuration. Stored separately in sync.json to avoid\n * accidentally committing the GitHub token to project configs.\n */\n sync?: SyncConfig | undefined;\n /**\n * Git behavior overrides for agent-run git commands.\n *\n * `identity` sets the commit author/committer used by every git process\n * WrongStack spawns (git tool, bash/exec shells, worktree manager,\n * plugins) via the `GIT_AUTHOR_*` / `GIT_COMMITTER_*` env vars. It never\n * touches the repo's or the user's `git config`, so commits made outside\n * WrongStack keep their normal identity. Unset \u2192 git's own config applies\n * (today's behavior). Manage at runtime with `/gitid`.\n *\n * SECURITY: in the in-project config DENY list \u2014 a repo-committed config\n * must not be able to spoof the identity written into the user's commit\n * history. Only honoured from the user's active-profile config.\n */\n git?: GitBehaviorConfig | undefined;\n /**\n * Per-plugin namespaced config sections. Each plugin reads its own\n * subtree via `ConfigStore.getExtension(pluginName)`. Plugins should\n * declare a `configSchema` so the loader validates this section\n * automatically before `setup()` runs.\n *\n * Example:\n * extensions: {\n * 'wstack-auth': { tokenUrl: 'https://...', refreshBefore: 300 },\n * 'wstack-metrics': { sink: 'prometheus', port: 9090 },\n * }\n */\n extensions?: Record<string, Record<string, unknown>>;\n}\n\nexport interface ConfigLoader {\n load(opts?: {\n cliFlags?: Partial<Config> | undefined;\n cwd?: string | undefined;\n }): Promise<Config>;\n /** Load and decrypt the sync config from ~/.wrongstack/sync.json. */\n loadSyncConfig(): Promise<SyncConfig | null>;\n /** Persist sync config to ~/.wrongstack/sync.json with encrypted token. */\n persistSyncConfig(cfg: SyncConfig): Promise<void>;\n}\n\n/**\n * Subscribable view over Config. Plugins and CLI subsystems use this instead\n * of holding a frozen Config reference, so they can react to runtime updates\n * (e.g. `/model` switching the active provider, secrets rotation, dynamic\n * extension reload).\n *\n * The store enforces immutability \u2014 `get()` always returns a frozen object.\n * Updates happen through `update(partial)`, which produces a new Config\n * (structurally cloned, then frozen) and notifies watchers.\n */\nexport interface ConfigStore {\n get(): Readonly<Config>;\n /**\n * Get a typed top-level section. Convenience for consumers that only\n * care about one slice (e.g. `tools` or `context`).\n */\n getSection<K extends keyof Config>(key: K): Readonly<Config[K]>;\n /**\n * Return the extension namespace for `pluginName`, or an empty record\n * when none is configured. The returned object is frozen.\n */\n getExtension(pluginName: string): Readonly<Record<string, unknown>>;\n /**\n * Apply a partial update. Returns the new Config. Watchers are notified\n * synchronously after the update completes. Throws if the result fails\n * any registered invariants (currently: version must stay 1).\n */\n update(partial: Partial<Config>): Readonly<Config>;\n /** Subscribe to changes. Returns an unsubscribe function. */\n watch(cb: (next: Readonly<Config>, prev: Readonly<Config>) => void): () => void;\n}\n", "import type { TextBlock } from './blocks.js';\nimport type { Tool } from './tool.js';\nimport type { MailboxAgentStatus } from '../coordination/mailbox-types.js';\n\n/** Model capabilities relevant to prompt composition. */\nexport interface ModelCapabilities {\n maxContextTokens: number;\n supportsTools: boolean;\n supportsVision: boolean;\n supportsReasoning: boolean;\n}\n\nexport interface BuildContext {\n cwd: string;\n projectRoot: string;\n tools: Tool[];\n /** Provider id (e.g. \"anthropic\", \"minimax-coding-plan\"). */\n provider?: string | undefined;\n /** Model id (e.g. \"configured-model\", \"MiniMax-M2.7\"). */\n model?: string | undefined;\n /**\n * True when the prompt is being built for a SUBAGENT, not the host\n * agent. Subagents are scoped to a single task \u2014 they should NOT see\n * the host's strategic plan board (which is anchoring the host across\n * turns, not steering individual subtasks). The plan-injection\n * layer short-circuits when this flag is set.\n */\n subagent?: boolean | undefined;\n /**\n * List of currently online agents in the shared mailbox system.\n * Includes agents from all clients, processes, sessions, branches, and\n * linked Git worktrees in the same canonical project.\n */\n onlineAgents?: MailboxAgentStatus[] | undefined;\n}\n\n/**\n * Stability regions for the system prompt.\n *\n * `core` and `session` form the provider-cache prefix and must remain byte-for-byte\n * stable after the first request in a session. `volatile` is appended at request\n * time and may change between turns without rewriting that prefix.\n */\nexport interface SystemPromptRegions {\n readonly core: readonly TextBlock[];\n readonly session: readonly TextBlock[];\n readonly volatile: readonly TextBlock[];\n}\n\nexport function flattenSystemPromptRegions(regions: SystemPromptRegions): TextBlock[] {\n return [...regions.core, ...regions.session, ...regions.volatile];\n}\n\nexport interface SystemPromptBuilder {\n build(ctx: BuildContext): Promise<TextBlock[]>;\n /** Region-aware build used by hosts that enforce prompt-prefix stability. */\n buildRegions?(ctx: BuildContext): Promise<SystemPromptRegions>;\n}\n", "/**\n * Compile a user-supplied regex with conservative bounds against ReDoS.\n *\n * Duplicated from @wrongstack/tools/_regex.ts to avoid a circular\n * dependency (tools depends on core, not vice versa). Keep both copies\n * in sync if the heuristics change.\n *\n * V8's regex engine is backtracking-based and cannot interrupt a\n * synchronous match \u2014 a pattern like `(a+)+$` against a sufficiently\n * long line will pin a worker for seconds.\n */\n\nconst MAX_PATTERN_LEN = 512;\n\n// Heuristics for catastrophic-backtracking constructs.\nconst DANGEROUS_PATTERNS: ReadonlyArray<RegExp> = [\n /(\\([^)]*[+*][^)]*\\))[+*]/, // (a+)+, (.*)+, etc\n /(\\(\\?:[^)]*[+*][^)]*\\))[+*]/, // same, with non-capturing group\n];\n\nexport interface CompileResult {\n ok: true;\n regex: RegExp;\n}\n\nexport interface CompileFail {\n ok: false;\n reason: string;\n}\n\nexport function compileUserRegex(pattern: string, flags: string): CompileResult | CompileFail {\n if (typeof pattern !== 'string') {\n return { ok: false, reason: 'pattern must be a string' };\n }\n if (pattern.length === 0) {\n return { ok: false, reason: 'pattern is empty' };\n }\n if (pattern.length > MAX_PATTERN_LEN) {\n return { ok: false, reason: `pattern exceeds ${MAX_PATTERN_LEN} characters` };\n }\n for (const rx of DANGEROUS_PATTERNS) {\n if (rx.test(pattern)) {\n return {\n ok: false,\n reason:\n 'pattern looks vulnerable to catastrophic backtracking \u2014 rewrite without nested quantifiers',\n };\n }\n }\n try {\n return { ok: true, regex: new RegExp(pattern, flags) };\n } catch (err) {\n return {\n ok: false,\n reason: err instanceof Error ? err.message : 'invalid regex',\n };\n }\n}\n", "import * as path from 'node:path';\nimport { ERROR_CODES, FsError } from '../types/errors.js';\n\n/**\n * Resolve `<dir>/<sessionId><suffix>` for per-session sidecar files\n * (annotations, audit chain, replay log, the session JSONL itself).\n *\n * Modern session ids are date-sharded (\"2026-06-11/sess_<ULID>\"),\n * so a forward slash is a legitimate shard separator \u2014 NOT traversal.\n * Escape attempts are blocked two ways: an explicit ban on `..` and\n * backslashes, plus a resolved-path containment check that rejects any\n * id whose resolved target leaves `dir`. Character bans alone are how\n * several stores ended up throwing on every modern session id.\n */\nexport function sessionScopedPath(dir: string, sessionId: string, suffix: string): string {\n if (!sessionId || sessionId.includes('\\\\') || sessionId.includes('..')) {\n throw invalid(sessionId);\n }\n const resolved = path.resolve(dir, `${sessionId}${suffix}`);\n const rel = path.relative(path.resolve(dir), resolved);\n if (rel.startsWith('..') || path.isAbsolute(rel)) {\n throw invalid(sessionId);\n }\n return resolved;\n}\n\nfunction invalid(sessionId: string): FsError {\n return new FsError({\n message: `Invalid sessionId: ${sessionId}`,\n code: ERROR_CODES.FS_DELETE_FAILED,\n path: sessionId,\n context: { reason: 'path_traversal' },\n });\n}\n", "import { toErrorMessage } from '../utils/index.js';\n\n/**\n * WrongStack error hierarchy.\n *\n * Every error thrown by the framework is a `WrongStackError` with a\n * machine-readable `code`, a `subsystem` tag, and a `severity` level.\n * This lets consumers (CLI, TUI, plugins, tests) branch on structured\n * data instead of parsing error messages.\n */\n\n// \u2500\u2500 Error codes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Machine-readable error codes as frozen constants.\n *\n * Use `ERROR_CODES.X` instead of raw string literals for:\n * - IDE autocomplete and compile-time validation\n * - Safe refactoring (rename updates all usages)\n * - Plugin extensibility (extend the object to add custom codes)\n *\n * The `ErrorCode` type is derived from this object, so adding a new\n * code here automatically updates the type without extra changes.\n */\nexport const ERROR_CODES = {\n // Provider\n PROVIDER_RATE_LIMITED: 'PROVIDER_RATE_LIMITED',\n PROVIDER_AUTH_FAILED: 'PROVIDER_AUTH_FAILED',\n PROVIDER_OVERLOADED: 'PROVIDER_OVERLOADED',\n PROVIDER_INVALID_REQUEST: 'PROVIDER_INVALID_REQUEST',\n PROVIDER_SERVER_ERROR: 'PROVIDER_SERVER_ERROR',\n PROVIDER_NETWORK_ERROR: 'PROVIDER_NETWORK_ERROR',\n PROVIDER_CONTEXT_OVERFLOW: 'PROVIDER_CONTEXT_OVERFLOW',\n // Tool\n TOOL_NOT_FOUND: 'TOOL_NOT_FOUND',\n TOOL_PERMISSION_DENIED: 'TOOL_PERMISSION_DENIED',\n TOOL_EXECUTION_FAILED: 'TOOL_EXECUTION_FAILED',\n TOOL_TIMEOUT: 'TOOL_TIMEOUT',\n TOOL_INPUT_INVALID: 'TOOL_INPUT_INVALID',\n // Config\n CONFIG_INVALID: 'CONFIG_INVALID',\n CONFIG_NOT_FOUND: 'CONFIG_NOT_FOUND',\n CONFIG_PARSE_FAILED: 'CONFIG_PARSE_FAILED',\n CONFIG_MIGRATION_NEEDED: 'CONFIG_MIGRATION_NEEDED',\n // Plugin\n PLUGIN_LOAD_FAILED: 'PLUGIN_LOAD_FAILED',\n PLUGIN_API_MISMATCH: 'PLUGIN_API_MISMATCH',\n PLUGIN_MISSING_DEPENDENCY: 'PLUGIN_MISSING_DEPENDENCY',\n // Agent\n AGENT_ITERATION_LIMIT: 'AGENT_ITERATION_LIMIT',\n AGENT_CONTEXT_OVERFLOW: 'AGENT_CONTEXT_OVERFLOW',\n AGENT_ABORTED: 'AGENT_ABORTED',\n AGENT_RUN_FAILED: 'AGENT_RUN_FAILED',\n // Session\n SESSION_NOT_FOUND: 'SESSION_NOT_FOUND',\n SESSION_CORRUPTED: 'SESSION_CORRUPTED',\n SESSION_WRITE_FAILED: 'SESSION_WRITE_FAILED',\n // Container / Registry\n CONTAINER_TOKEN_ALREADY_BOUND: 'CONTAINER_TOKEN_ALREADY_BOUND',\n CONTAINER_TOKEN_NOT_BOUND: 'CONTAINER_TOKEN_NOT_BOUND',\n CONTAINER_CIRCULAR_DEPENDENCY: 'CONTAINER_CIRCULAR_DEPENDENCY',\n REGISTRY_DUPLICATE: 'REGISTRY_DUPLICATE',\n REGISTRY_NOT_FOUND: 'REGISTRY_NOT_FOUND',\n REGISTRY_INVALID: 'REGISTRY_INVALID',\n // File system\n FS_READ_FAILED: 'FS_READ_FAILED',\n FS_WRITE_FAILED: 'FS_WRITE_FAILED',\n FS_MKDIR_FAILED: 'FS_MKDIR_FAILED',\n FS_DELETE_FAILED: 'FS_DELETE_FAILED',\n FS_ATOMIC_WRITE_FAILED: 'FS_ATOMIC_WRITE_FAILED',\n // SDD (Spec-Driven Development)\n SDD_VALIDATION_FAILED: 'SDD_VALIDATION_FAILED',\n SDD_PARSE_FAILED: 'SDD_PARSE_FAILED',\n SDD_INVALID_STATE: 'SDD_INVALID_STATE',\n SDD_NOT_READY: 'SDD_NOT_READY',\n // General\n VALIDATION_ERROR: 'VALIDATION_ERROR',\n PARSE_FAILED: 'PARSE_FAILED',\n UNKNOWN: 'UNKNOWN',\n} as const;\n\n/**\n * Union type derived from `ERROR_CODES`. Using `typeof ERROR_CODES[keyof typeof ERROR_CODES]`\n * instead of a string literal union means TypeScript auto-updates the type whenever\n * a new code is added to `ERROR_CODES` \u2014 no need to keep two lists in sync.\n */\nexport type ErrorCode = (typeof ERROR_CODES)[keyof typeof ERROR_CODES];\n\nexport type ErrorSubsystem =\n | 'provider'\n | 'tool'\n | 'config'\n | 'plugin'\n | 'agent'\n | 'session'\n | 'sdd'\n | 'container'\n | 'fs'\n | 'general';\nexport type ErrorSeverity = 'fatal' | 'error' | 'warning';\n\n// \u2500\u2500 Base error class \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class WrongStackError extends Error {\n readonly code: ErrorCode;\n readonly subsystem: ErrorSubsystem;\n readonly severity: ErrorSeverity;\n readonly recoverable: boolean;\n readonly context?: Record<string, unknown> | undefined;\n\n constructor(opts: {\n message: string;\n code: ErrorCode;\n subsystem: ErrorSubsystem;\n severity?: ErrorSeverity | undefined;\n recoverable?: boolean | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super(opts.message, { cause: opts.cause });\n this.name = 'WrongStackError';\n this.code = opts.code;\n this.subsystem = opts.subsystem;\n this.severity = opts.severity ?? 'error';\n this.recoverable = opts.recoverable ?? false;\n this.context = opts.context;\n }\n\n /**\n * Render a one-line user-facing description.\n * Subclasses should override for domain-specific formatting.\n */\n describe(): string {\n const ctx = this.context ? ` ${formatContext(this.context)}` : '';\n return `${this.code}: ${this.message}${ctx}`;\n }\n}\n\nfunction formatContext(ctx: Record<string, unknown>): string {\n const parts = Object.entries(ctx)\n .filter(([, v]) => v !== undefined)\n .slice(0, 3)\n .map(([k, v]) => `${k}=${String(v)}`);\n return parts.length > 0 ? `[${parts.join(' ')}]` : '';\n}\n\n// \u2500\u2500 Specific error classes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Tool execution errors \u2014 thrown by ToolExecutor and individual tools.\n */\nexport class ToolError extends WrongStackError {\n readonly toolName: string;\n\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n | 'TOOL_NOT_FOUND'\n | 'TOOL_PERMISSION_DENIED'\n | 'TOOL_EXECUTION_FAILED'\n | 'TOOL_TIMEOUT'\n | 'TOOL_INPUT_INVALID'\n >;\n toolName: string;\n recoverable?: boolean | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'tool',\n recoverable: opts.recoverable,\n context: { tool: opts.toolName, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'ToolError';\n this.toolName = opts.toolName;\n }\n}\n\n/**\n * Config loading / validation errors.\n */\nexport class ConfigError extends WrongStackError {\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'CONFIG_INVALID' | 'CONFIG_NOT_FOUND' | 'CONFIG_PARSE_FAILED' | 'CONFIG_MIGRATION_NEEDED'\n >;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'config',\n severity: 'fatal',\n recoverable: false,\n context: opts.context,\n cause: opts.cause,\n });\n this.name = 'ConfigError';\n }\n}\n\n/**\n * Plugin loading / lifecycle errors.\n */\nexport class PluginError extends WrongStackError {\n readonly pluginName: string;\n\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'PLUGIN_LOAD_FAILED' | 'PLUGIN_API_MISMATCH' | 'PLUGIN_MISSING_DEPENDENCY'\n >;\n pluginName: string;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'plugin',\n severity: 'error',\n recoverable: opts.code === ERROR_CODES.PLUGIN_MISSING_DEPENDENCY,\n context: { plugin: opts.pluginName, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'PluginError';\n this.pluginName = opts.pluginName;\n }\n}\n\n/**\n * Agent runtime errors \u2014 thrown by Agent.run when a non-WrongStackError\n * escapes the inner loop, so callers always see a structured error.\n */\nexport class AgentError extends WrongStackError {\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'AGENT_ITERATION_LIMIT' | 'AGENT_CONTEXT_OVERFLOW' | 'AGENT_ABORTED' | 'AGENT_RUN_FAILED'\n >;\n recoverable?: boolean | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'agent',\n severity: opts.code === ERROR_CODES.AGENT_ABORTED ? 'warning' : 'error',\n recoverable: opts.recoverable ?? opts.code === ERROR_CODES.AGENT_ITERATION_LIMIT,\n context: opts.context,\n cause: opts.cause,\n });\n this.name = 'AgentError';\n }\n}\n\n/**\n * Wrap an arbitrary thrown value into a `WrongStackError` so the caller\n * always gets a structured error. Pass-throughs WrongStackError instances\n * unchanged; raw `Error`s and primitives get an `AGENT_RUN_FAILED` wrapper\n * with the original preserved as `cause`.\n */\nexport function toWrongStackError(\n err: unknown,\n code: Extract<ErrorCode, 'AGENT_RUN_FAILED' | 'AGENT_ABORTED' | 'UNKNOWN'> = ERROR_CODES.AGENT_RUN_FAILED,\n): WrongStackError {\n if (err instanceof WrongStackError) return err;\n const message = toErrorMessage(err);\n return new AgentError({\n message,\n code: code === 'UNKNOWN' ? ERROR_CODES.AGENT_RUN_FAILED : code,\n cause: err,\n });\n}\n\n/**\n * Session storage errors.\n */\nexport class SessionError extends WrongStackError {\n readonly sessionId?: string | undefined;\n\n constructor(opts: {\n message: string;\n code: Extract<ErrorCode, 'SESSION_NOT_FOUND' | 'SESSION_CORRUPTED' | 'SESSION_WRITE_FAILED'>;\n sessionId?: string | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'session',\n severity: opts.code === ERROR_CODES.SESSION_WRITE_FAILED ? 'error' : 'warning',\n recoverable: opts.code !== ERROR_CODES.SESSION_CORRUPTED,\n context: { sessionId: opts.sessionId, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'SessionError';\n this.sessionId = opts.sessionId;\n }\n}\n\n/**\n * SDD (Spec-Driven Development) errors \u2014 spec validation, parsing, and\n * state machine violations in the AISpecBuilder, TaskFlow, and TaskTracker.\n */\nexport class SddError extends WrongStackError {\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'SDD_VALIDATION_FAILED' | 'SDD_PARSE_FAILED' | 'SDD_INVALID_STATE' | 'SDD_NOT_READY'\n >;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'sdd',\n severity: opts.code === ERROR_CODES.SDD_PARSE_FAILED ? 'warning' : 'error',\n recoverable: opts.code === ERROR_CODES.SDD_NOT_READY,\n context: opts.context,\n cause: opts.cause,\n });\n this.name = 'SddError';\n }\n}\n\n/**\n * File system operation errors.\n */\nexport class FsError extends WrongStackError {\n readonly path?: string | undefined;\n\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'FS_READ_FAILED' | 'FS_WRITE_FAILED' | 'FS_MKDIR_FAILED' | 'FS_DELETE_FAILED' | 'FS_ATOMIC_WRITE_FAILED'\n >;\n path?: string | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'fs',\n severity: 'error',\n recoverable: opts.code !== ERROR_CODES.FS_READ_FAILED,\n context: { path: opts.path, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'FsError';\n this.path = opts.path;\n }\n}\n\n/**\n * HTTP fetch error \u2014 thrown when a network request returns a non-OK status.\n * Carries the response status so {@link classifyToolError} can branch on it\n * (429 \u2192 transient, 404 \u2192 not_found, 401 \u2192 permission) without duck-typing\n * the error via `'response' in err`.\n *\n * P3 #18 (before-release.md): the previous `'response' in err` check caught\n * any Error with a `response` property, including custom errors, proxy\n * objects, or mocked errors in tests. `instanceof FetchError` is reliable.\n *\n * Tools and providers that make HTTP requests and need the executor to\n * classify their failures should throw `new FetchError({ status, message })`\n * instead of a bare `Error` with an ad-hoc `response` field.\n */\nexport class FetchError extends WrongStackError {\n readonly status: number;\n\n constructor(opts: {\n message: string;\n status: number;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: ERROR_CODES.VALIDATION_ERROR,\n subsystem: 'general',\n severity: 'error',\n recoverable: opts.status === 429 || opts.status >= 500,\n context: { status: opts.status, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'FetchError';\n this.status = opts.status;\n }\n}\n\n/**\n * Tool input validation error \u2014 thrown when a tool's input fails a validation\n * check that the JSON Schema cannot express (e.g. `old_string === new_string`\n * in edit, or a cross-field invariant). Use this instead of a bare\n * `throw new Error('...validation...')` so {@link classifyToolError} can\n * match on `instanceof` rather than a locale-dependent message substring.\n *\n * P2 #6 (before-release.md): the previous `err.message.includes('validation')`\n * check misclassified any error whose message happened to contain \"validation\"\n * (e.g. a third-party \"input validation timeout\") as a VALIDATION error.\n *\n * Named `ToolValidationError` (not `ValidationError`) to avoid colliding with\n * the existing `ValidationError` interface exported by json-schema-validate.ts\n * (a validation-result shape, not an Error subclass).\n */\nexport class ToolValidationError extends WrongStackError {\n constructor(opts: {\n message: string;\n /** Field path or tool name that failed validation, for diagnostics. */\n field?: string | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: ERROR_CODES.VALIDATION_ERROR,\n subsystem: 'general',\n severity: 'error',\n recoverable: false,\n context: { field: opts.field, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'ToolValidationError';\n }\n}\n\n/**\n * Response / payload parse error \u2014 thrown when an upstream HTTP response,\n * file, or data structure is well-formed at the transport layer (HTTP 200,\n * valid JSON) but is missing required fields or has an unexpected shape.\n *\n * Distinct from `ConfigError(CONFIG_PARSE_FAILED)` (which is specifically\n * for config-file parsing) and `FetchError` (which covers HTTP non-OK\n * responses). `ParseError` fills the gap: the request succeeded but the\n * response body couldn't be interpreted.\n *\n * Common sites: OAuth token responses missing `access_token`, device-code\n * responses missing `device_code`, registry responses with unexpected\n * schemas.\n */\nexport class ParseError extends WrongStackError {\n readonly source?: string | undefined;\n\n constructor(opts: {\n message: string;\n /**\n * What was being parsed \u2014 e.g. `'oauth-token-response'`,\n * `'device-code-response'`. Lets consumers distinguish parse failures\n * from different upstream APIs without parsing the message.\n */\n source?: string | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: ERROR_CODES.PARSE_FAILED,\n subsystem: 'general',\n severity: 'error',\n recoverable: false,\n context: { source: opts.source, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'ParseError';\n this.source = opts.source;\n }\n}\n\n// \u2500\u2500 Type guards \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function isWrongStackError(err: unknown): err is WrongStackError {\n return err instanceof WrongStackError;\n}\n\nexport function isToolError(err: unknown): err is ToolError {\n return err instanceof ToolError;\n}\n\nexport function isConfigError(err: unknown): err is ConfigError {\n return err instanceof ConfigError;\n}\n\nexport function isPluginError(err: unknown): err is PluginError {\n return err instanceof PluginError;\n}\n\nexport function isSessionError(err: unknown): err is SessionError {\n return err instanceof SessionError;\n}\n\nexport function isAgentError(err: unknown): err is AgentError {\n return err instanceof AgentError;\n}\n\nexport function isFsError(err: unknown): err is FsError {\n return err instanceof FsError;\n}\n\nexport function isToolValidationError(err: unknown): err is ToolValidationError {\n return err instanceof ToolValidationError;\n}\n\nexport function isFetchError(err: unknown): err is FetchError {\n return err instanceof FetchError;\n}\n\nexport function isParseError(err: unknown): err is ParseError {\n return err instanceof ParseError;\n}\n\nexport function isSddError(err: unknown): err is SddError {\n return err instanceof SddError;\n}\n", "import { truncate } from '../utils/string.js';\nimport type { ContentBlock, TextBlock } from './blocks.js';\nimport type { ErrorCode } from './errors.js';\nimport { ERROR_CODES, WrongStackError } from './errors.js';\nimport type { Message } from './messages.js';\nimport type { Tool } from './tool.js';\n\n/**\n * Token usage for a single provider call, normalized across providers.\n *\n * Disjoint semantics: the four fields never overlap. `input` is the count\n * of FRESH input tokens (billed at the full input rate); `cacheRead` and\n * `cacheWrite` are separate cached subsets each priced at their own rate.\n * The total context the model loaded for this turn is\n * `input + (cacheRead ?? 0) + (cacheWrite ?? 0)`.\n *\n * Provider quirks normalized at the adapter layer:\n * - Anthropic: returns `input_tokens` already disjoint from cache fields.\n * - OpenAI / OpenAI-compatible: `prompt_tokens` is the TOTAL including\n * cached portion; the adapter subtracts `cached_tokens` to stay disjoint.\n * - Google: `promptTokenCount` likewise includes cache; adapter subtracts\n * `cachedContentTokenCount`.\n *\n * Cost math and the context-fullness chip both depend on the disjoint\n * invariant \u2014 a TOTAL `input` plus a separate `cacheRead` count would bill\n * cached tokens twice and skew cache-hit-ratio reporting.\n */\nexport type ReasoningEffort = 'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max';\nexport type CacheTtl = '5m' | '1h';\n\n/**\n * Provider-agnostic response-format directive.\n *\n * - `{ type: 'text' }` \u2014 free-form text (default).\n * - `{ type: 'json_object' }` \u2014 valid JSON without a schema constraint.\n * - `{ type: 'json_schema', jsonSchema: { name, schema, strict? } }` \u2014 JSON\n * constrained to the supplied JSON Schema. The `strict` flag is\n * OpenAI-specific; Gemini ignores it in favour of `responseMimeType`.\n *\n * Each provider adapter maps this into its own wire format:\n * OpenAI \u2192 `response_format`\n * Gemini \u2192 `responseMimeType` + `responseSchema`\n * Anthropic \u2192 (not yet supported; uses tools for structured output)\n */\nexport interface JsonSchemaSpec {\n name: string;\n /** OpenAI-specific: enable strict schema adherence. */\n strict?: boolean | undefined;\n /** The JSON Schema object describing the expected shape. */\n schema: Record<string, unknown>;\n /** Optional human-readable description (OpenAI). */\n description?: string | undefined;\n}\n\nexport type ResponseFormat =\n | { type: 'text' }\n | { type: 'json_object' }\n | { type: 'json_schema'; jsonSchema: JsonSchemaSpec };\n\n/**\n * Safety category threshold pair used by Google Gemini's `safetySettings`.\n *\n * Categories: `HARM_CATEGORY_HARASSMENT`, `HARM_CATEGORY_HATE_SPEECH`,\n * `HARM_CATEGORY_SEXUALLY_EXPLICIT`, `HARM_CATEGORY_DANGEROUS_CONTENT`.\n *\n * Thresholds: `BLOCK_NONE`, `BLOCK_ONLY_HIGH`, `BLOCK_MEDIUM_AND_ABOVE`,\n * `BLOCK_LOW_AND_ABOVE`.\n */\nexport interface SafetySetting {\n category: string;\n threshold: string;\n}\n\nexport interface Usage {\n input: number;\n output: number;\n cacheRead?: number | undefined;\n /** Back-compat aggregate of all cache-write tokens. Prefer TTL-specific fields when present. */\n cacheWrite?: number | undefined;\n cacheWrite5m?: number | undefined;\n cacheWrite1h?: number | undefined;\n}\n\n/**\n * Effective prompt tokens loaded by the model for one request.\n *\n * Provider adapters normalize `Usage` to disjoint fields: `input` is fresh\n * full-rate tokens, `cacheRead` is cached prefix tokens, and `cacheWrite` is\n * the cache-written prefix segment. Context-window pressure cares about the\n * full prompt the model saw, not only the bill-at-full-rate slice.\n */\nexport function effectiveInputTokens(usage: Usage): number {\n return usage.input + (usage.cacheRead ?? 0) + (usage.cacheWrite ?? 0);\n}\n\nexport interface ReasoningRequest {\n enabled?: boolean | undefined;\n effort?: ReasoningEffort | undefined;\n preserve?: boolean | undefined;\n display?: 'summarized' | 'omitted' | undefined;\n}\n\nexport interface RequestCacheControl {\n ttl?: CacheTtl | undefined;\n /**\n * Provider-agnostic cache-partition key. A stable hash of the cacheable\n * system-prompt prefix (see `deriveCachePrefixKey`); requests sharing a prefix\n * share a key so provider backends route them to the same automatic-cache\n * partition. Consumed by OpenAI-family wires as `prompt_cache_key`; ignored by\n * Anthropic (which uses `ttl` + explicit `cache_control` markers).\n */\n key?: string | undefined;\n /**\n * Opt-in flag (from `ModelRuntimeCacheConfig.geminiExplicit`) telling the\n * Google provider to use explicit `cachedContents` for this request. Ignored\n * by other providers.\n */\n geminiExplicit?: boolean | undefined;\n /**\n * Resolved Gemini `cachedContents/*` resource name, injected by\n * `GoogleProvider.stream()` after it creates/reuses the cache. When present,\n * the Google wire sends `cachedContent` and OMITS the (now-cached) system\n * instruction + tool defs from the live body. Internal \u2014 never set by callers.\n */\n geminiCachedContentName?: string | undefined;\n}\n\nexport interface ReasoningConfig {\n default: 'enabled' | 'disabled' | 'adaptive' | 'always_on';\n disableSupported: boolean;\n effortSupported: boolean;\n effortLevels: ReasoningEffort[];\n preserveThinking: 'unsupported' | 'optional' | 'always_on';\n}\n\nexport interface Capabilities {\n tools: boolean;\n parallelTools: boolean;\n vision: boolean;\n streaming: boolean;\n promptCache: boolean;\n systemPrompt: boolean;\n jsonMode: boolean;\n reasoning: boolean;\n maxContext: number;\n /**\n * Maximum output tokens the model can produce in a single response.\n * Used as the default for `Request.maxTokens` when the caller doesn't\n * supply an explicit value \u2014 letting subagents run up to the model's\n * native ceiling instead of a fixed 8192 cap. Omit (undefined) to fall\n * back to a conservative default; populate per family in\n * `family-capabilities.ts` once you know the spec.\n */\n maxOutput?: number | undefined;\n cacheControl: 'native' | 'auto' | 'none';\n\n // \u2500\u2500 Extended parameter support (optional; family defaults in CAPABILITIES_BY_FAMILY) \u2500\u2500\n\n /** Model accepts `top_k` / `topK` sampling parameter. */\n topK?: boolean | undefined;\n /** Model accepts `frequency_penalty` / `frequencyPenalty` parameter. */\n frequencyPenalty?: boolean | undefined;\n /** Model accepts `presence_penalty` / `presencePenalty` parameter. */\n presencePenalty?: boolean | undefined;\n /** Model accepts `seed` parameter for deterministic generation. */\n seed?: boolean | undefined;\n /**\n * Model accepts JSON Schema / structured-output constraints\n * (OpenAI `response_format.json_schema`, Gemini `responseMimeType`+`responseSchema`).\n * Distinct from `jsonMode` (which is just a system-prompt hint).\n */\n structuredOutput?: boolean | undefined;\n /** Model supports log-probability output (`logprobs`, `top_logprobs`). */\n logprobs?: boolean | undefined;\n /** Model supports audio input/output modality. */\n audio?: boolean | undefined;\n /** Model supports the `n` parameter for multiple completions. */\n multipleCompletions?: boolean | undefined;\n}\n\nexport interface Request {\n model: string;\n system?: TextBlock[] | undefined;\n messages: Message[];\n tools?: Tool[] | undefined;\n /**\n * Cap on output tokens for this single response. Optional \u2014 when\n * omitted, the provider adapter falls back to its own\n * `capabilities.maxOutput` (which the catalog populates from\n * `ModelsDevModel.limit.output`). If neither is available, the\n * adapter applies a conservative 8192 safety net. Letting this stay\n * undefined at the call site means callers like Chimera can hand the\n * model its native output ceiling without hard-coding a number.\n */\n maxTokens?: number | undefined;\n temperature?: number | undefined;\n topP?: number | undefined;\n topK?: number | undefined;\n frequencyPenalty?: number | undefined;\n presencePenalty?: number | undefined;\n seed?: number | undefined;\n /**\n * End-user identifier for abuse monitoring and per-user rate limiting.\n * - Anthropic \u2192 `metadata.user_id`\n * - OpenAI \u2192 `user`\n * - Gemini \u2192 (not supported)\n */\n user?: string | undefined;\n /**\n * Number of response candidates to generate. Google Gemini supports\n * this via `generationConfig.candidateCount`. OpenAI does not have\n * an equivalent (`n` is conceptually similar but distinct).\n */\n candidateCount?: number | undefined;\n /**\n * Whether to return log probabilities for output tokens.\n * - OpenAI \u2192 `logprobs: boolean` (+ `topLogprobs: number`)\n * - Gemini \u2192 `generationConfig.logprobs: number` (how many top candidates)\n * Default undefined = no logprobs requested.\n */\n logprobs?: boolean | undefined;\n /**\n * Number of most probable tokens to return log probabilities for\n * (OpenAI `top_logprobs`). Only meaningful when `logprobs` is true.\n * Range: 0-20. Gemini ignores this (uses `logprobs` as the count).\n */\n topLogprobs?: number | undefined;\n stopSequences?: string[] | undefined;\n toolChoice?: 'auto' | 'required' | 'none' | { type: 'tool' | undefined; name: string };\n reasoning?: ReasoningRequest | undefined;\n cache?: RequestCacheControl | undefined;\n /**\n * Structured-output / response-format directive.\n * When set, the provider adapter maps this to its native response-format\n * parameter (OpenAI `response_format`, Gemini `responseMimeType`, etc.).\n * The model must advertise `capabilities.structuredOutput` for this to be\n * honoured; unsupported models will likely 400 or ignore it.\n */\n responseFormat?: ResponseFormat | undefined;\n /**\n * Safety category thresholds for filtering harmful content.\n * - Gemini \u2192 top-level `safetySettings` array with `{ category, threshold }`\n * - OpenAI \u2192 not supported (uses server-side moderation)\n * - Anthropic \u2192 not supported\n */\n safetySettings?: SafetySetting[] | undefined;\n}\n\nexport type StopReason = 'end_turn' | 'tool_use' | 'max_tokens' | 'stop_sequence' | 'refusal';\n\nexport interface Response {\n content: ContentBlock[];\n stopReason: StopReason;\n usage: Usage;\n model: string;\n}\n\nexport type StreamEvent =\n | { type: 'message_start'; model: string }\n | {\n type: 'content_block_start';\n kind: 'text' | 'tool_use' | 'thinking';\n id?: string | undefined;\n name?: string | undefined;\n }\n | { type: 'content_block_stop'; index: number }\n | { type: 'text_delta'; text: string }\n | { type: 'tool_use_start'; id: string; name: string }\n | { type: 'tool_use_input_delta'; id: string; partial: string }\n | { type: 'tool_use_stop'; id: string; input: unknown; providerMeta?: Record<string, unknown> }\n | { type: 'thinking_start'; providerMeta?: Record<string, unknown> }\n | { type: 'thinking_delta'; text: string }\n | { type: 'thinking_signature'; signature: string }\n | { type: 'thinking_stop' }\n | { type: 'message_stop'; stopReason: StopReason; usage: Usage };\n\nexport interface Provider {\n readonly id: string;\n readonly capabilities: Capabilities;\n /** Canonical streaming entry point. `complete()` defaults to a wrapper that\n * aggregates this stream \u2014 providers may override for non-streaming wires. */\n stream(req: Request, opts: { signal: AbortSignal }): AsyncIterable<StreamEvent>;\n complete(req: Request, opts: { signal: AbortSignal }): Promise<Response>;\n}\n\n/**\n * Structured body parsed from a provider's HTTP error response. Populated\n * best-effort: providers return JSON shaped differently (Anthropic uses\n * `{error: {type, message}}`, OpenAI uses `{error: {message, code}}`,\n * Google uses `{error: {status, message}}`), so the fields here are the\n * intersection that's usable for rendering and routing.\n */\nexport interface ProviderErrorBody {\n /** Provider-specific kind, e.g. \"overloaded_error\", \"rate_limit_error\", \"invalid_request_error\". */\n type?: string | undefined;\n /** Human-readable explanation from the provider. */\n message?: string | undefined;\n /** Provider request id, when present in the body or headers. */\n requestId?: string | undefined;\n /** Parsed Retry-After header (or equivalent body hint) in milliseconds. */\n retryAfterMs?: number | undefined;\n /** The raw response body (truncated to ~2 KB), kept for debugging. */\n raw?: string | undefined;\n /** True when `raw` was truncated; check `rawLength` for the original size. */\n truncated?: boolean | undefined;\n /** Original length of the response body in bytes, when `truncated` is true. */\n rawLength?: number | undefined;\n}\n\n/**\n * Canonical provider-failure taxonomy. Computed ONCE at error-construction\n * time (`classifyProviderError`) and carried on `ProviderError.kind` so\n * every downstream consumer \u2014 retry policy, cross-provider fallback,\n * recovery strategies, the subagent error classifier \u2014 branches on the\n * same classification instead of re-deriving it from status codes and\n * message regexes. When a new provider's error format needs special\n * handling, this module is the only place to teach it.\n */\nexport type ProviderErrorKind =\n | 'rate_limit' // 429 / rate_limit_error \u2014 back off (honour Retry-After), then failover\n | 'quota_exhausted' // credits/plan depleted \u2014 do not retry same route; fail over immediately\n | 'overloaded' // 529 / overloaded_error \u2014 retry with backoff, then failover\n | 'server' // other 5xx \u2014 retry same provider\n | 'timeout' // 408 request timeout\n | 'network' // status 0 \u2014 connection/DNS failure before a response arrived\n | 'stream_hang' // 599 sentinel \u2014 stream stalled mid-response (StreamHangError)\n | 'auth' // 401/403 \u2014 key invalid/expired; retrying without action is pointless\n | 'context_overflow' // 413 or an overflow-shaped 4xx \u2014 compact, don't retry as-is\n | 'content_filter' // provider refused on policy grounds \u2014 a sibling model may pass, but the `content_filter_reroute` recovery strategy owns that hop, NOT the fallback engine (which surfaces this kind)\n | 'invalid_request' // other 4xx \u2014 request is malformed; retrying won't help\n | 'unknown';\n\n/**\n * Overflow-shaped provider messages. Union of the patterns previously\n * scattered across `error-handler.ts` and `coordinator/error-classifier.ts`\n * (which had drifted apart) \u2014 keep additions here, nowhere else.\n */\nconst CONTEXT_OVERFLOW_RE =\n /context.length|context.window|maximum context|max.*tokens?.*exceeded|prompt is too long|too long|exceeds the context|\\btokens\\b.*exceed|too many tokens|reduce the length|resulted in \\d+ tokens|input.{0,12}too (?:large|long)|context_length_exceeded/i;\n\n/** Content-policy refusals surfaced as HTTP errors (Azure/OpenAI `content_filter`, etc.). */\nconst CONTENT_FILTER_RE = /content.(filter|policy|moderation)|safety (system|filter)/i;\nconst QUOTA_EXHAUSTED_RE =\n /(?:insufficient|exhausted|depleted|exceeded|no|not enough)[-_\\s]*(?:quota|credit|balance)|(?:quota|credit|balance)[-_\\s]*(?:exhausted|depleted|exceeded|insufficient)|billing[_\\s-]*(?:hard[_\\s-]*)?limit|payment required|spending limit|plan limit/i;\n\n/**\n * Classify a provider HTTP failure into the canonical taxonomy from its\n * status code plus the parsed error body (and, for message-only errors\n * without a structured body, the error message itself). Pure and total \u2014\n * always returns a kind, never throws.\n */\nexport function classifyProviderError(\n status: number,\n body?: ProviderErrorBody,\n message?: string,\n): ProviderErrorKind {\n const type = body?.type;\n const text = [message, body?.message, type, body?.raw].filter(Boolean).join('\\n');\n if (status === 0) return 'network';\n if (status === 408) return 'timeout';\n if (status === 599) return 'stream_hang';\n if (status === 402 || QUOTA_EXHAUSTED_RE.test(text)) return 'quota_exhausted';\n if (type === 'rate_limit_error' || status === 429) return 'rate_limit';\n if (type === 'overloaded_error' || status === 529) return 'overloaded';\n if (status >= 500) return 'server';\n if (\n type === 'authentication_error' ||\n type === 'permission_error' ||\n status === 401 ||\n status === 403\n ) {\n return 'auth';\n }\n if (type === 'content_filter' || CONTENT_FILTER_RE.test(text)) return 'content_filter';\n if (status === 413 || (status >= 400 && CONTEXT_OVERFLOW_RE.test(text))) {\n return 'context_overflow';\n }\n if (status >= 400) return 'invalid_request';\n return 'unknown';\n}\n\n/**\n * Whether a kind is worth retrying against the SAME provider/model.\n * `context_overflow` is deliberately false \u2014 the request must shrink first;\n * `auth`/`invalid_request`/`content_filter` won't improve on replay.\n *\n * Exhaustive by construction (`Record<ProviderErrorKind, \u2026>`): adding a new\n * kind refuses to compile until it is classified here. Every kind\u2192X mapping\n * in the codebase follows this drift-guard pattern \u2014 see also KIND_TO_CODE\n * below, DefaultRetryPolicy.maxAttempts, fallback-model shouldFallback, and\n * the coordinator's providerErrorToSubagentError.\n */\nexport function isRetryableKind(kind: ProviderErrorKind): boolean {\n return RETRYABLE_BY_KIND[kind];\n}\n\nconst RETRYABLE_BY_KIND: Record<ProviderErrorKind, boolean> = {\n rate_limit: true,\n quota_exhausted: false,\n overloaded: true,\n server: true,\n timeout: true,\n network: true,\n stream_hang: true,\n auth: false,\n context_overflow: false,\n content_filter: false,\n invalid_request: false,\n unknown: false,\n};\n\n/**\n * Whether a kind is worth HOPPING to a different provider/model \u2014 the gate for\n * the cross-provider fallback engine (agent-loop extension AND the one-shot\n * orchestrator both branch on this ONE table, so their behavior can't drift).\n *\n * A distinct question from {@link isRetryableKind} (retry the SAME model):\n * a hop only helps for capacity/transport failures. Request-shaped failures\n * surface instead \u2014 `context_overflow` needs compaction, `content_filter` is\n * owned by the `content_filter_reroute` recovery strategy, and `auth` /\n * `invalid_request` are user-actionable and would fail identically on a hop.\n * The value set is currently identical to the retryable set, but it is kept as\n * its own table on purpose: the two answer different questions and may diverge.\n *\n * Exhaustive by construction (`Record<ProviderErrorKind, \u2026>`) \u2014 a new kind\n * refuses to compile until it is classified here.\n */\nexport function isFallbackWorthy(kind: ProviderErrorKind): boolean {\n return FALLBACK_WORTHY_BY_KIND[kind];\n}\n\nconst FALLBACK_WORTHY_BY_KIND: Record<ProviderErrorKind, boolean> = {\n rate_limit: true,\n quota_exhausted: true,\n overloaded: true,\n server: true,\n timeout: true,\n network: true,\n stream_hang: true,\n auth: false,\n context_overflow: false,\n content_filter: false,\n invalid_request: false,\n unknown: false,\n};\n\nexport class ProviderError extends WrongStackError {\n public readonly status: number;\n public readonly retryable: boolean;\n public readonly providerId: string;\n /** Canonical failure classification \u2014 see {@link ProviderErrorKind}. */\n public readonly kind: ProviderErrorKind;\n public readonly body?: ProviderErrorBody | undefined;\n\n constructor(\n message: string,\n status: number,\n retryable: boolean,\n providerId: string,\n opts: {\n body?: ProviderErrorBody | undefined;\n cause?: unknown | undefined;\n /** Override the computed classification (rarely needed \u2014 tests, custom wires). */\n kind?: ProviderErrorKind | undefined;\n } = {},\n ) {\n const kind = opts.kind ?? classifyProviderError(status, opts.body, message);\n super({\n message,\n code: kindToCode(kind),\n subsystem: 'provider',\n severity: status >= 500 ? 'error' : 'warning',\n recoverable: retryable,\n context: { providerId, status },\n cause: opts.cause,\n });\n this.name = 'ProviderError';\n this.status = status;\n this.retryable = retryable;\n this.providerId = providerId;\n this.kind = kind;\n this.body = opts.body;\n }\n\n /**\n * Render a one-line, user-facing description. Designed for the CLI/TUI\n * status line and the agent's retry warning. Avoids dumping raw JSON\n * (which is what users see today when a 529 lands and the log message\n * includes the full `{\"type\":\"error\",...}` body).\n *\n * Examples:\n * \"minimax-coding-plan overloaded (529): High traffic detected. Upgrade for highspeed model. [req 06534785201de9c0\u2026]\"\n * \"openai rate limited (429): Retry after 12s\"\n * \"anthropic invalid request (400): messages.0.role must be one of 'user'|'assistant'\"\n * \"groq HTTP 500 (server error)\"\n */\n override describe(): string {\n const kind = describeStatus(this.status, this.body?.type);\n const head = `${this.providerId} ${kind}`;\n const detail = this.body?.message?.trim();\n const reqId = this.body?.requestId\n ? ` [req ${this.body.requestId.slice(0, 16)}${this.body.requestId.length > 16 ? '\u2026' : ''}]`\n : '';\n if (detail && detail.length > 0) {\n return `${head}: ${truncate(detail, 240)}${reqId}`;\n }\n return `${head}${reqId}`;\n }\n}\n\n/**\n * Belt-and-suspenders overflow detection for the recovery layer. Returns true\n * when a `ProviderError` is *shaped* like a context overflow even if its `kind`\n * says otherwise \u2014 an HTTP 413, or an overflow phrase anywhere in its message /\n * body. Gateways and proxies sometimes relabel an overflow as a generic\n * `invalid_request`/400 (or a caller constructs the error with an explicit\n * wrong `kind`); the `context_overflow_reduce` strategy uses this so those\n * still trigger compact-and-retry instead of failing terminally.\n */\nexport function isContextOverflowShaped(err: unknown): boolean {\n if (!(err instanceof ProviderError)) return false;\n if (err.kind === 'context_overflow' || err.status === 413) return true;\n if (err.status < 400) return false;\n const text = [err.message, err.body?.message, err.body?.type, err.body?.raw]\n .filter(Boolean)\n .join('\\n');\n return CONTEXT_OVERFLOW_RE.test(text);\n}\n\nfunction describeStatus(status: number, type?: string): string {\n if (status === 0) return 'network error';\n if (status === 599) return `stream hang (${status})`;\n if (type === 'overloaded_error' || status === 529) return `overloaded (${status})`;\n if (type === 'rate_limit_error' || status === 429) return `rate limited (${status})`;\n if (type === 'authentication_error' || status === 401) return `auth failed (${status})`;\n if (type === 'permission_error' || status === 403) return `forbidden (${status})`;\n if (type === 'not_found_error' || status === 404) return `not found (${status})`;\n if (type === 'content_filter') return `content filtered (${status})`;\n if (type === 'invalid_request_error' || status === 400) return `invalid request (${status})`;\n if (status === 408) return `timeout (${status})`;\n if (status >= 500 && status < 600) return `HTTP ${status} (server error)`;\n if (type) return `${type} (${status})`;\n return `HTTP ${status}`;\n}\n\n/**\n * Thrown when the provider stream stops delivering data mid-response.\n * This is distinct from a network error (TCP reset, DNS failure) \u2014 the\n * connection is established and the response started, but chunks stopped\n * arriving before the stream completed.\n *\n * Status 599 is used as a sentinel to distinguish stream hangs from\n * regular HTTP errors while still flowing through ProviderError-based\n * retry and fallback infrastructure.\n */\nexport class StreamHangError extends ProviderError {\n /** Name of the provider that hung, e.g. \"zai\", \"anthropic\". */\n public readonly hungProviderId: string;\n /** Model that was being called when the hang occurred. */\n public readonly hungModel: string;\n /** How long (ms) we waited for the next chunk before declaring a hang. */\n public readonly hangTimeoutMs: number;\n /** How many bytes were received before the hang. */\n public readonly bytesReceived: number;\n /** Elapsed time (ms) from the start of the stream until the hang. */\n public readonly elapsedMs: number;\n\n constructor(opts: {\n providerId: string;\n model: string;\n hangTimeoutMs: number;\n bytesReceived: number;\n elapsedMs: number;\n cause?: unknown | undefined;\n }) {\n super(\n `Stream hang: ${opts.providerId}/${opts.model} \u2014 no data for ${opts.hangTimeoutMs}ms after ${opts.bytesReceived} bytes (${opts.elapsedMs}ms elapsed)`,\n 599,\n true, // always retryable\n opts.providerId,\n {\n body: {\n message: `Stream stalled after ${opts.elapsedMs}ms, ${opts.bytesReceived} bytes received`,\n },\n cause: opts.cause,\n },\n );\n this.name = 'StreamHangError';\n this.hungProviderId = opts.providerId;\n this.hungModel = opts.model;\n this.hangTimeoutMs = opts.hangTimeoutMs;\n this.bytesReceived = opts.bytesReceived;\n this.elapsedMs = opts.elapsedMs;\n }\n}\n\n/** Exhaustive kind \u2192 ErrorCode mapping \u2014 new kinds must be added here or the\n * file stops compiling (same drift-guard pattern as RETRYABLE_BY_KIND). */\nconst KIND_TO_CODE: Record<ProviderErrorKind, ErrorCode> = {\n network: ERROR_CODES.PROVIDER_NETWORK_ERROR,\n timeout: ERROR_CODES.PROVIDER_NETWORK_ERROR,\n rate_limit: ERROR_CODES.PROVIDER_RATE_LIMITED,\n quota_exhausted: ERROR_CODES.PROVIDER_RATE_LIMITED,\n auth: ERROR_CODES.PROVIDER_AUTH_FAILED,\n overloaded: ERROR_CODES.PROVIDER_OVERLOADED,\n context_overflow: ERROR_CODES.PROVIDER_CONTEXT_OVERFLOW,\n server: ERROR_CODES.PROVIDER_SERVER_ERROR,\n stream_hang: ERROR_CODES.PROVIDER_SERVER_ERROR,\n content_filter: ERROR_CODES.PROVIDER_INVALID_REQUEST,\n invalid_request: ERROR_CODES.PROVIDER_INVALID_REQUEST,\n unknown: ERROR_CODES.PROVIDER_INVALID_REQUEST,\n};\n\nfunction kindToCode(kind: ProviderErrorKind): ErrorCode {\n return KIND_TO_CODE[kind];\n}\n", "/**\n * Shared configuration constants used across execution, storage, CLI, and WebUI.\n * Centralized here to avoid cross-domain import cycles.\n */\n\n/** Default tools config \u2014 mirrors values baked into BEHAVIOR_DEFAULTS. */\nexport const DEFAULT_TOOLS_CONFIG = Object.freeze({\n defaultExecutionStrategy: 'smart',\n maxIterations: 100,\n iterationTimeoutMs: 300_000,\n maxToolTimeoutMs: 300_000,\n sessionTimeoutMs: 1_800_000,\n perIterationOutputCapBytes: 100_000,\n descriptionMode: Object.freeze({}) as Record<string, 'extend' | 'simple' | undefined>,\n disabledTools: Object.freeze([]) as readonly string[],\n autoExtendLimit: true,\n restrictToProjectRoot: true,\n loopDetection: Object.freeze({\n mode: 'steer-then-cut',\n steerThreshold: 3,\n cutThreshold: 5,\n windowSize: 12,\n callRepeatThreshold: 4,\n }) as Readonly<{\n mode: 'steer-then-cut' | 'cut' | 'off';\n steerThreshold: number;\n cutThreshold: number;\n windowSize: number;\n callRepeatThreshold: number;\n }>,\n});\n\n/** Default context config \u2014 mirrors BEHAVIOR_DEFAULTS.context. */\nexport const DEFAULT_CONTEXT_CONFIG = Object.freeze({\n preserveK: 8,\n eliseThreshold: 1000,\n});\n\n/** Default autonomy config \u2014 auto-proceed delay etc. */\nexport const DEFAULT_AUTONOMY_CONFIG = Object.freeze({\n autoProceedDelayMs: 45_000,\n});\n\n/**\n * Default process circuit-breaker config. Protection is OFF by default \u2014 the\n * breaker only gates `bash`/`exec` once the user opts in via `/settings breaker on`.\n * The auto kill/reset delay is only consulted when protection is enabled.\n */\nexport const DEFAULT_CIRCUIT_BREAKER_CONFIG = Object.freeze({\n enabled: false,\n autoKillResetMs: 60_000,\n});\n\n/** Default session logging / audit configuration. */\nexport const DEFAULT_SESSION_LOGGING_CONFIG = Object.freeze({\n auditLevel: 'standard' as const,\n sampling: {\n toolProgress: {\n sampleRate: 8,\n },\n },\n});\n\n/** Default retention window for local session pruning. */\nexport const DEFAULT_SESSION_PRUNE_DAYS = 30;\n", "export type MemoryScope = 'project-agents' | 'project-memory' | 'user-memory';\n\n// \u2500\u2500 Memory categories \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport type MemoryType = 'fact' | 'decision' | 'convention' | 'preference' | 'reference' | 'anti_pattern';\n\nexport const MEMORY_TYPE_LABELS: Record<MemoryType, string> = {\n fact: 'Fact',\n decision: 'Decision',\n convention: 'Convention',\n preference: 'Preference',\n reference: 'Reference',\n anti_pattern: 'Anti-pattern',\n};\n\nexport type MemoryPriority = 'critical' | 'high' | 'medium' | 'low';\n\nexport interface MemoryEntry {\n scope: MemoryScope;\n text: string;\n ts: string;\n /** Category \u2014 helps the agent decide whether to inject or ignore. */\n type?: MemoryType | undefined;\n /** Free-form tags for grouping (e.g. [\"build\", \"pnpm\", \"typescript\"]). */\n tags?: string[] | undefined;\n /** Priority \u2014 critical entries are always injected; low may be skipped. */\n priority?: MemoryPriority | undefined;\n /** Session or agent that created this entry. */\n source?: string | undefined;\n /** 0.0\u20131.0 confidence. Low-confidence entries are injected less often. */\n confidence?: number | undefined;\n /** ISO timestamp of last access (read or injection into context). */\n lastAccessed?: string | undefined;\n}\n\n// \u2500\u2500 Memory events \u2014 emitted by SuperMemoryStore so plugins can react \u2500\u2500\n\nexport interface MemoryRememberedPayload {\n scope: MemoryScope;\n text: string;\n ts: string;\n type?: MemoryType | undefined;\n tags?: string[] | undefined;\n priority?: MemoryPriority | undefined;\n}\n\nexport interface MemoryForgottenPayload {\n scope: MemoryScope;\n query: string;\n removed: number;\n}\n\nexport interface MemoryClearedPayload {\n /** Scope that was cleared, or undefined when all scopes were cleared. */\n scope?: MemoryScope | undefined;\n}\n\nexport interface MemoryConsolidatedPayload {\n scope: MemoryScope;\n /** Entries removed by deduplication. */\n removed: number;\n}\n\n// \u2500\u2500 Relevance scoring \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Context used to score memory relevance for context injection.\n * Passed by the system prompt builder.\n */\nexport interface MemoryRelevanceContext {\n /** Current user message or task description. */\n currentTask: string;\n /** Active skills in this session (e.g. [\"typescript-strict\", \"git-flow\"]). */\n activeSkills?: string[] | undefined;\n /** Active mode (e.g. \"Teach\", \"Brief\", \"Code Reviewer\"). */\n activeMode?: string | undefined;\n /** Available tools \u2014 memories referencing relevant tools score higher. */\n toolNames?: string[] | undefined;\n}\n\nexport interface ScoredEntry extends MemoryEntry {\n score: number;\n matchReason: string;\n}\n\n// \u2500\u2500 Store interface \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface MemoryStore {\n readAll(): Promise<string>;\n read(scope: MemoryScope): Promise<string>;\n remember(text: string, scope?: MemoryScope, metadata?: Omit<Partial<MemoryEntry>, 'scope' | 'text' | 'ts'>): Promise<void>;\n forget(query: string, scope?: MemoryScope): Promise<number>;\n consolidate(scope: MemoryScope): Promise<void>;\n clear(scope?: MemoryScope): Promise<void>;\n /** List entries, newest first. */\n list(scope?: MemoryScope, limit?: number): Promise<MemoryEntry[]>;\n /** Search by content (substring or semantic). */\n search(query: string, scope?: MemoryScope, limit?: number): Promise<MemoryEntry[]>;\n /** Access the backend for advanced queries. */\n getBackend?(): unknown;\n /** Graph-based related memory traversal. */\n findRelated?(text: string, scope?: MemoryScope, limit?: number): Promise<MemoryEntry[]>;\n /**\n * Score and rank memories by relevance to the current context.\n * Returns only entries that meet a relevance threshold.\n */\n scoreRelevant?(ctx: MemoryRelevanceContext, scope?: MemoryScope, limit?: number): Promise<ScoredEntry[]>;\n /**\n * Run memory hygiene: verify anchors, mark stale entries, archive\n * low-confidence/old memories. Optional \u2014 only Super Memory stores\n * implement this. Declared on the interface so callers can invoke\n * it without a type-erasing cast.\n */\n hygiene?(opts?: {\n retentionDays?: number | undefined;\n archiveLowConfidenceAfterDays?: number | undefined;\n archiveUnusedAfterDays?: number | undefined;\n unusedMinInjections?: number | undefined;\n }): Promise<unknown>;\n /**\n * Attach a trace ID to this store so that all subsequent `storage.*`\n * events include it for observability correlation. Mutates the store\n * in place and returns the same instance (convenience chaining).\n */\n withTraceId(traceId: string): MemoryStore;\n}\n", "/**\n * Prompt library types \u2014 the canonical home for the prompt data model and the\n * loader/registry contracts. Has no internal dependencies so both `storage/`\n * (the writable store) and `execution/` (the layered loader) can import it\n * without creating a cycle.\n */\n\n/** Provenance of a prompt \u2014 which layer it came from. */\nexport type PromptSource = 'builtin' | 'user' | 'project' | 'synced';\n\n/**\n * The fourteen first-party categories shipped with the builtin dataset, plus\n * the `uncategorized` sentinel used when migrating legacy v1 entries. Builtin\n * prompts MUST use one of these (enforced by the dataset schema test); user and\n * project prompts may use any free-form string.\n */\nexport const BUILTIN_PROMPT_CATEGORIES = [\n 'coding',\n 'debugging',\n 'refactoring',\n 'testing',\n 'code-review',\n 'architecture',\n 'devops',\n 'documentation',\n 'data-analysis',\n 'writing',\n 'research',\n 'product',\n 'agentic-workflows',\n 'meta-prompting',\n 'uncategorized',\n] as const;\n\nexport type BuiltinPromptCategory = (typeof BUILTIN_PROMPT_CATEGORIES)[number];\n\n/**\n * Human-readable labels for the builtin categories (for UI chips / pickers).\n */\nexport const PROMPT_CATEGORY_LABELS: Record<BuiltinPromptCategory, string> = {\n coding: 'Coding',\n debugging: 'Debugging',\n refactoring: 'Refactoring',\n testing: 'Testing',\n 'code-review': 'Code Review',\n architecture: 'Architecture',\n devops: 'DevOps',\n documentation: 'Documentation',\n 'data-analysis': 'Data Analysis',\n writing: 'Writing',\n research: 'Research',\n product: 'Product',\n 'agentic-workflows': 'Agentic Workflows',\n 'meta-prompting': 'Meta-Prompting',\n uncategorized: 'Uncategorized',\n};\n\n/**\n * A prompt's category. Typed as a free-form string because user/project prompts\n * may invent their own; the builtin dataset is constrained to\n * {@link BUILTIN_PROMPT_CATEGORIES} by its schema.\n */\nexport type PromptCategory = BuiltinPromptCategory | (string & {});\n\nexport function isBuiltinCategory(value: string): value is BuiltinPromptCategory {\n return (BUILTIN_PROMPT_CATEGORIES as readonly string[]).includes(value);\n}\n\n/** A `{{name}}` placeholder declared by a prompt. */\nexport interface PromptVariable {\n /** Placeholder name as it appears between `{{ }}` (case-sensitive). */\n name: string;\n description?: string | undefined;\n default?: string | undefined;\n required?: boolean | undefined;\n /**\n * Closed set of allowed values. When present, surfaces render a dropdown\n * instead of a free text field and a supplied value outside the set is\n * reported as invalid by {@link renderPrompt}.\n */\n enum?: string[] | undefined;\n /**\n * UI hint: the value is expected to span multiple lines (pasted code, a\n * diff, a long passage). Surfaces render a textarea instead of a one-line\n * input. Has no effect on rendering \u2014 purely presentational.\n */\n multiline?: boolean | undefined;\n}\n\n/**\n * A reusable prompt. v2 schema. Legacy v1 entries (only `id/title/content/tags/\n * createdAt/updatedAt`) are upgraded lazily on read by `migratePromptEntry`.\n */\nexport interface PromptEntry {\n /** Stable unique handle (ULID for new entries; legacy short hex tolerated). */\n id: string;\n /** kebab-case stable key \u2014 the dedup key across layers and registry key. */\n slug: string;\n title: string;\n /** One-line summary shown in lists/pickers. */\n description: string;\n content: string;\n category: PromptCategory;\n /** Secondary facets (free-form). */\n tags: string[];\n source: PromptSource;\n favorite: boolean;\n /** `{{placeholder}}` variables this prompt expects, if any. */\n variables?: PromptVariable[] | undefined;\n author?: string | undefined;\n version?: string | undefined;\n license?: string | undefined;\n /** sha256 of `content` \u2014 set for builtin/synced entries for integrity. */\n checksum?: string | undefined;\n /** When a builtin was copy-on-written into the user layer, its origin slug. */\n forkedFrom?: string | undefined;\n createdAt: string;\n updatedAt: string;\n}\n\n/** One category with its prompt count, for picker chips. */\nexport interface PromptCategoryCount {\n id: PromptCategory;\n label: string;\n count: number;\n}\n\nexport interface PromptSearchOptions {\n category?: PromptCategory | undefined;\n /** Max results (default: unbounded). */\n limit?: number | undefined;\n}\n\n/**\n * Read-side contract over the three prompt layers (project > user > builtin),\n * merged and de-duplicated by slug. Mirrors `SkillLoader` in shape.\n */\nexport interface PromptLoader {\n /** All prompts across layers, project/user shadowing builtin by slug. */\n list(): Promise<PromptEntry[]>;\n /** Resolve by slug first, then by id. */\n find(slugOrId: string): Promise<PromptEntry | undefined>;\n /** Ranked search over title/description/content/tags, optional category filter. */\n search(query: string, opts?: PromptSearchOptions): Promise<PromptEntry[]>;\n /** Category counts across all layers, for UI chips. */\n categories(): Promise<PromptCategoryCount[]>;\n /**\n * Persist into the writable (user, or project when `scope:'project'`) layer.\n * Throws if the resolved target is the read-only builtin layer.\n */\n save(entry: PromptEntry, opts?: { scope?: 'user' | 'project' }): Promise<void>;\n /** Delete from a writable layer. Returns false if not found / builtin. */\n delete(slugOrId: string): Promise<boolean>;\n /**\n * Mark/unmark a prompt as favorite. Favoriting a builtin copies it down into\n * the user layer (copy-on-write, `source:'user'`, `forkedFrom:<slug>`).\n */\n setFavorite(slugOrId: string, favorite: boolean): Promise<PromptEntry | undefined>;\n /** Clear the internal cache so the next read re-scans disk. */\n invalidateCache(): void;\n}\n\n/**\n * The packed builtin index (also the shape a remote registry manifest mirrors\n * \u2014 see `types/prompt-registry.ts`).\n */\nexport interface PromptManifest {\n datasetVersion: number;\n generatedAt: string;\n count: number;\n categories: PromptCategoryCount[];\n prompts: PromptManifestRef[];\n}\n\nexport interface PromptManifestRef {\n id: string;\n slug: string;\n title: string;\n description: string;\n category: PromptCategory;\n tags: string[];\n checksum: string;\n /** Relative path of the per-prompt file within the dataset. */\n file: string;\n}\n", "/**\n * Prompt registry / sync types \u2014 the contract for a remote prompt hub\n * (e.g. prompts.wrongstack.com) and the local installed-prompts manifest.\n *\n * The manifest shape intentionally mirrors the bundled dataset's\n * `data/prompts/index.json` (see `PromptManifest` in `types/prompt.ts`): the\n * builtin dataset IS a local registry, so builtin and synced prompts can flow\n * through one validation + diff path. This file defines the format and the\n * structural validator; the actual fetch/download is a deliberately small stub\n * (see `prompts/prompt-installer.ts`) \u2014 \"groundwork now, sync later\".\n */\nimport type { PromptCategory } from './prompt.js';\n\nexport interface PromptRegistryRef {\n id: string;\n slug: string;\n title: string;\n description: string;\n category: PromptCategory;\n tags: string[];\n /** sha256 of the prompt content \u2014 drives the update diff. */\n checksum: string;\n version?: string | undefined;\n license?: string | undefined;\n /** Optional direct URL to the full prompt JSON. */\n url?: string | undefined;\n}\n\nexport interface PromptRegistryManifest {\n registryVersion: 1;\n /** Where this manifest came from (hub URL or `owner/repo`). */\n source: string;\n generatedAt: string;\n prompts: PromptRegistryRef[];\n}\n\n/** One entry recorded in `~/.wrongstack/installed-prompts.json`. */\nexport interface InstalledPromptEntry {\n slug: string;\n /** The registry/source this prompt was pulled from. */\n source: string;\n /** The ref pinned at install (tag/branch/commit or manifest version). */\n ref: string;\n checksum: string;\n /** True once the prompt body has actually been written locally. */\n synced: boolean;\n installedAt: string;\n}\n\nexport interface PromptManifestData {\n version: 1;\n entries: InstalledPromptEntry[];\n}\n\n/** Result of validating an untrusted manifest. */\nexport type ManifestValidation =\n | { ok: true; manifest: PromptRegistryManifest }\n | { ok: false; errors: string[] };\n\nconst SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\nconst CHECKSUM_RE = /^[a-f0-9]{64}$/;\nconst MAX_STR = 4096;\n\n/**\n * Structurally validate an untrusted registry manifest. Treats the manifest as\n * DATA, not instructions: enforces slug charset, checksum format, and field\n * lengths so a malicious hub can't smuggle oversized or malformed entries into\n * the local store. Does NOT fetch prompt bodies.\n */\nexport function validateRegistryManifest(raw: unknown): ManifestValidation {\n const errors: string[] = [];\n if (!raw || typeof raw !== 'object') return { ok: false, errors: ['manifest is not an object'] };\n const m = raw as Record<string, unknown>;\n\n if (m['registryVersion'] !== 1) errors.push('registryVersion must be 1');\n if (typeof m['source'] !== 'string' || !m['source'])\n errors.push('source must be a non-empty string');\n if (typeof m['generatedAt'] !== 'string') errors.push('generatedAt must be a string');\n if (!Array.isArray(m['prompts'])) {\n errors.push('prompts must be an array');\n return { ok: false, errors };\n }\n\n const seen = new Set<string>();\n const refs: PromptRegistryRef[] = [];\n (m['prompts'] as unknown[]).forEach((p, i) => {\n if (!p || typeof p !== 'object') {\n errors.push(`prompts[${i}] is not an object`);\n return;\n }\n const r = p as Record<string, unknown>;\n const slug = r['slug'];\n if (typeof slug !== 'string' || !SLUG_RE.test(slug)) {\n errors.push(`prompts[${i}].slug invalid (must be kebab-case)`);\n return;\n }\n if (seen.has(slug)) {\n errors.push(`prompts[${i}].slug \"${slug}\" duplicated`);\n return;\n }\n seen.add(slug);\n if (typeof r['checksum'] !== 'string' || !CHECKSUM_RE.test(r['checksum'])) {\n errors.push(`prompts[${i}].checksum must be a 64-char sha256 hex`);\n return;\n }\n for (const field of ['id', 'title', 'description', 'category'] as const) {\n const v = r[field];\n if (typeof v !== 'string' || v.length === 0 || v.length > MAX_STR) {\n errors.push(`prompts[${i}].${field} must be a non-empty string under ${MAX_STR} chars`);\n return;\n }\n }\n const tags = Array.isArray(r['tags'])\n ? (r['tags'].filter((t) => typeof t === 'string') as string[])\n : [];\n refs.push({\n id: r['id'] as string,\n slug,\n title: r['title'] as string,\n description: r['description'] as string,\n category: r['category'] as string,\n tags,\n checksum: r['checksum'] as string,\n version: typeof r['version'] === 'string' ? r['version'] : undefined,\n license: typeof r['license'] === 'string' ? r['license'] : undefined,\n url: typeof r['url'] === 'string' ? r['url'] : undefined,\n });\n });\n\n if (errors.length > 0) return { ok: false, errors };\n return {\n ok: true,\n manifest: {\n registryVersion: 1,\n source: m['source'] as string,\n generatedAt: m['generatedAt'] as string,\n prompts: refs,\n },\n };\n}\n\nexport interface RegistryDiff {\n /** Slugs present in the manifest but not locally. */\n added: PromptRegistryRef[];\n /** Slugs present locally but whose checksum differs in the manifest. */\n updated: PromptRegistryRef[];\n /** Slugs present locally and identical in the manifest. */\n unchanged: PromptRegistryRef[];\n}\n\n/**\n * Compute what a pull WOULD change, by slug+checksum, against the prompts the\n * caller already has. Pure \u2014 no I/O, no writes.\n */\nexport function diffRegistry(\n local: { slug: string; checksum?: string | undefined }[],\n manifest: PromptRegistryManifest,\n): RegistryDiff {\n const localBySlug = new Map(local.map((e) => [e.slug, e.checksum]));\n const diff: RegistryDiff = { added: [], updated: [], unchanged: [] };\n for (const ref of manifest.prompts) {\n if (!localBySlug.has(ref.slug)) diff.added.push(ref);\n else if (localBySlug.get(ref.slug) !== ref.checksum) diff.updated.push(ref);\n else diff.unchanged.push(ref);\n }\n return diff;\n}\n", "/**\n * Design Studio \u2014 curated frontend/mobile UI design kits.\n *\n * A \"design kit\" is a self-contained, selectable design direction (an aesthetic\n * + concrete design tokens + per-stack implementation guidance) that the model\n * commits to BEFORE writing UI code. Kits are surfaced progressively: a compact\n * menu is injected when frontend work is detected, and the heavy kit body is\n * only loaded once the model (or user) picks one \u2014 keeping per-turn tokens low.\n *\n * This mirrors the skills subsystem (`types/skill.ts` + `execution/skill-loader.ts`)\n * but adds the per-stack body selection and a token snapshot for visual pickers.\n */\n\n/** Target implementation stacks a kit can speak to. */\nexport const DESIGN_STACKS = ['web', 'react-native', 'flutter', 'swiftui', 'compose'] as const;\n\nexport type DesignStack = (typeof DESIGN_STACKS)[number];\n\nexport function isDesignStack(v: string): v is DesignStack {\n return (DESIGN_STACKS as readonly string[]).includes(v);\n}\n\nexport interface DesignKitManifest {\n id: string;\n name: string;\n /** One-line vibe shown in the menu, e.g. \"Restrained, Linear-style minimalism\". */\n aesthetic: string;\n /** Free-form tags for filtering. */\n tags: string[];\n /** Stacks this kit provides guidance for. */\n stacks: DesignStack[];\n /** Whether the kit ships light + dark themes (almost always true). */\n themes: string[];\n /** \"Best for\u2026\" one-liner used in menu + pickers. */\n bestFor: string;\n version?: string | undefined;\n path: string;\n source: 'project' | 'user' | 'bundled';\n}\n\n/** A single theme's concrete token values (OKLCH strings, font names, etc.). */\nexport interface DesignTokenSet {\n [token: string]: string;\n}\n\n/** Parsed `tokens.json` \u2014 light + dark token snapshots used by visual pickers. */\nexport interface DesignKitTokens {\n light?: DesignTokenSet | undefined;\n dark?: DesignTokenSet | undefined;\n}\n\n/** Compact menu entry rendered into the request when frontend work is detected. */\nexport interface DesignKitEntry {\n id: string;\n name: string;\n aesthetic: string;\n bestFor: string;\n stacks: DesignStack[];\n source: DesignKitManifest['source'];\n}\n\n/**\n * Live Design Studio state stashed on `ctx.meta.designStudio`. Set by the\n * detection middleware (user intent + frontend file writes); read by the\n * request middleware that injects the menu / active-kit reminder.\n */\nexport interface DesignStudioState {\n /** True once frontend/UI work has been detected this session. */\n active: boolean;\n /** Detected target stack, if any. */\n stack?: DesignStack | undefined;\n /** What triggered activation (for transparency / debugging). */\n signals: string[];\n /** Kit id the model/user committed to, if any. */\n activeKit?: string | undefined;\n /**\n * User color/token overrides applied over the active kit's tokens. Keys are\n * token names (`primary`) applied to both themes, or theme-scoped\n * (`light.bg`/`dark.bg`). See `applyTokenOverrides`.\n */\n overrides?: Record<string, string> | undefined;\n}\n\nexport interface DesignKitLoader {\n list(): Promise<DesignKitManifest[]>;\n /** Structured entries for the compact menu. */\n listEntries(): Promise<DesignKitEntry[]>;\n find(id: string): Promise<DesignKitManifest | undefined>;\n /** Compact, model-facing menu of every available kit. */\n menuText(): Promise<string>;\n /**\n * Full kit body for a given stack. Strips frontmatter and, when `stack` is\n * provided, narrows stack-specific sections to that stack.\n */\n readBody(id: string, stack?: DesignStack | undefined): Promise<string>;\n /** Parsed `tokens.json` for a kit (light/dark snapshots), if present. */\n readTokens(id: string): Promise<DesignKitTokens | undefined>;\n /** The mandatory cross-cutting baseline (responsive / a11y / theming / motion). */\n foundationsText(stack?: DesignStack | undefined): Promise<string>;\n invalidateCache(): void;\n}\n", "import { readFileSync, statSync } from 'node:fs';\nimport * as path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nexport function modePrompt(id: string): string {\n for (const dir of modePromptDirCandidates()) {\n try {\n return readFileSync(path.join(dir, `${id}.md`), 'utf8').trimEnd();\n } catch {\n // try next candidate\n }\n }\n return '';\n}\n\nfunction modePromptDirCandidates(): string[] {\n const here = path.dirname(fileURLToPath(import.meta.url));\n const candidates = [\n path.resolve(here, '../../instructions/modes'),\n path.resolve(here, '../instructions/modes'),\n path.resolve(here, 'instructions/modes'),\n ];\n return candidates.sort((a, b) => Number(!isDirectory(a)) - Number(!isDirectory(b)));\n}\n\nfunction isDirectory(candidate: string): boolean {\n try {\n return statSync(candidate).isDirectory();\n } catch {\n return false;\n }\n}\n", "import { modePrompt } from './mode-prompts.js';\nexport interface Mode {\n id: string;\n name: string;\n description: string;\n /** Additional prompt text injected into system prompt when mode is active */\n prompt: string;\n /** Tags for tool_search filtering */\n tags?: string[] | undefined;\n /** Tools that should be prioritized/highlighted when this mode is active */\n toolPreferences?: string[] | undefined;\n /**\n * Skill names that are particularly relevant to this mode. The system\n * prompt builder appends a \"Suggested skills\" note so the model knows\n * which domain knowledge to leverage first. Skill must exist in the\n * loaded skill set to appear.\n */\n suggestedSkills?: string[] | undefined;\n}\n\nexport interface ModeManifest {\n modes: Mode[];\n defaultMode?: string | undefined;\n}\n\nexport interface ModeStore {\n getActiveMode(): Promise<Mode | null>;\n setActiveMode(modeId: string | null): Promise<void>;\n listModes(): Promise<Mode[]>;\n getMode(modeId: string): Promise<Mode | null>;\n}\n\nexport interface ModeConfig {\n directory: string;\n}\n\nexport const DEFAULT_MODES: Mode[] = [\n {\n id: 'default',\n name: 'Default',\n description: 'Balanced general-purpose mode; use when no special token/coverage trade-off is needed',\n prompt: '',\n tags: ['general', 'balanced'],\n },\n {\n id: 'brief',\n name: 'Brief',\n description: 'Ultra-compact responses for low-context, high-speed work',\n prompt: modePrompt('brief'),\n tags: ['lite', 'fast', 'concise', 'token-saving'],\n toolPreferences: ['read', 'edit', 'bash'],\n suggestedSkills: [],\n },\n {\n id: 'review-lite',\n name: 'Review Lite',\n description: 'Token-saving code review: changed files only, top correctness/security risks',\n prompt: modePrompt('review-lite'),\n tags: ['lite', 'review', 'quality', 'token-saving'],\n toolPreferences: ['git', 'diff', 'read', 'grep'],\n suggestedSkills: ['bug-hunter', 'typescript-strict'],\n },\n {\n id: 'audit-lite',\n name: 'Audit Lite',\n description: 'Token-saving security triage for a small diff or named file',\n prompt: modePrompt('audit-lite'),\n tags: ['lite', 'security', 'audit', 'token-saving'],\n toolPreferences: ['grep', 'read', 'git'],\n suggestedSkills: ['security-scanner'],\n },\n {\n id: 'plan-lite',\n name: 'Plan Lite',\n description: 'Token-saving planning: 3-6 actionable steps, minimal design debate',\n prompt: modePrompt('plan-lite'),\n tags: ['lite', 'planning', 'architecture', 'token-saving'],\n toolPreferences: ['tree', 'glob', 'read', 'grep'],\n suggestedSkills: ['refactor-planner'],\n },\n {\n id: 'debug-lite',\n name: 'Debug Lite',\n description: 'Token-saving bug triage: one hypothesis, nearest evidence, narrow check',\n prompt: modePrompt('debug-lite'),\n tags: ['lite', 'debug', 'triage', 'token-saving'],\n toolPreferences: ['read', 'grep', 'test', 'logs'],\n suggestedSkills: ['bug-hunter'],\n },\n {\n id: 'test-lite',\n name: 'Test Lite',\n description: 'Token-saving tests: one focused regression or narrow verification target',\n prompt: modePrompt('test-lite'),\n tags: ['lite', 'testing', 'qa', 'token-saving'],\n toolPreferences: ['test', 'read', 'grep'],\n suggestedSkills: ['testing'],\n },\n {\n id: 'refactor-lite',\n name: 'Refactor Lite',\n description: 'Token-saving cleanup: small scoped behavior-preserving changes',\n prompt: modePrompt('refactor-lite'),\n tags: ['lite', 'refactor', 'token-saving'],\n toolPreferences: ['read', 'edit', 'test'],\n suggestedSkills: ['typescript-strict'],\n },\n {\n id: 'research-lite',\n name: 'Research Lite',\n description: 'Token-saving web research: one search, one authoritative fetch, short answer',\n prompt: modePrompt('research-lite'),\n tags: ['lite', 'research', 'web', 'token-saving'],\n toolPreferences: ['search', 'fetch'],\n suggestedSkills: ['research-web'],\n },\n {\n id: 'code-reviewer',\n name: 'Review Deep',\n description: 'Comprehensive code review across contracts, edge cases, lifecycle, errors, concurrency',\n prompt: modePrompt('code-reviewer'),\n tags: ['deep', 'review', 'quality', 'security'],\n toolPreferences: ['read', 'grep', 'git', 'diff', 'test'],\n suggestedSkills: ['bug-hunter', 'security-scanner', 'typescript-strict', 'testing'],\n },\n {\n id: 'code-auditor',\n name: 'Audit Deep',\n description: 'Comprehensive security audit with category coverage and exploitability notes',\n prompt: modePrompt('code-auditor'),\n tags: ['deep', 'security', 'audit', 'compliance'],\n toolPreferences: ['grep', 'read', 'audit', 'bash'],\n suggestedSkills: ['security-scanner', 'bug-hunter', 'audit-log'],\n },\n {\n id: 'architect',\n name: 'Architecture Deep',\n description: 'Comprehensive architecture and cross-module contract analysis',\n prompt: modePrompt('architect'),\n tags: ['deep', 'architecture', 'design', 'scalability'],\n toolPreferences: ['read', 'glob', 'tree', 'diff'],\n suggestedSkills: ['api-design', 'refactor-planner', 'node-modern', 'docker-deploy'],\n },\n {\n id: 'debugger',\n name: 'Debug Deep',\n description: 'Comprehensive root-cause analysis with traces, logs, assumptions, and verification',\n prompt: modePrompt('debugger'),\n tags: ['deep', 'debug', 'investigation', 'error-resolution'],\n toolPreferences: ['read', 'grep', 'bash', 'logs', 'test'],\n suggestedSkills: ['bug-hunter', 'audit-log', 'observability'],\n },\n {\n id: 'tester',\n name: 'Test Deep',\n description: 'Comprehensive QA mode for coverage, boundaries, isolation, and integration gaps',\n prompt: modePrompt('tester'),\n tags: ['deep', 'testing', 'qa', 'quality'],\n toolPreferences: ['read', 'grep', 'test', 'bash'],\n suggestedSkills: ['testing', 'bug-hunter', 'typescript-strict'],\n },\n {\n id: 'devops',\n name: 'DevOps Deep',\n description: 'Comprehensive infrastructure, deployment, observability, and operations review',\n prompt: modePrompt('devops'),\n tags: ['deep', 'devops', 'infrastructure', 'operations'],\n toolPreferences: ['read', 'bash', 'grep', 'logs', 'git'],\n suggestedSkills: ['docker-deploy', 'observability', 'security-scanner'],\n },\n {\n id: 'refactorer',\n name: 'Refactor Deep',\n description: 'Comprehensive modernization/refactor mode with contracts and verification discipline',\n prompt: modePrompt('refactorer'),\n tags: ['deep', 'refactor', 'modernization', 'improvement'],\n toolPreferences: ['read', 'edit', 'test', 'git', 'grep'],\n suggestedSkills: ['refactor-planner', 'typescript-strict', 'node-modern', 'testing'],\n },\n {\n id: 'ui-design',\n name: 'UI Design Deep',\n description: 'Comprehensive design-first frontend/mobile UI work with kit, tokens, and accessibility',\n prompt: modePrompt('ui-design'),\n tags: ['deep', 'ui', 'frontend', 'mobile', 'design'],\n toolPreferences: ['design', 'write', 'edit', 'read', 'scaffold'],\n suggestedSkills: ['react-modern'],\n },\n {\n id: 'teach',\n name: 'Teach Deep',\n description: 'Mentor mode with explanations, mental models, trade-offs, and takeaways',\n prompt: modePrompt('teach'),\n tags: ['deep', 'teaching', 'mentor', 'learning'],\n toolPreferences: ['read', 'edit', 'explain'],\n suggestedSkills: ['prompt-engineering', 'skill-creator', 'node-modern', 'typescript-strict'],\n },\n {\n id: 'research-web',\n name: 'Research Deep',\n description: 'Comprehensive current-data research with cross-checking and reusable findings',\n prompt: modePrompt('research-web'),\n tags: ['deep', 'research', 'web', 'current-data', 'up-to-date'],\n toolPreferences: ['search', 'fetch', 'context_manager'],\n suggestedSkills: ['research-web', 'tech-stack', 'node-modern', 'security-scanner', 'react-modern'],\n },\n];\n", "import { expectDefined } from '../utils/expect-defined.js';\nexport type ContextWindowModeId = 'balanced' | 'frugal' | 'deep' | 'archival';\n\nexport type ContextWindowAggressiveOn = 'hard' | 'soft' | 'warn';\n\nexport interface ContextWindowThresholds {\n warn: number;\n soft: number;\n hard: number;\n}\n\nexport interface ContextWindowMode {\n id: ContextWindowModeId;\n name: string;\n description: string;\n thresholds: ContextWindowThresholds;\n aggressiveOn: ContextWindowAggressiveOn;\n preserveK: number;\n eliseThreshold: number;\n targetLoad: number;\n}\n\nexport interface ContextWindowPolicy extends ContextWindowMode {}\n\nexport interface ContextWindowConfigLike {\n mode?: ContextWindowModeId | string | undefined;\n warnThreshold?: number | undefined;\n softThreshold?: number | undefined;\n hardThreshold?: number | undefined;\n preserveK?: number | undefined;\n eliseThreshold?: number | undefined;\n}\n\nexport const DEFAULT_CONTEXT_WINDOW_MODE_ID: ContextWindowModeId = 'frugal';\n\nexport const CONTEXT_WINDOW_MODES: readonly ContextWindowMode[] = Object.freeze([\n {\n id: 'balanced',\n name: 'Balanced',\n description: 'Default rolling compaction: recent work stays verbatim, old tool output is trimmed.',\n thresholds: { warn: 0.5, soft: 0.65, hard: 0.8 },\n aggressiveOn: 'soft',\n preserveK: 8,\n eliseThreshold: 1000,\n targetLoad: 0.55,\n },\n {\n id: 'frugal',\n name: 'Frugal',\n description: 'Token-saver mode: compacts early and keeps a tighter verbatim tail.',\n thresholds: { warn: 0.45, soft: 0.6, hard: 0.75 },\n aggressiveOn: 'warn',\n preserveK: 6,\n eliseThreshold: 700,\n targetLoad: 0.5,\n },\n {\n id: 'deep',\n name: 'Deep',\n description: 'Long-reasoning mode: delays compaction and keeps more recent turns intact.',\n thresholds: { warn: 0.72, soft: 0.86, hard: 0.96 },\n aggressiveOn: 'hard',\n preserveK: 18,\n eliseThreshold: 5000,\n targetLoad: 0.78,\n },\n {\n id: 'archival',\n name: 'Archival',\n description: 'Decision-preserving mode: compacts steadily while keeping summaries prominent.',\n thresholds: { warn: 0.55, soft: 0.7, hard: 0.84 },\n aggressiveOn: 'soft',\n preserveK: 8,\n eliseThreshold: 1200,\n targetLoad: 0.58,\n },\n]);\n\nexport function listContextWindowModes(): ContextWindowMode[] {\n return CONTEXT_WINDOW_MODES.map((m) => ({ ...m, thresholds: { ...m.thresholds } }));\n}\n\nexport function getContextWindowMode(id: string | null | undefined): ContextWindowMode | null {\n if (!id) return null;\n const mode = CONTEXT_WINDOW_MODES.find((m) => m.id === id);\n return mode ? { ...mode, thresholds: { ...mode.thresholds } } : null;\n}\n\nexport function isContextWindowModeId(id: string): id is ContextWindowModeId {\n return CONTEXT_WINDOW_MODES.some((m) => m.id === id);\n}\n\nexport function resolveContextWindowPolicy(\n config: ContextWindowConfigLike = {},\n overrideMode?: string | null | undefined,\n): ContextWindowPolicy {\n const requested = overrideMode ?? config.mode ?? DEFAULT_CONTEXT_WINDOW_MODE_ID;\n const mode = getContextWindowMode(requested) ?? expectDefined(getContextWindowMode(DEFAULT_CONTEXT_WINDOW_MODE_ID));\n\n return {\n ...mode,\n thresholds: {\n warn: config.warnThreshold ?? mode.thresholds.warn,\n soft: config.softThreshold ?? mode.thresholds.soft,\n hard: config.hardThreshold ?? mode.thresholds.hard,\n },\n preserveK: config.preserveK ?? mode.preserveK,\n eliseThreshold: config.eliseThreshold ?? mode.eliseThreshold,\n };\n}\n\nexport function formatContextWindowModeList(activeId?: string | null): string {\n return CONTEXT_WINDOW_MODES.map((m) => {\n const marker = m.id === activeId ? '*' : ' ';\n return `${marker} ${m.id.padEnd(9)} ${m.name} - ${m.description}`;\n }).join('\\n');\n}\n", "export type SpecStatus = 'draft' | 'review' | 'approved' | 'implemented' | 'deprecated';\nexport type SpecSectionType =\n | 'overview'\n | 'requirements'\n | 'architecture'\n | 'api'\n | 'data'\n | 'security'\n | 'acceptance';\n\nexport interface SpecSection {\n type: SpecSectionType;\n title: string;\n content: string;\n level: number;\n children?: SpecSection[] | undefined;\n}\n\nexport interface SpecRequirement {\n id: string;\n type: 'functional' | 'non-functional' | 'security' | 'performance' | 'ux';\n priority: 'critical' | 'high' | 'medium' | 'low';\n description: string;\n acceptanceCriteria: string[];\n blockedBy?: string[] | undefined;\n implements?: string[] | undefined;\n}\n\nexport interface SpecApiEndpoint {\n method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';\n path: string;\n description: string;\n request?: Record<string, unknown>;\n response?: Record<string, unknown>;\n auth?: boolean | undefined;\n}\n\nexport interface Specification {\n id: string;\n title: string;\n version: string;\n status: SpecStatus;\n overview: string;\n sections: SpecSection[];\n requirements: SpecRequirement[];\n apiEndpoints?: SpecApiEndpoint[] | undefined;\n dependencies?: string[] | undefined;\n createdAt: number;\n updatedAt: number;\n metadata?: Record<string, unknown>;\n}\n\nexport interface SpecAnalysis {\n specId: string;\n completeness: number; // 0-100\n coverage: {\n requirements: number;\n apiEndpoints: number;\n edgeCases: number;\n errorHandling: number;\n };\n gaps: string[];\n risks: { requirement: string; risk: string; severity: 'high' | 'medium' | 'low' }[];\n suggestions: string[];\n}\n\nexport interface SpecValidationResult {\n valid: boolean;\n errors: { path: string; message: string }[];\n warnings: { path: string; message: string }[];\n}\n\nexport interface SpecTemplate {\n id: string;\n name: string;\n description: string;\n sections: Omit<SpecSection, 'content'>[];\n defaultRequirements: Omit<SpecRequirement, 'id' | 'description'>[];\n}\n\nexport const DEFAULT_SPEC_TEMPLATE: SpecTemplate = {\n id: 'default',\n name: 'Default Feature Spec',\n description: 'Standard template for feature specifications',\n sections: [\n { type: 'overview', title: 'Overview', level: 1 },\n { type: 'requirements', title: 'Requirements', level: 1 },\n { type: 'architecture', title: 'Architecture', level: 1 },\n { type: 'api', title: 'API Design', level: 1 },\n { type: 'data', title: 'Data Model', level: 1 },\n { type: 'security', title: 'Security', level: 1 },\n { type: 'acceptance', title: 'Acceptance Criteria', level: 1 },\n ],\n defaultRequirements: [\n { type: 'functional', priority: 'high', acceptanceCriteria: [], blockedBy: [], implements: [] },\n {\n type: 'non-functional',\n priority: 'medium',\n acceptanceCriteria: [],\n blockedBy: [],\n implements: [],\n },\n ],\n};\n", "export type TaskStatus = 'pending' | 'in_progress' | 'blocked' | 'failed' | 'review' | 'completed';\nexport type TaskPriority = 'critical' | 'high' | 'medium' | 'low';\nexport type TaskType = 'feature' | 'bugfix' | 'refactor' | 'docs' | 'test' | 'chore';\n\nexport interface TaskNode {\n id: string;\n title: string;\n description: string;\n type: TaskType;\n priority: TaskPriority;\n status: TaskStatus;\n assignee?: string | undefined;\n estimateHours?: number | undefined;\n actualHours?: number | undefined;\n tags?: string[] | undefined;\n specRequirementId?: string | undefined;\n parentId?: string | undefined;\n children?: string[] | undefined;\n createdAt: number;\n updatedAt: number;\n startedAt?: number | undefined; // set when status \u2192 in_progress\n completedAt?: number | undefined;\n metadata?: Record<string, unknown>;\n}\n\nexport interface TaskEdge {\n id: string;\n from: string;\n to: string;\n type: 'blocks' | 'depends_on' | 'relates_to' | 'implements';\n weight?: number | undefined;\n}\n\nexport interface TaskGraph {\n id: string;\n specId: string;\n title: string;\n nodes: Map<string, TaskNode>;\n edges: TaskEdge[];\n rootNodes: string[];\n createdAt: number;\n updatedAt: number;\n}\n\nexport interface TaskDependency {\n taskId: string;\n blockedBy: string[];\n blocking: string[];\n}\n\nexport interface TaskAssignment {\n taskId: string;\n assignee: string;\n assignedAt: number;\n}\n\nexport interface TaskProgress {\n total: number;\n pending: number;\n inProgress: number;\n blocked: number;\n failed: number;\n review: number;\n completed: number;\n percentComplete: number;\n estimatedHours: number;\n actualHours: number;\n}\n\nexport interface TaskFilter {\n status?: TaskStatus[] | undefined;\n priority?: TaskPriority[] | undefined;\n type?: TaskType[] | undefined;\n assignee?: string[] | undefined;\n tags?: string[] | undefined;\n specRequirementId?: string | undefined;\n}\n\nexport interface TaskSort {\n field: 'priority' | 'createdAt' | 'updatedAt' | 'status';\n direction: 'asc' | 'desc';\n}\n\nexport interface CriticalPathResult {\n taskIds: string[];\n totalEstimateHours: number;\n bottleneckTasks: string[];\n}\n\nexport function computeTaskProgress(graph: TaskGraph): TaskProgress {\n let completed = 0;\n let pending = 0;\n let inProgress = 0;\n let blocked = 0;\n let failed = 0;\n let review = 0;\n let estimatedHours = 0;\n let actualHours = 0;\n for (const n of graph.nodes.values()) {\n switch (n.status) {\n case 'completed':\n completed++;\n break;\n case 'pending':\n pending++;\n break;\n case 'in_progress':\n inProgress++;\n break;\n case 'blocked':\n blocked++;\n break;\n case 'failed':\n failed++;\n break;\n case 'review':\n review++;\n break;\n }\n estimatedHours += n.estimateHours ?? 0;\n actualHours += n.actualHours ?? 0;\n }\n const total = graph.nodes.size;\n\n return {\n total,\n pending,\n inProgress,\n blocked,\n failed,\n review,\n completed,\n percentComplete: total > 0 ? Math.round((completed / total) * 100) : 0,\n estimatedHours,\n actualHours,\n };\n}\n\nexport function findCriticalPath(graph: TaskGraph): CriticalPathResult {\n const nodes = Array.from(graph.nodes.values());\n const criticalNodes = nodes.filter((n) => n.priority === 'critical');\n const bottleneckTasks = criticalNodes\n .filter((n) => graph.edges.some((e) => e.to === n.id && e.type === 'depends_on'))\n .map((n) => n.id);\n\n const totalEstimateHours = criticalNodes.reduce((sum, n) => sum + (n.estimateHours ?? 0), 0);\n\n return {\n taskIds: criticalNodes.map((n) => n.id),\n totalEstimateHours,\n bottleneckTasks,\n };\n}\n\nexport function topologicalSort(graph: TaskGraph): string[] {\n const visited = new Set<string>();\n const inStack = new Set<string>();\n const result: string[] = [];\n\n function visit(id: string): void {\n // Cycle: callers must detect cycles up-front if they care; we just stop recursing.\n if (inStack.has(id)) return;\n if (visited.has(id)) return;\n if (!graph.nodes.has(id)) return;\n\n visited.add(id);\n inStack.add(id);\n\n for (const edge of graph.edges) {\n if (edge.from === id) visit(edge.to);\n }\n\n inStack.delete(id);\n result.push(id);\n }\n\n for (const rootId of graph.rootNodes) {\n visit(rootId);\n }\n\n return result;\n}\n\nexport type SerializableTaskGraphNodes =\n | TaskNode[]\n | Array<[string, TaskNode]>\n | Record<string, TaskNode>;\n\nexport type SerializableTaskGraph = Omit<TaskGraph, 'nodes'> & {\n nodes: SerializableTaskGraphNodes;\n};\n\nexport type SerializedTaskGraph = Omit<TaskGraph, 'nodes'> & {\n nodes: TaskNode[];\n};\n\nexport function serializeTaskGraph(graph: TaskGraph): SerializedTaskGraph {\n return {\n ...graph,\n nodes: Array.from(graph.nodes.values()),\n };\n}\n\nexport function deserializeTaskGraph(input: SerializableTaskGraph): TaskGraph {\n const nodes = new Map<string, TaskNode>();\n if (Array.isArray(input.nodes)) {\n for (const entry of input.nodes) {\n if (Array.isArray(entry)) nodes.set(entry[0], { ...entry[1], id: entry[1].id || entry[0] });\n else nodes.set(entry.id, entry);\n }\n } else {\n for (const [id, node] of Object.entries(input.nodes)) {\n nodes.set(id, { ...node, id: node.id || id });\n }\n }\n return { ...input, nodes };\n}\n", "import * as fs from 'node:fs/promises';\nimport { expectDefined } from '../utils/expect-defined.js';\nimport type { ContentBlock } from '../types/blocks.js';\nimport type {\n DefaultSessionReaderOptions,\n SessionExportOptions,\n SessionQuery,\n SessionReader,\n SessionSearchHit,\n SessionSearchQuery,\n SessionSummaryLite,\n} from '../types/session-reader.js';\nimport { compileUserRegex } from '../utils/regex-guard.js';\nimport { sessionScopedPath } from '../utils/session-scoped-path.js';\nimport type { SessionData, SessionEvent, SessionMetadata, SessionStore } from '../types/session.js';\n\n/**\n * L2-A: read-only view over a `SessionStore` with query, replay, search,\n * and export helpers. Implemented on top of the public `SessionStore`\n * surface so any concrete store can be inspected without re-implementation.\n */\nexport class DefaultSessionReader implements SessionReader {\n private readonly store: SessionStore;\n private readonly eventCache = new Map<string, SessionData>();\n private readonly eventCacheMtimes = new Map<string, number>();\n private static readonly EVENT_CACHE_MAX_ENTRIES = 32;\n\n constructor(opts: DefaultSessionReaderOptions) {\n this.store = opts.store;\n }\n\n private async loadCachedSessionData(sessionId: string): Promise<SessionData> {\n const storeWithPath = this.store as SessionStore & {\n dir?: string | undefined;\n clearLoadCache?: ((sessionId?: string | undefined) => void) | undefined;\n };\n const rootDir = storeWithPath.dir;\n if (!rootDir) {\n return await this.store.load(sessionId);\n }\n const sessionPath = sessionScopedPath(rootDir, sessionId, '.jsonl');\n let mtimeMs: number | null = null;\n try {\n const stat = await fs.stat(sessionPath);\n mtimeMs = stat.mtimeMs;\n } catch {\n this.eventCache.delete(sessionId);\n this.eventCacheMtimes.delete(sessionId);\n return await this.store.load(sessionId);\n }\n\n const cachedMtime = this.eventCacheMtimes.get(sessionId);\n const cachedData = this.eventCache.get(sessionId);\n if (cachedData && cachedMtime === mtimeMs) {\n this.eventCache.delete(sessionId);\n this.eventCacheMtimes.delete(sessionId);\n this.eventCache.set(sessionId, cachedData);\n this.eventCacheMtimes.set(sessionId, mtimeMs);\n return cachedData;\n }\n\n const data = await this.store.load(sessionId);\n this.eventCache.delete(sessionId);\n this.eventCacheMtimes.delete(sessionId);\n this.eventCache.set(sessionId, data);\n this.eventCacheMtimes.set(sessionId, mtimeMs);\n while (this.eventCache.size > DefaultSessionReader.EVENT_CACHE_MAX_ENTRIES) {\n const oldest = this.eventCache.keys().next().value;\n if (oldest === undefined) break;\n this.eventCache.delete(oldest);\n this.eventCacheMtimes.delete(oldest);\n }\n\n if (data.metadata.endedAt) {\n storeWithPath.clearLoadCache?.(sessionId);\n }\n\n return data;\n }\n\n async query(q: SessionQuery = {}): Promise<SessionSummaryLite[]> {\n // Prefer the store's filtered list when available \u2014 it pushes the\n // filter into the cached index instead of fetching 1000 + linear scan.\n const storeWithFilter = this.store as SessionStore & {\n listFiltered?: ((criteria: {\n since?: string | undefined;\n until?: string | undefined;\n provider?: string | undefined;\n model?: string | undefined;\n minTokens?: number | undefined;\n titleContains?: string | undefined;\n limit?: number | undefined;\n }) => Promise<import('../types/session.js').SessionSummary[]>) | undefined;\n };\n let raw: import('../types/session.js').SessionSummary[];\n if (typeof storeWithFilter.listFiltered === 'function') {\n raw = await storeWithFilter.listFiltered({\n since: q.since,\n until: q.until,\n provider: q.provider,\n model: q.model,\n minTokens: q.minTokens,\n titleContains: q.titleContains,\n limit: q.limit,\n });\n } else {\n const fetched = await this.store.list(q.limit ? Math.max(q.limit, 100) : 1000);\n const titleNeedle = q.titleContains?.toLowerCase();\n raw = fetched.filter((s) => {\n if (q.since && s.startedAt < q.since) return false;\n if (q.until && s.startedAt > q.until) return false;\n if (q.provider && s.provider !== q.provider) return false;\n if (q.model && s.model !== q.model) return false;\n if (q.minTokens !== undefined && s.tokenTotal < q.minTokens) return false;\n if (titleNeedle && !s.title.toLowerCase().includes(titleNeedle)) return false;\n return true;\n });\n }\n const out: SessionSummaryLite[] = raw.map((s) => ({\n id: s.id,\n title: s.title,\n startedAt: s.startedAt,\n provider: s.provider,\n model: s.model,\n tokenTotal: s.tokenTotal,\n }));\n return q.limit ? out.slice(0, q.limit) : out;\n }\n\n async *replay(sessionId: string): AsyncIterable<SessionEvent> {\n const data = await this.loadCachedSessionData(sessionId);\n for (const e of data.events) yield e;\n }\n\n async search(q: SessionSearchQuery, sessionId?: string | undefined, sessionQuery?: SessionQuery): Promise<SessionSearchHit[]> {\n const limit = q.limit ?? 100;\n const matcher = buildMatcher(q);\n const allowedTypes = q.types ? new Set(q.types) : null;\n\n // Filter sessions BEFORE scanning events \u2014 avoids touching the JSONL\n // for sessions that don't match the time/provider/model criteria.\n let ids: string[];\n if (sessionId) {\n ids = [sessionId];\n } else {\n // Prefer the store's filtered list when available \u2014 avoids fetching\n // 1000 sessions and linear-filtering in-process.\n const storeWithFilter = this.store as SessionStore & {\n listFiltered?: ((criteria: {\n since?: string | undefined;\n until?: string | undefined;\n provider?: string | undefined;\n model?: string | undefined;\n minTokens?: number | undefined;\n titleContains?: string | undefined;\n limit?: number | undefined;\n }) => Promise<import('../types/session.js').SessionSummary[]>) | undefined;\n };\n let sessions: import('../types/session.js').SessionSummary[];\n if (typeof storeWithFilter.listFiltered === 'function') {\n sessions = await storeWithFilter.listFiltered({\n since: sessionQuery?.since,\n until: sessionQuery?.until,\n provider: sessionQuery?.provider,\n model: sessionQuery?.model,\n minTokens: sessionQuery?.minTokens,\n titleContains: sessionQuery?.titleContains,\n limit: 1000,\n });\n } else {\n sessions = await this.store.list(1000);\n const titleNeedle = sessionQuery?.titleContains?.toLowerCase();\n sessions = sessions.filter((s) => {\n if (sessionQuery?.since && s.startedAt < sessionQuery.since) return false;\n if (sessionQuery?.until && s.startedAt > sessionQuery.until) return false;\n if (sessionQuery?.provider && s.provider !== sessionQuery.provider) return false;\n if (sessionQuery?.model && s.model !== sessionQuery.model) return false;\n if (sessionQuery?.minTokens !== undefined && s.tokenTotal < sessionQuery.minTokens) return false;\n if (titleNeedle && !s.title.toLowerCase().includes(titleNeedle)) return false;\n return true;\n });\n }\n ids = sessions.map((s) => s.id);\n }\n\n const hits: SessionSearchHit[] = [];\n\n // Fast path: when the underlying store supports streaming search,\n // walk each session's JSONL line-by-line and bail out the moment we\n // hit `limit`. This avoids reading + parsing the entire file (which\n // `load()` does) and never reuses `_loadCache`, so concurrent\n // analytics queries don't churn the writer-side cache.\n const streaming = this.store.searchEvents?.bind(this.store);\n if (streaming) {\n for (const id of ids) {\n const matched = await streaming(\n id,\n (ev) => {\n if (allowedTypes && !allowedTypes.has(ev.type)) return false;\n const text = eventText(ev);\n if (text === null) return false;\n return matcher(text) !== null;\n },\n { limit: limit - hits.length },\n );\n for (const m of matched) {\n const text = expectDefined(eventText(m.event));\n const hit = expectDefined(matcher(text));\n hits.push({\n sessionId: id,\n eventIndex: m.eventIndex,\n ts: m.ts,\n type: m.event.type,\n snippet: snippetOf(text, hit.start, hit.end),\n });\n if (hits.length >= limit) return hits;\n }\n }\n return hits;\n }\n\n // Fallback: stores that don't implement streaming. Loads the full\n // event stream per session \u2014 necessary for in-memory or non-file\n // stores that don't expose a streaming surface.\n for (const id of ids) {\n let data;\n try {\n data = await this.loadCachedSessionData(id);\n } catch {\n continue;\n }\n for (let i = 0; i < data.events.length; i++) {\n const ev = expectDefined(data.events[i]);\n if (allowedTypes && !allowedTypes.has(ev.type)) continue;\n const text = eventText(ev);\n if (text === null) continue;\n const hit = matcher(text);\n if (!hit) continue;\n hits.push({\n sessionId: id,\n eventIndex: i,\n ts: ev.ts,\n type: ev.type,\n snippet: snippetOf(text, hit.start, hit.end),\n });\n if (hits.length >= limit) return hits;\n }\n }\n return hits;\n }\n\n async export(sessionId: string, opts: SessionExportOptions): Promise<string> {\n const data = await this.loadCachedSessionData(sessionId);\n const includeTools = opts.includeTools ?? true;\n const includeDiagnostics = opts.includeDiagnostics ?? true;\n\n const filtered = data.events.filter((e) => {\n if (\n !includeTools &&\n (e.type === 'tool_use' ||\n e.type === 'tool_result' ||\n e.type === 'tool_call_start' ||\n e.type === 'tool_call_end')\n ) {\n return false;\n }\n if (\n !includeDiagnostics &&\n (e.type === 'error' || e.type === 'compaction' || e.type === 'message_truncated')\n ) {\n return false;\n }\n return true;\n });\n\n if (opts.format === 'json') {\n return JSON.stringify({ metadata: data.metadata, events: filtered }, null, 2);\n }\n if (opts.format === 'text') {\n return renderPlainText(data.metadata, filtered);\n }\n return renderMarkdown(data.metadata, filtered);\n }\n\n async metadata(sessionId: string): Promise<SessionMetadata> {\n const data = await this.loadCachedSessionData(sessionId);\n return data.metadata;\n }\n}\n\nfunction buildMatcher(\n q: SessionSearchQuery,\n): (text: string) => { start: number; end: number } | null {\n const ci = q.caseInsensitive ?? true;\n if (q.regex) {\n const flags = ci ? 'i' : '';\n const compiled = compileUserRegex(q.query, flags);\n if (!compiled.ok) {\n throw new Error(`Invalid search regex \"${q.query}\": ${compiled.reason}`);\n }\n const re = compiled.regex;\n return (text) => {\n const m = re.exec(text);\n return m ? { start: m.index, end: m.index + m[0].length } : null;\n };\n }\n const needle = ci ? q.query.toLowerCase() : q.query;\n return (text) => {\n const hay = ci ? text.toLowerCase() : text;\n const idx = hay.indexOf(needle);\n return idx === -1 ? null : { start: idx, end: idx + needle.length };\n };\n}\n\nfunction eventText(e: SessionEvent): string | null {\n switch (e.type) {\n case 'user_input':\n return contentToString(e.content);\n case 'llm_response':\n return contentToString(e.content);\n case 'tool_use':\n return `${e.name} ${JSON.stringify(e.input)}`;\n case 'tool_result':\n return typeof e.content === 'string' ? e.content : JSON.stringify(e.content);\n case 'error':\n return `${e.phase}: ${e.message}`;\n case 'session_start':\n case 'session_resumed':\n return `${e.model}/${e.provider}`;\n case 'task_created':\n case 'task_completed':\n return e.title;\n case 'task_failed':\n return `${e.title}: ${e.error}`;\n case 'skill_activated':\n case 'skill_deactivated':\n return e.skillName;\n default:\n return null;\n }\n}\n\nfunction contentToString(content: string | ContentBlock[]): string {\n if (typeof content === 'string') return content;\n return content\n .map((b) => {\n switch (b.type) {\n case 'text':\n return b.text;\n case 'tool_use':\n return `[tool_use:${b.name} ${JSON.stringify(b.input)}]`;\n case 'tool_result':\n return typeof b.content === 'string' ? b.content : JSON.stringify(b.content);\n default:\n return '';\n }\n })\n .join('\\n');\n}\n\nconst SNIPPET_RADIUS = 60;\n\nfunction snippetOf(text: string, start: number, end: number): string {\n const from = Math.max(0, start - SNIPPET_RADIUS);\n const to = Math.min(text.length, end + SNIPPET_RADIUS);\n const prefix = from > 0 ? '\u2026' : '';\n const suffix = to < text.length ? '\u2026' : '';\n return prefix + text.slice(from, to).replace(/\\s+/g, ' ').trim() + suffix;\n}\n\nfunction renderMarkdown(meta: SessionMetadata, events: SessionEvent[]): string {\n const lines: string[] = [];\n lines.push(`# Session ${meta.id}`);\n lines.push('');\n if (meta.model || meta.provider) {\n lines.push(`- **Model:** ${meta.provider ?? '?'}/${meta.model ?? '?'}`);\n }\n lines.push(`- **Started:** ${meta.startedAt}`);\n if (meta.endedAt) lines.push(`- **Ended:** ${meta.endedAt}`);\n lines.push('');\n lines.push('---');\n lines.push('');\n for (const e of events) {\n switch (e.type) {\n case 'user_input': {\n lines.push(`## User \u2014 ${e.ts}`);\n lines.push('');\n lines.push(contentToString(e.content));\n lines.push('');\n break;\n }\n case 'llm_response': {\n lines.push(`## Assistant \u2014 ${e.ts}`);\n lines.push('');\n lines.push(contentToString(e.content));\n if (e.stopReason && e.stopReason !== 'end_turn') {\n lines.push('');\n lines.push(`*stop: ${e.stopReason}*`);\n }\n lines.push('');\n break;\n }\n case 'tool_use': {\n lines.push(`### Tool call: \\`${e.name}\\``);\n lines.push('');\n lines.push('```json');\n lines.push(JSON.stringify(e.input, null, 2));\n lines.push('```');\n lines.push('');\n break;\n }\n case 'tool_result': {\n const body = typeof e.content === 'string' ? e.content : JSON.stringify(e.content, null, 2);\n lines.push(`### Tool result${e.isError ? ' (error)' : ''}`);\n lines.push('');\n lines.push('```');\n lines.push(body);\n lines.push('```');\n lines.push('');\n break;\n }\n case 'error': {\n lines.push(`> **Error** (${e.phase}): ${e.message}`);\n lines.push('');\n break;\n }\n case 'compaction': {\n lines.push(`> **Compaction**: ${e.before} \u2192 ${e.after} tokens`);\n lines.push('');\n break;\n }\n default:\n break;\n }\n }\n return lines.join('\\n');\n}\n\nfunction renderPlainText(meta: SessionMetadata, events: SessionEvent[]): string {\n const lines: string[] = [];\n lines.push(\n `Session ${meta.id} \u2014 ${meta.provider ?? '?'}/${meta.model ?? '?'} \u2014 started ${meta.startedAt}`,\n );\n lines.push(''.padEnd(72, '-'));\n for (const e of events) {\n switch (e.type) {\n case 'user_input':\n lines.push(`[${e.ts}] USER`);\n lines.push(contentToString(e.content));\n lines.push('');\n break;\n case 'llm_response':\n lines.push(`[${e.ts}] ASSISTANT`);\n lines.push(contentToString(e.content));\n lines.push('');\n break;\n case 'tool_use':\n lines.push(`[${e.ts}] TOOL_USE ${e.name} ${JSON.stringify(e.input)}`);\n break;\n case 'tool_result':\n lines.push(\n `[${e.ts}] TOOL_RESULT${e.isError ? ' (error)' : ''} ${\n typeof e.content === 'string' ? e.content : JSON.stringify(e.content)\n }`,\n );\n break;\n case 'error':\n lines.push(`[${e.ts}] ERROR (${e.phase}): ${e.message}`);\n break;\n default:\n break;\n }\n }\n return lines.join('\\n');\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["export interface TextBlock {\n type: 'text';\n text: string;\n cache_control?: { type: 'ephemeral' | undefined };\n}\n\nexport interface ToolUseBlock {\n type: 'tool_use';\n id: string;\n name: string;\n input: Record<string, unknown>;\n /**\n * Provider-specific opaque metadata captured from the wire response.\n * Echoed back verbatim in the next request so providers that bind\n * extra state to function calls keep working. Example: Gemini's\n * `thoughtSignature` \u2014 required for tool-use turns with thinking\n * models, otherwise the next request fails with 400 \"Function call\n * is missing a thought_signature in functionCall parts\".\n *\n * Keys are namespaced by intent so multiple wires can coexist:\n * - `google.thoughtSignature` \u2014 Gemini signed-thought blob\n * Other providers can add their own keys without colliding.\n */\n providerMeta?: Record<string, unknown>;\n}\n\nexport interface ToolResultBlock {\n type: 'tool_result';\n tool_use_id: string;\n /**\n * The original tool name. Useful for providers like Google Gemini that\n * need the tool name in `functionResponse.name` \u2014 the tool_use_id is\n * only a session-local identifier and is not stable across replays.\n * Always set by ToolExecutor; may be absent on manually-constructed blocks.\n */\n name?: string | undefined;\n content: string;\n is_error?: boolean | undefined;\n}\n\nexport interface ImageBlock {\n type: 'image';\n source: {\n type: 'base64' | 'url';\n media_type?: string | undefined;\n data?: string | undefined;\n url?: string | undefined;\n };\n}\n\n/**\n * Chain-of-thought / extended-thinking content emitted by the model.\n *\n * Both Anthropic extended thinking (`{type:'thinking', thinking, signature}`)\n * and DeepSeek reasoning mode (top-level `reasoning_content` on the assistant\n * message) require this content to be echoed back verbatim on the next\n * request, otherwise the provider returns 400:\n * - Anthropic: \"The `content[].thinking` in the thinking mode must be passed back\"\n * - DeepSeek: \"The `reasoning_content` in the thinking mode must be passed back\"\n *\n * `signature` is Anthropic-specific (an opaque integrity blob). DeepSeek\n * doesn't issue a signature \u2014 the field is absent for that provider.\n *\n * Per Anthropic, thinking blocks MUST appear before any text/tool_use blocks\n * in an assistant message. Stream builders preserve that order.\n */\nexport interface ThinkingBlock {\n type: 'thinking';\n thinking: string;\n signature?: string | undefined;\n providerMeta?: Record<string, unknown>;\n}\n\nexport type ContentBlock = TextBlock | ToolUseBlock | ToolResultBlock | ImageBlock | ThinkingBlock;\n\nexport function isTextBlock(b: ContentBlock): b is TextBlock {\n return b.type === 'text';\n}\nexport function isToolUseBlock(b: ContentBlock): b is ToolUseBlock {\n return b.type === 'tool_use';\n}\nexport function isToolResultBlock(b: ContentBlock): b is ToolResultBlock {\n return b.type === 'tool_result';\n}\nexport function isImageBlock(b: ContentBlock): b is ImageBlock {\n return b.type === 'image';\n}\n", "import type { Context } from '../core/context.js';\n\nexport type Permission = 'auto' | 'confirm' | 'deny';\n\n/**\n * Risk tier for tools in UI/audit surfaces. YOLO auto-approves non-denied\n * calls regardless of risk tier; when YOLO is off, risk can inform prompts.\n *\n * - `safe` \u2014 read-only, no side effects (read, glob, grep, etc.)\n * - `standard` \u2014 non-destructive writes and mutations (write, edit, safe shell commands)\n * - `destructive` \u2014 irreversible or broadside effects (recursive deletes, db drops, etc.)\n */\nexport type RiskTier = 'safe' | 'standard' | 'destructive';\n\n/**\n * Icon identifiers for tools \u2014 each UI (WebUI/TUI/REPL) maps these to its own icon library.\n * Add the icon directly on each Tool so all UIs consume the same canonical value.\n */\nexport type ToolIconId =\n | 'file' // read, write \u2014 document operations\n | 'edit' // edit, patch \u2014 modifying files\n | 'search' // grep, search \u2014 searching content\n | 'folder' // glob \u2014 file discovery\n | 'terminal' // bash, exec \u2014 shell commands\n | 'web' // fetch \u2014 HTTP requests\n | 'git' // git \u2014 version control\n | 'tree' // tree \u2014 directory structure\n | 'code' // lint, format, typecheck \u2014 code quality\n | 'test' // test \u2014 testing\n | 'package' // install, audit, outdated \u2014 package management\n | 'document' // document \u2014 documentation\n | 'scaffold' // scaffold \u2014 project generation\n | 'todo' // todo \u2014 task tracking\n | 'plan' // plan \u2014 planning\n | 'task' // task \u2014 structured work items\n | 'meta' // tool-use, batch-tool-use, tool-search, tool-help \u2014 meta tools\n | 'index' // codebase-index, codebase-search, codebase-stats \u2014 code indexing\n | 'json' // json \u2014 JSON operations\n | 'diff' // diff \u2014 comparing changes\n | 'logs' // logs \u2014 log viewing\n | 'settings' // set-working-dir \u2014 configuration\n | 'fallback'; // unknown tool \u2014 fallback icon\n\nexport interface JSONSchema {\n type?: string | undefined;\n properties?: Record<string, JSONSchema>;\n required?: string[] | undefined;\n items?: JSONSchema | undefined;\n enum?: unknown[] | undefined;\n description?: string | undefined;\n [k: string]: unknown;\n}\n\n/**\n * Tool progress event \u2014 yielded by `Tool.executeStream` to give the UI\n * something to render while a long-running tool works. The executor\n * publishes each event via EventBus as `tool.progress` so the TUI, logger,\n * and observability layer can consume them uniformly.\n *\n * Keep events small. They are buffered through the EventBus synchronously\n * and rendered on the main thread.\n */\nexport interface ToolProgressEvent {\n /**\n * - `log` \u2014 verbose informational message (e.g. \"scanning\u2026\")\n * - `warning` \u2014 non-fatal issue (e.g. \"skipped X due to ENOENT\")\n * - `metric` \u2014 numeric data (e.g. files scanned so far)\n * - `file_changed` \u2014 a tool that mutates the workspace announces a write\n * - `partial_output` \u2014 stream of textual output (bash stdout, fetch body)\n */\n type: 'log' | 'warning' | 'metric' | 'file_changed' | 'partial_output';\n text?: string | undefined;\n data?: Record<string, unknown>;\n /** Canonical or project-relative target for file_changed events. */\n path?: string | undefined;\n operation?: 'write' | 'edit' | 'delete' | 'rename' | undefined;\n line?: number | undefined;\n endLine?: number | undefined;\n}\n\n/**\n * Terminal event for `executeStream`. The output must match the tool's\n * declared output type \u2014 the executor unwraps `output` and treats it like\n * a normal `execute` return value.\n */\nexport interface ToolFinalEvent<O> {\n type: 'final';\n output: O;\n}\n\nexport type ToolStreamEvent<O = unknown> = ToolProgressEvent | ToolFinalEvent<O>;\n\nexport interface Tool<I = unknown, O = unknown> {\n name: string;\n description: string;\n /**\n * Pre-computed token estimate for this tool's definition (name +\n * description + JSON-serialized inputSchema). Set by ToolRegistry on\n * registration; consumed by estimateToolDefTokens / estimateRequestTokens\n * to skip redundant JSON.stringify on every context-pressure check.\n */\n _estDefTokens?: number | undefined;\n usageHint?: string | undefined;\n /** Structured guidance for choosing between similar tools. */\n selection?:\n | {\n /** A concise boundary where this tool should not be selected. */\n doNotUseWhen: string;\n /** Tool names the model should prefer for that boundary. */\n useInstead?: readonly string[] | undefined;\n }\n | undefined;\n /** Optional category for grouping in help lists and system prompts. */\n category?: string | undefined;\n inputSchema: JSONSchema;\n permission: Permission;\n mutating: boolean;\n /**\n * Risk tier for selective YOLO gating. When YOLO is active, clearly\n * destructive calls still emit `confirm`. Defaults to `standard` when\n * omitted \u2014 callers should always check `riskTier` after the basic\n * permission decision.\n */\n riskTier?: RiskTier | undefined;\n /**\n * Input-field name that the permission policy should match trust rules\n * against. Without this, the policy falls back to a heuristic\n * (`command` / `path` / `url` / `name`) that can collide across tools \u2014\n * e.g. an HTTP tool whose `path` means \"request path\" would be checked\n * against filesystem-path trust rules. Set explicitly to avoid the\n * cross-tool subject collision.\n *\n * The named field's value must be a string at runtime; non-string values\n * fall back to the heuristic.\n */\n subjectKey?: string | undefined;\n maxOutputBytes?: number | undefined;\n timeoutMs?: number | undefined;\n /**\n * The tool owns its timeout/idle policy and only needs the executor to\n * propagate the parent abort signal. Use this sparingly for orchestration\n * tools such as `delegate` that already enforce a heartbeat-aware timeout;\n * otherwise the executor's fixed max-tool timeout can kill healthy work.\n */\n managesOwnTimeout?: boolean | undefined;\n /**\n * Hint for the TUI spinner \u2014 does NOT affect actual timeout enforcement.\n * Use `timeoutMs` for hard limits. Leave undefined when duration varies\n * unpredictably.\n */\n estimatedDurationMs?: number | undefined;\n\n /**\n * Declarative security capabilities granted by this tool.\n *\n * Examples: \"shell.arbitrary\", \"fs.write\", \"fs.write.outside-project\",\n * \"net.outbound\", \"mcp.proxy\", \"subagent.spawn\", \"config.mutate\".\n *\n * These are used by permission policies (especially subagent guards) and\n * future capability-based allowlists. Prefer well-known values over ad-hoc strings.\n *\n * This field is optional for backward compatibility. Tools without it are\n * treated conservatively by guards.\n */\n capabilities?: readonly string[] | undefined;\n /**\n * Icon identifier for this tool \u2014 consumed by all UIs (WebUI/TUI/REPL) to\n * render a tool-specific icon instead of a generic fallback.\n * Each UI maps this id to its own icon library.\n */\n icon?: ToolIconId | undefined;\n execute(input: I, ctx: Context, opts: { signal: AbortSignal }): Promise<O>;\n /**\n * Optional cross-field validation hook. Called by the executor AFTER\n * JSON Schema validation passes and AFTER PreToolUse hooks may have\n * rewritten the input, but BEFORE permission checks and execution.\n *\n * Use this for invariants the JSON Schema cannot express \u2014 e.g.\n * `old_string !== new_string` in edit, or `end > start` in a range tool.\n * Return an array of validation errors (empty = valid). The executor\n * surfaces them to the model just like schema validation errors, so the\n * model can self-correct without the tool's `execute()` running.\n *\n * P3 #16 (before-release.md): tools that implement cross-field checks\n * inside `execute()` can migrate them here for earlier rejection and\n * consistent error formatting.\n */\n validate?(input: I): string[];\n /**\n * Optional streaming variant. When defined, the executor prefers this\n * over `execute` \u2014 yielded events become `tool.progress` EventBus events\n * and the terminal `final` event provides the output. Tools that don't\n * have intermediate state shouldn't implement this; the default `execute`\n * path is more efficient.\n */\n executeStream?(\n input: I,\n ctx: Context,\n opts: { signal: AbortSignal },\n ): AsyncIterable<ToolStreamEvent<O>>;\n /**\n * Optional teardown hook fired by the executor when the tool's run is\n * aborted (signal triggered). Errors thrown here are swallowed so they\n * never mask the originating failure.\n *\n * **When to use `cleanup` vs `ctx.registerAbortHook`:**\n *\n * - Use `cleanup` for resources **owned by the tool author** that are\n * established at execute-time: child processes spawned by the tool,\n * file handles opened by the tool, network connections initiated by\n * the tool. The lifecycle is co-located with the tool definition, so\n * readers see the resource and its teardown in one place.\n *\n * ```ts\n * async execute(input, ctx, opts) {\n * const child = spawn(...);\n * // \u2026 tool work \u2026\n * },\n * async cleanup(_input, _ctx) {\n * // best-effort kill of any child still running\n * }\n * ```\n *\n * - Use `ctx.registerAbortHook` for **context-scoped teardown** registered\n * dynamically inside `execute`: when the tool delegates to a library\n * that needs cancellation, or when the resource is created lazily\n * somewhere down the call stack and the natural cleanup point isn't\n * at the tool boundary. The hook fires when the **agent run** ends,\n * not when this specific tool call aborts.\n *\n * ```ts\n * async execute(input, ctx, opts) {\n * const handle = openHelper();\n * ctx.registerAbortHook(() => handle.dispose());\n * // \u2026 work \u2026\n * }\n * ```\n *\n * If both are registered for the same resource, `cleanup` fires first\n * (on tool abort) and the abort-hook fires after on the wider run abort.\n * Avoid double-free by gating one on the other's effect, or pick a single\n * teardown channel per resource.\n */\n cleanup?(input: I, ctx: Context): Promise<void>;\n /**\n * Optional custom output serializer. When present, the executor's output\n * serializer calls this INSTEAD of the central `renderToolObject()` switch\n * \u2014 the tool owns its own pretty-printing.\n *\n * Return a string representation of the output that the model will see in\n * its tool_result block. The serializer applies the iteration output cap\n * AFTER this runs, so don't worry about truncation.\n *\n * P3 #21 (before-release.md): `renderToolObject()` is a god function with\n * 30+ per-tool branches, far from each tool's definition. New tools that\n * want custom output no longer need to add a branch there \u2014 they implement\n * this method instead. Existing branches stay until migrated incrementally.\n */\n serialize?(output: O, input: I): string;\n}\n\nexport interface ToolCallContext {\n tool: Tool;\n input: unknown;\n callId: string;\n ctx: Context;\n signal: AbortSignal;\n}\n\n/**\n * Error categories for tool execution failures.\n * Used by the executor to classify errors and determine retry strategy.\n */\nexport enum ToolErrorCategory {\n TRANSIENT = 'transient', // ETIMEDOUT, ECONNRESET, network timeout, HTTP 429/503\n NOT_FOUND = 'not_found', // ENOENT, ENOTDIR, HTTP 404\n PERMISSION = 'permission', // EACCES, EPERM, HTTP 401/403\n VALIDATION = 'validation', // schema validation error, HTTP 400\n FATAL = 'fatal', // unhandled exception, crash, invariant violation\n}\n\n/**\n * Structured tool error information for the LLM and retry logic.\n */\nexport interface ToolErrorInfo {\n readonly category: ToolErrorCategory;\n /** Whether the operation can be retried automatically. */\n readonly retryable: boolean;\n /** User-facing message describing the error. */\n readonly userMessage: string;\n /** Optional technical detail for debugging. */\n readonly detail?: string;\n}\n", "import type { ToolResultBlock, ToolUseBlock } from '../types/blocks.js';\nimport type { Tool } from '../types/tool.js';\n\n/** Context.meta key installed by ToolExecutor for governed calls made by meta-tools. */\nexport const GOVERNED_TOOL_EXECUTOR_META_KEY = 'toolExecutor.executeGoverned';\n\n/** Result returned to meta-tools after a nested call traverses the normal executor. */\nexport interface GovernedToolExecutionResult {\n success: boolean;\n result?: unknown | undefined;\n error?: string | undefined;\n}\n\n/** Governed execution bridge exposed to meta-tools through Context.meta. */\nexport type GovernedToolExecutor = (\n toolName: string,\n input: Record<string, unknown>,\n) => Promise<GovernedToolExecutionResult>;\n\n/**\n * Input for a single tool execution, scoped to a single iteration's budget.\n */\nexport interface ToolExecution {\n toolUse: ToolUseBlock;\n result: ToolResultBlock;\n /** True if the tool was not found in the registry. */\n unknownTool?: boolean | undefined;\n /** True if the tool execution threw an exception. */\n threw?: boolean | undefined;\n}\n\n/**\n * Output from a single tool execution.\n */\nexport interface ToolExecutionOutput {\n result: ToolResultBlock | ToolConfirmPendingResult;\n tool?: Tool | undefined;\n durationMs: number;\n}\n\n/**\n * Result of running a batch of tools for a single agent iteration.\n */\nexport interface ToolBatchResult {\n outputs: ToolExecutionOutput[];\n remainingBudget: number;\n}\n\nexport type ConfirmAwaiter = (\n tool: Tool,\n input: unknown,\n toolUseId: string,\n suggestedPattern: string,\n) => Promise<'yes' | 'no' | 'always' | 'deny'>;\n\nexport interface ToolExecutorOptions {\n permissionPolicy: import('../types/permission.js').PermissionPolicy;\n secretScrubber: import('../types/secret-scrubber.js').SecretScrubber;\n renderer?: import('../types/renderer.js').Renderer | undefined;\n /**\n * Optional event bus. When provided, the executor emits `tool.started`\n * before invoking each tool's `execute()`. Closes the observability gap\n * between \"model decided to call tool\" and \"tool finished\".\n */\n events?: import('../kernel/events.js').EventBus | undefined;\n /**\n * Optional tracer. When provided, every tool execution opens a\n * `tool.<name>` span with attributes for tool name, permission decision,\n * input size, output size, and outcome. Spans are no-op by default.\n */\n tracer?: import('../types/observability.js').Tracer | undefined;\n /**\n * Optional structured logger for production diagnostics. Tool execution logs\n * include correlation IDs and metadata only \u2014 never raw tool inputs or output.\n */\n logger?: import('../types/logger.js').Logger | undefined;\n /**\n * Async callback invoked when a tool needs user confirmation.\n * When omitted and confirmation is required, the executor returns a\n * failure result immediately (TUI path). When provided (CLI path),\n * the callback handles the interactive prompt and returns a decision.\n */\n confirmAwaiter?: ConfirmAwaiter | undefined;\n iterationTimeoutMs?: number | undefined;\n /** Hard upper bound for a single tool call timeout. Defaults to 5 minutes. */\n maxToolTimeoutMs?: number | undefined;\n perIterationOutputCapBytes?: number | undefined;\n /**\n * Optional lifecycle hook runner. When present, `PreToolUse` hooks run\n * before the permission check (and can block the call or rewrite its input)\n * and `PostToolUse` hooks run after the tool returns (and can append context\n * to the result the model sees).\n */\n hookRunner?: import('../hooks/runner.js').HookRunner | undefined;\n /**\n * Per-tool on-screen result render mode map (`tools.resultRenderMode[name]`).\n * When set, the executor reads this map to decide whether the next\n * `writeToolResult` call should render in `simple` (meta only) or `extend`\n * (full preview) mode. Independent of the LLM-side `descriptionMode`.\n */\n resultRenderModes?: import('./config.js').ToolResultRenderModeConfig | undefined;\n}\n\nexport interface ToolExecutorInit {\n registry: import('../registry/tool-registry.js').ToolRegistry;\n options: ToolExecutorOptions;\n}\n\n/**\n * Result returned by executeBatch when a tool needs confirmation and\n * no confirmAwaiter is available. The TUI catches this and surfaces a\n * confirmation dialog; once resolved the tool is re-executed.\n * The string tag identifies it as a \"pending confirm\" result so callers\n * can distinguish it from an error without inspecting content strings.\n */\nexport interface ToolConfirmPendingResult {\n type: 'tool_confirm_pending';\n toolUseId: string;\n toolName: string;\n input: unknown;\n suggestedPattern: string;\n decisionSource?: import('./permission.js').PermissionDecision['source'] | undefined;\n riskTier?: import('./tool.js').RiskTier | undefined;\n /** Present when approval is required specifically by a Kanban scope. */\n boundaryReason?: string | undefined;\n}\n\nexport type ToolExecutorStrategy = 'parallel' | 'sequential' | 'smart';\n\n/**\n * Minimal contract for tool execution.\n *\n * Defined here (in `types/`) so `core/` does not need to import the\n * concrete `ToolExecutor` class from `execution/`. Callers that create\n * the executor (e.g. CLI wiring) implement this interface.\n *\n * Only the methods actually called by `Agent` are included \u2014 keeping the\n * interface narrow prevents unnecessary coupling.\n */\nexport interface ToolExecutorLike {\n /**\n * Execute a batch of tool uses. The strategy controls whether tools run\n * sequentially, in parallel, or smart (parallel non-mutating + sequential mutating).\n */\n executeBatch(\n toolUses: import('./blocks.js').ToolUseBlock[],\n ctx: import('../core/context.js').Context,\n strategy: ToolExecutorStrategy,\n ): Promise<ToolBatchResult>;\n\n /**\n * Clear the interactive confirm awaiter so the executor returns\n * `ToolConfirmPendingResult` instead of blocking.\n */\n clearConfirmAwaiter(): void;\n\n /**\n * Execute a single tool with timeout and output capping.\n * Used by the agent when it needs to run one tool at a time.\n *\n * Returns the rendered `ToolResultBlock` plus the exact byte count it\n * consumed against the iteration output cap. The caller subtracts\n * `bytes` from the running budget \u2014 no second `Buffer.byteLength`\n * walk, and no `JSON.stringify` fallback for structured results.\n */\n executeTool(\n tool: Tool,\n use: ToolUseBlock,\n ctx: import('../core/context.js').Context,\n budget: number,\n ): Promise<{ block: ToolResultBlock; bytes: number }>;\n}\n", "/**\n * Sentinel keys provider adapters use to wrap tool-call arguments that could\n * not be parsed into a proper JSON object. Single source of truth \u2014 the core\n * tool executor (which DETECTS these markers to surface a friendly error)\n * defines them here, and the providers package (which PRODUCES them when\n * wrapping) imports from `@wrongstack/core`.\n *\n * P3 #14 (before-release.md): the list was duplicated in tool-executor.ts with\n * a \"Keep this list in sync\" comment \u2014 a manual rule that will eventually be\n * forgotten. Centralizing it removes the sync burden.\n *\n * Layering note: this lives in core (not providers) because the dependency\n * direction is providers \u2192 core, not the reverse. Putting it in providers\n * would force core into a forbidden upward dependency.\n *\n * Current markers:\n * - `__raw` \u2014 produced by `parseToolInput` (Anthropic / shared)\n * - `__raw_arguments` \u2014 produced by `contentFromOpenAI` (OpenAI / compatible)\n * - `_raw` \u2014 produced by the streaming response builder's\n * `safeJsonOrRaw` (legacy fallback)\n */\nexport const MALFORMED_ARG_MARKERS = ['__raw', '__raw_arguments', '_raw'] as const;\n", "/**\n * String utilities shared across the WrongStack codebase.\n */\n\n/**\n * Truncate a string to at most `max` characters, appending an ellipsis if it\n * was longer. Returns the original string unchanged when it fits.\n */\nexport function truncate(s: string, max: number): string {\n return s.length <= max ? s : `${s.slice(0, max - 1)}\u2026`;\n}\n", "/**\n * Converts an unknown error value to a human-readable string.\n * Used in 40+ files across the codebase to normalize error messaging.\n */\nexport function toErrorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n", "/** Assert a value is neither null nor undefined. Throws if it is.\n * Useful after optional chaining and indexed access when the\n * control flow guarantees the value exists but TypeScript can't\n * prove it (e.g. after a check on a related field). */\nexport function expectDefined<T>(value: T | null | undefined, label?: string): T {\n if (value === null || value === undefined) {\n const err = new Error(label ? `Expected ${label} to be defined` : 'Expected value to be defined');\n err.name = 'ExpectDefinedError';\n throw err;\n }\n return value;\n}\n", "import type { ContextWindowModeId } from './context-window.js';\nimport type { ConfiguredHook, HookEvent } from './hooks.js';\nimport type { WireFamily } from './models-registry.js';\nimport type { CacheTtl, Capabilities, ReasoningEffort } from './provider.js';\nimport type { Permission } from './tool.js';\n\n/**\n * Runtime reasoning controls the user can set per-session/project. Mapped into\n * the provider `Request.reasoning` field by the model-runtime request\n * middleware, gated by the active model's `reasoningConfig` capabilities so\n * unsupported values are omitted (and warned) instead of triggering provider\n * 400s. See `resolveReasoningForRequest()` in packages/core.\n */\nexport interface ModelRuntimeReasoningConfig {\n /**\n * Whether to send explicit reasoning enable/disable.\n * - 'auto' \u2192 do not send explicit fields; provider/model default wins\n * - 'on' \u2192 send `reasoning.enabled = true`\n * - 'off' \u2192 send `reasoning.enabled = false` only when the model supports disable\n */\n mode?: 'auto' | 'on' | 'off' | undefined;\n /** Reasoning effort. Only sent when the model advertises `effortSupported`. */\n effort?: ReasoningEffort | undefined;\n /** Preserve thinking across turns. Only sent when `preserveThinking !== 'unsupported'`. */\n preserve?: boolean | undefined;\n}\n\n/**\n * Runtime prompt-cache controls mapped into `Request.cache`. Currently only the\n * Anthropic TTL toggle (5m vs 1h) is exposed; other providers ignore it.\n */\nexport interface ModelRuntimeCacheConfig {\n ttl?: CacheTtl | undefined;\n /**\n * Opt-in explicit Gemini context caching. When true, the Google provider\n * creates a server-side `cachedContents` resource for the stable system\n * prefix (system instruction + tool defs) and references it by name instead\n * of resending it every turn. Default false: Gemini's automatic *implicit*\n * caching already covers a byte-stable prefix with no setup. Ignored by every\n * non-Google provider. Any failure in the create flow falls back to the\n * normal inline request, so enabling it can never break a request.\n */\n geminiExplicit?: boolean | undefined;\n}\n\n/**\n * Shared runtime controls applied to every provider request, regardless of host\n * (REPL / TUI / WebUI). The CLI installs a single request-pipeline middleware\n * that reads these and mutates the outgoing `Request`.\n */\nexport interface ModelRuntimeConfig {\n reasoning?: ModelRuntimeReasoningConfig | undefined;\n cache?: ModelRuntimeCacheConfig | undefined;\n /**\n * Generic generation parameters mapped directly onto `Request` fields.\n * Only sent when the active model's `Capabilities` advertise support.\n */\n parameters?: ModelRuntimeParametersConfig | undefined;\n}\n\n/**\n * Generic generation parameters the user can set per-session / per-project.\n * Each field maps to a `Request` field of the same name and is gated by the\n * corresponding `Capabilities` flag so unsupported models don't receive\n * parameters they'd reject.\n */\nexport interface ModelRuntimeParametersConfig {\n /** Top-K sampling (Anthropic, Gemini). Gated by `capabilities.topK`. */\n topK?: number | undefined;\n /** Frequency penalty (OpenAI, Gemini). Gated by `capabilities.frequencyPenalty`. */\n frequencyPenalty?: number | undefined;\n /** Presence penalty (OpenAI, Gemini). Gated by `capabilities.presencePenalty`. */\n presencePenalty?: number | undefined;\n /** Random seed (OpenAI, Gemini). Gated by `capabilities.seed`. */\n seed?: number | undefined;\n /** End-user identifier for abuse monitoring. */\n user?: string | undefined;\n /** Log probabilities (OpenAI, Gemini). Gated by `capabilities.logprobs`. */\n logprobs?: boolean | undefined;\n /** Number of top logprobs to return (OpenAI). Only when `logprobs` is true. */\n topLogprobs?: number | undefined;\n}\n\n/**\n * HQ client connection settings. Same-machine clients can auto-discover the\n * local HQ auth file; remote clients use this config-backed URL/token pair.\n */\nexport interface HqClientConfig {\n /** Enable HQ publishing. Env WRONGSTACK_HQ_ENABLED still overrides at runtime. */\n enabled?: boolean | undefined;\n /** HQ HTTP base URL, e.g. http://host:3499. */\n url?: string | undefined;\n /** Client token for /ws/client. Stored encrypted by SecretVault when persisted. */\n token?: string | undefined;\n /** Optional HQ data dir for same-machine auth.json discovery. */\n dataDir?: string | undefined;\n /** Send raw content previews to HQ instead of redacted previews. */\n rawContent?: boolean | undefined;\n /** Override project display name in HQ. */\n projectAlias?: string | undefined;\n}\n\n/**\n * Token-saving mode tier levels. Controls how aggressively the system prompt\n * is compacted to reduce per-request token consumption.\n *\n * - 'off' \u2014 Full prompt, all tools, complete guidance (no reduction)\n * - 'minimal' \u2014 TIER1 tools (13, including codebase index lifecycle), stripped guidance\n * - 'light' \u2014 Same Tier 1 tool surface, common patterns, minimal guidance\n * - 'medium' \u2014 TIER1 + TIER2 development tools, some guidance (default when `true`)\n * - 'aggressive' \u2014 Maximum savings before tools become unusable (~4-5k tokens saved)\n */\n/**\n * Prompt token-saving tiers. `'auto'` is an INPUT-only sentinel meaning \"pick a\n * concrete tier from the model's context window\" \u2014 it is resolved to one of the\n * concrete tiers by {@link resolveTokenSavingTier} before reaching the prompt\n * builder (which never sees `'auto'`; if it somehow does, it behaves as `'off'`,\n * i.e. the full prompt \u2014 the safe fallback).\n */\nexport type TokenSavingTier = 'off' | 'auto' | 'minimal' | 'light' | 'medium' | 'aggressive';\n\n/** Concrete tiers the prompt builder actually consumes ('auto' excluded). */\nexport type ConcreteTokenSavingTier = Exclude<TokenSavingTier, 'auto'>;\n\n/**\n * Normalize a TokenSavingTier value, handling backward-compatible boolean inputs.\n * - `true` \u2192 'medium' (existing behavior)\n * - `false` \u2192 'off'\n * - `'auto'` \u2192 `'off'` \u2014 the `'auto'` sentinel is window-dependent, so EVERY\n * consumer that isn't the prompt builder (tool selection, lazy-load gate, TUI\n * display) must treat it as the safe no-op `'off'`: it must NOT reduce the\n * registered tool set or enable lazy loading on its own. Only the prompt\n * builder expands `'auto'` \u2014 via {@link resolveTokenSavingTier} \u2014 and only for\n * the (cache-stable) prompt prose. This keeps auto-tiering capability-neutral.\n * - other valid strings are returned as-is; `undefined`/invalid \u2192 'off'\n */\nexport function normalizeTokenSavingTier(val?: TokenSavingTier | boolean): ConcreteTokenSavingTier {\n if (val === undefined) return 'off';\n if (typeof val === 'boolean') return val ? 'medium' : 'off';\n const validTiers = new Set<ConcreteTokenSavingTier>([\n 'off',\n 'minimal',\n 'light',\n 'medium',\n 'aggressive',\n ]);\n // 'auto' is deliberately absent \u2192 collapses to 'off' for non-prompt consumers.\n return validTiers.has(val as ConcreteTokenSavingTier) ? (val as ConcreteTokenSavingTier) : 'off';\n}\n\n/**\n * Resolve the effective (concrete) token-saving tier for the **prompt builder**,\n * expanding the `'auto'` sentinel from the model's context window. This is\n * **cache-safe**: the window is stable for a session, so it resolves to the same\n * tier every turn \u2014 the system-prompt prefix stays byte-stable and the provider\n * prompt cache is never busted by a shifting tier (unlike a per-turn\n * pressure-driven tier). It re-resolves only on `/model` switch, which busts the\n * cache anyway.\n *\n * Conservative thresholds (small windows only; large windows keep the full\n * prompt so nothing changes for the common 200k+/1M case):\n * - `< 32k` \u2192 `'medium'` (identity + tool prose is a big fraction \u2014 trim it)\n * - `< 96k` \u2192 `'light'`\n * - `>= 96k` \u2192 `'off'` (room to spare; favour cache stability + capability)\n * - unknown window \u2192 `'off'` (never guess a lean prompt without evidence)\n *\n * Explicit concrete tiers (a user who set `'medium'`, `'off'`, \u2026) are always\n * respected verbatim \u2014 `'auto'` is the only value that consults the window.\n */\nexport function resolveTokenSavingTier(\n val: TokenSavingTier | boolean | undefined,\n maxContext: number | undefined,\n): ConcreteTokenSavingTier {\n if (val === 'auto') {\n if (typeof maxContext !== 'number' || !Number.isFinite(maxContext) || maxContext <= 0) {\n return 'off';\n }\n if (maxContext < 32_000) return 'medium';\n if (maxContext < 96_000) return 'light';\n return 'off';\n }\n return normalizeTokenSavingTier(val);\n}\n\n/**\n * Verbosity of fleet/subagent activity streamed into the main TUI chat.\n * See {@link AutonomyConfig.fleetChatVerbosity}.\n */\nexport type FleetChatVerbosity = 'off' | 'full';\n\nexport const FLEET_CHAT_VERBOSITY_VALUES: readonly FleetChatVerbosity[] = ['off', 'full'];\n\n/**\n * Resolve the effective fleet-chat verbosity from autonomy config.\n * An explicit `fleetChatVerbosity` wins; otherwise the legacy `streamFleet`\n * boolean is honored (`false` \u2192 'off'); absence of both means 'off'.\n * `fleetChatVerbosity` must never be given a merge-time default \u2014 the\n * absence of the field is what lets legacy `streamFleet: false` configs\n * keep their intent.\n */\nexport function resolveFleetChatVerbosity(\n autonomy?: Pick<AutonomyConfig, 'fleetChatVerbosity' | 'streamFleet'>,\n): FleetChatVerbosity {\n const explicit = autonomy?.fleetChatVerbosity;\n if (explicit && (FLEET_CHAT_VERBOSITY_VALUES as readonly string[]).includes(explicit)) {\n return explicit;\n }\n if (autonomy?.streamFleet === false) return 'off';\n return 'off';\n}\n\nexport const DEFAULT_TUI_THINKING_WORD = 'thinking';\nexport const MAX_TUI_THINKING_WORD_LENGTH = 16;\n\n/**\n * Normalize the configurable statusline word shown while the TUI is working.\n * The value must be a single short word; invalid values fall back to the default.\n */\nexport function normalizeTuiThinkingWord(value: unknown): string {\n if (typeof value !== 'string') return DEFAULT_TUI_THINKING_WORD;\n const word = value.trim();\n if (word.length === 0 || word.length > MAX_TUI_THINKING_WORD_LENGTH) {\n return DEFAULT_TUI_THINKING_WORD;\n }\n if (!/^[\\p{L}\\p{N}_-]+$/u.test(word)) return DEFAULT_TUI_THINKING_WORD;\n return word;\n}\n\nexport interface ContextConfig {\n /** Context-window policy mode. Controls compaction thresholds and preservation depth. */\n mode?: ContextWindowModeId | undefined;\n warnThreshold: number;\n softThreshold: number;\n hardThreshold: number;\n /** Enable automatic compaction when thresholds are crossed (default: true). */\n autoCompact?: boolean | undefined;\n /**\n * Model used for LLM-assisted summarization in IntelligentCompactor.\n * Falls back to the main model when omitted.\n */\n summarizerModel?: string | undefined;\n /**\n * Override the effective context window size (in tokens). Use this when\n * you want the compactor to trigger earlier than the provider's actual\n * maxContext. Defaults to the provider's reported maxContext.\n */\n effectiveMaxContext?: number | undefined;\n maxSessionTokens?: number | undefined;\n maxDailyTokens?: number | undefined;\n preserveK: number;\n eliseThreshold: number;\n /** Compactor strategy: 'hybrid' (default, fast rules), 'intelligent' (LLM summarization), 'selective' (LLM-driven selection). */\n strategy?: 'hybrid' | 'intelligent' | 'selective' | undefined;\n /** Enable LLM-driven selective compaction (default: false for backward compat). */\n llmSelector?: boolean | undefined;\n}\n\n/**\n * Runtime configuration for the process circuit breaker (the one owned by the\n * ProcessRegistry that gates `bash`/`exec`). Toggle via `/settings breaker`.\n *\n * The breaker itself is a low-level primitive (`packages/tools/.../circuit-breaker.ts`)\n * that is on by default; this section controls whether the registry actually\n * participates in it and how it auto-recovers.\n */\nexport interface CircuitBreakerRuntimeConfig {\n /**\n * Enable circuit-breaker protection. When false (the default), the breaker\n * is bypassed \u2014 `bash`/`exec` calls always proceed regardless of failure\n * history. When true, the breaker trips on repeated failures / slow calls /\n * bursts and blocks further calls until it recovers.\n */\n enabled?: boolean | undefined;\n /**\n * When the breaker trips, automatically kill all tracked processes AND\n * reset the breaker to closed after this delay (ms). 0 = disabled (manual\n * recovery only via `/kill reset`). Only effective when `enabled` is true.\n * While armed, the statusline shows a live countdown to the kill/reset.\n */\n autoKillResetMs?: number | undefined;\n}\n\n/**\n * Adaptive concurrency controller configuration. When enabled, the controller\n * automatically adjusts `maxConcurrent` based on rate-limit (429) errors:\n * - On 429: halves `maxConcurrent` (floor at 1)\n * - On sustained success (no 429 for `recoveryIntervalMs`): increases `maxConcurrent` by 1\n */\nexport interface AdaptiveConcurrencyConfig {\n /** Enable adaptive concurrency. Default: false (disabled). */\n enabled?: boolean | undefined;\n /**\n * Minimum concurrency floor. The controller never drops below this.\n * Default: 1.\n */\n minConcurrent?: number | undefined;\n /**\n * Maximum concurrency ceiling. The controller never exceeds this.\n * Default: 16 (matches MultiAgentCoordinator default).\n */\n maxConcurrent?: number | undefined;\n /**\n * Multiplicative decrease factor when a 429 is hit.\n * `newConcurrency = floor(currentConcurrency * decreaseFactor)`.\n * Default: 0.5 (halves concurrency).\n */\n decreaseFactor?: number | undefined;\n /**\n * Number of consecutive successful requests before increasing concurrency by 1.\n * Default: 10.\n */\n successThreshold?: number | undefined;\n /**\n * How often (ms) to check for recovery and bump concurrency.\n * Default: 30_000 (30 seconds).\n */\n recoveryIntervalMs?: number | undefined;\n}\n\nexport interface ToolsConfig {\n defaultExecutionStrategy: 'parallel' | 'sequential' | 'smart';\n maxIterations: number;\n iterationTimeoutMs: number;\n /** Hard upper bound for a single tool call timeout. Defaults to 5 minutes. */\n maxToolTimeoutMs?: number | undefined;\n sessionTimeoutMs: number;\n perIterationOutputCapBytes: number;\n /**\n * Per-tool prose budget for the tool's top-level description and usage hint.\n * Missing entries default to \"extend\".\n */\n descriptionMode?: ToolDescriptionModeConfig | undefined;\n /**\n * Per-tool on-screen result rendering mode (terminal / WebUI / TUI).\n * Missing entries default to \"extend\". Independent of `descriptionMode`:\n * `/tool <name> result simple` toggles this without touching the\n * LLM-side description length.\n */\n resultRenderMode?: ToolResultRenderModeConfig | undefined;\n /**\n * Tool names to disable. Disabled tools are excluded from the tool registry\n * (`ToolRegistry.list()` / `get()`), so they do NOT appear in the system\n * prompt's \"## Tool usage\" block \u2014 reducing per-request token consumption.\n * Override per-session with `/tool enable <name>` or re-enable all via\n * `/tool enable-all`.\n */\n disabledTools?: string[] | undefined;\n /**\n * When true (default), the agent automatically extends its iteration\n * limit by 100 when hit. Set to false to require user confirmation.\n */\n autoExtendLimit?: boolean | undefined;\n /**\n * When true, file tools (read/write/edit/grep/glob/install) are confined to\n * the project root and `set_working_dir` may not leave it. Default: false \u2014\n * tools may access paths outside the project root, still subject to each\n * tool's permission tier (writes/edits prompt for confirmation). Toggle via\n * `/settings` (\"Filesystem access\").\n */\n restrictToProjectRoot?: boolean | undefined;\n /**\n * Per-command policy for the `exec` tool's allowlist. The tool ships a\n * curated default allowlist of dev/build commands; this extends or trims it.\n *\n * SECURITY: `allow` EXPANDS what the agent may execute, so it is honored only\n * from the trusted active-profile config \u2014 the config loader\n * strips `tools.exec.allow` from the untrusted, repo-committed\n * `<project>/.wrongstack/config.json`. `deny` only ever REMOVES commands, so\n * it is honored from any source.\n */\n exec?: ExecToolConfig | undefined;\n /**\n * Agent-loop repetition detector tuning. The detector watches two signals:\n * consecutive effectively-identical iterations (same tool-name set + inputs\n * + text) and per-call repeats (the same tool invoked with identical\n * arguments N times within a sliding window, even when interleaved with\n * other calls). In the default `steer-then-cut` mode the first detection\n * folds a corrective note into the conversation and lets the run continue;\n * only persistent repetition cuts the turn. Omitted fields use built-in\n * defaults (see DEFAULT_TOOLS_CONFIG.loopDetection).\n */\n loopDetection?: LoopDetectionConfig | undefined;\n}\n\n/** Tuning for the agent-loop repetition detector (`tools.loopDetection`). */\nexport interface LoopDetectionConfig {\n /**\n * `steer-then-cut` (default): inject a corrective note at the steer\n * threshold, cut the turn only if repetition persists to the cut threshold.\n * `cut`: legacy behavior \u2014 hard-stop at the steer threshold, per-call\n * detector disabled. `off`: disable loop detection entirely.\n */\n mode?: 'steer-then-cut' | 'cut' | 'off' | undefined;\n /** Consecutive identical iterations before the detector acts (default 3, min 2). */\n steerThreshold?: number | undefined;\n /**\n * Consecutive identical iterations at which the turn is cut in\n * `steer-then-cut` mode (default steerThreshold + 2, min steerThreshold + 1).\n */\n cutThreshold?: number | undefined;\n /** Sliding window of recent tool calls for per-call repeat detection (default 12, min 4). */\n windowSize?: number | undefined;\n /**\n * Identical (name + canonicalized args) calls within the window that\n * trigger a steer note (default 4, min 2).\n */\n callRepeatThreshold?: number | undefined;\n}\n\n/** Allow/deny extension of the `exec` tool's built-in command allowlist. */\nexport interface ExecToolConfig {\n /**\n * Extra command names to add to the allowlist (e.g. `[\"make\", \"dotnet\"]`).\n * Trusted sources only \u2014 stripped from in-project repo config.\n */\n allow?: string[] | undefined;\n /**\n * Command names to remove from the allowlist. Honored from any source \u2014\n * removing a command can only narrow what runs, so it is always safe.\n */\n deny?: string[] | undefined;\n /**\n * Per-rule bypass for the heuristic danger detector. Each entry is a\n * stable `matchedRule` id (e.g. `rm-recursive`, `git-push-force`); a\n * matched rule whose id is in this list is suppressed.\n *\n * Use case: a project that legitimately runs `rm -rf ./build` on every\n * CI run can add `\"rm-recursive\"` to bypass so the detector stops\n * emitting banners for that one rule \u2014 without disabling it for every\n * other `rm -rf` invocation.\n *\n * **Trusted sources only.** Bypassing a danger rule means the user\n * agreed to a specific destructive pattern; in-project repo config\n * could otherwise be used to silently opt everyone in. The boot path\n * strips this field from `<project>/.wrongstack/config.json` the\n * same way it strips `allow`.\n */\n danger?: ExecDangerConfig | undefined;\n}\n\nexport interface ExecDangerConfig {\n /**\n * List of danger rule ids to skip. Each id corresponds to a rule in\n * `@wrongstack/tools/src/_danger-detect.ts` (e.g. `rm-recursive`,\n * `git-push-force`, `inline-eval`, `sudo`). Unknown ids are ignored\n * (forward-compat: a rule added in a future version can be referenced\n * before the user upgrades).\n */\n bypass?: string[] | undefined;\n}\n\nexport type ToolDescriptionMode = 'extend' | 'simple';\nexport type ToolDescriptionModeConfig = Record<string, ToolDescriptionMode | undefined>;\n\n/**\n * Per-tool on-screen result rendering mode. Independent of\n * {@link ToolDescriptionMode}: `descriptionMode` controls the prose the\n * model sees in the system prompt, `resultRenderMode` controls how the\n * tool's RESULT is printed to the user (terminal / WebUI / TUI).\n *\n * - `simple` \u2014 meta only (filename, line count, exit code). Body is hidden\n * by default; the user can still expand on demand where the renderer\n * supports it.\n * - `extend` \u2014 full preview, up to 10 lines for read-like tools.\n *\n * The two modes are toggled independently via `/tool <name> desc simple`\n * and `/tool <name> result simple`. The legacy `/tool <name> simple`\n * command sets BOTH at once for backward compatibility.\n */\nexport type ToolResultRenderMode = 'extend' | 'simple';\nexport type ToolResultRenderModeConfig = Record<string, ToolResultRenderMode | undefined>;\n\nexport interface ProviderApiKey {\n /** Short human-readable label (e.g. \"personal\", \"work\", \"rate-limit-backup\"). */\n label: string;\n /**\n * The key itself. The field name contains `apiKey` so the secret-vault\n * walker will encrypt it on write and decrypt it on read.\n */\n apiKey: string;\n /** ISO-8601 timestamp the key was added. */\n createdAt: string;\n /**\n * How this credential was obtained.\n * - `api_key` \u2014 manually pasted API key (default)\n * - `oauth` \u2014 OAuth 2.0 device-code / authorization-code flow\n * - `session_token` \u2014 extracted from browser session (ChatGPT web, etc.)\n */\n authMethod?: 'api_key' | 'oauth' | 'session_token' | undefined;\n /** ISO-8601 expiry. When set, the token manager will refresh before this time. */\n expiresAt?: string | undefined;\n /**\n * OAuth refresh token. Stored encrypted by the secret-vault walker because\n * the field name contains `Token` (case-insensitive match by vault).\n */\n refreshToken?: string | undefined;\n /** Token type as returned by the OAuth endpoint (e.g. \"bearer\"). */\n tokenType?: string | undefined;\n /** OAuth scope string (e.g. \"openai.models.read openai.models.use\"). */\n scope?: string | undefined;\n /**\n * ChatGPT account id, extracted from the OAuth access-token JWT\n * (`https://api.openai.com/auth`.chatgpt_account_id). Sent as the\n * `chatgpt-account-id` header by the `openai-codex` wire family. Cached\n * here for display/diagnostics; the provider re-derives it from the live\n * token at request time so it can never go stale after a refresh.\n */\n accountId?: string | undefined;\n}\n\nexport interface ProviderConfig {\n type: string;\n /**\n * Legacy single-key field. Still honored as a read fallback when `apiKeys`\n * is empty (for configs not yet migrated to multi-key format). After key\n * management operations (`writeKeysBack`), this field is **cleared** to\n * prevent accidental serialization of the plaintext key. Consumers that\n * need the active API key should use `resolveActiveApiKey()` (cli) or\n * resolve from `apiKeys[]` directly \u2014 never read `cfg.apiKey` in new code.\n */\n apiKey?: string | undefined;\n /** Multiple keys for the same provider \u2014 pick one with `activeKey`. */\n apiKeys?: ProviderApiKey[] | undefined;\n /** Label of the entry in `apiKeys` to use. Defaults to the first one. */\n activeKey?: string | undefined;\n baseUrl?: string | undefined;\n headers?: Record<string, string>;\n model?: string | undefined;\n quirks?: Record<string, unknown>;\n capabilities?: Record<string, unknown>;\n /**\n * Optional wire-family override. When present, the provider can be\n * constructed without consulting the models.dev catalog \u2014 useful for\n * self-hosted endpoints, internal proxies, or for working offline.\n */\n family?: WireFamily | undefined;\n /** Custom env var names to probe when `apiKey` is missing. */\n envVars?: string[] | undefined;\n /** Optional list of models the user wants visible for this provider. */\n models?: string[] | undefined;\n /**\n * Fetch this provider's model list + per-model capabilities from its\n * `{baseUrl}/models` endpoint at startup and inject them into the catalog.\n * For openai-compatible gateways/proxies (omniroute, LiteLLM, vLLM, \u2026) that\n * expose rich metadata there. Defaults on for presets that set it (omniroute).\n * Discovery is best-effort: a down server or missing key is a no-op.\n */\n autoDiscoverModels?: boolean | undefined;\n /**\n * Provider-relative custom model definitions (maps modelId \u2192 definition).\n * Each entry adds/overrides a model for this provider with optional\n * capability overrides. The model id is the key, not a fully qualified id.\n */\n customModels?: Record<string, CustomModelDefinition>;\n /**\n * Per-provider OAuth configuration. When present, `wstack auth login <id>`\n * uses this instead of prompting for a raw API key. Set by the catalog or\n * by the user via `/settings`.\n */\n oauthConfig?:\n | {\n /** OAuth client id registered with the provider. */\n clientId?: string | undefined;\n /** Device authorization endpoint (RFC 8628). */\n deviceCodeEndpoint?: string | undefined;\n /** Token endpoint for code exchange and refresh. */\n tokenEndpoint?: string | undefined;\n /** Authorization server URL shown to the user for opening in browser. */\n authorizationEndpoint?: string | undefined;\n /** Default OAuth scopes to request. */\n scopes?: string[] | undefined;\n }\n | undefined;\n}\n\n/**\n * One entry in the per-task model matrix. Pins a catalog role, a phase, or\n * the `*` default to a specific model (and, optionally, a specific provider).\n * Resolved at subagent-spawn time so e.g. `security-scanner` can run a\n * different model than `documentation` while the leader stays on its own.\n */\nexport interface ModelMatrixEntry {\n /** Provider registry id (e.g. \"anthropic\", \"minimax\", \"zai\"). When omitted,\n * the leader's provider is used with this entry's model. */\n provider?: string | undefined;\n /** Model id to run for the matched role/phase/default. */\n model?: string | undefined;\n /**\n * Runtime request overrides for subagents matched by this entry. This is\n * intentionally scoped to subagents: leader requests keep using top-level\n * `Config.modelRuntime`, while a role/phase can opt into its own reasoning\n * effort, cache TTL, or gated generation parameters.\n */\n modelRuntime?: ModelRuntimeConfig | undefined;\n /**\n * Named fallback profile to use for the matched role/phase/default. When\n * `model` is omitted, the first model in the profile becomes the primary and\n * the remaining entries become that subagent's fallback chain.\n */\n fallbackProfile?: string | undefined;\n}\n\nexport interface MCPServerConfig {\n /** Human-readable description shown in `wstack mcp list`. */\n description?: string | undefined;\n name: string;\n transport: 'stdio' | 'sse' | 'streamable-http';\n command?: string | undefined;\n args?: string[] | undefined;\n env?: Record<string, string>;\n url?: string | undefined;\n headers?: Record<string, string>;\n enabled?: boolean | undefined;\n allowedTools?: string[] | undefined;\n permission?: Permission | undefined;\n startupTimeoutMs?: number | undefined;\n requestTimeoutMs?: number | undefined;\n /**\n * Lazy connect: when true, the server process is NOT spawned at boot. Its\n * tools are registered from a cached manifest (discovered on the first ever\n * connect) and the server only spawns when one of its tools is actually\n * called, then auto-sleeps after an idle period. Default (false/undefined) =\n * eager connect at boot.\n */\n lazy?: boolean | undefined;\n /**\n * Allowlist of environment variable names to forward from the parent process\n * to this MCP server's child process. The values are resolved from\n * `process.env` at spawn time, NOT stored in the config file.\n *\n * Why this exists: WrongStack's `buildChildEnv()` security filter scrubs\n * env vars whose names look like secrets (TOKEN, SECRET, AUTH, KEY, ...)\n * from all child processes \u2014 this prevents a compromised MCP server from\n * exfiltrating provider API keys. But most MCP servers (GitHub, Slack,\n * Brave Search, ...) need their own API tokens from the environment.\n * `passthroughEnv` is the explicit bypass: only vars listed here survive\n * the filter, and they go through the `extra` path (unfiltered merge).\n *\n * Built-in presets declare their required env vars here so they work\n * out of the box when the user has the corresponding env vars exported\n * in their shell. Users can also add entries for custom servers.\n *\n * Example: passthroughEnv: ['GITHUB_PERSONAL_ACCESS_TOKEN', 'GITHUB_TOKEN']\n */\n passthroughEnv?: string[] | undefined;\n /**\n * Operational-health settings for this MCP server. Thresholds are optional;\n * when omitted the server is considered healthy as long as its connection\n * lifecycle succeeds. Latency thresholds compare against the rolling p95 of\n * the bounded sample buffer; the in-flight threshold compares against the\n * observed peak in-flight call count.\n */\n health?: MCPHealthConfig | undefined;\n}\n\n/** Per-server operational-health knobs. */\nexport interface MCPHealthConfig {\n thresholds?: MCPHealthThresholds | undefined;\n}\n\n/**\n * Configurable thresholds that can push an otherwise-healthy MCP server into\n * the `degraded` health state. All thresholds are optional and disabled when\n * omitted so existing behaviour is preserved.\n */\nexport interface MCPHealthThresholds {\n /** Connection latency p95 above this value marks the server degraded. */\n connectionLatencyP95Ms?: number | undefined;\n /** Discovery (capability listing) latency p95 above this marks degraded. */\n discoveryLatencyP95Ms?: number | undefined;\n /** Tool-call latency p95 above this marks degraded. */\n callLatencyP95Ms?: number | undefined;\n /** Peak in-flight calls above this marks the server saturated/degraded. */\n inFlightCalls?: number | undefined;\n}\n\nexport interface LogConfig {\n level: 'error' | 'warn' | 'info' | 'debug' | 'trace';\n file?: string | undefined;\n}\n\nexport interface PluginConfig {\n name: string;\n enabled?: boolean | undefined;\n options?: Record<string, unknown>;\n}\n\n/**\n * Optional subsystems that the CLI can boot without. The core flow\n * (provider + agent loop + bundled tools + session) always works; these\n * just add capabilities. `--no-features` flips all of these off, which\n * is the minimum viable WrongStack: a single provider, a fixed config,\n * no network calls at startup.\n */\nexport interface FeaturesConfig {\n /** Load MCP servers declared in `mcpServers`. */\n mcp: boolean;\n /** Load + initialise npm plugins declared in `plugins`. */\n plugins: boolean;\n /** Register `remember` / `forget` tools backed by memory store. */\n memory: boolean;\n /**\n * Automatically consolidate session learnings into long-term memory\n * after each completed run. The agent extracts key facts, conventions,\n * and decisions via a lightweight LLM call and persists them.\n * Enabled by default when `memory` is on; set to false to opt out.\n */\n memoryConsolidation?: boolean | undefined;\n /** Fetch the models.dev catalog at startup. When false, the provider\n * must declare its `family` explicitly in `providers[<id>]`. */\n modelsRegistry: boolean;\n /** Discover + load skills from disk. */\n skills: boolean;\n /**\n * Enable the prompt library (`/prompt`, `/prompts`, `/prompt-gen`, the WebUI\n * modal and the bundled 168-prompt dataset). Defaults to on; set to false to\n * disable the subsystem entirely (the loader is withheld so every surface\n * reports it unavailable).\n */\n prompts?: boolean | undefined;\n /**\n * Token-saving mode tier. Controls how aggressively the system prompt\n * is compacted to reduce per-request token consumption.\n *\n * - 'off' \u2014 Full prompt, all tools, complete guidance\n * - 'minimal' \u2014 TIER1 tools only, stripped guidance (~3-4k tokens saved)\n * - 'light' \u2014 Core + memory tools, common patterns, minimal guidance\n * - 'medium' \u2014 Most development tools, some guidance\n * - 'aggressive' \u2014 Maximum savings before tools become unusable (~4-5k tokens)\n *\n * Boolean values are accepted for backward compatibility:\n * - `true` \u2192 'medium'\n * - `false` \u2192 'off'\n *\n * Enable via CLI: `--token-saving-tier <level>` or `--token-saving-mode` (maps to 'medium').\n * Configure via: `features.tokenSavingMode: \"minimal\"` in config.\n */\n tokenSavingMode?: TokenSavingTier | boolean | undefined;\n /**\n * Enable the autonomous-coordination toolkit (AutonomousCoordinator +\n * KnowledgeGraph + ConsensusProtocol + TaskAuctioneer + ChangeManager +\n * TaskDAG). When true (the default), the TUI boot wires the coordinator\n * lazily on the first Director spawn. When false, the coordinator is\n * never constructed and the `/coordinator` slash command reports it\n * unavailable \u2014 reducing the coordination domain's runtime surface for\n * users who only use the simpler Director/Fleet path.\n */\n autonomousCoordination?: boolean | undefined;\n /**\n * Allow tools to read/write paths outside the project root directory.\n * When true (default), tools can access any path on the filesystem.\n * When false, tools are restricted to the project root directory.\n */\n allowOutsideProjectRoot?: boolean | undefined;\n /**\n * Auto-bootstrap the mailbox HTTP bridge from any WrongStack surface\n * (REPL/TUI/WebUI/eternal). When 'auto' (the default), the first\n * surface to come up for a given project joins or spawns the bridge\n * so external agents can connect without the user running\n * `wstack mailbox serve` themselves. 'off' disables this \u2014 operators\n * must start the bridge explicitly (e.g. via the `/mailbox-serve`\n * slash command or the standalone `wstack mailbox serve` subcommand).\n * The per-project lock + token-persistence model means a second\n * surface on the same project joins the first's bridge rather than\n * spawning a duplicate.\n */\n mailboxBridge?: 'auto' | 'off' | undefined;\n}\n\nexport interface SuperMemoryConfig {\n /**\n * Default: true. Super Memory is the ONLY memory backend \u2014 this flag no longer\n * swaps the store. When `false`, the backend is still Super Memory (explicit\n * `/memory`, agent memory tools, and WebUI all keep working); only automatic\n * context injection and session-end hygiene are turned off.\n */\n enabled?: boolean | undefined;\n storage?:\n | {\n /** Store memory inside the project under a gitignored directory. Default: true. */\n projectLocal?: boolean | undefined;\n /** Project-relative directory. Default: \".wrongstack/memories\". */\n directory?: string | undefined;\n /** Storage engine: 'jsonl' (default, append-only JSONL) or 'sqlite' (indexed + FTS5 search, auto-migrates from JSONL). */\n engine?: 'jsonl' | 'sqlite' | undefined;\n }\n | undefined;\n inject?:\n | {\n /** Add relevant memory to ordinary turn-level context. Default: false (opt-in). */\n turnContext?: boolean | undefined;\n /** Add relevant memory to read/tree/grep/bash/edit tool results. Default: true. */\n toolResults?: boolean | undefined;\n /** Enrich tool retrieval with live todo/Kanban task state and context-pressure budgeting. Default: true. */\n taskAware?: boolean | undefined;\n /** Maximum diverse, structurally related hints appended to a single tool result. Default: 8. */\n maxHintsPerTool?: number | undefined;\n /** Maximum characters appended to a single tool result. Default: 2800. */\n maxCharsPerTool?: number | undefined;\n /** Maximum memories appended to ordinary turn context. Default: 8. */\n maxTurnMemories?: number | undefined;\n /** Maximum characters appended to ordinary turn context. Default: 2400. */\n maxCharsPerTurn?: number | undefined;\n /** Minimum retrieval score for ordinary hints. Default: 0.65. */\n minScore?: number | undefined;\n /** Cooldown before the same memory can be injected again. Default: 30 minutes. */\n repeatCooldownMs?: number | undefined;\n triggers?:\n | Partial<\n Record<\n | 'read'\n | 'tree'\n | 'grep'\n | 'glob'\n | 'codebase_search'\n | 'bash'\n | 'write'\n | 'edit'\n | 'patch',\n boolean\n >\n >\n | undefined;\n }\n | undefined;\n retrieval?:\n | {\n /**\n * Weight given to the metadata score floor (0\u20131) in the relevance-blended\n * scoring formula: `metadataScore * (metadataWeight + relevance * (1 - metadataWeight))`.\n * At 0.0, relevance fully gates injection. At 1.0, metadata alone decides.\n * Default: 0.3 \u2014 validated against 148 real query-memory pairs.\n */\n metadataWeight?: number | undefined;\n }\n | undefined;\n hygiene?:\n | {\n /** Run hygiene after successful sessions. Default: true. */\n autoAfterSession?: boolean | undefined;\n /** Re-check anchored memories when files are edited. Default: true. */\n autoOnFileChange?: boolean | undefined;\n /** Archive stale/low-value memories after this many days. Default: 90. */\n retentionDays?: number | undefined;\n /** Archive low-confidence memories after this many days. Default: 30. */\n archiveLowConfidenceAfterDays?: number | undefined;\n /**\n * Archive active memories that were injected at least `unusedMinInjections`\n * times but never referenced by the assistant, this many days after their\n * last content update. Default: 30.\n */\n archiveUnusedAfterDays?: number | undefined;\n /** Minimum injection count before a never-used memory is archived. Default: 10. */\n unusedMinInjections?: number | undefined;\n }\n | undefined;\n embeddings?:\n | {\n /** Optional future semantic layer. Disabled by default and never required. */\n enabled?: boolean | undefined;\n }\n | undefined;\n}\n\nexport interface AutonomyConfig {\n /** Default autonomy mode at startup. Default: \"auto\". */\n defaultMode?: 'off' | 'suggest' | 'auto' | undefined;\n /** ms to wait before auto-proceeding in 'auto' mode. Default: 45000. */\n autoProceedDelayMs?: number | undefined;\n /** Maximum consecutive auto-proceed turns before pausing. 0 = unlimited. Default: 50. */\n autoProceedMaxIterations?: number | undefined;\n /** Template used for YOLO+auto suggestions. Must include {{suggestion}}. */\n autonomyNextPrompt?: string | undefined;\n /** Animate the terminal/window title while the agent is active. Default: true. */\n terminalTitleAnimation?: boolean | undefined;\n /** Persisted YOLO preference mirrored into top-level config.yolo at runtime. Default: false. */\n yolo?: boolean | undefined;\n /**\n * @deprecated Mirror of `fleetChatVerbosity !== 'off'`, kept for readers that\n * still expect a boolean (webui prefs). Writers must keep it in sync.\n */\n streamFleet?: boolean | undefined;\n /**\n * How much fleet/subagent activity is streamed into the main TUI chat.\n * - 'off': no subagent lines (failures/errors still surface); F2/F3 stay live.\n * - 'full': every subagent tool call and interim message (legacy behavior).\n * Resolved via {@link resolveFleetChatVerbosity}. Default: 'off'.\n */\n fleetChatVerbosity?: FleetChatVerbosity | undefined;\n /** Ring terminal bell when an agent run completes. Default: false. */\n chime?: boolean | undefined;\n /** Ask for confirmation before interrupt/exit. Default: true. */\n confirmExit?: boolean | undefined;\n /** Terminal mouse tracking preference. Default: false. */\n mouseMode?: boolean | undefined;\n /** Enable prompt refinement before sending. Default: true. */\n enhance?: boolean | undefined;\n /**\n * Provider id to use for goal refinement (`/goal set`). When set,\n * the refiner uses this provider's model (see `refinerModel`)\n * instead of the session's main provider/model. Falls back to the\n * main session provider when unset or when the provider is unavailable.\n * Default: unset (uses the main session provider).\n */\n refinerProvider?: string | undefined;\n /**\n * Model id to use for goal refinement. When `refinerProvider` is\n * also set, the refiner uses this specific model on that provider.\n * When only `refinerModel` is set (without a provider), the model\n * is used on the session's main provider. When both are unset, the\n * session's main model is used. Falls back to heuristic on failure.\n * Default: unset (uses the main session model).\n */\n refinerModel?: string | undefined;\n /**\n * Named fallback profile to use for goal refinement. When set, the\n * refiner uses the first valid entry from the named chain (stored in\n * top-level `fallbackProfiles`) instead of `refinerProvider`+`refinerModel`.\n * Falls back to the session model when the profile is empty or missing.\n * Default: unset (uses refinerProvider+refinerModel, or session defaults).\n */\n refinerFallbackProfile?: string | undefined;\n /** Prompt-refinement preview countdown in ms. Default: 60000. */\n enhanceDelayMs?: number | undefined;\n /** Prompt-refinement language mode. Default: \"original\". */\n enhanceLanguage?: 'original' | 'english' | undefined;\n /**\n * `provider/model` ref used for the one-key \"retry with another model\" action\n * offered when a refinement fails. When unset, the recovery UI falls back to\n * the first entry of the effective fallback chain (see\n * `resolveEnhanceFallbackRef`). Default: unset.\n */\n enhanceFallbackModel?: string | undefined;\n /**\n * Timeout (ms) used when RETRYING a refinement after the first attempt timed\n * out \u2014 the \"extra time\" retry. When unset, the retry uses\n * `max(baseTimeout * 2, 180000)`. Default: unset.\n */\n enhanceRetryTimeoutMs?: number | undefined;\n /** TUI statusline density. Default: \"detailed\". */\n statuslineMode?: 'minimum' | 'detailed' | 'no-color' | undefined;\n /** Single short word shown in the TUI rainbow working-state chip. Default: \"thinking\". */\n thinkingWord?: string | undefined;\n /**\n * Show the \"Model Reasoning\" collapsible blocks in chat history that display\n * the LLM's structured reasoning / COT output. Separate from the `thinkingWord`\n * status-bar chip and from model-provisioning `reasoning` settings.\n * Default: true.\n */\n showModelReasoning?: boolean | undefined;\n /**\n * Persist the TUI prompt input history to disk per project so Up/Down\n * navigation recalls prompts across sessions. Secrets are scrubbed before\n * they reach disk. Default: enabled, 100 entries.\n */\n inputHistory?: InputHistoryConfig | undefined;\n}\n\n/**\n * Per-project TUI input history persistence options. Lives under\n * `config.autonomy.inputHistory` because the TUI-specific knobs on Config\n * are grouped there.\n */\nexport interface InputHistoryConfig {\n /** Persist history to ~/.wrongstack/projects/<slug>/input-history.json. Default: true. */\n enabled?: boolean | undefined;\n /** Max entries kept on disk (and in memory). Default: 100. */\n maxEntries?: number | undefined;\n}\n\n/**\n * Automatic codebase symbol-index maintenance. Keeps the `codebase-search`\n * index (SQLite, `~/.wrongstack/projects/<hash>/codebase-index/index.db`) fresh\n * without the user having to call `codebase-index` by hand.\n */\nexport interface IndexingConfig {\n /** Run a blocking incremental index at session start (with a visible summary). Default: true. */\n onSessionStart: boolean;\n /** Reindex files the agent writes/edits via tools, in the background. Default: true. */\n onEdit: boolean;\n /** Watch the project root for external editor changes and reindex them. Default: true. */\n watchExternal: boolean;\n /** Debounce window (ms) coalescing rapid edits to the same file. Default: 400. */\n debounceMs: number;\n /**\n * Watchdog timeout (ms) for a full index run. A run exceeding this is\n * aborted (so it can never wedge the indexing mutex or freeze the terminal)\n * and counts toward the indexing circuit breaker. Default: 240000.\n */\n indexTimeoutMs?: number | undefined;\n}\n\n/**\n * Saved launch preferences \u2014 restored on next boot so the pre-launch prompt\n * can offer a one-line \"Continue with last settings? [Y/n]\" instead of\n * re-asking every question from scratch.\n */\nexport interface LaunchConfig {\n /** Interactive mode: 'tui' (Ink TUI) or 'repl' (readline REPL). */\n mode?: 'tui' | 'repl' | undefined;\n // (removed: director \u2014 Director Mode is permanently on)\n /**\n * Launch-time autonomy mode (binary choice from pre-launch prompt).\n * 'off' = stops after each turn; 'auto' = self-driving.\n * Distinct from `AutonomyConfig.defaultMode` which also supports 'suggest'.\n */\n autonomy?: 'off' | 'auto' | undefined;\n /**\n * Last mode chosen from the interactive launch menu\n * (`packages/cli/src/boot/launch-menu.ts`).\n *\n * Stored so the menu can offer a one-line \"Continue with last\n * settings? [Y/n/q]\" summary on the next boot instead of re-asking\n * the same 1-of-4 question. Distinct from `mode` (tui/repl) \u2014 that\n * field is set by the inner pre-launch prompts that run AFTER the\n * user has chosen \"TUI/REPL\" here.\n *\n * Default port per mode is owned by the launcher (HQ=3499, WebUI=3456,\n * SimpleUI=3466). Storing an explicit override here makes\n * `wstack --no-menu` keep the user's last port too.\n */\n menuChoice?: LaunchMenuChoice | undefined;\n}\n\n/**\n * Persisted record of the user's last interactive launch-menu choice.\n * Distinct from {@link LaunchConfig} above because it survives a\n * `wstack --webui` \u2192 `wstack` round-trip without overwriting the\n * inner pre-launch `mode` (tui/repl) preference.\n */\nexport interface LaunchMenuChoice {\n /** Which top-level surface the user picked from the menu. */\n mode: 'tui-repl' | 'webui' | 'simpleui' | 'hq';\n /** Port override the user typed (defaults to the surface's default). */\n port?: number | undefined;\n /** Host override the user typed (defaults to 127.0.0.1). */\n host?: string | undefined;\n}\n\n/**\n * Controls how much detail is persisted to the per-session JSONL log\n * (`~/.wrongstack/projects/<hash>/sessions/<date>/sess_<ULID>.jsonl`).\n */\nexport interface SessionLoggingConfig {\n /**\n * How much detail to write to the persistent session log.\n *\n * - \"minimal\" \u2192 Only events required for resume/rewind/recovery\n * - \"standard\" \u2192 (default) + high-value lightweight audit events\n * (compaction, tool timing, retries, errors, etc.)\n * - \"full\" \u2192 Also persist full request payloads (very large).\n * Consider enabling a separate replay log instead.\n */\n auditLevel?: 'minimal' | 'standard' | 'full' | undefined;\n\n /**\n * Sampling configuration for high-volume events (especially relevant at\n * `auditLevel: \"full\"`).\n */\n sampling?: {\n /** Controls sampling of `tool_progress` events. */\n toolProgress?: {\n /**\n * Sample rate for noisy progress events (`log`, `partial_output`).\n * - 1 = no sampling (every message is logged)\n * - 8 = default (first message + every 8th)\n */\n sampleRate?: number | undefined;\n };\n };\n}\n\nexport type SyncCategory = 'settings' | 'skills' | 'prompts' | 'memory' | 'history';\n\nexport interface SyncConfig {\n enabled: boolean;\n repo: string;\n /** GitHub token (fine-grained PAT). Encrypted at rest via SecretVault. */\n githubToken: string;\n categories: SyncCategory[];\n lastSyncedAt?: string | undefined;\n}\n\n/**\n * Per-model capability overrides the user can define in their config.\n * Used to add models not in the models.dev catalog, or override catalog\n * facts when the real backend differs (e.g. local Ollama models, proxies).\n */\nexport interface CustomModelDefinition {\n /** Provider this model belongs to. Defaults to the owning ProviderConfig. */\n provider?: string | undefined;\n /** Optional display name. */\n name?: string | undefined;\n /** Capability overrides \u2014 only specified fields are overlaid. */\n capabilities?: Partial<Capabilities> | undefined;\n /**\n * Max output tokens. If not specified, the provider family default\n * or catalog entry is used.\n */\n maxOutput?: number | undefined;\n}\n\n/**\n * Skill subsystem configuration. All fields optional; the subsystem itself is\n * gated by `features.skills`. Honored from the user's active-profile config;\n * in the repo-committed in-project config the `extraDirs` field is stripped\n * (arbitrary directories are a prompt-injection vector) \u2014 only `readClaudeSkills`\n * and `mode` survive there.\n */\nexport interface SkillsConfig {\n /**\n * Read skills from foreign coding-agent directories (`<project>/.claude/skills`\n * and `~/.claude/skills`). Default `true`. Lets Claude Code / Codex / Gemini /\n * `asm` / `gh skill` skills be used without copying them.\n */\n readClaudeSkills?: boolean | undefined;\n /**\n * Scan OTHER coding agents' skill directories (`~/.codex/skills`,\n * `~/.cursor/skills`, `~/.agents/skills`, `~/.qwen/skills`,\n * `~/.trae/skills`, \u2026 + their `<project>/.<tool>/\u2026` equivalents). Default\n * `true` (all known tools); pass a tool-id list to restrict, or `false` to\n * disable. Non-existent dirs are skipped. Unknown ids in the list (likely\n * typos) are dropped and surfaced via a config warning.\n */\n foreignSources?: boolean | string[] | undefined;\n /**\n * How skill bodies reach the system prompt.\n * - `'eager'` (default): inject every discovered skill body into the prompt.\n * - `'progressive'`: inject only the metadata manifest; the agent loads a\n * skill body on demand via the `skill` tool (the agentskills.io model).\n */\n mode?: 'eager' | 'progressive' | undefined;\n /**\n * Extra skill directories to scan (lowest priority, after the `.claude`\n * layers). Honored only from the user config; stripped from in-project config.\n */\n extraDirs?: string[] | undefined;\n /**\n * In eager mode, the maximum total chars of skill bodies injected into the\n * prompt (highest-priority skills first; the rest are listed as a manifest the\n * agent loads via the `skill` tool). Bounds prompt cost when many skills are\n * discovered. Default 24000 (~6k tokens). Set very high to disable. Ignored in\n * progressive mode (which injects only the manifest anyway).\n */\n eagerMaxChars?: number | undefined;\n /**\n * Base URL of the skill registry used by `/skill-search` and\n * `/skill-install <registry>:<id>`. Default `https://skills.sh` (the open\n * marketplace backed by mastra-ai/skills-api). Honored only from the user\n * config; stripped from in-project config (a repo-committed override would be\n * an SSRF / prompt-injection vector \u2014 the registry response is parsed into the\n * prompt). Set to a self-hosted skills-api instance to use a private catalog.\n */\n registryUrl?: string | undefined;\n}\n\n/**\n * Fleet peer-awareness + supervision settings. All sub-features are\n * enabled-by-default with conservative throttles; each has its own kill\n * switch. See `FleetSupervisor` (coordination/fleet-supervisor.ts) for the\n * supervisor semantics.\n */\nexport interface FleetConfig {\n /** Subagent process/registry lifecycle after it is no longer doing work. */\n lifecycle?:\n | {\n /**\n * Remove a spawned or between-task subagent after this much idle time.\n * This is separate from the in-task activity watchdog. Default 30000.\n */\n idleTimeoutMs?: number | undefined;\n /**\n * Retire a subagent as soon as its final task result is delivered and\n * no queued task reused it in the same dispatch cycle. Default true.\n */\n retireOnTaskComplete?: boolean | undefined;\n }\n | undefined;\n /** Fleet-wide hard ceilings. In-flight work may finish; new spawns are refused at the cap. */\n budget?:\n | {\n /** Maximum subagents spawned during one Director lifetime. Default 64 in CLI. */\n maxSpawns?: number | undefined;\n /** Maximum cumulative input+output tokens across all fleet subagents. */\n maxTokens?: number | undefined;\n /** Maximum cumulative estimated USD cost across all fleet subagents. */\n maxCostUsd?: number | undefined;\n }\n | undefined;\n /** Periodic \"[FLEET PULSE]\" peer-status digest folded into each agent's context. */\n pulse?:\n | {\n /** Default true. */\n enabled?: boolean | undefined;\n /** Inject at most every N agent iterations. Default 5. */\n everyNIterations?: number | undefined;\n /** Hard cap on digest characters. Default 900. */\n maxChars?: number | undefined;\n /** Max peers listed per digest. Default 15. */\n maxAgents?: number | undefined;\n }\n | undefined;\n /** Broadcast `type:'status'` mails on meaningful subagent transitions. */\n statusBroadcasts?:\n | {\n /** Default true. */\n enabled?: boolean | undefined;\n /** Min interval between broadcasts about the same subagent. Default 15000. */\n minIntervalMsPerAgent?: number | undefined;\n /** Global cap on broadcasts per minute (excess dropped + counted). Default 20. */\n globalPerMinuteCap?: number | undefined;\n /**\n * Broadcast recoverable soft-budget warnings to every project agent.\n * Default false: the local fleet UI still tracks warnings/extensions,\n * but routine preemption and auto-extension do not flood peer mailboxes.\n */\n budgetWarnings?: boolean | undefined;\n }\n | undefined;\n /**\n * Per-subagent git-worktree isolation for Director fleets. The default is\n * `auto`: mutating/build-capable subagents run in isolated checkouts and are\n * squash-merged back on success; read-only review agents usually stay on the\n * shared checkout. Set `enabled:false` or `mode:'off'` when a workflow cannot\n * use worktrees.\n */\n worktrees?:\n | {\n /** Kill switch. Default true. */\n enabled?: boolean | undefined;\n /**\n * `auto` (default): isolate only side-effectful subagents.\n * `required`: side-effectful subagents must get a worktree or fail.\n * `off`: never allocate worktrees.\n */\n mode?: 'auto' | 'required' | 'off' | undefined;\n /**\n * Merge successful task branches back into the base checkout. Default\n * true. When false, successful worktrees are committed and kept for\n * manual `/worktree merge`.\n */\n autoMerge?: boolean | undefined;\n /** Keep failed/timeout worktrees when they contain changes. Default true. */\n keepFailed?: boolean | undefined;\n }\n | undefined;\n /** Brain-gated fleet supervisor (rebalance/steer/spawn-helper). */\n supervisor?: FleetSupervisorConfig | undefined;\n}\n\n/** Config surface for the brain-gated FleetSupervisor. */\nexport interface FleetSupervisorConfig {\n /** Kill switch. Default true (active whenever a Director is running). */\n enabled?: boolean | undefined;\n /** Evaluation tick. Default 20000. */\n intervalMs?: number | undefined;\n /** Per-(signal,subject) re-engagement cooldown. Default 120000. */\n cooldownMs?: number | undefined;\n /** Hard cap on interventions touching one subagent per run. Default 3. */\n maxInterventionsPerSubagent?: number | undefined;\n /** Pending task pinned to a busy worker longer than this \u2192 starvation signal. Default 60000. */\n pinnedWaitMs?: number | undefined;\n /** \u2265 this many pending tasks pinned to one worker (with an idle sibling) \u2192 overload signal. Default 2. */\n overloadPinnedThreshold?: number | undefined;\n /** pending > backlogFactor \u00D7 live workers (sustained) \u2192 spawn-helper signal. Default 2. */\n backlogFactor?: number | undefined;\n /** Running subagent with no observable fleet activity for this long \u2192 stuck signal. Default 180000. */\n stuckMs?: number | undefined;\n /** Consecutive failed/timeout results from one subagent \u2192 failure-streak signal. Default 2. */\n failureStreak?: number | undefined;\n /** Allow the supervisor to spawn helper subagents. Default true. */\n allowSpawn?: boolean | undefined;\n /** Allow the supervisor to terminate subagents (highest risk). Default false. */\n allowTerminate?: boolean | undefined;\n}\n\n/**\n * One member of the Brain's LLM pool or council. String entries elsewhere\n * (`Config.brain.models`, council voters) parse with the same `parseModelRef`\n * grammar as `fallbackModels`: bare `model`, `provider/model`, or\n * `provider model`.\n */\nexport interface BrainModelEntry {\n /** Provider id (a key of `Config.providers` or a catalog id). Defaults to the session provider. */\n provider?: string | undefined;\n /** Model id, required. */\n model: string;\n}\n\n/** One voting seat on the Brain council. */\nexport interface BrainCouncilVoterConfig extends BrainModelEntry {\n /**\n * Decision lens for this seat. Built-ins: 'executor' (progress-biased),\n * 'skeptic' (risk-hunting), 'auditor' (cost/waste-focused). Any other\n * string is injected verbatim as the persona description.\n */\n persona?: string | undefined;\n /** Vote weight in the tally. Default 1. */\n weight?: number | undefined;\n /** When true, this seat's explicit refusal denies the request outright. */\n veto?: boolean | undefined;\n}\n\n/** Multi-LLM council configuration for high-stakes Brain decisions. */\nexport interface BrainCouncilConfig {\n /** Kill switch. Default: enabled when `voters` is non-empty or \u22652 pool models exist. */\n enabled?: boolean | undefined;\n /**\n * Minimum request risk that convenes the council instead of the single-LLM\n * tier. Default 'high'. 'critical' = council only for critical questions;\n * 'medium' = council for most non-trivial questions (slow + expensive).\n */\n minRisk?: 'medium' | 'high' | 'critical' | undefined;\n /**\n * Voting seats. String entries use the `parseModelRef` grammar and get\n * default personas (executor, skeptic w/ veto, auditor) assigned in order.\n * When omitted, seats are derived from `brain.models` (up to 3).\n */\n voters?: Array<string | BrainCouncilVoterConfig> | undefined;\n /** Fraction of seats that must return a valid vote. Default 0.5. */\n quorum?: number | undefined;\n /** Fraction of cast vote weight the winning option must exceed. Default 0.5. */\n approval?: number | undefined;\n /**\n * Tie-breaker / synthesizer model (`parseModelRef` grammar or entry).\n * Sees every vote's rationale and issues the final structured decision.\n * Default: the first pool/voter model.\n */\n judge?: string | BrainModelEntry | undefined;\n}\n\n/**\n * Brain decision-layer configuration. SECURITY: in the in-project config\n * DENY list \u2014 a repo-committed config must not be able to raise the\n * autonomy ceiling, remove the human tier, or point Brain decisions at an\n * attacker-chosen provider. Only honoured from the active-profile config.\n */\nexport interface BrainConfig {\n /**\n * 'headless' \u2014 the Brain NEVER blocks on a human. Escalations resolve\n * via the terminal policy (recommended option for low/medium\n * risk, request fallback semantics, otherwise deny).\n * 'interactive' \u2014 escalations prompt the human in the TUI/WebUI.\n * Default (resolved at boot by `resolveBrainConfigDefaults`): 'headless' \u2014\n * minimum-human out of the box. Switch live with `/brain mode <m>`.\n */\n mode?: 'headless' | 'interactive' | undefined;\n /**\n * Initial autonomy ceiling for the LLM tier. Default (resolved at boot):\n * adaptive \u2014 'all' when a council can convene (\u22652 voters/pool models),\n * otherwise 'high'. Live-set via `/brain risk`.\n */\n maxAutoRisk?: 'off' | 'low' | 'medium' | 'high' | 'all' | undefined;\n /**\n * Ordered LLM pool for Brain decisions (`parseModelRef` grammar or\n * entries). With `strategy: 'fallback'` the first entry is primary and the\n * rest are tried in order when it fails; with 'round-robin' calls rotate\n * across the pool. Default (resolved at boot): the user's `fallbackModels`\n * chain; with none configured, the session provider/model is used.\n */\n models?: Array<string | BrainModelEntry> | undefined;\n /** Pool selection strategy. Default 'fallback'. */\n strategy?: 'fallback' | 'round-robin' | undefined;\n /** Per-LLM-call decision timeout (ms). Default 15000. */\n decisionTimeoutMs?: number | undefined;\n /**\n * Interactive mode only: how long an ask-human prompt may stay unanswered\n * before it resolves through the terminal policy instead of blocking\n * forever. Default (resolved at boot): 120000. Set 0 to wait indefinitely\n * (legacy behavior).\n */\n humanTimeoutMs?: number | undefined;\n /** Multi-LLM council for high-stakes decisions. */\n council?: BrainCouncilConfig | undefined;\n /**\n * Persistent decision ledger (`<project>/.wrongstack/brain-ledger.jsonl`):\n * every decision + observed outcome is appended, and outcome stats for\n * similar past decisions are fed back into the LLM/council prompts.\n * Default: enabled.\n */\n ledger?:\n | {\n enabled?: boolean | undefined;\n /**\n * Deterministic guard: once this many consecutive approvals of a\n * decision group ended in observed failures, deny outright without\n * consulting any LLM (a later success lifts the guard). Default 3.\n * 0 disables.\n */\n autoDenyAfterFailures?: number | undefined;\n }\n | undefined;\n /**\n * BrainMonitor distress-signal thresholds (self-activation). All optional;\n * defaults match `BrainMonitorOptions`.\n */\n monitor?:\n | {\n /** Consecutive failures of the same tool before engaging. Default 3. */\n toolFailureStreak?: number | undefined;\n /** Errors within 60s before engaging. Default 4. */\n errorStormCount?: number | undefined;\n /** Active run with no progress for this long \u2192 stall signal (ms). Default 300000. 0 disables. */\n stallMs?: number | undefined;\n /** Edits to the same file within the churn window before engaging. Default 5. */\n fileChurnThreshold?: number | undefined;\n /** Sliding window for the file-churn signal (ms). Default 600000. */\n fileChurnWindowMs?: number | undefined;\n /** Per-signal re-engagement cooldown (ms). Default 120000. */\n cooldownMs?: number | undefined;\n }\n | undefined;\n}\n\n/** Git behavior overrides for agent-run git commands. See `Config.git`. */\nexport interface GitBehaviorConfig {\n /**\n * Commit identity injected as `GIT_AUTHOR_NAME/EMAIL` +\n * `GIT_COMMITTER_NAME/EMAIL` into every child process. Either field may be\n * set alone; the missing one falls back to git's own config.\n */\n identity?:\n | {\n name?: string | undefined;\n email?: string | undefined;\n }\n | undefined;\n}\n\nexport interface Config {\n /** Recurring provider/model blackout windows used by autonomous routing. */\n modelAvailabilitySchedule?:\n | import('../core/model-availability-calendar.js').ModelBlackoutRule[]\n | undefined;\n version: 1;\n provider: string;\n model: string;\n apiKey?: string | undefined;\n baseUrl?: string | undefined;\n /**\n * Maximum number of subagent tasks the fleet coordinator dispatches\n * simultaneously. Extra tasks queue until a slot frees. Default: 4.\n * Overridden by WRONGSTACK_MAX_CONCURRENT env var and --max-concurrent\n * CLI flag. Change at runtime with /fleet concurrency <n>.\n */\n maxConcurrent?: number | undefined;\n /**\n * Display language for the UI chrome (WebUI + desktop shell). A BCP-47-ish\n * code from SUPPORTED_LOCALES (en/tr/de/fr/it/es/pt-BR). Persisted here so a\n * change in one surface propagates to all others via the shared machine\n * config; each surface may keep a local cache for instant reactivity. When\n * unset, surfaces fall back to their own browser/system detection.\n */\n uiLocale?: string | undefined;\n providers?: Record<string, ProviderConfig>;\n /**\n * Top-level custom models (maps modelId \u2192 definition). Merged with\n * per-provider `customModels` at resolution time. The key is the\n * model id \u2014 not a fully qualified name. When the same model id\n * appears in both places, the top-level one wins.\n */\n models?: Record<string, CustomModelDefinition>;\n /**\n * Per-task model matrix. Keys are catalog roles (e.g. \"security-scanner\"),\n * phase names (e.g. \"review\"), or the `*` default. Resolution precedence at\n * subagent spawn: exact role \u2192 the role's phase \u2192 `*` \u2192 leader model. Set via\n * the `/setmodel` slash command; persisted to the active-profile config.\n */\n modelMatrix?: Record<string, ModelMatrixEntry>;\n /**\n * User-curated model references shown/prioritized by model commands and used\n * by smart fallback derivation. Entries are `model`, `provider/model`, or\n * `provider model`.\n */\n favoriteModels?: string[] | undefined;\n /**\n * When true, auto-derived fallback chains are restricted to `favoriteModels`.\n * Explicit fallback profiles/chains are always honored as written.\n */\n favoriteModelsOnly?: boolean | undefined;\n context: ContextConfig;\n tools: ToolsConfig;\n mcpServers?: Record<string, MCPServerConfig>;\n /**\n * Per-agent ACP invocation overrides, keyed by catalog agent id\n * (`claude-code`, `codex-cli`, `gemini-cli`, \u2026). Lets a user correct an\n * agent's ACP entry command \u2014 e.g. point `claude-code` at the right\n * adapter \u2014 without a code change. Consumed by `/acp`, `/ensemble`, and\n * `wstack acp`. SECURITY: this is an arbitrary-command exec surface, so it\n * is in the in-project config DENY list \u2014 only honoured from the user's\n * active-profile config, never from a repo-committed config.\n */\n acp?: {\n agents?: Record<string, { command: string; args?: string[]; env?: Record<string, string> }>;\n };\n /**\n * Ordered list of fallback model references tried, in order, when the\n * primary model is overloaded (HTTP 429/529/5xx) and its own retries are\n * exhausted. Each entry is a model reference: a bare model id (same\n * provider), `provider/model`, or `provider model`. After a fallback hop,\n * the primary is retried only after its cooldown expires. See\n * `createFallbackModelExtension`.\n */\n fallbackModels?: string[] | undefined;\n /**\n * Named fallback chains. A profile's first entry can be used as a primary\n * model by `/setmodel`, while the whole ordered list is used for failover.\n */\n fallbackProfiles?: Record<string, string[]> | undefined;\n /**\n * When `true` (the default) and `fallbackModels` is empty, a fallback chain\n * is derived automatically from the other keyed providers/models so 429s\n * recover out of the box. Set `false` to disable the smart default and only\n * use an explicit `fallbackModels` list. Toggle via `/fallback auto on|off`.\n */\n fallbackAuto?: boolean | undefined;\n /**\n * Lifecycle command/HTTP hooks, keyed by event. Commands receive HookInput\n * JSON on stdin; HTTP hooks receive the same object as a POST body. A typed\n * outcome can allow, deny, or mutate. `policy: true` enforcement hooks remain\n * active under `--no-hooks`; ordinary automation is disabled.\n */\n hooks?: Partial<Record<HookEvent, ConfiguredHook[]>>;\n plugins?: (string | PluginConfig)[] | undefined;\n log: LogConfig;\n features: FeaturesConfig;\n /** Project-local structured memory, graph-ready anchors, retrieval, and hygiene. */\n superMemory?: SuperMemoryConfig | undefined;\n /** Skill subsystem options (readClaudeSkills / mode / extraDirs). */\n skills?: SkillsConfig | undefined;\n yolo?: boolean | undefined;\n /** When true, show lightweight LLM-predicted next steps after each turn (/next). */\n nextPrediction?: boolean | undefined;\n cwd?: string | undefined;\n /**\n * Active profile name selected by the root bootstrap config. Settings load\n * from ~/.wrongstack/profiles/<name>/config.json. Default: 'default'.\n */\n activeProfile?: string | undefined;\n /** Autonomy mode configuration (auto-proceed delay, etc.). */\n autonomy?: AutonomyConfig | undefined;\n /** Show rotating launch hints on startup. Default: true. Set to false to suppress. */\n hints?: boolean | undefined;\n /** Raw SSE stream debugging \u2014 hex-dump every byte received from providers to stderr. */\n debugStream?: boolean | undefined;\n /**\n * Where settings are persisted. 'global' \u2192 the active profile config\n * (default). 'project' \u2192 <project>/.wrongstack/config.json.\n * When 'project', safe settings are saved per-project.\n */\n configScope?: 'global' | 'project' | undefined;\n /** Automatic codebase symbol-index maintenance (session-start + live updates). */\n indexing?: IndexingConfig | undefined;\n /**\n * Process circuit-breaker protection (gates `bash`/`exec` on repeated\n * failures). Default off \u2014 toggle with `/settings breaker on|off`.\n */\n circuitBreaker?: CircuitBreakerRuntimeConfig | undefined;\n /**\n * Adaptive concurrency controller \u2014 automatically adjusts `maxConcurrent` based on\n * rate-limit (429) errors. On 429: decreases concurrency. On sustained success:\n * gradually increases concurrency back up. Default off.\n */\n adaptiveConcurrency?: AdaptiveConcurrencyConfig | undefined;\n /** Saved launch preferences \u2014 restored on next boot for one-line confirmation. */\n launch?: LaunchConfig | undefined;\n\n /**\n * Session logging & audit configuration.\n * Controls what gets written to the persistent JSONL transcript.\n */\n session?: SessionLoggingConfig | undefined;\n /**\n * Runtime reasoning / cache controls applied to every provider request\n * (REPL/TUI/WebUI). Mapped into `Request.reasoning` and `Request.cache` by a\n * single request-pipeline middleware, gated by the active model's\n * capabilities. See `ModelRuntimeConfig`.\n */\n modelRuntime?: ModelRuntimeConfig | undefined;\n /** HQ client publishing settings, used by CLI/REPL/TUI/WebUI consistently. */\n hq?: HqClientConfig | undefined;\n /**\n * Fleet awareness + supervision settings (peer-status pulse digests,\n * status-broadcast mails, and the brain-gated FleetSupervisor). SECURITY:\n * in the in-project config DENY list \u2014 a repo-committed config must not be\n * able to enable autonomous spawning/steering or mailbox traffic. Only\n * honoured from the user's active-profile config.\n */\n fleet?: FleetConfig | undefined;\n /**\n * Brain decision-layer settings: escalation mode (headless = never block\n * on a human), LLM pool with fallback/round-robin, autonomy ceiling, and\n * the multi-LLM council. SECURITY: in the in-project config DENY list \u2014\n * a repo-committed config must not be able to raise the autonomy ceiling\n * or reroute Brain decisions. Only honoured from the active-profile config.\n */\n brain?: BrainConfig | undefined;\n /**\n * Cloud sync configuration. Stored separately in sync.json to avoid\n * accidentally committing the GitHub token to project configs.\n */\n sync?: SyncConfig | undefined;\n /**\n * Git behavior overrides for agent-run git commands.\n *\n * `identity` sets the commit author/committer used by every git process\n * WrongStack spawns (git tool, bash/exec shells, worktree manager,\n * plugins) via the `GIT_AUTHOR_*` / `GIT_COMMITTER_*` env vars. It never\n * touches the repo's or the user's `git config`, so commits made outside\n * WrongStack keep their normal identity. Unset \u2192 git's own config applies\n * (today's behavior). Manage at runtime with `/gitid`.\n *\n * SECURITY: in the in-project config DENY list \u2014 a repo-committed config\n * must not be able to spoof the identity written into the user's commit\n * history. Only honoured from the user's active-profile config.\n */\n git?: GitBehaviorConfig | undefined;\n /**\n * Per-plugin namespaced config sections. Each plugin reads its own\n * subtree via `ConfigStore.getExtension(pluginName)`. Plugins should\n * declare a `configSchema` so the loader validates this section\n * automatically before `setup()` runs.\n *\n * Example:\n * extensions: {\n * 'wstack-auth': { tokenUrl: 'https://...', refreshBefore: 300 },\n * 'wstack-metrics': { sink: 'prometheus', port: 9090 },\n * }\n */\n extensions?: Record<string, Record<string, unknown>>;\n}\n\nexport interface ConfigLoader {\n load(opts?: {\n cliFlags?: Partial<Config> | undefined;\n cwd?: string | undefined;\n }): Promise<Config>;\n /** Load and decrypt the sync config from ~/.wrongstack/sync.json. */\n loadSyncConfig(): Promise<SyncConfig | null>;\n /** Persist sync config to ~/.wrongstack/sync.json with encrypted token. */\n persistSyncConfig(cfg: SyncConfig): Promise<void>;\n}\n\n/**\n * Subscribable view over Config. Plugins and CLI subsystems use this instead\n * of holding a frozen Config reference, so they can react to runtime updates\n * (e.g. `/model` switching the active provider, secrets rotation, dynamic\n * extension reload).\n *\n * The store enforces immutability \u2014 `get()` always returns a frozen object.\n * Updates happen through `update(partial)`, which produces a new Config\n * (structurally cloned, then frozen) and notifies watchers.\n */\nexport interface ConfigStore {\n get(): Readonly<Config>;\n /**\n * Get a typed top-level section. Convenience for consumers that only\n * care about one slice (e.g. `tools` or `context`).\n */\n getSection<K extends keyof Config>(key: K): Readonly<Config[K]>;\n /**\n * Return the extension namespace for `pluginName`, or an empty record\n * when none is configured. The returned object is frozen.\n */\n getExtension(pluginName: string): Readonly<Record<string, unknown>>;\n /**\n * Apply a partial update. Returns the new Config. Watchers are notified\n * synchronously after the update completes. Throws if the result fails\n * any registered invariants (currently: version must stay 1).\n */\n update(partial: Partial<Config>): Readonly<Config>;\n /** Subscribe to changes. Returns an unsubscribe function. */\n watch(cb: (next: Readonly<Config>, prev: Readonly<Config>) => void): () => void;\n}\n", "import type { TextBlock } from './blocks.js';\nimport type { Tool } from './tool.js';\nimport type { MailboxAgentStatus } from '../coordination/mailbox-types.js';\n\n/** Model capabilities relevant to prompt composition. */\nexport interface ModelCapabilities {\n maxContextTokens: number;\n supportsTools: boolean;\n supportsVision: boolean;\n supportsReasoning: boolean;\n}\n\nexport interface BuildContext {\n cwd: string;\n projectRoot: string;\n tools: Tool[];\n /** Provider id (e.g. \"anthropic\", \"minimax-coding-plan\"). */\n provider?: string | undefined;\n /** Model id (e.g. \"configured-model\", \"MiniMax-M2.7\"). */\n model?: string | undefined;\n /**\n * True when the prompt is being built for a SUBAGENT, not the host\n * agent. Subagents are scoped to a single task \u2014 they should NOT see\n * the host's strategic plan board (which is anchoring the host across\n * turns, not steering individual subtasks). The plan-injection\n * layer short-circuits when this flag is set.\n */\n subagent?: boolean | undefined;\n /**\n * List of currently online agents in the shared mailbox system.\n * Includes agents from all clients, processes, sessions, branches, and\n * linked Git worktrees in the same canonical project.\n */\n onlineAgents?: MailboxAgentStatus[] | undefined;\n}\n\n/**\n * Stability regions for the system prompt.\n *\n * `core` and `session` form the provider-cache prefix and must remain byte-for-byte\n * stable after the first request in a session. `volatile` is appended at request\n * time and may change between turns without rewriting that prefix.\n */\nexport interface SystemPromptRegions {\n readonly core: readonly TextBlock[];\n readonly session: readonly TextBlock[];\n readonly volatile: readonly TextBlock[];\n}\n\nexport function flattenSystemPromptRegions(regions: SystemPromptRegions): TextBlock[] {\n return [...regions.core, ...regions.session, ...regions.volatile];\n}\n\nexport interface SystemPromptBuilder {\n build(ctx: BuildContext): Promise<TextBlock[]>;\n /** Region-aware build used by hosts that enforce prompt-prefix stability. */\n buildRegions?(ctx: BuildContext): Promise<SystemPromptRegions>;\n}\n", "/**\n * Compile a user-supplied regex with conservative bounds against ReDoS.\n *\n * Duplicated from @wrongstack/tools/_regex.ts to avoid a circular\n * dependency (tools depends on core, not vice versa). Keep both copies\n * in sync if the heuristics change.\n *\n * V8's regex engine is backtracking-based and cannot interrupt a\n * synchronous match \u2014 a pattern like `(a+)+$` against a sufficiently\n * long line will pin a worker for seconds.\n */\n\nconst MAX_PATTERN_LEN = 512;\n\n// Heuristics for catastrophic-backtracking constructs.\nconst DANGEROUS_PATTERNS: ReadonlyArray<RegExp> = [\n /(\\([^)]*[+*][^)]*\\))[+*]/, // (a+)+, (.*)+, etc\n /(\\(\\?:[^)]*[+*][^)]*\\))[+*]/, // same, with non-capturing group\n];\n\nexport interface CompileResult {\n ok: true;\n regex: RegExp;\n}\n\nexport interface CompileFail {\n ok: false;\n reason: string;\n}\n\nexport function compileUserRegex(pattern: string, flags: string): CompileResult | CompileFail {\n if (typeof pattern !== 'string') {\n return { ok: false, reason: 'pattern must be a string' };\n }\n if (pattern.length === 0) {\n return { ok: false, reason: 'pattern is empty' };\n }\n if (pattern.length > MAX_PATTERN_LEN) {\n return { ok: false, reason: `pattern exceeds ${MAX_PATTERN_LEN} characters` };\n }\n for (const rx of DANGEROUS_PATTERNS) {\n if (rx.test(pattern)) {\n return {\n ok: false,\n reason:\n 'pattern looks vulnerable to catastrophic backtracking \u2014 rewrite without nested quantifiers',\n };\n }\n }\n try {\n return { ok: true, regex: new RegExp(pattern, flags) };\n } catch (err) {\n return {\n ok: false,\n reason: err instanceof Error ? err.message : 'invalid regex',\n };\n }\n}\n", "import * as path from 'node:path';\nimport { ERROR_CODES, FsError } from '../types/errors.js';\n\n/**\n * Resolve `<dir>/<sessionId><suffix>` for per-session sidecar files\n * (annotations, audit chain, replay log, the session JSONL itself).\n *\n * Modern session ids are date-sharded (\"2026-06-11/sess_<ULID>\"),\n * so a forward slash is a legitimate shard separator \u2014 NOT traversal.\n * Escape attempts are blocked two ways: an explicit ban on `..` and\n * backslashes, plus a resolved-path containment check that rejects any\n * id whose resolved target leaves `dir`. Character bans alone are how\n * several stores ended up throwing on every modern session id.\n */\nexport function sessionScopedPath(dir: string, sessionId: string, suffix: string): string {\n if (!sessionId || sessionId.includes('\\\\') || sessionId.includes('..')) {\n throw invalid(sessionId);\n }\n const resolved = path.resolve(dir, `${sessionId}${suffix}`);\n const rel = path.relative(path.resolve(dir), resolved);\n if (rel.startsWith('..') || path.isAbsolute(rel)) {\n throw invalid(sessionId);\n }\n return resolved;\n}\n\nfunction invalid(sessionId: string): FsError {\n return new FsError({\n message: `Invalid sessionId: ${sessionId}`,\n code: ERROR_CODES.FS_DELETE_FAILED,\n path: sessionId,\n context: { reason: 'path_traversal' },\n });\n}\n", "import { toErrorMessage } from '../utils/index.js';\n\n/**\n * WrongStack error hierarchy.\n *\n * Every error thrown by the framework is a `WrongStackError` with a\n * machine-readable `code`, a `subsystem` tag, and a `severity` level.\n * This lets consumers (CLI, TUI, plugins, tests) branch on structured\n * data instead of parsing error messages.\n */\n\n// \u2500\u2500 Error codes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Machine-readable error codes as frozen constants.\n *\n * Use `ERROR_CODES.X` instead of raw string literals for:\n * - IDE autocomplete and compile-time validation\n * - Safe refactoring (rename updates all usages)\n * - Plugin extensibility (extend the object to add custom codes)\n *\n * The `ErrorCode` type is derived from this object, so adding a new\n * code here automatically updates the type without extra changes.\n */\nexport const ERROR_CODES = {\n // Provider\n PROVIDER_RATE_LIMITED: 'PROVIDER_RATE_LIMITED',\n PROVIDER_AUTH_FAILED: 'PROVIDER_AUTH_FAILED',\n PROVIDER_OVERLOADED: 'PROVIDER_OVERLOADED',\n PROVIDER_INVALID_REQUEST: 'PROVIDER_INVALID_REQUEST',\n PROVIDER_SERVER_ERROR: 'PROVIDER_SERVER_ERROR',\n PROVIDER_NETWORK_ERROR: 'PROVIDER_NETWORK_ERROR',\n PROVIDER_CONTEXT_OVERFLOW: 'PROVIDER_CONTEXT_OVERFLOW',\n // Tool\n TOOL_NOT_FOUND: 'TOOL_NOT_FOUND',\n TOOL_PERMISSION_DENIED: 'TOOL_PERMISSION_DENIED',\n TOOL_EXECUTION_FAILED: 'TOOL_EXECUTION_FAILED',\n TOOL_TIMEOUT: 'TOOL_TIMEOUT',\n TOOL_INPUT_INVALID: 'TOOL_INPUT_INVALID',\n // Config\n CONFIG_INVALID: 'CONFIG_INVALID',\n CONFIG_NOT_FOUND: 'CONFIG_NOT_FOUND',\n CONFIG_PARSE_FAILED: 'CONFIG_PARSE_FAILED',\n CONFIG_MIGRATION_NEEDED: 'CONFIG_MIGRATION_NEEDED',\n // Plugin\n PLUGIN_LOAD_FAILED: 'PLUGIN_LOAD_FAILED',\n PLUGIN_API_MISMATCH: 'PLUGIN_API_MISMATCH',\n PLUGIN_MISSING_DEPENDENCY: 'PLUGIN_MISSING_DEPENDENCY',\n // Agent\n AGENT_ITERATION_LIMIT: 'AGENT_ITERATION_LIMIT',\n AGENT_CONTEXT_OVERFLOW: 'AGENT_CONTEXT_OVERFLOW',\n AGENT_ABORTED: 'AGENT_ABORTED',\n AGENT_RUN_FAILED: 'AGENT_RUN_FAILED',\n // Session\n SESSION_NOT_FOUND: 'SESSION_NOT_FOUND',\n SESSION_CORRUPTED: 'SESSION_CORRUPTED',\n SESSION_WRITE_FAILED: 'SESSION_WRITE_FAILED',\n // Container / Registry\n CONTAINER_TOKEN_ALREADY_BOUND: 'CONTAINER_TOKEN_ALREADY_BOUND',\n CONTAINER_TOKEN_NOT_BOUND: 'CONTAINER_TOKEN_NOT_BOUND',\n CONTAINER_CIRCULAR_DEPENDENCY: 'CONTAINER_CIRCULAR_DEPENDENCY',\n REGISTRY_DUPLICATE: 'REGISTRY_DUPLICATE',\n REGISTRY_NOT_FOUND: 'REGISTRY_NOT_FOUND',\n REGISTRY_INVALID: 'REGISTRY_INVALID',\n // File system\n FS_READ_FAILED: 'FS_READ_FAILED',\n FS_WRITE_FAILED: 'FS_WRITE_FAILED',\n FS_MKDIR_FAILED: 'FS_MKDIR_FAILED',\n FS_DELETE_FAILED: 'FS_DELETE_FAILED',\n FS_ATOMIC_WRITE_FAILED: 'FS_ATOMIC_WRITE_FAILED',\n // SDD (Spec-Driven Development)\n SDD_VALIDATION_FAILED: 'SDD_VALIDATION_FAILED',\n SDD_PARSE_FAILED: 'SDD_PARSE_FAILED',\n SDD_INVALID_STATE: 'SDD_INVALID_STATE',\n SDD_NOT_READY: 'SDD_NOT_READY',\n // General\n VALIDATION_ERROR: 'VALIDATION_ERROR',\n PARSE_FAILED: 'PARSE_FAILED',\n UNKNOWN: 'UNKNOWN',\n} as const;\n\n/**\n * Union type derived from `ERROR_CODES`. Using `typeof ERROR_CODES[keyof typeof ERROR_CODES]`\n * instead of a string literal union means TypeScript auto-updates the type whenever\n * a new code is added to `ERROR_CODES` \u2014 no need to keep two lists in sync.\n */\nexport type ErrorCode = (typeof ERROR_CODES)[keyof typeof ERROR_CODES];\n\nexport type ErrorSubsystem =\n | 'provider'\n | 'tool'\n | 'config'\n | 'plugin'\n | 'agent'\n | 'session'\n | 'sdd'\n | 'container'\n | 'fs'\n | 'general';\nexport type ErrorSeverity = 'fatal' | 'error' | 'warning';\n\n// \u2500\u2500 Base error class \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class WrongStackError extends Error {\n readonly code: ErrorCode;\n readonly subsystem: ErrorSubsystem;\n readonly severity: ErrorSeverity;\n readonly recoverable: boolean;\n readonly context?: Record<string, unknown> | undefined;\n\n constructor(opts: {\n message: string;\n code: ErrorCode;\n subsystem: ErrorSubsystem;\n severity?: ErrorSeverity | undefined;\n recoverable?: boolean | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super(opts.message, { cause: opts.cause });\n this.name = 'WrongStackError';\n this.code = opts.code;\n this.subsystem = opts.subsystem;\n this.severity = opts.severity ?? 'error';\n this.recoverable = opts.recoverable ?? false;\n this.context = opts.context;\n }\n\n /**\n * Render a one-line user-facing description.\n * Subclasses should override for domain-specific formatting.\n */\n describe(): string {\n const ctx = this.context ? ` ${formatContext(this.context)}` : '';\n return `${this.code}: ${this.message}${ctx}`;\n }\n}\n\nfunction formatContext(ctx: Record<string, unknown>): string {\n const parts = Object.entries(ctx)\n .filter(([, v]) => v !== undefined)\n .slice(0, 3)\n .map(([k, v]) => `${k}=${String(v)}`);\n return parts.length > 0 ? `[${parts.join(' ')}]` : '';\n}\n\n// \u2500\u2500 Specific error classes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Tool execution errors \u2014 thrown by ToolExecutor and individual tools.\n */\nexport class ToolError extends WrongStackError {\n readonly toolName: string;\n\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n | 'TOOL_NOT_FOUND'\n | 'TOOL_PERMISSION_DENIED'\n | 'TOOL_EXECUTION_FAILED'\n | 'TOOL_TIMEOUT'\n | 'TOOL_INPUT_INVALID'\n >;\n toolName: string;\n recoverable?: boolean | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'tool',\n recoverable: opts.recoverable,\n context: { tool: opts.toolName, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'ToolError';\n this.toolName = opts.toolName;\n }\n}\n\n/**\n * Config loading / validation errors.\n */\nexport class ConfigError extends WrongStackError {\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'CONFIG_INVALID' | 'CONFIG_NOT_FOUND' | 'CONFIG_PARSE_FAILED' | 'CONFIG_MIGRATION_NEEDED'\n >;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'config',\n severity: 'fatal',\n recoverable: false,\n context: opts.context,\n cause: opts.cause,\n });\n this.name = 'ConfigError';\n }\n}\n\n/**\n * Plugin loading / lifecycle errors.\n */\nexport class PluginError extends WrongStackError {\n readonly pluginName: string;\n\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'PLUGIN_LOAD_FAILED' | 'PLUGIN_API_MISMATCH' | 'PLUGIN_MISSING_DEPENDENCY'\n >;\n pluginName: string;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'plugin',\n severity: 'error',\n recoverable: opts.code === ERROR_CODES.PLUGIN_MISSING_DEPENDENCY,\n context: { plugin: opts.pluginName, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'PluginError';\n this.pluginName = opts.pluginName;\n }\n}\n\n/**\n * Agent runtime errors \u2014 thrown by Agent.run when a non-WrongStackError\n * escapes the inner loop, so callers always see a structured error.\n */\nexport class AgentError extends WrongStackError {\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'AGENT_ITERATION_LIMIT' | 'AGENT_CONTEXT_OVERFLOW' | 'AGENT_ABORTED' | 'AGENT_RUN_FAILED'\n >;\n recoverable?: boolean | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'agent',\n severity: opts.code === ERROR_CODES.AGENT_ABORTED ? 'warning' : 'error',\n recoverable: opts.recoverable ?? opts.code === ERROR_CODES.AGENT_ITERATION_LIMIT,\n context: opts.context,\n cause: opts.cause,\n });\n this.name = 'AgentError';\n }\n}\n\n/**\n * Wrap an arbitrary thrown value into a `WrongStackError` so the caller\n * always gets a structured error. Pass-throughs WrongStackError instances\n * unchanged; raw `Error`s and primitives get an `AGENT_RUN_FAILED` wrapper\n * with the original preserved as `cause`.\n */\nexport function toWrongStackError(\n err: unknown,\n code: Extract<ErrorCode, 'AGENT_RUN_FAILED' | 'AGENT_ABORTED' | 'UNKNOWN'> = ERROR_CODES.AGENT_RUN_FAILED,\n): WrongStackError {\n if (err instanceof WrongStackError) return err;\n const message = toErrorMessage(err);\n return new AgentError({\n message,\n code: code === 'UNKNOWN' ? ERROR_CODES.AGENT_RUN_FAILED : code,\n cause: err,\n });\n}\n\n/**\n * Session storage errors.\n */\nexport class SessionError extends WrongStackError {\n readonly sessionId?: string | undefined;\n\n constructor(opts: {\n message: string;\n code: Extract<ErrorCode, 'SESSION_NOT_FOUND' | 'SESSION_CORRUPTED' | 'SESSION_WRITE_FAILED'>;\n sessionId?: string | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'session',\n severity: opts.code === ERROR_CODES.SESSION_WRITE_FAILED ? 'error' : 'warning',\n recoverable: opts.code !== ERROR_CODES.SESSION_CORRUPTED,\n context: { sessionId: opts.sessionId, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'SessionError';\n this.sessionId = opts.sessionId;\n }\n}\n\n/**\n * SDD (Spec-Driven Development) errors \u2014 spec validation, parsing, and\n * state machine violations in the AISpecBuilder, TaskFlow, and TaskTracker.\n */\nexport class SddError extends WrongStackError {\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'SDD_VALIDATION_FAILED' | 'SDD_PARSE_FAILED' | 'SDD_INVALID_STATE' | 'SDD_NOT_READY'\n >;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'sdd',\n severity: opts.code === ERROR_CODES.SDD_PARSE_FAILED ? 'warning' : 'error',\n recoverable: opts.code === ERROR_CODES.SDD_NOT_READY,\n context: opts.context,\n cause: opts.cause,\n });\n this.name = 'SddError';\n }\n}\n\n/**\n * File system operation errors.\n */\nexport class FsError extends WrongStackError {\n readonly path?: string | undefined;\n\n constructor(opts: {\n message: string;\n code: Extract<\n ErrorCode,\n 'FS_READ_FAILED' | 'FS_WRITE_FAILED' | 'FS_MKDIR_FAILED' | 'FS_DELETE_FAILED' | 'FS_ATOMIC_WRITE_FAILED'\n >;\n path?: string | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: opts.code,\n subsystem: 'fs',\n severity: 'error',\n recoverable: opts.code !== ERROR_CODES.FS_READ_FAILED,\n context: { path: opts.path, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'FsError';\n this.path = opts.path;\n }\n}\n\n/**\n * HTTP fetch error \u2014 thrown when a network request returns a non-OK status.\n * Carries the response status so {@link classifyToolError} can branch on it\n * (429 \u2192 transient, 404 \u2192 not_found, 401 \u2192 permission) without duck-typing\n * the error via `'response' in err`.\n *\n * P3 #18 (before-release.md): the previous `'response' in err` check caught\n * any Error with a `response` property, including custom errors, proxy\n * objects, or mocked errors in tests. `instanceof FetchError` is reliable.\n *\n * Tools and providers that make HTTP requests and need the executor to\n * classify their failures should throw `new FetchError({ status, message })`\n * instead of a bare `Error` with an ad-hoc `response` field.\n */\nexport class FetchError extends WrongStackError {\n readonly status: number;\n\n constructor(opts: {\n message: string;\n status: number;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: ERROR_CODES.VALIDATION_ERROR,\n subsystem: 'general',\n severity: 'error',\n recoverable: opts.status === 429 || opts.status >= 500,\n context: { status: opts.status, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'FetchError';\n this.status = opts.status;\n }\n}\n\n/**\n * Tool input validation error \u2014 thrown when a tool's input fails a validation\n * check that the JSON Schema cannot express (e.g. `old_string === new_string`\n * in edit, or a cross-field invariant). Use this instead of a bare\n * `throw new Error('...validation...')` so {@link classifyToolError} can\n * match on `instanceof` rather than a locale-dependent message substring.\n *\n * P2 #6 (before-release.md): the previous `err.message.includes('validation')`\n * check misclassified any error whose message happened to contain \"validation\"\n * (e.g. a third-party \"input validation timeout\") as a VALIDATION error.\n *\n * Named `ToolValidationError` (not `ValidationError`) to avoid colliding with\n * the existing `ValidationError` interface exported by json-schema-validate.ts\n * (a validation-result shape, not an Error subclass).\n */\nexport class ToolValidationError extends WrongStackError {\n constructor(opts: {\n message: string;\n /** Field path or tool name that failed validation, for diagnostics. */\n field?: string | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: ERROR_CODES.VALIDATION_ERROR,\n subsystem: 'general',\n severity: 'error',\n recoverable: false,\n context: { field: opts.field, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'ToolValidationError';\n }\n}\n\n/**\n * Response / payload parse error \u2014 thrown when an upstream HTTP response,\n * file, or data structure is well-formed at the transport layer (HTTP 200,\n * valid JSON) but is missing required fields or has an unexpected shape.\n *\n * Distinct from `ConfigError(CONFIG_PARSE_FAILED)` (which is specifically\n * for config-file parsing) and `FetchError` (which covers HTTP non-OK\n * responses). `ParseError` fills the gap: the request succeeded but the\n * response body couldn't be interpreted.\n *\n * Common sites: OAuth token responses missing `access_token`, device-code\n * responses missing `device_code`, registry responses with unexpected\n * schemas.\n */\nexport class ParseError extends WrongStackError {\n readonly source?: string | undefined;\n\n constructor(opts: {\n message: string;\n /**\n * What was being parsed \u2014 e.g. `'oauth-token-response'`,\n * `'device-code-response'`. Lets consumers distinguish parse failures\n * from different upstream APIs without parsing the message.\n */\n source?: string | undefined;\n context?: Record<string, unknown> | undefined;\n cause?: unknown | undefined;\n }) {\n super({\n message: opts.message,\n code: ERROR_CODES.PARSE_FAILED,\n subsystem: 'general',\n severity: 'error',\n recoverable: false,\n context: { source: opts.source, ...opts.context },\n cause: opts.cause,\n });\n this.name = 'ParseError';\n this.source = opts.source;\n }\n}\n\n// \u2500\u2500 Type guards \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function isWrongStackError(err: unknown): err is WrongStackError {\n return err instanceof WrongStackError;\n}\n\nexport function isToolError(err: unknown): err is ToolError {\n return err instanceof ToolError;\n}\n\nexport function isConfigError(err: unknown): err is ConfigError {\n return err instanceof ConfigError;\n}\n\nexport function isPluginError(err: unknown): err is PluginError {\n return err instanceof PluginError;\n}\n\nexport function isSessionError(err: unknown): err is SessionError {\n return err instanceof SessionError;\n}\n\nexport function isAgentError(err: unknown): err is AgentError {\n return err instanceof AgentError;\n}\n\nexport function isFsError(err: unknown): err is FsError {\n return err instanceof FsError;\n}\n\nexport function isToolValidationError(err: unknown): err is ToolValidationError {\n return err instanceof ToolValidationError;\n}\n\nexport function isFetchError(err: unknown): err is FetchError {\n return err instanceof FetchError;\n}\n\nexport function isParseError(err: unknown): err is ParseError {\n return err instanceof ParseError;\n}\n\nexport function isSddError(err: unknown): err is SddError {\n return err instanceof SddError;\n}\n", "import { truncate } from '../utils/string.js';\nimport type { ContentBlock, TextBlock } from './blocks.js';\nimport type { ErrorCode } from './errors.js';\nimport { ERROR_CODES, WrongStackError } from './errors.js';\nimport type { Message } from './messages.js';\nimport type { Tool } from './tool.js';\n\n/**\n * Token usage for a single provider call, normalized across providers.\n *\n * Disjoint semantics: the four fields never overlap. `input` is the count\n * of FRESH input tokens (billed at the full input rate); `cacheRead` and\n * `cacheWrite` are separate cached subsets each priced at their own rate.\n * The total context the model loaded for this turn is\n * `input + (cacheRead ?? 0) + (cacheWrite ?? 0)`.\n *\n * Provider quirks normalized at the adapter layer:\n * - Anthropic: returns `input_tokens` already disjoint from cache fields.\n * - OpenAI / OpenAI-compatible: `prompt_tokens` is the TOTAL including\n * cached portion; the adapter subtracts `cached_tokens` to stay disjoint.\n * - Google: `promptTokenCount` likewise includes cache; adapter subtracts\n * `cachedContentTokenCount`.\n *\n * Cost math and the context-fullness chip both depend on the disjoint\n * invariant \u2014 a TOTAL `input` plus a separate `cacheRead` count would bill\n * cached tokens twice and skew cache-hit-ratio reporting.\n */\nexport type ReasoningEffort = 'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max';\nexport type CacheTtl = '5m' | '1h';\n\n/**\n * Provider-agnostic response-format directive.\n *\n * - `{ type: 'text' }` \u2014 free-form text (default).\n * - `{ type: 'json_object' }` \u2014 valid JSON without a schema constraint.\n * - `{ type: 'json_schema', jsonSchema: { name, schema, strict? } }` \u2014 JSON\n * constrained to the supplied JSON Schema. The `strict` flag is\n * OpenAI-specific; Gemini ignores it in favour of `responseMimeType`.\n *\n * Each provider adapter maps this into its own wire format:\n * OpenAI \u2192 `response_format`\n * Gemini \u2192 `responseMimeType` + `responseSchema`\n * Anthropic \u2192 (not yet supported; uses tools for structured output)\n */\nexport interface JsonSchemaSpec {\n name: string;\n /** OpenAI-specific: enable strict schema adherence. */\n strict?: boolean | undefined;\n /** The JSON Schema object describing the expected shape. */\n schema: Record<string, unknown>;\n /** Optional human-readable description (OpenAI). */\n description?: string | undefined;\n}\n\nexport type ResponseFormat =\n | { type: 'text' }\n | { type: 'json_object' }\n | { type: 'json_schema'; jsonSchema: JsonSchemaSpec };\n\n/**\n * Safety category threshold pair used by Google Gemini's `safetySettings`.\n *\n * Categories: `HARM_CATEGORY_HARASSMENT`, `HARM_CATEGORY_HATE_SPEECH`,\n * `HARM_CATEGORY_SEXUALLY_EXPLICIT`, `HARM_CATEGORY_DANGEROUS_CONTENT`.\n *\n * Thresholds: `BLOCK_NONE`, `BLOCK_ONLY_HIGH`, `BLOCK_MEDIUM_AND_ABOVE`,\n * `BLOCK_LOW_AND_ABOVE`.\n */\nexport interface SafetySetting {\n category: string;\n threshold: string;\n}\n\nexport interface Usage {\n input: number;\n output: number;\n cacheRead?: number | undefined;\n /** Back-compat aggregate of all cache-write tokens. Prefer TTL-specific fields when present. */\n cacheWrite?: number | undefined;\n cacheWrite5m?: number | undefined;\n cacheWrite1h?: number | undefined;\n}\n\n/**\n * Effective prompt tokens loaded by the model for one request.\n *\n * Provider adapters normalize `Usage` to disjoint fields: `input` is fresh\n * full-rate tokens, `cacheRead` is cached prefix tokens, and `cacheWrite` is\n * the cache-written prefix segment. Context-window pressure cares about the\n * full prompt the model saw, not only the bill-at-full-rate slice.\n */\nexport function effectiveInputTokens(usage: Usage): number {\n return usage.input + (usage.cacheRead ?? 0) + (usage.cacheWrite ?? 0);\n}\n\nexport interface ReasoningRequest {\n enabled?: boolean | undefined;\n effort?: ReasoningEffort | undefined;\n preserve?: boolean | undefined;\n display?: 'summarized' | 'omitted' | undefined;\n}\n\nexport interface RequestCacheControl {\n ttl?: CacheTtl | undefined;\n /**\n * Provider-agnostic cache-partition key. A stable hash of the cacheable\n * system-prompt prefix (see `deriveCachePrefixKey`); requests sharing a prefix\n * share a key so provider backends route them to the same automatic-cache\n * partition. Consumed by OpenAI-family wires as `prompt_cache_key`; ignored by\n * Anthropic (which uses `ttl` + explicit `cache_control` markers).\n */\n key?: string | undefined;\n /**\n * Opt-in flag (from `ModelRuntimeCacheConfig.geminiExplicit`) telling the\n * Google provider to use explicit `cachedContents` for this request. Ignored\n * by other providers.\n */\n geminiExplicit?: boolean | undefined;\n /**\n * Resolved Gemini `cachedContents/*` resource name, injected by\n * `GoogleProvider.stream()` after it creates/reuses the cache. When present,\n * the Google wire sends `cachedContent` and OMITS the (now-cached) system\n * instruction + tool defs from the live body. Internal \u2014 never set by callers.\n */\n geminiCachedContentName?: string | undefined;\n}\n\nexport interface ReasoningConfig {\n default: 'enabled' | 'disabled' | 'adaptive' | 'always_on';\n disableSupported: boolean;\n effortSupported: boolean;\n effortLevels: ReasoningEffort[];\n preserveThinking: 'unsupported' | 'optional' | 'always_on';\n}\n\nexport interface Capabilities {\n tools: boolean;\n parallelTools: boolean;\n vision: boolean;\n streaming: boolean;\n promptCache: boolean;\n systemPrompt: boolean;\n jsonMode: boolean;\n reasoning: boolean;\n maxContext: number;\n /**\n * Maximum output tokens the model can produce in a single response.\n * Used as the default for `Request.maxTokens` when the caller doesn't\n * supply an explicit value \u2014 letting subagents run up to the model's\n * native ceiling instead of a fixed 8192 cap. Omit (undefined) to fall\n * back to a conservative default; populate per family in\n * `family-capabilities.ts` once you know the spec.\n */\n maxOutput?: number | undefined;\n cacheControl: 'native' | 'auto' | 'none';\n\n // \u2500\u2500 Extended parameter support (optional; family defaults in CAPABILITIES_BY_FAMILY) \u2500\u2500\n\n /** Model accepts `top_k` / `topK` sampling parameter. */\n topK?: boolean | undefined;\n /** Model accepts `frequency_penalty` / `frequencyPenalty` parameter. */\n frequencyPenalty?: boolean | undefined;\n /** Model accepts `presence_penalty` / `presencePenalty` parameter. */\n presencePenalty?: boolean | undefined;\n /** Model accepts `seed` parameter for deterministic generation. */\n seed?: boolean | undefined;\n /**\n * Model accepts JSON Schema / structured-output constraints\n * (OpenAI `response_format.json_schema`, Gemini `responseMimeType`+`responseSchema`).\n * Distinct from `jsonMode` (which is just a system-prompt hint).\n */\n structuredOutput?: boolean | undefined;\n /** Model supports log-probability output (`logprobs`, `top_logprobs`). */\n logprobs?: boolean | undefined;\n /** Model supports audio input/output modality. */\n audio?: boolean | undefined;\n /** Model supports the `n` parameter for multiple completions. */\n multipleCompletions?: boolean | undefined;\n}\n\nexport interface Request {\n model: string;\n system?: TextBlock[] | undefined;\n messages: Message[];\n tools?: Tool[] | undefined;\n /**\n * Cap on output tokens for this single response. Optional \u2014 when\n * omitted, the provider adapter falls back to its own\n * `capabilities.maxOutput` (which the catalog populates from\n * `ModelsDevModel.limit.output`). If neither is available, the\n * adapter applies a conservative 8192 safety net. Letting this stay\n * undefined at the call site means callers like Chimera can hand the\n * model its native output ceiling without hard-coding a number.\n */\n maxTokens?: number | undefined;\n temperature?: number | undefined;\n topP?: number | undefined;\n topK?: number | undefined;\n frequencyPenalty?: number | undefined;\n presencePenalty?: number | undefined;\n seed?: number | undefined;\n /**\n * End-user identifier for abuse monitoring and per-user rate limiting.\n * - Anthropic \u2192 `metadata.user_id`\n * - OpenAI \u2192 `user`\n * - Gemini \u2192 (not supported)\n */\n user?: string | undefined;\n /**\n * Number of response candidates to generate. Google Gemini supports\n * this via `generationConfig.candidateCount`. OpenAI does not have\n * an equivalent (`n` is conceptually similar but distinct).\n */\n candidateCount?: number | undefined;\n /**\n * Whether to return log probabilities for output tokens.\n * - OpenAI \u2192 `logprobs: boolean` (+ `topLogprobs: number`)\n * - Gemini \u2192 `generationConfig.logprobs: number` (how many top candidates)\n * Default undefined = no logprobs requested.\n */\n logprobs?: boolean | undefined;\n /**\n * Number of most probable tokens to return log probabilities for\n * (OpenAI `top_logprobs`). Only meaningful when `logprobs` is true.\n * Range: 0-20. Gemini ignores this (uses `logprobs` as the count).\n */\n topLogprobs?: number | undefined;\n stopSequences?: string[] | undefined;\n toolChoice?: 'auto' | 'required' | 'none' | { type: 'tool' | undefined; name: string };\n reasoning?: ReasoningRequest | undefined;\n cache?: RequestCacheControl | undefined;\n /**\n * Structured-output / response-format directive.\n * When set, the provider adapter maps this to its native response-format\n * parameter (OpenAI `response_format`, Gemini `responseMimeType`, etc.).\n * The model must advertise `capabilities.structuredOutput` for this to be\n * honoured; unsupported models will likely 400 or ignore it.\n */\n responseFormat?: ResponseFormat | undefined;\n /**\n * Safety category thresholds for filtering harmful content.\n * - Gemini \u2192 top-level `safetySettings` array with `{ category, threshold }`\n * - OpenAI \u2192 not supported (uses server-side moderation)\n * - Anthropic \u2192 not supported\n */\n safetySettings?: SafetySetting[] | undefined;\n}\n\nexport type StopReason = 'end_turn' | 'tool_use' | 'max_tokens' | 'stop_sequence' | 'refusal';\n\nexport interface Response {\n content: ContentBlock[];\n stopReason: StopReason;\n usage: Usage;\n model: string;\n}\n\nexport type StreamEvent =\n | { type: 'message_start'; model: string }\n | {\n type: 'content_block_start';\n kind: 'text' | 'tool_use' | 'thinking';\n id?: string | undefined;\n name?: string | undefined;\n }\n | { type: 'content_block_stop'; index: number }\n | { type: 'text_delta'; text: string }\n | { type: 'tool_use_start'; id: string; name: string }\n | { type: 'tool_use_input_delta'; id: string; partial: string }\n | { type: 'tool_use_stop'; id: string; input: unknown; providerMeta?: Record<string, unknown> }\n | { type: 'thinking_start'; providerMeta?: Record<string, unknown> }\n | { type: 'thinking_delta'; text: string }\n | { type: 'thinking_signature'; signature: string }\n | { type: 'thinking_stop' }\n | { type: 'message_stop'; stopReason: StopReason; usage: Usage };\n\nexport interface Provider {\n readonly id: string;\n readonly capabilities: Capabilities;\n /** Canonical streaming entry point. `complete()` defaults to a wrapper that\n * aggregates this stream \u2014 providers may override for non-streaming wires. */\n stream(req: Request, opts: { signal: AbortSignal }): AsyncIterable<StreamEvent>;\n complete(req: Request, opts: { signal: AbortSignal }): Promise<Response>;\n}\n\n/**\n * Structured body parsed from a provider's HTTP error response. Populated\n * best-effort: providers return JSON shaped differently (Anthropic uses\n * `{error: {type, message}}`, OpenAI uses `{error: {message, code}}`,\n * Google uses `{error: {status, message}}`), so the fields here are the\n * intersection that's usable for rendering and routing.\n */\nexport interface ProviderErrorBody {\n /** Provider-specific kind, e.g. \"overloaded_error\", \"rate_limit_error\", \"invalid_request_error\". */\n type?: string | undefined;\n /** Human-readable explanation from the provider. */\n message?: string | undefined;\n /** Provider request id, when present in the body or headers. */\n requestId?: string | undefined;\n /** Parsed Retry-After header (or equivalent body hint) in milliseconds. */\n retryAfterMs?: number | undefined;\n /** The raw response body (truncated to ~2 KB), kept for debugging. */\n raw?: string | undefined;\n /** True when `raw` was truncated; check `rawLength` for the original size. */\n truncated?: boolean | undefined;\n /** Original length of the response body in bytes, when `truncated` is true. */\n rawLength?: number | undefined;\n}\n\n/**\n * Canonical provider-failure taxonomy. Computed ONCE at error-construction\n * time (`classifyProviderError`) and carried on `ProviderError.kind` so\n * every downstream consumer \u2014 retry policy, cross-provider fallback,\n * recovery strategies, the subagent error classifier \u2014 branches on the\n * same classification instead of re-deriving it from status codes and\n * message regexes. When a new provider's error format needs special\n * handling, this module is the only place to teach it.\n */\nexport type ProviderErrorKind =\n | 'rate_limit' // 429 / rate_limit_error \u2014 back off (honour Retry-After), then failover\n | 'quota_exhausted' // credits/plan depleted \u2014 do not retry same route; fail over immediately\n | 'overloaded' // 529 / overloaded_error \u2014 retry with backoff, then failover\n | 'server' // other 5xx \u2014 retry same provider\n | 'timeout' // 408 request timeout\n | 'network' // status 0 \u2014 connection/DNS failure before a response arrived\n | 'stream_hang' // 599 sentinel \u2014 stream stalled mid-response (StreamHangError)\n | 'auth' // 401/403 \u2014 key invalid/expired; retrying without action is pointless\n | 'context_overflow' // 413 or an overflow-shaped 4xx \u2014 compact, don't retry as-is\n | 'content_filter' // provider refused on policy grounds \u2014 a sibling model may pass, but the `content_filter_reroute` recovery strategy owns that hop, NOT the fallback engine (which surfaces this kind)\n | 'invalid_request' // other 4xx \u2014 request is malformed; retrying won't help\n | 'unknown';\n\n/**\n * Overflow-shaped provider messages. Union of the patterns previously\n * scattered across `error-handler.ts` and `coordinator/error-classifier.ts`\n * (which had drifted apart) \u2014 keep additions here, nowhere else.\n */\nconst CONTEXT_OVERFLOW_RE =\n /context.length|context.window|maximum context|max.*tokens?.*exceeded|prompt is too long|too long|exceeds the context|\\btokens\\b.*exceed|too many tokens|reduce the length|resulted in \\d+ tokens|input.{0,12}too (?:large|long)|context_length_exceeded/i;\n\n/** Content-policy refusals surfaced as HTTP errors (Azure/OpenAI `content_filter`, etc.). */\nconst CONTENT_FILTER_RE = /content.(filter|policy|moderation)|safety (system|filter)/i;\nconst QUOTA_EXHAUSTED_RE =\n /(?:insufficient|exhausted|depleted|exceeded|no|not enough)[-_\\s]*(?:quota|credit|balance)|(?:quota|credit|balance)[-_\\s]*(?:exhausted|depleted|exceeded|insufficient)|billing[_\\s-]*(?:hard[_\\s-]*)?limit|payment required|spending limit|plan limit|usage[-_\\s]*limit[-_\\s]*(?:reached|exceeded)/i;\n/** \"rate limit exceeded\" pattern \u2014 checked against body.message only, NOT the\n * raw JSON text, because OpenAI's `\"code\":\"rate_limit_exceeded\"` field would\n * produce a false positive in the combined-text regex. */\nconst RATE_LIMIT_EXCEEDED_RE = /rate[-_\\s]*limit[-_\\s]*exceeded/i;\n\n/**\n * Classify a provider HTTP failure into the canonical taxonomy from its\n * status code plus the parsed error body (and, for message-only errors\n * without a structured body, the error message itself). Pure and total \u2014\n * always returns a kind, never throws.\n */\nexport function classifyProviderError(\n status: number,\n body?: ProviderErrorBody,\n message?: string,\n): ProviderErrorKind {\n const type = body?.type;\n const text = [message, body?.message, type, body?.raw].filter(Boolean).join('\\n');\n if (status === 0) return 'network';\n if (status === 408) return 'timeout';\n if (status === 599) return 'stream_hang';\n if (status === 402 || QUOTA_EXHAUSTED_RE.test(text)) return 'quota_exhausted';\n // Check body.message separately for \"rate limit exceeded\" \u2014 this pattern\n // should NOT match against body.raw because OpenAI's error response\n // includes `\"code\":\"rate_limit_exceeded\"` in the JSON, which would be a\n // false positive (it's a transient burst, not a hard limit).\n if (status === 429 && body?.message && RATE_LIMIT_EXCEEDED_RE.test(body.message)) {\n return 'quota_exhausted';\n }\n if (type === 'rate_limit_error' || status === 429) return 'rate_limit';\n if (type === 'overloaded_error' || status === 529) return 'overloaded';\n if (status >= 500) return 'server';\n if (\n type === 'authentication_error' ||\n type === 'permission_error' ||\n status === 401 ||\n status === 403\n ) {\n return 'auth';\n }\n if (type === 'content_filter' || CONTENT_FILTER_RE.test(text)) return 'content_filter';\n if (status === 413 || (status >= 400 && CONTEXT_OVERFLOW_RE.test(text))) {\n return 'context_overflow';\n }\n if (status >= 400) return 'invalid_request';\n return 'unknown';\n}\n\n/**\n * Whether a kind is worth retrying against the SAME provider/model.\n * `context_overflow` is deliberately false \u2014 the request must shrink first;\n * `auth`/`invalid_request`/`content_filter` won't improve on replay.\n *\n * Exhaustive by construction (`Record<ProviderErrorKind, \u2026>`): adding a new\n * kind refuses to compile until it is classified here. Every kind\u2192X mapping\n * in the codebase follows this drift-guard pattern \u2014 see also KIND_TO_CODE\n * below, DefaultRetryPolicy.maxAttempts, fallback-model shouldFallback, and\n * the coordinator's providerErrorToSubagentError.\n */\nexport function isRetryableKind(kind: ProviderErrorKind): boolean {\n return RETRYABLE_BY_KIND[kind];\n}\n\nconst RETRYABLE_BY_KIND: Record<ProviderErrorKind, boolean> = {\n rate_limit: true,\n quota_exhausted: false,\n overloaded: true,\n server: true,\n timeout: true,\n network: true,\n stream_hang: true,\n auth: false,\n context_overflow: false,\n content_filter: false,\n invalid_request: false,\n unknown: false,\n};\n\n/**\n * Whether a kind is worth HOPPING to a different provider/model \u2014 the gate for\n * the cross-provider fallback engine (agent-loop extension AND the one-shot\n * orchestrator both branch on this ONE table, so their behavior can't drift).\n *\n * A distinct question from {@link isRetryableKind} (retry the SAME model):\n * a hop only helps for capacity/transport failures. Request-shaped failures\n * surface instead \u2014 `context_overflow` needs compaction, `content_filter` is\n * owned by the `content_filter_reroute` recovery strategy, and `auth` /\n * `invalid_request` are user-actionable and would fail identically on a hop.\n * The value set is currently identical to the retryable set, but it is kept as\n * its own table on purpose: the two answer different questions and may diverge.\n *\n * Exhaustive by construction (`Record<ProviderErrorKind, \u2026>`) \u2014 a new kind\n * refuses to compile until it is classified here.\n */\nexport function isFallbackWorthy(kind: ProviderErrorKind): boolean {\n return FALLBACK_WORTHY_BY_KIND[kind];\n}\n\nconst FALLBACK_WORTHY_BY_KIND: Record<ProviderErrorKind, boolean> = {\n rate_limit: true,\n quota_exhausted: true,\n overloaded: true,\n server: true,\n timeout: true,\n network: true,\n stream_hang: true,\n auth: false,\n context_overflow: false,\n content_filter: false,\n invalid_request: false,\n unknown: false,\n};\n\nexport class ProviderError extends WrongStackError {\n public readonly status: number;\n public readonly retryable: boolean;\n public readonly providerId: string;\n /** Canonical failure classification \u2014 see {@link ProviderErrorKind}. */\n public readonly kind: ProviderErrorKind;\n public readonly body?: ProviderErrorBody | undefined;\n\n constructor(\n message: string,\n status: number,\n retryable: boolean,\n providerId: string,\n opts: {\n body?: ProviderErrorBody | undefined;\n cause?: unknown | undefined;\n /** Override the computed classification (rarely needed \u2014 tests, custom wires). */\n kind?: ProviderErrorKind | undefined;\n } = {},\n ) {\n const kind = opts.kind ?? classifyProviderError(status, opts.body, message);\n super({\n message,\n code: kindToCode(kind),\n subsystem: 'provider',\n severity: status >= 500 ? 'error' : 'warning',\n recoverable: retryable,\n context: { providerId, status },\n cause: opts.cause,\n });\n this.name = 'ProviderError';\n this.status = status;\n this.retryable = retryable;\n this.providerId = providerId;\n this.kind = kind;\n this.body = opts.body;\n }\n\n /**\n * Render a one-line, user-facing description. Designed for the CLI/TUI\n * status line and the agent's retry warning. Avoids dumping raw JSON\n * (which is what users see today when a 529 lands and the log message\n * includes the full `{\"type\":\"error\",...}` body).\n *\n * Examples:\n * \"minimax-coding-plan overloaded (529): High traffic detected. Upgrade for highspeed model. [req 06534785201de9c0\u2026]\"\n * \"openai rate limited (429): Retry after 12s\"\n * \"anthropic invalid request (400): messages.0.role must be one of 'user'|'assistant'\"\n * \"groq HTTP 500 (server error)\"\n */\n override describe(): string {\n const kind = describeStatus(this.status, this.body?.type);\n const head = `${this.providerId} ${kind}`;\n const detail = this.body?.message?.trim();\n const reqId = this.body?.requestId\n ? ` [req ${this.body.requestId.slice(0, 16)}${this.body.requestId.length > 16 ? '\u2026' : ''}]`\n : '';\n if (detail && detail.length > 0) {\n return `${head}: ${truncate(detail, 240)}${reqId}`;\n }\n return `${head}${reqId}`;\n }\n}\n\n/**\n * Belt-and-suspenders overflow detection for the recovery layer. Returns true\n * when a `ProviderError` is *shaped* like a context overflow even if its `kind`\n * says otherwise \u2014 an HTTP 413, or an overflow phrase anywhere in its message /\n * body. Gateways and proxies sometimes relabel an overflow as a generic\n * `invalid_request`/400 (or a caller constructs the error with an explicit\n * wrong `kind`); the `context_overflow_reduce` strategy uses this so those\n * still trigger compact-and-retry instead of failing terminally.\n */\nexport function isContextOverflowShaped(err: unknown): boolean {\n if (!(err instanceof ProviderError)) return false;\n if (err.kind === 'context_overflow' || err.status === 413) return true;\n if (err.status < 400) return false;\n const text = [err.message, err.body?.message, err.body?.type, err.body?.raw]\n .filter(Boolean)\n .join('\\n');\n return CONTEXT_OVERFLOW_RE.test(text);\n}\n\nfunction describeStatus(status: number, type?: string): string {\n if (status === 0) return 'network error';\n if (status === 599) return `stream hang (${status})`;\n if (type === 'overloaded_error' || status === 529) return `overloaded (${status})`;\n if (type === 'rate_limit_error' || status === 429) return `rate limited (${status})`;\n if (type === 'authentication_error' || status === 401) return `auth failed (${status})`;\n if (type === 'permission_error' || status === 403) return `forbidden (${status})`;\n if (type === 'not_found_error' || status === 404) return `not found (${status})`;\n if (type === 'content_filter') return `content filtered (${status})`;\n if (type === 'invalid_request_error' || status === 400) return `invalid request (${status})`;\n if (status === 408) return `timeout (${status})`;\n if (status >= 500 && status < 600) return `HTTP ${status} (server error)`;\n if (type) return `${type} (${status})`;\n return `HTTP ${status}`;\n}\n\n/**\n * Thrown when the provider stream stops delivering data mid-response.\n * This is distinct from a network error (TCP reset, DNS failure) \u2014 the\n * connection is established and the response started, but chunks stopped\n * arriving before the stream completed.\n *\n * Status 599 is used as a sentinel to distinguish stream hangs from\n * regular HTTP errors while still flowing through ProviderError-based\n * retry and fallback infrastructure.\n */\nexport class StreamHangError extends ProviderError {\n /** Name of the provider that hung, e.g. \"zai\", \"anthropic\". */\n public readonly hungProviderId: string;\n /** Model that was being called when the hang occurred. */\n public readonly hungModel: string;\n /** How long (ms) we waited for the next chunk before declaring a hang. */\n public readonly hangTimeoutMs: number;\n /** How many bytes were received before the hang. */\n public readonly bytesReceived: number;\n /** Elapsed time (ms) from the start of the stream until the hang. */\n public readonly elapsedMs: number;\n\n constructor(opts: {\n providerId: string;\n model: string;\n hangTimeoutMs: number;\n bytesReceived: number;\n elapsedMs: number;\n cause?: unknown | undefined;\n }) {\n super(\n `Stream hang: ${opts.providerId}/${opts.model} \u2014 no data for ${opts.hangTimeoutMs}ms after ${opts.bytesReceived} bytes (${opts.elapsedMs}ms elapsed)`,\n 599,\n true, // always retryable\n opts.providerId,\n {\n body: {\n message: `Stream stalled after ${opts.elapsedMs}ms, ${opts.bytesReceived} bytes received`,\n },\n cause: opts.cause,\n },\n );\n this.name = 'StreamHangError';\n this.hungProviderId = opts.providerId;\n this.hungModel = opts.model;\n this.hangTimeoutMs = opts.hangTimeoutMs;\n this.bytesReceived = opts.bytesReceived;\n this.elapsedMs = opts.elapsedMs;\n }\n}\n\n/** Exhaustive kind \u2192 ErrorCode mapping \u2014 new kinds must be added here or the\n * file stops compiling (same drift-guard pattern as RETRYABLE_BY_KIND). */\nconst KIND_TO_CODE: Record<ProviderErrorKind, ErrorCode> = {\n network: ERROR_CODES.PROVIDER_NETWORK_ERROR,\n timeout: ERROR_CODES.PROVIDER_NETWORK_ERROR,\n rate_limit: ERROR_CODES.PROVIDER_RATE_LIMITED,\n quota_exhausted: ERROR_CODES.PROVIDER_RATE_LIMITED,\n auth: ERROR_CODES.PROVIDER_AUTH_FAILED,\n overloaded: ERROR_CODES.PROVIDER_OVERLOADED,\n context_overflow: ERROR_CODES.PROVIDER_CONTEXT_OVERFLOW,\n server: ERROR_CODES.PROVIDER_SERVER_ERROR,\n stream_hang: ERROR_CODES.PROVIDER_SERVER_ERROR,\n content_filter: ERROR_CODES.PROVIDER_INVALID_REQUEST,\n invalid_request: ERROR_CODES.PROVIDER_INVALID_REQUEST,\n unknown: ERROR_CODES.PROVIDER_INVALID_REQUEST,\n};\n\nfunction kindToCode(kind: ProviderErrorKind): ErrorCode {\n return KIND_TO_CODE[kind];\n}\n", "/**\n * Shared configuration constants used across execution, storage, CLI, and WebUI.\n * Centralized here to avoid cross-domain import cycles.\n */\n\n/** Default tools config \u2014 mirrors values baked into BEHAVIOR_DEFAULTS. */\nexport const DEFAULT_TOOLS_CONFIG = Object.freeze({\n defaultExecutionStrategy: 'smart',\n maxIterations: 100,\n iterationTimeoutMs: 300_000,\n maxToolTimeoutMs: 300_000,\n sessionTimeoutMs: 1_800_000,\n perIterationOutputCapBytes: 100_000,\n descriptionMode: Object.freeze({}) as Record<string, 'extend' | 'simple' | undefined>,\n disabledTools: Object.freeze([]) as readonly string[],\n autoExtendLimit: true,\n restrictToProjectRoot: true,\n loopDetection: Object.freeze({\n mode: 'steer-then-cut',\n steerThreshold: 3,\n cutThreshold: 5,\n windowSize: 12,\n callRepeatThreshold: 4,\n }) as Readonly<{\n mode: 'steer-then-cut' | 'cut' | 'off';\n steerThreshold: number;\n cutThreshold: number;\n windowSize: number;\n callRepeatThreshold: number;\n }>,\n});\n\n/** Default context config \u2014 mirrors BEHAVIOR_DEFAULTS.context. */\nexport const DEFAULT_CONTEXT_CONFIG = Object.freeze({\n preserveK: 8,\n eliseThreshold: 1000,\n});\n\n/** Default autonomy config \u2014 auto-proceed delay etc. */\nexport const DEFAULT_AUTONOMY_CONFIG = Object.freeze({\n autoProceedDelayMs: 45_000,\n});\n\n/**\n * Default process circuit-breaker config. Protection is OFF by default \u2014 the\n * breaker only gates `bash`/`exec` once the user opts in via `/settings breaker on`.\n * The auto kill/reset delay is only consulted when protection is enabled.\n */\nexport const DEFAULT_CIRCUIT_BREAKER_CONFIG = Object.freeze({\n enabled: false,\n autoKillResetMs: 60_000,\n});\n\n/** Default session logging / audit configuration. */\nexport const DEFAULT_SESSION_LOGGING_CONFIG = Object.freeze({\n auditLevel: 'standard' as const,\n sampling: {\n toolProgress: {\n sampleRate: 8,\n },\n },\n});\n\n/** Default retention window for local session pruning. */\nexport const DEFAULT_SESSION_PRUNE_DAYS = 30;\n", "export type MemoryScope = 'project-agents' | 'project-memory' | 'user-memory';\n\n// \u2500\u2500 Memory categories \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport type MemoryType = 'fact' | 'decision' | 'convention' | 'preference' | 'reference' | 'anti_pattern';\n\nexport const MEMORY_TYPE_LABELS: Record<MemoryType, string> = {\n fact: 'Fact',\n decision: 'Decision',\n convention: 'Convention',\n preference: 'Preference',\n reference: 'Reference',\n anti_pattern: 'Anti-pattern',\n};\n\nexport type MemoryPriority = 'critical' | 'high' | 'medium' | 'low';\n\nexport interface MemoryEntry {\n scope: MemoryScope;\n text: string;\n ts: string;\n /** Category \u2014 helps the agent decide whether to inject or ignore. */\n type?: MemoryType | undefined;\n /** Free-form tags for grouping (e.g. [\"build\", \"pnpm\", \"typescript\"]). */\n tags?: string[] | undefined;\n /** Priority \u2014 critical entries are always injected; low may be skipped. */\n priority?: MemoryPriority | undefined;\n /** Session or agent that created this entry. */\n source?: string | undefined;\n /** 0.0\u20131.0 confidence. Low-confidence entries are injected less often. */\n confidence?: number | undefined;\n /** ISO timestamp of last access (read or injection into context). */\n lastAccessed?: string | undefined;\n}\n\n// \u2500\u2500 Memory events \u2014 emitted by SuperMemoryStore so plugins can react \u2500\u2500\n\nexport interface MemoryRememberedPayload {\n scope: MemoryScope;\n text: string;\n ts: string;\n type?: MemoryType | undefined;\n tags?: string[] | undefined;\n priority?: MemoryPriority | undefined;\n}\n\nexport interface MemoryForgottenPayload {\n scope: MemoryScope;\n query: string;\n removed: number;\n}\n\nexport interface MemoryClearedPayload {\n /** Scope that was cleared, or undefined when all scopes were cleared. */\n scope?: MemoryScope | undefined;\n}\n\nexport interface MemoryConsolidatedPayload {\n scope: MemoryScope;\n /** Entries removed by deduplication. */\n removed: number;\n}\n\n// \u2500\u2500 Relevance scoring \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Context used to score memory relevance for context injection.\n * Passed by the system prompt builder.\n */\nexport interface MemoryRelevanceContext {\n /** Current user message or task description. */\n currentTask: string;\n /** Active skills in this session (e.g. [\"typescript-strict\", \"git-flow\"]). */\n activeSkills?: string[] | undefined;\n /** Active mode (e.g. \"Teach\", \"Brief\", \"Code Reviewer\"). */\n activeMode?: string | undefined;\n /** Available tools \u2014 memories referencing relevant tools score higher. */\n toolNames?: string[] | undefined;\n}\n\nexport interface ScoredEntry extends MemoryEntry {\n score: number;\n matchReason: string;\n}\n\n// \u2500\u2500 Store interface \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface MemoryStore {\n readAll(): Promise<string>;\n read(scope: MemoryScope): Promise<string>;\n remember(text: string, scope?: MemoryScope, metadata?: Omit<Partial<MemoryEntry>, 'scope' | 'text' | 'ts'>): Promise<void>;\n forget(query: string, scope?: MemoryScope): Promise<number>;\n consolidate(scope: MemoryScope): Promise<void>;\n clear(scope?: MemoryScope): Promise<void>;\n /** List entries, newest first. */\n list(scope?: MemoryScope, limit?: number): Promise<MemoryEntry[]>;\n /** Search by content (substring or semantic). */\n search(query: string, scope?: MemoryScope, limit?: number): Promise<MemoryEntry[]>;\n /** Access the backend for advanced queries. */\n getBackend?(): unknown;\n /** Graph-based related memory traversal. */\n findRelated?(text: string, scope?: MemoryScope, limit?: number): Promise<MemoryEntry[]>;\n /**\n * Score and rank memories by relevance to the current context.\n * Returns only entries that meet a relevance threshold.\n */\n scoreRelevant?(ctx: MemoryRelevanceContext, scope?: MemoryScope, limit?: number): Promise<ScoredEntry[]>;\n /**\n * Run memory hygiene: verify anchors, mark stale entries, archive\n * low-confidence/old memories. Optional \u2014 only Super Memory stores\n * implement this. Declared on the interface so callers can invoke\n * it without a type-erasing cast.\n */\n hygiene?(opts?: {\n retentionDays?: number | undefined;\n archiveLowConfidenceAfterDays?: number | undefined;\n archiveUnusedAfterDays?: number | undefined;\n unusedMinInjections?: number | undefined;\n }): Promise<unknown>;\n /**\n * Attach a trace ID to this store so that all subsequent `storage.*`\n * events include it for observability correlation. Mutates the store\n * in place and returns the same instance (convenience chaining).\n */\n withTraceId(traceId: string): MemoryStore;\n}\n", "/**\n * Prompt library types \u2014 the canonical home for the prompt data model and the\n * loader/registry contracts. Has no internal dependencies so both `storage/`\n * (the writable store) and `execution/` (the layered loader) can import it\n * without creating a cycle.\n */\n\n/** Provenance of a prompt \u2014 which layer it came from. */\nexport type PromptSource = 'builtin' | 'user' | 'project' | 'synced';\n\n/**\n * The fourteen first-party categories shipped with the builtin dataset, plus\n * the `uncategorized` sentinel used when migrating legacy v1 entries. Builtin\n * prompts MUST use one of these (enforced by the dataset schema test); user and\n * project prompts may use any free-form string.\n */\nexport const BUILTIN_PROMPT_CATEGORIES = [\n 'coding',\n 'debugging',\n 'refactoring',\n 'testing',\n 'code-review',\n 'architecture',\n 'devops',\n 'documentation',\n 'data-analysis',\n 'writing',\n 'research',\n 'product',\n 'agentic-workflows',\n 'meta-prompting',\n 'uncategorized',\n] as const;\n\nexport type BuiltinPromptCategory = (typeof BUILTIN_PROMPT_CATEGORIES)[number];\n\n/**\n * Human-readable labels for the builtin categories (for UI chips / pickers).\n */\nexport const PROMPT_CATEGORY_LABELS: Record<BuiltinPromptCategory, string> = {\n coding: 'Coding',\n debugging: 'Debugging',\n refactoring: 'Refactoring',\n testing: 'Testing',\n 'code-review': 'Code Review',\n architecture: 'Architecture',\n devops: 'DevOps',\n documentation: 'Documentation',\n 'data-analysis': 'Data Analysis',\n writing: 'Writing',\n research: 'Research',\n product: 'Product',\n 'agentic-workflows': 'Agentic Workflows',\n 'meta-prompting': 'Meta-Prompting',\n uncategorized: 'Uncategorized',\n};\n\n/**\n * A prompt's category. Typed as a free-form string because user/project prompts\n * may invent their own; the builtin dataset is constrained to\n * {@link BUILTIN_PROMPT_CATEGORIES} by its schema.\n */\nexport type PromptCategory = BuiltinPromptCategory | (string & {});\n\nexport function isBuiltinCategory(value: string): value is BuiltinPromptCategory {\n return (BUILTIN_PROMPT_CATEGORIES as readonly string[]).includes(value);\n}\n\n/** A `{{name}}` placeholder declared by a prompt. */\nexport interface PromptVariable {\n /** Placeholder name as it appears between `{{ }}` (case-sensitive). */\n name: string;\n description?: string | undefined;\n default?: string | undefined;\n required?: boolean | undefined;\n /**\n * Closed set of allowed values. When present, surfaces render a dropdown\n * instead of a free text field and a supplied value outside the set is\n * reported as invalid by {@link renderPrompt}.\n */\n enum?: string[] | undefined;\n /**\n * UI hint: the value is expected to span multiple lines (pasted code, a\n * diff, a long passage). Surfaces render a textarea instead of a one-line\n * input. Has no effect on rendering \u2014 purely presentational.\n */\n multiline?: boolean | undefined;\n}\n\n/**\n * A reusable prompt. v2 schema. Legacy v1 entries (only `id/title/content/tags/\n * createdAt/updatedAt`) are upgraded lazily on read by `migratePromptEntry`.\n */\nexport interface PromptEntry {\n /** Stable unique handle (ULID for new entries; legacy short hex tolerated). */\n id: string;\n /** kebab-case stable key \u2014 the dedup key across layers and registry key. */\n slug: string;\n title: string;\n /** One-line summary shown in lists/pickers. */\n description: string;\n content: string;\n category: PromptCategory;\n /** Secondary facets (free-form). */\n tags: string[];\n source: PromptSource;\n favorite: boolean;\n /** `{{placeholder}}` variables this prompt expects, if any. */\n variables?: PromptVariable[] | undefined;\n author?: string | undefined;\n version?: string | undefined;\n license?: string | undefined;\n /** sha256 of `content` \u2014 set for builtin/synced entries for integrity. */\n checksum?: string | undefined;\n /** When a builtin was copy-on-written into the user layer, its origin slug. */\n forkedFrom?: string | undefined;\n createdAt: string;\n updatedAt: string;\n}\n\n/** One category with its prompt count, for picker chips. */\nexport interface PromptCategoryCount {\n id: PromptCategory;\n label: string;\n count: number;\n}\n\nexport interface PromptSearchOptions {\n category?: PromptCategory | undefined;\n /** Max results (default: unbounded). */\n limit?: number | undefined;\n}\n\n/**\n * Read-side contract over the three prompt layers (project > user > builtin),\n * merged and de-duplicated by slug. Mirrors `SkillLoader` in shape.\n */\nexport interface PromptLoader {\n /** All prompts across layers, project/user shadowing builtin by slug. */\n list(): Promise<PromptEntry[]>;\n /** Resolve by slug first, then by id. */\n find(slugOrId: string): Promise<PromptEntry | undefined>;\n /** Ranked search over title/description/content/tags, optional category filter. */\n search(query: string, opts?: PromptSearchOptions): Promise<PromptEntry[]>;\n /** Category counts across all layers, for UI chips. */\n categories(): Promise<PromptCategoryCount[]>;\n /**\n * Persist into the writable (user, or project when `scope:'project'`) layer.\n * Throws if the resolved target is the read-only builtin layer.\n */\n save(entry: PromptEntry, opts?: { scope?: 'user' | 'project' }): Promise<void>;\n /** Delete from a writable layer. Returns false if not found / builtin. */\n delete(slugOrId: string): Promise<boolean>;\n /**\n * Mark/unmark a prompt as favorite. Favoriting a builtin copies it down into\n * the user layer (copy-on-write, `source:'user'`, `forkedFrom:<slug>`).\n */\n setFavorite(slugOrId: string, favorite: boolean): Promise<PromptEntry | undefined>;\n /** Clear the internal cache so the next read re-scans disk. */\n invalidateCache(): void;\n}\n\n/**\n * The packed builtin index (also the shape a remote registry manifest mirrors\n * \u2014 see `types/prompt-registry.ts`).\n */\nexport interface PromptManifest {\n datasetVersion: number;\n generatedAt: string;\n count: number;\n categories: PromptCategoryCount[];\n prompts: PromptManifestRef[];\n}\n\nexport interface PromptManifestRef {\n id: string;\n slug: string;\n title: string;\n description: string;\n category: PromptCategory;\n tags: string[];\n checksum: string;\n /** Relative path of the per-prompt file within the dataset. */\n file: string;\n}\n", "/**\n * Prompt registry / sync types \u2014 the contract for a remote prompt hub\n * (e.g. prompts.wrongstack.com) and the local installed-prompts manifest.\n *\n * The manifest shape intentionally mirrors the bundled dataset's\n * `data/prompts/index.json` (see `PromptManifest` in `types/prompt.ts`): the\n * builtin dataset IS a local registry, so builtin and synced prompts can flow\n * through one validation + diff path. This file defines the format and the\n * structural validator; the actual fetch/download is a deliberately small stub\n * (see `prompts/prompt-installer.ts`) \u2014 \"groundwork now, sync later\".\n */\nimport type { PromptCategory } from './prompt.js';\n\nexport interface PromptRegistryRef {\n id: string;\n slug: string;\n title: string;\n description: string;\n category: PromptCategory;\n tags: string[];\n /** sha256 of the prompt content \u2014 drives the update diff. */\n checksum: string;\n version?: string | undefined;\n license?: string | undefined;\n /** Optional direct URL to the full prompt JSON. */\n url?: string | undefined;\n}\n\nexport interface PromptRegistryManifest {\n registryVersion: 1;\n /** Where this manifest came from (hub URL or `owner/repo`). */\n source: string;\n generatedAt: string;\n prompts: PromptRegistryRef[];\n}\n\n/** One entry recorded in `~/.wrongstack/installed-prompts.json`. */\nexport interface InstalledPromptEntry {\n slug: string;\n /** The registry/source this prompt was pulled from. */\n source: string;\n /** The ref pinned at install (tag/branch/commit or manifest version). */\n ref: string;\n checksum: string;\n /** True once the prompt body has actually been written locally. */\n synced: boolean;\n installedAt: string;\n}\n\nexport interface PromptManifestData {\n version: 1;\n entries: InstalledPromptEntry[];\n}\n\n/** Result of validating an untrusted manifest. */\nexport type ManifestValidation =\n | { ok: true; manifest: PromptRegistryManifest }\n | { ok: false; errors: string[] };\n\nconst SLUG_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\nconst CHECKSUM_RE = /^[a-f0-9]{64}$/;\nconst MAX_STR = 4096;\n\n/**\n * Structurally validate an untrusted registry manifest. Treats the manifest as\n * DATA, not instructions: enforces slug charset, checksum format, and field\n * lengths so a malicious hub can't smuggle oversized or malformed entries into\n * the local store. Does NOT fetch prompt bodies.\n */\nexport function validateRegistryManifest(raw: unknown): ManifestValidation {\n const errors: string[] = [];\n if (!raw || typeof raw !== 'object') return { ok: false, errors: ['manifest is not an object'] };\n const m = raw as Record<string, unknown>;\n\n if (m['registryVersion'] !== 1) errors.push('registryVersion must be 1');\n if (typeof m['source'] !== 'string' || !m['source'])\n errors.push('source must be a non-empty string');\n if (typeof m['generatedAt'] !== 'string') errors.push('generatedAt must be a string');\n if (!Array.isArray(m['prompts'])) {\n errors.push('prompts must be an array');\n return { ok: false, errors };\n }\n\n const seen = new Set<string>();\n const refs: PromptRegistryRef[] = [];\n (m['prompts'] as unknown[]).forEach((p, i) => {\n if (!p || typeof p !== 'object') {\n errors.push(`prompts[${i}] is not an object`);\n return;\n }\n const r = p as Record<string, unknown>;\n const slug = r['slug'];\n if (typeof slug !== 'string' || !SLUG_RE.test(slug)) {\n errors.push(`prompts[${i}].slug invalid (must be kebab-case)`);\n return;\n }\n if (seen.has(slug)) {\n errors.push(`prompts[${i}].slug \"${slug}\" duplicated`);\n return;\n }\n seen.add(slug);\n if (typeof r['checksum'] !== 'string' || !CHECKSUM_RE.test(r['checksum'])) {\n errors.push(`prompts[${i}].checksum must be a 64-char sha256 hex`);\n return;\n }\n for (const field of ['id', 'title', 'description', 'category'] as const) {\n const v = r[field];\n if (typeof v !== 'string' || v.length === 0 || v.length > MAX_STR) {\n errors.push(`prompts[${i}].${field} must be a non-empty string under ${MAX_STR} chars`);\n return;\n }\n }\n const tags = Array.isArray(r['tags'])\n ? (r['tags'].filter((t) => typeof t === 'string') as string[])\n : [];\n refs.push({\n id: r['id'] as string,\n slug,\n title: r['title'] as string,\n description: r['description'] as string,\n category: r['category'] as string,\n tags,\n checksum: r['checksum'] as string,\n version: typeof r['version'] === 'string' ? r['version'] : undefined,\n license: typeof r['license'] === 'string' ? r['license'] : undefined,\n url: typeof r['url'] === 'string' ? r['url'] : undefined,\n });\n });\n\n if (errors.length > 0) return { ok: false, errors };\n return {\n ok: true,\n manifest: {\n registryVersion: 1,\n source: m['source'] as string,\n generatedAt: m['generatedAt'] as string,\n prompts: refs,\n },\n };\n}\n\nexport interface RegistryDiff {\n /** Slugs present in the manifest but not locally. */\n added: PromptRegistryRef[];\n /** Slugs present locally but whose checksum differs in the manifest. */\n updated: PromptRegistryRef[];\n /** Slugs present locally and identical in the manifest. */\n unchanged: PromptRegistryRef[];\n}\n\n/**\n * Compute what a pull WOULD change, by slug+checksum, against the prompts the\n * caller already has. Pure \u2014 no I/O, no writes.\n */\nexport function diffRegistry(\n local: { slug: string; checksum?: string | undefined }[],\n manifest: PromptRegistryManifest,\n): RegistryDiff {\n const localBySlug = new Map(local.map((e) => [e.slug, e.checksum]));\n const diff: RegistryDiff = { added: [], updated: [], unchanged: [] };\n for (const ref of manifest.prompts) {\n if (!localBySlug.has(ref.slug)) diff.added.push(ref);\n else if (localBySlug.get(ref.slug) !== ref.checksum) diff.updated.push(ref);\n else diff.unchanged.push(ref);\n }\n return diff;\n}\n", "/**\n * Design Studio \u2014 curated frontend/mobile UI design kits.\n *\n * A \"design kit\" is a self-contained, selectable design direction (an aesthetic\n * + concrete design tokens + per-stack implementation guidance) that the model\n * commits to BEFORE writing UI code. Kits are surfaced progressively: a compact\n * menu is injected when frontend work is detected, and the heavy kit body is\n * only loaded once the model (or user) picks one \u2014 keeping per-turn tokens low.\n *\n * This mirrors the skills subsystem (`types/skill.ts` + `execution/skill-loader.ts`)\n * but adds the per-stack body selection and a token snapshot for visual pickers.\n */\n\n/** Target implementation stacks a kit can speak to. */\nexport const DESIGN_STACKS = ['web', 'react-native', 'flutter', 'swiftui', 'compose'] as const;\n\nexport type DesignStack = (typeof DESIGN_STACKS)[number];\n\nexport function isDesignStack(v: string): v is DesignStack {\n return (DESIGN_STACKS as readonly string[]).includes(v);\n}\n\nexport interface DesignKitManifest {\n id: string;\n name: string;\n /** One-line vibe shown in the menu, e.g. \"Restrained, Linear-style minimalism\". */\n aesthetic: string;\n /** Free-form tags for filtering. */\n tags: string[];\n /** Stacks this kit provides guidance for. */\n stacks: DesignStack[];\n /** Whether the kit ships light + dark themes (almost always true). */\n themes: string[];\n /** \"Best for\u2026\" one-liner used in menu + pickers. */\n bestFor: string;\n version?: string | undefined;\n path: string;\n source: 'project' | 'user' | 'bundled';\n}\n\n/** A single theme's concrete token values (OKLCH strings, font names, etc.). */\nexport interface DesignTokenSet {\n [token: string]: string;\n}\n\n/** Parsed `tokens.json` \u2014 light + dark token snapshots used by visual pickers. */\nexport interface DesignKitTokens {\n light?: DesignTokenSet | undefined;\n dark?: DesignTokenSet | undefined;\n}\n\n/** Compact menu entry rendered into the request when frontend work is detected. */\nexport interface DesignKitEntry {\n id: string;\n name: string;\n aesthetic: string;\n bestFor: string;\n stacks: DesignStack[];\n source: DesignKitManifest['source'];\n}\n\n/**\n * Live Design Studio state stashed on `ctx.meta.designStudio`. Set by the\n * detection middleware (user intent + frontend file writes); read by the\n * request middleware that injects the menu / active-kit reminder.\n */\nexport interface DesignStudioState {\n /** True once frontend/UI work has been detected this session. */\n active: boolean;\n /** Detected target stack, if any. */\n stack?: DesignStack | undefined;\n /** What triggered activation (for transparency / debugging). */\n signals: string[];\n /** Kit id the model/user committed to, if any. */\n activeKit?: string | undefined;\n /**\n * User color/token overrides applied over the active kit's tokens. Keys are\n * token names (`primary`) applied to both themes, or theme-scoped\n * (`light.bg`/`dark.bg`). See `applyTokenOverrides`.\n */\n overrides?: Record<string, string> | undefined;\n}\n\nexport interface DesignKitLoader {\n list(): Promise<DesignKitManifest[]>;\n /** Structured entries for the compact menu. */\n listEntries(): Promise<DesignKitEntry[]>;\n find(id: string): Promise<DesignKitManifest | undefined>;\n /** Compact, model-facing menu of every available kit. */\n menuText(): Promise<string>;\n /**\n * Full kit body for a given stack. Strips frontmatter and, when `stack` is\n * provided, narrows stack-specific sections to that stack.\n */\n readBody(id: string, stack?: DesignStack | undefined): Promise<string>;\n /** Parsed `tokens.json` for a kit (light/dark snapshots), if present. */\n readTokens(id: string): Promise<DesignKitTokens | undefined>;\n /** The mandatory cross-cutting baseline (responsive / a11y / theming / motion). */\n foundationsText(stack?: DesignStack | undefined): Promise<string>;\n invalidateCache(): void;\n}\n", "import { readFileSync, statSync } from 'node:fs';\nimport * as path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nexport function modePrompt(id: string): string {\n for (const dir of modePromptDirCandidates()) {\n try {\n return readFileSync(path.join(dir, `${id}.md`), 'utf8').trimEnd();\n } catch {\n // try next candidate\n }\n }\n return '';\n}\n\nfunction modePromptDirCandidates(): string[] {\n const here = path.dirname(fileURLToPath(import.meta.url));\n const candidates = [\n path.resolve(here, '../../instructions/modes'),\n path.resolve(here, '../instructions/modes'),\n path.resolve(here, 'instructions/modes'),\n ];\n return candidates.sort((a, b) => Number(!isDirectory(a)) - Number(!isDirectory(b)));\n}\n\nfunction isDirectory(candidate: string): boolean {\n try {\n return statSync(candidate).isDirectory();\n } catch {\n return false;\n }\n}\n", "import { modePrompt } from './mode-prompts.js';\nexport interface Mode {\n id: string;\n name: string;\n description: string;\n /** Additional prompt text injected into system prompt when mode is active */\n prompt: string;\n /** Tags for tool_search filtering */\n tags?: string[] | undefined;\n /** Tools that should be prioritized/highlighted when this mode is active */\n toolPreferences?: string[] | undefined;\n /**\n * Skill names that are particularly relevant to this mode. The system\n * prompt builder appends a \"Suggested skills\" note so the model knows\n * which domain knowledge to leverage first. Skill must exist in the\n * loaded skill set to appear.\n */\n suggestedSkills?: string[] | undefined;\n}\n\nexport interface ModeManifest {\n modes: Mode[];\n defaultMode?: string | undefined;\n}\n\nexport interface ModeStore {\n getActiveMode(): Promise<Mode | null>;\n setActiveMode(modeId: string | null): Promise<void>;\n listModes(): Promise<Mode[]>;\n getMode(modeId: string): Promise<Mode | null>;\n}\n\nexport interface ModeConfig {\n directory: string;\n}\n\nexport const DEFAULT_MODES: Mode[] = [\n {\n id: 'default',\n name: 'Default',\n description: 'Balanced general-purpose mode; use when no special token/coverage trade-off is needed',\n prompt: '',\n tags: ['general', 'balanced'],\n },\n {\n id: 'brief',\n name: 'Brief',\n description: 'Ultra-compact responses for low-context, high-speed work',\n prompt: modePrompt('brief'),\n tags: ['lite', 'fast', 'concise', 'token-saving'],\n toolPreferences: ['read', 'edit', 'bash'],\n suggestedSkills: [],\n },\n {\n id: 'review-lite',\n name: 'Review Lite',\n description: 'Token-saving code review: changed files only, top correctness/security risks',\n prompt: modePrompt('review-lite'),\n tags: ['lite', 'review', 'quality', 'token-saving'],\n toolPreferences: ['git', 'diff', 'read', 'grep'],\n suggestedSkills: ['bug-hunter', 'typescript-strict'],\n },\n {\n id: 'audit-lite',\n name: 'Audit Lite',\n description: 'Token-saving security triage for a small diff or named file',\n prompt: modePrompt('audit-lite'),\n tags: ['lite', 'security', 'audit', 'token-saving'],\n toolPreferences: ['grep', 'read', 'git'],\n suggestedSkills: ['security-scanner'],\n },\n {\n id: 'plan-lite',\n name: 'Plan Lite',\n description: 'Token-saving planning: 3-6 actionable steps, minimal design debate',\n prompt: modePrompt('plan-lite'),\n tags: ['lite', 'planning', 'architecture', 'token-saving'],\n toolPreferences: ['tree', 'glob', 'read', 'grep'],\n suggestedSkills: ['refactor-planner'],\n },\n {\n id: 'debug-lite',\n name: 'Debug Lite',\n description: 'Token-saving bug triage: one hypothesis, nearest evidence, narrow check',\n prompt: modePrompt('debug-lite'),\n tags: ['lite', 'debug', 'triage', 'token-saving'],\n toolPreferences: ['read', 'grep', 'test', 'logs'],\n suggestedSkills: ['bug-hunter'],\n },\n {\n id: 'test-lite',\n name: 'Test Lite',\n description: 'Token-saving tests: one focused regression or narrow verification target',\n prompt: modePrompt('test-lite'),\n tags: ['lite', 'testing', 'qa', 'token-saving'],\n toolPreferences: ['test', 'read', 'grep'],\n suggestedSkills: ['testing'],\n },\n {\n id: 'refactor-lite',\n name: 'Refactor Lite',\n description: 'Token-saving cleanup: small scoped behavior-preserving changes',\n prompt: modePrompt('refactor-lite'),\n tags: ['lite', 'refactor', 'token-saving'],\n toolPreferences: ['read', 'edit', 'test'],\n suggestedSkills: ['typescript-strict'],\n },\n {\n id: 'research-lite',\n name: 'Research Lite',\n description: 'Token-saving web research: one search, one authoritative fetch, short answer',\n prompt: modePrompt('research-lite'),\n tags: ['lite', 'research', 'web', 'token-saving'],\n toolPreferences: ['search', 'fetch'],\n suggestedSkills: ['research-web'],\n },\n {\n id: 'code-reviewer',\n name: 'Review Deep',\n description: 'Comprehensive code review across contracts, edge cases, lifecycle, errors, concurrency',\n prompt: modePrompt('code-reviewer'),\n tags: ['deep', 'review', 'quality', 'security'],\n toolPreferences: ['read', 'grep', 'git', 'diff', 'test'],\n suggestedSkills: ['bug-hunter', 'security-scanner', 'typescript-strict', 'testing'],\n },\n {\n id: 'code-auditor',\n name: 'Audit Deep',\n description: 'Comprehensive security audit with category coverage and exploitability notes',\n prompt: modePrompt('code-auditor'),\n tags: ['deep', 'security', 'audit', 'compliance'],\n toolPreferences: ['grep', 'read', 'audit', 'bash'],\n suggestedSkills: ['security-scanner', 'bug-hunter', 'audit-log'],\n },\n {\n id: 'architect',\n name: 'Architecture Deep',\n description: 'Comprehensive architecture and cross-module contract analysis',\n prompt: modePrompt('architect'),\n tags: ['deep', 'architecture', 'design', 'scalability'],\n toolPreferences: ['read', 'glob', 'tree', 'diff'],\n suggestedSkills: ['api-design', 'refactor-planner', 'node-modern', 'docker-deploy'],\n },\n {\n id: 'debugger',\n name: 'Debug Deep',\n description: 'Comprehensive root-cause analysis with traces, logs, assumptions, and verification',\n prompt: modePrompt('debugger'),\n tags: ['deep', 'debug', 'investigation', 'error-resolution'],\n toolPreferences: ['read', 'grep', 'bash', 'logs', 'test'],\n suggestedSkills: ['bug-hunter', 'audit-log', 'observability'],\n },\n {\n id: 'tester',\n name: 'Test Deep',\n description: 'Comprehensive QA mode for coverage, boundaries, isolation, and integration gaps',\n prompt: modePrompt('tester'),\n tags: ['deep', 'testing', 'qa', 'quality'],\n toolPreferences: ['read', 'grep', 'test', 'bash'],\n suggestedSkills: ['testing', 'bug-hunter', 'typescript-strict'],\n },\n {\n id: 'devops',\n name: 'DevOps Deep',\n description: 'Comprehensive infrastructure, deployment, observability, and operations review',\n prompt: modePrompt('devops'),\n tags: ['deep', 'devops', 'infrastructure', 'operations'],\n toolPreferences: ['read', 'bash', 'grep', 'logs', 'git'],\n suggestedSkills: ['docker-deploy', 'observability', 'security-scanner'],\n },\n {\n id: 'refactorer',\n name: 'Refactor Deep',\n description: 'Comprehensive modernization/refactor mode with contracts and verification discipline',\n prompt: modePrompt('refactorer'),\n tags: ['deep', 'refactor', 'modernization', 'improvement'],\n toolPreferences: ['read', 'edit', 'test', 'git', 'grep'],\n suggestedSkills: ['refactor-planner', 'typescript-strict', 'node-modern', 'testing'],\n },\n {\n id: 'ui-design',\n name: 'UI Design Deep',\n description: 'Comprehensive design-first frontend/mobile UI work with kit, tokens, and accessibility',\n prompt: modePrompt('ui-design'),\n tags: ['deep', 'ui', 'frontend', 'mobile', 'design'],\n toolPreferences: ['design', 'write', 'edit', 'read', 'scaffold'],\n suggestedSkills: ['react-modern'],\n },\n {\n id: 'teach',\n name: 'Teach Deep',\n description: 'Mentor mode with explanations, mental models, trade-offs, and takeaways',\n prompt: modePrompt('teach'),\n tags: ['deep', 'teaching', 'mentor', 'learning'],\n toolPreferences: ['read', 'edit', 'explain'],\n suggestedSkills: ['prompt-engineering', 'skill-creator', 'node-modern', 'typescript-strict'],\n },\n {\n id: 'research-web',\n name: 'Research Deep',\n description: 'Comprehensive current-data research with cross-checking and reusable findings',\n prompt: modePrompt('research-web'),\n tags: ['deep', 'research', 'web', 'current-data', 'up-to-date'],\n toolPreferences: ['search', 'fetch', 'context_manager'],\n suggestedSkills: ['research-web', 'tech-stack', 'node-modern', 'security-scanner', 'react-modern'],\n },\n];\n", "import { expectDefined } from '../utils/expect-defined.js';\nexport type ContextWindowModeId = 'balanced' | 'frugal' | 'deep' | 'archival';\n\nexport type ContextWindowAggressiveOn = 'hard' | 'soft' | 'warn';\n\nexport interface ContextWindowThresholds {\n warn: number;\n soft: number;\n hard: number;\n}\n\nexport interface ContextWindowMode {\n id: ContextWindowModeId;\n name: string;\n description: string;\n thresholds: ContextWindowThresholds;\n aggressiveOn: ContextWindowAggressiveOn;\n preserveK: number;\n eliseThreshold: number;\n targetLoad: number;\n}\n\nexport interface ContextWindowPolicy extends ContextWindowMode {}\n\nexport interface ContextWindowConfigLike {\n mode?: ContextWindowModeId | string | undefined;\n warnThreshold?: number | undefined;\n softThreshold?: number | undefined;\n hardThreshold?: number | undefined;\n preserveK?: number | undefined;\n eliseThreshold?: number | undefined;\n}\n\nexport const DEFAULT_CONTEXT_WINDOW_MODE_ID: ContextWindowModeId = 'frugal';\n\nexport const CONTEXT_WINDOW_MODES: readonly ContextWindowMode[] = Object.freeze([\n {\n id: 'balanced',\n name: 'Balanced',\n description: 'Default rolling compaction: recent work stays verbatim, old tool output is trimmed.',\n thresholds: { warn: 0.5, soft: 0.65, hard: 0.8 },\n aggressiveOn: 'soft',\n preserveK: 8,\n eliseThreshold: 1000,\n targetLoad: 0.55,\n },\n {\n id: 'frugal',\n name: 'Frugal',\n description: 'Token-saver mode: compacts early and keeps a tighter verbatim tail.',\n thresholds: { warn: 0.45, soft: 0.6, hard: 0.75 },\n aggressiveOn: 'warn',\n preserveK: 6,\n eliseThreshold: 700,\n targetLoad: 0.5,\n },\n {\n id: 'deep',\n name: 'Deep',\n description: 'Long-reasoning mode: delays compaction and keeps more recent turns intact.',\n thresholds: { warn: 0.72, soft: 0.86, hard: 0.96 },\n aggressiveOn: 'hard',\n preserveK: 18,\n eliseThreshold: 5000,\n targetLoad: 0.78,\n },\n {\n id: 'archival',\n name: 'Archival',\n description: 'Decision-preserving mode: compacts steadily while keeping summaries prominent.',\n thresholds: { warn: 0.55, soft: 0.7, hard: 0.84 },\n aggressiveOn: 'soft',\n preserveK: 8,\n eliseThreshold: 1200,\n targetLoad: 0.58,\n },\n]);\n\nexport function listContextWindowModes(): ContextWindowMode[] {\n return CONTEXT_WINDOW_MODES.map((m) => ({ ...m, thresholds: { ...m.thresholds } }));\n}\n\nexport function getContextWindowMode(id: string | null | undefined): ContextWindowMode | null {\n if (!id) return null;\n const mode = CONTEXT_WINDOW_MODES.find((m) => m.id === id);\n return mode ? { ...mode, thresholds: { ...mode.thresholds } } : null;\n}\n\nexport function isContextWindowModeId(id: string): id is ContextWindowModeId {\n return CONTEXT_WINDOW_MODES.some((m) => m.id === id);\n}\n\nexport function resolveContextWindowPolicy(\n config: ContextWindowConfigLike = {},\n overrideMode?: string | null | undefined,\n): ContextWindowPolicy {\n const requested = overrideMode ?? config.mode ?? DEFAULT_CONTEXT_WINDOW_MODE_ID;\n const mode = getContextWindowMode(requested) ?? expectDefined(getContextWindowMode(DEFAULT_CONTEXT_WINDOW_MODE_ID));\n\n return {\n ...mode,\n thresholds: {\n warn: config.warnThreshold ?? mode.thresholds.warn,\n soft: config.softThreshold ?? mode.thresholds.soft,\n hard: config.hardThreshold ?? mode.thresholds.hard,\n },\n preserveK: config.preserveK ?? mode.preserveK,\n eliseThreshold: config.eliseThreshold ?? mode.eliseThreshold,\n };\n}\n\nexport function formatContextWindowModeList(activeId?: string | null): string {\n return CONTEXT_WINDOW_MODES.map((m) => {\n const marker = m.id === activeId ? '*' : ' ';\n return `${marker} ${m.id.padEnd(9)} ${m.name} - ${m.description}`;\n }).join('\\n');\n}\n", "export type SpecStatus = 'draft' | 'review' | 'approved' | 'implemented' | 'deprecated';\nexport type SpecSectionType =\n | 'overview'\n | 'requirements'\n | 'architecture'\n | 'api'\n | 'data'\n | 'security'\n | 'acceptance';\n\nexport interface SpecSection {\n type: SpecSectionType;\n title: string;\n content: string;\n level: number;\n children?: SpecSection[] | undefined;\n}\n\nexport interface SpecRequirement {\n id: string;\n type: 'functional' | 'non-functional' | 'security' | 'performance' | 'ux';\n priority: 'critical' | 'high' | 'medium' | 'low';\n description: string;\n acceptanceCriteria: string[];\n blockedBy?: string[] | undefined;\n implements?: string[] | undefined;\n}\n\nexport interface SpecApiEndpoint {\n method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';\n path: string;\n description: string;\n request?: Record<string, unknown>;\n response?: Record<string, unknown>;\n auth?: boolean | undefined;\n}\n\nexport interface Specification {\n id: string;\n title: string;\n version: string;\n status: SpecStatus;\n overview: string;\n sections: SpecSection[];\n requirements: SpecRequirement[];\n apiEndpoints?: SpecApiEndpoint[] | undefined;\n dependencies?: string[] | undefined;\n createdAt: number;\n updatedAt: number;\n metadata?: Record<string, unknown>;\n}\n\nexport interface SpecAnalysis {\n specId: string;\n completeness: number; // 0-100\n coverage: {\n requirements: number;\n apiEndpoints: number;\n edgeCases: number;\n errorHandling: number;\n };\n gaps: string[];\n risks: { requirement: string; risk: string; severity: 'high' | 'medium' | 'low' }[];\n suggestions: string[];\n}\n\nexport interface SpecValidationResult {\n valid: boolean;\n errors: { path: string; message: string }[];\n warnings: { path: string; message: string }[];\n}\n\nexport interface SpecTemplate {\n id: string;\n name: string;\n description: string;\n sections: Omit<SpecSection, 'content'>[];\n defaultRequirements: Omit<SpecRequirement, 'id' | 'description'>[];\n}\n\nexport const DEFAULT_SPEC_TEMPLATE: SpecTemplate = {\n id: 'default',\n name: 'Default Feature Spec',\n description: 'Standard template for feature specifications',\n sections: [\n { type: 'overview', title: 'Overview', level: 1 },\n { type: 'requirements', title: 'Requirements', level: 1 },\n { type: 'architecture', title: 'Architecture', level: 1 },\n { type: 'api', title: 'API Design', level: 1 },\n { type: 'data', title: 'Data Model', level: 1 },\n { type: 'security', title: 'Security', level: 1 },\n { type: 'acceptance', title: 'Acceptance Criteria', level: 1 },\n ],\n defaultRequirements: [\n { type: 'functional', priority: 'high', acceptanceCriteria: [], blockedBy: [], implements: [] },\n {\n type: 'non-functional',\n priority: 'medium',\n acceptanceCriteria: [],\n blockedBy: [],\n implements: [],\n },\n ],\n};\n", "export type TaskStatus = 'pending' | 'in_progress' | 'blocked' | 'failed' | 'review' | 'completed';\nexport type TaskPriority = 'critical' | 'high' | 'medium' | 'low';\nexport type TaskType = 'feature' | 'bugfix' | 'refactor' | 'docs' | 'test' | 'chore';\n\nexport interface TaskNode {\n id: string;\n title: string;\n description: string;\n type: TaskType;\n priority: TaskPriority;\n status: TaskStatus;\n assignee?: string | undefined;\n estimateHours?: number | undefined;\n actualHours?: number | undefined;\n tags?: string[] | undefined;\n specRequirementId?: string | undefined;\n parentId?: string | undefined;\n children?: string[] | undefined;\n createdAt: number;\n updatedAt: number;\n startedAt?: number | undefined; // set when status \u2192 in_progress\n completedAt?: number | undefined;\n metadata?: Record<string, unknown>;\n}\n\nexport interface TaskEdge {\n id: string;\n from: string;\n to: string;\n type: 'blocks' | 'depends_on' | 'relates_to' | 'implements';\n weight?: number | undefined;\n}\n\nexport interface TaskGraph {\n id: string;\n specId: string;\n title: string;\n nodes: Map<string, TaskNode>;\n edges: TaskEdge[];\n rootNodes: string[];\n createdAt: number;\n updatedAt: number;\n}\n\nexport interface TaskDependency {\n taskId: string;\n blockedBy: string[];\n blocking: string[];\n}\n\nexport interface TaskAssignment {\n taskId: string;\n assignee: string;\n assignedAt: number;\n}\n\nexport interface TaskProgress {\n total: number;\n pending: number;\n inProgress: number;\n blocked: number;\n failed: number;\n review: number;\n completed: number;\n percentComplete: number;\n estimatedHours: number;\n actualHours: number;\n}\n\nexport interface TaskFilter {\n status?: TaskStatus[] | undefined;\n priority?: TaskPriority[] | undefined;\n type?: TaskType[] | undefined;\n assignee?: string[] | undefined;\n tags?: string[] | undefined;\n specRequirementId?: string | undefined;\n}\n\nexport interface TaskSort {\n field: 'priority' | 'createdAt' | 'updatedAt' | 'status';\n direction: 'asc' | 'desc';\n}\n\nexport interface CriticalPathResult {\n taskIds: string[];\n totalEstimateHours: number;\n bottleneckTasks: string[];\n}\n\nexport function computeTaskProgress(graph: TaskGraph): TaskProgress {\n let completed = 0;\n let pending = 0;\n let inProgress = 0;\n let blocked = 0;\n let failed = 0;\n let review = 0;\n let estimatedHours = 0;\n let actualHours = 0;\n for (const n of graph.nodes.values()) {\n switch (n.status) {\n case 'completed':\n completed++;\n break;\n case 'pending':\n pending++;\n break;\n case 'in_progress':\n inProgress++;\n break;\n case 'blocked':\n blocked++;\n break;\n case 'failed':\n failed++;\n break;\n case 'review':\n review++;\n break;\n }\n estimatedHours += n.estimateHours ?? 0;\n actualHours += n.actualHours ?? 0;\n }\n const total = graph.nodes.size;\n\n return {\n total,\n pending,\n inProgress,\n blocked,\n failed,\n review,\n completed,\n percentComplete: total > 0 ? Math.round((completed / total) * 100) : 0,\n estimatedHours,\n actualHours,\n };\n}\n\nexport function findCriticalPath(graph: TaskGraph): CriticalPathResult {\n const nodes = Array.from(graph.nodes.values());\n const criticalNodes = nodes.filter((n) => n.priority === 'critical');\n const bottleneckTasks = criticalNodes\n .filter((n) => graph.edges.some((e) => e.to === n.id && e.type === 'depends_on'))\n .map((n) => n.id);\n\n const totalEstimateHours = criticalNodes.reduce((sum, n) => sum + (n.estimateHours ?? 0), 0);\n\n return {\n taskIds: criticalNodes.map((n) => n.id),\n totalEstimateHours,\n bottleneckTasks,\n };\n}\n\nexport function topologicalSort(graph: TaskGraph): string[] {\n const visited = new Set<string>();\n const inStack = new Set<string>();\n const result: string[] = [];\n\n function visit(id: string): void {\n // Cycle: callers must detect cycles up-front if they care; we just stop recursing.\n if (inStack.has(id)) return;\n if (visited.has(id)) return;\n if (!graph.nodes.has(id)) return;\n\n visited.add(id);\n inStack.add(id);\n\n for (const edge of graph.edges) {\n if (edge.from === id) visit(edge.to);\n }\n\n inStack.delete(id);\n result.push(id);\n }\n\n for (const rootId of graph.rootNodes) {\n visit(rootId);\n }\n\n return result;\n}\n\nexport type SerializableTaskGraphNodes =\n | TaskNode[]\n | Array<[string, TaskNode]>\n | Record<string, TaskNode>;\n\nexport type SerializableTaskGraph = Omit<TaskGraph, 'nodes'> & {\n nodes: SerializableTaskGraphNodes;\n};\n\nexport type SerializedTaskGraph = Omit<TaskGraph, 'nodes'> & {\n nodes: TaskNode[];\n};\n\nexport function serializeTaskGraph(graph: TaskGraph): SerializedTaskGraph {\n return {\n ...graph,\n nodes: Array.from(graph.nodes.values()),\n };\n}\n\nexport function deserializeTaskGraph(input: SerializableTaskGraph): TaskGraph {\n const nodes = new Map<string, TaskNode>();\n if (Array.isArray(input.nodes)) {\n for (const entry of input.nodes) {\n if (Array.isArray(entry)) nodes.set(entry[0], { ...entry[1], id: entry[1].id || entry[0] });\n else nodes.set(entry.id, entry);\n }\n } else {\n for (const [id, node] of Object.entries(input.nodes)) {\n nodes.set(id, { ...node, id: node.id || id });\n }\n }\n return { ...input, nodes };\n}\n", "import * as fs from 'node:fs/promises';\nimport { expectDefined } from '../utils/expect-defined.js';\nimport type { ContentBlock } from '../types/blocks.js';\nimport type {\n DefaultSessionReaderOptions,\n SessionExportOptions,\n SessionQuery,\n SessionReader,\n SessionSearchHit,\n SessionSearchQuery,\n SessionSummaryLite,\n} from '../types/session-reader.js';\nimport { compileUserRegex } from '../utils/regex-guard.js';\nimport { sessionScopedPath } from '../utils/session-scoped-path.js';\nimport type { SessionData, SessionEvent, SessionMetadata, SessionStore } from '../types/session.js';\n\n/**\n * L2-A: read-only view over a `SessionStore` with query, replay, search,\n * and export helpers. Implemented on top of the public `SessionStore`\n * surface so any concrete store can be inspected without re-implementation.\n */\nexport class DefaultSessionReader implements SessionReader {\n private readonly store: SessionStore;\n private readonly eventCache = new Map<string, SessionData>();\n private readonly eventCacheMtimes = new Map<string, number>();\n private static readonly EVENT_CACHE_MAX_ENTRIES = 32;\n\n constructor(opts: DefaultSessionReaderOptions) {\n this.store = opts.store;\n }\n\n private async loadCachedSessionData(sessionId: string): Promise<SessionData> {\n const storeWithPath = this.store as SessionStore & {\n dir?: string | undefined;\n clearLoadCache?: ((sessionId?: string | undefined) => void) | undefined;\n };\n const rootDir = storeWithPath.dir;\n if (!rootDir) {\n return await this.store.load(sessionId);\n }\n const sessionPath = sessionScopedPath(rootDir, sessionId, '.jsonl');\n let mtimeMs: number | null = null;\n try {\n const stat = await fs.stat(sessionPath);\n mtimeMs = stat.mtimeMs;\n } catch {\n this.eventCache.delete(sessionId);\n this.eventCacheMtimes.delete(sessionId);\n return await this.store.load(sessionId);\n }\n\n const cachedMtime = this.eventCacheMtimes.get(sessionId);\n const cachedData = this.eventCache.get(sessionId);\n if (cachedData && cachedMtime === mtimeMs) {\n this.eventCache.delete(sessionId);\n this.eventCacheMtimes.delete(sessionId);\n this.eventCache.set(sessionId, cachedData);\n this.eventCacheMtimes.set(sessionId, mtimeMs);\n return cachedData;\n }\n\n const data = await this.store.load(sessionId);\n this.eventCache.delete(sessionId);\n this.eventCacheMtimes.delete(sessionId);\n this.eventCache.set(sessionId, data);\n this.eventCacheMtimes.set(sessionId, mtimeMs);\n while (this.eventCache.size > DefaultSessionReader.EVENT_CACHE_MAX_ENTRIES) {\n const oldest = this.eventCache.keys().next().value;\n if (oldest === undefined) break;\n this.eventCache.delete(oldest);\n this.eventCacheMtimes.delete(oldest);\n }\n\n if (data.metadata.endedAt) {\n storeWithPath.clearLoadCache?.(sessionId);\n }\n\n return data;\n }\n\n async query(q: SessionQuery = {}): Promise<SessionSummaryLite[]> {\n // Prefer the store's filtered list when available \u2014 it pushes the\n // filter into the cached index instead of fetching 1000 + linear scan.\n const storeWithFilter = this.store as SessionStore & {\n listFiltered?: ((criteria: {\n since?: string | undefined;\n until?: string | undefined;\n provider?: string | undefined;\n model?: string | undefined;\n minTokens?: number | undefined;\n titleContains?: string | undefined;\n limit?: number | undefined;\n }) => Promise<import('../types/session.js').SessionSummary[]>) | undefined;\n };\n let raw: import('../types/session.js').SessionSummary[];\n if (typeof storeWithFilter.listFiltered === 'function') {\n raw = await storeWithFilter.listFiltered({\n since: q.since,\n until: q.until,\n provider: q.provider,\n model: q.model,\n minTokens: q.minTokens,\n titleContains: q.titleContains,\n limit: q.limit,\n });\n } else {\n const fetched = await this.store.list(q.limit ? Math.max(q.limit, 100) : 1000);\n const titleNeedle = q.titleContains?.toLowerCase();\n raw = fetched.filter((s) => {\n if (q.since && s.startedAt < q.since) return false;\n if (q.until && s.startedAt > q.until) return false;\n if (q.provider && s.provider !== q.provider) return false;\n if (q.model && s.model !== q.model) return false;\n if (q.minTokens !== undefined && s.tokenTotal < q.minTokens) return false;\n if (titleNeedle && !s.title.toLowerCase().includes(titleNeedle)) return false;\n return true;\n });\n }\n const out: SessionSummaryLite[] = raw.map((s) => ({\n id: s.id,\n title: s.title,\n startedAt: s.startedAt,\n provider: s.provider,\n model: s.model,\n tokenTotal: s.tokenTotal,\n }));\n return q.limit ? out.slice(0, q.limit) : out;\n }\n\n async *replay(sessionId: string): AsyncIterable<SessionEvent> {\n const data = await this.loadCachedSessionData(sessionId);\n for (const e of data.events) yield e;\n }\n\n async search(q: SessionSearchQuery, sessionId?: string | undefined, sessionQuery?: SessionQuery): Promise<SessionSearchHit[]> {\n const limit = q.limit ?? 100;\n const matcher = buildMatcher(q);\n const allowedTypes = q.types ? new Set(q.types) : null;\n\n // Filter sessions BEFORE scanning events \u2014 avoids touching the JSONL\n // for sessions that don't match the time/provider/model criteria.\n let ids: string[];\n if (sessionId) {\n ids = [sessionId];\n } else {\n // Prefer the store's filtered list when available \u2014 avoids fetching\n // 1000 sessions and linear-filtering in-process.\n const storeWithFilter = this.store as SessionStore & {\n listFiltered?: ((criteria: {\n since?: string | undefined;\n until?: string | undefined;\n provider?: string | undefined;\n model?: string | undefined;\n minTokens?: number | undefined;\n titleContains?: string | undefined;\n limit?: number | undefined;\n }) => Promise<import('../types/session.js').SessionSummary[]>) | undefined;\n };\n let sessions: import('../types/session.js').SessionSummary[];\n if (typeof storeWithFilter.listFiltered === 'function') {\n sessions = await storeWithFilter.listFiltered({\n since: sessionQuery?.since,\n until: sessionQuery?.until,\n provider: sessionQuery?.provider,\n model: sessionQuery?.model,\n minTokens: sessionQuery?.minTokens,\n titleContains: sessionQuery?.titleContains,\n limit: 1000,\n });\n } else {\n sessions = await this.store.list(1000);\n const titleNeedle = sessionQuery?.titleContains?.toLowerCase();\n sessions = sessions.filter((s) => {\n if (sessionQuery?.since && s.startedAt < sessionQuery.since) return false;\n if (sessionQuery?.until && s.startedAt > sessionQuery.until) return false;\n if (sessionQuery?.provider && s.provider !== sessionQuery.provider) return false;\n if (sessionQuery?.model && s.model !== sessionQuery.model) return false;\n if (sessionQuery?.minTokens !== undefined && s.tokenTotal < sessionQuery.minTokens) return false;\n if (titleNeedle && !s.title.toLowerCase().includes(titleNeedle)) return false;\n return true;\n });\n }\n ids = sessions.map((s) => s.id);\n }\n\n const hits: SessionSearchHit[] = [];\n\n // Fast path: when the underlying store supports streaming search,\n // walk each session's JSONL line-by-line and bail out the moment we\n // hit `limit`. This avoids reading + parsing the entire file (which\n // `load()` does) and never reuses `_loadCache`, so concurrent\n // analytics queries don't churn the writer-side cache.\n const streaming = this.store.searchEvents?.bind(this.store);\n if (streaming) {\n for (const id of ids) {\n const matched = await streaming(\n id,\n (ev) => {\n if (allowedTypes && !allowedTypes.has(ev.type)) return false;\n const text = eventText(ev);\n if (text === null) return false;\n return matcher(text) !== null;\n },\n { limit: limit - hits.length },\n );\n for (const m of matched) {\n const text = expectDefined(eventText(m.event));\n const hit = expectDefined(matcher(text));\n hits.push({\n sessionId: id,\n eventIndex: m.eventIndex,\n ts: m.ts,\n type: m.event.type,\n snippet: snippetOf(text, hit.start, hit.end),\n });\n if (hits.length >= limit) return hits;\n }\n }\n return hits;\n }\n\n // Fallback: stores that don't implement streaming. Loads the full\n // event stream per session \u2014 necessary for in-memory or non-file\n // stores that don't expose a streaming surface.\n for (const id of ids) {\n let data;\n try {\n data = await this.loadCachedSessionData(id);\n } catch {\n continue;\n }\n for (let i = 0; i < data.events.length; i++) {\n const ev = expectDefined(data.events[i]);\n if (allowedTypes && !allowedTypes.has(ev.type)) continue;\n const text = eventText(ev);\n if (text === null) continue;\n const hit = matcher(text);\n if (!hit) continue;\n hits.push({\n sessionId: id,\n eventIndex: i,\n ts: ev.ts,\n type: ev.type,\n snippet: snippetOf(text, hit.start, hit.end),\n });\n if (hits.length >= limit) return hits;\n }\n }\n return hits;\n }\n\n async export(sessionId: string, opts: SessionExportOptions): Promise<string> {\n const data = await this.loadCachedSessionData(sessionId);\n const includeTools = opts.includeTools ?? true;\n const includeDiagnostics = opts.includeDiagnostics ?? true;\n\n const filtered = data.events.filter((e) => {\n if (\n !includeTools &&\n (e.type === 'tool_use' ||\n e.type === 'tool_result' ||\n e.type === 'tool_call_start' ||\n e.type === 'tool_call_end')\n ) {\n return false;\n }\n if (\n !includeDiagnostics &&\n (e.type === 'error' || e.type === 'compaction' || e.type === 'message_truncated')\n ) {\n return false;\n }\n return true;\n });\n\n if (opts.format === 'json') {\n return JSON.stringify({ metadata: data.metadata, events: filtered }, null, 2);\n }\n if (opts.format === 'text') {\n return renderPlainText(data.metadata, filtered);\n }\n return renderMarkdown(data.metadata, filtered);\n }\n\n async metadata(sessionId: string): Promise<SessionMetadata> {\n const data = await this.loadCachedSessionData(sessionId);\n return data.metadata;\n }\n}\n\nfunction buildMatcher(\n q: SessionSearchQuery,\n): (text: string) => { start: number; end: number } | null {\n const ci = q.caseInsensitive ?? true;\n if (q.regex) {\n const flags = ci ? 'i' : '';\n const compiled = compileUserRegex(q.query, flags);\n if (!compiled.ok) {\n throw new Error(`Invalid search regex \"${q.query}\": ${compiled.reason}`);\n }\n const re = compiled.regex;\n return (text) => {\n const m = re.exec(text);\n return m ? { start: m.index, end: m.index + m[0].length } : null;\n };\n }\n const needle = ci ? q.query.toLowerCase() : q.query;\n return (text) => {\n const hay = ci ? text.toLowerCase() : text;\n const idx = hay.indexOf(needle);\n return idx === -1 ? null : { start: idx, end: idx + needle.length };\n };\n}\n\nfunction eventText(e: SessionEvent): string | null {\n switch (e.type) {\n case 'user_input':\n return contentToString(e.content);\n case 'llm_response':\n return contentToString(e.content);\n case 'tool_use':\n return `${e.name} ${JSON.stringify(e.input)}`;\n case 'tool_result':\n return typeof e.content === 'string' ? e.content : JSON.stringify(e.content);\n case 'error':\n return `${e.phase}: ${e.message}`;\n case 'session_start':\n case 'session_resumed':\n return `${e.model}/${e.provider}`;\n case 'task_created':\n case 'task_completed':\n return e.title;\n case 'task_failed':\n return `${e.title}: ${e.error}`;\n case 'skill_activated':\n case 'skill_deactivated':\n return e.skillName;\n default:\n return null;\n }\n}\n\nfunction contentToString(content: string | ContentBlock[]): string {\n if (typeof content === 'string') return content;\n return content\n .map((b) => {\n switch (b.type) {\n case 'text':\n return b.text;\n case 'tool_use':\n return `[tool_use:${b.name} ${JSON.stringify(b.input)}]`;\n case 'tool_result':\n return typeof b.content === 'string' ? b.content : JSON.stringify(b.content);\n default:\n return '';\n }\n })\n .join('\\n');\n}\n\nconst SNIPPET_RADIUS = 60;\n\nfunction snippetOf(text: string, start: number, end: number): string {\n const from = Math.max(0, start - SNIPPET_RADIUS);\n const to = Math.min(text.length, end + SNIPPET_RADIUS);\n const prefix = from > 0 ? '\u2026' : '';\n const suffix = to < text.length ? '\u2026' : '';\n return prefix + text.slice(from, to).replace(/\\s+/g, ' ').trim() + suffix;\n}\n\nfunction renderMarkdown(meta: SessionMetadata, events: SessionEvent[]): string {\n const lines: string[] = [];\n lines.push(`# Session ${meta.id}`);\n lines.push('');\n if (meta.model || meta.provider) {\n lines.push(`- **Model:** ${meta.provider ?? '?'}/${meta.model ?? '?'}`);\n }\n lines.push(`- **Started:** ${meta.startedAt}`);\n if (meta.endedAt) lines.push(`- **Ended:** ${meta.endedAt}`);\n lines.push('');\n lines.push('---');\n lines.push('');\n for (const e of events) {\n switch (e.type) {\n case 'user_input': {\n lines.push(`## User \u2014 ${e.ts}`);\n lines.push('');\n lines.push(contentToString(e.content));\n lines.push('');\n break;\n }\n case 'llm_response': {\n lines.push(`## Assistant \u2014 ${e.ts}`);\n lines.push('');\n lines.push(contentToString(e.content));\n if (e.stopReason && e.stopReason !== 'end_turn') {\n lines.push('');\n lines.push(`*stop: ${e.stopReason}*`);\n }\n lines.push('');\n break;\n }\n case 'tool_use': {\n lines.push(`### Tool call: \\`${e.name}\\``);\n lines.push('');\n lines.push('```json');\n lines.push(JSON.stringify(e.input, null, 2));\n lines.push('```');\n lines.push('');\n break;\n }\n case 'tool_result': {\n const body = typeof e.content === 'string' ? e.content : JSON.stringify(e.content, null, 2);\n lines.push(`### Tool result${e.isError ? ' (error)' : ''}`);\n lines.push('');\n lines.push('```');\n lines.push(body);\n lines.push('```');\n lines.push('');\n break;\n }\n case 'error': {\n lines.push(`> **Error** (${e.phase}): ${e.message}`);\n lines.push('');\n break;\n }\n case 'compaction': {\n lines.push(`> **Compaction**: ${e.before} \u2192 ${e.after} tokens`);\n lines.push('');\n break;\n }\n default:\n break;\n }\n }\n return lines.join('\\n');\n}\n\nfunction renderPlainText(meta: SessionMetadata, events: SessionEvent[]): string {\n const lines: string[] = [];\n lines.push(\n `Session ${meta.id} \u2014 ${meta.provider ?? '?'}/${meta.model ?? '?'} \u2014 started ${meta.startedAt}`,\n );\n lines.push(''.padEnd(72, '-'));\n for (const e of events) {\n switch (e.type) {\n case 'user_input':\n lines.push(`[${e.ts}] USER`);\n lines.push(contentToString(e.content));\n lines.push('');\n break;\n case 'llm_response':\n lines.push(`[${e.ts}] ASSISTANT`);\n lines.push(contentToString(e.content));\n lines.push('');\n break;\n case 'tool_use':\n lines.push(`[${e.ts}] TOOL_USE ${e.name} ${JSON.stringify(e.input)}`);\n break;\n case 'tool_result':\n lines.push(\n `[${e.ts}] TOOL_RESULT${e.isError ? ' (error)' : ''} ${\n typeof e.content === 'string' ? e.content : JSON.stringify(e.content)\n }`,\n );\n break;\n case 'error':\n lines.push(`[${e.ts}] ERROR (${e.phase}): ${e.message}`);\n break;\n default:\n break;\n }\n }\n return lines.join('\\n');\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["ToolErrorCategory", "path", "stat"]
7
7
  }