@ordewell/core 0.4.0 → 0.4.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 +1 @@
1
- {"version":3,"sources":["../src/interfaces/IFileSystem.ts","../src/interfaces/IApproval.ts","../src/services/commandPolicy.ts","../src/services/researchShell.ts","../src/services/pathScope.ts","../src/services/symbolPatterns.ts","../src/services/BaseFileSystem.ts","../src/services/ApprovalPolicy.ts","../src/services/PendingApprovals.ts","../src/services/ripgrepArgs.ts","../src/interfaces/IConfig.ts","../src/services/ProviderRegistry.ts","../src/interfaces/BaseConfig.ts","../src/interfaces/EnvConfig.ts","../src/interfaces/ILogger.ts","../src/services/BaseAiService.ts","../src/services/plannerModes.ts","../src/services/PlanPrompts.ts","../src/services/PlanRepair.ts","../src/services/researchTools.ts","../src/services/contextCompaction.ts","../src/utils/prdStore.ts","../src/services/ContextCollector.ts","../src/services/executeTool.ts","../src/services/ResearchSubagents.ts","../src/services/GeminiService.ts","../src/services/OpenAiService.ts","../src/services/promptAugment.ts","../src/services/VerdictEngine.ts","../src/services/PlanStore.ts","../src/services/TaskOrchestrator.ts","../src/services/ModelAllowlistResolver.ts","../src/services/Planner.ts","../src/services/ModelDiscovery.ts","../src/utils/shellPath.ts","../src/utils/launch.ts","../src/utils/shell.ts","../src/utils/processTree.ts","../src/services/ModelCatalog.ts","../src/services/ModelShortcuts.ts","../src/services/ProviderRouting.ts","../src/services/ModelResolver.ts","../src/services/RunnerInstallation.ts","../src/services/harness/CliAgentAiService.ts","../src/services/harness/AgentAdapter.ts","../src/services/harness/StdioAgentAdapter.ts","../src/services/harness/ClaudeCodeAdapter.ts","../src/services/harness/codexSandbox.ts","../src/services/harness/CodexAdapter.ts","../src/services/harness/OpenCodeAdapter.ts","../src/services/harness/agentTools.ts","../src/services/AiService.ts","../src/services/HttpWebFetcher.ts","../src/services/TaskRetarget.ts","../src/services/SessionMessage.ts","../src/utils/sessionStore.ts","../src/utils/fsHelpers.ts","../src/services/createSession.ts","../src/plugins/resolveArgs.ts","../src/services/buildRunnerArgs.ts","../src/services/HeadlessRunner.ts","../src/services/AbstractRunner.ts","../src/services/TmuxRunner.ts","../src/utils/tmux.ts","../src/plugins/RunnerRegistry.ts","../src/plugins/FsPluginStore.ts","../src/plugins/builtin/claude-code.manifest.ts","../src/plugins/builtin/codex.manifest.ts","../src/plugins/builtin/opencode.manifest.ts","../src/utils/stateStore.ts","../src/services/SettingsService.ts"],"sourcesContent":["export interface ToolOutcome {\n success: boolean;\n output: string;\n truncated: boolean;\n}\n\nexport interface ReadFileOpts {\n maxBytes?: number;\n offset?: number;\n limit?: number;\n}\n\n/**\n * `content` returns matching lines, `files` only the paths that matched, and\n * `count` a per-file tally. Cheap models otherwise grep and then read whole\n * files to answer \"which files touch this\", burning rounds against the budget.\n */\nexport type GrepOutputMode = 'content' | 'files' | 'count';\n\nexport interface GrepOptions {\n /** File glob filter, e.g. `*.ts`. */\n include?: string;\n /** Search root. Relative to the workspace unless approved as external. */\n path?: string;\n outputMode?: GrepOutputMode;\n /** Lines of context around each match (`content` mode only). */\n contextBefore?: number;\n contextAfter?: number;\n /** Treat the pattern as a literal string rather than a regex. */\n literal?: boolean;\n caseInsensitive?: boolean;\n /** Global cap on returned rows. Defaults to {@link GREP_DEFAULT_HEAD_LIMIT}. */\n headLimit?: number;\n}\n\nexport interface GlobOptions {\n /** Search root. Relative to the workspace unless approved as external. */\n path?: string;\n headLimit?: number;\n}\n\nexport interface FindSymbolOptions {\n /** Language id or file extension, e.g. `typescript` or `.go`. Narrows the keyword set. */\n language?: string;\n /** Search root. Relative to the workspace unless approved as external. */\n path?: string;\n}\n\n/** Global row cap for grep. A per-file cap is not a budget — see PoolFileSystem. */\nexport const GREP_DEFAULT_HEAD_LIMIT = 100;\n\n/**\n * Directories that are never interesting to a planner and would otherwise eat\n * the result budget. Applied by every search entry point, not just `glob` —\n * `dist/` and `.ordewell/` are frequently not gitignored.\n */\nexport const SEARCH_EXCLUSIONS = [\n 'node_modules', '.git', '.ordewell', 'dist', 'build', 'out', 'target',\n '.next', '.nuxt', '.venv', 'venv', '__pycache__', '.mypy_cache', '.pytest_cache',\n 'vendor', 'coverage', '.turbo', '.cache', '.gradle', 'Pods', '.terraform',\n];\n\nexport interface IFileSystem {\n readFile(path: string, opts?: ReadFileOpts): Promise<ToolOutcome>;\n readFiles(paths: string[]): Promise<ToolOutcome>;\n glob(pattern: string, opts?: GlobOptions): Promise<ToolOutcome>;\n grep(pattern: string, opts?: GrepOptions): Promise<ToolOutcome>;\n listDir(path: string, depth?: number): Promise<ToolOutcome>;\n bash(command: string): Promise<ToolOutcome>;\n /** Definition-first lookup for one symbol. See `symbolPatterns.ts`. */\n findSymbol(symbol: string, opts?: FindSymbolOptions): Promise<ToolOutcome>;\n getWorkspaceRoot(): string;\n /**\n * Inject the human-approval channel for out-of-envelope access. Optional so\n * test doubles stay small; every adapter extending `BaseFileSystem` has it.\n */\n setApproval?(approval: import('./IApproval').IApproval): void;\n}\n","/**\n * The planner's single approval seam. Every capability that reaches beyond the\n * default read-only, in-workspace envelope — a path outside the workspace root,\n * a shell command outside the auto-allowed set, a URL fetch — routes through\n * one `request()` so the policy has exactly one owner (the same \"one repair\n * owner\" shape as PlanRepair).\n *\n * Surfaces supply the human channel. VS Code answers with a modal; the web\n * server currently has no prompt UI, so it denies unless the scope was\n * pre-approved through config. Denial is always a visible, actionable tool\n * result — never a silent success.\n */\n\nexport type ApprovalKind = 'external_path' | 'shell_command' | 'url_fetch';\n\nexport interface ApprovalRequest {\n kind: ApprovalKind;\n /** The concrete thing being asked about: an absolute path, a command line, a URL. */\n subject: string;\n /**\n * What a grant covers. Approving remembers this, not `subject`, so reading a\n * second file from an already-approved directory does not prompt again.\n */\n scope: string;\n /** One-line context for the prompt. */\n detail?: string;\n}\n\nexport interface IApproval {\n request(req: ApprovalRequest): Promise<boolean>;\n}\n\n/** Denies everything. The safe default when a surface wires no approval channel. */\nexport const DENY_ALL: IApproval = {\n async request() { return false; },\n};\n","/**\n * Tiered classification for the planner's `bash` tool.\n *\n * The planner is a read-only researcher: it never edits files, and the runners\n * do the real work. But research legitimately means running things — querying a\n * cloud control plane (`az`, `gh`), reproducing a failure (`npm test`), or\n * shaping output (`jq`). The old allowlist refused all of that, so the model's\n * only escape was to guess.\n *\n * Three tiers replace the flat allowlist:\n *\n * auto read-only inspection — runs with no prompt (the historical list)\n * ask anything else that is not obviously destructive — one approval,\n * remembered for the rest of the session at `scope` granularity\n * refuse writes, privilege escalation, and anything that would smuggle\n * arbitrary code past this classifier — never runs, never prompts\n *\n * `refuse` is deliberately not promptable. A planner that can `rm` is a planner\n * that can silently break the workspace it was asked to reason about, and the\n * architecture already says mutation belongs to the runners.\n *\n * Classification walks every segment of the command line (pipes, `&&`, `;`, and\n * command substitution) rather than matching substrings against the raw string.\n * The old substring denylist both over-matched (`ls docs/removed` tripped `rm`)\n * and under-matched (`$(rm -rf /)` was invisible once chaining was allowed).\n *\n * The lexer is dialect-aware, because the interpreter that will actually run\n * the command decides what the tokens are, and getting that wrong is not a\n * cosmetic error here — it is the difference between classifying what runs and\n * classifying something else. See {@link Dialect}.\n */\n\nimport type { ShellDialect } from './researchShell';\n\nexport const AUTO_COMMANDS = [\n 'ls', 'tree', 'git', 'wc', 'du', 'df', 'file', 'head', 'tail', 'cat', 'sort', 'uniq',\n 'echo', 'printf', 'date', 'stat', 'basename', 'dirname', 'realpath', 'pwd',\n 'which', 'type', 'env', 'uname', 'whoami', 'cut', 'nl', 'rg', 'grep', 'find', 'jq', 'yq',\n];\n\nexport const GIT_READONLY_SUBCOMMANDS = [\n 'log', 'status', 'diff', 'show', 'ls-files', 'ls-remote', 'ls-tree', 'branch', 'tag',\n 'rev-parse', 'rev-list', 'describe', 'blame', 'grep', 'shortlog', 'whatchanged', 'cat-file',\n];\n\n/**\n * Never runs, with or without approval.\n *\n * The `cmd.exe` builtins at the end matter as much as the POSIX names above\n * them. `del`, `rd`, `move`, and friends mutate exactly what `rm` and `mv` do,\n * and on Windows they are what a model reaches for — so without them the whole\n * refusal tier was bypassable on that platform by writing the command the way\n * the platform spells it. Listed unconditionally rather than per-platform: a\n * POSIX box has no `del` to refuse, so the extra names cost nothing there.\n */\nexport const REFUSED_COMMANDS = [\n 'rm', 'rmdir', 'unlink', 'shred', 'truncate', 'dd', 'mkfs', 'fdisk', 'parted',\n 'mv', 'cp', 'install', 'ln', 'chmod', 'chown', 'chgrp', 'chattr',\n 'mount', 'umount', 'sudo', 'doas', 'su', 'passwd',\n 'kill', 'killall', 'pkill', 'shutdown', 'reboot', 'halt', 'poweroff',\n 'systemctl', 'service', 'crontab', 'tee', 'dput', 'mkdir', 'touch',\n // Windows: destructive cmd.exe builtins and their utility equivalents.\n 'del', 'erase', 'rd', 'md', 'move', 'copy', 'xcopy', 'robocopy', 'ren', 'rename',\n 'mklink', 'attrib', 'icacls', 'cacls', 'takeown', 'format', 'diskpart',\n 'taskkill', 'tskill', 'reg', 'regedit', 'sc', 'net', 'runas', 'schtasks',\n];\n\n/** Destructive or outward-facing subcommands of otherwise-permitted multiplexers. */\nconst REFUSED_SUBCOMMANDS: Record<string, string[]> = {\n git: ['push', 'reset', 'clean', 'checkout', 'switch', 'restore', 'rebase', 'merge', 'commit',\n 'am', 'apply', 'cherry-pick', 'revert', 'stash', 'gc', 'prune', 'filter-branch',\n 'update-ref', 'remote', 'config', 'init', 'clone', 'fetch', 'pull', 'submodule'],\n npm: ['publish', 'unpublish', 'deprecate', 'owner', 'access', 'token', 'login', 'logout'],\n yarn: ['publish', 'npm'],\n pnpm: ['publish'],\n docker: ['push', 'rm', 'rmi', 'kill', 'stop', 'prune', 'system'],\n kubectl: ['delete', 'apply', 'create', 'patch', 'replace', 'edit', 'drain', 'cordon', 'scale'],\n gh: ['release', 'secret', 'auth'],\n az: ['login', 'logout'],\n terraform: ['apply', 'destroy'],\n};\n\n/** Binaries that execute whatever they are handed — refused when given inline code or fed from a pipe. */\nconst INTERPRETERS = ['sh', 'bash', 'zsh', 'fish', 'dash', 'ksh', 'csh', 'tcsh', 'pwsh', 'powershell',\n 'python', 'python2', 'python3', 'node', 'deno', 'bun', 'ruby', 'perl', 'php', 'eval', 'exec', 'xargs',\n // Windows interpreters. `cmd /c \"…\"` is the platform's spelling of `sh -c`.\n 'cmd', 'wscript', 'cscript', 'mshta', 'rundll32', 'regsvr32'];\n\n/**\n * Flags that hand an interpreter code to run. Compared case-insensitively:\n * cmd.exe and PowerShell both accept their switches in any casing, so a\n * case-sensitive list refused `-Command` and waved `-command` through.\n */\nconst INLINE_CODE_FLAGS = ['-c', '-e', '--eval', '--command', '-Command', '--exec', '/c', '/k', '/r'];\n\nfunction isInlineCodeFlag(arg: string): boolean {\n const lower = arg.toLowerCase();\n return INLINE_CODE_FLAGS.some((f) => f.toLowerCase() === lower);\n}\n\n/** Multiplexers whose first non-flag argument is meaningful enough to scope a grant. */\nconst MULTIPLEXERS = ['git', 'npm', 'yarn', 'pnpm', 'npx', 'cargo', 'go', 'dotnet', 'docker', 'podman',\n 'kubectl', 'helm', 'az', 'aws', 'gcloud', 'gh', 'glab', 'terraform', 'make', 'mvn', 'gradle',\n 'composer', 'pip', 'pip3', 'poetry', 'uv', 'bundle', 'rake', 'swift', 'flutter', 'dart'];\n\n/**\n * What the interpreter that will run this command treats as syntax.\n *\n * `BaseFileSystem.execBashImpl` runs the command through `shell: true`, which\n * means `/bin/sh` on POSIX and `cmd.exe` on Windows — two different languages.\n * Lexing cmd.exe input with POSIX rules is not a near-miss, it inverts specific\n * answers: `\\` is an escape in sh and an ordinary path separator in cmd, so\n * `rg pattern C:\\repo\\src` tokenized to `C:reposrc`, which then failed\n * containment against the very workspace it named. And `'` is a quote in sh and\n * a literal character in cmd, so `echo it's & del x` hid the `del` inside what\n * the lexer believed was a quoted string.\n *\n * Only the four rules that actually diverge are modeled. Constructs cmd.exe\n * lacks (`$(…)`, backticks) are still recognized on Windows: over-splitting\n * costs a needless approval prompt, under-splitting costs the gate.\n */\nexport interface Dialect {\n /** The character that escapes the next one outside quotes. */\n escape: string;\n /**\n * Whether {@link escape} still escapes inside a double-quoted run.\n *\n * POSIX `\\` does; cmd.exe `^` does not. Getting this wrong is not cosmetic:\n * with `^` honoured inside quotes, `echo \"a^\"& del b` lexed as one `echo`\n * segment — the escape swallowed the closing quote, so the `&` looked quoted\n * and the `del` cmd.exe would actually run became an argument nobody\n * classified.\n */\n escapeInQuotes: boolean;\n /** Characters that open a quoted run. */\n quotes: string[];\n /** Matches a variable reference the interpreter will expand. */\n expansion: RegExp;\n /** Executable extensions stripped before a binary is matched against the tiers. */\n strippedExtensions: string[];\n}\n\nconst POSIX_DIALECT: Dialect = {\n escape: '\\\\',\n escapeInQuotes: true,\n quotes: [\"'\", '\"'],\n expansion: /^\\$[A-Za-z_{]/,\n strippedExtensions: [],\n};\n\nconst CMD_DIALECT: Dialect = {\n escape: '^',\n escapeInQuotes: false,\n quotes: ['\"'],\n // `%VAR%` and delayed-expansion `!VAR!`.\n expansion: /^[%!][A-Za-z_]/,\n // Without this, `del.exe` and `C:\\bin\\del.exe` both missed the refusal list.\n strippedExtensions: ['.exe', '.cmd', '.bat', '.com', '.ps1', '.msc'],\n};\n\nfunction dialectFor(dialect: ShellDialect | undefined): Dialect {\n const resolved = dialect ?? (process.platform === 'win32' ? 'cmd' : 'posix');\n return resolved === 'cmd' ? CMD_DIALECT : POSIX_DIALECT;\n}\n\n/**\n * Options threaded through classification.\n *\n * `dialect` is keyed to the interpreter rather than the OS on purpose: a Windows\n * host that has Git Bash runs the planner's commands in a POSIX shell (see\n * {@link resolveResearchShell}), and classifying those under cmd.exe rules\n * would be the same mismatch in the other direction. Callers pass the dialect of\n * the shell they are actually going to use; omitting it falls back to the host\n * default.\n */\nexport interface CommandPolicyOptions {\n dialect?: ShellDialect;\n}\n\nexport type CommandTier = 'auto' | 'ask' | 'refuse';\n\nexport interface CommandClassification {\n tier: CommandTier;\n /** What a grant covers, for `ask`. Derived from the non-auto segments only. */\n scope: string;\n /** Populated for `refuse`: why, in a sentence the model can act on. */\n reason?: string;\n}\n\ninterface Segment {\n binary: string;\n args: string[];\n /** True when this segment consumes another command's output (`… | seg`). */\n piped: boolean;\n /**\n * A token contains a `$var` the shell will expand. Tracked at lex time\n * because only the lexer knows a `$` inside single quotes is literal.\n */\n expandable: boolean;\n}\n\ninterface Lexed {\n segments: Segment[];\n /** An unquoted `>`/`>>` writes a file. */\n redirect: boolean;\n /** An unquoted `<(…)`/`>(…)` spawns a process this classifier never tokenizes. */\n processSubstitution: boolean;\n /** Lexing ran off the end inside a quote or a substitution — nothing here is trustworthy. */\n unbalanced: boolean;\n}\n\n/** Index of the `)` closing the `(` at `open`, or -1. */\nfunction matchParen(s: string, open: number): number {\n let depth = 0;\n for (let i = open; i < s.length; i++) {\n if (s[i] === '(') depth++;\n else if (s[i] === ')' && --depth === 0) return i;\n }\n return -1;\n}\n\n/**\n * Tokenize one command line the way a shell would: quotes and backslashes are\n * consumed, and only *unquoted* metacharacters are operators.\n *\n * This is the whole difference between the classifier seeing what will run and\n * seeing the raw string. Splitting on a bare `/[|;&]/` made `rg \"error|warn\"`\n * two segments (so the planner's commonest search asked for approval, scoped to\n * the nonsense binary `warn\"`), while leaving quotes on argument tokens hid\n * `cat \"/etc/passwd\"` from the path-confinement check entirely.\n *\n * Substitution bodies are lifted out into `nested` and classified as their own\n * command lines, so `$(rm -rf /)` cannot hide inside an `echo`.\n */\nfunction lex(command: string, nested: string[], dialect: Dialect): Lexed {\n const segments: Segment[] = [];\n let redirect = false;\n let processSubstitution = false;\n let unbalanced = false;\n\n let tokens: string[] = [];\n let expandable = false;\n let current = '';\n let started = false;\n let piped = false;\n let quote = '';\n\n const endToken = () => {\n if (started) tokens.push(current);\n current = '';\n started = false;\n };\n const endSegment = (nextPiped: boolean) => {\n endToken();\n if (tokens.length > 0) segments.push({ ...toSegment(tokens, piped, dialect), expandable });\n tokens = [];\n expandable = false;\n piped = nextPiped;\n };\n\n let i = 0;\n while (i < command.length) {\n const c = command[i];\n\n // A single-quoted run is literal end to end — no escapes, no expansion.\n // Only POSIX has one; `CMD_DIALECT.quotes` omits `'` so this never fires\n // there, and an apostrophe stays an ordinary character.\n if (quote === \"'\") {\n if (c === \"'\") { quote = ''; i++; continue; }\n current += c; started = true; i++; continue;\n }\n\n // `quote` is '' or '\"' here — the single-quote run returned above.\n if (c === dialect.escape && (quote === '' || dialect.escapeInQuotes)) {\n const next = command[i + 1];\n if (next !== undefined) { current += next; started = true; }\n i += 2; continue;\n }\n\n // Substitutions expand inside double quotes too, so these precede the\n // double-quote passthrough below.\n if (c === '$' && command[i + 1] === '(') {\n const close = matchParen(command, i + 1);\n if (close < 0) { unbalanced = true; break; }\n nested.push(command.slice(i + 2, close));\n started = true;\n i = close + 1; continue;\n }\n if (c === '`') {\n const close = command.indexOf('`', i + 1);\n if (close < 0) { unbalanced = true; break; }\n nested.push(command.slice(i + 1, close));\n started = true;\n i = close + 1; continue;\n }\n if (dialect.expansion.test(command.slice(i, i + 2))) {\n expandable = true;\n current += c; started = true; i++; continue;\n }\n\n if (quote === '\"') {\n if (c === '\"') { quote = ''; started = true; i++; continue; }\n current += c; started = true; i++; continue;\n }\n\n if (dialect.quotes.includes(c)) { quote = c; started = true; i++; continue; }\n\n if (c === '<' || c === '>') {\n if (command[i + 1] === '(') { processSubstitution = true; i += 2; continue; }\n if (c === '>') redirect = true;\n endToken();\n i += command[i + 1] === c ? 2 : 1;\n continue;\n }\n\n // Subshell grouping is not part of any token: `(rm -rf /)` must lex to `rm`.\n if (c === '(' || c === ')') { endToken(); i++; continue; }\n\n if (c === '|') {\n const double = command[i + 1] === '|';\n endSegment(!double);\n i += double ? 2 : 1;\n continue;\n }\n if (c === '&' || c === ';' || c === '\\n') {\n endSegment(false);\n i += command[i + 1] === c ? 2 : 1;\n continue;\n }\n\n if (/\\s/.test(c)) { endToken(); i++; continue; }\n\n current += c; started = true; i++;\n }\n\n if (quote !== '') unbalanced = true;\n endSegment(false);\n\n return { segments, redirect, processSubstitution, unbalanced };\n}\n\n/**\n * The name a segment's binary is matched against the tiers under.\n *\n * `path.basename` alone is not enough: Node's POSIX `path` does not split on\n * `\\`, so `C:\\Windows\\System32\\del.exe` came back whole and matched nothing in\n * `REFUSED_COMMANDS`. Both separators are stripped regardless of host, and the\n * dialect decides whether an executable extension comes off too.\n */\nfunction binaryName(token: string, dialect: Dialect): string {\n const base = token.split(/[/\\\\]/).pop() ?? '';\n // `dot > 0`, not `>= 0`: `lastIndexOf` returns -1 for a name with no dot, and\n // `slice(-1)` would then make the last character look like the extension.\n const dot = base.lastIndexOf('.');\n if (dot <= 0) return base;\n return dialect.strippedExtensions.includes(base.slice(dot).toLowerCase()) ? base.slice(0, dot) : base;\n}\n\nfunction toSegment(tokens: string[], piped: boolean, dialect: Dialect): Segment {\n const rest = [...tokens];\n // `FOO=bar cmd` — assignments precede the binary.\n while (rest.length > 0 && /^[A-Za-z_][A-Za-z0-9_]*=/.test(rest[0])) rest.shift();\n return { binary: rest.length > 0 ? binaryName(rest[0], dialect) : '', args: rest.slice(1), piped, expandable: false };\n}\n\n/** Lex a command line and every substitution body nested inside it. */\nfunction lexAll(command: string, dialect: Dialect): Lexed {\n const queue: string[] = [];\n const top = lex(command, queue, dialect);\n const all: Lexed = { ...top, segments: top.segments.filter((s) => s.binary) };\n\n // Bounded: a pathological `$($($(…)))` must not spin here.\n for (let depth = 0; depth < 32 && queue.length > 0; depth++) {\n const inner = lex(queue.shift()!, queue, dialect);\n all.segments.push(...inner.segments.filter((s) => s.binary));\n all.redirect ||= inner.redirect;\n all.processSubstitution ||= inner.processSubstitution;\n all.unbalanced ||= inner.unbalanced;\n }\n return all;\n}\n\n/**\n * Path-shaped arguments, in every spelling a host might use.\n *\n * The Windows forms are not cosmetic. `pathLikeArgs` feeds\n * `BaseFileSystem.authorizeCommandPaths`, so an argument this function fails to\n * recognize is one the workspace-confinement prompt never sees. With only the\n * POSIX forms, `cat C:\\Users\\me\\.ssh\\id_rsa` matched nothing and ran\n * unprompted — ADR-0008's escape gate silently absent on that platform rather\n * than merely weaker.\n */\nfunction looksLikePath(arg: string): boolean {\n if (arg.startsWith('--') && arg.includes('=')) return looksLikePath(arg.slice(arg.indexOf('=') + 1));\n return arg.startsWith('/')\n || arg.startsWith('~')\n || arg.startsWith('../')\n || arg === '..'\n || arg.startsWith('./')\n // Windows: drive-absolute (`C:\\x`, `C:/x`), drive-relative (`C:x`), UNC\n // (`\\\\server\\share`), and root-relative (`\\x`).\n || /^[A-Za-z]:/.test(arg)\n || arg.startsWith('\\\\')\n || arg.startsWith('..\\\\')\n || arg.startsWith('.\\\\');\n}\n\n/**\n * Every path-shaped argument across every segment (including inside `$(…)`),\n * for the workspace-confinement check `bash()` runs before an `auto`-tier\n * command reaches the shell. `auto` classification only ever looked at the\n * binary — `cat`, `find`, `rg` and friends are auto because *reading* is\n * read-only, but their arguments can still point anywhere on disk, which is\n * exactly the escape path confinement closes for `readFile`/`glob`/`grep`.\n */\nexport function pathLikeArgs(command: string, opts: CommandPolicyOptions = {}): string[] {\n const dialect = dialectFor(opts.dialect);\n return lexAll(command, dialect).segments.flatMap((seg) => seg.args.flatMap((a) => {\n // `--flag=value` is excluded by the leading-dash filter but its value can\n // still name an external path, so split it and check the value.\n if (a.startsWith('--') && a.includes('=')) {\n const v = a.slice(a.indexOf('=') + 1);\n return looksLikePath(v) ? [v] : [];\n }\n return (!a.startsWith('-') && looksLikePath(a)) ? [a] : [];\n }));\n}\n\nfunction scopeFor(seg: Segment): string {\n if (!MULTIPLEXERS.includes(seg.binary)) return seg.binary;\n const sub = seg.args.find((a) => !a.startsWith('-'));\n return sub ? `${seg.binary} ${sub}` : seg.binary;\n}\n\nfunction isAuto(seg: Segment): boolean {\n if (!AUTO_COMMANDS.includes(seg.binary)) return false;\n // `x=/etc/passwd; cat $x` gives `cat` the lone argument `$x`, which\n // `pathLikeArgs`/`looksLikePath` cannot see is a path at all — the shell\n // resolves it to whatever the variable holds. An auto-tier command whose\n // arguments are not fully visible at classification time is exactly the\n // confinement escape this file exists to close, so treat any variable\n // reference as disqualifying the fast path rather than trying to resolve it.\n if (seg.expandable) return false;\n if (seg.binary !== 'git') return true;\n const sub = seg.args.find((a) => !a.startsWith('-'));\n return sub !== undefined && GIT_READONLY_SUBCOMMANDS.includes(sub);\n}\n\nfunction refusalFor(seg: Segment): string | undefined {\n if (REFUSED_COMMANDS.includes(seg.binary)) {\n return `\"${seg.binary}\" modifies state. You are a read-only planner — describe the change as a task instead, and the runner executing the plan will make it.`;\n }\n // `eval`/`exec` exist only to run a string as a command — the whole point of\n // this classifier is to inspect those strings, so they are never promptable.\n if (seg.binary === 'eval' || seg.binary === 'exec') {\n return `\"${seg.binary}\" runs a string as a command, which this classifier cannot inspect. Use the read-only research tools, or describe it as a task.`;\n }\n const subs = REFUSED_SUBCOMMANDS[seg.binary];\n if (subs) {\n const sub = seg.args.find((a) => !a.startsWith('-'));\n if (sub && subs.includes(sub)) {\n return `\"${seg.binary} ${sub}\" changes state or reaches outward. You are a read-only planner — put it in the plan and let the runner do it.`;\n }\n }\n // `git branch`/`git tag` are read-only subcommands, but their delete/move\n // flag forms mutate refs. The readonly-subcommand allowlist only inspects\n // the first non-flag argument, so these have to be caught here.\n if (seg.binary === 'git') {\n const sub = seg.args.find((a) => !a.startsWith('-'));\n if (sub === 'branch' || sub === 'tag') {\n if (seg.args.some((a) => ['-D', '-d', '-m', '-M', '--delete', '--move'].includes(a))) {\n return `\"git ${sub}\" with a delete/move flag mutates refs. You are a read-only planner — describe the change as a task instead.`;\n }\n }\n }\n // `find` is auto because listing is read-only, but `-exec`/`-delete` make it\n // run an arbitrary inner command — the exact bypass this classifier exists\n // to close. Refuse rather than prompt: the inner command is unauditable.\n if (seg.binary === 'find') {\n const flag = seg.args.find((a) => ['-exec', '-execdir', '-ok', '-okdir', '-delete'].includes(a));\n if (flag) {\n return `find with \"${flag}\" runs an inner command this classifier cannot inspect. Use the read-only research tools on find's output, or describe the change as a task.`;\n }\n }\n // `sed -i`/`awk -i inplace` rewrite files in place — mutation, not research.\n if (seg.binary === 'sed' && seg.args.some((a) => a === '-i' || a === '--in-place' || /^-i./.test(a))) {\n return `\"sed -i\" edits files in place. You are a read-only planner — describe the change as a task instead.`;\n }\n if (seg.binary === 'awk' && seg.args.some((a) => a === 'inplace')) {\n return `\"awk -i inplace\" edits files in place. You are a read-only planner — describe the change as a task instead.`;\n }\n if (INTERPRETERS.includes(seg.binary)) {\n if (seg.piped) {\n return `Piping into \"${seg.binary}\" would run code this classifier cannot inspect. Run the producing command on its own and read its output.`;\n }\n if (seg.args.some(isInlineCodeFlag)) {\n return `Inline code via \"${seg.binary} ${seg.args.find(isInlineCodeFlag)}\" is not available to the planner. Use the read-only research tools, or describe it as a task.`;\n }\n }\n return undefined;\n}\n\n/**\n * Classify one command line. Output redirection is refused outright: a planner\n * that writes files has stopped being a planner.\n */\nexport function classifyCommand(command: string, opts: CommandPolicyOptions = {}): CommandClassification {\n const trimmed = command.trim();\n if (!trimmed) return { tier: 'refuse', scope: '', reason: 'Empty command.' };\n\n const dialect = dialectFor(opts.dialect);\n const { segments, redirect, processSubstitution, unbalanced } = lexAll(trimmed, dialect);\n\n if (unbalanced) {\n return {\n tier: 'refuse',\n scope: '',\n reason: 'Unterminated quote or command substitution — this classifier cannot tell what would actually run. Rewrite the command with balanced quotes.',\n };\n }\n\n // Process substitution `<(…)`/`>(…)` spawns a process this classifier never\n // tokenizes — `cat <(rm -rf /)` would otherwise run `rm` with no prompt.\n if (processSubstitution) {\n return {\n tier: 'refuse',\n scope: '',\n reason: 'Process substitution runs another command this classifier cannot inspect. Run the command on its own and read its output, or describe it as a task.',\n };\n }\n\n if (redirect) {\n return {\n tier: 'refuse',\n scope: '',\n reason: 'Output redirection writes files. You are a read-only planner — read the output instead, or describe the write as a task.',\n };\n }\n\n if (segments.length === 0) return { tier: 'refuse', scope: '', reason: 'No command found.' };\n\n for (const seg of segments) {\n const reason = refusalFor(seg);\n if (reason) return { tier: 'refuse', scope: '', reason };\n }\n\n const nonAuto = segments.filter((s) => !isAuto(s));\n if (nonAuto.length === 0) return { tier: 'auto', scope: '' };\n\n // A grant covers only the parts that actually needed one, so\n // `az group list | head` is remembered as `az group`, not the whole line.\n const scope = [...new Set(nonAuto.map(scopeFor))].sort().join(' + ');\n return { tier: 'ask', scope };\n}\n","import * as fsSync from 'fs';\nimport * as path from 'path';\n\n/**\n * Which interpreter runs the planner's `bash` tool, and in which language.\n *\n * `AUTO_COMMANDS` — the read-only tier that runs with no prompt — is `ls`, `cat`,\n * `wc`, `head`, `tail`, `du`, `df`, `file`, `sort`, `uniq`, `basename`, `find`,\n * `grep`. That set is POSIX, and passing it to `shell: true` on Windows means\n * cmd.exe, where most of those names do not exist and `find` is an unrelated\n * program that returns plausible wrong output instead of an error. The planner's\n * whole research surface degraded to guessing, quietly.\n *\n * Rather than write a Windows dialect of every research command — a second\n * behavior to keep in step forever — this finds a POSIX shell to run the\n * existing ones in. Git for Windows ships a full one, and git is already a\n * prerequisite for everything Ordewell does, so in practice it is there. Failing\n * that, cmd.exe is used and the classifier is told so, because the one thing\n * that must never happen is classifying a command in one language and running it\n * in another: `commandPolicy` reads {@link ResearchShell.dialect} for exactly\n * that reason.\n *\n * POSIX resolves to `{ file: null }`, meaning \"use `shell: true`\" — byte for\n * byte what the adapters did before this module existed.\n *\n * Windows paths are built with `path.win32` explicitly, not the host-flavoured\n * `path`, so the probe is the same on a Windows host as it is under a Linux\n * test runner.\n */\n\nexport type ShellDialect = 'posix' | 'cmd';\n\nexport interface ResearchShell {\n /**\n * Executable that takes a command string, or null to use the host default\n * via `shell: true`.\n */\n file: string | null;\n /** Arguments preceding the command string. */\n args: string[];\n /** The language the command string will be interpreted in. */\n dialect: ShellDialect;\n /**\n * Directory holding this shell's POSIX utilities, when it brings its own.\n * Prepended to PATH for the search subprocesses (`grep`, `tree`) that\n * `execFile` starts without a shell, so they resolve too.\n */\n utilsDir: string | null;\n}\n\nconst POSIX_SHELL: ResearchShell = { file: null, args: [], dialect: 'posix', utilsDir: null };\nconst CMD_SHELL: ResearchShell = { file: null, args: [], dialect: 'cmd', utilsDir: null };\n\nexport interface ResearchShellDeps {\n platform?: NodeJS.Platform;\n exists?: (candidate: string) => boolean;\n env?: NodeJS.ProcessEnv;\n}\n\nfunction defaultExists(candidate: string): boolean {\n try {\n return fsSync.statSync(candidate).isFile();\n } catch {\n return false;\n }\n}\n\n/**\n * Where Git for Windows puts its shell, per install flavour. `bin/bash.exe` is\n * the wrapper users get on PATH; `usr/bin/bash.exe` is the same shell in the\n * MSYS tree, listed because a minimal/portable install may omit the former.\n *\n * `C:\\Windows\\System32\\bash.exe` is deliberately absent and must stay absent:\n * that is the WSL launcher. It runs commands inside a Linux VM with its own\n * filesystem view (`/mnt/c/...`), so a workspace path means something different\n * there — which would put every command outside the root that path confinement\n * is checking against, and every relative path against the wrong tree.\n */\nfunction gitBashRoots(env: NodeJS.ProcessEnv): string[] {\n const roots = [\n env.ProgramFiles && path.win32.join(env.ProgramFiles, 'Git'),\n env['ProgramFiles(x86)'] && path.win32.join(env['ProgramFiles(x86)'], 'Git'),\n env.LOCALAPPDATA && path.win32.join(env.LOCALAPPDATA, 'Programs', 'Git'),\n 'C:\\\\Program Files\\\\Git',\n 'C:\\\\Program Files (x86)\\\\Git',\n ].filter((r): r is string => !!r);\n return [...new Set(roots)];\n}\n\nlet cached: ResearchShell | null = null;\n\n/**\n * The shell the planner's `bash` tool should use on this host. Resolved once per\n * process — the answer cannot change while Ordewell runs, and the probe costs a\n * handful of `stat` calls.\n */\nexport function resolveResearchShell(deps: ResearchShellDeps = {}): ResearchShell {\n if (cached && !deps.platform && !deps.exists && !deps.env) return cached;\n\n const platform = deps.platform ?? process.platform;\n if (platform !== 'win32') {\n if (!deps.platform && !deps.exists && !deps.env) cached = POSIX_SHELL;\n return POSIX_SHELL;\n }\n\n const exists = deps.exists ?? defaultExists;\n const env = deps.env ?? process.env;\n\n for (const root of gitBashRoots(env)) {\n for (const rel of [['bin', 'bash.exe'], ['usr', 'bin', 'bash.exe']]) {\n const file = path.win32.join(root, ...rel);\n if (!exists(file)) continue;\n const utilsDir = path.win32.join(root, 'usr', 'bin');\n const resolved: ResearchShell = {\n file,\n // `-c`, not `-lc`: a login shell sources the user's profile, which can\n // change directory out from under a command whose cwd is the workspace.\n args: ['-c'],\n dialect: 'posix',\n utilsDir: exists(path.win32.join(utilsDir, 'grep.exe')) ? utilsDir : null,\n };\n if (!deps.platform && !deps.exists && !deps.env) cached = resolved;\n return resolved;\n }\n }\n\n if (!deps.platform && !deps.exists && !deps.env) cached = CMD_SHELL;\n return CMD_SHELL;\n}\n\n/** Test seam: drop the per-process cache so the next call re-probes. */\nexport function clearResearchShellCache(): void {\n cached = null;\n}\n\n/**\n * PATH for the search subprocesses the adapters start without a shell, with the\n * research shell's own utilities in front. Without this, `grep` — the fallback\n * when ripgrep is absent — is unresolvable on a Windows box even when a\n * perfectly good `grep.exe` sits in the Git tree beside the shell.\n */\nexport function researchToolsPath(shell: ResearchShell, basePath: string | undefined): string {\n // `utilsDir` is only ever set on the Windows branch, so the delimiter is `;`.\n if (!shell.utilsDir) return basePath ?? '';\n const segments = [shell.utilsDir, ...(basePath ?? '').split(path.win32.delimiter)].filter(Boolean);\n return [...new Set(segments)].join(path.win32.delimiter);\n}\n\n/**\n * A message explaining a degraded research surface, or null when there is\n * nothing to explain. Surfaced by the adapters on the first refused command so\n * the limitation is visible rather than inferred from bad answers.\n */\nexport function researchShellWarning(shell: ResearchShell): string | null {\n if (shell.dialect !== 'cmd') return null;\n return 'No POSIX shell was found on this machine, so research commands run through cmd.exe, '\n + 'where most read-only tools (ls, cat, wc, head, grep, find) do not exist. '\n + 'Installing Git for Windows provides one and restores the full research toolset.';\n}\n","import * as os from 'os';\nimport * as path from 'path';\n\n/**\n * Workspace containment, in one place. Both the filesystem policy layer\n * (which may ask the user to approve an escape) and the research-subagent\n * wrapper (which may not, because nothing can prompt on its behalf) need the\n * same answer to \"is this path inside the workspace\", so neither re-derives it.\n *\n * Symlinks are resolved lexically, not on disk: a symlink inside the workspace\n * pointing outward still reads as inside. Closing that would mean a `realpath`\n * syscall on every path check, and the threat model here is an LLM wandering,\n * not an adversary planting links in a repo the user already trusts enough to\n * point Ordewell at.\n */\nexport interface ResolvedPath {\n abs: string;\n inside: boolean;\n}\n\n/**\n * `~` is expanded here because the *shell* will expand it later. Left alone,\n * `path.resolve(root, '~/.ssh/id_rsa')` yields `<root>/~/.ssh/id_rsa`, which\n * reads as inside the workspace — so `cat ~/.ssh/id_rsa` passed confinement\n * unprompted and then read the real file once the shell got hold of it.\n */\nfunction expandHome(target: string): string {\n if (!target.startsWith('~')) return target;\n const home = os.homedir();\n if (target === '~' || target.startsWith('~/')) return path.join(home, target.slice(1));\n // `~otheruser/…` resolved as a sibling of this user's home. Wrong on exotic\n // layouts, but it reliably lands outside the workspace, so the access\n // prompts rather than silently passing.\n return path.join(path.dirname(home), target.slice(1));\n}\n\nexport function resolveWithin(root: string, target: string): ResolvedPath {\n const abs = path.resolve(root, expandHome(target));\n const rel = path.relative(root, abs);\n return { abs, inside: rel === '' || (!rel.startsWith('..') && !path.isAbsolute(rel)) };\n}\n\n/** The directory a grant covers for `target` — its parent for files, itself for directories. */\nexport function grantScopeFor(abs: string, kind: 'file' | 'directory'): string {\n if (kind === 'directory') return path.join(abs, '*');\n const parent = path.dirname(abs);\n // A path immediately under the filesystem root (e.g. `/etc`) has the root as\n // its parent; scoping to `/*` would approve every top-level directory, so\n // scope to the directory itself instead.\n if (parent === path.parse(abs).root) return path.join(abs, '*');\n return path.join(parent, '*');\n}\n","/**\n * Definition-shaped search patterns for the `find_symbol` tool.\n *\n * Plain `grep` is bad at the question the planner actually asks. Searching for\n * `VerdictEngine` returns every import, call site, comment and string alongside\n * the one line that defines it, and with a hard result cap the definition is\n * often not even in the returned page. `find_symbol` spends the budget on\n * declarations first and reports references as a count plus a sample.\n *\n * This is deliberately regex over a real parser. An LSP-grade answer would mean\n * shipping per-language servers and waiting for them to index — the wrong trade\n * for the half of the architecture whose whole point is being cheap and fast.\n * The planner needs to scope tasks (\"defined here, used across ~14 files in 3\n * packages\"), not to prove rename-safety; that is the runner's job, and runners\n * have their own tools.\n *\n * Patterns target the Rust regex syntax ripgrep uses: non-capturing groups and\n * `\\b` are available, lookaround and backreferences are not.\n */\n\nexport interface SymbolLanguage {\n id: string;\n extensions: string[];\n /** Keywords that introduce a declaration in `kw Name` position. */\n keywords: string[];\n}\n\nexport const SYMBOL_LANGUAGES: SymbolLanguage[] = [\n {\n id: 'typescript',\n extensions: ['.ts', '.tsx', '.mts', '.cts', '.js', '.jsx', '.mjs', '.cjs'],\n keywords: ['function', 'class', 'interface', 'type', 'enum', 'const', 'let', 'var', 'namespace', 'module'],\n },\n { id: 'python', extensions: ['.py', '.pyi'], keywords: ['def', 'class'] },\n { id: 'go', extensions: ['.go'], keywords: ['func', 'type', 'var', 'const', 'package'] },\n {\n id: 'rust',\n extensions: ['.rs'],\n keywords: ['fn', 'struct', 'enum', 'trait', 'type', 'const', 'static', 'mod', 'impl', 'union', 'macro_rules!'],\n },\n {\n id: 'jvm',\n extensions: ['.java', '.kt', '.kts', '.scala', '.groovy'],\n keywords: ['class', 'interface', 'enum', 'record', 'object', 'trait', 'val', 'var', 'fun', 'def'],\n },\n {\n id: 'csharp',\n extensions: ['.cs', '.fs', '.fsi'],\n keywords: ['class', 'interface', 'enum', 'struct', 'record', 'namespace', 'delegate', 'let', 'type'],\n },\n {\n id: 'c',\n extensions: ['.c', '.h', '.cc', '.cpp', '.cxx', '.hpp', '.hh', '.hxx', '.m', '.mm'],\n keywords: ['struct', 'class', 'enum', 'union', 'typedef', 'namespace', 'define'],\n },\n { id: 'ruby', extensions: ['.rb', '.rake', '.gemspec'], keywords: ['def', 'class', 'module'] },\n { id: 'php', extensions: ['.php'], keywords: ['function', 'class', 'interface', 'trait', 'enum', 'const'] },\n {\n id: 'swift',\n extensions: ['.swift'],\n keywords: ['func', 'class', 'struct', 'enum', 'protocol', 'extension', 'var', 'let', 'typealias'],\n },\n { id: 'elixir', extensions: ['.ex', '.exs'], keywords: ['def', 'defp', 'defmodule', 'defstruct', 'defmacro'] },\n { id: 'shell', extensions: ['.sh', '.bash', '.zsh'], keywords: ['function'] },\n { id: 'lua', extensions: ['.lua'], keywords: ['function', 'local'] },\n { id: 'dart', extensions: ['.dart'], keywords: ['class', 'enum', 'mixin', 'typedef', 'extension', 'var', 'final'] },\n];\n\n/** Escape a symbol so it is matched literally inside a generated pattern. */\nexport function escapeRegex(literal: string): string {\n return literal.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nexport function languageForId(id: string): SymbolLanguage | undefined {\n const wanted = id.trim().toLowerCase();\n return SYMBOL_LANGUAGES.find((l) => l.id === wanted)\n ?? SYMBOL_LANGUAGES.find((l) => l.extensions.includes(wanted.startsWith('.') ? wanted : `.${wanted}`));\n}\n\n/** The `--glob` filter that narrows a search to one language's files. */\nexport function includeGlobFor(language: SymbolLanguage): string {\n return language.extensions.length === 1\n ? `*${language.extensions[0]}`\n : `*{${language.extensions.map((e) => e.slice(1)).join(',')}}`;\n}\n\nfunction allKeywords(): string[] {\n return [...new Set(SYMBOL_LANGUAGES.flatMap((l) => l.keywords))];\n}\n\n/**\n * Build the definition pattern for `symbol`. Three shapes cover essentially\n * every mainstream language:\n *\n * 1. `keyword Name` — declarations across all of them\n * 2. `Name = function|(` — assigned function expressions and arrows\n * 3. `… Name(args) {` — C/Java/Go-style bodies with a return type\n *\n * Passing a `language` narrows shape 1 to that language's keywords, which cuts\n * cross-language noise in polyglot repos.\n */\nexport function definitionPattern(symbol: string, language?: SymbolLanguage): string {\n const name = escapeRegex(symbol);\n const keywords = (language?.keywords ?? allKeywords()).map(escapeRegex).join('|');\n\n const declaration = `(?:^|[\\\\s(,;])(?:${keywords})\\\\s+${name}\\\\b`;\n const assignment = `\\\\b${name}\\\\s*[:=]\\\\s*(?:async\\\\s+)?(?:function\\\\b|\\\\()`;\n const body = `^[\\\\t ]*(?:[\\\\w<>\\\\[\\\\]*&:.~]+[\\\\t ]+)*${name}[\\\\t ]*\\\\([^;{]*\\\\)[\\\\t ]*(?:const[\\\\t ]*)?\\\\{`;\n\n return `${declaration}|${assignment}|${body}`;\n}\n\n/** Every mention of the symbol as a whole word — the reference side of the report. */\nexport function referencePattern(symbol: string): string {\n return `\\\\b${escapeRegex(symbol)}\\\\b`;\n}\n","import {\n IFileSystem,\n ReadFileOpts,\n GrepOptions,\n GlobOptions,\n FindSymbolOptions,\n ToolOutcome,\n GREP_DEFAULT_HEAD_LIMIT,\n} from '../interfaces/IFileSystem';\nimport { IApproval, DENY_ALL } from '../interfaces/IApproval';\nimport { classifyCommand, pathLikeArgs } from './commandPolicy';\nimport { resolveResearchShell, researchShellWarning, type ResearchShell } from './researchShell';\nimport { resolveWithin, grantScopeFor } from './pathScope';\nimport { definitionPattern, referencePattern, languageForId, includeGlobFor } from './symbolPatterns';\n\nexport { AUTO_COMMANDS, GIT_READONLY_SUBCOMMANDS, REFUSED_COMMANDS, classifyCommand, pathLikeArgs } from './commandPolicy';\n\n/**\n * The policy half of the planner's filesystem: path confinement, the tiered\n * `bash` gate, and the definition-first symbol lookup. Adapters supply only the\n * mechanics (`*Impl`), so the rules live in one place across the web server and\n * the VS Code extension rather than being re-derived per surface.\n *\n * Every public method resolves and authorizes before delegating, and every\n * `*Impl` therefore receives an absolute, already-approved path. Previously\n * each adapter did its own resolution, and `path.isAbsolute(p) ? p : …` meant\n * an absolute path walked straight out of the workspace with no prompt and no\n * record.\n */\nexport abstract class BaseFileSystem implements IFileSystem {\n private approval: IApproval = DENY_ALL;\n\n /**\n * The interpreter `execBashImpl` will hand the command to. Owned here rather\n * than per-adapter because {@link classifyCommand} has to be told the same\n * answer: a command lexed under POSIX rules and then run by cmd.exe is a\n * command this class did not actually classify.\n */\n protected readonly researchShell: ResearchShell = resolveResearchShell();\n\n /** Surfaces inject the human channel here; without it, external access is denied. */\n setApproval(approval: IApproval): void {\n this.approval = approval;\n }\n\n abstract getWorkspaceRoot(): string;\n\n protected abstract readFileImpl(absPath: string, opts?: ReadFileOpts): Promise<ToolOutcome>;\n protected abstract globImpl(pattern: string, absRoot: string, headLimit: number): Promise<ToolOutcome>;\n protected abstract grepImpl(pattern: string, absRoot: string, opts: GrepOptions): Promise<ToolOutcome>;\n protected abstract listDirImpl(absPath: string, depth: number): Promise<ToolOutcome>;\n protected abstract execBashImpl(command: string): Promise<ToolOutcome>;\n\n /**\n * Resolve `p` and confirm the planner may touch it. In-workspace paths pass\n * silently; anything else needs one approval, remembered per containing\n * directory so a second file in the same place does not prompt again.\n */\n protected async authorizePath(\n p: string,\n kind: 'file' | 'directory' = 'file',\n ): Promise<{ ok: true; abs: string } | { ok: false; outcome: ToolOutcome }> {\n const root = this.getWorkspaceRoot();\n const { abs, inside } = resolveWithin(root, p);\n if (inside) return { ok: true, abs };\n\n const granted = await this.approval.request({\n kind: 'external_path',\n subject: abs,\n scope: grantScopeFor(abs, kind),\n detail: `Planner research wants to read ${abs}, outside the workspace (${root}).`,\n });\n if (granted) return { ok: true, abs };\n\n return {\n ok: false,\n outcome: {\n success: false,\n output: `Access denied: \"${abs}\" is outside the workspace root (${root}) and was not approved. Keep research inside the workspace, or ask the user to approve this location.`,\n truncated: false,\n },\n };\n }\n\n async readFile(p: string, opts?: ReadFileOpts): Promise<ToolOutcome> {\n const auth = await this.authorizePath(p, 'file');\n return auth.ok ? this.readFileImpl(auth.abs, opts) : auth.outcome;\n }\n\n async readFiles(paths: string[]): Promise<ToolOutcome> {\n const results: string[] = [];\n let truncated = false;\n for (const p of paths) {\n const r = await this.readFile(p);\n // Denials are reported inline: silently dropping them would let the model\n // believe a file was empty rather than out of bounds.\n if (r.success) {\n results.push(`--- ${p} ---\\n${r.output}`);\n if (r.truncated) truncated = true;\n } else if (r.output) {\n results.push(`--- ${p} ---\\n[not read] ${r.output}`);\n }\n }\n if (results.length === 0) return { success: false, output: 'No files read.', truncated: false };\n return { success: true, output: results.join('\\n\\n'), truncated };\n }\n\n async glob(pattern: string, opts?: GlobOptions): Promise<ToolOutcome> {\n const auth = await this.authorizePath(opts?.path ?? '.', 'directory');\n if (!auth.ok) return auth.outcome;\n return this.globImpl(pattern, auth.abs, opts?.headLimit ?? 200);\n }\n\n async grep(pattern: string, opts?: GrepOptions): Promise<ToolOutcome> {\n const auth = await this.authorizePath(opts?.path ?? '.', 'directory');\n if (!auth.ok) return auth.outcome;\n return this.grepImpl(pattern, auth.abs, {\n ...opts,\n headLimit: opts?.headLimit ?? GREP_DEFAULT_HEAD_LIMIT,\n outputMode: opts?.outputMode ?? 'content',\n });\n }\n\n async listDir(p: string, depth?: number): Promise<ToolOutcome> {\n const auth = await this.authorizePath(p, 'directory');\n return auth.ok ? this.listDirImpl(auth.abs, depth ?? 1) : auth.outcome;\n }\n\n /**\n * Definitions first, then a reference tally. Two bounded searches beat one\n * unbounded `grep` because the 100-row budget gets spent on the rows that\n * answer the question.\n */\n async findSymbol(symbol: string, opts?: FindSymbolOptions): Promise<ToolOutcome> {\n const name = symbol.trim();\n if (!name) {\n return { success: false, output: 'find_symbol requires a non-empty \"symbol\".', truncated: false };\n }\n\n const auth = await this.authorizePath(opts?.path ?? '.', 'directory');\n if (!auth.ok) return auth.outcome;\n\n const language = opts?.language ? languageForId(opts.language) : undefined;\n if (opts?.language && !language) {\n return {\n success: false,\n output: `Unknown language \"${opts.language}\". Omit it to search every language, or pass a file extension such as \".go\".`,\n truncated: false,\n };\n }\n const include = language ? includeGlobFor(language) : undefined;\n\n const [defs, refs] = await Promise.all([\n this.grepImpl(definitionPattern(name, language), auth.abs, { include, outputMode: 'content', headLimit: 40 }),\n this.grepImpl(referencePattern(name), auth.abs, { include, outputMode: 'count', headLimit: 40 }),\n ]);\n\n const sections: string[] = [];\n const foundDefs = defs.success && defs.output.trim() && !/^No matches/i.test(defs.output.trim());\n sections.push(foundDefs\n ? `=== Definitions of \"${name}\" ===\\n${defs.output.trim()}`\n : `=== Definitions of \"${name}\" ===\\nNone matched the definition patterns. The symbol may be generated, re-exported, or defined in a language find_symbol does not cover — fall back to grep.`);\n\n if (refs.success && refs.output.trim() && !/^No matches/i.test(refs.output.trim())) {\n sections.push(`=== References by file (match count) ===\\n${refs.output.trim()}`);\n }\n\n return {\n success: true,\n output: sections.join('\\n\\n'),\n truncated: defs.truncated || refs.truncated,\n };\n }\n\n /**\n * Path confinement for `bash`: an `auto`-tier binary (`cat`, `find`, `rg`, …)\n * is only auto because *reading* is read-only — its arguments can still\n * name a path outside the workspace, which is the exact escape confinement\n * closes for `readFile`/`glob`/`grep`. Each escaping path needs its own\n * approval (scoped to its containing directory); approving one does not\n * approve another, so a single command touching two external dirs prompts\n * once per distinct scope rather than carrying the first grant to the rest.\n */\n private async authorizeCommandPaths(command: string): Promise<ToolOutcome | null> {\n const root = this.getWorkspaceRoot();\n const escaping = pathLikeArgs(command, { dialect: this.researchShell.dialect })\n .filter((p) => !resolveWithin(root, p).inside);\n if (escaping.length === 0) return null;\n\n for (const p of escaping) {\n const abs = resolveWithin(root, p).abs;\n const granted = await this.approval.request({\n kind: 'external_path',\n subject: abs,\n scope: grantScopeFor(abs, 'file'),\n detail: `Planner research wants to run \"${command}\", which touches ${abs}, outside the workspace (${root}).`,\n });\n if (!granted) {\n return {\n success: false,\n output: `Access denied: \"${command}\" touches ${abs}, outside the workspace root (${root}), and was not approved. Keep research inside the workspace, or ask the user to approve this location.`,\n truncated: false,\n };\n }\n }\n return null;\n }\n\n /**\n * Three tiers (see `commandPolicy.ts`): read-only inspection runs silently,\n * anything else asks once and is remembered, and writes are refused outright\n * because a planner that mutates the workspace has stopped being a planner.\n */\n async bash(command: string): Promise<ToolOutcome> {\n const { tier, scope, reason } = classifyCommand(command, { dialect: this.researchShell.dialect });\n\n if (tier === 'refuse') {\n return { success: false, output: `Command refused: ${reason}`, truncated: false };\n }\n\n const pathDenial = await this.authorizeCommandPaths(command);\n if (pathDenial) return pathDenial;\n\n if (tier === 'ask') {\n const granted = await this.approval.request({\n kind: 'shell_command',\n subject: command,\n scope,\n detail: `Planner research wants to run: ${command}`,\n });\n if (!granted) {\n return {\n success: false,\n output: `Command not approved: ${command}\\nIt is outside the auto-allowed read-only set (${scope}). Continue with the read-only research tools, or ask the user to approve it.`,\n truncated: false,\n };\n }\n }\n\n const outcome = await this.execBashImpl(command);\n if (outcome.success) return outcome;\n\n // A command that failed under cmd.exe most likely failed because the tool\n // does not exist there. Saying so turns \"exited 1\" into something the model\n // can act on — and, per the fail-visibly contract, keeps a degraded research\n // surface from reading as a repository that simply had no answer.\n const warning = researchShellWarning(this.researchShell);\n return warning ? { ...outcome, output: `${outcome.output}\\n\\n[${warning}]` } : outcome;\n }\n}\n","import type { IApproval, ApprovalRequest } from '../interfaces/IApproval';\n\n/**\n * Decides whether one out-of-envelope capability may run, and remembers the\n * answer for the rest of the session.\n *\n * Grants are keyed on {@link ApprovalRequest.scope}, never on the concrete\n * subject: approving a read of `/tmp/foo/a.log` grants `/tmp/foo/*`, and\n * approving `az group list` grants `az group`. Without that, a planner doing\n * real research would prompt on every single call and the feature would be\n * unusable.\n *\n * `mode` is the policy floor:\n * ask consult the human channel; no channel means deny (headless, web)\n * allow grant everything the tier system did not already refuse\n * deny grant nothing beyond `preApproved`\n *\n * Note the ordering: `preApproved` is honored under every mode including\n * `deny`, because it is an explicit operator decision rather than a default.\n */\nexport type ApprovalMode = 'ask' | 'allow' | 'deny';\n\nexport interface ApprovalPolicyOptions {\n mode?: ApprovalMode;\n /** Scopes granted up front from config. A trailing `*` matches by prefix. */\n preApproved?: string[];\n /** The human channel. Absent means there is nobody to ask. */\n ask?: (req: ApprovalRequest) => Promise<boolean>;\n /** Called whenever a decision is reached, for surfacing in a UI or a log. */\n onDecision?: (req: ApprovalRequest, granted: boolean, source: ApprovalSource) => void;\n}\n\nexport type ApprovalSource = 'pre-approved' | 'remembered' | 'mode' | 'asked' | 'no-channel';\n\nfunction scopeMatches(pattern: string, scope: string): boolean {\n if (pattern === scope) return true;\n if (pattern.endsWith('*')) return scope.startsWith(pattern.slice(0, -1));\n return false;\n}\n\nexport class ApprovalPolicy implements IApproval {\n private readonly mode: ApprovalMode;\n private readonly preApproved: string[];\n private readonly asker?: (req: ApprovalRequest) => Promise<boolean>;\n private readonly onDecision?: ApprovalPolicyOptions['onDecision'];\n\n private readonly granted = new Set<string>();\n private readonly refused = new Set<string>();\n /** One in-flight ask per scope: a parallel tool round must not prompt twice for the same thing. */\n private readonly inFlight = new Map<string, Promise<boolean>>();\n // Bumped on reset so an in-flight ask whose promise settles AFTER reset\n // cannot re-populate granted/refused — the continuation checks the\n // generation it was started under and bails if reset has intervened.\n private generation = 0;\n\n constructor(opts: ApprovalPolicyOptions = {}) {\n this.mode = opts.mode ?? 'ask';\n this.preApproved = opts.preApproved ?? [];\n this.asker = opts.ask;\n this.onDecision = opts.onDecision;\n }\n\n async request(req: ApprovalRequest): Promise<boolean> {\n const decide = (granted: boolean, source: ApprovalSource) => {\n this.onDecision?.(req, granted, source);\n return granted;\n };\n\n if (this.preApproved.some((p) => scopeMatches(p, req.scope))) return decide(true, 'pre-approved');\n if (this.granted.has(req.scope)) return decide(true, 'remembered');\n if (this.refused.has(req.scope)) return decide(false, 'remembered');\n\n if (this.mode === 'allow') { this.granted.add(req.scope); return decide(true, 'mode'); }\n if (this.mode === 'deny') { this.refused.add(req.scope); return decide(false, 'mode'); }\n if (!this.asker) return decide(false, 'no-channel');\n\n const existing = this.inFlight.get(req.scope);\n if (existing) return decide(await existing, 'asked');\n\n const gen = this.generation;\n const pending = this.asker(req)\n .catch(() => false)\n .finally(() => { if (this.generation === gen) this.inFlight.delete(req.scope); });\n this.inFlight.set(req.scope, pending);\n\n const answer = await pending;\n // A denial is remembered too, so a model that retries the same blocked\n // lookup burns one tool round instead of re-prompting the user each time.\n if (this.generation === gen) (answer ? this.granted : this.refused).add(req.scope);\n return decide(answer, 'asked');\n }\n\n /** Scopes the user has granted this session — for display and for persistence. */\n grantedScopes(): string[] { return [...this.granted]; }\n\n /** Drop every session-scoped decision. Called on session reset. */\n reset(): void {\n this.generation++;\n this.granted.clear();\n this.refused.clear();\n this.inFlight.clear();\n }\n}\n","import type { ApprovalRequest } from '../interfaces/IApproval';\n\n/**\n * The bridge between \"core needs an answer\" and \"a human somewhere is looking\n * at a UI\". Core cannot prompt: the human may be at a browser, a TUI, a CLI\n * stream, or a VS Code webview, and on the web server they are on the far end\n * of a socket. So the Session parks a promise here, announces the request\n * through the normal broadcast seam, and every surface answers through the\n * same `resolve(id, granted)` call.\n *\n * Timeouts are load-bearing rather than defensive: a planner turn that blocks\n * forever on an unanswered prompt would hang the whole research loop with no\n * visible cause. On expiry the request resolves to denied and the model gets a\n * normal, actionable tool result.\n */\n\nexport interface PendingApproval {\n id: string;\n request: ApprovalRequest;\n createdAt: string;\n}\n\nexport interface PendingApprovalsOptions {\n /** Denies and resolves after this long with no answer. Default 5 minutes. */\n timeoutMs?: number;\n /** Announce a new request to the surfaces. */\n onRequest?: (pending: PendingApproval) => void;\n /** Announce that a request is no longer actionable (answered or expired). */\n onSettled?: (id: string, granted: boolean) => void;\n}\n\nconst DEFAULT_TIMEOUT_MS = 5 * 60_000;\n\nlet counter = 0;\n\nexport class PendingApprovals {\n private readonly entries = new Map<string, {\n pending: PendingApproval;\n settle: (granted: boolean) => void;\n timer: ReturnType<typeof setTimeout>;\n }>();\n\n constructor(private readonly opts: PendingApprovalsOptions = {}) {}\n\n /** Park a request and return the promise the approval policy awaits. */\n ask(request: ApprovalRequest): Promise<boolean> {\n const id = `ap-${Date.now()}-${counter++}`;\n const pending: PendingApproval = { id, request, createdAt: new Date().toISOString() };\n\n return new Promise<boolean>((resolve) => {\n const settle = (granted: boolean) => {\n const entry = this.entries.get(id);\n if (!entry) return;\n clearTimeout(entry.timer);\n this.entries.delete(id);\n this.opts.onSettled?.(id, granted);\n resolve(granted);\n };\n\n const timer = setTimeout(() => settle(false), this.opts.timeoutMs ?? DEFAULT_TIMEOUT_MS);\n // Never hold the process open on a prompt nobody is watching.\n (timer as unknown as { unref?: () => void }).unref?.();\n\n this.entries.set(id, { pending, settle, timer });\n this.opts.onRequest?.(pending);\n });\n }\n\n /** Answer one request. Returns false when the id is unknown or already settled. */\n resolve(id: string, granted: boolean): boolean {\n const entry = this.entries.get(id);\n if (!entry) return false;\n entry.settle(granted);\n return true;\n }\n\n /** Everything still awaiting an answer — replayed to a surface that connects late. */\n outstanding(): PendingApproval[] {\n return [...this.entries.values()].map((e) => e.pending);\n }\n\n /** Deny everything in flight. Called on abort and on session reset. */\n clear(): void {\n for (const id of [...this.entries.keys()]) this.resolve(id, false);\n }\n}\n","import path from 'node:path';\nimport { GrepOptions, SEARCH_EXCLUSIONS } from '../interfaces/IFileSystem';\n\n/**\n * Argument construction for the search tools, shared by every filesystem\n * adapter. Two reasons this is core and not per-adapter:\n *\n * 1. The exclusion set and the result cap are policy. `glob` used to pass\n * `--iglob '!node_modules'` and friends while `grep` passed nothing, so a\n * repo that did not gitignore `dist/` spent its whole result budget on\n * build output in one tool but not the other.\n *\n * 2. Arguments are returned as an array for `execFile`, never as a shell\n * string. The previous string interpolation escaped only double quotes,\n * which meant a pattern containing a backtick or `$(` was a command\n * injection through the planner's own search box.\n */\n\n/** Ordering is part of the result quality: with a hard cap, what you drop matters. */\nconst SORT_BY_RECENCY = ['--sortr', 'modified'];\n\nfunction exclusionArgs(): string[] {\n return SEARCH_EXCLUSIONS.flatMap((dir) => ['--glob', `!**/${dir}/**`]);\n}\n\nexport interface GrepInvocation {\n args: string[];\n /** Rows beyond this are dropped by the caller — see `applyHeadLimit`. */\n headLimit: number;\n}\n\n/**\n * Build the ripgrep invocation for one grep call.\n *\n * `--max-count` is deliberately absent. It caps matches *per file*, so the old\n * `--max-count 100` on a 300-file hit returned ~30 000 lines, blew the 1 MB\n * exec buffer, and surfaced as `{ success: false, output: '' }` — a silent\n * empty result on exactly the broad searches where the model most needed a\n * signal. The cap belongs at the row level, applied after the fact.\n */\nexport function buildGrepArgs(pattern: string, opts: GrepOptions, root: string): GrepInvocation {\n // ripgrep applies `--glob` in order with last-wins, so the include must come\n // before the exclusions — otherwise `--glob '*.ts'` would override the\n // `!**/node_modules/**` negations and search build output.\n const args = ['--no-heading', '--color', 'never', ...SORT_BY_RECENCY];\n if (opts.include) args.push('--glob', opts.include);\n args.push(...exclusionArgs());\n\n if (opts.literal) args.push('--fixed-strings');\n if (opts.caseInsensitive) args.push('--ignore-case');\n\n switch (opts.outputMode) {\n case 'files':\n args.push('--files-with-matches');\n break;\n case 'count':\n args.push('--count-matches');\n break;\n default:\n args.push('--line-number');\n if (opts.contextBefore) args.push('--before-context', String(opts.contextBefore));\n if (opts.contextAfter) args.push('--after-context', String(opts.contextAfter));\n }\n\n // `-e` and `--` keep a pattern or path that begins with `-` from being read as a flag.\n args.push('-e', pattern, '--', root);\n return { args, headLimit: opts.headLimit ?? 100 };\n}\n\n/** Build the ripgrep invocation that lists files matching a glob. */\nexport function buildGlobArgs(pattern: string, root: string): string[] {\n // Include before exclusions: ripgrep's `--glob` is last-wins, so the include\n // must precede the negations or it would override them.\n return ['--files', ...SORT_BY_RECENCY, '--glob', pattern, ...exclusionArgs(), '--', root];\n}\n\n/**\n * The POSIX-grep fallback for machines without ripgrep. Ordering and `--sort`\n * are unavailable.\n *\n * `-P` (PCRE) is required, not optional: patterns built in core — most\n * notably `find_symbol`'s `definitionPattern` — use non-capturing groups and\n * `\\b`, which BRE has no syntax for and ERE (`-E`) still cannot express\n * ((?:...) is a PCRE construct). Without `-P`, GNU grep either errors\n * (\"Unmatched \\{\") or, worse, silently treats `(`/`)`/`|` as literal\n * characters and reports a confident empty result. `-P` and `-F` are\n * mutually exclusive, so literal mode skips it.\n */\nexport function buildFallbackGrepArgs(pattern: string, opts: GrepOptions, root: string): string[] {\n const args = ['-r', '-n'];\n if (opts.literal) args.push('-F');\n else args.push('-P');\n if (opts.caseInsensitive) args.push('-i');\n if (opts.outputMode === 'files') args.push('-l');\n if (opts.outputMode === 'count') args.push('-c');\n if (opts.outputMode !== 'files' && opts.outputMode !== 'count') {\n if (opts.contextBefore) args.push('-B', String(opts.contextBefore));\n if (opts.contextAfter) args.push('-A', String(opts.contextAfter));\n }\n if (opts.include) args.push(`--include=${opts.include}`);\n for (const dir of SEARCH_EXCLUSIONS) args.push(`--exclude-dir=${dir}`);\n args.push('-e', pattern, root);\n return args;\n}\n\nfunction globSegmentToRegex(segment: string): string {\n return segment.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&').replace(/\\*/g, '[^/]*').replace(/\\?/g, '.');\n}\n\n/** `subdir/*.txt`-style glob match against a path relative to the search root. */\nfunction matchesAnchoredGlob(relPath: string, pattern: string): boolean {\n const regex = pattern.split('/').map((seg) => (seg === '**' ? '.*' : globSegmentToRegex(seg))).join('/');\n return new RegExp(`^${regex}$`).test(relPath);\n}\n\nfunction extractFallbackGrepPath(line: string, outputMode?: GrepOptions['outputMode']): string {\n if (outputMode === 'files') return line;\n if (outputMode === 'count') return line.slice(0, line.lastIndexOf(':'));\n // content mode: \"path:lineNumber:content\" — cut before the line-number marker.\n const match = line.match(/^(.*?):\\d+:/);\n return match ? match[1] : line;\n}\n\n/**\n * GNU grep's own `--include` glob only ever matches a basename, so it silently\n * matches nothing against an anchored pattern like `subdir/*.txt` (there is no\n * `/` in a basename to match against). The fallback path drops such patterns\n * from the grep invocation and filters matches by relative path here instead.\n */\nexport function filterFallbackByAnchoredInclude(stdout: string, include: string, anchor: string, outputMode?: GrepOptions['outputMode']): string {\n return stdout\n .split('\\n')\n .filter((line) => {\n if (!line) return false;\n const reportedPath = extractFallbackGrepPath(line, outputMode);\n const relPath = path.isAbsolute(reportedPath) ? path.relative(anchor, reportedPath) : reportedPath;\n return matchesAnchoredGlob(relPath, include);\n })\n .join('\\n');\n}\n\nexport interface CappedRows {\n rows: string[];\n truncated: boolean;\n total: number;\n}\n\n/** Apply the global row cap and report honestly whether anything was dropped. */\nexport function applyHeadLimit(stdout: string, headLimit: number): CappedRows {\n const all = stdout.split('\\n').filter((line) => line.length > 0);\n return { rows: all.slice(0, headLimit), truncated: all.length > headLimit, total: all.length };\n}\n\n/**\n * Render capped rows for the model, with paths made workspace-relative and an\n * explicit note when rows were dropped — a silently truncated list reads as a\n * complete answer and the model plans against it.\n */\nexport function formatSearchOutput(\n capped: CappedRows,\n root: string,\n opts: { emptyMessage: string; hint?: string; sep?: string },\n): string {\n if (capped.rows.length === 0) return opts.emptyMessage;\n\n // Only strip the workspace prefix; the filesystem root (`/`) has no useful\n // prefix to strip and dropping a leading slash would keep the model from\n // passing the path back to read_file.\n //\n // The separator is the host's, not `/`. ripgrep on Windows emits\n // `C:\\repo\\src\\a.ts:12:…` against a root of `C:\\repo`, so a hardcoded `/`\n // built the prefix `C:\\repo/`, matched nothing, and left every row absolute —\n // paying full path length for every result on every search.\n const sep = opts.sep ?? path.sep;\n const prefix = root === sep || root.endsWith(sep) ? root : `${root}${sep}`;\n const body = prefix === sep ? capped.rows.join('\\n') : capped.rows.map((row) => (row.startsWith(prefix) ? row.slice(prefix.length) : row)).join('\\n');\n if (!capped.truncated) return body;\n\n const hint = opts.hint ? ` ${opts.hint}` : '';\n return `${body}\\n\\n[showing ${capped.rows.length} of ${capped.total} results.${hint}]`;\n}\n","import type { RunnerId } from '../models/Task';\nimport type { ApprovalMode } from '../services/ApprovalPolicy';\nimport type { ProviderModelLists } from '../services/ProviderRouting';\n\n/**\n * Who plans. Mostly LLM vendors reached over HTTP; the last three are *harness\n * planners* (ADR-0009) — a coding agent CLI already installed on the machine,\n * driven as the planner over its own programmatic transport and authenticated\n * by the subscription the user already holds. They are runners in the provider\n * axis, deliberately: \"what plans for me?\" is one question, and it belongs in\n * one setting. `isCliProvider` is the single guard that tells the two kinds\n * apart.\n */\nexport type AiProvider = 'google' | 'openrouter' | 'openai_compatible' | 'openai' | 'xai' | 'groq' | 'deepseek' | 'together' | 'mistral' | 'anthropic' | 'fireworks' | 'perplexity' | 'zhipu' | 'kimi' | 'cerebras' | 'deepinfra' | 'doubao' | 'qwen' | 'hunyuan' | 'baichuan' | 'minimax' | 'yi' | 'stepfun' | 'siliconflow' | 'cohere' | 'novita' | 'claude-code' | 'codex' | 'opencode';\n\nexport interface IConfig {\n aiProvider: AiProvider;\n apiKey: string;\n planningModel: string;\n enabledRunners: string[];\n maxParallelSessions: number;\n researchEnabled: boolean;\n researchMaxSteps: number;\n researchMaxFileSize: number;\n\n openAiBaseUrl: string;\n openAiApiKey: string;\n /** Provider keys + base URL the ModelResolver uses to fetch the picker catalogs. */\n openrouterKey: string;\n geminiKey: string;\n geminiBaseUrl?: string;\n /** Base URL + API key for a user-provided OpenAI-compatible endpoint (ollama, vLLM, LM Studio, etc.). */\n openaiCompatibleBaseUrl: string;\n openaiCompatibleApiKey: string;\n orchestratorModel: string;\n geminiModel: string;\n /** Model for research subagents (issue #34); defaults to the (cheap) planner model. */\n researchSubagentModel: string;\n /**\n * Thinking effort / model variant for a harness planner (ADR-0009), chosen\n * from the agent's own discovered variants. Separate from the per-task\n * efforts the plan carries — this one is the planner's own dial.\n */\n plannerThinkingEffort?: string;\n\n planMapEnabled: boolean;\n autonomousMode: boolean;\n\n /**\n * What to do when planner research reaches outside its default envelope — an\n * out-of-workspace path, or a shell command beyond the auto-allowed read-only\n * set. `ask` prompts the user (and denies where no surface can prompt, such as\n * headless runs); `allow` and `deny` skip the prompt entirely.\n */\n approvalMode: ApprovalMode;\n /** Scopes granted up front, so CI and power users never see a prompt. Trailing `*` matches by prefix. */\n approvalPreApproved: string[];\n\n /** Get the base URL for an OpenAI-compatible provider. */\n getProviderBaseUrl(provider: AiProvider): string;\n /** Get the API key for a provider. */\n getProviderApiKey(provider: AiProvider): string;\n\n /**\n * Push the canonical provider routing lists in (sole producer: ModelResolver).\n * Config consumes them when resolving a chosen model id to its serving API.\n */\n setProviderModelLists(lists: ProviderModelLists): void;\n}\n\nexport function enabledRunners(cfg: IConfig): RunnerId[] {\n return cfg.enabledRunners;\n}\n","import type { AiProvider } from '../interfaces/IConfig';\n\nexport const PROVIDER_LABEL: Record<AiProvider, string> = {\n openrouter: 'OpenRouter',\n google: 'Google Gemini',\n openai_compatible: 'Custom',\n openai: 'OpenAI',\n xai: 'xAI',\n groq: 'Groq',\n deepseek: 'DeepSeek',\n together: 'Together AI',\n mistral: 'Mistral',\n anthropic: 'Anthropic',\n fireworks: 'Fireworks AI',\n perplexity: 'Perplexity',\n zhipu: 'Zhipu / GLM',\n kimi: 'Moonshot / Kimi',\n cerebras: 'Cerebras',\n deepinfra: 'DeepInfra',\n doubao: 'ByteDance / Doubao',\n qwen: 'Alibaba / Qwen',\n hunyuan: 'Tencent Hunyuan',\n baichuan: 'Baichuan',\n minimax: 'MiniMax',\n yi: '01.AI / Yi',\n stepfun: 'StepFun',\n siliconflow: 'SiliconFlow',\n cohere: 'Cohere',\n novita: 'Novita AI',\n 'claude-code': 'Claude Code',\n codex: 'Codex',\n opencode: 'OpenCode',\n};\n\nexport const PROVIDER_SHORT_LABEL: Record<AiProvider, string> = {\n openrouter: 'OpenRouter',\n google: 'Gemini',\n openai_compatible: 'Custom',\n openai: 'OpenAI',\n xai: 'xAI',\n groq: 'Groq',\n deepseek: 'DeepSeek',\n together: 'Together',\n mistral: 'Mistral',\n anthropic: 'Anthropic',\n fireworks: 'Fireworks',\n perplexity: 'Perplexity',\n zhipu: 'Zhipu',\n kimi: 'Kimi',\n cerebras: 'Cerebras',\n deepinfra: 'DeepInfra',\n doubao: 'Doubao',\n qwen: 'Qwen',\n hunyuan: 'Hunyuan',\n baichuan: 'Baichuan',\n minimax: 'MiniMax',\n yi: 'Yi',\n stepfun: 'StepFun',\n siliconflow: 'SiliconFlow',\n cohere: 'Cohere',\n novita: 'Novita',\n 'claude-code': 'Claude Code',\n codex: 'Codex',\n opencode: 'OpenCode',\n};\n\nexport interface ProviderRegistration {\n id: AiProvider;\n label: string;\n shortLabel: string;\n /** `cli` is a harness planner (ADR-0009): a local coding agent, not an HTTP vendor. */\n serviceType: 'openai' | 'google' | 'cli';\n /** Harness planners only: the runner id whose manifest, models and binary this provider drives. */\n runnerId?: string;\n defaultBaseUrl: string;\n apiKeyEnvVar: string;\n detectEnvVars: string[];\n baseUrlEnvVar?: string;\n secretStoreKey?: string;\n vscodeBaseUrlKey?: string;\n vscodeApiKeyKey?: string;\n discoversModels: boolean;\n modelPrefix?: string;\n}\n\nexport const ALL_PROVIDERS: Record<AiProvider, ProviderRegistration> = {\n openrouter: {\n id: 'openrouter', label: 'OpenRouter', shortLabel: 'OpenRouter',\n serviceType: 'openai',\n defaultBaseUrl: 'https://openrouter.ai/api/v1',\n apiKeyEnvVar: 'OPENROUTER_API_KEY',\n // Intentionally NOT OPENAI_API_KEY: that belongs to the dedicated `openai`\n // provider (api.openai.com). Sharing it made a bare OPENAI_API_KEY resolve\n // to OpenRouter and marked both providers configured. The legacy\n // openrouterKey/openAiApiKey getters still fall back to OPENAI_API_KEY for\n // pre-existing setups; only provider detection/routing is de-coupled here.\n detectEnvVars: ['OPENROUTER_API_KEY'],\n baseUrlEnvVar: 'OPENROUTER_BASE_URL',\n secretStoreKey: 'openrouterKey',\n vscodeBaseUrlKey: 'openAiBaseUrl', vscodeApiKeyKey: 'openAiApiKey',\n discoversModels: true,\n },\n google: {\n id: 'google', label: 'Google Gemini', shortLabel: 'Gemini',\n serviceType: 'google',\n defaultBaseUrl: '',\n apiKeyEnvVar: 'GEMINI_API_KEY',\n detectEnvVars: ['GEMINI_API_KEY'],\n baseUrlEnvVar: 'GEMINI_BASE_URL',\n secretStoreKey: 'geminiKey',\n vscodeApiKeyKey: 'apiKey',\n discoversModels: true,\n modelPrefix: 'gemini:',\n },\n openai_compatible: {\n id: 'openai_compatible', label: 'Custom', shortLabel: 'Custom',\n serviceType: 'openai',\n defaultBaseUrl: 'http://localhost:11434/v1',\n apiKeyEnvVar: 'OPENAI_COMPATIBLE_API_KEY',\n detectEnvVars: [],\n baseUrlEnvVar: 'OPENAI_COMPATIBLE_BASE_URL',\n secretStoreKey: 'openaiCompatibleKey',\n vscodeBaseUrlKey: 'openaiCompatibleBaseUrl', vscodeApiKeyKey: 'openaiCompatibleApiKey',\n discoversModels: true,\n modelPrefix: 'openai_compat:',\n },\n openai: {\n id: 'openai', label: 'OpenAI', shortLabel: 'OpenAI',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.openai.com/v1',\n apiKeyEnvVar: 'OPENAI_API_KEY',\n detectEnvVars: ['OPENAI_API_KEY'],\n secretStoreKey: 'openaiKey',\n vscodeBaseUrlKey: 'openaiBaseUrl', vscodeApiKeyKey: 'openaiApiKey',\n discoversModels: true,\n modelPrefix: 'openai:',\n },\n xai: {\n id: 'xai', label: 'xAI', shortLabel: 'xAI',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.x.ai/v1',\n apiKeyEnvVar: 'XAI_API_KEY',\n detectEnvVars: ['XAI_API_KEY'],\n secretStoreKey: 'xaiKey',\n vscodeBaseUrlKey: 'xaiBaseUrl', vscodeApiKeyKey: 'xaiApiKey',\n discoversModels: true,\n modelPrefix: 'xai:',\n },\n groq: {\n id: 'groq', label: 'Groq', shortLabel: 'Groq',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.groq.com/openai/v1',\n apiKeyEnvVar: 'GROQ_API_KEY',\n detectEnvVars: ['GROQ_API_KEY'],\n secretStoreKey: 'groqKey',\n vscodeBaseUrlKey: 'groqBaseUrl', vscodeApiKeyKey: 'groqApiKey',\n discoversModels: true,\n modelPrefix: 'groq:',\n },\n deepseek: {\n id: 'deepseek', label: 'DeepSeek', shortLabel: 'DeepSeek',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.deepseek.com/v1',\n apiKeyEnvVar: 'DEEPSEEK_API_KEY',\n detectEnvVars: ['DEEPSEEK_API_KEY'],\n secretStoreKey: 'deepseekKey',\n vscodeBaseUrlKey: 'deepseekBaseUrl', vscodeApiKeyKey: 'deepseekApiKey',\n discoversModels: true,\n modelPrefix: 'deepseek:',\n },\n together: {\n id: 'together', label: 'Together AI', shortLabel: 'Together',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.together.xyz/v1',\n apiKeyEnvVar: 'TOGETHER_API_KEY',\n detectEnvVars: ['TOGETHER_API_KEY'],\n secretStoreKey: 'togetherKey',\n vscodeBaseUrlKey: 'togetherBaseUrl', vscodeApiKeyKey: 'togetherApiKey',\n discoversModels: true,\n modelPrefix: 'together:',\n },\n mistral: {\n id: 'mistral', label: 'Mistral', shortLabel: 'Mistral',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.mistral.ai/v1',\n apiKeyEnvVar: 'MISTRAL_API_KEY',\n detectEnvVars: ['MISTRAL_API_KEY'],\n secretStoreKey: 'mistralKey',\n vscodeBaseUrlKey: 'mistralBaseUrl', vscodeApiKeyKey: 'mistralApiKey',\n discoversModels: true,\n modelPrefix: 'mistral:',\n },\n anthropic: {\n id: 'anthropic', label: 'Anthropic', shortLabel: 'Anthropic',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.anthropic.com/v1',\n apiKeyEnvVar: 'ANTHROPIC_API_KEY',\n detectEnvVars: ['ANTHROPIC_API_KEY'],\n secretStoreKey: 'anthropicKey',\n vscodeBaseUrlKey: 'anthropicBaseUrl', vscodeApiKeyKey: 'anthropicApiKey',\n discoversModels: true,\n modelPrefix: 'anthropic:',\n },\n fireworks: {\n id: 'fireworks', label: 'Fireworks AI', shortLabel: 'Fireworks',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.fireworks.ai/inference/v1',\n apiKeyEnvVar: 'FIREWORKS_API_KEY',\n detectEnvVars: ['FIREWORKS_API_KEY'],\n secretStoreKey: 'fireworksKey',\n vscodeBaseUrlKey: 'fireworksBaseUrl', vscodeApiKeyKey: 'fireworksApiKey',\n discoversModels: true,\n modelPrefix: 'fireworks:',\n },\n perplexity: {\n id: 'perplexity', label: 'Perplexity', shortLabel: 'Perplexity',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.perplexity.ai',\n apiKeyEnvVar: 'PERPLEXITY_API_KEY',\n detectEnvVars: ['PERPLEXITY_API_KEY'],\n secretStoreKey: 'perplexityKey',\n vscodeBaseUrlKey: 'perplexityBaseUrl', vscodeApiKeyKey: 'perplexityApiKey',\n // Perplexity exposes no OpenAI-style GET /models list endpoint, so catalog\n // discovery always fails. Users set a perplexity model id explicitly\n // (AI_PROVIDER=perplexity + orchestratorModel=sonar-…) instead.\n discoversModels: false,\n modelPrefix: 'perplexity:',\n },\n zhipu: {\n id: 'zhipu', label: 'Zhipu / GLM', shortLabel: 'Zhipu',\n serviceType: 'openai',\n defaultBaseUrl: 'https://open.bigmodel.cn/api/paas/v4',\n apiKeyEnvVar: 'ZHIPU_API_KEY',\n detectEnvVars: ['ZHIPU_API_KEY'],\n secretStoreKey: 'zhipuKey',\n vscodeBaseUrlKey: 'zhipuBaseUrl', vscodeApiKeyKey: 'zhipuApiKey',\n discoversModels: true,\n modelPrefix: 'zhipu:',\n },\n kimi: {\n id: 'kimi', label: 'Moonshot / Kimi', shortLabel: 'Kimi',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.moonshot.cn/v1',\n apiKeyEnvVar: 'MOONSHOT_API_KEY',\n detectEnvVars: ['MOONSHOT_API_KEY'],\n secretStoreKey: 'kimiKey',\n vscodeBaseUrlKey: 'kimiBaseUrl', vscodeApiKeyKey: 'kimiApiKey',\n discoversModels: true,\n modelPrefix: 'kimi:',\n },\n cerebras: {\n id: 'cerebras', label: 'Cerebras', shortLabel: 'Cerebras',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.cerebras.ai/v1',\n apiKeyEnvVar: 'CEREBRAS_API_KEY',\n detectEnvVars: ['CEREBRAS_API_KEY'],\n secretStoreKey: 'cerebrasKey',\n vscodeBaseUrlKey: 'cerebrasBaseUrl', vscodeApiKeyKey: 'cerebrasApiKey',\n discoversModels: true,\n modelPrefix: 'cerebras:',\n },\n deepinfra: {\n id: 'deepinfra', label: 'DeepInfra', shortLabel: 'DeepInfra',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.deepinfra.com/v1/openai',\n apiKeyEnvVar: 'DEEPINFRA_API_KEY',\n detectEnvVars: ['DEEPINFRA_API_KEY'],\n secretStoreKey: 'deepinfraKey',\n vscodeBaseUrlKey: 'deepinfraBaseUrl', vscodeApiKeyKey: 'deepinfraApiKey',\n discoversModels: true,\n modelPrefix: 'deepinfra:',\n },\n doubao: {\n id: 'doubao', label: 'ByteDance / Doubao', shortLabel: 'Doubao',\n serviceType: 'openai',\n defaultBaseUrl: 'https://ark.cn-beijing.volces.com/api/v3',\n apiKeyEnvVar: 'ARK_API_KEY',\n detectEnvVars: ['ARK_API_KEY'],\n secretStoreKey: 'doubaoKey',\n vscodeBaseUrlKey: 'doubaoBaseUrl', vscodeApiKeyKey: 'doubaoApiKey',\n discoversModels: true,\n modelPrefix: 'doubao:',\n },\n qwen: {\n id: 'qwen', label: 'Alibaba / Qwen', shortLabel: 'Qwen',\n serviceType: 'openai',\n defaultBaseUrl: 'https://dashscope.aliyuncs.com/compatible-mode/v1',\n apiKeyEnvVar: 'DASHSCOPE_API_KEY',\n detectEnvVars: ['DASHSCOPE_API_KEY'],\n secretStoreKey: 'qwenKey',\n vscodeBaseUrlKey: 'qwenBaseUrl', vscodeApiKeyKey: 'qwenApiKey',\n discoversModels: true,\n modelPrefix: 'qwen:',\n },\n hunyuan: {\n id: 'hunyuan', label: 'Tencent Hunyuan', shortLabel: 'Hunyuan',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.hunyuan.cloud.tencent.com/v1',\n apiKeyEnvVar: 'HUNYUAN_API_KEY',\n detectEnvVars: ['HUNYUAN_API_KEY'],\n secretStoreKey: 'hunyuanKey',\n vscodeBaseUrlKey: 'hunyuanBaseUrl', vscodeApiKeyKey: 'hunyuanApiKey',\n discoversModels: true,\n modelPrefix: 'hunyuan:',\n },\n baichuan: {\n id: 'baichuan', label: 'Baichuan', shortLabel: 'Baichuan',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.baichuan-ai.com/v1',\n apiKeyEnvVar: 'BAICHUAN_API_KEY',\n detectEnvVars: ['BAICHUAN_API_KEY'],\n secretStoreKey: 'baichuanKey',\n vscodeBaseUrlKey: 'baichuanBaseUrl', vscodeApiKeyKey: 'baichuanApiKey',\n discoversModels: true,\n modelPrefix: 'baichuan:',\n },\n minimax: {\n id: 'minimax', label: 'MiniMax', shortLabel: 'MiniMax',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.minimax.chat/v1',\n apiKeyEnvVar: 'MINIMAX_API_KEY',\n detectEnvVars: ['MINIMAX_API_KEY'],\n secretStoreKey: 'minimaxKey',\n vscodeBaseUrlKey: 'minimaxBaseUrl', vscodeApiKeyKey: 'minimaxApiKey',\n discoversModels: true,\n modelPrefix: 'minimax:',\n },\n yi: {\n id: 'yi', label: '01.AI / Yi', shortLabel: 'Yi',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.lingyiwanwu.com/v1',\n apiKeyEnvVar: 'YI_API_KEY',\n detectEnvVars: ['YI_API_KEY'],\n secretStoreKey: 'yiKey',\n vscodeBaseUrlKey: 'yiBaseUrl', vscodeApiKeyKey: 'yiApiKey',\n discoversModels: true,\n modelPrefix: 'yi:',\n },\n stepfun: {\n id: 'stepfun', label: 'StepFun', shortLabel: 'StepFun',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.stepfun.com/v1',\n apiKeyEnvVar: 'STEPFUN_API_KEY',\n detectEnvVars: ['STEPFUN_API_KEY'],\n secretStoreKey: 'stepfunKey',\n vscodeBaseUrlKey: 'stepfunBaseUrl', vscodeApiKeyKey: 'stepfunApiKey',\n discoversModels: true,\n modelPrefix: 'stepfun:',\n },\n siliconflow: {\n id: 'siliconflow', label: 'SiliconFlow', shortLabel: 'SiliconFlow',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.siliconflow.cn/v1',\n apiKeyEnvVar: 'SILICONFLOW_API_KEY',\n detectEnvVars: ['SILICONFLOW_API_KEY'],\n secretStoreKey: 'siliconflowKey',\n vscodeBaseUrlKey: 'siliconflowBaseUrl', vscodeApiKeyKey: 'siliconflowApiKey',\n discoversModels: true,\n modelPrefix: 'siliconflow:',\n },\n cohere: {\n id: 'cohere', label: 'Cohere', shortLabel: 'Cohere',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.cohere.com/v1',\n apiKeyEnvVar: 'COHERE_API_KEY',\n detectEnvVars: ['COHERE_API_KEY'],\n secretStoreKey: 'cohereKey',\n vscodeBaseUrlKey: 'cohereBaseUrl', vscodeApiKeyKey: 'cohereApiKey',\n discoversModels: true,\n modelPrefix: 'cohere:',\n },\n novita: {\n id: 'novita', label: 'Novita AI', shortLabel: 'Novita',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.novita.ai/v3/openai',\n apiKeyEnvVar: 'NOVITA_API_KEY',\n detectEnvVars: ['NOVITA_API_KEY'],\n secretStoreKey: 'novitaKey',\n vscodeBaseUrlKey: 'novitaBaseUrl', vscodeApiKeyKey: 'novitaApiKey',\n discoversModels: true,\n modelPrefix: 'novita:',\n },\n\n // Harness planners (ADR-0009). No key, no base URL, no HTTP catalog: the\n // binary is local, the credential is the user's existing subscription, and\n // the model list comes from the runner's own discovery. `apiKeyEnvVar` is\n // empty on purpose — anything that resolves keys must skip these, which is\n // what `isCliProvider` is for.\n 'claude-code': {\n id: 'claude-code', label: 'Claude Code', shortLabel: 'Claude Code',\n serviceType: 'cli', runnerId: 'claude-code',\n defaultBaseUrl: '',\n apiKeyEnvVar: '',\n detectEnvVars: [],\n discoversModels: false,\n },\n codex: {\n id: 'codex', label: 'Codex', shortLabel: 'Codex',\n serviceType: 'cli', runnerId: 'codex',\n defaultBaseUrl: '',\n apiKeyEnvVar: '',\n detectEnvVars: [],\n discoversModels: false,\n },\n opencode: {\n id: 'opencode', label: 'OpenCode', shortLabel: 'OpenCode',\n serviceType: 'cli', runnerId: 'opencode',\n defaultBaseUrl: '',\n apiKeyEnvVar: '',\n detectEnvVars: [],\n discoversModels: false,\n },\n};\n\nexport function getProviderMeta(id: AiProvider): ProviderRegistration {\n return ALL_PROVIDERS[id];\n}\n\nexport function prefixModelId(provider: AiProvider, modelId: string): string {\n const meta = getProviderMeta(provider);\n return meta?.modelPrefix ? `${meta.modelPrefix}${modelId}` : modelId;\n}\n\nexport function stripModelPrefix(id: string, provider: AiProvider): string {\n const meta = getProviderMeta(provider);\n if (meta?.modelPrefix && id.startsWith(meta.modelPrefix)) {\n return id.slice(meta.modelPrefix.length);\n }\n return id;\n}\n\nexport function resolveProviderFromPrefix(id: string): AiProvider | null {\n for (const provider of PROVIDER_PRIORITY) {\n const meta = ALL_PROVIDERS[provider];\n if (meta.modelPrefix && id.startsWith(meta.modelPrefix)) return provider as AiProvider;\n }\n return null;\n}\n\n/**\n * The harness planners, in display order. Deliberately NOT part of\n * `PROVIDER_PRIORITY`: that list means \"vendors that take an API key\", and\n * every consumer of it — key prompts, catalog fetches, base-URL cache clearing\n * — would be asking a local binary for a credential it does not have. Surfaces\n * that offer a planner picker concatenate the two lists and gate these on\n * `RunnerInstallation.plannerUsability`.\n */\nexport const CLI_PROVIDERS: AiProvider[] = ['claude-code', 'codex', 'opencode'];\n\nexport const PROVIDER_PRIORITY: AiProvider[] = [\n 'openrouter', 'google',\n 'openai', 'anthropic', 'mistral', 'xai', 'groq', 'deepseek',\n 'together', 'fireworks', 'perplexity', 'cerebras', 'deepinfra', 'cohere', 'novita',\n 'zhipu', 'kimi', 'doubao', 'qwen', 'hunyuan', 'baichuan', 'minimax', 'yi', 'stepfun', 'siliconflow',\n 'openai_compatible',\n];\n\nexport const PROVIDER_DETECT_PRIORITY: AiProvider[] = [\n 'google', 'openrouter',\n 'openai', 'anthropic', 'mistral', 'xai', 'groq', 'deepseek',\n 'together', 'fireworks', 'perplexity', 'cerebras', 'deepinfra', 'cohere', 'novita',\n 'zhipu', 'kimi', 'doubao', 'qwen', 'hunyuan', 'baichuan', 'minimax', 'yi', 'stepfun', 'siliconflow',\n 'openai_compatible',\n];\n\nexport function isOpenAiProvider(id: AiProvider): boolean {\n return ALL_PROVIDERS[id]?.serviceType === 'openai';\n}\n\n/**\n * The one guard that separates a harness planner from an LLM vendor (ADR-0009).\n * Three places consult it: API-key resolution (skipped — the subscription is\n * the credential), provider routing (skipped — there is no HTTP endpoint), and\n * the planner-model picker (fed by per-runner discovery, not the vendor\n * catalog).\n */\nexport function isCliProvider(id: AiProvider): boolean {\n return ALL_PROVIDERS[id]?.serviceType === 'cli';\n}\n\n/** The runner a harness planner drives, or null for a vendor provider. */\nexport function runnerForProvider(id: AiProvider): string | null {\n return ALL_PROVIDERS[id]?.runnerId ?? null;\n}\n\n/** The harness planner that wraps a given runner, or null when none does. */\nexport function providerForRunner(runner: string): AiProvider | null {\n return CLI_PROVIDERS.find((p) => ALL_PROVIDERS[p].runnerId === runner) ?? null;\n}\n\n/**\n * The single definition of which providers count as \"configured\" — one API\n * key each, or (for `openai_compatible`) an explicit base URL. Every surface\n * (CLI listing, VS Code picker gating) derives its configured-provider set\n * from here so they can never diverge on what a user has set up. Order follows\n * PROVIDER_PRIORITY.\n */\nexport function configuredProviders(config: {\n getProviderApiKey(provider: AiProvider): string;\n openaiCompatibleBaseUrl: string;\n}): AiProvider[] {\n const out: AiProvider[] = [];\n for (const provider of PROVIDER_PRIORITY) {\n if (provider === 'openai_compatible') {\n if (config.openaiCompatibleBaseUrl) out.push(provider);\n } else if (config.getProviderApiKey(provider)) {\n out.push(provider);\n }\n }\n return out;\n}\n","import { IConfig, AiProvider } from './IConfig';\nimport type { ApprovalMode } from '../services/ApprovalPolicy';\nimport type { ProviderModelLists } from '../services/ProviderRouting';\nimport { ALL_PROVIDERS, getProviderMeta, PROVIDER_DETECT_PRIORITY } from '../services/ProviderRegistry';\n\nexport function normalizeGeminiModel(id: string): string {\n return id.replace(/^gemini:/, '').replace(/^google\\//, '');\n}\n\nexport abstract class BaseConfig implements IConfig {\n abstract aiProvider: AiProvider;\n abstract apiKey: string;\n abstract planningModel: string;\n abstract enabledRunners: string[];\n\n abstract setProviderModelLists(lists: ProviderModelLists): void;\n\n // --- Legacy named getters (backward compat) ---\n\n get openAiBaseUrl(): string { return process.env.OPENROUTER_BASE_URL || process.env.OPENAI_BASE_URL || 'https://openrouter.ai/api/v1'; }\n get openAiApiKey(): string { return process.env.OPENROUTER_API_KEY || process.env.OPENAI_API_KEY || ''; }\n get openrouterKey(): string { return process.env.OPENROUTER_API_KEY || process.env.OPENAI_API_KEY || ''; }\n get geminiKey(): string { return process.env.GEMINI_API_KEY || ''; }\n get geminiBaseUrl(): string | undefined { return process.env.GEMINI_BASE_URL || undefined; }\n get openaiCompatibleBaseUrl(): string { return process.env.OPENAI_COMPATIBLE_BASE_URL || ''; }\n get openaiCompatibleApiKey(): string { return process.env.OPENAI_COMPATIBLE_API_KEY || ''; }\n get orchestratorModel(): string { return process.env.ORCHESTRATOR_MODEL || ''; }\n // Grunt reading must never cost strong-model prices: subagents follow the\n // (cheap) planner model unless explicitly pinned elsewhere.\n get researchSubagentModel(): string { return process.env.ORDEWELL_SUBAGENT_MODEL || this.orchestratorModel; }\n get geminiModel(): string { return normalizeGeminiModel(process.env.GEMINI_MODEL || ''); }\n get plannerThinkingEffort(): string | undefined { return process.env.ORDEWELL_PLANNER_EFFORT || undefined; }\n\n // --- New preset getters ---\n\n get openaiBaseUrl(): string { return process.env.OPENAI_BASE_URL || 'https://api.openai.com/v1'; }\n get openaiApiKey(): string { return process.env.OPENAI_API_KEY || ''; }\n get xaiBaseUrl(): string { return process.env.XAI_BASE_URL || 'https://api.x.ai/v1'; }\n get xaiApiKey(): string { return process.env.XAI_API_KEY || ''; }\n get groqBaseUrl(): string { return process.env.GROQ_BASE_URL || 'https://api.groq.com/openai/v1'; }\n get groqApiKey(): string { return process.env.GROQ_API_KEY || ''; }\n get deepseekBaseUrl(): string { return process.env.DEEPSEEK_BASE_URL || 'https://api.deepseek.com/v1'; }\n get deepseekApiKey(): string { return process.env.DEEPSEEK_API_KEY || ''; }\n\n get togetherBaseUrl(): string { return process.env.TOGETHER_BASE_URL || 'https://api.together.xyz/v1'; }\n get togetherApiKey(): string { return process.env.TOGETHER_API_KEY || ''; }\n get mistralBaseUrl(): string { return process.env.MISTRAL_BASE_URL || 'https://api.mistral.ai/v1'; }\n get mistralApiKey(): string { return process.env.MISTRAL_API_KEY || ''; }\n get anthropicBaseUrl(): string { return process.env.ANTHROPIC_BASE_URL || 'https://api.anthropic.com/v1'; }\n get anthropicApiKey(): string { return process.env.ANTHROPIC_API_KEY || ''; }\n get fireworksBaseUrl(): string { return process.env.FIREWORKS_BASE_URL || 'https://api.fireworks.ai/inference/v1'; }\n get fireworksApiKey(): string { return process.env.FIREWORKS_API_KEY || ''; }\n get perplexityBaseUrl(): string { return process.env.PERPLEXITY_BASE_URL || 'https://api.perplexity.ai'; }\n get perplexityApiKey(): string { return process.env.PERPLEXITY_API_KEY || ''; }\n get zhipuBaseUrl(): string { return process.env.ZHIPU_BASE_URL || 'https://open.bigmodel.cn/api/paas/v4'; }\n get zhipuApiKey(): string { return process.env.ZHIPU_API_KEY || ''; }\n get kimiBaseUrl(): string { return process.env.KIMI_BASE_URL || 'https://api.moonshot.cn/v1'; }\n get kimiApiKey(): string { return process.env.MOONSHOT_API_KEY || ''; }\n get cerebrasBaseUrl(): string { return process.env.CEREBRAS_BASE_URL || 'https://api.cerebras.ai/v1'; }\n get cerebrasApiKey(): string { return process.env.CEREBRAS_API_KEY || ''; }\n get deepinfraBaseUrl(): string { return process.env.DEEPINFRA_BASE_URL || 'https://api.deepinfra.com/v1/openai'; }\n get deepinfraApiKey(): string { return process.env.DEEPINFRA_API_KEY || ''; }\n get doubaoBaseUrl(): string { return process.env.DOUBAO_BASE_URL || 'https://ark.cn-beijing.volces.com/api/v3'; }\n get doubaoApiKey(): string { return process.env.ARK_API_KEY || ''; }\n get qwenBaseUrl(): string { return process.env.QWEN_BASE_URL || 'https://dashscope.aliyuncs.com/compatible-mode/v1'; }\n get qwenApiKey(): string { return process.env.DASHSCOPE_API_KEY || ''; }\n get hunyuanBaseUrl(): string { return process.env.HUNYUAN_BASE_URL || 'https://api.hunyuan.cloud.tencent.com/v1'; }\n get hunyuanApiKey(): string { return process.env.HUNYUAN_API_KEY || ''; }\n get baichuanBaseUrl(): string { return process.env.BAICHUAN_BASE_URL || 'https://api.baichuan-ai.com/v1'; }\n get baichuanApiKey(): string { return process.env.BAICHUAN_API_KEY || ''; }\n get minimaxBaseUrl(): string { return process.env.MINIMAX_BASE_URL || 'https://api.minimax.chat/v1'; }\n get minimaxApiKey(): string { return process.env.MINIMAX_API_KEY || ''; }\n get yiBaseUrl(): string { return process.env.YI_BASE_URL || 'https://api.lingyiwanwu.com/v1'; }\n get yiApiKey(): string { return process.env.YI_API_KEY || ''; }\n get stepfunBaseUrl(): string { return process.env.STEPFUN_BASE_URL || 'https://api.stepfun.com/v1'; }\n get stepfunApiKey(): string { return process.env.STEPFUN_API_KEY || ''; }\n get siliconflowBaseUrl(): string { return process.env.SILICONFLOW_BASE_URL || 'https://api.siliconflow.cn/v1'; }\n get siliconflowApiKey(): string { return process.env.SILICONFLOW_API_KEY || ''; }\n get cohereBaseUrl(): string { return process.env.COHERE_BASE_URL || 'https://api.cohere.com/v1'; }\n get cohereApiKey(): string { return process.env.COHERE_API_KEY || ''; }\n get novitaBaseUrl(): string { return process.env.NOVITA_BASE_URL || 'https://api.novita.ai/v3/openai'; }\n get novitaApiKey(): string { return process.env.NOVITA_API_KEY || ''; }\n\n // --- Registry-driven generic getters ---\n\n getProviderBaseUrl(provider: AiProvider): string {\n const meta = getProviderMeta(provider);\n if (!meta) return '';\n if (meta.baseUrlEnvVar && process.env[meta.baseUrlEnvVar]) return process.env[meta.baseUrlEnvVar]!;\n return meta.defaultBaseUrl;\n }\n\n getProviderApiKey(provider: AiProvider): string {\n const meta = getProviderMeta(provider);\n if (!meta) return '';\n for (const envVar of [meta.apiKeyEnvVar, ...meta.detectEnvVars]) {\n const val = process.env[envVar];\n if (val) return val;\n }\n return '';\n }\n\n get maxParallelSessions(): number { return parseInt(process.env.ORDEWELL_MAX_PARALLEL || '3', 10); }\n get researchEnabled(): boolean { return process.env.ORDEWELL_RESEARCH_ENABLED !== 'false'; }\n get researchMaxSteps(): number { return parseInt(process.env.ORDEWELL_RESEARCH_MAX_STEPS || '48', 10); }\n get researchMaxFileSize(): number { return parseInt(process.env.ORDEWELL_RESEARCH_MAX_FILE_SIZE || '50', 10); }\n\n get planMapEnabled(): boolean { return process.env.ORDEWELL_PLAN_MAP_ENABLED !== 'false' && process.env.ORDEWELL_PLAN_MAP_ENABLED !== '0'; }\n\n get autonomousMode(): boolean { return process.env.ORDEWELL_AUTONOMOUS_MODE !== 'false' && process.env.ORDEWELL_AUTONOMOUS_MODE !== '0'; }\n\n get approvalMode(): ApprovalMode {\n const raw = (process.env.ORDEWELL_APPROVAL_MODE || '').trim().toLowerCase();\n return raw === 'allow' || raw === 'deny' ? raw : 'ask';\n }\n\n get approvalPreApproved(): string[] {\n // Comma- or newline-separated so a CI env var and a shell export both read naturally.\n return (process.env.ORDEWELL_APPROVAL_ALLOW || '')\n .split(/[,\\n]/)\n .map((s) => s.trim())\n .filter(Boolean);\n }\n\n protected static detectProvider(fallback: AiProvider): AiProvider {\n const env = process.env.AI_PROVIDER;\n if (env && ALL_PROVIDERS[env as AiProvider]) return env as AiProvider;\n\n for (const provider of PROVIDER_DETECT_PRIORITY) {\n const meta = ALL_PROVIDERS[provider];\n if (!meta) continue;\n if (meta.detectEnvVars.some((v) => process.env[v])) return provider as AiProvider;\n if (meta.baseUrlEnvVar && process.env[meta.baseUrlEnvVar]) return provider as AiProvider;\n }\n\n return fallback;\n }\n}\n","import { BaseConfig } from './BaseConfig';\nimport type { AiProvider } from './IConfig';\n\n/**\n * A fully `process.env`-backed IConfig for headless callers (e.g. the CLI's\n * `ordewell models` command) that need provider keys/base URLs but have no\n * editor settings or secret store. All resolution lives in BaseConfig; this\n * subclass only supplies the abstract members from the environment.\n */\nexport class EnvConfig extends BaseConfig {\n get aiProvider(): AiProvider {\n return BaseConfig.detectProvider('openrouter');\n }\n\n get apiKey(): string {\n return this.getProviderApiKey(this.aiProvider) || this.openrouterKey || this.geminiKey || '';\n }\n\n get planningModel(): string {\n return this.orchestratorModel;\n }\n\n get enabledRunners(): string[] {\n const raw = process.env.ORDEWELL_RUNNERS || process.env.ENABLED_RUNNERS || '';\n return raw.split(',').map((s) => s.trim()).filter(Boolean);\n }\n\n // The CLI does not persist routing lists; resolution happens per-invocation.\n setProviderModelLists(): void {}\n}\n","export interface ILogger {\n warn(scope: string, message: string, err?: unknown): void;\n}\n\nexport class ConsoleLogger implements ILogger {\n warn(scope: string, message: string, err?: unknown): void {\n const detail = err === undefined ? '' : ` :: ${formatError(err)}`;\n console.warn(`[${scope}] ${message}${detail}`);\n }\n}\n\nfunction formatError(err: unknown): string {\n if (err instanceof Error) return err.message;\n if (typeof err === 'string') return err;\n try { return JSON.stringify(err); } catch { return String(err); }\n}\n\nexport const defaultLogger: ILogger = new ConsoleLogger();\n","import { v4 as uuidv4 } from 'uuid';\nimport { Task, DiscoveredModel, ResearchStep, ResearchLogEntry, ResearchProgress, RunnerId } from '../models/Task';\nimport { IConfig } from '../interfaces/IConfig';\nimport { IFileSystem } from '../interfaces/IFileSystem';\nimport { IWebFetcher } from '../interfaces/IWebFetcher';\nimport { buildPlanWithResults } from './PlanPrompts';\nimport { DEFAULT_PLANNER_MODES, type PlannerModes } from './plannerModes';\nimport { generatePlanWithRepair, classifyPlannerReply, reEmitPlanPrompt, reEmitTaskOpsPrompt, truncatedPlanReEmitPrompt } from './PlanRepair';\nimport { compactResearchResults, withProactiveCompaction } from './contextCompaction';\nimport { extractPrdBlock } from '../utils/prdStore';\nimport type { RunnerModeInfo } from './ModeResolver';\nimport { collectResearchContext } from './ContextCollector';\nimport { executeTool } from './executeTool';\nimport { runResearchAgent, mapWithConcurrency, SUBAGENT_LIMITS } from './ResearchSubagents';\nimport { SPAWN_RESEARCH_AGENT } from './researchTools';\nimport { classifyOutcome } from './researchStepSummary';\nimport type { ConversationTurn } from './AiService';\n\n/**\n * Read-only, side-effect-free tools that can share a round. Deliberately a\n * denylist's opposite: `bash`, `fetch` and `web_search` are excluded because\n * they can pause on a user approval prompt, and an unknown tool is excluded\n * because we cannot reason about it.\n */\nconst PARALLEL_SAFE_TOOLS = new Set(['read_file', 'read_files', 'glob', 'grep', 'find_symbol', 'list_dir']);\n\n/** Concurrency for the read-only pre-pass. Bounded so a wide round cannot exhaust file handles. */\nconst TOOL_ROUND_CONCURRENCY = 8;\n\nexport interface ToolCall {\n name: string;\n args: Record<string, unknown>;\n id?: string;\n}\n\nexport interface ToolResult {\n name: string;\n output: string;\n truncated: boolean;\n totalChars: number;\n id?: string;\n}\n\nexport interface ResearchTurn {\n text: string;\n toolCalls: ToolCall[];\n hasToolCalls: boolean;\n /** Reasoning/chain-of-thought captured separately from `text` so it never pollutes plan JSON. */\n reasoning?: string;\n /** Provider finish reason, normalized: 'length' means the output-token limit cut the reply mid-stream. */\n finishReason?: string;\n /** Exact prompt tokens this turn consumed, when the provider reports usage — drives proactive compaction. */\n promptTokens?: number;\n}\n\nexport interface ResearchChat {\n sendMessage(text: string, signal?: AbortSignal): Promise<ResearchTurn>;\n sendToolResults(results: ToolResult[], signal?: AbortSignal): Promise<ResearchTurn>;\n /**\n * Optional: prune bulky raw tool outputs from the history in place (subagent\n * digests are kept) so a follow-up emission has context to spend on output.\n * Returns the number of characters removed. Providers whose SDK owns the\n * history (Gemini) may not support it.\n */\n compactHistory?(): number;\n}\n\n/** Everything one conversation turn needs beyond the user message itself. */\nexport interface ConversationTurnContext {\n chat: ResearchChat;\n fs: IFileSystem;\n runners: RunnerId[];\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>;\n autonomousDefault?: boolean;\n fetcher?: IWebFetcher;\n /** PRD toggle: a plan must not commit before a PRD block has appeared. */\n prdEnabled?: boolean;\n /** Set once any turn carries an ORDEWELL_PRD block; gates the missing-PRD nudge. */\n prdCaptured?: boolean;\n /** The missing-PRD corrective nudge is sent at most once per conversation. */\n prdNudgeSent?: boolean;\n}\n\nexport abstract class BaseAiService {\n protected conversation: { ctx: ConversationTurnContext; setProgress: (fn: (p: ResearchProgress) => void) => void } | null = null;\n protected activeAbort: AbortController | null = null;\n /** researchSubagents toggle (issue #34): set per operation from the live settings snapshot; off means bit-for-bit sequential behavior. */\n protected researchSubagentsEnabled = false;\n\n constructor(protected config: IConfig) {}\n\n abstract reset(): void;\n abstract ensureInit(): void;\n\n hasActiveConversation(): boolean { return this.conversation !== null; }\n\n protected startAbortScope(callerSignal?: AbortSignal): AbortSignal | undefined {\n this.activeAbort = new AbortController();\n if (!callerSignal) return this.activeAbort.signal;\n if (callerSignal.aborted) { this.activeAbort.abort(); return this.activeAbort.signal; }\n callerSignal.addEventListener('abort', () => this.activeAbort?.abort(), { once: true });\n return this.activeAbort.signal;\n }\n\n protected stopAbortScope(): void {\n this.activeAbort = null;\n }\n\n async sendPlanningPrompt(\n prompt: string,\n runners: RunnerId[],\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n autonomousDefault = true,\n ): Promise<Task[]> {\n this.ensureInit();\n return generatePlanWithRepair(\n (repairHint) => this.streamPlanText(prompt, repairHint, () => {}),\n runners, 2, runnerModes, autonomousDefault,\n );\n }\n\n async continueConversation(\n userMessage: string,\n onProgress: (progress: ResearchProgress) => void,\n signal?: AbortSignal,\n ): Promise<ConversationTurn> {\n this.ensureInit();\n if (!this.conversation) throw new Error('No active planner conversation. Start planning first.');\n this.conversation.setProgress(onProgress);\n const combinedSignal = this.startAbortScope(signal);\n try {\n const result = await this.runConversationTurn(this.conversation.ctx, userMessage, onProgress, combinedSignal);\n if (result.kind === 'plan') this.conversation = null;\n return result;\n } finally {\n this.stopAbortScope();\n }\n }\n\n protected abstract streamPlanText(\n prompt: string,\n repairHint: string | undefined,\n onToken: (token: string) => void,\n onReasoning?: (token: string) => void,\n signal?: AbortSignal,\n ): Promise<string>;\n\n /**\n * Build a fresh chat for one research subagent (own history, subagent system\n * prompt, cheap model). Null means the provider does not support subagents —\n * the spawn tool then degrades to a steering message. `onReasoning` streams\n * live reasoning deltas on models that expose them, same as the top-level loop.\n */\n protected createSubagentChat(_onReasoning?: (delta: string) => void): ResearchChat | null { return null; }\n\n /**\n * One spawn_research_agent tool call, executed at the service layer (not in\n * executeTool — that would cycle the imports). Every failure path returns a\n * steering/failed result and the loop continues sequentially: a subagent can\n * never fail a plan or a turn.\n */\n private async executeSpawnAgent(\n args: Record<string, unknown>,\n fs: IFileSystem,\n onProgress: (progress: ResearchProgress) => void,\n signal: AbortSignal | undefined,\n subagentId: string,\n ): Promise<{ success: boolean; output: string; truncated: boolean }> {\n if (!this.researchSubagentsEnabled) {\n return { success: false, output: 'spawn_research_agent is not available in this session. Continue researching sequentially with your other tools (read_file, glob, grep, list_dir, bash).', truncated: false };\n }\n const prompt = typeof args.prompt === 'string' ? args.prompt.trim() : '';\n if (!prompt) {\n return { success: false, output: 'spawn_research_agent requires a non-empty \"prompt\" string: a self-contained task for the agent, including what its digest must report back.', truncated: false };\n }\n return runResearchAgent(prompt, {\n createChat: (onReasoning) => {\n const chat = this.createSubagentChat(onReasoning);\n if (!chat) throw new Error('subagent chats are not available for this provider');\n return chat;\n },\n fs,\n signal,\n onProgress: (progress) => onProgress({ ...progress, subagentId }),\n });\n }\n\n /** Collect project context for the planning phase. Shared with the harness backend. */\n protected static async collectResearchContext(fs: IFileSystem, runners: RunnerId[]): Promise<string> {\n return collectResearchContext(fs, runners);\n }\n\n /**\n * Execute one round of tool calls and report each through onProgress.\n * Returns the results to feed back plus the log entries produced.\n */\n private async executeToolCalls(\n toolCalls: ToolCall[],\n fs: IFileSystem,\n onProgress: (progress: ResearchProgress) => void,\n fetcher: IWebFetcher | undefined,\n stepIndex: number,\n thinking: string,\n signal?: AbortSignal,\n ): Promise<{ toolResults: ToolResult[]; logEntries: ResearchStep[]; resultsText: string }> {\n const toolResults: ToolResult[] = [];\n const logEntries: ResearchStep[] = [];\n let resultsText = '';\n let thinkingAttached = false;\n\n // Two concurrent pre-passes, then one ordered merge.\n //\n // Spawn calls have always run in parallel. The pure reads now do too: when\n // a model asks for six files in one round, six serial HTTP-free round trips\n // was simply latency we were choosing to pay. They are side-effect free and\n // order-independent, so the only thing sequencing bought was the illusion\n // of determinism — results are still merged back in call order below.\n //\n // Everything else (bash, fetch, web_search, unknown tools) stays serial:\n // those can block on a user approval prompt, and firing several prompts at\n // once would be hostile in every surface.\n const precomputed = new Map<number, { success: boolean; output: string; truncated: boolean }>();\n const spawnSubagentIds = new Map<number, string>();\n const normalizedArgs = toolCalls.map((tc) => {\n const args = { ...tc.args };\n if (tc.name === 'read_file' && !('maxBytes' in args) && !('limit' in args)) args.limit = 2000;\n return args;\n });\n\n const spawnIndexes = toolCalls.flatMap((tc, i) => (tc.name === SPAWN_RESEARCH_AGENT ? [i] : []));\n const parallelIndexes = toolCalls.flatMap((tc, i) => (PARALLEL_SAFE_TOOLS.has(tc.name) ? [i] : []));\n\n await Promise.all([\n spawnIndexes.length > 0\n ? mapWithConcurrency(spawnIndexes, SUBAGENT_LIMITS.maxConcurrent, async (i) => {\n const subagentId = uuidv4();\n spawnSubagentIds.set(i, subagentId);\n onProgress({ type: 'tool_call', tool: toolCalls[i].name, toolArgs: JSON.stringify(toolCalls[i].args), subagentId, toolCallId: toolCalls[i].id });\n precomputed.set(i, await this.executeSpawnAgent({ ...toolCalls[i].args }, fs, onProgress, signal, subagentId));\n })\n : Promise.resolve(),\n parallelIndexes.length > 1\n ? mapWithConcurrency(parallelIndexes, TOOL_ROUND_CONCURRENCY, async (i) => {\n onProgress({ type: 'tool_call', tool: toolCalls[i].name, toolArgs: JSON.stringify(toolCalls[i].args), toolCallId: toolCalls[i].id });\n precomputed.set(i, await executeTool(toolCalls[i].name, normalizedArgs[i], fs, fetcher));\n })\n : Promise.resolve(),\n ]);\n\n for (const [index, tc] of toolCalls.entries()) {\n const toolArgs = normalizedArgs[index];\n\n const preResult = precomputed.get(index);\n if (!preResult) onProgress({ type: 'tool_call', tool: tc.name, toolArgs: JSON.stringify(tc.args), toolCallId: tc.id });\n\n const toolResult = preResult ?? await executeTool(tc.name, toolArgs, fs, fetcher);\n\n const MAX_RESPONSE_CHARS = 50000;\n const truncatedResponse = toolResult.success && (toolResult.truncated || toolResult.output.length > MAX_RESPONSE_CHARS);\n const llmOutput = toolResult.output.length > MAX_RESPONSE_CHARS\n ? toolResult.output.slice(0, MAX_RESPONSE_CHARS) + `\\n[... truncated to ${MAX_RESPONSE_CHARS} chars, total ${toolResult.output.length}]`\n : toolResult.output;\n\n const LOG_MAX = 10000;\n const outcome = classifyOutcome(toolResult.success, toolResult.output);\n const stepEntry: ResearchStep = {\n id: `rs-${Date.now()}-${stepIndex}-${logEntries.length}`,\n tool: tc.name as ResearchStep['tool'],\n args: JSON.stringify(tc.args),\n result: toolResult.output.length > LOG_MAX\n ? toolResult.output.slice(0, LOG_MAX) + `\\n[... truncated, total ${toolResult.output.length} chars]`\n : toolResult.output,\n success: toolResult.success,\n outcome,\n toolCallId: tc.id,\n timestamp: new Date().toISOString(),\n ...(thinking && !thinkingAttached ? { thinkingText: thinking } : {}),\n };\n if (thinking && !thinkingAttached) thinkingAttached = true;\n logEntries.push(stepEntry);\n\n if (toolResult.success) {\n // llmOutput, not the raw output: the fallback plan prompt must not\n // carry text the conversation itself never saw.\n resultsText += `\\n[${tc.name}(${JSON.stringify(tc.args)})]\\n${llmOutput}\\n`;\n }\n\n onProgress({ type: 'tool_result', toolResult: toolResult.output, step: stepEntry, subagentId: spawnSubagentIds.get(index), toolCallId: tc.id });\n\n toolResults.push({ name: tc.name, output: llmOutput, truncated: truncatedResponse, totalChars: toolResult.output.length, id: tc.id });\n }\n\n return { toolResults, logEntries, resultsText };\n }\n\n /**\n * Countdown appended to the last tool result of the final few rounds, so the\n * model lands the turn on its own terms instead of being cut off exactly at\n * the budget boundary mid-exploration.\n */\n private static appendBudgetCountdown(toolResults: ToolResult[], remaining: number, wrapUpAction: string): void {\n if (remaining <= 0 || remaining > 3 || toolResults.length === 0) return;\n const note = `\\n\\n[research budget: only ${remaining} tool round${remaining === 1 ? '' : 's'} left this turn — prioritize the most important remaining lookups, then ${wrapUpAction}.]`;\n const last = toolResults[toolResults.length - 1];\n last.output += note;\n last.totalChars += note.length;\n }\n\n /**\n * Run one planner conversation turn (ADR-0002): send the message, satisfy\n * tool calls until the model answers in prose or JSON, then classify the\n * result. The model decides transitions — there are no sentinels, no\n * question tags, and no correction nags. A turn whose final text parses as\n * a `{tasks:[...]}` object commits the plan; anything else is a message to\n * the user.\n */\n protected async runConversationTurn(\n ctx: ConversationTurnContext,\n message: string,\n onProgress: (progress: ResearchProgress) => void,\n signal?: AbortSignal,\n ): Promise<ConversationTurn> {\n const researchLog: ResearchLogEntry[] = [];\n const MAX_STEPS = this.config.researchMaxSteps;\n\n // Turns reporting prompt-token pressure compact the underlying history\n // before the next call — the plan emission should never be the first\n // moment the context problem surfaces.\n const chat = withProactiveCompaction(ctx.chat);\n\n let pending = message;\n let emptyNudgeSent = false;\n // Broken JSON (a plan or task-ops attempt that failed to parse) gets a\n // bounded number of corrective re-emits before degrading to prose.\n let jsonRepairAttempts = 0;\n const MAX_JSON_REPAIRS = 2;\n for (;;) {\n let turn = await chat.sendMessage(pending, signal);\n\n // Wrap-up rounds after the tool budget runs out: the pending calls are\n // answered synthetically (never executed) so the API history stays\n // valid and the model is pushed to reply in prose. Bounded, because a\n // model could keep requesting tools forever.\n let wrapUpRounds = 0;\n for (let step = 0; turn.hasToolCalls; step++) {\n if (signal?.aborted) {\n onProgress({ type: 'interrupted' });\n return { kind: 'message', text: turn.text, researchLog };\n }\n if (step >= MAX_STEPS) {\n // Budget exhausted while the model still wants tools. Dropping the\n // calls here used to surface the model's preamble (\"Let me read…\")\n // as the reply and leave dangling tool_calls in the API history.\n if (wrapUpRounds >= 2) break;\n wrapUpRounds++;\n const notice = `Research tool budget for this turn is exhausted (${MAX_STEPS} rounds) — this call was NOT executed and no further tool calls will be. Reply to the user now using what you already learned: summarize your findings and ask how to proceed, ask your next question, or emit the plan JSON.`;\n // These calls are answered without running. Reporting them as\n // not-executed steps keeps the budget boundary visible; dropping\n // them silently made a whole refused round look like it never\n // happened on every surface.\n for (const tc of turn.toolCalls) {\n const step: ResearchStep = {\n id: `rs-${Date.now()}-budget-${researchLog.length}`,\n tool: tc.name as ResearchStep['tool'],\n args: JSON.stringify(tc.args),\n result: notice,\n success: false,\n outcome: 'not_executed',\n toolCallId: tc.id,\n timestamp: new Date().toISOString(),\n };\n researchLog.push(step);\n onProgress({ type: 'tool_call', tool: tc.name, toolArgs: step.args, toolCallId: tc.id });\n onProgress({ type: 'tool_result', toolResult: notice, step, toolCallId: tc.id });\n }\n turn = await chat.sendToolResults(\n turn.toolCalls.map((tc) => ({ name: tc.name, output: notice, truncated: false, totalChars: notice.length, id: tc.id })),\n signal,\n );\n continue;\n }\n const thinking = turn.reasoning ? turn.reasoning.slice(-200) : '';\n const { toolResults, logEntries } = await this.executeToolCalls(\n turn.toolCalls, ctx.fs, onProgress, ctx.fetcher, step, thinking, signal,\n );\n researchLog.push(...logEntries);\n BaseAiService.appendBudgetCountdown(toolResults, MAX_STEPS - step - 1, 'reply to the user (summary, question, or plan JSON)');\n turn = await chat.sendToolResults(toolResults, signal);\n }\n\n // A plain-reply turn (no tool calls) never passes through the loop\n // above, so this is the first point it can notice an abort raised\n // while its HTTP call was already in flight — without it, a stale\n // turn classifies and returns as a normal plan/message after reset().\n if (signal?.aborted) {\n onProgress({ type: 'interrupted' });\n return { kind: 'message', text: turn.text, researchLog };\n }\n\n // Forced break with nothing to show: degrade to a visible failure\n // instead of an empty planner bubble.\n if (turn.hasToolCalls && !turn.text.trim()) {\n return {\n kind: 'message',\n text: `I hit the research tool budget for this turn (${MAX_STEPS} rounds) before finishing. Tell me to continue, or narrow the request.`,\n researchLog,\n };\n }\n\n // An empty turn (no text, no tool calls — flash-lite does this) would\n // leave the user staring at silence. Nudge the model once; if it comes\n // back empty again, degrade to a visible failure.\n if (!turn.text.trim()) {\n if (!emptyNudgeSent && !signal?.aborted) {\n emptyNudgeSent = true;\n pending = 'Your last reply was empty. Respond to the user now: answer their last message directly, ask your next question, or emit the plan JSON.';\n continue;\n }\n return {\n kind: 'message',\n text: 'The planner returned an empty reply twice. Please rephrase or try again.',\n researchLog,\n };\n }\n\n if (extractPrdBlock(turn.text)) ctx.prdCaptured = true;\n\n // What did the model emit? PlanRepair owns the classification (envelope\n // keys, attempt-detection) and the corrective prompt texts; this loop\n // only applies its policies: the repair budget, the abort guard, and\n // the PRD gate.\n const reply = classifyPlannerReply(turn.text, {\n runners: ctx.runners,\n runnerModes: ctx.runnerModes,\n autonomousDefault: ctx.autonomousDefault,\n });\n\n switch (reply.kind) {\n case 'task_ops':\n return { kind: 'task_ops', ops: reply.ops, text: turn.text, researchLog };\n\n case 'plan':\n // PRD mode fail-safe: a cheap model that skips the PRD and jumps to\n // JSON would otherwise commit a plan with no PRD on record. Bounce\n // once with a corrective message; if it still refuses, accept the\n // plan rather than trap the user in a loop.\n if (ctx.prdEnabled && !ctx.prdCaptured && !ctx.prdNudgeSent && !signal?.aborted) {\n ctx.prdNudgeSent = true;\n pending = [\n 'PRD mode is enabled but no PRD has been produced yet, so the plan was NOT committed.',\n 'In your next reply: first output the full markdown PRD wrapped EXACTLY in',\n '<!-- ORDEWELL_PRD_START slug=\"<feature-slug>\" --> and <!-- ORDEWELL_PRD_END -->,',\n 'then re-emit the exact same task plan JSON after the PRD block.',\n ].join(' ');\n continue;\n }\n return { kind: 'plan', tasks: reply.tasks, text: turn.text, researchLog };\n\n // Botched attempts get a bounded corrective retry — otherwise the\n // broken JSON would surface as a prose bubble and the edit or plan\n // would silently fail to commit.\n case 'broken_task_ops':\n if (jsonRepairAttempts < MAX_JSON_REPAIRS && !signal?.aborted) {\n jsonRepairAttempts++;\n pending = reEmitTaskOpsPrompt(reply.error.message);\n continue;\n }\n break;\n\n case 'broken_plan':\n if (jsonRepairAttempts < MAX_JSON_REPAIRS && !signal?.aborted) {\n jsonRepairAttempts++;\n if (reply.error.truncated || turn.finishReason === 'length') {\n // Output-limit truncation: re-asking in the same context would be\n // cut at the same point. Free input space first (raw transcripts\n // pruned, digests kept), then ask for a terser re-emit.\n const removed = chat.compactHistory?.() ?? 0;\n pending = truncatedPlanReEmitPrompt(removed > 0);\n } else {\n pending = reEmitPlanPrompt(reply.error.message);\n }\n continue;\n }\n break;\n\n case 'prose':\n break;\n }\n\n return { kind: 'message', text: turn.text, researchLog };\n }\n }\n\n /**\n * Run the LLM tool-calling research loop for one-shot planning. Returns\n * parsed tasks if a plan was emitted mid-loop, or null if the loop\n * exhausted without a valid plan.\n */\n protected async runResearchLoop(\n chat: ResearchChat,\n firstMessage: string,\n fs: IFileSystem,\n onProgress: (progress: ResearchProgress) => void,\n runners: RunnerId[],\n initialLog?: ResearchLogEntry[],\n fetcher?: IWebFetcher,\n userGoal?: string,\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n autonomousDefault?: boolean,\n signal?: AbortSignal,\n ): Promise<{ tasks: Task[] | null; researchLog: ResearchLogEntry[]; researchResults: string }> {\n const researchLog: ResearchLogEntry[] = initialLog ? [...initialLog] : [];\n if (!initialLog && userGoal) {\n researchLog.push({\n id: `up-${Date.now()}`,\n type: 'user_prompt',\n content: userGoal,\n timestamp: new Date().toISOString(),\n });\n }\n let researchResults = '';\n const MAX_STEPS = this.config.researchMaxSteps;\n\n chat = withProactiveCompaction(chat);\n let turn = await chat.sendMessage(firstMessage, signal);\n\n for (let step = 0; step < MAX_STEPS; step++) {\n if (signal?.aborted) {\n onProgress({ type: 'interrupted' });\n return { tasks: null, researchLog, researchResults };\n }\n // Prefer the model's reasoning channel for the live thinking trace; fall back to\n // the answer content when a model doesn't expose reasoning separately.\n const thinking = turn.reasoning ? turn.reasoning.slice(-200) : turn.text.slice(-200);\n\n // A research turn is a candidate plan whenever its (reasoning-free) content\n // carries a tasks key — not only when it starts with `{`. Reasoning models often\n // emit a short preamble before the JSON; throwing that away forced a wasteful\n // second LLM call even when the plan was already in hand.\n const reply = classifyPlannerReply(turn.text, { runners, runnerModes, autonomousDefault });\n if (reply.kind === 'plan') {\n return { tasks: reply.tasks, researchLog, researchResults };\n }\n\n if (!turn.hasToolCalls) break;\n\n const { toolResults, logEntries, resultsText } = await this.executeToolCalls(\n turn.toolCalls, fs, onProgress, fetcher, step, thinking, signal,\n );\n researchLog.push(...logEntries);\n researchResults += resultsText;\n\n BaseAiService.appendBudgetCountdown(toolResults, MAX_STEPS - step - 1, 'emit the plan JSON');\n turn = await chat.sendToolResults(toolResults, signal);\n }\n\n if (turn.text) {\n researchResults += `\\n[LLM response]\\n${turn.text}\\n`;\n }\n\n return { tasks: null, researchLog, researchResults };\n }\n\n protected async generatePlanFallback(\n userDescription: string,\n contextStr: string,\n researchResults: string,\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n runners: RunnerId[],\n onProgress: (progress: ResearchProgress) => void,\n researchLog: ResearchLogEntry[] = [],\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n autonomousDefault = true,\n signal?: AbortSignal,\n modes: PlannerModes = DEFAULT_PLANNER_MODES,\n ): Promise<{ tasks: Task[]; researchLog: ResearchLogEntry[] }> {\n // A long research phase (especially with subagents) can outgrow what one\n // prompt can carry alongside a full plan emission — bound it, digests first.\n const prompt = buildPlanWithResults(userDescription, contextStr, compactResearchResults(researchResults), modelsByRunner, runners, runnerModes, modes);\n const tasks = await generatePlanWithRepair((repairHint) =>\n this.streamPlanText(\n prompt,\n repairHint,\n (token) => onProgress({ type: 'plan_token', planToken: token }),\n (reasoning) => onProgress({ type: 'thinking', text: reasoning }),\n signal,\n ),\n runners,\n 2,\n runnerModes,\n autonomousDefault,\n );\n return { tasks, researchLog };\n }\n}\n","import type { UserSettings } from './SettingsService';\n\n/**\n * The mode toggles, as data, and which planner entry points honour each one.\n *\n * A toggle used to be a boolean threaded by hand down every path, which made an\n * intentional omission indistinguishable from a dropped one: the one-shot\n * planner honoured `verification` and silently ignored `review`, while every\n * surface still displayed review as ON. Declaring the scope is what makes the\n * difference visible — `modesFor` applies it, so a path cannot quietly diverge\n * from what this table says.\n */\n\n/** The id a surface shows and a user types. Deliberately not the settings key. */\nexport type ModeToggleId = 'grill-me' | 'tdd' | 'prd' | 'review' | 'verify' | 'research-subagents';\n\n/**\n * Where a toggle can take effect. `chat` is the conversation loop (ADR-0002),\n * `one-shot` the non-conversational planners (`ordewell plan --goal`, web REST),\n * `task` a runner task's prompt rather than the planner's.\n */\nexport type ModeScope = 'chat' | 'one-shot' | 'task';\n\n/** The settings-file keys that hold a toggle, as opposed to `modelAllowlist` and friends. */\ntype ToggleSettingsKey = {\n // `-?` because an optional member (`modelAllowlist`) otherwise widens the\n // lookup to include `undefined`, which cannot index anything.\n [K in keyof UserSettings]-?: UserSettings[K] extends { enabled: boolean } ? K : never;\n}[keyof UserSettings];\n\n/** How the same toggle is named once a host has read it off disk. */\nexport interface PlannerRuntimeToggles {\n grillMeEnabled: boolean;\n tddEnabled: boolean;\n prdEnabled: boolean;\n reviewEnabled: boolean;\n verificationEnabled: boolean;\n researchSubagentsEnabled: boolean;\n}\n\nexport interface ModeToggle {\n id: ModeToggleId;\n /** Key in the persisted settings file. `verify` maps to `verification`. */\n settingsKey: ToggleSettingsKey;\n /** Key a host passes to the Session. `review` on disk is `reviewEnabled` here. */\n runtimeKey: keyof PlannerRuntimeToggles;\n scopes: readonly ModeScope[];\n}\n\nexport const MODE_TOGGLES: readonly ModeToggle[] = [\n // Both of these interview the user, and a one-shot run has nobody to ask —\n // its prompt says so outright. Their absence there is a decision, not a gap.\n { id: 'grill-me', settingsKey: 'grillMe', runtimeKey: 'grillMeEnabled', scopes: ['chat'] },\n { id: 'prd', settingsKey: 'prd', runtimeKey: 'prdEnabled', scopes: ['chat'] },\n // Structural: append a final review task. Nothing about it needs a dialogue.\n { id: 'review', settingsKey: 'review', runtimeKey: 'reviewEnabled', scopes: ['chat', 'one-shot'] },\n { id: 'verify', settingsKey: 'verification', runtimeKey: 'verificationEnabled', scopes: ['chat', 'one-shot'] },\n { id: 'research-subagents', settingsKey: 'researchSubagents', runtimeKey: 'researchSubagentsEnabled', scopes: ['chat', 'one-shot'] },\n { id: 'tdd', settingsKey: 'tdd', runtimeKey: 'tddEnabled', scopes: ['task'] },\n];\n\n/**\n * Read every toggle off the settings file under the name a Session expects.\n *\n * Both hosts used to hand-map `getReview()` to `reviewEnabled` and its five\n * siblings, in two identical blocks that nothing kept in step — which is how a\n * toggle came to have three unrelated names and how one of them got dropped.\n * Callers add whatever else `SessionRuntimeSettings` carries (`modelAllowlist`).\n */\nexport function plannerRuntimeToggles(settings: UserSettings): PlannerRuntimeToggles {\n const toggles = {} as PlannerRuntimeToggles;\n for (const toggle of MODE_TOGGLES) toggles[toggle.runtimeKey] = settings[toggle.settingsKey].enabled;\n return toggles;\n}\n\n/**\n * The planner-facing mode set for one operation. Replaces the boolean tail that\n * every planner signature used to carry positionally — where a thirteenth\n * parameter was the only place left to put a new toggle.\n */\nexport interface PlannerModes {\n autonomousDefault: boolean;\n grillMe: boolean;\n prd: boolean;\n review: boolean;\n verification: boolean;\n researchSubagents: boolean;\n}\n\nexport const DEFAULT_PLANNER_MODES: PlannerModes = {\n autonomousDefault: true,\n grillMe: false,\n prd: false,\n review: false,\n verification: false,\n researchSubagents: false,\n};\n\n/** Read the toggles a planner cares about off whatever the settings callback returned. */\nexport function plannerModesFrom(\n settings: {\n grillMeEnabled?: boolean;\n prdEnabled?: boolean;\n reviewEnabled?: boolean;\n verificationEnabled?: boolean;\n researchSubagentsEnabled?: boolean;\n },\n autonomousDefault: boolean,\n): PlannerModes {\n return {\n autonomousDefault,\n grillMe: settings.grillMeEnabled ?? false,\n prd: settings.prdEnabled ?? false,\n review: settings.reviewEnabled ?? false,\n verification: settings.verificationEnabled ?? false,\n researchSubagents: settings.researchSubagentsEnabled ?? false,\n };\n}\n\nconst MODE_FIELD: Record<ModeToggleId, keyof PlannerModes | null> = {\n 'grill-me': 'grillMe',\n prd: 'prd',\n review: 'review',\n verify: 'verification',\n 'research-subagents': 'researchSubagents',\n tdd: null,\n};\n\n/**\n * Clear the toggles this scope does not honour, so a prompt builder reads a\n * mode set that already tells the truth about the path it is on.\n */\nexport function modesFor(scope: ModeScope, modes: PlannerModes): PlannerModes {\n const scoped = { ...modes };\n for (const toggle of MODE_TOGGLES) {\n const field = MODE_FIELD[toggle.id];\n if (field && !toggle.scopes.includes(scope)) scoped[field] = false;\n }\n return scoped;\n}\n","import { DiscoveredModel, RunnerId, type TaskSnapshot, type Task } from '../models/Task';\nimport type { LegacyPlanState } from '../models/Task';\nimport { buildModeGuide, filteredBuildModes, type RunnerModeInfo } from './ModeResolver';\nimport { DEFAULT_PLANNER_MODES, modesFor, type PlannerModes } from './plannerModes';\n\nexport function buildResearchToolsPrompt(subagentsEnabled = false): string {\n const lines = [\n 'You have access to the following tools to explore the workspace:',\n '',\n 'read_file(path: string, offset?: number, limit?: number) - Read file contents with line numbers and optional pagination. offset is a 0-based line number (default 0). limit is max lines (default 2000). Output lines are prefixed with their line numbers. When a file has more lines than requested, a hint shows the offset to use next. Files larger than ~1 MB are rejected — use grep instead.',\n 'read_files(paths: string[]) - Read multiple files at once. Batch reads when you have several known paths — this is faster than calling read_file repeatedly.',\n 'glob(pattern: string) - Find files matching a glob pattern (e.g. \"src/**/*.ts\"). Use for finding files by name/path. Results sorted by modification time, newest first.',\n 'grep(pattern: string, include?: string) - Search for a regex pattern inside file contents. Use for finding code patterns, function definitions, imports, etc. Use \"include\" to filter by file type (e.g. \"*.ts\").',\n 'list_dir(path: string, depth?: number) - List directory contents as a tree. Use for orientation — to see what directories and files exist. Use depth=2 or depth=3 for a tree view.',\n 'bash(command: string) - Run a read-only shell command (ls, tree, git log/status/diff, cat, head, wc, etc.). Do NOT use bash for file search — use the dedicated glob and grep tools instead.',\n '',\n 'TOOL CHOICE GUIDE:',\n '- list_dir: for browsing/orientation and understanding project structure',\n '- glob: for finding files by name/path pattern',\n '- grep: for searching inside file contents',\n '',\n 'When multiple independent tool calls are needed, batch them in a single response to save round-trips. For example, if you need to read README.md and AGENTS.md, call read_files with both paths at once.',\n ];\n if (subagentsEnabled) {\n lines.push(\n '',\n 'spawn_research_agent(prompt: string) - Launch a stateless read-only research agent that explores the workspace with its own tools and returns a digest. Use it to delegate an open-ended exploration thread — a subsystem to map, or a \"how does X work here\" question — whenever one emerges during research. To explore several independent areas, launch the agents CONCURRENTLY: put multiple spawn_research_agent calls in one reply and they run in parallel.',\n 'The agent sees nothing of this conversation, so its prompt must be self-contained: the area or question, the paths/symbols to start from, and exactly what the digest must report back. Do NOT use it on small or single-subsystem repos, or to read one known file — direct tools are faster there.',\n );\n }\n return lines.join('\\n');\n}\n\n/**\n * System prompt for one read-only research subagent (issue #34). The digest\n * contract matters: the reply goes back to the planner as a tool result, so it\n * must be dense, self-contained, and carry exact file paths — never questions,\n * never a task plan.\n */\nexport function buildSubagentSystemPrompt(): string {\n return [\n 'You are a read-only research subagent working for a project planner. You receive one self-contained research task, explore the workspace with your tools, and reply with a single digest. You never modify files, never fetch URLs, and cannot spawn further agents.',\n '',\n 'Work efficiently: batch independent tool calls in one reply; prefer glob/grep to locate, then read only what matters. Your tool budget is small — stop exploring when you can answer the task.',\n '',\n 'Your final reply IS the digest — it goes straight back to the planner, not to a human. It must contain:',\n '- The exact file paths (and key line references) relevant to the task',\n '- The key symbols/functions involved and how they connect',\n '- Constraints, gotchas, or conventions the planner must respect',\n '- Direct answers to every question the task asked',\n 'Plain prose/markdown only. No questions, no task plans, no JSON. Be dense and specific; vague summaries are useless to the planner.',\n ].join('\\n');\n}\n\nfunction buildModeGuideForRunners(runners: RunnerId[], _autonomousDefault: boolean): string {\n const lines = ['Assign a \"taskMode\" to each AI task based on the runner:'];\n for (const r of runners) {\n if (r === 'claude-code') {\n lines.push('- For claude-code: \"acceptEdits\" (edit automatically, recommended), \"default\" (ask before edits), \"plan\" (read-only analysis), \"bypassPermissions\" (skip all prompts, CI only).');\n } else if (r === 'opencode') {\n lines.push('- For opencode: \"build\" (full access agent), \"plan\" (read-only analysis).');\n } else {\n lines.push(`- For ${r}: use the modes from the runner's manifest.`);\n }\n }\n lines.push('Use the recommended mode for implementation. Use \"plan\" for analysis-only requests.');\n return lines.join('\\n');\n}\n\nfunction buildModeExamplesForRunners(runners: RunnerId[]): string {\n return runners.map(r => {\n if (r === 'claude-code') return 'claude-code: acceptEdits|default|plan|bypassPermissions';\n if (r === 'opencode') return 'opencode: build|plan';\n return `${r}: default|plan`;\n }).join(', ');\n}\n\n/**\n * Verification mode (evidence-based, AFK) is the counterpart to review mode\n * (opinion-based, HITL): a final task whose verdict comes from running the\n * suite, closing the \"every task passed but the feature is short\" gap that\n * per-task exit codes cannot see.\n */\nfunction verificationModeBlock(reviewAlsoEnabled = false): string {\n return [\n '',\n 'VERIFICATION MODE:',\n reviewAlsoEnabled\n ? 'Add a FINAL verification task immediately before the review task. The review task keeps the highest order number and must list the verification task among its dependencies.'\n : 'Add a FINAL verification task to the end of the plan (highest order number).',\n 'This task closes the gap between \"every task finished\" and \"the feature is correct\": tasks executed in isolated sessions can each pass while the integrated feature is still short. Its outcome must come from commands and exit codes, never from judgement.',\n 'This task must:',\n '- Have type \"ai\" and autonomy \"AFK\" — it needs no human input',\n '- Have dependencies on ALL other AI tasks in the plan',\n '- Use the same runner as the other tasks; a mid-tier model is fine (the work is running and writing tests, not architecture)',\n '- Its prompt should instruct the agent to:',\n ' * Re-read the ORIGINAL goal (and the PRD at `.scratch/<slug>/PRD.md` if one exists) — the whole feature spec, not any single task\\'s slice',\n ' * Run the project\\'s full test suite and typecheck/build, and fix any failure it finds',\n ' * If the project has NO test infrastructure, do not bootstrap a framework just for verification (unless an earlier task already added one) — instead write a standalone verification script that exercises the feature end-to-end through its public interface and exits non-zero on any failed check, and run it',\n ' * Walk the spec requirement by requirement — including every edge case the spec mentions — and check each one is covered by an executable test; write the missing tests at the public interface and make them pass',\n ' * Exercise the feature END-TO-END: integration gaps between task boundaries are this task\\'s responsibility',\n ' * Succeed ONLY when the full suite, including the newly written tests, is green; if a check cannot be made to pass, fail the task loudly — never skip, weaken, or delete a check to get green',\n ].join('\\n');\n}\n\n/**\n * The research-phase instructions, in the two variants the planner ships\n * (ADR-0009).\n *\n * The API variant names Ordewell's own tools because Ordewell is the one running\n * them. A harness planner brings its own toolbox, so naming `list_dir` or\n * `glob` there would be telling a coding agent to call tools it does not have.\n *\n * Only this block and the tool-envelope appendix differ between the two: the\n * plan schema, the runner and mode vocabulary, the model catalog, the\n * conversational protocol and every mode-toggle block are shared verbatim. A\n * forked prompt would mean each future toggle gets written twice, or silently\n * works on one backend only.\n */\nfunction researchPhaseBlock(harnessMode: boolean): string {\n const shared = [\n 'RESEARCH PHASE:',\n '- Start by reading README.md and any agent config files (AGENTS.md, CLAUDE.md)',\n ];\n const toolSpecific = harnessMode\n ? [\n '- Explore the repository with your own tools until you understand its architecture',\n '- You are planning, not implementing: do NOT edit, create, or delete any file, and do not run commands that change the workspace',\n ]\n : [\n '- Use list_dir with depth=2-3 for a tree overview',\n '- Use glob and grep to find relevant source files',\n '- Read key source files to understand architecture',\n ];\n return [\n ...shared,\n ...toolSpecific,\n '- Synthesize tool findings into your messages. The user does not see raw tool output; only your synthesis reaches them.',\n '- Research and questions can interleave — you can explore a file, then ask a question grounded in it, in one response',\n ].join('\\n');\n}\n\nexport function buildConversationSystemPrompt(\n goal: string,\n context: string,\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n runners: RunnerId[],\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n autonomousDefault = true,\n grillMeEnabled = false,\n prdEnabled = false,\n reviewEnabled = false,\n verificationEnabled = false,\n /** Harness planner (ADR-0009): the agent owns its own tools and research budget. */\n harnessMode = false,\n): string {\n const modelsJson = modelsJsonFor(modelsByRunner, runners);\n const modeGuide = runnerModes ? buildModeGuide(runnerModes, autonomousDefault) : buildModeGuideForRunners(runners, autonomousDefault);\n\n const modeExamples = runnerModes\n ? Object.entries(runnerModes).map(([r, ms]) => {\n const filtered = filteredBuildModes(ms, autonomousDefault);\n return `${r}: ${filtered.map(m => m.id).join('|')}${ms.some(m => m.id === 'plan') ? '|plan' : ''}`;\n }).join(', ')\n : buildModeExamplesForRunners(runners);\n\n const grillMeBlock = grillMeEnabled ? [\n '',\n 'INTERVIEW MODE — GRILL-ME:',\n 'Interview the user relentlessly about every aspect of their goal until you reach a shared understanding. Walk down each branch of the design tree, resolving dependencies between decisions one-by-one.',\n 'Ask one question at a time, waiting for the user\\'s answer before continuing. For each question, propose your recommended answer so they can confirm or correct it. Asking multiple questions at once is bewildering.',\n 'If a fact can be found by exploring the codebase, look it up instead of asking. The decisions, though, are the user\\'s — put each one to them and wait.',\n 'Only propose an outline after the user has answered enough questions that you genuinely understand the goal. Then present the prose outline and wait for explicit confirmation before emitting the task plan JSON.',\n ].join('\\n') : '';\n\n const prdBlock = prdEnabled ? [\n '',\n 'PRD MODE: Before producing the outline, generate a PRD in two steps.',\n 'Step 1 — Propose a short prose preview containing: the problem statement, the proposed approach, the testing seams, and the main risks. Prefer existing seams over new ones; propose new seams at the highest point possible. The fewer seams across the codebase, the better — the ideal number is one. Propose a feature-slug for saving the PRD (e.g. `my-feature`). Ask the user whether they agree.',\n 'Step 2 — Only after the user explicitly agrees, write the full markdown PRD using the standard PRD format (problem, user stories, implementation decisions, testing seams, out of scope). The user may edit the proposed feature-slug before you write the PRD; use the agreed slug in the final output.',\n 'PRD content rules: user stories are an extensive numbered list, each \"As an <actor>, I want <feature>, so that <benefit>\". Record implementation decisions as decisions (modules, interfaces, schema changes, API contracts) — do NOT include specific file paths or code snippets; they go stale fast. Exception: a snippet from a prototype that encodes a decision more precisely than prose (state machine, reducer, schema, type shape) may be inlined, trimmed to the decision-rich parts.',\n 'When writing the full PRD, wrap it EXACTLY with these markers so the system can save it automatically:',\n '<!-- ORDEWELL_PRD_START slug=\"<feature-slug>\" -->',\n '... full markdown PRD ...',\n '<!-- ORDEWELL_PRD_END -->',\n 'Do NOT emit the full PRD before the user agrees to the preview. Do NOT emit task plan JSON before the PRD is agreed and the outline is confirmed.',\n ].join('\\n') : '';\n\n const reviewBlock = reviewEnabled ? reviewModeBlock() : '';\n const verificationBlock = verificationEnabled ? verificationModeBlock(reviewEnabled) : '';\n\n return buildConversationBody(\n goal, context, modelsJson, runners, modeGuide, modeExamples, harnessMode,\n grillMeBlock, prdBlock, reviewBlock, verificationBlock,\n );\n}\n\n/**\n * The review-mode instruction. Structural rather than conversational — it only\n * appends a task — so both the conversation loop and the one-shot planners emit\n * it; keeping one copy is what stopped them diverging.\n */\nfunction reviewModeBlock(): string {\n return [\n '',\n 'REVIEW MODE:',\n 'Add a FINAL review task to the end of the plan (highest order number).',\n 'This task must:',\n '- Have type \"ai\" and use the STRONGEST available model',\n '- Have dependencies on ALL other AI/user tasks in the plan',\n '- Be assigned appropriately as HITL (human review) since the results need human sign-off',\n '- Its prompt should instruct the agent to:',\n ' * Review every completed task\\'s outputs and verify the original goal was met',\n ' * Check that each task delivers what its description promised',\n ' * Review the work on two axes, reported SEPARATELY so one cannot mask the other:',\n ' - SPEC axis: if a PRD exists for this plan (`.scratch/<slug>/PRD.md`), verify against it: (a) requirements asked for but missing or partial; (b) behaviour delivered that the PRD never asked for (scope creep); (c) requirements that look implemented but wrongly. Quote the PRD line for each finding. With no PRD, review against the original goal.',\n ' - STANDARDS axis: check the diff against the repo\\'s documented coding standards (CONTRIBUTING.md, CLAUDE.md, etc.) plus this smell baseline: Mysterious Name (rename), Duplicated Code (extract shared shape), Feature Envy (move method to the data), Data Clumps (bundle into a type), Primitive Obsession (give the concept a type), Repeated Switches (polymorphism or shared map), Shotgun Surgery (gather into one module), Divergent Change (split by reason to change), Speculative Generality (delete it), Message Chains (hide the walk), Middle Man (call the target direct), Refused Bequest (composition over inheritance). Smell findings are always judgement calls, never hard failures; documented repo standards override the baseline; skip anything tooling already enforces.',\n ' * Produce a structured review report listing what was checked and whether each check passed',\n ' * Flag any gaps, bugs, or incomplete work',\n ' * Output a final PASS/FAIL conclusion with evidence (standards-axis judgement calls alone must not fail the verification)',\n '- Use the same runner as the other tasks',\n ].join('\\n');\n}\n\nfunction buildConversationBody(\n goal: string,\n context: string,\n modelsJson: string,\n runners: RunnerId[],\n modeGuide: string,\n modeExamples: string,\n harnessMode: boolean,\n grillMeBlock: string,\n prdBlock: string,\n reviewBlock: string,\n verificationBlock: string,\n): string {\n return [\n 'You are Ordewell\\'s project planner. You explore the codebase, ask concise clarifying questions grounded in your findings, and produce structured task plans as JSON. Be direct: avoid unnecessary preamble, summaries, or explanations unless the user asks for detail.',\n '',\n 'WORKFLOW:',\n '1. Explore the workspace with tools to understand the codebase.',\n '2. Ask clarifying questions grounded in your findings. Reference actual files. When the goal is vague, or a decision would materially change the outcome (storage engine, library choice, scope, API shape), ask the user BEFORE planning — never silently assume. Clear, fully-specified goals need no questions.',\n '3. When you have enough context, produce a prose outline — a short list describing each vertical slice in order.',\n '4. After the user confirms the outline, emit the final task plan as a JSON object with a \"tasks\" array.',\n '',\n researchPhaseBlock(harnessMode),\n grillMeBlock,\n prdBlock,\n reviewBlock,\n verificationBlock,\n '',\n 'OUTLINE PHASE:',\n '- When you are ready to propose a plan, first show a prose outline. DO NOT jump straight to JSON.',\n '- Format: a numbered list describing each vertical tracer-bullet slice, with the files/layers each slice touches.',\n '- Example: \"1. Set up database schema (src/db/schema.ts) — creates tables for users and sessions\\n2. Add auth middleware (src/auth/middleware.ts) — validates JWTs on protected routes\\n3. Build login page (src/ui/Login.tsx) — form component with validation\"',\n '- The user may reply with adjustments. Revise the outline and re-present it.',\n '- When the user confirms the outline, emit the task plan JSON.',\n '',\n 'PLAN FORMAT:',\n 'Generate a task plan using this JSON format:',\n '',\n '{',\n ' \"tasks\": [',\n ' {',\n ' \"id\": \"unique-task-id (any short unique string, e.g. task-1)\",',\n ' \"order\": 1,',\n ' \"title\": \"Concise title\",',\n ' \"description\": \"What this task accomplishes\",',\n ' \"type\": \"ai|user\",',\n ' \"dependencies\": [\"task-id-string\"],',\n ' \"prompt\": \"Detailed instructions for the AI assistant (ai tasks only)\",',\n ' \"userSteps\": [{ \"order\": 1, \"instruction\": \"Step description\", \"completed\": false }],',\n ' \"assignedModel\": { \"modelId\": \"model-id\", \"modelLabel\": \"Model Label\", \"thinkingEffort\": \"a variant id from that model\\'s variants list — omit if the model has none\" },',\n ' \"assignedRunner\": \"' + runners.join('|') + '\",',\n ' \"taskMode\": \"' + modeExamples + '\",',\n ' \"autonomy\": \"AFK|HITL\",',\n ' \"sliceType\": \"AFK|HITL\",',\n ' \"userStoriesCovered\": [\"user story text\"],',\n ' \"subtasks\": [{ \"id\": \"sub-id-string\", \"order\": 1, \"title\": \"Sub-step title\", \"description\": \"What it accomplishes\", \"type\": \"ai\", \"dependencies\": [], \"prompt\": \"Detailed instructions\", \"autonomy\": \"AFK|HITL\", \"sliceType\": \"AFK|HITL\", \"subtasks\": [] }]',\n ' }',\n ' ]',\n '}',\n '',\n 'VERTICAL SLICE PLANNING:',\n 'Design each task as a VERTICAL TRACER-BULLET SLICE — a narrow but complete, independently demoable path. Do NOT create horizontal layer-by-layer tasks.',\n '- Size each slice to fit a single fresh agent session\\'s context window — if a slice is too big, split it.',\n '- If preparatory refactoring would make the feature easier, make it its own leading task (\"make the change easy, then make the easy change\") and have dependent slices declare it as a dependency.',\n '- Wide mechanical refactors (rename a shared symbol, retype a column) whose blast radius spans the codebase are the exception to vertical slicing: sequence them as EXPAND-CONTRACT — one task adds the new form beside the old, parallel migration tasks (each depending on it) move call sites over in batches, and a final contract task depending on all migrations deletes the old form.',\n '',\n 'SLICE CLASSIFICATION:',\n '- \"autonomy\": AFK (agent works autonomously) or HITL (needs user confirmation)',\n '- \"sliceType\": Same vocabulary as autonomy.',\n '- AFK tasks MUST NOT contain \"userSteps\". HITL tasks MAY contain userSteps.',\n '- User tasks (type \"user\") always have sliceType \"HITL\".',\n '- \"sliceType\" is REQUIRED on every task, and \"autonomy\" on every \"ai\" task, at every depth — a \"subtasks\" entry is a full task object with all the same required fields, not a bare label.',\n '',\n 'DEPENDENCY & PARALLELISM:',\n '- Independent slices should have NO dependencies — they run in parallel.',\n '- Only add dependencies when a slice truly depends on artifacts another slice creates.',\n '',\n 'RULES:',\n '- Do NOT wrap the JSON in markdown code blocks. Output ONLY the JSON object when committing the plan.',\n '- Emit the outline BEFORE the JSON. Do not skip the outline.',\n '- Reference specific files and patterns from your research in task prompts.',\n '- For parallel tasks, specify different target files to avoid merge conflicts.',\n '',\n 'CONVENTIONS:',\n '- When suggesting libraries, frameworks, or patterns, first verify they already exist in the codebase. NEVER assume a library is available just because it is well-known. Check package.json, imports, or surrounding files first.',\n '- Follow the existing code style, naming conventions, and architectural patterns of the project.',\n '',\n 'MODEL ASSIGNMENT:',\n 'Available models:',\n modelsJson,\n '',\n runnerInstruction(runners),\n 'MODEL SELECTION GUIDELINES:',\n '- Use stronger models for complex refactoring, architecture changes, security-critical code.',\n '- Use weaker/faster models for simple file operations, test generation, config changes, documentation.',\n '- Assign thinkingEffort based on task complexity, choosing ONLY from the assigned model\\'s \"variants\" list above (e.g. low for simple tasks, high for complex ones). Omit thinkingEffort if the model has no variants.',\n '',\n 'TASK MODE:',\n modeGuide,\n '',\n context ? `PROJECT CONTEXT:\\n${context}\\n` : '',\n `USER GOAL: ${goal}`,\n ].join('\\n');\n}\n\nconst RESEARCH_SECTION = [\n 'PHASE 1 - RESEARCH:',\n 'First, use the available tools to explore the workspace thoroughly. You can combine independent steps into a single response to save round-trips — for instance, read README.md and AGENTS.md simultaneously.',\n '- Start by reading README.md and any agent config files (AGENTS.md, CLAUDE.md)',\n '- Use list_dir with depth=3 for a tree overview of the project structure',\n '- Use glob to find relevant source files by pattern',\n '- Use grep to search for code patterns related to the user\\'s goal',\n '- Read key source files to understand existing architecture',\n '- Do NOT use bash for file search — use glob/grep/list_dir instead',\n '- Only generate the plan AFTER you have enough context',\n '{{CLARIFICATION_INSTRUCTIONS}}',\n].join('\\n');\n\nconst ONE_SHOT_INSTRUCTIONS = [\n '',\n 'This is a ONE-SHOT run: there is no user to ask questions to. Where the request is ambiguous, make the most reasonable assumption grounded in your research and record it in the relevant task description.',\n '',\n].join('\\n');\n\nexport const CORE_PLANNER_PROMPT = [\n 'You are a software project planner that produces structured task plans as JSON.',\n 'Given a user\\'s goal, create an ordered list of tasks that accomplish it.',\n '',\n 'Generate a task plan using this JSON format:',\n '',\n '{',\n ' \"tasks\": [',\n ' {',\n ' \"id\": \"unique-task-id (any short unique string, e.g. task-1)\",',\n ' \"order\": 1,',\n ' \"title\": \"Concise title summarizing the task\",',\n ' \"description\": \"What this task accomplishes\",',\n ' \"type\": \"ai|user\",',\n ' \"dependencies\": [\"task-id-string\"],',\n ' \"prompt\": \"Detailed instructions for the AI assistant (ai tasks only)\",',\n ' \"userSteps\": [{ \"order\": 1, \"instruction\": \"Step description\", \"completed\": false }],',\n ' \"assignedModel\": { \"modelId\": \"model-id\", \"modelLabel\": \"Model Label\", \"thinkingEffort\": \"a variant id from that model\\'s variants list — omit if the model has none\" },',\n ' \"assignedRunner\": \"{{RUNNER_CHOICES}}\",',\n ' \"taskMode\": \"{{MODE_EXAMPLES}}\",',\n ' \"autonomy\": \"AFK|HITL\",',\n ' \"sliceType\": \"AFK|HITL\",',\n ' \"userStoriesCovered\": [\"user story text\"],',\n ' \"subtasks\": [{ \"id\": \"sub-id-string\", \"order\": 1, \"title\": \"Sub-step title\", \"description\": \"What it accomplishes\", \"type\": \"ai\", \"dependencies\": [], \"prompt\": \"Detailed instructions\", \"autonomy\": \"AFK|HITL\", \"sliceType\": \"AFK|HITL\", \"subtasks\": [] }]',\n ' }',\n ' ]',\n '}',\n '',\n 'VERTICAL SLICE PLANNING:',\n 'Design each task as a VERTICAL TRACER-BULLET SLICE — a narrow but complete, independently demoable path that cuts through all layers (schema → backend logic → API/route → UI/consumer → tests). Do NOT create horizontal layer-by-layer tasks (e.g. \"build all models\", then \"build all routes\", then \"build all tests\"). Each slice should stand alone as a working end-to-end increment.',\n '- Size each slice to fit a single fresh agent session\\'s context window — if a slice is too big, split it.',\n '- If preparatory refactoring would make the feature easier, make it its own leading task (\"make the change easy, then make the easy change\") and have dependent slices declare it as a dependency.',\n '- Wide mechanical refactors (rename a shared symbol, retype a column) whose blast radius spans the codebase are the exception to vertical slicing: sequence them as EXPAND-CONTRACT — one task adds the new form beside the old, parallel migration tasks (each depending on it) move call sites over in batches, and a final contract task depending on all migrations deletes the old form.',\n '',\n 'SLICE CLASSIFICATION:',\n '- \"autonomy\": Classify each AI task as AFK (Away From Keyboard — the agent works autonomously with no user interaction needed) or HITL (Human In The Loop — the agent needs user confirmation, review, or input partway through).',\n '- \"sliceType\": Same vocabulary as autonomy. Use HITL for tasks that contain user-facing touchpoints (manual verification, approval gates, UI decisions a human must make). Use AFK for fully autonomous slices.',\n '- \"userStoriesCovered\": Link each task to the specific user story/stories from the PRD that it delivers. Copy the exact user story text.',\n '- AFK tasks MUST NOT contain \"userSteps\" — they are fully autonomous. HITL tasks MAY contain userSteps for the human touchpoints.',\n '- User tasks (type \"user\") always have sliceType \"HITL\" and must include \"userSteps\".',\n '- \"sliceType\" is REQUIRED on every task, and \"autonomy\" on every \"ai\" task, at every depth — a \"subtasks\" entry is a full task object with all the same required fields, not a bare label.',\n '',\n 'DEPENDENCY & PARALLELISM RULES:',\n '- Independent vertical slices (no shared files/modules) should have NO dependencies between them — they can run in parallel.',\n '- Only add dependencies when the second slice truly depends on artifacts (files, APIs) that the first slice creates.',\n '- Prefer parallelism over serial chains. A plan with 3 independent slices running in parallel is better than 3 sequential tasks.',\n '- Slices that touch different areas of the codebase are naturally parallel.',\n '',\n 'RULES:',\n '- Mark as type \"ai\" any task the coding assistant can do autonomously.',\n '- Mark as type \"user\" any task requiring manual action outside the codebase.',\n '- Each AI task must have a detailed \"prompt\" field with clear, specific instructions. Include the exact files to create/modify.',\n '- Each user task must have \"userSteps\" with an ordered array of step-by-step instructions.',\n '- Tasks can have \"subtasks\" for finer-grained sub-steps.',\n '- Use concise but clear titles and descriptions.',\n '',\n 'PROMPT QUALITY RULES:',\n '- Include specific file paths discovered during research in prompts (e.g. \"In src/components/Settings.tsx\").',\n '- Reference existing patterns and hooks found in the codebase (e.g. \"Use the existing useLocalStorage hook from src/hooks/useLocalStorage.ts\").',\n '- For parallel tasks, specify different target files to avoid merge conflicts.',\n '',\n 'Do NOT wrap the JSON in markdown code blocks. Output ONLY the JSON object.',\n].join('\\n');\n\nfunction getPlanTemplate(): string {\n return [\n CORE_PLANNER_PROMPT,\n '',\n '{{RESEARCH_SECTION}}',\n 'MODEL ASSIGNMENT:',\n 'You must assign an \"assignedModel\" to each AI task. Available models:',\n '',\n '{{MODELS_JSON}}',\n '',\n '{{RUNNER_INSTRUCTION}}',\n 'MODEL SELECTION GUIDELINES:',\n '- Use stronger models (Opus, DeepSeek V4 Pro, Kimi 2.6) for: complex refactoring, architecture changes, security-critical code, performance optimization, large-scale changes.',\n '- Use weaker/faster models (Sonnet, DeepSeek V4 Flash) for: simple file operations, test generation, config changes, documentation, straightforward bug fixes.',\n '- Assign thinkingEffort based on task complexity: \"low\" for simple tasks, \"medium\" or \"high\" for moderate/complex tasks.',\n ' For OpenCode models that support variants (e.g. deepseek-v4-pro), use the variant IDs from the models list.',\n ' For Claude Code, use the variant IDs listed for each model in the models list (adaptive, low, medium, high, xhigh, max — per-model).',\n ' Omit thinkingEffort if the model has no variants.',\n '',\n 'TASK MODE:',\n '{{MODE_GUIDE}}',\n '{{REVIEW_BLOCK}}',\n '{{VERIFICATION_BLOCK}}',\n '',\n 'CONTEXT:',\n '{{CONTEXT}}',\n '{{RESEARCH_RESULTS}}',\n ].join('\\n');\n}\n\nfunction serializeModels(models: DiscoveredModel[]) {\n return models.map((m) => ({ modelId: m.modelId, modelLabel: m.modelLabel, variants: m.variants }));\n}\n\nfunction modelsJsonFor(\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n runners: RunnerId[]\n): string {\n const out: Record<string, ReturnType<typeof serializeModels>> = {};\n for (const r of runners) {\n out[r] = serializeModels(modelsByRunner[r] ?? []);\n }\n return JSON.stringify(out, null, 2);\n}\n\nfunction runnerInstruction(runners: RunnerId[]): string {\n const modelList = runners.map(r => `\"${r}\"`).join(' or ');\n if (runners.length > 1) {\n return [\n 'RUNNER ASSIGNMENT (MULTI-RUNNER MODE):',\n `Multiple runners are enabled. The MODELS object above is keyed by runner.`,\n `For EACH AI task, set \"assignedRunner\" to ${modelList},`,\n 'then pick \"assignedModel\" from THAT runner\\'s list (modelId must match exactly).',\n 'IMPORTANT: Only the runners and models listed above may be used. Do not reference any other runner.',\n '',\n ].join('\\n');\n }\n return [\n `RUNNER ASSIGNMENT: All AI tasks run on \"${runners[0]}\". Set \"assignedRunner\" to \"${runners[0]}\" on each task.`,\n 'IMPORTANT: Only the runner and models listed above may be used. Do not reference any other runner or model.',\n '',\n ].join('\\n');\n}\n\nfunction buildPlanPromptBase(\n userGoal: string,\n context: string,\n researchResults: string,\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n runners: RunnerId[],\n includeResearchSection: boolean,\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n modes: PlannerModes = DEFAULT_PLANNER_MODES,\n): string {\n // Scoping here, once, is what keeps a one-shot prompt honest: grill-me and\n // PRD interview the user, and this path has told the model there is nobody\n // to ask. Review is structural, so it belongs.\n const scoped = modesFor('one-shot', modes);\n const { autonomousDefault } = scoped;\n const template = getPlanTemplate();\n const researchReplacement = includeResearchSection ? RESEARCH_SECTION : '';\n const modelsJson = modelsJsonFor(modelsByRunner, runners);\n\n const modeGuide = runnerModes ? buildModeGuide(runnerModes, autonomousDefault) : buildModeGuideForRunners(runners, autonomousDefault);\n\n const modeExamples = runnerModes\n ? Object.entries(runnerModes).map(([r, ms]) => {\n const filtered = filteredBuildModes(ms, autonomousDefault);\n return `${r}: ${filtered.map(m => m.id).join('|')}${ms.some(m => m.id === 'plan') ? '|plan' : ''}`;\n }).join(', ')\n : buildModeExamplesForRunners(runners);\n\n return template\n .replace('{{RESEARCH_SECTION}}', researchReplacement)\n .replace('{{CLARIFICATION_INSTRUCTIONS}}', ONE_SHOT_INSTRUCTIONS)\n .replace('{{MODELS_JSON}}', modelsJson)\n .replace('{{RUNNER_CHOICES}}', runners.join('|'))\n .replace('{{RUNNER_INSTRUCTION}}', runnerInstruction(runners))\n .replace('{{MODE_GUIDE}}', modeGuide)\n .replace('{{REVIEW_BLOCK}}', scoped.review ? `\\n${reviewModeBlock()}\\n` : '')\n .replace('{{VERIFICATION_BLOCK}}', scoped.verification ? `\\n${verificationModeBlock(scoped.review)}\\n` : '')\n .replace('{{MODE_EXAMPLES}}', modeExamples)\n .replace('{{CONTEXT}}', context || '(no additional context)')\n .replace('{{RESEARCH_RESULTS}}', researchResults ? `\\n\\nRESEARCH FINDINGS:\\n${researchResults}` : '')\n + `\\n\\nUser goal: ${userGoal}`;\n}\n\nexport function buildResearchPrompt(\n userGoal: string,\n context: string,\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n runners: RunnerId[],\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n modes: PlannerModes = DEFAULT_PLANNER_MODES,\n): string {\n return buildPlanPromptBase(userGoal, context, '', modelsByRunner, runners, true, runnerModes, modes);\n}\n\nexport function buildPlanWithResults(\n userGoal: string,\n context: string,\n researchResults: string,\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n runners: RunnerId[],\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n modes: PlannerModes = DEFAULT_PLANNER_MODES,\n): string {\n return buildPlanPromptBase(userGoal, context, researchResults, modelsByRunner, runners, false, runnerModes, modes);\n}\n\nexport function buildModifyPlanPrompt(\n existingPlan: LegacyPlanState,\n userRequest: string,\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n aiflowContext?: string,\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n autonomousDefault = true,\n): string {\n const modelsJson = modelsJsonFor(modelsByRunner, existingPlan.runners);\n const planJson = JSON.stringify(existingPlan.tasks, null, 2);\n const aiflowBlock = aiflowContext\n ? `<aiflow_context>\\n${aiflowContext}\\n</aiflow_context>\\n\\n`\n : '';\n\n const modeGuide = runnerModes ? buildModeGuide(runnerModes, autonomousDefault) : '';\n\n return [\n 'You are a software project planner. You previously generated a task plan and the user now wants to modify it.',\n '',\n 'Here is the CURRENT plan as JSON:',\n planJson,\n '',\n 'Available models:',\n modelsJson,\n '',\n `${aiflowBlock}USER MODIFICATION REQUEST:`,\n userRequest,\n '',\n 'Modify the plan according to the user request. You may add, remove, reorder, or change any task properties.',\n 'Return the COMPLETE modified plan as a JSON object with a single \"tasks\" array.',\n '',\n 'RULES:',\n '- For each task, preserve these exact fields: id, order, title, description, type, status, dependencies, prompt, userSteps, subtasks, assignedModel, thinkingEffort, taskMode.',\n '- DO NOT modify or delete completed tasks UNLESS the user explicitly asks to redo or replace them. If the user asks to redo a completed task, change its status from \"completed\" to \"pending\" and update its properties as requested.',\n '- DO NOT modify or delete tasks with status \"in_progress\" — they are currently executing.',\n '- DO NOT modify or delete tasks with status \"failed\" UNLESS the user asks to fix them — then update the prompt and change status from \"failed\" to \"pending\".',\n '- DO NOT modify or delete tasks with status \"blocked\" UNLESS the user asks to unblock them. If unblocking, remove the failed dependency from the blocked task\\'s dependencies array.',\n '- When the user fixes a failed task, also update any blocked tasks that depend on it: change their status from \"blocked\" to \"pending\".',\n '- Preserve existing task IDs for all unchanged, completed, and in-progress tasks.',\n '- Only create new IDs for newly added tasks.',\n '- When removing a task, update all other tasks that reference the deleted ID in their dependencies.',\n '- Ensure dependency chains remain valid — no dangling references to deleted IDs.',\n '- Renumber task \"order\" fields sequentially starting from 1 after insertions or deletions.',\n '- When adding new tasks, assign appropriate models and thinking efforts based on complexity.',\n ...(modeGuide ? ['', modeGuide] : []),\n '- Do NOT wrap the JSON in markdown code blocks. Output ONLY the JSON object.',\n ].join('\\n');\n}\n\n\n\n\nexport function modelContextBlock(\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n runners: RunnerId[],\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n autonomousDefault = true,\n): string {\n const modelsJson = modelsJsonFor(modelsByRunner, runners);\n const modeGuide = runnerModes ? buildModeGuide(runnerModes, autonomousDefault) : buildModeGuideForRunners(runners, autonomousDefault);\n\n return [\n 'MODEL ASSIGNMENT:',\n 'You must assign an \"assignedModel\" to each AI task. Available models:',\n '',\n modelsJson,\n '',\n runnerInstruction(runners),\n 'MODEL SELECTION GUIDELINES:',\n '- Use stronger models (Opus, DeepSeek V4 Pro, Kimi 2.6) for: complex refactoring, architecture changes, security-critical code, performance optimization, large-scale changes.',\n '- Use weaker/faster models (Sonnet, DeepSeek V4 Flash) for: simple file operations, test generation, config changes, documentation, straightforward bug fixes.',\n '- Assign thinkingEffort based on task complexity: \"low\" for simple tasks, \"medium\" or \"high\" for moderate/complex tasks.',\n '',\n 'TASK MODE:',\n modeGuide,\n '',\n ].join('\\n');\n}\n\nexport function executionLogBlock(executionLog: TaskSnapshot[]): string {\n if (executionLog.length === 0) return '';\n\n const completed = executionLog.filter((t) => t.status === 'completed');\n const failed = executionLog.filter((t) => t.status === 'failed');\n\n const lines = ['EXECUTION LOG SUMMARY:'];\n lines.push(`Total entries: ${executionLog.length} (${completed.length} completed, ${failed.length} failed)`);\n\n if (completed.length > 0) {\n lines.push('');\n lines.push('COMPLETED TASKS:');\n for (const t of completed) {\n const verdict = t.verdict ? ` — ${t.verdict.outcome.toUpperCase()}: ${t.verdict.reason}` : '';\n lines.push(`- [${t.id}] ${t.title}${verdict}`);\n }\n }\n\n if (failed.length > 0) {\n lines.push('');\n lines.push('FAILED TASKS (eligible for retry):');\n for (const t of failed) {\n const verdict = t.verdict ? ` — ${t.verdict.reason}` : '';\n lines.push(`- [${t.id}] ${t.title} (retry #${t.retryCount})${verdict}`);\n }\n }\n\n return lines.join('\\n');\n}\n\nexport function pendingEditRulesBlock(): string {\n return [\n 'MODIFICATION RULES:',\n '- Preserve existing task IDs for all unchanged tasks. Only create new IDs for newly added tasks.',\n '- DO NOT modify completed tasks from the execution log UNLESS the user explicitly asks to retry them. If retrying a completed task, assign it the SAME id as the original and set its status to \"pending\".',\n '- DO NOT modify or remove tasks that are currently in_progress — they are being executed by an active agent session.',\n '- When removing a task, update all other tasks that reference the deleted ID in their dependencies.',\n '- Ensure dependency chains remain valid — no dangling references to deleted IDs.',\n '- Renumber task \"order\" fields sequentially starting from 1 after insertions or deletions.',\n '- When adding new tasks, assign appropriate models and thinking efforts based on complexity.',\n '- For failed tasks being retried: use the same ID, update the prompt to address the failure reason, and set status to \"pending\".',\n '- Only modify the tasks the user asked to change. Return ALL pending tasks, not just the modified ones.',\n '',\n ].join('\\n');\n}\n\nexport function buildModifyDuringExecutionPrompt(\n executionLog: TaskSnapshot[],\n pendingTasks: string,\n userMessage: string,\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n runners: RunnerId[],\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n autonomousDefault = true,\n): string {\n const execLogBlock = executionLogBlock(executionLog);\n const rulesBlock = pendingEditRulesBlock();\n const modelBlock = modelContextBlock(modelsByRunner, runners, runnerModes, autonomousDefault);\n\n const sections = [\n CORE_PLANNER_PROMPT,\n '',\n 'You are modifying a plan that is currently executing. Some tasks have already been completed or failed.',\n '',\n ];\n\n if (execLogBlock) {\n sections.push(execLogBlock);\n sections.push('');\n }\n\n sections.push('CURRENT PENDING TASKS (these are NOT yet executed):');\n sections.push(pendingTasks);\n sections.push('');\n sections.push(rulesBlock);\n sections.push(modelBlock);\n sections.push('');\n sections.push('USER REQUEST:');\n sections.push(userMessage);\n sections.push('');\n sections.push('Return the COMPLETE modified pending tasks as a JSON object with a single \"tasks\" array. Include all pending tasks, not just the modified ones.\\nDo NOT wrap the JSON in markdown code blocks. Output ONLY the JSON object.');\n\n return sections.join('\\n');\n}\n\n/**\n * User-message prompt for a planner-driven merge: asks the model to combine the\n * selected tasks into one. Routed through the conversation loop, so the\n * task-ops protocol (with the \"merge\" op) is injected alongside it by\n * `planContextBlock`. The model emits a single taskOps merge op.\n */\nexport function buildMergePrompt(taskIds: string[], tasks: Task[]): string {\n const idSet = new Set(taskIds);\n const selected = tasks.filter((t) => idSet.has(t.id)).sort((a, b) => a.order - b.order);\n const refs = selected.map((t) => `#${t.order} \"${t.title}\" (id=${t.id})`).join(', ');\n return [\n `Merge these tasks into ONE combined task: ${refs}.`,\n 'Write a clear combined title, description, and prompt that cover all of their work.',\n 'The merged task takes the union of their dependencies (excluding the merged tasks themselves) and preserves their user stories.',\n 'Set \"assignedRunner\" and \"assignedModel\" on the merged task — use one of the runners and models listed in <available_models> above. Prefer the strongest model if the merged work is complex.',\n 'Reply with ONLY a taskOps JSON object using a single \"merge\" op:',\n ` {\"taskOps\":[{\"op\":\"merge\",\"taskIds\":[${selected.map((t) => `\"${t.id}\"`).join(', ')}],\"merged\":{\"title\":\"...\",\"description\":\"...\",\"prompt\":\"...\",\"assignedRunner\":\"...\",\"assignedModel\":{\"modelId\":\"...\",\"modelLabel\":\"...\"}}}]}`,\n ].join('\\n');\n}\n\n/**\n * User-message prompt for a planner-driven split: asks the model to decompose\n * one task into a sequence of smaller tasks. The model decides the breakdown —\n * the user does not hand-type the parts.\n */\nexport function buildSplitPrompt(taskId: string, tasks: Task[]): string {\n const task = tasks.find((t) => t.id === taskId);\n if (!task) return `Split task ${taskId} into smaller tasks.`;\n return [\n `Split task #${task.order} \"${task.title}\" (id=${task.id}) into multiple smaller tasks that together accomplish the same work.`,\n 'Decompose it into a sensible ordered sequence. Write a clear title, description, and prompt for each part.',\n 'The first part inherits the original task\\'s dependencies. Each later part depends on the previous part. Tasks that depended on the original now depend on the LAST part.',\n 'Set \"assignedRunner\" and \"assignedModel\" on each part — use the runners and models listed in <available_models> above. You may assign different models to different parts (e.g. a stronger model for a complex part, a faster one for a simple part).',\n 'Reply with ONLY a taskOps JSON object using a single \"split\" op:',\n ` {\"taskOps\":[{\"op\":\"split\",\"taskId\":\"${task.id}\",\"parts\":[{\"title\":\"...\",\"description\":\"...\",\"prompt\":\"...\",\"assignedRunner\":\"...\",\"assignedModel\":{\"modelId\":\"...\",\"modelLabel\":\"...\"}},...]}]}`,\n ].join('\\n');\n}\n","import type { Task, RunnerId } from '../models/Task';\nimport {\n PlanParseError, extractObjectsWithKey,\n PLAN_ENVELOPE_KEY, TASK_OPS_ENVELOPE_KEY,\n} from './JsonExtractor';\nimport { parsePlanJson, looksLikePlanAttempt } from './PlanValidator';\nimport { parseTaskOpsJson, textHasTaskOps, type TaskOp } from './TaskOps';\nimport type { RunnerModeInfo } from './ModeResolver';\n\n/**\n * The one owner of \"the model emitted something unusable — correct it and\n * retry\". Every repair path in the planner routes through this module:\n *\n * - {@link repairLoop} is the bounded driver (first reply → interpret →\n * corrective re-send), used by plan generation ({@link generatePlanWithRepair}),\n * the Session's task-ops settlement, and Planner.modifyDuringExecution.\n * - {@link classifyPlannerReply} decides what a planner reply *is* — a plan,\n * targeted task edits, a botched attempt at either (worth a corrective\n * retry), or prose. The conversation loop in BaseAiService keeps its own\n * driver (it also runs the tool rounds) but delegates classification here.\n * - The corrective prompt texts live here, once.\n *\n * Policies stay at the call sites (PRD nudge, ops validation, abort guards) —\n * they are inputs to the loop, not part of it.\n */\n\nexport type RepairVerdict<T> =\n | { done: T }\n | { retry: { errors: string[]; corrective: string; cause?: unknown } };\n\nexport interface RepairLoopOpts<R, T> {\n /** Produce the first reply (attempt 0) — often already in hand. */\n first: () => R | Promise<R>;\n /** Ask the model again with a corrective prompt after a retryable failure. */\n resend: (corrective: string) => Promise<R>;\n /**\n * Judge one reply: `done` with the settled value, or `retry` with the\n * errors and the corrective prompt to send. Throw for non-retryable\n * failures — those propagate immediately.\n */\n interpret: (reply: R) => RepairVerdict<T> | Promise<RepairVerdict<T>>;\n /** Corrective re-sends allowed after the first attempt (N repairs = N+1 attempts). */\n maxRepairs: number;\n /** Budget exhausted: receives the last reply and its errors; return a fallback or throw. */\n onExhausted: (last: { reply: R; errors: string[]; cause?: unknown }) => T;\n}\n\nexport async function repairLoop<R, T>(opts: RepairLoopOpts<R, T>): Promise<T> {\n let reply = await opts.first();\n for (let repairs = 0; ; repairs++) {\n const verdict = await opts.interpret(reply);\n if ('done' in verdict) return verdict.done;\n if (repairs >= opts.maxRepairs) {\n return opts.onExhausted({ reply, errors: verdict.retry.errors, cause: verdict.retry.cause });\n }\n reply = await opts.resend(verdict.retry.corrective);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Corrective prompts — the texts the model sees when it must re-emit.\n// ---------------------------------------------------------------------------\n\n/** Instruction appended to a follow-up request asking the model to re-emit strict JSON. */\nexport const JSON_REPAIR_INSTRUCTION =\n 'Your previous response could not be parsed as JSON. Re-send ONLY the JSON object — ' +\n 'no prose before or after, no explanation, no markdown code fences.';\n\n/**\n * The emission hit the output-token limit: a plain \"re-send the JSON\" retry\n * would be cut off at the same point, so this one asks for terser output.\n */\nexport const TRUNCATED_PLAN_REPAIR_INSTRUCTION =\n 'Your previous response was cut off by the output length limit before the JSON finished. ' +\n `Re-send the COMPLETE plan as a single {\"${PLAN_ENVELOPE_KEY}\":[...]} JSON object — no prose, no code fences — ` +\n 'and keep every task description and prompt brief so the whole object fits within the limit.';\n\n/** A plan attempt was botched (invalid or truncated JSON): re-emit the whole plan. */\nexport function reEmitPlanPrompt(detail: string): string {\n return `Your plan JSON could not be committed: ${detail}. Re-emit the COMPLETE corrected plan as a single {\"${PLAN_ENVELOPE_KEY}\":[...]} JSON object — every task included, no prose, no code fences.`;\n}\n\n/** A plan emission was truncated mid-JSON; the caller may also have compacted the history to free input context. */\nexport function truncatedPlanReEmitPrompt(historyCompacted: boolean): string {\n return (historyCompacted\n ? 'Older raw research transcripts have been trimmed from this conversation to free space (subagent digests are intact). '\n : '') + TRUNCATED_PLAN_REPAIR_INSTRUCTION;\n}\n\n/** A task-ops attempt was botched (unparseable JSON): re-emit the ops object. */\nexport function reEmitTaskOpsPrompt(detail: string): string {\n return `Your task edits could not be applied: ${detail}. Re-emit ONLY a corrected {\"${TASK_OPS_ENVELOPE_KEY}\":[...]} JSON object — no prose, no code fences — or reply in prose if you did not intend to edit tasks.`;\n}\n\n/** Task ops parsed but failed semantic validation (cycles, unknown refs, locked tasks). */\nexport function taskOpsRejectedPrompt(errors: string[]): string {\n return `Those task edits were rejected:\\n- ${errors.join('\\n- ')}\\nRe-emit a corrected {\"${TASK_OPS_ENVELOPE_KEY}\":[...]} JSON object, or reply in prose if something is unclear.`;\n}\n\n/** A modified plan failed validation during execution: full re-prompt feedback block. */\nexport function modifyValidationFeedback(errors: string[]): string {\n return [\n '',\n '=== VALIDATION ERRORS FROM PREVIOUS ATTEMPT ===',\n 'Your previous plan modification was rejected by validation. Fix these issues:',\n ...errors.map((e, i) => `${i + 1}. ${e}`),\n '',\n 'Resubmit the corrected plan. Do NOT wrap in markdown code blocks.',\n ].join('\\n');\n}\n\n// ---------------------------------------------------------------------------\n// Reply classification — what did the planner actually emit?\n// ---------------------------------------------------------------------------\n\nexport type PlannerReplyClassification =\n | { kind: 'plan'; tasks: Task[] }\n | { kind: 'task_ops'; ops: TaskOp[] }\n /** Clearly attempted a plan (tasks-keyed object, or JSON cut off mid-stream) and botched it — worth a corrective retry. */\n | { kind: 'broken_plan'; error: PlanParseError }\n /** Clearly attempted an ops object and botched it — worth a corrective retry. */\n | { kind: 'broken_task_ops'; error: PlanParseError }\n | { kind: 'prose' };\n\n/**\n * Classify one planner reply. Task ops are checked before the plan key — an\n * ops object never carries a top-level tasks array, but a model may mention\n * the word in prose around it. \"Broken\" is deliberately narrower than \"failed\n * to parse\": prose that merely mentions the envelope key is left alone.\n */\nexport function classifyPlannerReply(\n text: string,\n opts: {\n runners: RunnerId[];\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>;\n autonomousDefault?: boolean;\n },\n): PlannerReplyClassification {\n if (textHasTaskOps(text)) {\n try {\n return { kind: 'task_ops', ops: parseTaskOpsJson(text) };\n } catch (err) {\n if (!(err instanceof PlanParseError)) throw err;\n // Repairable only when the reply carries a real ops object and no plan\n // to fall through to; otherwise it may still be a plan, else prose.\n if (\n !text.includes(`\"${PLAN_ENVELOPE_KEY}\"`) &&\n extractObjectsWithKey(text, TASK_OPS_ENVELOPE_KEY).matches.length > 0\n ) {\n return { kind: 'broken_task_ops', error: err };\n }\n }\n }\n\n // A reply is a candidate plan whenever its content carries a tasks key —\n // models often emit a short preamble before the JSON.\n if (text.includes(`\"${PLAN_ENVELOPE_KEY}\"`)) {\n try {\n return { kind: 'plan', tasks: parsePlanJson(text, opts.runners, opts.runnerModes, opts.autonomousDefault) };\n } catch (err) {\n if (!(err instanceof PlanParseError)) throw err;\n if (looksLikePlanAttempt(text)) return { kind: 'broken_plan', error: err };\n }\n }\n\n return { kind: 'prose' };\n}\n\n// ---------------------------------------------------------------------------\n// Plan-stream adapter — one-shot generation with JSON repair.\n// ---------------------------------------------------------------------------\n\n/**\n * Generate a plan, retrying on unparseable JSON. `generate` is called with an\n * optional repair hint (undefined on the first attempt, {@link JSON_REPAIR_INSTRUCTION}\n * thereafter) and must return the model's raw text. Only {@link PlanParseError} is\n * retried; transport/other errors propagate immediately. The last parse error is\n * re-thrown if every attempt fails.\n */\nexport async function generatePlanWithRepair(\n generate: (repairHint?: string) => Promise<string>,\n runners: RunnerId[],\n maxAttempts = 2,\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n autonomousDefault = true,\n): Promise<Task[]> {\n return repairLoop<string, Task[]>({\n first: () => generate(undefined),\n resend: (corrective) => generate(corrective),\n interpret: (text) => {\n try {\n return { done: parsePlanJson(text, runners, runnerModes, autonomousDefault) };\n } catch (err) {\n if (!(err instanceof PlanParseError)) throw err;\n // A shape rejection is not a parse failure: telling the model its JSON\n // \"could not be parsed\" spends the one retry on a problem that does not\n // exist, and it re-sends the same object. Name the rule instead — the\n // conversational path has always done this.\n const corrective = err.truncated\n ? TRUNCATED_PLAN_REPAIR_INSTRUCTION\n : err.semantic\n ? reEmitPlanPrompt(err.message)\n : JSON_REPAIR_INSTRUCTION;\n return { retry: { errors: [err.message], corrective, cause: err } };\n }\n },\n maxRepairs: maxAttempts - 1,\n onExhausted: ({ cause }) => {\n throw cause ?? new PlanParseError('Plan generation produced no parseable output', '');\n },\n });\n}\n","import type OpenAI from 'openai';\nimport { SchemaType, type FunctionDeclaration, type Schema } from '@google/generative-ai';\n\n/**\n * Canonical definition of the read-only research tools the planner uses to\n * explore a workspace. Both the OpenAI- and Gemini-backed services drive the\n * same loop over the same tools, so the names, descriptions, and parameter\n * shapes live here once and are projected into each SDK's tool format. Keeping\n * a single source of truth stops the two provider lists from drifting apart.\n */\n\ntype ParamType = 'string' | 'number' | 'array' | 'boolean';\n\ninterface ResearchToolParam {\n type: ParamType;\n description: string;\n /** Element type for `array` parameters. */\n items?: { type: ParamType };\n /** Closed value set, projected as a JSON-schema enum. */\n enum?: string[];\n}\n\nexport interface ResearchToolSpec {\n name: string;\n description: string;\n properties: Record<string, ResearchToolParam>;\n required: string[];\n}\n\nexport const SPAWN_RESEARCH_AGENT = 'spawn_research_agent';\n\n/**\n * Optional subagent tool (issue #34), opencode-style: one stateless read-only\n * research agent per call. Only declared when the researchSubagents toggle is\n * on AND the active service can build subagent chats. Kept out of\n * RESEARCH_TOOLS so the default projections stay bit-for-bit today's list.\n */\nexport const SPAWN_RESEARCH_AGENT_SPEC: ResearchToolSpec = {\n name: SPAWN_RESEARCH_AGENT,\n description: 'Launch a read-only research agent that explores the workspace with its own tools (read_file, read_files, glob, grep, find_symbol, list_dir, bash) and returns a single digest. When to use: an open-ended exploration thread you want answered without doing every lookup yourself — a subsystem to map, a question like \"how does X flow through this codebase\". Launch a new agent whenever such a thread emerges during research. To explore several independent areas, launch multiple agents CONCURRENTLY by putting several spawn_research_agent calls in one reply — they run in parallel. When NOT to use: reading a specific known file (read it directly), or small single-subsystem repos where direct exploration is already fast. Each agent is stateless: it sees nothing of this conversation and you cannot message it again. Its prompt must be self-contained — name the area or question, the paths or symbols to start from, and exactly what the digest must report back. Agents are read-only, cannot spawn further agents, and only their final digest returns to you.',\n properties: {\n prompt: { type: 'string', description: 'Self-contained task for the research agent, including what the digest must contain.' },\n },\n required: ['prompt'],\n};\n\nexport const RESEARCH_TOOLS: ResearchToolSpec[] = [\n {\n name: 'read_file',\n description: 'Read the contents of a file with line-numbered output and optional offset/limit for pagination. Path is relative to the workspace root; a path outside it requires user approval. When to use: read a file you already know the path of (from glob/grep/find_symbol results). When NOT to use: to find files — use glob or grep first to locate the right files.',\n properties: {\n path: { type: 'string', description: 'Relative path to the file' },\n offset: { type: 'number', description: '0-based line number to start reading from (default: 0)' },\n limit: { type: 'number', description: 'Maximum number of lines to return (default: 2000). Files larger than ~1 MB are rejected with an error — use grep instead for those.' },\n },\n required: ['path'],\n },\n {\n name: 'read_files',\n description: 'Read multiple known files at once. When to use: batch-read several files whose paths you already know. When NOT to use: discovering which files to read — use glob/grep first.',\n properties: {\n paths: { type: 'array', items: { type: 'string' }, description: 'Array of relative file paths to read' },\n },\n required: ['paths'],\n },\n {\n name: 'glob',\n description: 'Find files matching a glob pattern (e.g. \"src/**/*.ts\"). Uses ripgrep for speed. When to use: find files by name/path pattern. When NOT to use: searching file contents (use grep) or browsing directory layout (use list_dir).',\n properties: {\n pattern: { type: 'string', description: 'Glob pattern' },\n path: { type: 'string', description: 'Directory to search under (default: workspace root). Paths outside the workspace require user approval.' },\n },\n required: ['pattern'],\n },\n {\n name: 'grep',\n description: 'Search file contents with ripgrep. When to use: find code patterns, imports, or any text within files. When NOT to use: finding files by name (use glob), or locating where a named symbol is DEFINED (use find_symbol — it filters out the call sites that would otherwise fill this tool\\'s result budget). Results are capped globally; use output_mode=\"files\" to survey breadth cheaply, then re-run with output_mode=\"content\" on a narrower path.',\n properties: {\n pattern: { type: 'string', description: 'Regex pattern to search for (set literal=true to match it as plain text instead)' },\n include: { type: 'string', description: 'Optional file glob to filter (e.g. \"*.ts\")' },\n path: { type: 'string', description: 'Directory to search under (default: workspace root). Paths outside the workspace require user approval.' },\n output_mode: { type: 'string', enum: ['content', 'files', 'count'], description: '\"content\" (default) returns matching lines; \"files\" returns only file paths; \"count\" returns per-file match counts. Prefer \"files\" or \"count\" when surveying breadth.' },\n context_before: { type: 'number', description: 'Lines of context before each match (content mode only)' },\n context_after: { type: 'number', description: 'Lines of context after each match (content mode only)' },\n literal: { type: 'boolean', description: 'Treat the pattern as a literal string rather than a regex' },\n case_insensitive: { type: 'boolean', description: 'Case-insensitive match' },\n head_limit: { type: 'number', description: 'Maximum rows returned (default 100)' },\n },\n required: ['pattern'],\n },\n {\n name: 'find_symbol',\n description: 'Locate where a named symbol is DEFINED, plus a per-file count of where it is referenced. Understands declaration syntax across TypeScript, Python, Go, Rust, JVM languages, C#, C/C++, Ruby, PHP, Swift, Elixir and more. When to use: \"where is X defined\", \"what would changing X affect\", scoping the blast radius of a task. When NOT to use: free-text or pattern search (use grep), or finding files by name (use glob). Strongly preferred over grep for named symbols — grep returns every import and call site, so the definition often falls outside the result cap.',\n properties: {\n symbol: { type: 'string', description: 'Exact symbol name (function, class, type, constant, …)' },\n language: { type: 'string', description: 'Optional language id or file extension (\"typescript\", \"go\", \".rs\") to narrow the search in polyglot repos' },\n path: { type: 'string', description: 'Directory to search under (default: workspace root)' },\n },\n required: ['symbol'],\n },\n {\n name: 'list_dir',\n description: 'List directory contents as a tree. Use depth > 1 for nested tree view. When to use: getting oriented with project structure, seeing what directories exist. When NOT to use: finding specific files by name (use glob) or searching file contents (use grep).',\n properties: {\n path: { type: 'string', description: 'Relative path to the directory' },\n depth: { type: 'number', description: 'Directory depth for tree view (default: 1, flat listing)' },\n },\n required: ['path'],\n },\n {\n name: 'bash',\n description: 'Run a shell command for research. Read-only inspection (ls, tree, git log/status/diff/show, wc, find, rg, jq, …) runs immediately. Anything else — test suites, package managers, cloud CLIs like az/gh/aws/kubectl — pauses for one user approval and is then remembered for the rest of the session. Commands that write or mutate (rm, mv, cp, chmod, sudo, mkdir, git push/commit, output redirection, piping into a shell) are always refused: you are a planner, so describe the change as a task and let the runner make it. When to use: diagnosing before planning — reproduce a failure, query a remote environment, inspect build config. When NOT to use: file search (use glob/grep/find_symbol/list_dir instead).',\n properties: {\n command: { type: 'string', description: 'The shell command to run' },\n },\n required: ['command'],\n },\n {\n name: 'fetch',\n description: 'Fetch content from a URL (HTTP/HTTPS). Use for reading API documentation, library references, or package docs. URL confirmation is required — the tool may pause while awaiting approval.',\n properties: {\n url: { type: 'string', description: 'The URL to fetch' },\n },\n required: ['url'],\n },\n {\n name: 'web_search',\n description: 'Search the web for result titles, URLs and snippets. When to use: you need docs for an unfamiliar library or API and have no URL yet — search first, then fetch the most promising result. When NOT to use: anything answerable from the workspace itself (use grep or find_symbol).',\n properties: {\n query: { type: 'string', description: 'Search query' },\n },\n required: ['query'],\n },\n];\n\n/**\n * The toolset a research subagent gets: the read-only exploration tools minus\n * the network tools (`fetch`/`web_search` can pause on user confirmation, which\n * a background subagent must never do) and minus the spawn tool itself (no\n * recursion). `bash` stays, but its own approval gate means a subagent can only\n * ever run the auto-tier read-only commands — an ask-tier command from a\n * background agent resolves to denied rather than prompting.\n */\nconst SUBAGENT_EXCLUDED = new Set(['fetch', 'web_search']);\n\nexport function subagentToolSpecs(): ResearchToolSpec[] {\n return RESEARCH_TOOLS.filter((t) => !SUBAGENT_EXCLUDED.has(t.name));\n}\n\nfunction withSpawn(includeSubagents: boolean): ResearchToolSpec[] {\n return includeSubagents ? [...RESEARCH_TOOLS, SPAWN_RESEARCH_AGENT_SPEC] : RESEARCH_TOOLS;\n}\n\nfunction projectOpenAi(specs: ResearchToolSpec[]): OpenAI.Chat.Completions.ChatCompletionTool[] {\n return specs.map((t) => ({\n type: 'function',\n function: {\n name: t.name,\n description: t.description,\n parameters: {\n type: 'object',\n properties: Object.fromEntries(Object.entries(t.properties).map(([key, param]) => [key, {\n type: param.type,\n description: param.description,\n ...(param.items ? { items: param.items } : {}),\n ...(param.enum ? { enum: param.enum } : {}),\n }])),\n required: t.required,\n },\n },\n }));\n}\n\n/** Project the canonical tools into OpenAI's chat-completions tool format. */\nexport function toOpenAiTools(includeSubagents = false): OpenAI.Chat.Completions.ChatCompletionTool[] {\n return projectOpenAi(withSpawn(includeSubagents));\n}\n\n/** The subagent's own tool list in OpenAI format. */\nexport function toOpenAiSubagentTools(): OpenAI.Chat.Completions.ChatCompletionTool[] {\n return projectOpenAi(subagentToolSpecs());\n}\n\nconst SCHEMA_TYPE: Record<ParamType, SchemaType> = {\n string: SchemaType.STRING,\n number: SchemaType.NUMBER,\n array: SchemaType.ARRAY,\n boolean: SchemaType.BOOLEAN,\n};\n\n/** Project the canonical tools into Gemini's function-declaration format. */\nexport function toGeminiToolDeclarations(includeSubagents = false): FunctionDeclaration[] {\n return withSpawn(includeSubagents).map((t) => {\n const properties: Record<string, Schema> = {};\n for (const [key, param] of Object.entries(t.properties)) {\n properties[key] = {\n type: SCHEMA_TYPE[param.type],\n description: param.description,\n ...(param.items ? { items: { type: SCHEMA_TYPE[param.items.type] } } : {}),\n ...(param.enum ? { format: 'enum', enum: param.enum } : {}),\n };\n }\n return {\n name: t.name,\n description: t.description,\n parameters: { type: SchemaType.OBJECT, properties, required: t.required },\n };\n });\n}\n","import { RESEARCH_TOOLS, SPAWN_RESEARCH_AGENT } from './researchTools';\nimport type { ResearchChat, ResearchTurn } from './BaseAiService';\n\n/**\n * Research-context compaction (Option 1 for the truncated-plan bug): a long\n * research phase — especially with parallel subagents — can bloat the planner\n * context enough that the final plan-JSON emission runs out of output tokens\n * mid-object. The fix is on the input side: raw tool transcripts are pruned\n * to stubs while subagent digests are preserved — a digest is already the\n * compressed form of a whole research thread; the raw outputs are what it\n * summarized.\n */\n\nexport const COMPACTION_LIMITS = {\n /** Pruned outputs keep this much leading text so the model still sees what was there. */\n keepHeadChars: 400,\n /** Outputs at or below this size are never pruned — the savings would not pay for the loss. */\n minPrunableChars: 1500,\n /** Aggregate research-findings budget for the one-shot fallback plan prompt. */\n researchResultsMaxChars: 60_000,\n /**\n * Prompt-token level at which history is compacted proactively, before an\n * emission ever truncates: ~80% of a 128k context, the smallest window in\n * common planner use. Bigger-window models just compact earlier — that only\n * stubs bulky raw transcripts (digests are kept), a mild loss taken for\n * predictability.\n */\n proactivePromptTokens: 100_000,\n};\n\n/** Structural subset of an OpenAI-style chat message that compaction reads and rewrites. */\nexport interface CompactableMessage {\n role: string;\n content?: unknown;\n tool_call_id?: string;\n tool_calls?: Array<{ id?: string; function?: { name?: string } }>;\n}\n\n/**\n * Prune bulky raw tool outputs from a chat history in place so a follow-up\n * plan emission gets its context back. Subagent digests are kept whole.\n * Returns the number of characters removed.\n */\nexport function compactToolMessages(\n messages: CompactableMessage[],\n preserveToolNames: ReadonlySet<string> = new Set([SPAWN_RESEARCH_AGENT]),\n): number {\n const nameById = new Map<string, string>();\n for (const m of messages) {\n for (const tc of m.tool_calls ?? []) {\n if (tc.id && tc.function?.name) nameById.set(tc.id, tc.function.name);\n }\n }\n\n let removed = 0;\n for (const m of messages) {\n if (m.role !== 'tool' || typeof m.content !== 'string') continue;\n const name = m.tool_call_id ? nameById.get(m.tool_call_id) : undefined;\n if (name && preserveToolNames.has(name)) continue;\n if (m.content.length <= COMPACTION_LIMITS.minPrunableChars) continue;\n const stub = m.content.slice(0, COMPACTION_LIMITS.keepHeadChars)\n + `\\n[... ${name ?? 'tool'} output pruned (${m.content.length} chars) to free context for the plan — re-run the tool if needed]`;\n removed += m.content.length - stub.length;\n m.content = stub;\n }\n return removed;\n}\n\n/**\n * Wrap a chat so that any turn reporting prompt tokens past the threshold\n * compacts the history immediately — the next call (tool round or the plan\n * emission itself) then runs against a pruned context instead of a saturated\n * one. Opencode-style auto-compact, but deterministic: no summarizer model.\n * Reactive truncation repair stays as the backstop for whatever this misses.\n */\nexport function withProactiveCompaction(chat: ResearchChat): ResearchChat {\n const check = (turn: ResearchTurn): ResearchTurn => {\n if ((turn.promptTokens ?? 0) >= COMPACTION_LIMITS.proactivePromptTokens) chat.compactHistory?.();\n return turn;\n };\n return {\n sendMessage: (text, signal) => chat.sendMessage(text, signal).then(check),\n sendToolResults: (results, signal) => chat.sendToolResults(results, signal).then(check),\n compactHistory: chat.compactHistory?.bind(chat),\n };\n}\n\ninterface ResultsBlock {\n tool: string | null;\n lines: string[];\n}\n\nconst PRESERVED_BLOCKS = new Set([SPAWN_RESEARCH_AGENT, 'llm_response']);\n\n/**\n * Bound the accumulated research-findings text embedded in the one-shot\n * fallback plan prompt. Blocks are pruned oldest-first: raw tool transcripts\n * before subagent digests and the model's own closing synthesis, which only\n * shrink if the budget still cannot be met without them.\n */\nexport function compactResearchResults(\n resultsText: string,\n maxChars = COMPACTION_LIMITS.researchResultsMaxChars,\n): string {\n if (resultsText.length <= maxChars) return resultsText;\n\n // Blocks are delimited by the headers executeToolCalls writes:\n // \"[toolName({...args})]\" or \"[LLM response]\", always at line start.\n const knownNames = new Set(RESEARCH_TOOLS.map((t) => t.name)).add(SPAWN_RESEARCH_AGENT);\n const headerRe = /^\\[([a-z_]+)\\(/;\n const blocks: ResultsBlock[] = [{ tool: null, lines: [] }];\n for (const line of resultsText.split('\\n')) {\n const m = headerRe.exec(line);\n const tool = m && knownNames.has(m[1]) ? m[1] : line === '[LLM response]' ? 'llm_response' : null;\n if (tool) blocks.push({ tool, lines: [line] });\n else blocks[blocks.length - 1].lines.push(line);\n }\n\n // Splitting the line list into blocks and re-joining is the identity, so\n // untouched blocks survive byte-for-byte.\n const texts = blocks.map((b) => b.lines.join('\\n'));\n let total = texts.reduce((n, t) => n + t.length, 0);\n const prunePasses: Array<(b: ResultsBlock) => boolean> = [\n (b) => b.tool !== null && !PRESERVED_BLOCKS.has(b.tool),\n (b) => b.tool !== null && PRESERVED_BLOCKS.has(b.tool),\n ];\n for (const shouldPrune of prunePasses) {\n for (const [i, b] of blocks.entries()) {\n if (total <= maxChars) break;\n if (!shouldPrune(b) || texts[i].length <= COMPACTION_LIMITS.minPrunableChars) continue;\n const stub = texts[i].slice(0, COMPACTION_LIMITS.keepHeadChars)\n + `\\n[... pruned ${texts[i].length} chars to fit the research budget]`;\n total -= texts[i].length - stub.length;\n texts[i] = stub;\n }\n }\n\n // Blocks partition the split lines, so joining block texts with '\\n' undoes\n // the split exactly — except the synthetic empty first block, which must not\n // inject a leading newline when the text opened with a header line.\n return (blocks[0].lines.length === 0 ? texts.slice(1) : texts).join('\\n');\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\n\nconst PRD_BLOCK_RE = /<!--\\s*ORDEWELL_PRD_START\\s+slug=\"([^\"]+)\"\\s*-->\\s*([\\s\\S]*?)\\s*<!--\\s*ORDEWELL_PRD_END\\s*-->/;\n\nexport interface PrdBlock {\n slug: string;\n markdown: string;\n}\n\n/**\n * Detect a full markdown PRD in a planner message. The markers are the only\n * structured artifact left in the conversation loop — they exist so the PRD\n * can be saved to disk, not to drive any state machine.\n */\nexport function extractPrdBlock(text: string): PrdBlock | null {\n const match = PRD_BLOCK_RE.exec(text);\n if (!match) return null;\n const slug = sanitizeSlug(match[1]);\n const markdown = match[2].trim();\n if (!slug || !markdown) return null;\n return { slug, markdown };\n}\n\n/** Kebab-case, path-safe feature slug. */\nexport function sanitizeSlug(raw: string): string {\n return raw\n .toLowerCase()\n .replace(/[^a-z0-9-_]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 80);\n}\n\n/** Save the PRD to `<workspace>/.scratch/<slug>/PRD.md` (to-prd native convention). */\nexport function savePrdMarkdown(workspace: string, slug: string, markdown: string): string {\n const dir = path.join(workspace, '.scratch', sanitizeSlug(slug));\n fs.mkdirSync(dir, { recursive: true });\n const file = path.join(dir, 'PRD.md');\n fs.writeFileSync(file, markdown.endsWith('\\n') ? markdown : markdown + '\\n', 'utf8');\n return file;\n}\n","import { IFileSystem } from '../interfaces/IFileSystem';\nimport type { RunnerRegistry } from '../plugins/RunnerRegistry';\n\nexport interface CollectedContext {\n agentConfig: string | null;\n agentConfigPath: string | null;\n dirStructure: string | null;\n aiflowContext: string | null;\n}\n\nconst ORDEWELL_CONTEXT_MAX = 8000;\n\n/**\n * The project-context preamble every planner backend puts in front of its\n * system prompt: ORDEWELL.md, each runner's own agent config, and the directory\n * structure. Lives here rather than on a service base class because both\n * transports need it and only one of them has a base class (ADR-0009).\n */\nexport async function collectResearchContext(fs: IFileSystem, runners: string[]): Promise<string> {\n const collector = new ContextCollector(fs);\n\n let contextStr = '';\n let firstContext: CollectedContext | null = null;\n for (const r of runners) {\n const ctx = await collector.collect(r);\n if (!firstContext) firstContext = ctx;\n if (ctx.agentConfig && ctx.agentConfigPath) {\n contextStr += `\\n=== ${ctx.agentConfigPath} (${r}) ===\\n${ctx.agentConfig.slice(0, 3000)}\\n`;\n }\n }\n if (firstContext?.aiflowContext) {\n contextStr = `\\n<aiflow_context>\\n${firstContext.aiflowContext}\\n</aiflow_context>\\n` + contextStr;\n }\n if (firstContext?.dirStructure) contextStr += `\\n=== Directory Structure ===\\n${firstContext.dirStructure}\\n`;\n return contextStr;\n}\n\nexport class ContextCollector {\n constructor(private fs: IFileSystem, private registry?: RunnerRegistry) {}\n\n setRegistry(registry: RunnerRegistry): void {\n this.registry = registry;\n }\n\n async collect(runner: string): Promise<CollectedContext> {\n const context: CollectedContext = {\n agentConfig: null,\n agentConfigPath: null,\n dirStructure: null,\n aiflowContext: null,\n };\n\n const aiflowResult = await this.readIfExists('ORDEWELL.md');\n if (aiflowResult) context.aiflowContext = aiflowResult.output.slice(0, ORDEWELL_CONTEXT_MAX);\n\n const plugin = this.registry?.getManifest(runner);\n if (plugin?.contextFile) {\n const configResult = await this.readIfExists(plugin.contextFile)\n || (plugin.contextFileAltPath ? await this.readIfExists(plugin.contextFileAltPath) : null);\n if (configResult) {\n context.agentConfig = configResult.output;\n context.agentConfigPath = plugin.contextFile;\n }\n }\n\n const dirResult = await this.fs.listDir('.', 3);\n if (dirResult.success) context.dirStructure = dirResult.output;\n\n return context;\n }\n\n private async readIfExists(filePath: string) {\n const result = await this.fs.readFile(filePath);\n if (result.success && result.output.length > 0) return result;\n return null;\n }\n}\n","import { IFileSystem, GrepOptions, GrepOutputMode, ToolOutcome } from '../interfaces/IFileSystem';\nimport { IWebFetcher } from '../interfaces/IWebFetcher';\n\nconst GREP_OUTPUT_MODES: GrepOutputMode[] = ['content', 'files', 'count'];\n\nfunction num(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction bool(value: unknown): boolean | undefined {\n return typeof value === 'boolean' ? value : undefined;\n}\n\nfunction str(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\n/**\n * Models emit these in snake_case (that is how the schema declares them), so\n * the mapping to the camelCase {@link GrepOptions} lives here rather than being\n * re-derived in every filesystem adapter.\n */\nfunction grepOptions(args: Record<string, unknown>): GrepOptions {\n const mode = str(args.output_mode ?? args.outputMode);\n return {\n include: str(args.include),\n path: str(args.path),\n outputMode: GREP_OUTPUT_MODES.includes(mode as GrepOutputMode) ? (mode as GrepOutputMode) : undefined,\n contextBefore: num(args.context_before ?? args.contextBefore),\n contextAfter: num(args.context_after ?? args.contextAfter),\n literal: bool(args.literal),\n caseInsensitive: bool(args.case_insensitive ?? args.caseInsensitive),\n headLimit: num(args.head_limit ?? args.headLimit),\n };\n}\n\nexport async function executeTool(\n name: string,\n args: Record<string, unknown>,\n fs: IFileSystem,\n fetcher?: IWebFetcher,\n): Promise<ToolOutcome> {\n switch (name) {\n case 'read_file': {\n const offset = num(args.offset);\n const limit = num(args.limit);\n const maxBytes = num(args.maxBytes);\n return fs.readFile(String(args.path ?? ''), { offset, limit, maxBytes });\n }\n case 'read_files': {\n const paths = Array.isArray(args.paths) ? args.paths.map(String) : [];\n return fs.readFiles(paths);\n }\n case 'glob': return fs.glob(String(args.pattern ?? ''), { path: str(args.path), headLimit: num(args.head_limit ?? args.headLimit) });\n case 'grep': return fs.grep(String(args.pattern ?? ''), grepOptions(args));\n case 'find_symbol': return fs.findSymbol(String(args.symbol ?? ''), { language: str(args.language), path: str(args.path) });\n case 'list_dir': return fs.listDir(String(args.path ?? ''), num(args.depth));\n case 'bash': return fs.bash(String(args.command ?? ''));\n case 'fetch': {\n if (!fetcher) return { success: false, output: 'Web fetching is not available in this environment.', truncated: false };\n const url = String(args.url ?? '');\n const allowed = await fetcher.confirm(url);\n if (!allowed) return { success: false, output: `URL fetch denied by user: ${url}`, truncated: false };\n return fetcher.fetch(url);\n }\n case 'web_search': {\n if (!fetcher?.search) {\n return { success: false, output: 'Web search is not available in this environment. If you already know a documentation URL, use the fetch tool instead.', truncated: false };\n }\n const query = String(args.query ?? '').trim();\n if (!query) return { success: false, output: 'web_search requires a non-empty \"query\".', truncated: false };\n return fetcher.search(query);\n }\n // Budget models hallucinate two kinds of tools: plan-committing ones\n // (create_task, submit_plan) and implementation ones (create_file,\n // write_file). Steer both back: you are a planner, tasks run later,\n // and the commit channel is raw JSON in the reply text.\n default: return {\n success: false,\n output: `Unknown tool: ${name}. You are a PLANNER — you never create or edit files yourself; the coding agents executing the plan will do that later. Your tools are read-only research tools: read_file, read_files, glob, grep, find_symbol, list_dir, bash, fetch, web_search. To commit the final plan, output it as a raw JSON object with a \"tasks\" array directly in your reply text (no tool call).`,\n truncated: false,\n };\n }\n}\n","import { executeTool } from './executeTool';\nimport { subagentToolSpecs } from './researchTools';\nimport { classifyCommand, pathLikeArgs } from './commandPolicy';\nimport { resolveResearchShell } from './researchShell';\nimport { resolveWithin } from './pathScope';\nimport { classifyOutcome } from './researchStepSummary';\nimport type { IFileSystem, ToolOutcome } from '../interfaces/IFileSystem';\nimport type { ResearchChat, ToolResult } from './BaseAiService';\nimport type { ResearchProgress, ResearchStep } from '../models/Task';\n\n/**\n * Read-only research subagents (issue #34), opencode-style: one stateless\n * subagent per spawn_research_agent tool call, so the planner can follow\n * threads as they emerge; parallelism comes from the planner batching several\n * spawn calls in one message (the service layer runs them concurrently).\n * This module owns one subagent's mini research loop — it never imports\n * BaseAiService/OpenAiService (the chat factory comes in as a dependency), so\n * the service → executeTool import chain stays acyclic.\n */\n\nexport const SUBAGENT_LIMITS = {\n /** Max spawn calls in flight at once; extra calls in the same turn wait for a slot. */\n maxConcurrent: 3,\n maxSteps: 10,\n digestMaxChars: 6000,\n toolOutputMaxChars: 20000,\n};\n\nexport interface SubagentDeps {\n /**\n * Builds a fresh chat (own history, subagent system prompt, cheap model).\n * Receives a reasoning-delta callback to wire into the chat, so a\n * reasoning-capable subagent model streams its own live thinking too.\n */\n createChat: (onReasoning: (delta: string) => void) => ResearchChat;\n fs: IFileSystem;\n signal?: AbortSignal;\n /** Structured thinking/tool_call/tool_result events for the UI while the subagent works (caller tags with subagentId). */\n onProgress?: (progress: ResearchProgress) => void;\n}\n\nexport interface SubagentToolOutcome {\n success: boolean;\n output: string;\n truncated: boolean;\n}\n\nconst ALLOWED_TOOL_NAMES = new Set(subagentToolSpecs().map((t) => t.name));\n\nfunction refused(output: string): ToolOutcome {\n return { success: false, output, truncated: false };\n}\n\n/**\n * A subagent runs in the background with nobody watching it, so it must never\n * reach a code path that pauses for approval — a prompt attributed to no\n * visible action, or three prompts at once from three concurrent agents, is\n * worse than a refusal. This wrapper enforces that at the capability boundary\n * rather than trusting the agent's prompt: the auto-tier read-only commands\n * still work, and anything that would ask is refused with an actionable\n * message telling the agent to report the gap in its digest instead.\n *\n * Delegation is explicit rather than a spread — `fs` is a class instance, so\n * its methods live on the prototype and would not survive being copied.\n */\nfunction nonPromptingFs(fs: IFileSystem): IFileSystem {\n const withinWorkspace = (p: string | undefined): boolean =>\n resolveWithin(fs.getWorkspaceRoot(), p ?? '.').inside;\n\n const outsideRefusal = (p: string) => refused(\n `Path \"${p}\" is outside the workspace. Research agents are confined to the workspace root — note the gap in your digest and let the planner request it directly.`,\n );\n\n return {\n getWorkspaceRoot: () => fs.getWorkspaceRoot(),\n readFile: (p, opts) => (withinWorkspace(p) ? fs.readFile(p, opts) : Promise.resolve(outsideRefusal(p))),\n readFiles: (paths) => {\n const escaping = paths.find((p) => !withinWorkspace(p));\n return escaping ? Promise.resolve(outsideRefusal(escaping)) : fs.readFiles(paths);\n },\n glob: (pattern, opts) => (withinWorkspace(opts?.path) ? fs.glob(pattern, opts) : Promise.resolve(outsideRefusal(opts!.path!))),\n grep: (pattern, opts) => (withinWorkspace(opts?.path) ? fs.grep(pattern, opts) : Promise.resolve(outsideRefusal(opts!.path!))),\n findSymbol: (symbol, opts) => (withinWorkspace(opts?.path) ? fs.findSymbol(symbol, opts) : Promise.resolve(outsideRefusal(opts!.path!))),\n listDir: (p, depth) => (withinWorkspace(p) ? fs.listDir(p, depth) : Promise.resolve(outsideRefusal(p))),\n bash: async (command) => {\n // Same dialect the wrapped filesystem will execute under — a subagent\n // must not classify under different rules than the parent.\n const dialect = resolveResearchShell().dialect;\n const { tier, reason } = classifyCommand(command, { dialect });\n if (tier !== 'auto') {\n return refused(\n tier === 'refuse'\n ? `Command refused: ${reason}`\n : `\"${command}\" needs user approval, and research agents run in the background where nothing can be approved. Use the read-only research tools, and note in your digest that this command would answer the question.`,\n );\n }\n // An `auto` binary (cat, find, rg, …) is only auto because reading is\n // read-only — its arguments can still name a path outside the\n // workspace, and a subagent can never prompt to approve one.\n const escaping = pathLikeArgs(command, { dialect }).find((p) => !withinWorkspace(p));\n if (escaping) return outsideRefusal(escaping);\n return fs.bash(command);\n },\n };\n}\n\nasync function runLoop(prompt: string, deps: SubagentDeps): Promise<string> {\n if (deps.signal?.aborted) return '[research agent aborted before starting]';\n const fs = nonPromptingFs(deps.fs);\n const chat = deps.createChat((delta) => deps.onProgress?.({ type: 'thinking', text: delta }));\n let turn = await chat.sendMessage(prompt, deps.signal);\n\n for (let step = 0; turn.hasToolCalls && step < SUBAGENT_LIMITS.maxSteps; step++) {\n if (deps.signal?.aborted) return `[research agent aborted] Partial findings:\\n${turn.text}`;\n const results: ToolResult[] = [];\n for (const tc of turn.toolCalls) {\n // Anything outside the read-only allowlist (fetch, recursive spawn,\n // hallucinated write tools) is refused with a synthetic result — never\n // dispatched — so the API history stays valid and nothing executes.\n if (!ALLOWED_TOOL_NAMES.has(tc.name)) {\n const refusal = `Tool \"${tc.name}\" is not available. You are a read-only research subagent: your only tools are ${[...ALLOWED_TOOL_NAMES].join(', ')}. You cannot fetch URLs, spawn further agents, or modify files. If a specific URL or resource would have answered your question, name it in your digest so the planner can fetch it directly. Otherwise continue with the available tools, then reply with your digest.`;\n results.push({ name: tc.name, output: refusal, truncated: false, totalChars: refusal.length, id: tc.id });\n continue;\n }\n const args = { ...tc.args };\n if (tc.name === 'read_file' && !('maxBytes' in args) && !('limit' in args)) args.limit = 2000;\n const toolArgs = JSON.stringify(tc.args);\n deps.onProgress?.({ type: 'tool_call', tool: tc.name, toolArgs, toolCallId: tc.id });\n const res = await executeTool(tc.name, args, fs);\n const output = res.output.length > SUBAGENT_LIMITS.toolOutputMaxChars\n ? res.output.slice(0, SUBAGENT_LIMITS.toolOutputMaxChars) + `\\n[... truncated to ${SUBAGENT_LIMITS.toolOutputMaxChars} chars, total ${res.output.length}]`\n : res.output;\n const stepEntry: ResearchStep = {\n id: `subrs-${Date.now()}-${step}`,\n tool: tc.name as ResearchStep['tool'],\n args: toolArgs,\n result: output,\n success: res.success,\n outcome: classifyOutcome(res.success, res.output),\n toolCallId: tc.id,\n timestamp: new Date().toISOString(),\n };\n deps.onProgress?.({ type: 'tool_result', toolResult: output, step: stepEntry, toolCallId: tc.id });\n results.push({ name: tc.name, output, truncated: res.truncated || output.length < res.output.length, totalChars: res.output.length, id: tc.id });\n }\n turn = await chat.sendToolResults(results, deps.signal);\n }\n\n // Step budget exhausted while the model still wants tools: answer the\n // pending calls synthetically (history stays valid, nothing executes) and\n // push for the digest — mirrors the parent loop's wrap-up rounds.\n if (turn.hasToolCalls && !deps.signal?.aborted) {\n const notice = `Research budget exhausted (${SUBAGENT_LIMITS.maxSteps} tool rounds) — this call was NOT executed and no further tool calls will be. Reply now with your digest of everything learned so far.`;\n turn = await chat.sendToolResults(\n turn.toolCalls.map((tc) => ({ name: tc.name, output: notice, truncated: false, totalChars: notice.length, id: tc.id })),\n deps.signal,\n );\n }\n\n const digest = turn.text;\n return digest.length > SUBAGENT_LIMITS.digestMaxChars\n ? digest.slice(0, SUBAGENT_LIMITS.digestMaxChars) + `\\n[... digest truncated to ${SUBAGENT_LIMITS.digestMaxChars} chars, total ${digest.length}]`\n : digest;\n}\n\n/**\n * Run one research agent to completion. Never throws: any failure becomes a\n * failed tool result telling the planner to continue sequentially — a subagent\n * can never fail a plan or a turn.\n */\nexport async function runResearchAgent(prompt: string, deps: SubagentDeps): Promise<SubagentToolOutcome> {\n try {\n return { success: true, output: await runLoop(prompt, deps), truncated: false };\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err);\n return { success: false, output: `[research agent failed: ${reason}] Continue researching this area yourself with your own tools.`, truncated: false };\n }\n}\n\n/**\n * Bounded-concurrency helper for a turn that carries several spawn calls:\n * chunks of maxConcurrent run in parallel, later chunks wait — nothing is\n * refused. Results come back in input order.\n */\nexport async function mapWithConcurrency<T, R>(items: T[], limit: number, fn: (item: T, index: number) => Promise<R>): Promise<R[]> {\n const results: R[] = new Array(items.length);\n for (let start = 0; start < items.length; start += limit) {\n const chunk = items.slice(start, start + limit);\n await Promise.all(chunk.map(async (item, offset) => {\n results[start + offset] = await fn(item, start + offset);\n }));\n }\n return results;\n}\n","import {\n GoogleGenerativeAI,\n GenerativeModel,\n Part,\n} from '@google/generative-ai';\nimport { Task, DiscoveredModel, ResearchLogEntry, ResearchProgress, RunnerId } from '../models/Task';\nimport { IConfig } from '../interfaces/IConfig';\nimport { IFileSystem } from '../interfaces/IFileSystem';\nimport { IWebFetcher } from '../interfaces/IWebFetcher';\nimport {\n buildResearchPrompt,\n buildPlanWithResults,\n buildModifyPlanPrompt,\n buildResearchToolsPrompt,\n buildConversationSystemPrompt,\n} from './PlanPrompts';\nimport { generatePlanWithRepair } from './PlanRepair';\nimport type { RunnerModeInfo } from './ModeResolver';\nimport { ContextCollector } from './ContextCollector';\nimport { DEFAULT_PLANNER_MODES, type PlannerModes } from './plannerModes';\nimport { IAiService, ConversationRequest, ConversationTurn } from './AiService';\nimport { BaseAiService, ResearchChat, ResearchTurn, ToolResult, ConversationTurnContext } from './BaseAiService';\nimport { toGeminiToolDeclarations } from './researchTools';\nimport type { LegacyPlanState } from '../models/Task';\n\nconst TOOL_DEFINITIONS = toGeminiToolDeclarations();\n\ninterface GeminiResult {\n response: {\n candidates?: Array<{\n content?: { parts?: Array<Record<string, unknown>> };\n finishReason?: string;\n }>;\n usageMetadata?: { promptTokenCount?: number };\n };\n}\n\nfunction parseGeminiTurn(resultRaw: unknown): ResearchTurn {\n const result = resultRaw as GeminiResult;\n const candidate = result.response.candidates?.[0];\n if (!candidate) return { text: '', toolCalls: [], hasToolCalls: false };\n const parts = candidate.content?.parts || [];\n let text = '';\n let reasoning = '';\n const toolCalls: ResearchTurn['toolCalls'] = [];\n for (const part of parts) {\n if ('text' in part) {\n if ((part as { thought?: boolean }).thought) reasoning += (part as { text: string }).text;\n else text += (part as { text: string }).text;\n }\n if ('functionCall' in part) {\n const fc = part.functionCall as { name: string; args: Record<string, unknown> };\n toolCalls.push({ name: fc.name, args: fc.args });\n }\n }\n // Normalize Gemini's MAX_TOKENS to the OpenAI-style 'length' the\n // conversation loop keys its truncation recovery on.\n const finishReason = candidate.finishReason === 'MAX_TOKENS' ? 'length' : undefined;\n const promptTokens = result.response.usageMetadata?.promptTokenCount;\n return { text, toolCalls, hasToolCalls: toolCalls.length > 0, reasoning: reasoning || undefined, finishReason, promptTokens };\n}\n\nclass GeminiResearchChat implements ResearchChat {\n constructor(\n private chat: ReturnType<GenerativeModel['startChat']>,\n /** Gemini's chat API is non-streaming here, so reasoning/content are emitted once per turn. */\n private onReasoning?: (text: string) => void,\n private onContent?: (text: string) => void,\n ) {}\n\n async sendMessage(text: string, signal?: AbortSignal): Promise<ResearchTurn> {\n if (signal?.aborted) throw new DOMException('Aborted', 'AbortError');\n const result = await this.chat.sendMessage(text);\n return this.emit(parseGeminiTurn(result));\n }\n\n async sendToolResults(results: ToolResult[], signal?: AbortSignal): Promise<ResearchTurn> {\n if (signal?.aborted) throw new DOMException('Aborted', 'AbortError');\n const funcResponses = results.map(r => ({\n functionResponse: {\n name: r.name,\n response: { output: r.output, truncated: r.truncated, totalChars: r.totalChars },\n },\n }));\n const result = await this.chat.sendMessage(funcResponses);\n return this.emit(parseGeminiTurn(result));\n }\n\n private emit(turn: ResearchTurn): ResearchTurn {\n if (turn.reasoning) this.onReasoning?.(turn.reasoning);\n if (turn.text && !turn.hasToolCalls) this.onContent?.(turn.text);\n return turn;\n }\n}\n\nexport class GeminiService extends BaseAiService implements IAiService {\n private genAI: GoogleGenerativeAI | null = null;\n private model: GenerativeModel | null = null;\n\n constructor(config: IConfig) { super(config); }\n\n private init(): boolean {\n if (!this.config.apiKey) return false;\n if (!this.genAI) this.genAI = new GoogleGenerativeAI(this.config.apiKey);\n return true;\n }\n\n private getPlanningModel(): GenerativeModel {\n if (!this.genAI) this.init();\n if (!this.model || this.model.model !== this.config.planningModel) {\n this.model = this.genAI!.getGenerativeModel({\n model: this.config.planningModel,\n generationConfig: { temperature: 0.3, topP: 0.95, maxOutputTokens: 16384 },\n });\n }\n return this.model;\n }\n\n ensureInit(): void {\n if (!this.init()) throw new Error('Gemini API key not configured. Set GEMINI_API_KEY or ordewell.apiKey.');\n }\n\n reset(): void {\n this.activeAbort?.abort();\n this.genAI = null;\n this.model = null;\n this.conversation = null;\n }\n\n async startConversation(req: ConversationRequest): Promise<ConversationTurn> {\n this.ensureInit();\n const genModel = this.getPlanningModel();\n\n const contextStr = await BaseAiService.collectResearchContext(req.fs, req.runners);\n const systemPrompt = buildConversationSystemPrompt(\n req.goal,\n contextStr,\n req.modelsByRunner,\n req.runners,\n req.runnerModes,\n req.autonomousDefault ?? true,\n req.grillMeEnabled ?? false,\n req.prdEnabled ?? false,\n req.reviewEnabled ?? false,\n req.verificationEnabled ?? false,\n );\n\n // Gemini requires strict user/model alternation, so consecutive same-role\n // persisted turns are merged. A leading assistant turn is also absorbed by\n // the system-prompt user message never being followed by a model reply —\n // hence history seeding starts with a synthetic model ack when needed.\n const seededHistory: { role: 'user' | 'model'; parts: Part[] }[] = [\n { role: 'user', parts: [{ text: `${systemPrompt}\\n\\n${buildResearchToolsPrompt()}` }] },\n ];\n for (const m of req.priorHistory ?? []) {\n const role = m.role === 'assistant' ? 'model' : 'user';\n const last = seededHistory[seededHistory.length - 1];\n if (last.role === role) {\n last.parts.push({ text: `\\n\\n${m.content}` });\n } else {\n seededHistory.push({ role, parts: [{ text: m.content }] });\n }\n }\n // A seeded history must end on a model turn so the next sendMessage is a\n // user turn (only relevant on resume; the fresh path keeps its old shape).\n if ((req.priorHistory?.length ?? 0) > 0 && seededHistory[seededHistory.length - 1].role === 'user') {\n seededHistory.push({ role: 'model', parts: [{ text: 'Understood.' }] });\n }\n\n const chat = genModel.startChat({\n history: seededHistory,\n tools: [{ functionDeclarations: TOOL_DEFINITIONS }],\n generationConfig: { temperature: 0.3, topP: 0.95, maxOutputTokens: 16384 },\n });\n\n let currentProgress = req.onProgress;\n const researchChat = new GeminiResearchChat(\n chat,\n (text) => currentProgress({ type: 'thinking', text }),\n (text) => currentProgress({ type: 'plan_token', planToken: text }),\n );\n\n const ctx: ConversationTurnContext = {\n chat: researchChat,\n fs: req.fs,\n runners: req.runners,\n runnerModes: req.runnerModes,\n autonomousDefault: req.autonomousDefault,\n fetcher: req.fetcher,\n prdEnabled: req.prdEnabled ?? false,\n };\n\n this.conversation = { ctx, setProgress: (onProgress) => { currentProgress = onProgress; } };\n\n const combinedSignal = this.startAbortScope(req.signal);\n try {\n const result = await this.runConversationTurn(ctx, req.initialMessage ?? req.goal, req.onProgress, combinedSignal);\n if (result.kind === 'plan') this.conversation = null;\n return result;\n } finally {\n this.stopAbortScope();\n }\n }\n\n\n // --- BaseAiService abstract methods ---\n\n protected async streamPlanText(\n prompt: string,\n repairHint: string | undefined,\n onToken: (token: string) => void,\n onReasoning?: (token: string) => void,\n _signal?: AbortSignal,\n ): Promise<string> {\n const model = this.getPlanningModel();\n const finalParts: Part[] = repairHint\n ? [{ text: prompt }, { text: `\\n\\n${repairHint}` }]\n : [{ text: prompt }];\n const result = await model.generateContentStream({\n contents: [{ role: 'user', parts: finalParts }],\n });\n return this.consumePlanStream(result, onToken, onReasoning);\n }\n\n /**\n * Drain a Gemini content stream, routing \"thought\" parts to the reasoning channel\n * and answer text to the parser. `chunk.text()` throws when a chunk is reasoning-only,\n * so parts are inspected directly.\n */\n private async consumePlanStream(\n result: Awaited<ReturnType<GenerativeModel['generateContentStream']>>,\n onToken: (token: string) => void,\n onReasoning?: (token: string) => void,\n ): Promise<string> {\n let fullResponse = '';\n for await (const chunk of result.stream) {\n const parts = chunk.candidates?.[0]?.content?.parts ?? [];\n for (const part of parts) {\n const text = (part as { text?: string }).text;\n if (!text) continue;\n if ((part as { thought?: boolean }).thought) onReasoning?.(text);\n else { fullResponse += text; onToken(text); }\n }\n }\n return fullResponse;\n }\n\n /** Gemini-specific stream over raw Parts for generatePlanDirect / modifyPlan. */\n private async streamPlanTextWithParts(parts: Part[], repairHint: string | undefined, onToken: (token: string) => void): Promise<string> {\n const model = this.getPlanningModel();\n const finalParts: Part[] = repairHint ? [...parts, { text: `\\n\\n${repairHint}` }] : parts;\n const result = await model.generateContentStream({\n contents: [{ role: 'user', parts: finalParts }],\n });\n return this.consumePlanStream(result, onToken);\n }\n\n // --- IAiService implementation ---\n\n async researchAndPlan(\n userDescription: string,\n runners: RunnerId[],\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n fs: IFileSystem,\n onProgress: (progress: ResearchProgress) => void,\n fetcher?: IWebFetcher,\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n modes: PlannerModes = DEFAULT_PLANNER_MODES,\n signal?: AbortSignal,\n ): Promise<{ tasks: Task[]; researchLog: ResearchLogEntry[]; researchResults: string }> {\n this.ensureInit();\n const { autonomousDefault } = modes;\n const genModel = this.getPlanningModel();\n\n const contextStr = await BaseAiService.collectResearchContext(fs, runners);\n const systemPrompt = buildResearchPrompt(userDescription, contextStr, modelsByRunner, runners, runnerModes, modes);\n const firstMessage = `${buildResearchToolsPrompt()}\\n\\nExplore the workspace to understand the codebase, then generate the plan.`;\n\n const chat = genModel.startChat({\n history: [{ role: 'user', parts: [{ text: systemPrompt }] }],\n tools: [{ functionDeclarations: TOOL_DEFINITIONS }],\n generationConfig: { temperature: 0.3, topP: 0.95, maxOutputTokens: 16384 },\n });\n\n const researchChat: ResearchChat = new GeminiResearchChat(chat);\n\n const result = await this.runResearchLoop(researchChat, firstMessage, fs, onProgress, runners, undefined, fetcher, userDescription, runnerModes, autonomousDefault, signal);\n if (result.tasks) return { tasks: result.tasks, researchLog: result.researchLog, researchResults: result.researchResults };\n const fallback = await this.generatePlanFallback(userDescription, contextStr, result.researchResults, modelsByRunner, runners, onProgress, result.researchLog, runnerModes, autonomousDefault, signal, modes);\n return { tasks: fallback.tasks, researchLog: fallback.researchLog, researchResults: result.researchResults };\n }\n\n async generatePlanDirect(\n userDescription: string,\n runners: RunnerId[] = ['claude-code'],\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>> = {},\n onToken?: (token: string) => void,\n fs?: IFileSystem,\n _fetcher?: IWebFetcher,\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n modes: PlannerModes = DEFAULT_PLANNER_MODES,\n _signal?: AbortSignal,\n ): Promise<Task[]> {\n this.ensureInit();\n const { autonomousDefault } = modes;\n let ctx = '';\n if (fs) {\n const collected = await new ContextCollector(fs).collect(runners[0] ?? 'claude-code');\n if (collected.aiflowContext) ctx = `\\n<aiflow_context>\\n${collected.aiflowContext}\\n</aiflow_context>\\n`;\n }\n const prompt = buildPlanWithResults(userDescription, ctx, '', modelsByRunner, runners, runnerModes, modes);\n return generatePlanWithRepair((repairHint) =>\n this.streamPlanTextWithParts([{ text: prompt }], repairHint, (token) => onToken?.(token)),\n runners,\n 2,\n runnerModes,\n autonomousDefault,\n );\n }\n\n async modifyPlan(\n existingPlan: LegacyPlanState,\n userRequest: string,\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n onProgress?: (progress: ResearchProgress) => void,\n fs?: IFileSystem,\n _fetcher?: IWebFetcher,\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n modes: PlannerModes = DEFAULT_PLANNER_MODES,\n _signal?: AbortSignal,\n ): Promise<{ tasks: Task[] }> {\n this.ensureInit();\n const { autonomousDefault } = modes;\n let aiflowContext: string | undefined;\n if (fs) {\n const collected = await new ContextCollector(fs).collect(existingPlan.runners[0] ?? 'claude-code');\n if (collected.aiflowContext) aiflowContext = collected.aiflowContext;\n }\n const prompt = buildModifyPlanPrompt(existingPlan, userRequest, modelsByRunner, aiflowContext, runnerModes, autonomousDefault);\n try {\n const tasks = await generatePlanWithRepair((repairHint) =>\n this.streamPlanTextWithParts([{ text: prompt }], repairHint, (token) =>\n onProgress?.({ type: 'plan_token', planToken: token })\n ),\n existingPlan.runners,\n 2,\n runnerModes,\n autonomousDefault,\n );\n return { tasks };\n } catch (err) {\n throw new Error(`Plan modification failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n}\n","import OpenAI from 'openai';\nimport {\n Task,\n DiscoveredModel,\n ResearchLogEntry,\n ResearchProgress,\n RunnerId,\n} from '../models/Task';\nimport { IConfig } from '../interfaces/IConfig';\nimport { IFileSystem } from '../interfaces/IFileSystem';\nimport { IWebFetcher } from '../interfaces/IWebFetcher';\nimport {\n buildResearchPrompt,\n buildPlanWithResults,\n buildModifyPlanPrompt,\n buildResearchToolsPrompt,\n buildConversationSystemPrompt,\n buildSubagentSystemPrompt,\n} from './PlanPrompts';\nimport { generatePlanWithRepair } from './PlanRepair';\nimport type { RunnerModeInfo } from './ModeResolver';\nimport { ContextCollector } from './ContextCollector';\nimport { DEFAULT_PLANNER_MODES, type PlannerModes } from './plannerModes';\nimport { IAiService, ConversationRequest, ConversationTurn } from './AiService';\nimport { BaseAiService, ResearchChat, ResearchTurn, ToolResult, ConversationTurnContext } from './BaseAiService';\nimport { toOpenAiTools, toOpenAiSubagentTools } from './researchTools';\nimport { stripModelPrefix } from './ProviderRegistry';\nimport { compactToolMessages, type CompactableMessage } from './contextCompaction';\nimport type { LegacyPlanState } from '../models/Task';\n\nclass OpenAiResearchChat implements ResearchChat {\n constructor(\n private messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[],\n private client: OpenAI,\n private model: string,\n private tools: OpenAI.Chat.Completions.ChatCompletionTool[],\n /** Live reasoning deltas during a turn, so the UI isn't frozen while a reasoning\n * model thinks for tens of seconds before it emits any tool call or content. */\n private onReasoning?: (delta: string) => void,\n /** Live answer-content deltas, so planner messages stream into the chat as they\n * are produced instead of appearing all at once when the turn completes. */\n private onContent?: (delta: string) => void,\n ) {}\n\n async sendMessage(text: string, signal?: AbortSignal): Promise<ResearchTurn> {\n this.messages.push({ role: 'user', content: text });\n return this.callApi(signal);\n }\n\n async sendToolResults(results: ToolResult[], signal?: AbortSignal): Promise<ResearchTurn> {\n for (const r of results) {\n this.messages.push({ role: 'tool', tool_call_id: r.id!, content: r.output });\n }\n return this.callApi(signal);\n }\n\n compactHistory(): number {\n return compactToolMessages(this.messages as CompactableMessage[]);\n }\n\n private async callApi(signal?: AbortSignal): Promise<ResearchTurn> {\n // Stream the turn so reasoning surfaces live. A non-streamed completion blocks\n // for the model's entire think time with no signal — the \"0 steps / nothing for\n // a long time\" symptom on reasoning models. Tool-call deltas are reassembled by\n // index into the final message the loop acts on.\n const stream = await this.client.chat.completions.create({\n model: this.model,\n messages: this.messages,\n tools: this.tools,\n tool_choice: 'auto',\n stream: true,\n // Explicit cap, matching streamPlanText: with max_tokens unset, some\n // OpenRouter providers default far lower and silently cut long plan\n // emissions mid-JSON.\n max_tokens: 32000,\n // Exact prompt-token usage arrives in the final chunk — the signal\n // proactive history compaction keys on.\n stream_options: { include_usage: true },\n }, signal ? { signal } : undefined);\n\n let content = '';\n let reasoning = '';\n let finishReason: string | undefined;\n let promptTokens: number | undefined;\n const toolAcc = new Map<number, { id: string; name: string; args: string }>();\n\n for await (const chunk of stream) {\n if (chunk.usage) promptTokens = chunk.usage.prompt_tokens;\n const fr = chunk.choices[0]?.finish_reason;\n if (fr) finishReason = fr;\n const delta = chunk.choices[0]?.delta as\n | { content?: string; reasoning?: string; tool_calls?: Array<{ index: number; id?: string; function?: { name?: string; arguments?: string } }> }\n | undefined;\n if (!delta) continue;\n if (delta.reasoning) { reasoning += delta.reasoning; this.onReasoning?.(delta.reasoning); }\n if (delta.content) { content += delta.content; this.onContent?.(delta.content); }\n for (const tc of delta.tool_calls ?? []) {\n const acc = toolAcc.get(tc.index) ?? { id: '', name: '', args: '' };\n if (tc.id) acc.id = tc.id;\n if (tc.function?.name) acc.name = tc.function.name;\n if (tc.function?.arguments) acc.args += tc.function.arguments;\n toolAcc.set(tc.index, acc);\n }\n }\n\n const accepted = [...toolAcc.entries()].sort((a, b) => a[0] - b[0]).map(([, v]) => v).filter((v) => v.name);\n\n // Rebuild the assistant message so subsequent turns (which reference tool_call_id)\n // stay consistent with what we executed.\n const assistantMsg: OpenAI.Chat.Completions.ChatCompletionMessageParam = accepted.length > 0\n ? { role: 'assistant', content: content || null, tool_calls: accepted.map((v) => ({ id: v.id, type: 'function', function: { name: v.name, arguments: v.args } })) }\n : { role: 'assistant', content };\n this.messages.push(assistantMsg);\n\n const toolCalls: ResearchTurn['toolCalls'] = accepted.map((v) => {\n let args: Record<string, unknown> = {};\n try { args = JSON.parse(v.args); } catch { /* empty */ }\n return { name: v.name, args, id: v.id };\n });\n return { text: content, toolCalls, hasToolCalls: toolCalls.length > 0, reasoning: reasoning || undefined, finishReason, promptTokens };\n }\n}\n\nexport class OpenAiService extends BaseAiService implements IAiService {\n private client: OpenAI | null = null;\n\n constructor(config: IConfig) { super(config); }\n\n private getClient(): OpenAI {\n if (!this.client) {\n const baseUrl = this.config.getProviderBaseUrl(this.config.aiProvider);\n const apiKey = this.config.getProviderApiKey(this.config.aiProvider);\n this.client = new OpenAI({ baseURL: baseUrl, apiKey });\n }\n return this.client;\n }\n\n ensureInit(): void {\n if (this.config.aiProvider === 'openai_compatible' && !this.config.openaiCompatibleBaseUrl) {\n throw new Error('OpenAI-compatible base URL not configured. Set OPENAI_COMPATIBLE_BASE_URL.');\n }\n const apiKey = this.config.getProviderApiKey(this.config.aiProvider);\n if (!apiKey) {\n throw new Error('OpenAI API key not configured. Set OPENAI_API_KEY.');\n }\n }\n\n private requireModel(field: string, value: string | undefined | null): string {\n // Picker/stored ids carry a provider qualifier (e.g. `openai:gpt-4o`,\n // `openai_compat:llama3`); the serving API only knows the bare model name.\n const id = stripModelPrefix((value ?? '').trim(), this.config.aiProvider);\n if (!id) throw new Error(`OpenAI model not configured: \"${field}\" is empty.`);\n return id;\n }\n\n reset(): void { this.activeAbort?.abort(); this.client = null; this.conversation = null; }\n\n // --- BaseAiService abstract methods ---\n\n protected async streamPlanText(\n prompt: string,\n repairHint: string | undefined,\n onToken: (token: string) => void,\n onReasoning?: (token: string) => void,\n signal?: AbortSignal,\n ): Promise<string> {\n const client = this.getClient();\n const messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[] = [{ role: 'user', content: prompt }];\n if (repairHint) messages.push({ role: 'user', content: repairHint });\n const stream = await client.chat.completions.create({\n model: this.requireModel('orchestratorModel', this.config.orchestratorModel),\n messages,\n stream: true,\n max_tokens: 32000,\n }, { signal });\n let fullResponse = '';\n for await (const chunk of stream) {\n const delta = chunk.choices[0]?.delta as { content?: string; reasoning?: string } | undefined;\n // Only content contributes to the text handed to the parser; reasoning is routed\n // to the thinking trace so chain-of-thought can never pollute the JSON.\n const reasoning = delta?.reasoning;\n if (reasoning) onReasoning?.(reasoning);\n const token = delta?.content;\n if (token) { fullResponse += token; onToken(token); }\n }\n return fullResponse;\n }\n\n /** A research subagent: fresh history, digest contract, cheap model, read-only tools. */\n protected createSubagentChat(onReasoning?: (delta: string) => void): ResearchChat | null {\n const client = this.getClient();\n const messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[] = [\n { role: 'system', content: buildSubagentSystemPrompt() },\n ];\n return new OpenAiResearchChat(\n messages,\n client,\n this.requireModel('researchSubagentModel', this.config.researchSubagentModel),\n toOpenAiSubagentTools(),\n onReasoning,\n );\n }\n\n // --- Conversation loop (ADR-0002) ---\n\n async startConversation(req: ConversationRequest): Promise<ConversationTurn> {\n this.ensureInit();\n const client = this.getClient();\n this.researchSubagentsEnabled = req.researchSubagentsEnabled ?? false;\n\n const contextStr = await BaseAiService.collectResearchContext(req.fs, req.runners);\n const systemPrompt = buildConversationSystemPrompt(\n req.goal,\n contextStr,\n req.modelsByRunner,\n req.runners,\n req.runnerModes,\n req.autonomousDefault ?? true,\n req.grillMeEnabled ?? false,\n req.prdEnabled ?? false,\n req.reviewEnabled ?? false,\n req.verificationEnabled ?? false,\n );\n\n const userText = req.goal;\n\n const messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[] = [\n { role: 'system', content: `${systemPrompt}\\n\\n${buildResearchToolsPrompt(this.researchSubagentsEnabled)}` },\n ];\n for (const m of req.priorHistory ?? []) {\n messages.push({ role: m.role, content: m.content });\n }\n\n let currentProgress = req.onProgress;\n const chat = new OpenAiResearchChat(\n messages,\n client,\n this.requireModel('orchestratorModel', this.config.orchestratorModel),\n toOpenAiTools(this.researchSubagentsEnabled),\n (delta) => currentProgress({ type: 'thinking', text: delta }),\n (delta) => currentProgress({ type: 'plan_token', planToken: delta }),\n );\n\n const ctx: ConversationTurnContext = {\n chat,\n fs: req.fs,\n runners: req.runners,\n runnerModes: req.runnerModes,\n autonomousDefault: req.autonomousDefault,\n fetcher: req.fetcher,\n prdEnabled: req.prdEnabled ?? false,\n };\n\n this.conversation = {\n ctx,\n setProgress: (onProgress) => { currentProgress = onProgress; },\n };\n\n const combinedSignal = this.startAbortScope(req.signal);\n try {\n const result = await this.runConversationTurn(ctx, req.initialMessage ?? userText, req.onProgress, combinedSignal);\n if (result.kind === 'plan') this.conversation = null;\n return result;\n } finally {\n this.stopAbortScope();\n }\n }\n\n // --- IAiService implementation ---\n\n async researchAndPlan(\n userDescription: string,\n runners: RunnerId[],\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n fs: IFileSystem,\n onProgress: (progress: ResearchProgress) => void,\n fetcher?: IWebFetcher,\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n modes: PlannerModes = DEFAULT_PLANNER_MODES,\n signal?: AbortSignal,\n ): Promise<{ tasks: Task[]; researchLog: ResearchLogEntry[]; researchResults: string }> {\n this.ensureInit();\n const client = this.getClient();\n const { autonomousDefault, researchSubagents: researchSubagentsEnabled } = modes;\n this.researchSubagentsEnabled = researchSubagentsEnabled;\n\n const contextStr = await BaseAiService.collectResearchContext(fs, runners);\n const systemPrompt = buildResearchPrompt(userDescription, contextStr, modelsByRunner, runners, runnerModes, modes);\n\n const userText = `User goal: ${userDescription}`;\n const firstMessage = `${buildResearchToolsPrompt(researchSubagentsEnabled)}\\n\\nExplore the workspace to understand the codebase, then generate the plan.\\n\\n${userText}`;\n\n const messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[] = [\n { role: 'system', content: systemPrompt },\n ];\n\n const researchChat: ResearchChat = new OpenAiResearchChat(\n messages,\n client,\n this.requireModel('orchestratorModel', this.config.orchestratorModel),\n toOpenAiTools(researchSubagentsEnabled),\n (delta) => onProgress({ type: 'thinking', text: delta }),\n );\n\n const result = await this.runResearchLoop(researchChat, firstMessage, fs, onProgress, runners, undefined, fetcher, userDescription, runnerModes, autonomousDefault, signal);\n if (result.tasks) return { tasks: result.tasks, researchLog: result.researchLog, researchResults: result.researchResults };\n const fallback = await this.generatePlanFallback(userDescription, contextStr, result.researchResults, modelsByRunner, runners, onProgress, result.researchLog, runnerModes, autonomousDefault, signal, modes);\n return { tasks: fallback.tasks, researchLog: fallback.researchLog, researchResults: result.researchResults };\n }\n\n async generatePlanDirect(\n userDescription: string,\n runners: RunnerId[] = ['claude-code'],\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>> = {},\n onToken?: (token: string) => void,\n fs?: IFileSystem,\n _fetcher?: IWebFetcher,\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n modes: PlannerModes = DEFAULT_PLANNER_MODES,\n signal?: AbortSignal,\n ): Promise<Task[]> {\n this.ensureInit();\n const { autonomousDefault } = modes;\n let ctx = '';\n if (fs) {\n const collected = await new ContextCollector(fs).collect(runners[0] ?? 'claude-code');\n if (collected.aiflowContext) ctx = `\\n<aiflow_context>\\n${collected.aiflowContext}\\n</aiflow_context>\\n`;\n }\n const prompt = buildPlanWithResults(userDescription, ctx, '', modelsByRunner, runners, runnerModes, modes);\n return generatePlanWithRepair((repairHint) =>\n this.streamPlanText(prompt, repairHint, (token) => onToken?.(token), undefined, signal),\n runners,\n 2,\n runnerModes,\n autonomousDefault,\n );\n }\n\n async modifyPlan(\n existingPlan: LegacyPlanState,\n userRequest: string,\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n onProgress?: (progress: ResearchProgress) => void,\n fs?: IFileSystem,\n _fetcher?: IWebFetcher,\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n modes: PlannerModes = DEFAULT_PLANNER_MODES,\n signal?: AbortSignal,\n ): Promise<{ tasks: Task[] }> {\n this.ensureInit();\n const { autonomousDefault } = modes;\n let aiflowContext: string | undefined;\n if (fs) {\n const collected = await new ContextCollector(fs).collect(existingPlan.runners[0] ?? 'claude-code');\n if (collected.aiflowContext) aiflowContext = collected.aiflowContext;\n }\n const prompt = buildModifyPlanPrompt(existingPlan, userRequest, modelsByRunner, aiflowContext, runnerModes, autonomousDefault);\n try {\n const tasks = await generatePlanWithRepair((repairHint) =>\n this.streamPlanText(prompt, repairHint, (token) => onProgress?.({ type: 'plan_token', planToken: token }), undefined, signal),\n existingPlan.runners,\n 2,\n runnerModes,\n autonomousDefault,\n );\n return { tasks };\n } catch (err) {\n throw new Error(`Plan modification failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n}\n","import type { Task } from '../models/Task';\n\nconst MAX_TAIL_CHARS = 500;\nconst DEFAULT_PLAN_MAP_MAX_ENTRIES = 30;\nconst PLAN_MAP_MIN_TASKS = 3;\n\nexport interface PriorOutput {\n order: number;\n title: string;\n reviewReason: string;\n logTail: string;\n}\n\nexport function summarizeOutput(reviewReason: string | undefined, output: string): { reviewReason: string; logTail: string; capturedAt: string } {\n return {\n reviewReason: (reviewReason ?? '').trim(),\n logTail: (output ?? '').slice(-MAX_TAIL_CHARS).trim(),\n capturedAt: new Date().toISOString(),\n };\n}\n\nexport function collectDirectDependencyOutputs(task: Task, allTasks: Task[]): PriorOutput[] {\n const byId = new Map(allTasks.map((t) => [t.id, t]));\n const out: PriorOutput[] = [];\n for (const depId of task.dependencies ?? []) {\n const dep = byId.get(depId);\n if (!dep || !dep.outputSummary) continue;\n out.push({\n order: dep.order,\n title: dep.title,\n reviewReason: dep.outputSummary.reviewReason,\n logTail: dep.outputSummary.logTail,\n });\n }\n return out;\n}\n\n/**\n * Break marker tokens carried in a predecessor's captured output. Interactive\n * runners echo the prompt they are given, and the watcher scans that terminal\n * output — a quoted marker would settle this task on the previous one's\n * evidence. Hyphenated rather than spaced: the scanner also reads a\n * whitespace-flattened view of the terminal, which would rejoin a space.\n */\nfunction defuseMarkers(text: string): string {\n return text.replace(/<<<ORDEWELL_/g, '<<<ORDEWELL-');\n}\n\nexport function renderPriorOutputs(outputs: PriorOutput[]): string {\n if (outputs.length === 0) return '';\n const blocks = outputs\n .sort((a, b) => a.order - b.order)\n .map((o) => {\n const tail = o.logTail\n ? defuseMarkers(o.logTail).split('\\n').map((l) => ' ' + l).join('\\n')\n : ' (no output captured)';\n const reason = defuseMarkers(o.reviewReason) || '(no review note)';\n return `### Task ${o.order}: ${o.title}\\n- Review: ${reason}\\n- Tail:\\n${tail}`;\n });\n return `## Prior task outputs\\n\\n${blocks.join('\\n\\n')}`;\n}\n\nexport function augmentPromptWithPriorOutputs(task: Task, allTasks: Task[]): string {\n const basePrompt = task.prompt ?? '';\n const outputs = collectDirectDependencyOutputs(task, allTasks);\n if (outputs.length === 0) return basePrompt;\n return `${renderPriorOutputs(outputs)}\\n\\n${basePrompt}`;\n}\n\nfunction planMapStatus(task: Task, isCurrent: boolean): string {\n if (isCurrent) return 'NOW';\n if (task.status === 'completed') return 'done';\n if (task.status === 'failed') return 'failed';\n if (task.status === 'blocked') return 'blocked';\n if (task.status === 'in_progress') return 'running';\n if (task.type === 'user') return 'user';\n return 'next';\n}\n\nfunction pickWindow(sorted: Task[], currentIdx: number, max: number): { window: Task[]; omitted: number } {\n if (sorted.length <= max) return { window: sorted, omitted: 0 };\n if (currentIdx < 0) return { window: sorted.slice(0, max), omitted: sorted.length - max };\n const lookBack = Math.min(currentIdx, Math.floor(max / 3));\n let start = currentIdx - lookBack;\n if (start + max > sorted.length) start = sorted.length - max;\n if (start < 0) start = 0;\n const window = sorted.slice(start, start + max);\n return { window, omitted: sorted.length - window.length };\n}\n\nexport function renderPlanMap(allTasks: Task[], currentTaskId: string, opts?: { maxEntries?: number }): string {\n if (allTasks.length < PLAN_MAP_MIN_TASKS) return '';\n\n const sorted = [...allTasks].sort((a, b) => a.order - b.order);\n const max = opts?.maxEntries ?? DEFAULT_PLAN_MAP_MAX_ENTRIES;\n const currentIdx = sorted.findIndex((t) => t.id === currentTaskId);\n const { window, omitted } = pickWindow(sorted, currentIdx, max);\n\n const currentTask = sorted.find((t) => t.id === currentTaskId);\n\n const widthOrder = Math.max(2, String(sorted[sorted.length - 1]?.order ?? sorted.length).length);\n const lines = window.map((t) => {\n const isCurrent = t.id === currentTaskId;\n const tag = planMapStatus(t, isCurrent);\n const order = String(t.order).padStart(widthOrder, ' ');\n const arrow = isCurrent ? ' ← you are here' : '';\n const runner = t.assignedRunner ? ` (${t.assignedRunner})` : '';\n return `${order}. [${tag.padEnd(7, ' ')}] ${t.title}${runner}${arrow}`;\n });\n\n const footer = omitted > 0 ? `\\n(${omitted} task${omitted === 1 ? '' : 's'} omitted from this view)` : '';\n const runnerNote = currentTask?.assignedRunner\n ? `\\nYou are running as: ${currentTask.assignedRunner}`\n : '';\n\n return [\n '## Plan map',\n '',\n 'This is for context only — do ONLY the task marked `← you are here`. Future tasks will handle their own scope; do not preempt them.',\n '',\n lines.join('\\n') + footer + runnerNote,\n ].join('\\n');\n}\n\nexport interface ComposeOptions {\n planMapEnabled?: boolean;\n planMapMaxEntries?: number;\n tddEnabled?: boolean;\n}\n\nfunction renderCompletionMarker(task: Task): string {\n // The marker is given in two halves so the assembled token never appears in\n // this prompt. Interactive TUIs echo the prompt into the terminal, and the\n // watcher scans terminal output for the token — a literal marker here would\n // complete the task the moment the session starts.\n return `\\n\\nWhen you have fully completed this task, print one final line containing only the completion marker. Build it by writing \\`<<<ORDEWELL_\\` immediately followed by \\`DONE_${task.completionMarker}>>>\\` — joined into a single unbroken token, with no space, quote, or any other character between the two parts.`;\n}\n\nfunction renderTddInstruction(): string {\n return [\n '## Implementation workflow (TDD)',\n '',\n 'Work test-first in vertical slices at the seams your task prompt names. A seam is the public boundary you test at — if the prompt names none, identify the highest public interface and test there, never against internals.',\n '',\n '1. RED: Write ONE failing test for the next behavior, through the public interface',\n '2. GREEN: Write minimal production code to make that test pass',\n '',\n 'Rules:',\n '- One test per RED-GREEN cycle — do not write all tests first',\n '- Expected values must come from an independent source of truth (spec, worked example, known-good literal), never recomputed the way the code computes them',\n '- Prefer integration-style tests over unit tests with mocks; tests should survive internal refactors',\n '- Use the project\\'s existing test framework and patterns',\n '- While iterating, run the typechecker and the single test file you are touching frequently; run the full test suite once at the end of the task',\n '- Refactoring is not part of the red-green cycle: only once all tests are green, tidy what this task touched, keeping tests green',\n ].join('\\n');\n}\n\nfunction renderCheckpointInstruction(): string {\n return [\n '## Human-in-the-loop checkpoints',\n '',\n 'When you reach a decision point that requires human judgment — before destructive',\n 'operations, after major design decisions, or when multiple viable paths exist — pause',\n 'and request input:',\n '',\n // Two halves, for the same reason as the completion marker above: the\n // watcher scans terminal output for this token, and interactive runners echo\n // the prompt — a literal marker here checkpointed the task (dropping it out\n // of `in_progress`) the moment the session started.\n '1. Print one line holding only the checkpoint marker. Build it by writing `<<<ORDEWELL_` immediately followed by `CHECKPOINT:` — no space, quote, or any other character between those two parts — then a brief summary of what you are about to do and why human input is needed, closed with `>>>`',\n '2. Wait for the human to respond (they will send ORDEWELL_CONTINUE or ORDEWELL_REJECT)',\n '3. On CONTINUE: proceed with the action you described',\n '4. On REJECT: adjust your approach and re-emit a checkpoint if needed',\n ].join('\\n');\n}\n\nfunction isHitlTask(task: Task): boolean {\n return task.autonomy === 'HITL' || task.sliceType === 'HITL';\n}\n\nexport function composeAugmentedPrompt(task: Task, allTasks: Task[], opts?: ComposeOptions): string {\n const basePrompt = task.prompt ?? '';\n const blocks: string[] = [];\n\n if (opts?.planMapEnabled !== false) {\n const map = renderPlanMap(allTasks, task.id, { maxEntries: opts?.planMapMaxEntries });\n if (map) blocks.push(map);\n }\n\n const outputs = collectDirectDependencyOutputs(task, allTasks);\n if (outputs.length > 0) blocks.push(renderPriorOutputs(outputs));\n\n if (opts?.tddEnabled) {\n blocks.push(renderTddInstruction());\n }\n\n if (isHitlTask(task)) {\n blocks.push(renderCheckpointInstruction());\n }\n\n const marker = renderCompletionMarker(task);\n\n if (blocks.length === 0) return basePrompt + marker;\n return `${blocks.join('\\n\\n')}\\n\\n${basePrompt}${marker}`;\n}\n","import type { Task, Verdict, VerificationCheck } from '../models/Task';\nimport type { ITerminalSession } from '../interfaces/ITerminalRunner';\n\nexport type VerdictListener = (taskId: string, verdict: Verdict, output: string) => void;\nexport type CheckpointListener = (taskId: string, summary: string) => void;\n\nconst CHECKPOINT_RE = /<<<ORDEWELL_CHECKPOINT:\\s*(.*?)>>>/gs;\n\n// eslint-disable-next-line no-control-regex\nconst ANSI_OR_CTRL_RE = /\\x1b\\[[0-9;?]*[A-Za-z]|\\x1b\\][^\\x07\\x1b]*(?:\\x07|\\x1b\\\\)?|\\x1b[()][AB012]|\\x1b[=>]|[\\x00-\\x08\\x0b-\\x1f\\x7f]/g;\n\n/**\n * Collapse terminal rendering out of raw PTY output: strip ANSI/OSC escape\n * sequences, box-drawing gutter characters, and ALL whitespace. Interactive\n * TUIs soft-wrap long lines, so a completion marker arrives split across\n * lines with escapes interleaved — a raw `includes()` never matches it.\n * Markers contain no whitespace, so this flattened view is safe to scan.\n */\nexport function flattenTerminalOutput(raw: string): string {\n return raw\n .replace(ANSI_OR_CTRL_RE, '')\n .replace(/[─-▟]/g, '') // box-drawing + block elements (TUI borders/gutters)\n .replace(/\\s+/g, '');\n}\n\n/**\n * Reconstruct the small terminal screen represented by a PTY output tail.\n *\n * Full-screen TUIs do not emit answer text as one chronological stream. They\n * paint fragments at absolute cursor positions and repaint unrelated widgets\n * between those writes. OpenCode, for example, may emit:\n *\n * row 9: \"<<<ORDEW\"\n * row 23: spinner repaint\n * row 9: \"ELL_DONE_...\"\n *\n * Flattening that byte stream inserts the spinner inside the marker. Rendering\n * the cursor-positioned writes first recovers the token the user actually sees.\n * This intentionally implements only the common cursor/erase subset used by\n * coding-agent TUIs; the chronological scanner remains the fallback for plain\n * output and soft-wrapped lines.\n */\nexport function renderTerminalOutput(raw: string): string {\n const rows = new Map<number, string[]>();\n let row = 1;\n let col = 1;\n let savedRow = 1;\n let savedCol = 1;\n\n const cells = (r: number): string[] => {\n let line = rows.get(r);\n if (!line) {\n line = [];\n rows.set(r, line);\n }\n return line;\n };\n const firstParam = (params: number[], fallback = 1): number => params[0] || fallback;\n const eraseLine = (mode: number): void => {\n const line = cells(row);\n if (mode === 2) {\n rows.set(row, []);\n } else if (mode === 1) {\n for (let c = 0; c < col; c++) line[c] = ' ';\n } else {\n line.length = Math.max(0, col - 1);\n }\n };\n\n for (let i = 0; i < raw.length;) {\n const ch = raw[i];\n if (ch === '\\x1b') {\n const kind = raw[i + 1];\n if (kind === '[') {\n let end = i + 2;\n while (end < raw.length) {\n const code = raw.charCodeAt(end);\n if (code >= 0x40 && code <= 0x7e) break;\n end++;\n }\n if (end >= raw.length) break;\n const final = raw[end];\n const body = raw.slice(i + 2, end).replace(/^[?<>=!]+/, '');\n const params = body.split(';').map((p) => Number.parseInt(p, 10) || 0);\n switch (final) {\n case 'H':\n case 'f':\n row = params[0] || 1;\n col = params[1] || 1;\n break;\n case 'G': col = firstParam(params); break;\n case 'd': row = firstParam(params); break;\n case 'A': row = Math.max(1, row - firstParam(params)); break;\n case 'B': row += firstParam(params); break;\n case 'C': col += firstParam(params); break;\n case 'D': col = Math.max(1, col - firstParam(params)); break;\n case 'E': row += firstParam(params); col = 1; break;\n case 'F': row = Math.max(1, row - firstParam(params)); col = 1; break;\n case 's': savedRow = row; savedCol = col; break;\n case 'u': row = savedRow; col = savedCol; break;\n case 'K': eraseLine(params[0] || 0); break;\n case 'J':\n if ((params[0] || 0) === 2 || (params[0] || 0) === 3) rows.clear();\n break;\n case 'X': {\n const line = cells(row);\n for (let c = 0; c < firstParam(params); c++) line[col - 1 + c] = ' ';\n break;\n }\n case 'P': {\n cells(row).splice(col - 1, firstParam(params));\n break;\n }\n case '@': {\n cells(row).splice(col - 1, 0, ...Array(firstParam(params)).fill(' '));\n break;\n }\n default:\n break;\n }\n i = end + 1;\n continue;\n }\n if (kind === ']' || kind === 'P' || kind === '^' || kind === '_') {\n let end = i + 2;\n while (end < raw.length && raw[end] !== '\\x07' && !(raw[end] === '\\x1b' && raw[end + 1] === '\\\\')) end++;\n if (end >= raw.length) break;\n i = raw[end] === '\\x07' ? end + 1 : end + 2;\n continue;\n }\n if (kind === '7') {\n savedRow = row;\n savedCol = col;\n } else if (kind === '8') {\n row = savedRow;\n col = savedCol;\n } else if (kind === 'c') {\n rows.clear();\n row = 1;\n col = 1;\n }\n // Character-set selection sequences carry one extra byte.\n i += kind === '(' || kind === ')' ? 3 : 2;\n continue;\n }\n if (ch === '\\r') {\n col = 1;\n i++;\n continue;\n }\n if (ch === '\\n') {\n row++;\n i++;\n continue;\n }\n if (ch === '\\b') {\n col = Math.max(1, col - 1);\n i++;\n continue;\n }\n if (ch === '\\t') {\n col += 8 - ((col - 1) % 8);\n i++;\n continue;\n }\n if (ch < ' ' || ch === '\\x7f') {\n i++;\n continue;\n }\n cells(row)[col - 1] = ch;\n col++;\n i++;\n }\n\n const populated = [...rows.keys()].sort((a, b) => a - b);\n return populated.map((r) => cells(r).join('')).join('\\n');\n}\n\n/** Only the tail of the buffer is flattened per chunk — markers are short and\n * recent, and re-flattening an unbounded buffer on every write is O(n²). */\nconst MARKER_SCAN_TAIL = 16384;\n\nexport class VerdictEngine {\n private markerSeen = new Set<string>();\n private buffers = new Map<string, string>();\n private checkpointCounts = new Map<string, number>();\n private pausedSessions = new Map<string, ITerminalSession>();\n private listeners: VerdictListener[] = [];\n private checkpointListeners: CheckpointListener[] = [];\n /**\n * Per-task generation counter. Incremented on every watch() and clear().\n * Stale callbacks (from a prior session whose generation doesn't match\n * the current one) bail out instead of delivering a verdict for the\n * wrong session.\n */\n private generations = new Map<string, number>();\n\n onVerdict(listener: VerdictListener): void {\n this.listeners.push(listener);\n }\n\n onCheckpoint(listener: CheckpointListener): void {\n this.checkpointListeners.push(listener);\n }\n\n approveCheckpoint(taskId: string): void {\n const session = this.pausedSessions.get(taskId);\n if (session) {\n session.write('\\nORDEWELL_CONTINUE\\n');\n this.pausedSessions.delete(taskId);\n }\n }\n\n rejectCheckpoint(taskId: string, reason: string): void {\n const session = this.pausedSessions.get(taskId);\n if (session) {\n session.write(`\\nORDEWELL_REJECT: ${reason}\\n`);\n this.pausedSessions.delete(taskId);\n }\n }\n\n /**\n * Attach to a spawned session: buffer output, scan for the task's completion\n * marker (delivering a verdict immediately while leaving interactive sessions\n * open), scan for checkpoint markers, and on exit produce a failed verdict\n * when the marker was never observed.\n */\n watch(task: Task, session: ITerminalSession): void {\n const doneToken = `<<<ORDEWELL_DONE_${task.completionMarker}>>>`;\n const gen = (this.generations.get(task.id) ?? 0) + 1;\n this.generations.set(task.id, gen);\n this.buffers.set(task.id, '');\n this.checkpointCounts.set(task.id, 0);\n session.onOutput((text: string) => {\n if (this.generations.get(task.id) !== gen) return;\n if (this.markerSeen.has(task.id)) return;\n const buf = (this.buffers.get(task.id) ?? '') + text;\n this.buffers.set(task.id, buf);\n const tail = buf.slice(-MARKER_SCAN_TAIL);\n const markerVisible = flattenTerminalOutput(tail).includes(doneToken)\n || flattenTerminalOutput(renderTerminalOutput(tail)).includes(doneToken);\n if (markerVisible) {\n this.markerSeen.add(task.id);\n // Deliver verdict immediately instead of killing the session.\n // The terminal stays open so the user can read output or keep chatting\n // with the AI runner. Bump the generation so the onExit callback\n // (which will fire when the terminal eventually closes) bails out.\n const output = buf;\n this.buffers.delete(task.id);\n this.checkpointCounts.delete(task.id);\n this.pausedSessions.delete(task.id);\n this.generations.set(task.id, gen + 1);\n const verdict = this.decide(task, 0);\n for (const l of this.listeners) l(task.id, verdict, output);\n return;\n }\n const matches = [...buf.matchAll(CHECKPOINT_RE)];\n const prevCount = this.checkpointCounts.get(task.id) ?? 0;\n for (let i = prevCount; i < matches.length; i++) {\n const summary = matches[i][1].trim();\n this.pausedSessions.set(task.id, session);\n for (const l of this.checkpointListeners) l(task.id, summary);\n }\n this.checkpointCounts.set(task.id, matches.length);\n });\n session.onExit((exitCode: number) => {\n if (this.generations.get(task.id) !== gen) return;\n const output = session.getOutput();\n const tail = output.slice(-MARKER_SCAN_TAIL);\n if (\n flattenTerminalOutput(tail).includes(doneToken)\n || flattenTerminalOutput(renderTerminalOutput(tail)).includes(doneToken)\n ) {\n this.markerSeen.add(task.id);\n }\n this.buffers.delete(task.id);\n this.checkpointCounts.delete(task.id);\n this.pausedSessions.delete(task.id);\n const verdict = this.decide(task, exitCode);\n for (const l of this.listeners) l(task.id, verdict, output);\n });\n }\n\n /** Manual \"Mark complete\" override: a pass verdict that bypasses evidence. */\n markComplete(task: Task): Verdict {\n this.markerSeen.delete(task.id);\n this.buffers.delete(task.id);\n this.checkpointCounts.delete(task.id);\n this.pausedSessions.delete(task.id);\n this.generations.set(task.id, (this.generations.get(task.id) ?? 0) + 1);\n return {\n outcome: 'pass',\n reason: 'Manually marked complete by user.',\n checks: [\n {\n name: 'manual',\n passed: true,\n skipped: false,\n detail: 'Task was manually marked complete by the user; no automatic verification was performed.',\n },\n ],\n decidedAt: new Date().toISOString(),\n };\n }\n\n /** Clear verification state for a task (used on retry). */\n clear(task: Task): void {\n this.markerSeen.delete(task.id);\n this.buffers.delete(task.id);\n this.checkpointCounts.delete(task.id);\n this.pausedSessions.delete(task.id);\n this.generations.set(task.id, (this.generations.get(task.id) ?? 0) + 1);\n }\n\n /** Drop all tracking state (used on stop / loadPlan). */\n reset(): void {\n this.markerSeen.clear();\n this.buffers.clear();\n this.checkpointCounts.clear();\n this.pausedSessions.clear();\n this.generations.clear();\n }\n\n private decide(task: Task, exitCode: number): Verdict {\n const normalized = exitCode == null ? 0 : exitCode;\n const markerWasSeen = this.markerSeen.has(task.id);\n if (markerWasSeen) this.markerSeen.delete(task.id);\n\n const checks: VerificationCheck[] = [];\n if (markerWasSeen) {\n checks.push({\n name: 'completion_marker',\n passed: true,\n skipped: false,\n detail: 'task completion marker was seen in agent output',\n });\n checks.push({\n name: 'exit_code',\n passed: true,\n skipped: true,\n detail: 'bypassed — completion marker was seen in agent output',\n });\n return {\n outcome: 'pass',\n reason: 'Verified: completion marker detected in agent output. Task completed successfully.',\n checks,\n decidedAt: new Date().toISOString(),\n };\n }\n\n const exitOk = normalized === 0;\n checks.push({\n name: 'completion_marker',\n passed: false,\n skipped: false,\n detail: 'agent exited before Ordewell detected the task completion marker',\n });\n checks.push({\n name: 'exit_code',\n passed: exitOk,\n skipped: false,\n detail: exitOk ? 'agent exited cleanly (code 0)' : `agent exited with code ${normalized}`,\n });\n\n return {\n outcome: 'fail',\n reason: exitOk\n ? 'Failed verification: agent exited cleanly but did not emit the completion marker.'\n : `Failed verification: completion marker missing; agent exited with code ${normalized}.`,\n checks,\n decidedAt: new Date().toISOString(),\n };\n }\n}\n","import {\n Task, TaskSnapshot, RunnerId, flattenTasks,\n addTaskToPlan, removeTaskFromPlan, updateTaskInPlan,\n createTask, renumberTasks,\n} from '../models/Task';\n\n/**\n * The deep module owning all plan-shaped state. Holds `planTasks` (the ordered\n * tree the user edits), the flattened `allTasks` view, the `taskMap` index, and\n * the `completedTasks`/`failedTasks` sets the scheduler reads. The orchestrator\n * calls `markCompleted`/`markFailed`/`markInProgress`/`retry` to update task\n * status — it never mutates task state directly.\n *\n * `rebuild` is the internal seam that keeps the flat views in sync with the\n * tree. Structural removals (remove/merge/split) additionally prune\n * `completedTasks`/`failedTasks` for ids that no longer exist; `removeFromActive`\n * deliberately does not, so a completed task that leaves the active list still\n * satisfies its dependents' dependency checks.\n *\n * `planRunners` lives here because it's part of the plan's identity (the runner\n * set, carried on the plan). `validateAssignedRunners` is pure store logic.\n */\nexport class PlanStore {\n private _planTasks: Task[] = [];\n private _allTasks: Task[] = [];\n private _taskMap = new Map<string, Task>();\n private _completedTasks = new Set<string>();\n private _failedTasks = new Set<string>();\n private _planRunners: RunnerId[] = ['claude-code'];\n private _onMutate: (() => void) | null = null;\n private _executionLog: TaskSnapshot[] = [];\n\n /** Hook called after every structural mutation (add/remove/update/merge/split/load). */\n set onMutate(cb: (() => void) | null) { this._onMutate = cb; }\n\n get planTasks(): Task[] { return this._planTasks; }\n get allTasks(): Task[] { return this._allTasks; }\n get planRunners(): RunnerId[] { return this._planRunners; }\n get completedCount(): number { return this._completedTasks.size; }\n get failedCount(): number { return this._failedTasks.size; }\n\n isAllComplete(): boolean { return this._allTasks.every((t) => t.status === 'completed'); }\n isAnyFailed(): boolean { return this._failedTasks.size > 0; }\n isCompleted(id: string): boolean { return this._completedTasks.has(id); }\n isFailed(id: string): boolean { return this._failedTasks.has(id); }\n\n get(taskId: string): Task | undefined { return this._taskMap.get(taskId); }\n\n getExecutionLog(): TaskSnapshot[] { return this._executionLog; }\n\n appendToLog(snapshot: TaskSnapshot): void {\n const idx = this._executionLog.findIndex((s) => s.id === snapshot.id);\n if (idx >= 0) {\n this._executionLog[idx] = snapshot;\n } else {\n this._executionLog.push(snapshot);\n }\n }\n\n /**\n * Drop a task's archived snapshot. Un-marking a completion has to erase the\n * \"finished\" record too — dependent tasks are prompted from the log, so a\n * left-behind snapshot would keep feeding them a result that no longer exists.\n */\n removeFromLog(taskId: string): void {\n this._executionLog = this._executionLog.filter((s) => s.id !== taskId);\n }\n\n removeFromActive(taskId: string): void {\n this._planTasks = this._planTasks.filter((t) => t.id !== taskId);\n this.rebuild();\n this.notifyMutate();\n }\n\n clearLog(): void {\n this._executionLog = [];\n }\n\n private notifyMutate(): void { this._onMutate?.(); }\n\n load(tasks: Task[], runners: RunnerId[]): void {\n this._planTasks = tasks;\n this._planRunners = runners;\n this._completedTasks.clear();\n this._failedTasks.clear();\n this.rebuild();\n // Completed tasks survive a reload so a half-finished plan resumes the\n // remainder (their output summaries still feed dependents). Failed tasks\n // get a fresh chance. In-progress is left alone — load() also runs while\n // a task's terminal session is live (forceStartTask); orphaned in_progress\n // from a saved session is normalized at the disk-load boundary instead.\n for (const task of this._allTasks) {\n if (task.status === 'completed') {\n this._completedTasks.add(task.id);\n } else if (task.status === 'failed') {\n task.status = 'pending';\n }\n }\n this.validateAssignedRunners();\n }\n\n add(partial: Partial<Task>): Task {\n const oldIds = new Set(this._taskMap.keys());\n this._planTasks = addTaskToPlan(this._planTasks, partial);\n this.rebuild();\n this.notifyMutate();\n return this._allTasks.find(t => !oldIds.has(t.id))!;\n }\n\n remove(taskId: string): void {\n if (!this._taskMap.has(taskId)) return;\n this._planTasks = removeTaskFromPlan(this._planTasks, taskId);\n this.rebuild();\n this.pruneTerminalSets();\n this.notifyMutate();\n }\n\n update(taskId: string, changes: Partial<Task>): Task | undefined {\n if (!this._taskMap.has(taskId)) return undefined;\n const safe: Partial<Task> = { ...changes };\n delete safe.id;\n delete safe.order;\n this._planTasks = updateTaskInPlan(this._planTasks, taskId, safe);\n this.rebuild();\n this.notifyMutate();\n return this._taskMap.get(taskId);\n }\n\n mergeMultiple(taskIds: string[]): Task {\n if (taskIds.length < 2) throw new Error('Must provide at least two task IDs to merge');\n const sorted = [...new Set(taskIds)]\n .map(id => ({ id, task: this._taskMap.get(id) }))\n .filter(x => x.task)\n .sort((a, b) => (a.task?.order ?? 0) - (b.task?.order ?? 0));\n\n if (sorted.length < 2) throw new Error('At least two valid tasks required for merge');\n\n let current = sorted[0].id;\n for (let i = 1; i < sorted.length; i++) {\n const merged = this.merge(current, sorted[i].id);\n current = merged.id;\n }\n return this._taskMap.get(current)!;\n }\n\n merge(taskIdA: string, taskIdB: string): Task {\n const taskA = this._taskMap.get(taskIdA);\n const taskB = this._taskMap.get(taskIdB);\n if (!taskA) throw new Error(`Task ${taskIdA} not found`);\n if (!taskB) throw new Error(`Task ${taskIdB} not found`);\n\n const mergedDeps = [...new Set([...taskA.dependencies, ...taskB.dependencies])]\n .filter(depId => depId !== taskIdA && depId !== taskIdB);\n\n const mergedStories = [...new Set([...(taskA.userStoriesCovered ?? []), ...(taskB.userStoriesCovered ?? [])])];\n\n const mergedPrompt = [taskA.prompt, taskB.prompt].filter(Boolean).join('\\n\\n---\\n\\n');\n\n const merged = createTask({\n title: `${taskA.title} + ${taskB.title}`,\n description: `${taskA.description}\\n\\n${taskB.description}`,\n type: taskA.type === 'user' || taskB.type === 'user' ? 'user' : 'ai',\n dependencies: mergedDeps,\n prompt: mergedPrompt || undefined,\n autonomy: taskA.autonomy ?? taskB.autonomy,\n sliceType: taskA.sliceType ?? taskB.sliceType,\n userStoriesCovered: mergedStories.length > 0 ? mergedStories : undefined,\n assignedRunner: taskA.assignedRunner,\n assignedModel: taskA.assignedModel,\n taskMode: taskA.taskMode,\n order: Math.min(taskA.order, taskB.order),\n });\n\n const mergedId = merged.id;\n const userIds = new Set([taskIdA, taskIdB]);\n const sanitized = this._planTasks\n .filter(t => !userIds.has(t.id))\n .map(t => ({\n ...t,\n dependencies: t.dependencies.map(depId =>\n depId === taskIdA || depId === taskIdB ? mergedId : depId\n ),\n }));\n\n this._planTasks = renumberTasks([...sanitized, merged]);\n this.rebuild();\n this.pruneTerminalSets();\n this.notifyMutate();\n return merged;\n }\n\n split(taskId: string, newTaskSpecs: Partial<Task>[]): Task[] {\n const original = this._taskMap.get(taskId);\n if (!original) throw new Error(`Task ${taskId} not found`);\n if (!newTaskSpecs.length) throw new Error('Must provide at least one new task spec');\n\n const newTasks = newTaskSpecs.map((spec, i) =>\n createTask({\n ...spec,\n order: original.order + i,\n dependencies: i === 0 ? [...original.dependencies] : [newTaskSpecs[0].id ?? `split-${taskId}-0`],\n type: spec.type ?? original.type,\n assignedRunner: spec.assignedRunner ?? original.assignedRunner,\n assignedModel: spec.assignedModel ?? original.assignedModel,\n taskMode: spec.taskMode ?? original.taskMode,\n autonomy: spec.autonomy ?? original.autonomy,\n sliceType: spec.sliceType ?? original.sliceType,\n userStoriesCovered: spec.userStoriesCovered ?? original.userStoriesCovered,\n })\n );\n\n const newTaskIds = new Map<number, string>();\n newTasks.forEach((t, i) => newTaskIds.set(i, t.id));\n\n const finalized = newTasks.map((t) => {\n const deps = t.dependencies.map(depId => {\n const idx = newTaskSpecs.findIndex(s => (s.id ?? '') === depId);\n if (idx >= 0) return newTaskIds.get(idx) ?? depId;\n return depId;\n });\n return { ...t, dependencies: deps };\n });\n\n const tailId = finalized[finalized.length - 1].id;\n\n const updatedOthers = this._planTasks\n .filter(t => t.id !== taskId)\n .map(t => ({\n ...t,\n dependencies: t.dependencies.map(depId => depId === taskId ? tailId : depId),\n }));\n\n this._planTasks = renumberTasks([...updatedOthers, ...finalized]);\n this.rebuild();\n this.pruneTerminalSets();\n this.notifyMutate();\n return finalized;\n }\n\n /**\n * Run preparation as one named op: flip every AI task to 'approved'. By\n * default completed tasks keep their status so a reloaded half-finished plan\n * resumes the remainder instead of re-running work that already succeeded;\n * `preserveCompleted: false` is for a freshly committed plan, where\n * everything starts over.\n */\n resetForRun(opts: { preserveCompleted?: boolean } = {}): void {\n const preserveCompleted = opts.preserveCompleted ?? true;\n for (const t of this._allTasks) {\n if (t.type !== 'ai') continue;\n if (preserveCompleted && t.status === 'completed') continue;\n t.status = 'approved';\n }\n }\n\n markCompleted(id: string): void {\n this._failedTasks.delete(id);\n this._completedTasks.add(id);\n const task = this._taskMap.get(id);\n if (task) task.status = 'completed';\n }\n\n markFailed(id: string): void {\n this._completedTasks.delete(id);\n this._failedTasks.add(id);\n const task = this._taskMap.get(id);\n if (task) task.status = 'failed';\n }\n\n markInProgress(id: string): void {\n this._completedTasks.delete(id);\n this._failedTasks.delete(id);\n const task = this._taskMap.get(id);\n if (task) task.status = 'in_progress';\n }\n\n markAwaitingUser(id: string): void {\n const task = this._taskMap.get(id);\n if (task) task.status = 'awaiting_user';\n }\n\n markPending(id: string): void {\n this._completedTasks.delete(id);\n this._failedTasks.delete(id);\n const task = this._taskMap.get(id);\n if (task) task.status = 'pending';\n }\n\n retry(id: string): void {\n this._failedTasks.delete(id);\n this._completedTasks.delete(id);\n const task = this._taskMap.get(id);\n if (task) {\n task.status = 'pending';\n task.verdict = undefined;\n task.outputSummary = undefined;\n }\n }\n\n blockDependents(id: string): void {\n for (const t of this._allTasks) {\n if (t.dependencies.includes(id) && t.status !== 'completed') {\n t.status = 'blocked';\n }\n }\n }\n\n unblockDependents(id: string): void {\n for (const t of this._allTasks) {\n if (t.status === 'blocked' && t.dependencies.includes(id)) {\n t.status = 'pending';\n }\n }\n }\n\n setTaskVerdict(id: string, verdict: Task['verdict']): void {\n const task = this._taskMap.get(id);\n if (task) task.verdict = verdict;\n }\n\n setTaskOutputSummary(id: string, summary: Task['outputSummary']): void {\n const task = this._taskMap.get(id);\n if (task) task.outputSummary = summary;\n }\n\n getPlanVisualization(): { tasks: { id: string; title: string; dependencies: string[]; parallelGroups: number[][] }[]; parallelGroups: number[][] } {\n const unscheduled = new Set(this._planTasks.map(t => t.id));\n const completed = new Set<string>();\n const parallelGroups: number[][] = [];\n\n while (unscheduled.size > 0) {\n const batch: string[] = [];\n for (const t of this._planTasks) {\n if (!unscheduled.has(t.id)) continue;\n if (t.dependencies.length > 0 && t.dependencies.some(depId => !completed.has(depId))) continue;\n batch.push(t.id);\n }\n if (batch.length === 0) break;\n for (const id of batch) {\n unscheduled.delete(id);\n completed.add(id);\n }\n parallelGroups.push(batch.map(id => this._taskMap.get(id)?.order ?? 0).sort((a, b) => a - b));\n }\n\n return {\n tasks: this._planTasks.map(t => ({ id: t.id, title: t.title, dependencies: t.dependencies, parallelGroups: [] })),\n parallelGroups,\n };\n }\n\n /**\n * Widen the plan's runner set. Retargeting a task onto a runner the plan has\n * not used before has to land here as well as on the plan state, or\n * {@link resolveTaskRunner} reads the new runner as foreign and spawns the\n * plan's first one instead.\n */\n admitRunner(runner: RunnerId): void {\n if (!this._planRunners.includes(runner)) this._planRunners = [...this._planRunners, runner];\n }\n\n resolveTaskRunner(task: Task): RunnerId {\n if (task.assignedRunner && this._planRunners.includes(task.assignedRunner)) return task.assignedRunner;\n const fallback = this._planRunners[0] ?? 'claude-code';\n if (task.assignedRunner) {\n console.warn(\n `[PlanStore] Task \"${task.title}\" is assigned to \"${task.assignedRunner}\", which is not in this plan's ` +\n `runner set [${this._planRunners.join(', ')}] — spawning \"${fallback}\" instead.`,\n );\n }\n return fallback;\n }\n\n private rebuild(): void {\n this._allTasks = flattenTasks(this._planTasks);\n this._taskMap.clear();\n for (const task of this._allTasks) {\n this._taskMap.set(task.id, task);\n }\n }\n\n /**\n * Drop completed/failed ids that no longer exist in the plan. Called by the\n * structural removals (remove/merge/split) — but NOT by removeFromActive,\n * where a completed task leaves the active list yet must still satisfy its\n * dependents' dependency checks.\n */\n private pruneTerminalSets(): void {\n for (const id of [...this._completedTasks]) {\n if (!this._taskMap.has(id)) this._completedTasks.delete(id);\n }\n for (const id of [...this._failedTasks]) {\n if (!this._taskMap.has(id)) this._failedTasks.delete(id);\n }\n }\n\n private validateAssignedRunners(): void {\n for (const task of this._allTasks) {\n if (task.type !== 'ai') continue;\n if (!this._planRunners.includes(task.assignedRunner)) {\n throw new Error(\n `Task \"${task.title}\" has assignedRunner \"${task.assignedRunner}\" ` +\n `which is not in the plan's runner set: [${this._planRunners.join(', ')}]`\n );\n }\n }\n }\n}\n","import { Task, TaskSnapshot, Verdict, QueuedMessage, RunnerId } from '../models/Task';\nimport { IConfig } from '../interfaces/IConfig';\nimport { INotification } from '../interfaces/INotification';\nimport { ITerminalRunner } from '../interfaces/ITerminalRunner';\nimport { composeAugmentedPrompt, summarizeOutput } from './promptAugment';\nimport { VerdictEngine } from './VerdictEngine';\nimport { PlanStore } from './PlanStore';\nimport type { RunnerRegistry } from '../plugins/RunnerRegistry';\n\n/**\n * The one notification channel out of the orchestrator. Everything that used\n * to travel over separate callbacks (onRefresh, onQueueReady) is an observer\n * event; the Session subscribes once and turns these into SessionMessages.\n */\nexport interface OrchestratorObserver {\n /** Any task-shaped state changed (store mutation, checkpoint, retry, …). */\n onTaskChanged?(): void;\n onTick?(): void;\n onExecutionComplete?(): void;\n /** Queued user messages are ready to be processed by the planner. */\n onQueueReady?(): void;\n onReviewNeeded?(data: { tasks: Task[]; planRunners: RunnerId[] }): void;\n onReviewApproved?(data: { tasks: Task[] }): void;\n onCheckpoint?(data: { taskId: string; taskTitle: string; summary: string }): void;\n}\n\n/**\n * The pure scheduler. Owns execution state (`running`, `planStatus`,\n * `reviewApproved`, `activeTaskSessions`, `messageQueue`) and the verifier.\n * All task-shaped state — the plan tree, the flat index, the completed set\n * — lives in {@link PlanStore}, injected at construction. The orchestrator\n * calls `store.markCompleted(id)` / `store.markFailed(id)` instead of mutating\n * task state directly. A task completes only after the runner emits its\n * per-task completion marker; process exit without that evidence is a visible\n * failure and does not unblock dependent work.\n */\nexport class TaskOrchestrator {\n private store: PlanStore;\n private activeTaskSessions = new Map<string, string>();\n private startingTaskIds = new Set<string>();\n private verifier = new VerdictEngine();\n private running = false;\n private planStatus: 'approved' | 'running' | 'completed' = 'approved';\n private messageQueue: QueuedMessage[] = [];\n private reviewApproved = false;\n private retryCounts = new Map<string, number>();\n /**\n * Tasks pulled out of auto-scheduling (user-cancelled or failed to spawn).\n * They stay 'pending' — \"not executed\" — but the scheduler skips them until\n * the user retries or force-starts, which would otherwise loop forever on a\n * task whose spawn always throws.\n */\n private onHold = new Set<string>();\n\n private registry: RunnerRegistry | null = null;\n private workspaceRootFn: () => string = () => process.cwd();\n private observers: OrchestratorObserver[] = [];\n private tddEnabled: () => boolean = () => false;\n\n constructor(\n private config: IConfig,\n private notifications: INotification,\n private terminalRunner: ITerminalRunner,\n store?: PlanStore,\n ) {\n this.store = store ?? new PlanStore();\n this.store.onMutate = () => this.emit('onTaskChanged');\n this.verifier.onVerdict((taskId, verdict, output) => this.onVerdict(taskId, verdict, output));\n this.verifier.onCheckpoint((taskId, summary) => {\n const task = this.store.get(taskId);\n if (!task) return;\n this.store.markAwaitingUser(taskId);\n this.emit('onCheckpoint', { taskId, taskTitle: task.title, summary });\n });\n }\n\n get storeInstance(): PlanStore { return this.store; }\n\n setWorkspaceRoot(fn: () => string): void {\n this.workspaceRootFn = fn;\n }\n\n setRegistry(registry: RunnerRegistry): void {\n this.registry = registry;\n }\n\n /**\n * A getter rather than a value where the caller has one: every task gets its\n * prompt composed at spawn time, but only a full-plan run passes through a\n * point where a snapshot could be refreshed — so \"Run task\", force-start and\n * retry would compose against whatever the last run happened to set.\n */\n setTddEnabled(enabled: boolean | (() => boolean)): void {\n this.tddEnabled = typeof enabled === 'function' ? enabled : () => enabled;\n }\n\n approveCheckpoint(taskId: string): void {\n this.verifier.approveCheckpoint(taskId);\n this.store.markInProgress(taskId);\n this.emit('onTaskChanged');\n }\n\n rejectCheckpoint(taskId: string, reason?: string): void {\n this.verifier.rejectCheckpoint(taskId, reason ?? 'Checkpoint rejected by user');\n this.store.markInProgress(taskId);\n this.emit('onTaskChanged');\n }\n\n subscribe(observer: OrchestratorObserver): () => void {\n this.observers.push(observer);\n return () => {\n this.observers = this.observers.filter(o => o !== observer);\n };\n }\n\n private emit(event: keyof OrchestratorObserver, ...args: unknown[]): void {\n for (const o of this.observers) {\n const fn = o[event] as (...args: unknown[]) => void;\n if (fn) fn(...args);\n }\n }\n\n get isRunning(): boolean {\n return this.running || this.startingTaskIds.size > 0 || this.activeTaskSessions.size > 0;\n }\n get isReviewApproved(): boolean { return this.reviewApproved; }\n get status(): 'approved' | 'running' | 'completed' { return this.planStatus; }\n get activeTaskIds(): string[] { return [...this.activeTaskSessions.keys()]; }\n get activeSessionMap(): Map<string, string> { return new Map(this.activeTaskSessions); }\n get queuedCount(): number { return this.messageQueue.length; }\n\n queueMessage(text: string): void {\n this.messageQueue.push({\n id: `q-${Date.now()}`,\n text,\n timestamp: new Date().toISOString(),\n });\n this.emit('onTaskChanged');\n }\n\n getQueuedMessages(): QueuedMessage[] {\n return [...this.messageQueue];\n }\n\n setQueuedMessages(messages: QueuedMessage[]): void {\n this.messageQueue = [...messages];\n }\n\n clearQueuedMessages(): void {\n this.messageQueue = [];\n }\n\n processNextQueuedMessage(): QueuedMessage | null {\n if (this.messageQueue.length === 0) return null;\n return this.messageQueue.shift() ?? null;\n }\n\n loadPlan(tasks: Task[], planRunners: RunnerId[] = ['claude-code']): void {\n this.store.load(tasks, planRunners);\n this.activeTaskSessions.clear();\n this.startingTaskIds.clear();\n this.verifier.reset();\n this.planStatus = 'approved';\n this.reviewApproved = false;\n this.retryCounts.clear();\n this.onHold.clear();\n }\n\n reconcilePlan(newTasks: Task[], planRunners: RunnerId[] = ['claude-code']): void {\n for (const taskId of this.activeTaskSessions.keys()) {\n const task = this.store.get(taskId);\n if (!task) continue;\n\n const inNewPlan = newTasks.find((t) => t.id === taskId);\n if (!inNewPlan) {\n newTasks.push({ ...task });\n } else if (inNewPlan.status !== 'in_progress') {\n console.warn(`[TaskOrchestrator] Running task \"${task.title}\" status changed to \"${inNewPlan.status}\" in modified plan, using orchestrator truth`);\n }\n }\n\n this.store.load(newTasks, planRunners);\n this.planStatus = 'running';\n }\n\n async start(): Promise<void> {\n if (this.running) {\n console.error('[TaskOrchestrator] start() called but already running — no-op');\n return;\n }\n if (!this.reviewApproved) {\n console.log('[TaskOrchestrator] start() blocked — plan review not yet approved. Emitting onReviewNeeded.');\n this.emit('onReviewNeeded', { tasks: this.store.planTasks, planRunners: this.store.planRunners });\n return;\n }\n console.log(`[TaskOrchestrator] Starting with ${this.store.allTasks.length} tasks (${this.store.allTasks.filter(t => t.type === 'ai' && t.prompt).length} AI ready)`);\n this.running = true;\n this.planStatus = 'running';\n this.emit('onTaskChanged');\n await this.tick();\n }\n\n stop(): void {\n this.running = false;\n this.planStatus = 'approved';\n this.terminalRunner.stopAll();\n this.activeTaskSessions.clear();\n this.startingTaskIds.clear();\n this.verifier.reset();\n this.onHold.clear();\n this.emit('onTaskChanged');\n }\n\n async onUserTaskComplete(taskId: string): Promise<void> {\n return this.markTaskComplete(taskId);\n }\n\n private async onVerdict(taskId: string, verdict: Verdict, output: string): Promise<void> {\n const task = this.store.get(taskId);\n if (!task) return;\n this.activeTaskSessions.delete(taskId);\n\n console.error(`[TaskOrchestrator] Task #${task.order} \"${task.title}\" verdict=${verdict.outcome}`);\n console.error(`[TaskOrchestrator] Runner: ${task.assignedRunner}, Model: ${task.assignedModel?.modelId ?? 'default'}`);\n console.error(`[TaskOrchestrator] Prompt preview: ${(task.prompt ?? '').slice(0, 200)}`);\n if (output && output.length > 0) {\n console.error(`[TaskOrchestrator] Output (last 3000 chars):\\n${output.slice(-3000)}`);\n } else {\n console.error(`[TaskOrchestrator] Output: (empty — no stdout/stderr captured)`);\n }\n\n this.store.setTaskVerdict(taskId, verdict);\n\n if (verdict.outcome === 'pass') {\n this.store.markCompleted(taskId);\n this.notifications.info(`Task \"${task.title}\" completed.`);\n } else {\n this.store.markFailed(taskId);\n // Missing completion evidence is a hard boundary: do not launch more\n // work from a full-plan run until the user retries/resumes explicitly.\n // Already-active parallel tasks may finish, but no new task is spawned.\n this.running = false;\n this.planStatus = 'approved';\n this.notifications.error(`Task \"${task.title}\" failed verification: ${verdict.reason}`);\n }\n\n this.store.setTaskOutputSummary(taskId, summarizeOutput(verdict.reason, output));\n\n this.logAndArchive(task, verdict);\n\n this.emit('onTaskChanged');\n if (!this.running) {\n if (this.activeTaskSessions.size === 0 && this.startingTaskIds.size === 0) {\n if (this.store.isAllComplete()) this.planStatus = 'completed';\n this.emit('onTick');\n this.emit('onExecutionComplete');\n }\n return;\n }\n await this.tick();\n }\n\n getReadyTasks(): Task[] {\n if (!this.running) return [];\n const maxParallel = this.config.maxParallelSessions;\n const currentActive = this.activeTaskSessions.size;\n if (currentActive >= maxParallel) return [];\n const availableSlots = maxParallel - currentActive;\n\n const candidates = this.store.allTasks.filter((t) => {\n if (t.status !== 'pending' && t.status !== 'approved') return false;\n if (t.type === 'user') return false;\n if (!t.prompt) return false;\n if (this.onHold.has(t.id)) return false;\n if (this.isBlocked(t)) return false;\n if (t.dependencies.length > 0 && !t.dependencies.every((depId) => this.store.isCompleted(depId))) return false;\n return true;\n });\n\n const excluded = this.store.allTasks.filter(t => t.type === 'ai' && t.prompt && !candidates.includes(t));\n if (excluded.length > 0) {\n for (const t of excluded) {\n const reasons: string[] = [];\n if (t.status !== 'pending' && t.status !== 'approved') reasons.push(`status=${t.status}`);\n if (this.onHold.has(t.id)) reasons.push('on-hold');\n if (this.isBlocked(t)) reasons.push('blocked');\n if (t.dependencies.length > 0 && !t.dependencies.every((depId) => this.store.isCompleted(depId))) reasons.push('deps');\n console.log(`[TaskOrchestrator] excluded: #${t.order} \"${t.title}\" — ${reasons.join(', ')}`);\n }\n }\n\n console.log(`[TaskOrchestrator] getReadyTasks: ${candidates.length} candidates, ${availableSlots} slots, maxParallel=${maxParallel}`);\n return candidates.sort((a, b) => a.order - b.order).slice(0, availableSlots);\n }\n\n isBlocked(task: Task): boolean {\n if (task.status === 'blocked') return true;\n if (task.dependencies.length > 0) return task.dependencies.some((depId) => this.store.isFailed(depId));\n return false;\n }\n\n /**\n * Cancel a running (or scheduled) task: kill its session and return it to\n * 'pending' — \"not executed\". The task is put on hold so the scheduler\n * doesn't immediately restart it; Retry / Force Start release the hold.\n */\n async cancelTask(taskId: string): Promise<void> {\n const task = this.store.get(taskId);\n if (!task) return;\n // Bump the verifier's generation *before* stopping the runner: some\n // runners (e.g. tmux) fire onExit synchronously from stop(), and if that\n // exit reaches VerdictEngine under the still-valid generation it delivers\n // a verdict that marks this cancelled task 'completed' for one tick —\n // long enough for the scheduler to synchronously start a dependent task.\n this.verifier.clear(task);\n const sessionId = this.activeTaskSessions.get(taskId);\n if (sessionId) {\n this.terminalRunner.stop(sessionId);\n this.activeTaskSessions.delete(taskId);\n }\n this.store.markPending(taskId);\n this.onHold.add(taskId);\n this.emit('onTaskChanged');\n await this.tick();\n }\n\n async markTaskComplete(taskId: string): Promise<void> {\n const task = this.store.get(taskId);\n if (!task || task.status === 'completed') return;\n\n const sessionId = this.activeTaskSessions.get(taskId);\n if (sessionId) {\n this.terminalRunner.stop(sessionId);\n this.activeTaskSessions.delete(taskId);\n }\n\n this.verifier.clear(task);\n const verdict = this.verifier.markComplete(task);\n\n this.store.markCompleted(taskId);\n this.store.setTaskVerdict(taskId, verdict);\n this.store.setTaskOutputSummary(taskId, summarizeOutput(verdict.reason, ''));\n this.logAndArchive(task, verdict);\n this.store.unblockDependents(taskId);\n this.onHold.delete(taskId);\n\n this.notifications.info(`Task \"${task.title}\" marked complete.`);\n this.emit('onTaskChanged');\n await this.tick();\n }\n\n async markAiTaskComplete(taskId: string): Promise<void> {\n return this.markTaskComplete(taskId);\n }\n\n /**\n * Undo a completion: return the task to \"not executed\" — pending, verdict and\n * summary dropped, archive entry removed. It is put on hold like a cancel, so\n * a running plan does not immediately re-spawn the work the user just\n * un-marked; Retry / Force Start / Run release the hold. Dependents fall back\n * to waiting on their own, because the scheduler gates on `isCompleted`.\n */\n async markTaskIncomplete(taskId: string): Promise<void> {\n const task = this.store.get(taskId);\n if (!task || task.status !== 'completed') return;\n\n this.verifier.clear(task);\n this.store.retry(taskId);\n this.store.removeFromLog(taskId);\n this.onHold.add(taskId);\n // A finished plan is no longer finished — leaving 'completed' would tell\n // every surface the run is over while a task sits pending.\n if (this.planStatus === 'completed') this.planStatus = 'approved';\n\n this.notifications.info(`Task \"${task.title}\" marked not done.`);\n this.emit('onTaskChanged');\n await this.tick();\n }\n\n private logAndArchive(task: Task, verdict: Verdict): void {\n const snapshot: TaskSnapshot = {\n ...task,\n completedAt: Date.now(),\n verdict,\n retryCount: this.retryCounts.get(task.id) ?? 0,\n finalized: true,\n };\n this.store.appendToLog(snapshot);\n // Completed tasks remain in the active plan tree so the UI can keep\n // showing them alongside pending and running work.\n }\n\n async retryTask(taskId: string): Promise<void> {\n const task = this.store.get(taskId);\n if (!task) return;\n this.retryCounts.set(taskId, (this.retryCounts.get(taskId) ?? 0) + 1);\n this.store.retry(taskId);\n this.verifier.clear(task);\n this.store.unblockDependents(taskId);\n this.onHold.delete(taskId);\n this.emit('onTaskChanged');\n await this.tick();\n }\n\n /**\n * Manually start a single AI task right now, bypassing dependency/readiness\n * gating (the \"force start\" affordance on a task card). Reuses the scheduler's\n * own startTask so a force-started task gets the same augmented prompt, session\n * tracking, and exit handling — callers must not re-spawn the runner themselves.\n * No-op if the task is unknown, not an AI task, or already running.\n */\n async forceStartTask(taskId: string): Promise<void> {\n const task = this.store.get(taskId);\n if (!task || task.type !== 'ai') return;\n if (this.activeTaskSessions.has(taskId)) return;\n this.onHold.delete(taskId);\n await this.startTask(task);\n }\n\n /**\n * Run exactly one task outside full-plan scheduling. The active/starting\n * session still contributes to isRunning so every surface exposes Stop and\n * disables Execute Plan, but onVerdict cannot auto-schedule other tasks\n * because the plan scheduler's `running` flag remains false.\n */\n async runTask(taskId: string): Promise<void> {\n if (this.isRunning) return;\n const task = this.store.get(taskId);\n if (!task || task.type !== 'ai') return;\n this.onHold.delete(taskId);\n await this.startTask(task);\n }\n\n getCompletedCount(): number { return this.store.completedCount; }\n getTotalCount(): number { return this.store.allTasks.length; }\n isAllComplete(): boolean { return this.store.isAllComplete(); }\n isAnyFailed(): boolean { return this.store.isAnyFailed(); }\n\n async approveReview(): Promise<void> {\n if (this.reviewApproved) {\n console.log('[TaskOrchestrator] approveReview() called but already approved — no-op');\n return;\n }\n this.reviewApproved = true;\n this.planStatus = 'approved';\n this.emit('onTaskChanged');\n this.emit('onReviewApproved', { tasks: this.store.planTasks });\n await this.start();\n }\n\n getPlanVisualization() { return this.store.getPlanVisualization(); }\n\n async tick(): Promise<void> {\n if (!this.running) return;\n\n if (this.messageQueue.length > 0) {\n if (this.activeTaskSessions.size === 0) {\n this.emit('onQueueReady');\n }\n return;\n }\n\n const ready = this.getReadyTasks();\n console.log(`[TaskOrchestrator] tick(): ${ready.length} ready, ${this.activeTaskSessions.size} active, queue=${this.messageQueue.length}`);\n\n if (ready.length === 0 && this.activeTaskSessions.size === 0) {\n const remaining = this.store.allTasks.filter(t => t.status !== 'completed');\n console.log(`[TaskOrchestrator] tick(): no work. remaining=${remaining.length}, completed=${this.store.isAllComplete()}`);\n for (const t of remaining) {\n console.log(` - ${t.order}. ${t.title} [${t.type}/${t.status}] prompt=${!!t.prompt}`);\n }\n if (this.store.isAllComplete()) {\n // Genuinely done — stop the loop so a fresh Execute click can start it again.\n this.running = false;\n this.planStatus = 'completed';\n this.notifications.info('All tasks completed!');\n this.emit('onTaskChanged');\n this.emit('onTick');\n this.emit('onExecutionComplete');\n } else {\n // Not done — just waiting on a user task, checkpoint, or held task.\n // Keep `running` true: markTaskComplete/retryTask/forceStartTask/cancelTask\n // all re-tick() afterward, and that only ever schedules new work while\n // `running` is true. Flipping it false here would silently kill the\n // scheduler and leave dependents unblocked-but-never-started.\n // Do NOT emit onExecutionComplete here: a paused run is not a finished\n // one, and every surface treats that signal as terminal (the TUI closes\n // its execution stream on receipt, so a later fan-out from completing the\n // user task would arrive to a closed socket and be invisible).\n this.notifications.info('Remaining tasks require user action or are on hold.');\n this.emit('onTaskChanged');\n this.emit('onTick');\n }\n return;\n }\n\n for (const task of ready) await this.startTask(task);\n this.emit('onTick');\n }\n\n private async startTask(task: Task): Promise<void> {\n if (this.activeTaskSessions.has(task.id) || this.startingTaskIds.has(task.id)) return;\n this.startingTaskIds.add(task.id);\n this.store.markInProgress(task.id);\n this.emit('onTaskChanged');\n try {\n const cwd = this.workspaceRootFn();\n const runner = this.store.resolveTaskRunner(task);\n const finalPrompt = composeAugmentedPrompt(task, this.store.allTasks, {\n planMapEnabled: this.config.planMapEnabled,\n tddEnabled: this.tddEnabled(),\n });\n const session = await this.terminalRunner.spawn({\n taskId: task.id,\n runner,\n prompt: finalPrompt,\n modelId: task.assignedModel?.modelId,\n thinkingEffort: task.assignedModel?.thinkingEffort,\n modelVariants: task.assignedModel?.availableVariants,\n mode: task.taskMode ?? 'build',\n cwd,\n registry: this.registry ?? undefined,\n order: task.order,\n title: task.title,\n });\n\n // Stop/load can invalidate a spawn while the async adapter is starting.\n // Do not resurrect that execution after the surface already went idle.\n if (!this.startingTaskIds.delete(task.id)) {\n session.kill();\n this.store.markPending(task.id);\n this.emit('onTaskChanged');\n return;\n }\n this.activeTaskSessions.set(task.id, session.id);\n\n this.verifier.watch(task, session);\n\n this.emit('onTaskChanged');\n this.notifications.info(`Task \"${task.title}\" started (${runner})`);\n } catch (err) {\n this.startingTaskIds.delete(task.id);\n // Couldn't spawn — the task was never executed, so it stays \"to do\".\n // Held out of auto-scheduling to avoid a spawn-throw retry loop.\n this.store.markPending(task.id);\n this.onHold.add(task.id);\n this.notifications.error(`Failed to start task \"${task.title}\": ${err}`);\n this.emit('onTaskChanged');\n await this.tick();\n }\n }\n}\n","import type { DiscoveredModel, RunnerId, Task } from '../models/Task';\n\n/**\n * The ids a runner may actually run: the user's allowlist with the ids that\n * provably belong to a *different* runner dropped. `undefined` means no\n * restriction.\n *\n * Model ids are scoped to the agent that lists them, so an OpenRouter slug\n * allowlisted for Claude Code does not limit it — it points it at something it\n * cannot spawn, and the plan only dies once a task is already running. But\n * \"this runner didn't list it\" is not enough to call an id wrong: discovery can\n * be stale, and a plugin runner may have no list at all. What settles it is\n * whether *another* runner listed the id. So:\n *\n * - listed for this runner → keep;\n * - listed for no runner → unknown, and the user said it explicitly, so keep it\n * and let the runner validate last (the same call `coerceAssignments` and\n * `TaskRetarget` make);\n * - listed only for other runners → provably not this runner's, so drop it.\n *\n * When that leaves nothing, the whole allowlist was about some other runner\n * (a settings file written before a surface scoped its picker to one). No\n * restriction is the only safe reading — the alternative is handing the planner\n * a list of models that cannot run.\n */\nexport function effectiveAllowlist(\n allowlist: string[] | undefined,\n runner: string,\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>> | undefined,\n): string[] | undefined {\n if (!allowlist || allowlist.length === 0) return undefined;\n if (!modelsByRunner) return allowlist;\n\n const own = new Set((modelsByRunner[runner] ?? []).map((m) => m.modelId));\n const elsewhere = new Set<string>();\n for (const [other, models] of Object.entries(modelsByRunner)) {\n if (other === runner) continue;\n for (const m of models ?? []) elsewhere.add(m.modelId);\n }\n\n const kept = allowlist.filter((id) => own.has(id) || !elsewhere.has(id));\n return kept.length > 0 ? kept : undefined;\n}\n\nexport function filterModelsForPrompt(\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n perRunnerAllowlist: Partial<Record<RunnerId, string[]>>,\n): Partial<Record<RunnerId, DiscoveredModel[]>> {\n const result: Partial<Record<RunnerId, DiscoveredModel[]>> = {};\n for (const [runner, models] of Object.entries(modelsByRunner)) {\n if (!models) continue;\n const allowed = effectiveAllowlist(perRunnerAllowlist[runner], runner, modelsByRunner);\n if (!allowed) {\n result[runner] = models;\n continue;\n }\n const allowedSet = new Set(allowed);\n const intersection = models.filter((m) => allowedSet.has(m.modelId));\n // A set allowlist is a hard constraint: the planner must never see models\n // outside it. An allowed id no runner has listed is one discovery doesn't\n // cover, so synthesize an entry rather than leaking the full list.\n const covered = new Set(intersection.map((m) => m.modelId));\n const missing = allowed\n .filter((id) => !covered.has(id))\n .map((id) => ({ modelId: id, modelLabel: id.split('/').pop() || id, variants: [] }));\n result[runner] = [...intersection, ...missing];\n }\n return result;\n}\n\n/** Canonical low→high ordering of the well-known effort ladder. */\nconst EFFORT_LADDER = ['none', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max', 'ultra'];\n/** Runner-specific spellings mapped onto the ladder. */\nconst EFFORT_ALIASES: Record<string, string> = { disabled: 'none', adaptive: 'medium' };\n\n/**\n * Clamp a planner/user-supplied thinking effort to what the model actually\n * offers. Invalid values map to the nearest rung the model supports (so a\n * Claude-style \"xhigh\" on a low/medium/high model becomes \"high\") and fall\n * back to undefined — the runner's own default — when no mapping exists.\n */\nexport function clampThinkingEffort(\n effort: string | undefined,\n variants: { id: string }[],\n): string | undefined {\n if (!effort) return undefined;\n if (variants.length === 0) return undefined;\n const ids = new Set(variants.map((v) => v.id));\n if (ids.has(effort)) return effort;\n const canon = EFFORT_ALIASES[effort] ?? effort;\n if (ids.has(canon)) return canon;\n const idx = EFFORT_LADDER.indexOf(canon);\n if (idx < 0) return undefined;\n for (let d = 1; d < EFFORT_LADDER.length; d++) {\n const lower = EFFORT_LADDER[idx - d];\n if (lower && ids.has(lower)) return lower;\n const higher = EFFORT_LADDER[idx + d];\n if (higher && ids.has(higher)) return higher;\n }\n return undefined;\n}\n\nexport function coerceAssignments(\n tasks: Task[],\n perRunnerAllowlist: Partial<Record<RunnerId, string[]>>,\n allowedRunners?: RunnerId[],\n modelsByRunner?: Partial<Record<RunnerId, DiscoveredModel[]>>,\n): Task[] {\n // When the discovered catalog is available, snap each assignment's\n // thinkingEffort to a variant the model really has and stamp the model's\n // variant ids on the assignment (runners need them at spawn time); a model\n // we can't find in the catalog keeps its effort untouched (the runner\n // validates last).\n const clampVariant = (task: Task): Task => {\n if (!task.assignedModel || !modelsByRunner) return task;\n const model = modelsByRunner[task.assignedRunner]?.find(\n (m) => m.modelId === task.assignedModel!.modelId,\n );\n if (!model) return task;\n const clamped = clampThinkingEffort(task.assignedModel.thinkingEffort, model.variants);\n return {\n ...task,\n assignedModel: {\n ...task.assignedModel,\n thinkingEffort: clamped,\n availableVariants: model.variants.map((v) => v.id),\n },\n };\n };\n\n // One reading of the allowlist for the whole pass, so the models a task is\n // snapped to are the same ones the planner was shown (`filterModelsForPrompt`).\n const allowedFor = (runner: RunnerId): string[] | undefined =>\n effectiveAllowlist(perRunnerAllowlist[runner], runner, modelsByRunner);\n\n // A snapped-to model keeps the catalog's label and variant list where we have\n // one — an id alone reads as the model's name in every surface, and leaves the\n // effort picker with nothing to offer.\n const assignmentFor = (runner: RunnerId, modelId: string): NonNullable<Task['assignedModel']> => {\n const known = modelsByRunner?.[runner]?.find((m) => m.modelId === modelId);\n return {\n modelId,\n modelLabel: known?.modelLabel ?? modelId,\n thinkingEffort: undefined,\n ...(known ? { availableVariants: known.variants.map((v) => v.id) } : {}),\n };\n };\n\n return tasks.map((task) => {\n if (task.type === 'user') return task;\n\n if (allowedRunners && !allowedRunners.includes(task.assignedRunner)) {\n const fallbackRunner = allowedRunners[0];\n const fallbackModels = allowedFor(fallbackRunner);\n const fallbackModel = fallbackModels?.length\n ? assignmentFor(fallbackRunner, fallbackModels[0])\n : modelsByRunner?.[fallbackRunner]?.[0]\n ? assignmentFor(fallbackRunner, modelsByRunner[fallbackRunner]![0].modelId)\n : task.assignedModel;\n return clampVariant({\n ...task,\n assignedRunner: fallbackRunner,\n assignedModel: fallbackModel,\n });\n }\n\n const allowlist = allowedFor(task.assignedRunner);\n // No model assigned: fill in from the allowlist or discovered catalog so\n // merge/split/add outputs (which may omit assignedModel) always land with a\n // valid model for the task's runner.\n if (!task.assignedModel) {\n if (allowlist && allowlist.length > 0) {\n return clampVariant({ ...task, assignedModel: assignmentFor(task.assignedRunner, allowlist[0]) });\n }\n const discovered = modelsByRunner?.[task.assignedRunner]?.[0];\n if (discovered) {\n return clampVariant({ ...task, assignedModel: assignmentFor(task.assignedRunner, discovered.modelId) });\n }\n return task;\n }\n if (!allowlist || allowlist.length === 0) return clampVariant(task);\n if (allowlist.includes(task.assignedModel.modelId)) return clampVariant(task);\n return { ...task, assignedModel: assignmentFor(task.assignedRunner, allowlist[0]) };\n });\n}\n","import { Task, TaskSnapshot, RunnerId, DiscoveredModel, ResearchLogEntry, ResearchProgress, LegacyPlanState, type ActiveTaskSession } from '../models/Task';\nimport { IConfig } from '../interfaces/IConfig';\nimport { IFileSystem } from '../interfaces/IFileSystem';\nimport { IWebFetcher } from '../interfaces/IWebFetcher';\nimport { IAiService } from './AiService';\nimport type { RunnerModeInfo } from './ModeResolver';\nimport { validatePlanModification } from './PlanValidator';\nimport { repairLoop, modifyValidationFeedback } from './PlanRepair';\nimport { buildModifyDuringExecutionPrompt } from './PlanPrompts';\nimport { filterModelsForPrompt, coerceAssignments } from './ModelAllowlistResolver';\nimport { DEFAULT_PLANNER_MODES, type PlannerModes } from './plannerModes';\n\n/**\n * `autonomousDefault` still arrives on its own — it is not a user toggle but a\n * property of the run — so it wins over whatever the mode set carried.\n */\nfunction plannerModesWith(req: { modes?: PlannerModes; autonomousDefault?: boolean }): PlannerModes {\n const modes = req.modes ?? DEFAULT_PLANNER_MODES;\n return { ...modes, autonomousDefault: req.autonomousDefault ?? modes.autonomousDefault };\n}\n\n/**\n * Everything needed to produce a plan from a goal. Carries the planning context\n * that previously threaded through the scheduler as positional args.\n */\nexport interface PlanRequest {\n goal: string;\n runners: RunnerId[];\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>;\n fs?: IFileSystem;\n fetcher?: IWebFetcher;\n onProgress?: (progress: ResearchProgress) => void;\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>;\n autonomousDefault?: boolean;\n signal?: AbortSignal;\n perRunnerAllowlist?: Partial<Record<RunnerId, string[]>>;\n /** The mode toggles this run honours. `modesFor('one-shot', …)` decides which apply. */\n modes?: PlannerModes;\n}\n\nexport interface ModifyPlanRequest {\n existingPlan: LegacyPlanState;\n userRequest: string;\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>;\n fs?: IFileSystem;\n fetcher?: IWebFetcher;\n onProgress?: (progress: ResearchProgress) => void;\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>;\n autonomousDefault?: boolean;\n perRunnerAllowlist?: Partial<Record<RunnerId, string[]>>;\n modes?: PlannerModes;\n}\n\nexport interface ModifyDuringExecutionRequest {\n executionLog: TaskSnapshot[];\n pendingTasks: Task[];\n activeSessions: Map<string, ActiveTaskSession>;\n userMessage: string;\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>;\n runners: RunnerId[];\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>;\n autonomousDefault?: boolean;\n perRunnerAllowlist?: Partial<Record<RunnerId, string[]>>;\n}\n\nexport interface ModifyDuringExecutionResult {\n pendingTasks: Task[];\n message: string;\n}\n\n/**\n * Owns one-shot plan generation and plan modification — the \"planning is a\n * different workload from execution\" thesis, as a module. The conversational\n * planning loop (ADR-0002) lives on {@link Session}, which talks to the AI\n * service directly because the conversation state is held there.\n */\nexport class Planner {\n /**\n * Resolved per call, never captured: the planner backend can change while a\n * surface is open (`/planner`, the webview pills), and a Planner holding the\n * service it was built with would keep planning on the backend the host has\n * already switched away from.\n */\n private readonly resolveAiService: () => IAiService;\n\n constructor(private config: IConfig, aiService: IAiService | (() => IAiService)) {\n this.resolveAiService = typeof aiService === 'function' ? aiService : () => aiService;\n }\n\n private get aiService(): IAiService { return this.resolveAiService(); }\n\n /** One-shot plan generation for non-conversational surfaces. Never asks questions. */\n async generate(req: PlanRequest): Promise<LegacyPlanState> {\n const now = new Date().toISOString();\n let tasks: Task[];\n let researchLog: ResearchLogEntry[] | undefined;\n\n const filteredModels = filterModelsForPrompt(req.modelsByRunner, req.perRunnerAllowlist ?? {});\n\n if (this.config.researchEnabled) {\n const result = await this.aiService.researchAndPlan(\n req.goal,\n req.runners,\n filteredModels,\n req.fs!,\n req.onProgress ?? (() => {}),\n req.fetcher,\n req.runnerModes,\n plannerModesWith(req),\n req.signal,\n );\n tasks = result.tasks;\n researchLog = result.researchLog;\n } else {\n const onProgress = req.onProgress;\n tasks = await this.aiService.generatePlanDirect(\n req.goal,\n req.runners,\n filteredModels,\n onProgress ? (token: string) => onProgress({ type: 'plan_token', planToken: token }) : undefined,\n req.fs,\n req.fetcher,\n req.runnerModes,\n plannerModesWith(req),\n req.signal,\n );\n }\n\n return {\n tasks: coerceAssignments(tasks, req.perRunnerAllowlist ?? {}, req.runners, req.modelsByRunner),\n generatedAt: now,\n status: 'draft',\n runners: req.runners,\n lastUpdated: now,\n researchLog,\n };\n }\n\n async modify(req: ModifyPlanRequest): Promise<{ tasks: Task[] }> {\n const filteredModels = filterModelsForPrompt(req.modelsByRunner, req.perRunnerAllowlist ?? {});\n const result = await this.aiService.modifyPlan(\n req.existingPlan,\n req.userRequest,\n filteredModels,\n req.onProgress,\n req.fs,\n req.fetcher,\n req.runnerModes,\n plannerModesWith(req),\n );\n return { tasks: coerceAssignments(result.tasks, req.perRunnerAllowlist ?? {}, req.existingPlan.runners, req.modelsByRunner) };\n }\n\n async modifyDuringExecution(req: ModifyDuringExecutionRequest): Promise<ModifyDuringExecutionResult> {\n const pendingJson = JSON.stringify(req.pendingTasks, null, 2);\n const filteredModels = filterModelsForPrompt(req.modelsByRunner, req.perRunnerAllowlist ?? {});\n const allowlist = req.perRunnerAllowlist ?? {};\n\n const basePrompt = buildModifyDuringExecutionPrompt(\n req.executionLog,\n pendingJson,\n req.userMessage,\n filteredModels,\n req.runners,\n req.runnerModes,\n req.autonomousDefault ?? true,\n );\n const send = (corrective?: string) => this.aiService.sendPlanningPrompt(\n corrective ? basePrompt + corrective : basePrompt,\n req.runners,\n req.runnerModes,\n req.autonomousDefault ?? true,\n );\n\n return repairLoop<Task[], ModifyDuringExecutionResult>({\n first: () => send(),\n resend: (corrective) => send(corrective),\n interpret: (tasks) => {\n const coerced = coerceAssignments(tasks, allowlist, req.runners, req.modelsByRunner);\n const validation = validatePlanModification({\n executionLog: req.executionLog,\n oldPending: req.pendingTasks,\n newPending: coerced,\n activeSessions: req.activeSessions,\n });\n if (validation.valid) {\n return { done: { pendingTasks: coerced, message: `Plan modified: ${coerced.length} pending task(s)` } };\n }\n return { retry: { errors: validation.errors, corrective: modifyValidationFeedback(validation.errors) } };\n },\n maxRepairs: 2,\n onExhausted: ({ errors }) => {\n throw new Error(\n `Plan modification validation exhausted after 3 attempts. Last errors:\\n${errors.map((e) => `- ${e}`).join('\\n')}`,\n );\n },\n });\n }\n}\n","import * as path from 'path';\nimport { exec, spawn } from 'child_process';\nimport { promisify } from 'util';\nimport * as fsSync from 'fs';\nimport * as osMod from 'os';\nimport { DiscoveredModel } from '../models/Task';\nimport type { RunnerRegistry } from '../plugins/RunnerRegistry';\nimport type { RunnerPluginManifest, DiscoveryCommand, ApiDiscoveryConfig, ApiAuthMethod } from '../plugins/types';\nimport { augmentedPath, withPath } from '../utils/shellPath';\nimport { planDirectLaunch } from '../utils/launch';\nimport { killTree } from '../utils/processTree';\n\nconst execAsync = promisify(exec);\n\n/**\n * Injectable command runner. Defaults to the real `child_process` exec wrapper;\n * tests pass a fake so discovery never spawns a process.\n */\nexport type ExecImpl = (\n command: string,\n options?: { timeout?: number }\n) => Promise<{ stdout: string }>;\n\n// Discovery must find `claude`/`opencode` wherever the user installed them,\n// even when the host process (GUI-launched VS Code, service-launched web\n// server) inherits a minimal PATH — hence the augmented PATH.\nconst defaultExec: ExecImpl = async (command, options) => {\n const PATH = await augmentedPath();\n // `opencode models --verbose` emits a JSON block per model and grows with\n // every provider the user enables (~0.5MB with three providers today);\n // node's default 1MB maxBuffer would kill the child mid-stream and silently\n // degrade discovery to the variant-less plain parser.\n const { stdout } = await execAsync(command, { ...options, maxBuffer: 32 * 1024 * 1024, env: withPath(process.env, PATH) });\n return { stdout: String(stdout) };\n};\n\n/**\n * One raw model entry from an app-server `model/list` response (Codex's stdio\n * JSON-RPC protocol). Field names are the protocol's, not Ordewell's.\n */\nexport interface AppServerModel {\n id: string;\n displayName?: string;\n hidden?: boolean;\n defaultReasoningEffort?: string;\n supportedReasoningEfforts?: { reasoningEffort: string; description?: string }[];\n}\n\n/**\n * Injectable app-server JSON-RPC client: spawn the command, drive\n * `initialize` → `model/list` over stdio, return the raw model list. Returns\n * null on any failure (spawn error, timeout, malformed response) so discovery\n * falls through to the on-disk cache file. Tests inject a fake so discovery\n * never spawns a real app-server.\n */\nexport type AppServerClientImpl = (\n command: string,\n args: string[],\n options?: { timeout?: number }\n) => Promise<AppServerModel[] | null>;\n\nconst defaultAppServerClient: AppServerClientImpl = async (command, args, options) => {\n const PATH = await augmentedPath();\n // No shell here, so on Windows the command has to be resolved against\n // PATHEXT first — `codex` alone is a `.cmd` shim that CreateProcess cannot\n // start. A resolution failure returns the command unchanged, and the spawn's\n // own error still routes discovery to the on-disk cache.\n const launch = await planDirectLaunch(command, args).catch(() => null);\n if (!launch) return null;\n return new Promise((resolve) => {\n let child: import('child_process').ChildProcess;\n try {\n child = spawn(launch.file, launch.args, {\n env: withPath(process.env, PATH),\n stdio: ['pipe', 'pipe', 'ignore'],\n windowsVerbatimArguments: launch.verbatim,\n });\n } catch {\n resolve(null);\n return;\n }\n let settled = false;\n const finish = (value: AppServerModel[] | null) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n // Tree-wide, for the same reason every other dispose path is: when\n // `codex` resolved to a shim the direct child is the interpreter, and\n // killing it leaves the app-server alive — holding its port, and\n // outliving the discovery call that started it.\n killTree(child);\n resolve(value);\n };\n const timer = setTimeout(() => finish(null), options?.timeout ?? 20000);\n child.on('error', () => finish(null));\n child.on('exit', () => finish(null));\n\n let buffer = '';\n const send = (id: number, method: string, params: unknown) => {\n try {\n child.stdin!.write(JSON.stringify({ jsonrpc: '2.0', id, method, params }) + '\\n');\n } catch {\n finish(null);\n }\n };\n child.stdout!.on('data', (chunk: Buffer) => {\n buffer += chunk.toString();\n let newline: number;\n while ((newline = buffer.indexOf('\\n')) >= 0) {\n const line = buffer.slice(0, newline);\n buffer = buffer.slice(newline + 1);\n let msg: { id?: number; result?: { data?: AppServerModel[] } };\n try { msg = JSON.parse(line); } catch { continue; }\n if (msg.id === 1) {\n send(2, 'model/list', {});\n } else if (msg.id === 2) {\n finish(Array.isArray(msg.result?.data) ? msg.result!.data! : null);\n }\n }\n });\n send(1, 'initialize', { clientInfo: { name: 'ordewell', title: 'Ordewell', version: '0.1.0' } });\n });\n};\n\nfunction effortVariant(effort: string): { id: string; label: string } {\n return { id: effort, label: effort.charAt(0).toUpperCase() + effort.slice(1) };\n}\n\n/** Map app-server `model/list` entries to DiscoveredModels, dropping hidden ones. */\nexport function parseAppServerModels(raw: AppServerModel[]): DiscoveredModel[] {\n return raw\n .filter((m) => m.id && !m.hidden)\n .map((m) => ({\n modelId: m.id,\n modelLabel: m.displayName || m.id,\n runnerProvider: 'openai',\n variants: (m.supportedReasoningEfforts ?? []).map((e) => effortVariant(e.reasoningEffort)),\n }));\n}\n\n/**\n * Parse the runner's own on-disk catalog cache (Codex `models_cache.json`).\n * Same catalog as `model/list` but in the cache file's snake_case shape, with\n * `visibility: \"hide\"` in place of the protocol's `hidden` flag.\n */\nexport function parseCodexModelsCache(content: string): DiscoveredModel[] {\n try {\n const data = JSON.parse(content) as {\n models?: Array<{\n slug?: string;\n display_name?: string;\n visibility?: string;\n supported_reasoning_levels?: { effort: string; description?: string }[];\n }>;\n };\n if (!Array.isArray(data.models)) return [];\n return data.models\n .filter((m) => m.slug && m.visibility !== 'hide')\n .map((m) => ({\n modelId: m.slug!,\n modelLabel: m.display_name || m.slug!,\n runnerProvider: 'openai',\n variants: (m.supported_reasoning_levels ?? []).map((l) => effortVariant(l.effort)),\n }));\n } catch {\n return [];\n }\n}\n\nconst GEMINI_MODELS_CACHE_TTL_MS = 24 * 60 * 60 * 1000;\n\ninterface GeminiApiModel {\n name: string;\n displayName: string;\n supportedGenerationMethods?: string[];\n}\n\nfunction geminiDiscoveryCacheKey(apiKey: string): { key: string; dir: string; file: string } {\n const dir = path.join(osMod.homedir(), '.config', 'ordewell');\n const hash = apiKey.slice(-8);\n return {\n key: `gemini-models:${hash}`,\n dir,\n file: path.join(dir, `gemini_models_${hash}.json`),\n };\n}\n\nfunction readGeminiCache(apiKey: string): DiscoveredModel[] | null {\n try {\n const { file } = geminiDiscoveryCacheKey(apiKey);\n if (!fsSync.existsSync(file)) return null;\n const raw = fsSync.readFileSync(file, 'utf8');\n const data = JSON.parse(raw);\n if (Date.now() - data.cachedAt > GEMINI_MODELS_CACHE_TTL_MS) return null;\n return data.models as DiscoveredModel[];\n } catch {\n return null;\n }\n}\n\nfunction writeGeminiCache(apiKey: string, models: DiscoveredModel[]): void {\n try {\n const { dir, file } = geminiDiscoveryCacheKey(apiKey);\n fsSync.mkdirSync(dir, { recursive: true });\n fsSync.writeFileSync(\n file,\n JSON.stringify({ models, cachedAt: Date.now() }, null, 2)\n );\n } catch { /* empty */ }\n}\n\n/**\n * Delete the on-disk Gemini discovery cache for an API key so the next\n * discovery re-runs. Used by the resolver's `invalidate()` in production (no\n * injected fetch); best-effort — a missing file is a no-op.\n */\nexport function clearGeminiCache(apiKey: string): void {\n if (!apiKey) return;\n try {\n const { file } = geminiDiscoveryCacheKey(apiKey);\n if (fsSync.existsSync(file)) fsSync.rmSync(file);\n } catch { /* empty */ }\n}\n\nexport async function discoverGeminiModels(apiKey: string, baseUrl?: string, fetchImpl?: typeof fetch): Promise<DiscoveredModel[]> {\n if (!apiKey) return [];\n\n // An injected fetch means the resolver owns caching — bypass the file cache.\n const useFileCache = !fetchImpl;\n if (useFileCache) {\n const cached = readGeminiCache(apiKey);\n if (cached && cached.length > 0) return cached;\n }\n\n const url = (baseUrl || 'https://generativelanguage.googleapis.com').replace(/\\/+$/, '');\n\n try {\n const models: DiscoveredModel[] = [];\n let pageToken: string | undefined;\n\n do {\n const params = new URLSearchParams({ key: apiKey });\n if (pageToken) params.set('pageToken', pageToken);\n const response = await (fetchImpl ?? fetch)(`${url}/v1beta/models?${params}`, {\n headers: { 'Content-Type': 'application/json' },\n });\n\n if (!response.ok) return [];\n\n const data = (await response.json()) as { models?: GeminiApiModel[]; nextPageToken?: string };\n for (const m of data.models ?? []) {\n const methods = m.supportedGenerationMethods ?? [];\n if (methods.includes('generateContent')) {\n const modelId = m.name.replace(/^models\\//, '');\n models.push({\n modelId,\n modelLabel: m.displayName || modelId,\n runnerProvider: 'gemini',\n variants: [],\n });\n }\n }\n\n pageToken = data.nextPageToken || undefined;\n } while (pageToken);\n\n models.sort((a, b) => {\n const aPro = a.modelId.includes('-pro');\n const bPro = b.modelId.includes('-pro');\n if (aPro && !bPro) return -1;\n if (!aPro && bPro) return 1;\n return b.modelId.localeCompare(a.modelId);\n });\n\n if (useFileCache && models.length > 0) writeGeminiCache(apiKey, models);\n return models;\n } catch {\n return [];\n }\n}\n\nfunction applyVariants(models: DiscoveredModel[], manifest: RunnerPluginManifest): DiscoveredModel[] {\n const variants = manifest.modelDiscovery.variants;\n if (!variants || variants.length === 0) return models;\n // Only fill in models whose variants are empty (e.g. --help parsing or\n // canonical-alias fallback). Models that already carry per-model variants\n // from the API must keep them — the static list is a fallback, not an override.\n return models.map((m) => (m.variants.length > 0 ? m : { ...m, variants }));\n}\n\n/**\n * Resolve an auth token from a manifest's `apiDiscovery.auth` list. Each method\n * is tried in order; the first that yields a non-empty token wins.\n *\n * - `env`: reads `process.env[varName]`\n * - `file`: reads a JSON file at `path` (with `~` expansion) and extracts the\n * value at `jsonPath` (dot-notation, e.g. `claudeAiOauth.accessToken`)\n *\n * Returns `{ header, value }` ready to set on the fetch `headers` object, or\n * `null` when no auth method yields a token.\n */\nfunction resolveApiAuth(authMethods: ApiAuthMethod[]): { header: string; value: string } | null {\n for (const method of authMethods) {\n try {\n let token: string | undefined;\n if (method.type === 'env') {\n token = process.env[method.varName];\n } else {\n const filePath = method.path.replace(/^~/, osMod.homedir());\n if (!fsSync.existsSync(filePath)) continue;\n const data = JSON.parse(fsSync.readFileSync(filePath, 'utf8'));\n token = method.jsonPath.split('.').reduce((obj: unknown, key: string) => {\n if (obj && typeof obj === 'object') return (obj as Record<string, unknown>)[key] as unknown;\n return undefined;\n }, data) as string | undefined;\n }\n if (token) {\n const value = method.prefix ? `${method.prefix}${token}` : token;\n return { header: method.header, value };\n }\n } catch { /* try next auth method */ }\n }\n return null;\n}\n\n/**\n * Query an HTTP API endpoint for the model list. Used when the runner's CLI\n * has no model-listing subcommand (Claude Code). Returns the parsed models, or\n * `null` when no auth token is available or the request fails — in both cases\n * the caller falls through to command-based discovery.\n */\nasync function discoverFromApi(\n config: ApiDiscoveryConfig,\n fetchImpl?: typeof fetch\n): Promise<DiscoveredModel[] | null> {\n const auth = resolveApiAuth(config.auth);\n if (!auth) return null;\n\n try {\n const headers: Record<string, string> = { ...config.headers, [auth.header]: auth.value };\n const response = await (fetchImpl ?? fetch)(config.url, { headers });\n if (!response.ok) return null;\n const data = await response.json();\n const text = JSON.stringify(data);\n return parseModelOutput(text, config.parser, {} as RunnerPluginManifest);\n } catch {\n return null;\n }\n}\n\n/**\n * Parse the Anthropic Models API response (`GET /v1/models`). The API returns\n * full model IDs (e.g. `claude-haiku-4-5-20251001`) sorted most-recent first.\n * We derive the short family alias (`haiku`, `opus`, `sonnet`, `fable`) that\n * the Claude Code CLI's `--model` flag accepts, deduplicating by family to\n * keep only the latest (first in the API's ordering).\n *\n * Per-model thinking variants come from two independent capabilities:\n * `capabilities.thinking.types.adaptive` (the model reasons without being told\n * how hard) and `capabilities.effort.{level}` (the rungs `--effort` accepts).\n * They are read separately because they are separate axes — the current model\n * line reports `thinking.types.enabled: false` alongside all five effort rungs,\n * so treating `enabled` as the gate for effort hid every rung on exactly the\n * models a user is most likely to plan with. A model with no capabilities gets\n * an empty variants array — the caller's static fallback fills in only when\n * variants are empty (see `applyVariants`).\n */\nconst ANTHROPIC_EFFORT_LEVELS = ['low', 'medium', 'high', 'xhigh', 'max'] as const;\nconst ANTHROPIC_VARIANT_LABELS: Record<string, string> = {\n adaptive: 'Adaptive',\n low: 'Low effort',\n medium: 'Medium effort',\n high: 'High effort',\n xhigh: 'Extra high effort',\n max: 'Max effort',\n};\n\nfunction anthropicCapabilitiesToVariants(\n caps?:\n | {\n thinking?: {\n supported?: boolean;\n types?: {\n adaptive?: { supported?: boolean };\n enabled?: { supported?: boolean };\n };\n };\n effort?: {\n supported?: boolean;\n low?: { supported?: boolean };\n medium?: { supported?: boolean };\n high?: { supported?: boolean };\n xhigh?: { supported?: boolean };\n max?: { supported?: boolean };\n };\n }\n | undefined,\n): { id: string; label: string }[] {\n const variants: { id: string; label: string }[] = [];\n if (caps?.thinking?.supported && caps.thinking.types?.adaptive?.supported) {\n variants.push({ id: 'adaptive', label: ANTHROPIC_VARIANT_LABELS.adaptive });\n }\n if (caps?.effort?.supported) {\n for (const level of ANTHROPIC_EFFORT_LEVELS) {\n if (caps.effort[level]?.supported) {\n variants.push({ id: level, label: ANTHROPIC_VARIANT_LABELS[level] });\n }\n }\n }\n return variants;\n}\n\nfunction parseAnthropicModels(stdout: string): DiscoveredModel[] {\n try {\n const data = JSON.parse(stdout) as {\n data?: Array<{\n id: string;\n display_name?: string;\n capabilities?: Parameters<typeof anthropicCapabilitiesToVariants>[0];\n }>;\n };\n const models = data.data;\n if (!Array.isArray(models)) return [];\n\n const seen = new Set<string>();\n const result: DiscoveredModel[] = [];\n\n for (const m of models) {\n if (!m.id || typeof m.id !== 'string') continue;\n if (!m.id.startsWith('claude-')) continue;\n const segments = m.id.split('-');\n const family = segments[1];\n if (!family || !['opus', 'sonnet', 'haiku', 'fable'].includes(family)) continue;\n if (seen.has(family)) continue;\n seen.add(family);\n const label = m.display_name || family.charAt(0).toUpperCase() + family.slice(1);\n result.push({\n modelId: family,\n modelLabel: label,\n runnerProvider: 'anthropic',\n variants: anthropicCapabilitiesToVariants(m.capabilities),\n });\n }\n\n return result;\n } catch {\n return [];\n }\n}\n\nasync function discoverFromCommand(manifest: RunnerPluginManifest, execImpl: ExecImpl): Promise<{ models: DiscoveredModel[]; fromFallback: boolean }> {\n const discovery = manifest.modelDiscovery;\n const commands: DiscoveryCommand[] = discovery.discoveryCommands ?? [\n { command: discovery.command!, args: discovery.args || [], parser: discovery.parser || 'line-by-line' },\n ];\n\n const runCommands = async (): Promise<DiscoveredModel[] | null> => {\n for (const cmd of commands) {\n try {\n // Generous timeout: a cold runner CLI may spawn its server, install\n // plugins, and fetch its catalog on first invocation after boot.\n const { stdout } = await execImpl(`${cmd.command} ${cmd.args.join(' ')}`, { timeout: 45000 });\n const models = parseModelOutput(stdout, cmd.parser || 'line-by-line', manifest);\n if (models.length > 0) return applyVariants(mergeCanonicalAliases(models, manifest), manifest);\n } catch { /* try next command */ }\n }\n return null;\n };\n\n // First pass. If every command timed out or came back empty, the CLI was\n // likely cold — it just spawned its server and hadn't fetched its catalog\n // yet. Retry once (the server is now warm) before degrading to the manifest\n // fallback, so a cold start never silently produces a short/empty list.\n const first = await runCommands();\n if (first) return { models: first, fromFallback: false };\n const second = await runCommands();\n if (second) return { models: second, fromFallback: false };\n\n return { models: applyVariants(buildFallbackModels(manifest), manifest), fromFallback: true };\n}\n\n/**\n * Merge `manifest.modelDiscovery.canonicalAliases` into a successful discovery\n * result. Discovered models take precedence (they reflect the installed CLI);\n * any canonical alias NOT already present is appended, so stable `--model`\n * contracts that the CLI's help text omits (e.g. Claude's 'haiku') are always\n * offered. Only applies when `canonicalAliases` is declared.\n */\nfunction mergeCanonicalAliases(discovered: DiscoveredModel[], manifest: RunnerPluginManifest): DiscoveredModel[] {\n const canonical = manifest.modelDiscovery.canonicalAliases;\n if (!canonical || canonical.length === 0) return discovered;\n const seen = new Set(discovered.map((m) => m.modelId));\n const gaps = canonical\n .filter((f) => !seen.has(f.modelId))\n .map((f) => ({\n modelId: f.modelId,\n modelLabel: f.modelLabel,\n runnerProvider: f.modelId.includes('/') ? f.modelId.split('/')[0] : undefined,\n variants: [],\n }));\n return gaps.length > 0 ? [...discovered, ...gaps] : discovered;\n}\n\nfunction buildFallbackModels(manifest: RunnerPluginManifest): DiscoveredModel[] {\n // Prefer canonicalAliases (stable CLI contracts, e.g. Claude's opus/sonnet/\n // haiku) when declared; fall back to the generic fallbackModels list for\n // user plugins that have no canonical alias concept.\n const list = manifest.modelDiscovery.canonicalAliases ?? manifest.modelDiscovery.fallbackModels ?? [];\n return list.map((m) => ({\n modelId: m.modelId,\n modelLabel: m.modelLabel,\n runnerProvider: m.modelId.includes('/') ? m.modelId.split('/')[0] : undefined,\n variants: manifest.modelDiscovery.variants || [],\n }));\n}\n\nfunction parseModelOutput(stdout: string, parser: string, manifest: RunnerPluginManifest): DiscoveredModel[] {\n switch (parser) {\n case 'claude-help':\n return parseClaudeHelp(stdout);\n case 'opencode-models':\n return parseOpencodeModels(stdout, manifest);\n case 'opencode-models-verbose':\n return parseOpencodeModelsVerbose(stdout, manifest);\n case 'anthropic-models':\n return parseAnthropicModels(stdout);\n case 'line-by-line':\n return parseLineByLine(stdout);\n case 'json':\n return parseJson(stdout, manifest);\n case 'json-table':\n return parseJsonTable(stdout);\n default:\n return parseLineByLine(stdout);\n }\n}\n\nfunction parseClaudeHelp(stdout: string): DiscoveredModel[] {\n const models: DiscoveredModel[] = [];\n const seen = new Set<string>();\n\n const extractIds = (text: string) => {\n for (const line of text.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n const words = trimmed.split(/\\s+/);\n for (const w of words) {\n const cleaned = w.replace(/[\",()]/g, '');\n if (cleaned.length < 5) continue;\n if (cleaned.includes('-') && cleaned.length > 10 && !seen.has(cleaned)) {\n seen.add(cleaned);\n let label = cleaned.replace(/-20\\d{6}/, '').replace(/-/g, ' ');\n label = label.replace(/\\b\\w/g, (c) => c.toUpperCase());\n if (cleaned.includes('sonnet')) label = 'Sonnet';\n else if (cleaned.includes('opus')) label = 'Opus';\n else if (cleaned.includes('haiku')) label = 'Haiku';\n models.push({ modelId: cleaned, modelLabel: label, variants: [] });\n }\n }\n }\n };\n\n // Prefer an explicit enumeration of model IDs when present, e.g.\n // --model <model> Available values: claude-opus-..., claude-sonnet-...\n const modelMatch = stdout.match(/--model\\s+<model>\\s+(?:.*?\\n)*?\\s*(?:Available|valid)(?:\\s+values?|:\\s*options?)\\s*:\\s*([\\s\\S]*?)(?:\\n\\s*\\n|$)/i);\n\n if (modelMatch) {\n extractIds(modelMatch[1]);\n }\n if (models.length > 0) return models;\n\n // Modern `claude --help` describes --model in prose with quoted example\n // aliases: \"Provide an alias for the latest model (e.g. 'fable', 'opus', or\n // 'sonnet') or a model's full name (e.g. 'claude-fable-5').\" Those aliases\n // are the CLI's own contract for what --model accepts, so they ARE the model\n // list — extracted from the installed binary, never hardcoded here.\n // The option block: the `--model` line plus its indented continuation lines\n // (a line whose first non-space char is `-` starts the next option).\n const optionBlock = stdout.match(/--model\\s+<model>[^\\n]*(?:\\n(?!\\s*-)[^\\n]*)*/);\n if (optionBlock) {\n const quoted = [...optionBlock[0].matchAll(/'([a-z][a-z0-9._/-]*)'/gi)].map((m) => m[1]);\n // Aliases (no separator, e.g. 'opus') resolve to the latest model of their\n // family and are always valid; full-name examples (e.g. 'claude-fable-5')\n // duplicate an alias, so only use them when no alias was found.\n const aliases = quoted.filter((q) => /^[a-z][a-z0-9]{2,19}$/.test(q));\n const chosen = aliases.length > 0 ? aliases : quoted.filter((q) => q.length >= 5);\n for (const id of chosen) {\n if (seen.has(id)) continue;\n seen.add(id);\n const label = id.replace(/-20\\d{6}$/, '').split(/[-_]/).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(' ');\n models.push({ modelId: id, modelLabel: label, variants: [] });\n }\n }\n\n return models;\n}\n\nfunction parseOpencodeModels(stdout: string, manifest: RunnerPluginManifest): DiscoveredModel[] {\n // The CLI output is the source of truth: accept ANY `provider/model` line\n // (custom providers included) rather than a hand-listed charset. Structure\n // required: a plain provider segment (no colon — excludes URLs), a slash,\n // and a whitespace-free remainder.\n const lines = stdout.split('\\n').map((l) => l.trim()).filter((l) => /^[A-Za-z0-9._-]+\\/[^\\s\"{}]+$/.test(l));\n if (lines.length === 0) return [];\n\n const preferred = manifest.modelDiscovery.preferredPatterns;\n const prefLabels = new Map<string, string>();\n if (preferred) {\n for (const { id, label } of preferred) {\n prefLabels.set(id, label);\n }\n }\n\n const seen = new Set<string>();\n const models: DiscoveredModel[] = [];\n\n for (const id of lines) {\n if (prefLabels.has(id) && !seen.has(id)) {\n seen.add(id);\n const provider = id.split('/')[0];\n models.push({ modelId: id, modelLabel: prefLabels.get(id)!, runnerProvider: provider, variants: [] });\n }\n }\n\n for (const id of lines) {\n if (!seen.has(id)) {\n seen.add(id);\n const provider = id.split('/')[0];\n models.push({ modelId: id, modelLabel: id.split('/').pop() || id, runnerProvider: provider, variants: [] });\n }\n }\n\n return models;\n}\n\n/**\n * Parse `opencode models --verbose` output.\n *\n * The format alternates between a `provider/model-id` line and a JSON block:\n * opencode/claude-sonnet-4-6\n * { \"id\": \"claude-sonnet-4-6\", ... \"variants\": { \"low\": {...}, \"high\": {...} } }\n * opencode-go/deepseek-v4-pro\n * { ... \"variants\": {} }\n *\n * Per-model variants are extracted directly from the JSON; models with no\n * variants get an empty array (the old static manifest variants are NOT applied).\n */\nfunction parseOpencodeModelsVerbose(stdout: string, manifest: RunnerPluginManifest): DiscoveredModel[] {\n // Ensure trailing newline so the last model-id line is always captured by the split regex.\n // The CLI output is the source of truth: accept ANY `provider/model` id line\n // (custom providers, uppercase, version pins, multi-segment models). The only\n // structure required is a plain provider segment (no colon — excludes URLs)\n // followed by a whitespace-free remainder; JSON block lines never match\n // because they start with `{`, `}`, `\"` or indentation.\n const normalized = stdout.endsWith('\\n') ? stdout : stdout + '\\n';\n const parts = normalized.split(/^([A-Za-z0-9._-]+\\/[^\\s\"{}]+)\\n/m);\n\n const preferred = manifest.modelDiscovery.preferredPatterns;\n const prefLabels = new Map<string, string>();\n if (preferred) {\n for (const { id, label } of preferred) prefLabels.set(id, label);\n }\n\n const seen = new Set<string>();\n const models: DiscoveredModel[] = [];\n\n for (let i = 1; i < parts.length - 1; i += 2) {\n const fullId = parts[i].trim();\n const jsonText = parts[i + 1].trim();\n if (seen.has(fullId)) continue;\n\n let variantIds: string[] = [];\n let modelLabel = prefLabels.get(fullId) || fullId.split('/').pop() || fullId;\n // The provider IS the printed prefix before the first `/` — exactly as\n // the CLI lists it (`opencode/…`, `opencode-go/…`, `openrouter/…`, or any\n // future provider). The JSON's providerID never overrides it.\n const runnerProvider = fullId.split('/')[0];\n\n try {\n const data = JSON.parse(jsonText) as {\n name?: string;\n variants?: Record<string, unknown>;\n };\n if (data.name) modelLabel = prefLabels.get(fullId) || data.name;\n variantIds = Object.keys(data.variants ?? {});\n } catch {\n // No parseable JSON block — keep the id-derived label, no variants.\n }\n\n seen.add(fullId);\n models.push({\n modelId: fullId,\n modelLabel,\n runnerProvider,\n variants: variantIds.map((id) => ({ id, label: id.charAt(0).toUpperCase() + id.slice(1) })),\n });\n }\n\n if (models.length === 0) return [];\n\n // Put preferred patterns first, then the rest alphabetically\n const prefOrder = preferred?.map((p) => p.id) ?? [];\n models.sort((a, b) => {\n const ai = prefOrder.indexOf(a.modelId);\n const bi = prefOrder.indexOf(b.modelId);\n if (ai >= 0 && bi >= 0) return ai - bi;\n if (ai >= 0) return -1;\n if (bi >= 0) return 1;\n return a.modelId.localeCompare(b.modelId);\n });\n\n return models;\n}\n\nfunction parseLineByLine(stdout: string): DiscoveredModel[] {\n return stdout\n .split('\\n')\n .map((l) => l.trim())\n .filter(Boolean)\n .slice(0, 50)\n .map((line) => {\n const parts = line.split(/\\s+/);\n const id = parts[0];\n const label = parts.slice(1).join(' ') || id;\n return { modelId: id, modelLabel: label, runnerProvider: id.includes('/') ? id.split('/')[0] : undefined, variants: [] };\n });\n}\n\nfunction parseJson(stdout: string, manifest: RunnerPluginManifest): DiscoveredModel[] {\n try {\n let data = JSON.parse(stdout);\n const jsonPath = manifest.modelDiscovery.jsonPath;\n if (jsonPath) {\n for (const key of jsonPath.split('.')) {\n if (data && typeof data === 'object') {\n data = (data as Record<string, unknown>)[key];\n }\n }\n }\n const arr = Array.isArray(data) ? data : [];\n return arr.map((item: unknown) => {\n if (typeof item === 'string') {\n const id = item;\n return { modelId: id, modelLabel: id, runnerProvider: id.includes('/') ? id.split('/')[0] : undefined, variants: [] };\n }\n if (typeof item === 'object' && item !== null) {\n const obj = item as Record<string, unknown>;\n const modelId = String(obj.id || obj.modelId || obj.model || '');\n return {\n modelId,\n modelLabel: String(obj.label || obj.name || obj.modelLabel || obj.id || ''),\n runnerProvider: modelId.includes('/') ? modelId.split('/')[0] : undefined,\n variants: [],\n };\n }\n const id = String(item);\n return { modelId: id, modelLabel: id, runnerProvider: id.includes('/') ? id.split('/')[0] : undefined, variants: [] };\n });\n } catch {\n return [];\n }\n}\n\nfunction parseJsonTable(stdout: string): DiscoveredModel[] {\n try {\n const data = JSON.parse(stdout);\n if (typeof data === 'object' && data !== null && !Array.isArray(data)) {\n const outer = Object.values(data)[0];\n const arr = Array.isArray(outer) ? outer : [];\n return arr.map((item: unknown) => {\n if (typeof item === 'string') {\n const id = item;\n return { modelId: id, modelLabel: id, runnerProvider: id.includes('/') ? id.split('/')[0] : undefined, variants: [] };\n }\n if (typeof item === 'object' && item !== null) {\n const obj = item as Record<string, unknown>;\n const modelId = String(obj.id || obj.modelId || obj.model || '');\n return {\n modelId,\n modelLabel: String(obj.label || obj.name || obj.modelLabel || obj.id || ''),\n runnerProvider: modelId.includes('/') ? modelId.split('/')[0] : undefined,\n variants: [],\n };\n }\n const id = String(item);\n return { modelId: id, modelLabel: id, runnerProvider: id.includes('/') ? id.split('/')[0] : undefined, variants: [] };\n });\n }\n } catch { /* fall through */ }\n return [];\n}\n\n/**\n * @internal Per-runner executor-model discovery. This is the *implementation*\n * behind ModelResolver, not part of the public package API — construct it only\n * through ModelResolver (see CONTEXT.md \"ModelResolver\"). The resolver owns the\n * cache lifecycle via `discover()` + `clear()`.\n */\nexport class ModelDiscovery {\n private cache: Map<string, DiscoveredModel[]> = new Map();\n private registry: RunnerRegistry;\n private execImpl: ExecImpl;\n private fetchImpl?: typeof fetch;\n private appServerClient: AppServerClientImpl;\n private readFileImpl: (path: string) => string | null;\n\n constructor(\n registry: RunnerRegistry,\n execImpl: ExecImpl = defaultExec,\n fetchImpl?: typeof fetch,\n appServerClient: AppServerClientImpl = defaultAppServerClient,\n readFileImpl?: (path: string) => string | null,\n ) {\n this.registry = registry;\n this.execImpl = execImpl;\n this.fetchImpl = fetchImpl;\n this.appServerClient = appServerClient;\n this.readFileImpl = readFileImpl ?? ((filePath: string) => {\n try {\n return fsSync.readFileSync(filePath.replace(/^~/, osMod.homedir()), 'utf8');\n } catch {\n return null;\n }\n });\n }\n\n /**\n * App-server discovery chain (ADR-0004): live `model/list` over stdio\n * JSON-RPC first, the runner's own on-disk catalog cache second. Returns\n * null when both fail so `discover()` falls through to the remaining\n * methods.\n */\n private async discoverFromAppServer(manifest: RunnerPluginManifest): Promise<DiscoveredModel[] | null> {\n const config = manifest.modelDiscovery.appServer;\n if (!config) return null;\n\n const raw = await this.appServerClient(config.command, config.args);\n if (raw) {\n const models = parseAppServerModels(raw);\n if (models.length > 0) return models;\n }\n\n if (config.cacheFile) {\n const content = this.readFileImpl(config.cacheFile);\n if (content) {\n const models = parseCodexModelsCache(content);\n if (models.length > 0) return models;\n }\n }\n\n return null;\n }\n\n /**\n * Every model this runner offers, each stamped with the runner it came from.\n * The stamp lives here rather than in the parsers because this is the only\n * place that knows both — a parser sees output, not which agent produced it.\n */\n async discover(runner: string): Promise<DiscoveredModel[]> {\n const models = await this.discoverRaw(runner);\n const manifest = this.registry.getManifest(runner);\n if (!manifest) return models;\n const runnerLabel = manifest.displayName || runner;\n return models.map((m) => ({ ...m, runnerId: runner, runnerLabel }));\n }\n\n private async discoverRaw(runner: string): Promise<DiscoveredModel[]> {\n if (this.cache.has(runner)) {\n return this.cache.get(runner)!;\n }\n\n const manifest = this.registry.getManifest(runner);\n if (!manifest) {\n return [];\n }\n\n let models: DiscoveredModel[];\n let cacheable = true;\n const discovery = manifest.modelDiscovery;\n\n // 0. App-server JSON-RPC discovery (Codex). Live catalog first, the\n // runner's own cache file second; falls through on total failure.\n if (discovery.appServer) {\n const appServerModels = await this.discoverFromAppServer(manifest);\n if (appServerModels && appServerModels.length > 0) {\n this.cache.set(runner, appServerModels);\n return appServerModels;\n }\n // Both live and cache-file sources failed — whatever the remaining\n // methods produce is a degraded fallback; don't cache it, so a\n // transient failure heals on the next lookup.\n cacheable = false;\n }\n\n // 1. Try API discovery first (e.g. Anthropic Models API for Claude Code).\n // Returns null when no auth token is available or the request fails —\n // in both cases we fall through to command-based discovery.\n if (discovery.apiDiscovery) {\n const apiModels = await discoverFromApi(discovery.apiDiscovery, this.fetchImpl);\n if (apiModels && apiModels.length > 0) {\n models = applyVariants(mergeCanonicalAliases(apiModels, manifest), manifest);\n if (cacheable && models.length > 0) this.cache.set(runner, models);\n return models;\n }\n }\n\n // 2. Command-based discovery (CLI subcommand or --help parsing).\n if (discovery.method === 'command' && (discovery.command || discovery.discoveryCommands?.length)) {\n const result = await discoverFromCommand(manifest, this.execImpl);\n models = result.models;\n // A fallback-only result means the CLI wasn't reachable — don't cache\n // it, so a transient failure (PATH, network, cold start) heals on the\n // next lookup instead of persisting until an explicit refresh.\n cacheable = !result.fromFallback;\n } else {\n models = buildFallbackModels(manifest);\n }\n\n if (cacheable && models.length > 0) this.cache.set(runner, models);\n return models;\n }\n\n clear(): void {\n this.cache.clear();\n }\n}\n","import { exec } from 'child_process';\nimport { promisify } from 'util';\nimport * as os from 'os';\nimport * as path from 'path';\n\nconst execAsync = promisify(exec);\n\n/**\n * GUI-launched processes (the VS Code extension host, a desktop-spawned web\n * server) often inherit a minimal PATH that misses user-level install dirs\n * (~/.local/bin, ~/.opencode/bin, nvm shims, …), so spawning `claude` or\n * `opencode` fails even though the user has them installed. This module\n * resolves an augmented PATH once per process: the interactive login shell's\n * PATH (which runs the user's profile, covering nvm/volta/asdf and friends)\n * merged over the current PATH, plus the well-known per-user bin dirs as a\n * final safety net when the login shell itself can't be queried. On Windows\n * there is no login shell to query, so the well-known dirs are the whole net —\n * see {@link windowsBinDirs}.\n *\n * {@link withPath} is the other half: handing the resolved PATH to a child\n * without accidentally giving it two.\n */\n\nconst LOGIN_SHELL_TIMEOUT_MS = 5000;\nconst PATH_MARKER = '__ORDEWELL_PATH__';\n\ntype ExecFn = (command: string, options?: { timeout?: number }) => Promise<{ stdout: string }>;\n\nconst defaultExec: ExecFn = async (command, options) => {\n const { stdout } = await execAsync(command, options);\n return { stdout: String(stdout) };\n};\n\nfunction posixBinDirs(): string[] {\n const home = os.homedir();\n return [\n path.join(home, '.local', 'bin'),\n path.join(home, '.opencode', 'bin'),\n path.join(home, '.claude', 'bin'),\n path.join(home, '.bun', 'bin'),\n path.join(home, '.volta', 'bin'),\n path.join(home, '.npm-global', 'bin'),\n path.join(home, 'bin'),\n '/usr/local/bin',\n '/opt/homebrew/bin',\n ];\n}\n\n/**\n * The Windows counterpart of {@link posixBinDirs}. There is no login shell to\n * ask on Windows, so this list is the only safety net when a runner was\n * installed after the host process started (the registry PATH a GUI-launched\n * VS Code inherited is a snapshot from launch time) or by an installer that\n * writes its own directory rather than amending PATH.\n *\n * The three built-in runners can each arrive by several routes, and the list\n * has to cover all of them or the picker greys out a CLI the user just\n * installed:\n *\n * - **PowerShell one-liner installers.** `irm https://claude.ai/install.ps1 |\n * iex` writes a native `claude.exe` to `%USERPROFILE%\\.local\\bin`, and\n * OpenCode's writes to `%USERPROFILE%\\.opencode\\bin`. `.local\\bin` was the\n * conspicuous omission — it is in {@link posixBinDirs}, where the same\n * installer puts the same binary, and its absence here meant the officially\n * documented Windows install of the flagship runner was the one Ordewell\n * could not find.\n * - **Node package managers.** npm's global prefix, and pnpm's and Yarn's,\n * which are not under it.\n * - **Windows package managers.** Scoop and Chocolatey shim directories, and\n * WinGet's `Links` folder for portable packages (distinct from\n * `WindowsApps`, which is MSIX only).\n * - **Version managers.** Volta spells its home `%LOCALAPPDATA%\\Volta` here,\n * not `~/.volta` as it does on POSIX.\n */\nfunction windowsBinDirs(env: NodeJS.ProcessEnv, home: string): string[] {\n const join = (...parts: string[]) => path.win32.join(...parts);\n const under = (base: string | undefined, ...parts: string[]) => (base ? [join(base, ...parts)] : []);\n const appData = env.APPDATA;\n const localAppData = env.LOCALAPPDATA;\n const programData = env.ProgramData;\n\n return [\n // Native per-user installers, PowerShell-driven and otherwise.\n join(home, '.local', 'bin'),\n join(home, '.opencode', 'bin'),\n join(home, '.claude', 'bin'),\n join(home, '.codex', 'bin'),\n ...under(localAppData, 'Programs', 'claude'),\n\n // Node package managers. npm's global prefix is `%APPDATA%\\npm`; the\n // literal spelling is kept as a fallback for a host that does not export\n // APPDATA (a service account, a stripped CI container).\n ...under(appData, 'npm'),\n join(home, 'AppData', 'Roaming', 'npm'),\n ...under(localAppData, 'pnpm'),\n ...under(localAppData, 'Yarn', 'bin'),\n join(home, '.bun', 'bin'),\n\n // Windows package managers.\n join(home, 'scoop', 'shims'),\n ...under(env.SCOOP, 'shims'),\n ...under(env.SCOOP_GLOBAL ?? programData, 'scoop', 'shims'),\n ...under(programData, 'chocolatey', 'bin'),\n // WinGet portable packages land here; `WindowsApps` only ever holds MSIX\n // aliases, so both are needed and neither substitutes for the other.\n ...under(localAppData, 'Microsoft', 'WinGet', 'Links'),\n ...under(localAppData, 'Microsoft', 'WindowsApps'),\n\n // Version managers. Volta's Windows home is not the POSIX `~/.volta`.\n ...under(localAppData, 'Volta', 'bin'),\n join(home, '.volta', 'bin'),\n ];\n}\n\n/**\n * Exported for test: the Windows arm cannot be exercised from a Linux CI box\n * through {@link augmentedPath}, which reads `process.platform` and the real\n * environment. Production always calls it through the no-argument form.\n */\nexport function wellKnownBinDirs(deps: { platform?: NodeJS.Platform; env?: NodeJS.ProcessEnv; home?: string } = {}): string[] {\n const platform = deps.platform ?? process.platform;\n if (platform !== 'win32') return posixBinDirs();\n return [...new Set(windowsBinDirs(deps.env ?? process.env, deps.home ?? os.homedir()))];\n}\n\nasync function loginShellPath(execImpl: ExecFn): Promise<string | null> {\n if (process.platform === 'win32') return null;\n const shell = process.env.SHELL || '/bin/sh';\n try {\n // Markers isolate $PATH from any profile noise (motd, echo in .zprofile…).\n const { stdout } = await execImpl(\n `${shell} -l -c 'echo \"${PATH_MARKER}$PATH${PATH_MARKER}\"'`,\n { timeout: LOGIN_SHELL_TIMEOUT_MS },\n );\n const match = stdout.match(new RegExp(`${PATH_MARKER}([^\\\\n]*)${PATH_MARKER}`));\n return match?.[1] || null;\n } catch {\n return null;\n }\n}\n\nlet cachedPath: Promise<string> | null = null;\n\n/**\n * The augmented PATH for spawning user-installed CLI tools. Resolved once per\n * process and cached (the login shell query costs ~50-200ms).\n */\nexport function augmentedPath(execImpl: ExecFn = defaultExec): Promise<string> {\n if (!cachedPath) {\n cachedPath = (async () => {\n const segments: string[] = [];\n const push = (p: string | null | undefined) => {\n if (!p) return;\n for (const seg of p.split(path.delimiter)) {\n if (seg && !segments.includes(seg)) segments.push(seg);\n }\n };\n push(process.env.PATH);\n push(await loginShellPath(execImpl));\n for (const dir of wellKnownBinDirs()) push(dir);\n return segments.join(path.delimiter);\n })();\n }\n return cachedPath;\n}\n\n/** Test seam: drop the per-process cache so the next call re-resolves. */\nexport function clearAugmentedPathCache(): void {\n cachedPath = null;\n}\n\n/**\n * Build a child environment whose PATH is `resolvedPath`, with exactly one\n * PATH-ish key in it.\n *\n * `{ ...process.env, PATH }` is the obvious spelling and it is wrong on\n * Windows. Node's `process.env` is a case-insensitive proxy, but spreading it\n * yields the OS's actual casing — `Path` — so adding `PATH` produces an\n * environment block carrying both. Which one the child sees is undefined, and\n * the loser is silently discarded. Every existing site passed the same value\n * under both keys, so the bug was latent rather than live; this makes it\n * impossible instead of unlikely.\n */\nexport function withPath(\n base: NodeJS.ProcessEnv,\n resolvedPath: string,\n overrides: Record<string, string> = {},\n): NodeJS.ProcessEnv {\n const env: NodeJS.ProcessEnv = {};\n // Both sources are filtered, not just `base`: an `overrides` map carrying its\n // own PATH is exactly how the duplicate reappears.\n for (const source of [base, overrides]) {\n for (const [key, value] of Object.entries(source)) {\n if (key.toLowerCase() === 'path') continue;\n env[key] = value;\n }\n }\n // Windows canonically spells it `Path`; POSIX requires `PATH`. Matching the\n // platform keeps anything downstream that reads the raw block unsurprised.\n env[process.platform === 'win32' ? 'Path' : 'PATH'] = resolvedPath;\n return env;\n}\n","import * as fsSync from 'fs';\nimport * as path from 'path';\nimport { buildShellInvocation } from './shell';\nimport { augmentedPath } from './shellPath';\n\n/**\n * How a runner or planner CLI is started on this operating system.\n *\n * Every surface that starts an external agent — the VS Code terminal, the\n * headless runner, each harness-planner adapter, Codex model discovery — asks\n * this module rather than deciding for itself. Before it existed, four call\n * sites each did `spawn('claude', args)`, which is correct on POSIX (execvp\n * searches PATH) and broken on Windows, where CreateProcess performs no PATHEXT\n * lookup: an npm-installed `claude` is `claude.cmd`, so the spawn failed with\n * ENOENT while `RunnerInstallation`'s `exec` probe — which does go through\n * cmd.exe — reported the runner installed and healthy.\n *\n * Every path operation in the Windows branch goes through `path.win32`\n * explicitly rather than the host-flavoured `path`. On a real Windows host they\n * are the same object, so production is unaffected — but it makes the Windows\n * logic independent of where the process runs, which is the only way the\n * behavior can be pinned by a test on a Linux CI box. Host `path` is used for\n * nothing here.\n *\n * There are three Windows routes, tried in this order because it is the order\n * that gets to a directly-spawnable file soonest: a native `.exe`, a `.cmd`\n * shim through cmd.exe, a `.ps1` shim through `powershell.exe -File`. The\n * ordering is what keeps the common case off an interpreter, and off the\n * 8191-character buffer cmd.exe brings with it.\n *\n * The batch route is skipped outright for a multi-line argument: cmd.exe stops\n * reading at the first line break and discards the rest without an error — see\n * {@link EmbeddedNewlineError}.\n *\n * `-File` is chosen over `-Command` for the PowerShell tier because it evaluates\n * nothing: the script path and the arguments after it are strings, so a prompt\n * containing `$(…)` is data rather than PowerShell source. Argument fidelity\n * there — embedded newlines, backticks, `%VAR%` — is verified on a Windows host.\n *\n * POSIX behavior is deliberately identity. `planDirectLaunch` hands back the\n * command and args untouched, and `planShellLaunch` produces exactly the\n * `bash -lc` invocation it always did, so nothing about macOS or Linux changes.\n * All of the machinery below is reached only when `platform === 'win32'`.\n */\n\n/** Extensions CreateProcess can start on its own, in preference order. */\nconst DIRECT_EXTENSIONS = ['.exe', '.com'];\n\n/**\n * Extensions only a command interpreter can start. Node refuses to spawn these\n * without `shell: true` (CVE-2024-27980), so they route through cmd.exe.\n */\nconst BATCH_EXTENSIONS = ['.cmd', '.bat'];\n\n/**\n * Extensions only PowerShell can start. Reached last, and only when neither a\n * native executable nor a batch shim exists.\n *\n * Every Node package manager that writes a `.ps1` shim writes a `.cmd` beside\n * it, so on those installs this tier is never selected — it is here for the\n * install shapes that do not: a PowerShell installer that dropped a script\n * rather than a binary, a hand-rolled shim, a tool distributed as a module.\n * The alternative for those is a bare `spawn ENOENT` naming a command the user\n * can plainly see is installed.\n *\n * `.ps1` is deliberately not filtered against PATHEXT. Windows' default\n * PATHEXT does not list it — PowerShell resolves scripts itself rather than\n * through CreateProcess — so honouring PATHEXT here would exclude the tier on\n * exactly the machines it exists for.\n */\nconst POWERSHELL_EXTENSIONS = ['.ps1'];\n\n/**\n * cmd.exe's command-line buffer. A longer line is truncated rather than\n * rejected, which would corrupt a planner's system prompt or a task's prompt\n * mid-sentence and produce a confident answer to half a question — so the\n * batch route refuses instead. See {@link CommandLineTooLongError}.\n */\nexport const CMD_EXE_MAX_COMMAND_LINE = 8191;\n\n/**\n * CreateProcess's own ceiling, which the native and PowerShell routes are\n * bounded by instead. Windows truncates here too, so the same refusal applies —\n * it is simply four times further away.\n */\nexport const WINDOWS_MAX_COMMAND_LINE = 32767;\n\nexport interface LaunchPlan {\n /** The executable handed to `spawn()` or `vscode.window.createTerminal`. */\n file: string;\n /** Arguments for `file`. Pass verbatim when {@link verbatim} is set. */\n args: string[];\n /**\n * Windows batch route only: `args` is already a quoted command line and must\n * not be re-quoted. Maps to `windowsVerbatimArguments` for `spawn`, and to\n * the string form of `shellArgs` for a VS Code terminal.\n */\n verbatim?: boolean;\n}\n\n/** Test seam: every OS touchpoint is injectable, and production uses the defaults. */\nexport interface LaunchDeps {\n platform?: NodeJS.Platform;\n /** The PATH executables are looked up on. Defaults to the augmented PATH. */\n resolvePath?: () => Promise<string>;\n /** True when `candidate` names an existing file. */\n exists?: (candidate: string) => boolean;\n /** Absolute path to the Windows command interpreter. */\n comSpec?: () => string;\n /** Absolute path to Windows PowerShell. */\n powerShell?: () => string;\n /** PATHEXT, as the environment reports it. */\n pathExt?: () => string;\n}\n\n/**\n * Windows PowerShell's fixed location. Resolved absolutely rather than by name\n * because this is a fallback route reached when PATH lookup has already\n * disappointed us once; `powershell.exe` remains as a last resort for a host\n * that does not export SystemRoot.\n */\nfunction defaultPowerShell(): string {\n const root = process.env.SystemRoot || process.env.windir;\n return root\n ? path.win32.join(root, 'System32', 'WindowsPowerShell', 'v1.0', 'powershell.exe')\n : 'powershell.exe';\n}\n\n/**\n * The flags every PowerShell shim invocation carries.\n *\n * `-NoProfile` is not a nicety: a user profile can print a banner into stdout,\n * which for the harness planners is a JSON-RPC stream. `-ExecutionPolicy\n * Bypass` applies to this process only and is what lets a shim run on the\n * default `Restricted` policy at all. `-File` must stay last — everything\n * after it is the script and its arguments.\n */\nconst POWERSHELL_FLAGS = ['-NoLogo', '-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', '-File'];\n\n/**\n * Thrown when a command's arguments do not fit the buffer of the only\n * interpreter that can start it. Windows truncates rather than rejecting, and a\n * system prompt cut off mid-sentence makes the planner answer half a question\n * confidently — the silent success this repo refuses — so this is raised\n * instead. `TaskOrchestrator.startTask` catches it and holds the task, so the\n * message is what the user reads: it names the fix, because they cannot infer\n * it from a truncated prompt.\n */\nexport class CommandLineTooLongError extends Error {\n constructor(readonly command: string, readonly length: number, readonly limit: number = CMD_EXE_MAX_COMMAND_LINE) {\n super(\n limit === CMD_EXE_MAX_COMMAND_LINE\n ? `Cannot start \"${command}\" on Windows: its arguments are ${length} characters, over cmd.exe's ${limit}-character limit.\\n\\n` +\n `Only a batch shim (${command}.cmd) was found on PATH, and a shim has to be started through cmd.exe. ` +\n `Install the native executable — Claude Code's Windows installer, Codex's release binary, or OpenCode's install script all provide one — ` +\n `and Ordewell will launch it directly, with no buffer in the way.`\n : `Cannot start \"${command}\" on Windows: its arguments are ${length} characters, over the ${limit}-character limit Windows places on any command line.\\n\\n` +\n `This is the OS ceiling rather than a shim's, so no reinstall avoids it. ` +\n `Shorten the task prompt, or turn off some planner mode toggles — each one appends to the system prompt the runner is started with.`,\n );\n this.name = 'CommandLineTooLongError';\n }\n}\n\n/**\n * Thrown when only a batch shim resolved for a multi-line argument. cmd.exe\n * reads up to the first CR/LF and discards the rest with no error and exit code\n * 0 — quoting does not help — so the agent would get the first paragraph of its\n * prompt without the completion marker instruction, then exit looking successful.\n */\nexport class EmbeddedNewlineError extends Error {\n constructor(readonly command: string) {\n super(\n `Cannot start \"${command}\" on Windows: its prompt spans multiple lines, and the only launcher found on PATH was a batch shim (${command}.cmd).\\n\\n` +\n `cmd.exe stops reading a command line at the first line break and silently discards the rest, so the agent would be handed a prompt cut off at its first blank line — no plan map, no prior task output, and no completion marker, which is what Ordewell watches for to know the task finished.\\n\\n` +\n `Install the native executable — Claude Code's Windows installer, Codex's release binary, or OpenCode's install script all provide one — and Ordewell will launch it directly, with no interpreter in the way. A PowerShell shim (${command}.ps1) beside the batch one is also enough.`,\n );\n this.name = 'EmbeddedNewlineError';\n }\n}\n\nfunction hasLineBreak(parts: string[]): boolean {\n return parts.some((part) => /[\\r\\n]/.test(part));\n}\n\nfunction defaultExists(candidate: string): boolean {\n try {\n return fsSync.statSync(candidate).isFile();\n } catch {\n return false;\n }\n}\n\n/**\n * Quote one argument for cmd.exe.\n *\n * The backslash rule is the documented CommandLineToArgvW inverse: a run of\n * backslashes is only doubled when it precedes a quote we are adding or\n * escaping, which is why a trailing `C:\\repo\\` has to be handled separately\n * from one in the middle of an argument.\n *\n * `%` is NOT escaped, because in a `cmd /c` context it cannot be: `%%` is a\n * batch-file construct, and `^%` still expands. An argument naming a defined\n * environment variable (`%PATH%`) is therefore expanded by cmd.exe on the batch\n * route. Preferring a native executable — which this module always does — skips\n * cmd.exe and the hazard with it.\n */\nfunction quoteForCmd(arg: string): string {\n if (arg === '') return '\"\"';\n if (!/[\\s\"^&|<>()]/.test(arg)) return arg;\n\n let quoted = '\"';\n let backslashes = 0;\n for (const ch of arg) {\n if (ch === '\\\\') {\n backslashes++;\n continue;\n }\n if (ch === '\"') {\n quoted += '\\\\'.repeat(backslashes * 2 + 1) + '\"';\n backslashes = 0;\n continue;\n }\n quoted += '\\\\'.repeat(backslashes) + ch;\n backslashes = 0;\n }\n return `${quoted}${'\\\\'.repeat(backslashes * 2)}\"`;\n}\n\n/** The verbatim command line cmd.exe receives after `/d /s /c`, before wrapping. */\nexport function windowsCommandLine(file: string, args: string[]): string {\n return [file, ...args].map(quoteForCmd).join(' ');\n}\n\n/**\n * The `/d /s /c` argument list for a command line, wrapped the one way cmd.exe\n * can be relied on to unwrap.\n *\n * The outer quote pair is not decoration. With `/s`, cmd's documented rule is:\n * if the first character after `/c` is a quote, strip that quote and the *last*\n * quote on the whole line, then take everything between them verbatim. Handing\n * it a bare line whose first token is a quoted path — `\"C:\\Program\n * Files\\nodejs\\claude.cmd\" -p \"go\"` — therefore strips the opening quote of the\n * executable and the closing quote of the final argument, leaving cmd to run\n * `C:\\Program`. Any user whose name has a space in it hits this on the first\n * task. Wrapping the whole line makes the two quotes cmd removes the two we\n * added, which is what Node's own `shell: true` does for the same reason.\n */\nfunction cmdArgs(line: string): string[] {\n return ['/d', '/s', '/c', `\"${line}\"`];\n}\n\n/**\n * The extensions to try for `command`, in the order that gets us to a\n * directly-spawnable file soonest.\n *\n * Windows itself resolves per-directory (every PATHEXT tried in dir 1 before\n * dir 2), so a `claude.cmd` early on PATH would shadow a `claude.exe` later.\n * This searches by extension class instead — every directory for a `.exe`,\n * then every directory for a `.cmd`. Two installs of the same CLI are the same\n * program, so the global preference never selects a different tool, and it is\n * what keeps the common case off the batch route.\n */\nfunction candidateExtensions(command: string, pathExt: string): Record<Route, string[]> {\n const declared = pathExt.split(path.win32.delimiter).map((e) => e.trim().toLowerCase()).filter(Boolean);\n const known = new Set([...DIRECT_EXTENSIONS, ...BATCH_EXTENSIONS, ...POWERSHELL_EXTENSIONS, ...declared]);\n const ext = path.win32.extname(command).toLowerCase();\n\n // An explicit extension is a request, not a hint: honour it and search no other.\n if (ext && known.has(ext)) {\n const route: Route = BATCH_EXTENSIONS.includes(ext) ? 'cmd'\n : POWERSHELL_EXTENSIONS.includes(ext) ? 'powershell'\n : 'direct';\n return { direct: [], cmd: [], powershell: [], [route]: [''] };\n }\n\n const declaredOr = (extensions: string[]) => {\n const filtered = extensions.filter((e) => declared.length === 0 || declared.includes(e));\n return filtered.length > 0 ? filtered : extensions;\n };\n return {\n direct: declaredOr(DIRECT_EXTENSIONS),\n cmd: declaredOr(BATCH_EXTENSIONS),\n // Not filtered: `.ps1` is absent from Windows' default PATHEXT by design.\n powershell: POWERSHELL_EXTENSIONS,\n };\n}\n\n/** How a resolved file has to be started. */\ntype Route = 'direct' | 'cmd' | 'powershell';\n\n/** Tried in this order — soonest to a directly-spawnable file wins. */\nconst ROUTES: Route[] = ['direct', 'cmd', 'powershell'];\n\ninterface FoundExecutable {\n file: string;\n route: Route;\n}\n\n/**\n * Every route `command` can be reached by on this host, best first.\n *\n * All of them rather than just the first, because the best route is not only a\n * function of preference: a batch shim that would overflow cmd.exe's buffer is\n * no route at all, and knowing a PowerShell shim sits beside it is what\n * separates a held task from a running one.\n */\nasync function findWindowsExecutables(command: string, deps: LaunchDeps): Promise<FoundExecutable[]> {\n const exists = deps.exists ?? defaultExists;\n const pathExt = (deps.pathExt ?? (() => process.env.PATHEXT ?? ''))();\n const byRoute = candidateExtensions(command, pathExt);\n\n // A command that already names a location is not a PATH lookup.\n const dirs = path.win32.basename(command) !== command\n ? [path.win32.dirname(path.win32.resolve(command))]\n : ((await (deps.resolvePath ?? augmentedPath)()) || '')\n .split(path.win32.delimiter)\n .map((d) => d.trim().replace(/^\"|\"$/g, ''))\n .filter(Boolean);\n\n const base = path.win32.basename(command);\n const found: FoundExecutable[] = [];\n for (const route of ROUTES) {\n outer: for (const ext of byRoute[route]) {\n for (const dir of dirs) {\n const candidate = path.win32.join(dir, `${base}${ext}`);\n if (exists(candidate)) {\n found.push({ file: candidate, route });\n break outer;\n }\n }\n }\n }\n return found;\n}\n\n/** Why a candidate was rejected: `tooLong` is fatal, `lineBreak` falls through to the next route. */\ntype Disqualified = { tooLong: number; limit: number } | { lineBreak: true };\n\nfunction planFor(found: FoundExecutable, args: string[], deps: LaunchDeps): LaunchPlan | Disqualified {\n if (found.route === 'direct') {\n const length = windowsCommandLine(found.file, args).length;\n return length > WINDOWS_MAX_COMMAND_LINE\n ? { tooLong: length, limit: WINDOWS_MAX_COMMAND_LINE }\n : { file: found.file, args };\n }\n\n if (found.route === 'cmd') {\n if (hasLineBreak([found.file, ...args])) return { lineBreak: true };\n\n const comSpec = (deps.comSpec ?? (() => process.env.ComSpec || 'cmd.exe'))();\n const cmdLine = cmdArgs(windowsCommandLine(found.file, args));\n // The budget is the line cmd.exe receives, so it is measured after wrapping\n // and with the interpreter's own path in it — not just the inner command.\n const length = [comSpec, ...cmdLine].join(' ').length;\n return length > CMD_EXE_MAX_COMMAND_LINE\n ? { tooLong: length, limit: CMD_EXE_MAX_COMMAND_LINE }\n : { file: comSpec, args: cmdLine, verbatim: true };\n }\n\n // PowerShell takes an ordinary argument vector, so Node's own quoting applies\n // and nothing here is verbatim. `-File` is the mode with no expression\n // evaluation: the script path and the arguments after it are strings, never\n // PowerShell source, so a prompt containing `$(…)` or a backtick is data.\n const shell = (deps.powerShell ?? defaultPowerShell)();\n const psArgs = [...POWERSHELL_FLAGS, found.file, ...args];\n const length = windowsCommandLine(shell, psArgs).length;\n return length > WINDOWS_MAX_COMMAND_LINE\n ? { tooLong: length, limit: WINDOWS_MAX_COMMAND_LINE }\n : { file: shell, args: psArgs };\n}\n\n/**\n * How to start `command` with `args` through `spawn()`, with no shell.\n *\n * POSIX returns its input unchanged — execvp already searches PATH, and adding\n * a resolution step there would be a new way for a working setup to break.\n *\n * Windows resolves the command against PATH × PATHEXT, preferring a native\n * executable (spawned directly) over a batch shim (through cmd.exe) over a\n * PowerShell script shim (through `powershell.exe -File`). A command that\n * resolves to nothing is returned unchanged, so the caller's existing ENOENT —\n * which names what the user typed — is what surfaces rather than a second,\n * vaguer error from here.\n *\n * The tiers are tried in preference order and the first that *fits* wins, with\n * one deliberate exception: an overflowing batch shim does not fall through to\n * PowerShell. Overflow means a very large prompt, which is precisely where\n * `-File` argument fidelity is least worth betting on, and where a clear held\n * task beats a plausibly-mangled one. So capacity does not reorder the tiers —\n * a `.ps1` beside a too-long `.cmd` still raises.\n *\n * A line break does reorder them: cmd.exe cannot carry one at any length, so a\n * `.ps1` beside a `.cmd` wins, and a lone `.cmd` raises.\n *\n * @throws {CommandLineTooLongError} when the selected route's buffer cannot\n * carry the arguments.\n * @throws {EmbeddedNewlineError} when the arguments span lines and only the\n * batch route resolved.\n */\nexport async function planDirectLaunch(\n command: string,\n args: string[],\n deps: LaunchDeps = {},\n): Promise<LaunchPlan> {\n if ((deps.platform ?? process.platform) !== 'win32') return { file: command, args };\n\n const found = await findWindowsExecutables(command, deps);\n if (found.length === 0) return { file: command, args };\n\n for (const candidate of found) {\n const plan = planFor(candidate, args, deps);\n if ('lineBreak' in plan) continue;\n if ('tooLong' in plan) throw new CommandLineTooLongError(command, plan.tooLong, plan.limit);\n return plan;\n }\n // Only the batch route declines for a line break, so exhausting the loop means\n // every candidate was that route.\n throw new EmbeddedNewlineError(command);\n}\n\n/**\n * How to start `command` for a surface that hands an executable and arguments\n * to a terminal — the VS Code runner today, a Windows TUI later.\n *\n * On POSIX this is the login shell, unchanged: `bash -lc` runs the user's\n * profile, which is how nvm/volta/asdf-managed runner binaries resolve at all.\n * Windows has no login-shell equivalent (its PATH comes from the registry and\n * is already inherited), so it takes the direct route instead. That is not just\n * a simplification: it means the runner's own exit code is the terminal's exit\n * code, rather than a `$LASTEXITCODE` that PowerShell propagates unreliably —\n * and the exit code is half of what {@link VerdictEngine} judges a task on.\n */\nexport async function planShellLaunch(\n command: string,\n args: string[],\n deps: LaunchDeps = {},\n): Promise<LaunchPlan> {\n if ((deps.platform ?? process.platform) === 'win32') return planDirectLaunch(command, args, deps);\n const { shellPath, shellArgs } = buildShellInvocation(command, args);\n return { file: shellPath, args: shellArgs };\n}\n","// eslint-disable-next-line no-control-regex\nconst ANSI_RE = /\\x1b\\[[0-9;]*[A-Za-z]|\\x1b\\][^\\x07]*\\x07|\\x1b[()][AB012]|\\r/g;\n\nexport function stripAnsi(text: string): string {\n return text.replace(ANSI_RE, '');\n}\n\nexport function posixShellQuote(s: string): string {\n return `'${s.replace(/'/g, `'\\\\''`)}'`;\n}\n\n/**\n * Wrap a command for execution inside a POSIX login shell, which is what\n * resolves runner binaries managed by nvm/volta/asdf.\n *\n * Deliberately POSIX-only. This used to take a `platform` and emit\n * `powershell.exe -Command \"'claude' '-p' '…'\"` for Windows, which PowerShell\n * cannot run at all: a quoted string in leading position is parsed in\n * expression mode, so the invocation died with a parse error before the runner\n * started — a task that failed instantly, every time, on that platform. Windows\n * has no login-shell equivalent to emulate (its PATH comes from the registry\n * and is already inherited), so {@link planShellLaunch} starts the runner\n * directly there instead of routing it through a shell. Platform choice belongs\n * to that function; this one only knows how to phrase the POSIX half.\n */\nexport function buildShellInvocation(\n command: string,\n args: string[],\n): { shellPath: string; shellArgs: string[] } {\n const inner = [command, ...args].map(posixShellQuote).join(' ');\n return { shellPath: '/bin/bash', shellArgs: ['-lc', inner] };\n}\n\n/**\n * Wrap a command in `script` to allocate the PTY some runners require when\n * headless; `-e` propagates the child's exit code so verification still works.\n *\n * POSIX-only by nature — there is no `script` on Windows, which\n * `HeadlessRunner`'s `hasScriptCmd` probe already discovers, so this is never\n * reached there.\n */\nexport function wrapWithPty(command: string, args: string[]): { command: string; args: string[] } {\n const inner = [command, ...args].map(posixShellQuote).join(' ');\n return { command: 'script', args: ['-q', '-e', '-f', '-c', inner, '/dev/null'] };\n}\n","import { execFile } from 'child_process';\nimport type { ChildProcess } from 'child_process';\n\n/**\n * Stopping an agent process, on every platform.\n *\n * POSIX gets the escalation it always had: SIGTERM, then SIGKILL after a grace\n * period. Windows has no signals — `ChildProcess.kill` calls TerminateProcess\n * on the direct child only — and on Windows the direct child is frequently not\n * the agent. A `claude.cmd` shim launched through cmd.exe puts an interpreter\n * between Ordewell and the `node cli.js` doing the work, so terminating the child\n * left the real agent running: still holding the workspace, still spending the\n * user's subscription, invisible to the surface that thought it had stopped.\n * `taskkill /T` walks the tree instead.\n *\n * Both paths are best-effort and idempotent by construction. A process that has\n * already exited is not an error here — every caller is on a dispose path.\n */\n\n/** Grace period between the polite stop and the forced one. */\nconst HARD_KILL_DELAY_MS = 5000;\n\nexport interface KillTreeDeps {\n platform?: NodeJS.Platform;\n /** Runs `taskkill`. Injected so the Windows path is testable off Windows. */\n execFileImpl?: (file: string, args: string[], cb: (err: Error | null) => void) => void;\n /** Schedules the forced kill. Injected so tests need no timers. */\n setTimeoutImpl?: (fn: () => void, ms: number) => { unref?: () => void };\n clearTimeoutImpl?: (handle: unknown) => void;\n}\n\nfunction defaultExecFile(file: string, args: string[], cb: (err: Error | null) => void): void {\n execFile(file, args, (err) => cb(err ?? null));\n}\n\n/**\n * Terminate `proc` and everything it started.\n *\n * Returns immediately; the forced follow-up (SIGKILL, or `taskkill /F`) is\n * scheduled and unref'd, so a disposed session is never the reason the host\n * process refuses to exit.\n */\nexport function killTree(proc: ChildProcess | null, deps: KillTreeDeps = {}): void {\n // `typeof … === 'number'`, not `!== null`: only a numeric exit code is\n // positive evidence the process is gone. A running child reports null, and an\n // object that reports neither is treated as running — the cost of a redundant\n // kill is nothing, the cost of skipping a live one is an orphaned agent.\n if (!proc || proc.killed || typeof proc.exitCode === 'number') return;\n\n const platform = deps.platform ?? process.platform;\n const setTimeoutImpl = deps.setTimeoutImpl ?? ((fn, ms) => setTimeout(fn, ms) as unknown as { unref?: () => void });\n const clearTimeoutImpl = deps.clearTimeoutImpl ?? ((h) => clearTimeout(h as NodeJS.Timeout));\n\n if (platform === 'win32') {\n // No pid means the process never started; there is no tree to walk.\n if (typeof proc.pid !== 'number') return;\n const pid = proc.pid;\n const run = deps.execFileImpl ?? defaultExecFile;\n\n // `/T` is the whole point: without it this is the TerminateProcess call\n // that already failed to reach the agent. The unforced pass first gives a\n // console app a chance to flush; `/F` follows if it did not take.\n run('taskkill', ['/pid', String(pid), '/T'], () => { /* exit code is not news */ });\n const hardKill = setTimeoutImpl(() => {\n run('taskkill', ['/pid', String(pid), '/T', '/F'], () => { /* already gone */ });\n }, HARD_KILL_DELAY_MS);\n hardKill.unref?.();\n proc.once('exit', () => clearTimeoutImpl(hardKill));\n return;\n }\n\n try {\n proc.kill('SIGTERM');\n const hardKill = setTimeoutImpl(() => {\n try { proc.kill('SIGKILL'); } catch { /* already gone */ }\n }, HARD_KILL_DELAY_MS);\n hardKill.unref?.();\n proc.once('exit', () => clearTimeoutImpl(hardKill));\n } catch {\n // Process already gone — nothing to clean up.\n }\n}\n","import * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as os from \"os\";\nexport interface CatalogModel {\n id: string;\n name: string;\n description: string;\n pricing: { prompt: string; completion: string };\n contextLength: number;\n}\n\ninterface OpenRouterModel {\n id: string;\n name: string;\n description?: string;\n pricing?: { prompt: string; completion: string };\n context_length?: number;\n}\n\nconst CACHE_KEY = 'model-catalog';\nconst CACHE_TTL_MS = 60 * 60 * 1000; // 1 hour\n\nfunction storageKey(baseUrl: string): string {\n return `${CACHE_KEY}:${baseUrl}`;\n}\n\nexport class ModelCatalog {\n static async fetchModels(apiKey: string, baseUrl?: string, fetchImpl?: typeof fetch): Promise<CatalogModel[]> {\n const url = (baseUrl || 'https://openrouter.ai/api/v1').replace(/\\/+$/, '');\n // An injected fetch means the resolver owns caching — bypass the file cache\n // so callers (and tests) get exactly what the seam returns.\n const useFileCache = !fetchImpl;\n if (useFileCache) {\n const cached = this.readCache(storageKey(url));\n if (cached) {\n try {\n return JSON.parse(cached) as CatalogModel[];\n } catch { /* empty */ }\n }\n }\n\n // OpenRouter's /models endpoint is public, so the catalog can be fetched\n // without a key. Only send Authorization when we actually have one.\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n if (apiKey) headers.Authorization = `Bearer ${apiKey}`;\n const response = await (fetchImpl ?? fetch)(`${url}/models`, { headers });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch models: ${response.status} ${response.statusText}`);\n }\n\n const data = (await response.json()) as { data?: OpenRouterModel[] };\n const models: CatalogModel[] = (data.data ?? []).map((m) => ({\n id: m.id,\n name: m.name,\n description: m.description ?? '',\n pricing: {\n prompt: m.pricing?.prompt ?? '?',\n completion: m.pricing?.completion ?? '?',\n },\n contextLength: m.context_length ?? 0,\n }));\n\n if (useFileCache) this.writeCache(storageKey(url), models);\n return models;\n }\n\n /**\n * Delete the on-disk catalog cache for a base URL so the next fetch re-runs.\n * Used by the resolver's `invalidate()` in production (no injected fetch);\n * best-effort — a missing file or unreadable dir is a no-op.\n */\n static clearCache(baseUrl?: string): void {\n try {\n const url = (baseUrl || 'https://openrouter.ai/api/v1').replace(/\\/+$/, '');\n const key = storageKey(url);\n const cacheDir = path.join(os.homedir(), '.config', 'ordewell');\n const cacheFile = path.join(cacheDir, `${key.replace(/[:/]/g, '_')}.json`);\n if (fs.existsSync(cacheFile)) fs.rmSync(cacheFile);\n } catch { /* empty */ }\n }\n\n private static readCache(key: string): string | null {\n try {\n const cacheDir = path.join(os.homedir(), '.config', 'ordewell');\n const cacheFile = path.join(cacheDir, `${key.replace(/[:/]/g, '_')}.json`);\n if (!fs.existsSync(cacheFile)) return null;\n const raw = fs.readFileSync(cacheFile, 'utf8');\n const data = JSON.parse(raw);\n if (Date.now() - data.cachedAt > CACHE_TTL_MS) return null;\n return JSON.stringify(data.models);\n } catch {\n return null;\n }\n }\n\n private static writeCache(key: string, models: CatalogModel[]): void {\n try {\n const cacheDir = path.join(os.homedir(), '.config', 'ordewell');\n fs.mkdirSync(cacheDir, { recursive: true });\n const cacheFile = path.join(cacheDir, `${key.replace(/[:/]/g, '_')}.json`);\n fs.writeFileSync(\n cacheFile,\n JSON.stringify({ models, cachedAt: Date.now() }, null, 2)\n );\n } catch { /* empty */ }\n }\n}\n","export interface ModelShortcut {\n label: string;\n id: string;\n provider: string;\n description: string;\n pricing?: string;\n}\n\nexport function extractProvider(modelId: string): string {\n const slash = modelId.indexOf('/');\n if (slash < 0) return '';\n return modelId.slice(0, slash);\n}\n\nexport function groupByProvider<T extends { id: string }>(items: T[], extract?: (item: T) => string): Map<string, T[]> {\n const grouped = new Map<string, T[]>();\n for (const item of items) {\n const provider = extract ? extract(item) : extractProvider(item.id);\n const key = provider || 'Other';\n if (!grouped.has(key)) grouped.set(key, []);\n grouped.get(key)!.push(item);\n }\n return grouped;\n}\n\nexport const ORCHESTRATOR_SHORTCUTS: ModelShortcut[] = [\n { label: 'DeepSeek V4 Flash', id: 'deepseek/deepseek-v4-flash', provider: 'OpenRouter', description: 'Best all-around — strong coding, cheap', pricing: '0.09/0.18' },\n { label: 'DeepSeek R1', id: 'deepseek/deepseek-r1', provider: 'OpenRouter', description: 'Reasoning model — complex logic, zero-cost thinking tokens', pricing: '0.55/2.19' },\n { label: 'Claude Sonnet 4', id: 'anthropic/claude-sonnet-4', provider: 'OpenRouter', description: 'Top-tier reasoning, careful editing', pricing: '3/15' },\n { label: 'Claude Opus 4', id: 'anthropic/claude-opus-4.7', provider: 'OpenRouter', description: 'Strongest overall — complex refactoring, architecture', pricing: '15/75' },\n { label: 'GPT-4o', id: 'openai/gpt-4o', provider: 'OpenRouter', description: 'General purpose, strong multimodal', pricing: '2.50/10' },\n { label: 'GPT-4.1', id: 'openai/gpt-4.1', provider: 'OpenRouter', description: 'Latest GPT — strong coding, 1M context', pricing: '2/8' },\n { label: 'Kimi K2.6', id: 'moonshot/kimi-k2.6', provider: 'OpenRouter', description: 'Strong coding, cheap', pricing: '0.60/2.40' },\n { label: 'Qwen 3 Max', id: 'qwen/qwen3-max', provider: 'OpenRouter', description: 'Strong open model', pricing: '0.80/3.20' },\n];\n\nexport function resolveModelShortcut(input: string, shortcuts: ModelShortcut[]): string | null {\n for (const s of shortcuts) {\n if (s.id === input) return s.id;\n if (s.label.toLowerCase() === input.toLowerCase()) return s.id;\n }\n return null;\n}\n\n/**\n * Resolves a value to a model id ONLY when it is in the supplied catalog\n * option list — either directly or via a shortcut label. Free-typed, unknown,\n * or not-currently-available values return null, so callers never store an id\n * the user couldn't have selected from the list. Keeps model-setting list-only.\n */\nexport function knownModelId(value: string, optionIds: string[], shortcuts: ModelShortcut[]): string | null {\n if (!value) return null;\n const viaShortcut = resolveModelShortcut(value, shortcuts);\n if (viaShortcut && optionIds.includes(viaShortcut)) return viaShortcut;\n return optionIds.includes(value) ? value : null;\n}\n","import type { AiProvider } from '../interfaces/IConfig';\nimport { PROVIDER_PRIORITY, getProviderMeta, prefixModelId } from './ProviderRegistry';\n\nexport type ProviderModelLists = Record<string, string[]>;\n\nexport interface OrchestratorOption {\n id: string;\n label: string;\n provider: string;\n apiProvider: AiProvider;\n description?: string;\n pricing?: string;\n}\n\nimport type { CatalogModel } from './ModelCatalog';\nimport type { DiscoveredModel } from '../models/Task';\nimport type { ModelShortcut } from './ModelShortcuts';\nimport { extractProvider } from './ModelShortcuts';\nimport { ModelCatalog } from './ModelCatalog';\nimport { discoverGeminiModels } from './ModelDiscovery';\n\nexport interface FetchAllProviderModelsOptions {\n apiKeys: Record<string, string>;\n baseUrls: Record<string, string>;\n fetchImpl?: typeof fetch;\n}\n\nexport type AllProviderModels = Record<string, CatalogModel[]>;\n\n/**\n * Result of a picker-catalog fetch fan-out: the per-provider model lists plus\n * the per-provider failures. `errors` is keyed by provider id and holds the\n * failure message for any provider whose catalog fetch rejected — the seam the\n * surfaces (CLI, VS Code) use to flag \"this configured provider didn't work\"\n * rather than silently showing a short list.\n */\nexport interface ProviderModelsResult {\n models: AllProviderModels;\n errors: Record<string, string>;\n}\n\n/** The provider config fields the discovery fan-out needs. */\nexport interface ProviderCredentialSource {\n getProviderApiKey(provider: AiProvider): string;\n getProviderBaseUrl(provider: AiProvider): string;\n openaiCompatibleBaseUrl: string;\n}\n\n/**\n * Collect the API keys and base URLs the picker fan-out should probe, applying\n * the single \"configured\" policy shared by every surface (CLI + VS Code):\n * - a preset is discovered only when it has an API key (OpenRouter included —\n * its public catalog is not probed keyless, matching the product rule that\n * only key-configured providers appear);\n * - `openai_compatible` is discovered only when an explicit endpoint is set\n * (keyless local servers like ollama / LM Studio).\n * Base URLs are handed through only for providers that pass the gate, so the\n * fan-out never touches an unconfigured third-party endpoint.\n */\nexport function collectProviderCredentials(config: ProviderCredentialSource): {\n apiKeys: Record<string, string>;\n baseUrls: Record<string, string>;\n} {\n const apiKeys: Record<string, string> = {};\n const baseUrls: Record<string, string> = {};\n for (const provider of PROVIDER_PRIORITY) {\n const key = config.getProviderApiKey(provider);\n if (key) apiKeys[provider] = key;\n }\n for (const provider of PROVIDER_PRIORITY) {\n const url = config.getProviderBaseUrl(provider);\n if (!url) continue;\n if (provider === 'openai_compatible') {\n if (config.openaiCompatibleBaseUrl) baseUrls[provider] = url;\n } else if (apiKeys[provider]) {\n baseUrls[provider] = url;\n }\n }\n return { apiKeys, baseUrls };\n}\n\nfunction discoveredToCatalog(m: DiscoveredModel): CatalogModel {\n return {\n id: m.modelId,\n name: m.modelLabel,\n description: '',\n pricing: { prompt: '?', completion: '?' },\n contextLength: 0,\n };\n}\n\nexport async function fetchAllProviderModels(\n opts: FetchAllProviderModelsOptions,\n): Promise<ProviderModelsResult> {\n const entries: [string, () => Promise<CatalogModel[]>][] = [];\n\n for (const provider of PROVIDER_PRIORITY) {\n const meta = getProviderMeta(provider);\n if (!meta || !meta.discoversModels) continue;\n\n if (provider === 'google') {\n if (!opts.apiKeys[provider]) continue;\n entries.push([\n provider,\n async () => {\n const models = await discoverGeminiModels(\n opts.apiKeys[provider],\n opts.baseUrls[provider] || undefined,\n opts.fetchImpl,\n );\n return models.map(discoveredToCatalog);\n },\n ]);\n } else if (provider === 'openrouter') {\n // OpenRouter's catalog is technically public, but the product rule is\n // \"only providers with a key set are shown\", so it needs a key like any\n // other preset.\n if (!opts.apiKeys[provider]) continue;\n entries.push([\n provider,\n async () =>\n ModelCatalog.fetchModels(\n opts.apiKeys[provider],\n opts.baseUrls[provider] || undefined,\n opts.fetchImpl,\n ),\n ]);\n } else {\n const baseUrl = opts.baseUrls[provider];\n const apiKey = opts.apiKeys[provider];\n if (!baseUrl) continue;\n entries.push([\n provider,\n async () =>\n ModelCatalog.fetchModels(\n apiKey ?? '',\n baseUrl,\n opts.fetchImpl,\n ),\n ]);\n }\n }\n\n const results = await Promise.allSettled(entries.map(([, fn]) => fn()));\n const models: AllProviderModels = {};\n const errors: Record<string, string> = {};\n\n for (let i = 0; i < entries.length; i++) {\n const [provider] = entries[i];\n const result = results[i];\n if (result.status === 'fulfilled') {\n models[provider] = result.value;\n } else {\n models[provider] = [];\n const reason = result.reason;\n errors[provider] = reason instanceof Error ? reason.message : String(reason);\n }\n }\n\n return { models, errors };\n}\n\nexport function resolveProvider(\n modelId: string,\n providerModelLists: Record<string, string[]>,\n): AiProvider | null {\n for (const provider of PROVIDER_PRIORITY) {\n const list = providerModelLists[provider];\n if (list && list.includes(modelId)) return provider;\n }\n return null;\n}\n\nfunction perMTok(prompt: string, completion: string): string | undefined {\n const p = parseFloat(prompt);\n const c = parseFloat(completion);\n if (!isFinite(p) || !isFinite(c)) return undefined;\n const fmt = (n: number) => String(+(n * 1_000_000).toFixed(2));\n return `${fmt(p)}/${fmt(c)}`;\n}\n\nexport function toOrchestratorOptions(\n providerModels: AllProviderModels,\n shortcuts: ModelShortcut[],\n): OrchestratorOption[] {\n const seen = new Set<string>();\n const options: OrchestratorOption[] = [];\n const shortcutById = new Map(shortcuts.map((s) => [s.id, s]));\n\n for (const provider of PROVIDER_PRIORITY) {\n const models = providerModels[provider];\n if (!models || models.length === 0) continue;\n\n for (const m of models) {\n const id = prefixModelId(provider, m.id);\n if (seen.has(id)) continue;\n seen.add(id);\n\n const s = shortcutById.get(id);\n let providerLabel: string;\n let pricing: string | undefined;\n\n if (provider === 'openrouter') {\n const rawProvider = extractProvider(m.id);\n providerLabel = s?.provider\n || (rawProvider ? rawProvider.charAt(0).toUpperCase() + rawProvider.slice(1) : 'OpenRouter');\n const livePricing = m.pricing?.prompt && m.pricing?.completion\n ? perMTok(m.pricing.prompt, m.pricing.completion)\n : undefined;\n pricing = livePricing ?? s?.pricing;\n } else {\n const meta = getProviderMeta(provider);\n providerLabel = s?.provider || meta?.shortLabel || provider;\n pricing = s?.pricing;\n }\n\n options.push({\n id,\n label: s?.label || m.name || m.id,\n provider: providerLabel,\n apiProvider: provider,\n description: s?.description || m.description || undefined,\n pricing,\n });\n }\n }\n\n const shortcutOrder = new Map(shortcuts.map((s, i) => [s.id, i]));\n return [\n ...options.filter((o) => shortcutOrder.has(o.id)).sort((a, b) => shortcutOrder.get(a.id)! - shortcutOrder.get(b.id)!),\n ...options.filter((o) => !shortcutOrder.has(o.id)),\n ];\n}\n","import { ModelDiscovery, clearGeminiCache, type ExecImpl } from './ModelDiscovery';\nimport { ModelCatalog } from './ModelCatalog';\nimport type { RunnerRegistry } from '../plugins/RunnerRegistry';\nimport type { IConfig } from '../interfaces/IConfig';\nimport type { DiscoveredModel, RunnerId } from '../models/Task';\nimport { fetchAllProviderModels, collectProviderCredentials, toOrchestratorOptions, type OrchestratorOption, type ProviderModelLists } from './ProviderRouting';\nimport { ORCHESTRATOR_SHORTCUTS } from './ModelShortcuts';\nimport { PROVIDER_PRIORITY } from './ProviderRegistry';\n\nexport interface ModelResolverDeps {\n fetchImpl?: typeof fetch;\n execImpl?: ExecImpl;\n}\n\nexport class ModelResolver {\n private discovery: ModelDiscovery;\n private fetchImpl?: typeof fetch;\n private cachedPickerOptions: OrchestratorOption[] | null = null;\n private lastDiscoveryErrors: Record<string, string> = {};\n\n constructor(\n private registry: RunnerRegistry,\n private config: IConfig,\n deps: ModelResolverDeps = {}\n ) {\n this.discovery = new ModelDiscovery(registry, deps.execImpl, deps.fetchImpl);\n this.fetchImpl = deps.fetchImpl;\n }\n\n static builtinOptions(): OrchestratorOption[] {\n return toOrchestratorOptions({}, ORCHESTRATOR_SHORTCUTS);\n }\n\n async modelsForRunners(runners: RunnerId[]): Promise<Partial<Record<RunnerId, DiscoveredModel[]>>> {\n const out: Partial<Record<RunnerId, DiscoveredModel[]>> = {};\n for (const runner of runners) {\n try {\n out[runner] = await this.discovery.discover(runner);\n } catch {\n out[runner] = [];\n }\n }\n return out;\n }\n\n async pickerOptions(): Promise<OrchestratorOption[]> {\n if (this.cachedPickerOptions) return this.cachedPickerOptions;\n\n // Which endpoints to probe is one policy shared with every other surface —\n // see collectProviderCredentials (only key-configured providers, plus an\n // explicitly-pointed openai_compatible endpoint).\n const { apiKeys, baseUrls } = collectProviderCredentials(this.config);\n\n const { models, errors } = await fetchAllProviderModels({\n apiKeys,\n baseUrls,\n fetchImpl: this.fetchImpl,\n });\n this.lastDiscoveryErrors = errors;\n this.cachedPickerOptions = toOrchestratorOptions(models, ORCHESTRATOR_SHORTCUTS);\n return this.cachedPickerOptions;\n }\n\n /**\n * Per-provider failures from the most recent `pickerOptions()` fetch, keyed\n * by provider id. Empty when every configured provider's catalog loaded (or\n * before the first fetch). Surfaces consume this to flag a provider whose\n * key/endpoint is set but whose catalog could not be reached.\n */\n getDiscoveryErrors(): Record<string, string> {\n return this.lastDiscoveryErrors;\n }\n\n async refresh(): Promise<ProviderModelLists> {\n const options = await this.pickerOptions();\n const lists: ProviderModelLists = {};\n for (const provider of PROVIDER_PRIORITY) {\n lists[provider] = options.filter((o) => o.apiProvider === provider).map((o) => o.id);\n }\n this.config.setProviderModelLists(lists);\n return lists;\n }\n\n refreshRunnerModels(): void {\n this.discovery.clear();\n }\n\n invalidate(): void {\n this.discovery.clear();\n this.cachedPickerOptions = null;\n this.lastDiscoveryErrors = {};\n if (!this.fetchImpl) {\n for (const provider of PROVIDER_PRIORITY) {\n const baseUrl = this.config.getProviderBaseUrl(provider);\n if (baseUrl) ModelCatalog.clearCache(baseUrl);\n }\n clearGeminiCache(this.config.geminiKey);\n }\n }\n}\n","import { exec } from 'child_process';\nimport { promisify } from 'util';\nimport type { RunnerRegistry } from '../plugins/RunnerRegistry';\nimport { augmentedPath, withPath } from '../utils/shellPath';\nimport { planDirectLaunch } from '../utils/launch';\nimport type { ExecImpl } from './ModelDiscovery';\n\nconst execAsync = promisify(exec);\n\n// Installation checks must find `claude`/`opencode` wherever the user installed\n// them, even under the minimal PATH a GUI-launched host inherits — same\n// augmented-PATH rationale as ModelDiscovery.\nconst defaultExec: ExecImpl = async (command, options) => {\n const PATH = await augmentedPath();\n const { stdout } = await execAsync(command, { ...options, env: withPath(process.env, PATH) });\n return { stdout: String(stdout) };\n};\n\nconst CHECK_TIMEOUT_MS = 8000;\n\n/**\n * Runners with a harness-planner adapter (ADR-0009). Plugin runners are\n * deliberately absent: a manifest-level planner capability block, so user\n * plugins can declare themselves plannable, is a follow-up.\n */\nconst PLANNER_CAPABLE_RUNNERS = new Set(['claude-code', 'codex', 'opencode']);\n\n/**\n * Detects whether a runner's underlying CLI is actually installed on the host,\n * by invoking `<command> --version`. Mirrors ModelDiscovery: injectable exec,\n * augmented PATH, per-process cache. A runner that isn't installed should never\n * be offered for selection in any surface.\n */\nexport class RunnerInstallation {\n private cache: Map<string, boolean> = new Map();\n private inflight: Map<string, Promise<boolean>> = new Map();\n private registry: RunnerRegistry;\n private execImpl: ExecImpl;\n\n constructor(registry: RunnerRegistry, execImpl: ExecImpl = defaultExec) {\n this.registry = registry;\n this.execImpl = execImpl;\n }\n\n /** True if the runner's CLI responds to `--version`. Cached per process. */\n async isInstalled(runner: string): Promise<boolean> {\n if (this.cache.has(runner)) return this.cache.get(runner)!;\n\n const existing = this.inflight.get(runner);\n if (existing) return existing;\n\n const manifest = this.registry.getManifest(runner);\n const command = manifest?.runner.command;\n if (!command) {\n this.cache.set(runner, false);\n return false;\n }\n\n const probe = (async () => {\n try {\n await this.execImpl(`${command} --version`, { timeout: CHECK_TIMEOUT_MS });\n return true;\n } catch {\n return false;\n }\n })().then((installed) => {\n this.cache.set(runner, installed);\n this.inflight.delete(runner);\n return installed;\n });\n\n this.inflight.set(runner, probe);\n return probe;\n }\n\n /**\n * Whether this runner can serve as a harness planner (ADR-0009, T9), and why\n * not when it cannot. Surfaces call this to grey out an unusable agent in the\n * planner picker with the reason attached — discovering a missing CLI after\n * typing a real goal is the failure this exists to prevent.\n *\n * \"Usable\" is deliberately shallow: the binary answers `--version`, and the\n * runner declares a planner transport. Whether the user's subscription is\n * live cannot be known without spending a turn on it, so an expired login\n * surfaces where it actually bites — as the agent's own error text on the\n * first turn.\n */\n async plannerUsability(runner: string): Promise<{ usable: boolean; reason?: string }> {\n const manifest = this.registry.getManifest(runner);\n if (!manifest) return { usable: false, reason: `No runner manifest is registered for \"${runner}\".` };\n if (!PLANNER_CAPABLE_RUNNERS.has(runner)) {\n return { usable: false, reason: `${manifest.displayName ?? runner} has no planner transport yet.` };\n }\n if (!(await this.isInstalled(runner))) {\n return { usable: false, reason: `${manifest.runner.command} is not installed or is not on PATH.` };\n }\n const spawnable = await this.isSpawnable(manifest.runner.command);\n if (!spawnable) {\n return {\n usable: false,\n reason: `${manifest.runner.command} answers --version through a shell, but no file Ordewell can start directly was found on PATH. ` +\n `The planner speaks to the agent over stdio with no shell in between, so it needs a real executable or a .cmd/.bat shim. ` +\n `Reinstall with the CLI's own installer, or add its install directory to PATH.`,\n };\n }\n return { usable: true };\n }\n\n /**\n * Whether the CLI can be started the way the harness planner actually starts\n * it: `spawn` with no shell.\n *\n * `isInstalled` probes through `exec`, which goes through cmd.exe on Windows\n * and so happily resolves a `.cmd` shim — while the planner's own spawn does\n * not, because CreateProcess performs no PATHEXT lookup. That gap produced\n * the worst failure shape available: the picker reported the runner healthy,\n * then the session died on ENOENT with nothing to act on. POSIX has no such\n * split (`execvp` and `exec` search PATH identically), so this always agrees\n * with `isInstalled` there.\n */\n private async isSpawnable(command: string): Promise<boolean> {\n if (process.platform !== 'win32') return true;\n try {\n const plan = await planDirectLaunch(command, []);\n // An unresolvable command is handed back verbatim; anything else means a\n // real file was found, directly or behind the interpreter.\n return plan.file !== command;\n } catch {\n // A CommandLineTooLongError cannot happen with no arguments; anything\n // else here is a resolution failure, which is the answer.\n return false;\n }\n }\n\n /** Subset of the given runner ids whose CLI is installed. */\n async filterInstalled(runners: string[]): Promise<string[]> {\n const results = await Promise.all(\n runners.map(async (r) => ({ r, ok: await this.isInstalled(r) })),\n );\n return results.filter((x) => x.ok).map((x) => x.r);\n }\n\n clear(): void {\n this.cache.clear();\n this.inflight.clear();\n }\n}\n","import { spawn as nodeSpawn } from 'child_process';\nimport {\n type Task,\n type DiscoveredModel,\n type ResearchLogEntry,\n type ResearchProgress,\n type ResearchStep,\n type RunnerId,\n type LegacyPlanState,\n} from '../../models/Task';\nimport type { IConfig } from '../../interfaces/IConfig';\nimport type { IFileSystem } from '../../interfaces/IFileSystem';\nimport type { IWebFetcher } from '../../interfaces/IWebFetcher';\nimport type { RunnerModeInfo } from '../ModeResolver';\nimport type { IAiService, ConversationRequest, ConversationTurn } from '../AiService';\nimport {\n buildConversationSystemPrompt,\n buildPlanWithResults,\n buildModifyPlanPrompt,\n} from '../PlanPrompts';\nimport {\n classifyPlannerReply,\n generatePlanWithRepair,\n reEmitPlanPrompt,\n reEmitTaskOpsPrompt,\n} from '../PlanRepair';\nimport { extractPrdBlock } from '../../utils/prdStore';\nimport { runnerForProvider } from '../ProviderRegistry';\nimport { collectResearchContext } from '../ContextCollector';\nimport type { AgentAdapter, AgentEvent, AgentProcessDeps, AgentStartOptions } from './AgentAdapter';\nimport { ClaudeCodeAdapter } from './ClaudeCodeAdapter';\nimport { CodexAdapter } from './CodexAdapter';\nimport { OpenCodeAdapter } from './OpenCodeAdapter';\nimport { mapAgentTool, normalizeAgentArgs } from './agentTools';\nimport { DEFAULT_PLANNER_MODES, type PlannerModes } from '../plannerModes';\n\n/** Corrective re-emits allowed for botched JSON, matching the API backend. */\nconst MAX_JSON_REPAIRS = 2;\n\n/** Kept out of the reply text and the log; a long trace would drown both. */\nconst LOG_MAX_CHARS = 10000;\n\nexport interface CliAgentAiServiceDeps extends Partial<AgentProcessDeps> {\n /** Overrides adapter construction. Tests supply a fake agent; production picks by runner id. */\n createAdapter?: (runner: string, deps: AgentProcessDeps) => AgentAdapter | null;\n /** Workspace root the agent explores. Defaults to the host process's cwd. */\n workspaceRoot?: () => string;\n}\n\nfunction defaultAdapter(runner: string, deps: AgentProcessDeps): AgentAdapter | null {\n switch (runner) {\n case 'claude-code': return new ClaudeCodeAdapter(deps);\n case 'codex': return new CodexAdapter(deps);\n case 'opencode': return new OpenCodeAdapter(deps);\n default: return null;\n }\n}\n\n/** One completed harness turn, before classification. */\ninterface HarnessTurn {\n text: string;\n researchLog: ResearchStep[];\n /** The agent's own failure, verbatim. Present means the turn did not complete. */\n error?: string;\n aborted?: boolean;\n}\n\n/**\n * A coding agent driven as Ordewell's planner (ADR-0009).\n *\n * The second transport behind `IAiService`, sitting beside `OpenAiService` and\n * `GeminiService`. It deliberately does **not** extend {@link BaseAiService}:\n * that class's body is Ordewell executing research tools on a model's behalf,\n * which is precisely the part a coding agent replaces. What it reuses instead\n * is everything above the transport — `classifyPlannerReply`, the bounded\n * corrective re-emit loop, `parsePlanJson`, the `ResearchProgress` events the\n * four surfaces already render. That is why this backend reaches VS Code, the\n * web UI, the CLI and the TUI without any of them learning a coding agent is\n * on the other end.\n */\nexport class CliAgentAiService implements IAiService {\n private readonly runner: string;\n private readonly processDeps: AgentProcessDeps;\n private readonly makeAdapter: (runner: string, deps: AgentProcessDeps) => AgentAdapter | null;\n private readonly workspaceRoot: () => string;\n\n private adapter: AgentAdapter | null = null;\n /**\n * The agent's own session id, kept across a process death so the next turn\n * can resume warm context instead of re-reading the repository. Cleared at\n * every session boundary — nothing from one goal may reach the next.\n */\n private lastNativeSessionId: string | null = null;\n private conversation: { startOptions: AgentStartOptions; runners: RunnerId[]; runnerModes?: Record<RunnerId, RunnerModeInfo[]>; autonomousDefault?: boolean; prdEnabled: boolean; prdCaptured: boolean; prdNudgeSent: boolean } | null = null;\n private activeAbort: AbortController | null = null;\n\n constructor(private config: IConfig, deps: CliAgentAiServiceDeps = {}) {\n const runner = runnerForProvider(config.aiProvider);\n if (!runner) throw new Error(`${config.aiProvider} is not a coding-agent planner.`);\n this.runner = runner;\n this.processDeps = {\n spawn: deps.spawn ?? nodeSpawn,\n fetch: deps.fetch ?? globalThis.fetch,\n resolvePath: deps.resolvePath,\n platform: deps.platform,\n };\n this.makeAdapter = deps.createAdapter ?? defaultAdapter;\n this.workspaceRoot = deps.workspaceRoot ?? (() => process.cwd());\n }\n\n hasActiveConversation(): boolean { return this.conversation !== null; }\n\n /**\n * False when the running agent process was spawned under a model/effort the\n * user has since changed in the picker. Unlike a vendor backend, the model\n * is a spawn-time argument to the agent CLI (`--model`), not a per-request\n * field — `continueConversation` sends the next turn to whatever process is\n * already running, so a plain config read here would silently keep planning\n * on the old model. No conversation yet is vacuously \"current\".\n */\n conversationMatchesConfig(): boolean {\n if (!this.conversation) return true;\n return this.conversation.startOptions.model === this.plannerModel()\n && this.conversation.startOptions.effort === this.config.plannerThinkingEffort;\n }\n\n /** The agent's own session id, a resumption hint only — Ordewell's transcript is authoritative (T4). */\n nativeSessionId(): string | null { return this.adapter?.nativeSessionId() ?? null; }\n\n reset(): void {\n this.activeAbort?.abort();\n this.activeAbort = null;\n this.adapter?.dispose();\n this.adapter = null;\n // Session boundaries are hard (ADR-0008): the next goal must not resume\n // the previous goal's agent session.\n this.lastNativeSessionId = null;\n this.conversation = null;\n }\n\n // --- Conversation (ADR-0002) ---\n\n async startConversation(req: ConversationRequest): Promise<ConversationTurn> {\n this.reset();\n\n const contextStr = await collectResearchContext(req.fs, req.runners);\n const systemPrompt = buildConversationSystemPrompt(\n req.goal,\n contextStr,\n req.modelsByRunner,\n req.runners,\n req.runnerModes,\n req.autonomousDefault ?? true,\n req.grillMeEnabled ?? false,\n req.prdEnabled ?? false,\n req.reviewEnabled ?? false,\n req.verificationEnabled ?? false,\n true,\n );\n\n const startOptions: AgentStartOptions = {\n cwd: this.workspaceRoot(),\n systemPrompt,\n model: this.plannerModel(),\n effort: this.config.plannerThinkingEffort,\n };\n\n await this.startAdapter(startOptions);\n\n this.conversation = {\n startOptions,\n runners: req.runners,\n runnerModes: req.runnerModes,\n autonomousDefault: req.autonomousDefault,\n prdEnabled: req.prdEnabled ?? false,\n prdCaptured: false,\n prdNudgeSent: false,\n };\n\n // A reloaded session replays its transcript instead of re-running the\n // research the agent already paid for. The agent gets it as context, not\n // as turns: the reply we act on is the one the user's new message opens.\n const opening = this.openingMessage(req);\n return this.runConversation(opening, req.onProgress, req.signal);\n }\n\n async continueConversation(\n userMessage: string,\n onProgress: (progress: ResearchProgress) => void,\n signal?: AbortSignal,\n ): Promise<ConversationTurn> {\n if (!this.conversation) throw new Error('No active planner conversation. Start planning first.');\n return this.runConversation(userMessage, onProgress, signal);\n }\n\n private openingMessage(req: ConversationRequest): string {\n const history = req.priorHistory ?? [];\n if (history.length === 0) return req.initialMessage ?? req.goal;\n const transcript = history\n .map((m) => `${m.role === 'user' ? 'User' : 'You'}: ${m.content}`)\n .join('\\n\\n');\n return [\n 'This planning conversation is being resumed. Here is what has been said so far:',\n '',\n '<previous_conversation>',\n transcript,\n '</previous_conversation>',\n '',\n 'Continue from there. The user now says:',\n '',\n req.initialMessage ?? req.goal,\n ].join('\\n');\n }\n\n /**\n * Drive one user message to a settled planner turn. Same shape as the API\n * backend's conversation loop minus the tool rounds — those belong to the\n * agent now — and with the same three policies layered on top: the PRD gate,\n * the empty-reply nudge, and a bounded corrective re-emit for botched JSON.\n */\n private async runConversation(\n message: string,\n onProgress: (progress: ResearchProgress) => void,\n signal?: AbortSignal,\n ): Promise<ConversationTurn> {\n const conversation = this.conversation!;\n const combined = this.startAbortScope(signal);\n const researchLog: ResearchLogEntry[] = [];\n let pending = message;\n let emptyNudgeSent = false;\n let jsonRepairAttempts = 0;\n\n try {\n for (;;) {\n const turn = await this.runTurn(pending, onProgress, combined);\n researchLog.push(...turn.researchLog);\n\n if (turn.aborted || combined?.aborted) {\n onProgress({ type: 'interrupted' });\n return { kind: 'message', text: turn.text, researchLog };\n }\n\n // Fail visibly, per the repo's fail-safe contract: an agent that died,\n // hit its rate limit, or lost its login must say so in the chat rather\n // than leave an empty planner bubble.\n if (turn.error) {\n return { kind: 'message', text: turn.error, researchLog };\n }\n\n if (!turn.text.trim()) {\n // An agent whose tool was refused can end its turn on the refusal,\n // saying nothing. Naming it keeps the failure visible instead of\n // reporting a blank reply the user cannot act on.\n const refused = turn.researchLog.find((step) => step.outcome === 'denied');\n if (!emptyNudgeSent) {\n emptyNudgeSent = true;\n pending = refused\n ? `Your last reply was empty because \"${refused.toolLabel ?? refused.tool}\" was refused: you are planning read-only and confined to this workspace. Do not retry it. Answer the user now with what you already know, or ask your next question.`\n : 'Your last reply was empty. Respond to the user now: answer their last message directly, ask your next question, or emit the plan JSON.';\n continue;\n }\n return {\n kind: 'message',\n text: refused\n ? `The planner stopped without replying: \"${refused.toolLabel ?? refused.tool}\" was refused because planning is read-only and confined to this workspace.`\n : 'The planner returned an empty reply twice. Please rephrase or try again.',\n researchLog,\n };\n }\n\n if (extractPrdBlock(turn.text)) conversation.prdCaptured = true;\n\n const reply = classifyPlannerReply(turn.text, {\n runners: conversation.runners,\n runnerModes: conversation.runnerModes,\n autonomousDefault: conversation.autonomousDefault,\n });\n\n switch (reply.kind) {\n case 'task_ops':\n return { kind: 'task_ops', ops: reply.ops, text: turn.text, researchLog };\n\n case 'plan':\n if (conversation.prdEnabled && !conversation.prdCaptured && !conversation.prdNudgeSent && !combined?.aborted) {\n conversation.prdNudgeSent = true;\n pending = [\n 'PRD mode is enabled but no PRD has been produced yet, so the plan was NOT committed.',\n 'In your next reply: first output the full markdown PRD wrapped EXACTLY in',\n '<!-- ORDEWELL_PRD_START slug=\"<feature-slug>\" --> and <!-- ORDEWELL_PRD_END -->,',\n 'then re-emit the exact same task plan JSON after the PRD block.',\n ].join(' ');\n continue;\n }\n // A committed plan closes the conversation, matching the API\n // backend: post-plan chat re-enters through `startConversation`\n // with the plan's own transcript rather than inheriting this\n // session's context.\n this.conversation = null;\n return { kind: 'plan', tasks: reply.tasks, text: turn.text, researchLog };\n\n case 'broken_task_ops':\n if (jsonRepairAttempts < MAX_JSON_REPAIRS && !combined?.aborted) {\n jsonRepairAttempts++;\n pending = reEmitTaskOpsPrompt(reply.error.message);\n continue;\n }\n break;\n\n case 'broken_plan':\n if (jsonRepairAttempts < MAX_JSON_REPAIRS && !combined?.aborted) {\n jsonRepairAttempts++;\n pending = reEmitPlanPrompt(reply.error.message);\n continue;\n }\n break;\n\n case 'prose':\n break;\n }\n\n return { kind: 'message', text: turn.text, researchLog };\n }\n } finally {\n this.activeAbort = null;\n }\n }\n\n /**\n * Run one agent turn: stream its events into `ResearchProgress`, collect the\n * reply text, and return the research steps produced. Tool calls are matched\n * to their results by the agent's own call id — matching by tool name puts\n * one file's body on another file's row the moment an agent runs two reads\n * at once, which all three of these do routinely.\n */\n private async runTurn(\n message: string,\n onProgress: (progress: ResearchProgress) => void,\n signal?: AbortSignal,\n ): Promise<HarnessTurn> {\n const adapter = await this.ensureAdapter();\n const pendingCalls = new Map<string, { tool: ResearchStep['tool']; toolLabel?: string; args: string }>();\n const researchLog: ResearchStep[] = [];\n let text = '';\n let error: string | undefined;\n let stepIndex = 0;\n\n const truncate = (value: string) =>\n value.length > LOG_MAX_CHARS ? `${value.slice(0, LOG_MAX_CHARS)}\\n[... truncated, total ${value.length} chars]` : value;\n\n const settle = (id: string, output: string, success: boolean, outcome: ResearchStep['outcome']) => {\n const call = pendingCalls.get(id);\n pendingCalls.delete(id);\n const step: ResearchStep = {\n id: `rs-${Date.now()}-${stepIndex++}`,\n tool: call?.tool ?? 'agent_tool',\n toolLabel: call?.toolLabel,\n args: call?.args ?? '{}',\n result: truncate(output),\n success,\n outcome,\n toolCallId: id,\n timestamp: new Date().toISOString(),\n };\n researchLog.push(step);\n onProgress({ type: 'tool_result', toolResult: output, step, toolCallId: id });\n };\n\n await adapter.send(message, (event: AgentEvent) => {\n switch (event.type) {\n case 'assistant_text':\n text += event.text;\n onProgress({ type: 'plan_token', planToken: event.text });\n return;\n\n case 'thinking':\n onProgress({ type: 'thinking', text: event.text });\n return;\n\n case 'tool_call': {\n const mapped = mapAgentTool(event.name);\n const args = JSON.stringify(normalizeAgentArgs(mapped.tool, event.args));\n pendingCalls.set(event.id, { tool: mapped.tool, toolLabel: mapped.toolLabel, args });\n onProgress({ type: 'tool_call', tool: mapped.tool, toolLabel: mapped.toolLabel, toolArgs: args, toolCallId: event.id });\n return;\n }\n\n case 'tool_result':\n settle(event.id, event.output, event.success, event.success ? 'success' : 'failure');\n return;\n\n case 'permission_request': {\n // Auto-denied, always (T1). The request is still announced so the\n // user can see the planner reached for something it may not have —\n // a silently swallowed denial reads as the agent losing interest.\n const mapped = mapAgentTool(event.name);\n const args = JSON.stringify({ detail: event.detail });\n if (!pendingCalls.has(event.id)) {\n pendingCalls.set(event.id, { tool: mapped.tool, toolLabel: mapped.toolLabel, args });\n onProgress({ type: 'tool_call', tool: mapped.tool, toolLabel: mapped.toolLabel, toolArgs: args, toolCallId: event.id });\n }\n settle(\n event.id,\n `Access denied: the planner runs read-only, so \"${event.name}\" was refused. Mutation belongs to the runners that execute the plan.`,\n false,\n 'denied',\n );\n return;\n }\n\n case 'error':\n error = event.message;\n return;\n\n case 'turn_end':\n return;\n }\n }, signal);\n\n // Anything still pending when the turn ended never produced a result —\n // report it rather than leaving a spinner running in every surface.\n for (const id of [...pendingCalls.keys()]) {\n settle(id, 'The agent ended the turn without reporting this call\\'s result.', false, 'not_executed');\n }\n\n this.lastNativeSessionId = adapter.nativeSessionId() ?? this.lastNativeSessionId;\n // A failed turn usually means the process is gone, and an aborted one kills\n // the process by contract. Either way the adapter cannot be sent to again —\n // `dispose()` is terminal — so drop it and let the next turn restart from\n // the session id rather than throwing into a dead stdin.\n if (error || signal?.aborted) { adapter.dispose(); this.adapter = null; }\n\n return { text, researchLog, error, aborted: signal?.aborted };\n }\n\n // --- Process lifecycle ---\n\n private async startAdapter(opts: AgentStartOptions): Promise<AgentAdapter> {\n const adapter = this.makeAdapter(this.runner, this.processDeps);\n if (!adapter) throw new Error(`No planner adapter is available for \"${this.runner}\".`);\n await adapter.start(opts);\n this.adapter = adapter;\n return adapter;\n }\n\n /**\n * The live agent process, restarted from its own session id if it died\n * between turns. Resume is a hint: when it fails, the caller's next\n * `startConversation` reseeds from Ordewell's transcript, which is the same\n * degradation `restoreChat` already performs on every surface.\n */\n private async ensureAdapter(): Promise<AgentAdapter> {\n if (this.adapter) return this.adapter;\n const conversation = this.conversation;\n if (!conversation) throw new Error('No active planner conversation.');\n await this.startAdapter({ ...conversation.startOptions, resumeSessionId: this.lastNativeSessionId ?? undefined });\n return this.adapter!;\n }\n\n private startAbortScope(callerSignal?: AbortSignal): AbortSignal | undefined {\n this.activeAbort = new AbortController();\n if (!callerSignal) return this.activeAbort.signal;\n if (callerSignal.aborted) { this.activeAbort.abort(); return this.activeAbort.signal; }\n callerSignal.addEventListener('abort', () => this.activeAbort?.abort(), { once: true });\n return this.activeAbort.signal;\n }\n\n private plannerModel(): string | undefined {\n const id = (this.config.orchestratorModel ?? '').trim();\n return id || undefined;\n }\n\n // --- One-shot paths (CLI `plan --goal`, web REST, plan modification) ---\n\n /**\n * A single agent session that answers one prompt and exits. Used by every\n * non-conversational entry point; the plan is parsed from the reply text by\n * the same extractor the conversational path uses.\n */\n private async oneShot(prompt: string, onProgress?: (p: ResearchProgress) => void, signal?: AbortSignal): Promise<{ text: string; researchLog: ResearchLogEntry[] }> {\n const previous = this.adapter;\n const previousConversation = this.conversation;\n const previousSessionId = this.lastNativeSessionId;\n this.adapter = null;\n\n const startOptions: AgentStartOptions = {\n cwd: this.workspaceRoot(),\n systemPrompt: prompt,\n model: this.plannerModel(),\n effort: this.config.plannerThinkingEffort,\n };\n let oneShotAdapter: AgentAdapter | null = null;\n try {\n oneShotAdapter = await this.startAdapter(startOptions);\n this.conversation = {\n startOptions,\n runners: [],\n prdEnabled: false,\n prdCaptured: false,\n prdNudgeSent: false,\n };\n const turn = await this.runTurn(\n 'Follow the instructions in your system prompt and produce the plan now.',\n onProgress ?? (() => {}),\n signal,\n );\n if (turn.error) throw new Error(turn.error);\n return { text: turn.text, researchLog: turn.researchLog };\n } finally {\n // A one-shot never leaves a process behind, and never disturbs a\n // conversational session that happened to be open around it — including\n // when its own agent failed to start, which happens before there is\n // anything to dispose.\n oneShotAdapter?.dispose();\n this.adapter = previous;\n this.conversation = previousConversation;\n // The one-shot's own agent session must not become the conversation's\n // resume hint: restarting the chat into a plan-generation session would\n // cross two sessions that never shared a goal.\n this.lastNativeSessionId = previousSessionId;\n }\n }\n\n async researchAndPlan(\n userDescription: string,\n runners: RunnerId[],\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n fs: IFileSystem,\n onProgress: (progress: ResearchProgress) => void,\n _fetcher?: IWebFetcher,\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n modes: PlannerModes = DEFAULT_PLANNER_MODES,\n signal?: AbortSignal,\n ): Promise<{ tasks: Task[]; researchLog: ResearchLogEntry[]; researchResults: string }> {\n const contextStr = await collectResearchContext(fs, runners);\n const researchLog: ResearchLogEntry[] = [\n { id: `up-${Date.now()}`, type: 'user_prompt', content: userDescription, timestamp: new Date().toISOString() },\n ];\n let lastText = '';\n const tasks = await generatePlanWithRepair(\n async (repairHint) => {\n const prompt = buildPlanWithResults(userDescription, contextStr, '', modelsByRunner, runners, runnerModes, modes);\n const result = await this.oneShot(repairHint ? `${prompt}\\n\\n${repairHint}` : prompt, onProgress, signal);\n researchLog.push(...result.researchLog);\n lastText = result.text;\n return result.text;\n },\n runners, 2, runnerModes, modes.autonomousDefault,\n );\n return { tasks, researchLog, researchResults: lastText };\n }\n\n async generatePlanDirect(\n userDescription: string,\n runners: RunnerId[] = ['claude-code'],\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>> = {},\n onToken?: (token: string) => void,\n _fs?: IFileSystem,\n _fetcher?: IWebFetcher,\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n modes: PlannerModes = DEFAULT_PLANNER_MODES,\n signal?: AbortSignal,\n ): Promise<Task[]> {\n const prompt = buildPlanWithResults(userDescription, '', '', modelsByRunner, runners, runnerModes, modes);\n return generatePlanWithRepair(\n async (repairHint) => {\n const result = await this.oneShot(\n repairHint ? `${prompt}\\n\\n${repairHint}` : prompt,\n (p) => { if (p.type === 'plan_token' && p.planToken) onToken?.(p.planToken); },\n signal,\n );\n return result.text;\n },\n runners, 2, runnerModes, modes.autonomousDefault,\n );\n }\n\n async modifyPlan(\n existingPlan: LegacyPlanState,\n userRequest: string,\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n onProgress?: (progress: ResearchProgress) => void,\n _fs?: IFileSystem,\n _fetcher?: IWebFetcher,\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n modes: PlannerModes = DEFAULT_PLANNER_MODES,\n signal?: AbortSignal,\n ): Promise<{ tasks: Task[] }> {\n const prompt = buildModifyPlanPrompt(existingPlan, userRequest, modelsByRunner, undefined, runnerModes, modes.autonomousDefault);\n try {\n const tasks = await generatePlanWithRepair(\n async (repairHint) => {\n const result = await this.oneShot(repairHint ? `${prompt}\\n\\n${repairHint}` : prompt, onProgress, signal);\n return result.text;\n },\n existingPlan.runners, 2, runnerModes, modes.autonomousDefault,\n );\n return { tasks };\n } catch (err) {\n throw new Error(`Plan modification failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n async sendPlanningPrompt(\n prompt: string,\n runners: RunnerId[],\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n autonomousDefault = true,\n ): Promise<Task[]> {\n return generatePlanWithRepair(\n async (repairHint) => {\n const result = await this.oneShot(repairHint ? `${prompt}\\n\\n${repairHint}` : prompt);\n return result.text;\n },\n runners, 2, runnerModes, autonomousDefault,\n );\n }\n}\n","import type { SpawnFn } from '../HeadlessRunner';\n\n\n/**\n * The harness-planner transport contract (ADR-0009).\n *\n * One adapter per coding agent, each speaking that agent's own programmatic\n * protocol and normalizing it to the event union below. Everything above this\n * line — reply classification, the repair loop, plan validation, the four\n * surfaces — is already provider-agnostic, so an adapter is the entire cost of\n * teaching Ordewell to plan with another agent.\n */\n\n/**\n * One normalized event from a running agent turn. Deliberately smaller than\n * any single agent's native protocol: this is the intersection Ordewell can act\n * on, not a lossless re-encoding. Event fidelity differs by agent — `thinking`\n * is rich on Claude Code and absent elsewhere — so consumers must tolerate a\n * turn that emits nothing but `assistant_text` and `turn_end`.\n */\nexport type AgentEvent =\n /** A chunk of the assistant's reply. Concatenated in order to form the turn's text. */\n | { type: 'assistant_text'; text: string }\n /** Reasoning the agent chose to expose. Never contributes to the reply text. */\n | { type: 'thinking'; text: string }\n | { type: 'tool_call'; id: string; name: string; args: Record<string, unknown> }\n | { type: 'tool_result'; id: string; name: string; output: string; success: boolean }\n /**\n * The agent asked to do something its read-only mode does not cover. Always\n * auto-denied (T1) — a planner that can mutate is not a planner. The adapter\n * is responsible for answering the agent so the turn does not hang.\n */\n | { type: 'permission_request'; id: string; name: string; detail: string }\n /** The agent finished its turn and is waiting for the next user message. */\n | { type: 'turn_end' }\n /** The turn failed. Carries the agent's own words — never a Ordewell paraphrase. */\n | { type: 'error'; message: string };\n\nexport interface AgentStartOptions {\n /** Workspace root. The agent explores from here and, in read-only mode, cannot leave it. */\n cwd: string;\n /** The planner system prompt, in its harness variant. */\n systemPrompt: string;\n /** Model id from the runner's own discovery catalog. Omitted means the agent's default. */\n model?: string;\n /** Variant / reasoning effort id from that model's `variants` list. */\n effort?: string;\n /**\n * The agent's own session id from a previous run. A hint only: Ordewell's\n * transcript is the source of truth (T4), so a failed resume degrades to a\n * fresh session seeded from the stored history rather than an error.\n */\n resumeSessionId?: string;\n}\n\nexport interface AgentAdapter {\n /** The runner id this adapter drives — `claude-code`, `codex`, `opencode`. */\n readonly agentId: string;\n\n /** Spawn the agent in its read-only mode and get it ready to receive messages. */\n start(opts: AgentStartOptions): Promise<void>;\n\n /**\n * Send one user message and stream the turn's events until it ends. Resolves\n * when the agent yields the floor; rejects only when the transport itself\n * failed in a way no `error` event could describe.\n */\n send(message: string, onEvent: (event: AgentEvent) => void, signal?: AbortSignal): Promise<void>;\n\n /** The agent's native session id once it has announced one. Resumption hint only. */\n nativeSessionId(): string | null;\n\n /** Kill the process and release its resources. Idempotent. */\n dispose(): void;\n}\n\n/**\n * The single injected boundary between Ordewell and the operating system —\n * the same pattern `HeadlessRunnerDeps` uses for task execution. Tests feed\n * recorded agent output through `spawn` (and, for HTTP-transport agents,\n * `fetch`) so one test exercises adapter parsing, event mapping, reply\n * classification and the repair loop as a single observable behavior.\n */\nexport interface AgentProcessDeps {\n spawn: SpawnFn;\n fetch: typeof globalThis.fetch;\n /** Resolves the PATH agents are spawned under. Defaults to the augmented PATH. */\n resolvePath?: () => Promise<string>;\n /** Host platform. Defaults to the real one; injected so OS-specific behavior is testable anywhere. */\n platform?: NodeJS.Platform;\n}\n\n/** Builds the adapter for one runner id, or null when that runner cannot plan. */\nexport type AgentAdapterFactory = (runner: string, deps: AgentProcessDeps) => AgentAdapter | null;\n\n/**\n * Split a stream of chunks into complete lines. Every agent transport here is\n * newline-delimited JSON of some shape, and a chunk boundary lands mid-object\n * often enough that parsing per-chunk silently drops events.\n */\nexport class LineBuffer {\n private buffer = '';\n\n push(chunk: string, onLine: (line: string) => void): void {\n this.buffer += chunk;\n let newline: number;\n while ((newline = this.buffer.indexOf('\\n')) >= 0) {\n const line = this.buffer.slice(0, newline).trim();\n this.buffer = this.buffer.slice(newline + 1);\n if (line) onLine(line);\n }\n }\n\n /** Anything left unterminated when the stream closed. */\n flush(): string {\n const rest = this.buffer.trim();\n this.buffer = '';\n return rest;\n }\n}\n","import type { ChildProcess } from 'child_process';\nimport { augmentedPath, withPath } from '../../utils/shellPath';\nimport { planDirectLaunch } from '../../utils/launch';\nimport { killTree } from '../../utils/processTree';\nimport { LineBuffer, type AgentAdapter, type AgentEvent, type AgentProcessDeps, type AgentStartOptions } from './AgentAdapter';\n\n/** Stderr kept for the failure message; a dying CLI's last words are the only useful diagnostic. */\nconst STDERR_TAIL_CHARS = 4000;\n/** An idle agent that chatters must not grow the between-turn buffer without bound. */\nconst BETWEEN_TURN_EVENT_CAP = 50;\n\n/**\n * Event kinds never carried across a turn boundary. Reply text belongs to the\n * turn that produced it, and the two terminal kinds would settle the *next*\n * turn the moment it opened — a trailing `turn/completed` after a fatal error\n * would leave the following message answered by nothing at all.\n */\nconst TURN_SCOPED_EVENTS = new Set(['assistant_text', 'turn_end', 'error']);\n\nexport interface SpawnSpec {\n command: string;\n args: string[];\n env?: Record<string, string>;\n}\n\n/**\n * Shared plumbing for the agents that speak newline-delimited JSON over stdio.\n *\n * One long-lived process per planner session (ADR-0009, T3): spawned at\n * `start`, fed one message per turn, disposed at the session boundary. The\n * alternative — respawning per turn — pays a cold start on every message\n * *including each corrective re-emit*, and re-reads the repository from\n * scratch when it cannot resume.\n *\n * Subclasses own their agent's protocol: what to spawn, how to phrase a user\n * turn, and how to read one protocol line. Everything below — line framing,\n * turn lifecycle, abort, stderr capture, premature-exit detection — is the\n * same for all of them.\n */\nexport abstract class StdioAgentAdapter implements AgentAdapter {\n abstract readonly agentId: string;\n\n protected process: ChildProcess | null = null;\n protected sessionId: string | null = null;\n private readonly stdout = new LineBuffer();\n private stderrTail = '';\n private exited: { code: number | null; signal: string | null } | null = null;\n /** Set for the duration of a turn. Outside one, events are buffered rather than dropped. */\n private turnEmit: ((event: AgentEvent) => void) | null = null;\n /**\n * Events the agent produced between turns — in practice the startup warnings\n * that arrive during the handshake. Dropping them hid the one diagnostic\n * that explains a planner which cannot read the workspace, so they are held\n * until a turn exists to show them in.\n */\n private betweenTurns: AgentEvent[] = [];\n private disposed = false;\n /** Resolves when the process ends, so a handshake can lose the race instead of waiting out its timeout. */\n protected processEnded!: Promise<void>;\n /** The environment the agent was spawned under, for any side process a handshake needs. */\n protected spawnEnv: NodeJS.ProcessEnv = {};\n private markEnded: (() => void) | null = null;\n\n constructor(protected deps: AgentProcessDeps) {}\n\n /** The command line that starts this agent in its read-only mode. */\n protected abstract spawnSpec(opts: AgentStartOptions): SpawnSpec;\n\n /** The bytes written to stdin to open one user turn. Must end with a newline. */\n protected abstract turnPayload(message: string): string;\n\n /**\n * Interpret one line of the agent's protocol, emitting normalized events.\n * Emitting `turn_end` ends the turn; emitting `error` ends it as a failure.\n */\n protected abstract handleLine(line: string, emit: (event: AgentEvent) => void): void;\n\n /** Protocol handshake, if the agent needs one before it accepts a turn. */\n protected async handshake(_opts: AgentStartOptions): Promise<void> {}\n\n async start(opts: AgentStartOptions): Promise<void> {\n this.processEnded = new Promise<void>((resolve) => { this.markEnded = resolve; });\n const spec = this.spawnSpec(opts);\n const resolvePath = this.deps.resolvePath ?? augmentedPath;\n // Same PATH treatment as model discovery and the headless runner: the\n // agent binary must resolve wherever the user installed it, even under the\n // minimal PATH a GUI-launched host inherits.\n const PATH = await resolvePath();\n\n this.spawnEnv = withPath(process.env, PATH, spec.env);\n // On POSIX this hands back `spec` untouched; on Windows it resolves the\n // agent's `.exe` (or routes its `.cmd` shim through cmd.exe), because\n // CreateProcess performs no PATHEXT lookup of its own.\n const launch = await planDirectLaunch(spec.command, spec.args, {\n platform: this.deps.platform,\n resolvePath,\n });\n this.process = this.deps.spawn(launch.file, launch.args, {\n env: this.spawnEnv,\n stdio: ['pipe', 'pipe', 'pipe'],\n cwd: opts.cwd,\n windowsVerbatimArguments: launch.verbatim,\n });\n\n // Every protocol line goes to `handleLine`, turn or no turn: an agent's\n // handshake and its session-id announcement both arrive before the first\n // message is sent, and dropping them left the handshake waiting on a reply\n // that had already come and gone.\n this.process.stdout?.on('data', (chunk: Buffer) => {\n this.stdout.push(chunk.toString(), (line) => this.handleLine(line, (event) => {\n if (this.turnEmit) this.turnEmit(event);\n else if (!TURN_SCOPED_EVENTS.has(event.type) && this.betweenTurns.length < BETWEEN_TURN_EVENT_CAP) {\n this.betweenTurns.push(event);\n }\n }));\n });\n this.process.stderr?.on('data', (chunk: Buffer) => {\n this.stderrTail = (this.stderrTail + chunk.toString()).slice(-STDERR_TAIL_CHARS);\n });\n this.process.on('exit', (code, signal) => { this.exited = { code, signal }; this.markEnded?.(); });\n this.process.on('error', (err) => {\n this.stderrTail = (this.stderrTail + `\\n${err.message}`).slice(-STDERR_TAIL_CHARS);\n this.exited = { code: -1, signal: null };\n this.markEnded?.();\n });\n\n await this.handshake(opts);\n }\n\n async send(message: string, onEvent: (event: AgentEvent) => void, signal?: AbortSignal): Promise<void> {\n if (!this.process) throw new Error(`${this.agentId} planner session is not started`);\n if (this.exited) {\n onEvent({ type: 'error', message: this.exitMessage() });\n return;\n }\n\n await new Promise<void>((resolve) => {\n let settled = false;\n const finish = () => {\n if (settled) return;\n settled = true;\n this.turnEmit = null;\n signal?.removeEventListener('abort', onAbort);\n this.process?.removeListener('exit', onExit);\n this.process?.removeListener('error', onExit);\n resolve();\n };\n\n const emit = (event: AgentEvent) => {\n onEvent(event);\n if (event.type === 'turn_end' || event.type === 'error') finish();\n };\n\n // A process that dies mid-turn must surface its stderr, not hang the\n // planner behind a `turn_end` that will never come.\n const onExit = () => {\n if (settled) return;\n onEvent({ type: 'error', message: this.exitMessage() });\n finish();\n };\n const onAbort = () => {\n if (settled) return;\n // Stop means stop: the agent is holding real context we are abandoning,\n // so the process goes with the turn rather than being left running.\n this.dispose();\n finish();\n };\n\n this.turnEmit = emit;\n this.process!.once('exit', onExit);\n this.process!.once('error', onExit);\n if (signal?.aborted) { onAbort(); return; }\n signal?.addEventListener('abort', onAbort, { once: true });\n\n const buffered = this.betweenTurns;\n this.betweenTurns = [];\n for (const event of buffered) {\n emit(event);\n if (settled) return;\n }\n\n try {\n this.process!.stdin!.write(this.turnPayload(message));\n } catch (err) {\n onEvent({ type: 'error', message: `Could not send to ${this.agentId}: ${err instanceof Error ? err.message : String(err)}` });\n finish();\n }\n });\n }\n\n nativeSessionId(): string | null { return this.sessionId; }\n\n dispose(): void {\n if (this.disposed) return;\n this.disposed = true;\n this.turnEmit = null;\n const proc = this.process;\n this.process = null;\n // Tree-wide, because on Windows the direct child may be the cmd.exe shim\n // rather than the agent. The forced follow-up is scheduled and unref'd, so\n // a disposed planner is never the reason the host refuses to exit.\n killTree(proc, { platform: this.deps.platform });\n }\n\n /** Write one raw protocol line to the agent. */\n protected writeLine(payload: unknown): void {\n this.process?.stdin?.write(`${JSON.stringify(payload)}\\n`);\n }\n\n /** Fail-safe contract: a dead agent reports its own last words, never an empty bubble. */\n protected exitMessage(): string {\n const how = this.exited?.signal\n ? `was killed (${this.exited.signal})`\n : `exited with code ${this.exited?.code ?? 'unknown'}`;\n const tail = this.stderrTail.trim();\n return `The ${this.agentId} planner ${how}.${tail ? `\\n\\n${tail}` : ''}`;\n }\n\n /** Parse a protocol line, ignoring the non-JSON banners some CLIs print. */\n protected static parse<T>(line: string): T | null {\n try {\n const value = JSON.parse(line);\n return typeof value === 'object' && value !== null ? (value as T) : null;\n } catch {\n return null;\n }\n }\n}\n","import type { AgentEvent, AgentStartOptions } from './AgentAdapter';\nimport { StdioAgentAdapter, type SpawnSpec } from './StdioAgentAdapter';\n\n/**\n * Tools a planning Claude Code session may use. `--permission-mode plan`\n * already refuses edits; naming the write tools explicitly means a future\n * permission-mode change cannot quietly hand the planner a `Write` (T1).\n */\nconst DISALLOWED_TOOLS = ['Edit', 'Write', 'MultiEdit', 'NotebookEdit', 'KillShell'];\n\ninterface ClaudeBlock {\n type: string;\n text?: string;\n thinking?: string;\n id?: string;\n name?: string;\n input?: Record<string, unknown>;\n tool_use_id?: string;\n content?: unknown;\n is_error?: boolean;\n}\n\ninterface ClaudeLine {\n type: string;\n subtype?: string;\n session_id?: string;\n result?: string;\n is_error?: boolean;\n request_id?: string;\n request?: { subtype?: string; tool_name?: string; input?: Record<string, unknown> };\n message?: { content?: ClaudeBlock[] | string };\n}\n\n/** Tool results arrive as a string, or as a content-block array. Flatten both. */\nfunction flattenContent(content: unknown): string {\n if (typeof content === 'string') return content;\n if (Array.isArray(content)) {\n return content\n .map((block) => (typeof block === 'string' ? block : typeof (block as ClaudeBlock)?.text === 'string' ? (block as ClaudeBlock).text : ''))\n .filter(Boolean)\n .join('\\n');\n }\n return '';\n}\n\n/**\n * Claude Code as a planner, over its bidirectional streaming-JSON transport\n * (ADR-0009).\n *\n * `-p --input-format stream-json --output-format stream-json` keeps one process\n * alive across turns: user messages go in as JSON lines, and the session's\n * assistant blocks, tool uses, tool results and turn boundaries come back the\n * same way. It is the richest of the three streams — partial messages and\n * separate thinking blocks — which is why this agent went first.\n */\nexport class ClaudeCodeAdapter extends StdioAgentAdapter {\n readonly agentId = 'claude-code';\n\n protected spawnSpec(opts: AgentStartOptions): SpawnSpec {\n const args = [\n '-p',\n '--input-format', 'stream-json',\n '--output-format', 'stream-json',\n // stream-json output is rejected without it.\n '--verbose',\n '--include-partial-messages',\n // The read-only guarantee, enforced at spawn rather than by prompt.\n '--permission-mode', 'plan',\n '--disallowedTools', DISALLOWED_TOOLS.join(','),\n '--append-system-prompt', opts.systemPrompt,\n ];\n if (opts.model) args.push('--model', opts.model);\n // `adaptive` is a thinking *type*, not an effort rung: `--effort adaptive`\n // is warned about and ignored, and adaptive is the default for every model\n // that offers it. Passing nothing is the same run without the warning on\n // stderr.\n if (opts.effort && opts.effort !== 'adaptive') args.push('--effort', opts.effort);\n if (opts.resumeSessionId) args.push('--resume', opts.resumeSessionId);\n return { command: 'claude', args };\n }\n\n protected turnPayload(message: string): string {\n return `${JSON.stringify({\n type: 'user',\n message: { role: 'user', content: [{ type: 'text', text: message }] },\n })}\\n`;\n }\n\n protected handleLine(line: string, emit: (event: AgentEvent) => void): void {\n const msg = StdioAgentAdapter.parse<ClaudeLine>(line);\n if (!msg) return;\n\n if (msg.session_id) this.sessionId = msg.session_id;\n\n switch (msg.type) {\n // The control channel: Claude asks whether a tool may run when its mode\n // cannot decide alone. A read-only planner answers \"deny\", every time —\n // and must answer, because an unacknowledged request stalls the turn.\n case 'control_request': {\n if (msg.request?.subtype !== 'can_use_tool') return;\n this.writeLine({\n type: 'control_response',\n response: {\n subtype: 'success',\n request_id: msg.request_id,\n response: { behavior: 'deny', message: 'The Ordewell planner is read-only. Mutation belongs to the runners that execute the plan.' },\n },\n });\n emit({\n type: 'permission_request',\n id: msg.request_id ?? '',\n name: msg.request?.tool_name ?? 'unknown',\n detail: JSON.stringify(msg.request?.input ?? {}),\n });\n return;\n }\n\n case 'assistant':\n for (const block of Array.isArray(msg.message?.content) ? msg.message!.content as ClaudeBlock[] : []) {\n if (block.type === 'text' && block.text) emit({ type: 'assistant_text', text: block.text });\n else if (block.type === 'thinking' && block.thinking) emit({ type: 'thinking', text: block.thinking });\n else if (block.type === 'tool_use' && block.name) {\n emit({ type: 'tool_call', id: block.id ?? block.name, name: block.name, args: block.input ?? {} });\n }\n }\n return;\n\n case 'user':\n // The transport echoes tool results back as a synthetic user message.\n for (const block of Array.isArray(msg.message?.content) ? msg.message!.content as ClaudeBlock[] : []) {\n if (block.type !== 'tool_result') continue;\n emit({\n type: 'tool_result',\n id: block.tool_use_id ?? '',\n name: '',\n output: flattenContent(block.content),\n success: block.is_error !== true,\n });\n }\n return;\n\n case 'result':\n // `result` closes every turn — success or failure. The final assistant\n // text (which carries the plan JSON) already arrived as assistant\n // blocks, so this only settles the turn.\n if (msg.is_error || (msg.subtype && msg.subtype !== 'success')) {\n emit({ type: 'error', message: msg.result?.trim() || `Claude Code ended the turn: ${msg.subtype ?? 'error'}` });\n } else {\n emit({ type: 'turn_end' });\n }\n return;\n\n // `system`/`stream_event` carry init metadata and partial deltas. The\n // session id is picked up above; partials are ignored because the\n // complete blocks follow and would otherwise be counted twice.\n default:\n return;\n }\n }\n}\n","import type { AgentProcessDeps } from './AgentAdapter';\n\n/** A probe that hangs must not hold up session start; an unclear answer means \"change nothing\". */\nconst PROBE_TIMEOUT_MS = 10000;\n\n/**\n * The bubblewrap failure this module exists for, as the sandbox itself reports\n * it. Matching the message — rather than treating any non-zero exit as a broken\n * sandbox — keeps an older `codex` without the `sandbox` subcommand, or a probe\n * that fails for some unrelated reason, from being \"fixed\" by a workaround it\n * does not need.\n */\nconst USERNS_FAILURE = /bwrap|bubblewrap|user namespace|RTM_NEWADDR/i;\n\nexport type CodexSandboxDecision =\n /** Leave Codex alone: its sandbox works, or nothing recognizable is wrong with it. */\n | 'default'\n /** Bubblewrap cannot start; Codex's pre-bubblewrap Landlock backend can. */\n | 'legacy-landlock'\n /** Both backends failed. Codex can run no command at all, so it cannot explore. */\n | 'unavailable';\n\n/**\n * Decide which sandbox backend Codex should plan under on this machine.\n *\n * Codex's Linux sandbox is bubblewrap, which needs unprivileged user\n * namespaces. Ubuntu 24.04 restricts those through AppArmor\n * (`kernel.apparmor_restrict_unprivileged_userns=1`) and ships no `bwrap`\n * profile, so every command the planner runs dies with `bwrap: loopback:\n * Failed RTM_NEWADDR: Operation not permitted` — and Codex answers anyway,\n * from memory and web search, which is exactly the confident uninformed plan\n * this repo treats as a silent success (openai/codex#15496, #16334).\n *\n * `use_legacy_landlock` selects the backend Codex used before bubblewrap.\n * Landlock is an LSM, needs no namespace, and still denies the writes that make\n * read-only planning read-only. It is deprecated upstream, which is why it is\n * opted into only on a machine that has been observed to need it, and why its\n * own failure is not special-cased: an unrecognized outcome leaves Codex\n * configured exactly as it configures itself.\n *\n * Asking the binary beats inferring from `/proc` and `/etc/apparmor.d`: it is\n * the same question, put to the thing that will have to answer it, and it costs\n * one ~40ms process.\n */\nexport async function probeCodexSandbox(\n deps: AgentProcessDeps,\n cwd: string,\n env: NodeJS.ProcessEnv,\n): Promise<CodexSandboxDecision> {\n // Bubblewrap is the Linux backend only, so there is nothing here to probe\n // elsewhere: macOS uses Seatbelt, which cannot fail this way.\n //\n // Windows is a weaker statement and deliberately not dressed up as a stronger\n // one. Codex's own sandboxing there is not the OS-enforced equivalent of\n // Seatbelt or Landlock, so `sandbox: 'read-only'` in `CodexAdapter.startThread`\n // may be honoured by Codex's tool layer rather than by the kernel. The\n // approvals side of the invariant still holds by construction\n // (`approvalPolicy: 'never'`, and the whole server→client request surface is\n // refused), and the planner prompt never asks for a write — but \"read-only by\n // construction\" (ADR-0009) is a Linux/macOS guarantee, not yet a verified\n // Windows one. Returning 'default' declines to invent a workaround for a\n // failure mode nobody has observed; it does not claim the guarantee is proven.\n if ((deps.platform ?? process.platform) !== 'linux') return 'default';\n\n const bubblewrap = await runProbe(deps, cwd, env, []);\n if (bubblewrap.code === 0) return 'default';\n if (!USERNS_FAILURE.test(bubblewrap.output)) return 'default';\n\n const landlock = await runProbe(deps, cwd, env, ['--enable', 'use_legacy_landlock']);\n return landlock.code === 0 ? 'legacy-landlock' : 'unavailable';\n}\n\n/** The message shown when Codex has no working sandbox, naming both documented fixes. */\nexport function codexSandboxUnavailableMessage(): string {\n return [\n 'Codex cannot start a sandbox on this machine, so it can run no command and cannot read the workspace.',\n '',\n \"Its Linux sandbox needs unprivileged user namespaces, which this kernel restricts (Ubuntu 24.04's AppArmor default), and the legacy Landlock backend did not work either.\",\n '',\n 'Either allow them:',\n ' sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0',\n '',\n 'or install an AppArmor profile for bwrap, then plan with Codex again.',\n ].join('\\n');\n}\n\nfunction runProbe(\n deps: AgentProcessDeps,\n cwd: string,\n env: NodeJS.ProcessEnv,\n flags: string[],\n): Promise<{ code: number | null; output: string }> {\n return new Promise((resolve) => {\n let output = '';\n let settled = false;\n const finish = (code: number | null) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n resolve({ code, output });\n };\n\n const timer = setTimeout(() => finish(null), PROBE_TIMEOUT_MS);\n timer.unref?.();\n\n let proc;\n try {\n proc = deps.spawn('codex', ['sandbox', ...flags, '--', '/bin/true'], {\n env, stdio: ['pipe', 'pipe', 'pipe'], cwd,\n });\n } catch {\n finish(null);\n return;\n }\n\n proc.stdout?.on('data', (chunk: Buffer) => { output += chunk.toString(); });\n proc.stderr?.on('data', (chunk: Buffer) => { output += chunk.toString(); });\n proc.on('error', () => finish(null));\n proc.on('exit', (code) => finish(code));\n });\n}\n","import type { AgentEvent, AgentStartOptions } from './AgentAdapter';\nimport { StdioAgentAdapter, type SpawnSpec } from './StdioAgentAdapter';\nimport { probeCodexSandbox, codexSandboxUnavailableMessage, type CodexSandboxDecision } from './codexSandbox';\n\nconst HANDSHAKE_TIMEOUT_MS = 30000;\n\ninterface RpcMessage {\n id?: number | string;\n method?: string;\n params?: Record<string, unknown>;\n result?: Record<string, unknown>;\n error?: { message?: string };\n}\n\n/**\n * One entry of a Codex turn. Field names are the app-server protocol's, taken\n * from `codex app-server generate-json-schema`, not invented here.\n */\ninterface ThreadItem {\n id?: string;\n type?: string;\n text?: string;\n /** Reasoning carries arrays of blocks, not a string — see `flattenText`. */\n summary?: unknown;\n content?: unknown;\n command?: string | string[];\n cwd?: string;\n aggregatedOutput?: string;\n exitCode?: number;\n server?: string;\n tool?: string;\n arguments?: Record<string, unknown>;\n result?: unknown;\n error?: string;\n status?: string;\n success?: boolean;\n query?: string;\n /** `final_answer` vs `commentary`; both are prose the user should see. */\n phase?: string;\n}\n\n/**\n * Codex carries prose as arrays of blocks — `reasoning.summary`, and the\n * `content` of an MCP tool result — where each block is a string or an object\n * with a `text` field. Reading them as plain strings produced empty thinking\n * events against the real CLI, which is why this exists.\n */\nfunction flattenText(value: unknown): string {\n if (typeof value === 'string') return value;\n if (Array.isArray(value)) return value.map(flattenText).filter(Boolean).join('\\n');\n if (value && typeof value === 'object') {\n const text = (value as { text?: unknown }).text;\n if (typeof text === 'string') return text;\n const content = (value as { content?: unknown }).content;\n if (content !== undefined) return flattenText(content);\n }\n return '';\n}\n\n/**\n * Server→client requests that carry a refusal in their own result schema, and\n * the exact payload that expresses it. Anything not listed here is refused with\n * a JSON-RPC error instead — see {@link CodexAdapter.answerServerRequest}.\n */\nconst DECLINE_RESULTS: Record<string, Record<string, unknown>> = {\n 'item/commandExecution/requestApproval': { decision: 'decline' },\n 'item/fileChange/requestApproval': { decision: 'decline' },\n 'mcpServer/elicitation/request': { action: 'decline' },\n // The pre-`item/*` spellings, still emitted by older app-servers.\n execCommandApproval: { decision: 'denied' },\n applyPatchApproval: { decision: 'denied' },\n};\n\nconst LANDLOCK_FALLBACK_NOTE = [\n \"Codex's bubblewrap sandbox cannot create user namespaces on this machine, so planning fell back to its legacy Landlock backend.\",\n 'Exploration works and writes are still denied, but that backend is deprecated upstream. To fix the host:',\n ' sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0',\n].join('\\n');\n\n/** Requests worth showing in the timeline: the planner reached for something it may not have. */\nconst ANNOUNCED_REQUESTS = new Set([\n ...Object.keys(DECLINE_RESULTS),\n 'item/permissions/requestApproval',\n 'item/tool/requestUserInput',\n 'item/tool/call',\n]);\n\n/**\n * Codex as a planner, over its `app-server` stdio JSON-RPC transport\n * (ADR-0009).\n *\n * Ordewell already speaks a slice of this protocol — `ModelDiscovery` drives\n * `initialize` → `model/list` to build the Codex model catalog — so the\n * handshake here is that one continued into a thread.\n *\n * Codex's own CLI marks `app-server` experimental, and it is the transport\n * most likely to drift: the method names below (`thread/start`, `turn/start`,\n * `item/completed`) come from the schema the installed binary generates, and a\n * version that renames them will surface as a visible dead turn rather than a\n * hang, because the base class watches the process as well as the protocol.\n */\nexport class CodexAdapter extends StdioAgentAdapter {\n readonly agentId = 'codex';\n\n private threadId: string | null = null;\n private nextRequestId = 100;\n private settleHandshake: ((ok: boolean) => void) | null = null;\n private handshakeError: string | null = null;\n private startOpts: AgentStartOptions | null = null;\n /** Whether this turn has already emitted prose — see the `agentMessage` case. */\n private turnHasText = false;\n private resumeAttempted = false;\n private resumeFallbackSent = false;\n private sandbox: CodexSandboxDecision = 'default';\n\n protected spawnSpec(opts: AgentStartOptions): SpawnSpec {\n this.startOpts = opts;\n return { command: 'codex', args: ['app-server'] };\n }\n\n /**\n * `initialize`, then `thread/start`, both before the first user message. The\n * thread is pinned to the read-only sandbox with approvals set to `never` —\n * with nobody watching a planner's prompts, \"ask\" would mean \"hang\", which is\n * ADR-0008's absent-is-denial invariant kept by construction.\n */\n protected async handshake(opts: AgentStartOptions): Promise<void> {\n // Before the protocol, the machine: a Codex whose sandbox cannot start runs\n // no command and plans from imagination instead of from the repository.\n this.sandbox = await probeCodexSandbox(this.deps, opts.cwd, this.spawnEnv);\n if (this.sandbox === 'unavailable') throw new Error(codexSandboxUnavailableMessage());\n\n const ready = new Promise<boolean>((resolve) => { this.settleHandshake = resolve; });\n this.writeLine({\n jsonrpc: '2.0', id: 1, method: 'initialize',\n params: { clientInfo: { name: 'ordewell', title: 'Ordewell', version: '0.1.0' } },\n });\n\n const ok = await Promise.race([\n ready,\n // A binary that rejects `app-server` outright dies immediately; waiting\n // out the timeout would turn a one-line diagnostic into a 30s stall.\n this.processEnded.then(() => false),\n new Promise<boolean>((resolve) => { const t = setTimeout(() => resolve(false), HANDSHAKE_TIMEOUT_MS); t.unref?.(); }),\n ]);\n this.settleHandshake = null;\n if (!ok) {\n throw new Error(this.handshakeError ?? `The Codex app-server did not complete its handshake.\\n\\n${this.exitMessage()}`);\n }\n void opts;\n }\n\n /**\n * Open the thread this session plans in. A resume id means the previous\n * process died mid-session: `thread/resume` puts the agent back in front of\n * the context it already paid to read. A failed resume is not an error — the\n * response handler falls back to a fresh thread, which is the same\n * degradation `restoreChat` performs on every surface (T4).\n */\n private startThread(resumeSessionId?: string): void {\n const opts = this.startOpts;\n this.resumeAttempted = this.resumeAttempted || !!resumeSessionId;\n this.writeLine({\n jsonrpc: '2.0',\n id: 2,\n method: resumeSessionId ? 'thread/resume' : 'thread/start',\n params: {\n ...(resumeSessionId ? { threadId: resumeSessionId } : {}),\n cwd: opts?.cwd,\n ...(opts?.model ? { model: opts.model } : {}),\n sandbox: 'read-only',\n approvalPolicy: 'never',\n ...(this.sandbox === 'legacy-landlock'\n ? { config: { features: { use_legacy_landlock: true } } }\n : {}),\n // `developerInstructions` layers on top of Codex's own base prompt, the\n // way Claude Code's `--append-system-prompt` does. `baseInstructions`\n // replaces it — which takes Codex's description of its own tools with\n // it, and a planner that has forgotten it can read the workspace\n // answers from a web search instead.\n developerInstructions: opts?.systemPrompt,\n },\n });\n }\n\n protected turnPayload(message: string): string {\n const opts = this.startOpts;\n return `${JSON.stringify({\n jsonrpc: '2.0',\n id: this.nextRequestId++,\n method: 'turn/start',\n params: {\n threadId: this.threadId,\n input: [{ type: 'text', text: message }],\n ...(opts?.effort ? { effort: opts.effort } : {}),\n },\n })}\\n`;\n }\n\n protected handleLine(line: string, emit: (event: AgentEvent) => void): void {\n const msg = StdioAgentAdapter.parse<RpcMessage>(line);\n if (!msg) return;\n\n if (msg.id === 1 && !msg.method) {\n if (msg.error) {\n this.handshakeError = `The Codex app-server rejected initialize: ${msg.error.message ?? 'unknown error'}`;\n this.settleHandshake?.(false);\n return;\n }\n this.startThread(this.startOpts?.resumeSessionId);\n return;\n }\n\n if (msg.id === 2 && !msg.method) {\n const thread = msg.result?.thread as { id?: string } | undefined;\n if (msg.error || !thread?.id) {\n if (this.resumeAttempted && !this.resumeFallbackSent) {\n this.resumeFallbackSent = true;\n this.startThread();\n return;\n }\n this.handshakeError = `The Codex app-server could not start a thread: ${msg.error?.message ?? 'no thread id returned'}`;\n this.settleHandshake?.(false);\n return;\n }\n this.threadId = thread.id;\n this.sessionId = thread.id;\n this.settleHandshake?.(true);\n return;\n }\n\n // Every server→client request — one that carries both a method and an id —\n // gets an answer, because an unanswered one stalls the turn forever. That\n // is ADR-0008's absent-is-denial invariant applied to the whole request\n // surface rather than to the three approval methods that happened to be\n // known when this adapter was written.\n if (msg.method && msg.id !== undefined) {\n this.answerServerRequest(msg, emit);\n return;\n }\n\n switch (msg.method) {\n case 'item/started':\n this.emitItemStart(msg.params?.item as ThreadItem | undefined, emit);\n return;\n case 'item/completed':\n this.emitItemDone(msg.params?.item as ThreadItem | undefined, emit);\n return;\n case 'turn/started':\n this.turnHasText = false;\n return;\n // Codex reports a setup problem once, at startup, and then plans anyway.\n // Surfacing it is enough: the warning is not always fatal, and refusing to\n // plan on an unrecognized one would be worse than showing it.\n case 'configWarning': {\n const warning = msg.params as { summary?: string; details?: string } | undefined;\n const text = [warning?.summary, warning?.details].filter(Boolean).join('\\n');\n // Codex emits the bubblewrap warning from its default config, before the\n // thread picks a backend, so it arrives even on the Landlock fallback\n // that just fixed it. Passing it through would be a false alarm, and\n // dropping it would hide a host that still needs fixing — Landlock is\n // deprecated upstream, so this is a reprieve, not a repair.\n if (this.sandbox === 'legacy-landlock' && /bubblewrap|user namespace/i.test(text)) {\n emit({ type: 'thinking', text: LANDLOCK_FALLBACK_NOTE });\n return;\n }\n if (text) emit({ type: 'thinking', text: `Codex configuration warning: ${text}` });\n return;\n }\n // A turn that fails without retry may never reach `turn/completed` — a\n // rate limit or an exhausted context window would otherwise hang until\n // the process died.\n case 'error': {\n const failure = msg.params as { error?: { message?: string }; willRetry?: boolean } | undefined;\n if (failure?.willRetry) return;\n emit({ type: 'error', message: failure?.error?.message || 'Codex ended the turn with an error.' });\n return;\n }\n case 'turn/completed': {\n const turn = msg.params?.turn as { status?: string; error?: { message?: string } } | undefined;\n if (turn?.status === 'failed') {\n emit({ type: 'error', message: turn.error?.message || 'Codex ended the turn with an error.' });\n } else {\n emit({ type: 'turn_end' });\n }\n return;\n }\n // Deltas (`item/agentMessage/delta`, `item/reasoning/*Delta`) are skipped:\n // the completed item follows and would otherwise be counted twice.\n default:\n return;\n }\n }\n\n /**\n * Refuse one server→client request. Requests whose result schema can express\n * a refusal get that payload; everything else — a permission grant, a\n * question for a user who is not watching, a tool call the client is supposed\n * to run — gets a JSON-RPC error, which Codex surfaces to the model as a\n * failed request and plans around, rather than waiting on.\n */\n private answerServerRequest(msg: RpcMessage, emit: (e: AgentEvent) => void): void {\n const method = msg.method!;\n const result = DECLINE_RESULTS[method];\n if (result) {\n this.writeLine({ jsonrpc: '2.0', id: msg.id, result });\n } else if (method === 'currentTime/read') {\n // Answered rather than refused: it is not a capability request, and\n // failing it would break a tool for no reason.\n this.writeLine({ jsonrpc: '2.0', id: msg.id, result: { currentTimeAt: Math.floor(Date.now() / 1000) } });\n return;\n } else {\n this.writeLine({\n jsonrpc: '2.0',\n id: msg.id,\n error: { code: -32601, message: 'The Ordewell planner is read-only and has no user to consult. Mutation belongs to the runners that execute the plan.' },\n });\n }\n if (!ANNOUNCED_REQUESTS.has(method)) return;\n emit({\n type: 'permission_request',\n id: String(msg.id ?? ''),\n name: method.split('/').pop() ?? method,\n detail: JSON.stringify(msg.params ?? {}),\n });\n }\n\n /** A tool item entering `inProgress` — announce the call so the timeline moves. */\n private emitItemStart(item: ThreadItem | undefined, emit: (e: AgentEvent) => void): void {\n if (!item?.id) return;\n switch (item.type) {\n case 'commandExecution':\n emit({ type: 'tool_call', id: item.id, name: 'shell', args: { command: item.command, cwd: item.cwd } });\n return;\n case 'mcpToolCall':\n emit({ type: 'tool_call', id: item.id, name: item.tool ?? 'mcp_tool', args: item.arguments ?? {} });\n return;\n case 'dynamicToolCall':\n emit({ type: 'tool_call', id: item.id, name: item.tool ?? 'tool', args: item.arguments ?? {} });\n return;\n case 'webSearch':\n emit({ type: 'tool_call', id: item.id, name: 'web_search', args: { query: item.query } });\n return;\n default:\n return;\n }\n }\n\n private emitItemDone(item: ThreadItem | undefined, emit: (e: AgentEvent) => void): void {\n if (!item?.type) return;\n const id = item.id ?? '';\n switch (item.type) {\n // A Codex turn is several whole messages — progress commentary, then the\n // final answer — not a token stream. Concatenated raw they run together\n // (\"…as requested.`head` failed because…\"), so each one after the first\n // opens a paragraph.\n case 'agentMessage':\n if (!item.text) return;\n emit({ type: 'assistant_text', text: this.turnHasText ? `\\n\\n${item.text}` : item.text });\n this.turnHasText = true;\n return;\n case 'reasoning': {\n const text = flattenText(item.summary) || flattenText(item.content) || item.text || '';\n if (text.trim()) emit({ type: 'thinking', text });\n return;\n }\n case 'commandExecution':\n emit({\n type: 'tool_result', id, name: 'shell',\n output: item.aggregatedOutput ?? '',\n success: (item.exitCode ?? 0) === 0,\n });\n return;\n case 'mcpToolCall':\n case 'dynamicToolCall':\n emit({\n type: 'tool_result', id, name: item.tool ?? 'tool',\n output: item.error ?? flattenText(item.result) ?? '',\n success: item.status !== 'error' && item.success !== false && !item.error,\n });\n return;\n // The query is empty when the search starts and filled when it lands, so\n // the result — not the call — is what carries what was actually searched.\n case 'webSearch':\n emit({ type: 'tool_result', id, name: 'web_search', output: item.query ?? '', success: true });\n return;\n // `fileChange` can only appear if the read-only sandbox was bypassed;\n // reporting it keeps that visible rather than silent.\n case 'fileChange':\n emit({ type: 'tool_result', id, name: 'file_change', output: JSON.stringify(item), success: false });\n return;\n default:\n return;\n }\n }\n}\n","import type { ChildProcess } from 'child_process';\nimport { augmentedPath, withPath } from '../../utils/shellPath';\nimport { planDirectLaunch } from '../../utils/launch';\nimport { killTree } from '../../utils/processTree';\nimport type { AgentAdapter, AgentEvent, AgentProcessDeps, AgentStartOptions } from './AgentAdapter';\n\nconst SERVER_READY_TIMEOUT_MS = 30000;\nconst STDERR_TAIL_CHARS = 4000;\n/** How long a turn waits for `/event` before posting anyway. See {@link OpenCodeAdapter.send}. */\nconst STREAM_CONNECT_TIMEOUT_MS = 5000;\n\n/**\n * Tools withheld from a planning session (T1). `question` is the load-bearing\n * one: it blocks the turn on an answer from a user who is not watching, and the\n * message POST then never returns — an absent answer has to mean denial, not a\n * hung planner. The rest are the write tools, withheld for the same reason\n * {@link ClaudeCodeAdapter} names them despite `--permission-mode plan`: the\n * `plan` agent already refuses them, and a future default must not quietly\n * hand the planner an edit.\n */\nconst DISABLED_TOOLS: Record<string, boolean> = {\n question: false,\n edit: false,\n write: false,\n apply_patch: false,\n todowrite: false,\n};\n\ninterface OpenCodePart {\n id?: string;\n type?: string;\n text?: string;\n tool?: string;\n callID?: string;\n messageID?: string;\n state?: { status?: string; input?: Record<string, unknown>; output?: string; error?: string };\n}\n\n/** `permission.asked` (and its v2 spelling) — the only server→client request OpenCode makes. */\ninterface OpenCodePermissionAsk {\n id?: string;\n sessionID?: string;\n permission?: string;\n action?: string;\n patterns?: string[];\n resources?: string[];\n metadata?: Record<string, unknown>;\n}\n\ninterface OpenCodeMessageResponse {\n parts?: OpenCodePart[];\n /** `AssistantMessage.error` is a tagged union: `{ name, data: { message } }`. */\n info?: { id?: string; error?: { name?: string; data?: { message?: string } } };\n error?: { message?: string } | string;\n}\n\n/**\n * OpenCode addresses a model as `{providerID, modelID}`; discovery and the\n * plan artifact carry the flat `provider/model` id the CLI's `--model` flag\n * takes. Split on the first slash — provider ids never contain one, model ids\n * sometimes do (`openrouter/anthropic/claude-sonnet-4`).\n */\nfunction splitModelId(id: string): { providerID: string; modelID: string } | null {\n const slash = id.indexOf('/');\n if (slash <= 0 || slash === id.length - 1) return null;\n return { providerID: id.slice(0, slash), modelID: id.slice(slash + 1) };\n}\n\n/**\n * OpenCode as a planner, over its headless HTTP server (ADR-0009).\n *\n * The odd one out: `opencode serve` is a real server rather than a stdio\n * protocol, so this adapter owns both halves of the boundary — it spawns the\n * process through the same injected `spawn` every other adapter uses, then\n * talks to it through the injected `fetch`. Both are part of the one seam the\n * tests drive.\n *\n * The turn ends when the message POST resolves. Live events stream from the\n * server's `/event` channel, but the POST is what settles the turn: an event\n * name that changes between OpenCode versions then costs liveness, not\n * correctness.\n */\nexport class OpenCodeAdapter implements AgentAdapter {\n readonly agentId = 'opencode';\n\n private process: ChildProcess | null = null;\n private baseUrl: string | null = null;\n private sessionId: string | null = null;\n private stderrTail = '';\n private exited = false;\n private disposed = false;\n private opts: AgentStartOptions | null = null;\n\n constructor(private deps: AgentProcessDeps) {}\n\n async start(opts: AgentStartOptions): Promise<void> {\n this.opts = opts;\n const resolvePath = this.deps.resolvePath ?? augmentedPath;\n const PATH = await resolvePath();\n\n // On POSIX this is `opencode` unchanged; on Windows it resolves the real\n // executable, because CreateProcess performs no PATHEXT lookup.\n const launch = await planDirectLaunch('opencode', ['serve', '--hostname', '127.0.0.1', '--port', '0'], {\n platform: this.deps.platform,\n resolvePath,\n });\n this.process = this.deps.spawn(launch.file, launch.args, {\n env: withPath(process.env, PATH),\n stdio: ['pipe', 'pipe', 'pipe'],\n cwd: opts.cwd,\n windowsVerbatimArguments: launch.verbatim,\n });\n\n const banner = new Promise<string | null>((resolve) => {\n let seen = '';\n const scan = (chunk: Buffer) => {\n seen += chunk.toString();\n const match = seen.match(/https?:\\/\\/[^\\s]+/);\n if (match) resolve(match[0].replace(/[.,)]$/, ''));\n };\n this.process!.stdout?.on('data', scan);\n this.process!.stderr?.on('data', (chunk: Buffer) => {\n this.stderrTail = (this.stderrTail + chunk.toString()).slice(-STDERR_TAIL_CHARS);\n scan(chunk);\n });\n this.process!.on('exit', () => { this.exited = true; resolve(null); });\n this.process!.on('error', (err) => {\n this.exited = true;\n this.stderrTail = (this.stderrTail + `\\n${err.message}`).slice(-STDERR_TAIL_CHARS);\n resolve(null);\n });\n const timer = setTimeout(() => resolve(null), SERVER_READY_TIMEOUT_MS);\n timer.unref?.();\n });\n\n this.baseUrl = await banner;\n if (!this.baseUrl) {\n throw new Error(`The OpenCode planner server did not start.${this.stderrTail.trim() ? `\\n\\n${this.stderrTail.trim()}` : ''}`);\n }\n\n // A resume id names a session on disk, not on this process — so it is\n // checked rather than trusted. A stale one degrades to a fresh session\n // (T4), where the caller reseeds from Ordewell's own transcript.\n if (opts.resumeSessionId) {\n const existing = await this.json<{ id?: string }>('GET', `/session/${opts.resumeSessionId}`).catch(() => null);\n if (existing?.id) {\n this.sessionId = existing.id;\n return;\n }\n }\n const created = await this.json<{ id?: string }>('POST', '/session', {});\n if (!created?.id) throw new Error('The OpenCode planner server did not return a session id.');\n this.sessionId = created.id;\n }\n\n async send(message: string, onEvent: (event: AgentEvent) => void, signal?: AbortSignal): Promise<void> {\n if (!this.baseUrl || !this.sessionId) throw new Error('OpenCode planner session is not started');\n if (this.exited) {\n onEvent({ type: 'error', message: this.exitMessage() });\n return;\n }\n\n const seen = new Set<string>();\n const streamAbort = new AbortController();\n let connected: () => void = () => {};\n const streamReady = new Promise<void>((resolve) => { connected = resolve; });\n // The live stream carries tool activity only. It also replays the user's\n // own message back as text parts, and the event frame gives no role to\n // filter on — so prose is taken from the settled response instead, where\n // `info.id` says exactly which message is the assistant's. Letting the\n // echo through would put the user's goal into the planner's reply text,\n // and a goal containing JSON would then be parsed as the plan.\n const live = this.streamEvents(\n streamAbort.signal,\n (part) => { if (part.type === 'tool') this.emitPart(part, seen, onEvent); },\n (ask) => this.denyPermission(ask, seen, onEvent),\n connected,\n );\n\n // The stream stopped being best-effort the moment permission denial moved\n // onto it: a request raised before we connect is one nobody answers, and\n // the message POST then hangs until its own timeout. Waiting is bounded so\n // a server that never opens `/event` still gets its turn.\n await Promise.race([streamReady, new Promise<void>((r) => { const t = setTimeout(r, STREAM_CONNECT_TIMEOUT_MS); t.unref?.(); })]);\n\n try {\n const model = this.opts?.model ? splitModelId(this.opts.model) : null;\n const body = {\n parts: [{ type: 'text', text: message }],\n // The read-only guarantee: OpenCode's own plan agent has no write tools.\n agent: 'plan',\n tools: DISABLED_TOOLS,\n ...(model ? { model } : {}),\n ...(this.opts?.effort ? { variant: this.opts.effort } : {}),\n ...(this.opts?.systemPrompt ? { system: this.opts.systemPrompt } : {}),\n };\n const reply = await this.json<OpenCodeMessageResponse>('POST', `/session/${this.sessionId}/message`, body, signal);\n\n if (signal?.aborted) { this.dispose(); return; }\n\n const failure = typeof reply?.error === 'string'\n ? reply.error\n : (reply?.error as { message?: string } | undefined)?.message ?? reply?.info?.error?.data?.message;\n if (failure) {\n onEvent({ type: 'error', message: failure });\n return;\n }\n // The settled response is authoritative: it names the assistant message,\n // so its parts are the ones that make up the reply. Tool parts already\n // seen live are deduplicated by call id; anything the stream missed\n // (including a stream that never connected) arrives here.\n const assistantId = reply?.info?.id;\n for (const part of reply?.parts ?? []) {\n if (part.type !== 'tool' && assistantId && part.messageID !== assistantId) continue;\n this.emitPart(part, seen, onEvent);\n }\n onEvent({ type: 'turn_end' });\n } catch (err) {\n if (signal?.aborted) { this.dispose(); return; }\n onEvent({ type: 'error', message: `The OpenCode planner turn failed: ${err instanceof Error ? err.message : String(err)}` });\n } finally {\n streamAbort.abort();\n await live.catch(() => { /* the stream is best-effort */ });\n }\n }\n\n /**\n * Emit one message part, once. OpenCode reports a tool part repeatedly as it\n * moves through pending → running → completed, so parts are keyed by id and\n * only the terminal state produces a result.\n */\n private emitPart(part: OpenCodePart, seen: Set<string>, onEvent: (e: AgentEvent) => void): void {\n if (!part?.type) return;\n const id = part.id ?? part.callID ?? '';\n\n if (part.type === 'text' && part.text) {\n if (seen.has(`text:${id}`)) return;\n seen.add(`text:${id}`);\n onEvent({ type: 'assistant_text', text: part.text });\n return;\n }\n if (part.type === 'reasoning' && part.text) {\n if (seen.has(`reasoning:${id}`)) return;\n seen.add(`reasoning:${id}`);\n onEvent({ type: 'thinking', text: part.text });\n return;\n }\n if (part.type !== 'tool') return;\n\n const callId = part.callID ?? id;\n const name = part.tool ?? 'tool';\n const status = part.state?.status;\n const input = part.state?.input;\n // A `pending` tool part carries no input yet, so announcing it there gave\n // every call an empty arg summary. Waiting for the first state that has\n // input costs a moment of liveness and buys a readable timeline.\n if (!seen.has(`call:${callId}`) && (status !== 'pending' || (input && Object.keys(input).length > 0))) {\n seen.add(`call:${callId}`);\n onEvent({ type: 'tool_call', id: callId, name, args: input ?? {} });\n }\n if ((status === 'completed' || status === 'error') && !seen.has(`result:${callId}`)) {\n seen.add(`result:${callId}`);\n onEvent({\n type: 'tool_result',\n id: callId,\n name,\n output: part.state?.output ?? part.state?.error ?? '',\n success: status === 'completed',\n });\n }\n }\n\n /**\n * Deny one permission request (T1). OpenCode blocks the turn until the\n * request is answered, so this must answer — `reject` rather than a silent\n * drop, which is the same \"absent answer is a denial\" invariant ADR-0008\n * states for Ordewell's own tools. The refusal is announced so the timeline\n * shows the planner reaching for something it may not have.\n */\n private denyPermission(ask: OpenCodePermissionAsk, seen: Set<string>, onEvent: (e: AgentEvent) => void): void {\n const id = ask.id;\n if (!id || seen.has(`perm:${id}`)) return;\n seen.add(`perm:${id}`);\n const name = ask.permission ?? ask.action ?? 'permission';\n const scope = (ask.patterns ?? ask.resources ?? []).join(', ');\n onEvent({\n type: 'permission_request',\n id,\n name,\n detail: JSON.stringify({ ...(scope ? { scope } : {}), ...(ask.metadata ?? {}) }),\n });\n void this.json('POST', `/session/${ask.sessionID ?? this.sessionId}/permissions/${id}`, { response: 'reject' })\n .catch(() => { /* a server that forgot the request will not hang on it either */ });\n }\n\n /**\n * Server-sent events from `/event`. Tool activity on it is liveness only —\n * the settled POST repeats it — but permission requests arrive nowhere else,\n * so the stream is load-bearing for {@link denyPermission}.\n */\n private async streamEvents(\n signal: AbortSignal,\n onPart: (part: OpenCodePart) => void,\n onPermission: (ask: OpenCodePermissionAsk) => void,\n onConnected: () => void,\n ): Promise<void> {\n const response = await this.deps.fetch(`${this.baseUrl}/event`, { signal }).catch(() => null);\n const body = response?.body;\n if (!body) { onConnected(); return; }\n onConnected();\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n for (;;) {\n const { done, value } = await reader.read().catch(() => ({ done: true, value: undefined }));\n if (done) return;\n buffer += decoder.decode(value, { stream: true });\n let newline: number;\n while ((newline = buffer.indexOf('\\n')) >= 0) {\n const line = buffer.slice(0, newline).trim();\n buffer = buffer.slice(newline + 1);\n if (!line.startsWith('data:')) continue;\n try {\n const event = JSON.parse(line.slice(5).trim()) as {\n type?: string;\n properties?: (OpenCodePermissionAsk & { part?: OpenCodePart });\n };\n const props = event.properties;\n if (!props) continue;\n if (props.sessionID && props.sessionID !== this.sessionId) continue;\n if (event.type === 'permission.asked' || event.type === 'permission.v2.asked') onPermission(props);\n else if (props.part) onPart(props.part);\n } catch {\n // A partial or unrecognized frame costs one event, not the turn.\n }\n }\n }\n }\n\n private async json<T>(method: string, path: string, body?: unknown, signal?: AbortSignal): Promise<T | null> {\n const response = await this.deps.fetch(`${this.baseUrl}${path}`, {\n method,\n headers: { 'content-type': 'application/json' },\n ...(body === undefined ? {} : { body: JSON.stringify(body) }),\n ...(signal ? { signal } : {}),\n });\n if (!response.ok) throw new Error(`${method} ${path} failed: ${response.status} ${response.statusText}`);\n return (await response.json().catch(() => null)) as T | null;\n }\n\n nativeSessionId(): string | null { return this.sessionId; }\n\n dispose(): void {\n if (this.disposed) return;\n this.disposed = true;\n const proc = this.process;\n this.process = null;\n this.baseUrl = null;\n // Tree-wide: `opencode serve` is a server, and on Windows it may sit behind\n // a cmd.exe shim. A surviving server keeps the port and the session.\n killTree(proc, { platform: this.deps.platform });\n }\n\n private exitMessage(): string {\n const tail = this.stderrTail.trim();\n return `The OpenCode planner server exited.${tail ? `\\n\\n${tail}` : ''}`;\n }\n}\n","import type { ResearchToolType } from '../../models/Task';\n\n/**\n * Map a coding agent's own tool name onto Ordewell's research vocabulary\n * (ADR-0009, T5).\n *\n * A harness planner brings its own toolbox, and most of it overlaps ours: a\n * `Read` is a `read_file`, a `Grep` is a `grep`. Those map onto existing\n * members and render in every surface through the code path that is already\n * there. Everything else — `Edit`, `WebFetch`, `TodoWrite`, `Task`, whatever\n * ships next — becomes `agent_tool` carrying its real name.\n *\n * Nothing is relabelled as a tool it is not. Calling a web fetch a `bash` to\n * avoid adding a union member would put a lie in the timeline, which is the\n * point ADR-0008 spent its effort establishing.\n */\nconst KNOWN_TOOLS: Record<string, ResearchToolType> = {\n // Claude Code\n read: 'read_file',\n grep: 'grep',\n glob: 'glob',\n bash: 'bash',\n ls: 'list_dir',\n webfetch: 'fetch',\n websearch: 'web_search',\n // Codex — its sandboxed command tool is a shell by another name\n shell: 'bash',\n exec_command: 'bash',\n local_shell: 'bash',\n // OpenCode\n list: 'list_dir',\n fetch: 'fetch',\n};\n\nexport interface MappedTool {\n tool: ResearchToolType;\n /** The agent's own name, kept whenever it differs from the member it mapped to. */\n toolLabel?: string;\n}\n\n/**\n * Classify one agent tool name. Case- and separator-insensitive, because the\n * three agents disagree on `Read` vs `read` vs `read_file` for the same thing.\n */\nexport function mapAgentTool(name: string): MappedTool {\n const normalized = name.trim().toLowerCase().replace(/[_-]/g, '');\n const direct = KNOWN_TOOLS[normalized] ?? KNOWN_TOOLS[name.trim().toLowerCase()];\n if (direct) {\n // The label survives even on a mapped tool: `Read` and `read_file` render\n // the same way, but the transcript should still say which one ran.\n return { tool: direct, toolLabel: name };\n }\n return { tool: 'agent_tool', toolLabel: name };\n}\n\n/**\n * Normalize an agent's tool arguments into the shapes `summarizeToolCall`\n * already knows how to read, so a harness `Read` gets a one-line summary\n * instead of a bare tool name. Unknown keys are preserved — the raw args stay\n * visible under the surfaces' output chevron.\n */\nexport function normalizeAgentArgs(tool: ResearchToolType, args: Record<string, unknown>): Record<string, unknown> {\n const out = { ...args };\n const alias = (from: string, to: string) => {\n if (out[to] === undefined && out[from] !== undefined) out[to] = out[from];\n };\n if (tool === 'read_file' || tool === 'list_dir') {\n alias('filePath', 'path');\n alias('file_path', 'path');\n alias('target', 'path');\n }\n if (tool === 'bash') {\n alias('cmd', 'command');\n alias('script', 'command');\n // Codex hands the command over as an argv array; the summary wants a string.\n if (typeof out.command !== 'string' && Array.isArray(out.command)) {\n out.command = (out.command as unknown[]).join(' ');\n }\n }\n if (tool === 'fetch') alias('uri', 'url');\n if (tool === 'web_search') alias('q', 'query');\n return out;\n}\n","import { Task, ConversationMessage, DiscoveredModel, ResearchLogEntry, ResearchProgress, RunnerId } from '../models/Task';\nimport { IConfig } from '../interfaces/IConfig';\nimport { IFileSystem } from '../interfaces/IFileSystem';\nimport { IWebFetcher } from '../interfaces/IWebFetcher';\nimport type { LegacyPlanState } from '../models/Task';\nimport type { RunnerModeInfo } from './ModeResolver';\nimport { GeminiService } from './GeminiService';\nimport { OpenAiService } from './OpenAiService';\nimport { isCliProvider } from './ProviderRegistry';\nimport { CliAgentAiService, type CliAgentAiServiceDeps } from './harness/CliAgentAiService';\nimport type { PlannerModes } from './plannerModes';\n\n/**\n * Everything the conversation loop needs to start planning (ADR-0002).\n * The AI service keeps the tool-use message history internally across turns;\n * the surfaces only exchange user/assistant messages with it.\n */\nexport interface ConversationRequest {\n goal: string;\n runners: RunnerId[];\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>;\n fs: IFileSystem;\n onProgress: (progress: ResearchProgress) => void;\n fetcher?: IWebFetcher;\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>;\n autonomousDefault?: boolean;\n grillMeEnabled?: boolean;\n prdEnabled?: boolean;\n reviewEnabled?: boolean;\n verificationEnabled?: boolean;\n /** Declare the spawn_research_agent tool to the planner (issue #34, default off). */\n researchSubagentsEnabled?: boolean;\n signal?: AbortSignal;\n /**\n * Persisted dialogue to seed a resumed conversation (session reload). The\n * turns are injected into the message history verbatim — no LLM call happens\n * for them; the first call is the turn opened by `initialMessage`.\n */\n priorHistory?: ConversationMessage[];\n /**\n * The user message that opens this turn. Defaults to `goal` — set it when\n * resuming so the system prompt keeps the original goal while the turn\n * carries the user's new message.\n */\n initialMessage?: string;\n}\n\n/**\n * One planner turn's outcome. The planner talks to the user (`message`),\n * commits a full plan (`plan`, a `{tasks:[...]}` JSON object), or emits\n * targeted task edits (`task_ops`, a `{taskOps:[...]}` JSON object). The\n * Session validates and applies task ops atomically; the AI service only\n * parses them.\n */\nexport type ConversationTurn =\n | { kind: 'message'; text: string; researchLog: ResearchLogEntry[] }\n | { kind: 'plan'; tasks: Task[]; text: string; researchLog: ResearchLogEntry[] }\n | { kind: 'task_ops'; ops: import('./TaskOps').TaskOp[]; text: string; researchLog: ResearchLogEntry[] };\n\nexport interface IAiService {\n /**\n * Begin the planner conversation: collect workspace context, run the\n * research/tool loop, and return the first planner turn. The service\n * retains the full API message history for subsequent\n * {@link continueConversation} calls.\n */\n startConversation(req: ConversationRequest): Promise<ConversationTurn>;\n\n /**\n * Feed the user's reply into the active conversation and return the next\n * planner turn. Throws if no conversation is active.\n */\n continueConversation(\n userMessage: string,\n onProgress: (progress: ResearchProgress) => void,\n signal?: AbortSignal,\n ): Promise<ConversationTurn>;\n\n /**\n * Whether a planner conversation is currently held in memory. A branching\n * predicate only — never a test for whether there is anything to release.\n * The harness backend holds an OS process that outlives its conversation, so\n * guarding {@link reset} with this leaks an agent process; call `reset`\n * unconditionally instead.\n */\n hasActiveConversation(): boolean;\n\n /**\n * Whether the active conversation (if any) still matches the planner\n * model/effort currently configured. Optional, and true when absent: a\n * vendor backend re-reads its model from config on every turn, so there is\n * nothing to drift. A harness planner (ADR-0009) is the exception — its\n * model is baked into the agent process at spawn — so only\n * {@link CliAgentAiService} answers this for real. False tells the caller\n * the same thing an absent conversation would: don't call\n * `continueConversation`, restart instead so the new model takes effect.\n */\n conversationMatchesConfig?(): boolean;\n\n /**\n * One-shot research + plan for non-conversational surfaces (CLI `plan --goal`,\n * web REST). Never asks questions — it plans with what it can find.\n */\n researchAndPlan(\n userDescription: string,\n runners: RunnerId[],\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n fs: IFileSystem,\n onProgress: (progress: ResearchProgress) => void,\n fetcher?: IWebFetcher,\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n modes?: PlannerModes,\n signal?: AbortSignal,\n ): Promise<{ tasks: Task[]; researchLog: ResearchLogEntry[]; researchResults: string }>;\n\n generatePlanDirect(\n userDescription: string,\n runners: RunnerId[],\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n onToken?: (token: string) => void,\n fs?: IFileSystem,\n fetcher?: IWebFetcher,\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n modes?: PlannerModes,\n signal?: AbortSignal,\n ): Promise<Task[]>;\n\n modifyPlan(\n existingPlan: LegacyPlanState,\n userRequest: string,\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n onProgress?: (progress: ResearchProgress) => void,\n fs?: IFileSystem,\n fetcher?: IWebFetcher,\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n modes?: PlannerModes,\n signal?: AbortSignal,\n ): Promise<{ tasks: Task[] }>;\n\n /**\n * Release everything this service holds: the conversation, any in-flight\n * turn, and — on the harness backend — the agent process itself. Idempotent\n * and cheap in every implementation, so callers never gate it.\n */\n reset(): void;\n\n sendPlanningPrompt(\n prompt: string,\n runners: RunnerId[],\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n autonomousDefault?: boolean,\n ): Promise<Task[]>;\n}\n\n/**\n * The single branch point between planner transports. Two of them talk HTTP to\n * an LLM vendor; the third (ADR-0009) drives a coding agent already installed\n * on the machine. Everything downstream — the plan contract, the research-step\n * stream, the four surfaces — is shared.\n */\nexport function createAiService(config: IConfig, deps?: CliAgentAiServiceDeps): IAiService {\n if (isCliProvider(config.aiProvider)) {\n return new CliAgentAiService(config, deps);\n }\n if (config.aiProvider === 'google') {\n return new GeminiService(config);\n }\n return new OpenAiService(config);\n}\n","import { lookup } from 'node:dns/promises';\nimport type { IWebFetcher } from '../interfaces/IWebFetcher';\nimport type { IApproval } from '../interfaces/IApproval';\nimport type { ToolOutcome } from '../interfaces/IFileSystem';\n\n/**\n * The concrete `fetch`/`web_search` implementation, in core so the web server\n * and the VS Code extension share one behavior. Until now `IWebFetcher` had no\n * implementation anywhere, which meant the `fetch` tool was declared to every\n * planner and always answered \"not available in this environment\" — a tool the\n * model could see, choose, and never use.\n *\n * Approval is per origin, not per URL: reading three pages of one library's\n * docs is one decision, not three.\n */\n\nexport interface HttpWebFetcherOptions {\n approval: IApproval;\n /** Injected in tests; defaults to the platform `fetch`. */\n fetchImpl?: typeof fetch;\n maxChars?: number;\n timeoutMs?: number;\n /** Override the SSRF / private-host guard in tests. */\n isBlockedHost?: (host: string, port: string) => Promise<boolean>;\n /** Override DNS resolution in tests. */\n resolveHost?: (host: string) => Promise<string[]>;\n}\n\nconst DEFAULT_MAX_CHARS = 40_000;\nconst DEFAULT_TIMEOUT_MS = 20_000;\nconst MAX_BODY_BYTES = 2_000_000;\nconst MAX_REDIRECTS = 5;\n/** A default UA gets refused by enough sites that it is not worth the confusing failures. */\nconst USER_AGENT = 'Mozilla/5.0 (compatible; Ordewell-Planner/1.0; +https://github.com/ordewell)';\n\n/**\n * DuckDuckGo's lite endpoint: no API key, no account, and stable enough for\n * \"find me the docs URL\". It is HTML scraping, so it is the most brittle thing\n * here by construction — every failure path degrades to a tool result that\n * tells the planner to fall back to `fetch` with a known URL.\n */\nconst SEARCH_ENDPOINT = 'https://lite.duckduckgo.com/lite/?q=';\n\nfunction decodeEntities(text: string): string {\n return text\n .replace(/&nbsp;/g, ' ')\n .replace(/&amp;/g, '&')\n .replace(/&lt;/g, '<')\n .replace(/&gt;/g, '>')\n .replace(/&quot;/g, '\"')\n .replace(/&#39;/g, \"'\")\n .replace(/&#x27;/g, \"'\");\n}\n\nfunction htmlToText(html: string): string {\n return decodeEntities(\n html\n .replace(/<script\\b[^>]*>[\\s\\S]*?<\\/script>/gi, ' ')\n .replace(/<style\\b[^>]*>[\\s\\S]*?<\\/style>/gi, ' ')\n .replace(/<noscript\\b[^>]*>[\\s\\S]*?<\\/noscript>/gi, ' ')\n .replace(/<\\/(p|div|li|h[1-6]|tr|section|article)>/gi, '\\n')\n .replace(/<br\\s*\\/?>/gi, '\\n')\n .replace(/<[^>]+>/g, ' '),\n )\n .replace(/[ \\t\\f\\v]+/g, ' ')\n .replace(/\\n\\s*\\n\\s*\\n+/g, '\\n\\n')\n .split('\\n')\n .map((line) => line.trim())\n .join('\\n')\n .trim();\n}\n\ninterface SearchHit { title: string; url: string; snippet?: string }\n\n/** Pull result links out of the lite endpoint's markup. */\nfunction parseSearchHits(html: string): SearchHit[] {\n const hits: SearchHit[] = [];\n const linkPattern = /<a\\b[^>]*class=\"[^\"]*result(?:-link|__a)[^\"]*\"[^>]*href=\"([^\"]+)\"[^>]*>([\\s\\S]*?)<\\/a>/gi;\n const snippetPattern = /class=\"[^\"]*result(?:-snippet|__snippet)[^\"]*\"[^>]*>([\\s\\S]*?)</gi;\n\n const snippets: string[] = [];\n for (let m = snippetPattern.exec(html); m; m = snippetPattern.exec(html)) {\n snippets.push(decodeEntities(m[1].replace(/<[^>]+>/g, ' ')).replace(/\\s+/g, ' ').trim());\n }\n\n for (let m = linkPattern.exec(html); m; m = linkPattern.exec(html)) {\n const title = decodeEntities(m[2].replace(/<[^>]+>/g, ' ')).replace(/\\s+/g, ' ').trim();\n if (!title) continue;\n hits.push({ title, url: decodeEntities(m[1]), snippet: snippets[hits.length] });\n }\n return hits;\n}\n\n/**\n * Reject hosts that resolve to (or literally name) loopback, link-local, or\n * RFC1918 private space — the SSRF surface. `fetch` is the one capability that\n * leaves the machine, so an unguarded `http://169.254.169.254/` would hand a\n * prompt-injected planner the cloud metadata credentials.\n */\nfunction isPrivateIp(ip: string): boolean {\n // `dns.lookup('')` resolves rather than rejecting, with `address: null` —\n // fail closed instead of letting a falsy/non-string address slip past every\n // regex below untested.\n if (!ip) return true;\n if (ip === '0.0.0.0' || ip === '::' || ip === '::1' || ip === '::ffff:127.0.0.1') return true;\n if (/^127\\./.test(ip)) return true;\n if (/^169\\.254\\./.test(ip)) return true;\n if (/^10\\./.test(ip)) return true;\n if (/^192\\.168\\./.test(ip)) return true;\n // 172.16.0.0/12 = 172.16.0.0 – 172.31.255.255\n const m172 = /^172\\.(\\d+)\\./.exec(ip);\n if (m172 && Number(m172[1]) >= 16 && Number(m172[1]) <= 31) return true;\n // fe80::/10 link-local IPv6\n if (/^fe[89ab][0-9a-f]/i.test(ip)) return true;\n return false;\n}\n\nfunction isIpLiteral(host: string): boolean {\n return /^\\d{1,3}(\\.\\d{1,3}){3}$/.test(host) || /^\\[?[0-9a-fA-F:]+\\]?$/i.test(host);\n}\n\nfunction sanitizeError(err: unknown): string {\n const msg = err instanceof Error ? err.message : String(err);\n if (/abort/i.test(msg)) return 'timed out';\n if (/ECONNREFUSED|ECONNRESET|EHOSTUNREACH|ENETUNREACH/i.test(msg)) return 'host not reachable';\n if (/ENOTFOUND|getaddrinfo/i.test(msg)) return 'host not found';\n return msg.replace(/https?:\\/\\/\\S+/g, '<url>');\n}\n\nexport class HttpWebFetcher implements IWebFetcher {\n private readonly approval: IApproval;\n private readonly fetchImpl: typeof fetch;\n private readonly maxChars: number;\n private readonly timeoutMs: number;\n private readonly isBlockedHost: (host: string, port: string) => Promise<boolean>;\n private readonly resolveHost: (host: string) => Promise<string[]>;\n\n constructor(opts: HttpWebFetcherOptions) {\n this.approval = opts.approval;\n this.fetchImpl = opts.fetchImpl ?? globalThis.fetch;\n this.maxChars = opts.maxChars ?? DEFAULT_MAX_CHARS;\n this.timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n this.isBlockedHost = opts.isBlockedHost ?? this.defaultIsBlocked.bind(this);\n this.resolveHost = opts.resolveHost ?? (async (h) => { const r = await lookup(h); return [r.address]; });\n }\n\n private async defaultIsBlocked(host: string, port: string): Promise<boolean> {\n if (!['', '80', '443'].includes(port)) return true;\n if (isIpLiteral(host)) return isPrivateIp(host.startsWith('[') ? host.slice(1, -1) : host);\n const lower = host.toLowerCase();\n if (lower === 'localhost' || lower === 'ip6-localhost' || lower === 'ip6-loopback') return true;\n try {\n const addrs = await this.resolveHost(host);\n if (addrs.some((a) => isPrivateIp(a))) return true;\n } catch {\n return true;\n }\n return false;\n }\n\n async confirm(url: string): Promise<boolean> {\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n return false;\n }\n // Only the two network schemes. `file:` would turn this into a second,\n // unconfined path reader that bypasses the filesystem's confinement.\n if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') return false;\n\n if (await this.isBlockedHost(parsed.hostname, parsed.port)) return false;\n\n return this.approval.request({\n kind: 'url_fetch',\n subject: url,\n scope: `${parsed.origin}/*`,\n detail: `Planner research wants to fetch ${parsed.origin}`,\n });\n }\n\n async fetch(url: string): Promise<ToolOutcome> {\n // Gate on the same confirm search uses, so the SSRF guard and the\n // per-origin approval both run even when a caller invokes fetch directly\n // rather than through executeTool.\n if (!await this.confirm(url)) {\n return { success: false, output: `Fetch denied (blocked host or not approved): ${url}`, truncated: false };\n }\n return this.get(url, 'Fetch');\n }\n\n async search(query: string): Promise<ToolOutcome> {\n const url = SEARCH_ENDPOINT + encodeURIComponent(query);\n if (!await this.confirm(url)) {\n return { success: false, output: `Web search denied by user for query: ${query}`, truncated: false };\n }\n\n const page = await this.request(url);\n if (!page.ok) return { success: false, output: `Web search failed: ${page.error}`, truncated: false };\n\n const hits = parseSearchHits(page.body).slice(0, 10);\n if (hits.length === 0) {\n return {\n success: false,\n output: `No results could be parsed for \"${query}\". Search is best-effort; if you already know a documentation URL, use the fetch tool directly.`,\n truncated: false,\n };\n }\n\n const output = hits\n .map((hit, i) => `${i + 1}. ${hit.title}\\n ${hit.url}${hit.snippet ? `\\n ${hit.snippet}` : ''}`)\n .join('\\n\\n');\n return { success: true, output, truncated: false };\n }\n\n private async get(url: string, label: string): Promise<ToolOutcome> {\n const page = await this.request(url);\n if (!page.ok) return { success: false, output: `${label} failed: ${page.error}`, truncated: false };\n\n const text = page.isHtml ? htmlToText(page.body) : page.body;\n if (page.truncated || text.length > this.maxChars) {\n const sliced = text.slice(0, this.maxChars);\n return {\n success: true,\n output: `${sliced}\\n\\n[... truncated to ${this.maxChars} chars, total ${text.length}${page.truncated ? '+, body was byte-capped at the source' : ''}]`,\n truncated: true,\n };\n }\n return { success: true, output: text, truncated: false };\n }\n\n private async request(url: string): Promise<{ ok: true; body: string; isHtml: boolean; truncated: boolean } | { ok: false; error: string }> {\n let current = url;\n for (let hop = 0; hop <= MAX_REDIRECTS; hop++) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n try {\n const res = await this.fetchImpl(current, {\n signal: controller.signal,\n headers: { 'user-agent': USER_AGENT, accept: 'text/html,application/xhtml+xml,application/json;q=0.9,*/*;q=0.8' },\n redirect: 'manual',\n });\n if (res.status >= 300 && res.status < 400) {\n const location = res.headers.get('location');\n if (!location) return { ok: false, error: `redirect (${res.status}) with no Location` };\n const next = new URL(location, current).href;\n // Re-check the destination the same way `confirm` checked the origin:\n // a redirect to a private IP, or to a non-http(s) scheme like\n // `file:`, would otherwise bypass both guards `confirm` applies to\n // the initial URL.\n const nextParsed = new URL(next);\n if (nextParsed.protocol !== 'https:' && nextParsed.protocol !== 'http:') {\n return { ok: false, error: 'redirect to a non-HTTP scheme' };\n }\n if (await this.isBlockedHost(nextParsed.hostname, nextParsed.port)) {\n return { ok: false, error: 'redirect to a blocked host' };\n }\n current = next;\n continue;\n }\n if (!res.ok) return { ok: false, error: `HTTP ${res.status}` };\n\n const contentType = res.headers.get('content-type') ?? '';\n const { body, truncated } = await readBounded(res, MAX_BODY_BYTES);\n return { ok: true, body, isHtml: /html|xml/i.test(contentType), truncated };\n } catch (err) {\n return { ok: false, error: sanitizeError(err) };\n } finally {\n clearTimeout(timer);\n }\n }\n return { ok: false, error: `too many redirects (>${MAX_REDIRECTS})` };\n }\n}\n\nasync function readBounded(res: Response, maxBytes: number): Promise<{ body: string; truncated: boolean }> {\n const reader = res.body?.[Symbol.asyncIterator]\n ? readFromIterable(res.body as unknown as AsyncIterable<Uint8Array>, maxBytes)\n : readFromText(res, maxBytes);\n return reader;\n}\n\nasync function readFromIterable(source: AsyncIterable<Uint8Array>, maxBytes: number): Promise<{ body: string; truncated: boolean }> {\n const chunks: Buffer[] = [];\n let total = 0;\n let truncated = false;\n for await (const chunk of source) {\n const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);\n if (total + buf.length > maxBytes) {\n chunks.push(buf.subarray(0, maxBytes - total));\n total = maxBytes;\n truncated = true;\n break;\n }\n chunks.push(buf);\n total += buf.length;\n }\n return { body: Buffer.concat(chunks).toString('utf8'), truncated };\n}\n\nasync function readFromText(res: Response, maxBytes: number): Promise<{ body: string; truncated: boolean }> {\n const text = await res.text();\n if (Buffer.byteLength(text, 'utf8') <= maxBytes) return { body: text, truncated: false };\n return { body: Buffer.from(text, 'utf8').subarray(0, maxBytes).toString('utf8'), truncated: true };\n}\n","import type { DiscoveredModel, RunnerId, Task } from '../models/Task';\nimport { clampThinkingEffort } from './ModelAllowlistResolver';\nimport type { RunnerModeInfo } from './ModeResolver';\n\n/** What a runner offers a task: the models discovered for it and the modes its manifest declares. */\nexport interface RunnerCatalog {\n models: DiscoveredModel[];\n modes: RunnerModeInfo[];\n}\n\n/**\n * The model, thinking effort and mode a runner offers for a task.\n *\n * A task's model, effort and mode are all scoped to its runner:\n * `claude-sonnet-4-5` on Codex, or `acceptEdits` on OpenCode, are not degraded\n * choices but unspawnable ones. So this is where any task acquires a runnable\n * assignment — a runner change (below) and a hand-added task derive it the same\n * way. Each field in `current` is preserved when the runner also offers it, and\n * otherwise snapped to that runner's preferred entry (discovery already sorts\n * models by the manifest's `preferredPatterns`; `modes[0]` is the manifest's own\n * first choice).\n *\n * An empty catalog means discovery failed or the runner is a plugin we have no\n * list for — not that the runner offers nothing. That field is left out of the\n * patch and the runner validates last, matching `coerceAssignments`.\n */\nexport function runnerAssignment(\n catalog: RunnerCatalog,\n current?: Pick<Task, 'assignedModel' | 'taskMode'>,\n): Partial<Task> {\n const changes: Partial<Task> = {};\n\n const kept = current?.assignedModel && catalog.models.find((m) => m.modelId === current.assignedModel!.modelId);\n const model = kept ?? catalog.models[0];\n if (model) {\n const thinkingEffort = clampThinkingEffort(current?.assignedModel?.thinkingEffort, model.variants);\n changes.assignedModel = {\n modelId: model.modelId,\n modelLabel: model.modelLabel,\n thinkingEffort,\n availableVariants: model.variants.map((v) => v.id),\n };\n // Task.thinkingEffort predates assignedModel.thinkingEffort and is still\n // read by migration and task_ops. Left behind it would name an effort the\n // new model has no variant for.\n changes.thinkingEffort = thinkingEffort;\n }\n\n if (catalog.modes.length > 0) {\n changes.taskMode = catalog.modes.some((m) => m.id === current?.taskMode) ? current!.taskMode : catalog.modes[0].id;\n }\n\n return changes;\n}\n\n/**\n * Move a task onto a different runner, carrying its model, thinking effort and\n * mode over to values that runner actually offers. A runner change is never a\n * single-field edit — it either brings the other three with it or leaves the\n * task unrunnable.\n *\n * Returns the patch to apply, or `{}` when there is nothing to change.\n */\nexport function retargetTaskRunner(task: Task, runner: RunnerId, catalog: RunnerCatalog): Partial<Task> {\n if (task.type === 'user') return {};\n if (task.assignedRunner === runner) return {};\n return { assignedRunner: runner, ...runnerAssignment(catalog, task) };\n}\n","import type { LegacyPlanState, QueuedMessage, ResearchStep, RunnerId, Task, Verdict } from '../models/Task';\nimport type { ApprovalKind } from '../interfaces/IApproval';\nimport type { ApprovalSource } from './ApprovalPolicy';\n\nexport type SerializedTaskStatus = {\n id: string;\n status: string;\n verdict: { outcome: 'pass' | 'fail'; reason: string; checks: Verdict['checks'] } | null;\n};\n\nexport type SerializedTask = {\n id: string;\n order: number;\n title: string;\n type: string;\n description: string;\n dependencies: string[];\n assignedRunner: RunnerId;\n assignedModel: Task['assignedModel'] | null;\n taskMode: string;\n prompt: string | null;\n subtasks: SerializedTask[];\n userSteps: Task['userSteps'];\n thinkingEffort: Task['thinkingEffort'];\n autonomy: Task['autonomy'];\n sliceType: Task['sliceType'];\n userStoriesCovered: Task['userStoriesCovered'];\n};\n\nexport type SerializedPlan = {\n tasks: SerializedTask[];\n runners: RunnerId[];\n generatedAt: string;\n conversationHistory?: LegacyPlanState['conversationHistory'];\n prdMarkdown?: string;\n queuedMessages?: QueuedMessage[];\n};\n\nexport type SessionMessage =\n | { type: 'plan_generated'; plan: SerializedPlan; goal: string; runners: RunnerId[] }\n | { type: 'planner_message'; content: string; timestamp: string }\n | { type: 'status_update'; tasks: SerializedTaskStatus[] }\n | { type: 'review_needed'; tasks: SerializedTask[] }\n | { type: 'review_approved' }\n | { type: 'checkpoint'; taskId: string; taskTitle: string; summary: string }\n | { type: 'execution_complete'; summary: { total: number; completed: number; failed: number } }\n | { type: 'execution_stopped' }\n | { type: 'queue_ready' }\n | { type: 'task_updated'; taskId: string; changes: Record<string, unknown> }\n | { type: 'task_started'; taskId: string; order: number; title: string; runner: RunnerId; modelId?: string }\n | { type: 'task_output'; taskId: string; text: string }\n | { type: 'plan_thinking'; text: string }\n // `toolLabel` carries a harness planner's own name for the tool (ADR-0009) —\n // always set when `tool` is `agent_tool`, so no surface has to render the\n // catch-all member name at the user.\n | { type: 'research_step'; tool: string; toolLabel?: string; args: string; subagentId?: string; toolCallId?: string }\n | { type: 'plan_token'; token: string }\n | { type: 'research_step_done'; step: ResearchStep; subagentId?: string }\n // Planner research wants something outside its default envelope and is\n // blocked until a human answers. Broadcast rather than returned, because the\n // human may be on any surface (or several at once) and the request outlives\n // whichever HTTP call triggered it.\n | { type: 'approval_request'; id: string; kind: ApprovalKind; subject: string; scope: string; detail?: string }\n | { type: 'approval_settled'; id: string; granted: boolean }\n // A decision reached with no round-trip prompt: pre-approved via config,\n // remembered from earlier in this session, or the operator's mode floor\n // (allow/deny skipping the human entirely). The interactive path above\n // already has full visibility via approval_request/approval_settled; this\n // is the one that previously had none — a model silently auto-running\n // `npm test` because the scope was already granted looked identical, from\n // every UI, to it never having been asked in the first place.\n | {\n type: 'approval_decided';\n kind: ApprovalKind;\n subject: string;\n scope: string;\n detail?: string;\n granted: boolean;\n source: Exclude<ApprovalSource, 'asked'>;\n };\n\nexport type SessionBroadcaster = (msg: SessionMessage) => void;\n\nexport function serializeTask(t: Task): SerializedTask {\n return {\n id: t.id,\n order: t.order,\n title: t.title,\n type: t.type,\n description: t.description,\n dependencies: t.dependencies || [],\n assignedRunner: t.assignedRunner,\n assignedModel: t.assignedModel || null,\n taskMode: t.taskMode || 'build',\n prompt: t.prompt || null,\n subtasks: (t.subtasks || []).map(serializeTask),\n userSteps: t.userSteps || undefined,\n thinkingEffort: t.thinkingEffort || undefined,\n autonomy: t.autonomy || undefined,\n sliceType: t.sliceType || undefined,\n userStoriesCovered: t.userStoriesCovered || undefined,\n };\n}\n\nexport function serializeTaskStatus(t: Task): SerializedTaskStatus {\n return {\n id: t.id,\n status: t.status,\n verdict: t.verdict\n ? { outcome: t.verdict.outcome, reason: t.verdict.reason, checks: t.verdict.checks || [] }\n : null,\n };\n}\n\nexport function serializePlan(plan: LegacyPlanState): SerializedPlan {\n return {\n tasks: plan.tasks.map(serializeTask),\n runners: plan.runners,\n generatedAt: plan.generatedAt,\n conversationHistory: plan.conversationHistory,\n prdMarkdown: plan.prdMarkdown,\n queuedMessages: plan.queuedMessages,\n };\n}\n\nexport function executionSummary(tasks: Task[]): { total: number; completed: number; failed: number } {\n return {\n total: tasks.length,\n completed: tasks.filter((t) => t.status === 'completed').length,\n failed: tasks.filter((t) => t.status === 'failed').length,\n };\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport type { LegacyPlanState, PlanState } from '../models/Task';\nimport { migratePlanState } from '../models/Task';\nimport type { SessionMeta, SessionData } from '../models/Session';\nimport { defaultLogger, type ILogger } from '../interfaces/ILogger';\nimport { getStateDir, ensureDir } from './fsHelpers';\n\nconst SESSIONS_SUBDIR = 'sessions';\n\nfunction getSessionsDir(baseDir?: string): string {\n return path.join(getStateDir(baseDir), SESSIONS_SUBDIR);\n}\n\nconst REJECTION_MESSAGE = 'This session was created with an older version of Ordewell. Please re-plan.';\n\nfunction hasScalarRunner(parsed: Record<string, unknown>): boolean {\n const meta = parsed.meta as Record<string, unknown> | undefined;\n const plan = parsed.plan as Record<string, unknown> | undefined;\n return (typeof meta?.runner === 'string') || (typeof plan?.runner === 'string');\n}\n\nfunction sanitizeName(goal: string): string {\n return goal\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 40);\n}\n\nfunction sessionFilename(session: SessionMeta): string {\n const date = new Date(session.createdAt).toISOString().replace(/:/g, '-').replace(/\\..+/, '');\n const name = sanitizeName(session.goal);\n return `${date}_${name || 'session'}_${session.id.slice(0, 8)}.json`;\n}\n\nexport function saveSession(plan: LegacyPlanState, goal: string, baseDir?: string, id?: string): SessionMeta {\n const sessionsDir = getSessionsDir(baseDir);\n ensureDir(sessionsDir);\n\n const now = new Date().toISOString();\n\n const meta: SessionMeta = {\n id: id || `session-${Date.now()}`,\n goal: goal || '(untitled)',\n runners: plan.runners,\n taskCount: plan.tasks.flatMap((t) => [t, ...(((t as unknown) as { subtasks?: unknown[] }).subtasks || [])]).length,\n status: plan.status,\n createdAt: plan.generatedAt || now,\n updatedAt: now,\n };\n\n const session: SessionData = {\n meta,\n plan: JSON.parse(JSON.stringify(plan)),\n };\n\n const filename = sessionFilename(meta);\n const filePath = path.join(sessionsDir, filename);\n\n fs.writeFileSync(filePath, JSON.stringify(session, null, 2));\n\n return meta;\n}\n\nexport function listSessions(baseDir?: string, logger: ILogger = defaultLogger): SessionMeta[] {\n const sessionsDir = getSessionsDir(baseDir);\n if (!fs.existsSync(sessionsDir)) return [];\n\n const files = fs.readdirSync(sessionsDir).filter((f) => f.endsWith('.json'));\n\n return files\n .map((f) => {\n try {\n const raw = fs.readFileSync(path.join(sessionsDir, f), 'utf-8');\n const parsed = JSON.parse(raw);\n if (hasScalarRunner(parsed)) {\n logger.warn('sessionStore', `session file ${f}: ${REJECTION_MESSAGE}`);\n return null;\n }\n const session = parsed as SessionData;\n return session.meta;\n } catch (err: unknown) {\n logger.warn('sessionStore', `failed to read session file ${f}; skipping`, err);\n return null;\n }\n })\n .filter((m): m is SessionMeta => m !== null)\n .sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());\n}\n\nfunction findSessionFile(sessionsDir: string, sessionId: string, logger: ILogger): string | null {\n const files = fs.readdirSync(sessionsDir).filter((f) => f.endsWith('.json'));\n for (const f of files) {\n try {\n const raw = fs.readFileSync(path.join(sessionsDir, f), 'utf-8');\n const session = JSON.parse(raw) as SessionData;\n if (session.meta.id === sessionId) return f;\n } catch (err: unknown) {\n logger.warn('sessionStore', `failed to read session file ${f}; skipping`, err);\n }\n }\n return null;\n}\n\nexport function loadSession(sessionId: string, baseDir?: string, logger: ILogger = defaultLogger): { meta: SessionMeta; plan: LegacyPlanState } | null {\n const sessionsDir = getSessionsDir(baseDir);\n if (!fs.existsSync(sessionsDir)) return null;\n try {\n const file = findSessionFile(sessionsDir, sessionId, logger);\n if (file) {\n const raw = fs.readFileSync(path.join(sessionsDir, file), 'utf-8');\n const parsed = JSON.parse(raw);\n if (hasScalarRunner(parsed)) {\n logger.warn('sessionStore', `session file ${file}: ${REJECTION_MESSAGE}`);\n return null;\n }\n const session = parsed as SessionData;\n const plan = session.plan as LegacyPlanState;\n // Nothing is running when a session comes off disk — an in_progress\n // status is an orphan from an interrupted run; give it a fresh chance.\n for (const t of plan.tasks.flatMap((task) => [task, ...(task.subtasks ?? [])])) {\n if (t.status === 'in_progress') t.status = 'pending';\n }\n return { meta: session.meta, plan };\n }\n } catch (err: unknown) {\n logger.warn('sessionStore', `failed to list sessions directory while searching for ${sessionId}`, err);\n }\n return null;\n}\n\nexport function loadSessionPlanState(sessionId: string, baseDir?: string, logger: ILogger = defaultLogger): { meta: SessionMeta; plan: PlanState } | null {\n const result = loadSession(sessionId, baseDir, logger);\n if (!result) return null;\n return { meta: result.meta, plan: migratePlanState(result.plan) };\n}\n\nexport function getLatestSession(baseDir?: string, logger: ILogger = defaultLogger): { meta: SessionMeta; plan: LegacyPlanState } | null {\n const sessions = listSessions(baseDir, logger);\n if (sessions.length === 0) return null;\n return loadSession(sessions[0].id, baseDir, logger);\n}\n\nexport function deleteSession(sessionId: string, baseDir?: string, logger: ILogger = defaultLogger): boolean {\n const sessionsDir = getSessionsDir(baseDir);\n if (!fs.existsSync(sessionsDir)) return false;\n try {\n const file = findSessionFile(sessionsDir, sessionId, logger);\n if (file) { fs.unlinkSync(path.join(sessionsDir, file)); return true; }\n } catch (err: unknown) {\n logger.warn('sessionStore', `failed to list sessions directory for deletion of ${sessionId}`, err);\n }\n return false;\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\n\nexport const STATE_DIR = '.ordewell';\n\nexport function ensureDir(dir: string): void {\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n}\n\nexport function getStateDir(baseDir?: string): string {\n return path.join(baseDir ?? process.cwd(), STATE_DIR);\n}\n","import { createAiService, type IAiService, type ConversationTurn } from './AiService';\nimport { applyTaskOps, canMergeTasks, canSetDependencies, canSplitTask } from './TaskOps';\nimport { repairLoop, taskOpsRejectedPrompt } from './PlanRepair';\nimport { Planner } from './Planner';\nimport { TaskOrchestrator } from './TaskOrchestrator';\nimport type { OrchestratorObserver } from './TaskOrchestrator';\nimport { PlanStore } from './PlanStore';\nimport { ApprovalPolicy } from './ApprovalPolicy';\nimport { PendingApprovals, type PendingApproval } from './PendingApprovals';\nimport { HttpWebFetcher } from './HttpWebFetcher';\nimport { ModelResolver } from './ModelResolver';\nimport { filterModelsForPrompt, coerceAssignments, effectiveAllowlist } from './ModelAllowlistResolver';\nimport { retargetTaskRunner, runnerAssignment, type RunnerCatalog } from './TaskRetarget';\nimport { plannerModesFrom, plannerRuntimeToggles } from './plannerModes';\nimport type { UserSettings } from './SettingsService';\nimport { buildMergePrompt, buildSplitPrompt } from './PlanPrompts';\nimport {\n serializeTask,\n serializeTaskStatus,\n serializePlan,\n executionSummary,\n type SessionBroadcaster,\n} from './SessionMessage';\nimport { saveSession } from '../utils/sessionStore';\nimport { savePrdMarkdown, extractPrdBlock } from '../utils/prdStore';\nimport { type ConversationMessage, type DiscoveredModel, type LegacyPlanState, type PlanState, type Task, type TaskSnapshot, type RunnerId, type ResearchProgress } from '../models/Task';\nimport type { AiProvider, IConfig } from '../interfaces/IConfig';\nimport type { IFileSystem } from '../interfaces/IFileSystem';\nimport type { INotification } from '../interfaces/INotification';\nimport type { ITerminalRunner } from '../interfaces/ITerminalRunner';\nimport type { RunnerRegistry } from '../plugins/RunnerRegistry';\nimport { runnerModesFrom, type RunnerModeInfo } from './ModeResolver';\n\n/**\n * Options for plan generation. Progress is not overridable: every planner\n * progress event is translated to a SessionMessage inside the Session and\n * emitted through the broadcast seam, so all surfaces consume one union.\n */\nexport interface GeneratePlanOptions {\n signal?: AbortSignal;\n}\n\n/** The slice of Planner the Session drives — the injection seam for tests. */\nexport type SessionPlanner = Pick<Planner, 'generate' | 'modify' | 'modifyDuringExecution'>;\n\n/** Runtime prefs read live — may toggle between operations. */\nexport interface SessionRuntimeSettings {\n tddEnabled: boolean;\n grillMeEnabled: boolean;\n prdEnabled?: boolean;\n reviewEnabled?: boolean;\n verificationEnabled?: boolean;\n researchSubagentsEnabled?: boolean;\n modelAllowlist?: Record<string, string[]>;\n}\n\n/**\n * The whole of what a host reads off disk for a Session. Both hosts used to\n * assemble this by hand, mapping each toggle's settings key to its runtime key\n * in two blocks nothing kept in step — which is how one toggle came to be\n * dropped. `MODE_TOGGLES` holds the mapping now; this adds the one field that\n * is not a toggle.\n */\nexport function sessionRuntimeSettings(settings: UserSettings): SessionRuntimeSettings {\n return { ...plannerRuntimeToggles(settings), modelAllowlist: settings.modelAllowlist };\n}\n\n/**\n * Everything a delivery surface constructs to host a session. Structural config\n * (enabledRunners, orchestratorModel, providerModelLists) is snapshotted inside\n * `config` at construction and never re-read from the environment. Runtime\n * settings (tdd, grillMe) are read live via the `settings` callback so a toggle\n * between generate and execute takes effect.\n */\nexport interface SessionDeps {\n config: IConfig;\n notifications: INotification;\n runner: ITerminalRunner;\n registry: RunnerRegistry;\n /** Resolves the workspace root for the orchestrator (lazy — VS Code can change it). */\n workspaceRoot: () => string;\n /** Filesystem adapter for planner research. */\n fsAdapter: IFileSystem;\n /** Emits plan-lifecycle events to the surface. Transport-agnostic. */\n broadcast: SessionBroadcaster;\n /** Shared across sessions — sole producer of model catalogs and routing lists. */\n modelResolver: ModelResolver;\n /** Live runtime settings (tdd, grillMe). Read at each operation that needs them. */\n settings: () => SessionRuntimeSettings;\n /**\n * Host-assigned session id. When set, every persist writes under this id so\n * the host's REST/UI ids match the saved-session store. When omitted, the\n * Session mints a fresh id per plan (generatePlan/startPlanning).\n */\n sessionId?: string;\n /**\n * Planner-conversation seam. Defaults to the provider service for\n * `config.aiProvider`; inject a fake to test the conversation half without\n * an LLM.\n */\n aiService?: IAiService;\n /** Plan-generation seam. Defaults to a Planner over the session's aiService. */\n planner?: SessionPlanner;\n}\n\n// Session ids are timestamp-based; two mints inside the same millisecond\n// (e.g. reset() right after construction) must still differ or they'd share\n// one persisted session file.\nlet lastMintedAt = 0;\nfunction mintSessionId(): string {\n lastMintedAt = Math.max(Date.now(), lastMintedAt + 1);\n return `session-${lastMintedAt}`;\n}\n\n/**\n * The per-session execution stack — deepened from a wiring bag into the\n * lifecycle owner. Owns plan generation, execution, mutation, persistence, and\n * the orchestrator observer wiring. The orchestrator's observer is subscribed\n * once for the session's lifetime (not per-operation), which kills the\n * double-subscribe class of bug. Persistence is an internal seam: every plan\n * mutation routes through `persist()`, so the obligation has a home instead of\n * being scattered across 11 call sites.\n *\n * The broadcast seam carries {@link SessionMessage} — the 15 plan-lifecycle\n * events. Catalog/config messages (setModels, setRunnerList, …) stay on the\n * host; Session never emits them.\n */\nexport class Session {\n /** Injected by a test; when present it is the service, forever. */\n private readonly pinnedAiService?: IAiService;\n private liveAiService: IAiService | null = null;\n private liveAiProvider: AiProvider | null = null;\n private readonly workspaceRootFn: () => string;\n private planner: SessionPlanner;\n private orchestrator: TaskOrchestrator;\n private store: PlanStore;\n private config: IConfig;\n private registry: RunnerRegistry;\n private plan: LegacyPlanState | null = null;\n private goal = '';\n private workspace: string;\n private broadcast: SessionBroadcaster;\n private modelResolver: ModelResolver;\n private fsAdapter: IFileSystem;\n private approvals: PendingApprovals;\n private approvalPolicy: ApprovalPolicy;\n private fetcher: HttpWebFetcher;\n private settingsFn: () => SessionRuntimeSettings;\n private currentAllowlist: Record<string, string[]> = {};\n /** Last discovered model catalog — lets sync plan commits clamp thinking efforts to real variants. */\n private modelsCache: Partial<Record<RunnerId, DiscoveredModel[]>> = {};\n private unsubObserver: (() => void) | null = null;\n private readonly hostSessionId?: string;\n private currentSessionId: string;\n\n constructor(deps: SessionDeps) {\n this.config = deps.config;\n this.registry = deps.registry;\n this.pinnedAiService = deps.aiService;\n this.workspaceRootFn = deps.workspaceRoot;\n this.planner = deps.planner ?? new Planner(deps.config, () => this.aiService);\n this.store = new PlanStore();\n this.orchestrator = new TaskOrchestrator(deps.config, deps.notifications, deps.runner, this.store);\n this.orchestrator.setRegistry(deps.registry);\n this.orchestrator.setWorkspaceRoot(deps.workspaceRoot);\n this.orchestrator.setTddEnabled(() => this.settingsFn().tddEnabled);\n this.workspace = deps.workspaceRoot();\n this.broadcast = deps.broadcast;\n this.modelResolver = deps.modelResolver;\n this.fsAdapter = deps.fsAdapter;\n this.settingsFn = deps.settings;\n this.hostSessionId = deps.sessionId;\n this.currentSessionId = deps.sessionId ?? mintSessionId();\n\n // The approval chain, wired once per session: the filesystem asks the\n // policy, the policy asks the registry, the registry announces on the same\n // broadcast seam every other planner event uses, and any surface answers\n // through `resolveApproval`. Nothing in core knows which UI is listening.\n this.approvals = new PendingApprovals({\n onRequest: ({ id, request }) => this.broadcast({\n type: 'approval_request',\n id,\n kind: request.kind,\n subject: request.subject,\n scope: request.scope,\n detail: request.detail,\n }),\n onSettled: (id, granted) => this.broadcast({ type: 'approval_settled', id, granted }),\n });\n this.approvalPolicy = new ApprovalPolicy({\n mode: this.config.approvalMode,\n preApproved: this.config.approvalPreApproved,\n ask: (req) => this.approvals.ask(req),\n // The interactive path (`asked`) already broadcasts approval_request +\n // approval_settled; only the silent sources need a signal, or a\n // remembered/pre-approved/mode grant is invisible to every surface.\n onDecision: (req, granted, source) => {\n if (source === 'asked') return;\n this.broadcast({\n type: 'approval_decided',\n kind: req.kind,\n subject: req.subject,\n scope: req.scope,\n detail: req.detail,\n granted,\n source,\n });\n },\n });\n this.fsAdapter.setApproval?.(this.approvalPolicy);\n // `fetch`/`web_search` route through the same approval channel as paths and\n // commands — one decision surface for everything that leaves the workspace.\n this.fetcher = new HttpWebFetcher({ approval: this.approvalPolicy });\n\n this.attachObserver();\n }\n\n /**\n * The planner transport for the provider configured *right now* (ADR-0009).\n *\n * Resolved on every read rather than once in the constructor, because a\n * Session outlives the choice: VS Code hosts exactly one for the whole\n * window, and the webview pills and `/planner` switch backends underneath it.\n * The model id was already read live, so a service captured at construction\n * meant a switched planner kept the old backend and got handed the new one's\n * model — an OpenCode model id spawned as `claude --model opencode/…`, which\n * the agent rejects as nonexistent.\n *\n * Switching releases the outgoing service: a harness planner holds an OS\n * process, so dropping the reference without `reset()` leaks an agent.\n */\n private get aiService(): IAiService {\n if (this.pinnedAiService) return this.pinnedAiService;\n const provider = this.config.aiProvider;\n if (this.liveAiService && this.liveAiProvider === provider) return this.liveAiService;\n this.liveAiService?.reset();\n this.liveAiService = createAiService(this.config, { workspaceRoot: this.workspaceRootFn });\n this.liveAiProvider = provider;\n return this.liveAiService;\n }\n\n /**\n * Answer an outstanding approval. Every surface funnels here — the web\n * server's HTTP route, the VS Code webview, the TUI prompt — so the decision\n * path is identical regardless of who is looking.\n */\n resolveApproval(id: string, granted: boolean): boolean {\n return this.approvals.resolve(id, granted);\n }\n\n /** Requests still waiting for an answer, replayed to a surface that connects mid-prompt. */\n outstandingApprovals(): PendingApproval[] {\n return this.approvals.outstanding();\n }\n\n /** Scopes the user granted this session — surfaced so a UI can show what is already allowed. */\n approvedScopes(): string[] {\n return this.approvalPolicy.grantedScopes();\n }\n\n /** The stable id this session persists under — matches the host's id when one was provided. */\n get sessionId(): string { return this.currentSessionId; }\n get executionLog(): TaskSnapshot[] { return this.store.getExecutionLog(); }\n /** Tasks always read from PlanStore — the single source of truth. */\n get planTasks(): Task[] { return this.store.planTasks; }\n\n private attachObserver(): void {\n if (this.unsubObserver) this.unsubObserver();\n this.unsubObserver = this.orchestrator.subscribe(this.buildObserver());\n }\n\n private buildObserver(): OrchestratorObserver {\n return {\n onTaskChanged: () => {\n if (!this.plan) return;\n const tasks = this.store.allTasks;\n this.broadcast({ type: 'status_update', tasks: tasks.map(serializeTaskStatus) });\n },\n onQueueReady: () => {\n this.broadcast({ type: 'queue_ready' });\n },\n onReviewNeeded: () => {\n const tasks = this.store.allTasks;\n this.broadcast({ type: 'review_needed', tasks: tasks.map(serializeTask) });\n },\n onReviewApproved: () => {\n this.broadcast({ type: 'review_approved' });\n },\n onCheckpoint: (data) => {\n this.broadcast({ type: 'checkpoint', taskId: data.taskId, taskTitle: data.taskTitle, summary: data.summary });\n },\n onTick: () => {\n if (!this.plan) return;\n const tasks = this.store.allTasks;\n this.broadcast({ type: 'status_update', tasks: tasks.map(serializeTaskStatus) });\n },\n onExecutionComplete: () => {\n if (!this.plan) return;\n const tasks = this.store.allTasks;\n this.broadcast({ type: 'execution_complete', summary: executionSummary(tasks) });\n this.persist();\n },\n };\n }\n\n private translateProgress(progress: ResearchProgress): void {\n if (progress.type === 'thinking' && progress.text) {\n this.broadcast({ type: 'plan_thinking', text: progress.text });\n }\n if (progress.type === 'tool_call' && progress.tool) {\n this.broadcast({ type: 'research_step', tool: progress.tool, toolLabel: progress.toolLabel, args: progress.toolArgs || '', subagentId: progress.subagentId, toolCallId: progress.toolCallId });\n }\n if (progress.type === 'plan_token' && progress.planToken) {\n this.broadcast({ type: 'plan_token', token: progress.planToken });\n }\n if (progress.type === 'tool_result' && progress.step) {\n this.broadcast({ type: 'research_step_done', step: progress.step, subagentId: progress.subagentId });\n }\n }\n\n /** Persists PlanStore state to disk. PlanStore is the single authority;\n * LegacyPlanState.tasks is populated only here, at persist time. */\n private persist(): void {\n if (!this.plan) return;\n this.plan.tasks = this.store.planTasks;\n this.plan.lastUpdated = new Date().toISOString();\n saveSession(this.plan, this.goal, this.workspace, this.currentSessionId);\n }\n\n /** A new plan on a long-lived Session gets its own persisted identity (unless the host fixed one). */\n private remintSessionId(): void {\n if (!this.hostSessionId) this.currentSessionId = mintSessionId();\n }\n\n /**\n * A new plan starts from zero: drop the live planner conversation and every\n * task, log, and queued message left over from a previous plan on this\n * Session. Without this, a long-lived Session (VS Code hosts exactly one)\n * leaks the previous session's tasks into `planContextBlock()` — the model\n * is told they are the CURRENT plan and re-presents them as its draft.\n */\n private beginFreshPlan(): void {\n if (this.isExecuting) this.stopExecution();\n this.aiService.reset();\n // A prompt raised by the turn we are abandoning has nobody left to serve;\n // denying it unblocks the old research loop instead of stranding it.\n this.approvals.clear();\n this.orchestrator.clearQueuedMessages();\n this.store.clearLog();\n this.orchestrator.loadPlan([]);\n }\n\n /**\n * Return the Session to a blank slate — hosts call this on \"new session\".\n * Everything scoped to the old session goes: the live AI conversation, plan,\n * goal, tasks, execution log, queued messages, model cache, and (unless the\n * host fixed one) the persisted identity, so nothing can bleed into the next\n * session.\n */\n reset(): void {\n // Null the plan first so orchestrator-stop observer callbacks\n // (onTaskChanged → status_update) no-op instead of broadcasting the\n // dying session's tasks.\n this.plan = null;\n this.goal = '';\n this.beginFreshPlan();\n // Session boundaries are hard (see ADR-0008): a path or command the user\n // approved for the previous goal must not stay approved for the next one.\n this.approvalPolicy.reset();\n this.modelsCache = {};\n this.currentAllowlist = {};\n this.remintSessionId();\n }\n\n private runnerModesFor(runners: RunnerId[]): Record<RunnerId, RunnerModeInfo[]> {\n return runnerModesFrom(this.registry, runners);\n }\n\n get planState(): LegacyPlanState | null { return this.plan; }\n\n /**\n * The live plan in the shape a saved session is read back as. The disk\n * boundary rewrites `in_progress` to `pending` — nothing is running when a\n * session comes off a file — so a surface that re-reads the plan mid-run must\n * come here instead, or every task it is watching reads as never started.\n */\n get currentPlanState(): PlanState | null {\n if (!this.plan) return null;\n const executionLog = this.store.getExecutionLog();\n const logged = new Set(executionLog.map((s) => s.id));\n const pendingTasks = this.store.planTasks.filter((t) => !logged.has(t.id));\n if (executionLog.length === 0 && !this.orchestrator.isRunning) {\n return { phase: 'planning', history: [], message: '', pendingTasks };\n }\n return {\n phase: 'executing',\n history: [],\n message: '',\n executionLog,\n pendingTasks,\n goal: this.goal,\n runners: this.plan.runners,\n status: this.plan.status,\n };\n }\n\n get currentGoal(): string { return this.goal; }\n get isPlanning(): boolean { return !this.orchestrator.isRunning; }\n get isExecuting(): boolean { return this.orchestrator.isRunning; }\n get status(): 'approved' | 'running' | 'completed' { return this.orchestrator.status; }\n get sessionConfig(): IConfig { return this.config; }\n\n async startExecution(): Promise<void> {\n if (!this.plan || !this.store.planTasks.length) throw new Error('No plan to execute');\n this.store.clearLog();\n this.plan.status = 'approved';\n this.store.resetForRun();\n this.orchestrator.loadPlan(this.store.planTasks, this.plan.runners);\n await this.orchestrator.start();\n }\n\n async generatePlan(goal: string, runners: RunnerId[], options?: GeneratePlanOptions): Promise<LegacyPlanState> {\n this.plan = null;\n this.goal = goal;\n this.remintSessionId();\n this.beginFreshPlan();\n const enabled = this.config.enabledRunners;\n const chosenRunners = runners.filter((r) => enabled.includes(r));\n if (chosenRunners.length === 0) throw new Error('None of the requested runners are enabled');\n\n const modelsByRunner = await this.modelResolver.modelsForRunners(chosenRunners);\n this.modelsCache = modelsByRunner;\n const runnerModes = this.runnerModesFor(chosenRunners);\n // Every planner toggle, not the two this path used to remember: `modesFor`\n // drops the ones a one-shot run cannot honour, so review — which only\n // appends a task — stops being silently lost between here and the prompt.\n const settings = this.settingsFn();\n const { modelAllowlist } = settings;\n const modes = plannerModesFrom(settings, this.config.autonomousMode);\n\n const plan = await this.planner.generate({\n goal,\n runners: chosenRunners,\n modelsByRunner,\n runnerModes,\n autonomousDefault: this.config.autonomousMode,\n fs: this.fsAdapter,\n fetcher: this.fetcher,\n onProgress: (p) => this.translateProgress(p),\n signal: options?.signal,\n perRunnerAllowlist: modelAllowlist,\n modes,\n });\n\n this.plan = plan;\n this.orchestrator.loadPlan(plan.tasks, plan.runners);\n this.store.resetForRun({ preserveCompleted: false });\n this.persist();\n this.broadcastPlan();\n return plan;\n }\n\n /**\n * Kick off the planner conversation (ADR-0002): research + the first planner\n * message. The AI service retains the tool-use history; the Session persists\n * the user/assistant dialogue on the plan state.\n */\n async startPlanning(goal: string, runners: RunnerId[], options?: GeneratePlanOptions): Promise<LegacyPlanState> {\n this.plan = null;\n this.goal = goal;\n this.remintSessionId();\n this.beginFreshPlan();\n const enabled = this.config.enabledRunners;\n const chosenRunners = runners.filter((r) => enabled.includes(r));\n if (chosenRunners.length === 0) throw new Error('None of the requested runners are enabled');\n\n const modelsByRunner = await this.modelResolver.modelsForRunners(chosenRunners);\n this.modelsCache = modelsByRunner;\n const runnerModes = this.runnerModesFor(chosenRunners);\n const { grillMeEnabled, prdEnabled, reviewEnabled, verificationEnabled, researchSubagentsEnabled, modelAllowlist } = this.settingsFn();\n this.currentAllowlist = modelAllowlist ?? {};\n const filteredModels = filterModelsForPrompt(modelsByRunner, this.currentAllowlist);\n\n const now = new Date().toISOString();\n this.plan = {\n tasks: [],\n generatedAt: now,\n status: 'draft',\n runners: chosenRunners,\n lastUpdated: now,\n researchLog: [{ id: `up-${Date.now()}`, type: 'user_prompt', content: goal, timestamp: now }],\n conversationHistory: [{ role: 'user', content: goal, timestamp: now }],\n };\n\n const turn = await this.aiService.startConversation({\n goal,\n runners: chosenRunners,\n modelsByRunner: filteredModels,\n runnerModes,\n autonomousDefault: this.config.autonomousMode,\n grillMeEnabled: grillMeEnabled ?? false,\n prdEnabled: prdEnabled ?? false,\n reviewEnabled: reviewEnabled ?? false,\n verificationEnabled: verificationEnabled ?? false,\n researchSubagentsEnabled: researchSubagentsEnabled ?? false,\n fs: this.fsAdapter,\n fetcher: this.fetcher,\n onProgress: (p) => this.translateProgress(p),\n signal: options?.signal,\n });\n\n return this.settleTurn(turn, options);\n }\n\n /**\n * Every subsequent user reply in the planning conversation — grill-me\n * answers, PRD accept/adjust, outline confirm. One branch, no phase ladder.\n */\n async continueConversation(userMessage: string, options?: GeneratePlanOptions): Promise<LegacyPlanState> {\n if (!this.plan) throw new Error('No planning conversation to continue');\n const priorHistory = this.plan.conversationHistory ?? [];\n const now = new Date().toISOString();\n this.appendTranscript('user', userMessage, now);\n this.plan.researchLog = [...(this.plan.researchLog ?? []), { id: `up-${Date.now()}`, type: 'user_prompt', content: userMessage, timestamp: now }];\n\n // The persisted transcript keeps the raw user message; the model gets the\n // current plan (tasks, statuses, edit protocol) alongside it.\n const contextBlock = this.planContextBlock();\n const outgoing = contextBlock ? `${contextBlock}\\n\\n${userMessage}` : userMessage;\n\n // A live conversation is only safe to continue in-place when it also\n // matches the model/effort configured right now — a harness planner's\n // running process was spawned with the old one baked in and cannot pick\n // up a switch (ADR-0009). `resumeConversation` handles both cases the\n // same way: tear down and restart, folding the transcript so far into the\n // opening message.\n const aiService = this.aiService;\n const canContinueLive = aiService.hasActiveConversation() && (aiService.conversationMatchesConfig?.() ?? true);\n let turn = canContinueLive\n ? await aiService.continueConversation(\n outgoing,\n (p) => this.translateProgress(p),\n options?.signal,\n )\n : await this.resumeConversation(outgoing, priorHistory, options);\n\n // Structural changes while tasks execute are queued, never applied live —\n // the orchestrator must not have the plan mutated under a running batch.\n if ((turn.kind === 'task_ops' || turn.kind === 'plan') && this.isExecuting) {\n this.queueMessage(userMessage);\n this.plan.queuedMessages = this.getQueuedMessages();\n turn = {\n kind: 'message',\n text: `Execution is running, so I queued your change — it will be applied between task batches (${this.queuedCount} queued).`,\n researchLog: turn.researchLog,\n };\n }\n\n return this.settleTurn(turn, options);\n }\n\n /**\n * Drive a planner turn to a persisted, broadcast outcome. Task edits apply\n * atomically; validation failures are fed back to the model for up to 2\n * silent retries, then surfaced as a message with the plan untouched. The\n * first turn (startPlanning) and every later turn route through here — one\n * path, not two.\n */\n private async settleTurn(turn: ConversationTurn, options?: GeneratePlanOptions): Promise<LegacyPlanState> {\n type Settled = { plan: LegacyPlanState } | { turn: Exclude<ConversationTurn, { kind: 'task_ops' }> };\n const invalidOps = (errors: string[], researchLog: ConversationTurn['researchLog']): Settled => ({\n turn: {\n kind: 'message',\n text: `I tried to modify the tasks, but the changes were invalid:\\n- ${errors.join('\\n- ')}\\n\\nThe plan is unchanged. Rephrase the request, or adjust the tasks manually.`,\n researchLog,\n },\n });\n\n const settled = await repairLoop<ConversationTurn, Settled>({\n first: () => turn,\n resend: (corrective) => this.aiService.continueConversation(\n corrective,\n (p) => this.translateProgress(p),\n options?.signal,\n ),\n interpret: (t) => {\n if (t.kind !== 'task_ops') return { done: { turn: t } };\n const applied = this.applyTaskOpsTurn(t);\n if ('plan' in applied) return { done: { plan: applied.plan } };\n // No live conversation (or an abort) means no corrective re-send is\n // possible — surface the failure instead of retrying into the void.\n if (!this.aiService.hasActiveConversation() || options?.signal?.aborted) {\n return { done: invalidOps(applied.errors, t.researchLog) };\n }\n return { retry: { errors: applied.errors, corrective: taskOpsRejectedPrompt(applied.errors) } };\n },\n maxRepairs: 2,\n onExhausted: ({ reply, errors }) => invalidOps(errors, reply.researchLog),\n });\n\n if ('plan' in settled) return settled.plan;\n return this.applyConversationTurn(settled.turn);\n }\n\n /**\n * The \"you are here\" block for post-plan chat: current tasks with stable\n * references, plus the task-ops protocol. Injected per turn (never\n * persisted) so the model always sees live statuses — including which tasks\n * are locked by a running execution.\n */\n private planContextBlock(): string | null {\n if (!this.plan || this.store.planTasks.length === 0) return null;\n const orderOf = new Map(this.store.planTasks.map((t) => [t.id, `#${t.order}`]));\n const lines = this.store.planTasks.map((t) =>\n `#${t.order} id=${t.id} \"${t.title}\" [${t.status}] runner:${t.assignedRunner}${t.assignedModel ? ` model:${t.assignedModel.modelId}` : ''} deps:[${t.dependencies.map((d) => orderOf.get(d) ?? d).join(', ')}]`,\n );\n const running = this.store.planTasks.filter((t) => t.status === 'in_progress');\n const execNote = this.isExecuting\n ? `\\nExecution is RUNNING${running.length ? ` — these tasks are locked: ${running.map((t) => `#${t.order}`).join(', ')}` : ''}. Any task edits you emit will be queued and applied between batches.`\n : '';\n // Compact model availability so any task edit (add/merge/split/update) can\n // assign a valid runner + model without scrolling back to the system prompt.\n const modelLines: string[] = [];\n for (const runner of this.plan.runners) {\n const models = this.modelsCache[runner] ?? [];\n const ids = models.map((m) => m.modelId).join(', ');\n modelLines.push(`${runner}: ${ids || '(no models discovered)'}`);\n }\n const modelBlock = modelLines.length > 0\n ? ['<available_models>', ...modelLines, '</available_models>'].join('\\n')\n : '';\n return [\n '<current_plan>',\n ...lines,\n '</current_plan>',\n modelBlock,\n 'The block above is the CURRENT task plan. Choose how to respond:',\n '- To answer a question or discuss, reply in plain prose (no JSON).',\n '- To modify specific tasks, reply with ONLY this JSON object:',\n ' {\"taskOps\": [',\n ' {\"op\":\"update\",\"taskId\":\"<id or #order>\",\"changes\":{\"title\"?,\"description\"?,\"prompt\"?,\"dependencies\"?:[\"<id or #order>\"],\"assignedRunner\"?,\"assignedModel\"?,\"taskMode\"?}},',\n ' {\"op\":\"add\",\"task\":{\"title\",\"description\",\"prompt\",\"dependencies\":[\"<id or #order>\"],\"assignedRunner\"?,\"assignedModel\"?}},',\n ' {\"op\":\"remove\",\"taskId\":\"<id or #order>\"},',\n ' {\"op\":\"reorder\",\"taskIds\":[\"<id or #order>\", \"... every task exactly once\"]},',\n ' {\"op\":\"merge\",\"taskIds\":[\"<id or #order>\", \"...\"],\"merged\":{\"title\",\"description\",\"prompt\"?,\"assignedRunner\"?,\"assignedModel\"?,...}},',\n ' {\"op\":\"split\",\"taskId\":\"<id or #order>\",\"parts\":[{\"title\",\"description\",\"prompt\"?,\"assignedRunner\"?,\"assignedModel\"?,...}, ...]}',\n ' ]}',\n '- For sweeping changes, you may instead emit a full {\"tasks\":[...]} plan JSON.',\n 'When creating or changing tasks, set \"assignedRunner\" and \"assignedModel\" ({\"modelId\",\"modelLabel\",\"thinkingEffort\"?}) using only the runners and models listed in <available_models>.',\n 'Keep dependencies consistent: no cycles, no references to removed tasks, dependencies must come before dependents, and never touch running or completed tasks.' + execNote,\n ].filter(Boolean).join('\\n');\n }\n\n /** Validate + commit a task_ops turn atomically. Returns the errors on rejection (plan untouched). */\n private applyTaskOpsTurn(turn: Extract<ConversationTurn, { kind: 'task_ops' }>): { plan: LegacyPlanState } | { errors: string[] } {\n if (!this.plan) throw new Error('No active plan state');\n const result = applyTaskOps(this.store.planTasks, turn.ops, this.plan.runners);\n if (!result.ok) return { errors: result.errors };\n\n const now = new Date().toISOString();\n const content = `Tasks updated:\\n- ${result.summary.join('\\n- ')}`;\n const plan = this.mutatePlan(\n () => {\n this.plan!.researchLog = [...(this.plan!.researchLog ?? []), ...turn.researchLog];\n const allowlist = this.settingsFn().modelAllowlist ?? this.currentAllowlist;\n const coerced = coerceAssignments(result.tasks, allowlist, this.plan!.runners, this.modelsCache);\n this.orchestrator.loadPlan(coerced, this.plan!.runners);\n this.store.resetForRun();\n this.appendTranscript('assistant', content, now);\n return true;\n },\n () => {\n this.broadcast({ type: 'planner_message', content, timestamp: now });\n this.broadcastPlan();\n },\n );\n return { plan: plan! };\n }\n\n /**\n * Resume a persisted dialogue onto a fresh AI-service conversation — either\n * because the in-memory one is gone (session reload, extension restart), or\n * because {@link continueConversation} found it stale against the planner\n * config now in effect (a harness planner's model/effort switched mid-chat).\n * The saved transcript seeds the new conversation; no LLM call happens\n * before the user's message is sent.\n */\n private async resumeConversation(\n userMessage: string,\n priorHistory: ConversationMessage[],\n options?: GeneratePlanOptions,\n ): Promise<Awaited<ReturnType<IAiService['startConversation']>>> {\n if (!this.plan) throw new Error('No active plan state');\n const runners = this.plan.runners;\n const modelsByRunner = await this.modelResolver.modelsForRunners(runners);\n this.modelsCache = modelsByRunner;\n const runnerModes = this.runnerModesFor(runners);\n const { grillMeEnabled, prdEnabled, reviewEnabled, verificationEnabled, researchSubagentsEnabled, modelAllowlist } = this.settingsFn();\n this.currentAllowlist = modelAllowlist ?? {};\n const filteredModels = filterModelsForPrompt(modelsByRunner, this.currentAllowlist);\n const goal = this.goal || priorHistory.find((m) => m.role === 'user')?.content || userMessage;\n\n return this.aiService.startConversation({\n goal,\n runners,\n modelsByRunner: filteredModels,\n runnerModes,\n autonomousDefault: this.config.autonomousMode,\n grillMeEnabled: grillMeEnabled ?? false,\n prdEnabled: prdEnabled ?? false,\n reviewEnabled: reviewEnabled ?? false,\n verificationEnabled: verificationEnabled ?? false,\n researchSubagentsEnabled: researchSubagentsEnabled ?? false,\n fs: this.fsAdapter,\n fetcher: this.fetcher,\n onProgress: (p) => this.translateProgress(p),\n signal: options?.signal,\n priorHistory,\n initialMessage: userMessage,\n });\n }\n\n /** Whether the planner conversation is live (started and not yet committed to a plan). */\n get isConversationActive(): boolean {\n return this.aiService.hasActiveConversation();\n }\n\n /** Append one dialogue entry to the persisted transcript. Callers persist via the mutatePlan ritual. */\n private appendTranscript(role: 'user' | 'assistant', content: string, timestamp: string, kind?: 'plan_generated'): void {\n if (!this.plan) return;\n this.plan.conversationHistory = [\n ...(this.plan.conversationHistory ?? []),\n { role, content, timestamp, ...(kind ? { kind } : {}) },\n ];\n }\n\n /** Commit a settled (non-task_ops) turn. Both branches run the mutatePlan ritual. */\n private applyConversationTurn(turn: Exclude<ConversationTurn, { kind: 'task_ops' }>): LegacyPlanState {\n if (!this.plan) throw new Error('No active plan state');\n const now = new Date().toISOString();\n\n if (turn.kind === 'plan') {\n return this.mutatePlan(() => {\n this.plan!.researchLog = [...(this.plan!.researchLog ?? []), ...turn.researchLog];\n // A cheap model may emit the PRD block and the plan JSON in one turn —\n // capture the PRD here too so it isn't dropped with the plan preamble.\n this.capturePrd(turn.text);\n // Read the allowlist live: it may have changed since startPlanning, and\n // committed tasks must respect the current one.\n const allowlist = this.settingsFn().modelAllowlist ?? this.currentAllowlist;\n const coerced = coerceAssignments(turn.tasks, allowlist, this.plan!.runners, this.modelsCache);\n this.orchestrator.loadPlan(coerced, this.plan!.runners);\n this.store.resetForRun({ preserveCompleted: false });\n this.appendTranscript('assistant', `Plan generated with ${coerced.length} task${coerced.length === 1 ? '' : 's'}.`, now, 'plan_generated');\n return true;\n })!;\n }\n\n // A message turn: persist it in the dialogue; the UI re-renders from here.\n // Budget models occasionally return an empty content turn after tool use —\n // surface that visibly instead of rendering a blank bubble.\n const text = turn.text.trim()\n ? turn.text\n : '(The planner returned an empty response. Reply to continue, or rephrase your goal.)';\n return this.mutatePlan(\n () => {\n this.plan!.researchLog = [...(this.plan!.researchLog ?? []), ...turn.researchLog];\n this.appendTranscript('assistant', text, now);\n this.capturePrd(text);\n return true;\n },\n () => this.broadcast({ type: 'planner_message', content: text, timestamp: now }),\n )!;\n }\n\n /**\n * PRD mode: when the planner writes the full markdown PRD, save it to\n * .scratch/<slug>/PRD.md (Matt Pocock to-prd convention) and keep it on the plan.\n */\n private capturePrd(text: string): void {\n if (!this.plan) return;\n const prd = extractPrdBlock(text);\n if (!prd) return;\n this.plan.prdMarkdown = prd.markdown;\n try {\n savePrdMarkdown(this.workspace, prd.slug, prd.markdown);\n } catch {\n // Saving the PRD file is best-effort; the markdown stays on the plan state.\n }\n }\n\n async executePlan(): Promise<void> {\n if (!this.plan || !this.store.planTasks.length) throw new Error('No plan to execute');\n if (this.orchestrator.isRunning) throw new Error('Session already executing');\n\n this.plan.status = 'approved';\n this.store.clearLog();\n this.store.resetForRun();\n\n this.orchestrator.loadPlan(this.store.planTasks, this.plan.runners);\n await this.orchestrator.approveReview();\n\n if (!this.orchestrator.isRunning) {\n const tasks = this.store.allTasks;\n this.broadcast({ type: 'execution_complete', summary: executionSummary(tasks) });\n this.persist();\n }\n }\n\n async approveReview(): Promise<LegacyPlanState> {\n if (!this.plan) throw new Error('No plan to review');\n await this.orchestrator.approveReview();\n return this.plan;\n }\n\n async forceStartTask(taskId: string): Promise<void> {\n if (!this.plan) return;\n if (!this.store.get(taskId)) {\n this.orchestrator.loadPlan(this.store.planTasks, this.plan.runners);\n }\n await this.orchestrator.forceStartTask(taskId);\n }\n\n async runTask(taskId: string): Promise<void> {\n if (!this.plan) return;\n if (!this.store.get(taskId)) {\n this.orchestrator.loadPlan(this.store.planTasks, this.plan.runners);\n }\n await this.orchestrator.runTask(taskId);\n }\n\n async retryTask(taskId: string): Promise<void> {\n await this.orchestrator.retryTask(taskId);\n this.persist();\n }\n\n async cancelTask(taskId: string): Promise<void> {\n await this.orchestrator.cancelTask(taskId);\n this.persist();\n }\n\n async markAiTaskComplete(taskId: string): Promise<void> {\n await this.orchestrator.markAiTaskComplete(taskId);\n this.persist();\n }\n\n async markTaskComplete(taskId: string): Promise<void> {\n await this.orchestrator.markTaskComplete(taskId);\n this.persist();\n }\n\n async markTaskIncomplete(taskId: string): Promise<void> {\n await this.orchestrator.markTaskIncomplete(taskId);\n this.persist();\n }\n\n async tick(): Promise<void> {\n await this.orchestrator.tick();\n this.persist();\n }\n\n async processQueuedMessages(): Promise<void> {\n const messages = this.orchestrator.getQueuedMessages();\n if (messages.length === 0) return;\n\n this.orchestrator.clearQueuedMessages();\n\n const batchText = messages.map((m) => m.text).join('\\n');\n const activeSessions = new Map(\n [...this.orchestrator.activeSessionMap.entries()].map(([taskId, sessionId]) => [\n taskId,\n { id: sessionId, taskId },\n ])\n );\n\n const modelsByRunner = await this.modelResolver.modelsForRunners(this.config.enabledRunners);\n const runnerModes = this.runnerModesFor(this.plan?.runners ?? ['claude-code']);\n const { modelAllowlist } = this.settingsFn();\n\n const result = await this.planner.modifyDuringExecution({\n executionLog: this.store.getExecutionLog(),\n pendingTasks: this.store.planTasks,\n activeSessions,\n userMessage: batchText,\n modelsByRunner,\n runners: this.plan?.runners ?? ['claude-code'],\n runnerModes,\n autonomousDefault: this.config.autonomousMode,\n perRunnerAllowlist: modelAllowlist,\n });\n\n this.orchestrator.reconcilePlan(result.pendingTasks, this.plan?.runners ?? ['claude-code']);\n this.persist();\n\n // Re-schedule. `onQueueReady` only fires when no task is active, so a paused\n // run still has `running === true` — `start()` would no-op (it early-returns\n // when already running). Ticking directly spawns the dependents that became\n // ready after reconcile. `start()` covers the halted case (`running === false`,\n // e.g. a retry that cleared the queue), re-entering approval-free.\n if (this.orchestrator.isRunning) {\n await this.orchestrator.tick();\n } else {\n await this.orchestrator.start();\n }\n }\n\n approveCheckpoint(taskId: string): void {\n this.orchestrator.approveCheckpoint(taskId);\n }\n\n rejectCheckpoint(taskId: string, reason?: string): void {\n this.orchestrator.rejectCheckpoint(taskId, reason);\n }\n\n queueMessage(text: string): void {\n this.orchestrator.queueMessage(text);\n }\n\n getQueuedMessages() { return this.orchestrator.getQueuedMessages(); }\n setQueuedMessages(msgs: ReturnType<TaskOrchestrator['getQueuedMessages']>): void {\n this.orchestrator.setQueuedMessages(msgs);\n }\n processNextQueuedMessage() { return this.orchestrator.processNextQueuedMessage(); }\n get queuedCount(): number { return this.orchestrator.queuedCount; }\n getTask(taskId: string) { return this.store.get(taskId); }\n get isReviewApproved(): boolean { return this.orchestrator.isReviewApproved; }\n\n stopExecution(): void {\n this.orchestrator.stop();\n this.broadcast({ type: 'execution_stopped' });\n }\n\n /**\n * The one mutation seam: every structural plan mutation runs the same\n * ritual — store op → persist (which snapshots tasks from PlanStore) →\n * broadcast — in that order, once. A store op returning false aborts\n * before anything is persisted. PlanStore is the single authority for\n * task state; LegacyPlanState.tasks is populated only at persist time.\n */\n private mutatePlan(op: () => boolean, notify: () => void = () => this.broadcastPlan()): LegacyPlanState | null {\n if (!this.plan) return null;\n if (!op()) return null;\n this.persist();\n notify();\n return this.plan;\n }\n\n updateTask(taskId: string, changes: Partial<Task>): LegacyPlanState | null {\n return this.mutatePlan(\n () => Boolean(this.store.update(taskId, changes)),\n () => this.broadcast({ type: 'task_updated', taskId, changes: changes as Record<string, unknown> }),\n );\n }\n\n /**\n * Move one task onto a different runner. Distinct from {@link updateTask}\n * because a runner change is never a single-field edit: the task's model,\n * thinking effort and mode are all scoped to its runner, so they are\n * re-derived from the new runner's catalog (see {@link retargetTaskRunner}).\n * That needs discovery, which is async — hence a method of its own rather\n * than a branch inside the sync `updateTask`.\n *\n * The runner is also admitted into `plan.runners` — see {@link admitRunner}.\n */\n async setTaskRunner(taskId: string, runner: RunnerId): Promise<LegacyPlanState | null> {\n if (!this.plan) return null;\n const task = this.store.get(taskId);\n if (!task) return null;\n // Guard before discovery, not after: `modelsForRunners` spawns the runner's\n // own CLI to list models, which is far too expensive for a no-op re-pick.\n if (task.assignedRunner === runner || task.type === 'user') return this.plan;\n\n const catalog = await this.catalogFor(runner);\n const changes = retargetTaskRunner(task, runner, this.allowedCatalog(catalog, runner));\n if (Object.keys(changes).length === 0) return this.plan;\n\n return this.mutatePlan(() => {\n if (!this.store.update(taskId, changes)) return false;\n this.admitRunner(runner, catalog.models);\n return true;\n });\n }\n\n /** What a runner offers, as {@link runnerAssignment} needs it. Spawns the runner's CLI to list models. */\n private async catalogFor(runner: RunnerId): Promise<RunnerCatalog> {\n return {\n models: (await this.modelResolver.modelsForRunners([runner]))[runner] ?? [],\n modes: this.runnerModesFor([runner])[runner],\n };\n }\n\n /**\n * What a *derived* assignment may draw from: the runner's catalog narrowed to\n * the user's allowlist. Deriving from the full catalog would hand a task the\n * runner's first model regardless of a restriction the user set — the next\n * planner turn's `coerceAssignments` would snap it back anyway, so the user\n * would see their pick silently change instead of never being offered.\n *\n * `catalogFor` stays unnarrowed because {@link admitRunner} caches it as what\n * the runner really offers, which is what effort clamping needs.\n */\n private allowedCatalog(catalog: RunnerCatalog, runner: RunnerId): RunnerCatalog {\n // The other runners' catalogs are what lets `effectiveAllowlist` tell an id\n // this runner hasn't listed yet from one that belongs to a different runner.\n const allowed = effectiveAllowlist(\n this.settingsFn().modelAllowlist?.[runner],\n runner,\n { ...this.modelsCache, [runner]: catalog.models },\n );\n if (!allowed) return catalog;\n const models = catalog.models.filter((m) => allowed.includes(m.modelId));\n // Nothing left means the allowlist named only ids this runner hasn't\n // listed. An empty catalog reads as \"discovery failed\" to\n // `runnerAssignment`, which then leaves the task on the *old* runner's\n // model — a worse outcome than ignoring the restriction for this derivation.\n return models.length > 0 ? { ...catalog, models } : catalog;\n }\n\n /**\n * Make a runner a first-class member of this plan. Without this, the next\n * planner turn's `coerceAssignments` would treat it as disallowed and snap\n * every task on it back, silently undoing the user's choice; and that same\n * pass clamps efforts against `modelsCache`, so a catalog missing from there\n * makes the effort we just derived read as unverifiable.\n */\n private admitRunner(runner: RunnerId, models: DiscoveredModel[]): void {\n if (!this.plan) return;\n if (!this.plan.runners.includes(runner)) this.plan.runners = [...this.plan.runners, runner];\n // The store is what the orchestrator resolves a spawn against, and nothing\n // reloads it between this edit and a single-task run.\n this.store.admitRunner(runner);\n if (models.length > 0) this.modelsCache = { ...this.modelsCache, [runner]: models };\n }\n\n /**\n * Replace one task's dependency list. Separate from {@link updateTask}\n * because a hand-edited graph is the one task edit that can leave a plan\n * unschedulable: `canSetDependencies` is the guard, and it lives behind this\n * one method so the API and both surfaces' pickers reject the same edits\n * rather than each carrying a copy of the rule. Throws so a surface can say\n * why the edit was refused.\n */\n setTaskDependencies(taskId: string, dependencies: string[]): LegacyPlanState | null {\n if (!this.plan) return null;\n const check = canSetDependencies(this.store.planTasks, taskId, dependencies);\n if (!check.ok) throw new Error(check.error ?? 'Those dependencies are not valid');\n return this.updateTask(taskId, { dependencies });\n }\n\n async completeTask(taskId: string): Promise<void> {\n await this.markTaskComplete(taskId);\n }\n\n removeTask(taskId: string): LegacyPlanState | null {\n return this.mutatePlan(() => (this.store.remove(taskId), true));\n }\n\n /**\n * Add one task, filling in whatever the caller left unset. A task with no\n * runnable assignment is not a lighter task but an unspawnable one, so the\n * runner falls back to the plan's first and the model, effort and mode are\n * derived from that runner's catalog — the same derivation a runner change\n * uses ({@link runnerAssignment}), which is why this is async like\n * {@link setTaskRunner}. Anything the caller did choose survives when the\n * runner offers it.\n *\n * Dependencies naming tasks that don't exist are dropped rather than rejected:\n * the caller is a picker over the current plan, so a stale id means the plan\n * moved on, not that the whole task should be refused.\n */\n async addTask(draft: Partial<Task>): Promise<LegacyPlanState | null> {\n if (!this.plan) return null;\n const runner = draft.assignedRunner ?? this.plan.runners[0];\n const dependencies = (draft.dependencies ?? []).filter((id) => this.store.get(id));\n const catalog = draft.type === 'user' ? null : await this.catalogFor(runner);\n\n return this.mutatePlan(() => {\n this.store.add({ ...draft, ...(catalog ? runnerAssignment(this.allowedCatalog(catalog, runner), draft) : {}), assignedRunner: runner, dependencies });\n if (catalog) this.admitRunner(runner, catalog.models);\n return true;\n });\n }\n\n mergeTasks(taskIdA: string, taskIdB: string): LegacyPlanState | null {\n return this.mutatePlan(() => (this.store.merge(taskIdA, taskIdB), true));\n }\n\n mergeMultipleTasks(taskIds: string[]): LegacyPlanState | null {\n return this.mutatePlan(() => (this.store.mergeMultiple(taskIds), true));\n }\n\n splitTask(taskId: string, newTasks: Partial<Task>[]): LegacyPlanState | null {\n return this.mutatePlan(() => (this.store.split(taskId, newTasks), true));\n }\n\n /**\n * Planner-driven merge: validate compatibility up front, then ask the planner\n * LLM to produce a single \"merge\" taskOps op combining the selected tasks.\n * Goes through the same conversation loop + validated-atomic-edit + corrective\n * retry flow as every other task_ops edit (ADR-0002). Throws on a\n * pre-flight compatibility failure so the host surfaces an inline error\n * before any LLM call.\n */\n async requestMerge(taskIds: string[], options?: GeneratePlanOptions): Promise<LegacyPlanState> {\n if (!this.plan) throw new Error('No active plan state');\n const check = canMergeTasks(this.store.planTasks, taskIds);\n if (!check.ok) throw new Error(check.error ?? 'These tasks cannot be merged');\n const prompt = buildMergePrompt(taskIds, this.store.planTasks);\n return this.continueConversation(prompt, options);\n }\n\n /**\n * Planner-driven split: ask the planner LLM to decompose one task into a\n * sequence of smaller tasks. The model generates the breakdown (no manual\n * per-task specs from the user). Same conversation-loop/repair path as merge.\n */\n async requestSplit(taskId: string, options?: GeneratePlanOptions): Promise<LegacyPlanState> {\n if (!this.plan) throw new Error('No active plan state');\n const check = canSplitTask(this.store.planTasks, taskId);\n if (!check.ok) throw new Error(check.error ?? 'This task cannot be split');\n const prompt = buildSplitPrompt(taskId, this.store.planTasks);\n return this.continueConversation(prompt, options);\n }\n\n loadPlan(plan: LegacyPlanState, goal: string, workspace: string, opts?: { sessionId?: string; persist?: boolean }): void {\n // A live planner conversation belongs to the plan it was started for.\n // Adopting a different plan (session load/switch) must drop it — otherwise\n // the next user message continues the OLD session's LLM thread and the\n // planner re-emits that session's plan here. The same-object case (e.g.\n // re-adopting the current plan on approval) keeps the conversation; after\n // a drop, the first user send reseeds it from this plan's own transcript.\n if (plan !== this.plan) {\n this.aiService.reset();\n // The execution log and queued messages are scoped to the outgoing plan;\n // callers restoring a saved queue re-apply it after adoption.\n this.store.clearLog();\n this.orchestrator.clearQueuedMessages();\n // Approval scopes are equally session-scoped: a path or command approved\n // for the previous plan must not stay approved for the newly adopted one.\n this.approvals.clear();\n this.approvalPolicy.reset();\n }\n this.plan = plan;\n this.goal = goal;\n this.workspace = workspace;\n // Adopting the saved session's id keeps subsequent persists writing to the\n // same file instead of forking the session under a fresh identity.\n if (opts?.sessionId) this.currentSessionId = opts.sessionId;\n this.orchestrator.loadPlan(plan.tasks, plan.runners);\n if (opts?.persist !== false) this.persist();\n }\n\n async modifyPlan(userRequest: string): Promise<Task[]> {\n if (!this.plan) throw new Error('No plan to modify');\n const now = new Date().toISOString();\n this.appendTranscript('user', userRequest, now);\n const modelsByRunner = await this.modelResolver.modelsForRunners(this.plan.runners);\n const runnerModes = this.runnerModesFor(this.plan.runners);\n const { modelAllowlist } = this.settingsFn();\n const result = await this.planner.modify({\n existingPlan: this.plan,\n userRequest,\n modelsByRunner,\n runnerModes,\n autonomousDefault: this.config.autonomousMode,\n fs: this.fsAdapter,\n fetcher: this.fetcher,\n perRunnerAllowlist: modelAllowlist,\n });\n this.orchestrator.loadPlan(result.tasks, this.plan.runners);\n this.appendTranscript('assistant', `Plan updated — now ${result.tasks.length} task${result.tasks.length === 1 ? '' : 's'}.`, new Date().toISOString(), 'plan_generated');\n this.persist();\n return result.tasks;\n }\n\n destroy(): void {\n this.stopExecution();\n // Planning research runs on a separate conduit from task execution — a\n // live spawn_research_agent/bash tool call would otherwise keep running\n // server-side after the client has already moved on to a new session.\n this.aiService.reset();\n // Deny any still-pending approval prompts so their timers and awaited\n // continuations settle before the Session goes away.\n this.approvals.clear();\n this.approvalPolicy.reset();\n this.unsubObserver?.();\n this.unsubObserver = null;\n }\n\n private broadcastPlan(): void {\n if (!this.plan) return;\n this.broadcast({\n type: 'plan_generated',\n plan: serializePlan(this.plan),\n goal: this.goal,\n runners: this.plan.runners,\n });\n }\n\n get aiServiceInstance(): IAiService { return this.aiService; }\n}\n\n","import type { RunnerPluginManifest, ResolveContext, RunnerInvocation } from './types';\n\nexport class ResolveError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ResolveError';\n }\n}\n\nenum Block {\n None,\n IfModel,\n IfThinking,\n IfPlanMode,\n IfBuildMode,\n IfHeadless,\n IfVariant,\n IfInteractive,\n IfHeadlessSession,\n IfInteractiveVariant,\n}\n\nexport function resolveArgs(manifest: RunnerPluginManifest, ctx: ResolveContext): RunnerInvocation {\n const args: string[] = [];\n const env: Record<string, string> = {};\n\n if (manifest.runner.env) {\n for (const [key, value] of Object.entries(manifest.runner.env)) {\n const resolved = substituteSimple(value, ctx);\n // An env value that resolves to nothing (e.g. its {{if …}} condition is\n // false) is omitted entirely rather than exported as an empty string.\n if (resolved.length > 0) env[key] = resolved;\n }\n }\n\n let block = Block.None;\n let include = true;\n\n for (let i = 0; i < manifest.runner.argsTemplate.length; i++) {\n const raw = manifest.runner.argsTemplate[i];\n\n const blockOpen = parseBlockOpen(raw);\n if (blockOpen !== null) {\n if (block !== Block.None) throw new ResolveError(`Nested conditional block at position ${i}: \"${raw}\"`);\n block = blockOpen;\n include = shouldIncludeBlock(block, ctx);\n continue;\n }\n\n if (raw === '{{/if}}') {\n if (block === Block.None) throw new ResolveError(`Unmatched {{/if}} at position ${i}`);\n block = Block.None;\n include = true;\n continue;\n }\n\n if (!include) continue;\n\n const resolved = resolveToken(raw, manifest, ctx);\n if (resolved.length === 0) continue;\n\n if (isFeatureToken(raw)) {\n const parts = resolved.split(/(?<!\\\\) /);\n for (const part of parts) {\n if (part.length > 0) args.push(part);\n }\n } else {\n args.push(resolved);\n }\n }\n\n if (block !== Block.None) {\n throw new ResolveError(`Unclosed conditional block: ${Block[block]}`);\n }\n\n return {\n command: manifest.runner.command,\n args,\n env,\n promptInArgs: manifest.runner.promptInArgs,\n };\n}\n\nfunction parseBlockOpen(raw: string): Block | null {\n switch (raw) {\n case '{{if model}}': return Block.IfModel;\n case '{{if thinking}}': return Block.IfThinking;\n case '{{if planMode}}': return Block.IfPlanMode;\n case '{{if buildMode}}': return Block.IfBuildMode;\n case '{{if headless}}': return Block.IfHeadless;\n case '{{if variant}}': return Block.IfVariant;\n case '{{if interactive}}': return Block.IfInteractive;\n case '{{if headlessSession}}': return Block.IfHeadlessSession;\n case '{{if interactiveVariant}}': return Block.IfInteractiveVariant;\n default: return null;\n }\n}\n\nfunction shouldIncludeBlock(block: Block, ctx: ResolveContext): boolean {\n switch (block) {\n case Block.IfModel: return !!ctx.model;\n case Block.IfThinking: return !!ctx.thinkingEffort && !!ctx.model;\n case Block.IfPlanMode: return ctx.mode === 'plan';\n case Block.IfBuildMode: return ctx.mode !== 'plan';\n // Headless skip-permission flags only make sense for build-mode (write) tasks;\n // plan mode is read-only and the flag can conflict with --permission-mode plan.\n case Block.IfHeadless: return !!ctx.headless && ctx.mode !== 'plan';\n // `--variant` is a headless-only flag: it exists on `opencode run` but not\n // on the interactive TUI, which exits immediately if handed an unknown flag.\n case Block.IfVariant: return !!ctx.thinkingEffort && !!ctx.headless;\n // Session-shape blocks: unlike IfHeadless (a permission-flag gate with a\n // plan-mode carve-out), these pick the CLI invocation shape — e.g.\n // opencode's `run` subcommand vs its interactive TUI — so no mode carve-out.\n case Block.IfInteractive: return !ctx.headless;\n case Block.IfHeadlessSession: return !!ctx.headless;\n // Interactive counterpart of IfVariant, for runners whose TUI has no\n // variant flag and must receive the variant via env config instead.\n // Requires a provider-prefixed model: the config pins variant per model.\n case Block.IfInteractiveVariant:\n return !!ctx.thinkingEffort && !!ctx.model?.includes('/') && !ctx.headless;\n default: return true;\n }\n}\n\nfunction isFeatureToken(token: string): boolean {\n return token.startsWith('{{feature:') && token.endsWith('}}');\n}\n\n/**\n * Map a thinking effort variant ID to the Claude Code CLI flags string.\n * Effort IDs: adaptive, low, medium, high, xhigh, max (per-model from the\n * Anthropic API). `disabled` is handled as a legacy value for old tasks.\n * Returns a space-separated string that will be split into separate args.\n */\nfunction resolveClaudeThinkingFlags(effort: string): string {\n if (effort === 'disabled') return '--thinking disabled';\n if (effort === 'adaptive') return '--thinking adaptive';\n // low/medium/high/xhigh/max all use --thinking enabled + --effort <level>\n if (['low', 'medium', 'high', 'xhigh', 'max'].includes(effort)) {\n return `--thinking enabled --effort ${effort}`;\n }\n // Legacy: old variant IDs — map to adaptive\n return '--thinking adaptive';\n}\n\nfunction resolveToken(token: string, manifest: RunnerPluginManifest, ctx: ResolveContext): string {\n if (token === '{{prompt}}') return ctx.prompt;\n if (token === '{{model}}') return ctx.model || '';\n if (token === '{{thinkingEffort}}') return ctx.thinkingEffort || '';\n if (token === '{{mode}}') return ctx.mode || 'build';\n\n if (token === '{{feature:thinking}}') {\n return manifest.features.thinkingFlag || '';\n }\n\n if (token === '{{feature:thinkingVal}}') {\n const effort = ctx.thinkingEffort || 'medium';\n if (effort === 'high') return manifest.features.thinkingValueEnabled || 'enabled';\n if (effort === 'low') return manifest.features.thinkingValueDisabled || 'disabled';\n return manifest.features.thinkingValueAdaptive || 'adaptive';\n }\n\n // Combined thinking flags: --thinking MODE [--effort LEVEL]\n // Used by Claude Code's new argsTemplate.\n if (token === '{{feature:thinkingFlags}}') {\n const effort = ctx.thinkingEffort;\n if (!effort) return '';\n return resolveClaudeThinkingFlags(effort);\n }\n\n // Reasoning effort as a config override: `-c model_reasoning_effort=<level>`.\n // Used by Codex, whose CLI has no dedicated effort flag. Left unquoted on\n // purpose: bare levels fail TOML parsing and fall back to the raw string,\n // which is what codex expects — quoting would diverge between shell-mediated\n // (interactive terminal) and direct-spawn (headless) invocations.\n if (token === '{{feature:reasoningEffortConfig}}') {\n const effort = ctx.thinkingEffort;\n if (!effort) return '';\n return `-c model_reasoning_effort=${effort}`;\n }\n\n // Maps the current mode to the runner's --permission-mode CLI value.\n if (token === '{{feature:permissionModeVal}}') {\n const mode = ctx.mode || 'default';\n const map = manifest.features.permissionModeValues;\n if (map && map[mode] !== undefined) return map[mode];\n // Fallback: use mode ID directly as CLI value\n return mode;\n }\n\n if (token === '{{feature:planMode}}') {\n return manifest.features.planModeFlag || '';\n }\n\n if (token === '{{feature:buildMode}}') {\n return manifest.features.buildModeFlag || '';\n }\n\n if (token === '{{feature:headless}}') {\n return manifest.features.headlessFlag || '';\n }\n\n if (token.startsWith('{{feature:') && token.endsWith('}}')) {\n return '';\n }\n\n return token;\n}\n\n/**\n * The OPENCODE_CONFIG_CONTENT payload that pins a variant for a TUI session:\n * agent-scoped model+variant (opencode applies an agent's variant only when\n * the session uses that agent's configured model) PLUS disabling the model's\n * other variants — without the disables, the TUI's remembered last-used\n * variant silently wins over the agent config.\n */\nfunction resolveOpencodeVariantConfig(ctx: ResolveContext): string {\n const model = ctx.model;\n const effort = ctx.thinkingEffort;\n if (!model || !effort) return '';\n const slash = model.indexOf('/');\n if (slash <= 0) return '';\n const provider = model.slice(0, slash);\n const bareModel = model.slice(slash + 1);\n const config: Record<string, unknown> = {\n agent: { [ctx.mode || 'build']: { model, variant: effort } },\n };\n const others = (ctx.modelVariants ?? []).filter((v) => v !== effort);\n if (others.length > 0) {\n config.provider = {\n [provider]: {\n models: {\n [bareModel]: {\n variants: Object.fromEntries(others.map((v) => [v, { disabled: true }])),\n },\n },\n },\n };\n }\n return JSON.stringify(config);\n}\n\nfunction substituteSimple(value: string, ctx: ResolveContext): string {\n // Env values support the same (non-nested) {{if X}}…{{/if}} conditions as\n // the args template: the wrapped text is kept or dropped as a whole.\n const conditioned = value.replace(/\\{\\{if (\\w+)\\}\\}([\\s\\S]*?)\\{\\{\\/if\\}\\}/g, (match, name, body) => {\n const block = parseBlockOpen(`{{if ${name}}}`);\n if (block === null) return match;\n return shouldIncludeBlock(block, ctx) ? body : '';\n });\n return conditioned\n .replace(/\\{\\{opencodeVariantConfig\\}\\}/g, () => resolveOpencodeVariantConfig(ctx))\n .replace(/\\{\\{prompt\\}\\}/g, ctx.prompt)\n .replace(/\\{\\{model\\}\\}/g, ctx.model || '')\n .replace(/\\{\\{thinkingEffort\\}\\}/g, ctx.thinkingEffort || '')\n .replace(/\\{\\{mode\\}\\}/g, ctx.mode || 'build');\n}\n","import type { RunnerRegistry } from '../plugins/RunnerRegistry';\nimport { resolveArgs } from '../plugins/resolveArgs';\nimport type { RunnerInvocation } from '../plugins/types';\n\nexport type RunnerMode = string;\n\nexport type { RunnerInvocation } from '../plugins/types';\n\nexport function buildRunnerInvocation(opts: {\n runner: string;\n prompt: string;\n modelId?: string;\n thinkingEffort?: string;\n modelVariants?: string[];\n mode?: RunnerMode;\n headless?: boolean;\n registry: RunnerRegistry;\n}): RunnerInvocation {\n const entry = opts.registry.get(opts.runner);\n if (!entry) {\n throw new Error(`Unknown runner: ${opts.runner}. Use \\`ordewell plugins list\\` to see registered runners.`);\n }\n\n const manifest = entry.manifest;\n\n return resolveArgs(manifest, {\n prompt: opts.prompt,\n model: opts.modelId,\n thinkingEffort: opts.thinkingEffort,\n modelVariants: opts.modelVariants,\n mode: opts.mode ?? 'build',\n headless: opts.headless,\n });\n}\n","import { spawn as nodeSpawn, execSync, ChildProcess } from 'child_process';\nimport { ITerminalSession } from '../interfaces/ITerminalRunner';\nimport { buildRunnerInvocation } from './buildRunnerArgs';\nimport { AbstractTerminalSession, AbstractRunner } from './AbstractRunner';\nimport { augmentedPath, withPath } from '../utils/shellPath';\nimport { stripAnsi, wrapWithPty } from '../utils/shell';\nimport { planDirectLaunch, type LaunchDeps, type LaunchPlan } from '../utils/launch';\nimport { killTree } from '../utils/processTree';\n\nexport type SpawnFn = (\n command: string,\n args: string[],\n options: {\n env: NodeJS.ProcessEnv;\n stdio: ['pipe', 'pipe', 'pipe'];\n cwd: string;\n /** Set by the Windows batch route, where `args` is already a quoted command line. */\n windowsVerbatimArguments?: boolean;\n },\n) => ChildProcess;\n\n/** Test seam: every OS touchpoint is injectable; production uses the defaults. */\nexport interface HeadlessRunnerDeps {\n spawnImpl?: SpawnFn;\n hasScriptCmd?: () => boolean;\n resolvePath?: () => Promise<string>;\n /**\n * Overrides for executable resolution ({@link planDirectLaunch}). Only the\n * Windows branch consults them, so a POSIX test never needs to pass anything.\n */\n launchDeps?: LaunchDeps;\n}\n\n/**\n * `script` is POSIX-only, and the probe reflects that: `which` does not exist\n * on Windows, so `execSync` throws and the answer is a correct `false`. The\n * PTY wrapper (`wrapWithPty`) is therefore never reached there — which is the\n * intended outcome, not a lucky one.\n */\nfunction defaultHasScriptCmd(): boolean {\n if (process.platform === 'win32') return false;\n try { execSync('which script', { stdio: 'ignore' }); return true; } catch { return false; }\n}\n\nclass HeadlessSession extends AbstractTerminalSession {\n private process: ChildProcess | null = null;\n private outputBuffer = '';\n\n constructor(id: string, taskId: string, private spawnImpl: SpawnFn) {\n super(id, taskId);\n }\n\n start(launch: LaunchPlan, cwd: string, resolvedPath: string, env?: Record<string, string>): void {\n this.process = this.spawnImpl(launch.file, launch.args, {\n env: withPath(process.env, resolvedPath, env),\n stdio: ['pipe', 'pipe', 'pipe'],\n cwd,\n windowsVerbatimArguments: launch.verbatim,\n });\n\n const onData = (data: Buffer) => {\n const raw = data.toString();\n this.outputBuffer += stripAnsi(raw);\n this.outputEmitter.emit('output', raw);\n };\n this.process.stdout?.on('data', onData);\n this.process.stderr?.on('data', onData);\n\n this.process.on('close', (code) => { this.baseHandleExit(code ?? -1); });\n this.process.on('error', (err) => {\n this.outputBuffer += `\\nProcess error: ${err.message}\\n`;\n this.outputEmitter.emit('output', `\\nProcess error: ${err.message}\\n`);\n this.baseHandleExit(-1);\n });\n }\n\n kill(): void {\n // Tree-wide: on Windows the direct child may be a cmd.exe shim, and killing\n // it would leave the runner itself alive and still editing the workspace.\n killTree(this.process);\n }\n\n getOutput(): string { return this.outputBuffer; }\n\n write(text: string): void {\n if (this.process?.stdin && !this.process.killed) {\n this.process.stdin.write(text);\n }\n }\n}\n\nexport class HeadlessRunner extends AbstractRunner<HeadlessSession> {\n private spawnImpl: SpawnFn;\n private hasScriptCmd: () => boolean;\n private resolvePath: () => Promise<string>;\n private launchDeps: LaunchDeps;\n\n constructor(deps: HeadlessRunnerDeps = {}) {\n super();\n this.spawnImpl = deps.spawnImpl ?? nodeSpawn;\n this.hasScriptCmd = deps.hasScriptCmd ?? defaultHasScriptCmd;\n this.resolvePath = deps.resolvePath ?? augmentedPath;\n this.launchDeps = { resolvePath: this.resolvePath, ...deps.launchDeps };\n }\n\n async spawn(opts: {\n taskId: string;\n runner: string;\n prompt: string;\n modelId?: string;\n thinkingEffort?: string;\n modelVariants?: string[];\n mode?: string;\n headless?: boolean;\n cwd: string;\n registry?: import('../plugins/RunnerRegistry').RunnerRegistry;\n }): Promise<ITerminalSession> {\n const id = `ordewell-${opts.taskId.slice(0, 8)}`;\n const session = new HeadlessSession(id, opts.taskId, this.spawnImpl);\n\n const invocation = buildRunnerInvocation({\n runner: opts.runner,\n prompt: opts.prompt,\n modelId: opts.modelId,\n thinkingEffort: opts.thinkingEffort,\n modelVariants: opts.modelVariants,\n mode: opts.mode,\n headless: opts.headless ?? true,\n registry: opts.registry!,\n });\n\n const manifest = opts.registry?.get(opts.runner)?.manifest;\n const requiresTty = manifest?.runner.requiresTty === true && this.hasScriptCmd();\n\n const modeStr = opts.mode === 'plan' ? 'plan' : 'build';\n console.error(`[headless] Starting ${opts.runner} [${modeStr}] (${opts.modelId || 'default'}) for task ${opts.taskId.slice(0, 8)}${requiresTty ? ' (PTY)' : ''}`);\n\n // Same PATH treatment as model discovery: the runner binary must resolve\n // wherever the user installed it, even under a GUI-minimal PATH.\n const resolvedPath = await this.resolvePath();\n\n // The PTY wrapper is POSIX-only (`requiresTty` is gated on `script`\n // existing), so on Windows this is always the direct path.\n const { command, args } = requiresTty\n ? wrapWithPty(invocation.command, invocation.args)\n : { command: invocation.command, args: invocation.args };\n\n session.start(\n await planDirectLaunch(command, args, this.launchDeps),\n opts.cwd,\n resolvedPath,\n invocation.env,\n );\n this.registerSession(id, session);\n return session;\n }\n}\n","import { EventEmitter } from 'events';\nimport { ITerminalRunner, ITerminalSession } from '../interfaces/ITerminalRunner';\n\nexport abstract class AbstractTerminalSession implements ITerminalSession {\n public id: string;\n public taskId: string;\n protected exited = false;\n protected outputEmitter = new EventEmitter();\n protected exitEmitter = new EventEmitter();\n\n constructor(id: string, taskId: string) {\n this.id = id;\n this.taskId = taskId;\n }\n\n protected baseHandleExit(code: number): void {\n if (this.exited) return;\n this.exited = true;\n this.exitEmitter.emit('exit', code);\n }\n\n onOutput(callback: (text: string) => void): void {\n this.outputEmitter.on('output', callback);\n }\n\n onExit(callback: (code: number) => void): void {\n this.exitEmitter.on('exit', callback);\n }\n\n abstract kill(): void;\n abstract getOutput(): string;\n abstract write(text: string): void;\n}\n\nexport abstract class AbstractRunner<S extends ITerminalSession> implements ITerminalRunner {\n protected sessions: Map<string, S> = new Map();\n\n get activeCount(): number { return this.sessions.size; }\n\n stop(sessionId: string): void {\n const session = this.sessions.get(sessionId);\n if (!session) return;\n session.kill();\n this.sessions.delete(sessionId);\n }\n\n stopAll(): void {\n for (const [, session] of this.sessions) {\n session.kill();\n }\n this.sessions.clear();\n }\n\n protected registerSession(id: string, session: S): void {\n this.sessions.set(id, session);\n session.onExit(() => this.sessions.delete(id));\n }\n\n abstract spawn(opts: {\n taskId: string;\n runner: string;\n prompt: string;\n modelId?: string;\n thinkingEffort?: string;\n mode?: string;\n headless?: boolean;\n cwd: string;\n registry?: import('../plugins/RunnerRegistry').RunnerRegistry;\n }): Promise<ITerminalSession>;\n}\n","import { execFile } from 'child_process';\nimport { promisify } from 'util';\nimport { tmpdir } from 'os';\nimport { join } from 'path';\nimport { existsSync, readFileSync, unlinkSync, writeFileSync } from 'fs';\nimport { ITerminalSession } from '../interfaces/ITerminalRunner';\nimport { buildRunnerInvocation } from './buildRunnerArgs';\nimport { AbstractTerminalSession, AbstractRunner } from './AbstractRunner';\nimport { augmentedPath } from '../utils/shellPath';\nimport { posixShellQuote, stripAnsi } from '../utils/shell';\nimport { tmuxSessionName, tmuxSocketName, tmuxWindowName } from '../utils/tmux';\n\nconst EXIT_RE = /<<<ORDEWELL_TMUX_EXIT:(\\d+)>>>/;\n\nexport type ExecFileFn = (command: string, args: string[]) => Promise<{ stdout: string; stderr: string }>;\n\nconst execFileAsync = promisify(execFile);\nconst defaultExecFile: ExecFileFn = async (command, args) => {\n const { stdout, stderr } = await execFileAsync(command, args);\n return { stdout: String(stdout), stderr: String(stderr) };\n};\n\n/** Test seam: every OS touchpoint is injectable; production uses the defaults. */\nexport interface TmuxRunnerDeps {\n port: number;\n execFileImpl?: ExecFileFn;\n resolvePath?: () => Promise<string>;\n pollIntervalMs?: number;\n logDir?: string;\n}\n\nclass TmuxSession extends AbstractTerminalSession {\n private outputBuffer = '';\n private offset = 0;\n private timer: ReturnType<typeof setInterval> | null = null;\n\n constructor(\n id: string,\n taskId: string,\n private tmuxSession: string,\n private windowName: string,\n private execFileImpl: ExecFileFn,\n private pollIntervalMs: number,\n private logPath: string,\n private socket: string,\n ) {\n super(id, taskId);\n }\n\n private get target(): string {\n return `${this.tmuxSession}:${this.windowName}`;\n }\n\n /** Every tmux call must name the daemon's own socket; an unprefixed one\n * silently targets the shared default server (see `tmuxSocketName`). */\n private tmux(args: string[]): Promise<{ stdout: string; stderr: string }> {\n return this.execFileImpl('tmux', ['-L', this.socket, ...args]);\n }\n\n /**\n * Runs the invocation in a fresh tmux window, tailed via `pipe-pane` into a\n * log file rather than polling `capture-pane` snapshots — a byte-exact\n * stream needs no diff/resync heuristics. The command is wrapped so the\n * window survives its own exit (an `exec`'d login shell), which is what\n * lets the user keep poking at a finished task's terminal.\n */\n async start(command: string, args: string[], cwd: string, env?: Record<string, string>): Promise<void> {\n writeFileSync(this.logPath, '');\n\n const envAssignments = Object.entries(env ?? {})\n .map(([k, v]) => `${k}=${posixShellQuote(v)}`)\n .join(' ');\n const inner = [command, ...args].map(posixShellQuote).join(' ');\n const prefix = envAssignments ? `env ${envAssignments} ` : '';\n const loginShell = process.env.SHELL || '/bin/bash';\n const shellCmd = `${prefix}${inner}; printf '\\\\n<<<ORDEWELL_TMUX_EXIT:%s>>>\\\\n' \"$?\"; exec ${posixShellQuote(loginShell)} -l`;\n\n await this.tmux(['new-window', '-t', this.tmuxSession, '-n', this.windowName, '-c', cwd, shellCmd]);\n await this.tmux(['pipe-pane', '-t', this.target, `cat >> ${posixShellQuote(this.logPath)}`]);\n\n this.timer = setInterval(() => this.poll(), this.pollIntervalMs);\n }\n\n private poll(): void {\n if (this.exited) return;\n let content: string;\n try {\n content = existsSync(this.logPath) ? readFileSync(this.logPath, 'utf8') : '';\n } catch {\n return;\n }\n if (content.length <= this.offset) return;\n\n const diff = content.slice(this.offset);\n this.offset = content.length;\n this.outputBuffer += stripAnsi(diff);\n this.outputEmitter.emit('output', diff);\n\n // Scan the accumulated tail, not just this read: pipe-pane can flush half\n // the sentinel in one write and the rest in the next, and a marker split\n // across two reads must still be seen exactly once.\n const match = this.outputBuffer.slice(-4096).match(EXIT_RE);\n if (match) this.finish(Number(match[1]));\n }\n\n /**\n * A task finishing (or being killed) stops observation, but never the\n * window itself on the sentinel path — only `kill()` closes the window.\n * Piping is turned off and the log file removed either way, so a finished\n * task doesn't leave a `cat` process appending to it for the rest of the\n * daemon's life.\n */\n private finish(code: number): void {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n this.tmux(['pipe-pane', '-t', this.target]).catch(() => {});\n try {\n unlinkSync(this.logPath);\n } catch {\n /* already gone */\n }\n this.baseHandleExit(code);\n }\n\n kill(): void {\n this.tmux(['kill-window', '-t', this.target]).catch(() => {});\n this.finish(-1);\n }\n\n getOutput(): string {\n return this.outputBuffer;\n }\n\n write(text: string): void {\n this.tmux(['send-keys', '-t', this.target, '-l', text]).catch(() => {});\n }\n}\n\n/**\n * Runs tasks in a real tmux window instead of a piped subprocess, so a user\n * can open a genuine, interactive terminal on any task (running or\n * finished) from outside Ordewell's own process. `ITerminalSession` hides the\n * transport from `VerdictEngine`/`PoolAwareRunner`, so orchestration is\n * unchanged — this is a drop-in replacement for `HeadlessRunner`.\n */\nexport class TmuxRunner extends AbstractRunner<TmuxSession> {\n private sessionName: string;\n private socket: string;\n private execFileImpl: ExecFileFn;\n private resolvePath: () => Promise<string>;\n private pollIntervalMs: number;\n private logDir: string;\n /** Retries get a freshly named window so a failed attempt's output stays inspectable. */\n private attempts = new Map<string, number>();\n private ready: Promise<void> | null = null;\n\n constructor(deps: TmuxRunnerDeps) {\n super();\n this.sessionName = tmuxSessionName(deps.port);\n this.socket = tmuxSocketName(deps.port);\n this.execFileImpl = deps.execFileImpl ?? defaultExecFile;\n this.resolvePath = deps.resolvePath ?? augmentedPath;\n this.pollIntervalMs = deps.pollIntervalMs ?? 500;\n this.logDir = deps.logDir ?? tmpdir();\n }\n\n /**\n * Reaps a session orphaned by a crashed prior daemon on the same port, then\n * creates a fresh one. Memoized: `spawn` awaits it too, so a task spawned\n * before startup's own call has settled never lands in a missing session —\n * and a settled failure clears the memo so the next spawn can retry.\n */\n ensureSession(): Promise<void> {\n this.ready ??= this.createFreshSession().catch((err) => {\n this.ready = null;\n throw err;\n });\n return this.ready;\n }\n\n /** Every tmux call must name this daemon's socket; see `tmuxSocketName`. */\n private tmux(args: string[]): Promise<{ stdout: string; stderr: string }> {\n return this.execFileImpl('tmux', ['-L', this.socket, ...args]);\n }\n\n private async createFreshSession(): Promise<void> {\n try {\n await this.tmux(['has-session', '-t', this.sessionName]);\n await this.tmux(['kill-session', '-t', this.sessionName]);\n } catch {\n /* no stale session */\n }\n await this.tmux(['new-session', '-d', '-s', this.sessionName]);\n await this.configureScrolling();\n }\n\n /**\n * Makes an attached runner terminal scrollable with the mouse wheel and\n * Page Up/Down. A fresh tmux session ships with `mouse off`, a 2000-line\n * scrollback, and no PageUp binding — none of which lets a user page back\n * through a finished task's output, which is the whole point of opening its\n * window. Scoping is harmless: the daemon owns a private socket\n * (`tmuxSocketName`), so these server-wide options touch nothing but its\n * own session. Best-effort so an ancient or stripped tmux cannot stop tasks\n * from spawning — the session still works without the scroll comforts.\n */\n private async configureScrolling(): Promise<void> {\n try {\n // `history-limit` only governs windows created after it is set, so it\n // must run before any `new-window` — once, here at session creation.\n await this.tmux(['set-option', '-g', 'history-limit', '100000']);\n // Wheel-aware copy mode: with `mouse on`, wheel-up enters copy mode and\n // scrolls the pane's scrollback instead of going to the inner app.\n await this.tmux(['set-option', '-g', 'mouse', 'on']);\n // PageUp enters copy mode scrolled up one page; without a root binding it\n // is delivered to the inner app and never reaches tmux's scrollback.\n await this.tmux(['bind-key', '-n', 'PageUp', 'copy-mode', '-u']);\n // PageUp/PageDown then page through the scrollback inside copy mode, in\n // both key tables so the bindings hold regardless of `mode-keys`.\n await this.tmux(['bind-key', '-T', 'copy-mode', 'PageUp', 'send-keys', '-X', 'page-up']);\n await this.tmux(['bind-key', '-T', 'copy-mode', 'PageDown', 'send-keys', '-X', 'page-down']);\n await this.tmux(['bind-key', '-T', 'copy-mode-vi', 'PageUp', 'send-keys', '-X', 'page-up']);\n await this.tmux(['bind-key', '-T', 'copy-mode-vi', 'PageDown', 'send-keys', '-X', 'page-down']);\n } catch {\n /* scroll comforts unavailable — session still usable */\n }\n }\n\n /**\n * Called on daemon shutdown — the one guarantee against leaked tmux\n * processes. Kills the whole server, not just the session: the socket\n * belongs to this daemon alone, so nothing else can be on it, and a runner\n * that somehow escaped its session would otherwise keep running (and keep\n * billing) unattached for as long as the server lived.\n */\n async killSession(): Promise<void> {\n this.ready = null;\n try {\n await this.tmux(['kill-server']);\n } catch {\n /* already gone */\n }\n }\n\n async spawn(opts: {\n taskId: string;\n runner: string;\n prompt: string;\n modelId?: string;\n thinkingEffort?: string;\n modelVariants?: string[];\n mode?: string;\n headless?: boolean;\n cwd: string;\n registry?: import('../plugins/RunnerRegistry').RunnerRegistry;\n planSessionId?: string;\n }): Promise<ITerminalSession> {\n const invocation = buildRunnerInvocation({\n runner: opts.runner,\n prompt: opts.prompt,\n modelId: opts.modelId,\n thinkingEffort: opts.thinkingEffort,\n modelVariants: opts.modelVariants,\n mode: opts.mode,\n headless: opts.headless ?? true,\n registry: opts.registry!,\n });\n\n await this.ensureSession();\n\n // Attempts are counted per plan-scoped task: task ids like \"task-1\" repeat\n // across plans, and mixing their counters would mislabel retry windows.\n const attemptKey = `${opts.planSessionId ?? ''}:${opts.taskId}`;\n const attempt = (this.attempts.get(attemptKey) ?? 0) + 1;\n this.attempts.set(attemptKey, attempt);\n const base = tmuxWindowName(opts.taskId, opts.planSessionId);\n const windowName = attempt > 1 ? `${base}-${attempt}` : base;\n\n // The window name is already unique per plan, task and attempt, so it also\n // keys the session registry and the log file — two live sessions must\n // never share a log, or their output streams would cross-contaminate.\n const id = `ordewell-${windowName}`;\n const session = new TmuxSession(\n id,\n opts.taskId,\n this.sessionName,\n windowName,\n this.execFileImpl,\n this.pollIntervalMs,\n join(this.logDir, `${id}.log`),\n this.socket,\n );\n\n invocation.env = { ...invocation.env, PATH: await this.resolvePath() };\n await session.start(invocation.command, invocation.args, opts.cwd, invocation.env);\n this.registerSession(id, session);\n return session;\n }\n}\n","import { execSync } from 'child_process';\n\n/** One shared tmux session per daemon, scoped by port so multiple daemons never collide. */\nexport function tmuxSessionName(port: number): string {\n return `ordewell-${port}`;\n}\n\n/**\n * Each daemon gets its own tmux *server*, not just its own session name.\n *\n * A plain `tmux new-session` attaches to whatever server already owns the\n * default socket, and a session created on an existing server inherits that\n * **server's** environment — not the environment of the process that asked for\n * it (tmux only refreshes `update-environment` vars, and only on attach). So a\n * daemon started with, say, a particular provider API key would silently hand\n * its runners a stale key left behind by whoever started the server first,\n * possibly hours earlier under a different configuration entirely.\n *\n * A private socket makes the server a child of this daemon, so the runner\n * inherits the daemon's environment the way any child process would, and\n * `kill-server` at shutdown is authoritative — a runner cannot outlive the\n * daemon by hiding on a shared server. Users attaching by hand need the same\n * flag: `tmux -L ordewell-<port> attach -t ordewell-<port>`.\n */\nexport function tmuxSocketName(port: number): string {\n return `ordewell-${port}`;\n}\n\nconst slug = (text: string) => text.replace(/[^a-zA-Z0-9]/g, '');\n\n/**\n * tmux window targeting breaks on `:` and other punctuation, so ids are\n * slugged. Task ids are only unique within one plan (\"task-1\" is every\n * planner's favourite), so the window is also scoped by the plan session id —\n * without it, the second plan run in a daemon's lifetime would collide with\n * the first plan's still-open windows and pipe its output into the wrong one.\n */\nexport function tmuxWindowName(taskId: string, planSessionId?: string): string {\n const scope = planSessionId ? `${slug(planSessionId).slice(-6)}-` : '';\n return `t-${scope}${slug(taskId).slice(0, 16)}`;\n}\n\nexport type ProbeFn = () => void;\n\nconst defaultProbe: ProbeFn = () => {\n execSync(process.platform === 'win32' ? 'where tmux' : 'which tmux', { stdio: 'ignore' });\n};\n\n/** Feature-detects tmux the same way `HeadlessRunner` detects `script`. */\nexport function hasTmux(probe: ProbeFn = defaultProbe): boolean {\n try {\n probe();\n return true;\n } catch {\n return false;\n }\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\nimport { execSync } from 'child_process';\nimport type { RunnerPluginManifest, PluginEntry, IPluginStore } from './types';\nimport { FsPluginStore } from './FsPluginStore';\nimport { CLAUDE_CODE_MANIFEST } from './builtin/claude-code.manifest';\nimport { CODEX_MANIFEST } from './builtin/codex.manifest';\nimport { OPENCODE_MANIFEST } from './builtin/opencode.manifest';\nimport type { IConfig } from '../interfaces/IConfig';\n\n// Insertion order is picker order on every surface (registry.list() preserves it).\nconst BUILTIN_MANIFESTS: RunnerPluginManifest[] = [\n CLAUDE_CODE_MANIFEST,\n CODEX_MANIFEST,\n OPENCODE_MANIFEST,\n];\n\nexport class RunnerRegistry {\n private plugins: Map<string, PluginEntry> = new Map();\n private store: IPluginStore;\n\n constructor(store?: IPluginStore) {\n this.store = store ?? new FsPluginStore();\n this.loadBuiltins();\n }\n\n private loadBuiltins(): void {\n for (const manifest of BUILTIN_MANIFESTS) {\n this.plugins.set(manifest.name, { manifest, source: 'builtin' });\n }\n }\n\n loadUserPlugins(): void {\n const names = this.store.listUserPluginDirs();\n for (const name of names) {\n const pluginDir = path.join(this.store.getUserPluginsDir(), name);\n const manifest = this.store.loadManifest(pluginDir);\n if (!manifest) continue;\n this.plugins.set(manifest.name, {\n manifest,\n source: 'user',\n installPath: pluginDir,\n });\n }\n }\n\n get(id: string): PluginEntry | undefined {\n return this.plugins.get(id);\n }\n\n getManifest(id: string): RunnerPluginManifest | undefined {\n return this.plugins.get(id)?.manifest;\n }\n\n list(): PluginEntry[] {\n return [...this.plugins.values()];\n }\n\n listEnabled(config: IConfig): PluginEntry[] {\n const enabled = config.enabledRunners;\n return this.list().filter((p) => enabled.includes(p.manifest.name));\n }\n\n listEnabledIds(config: IConfig): string[] {\n return this.listEnabled(config).map((p) => p.manifest.name);\n }\n\n isBuiltIn(id: string): boolean {\n const entry = this.plugins.get(id);\n return entry?.source === 'builtin';\n }\n\n installFromPath(sourcePath: string): RunnerPluginManifest {\n const absPath = path.resolve(sourcePath);\n if (!this.store.dirExists(absPath)) {\n throw new Error(`Plugin source must be a directory: ${absPath}`);\n }\n\n const manifest = this.store.loadManifest(absPath);\n if (!manifest) {\n throw new Error(`No valid manifest.json found in: ${absPath}`);\n }\n\n const destDir = path.join(this.store.getUserPluginsDir(), manifest.name);\n this.store.ensureDir(destDir);\n this.store.copyDir(absPath, destDir);\n\n this.plugins.set(manifest.name, {\n manifest,\n source: 'user',\n installPath: destDir,\n });\n\n return manifest;\n }\n\n installFromGit(url: string): RunnerPluginManifest {\n const repoName = url.split('/').pop()?.replace(/\\.git$/, '') || 'plugin';\n const tmpDir = path.join(os.tmpdir(), `ordewell-plugin-${Date.now()}`);\n this.store.ensureDir(tmpDir);\n\n try {\n execSync(`git clone --depth 1 \"${url}\" \"${tmpDir}\"`, { stdio: 'pipe', timeout: 30000 });\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(`Failed to clone repository: ${message}`);\n }\n\n const contents = fsReaddirSync(tmpDir);\n const hasManifest = contents.some((f) => f === 'manifest.json');\n\n if (!hasManifest && contents.length === 1 && this.store.dirExists(path.join(tmpDir, contents[0]))) {\n const subDir = path.join(tmpDir, contents[0]);\n return this.finishInstall(subDir, repoName, tmpDir);\n }\n\n if (!hasManifest) {\n this.store.removeDir(tmpDir);\n throw new Error(`No manifest.json found in repository: ${url}`);\n }\n\n return this.finishInstall(tmpDir, repoName, tmpDir);\n }\n\n private finishInstall(sourceDir: string, repoName: string, tmpDir: string): RunnerPluginManifest {\n const manifest = this.store.loadManifest(sourceDir);\n if (!manifest) {\n this.store.removeDir(tmpDir);\n throw new Error(`No valid manifest.json found in cloned repository`);\n }\n\n const destDir = path.join(this.store.getUserPluginsDir(), manifest.name);\n this.store.ensureDir(destDir);\n this.store.copyDir(sourceDir, destDir);\n this.store.removeDir(tmpDir);\n\n this.plugins.set(manifest.name, {\n manifest,\n source: 'user',\n installPath: destDir,\n });\n\n return manifest;\n }\n\n remove(name: string): void {\n const entry = this.plugins.get(name);\n if (!entry) throw new Error(`Plugin not found: ${name}`);\n if (entry.source === 'builtin') throw new Error(`Cannot remove built-in plugin: ${name}`);\n\n if (entry.installPath) {\n try {\n this.store.removeDir(entry.installPath);\n } catch { /* ignore cleanup errors */ }\n }\n\n this.plugins.delete(name);\n }\n\n createSkeleton(name: string, outputDir: string): string {\n const dir = path.resolve(outputDir, name);\n this.store.ensureDir(dir);\n\n const manifest: RunnerPluginManifest = {\n name,\n displayName: name.replace(/-/g, ' ').replace(/\\b\\w/g, (c) => c.toUpperCase()),\n description: `Custom runner plugin: ${name}`,\n version: '0.1.0',\n runner: {\n command: 'bash',\n argsTemplate: [\n '{{if model}}', '--model', '{{model}}', '{{/if}}',\n '--prompt', '{{prompt}}',\n ],\n promptInArgs: true,\n },\n features: {\n modelSelection: false,\n thinkingEffort: false,\n planMode: false,\n planModeFlag: '',\n },\n modelDiscovery: {\n method: 'hardcoded',\n fallbackModels: [\n { modelId: 'gpt-4o', modelLabel: 'GPT-4o' },\n ],\n },\n };\n\n this.store.writeFile(path.join(dir, 'manifest.json'), JSON.stringify(manifest, null, 2) + '\\n');\n\n const runSh = path.join(dir, 'run.sh');\n const scriptContent = `#!/usr/bin/env bash\n# Custom runner script for ${name}\n# Receives:\n# $1 = prompt text\n# $2 = model ID (optional)\n#\n# This script should invoke your desired CLI tool with the prompt.\n# Replace the echo below with your actual command.\n\nprompt=\"$1\"\nmodel=\"$2\"\n\necho \"Running ${name} with prompt: $prompt\"\n# Example: your-cli-tool --message \"$prompt\"\n`;\n this.store.writeFile(runSh, scriptContent);\n try { fsChmodSync(runSh, 0o755); } catch { /* ignore */ }\n\n return dir;\n }\n}\n\nfunction fsReaddirSync(dir: string): string[] {\n try {\n return fs.readdirSync(dir);\n } catch {\n return [];\n }\n}\n\nfunction fsChmodSync(fpath: string, mode: number): void {\n try {\n fs.chmodSync(fpath, mode);\n } catch { /* ignore */ }\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\nimport { ensureDir } from '../utils/fsHelpers';\nimport type { RunnerPluginManifest, IPluginStore } from './types';\n\nfunction userPluginsDir(): string {\n return path.join(os.homedir(), '.config', 'ordewell', 'plugins');\n}\n\nfunction isValidManifest(obj: unknown): obj is RunnerPluginManifest {\n if (!obj || typeof obj !== 'object') return false;\n const m = obj as Record<string, unknown>;\n return (\n typeof m.name === 'string' &&\n typeof m.displayName === 'string' &&\n typeof m.description === 'string' &&\n typeof m.version === 'string' &&\n typeof m.runner === 'object' && m.runner !== null &&\n typeof (m.runner as Record<string, unknown>).command === 'string' &&\n Array.isArray((m.runner as Record<string, unknown>).argsTemplate) &&\n typeof m.features === 'object' && m.features !== null &&\n typeof m.modelDiscovery === 'object' && m.modelDiscovery !== null\n );\n}\n\nfunction loadManifestFromDir(dir: string): RunnerPluginManifest | null {\n const manifestPath = path.join(dir, 'manifest.json');\n if (!fs.existsSync(manifestPath)) return null;\n try {\n const raw = fs.readFileSync(manifestPath, 'utf8');\n const parsed = JSON.parse(raw);\n if (!isValidManifest(parsed)) return null;\n return parsed as RunnerPluginManifest;\n } catch {\n return null;\n }\n}\n\nfunction copyDirSync(src: string, dest: string): void {\n ensureDir(dest);\n const entries = fs.readdirSync(src, { withFileTypes: true });\n for (const entry of entries) {\n const srcPath = path.join(src, entry.name);\n const destPath = path.join(dest, entry.name);\n if (entry.isDirectory()) {\n copyDirSync(srcPath, destPath);\n } else {\n fs.copyFileSync(srcPath, destPath);\n }\n }\n}\n\nfunction rmDirSync(dir: string): void {\n if (!fs.existsSync(dir)) return;\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n const p = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n rmDirSync(p);\n } else {\n fs.unlinkSync(p);\n }\n }\n fs.rmdirSync(dir);\n}\n\nexport class FsPluginStore implements IPluginStore {\n getUserPluginsDir(): string {\n return userPluginsDir();\n }\n\n listUserPluginDirs(): string[] {\n const dir = userPluginsDir();\n if (!fs.existsSync(dir)) return [];\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true });\n } catch {\n return [];\n }\n return entries.filter((e) => e.isDirectory()).map((e) => e.name);\n }\n\n loadManifest(pluginDir: string): RunnerPluginManifest | null {\n return loadManifestFromDir(pluginDir);\n }\n\n copyDir(sourceDir: string, destDir: string): void {\n copyDirSync(sourceDir, destDir);\n }\n\n removeDir(dir: string): void {\n rmDirSync(dir);\n }\n\n ensureDir(dir: string): void {\n ensureDir(dir);\n }\n\n writeFile(filePath: string, content: string): void {\n fs.writeFileSync(filePath, content);\n }\n\n readFile(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, 'utf8');\n } catch {\n return null;\n }\n }\n\n dirExists(path: string): boolean {\n return fs.existsSync(path) && fs.statSync(path).isDirectory();\n }\n\n exists(path: string): boolean {\n return fs.existsSync(path);\n }\n}\n","import type { RunnerPluginManifest } from '../types';\n\nexport const CLAUDE_CODE_MANIFEST: RunnerPluginManifest = {\n name: 'claude-code',\n displayName: 'Claude Code',\n description: 'Anthropic Claude Code - AI coding assistant in your terminal',\n version: '1.0.0',\n\n runner: {\n command: 'claude',\n argsTemplate: [\n '{{if model}}', '--model', '{{model}}', '{{/if}}',\n '{{if thinking}}', '{{feature:thinkingFlags}}', '{{/if}}',\n '--permission-mode', '{{feature:permissionModeVal}}',\n '{{if headless}}', '{{feature:headless}}', '{{/if}}',\n '{{prompt}}',\n ],\n promptInArgs: true,\n },\n\n features: {\n modelSelection: true,\n thinkingEffort: true,\n planMode: true,\n planModeFlag: '--permission-mode',\n headlessFlag: '--dangerously-skip-permissions',\n thinkingFlag: '--thinking',\n thinkingValueEnabled: 'enabled',\n thinkingValueDisabled: 'disabled',\n thinkingValueAdaptive: 'adaptive',\n permissionModeValues: {\n // Map mode IDs to --permission-mode CLI values\n 'default': 'default',\n 'acceptEdits': 'acceptEdits',\n 'plan': 'plan',\n 'bypassPermissions': 'bypassPermissions',\n // Legacy aliases used by older tasks\n 'build': 'acceptEdits',\n },\n },\n\n modelDiscovery: {\n method: 'command',\n // Claude Code has no `claude models` subcommand. Discovery tries three\n // sources in order, each falling through to the next on failure:\n //\n // 1. Anthropic Models API (apiDiscovery) — GET /v1/models returns the\n // authoritative live list of models the user's account can access,\n // including aliases the --help prose omits (e.g. haiku). Auth works for\n // both API-key users (ANTHROPIC_API_KEY → X-Api-Key) and OAuth/claude.ai\n // users (token from ~/.claude/.credentials.json → Authorization: Bearer).\n // Short aliases (opus, sonnet, haiku, fable) are derived from the full\n // model IDs, deduplicated by family keeping the latest.\n //\n // 2. `claude --help` prose (discoveryCommands) — the CLI's --model\n // description lists example aliases. Fragile (uses \"e.g.\", not\n // exhaustive) but works offline and needs no auth.\n //\n // 3. canonicalAliases — stable --model contracts (opus/sonnet/haiku/fable)\n // merged into any successful result to fill gaps, and used as the full\n // last-resort list when both API and CLI are unavailable.\n apiDiscovery: {\n url: 'https://api.anthropic.com/v1/models?limit=100',\n headers: { 'anthropic-version': '2023-06-01' },\n auth: [\n { type: 'env', varName: 'ANTHROPIC_API_KEY', header: 'X-Api-Key' },\n { type: 'file', path: '~/.claude/.credentials.json', jsonPath: 'claudeAiOauth.accessToken', header: 'Authorization', prefix: 'Bearer ' },\n ],\n parser: 'anthropic-models',\n },\n discoveryCommands: [\n { command: 'claude', args: ['--help'], parser: 'claude-help' },\n ],\n canonicalAliases: [\n { modelId: 'opus', modelLabel: 'Opus' },\n { modelId: 'sonnet', modelLabel: 'Sonnet' },\n { modelId: 'haiku', modelLabel: 'Haiku' },\n { modelId: 'fable', modelLabel: 'Fable' },\n ],\n variants: [\n { id: 'adaptive', label: 'Adaptive' },\n { id: 'low', label: 'Low effort' },\n { id: 'medium', label: 'Medium effort' },\n { id: 'high', label: 'High effort' },\n { id: 'xhigh', label: 'Extra high effort' },\n { id: 'max', label: 'Max effort' },\n ],\n },\n\n contextFile: 'CLAUDE.md',\n contextFileAltPath: '.claude/CLAUDE.md',\n\n modes: [\n { id: 'default', label: 'Ask before edits', description: 'Standard mode: asks permission before editing files', cliValue: 'default', safe: true },\n { id: 'acceptEdits', label: 'Edit automatically', description: 'Edits files without asking, still asks for risky operations', cliValue: 'acceptEdits' },\n { id: 'plan', label: 'Plan mode', description: 'Read-only analysis, no edits allowed', cliValue: 'plan' },\n { id: 'bypassPermissions', label: 'Auto mode', description: 'Skips all permission prompts — use for AI-driven autonomous runs', cliValue: 'bypassPermissions', autonomous: true },\n ],\n};\n","import type { RunnerPluginManifest } from '../types';\n\nexport const CODEX_MANIFEST: RunnerPluginManifest = {\n name: 'codex',\n displayName: 'Codex',\n description: 'OpenAI Codex CLI - AI coding agent in your terminal',\n version: '1.0.0',\n\n runner: {\n command: 'codex',\n // Headless surfaces (CLI/web) use the non-interactive `exec` subcommand\n // (`--skip-git-repo-check`: task workspaces aren't always git repos, and\n // exec hard-fails outside one by default); interactive surfaces (VS Code\n // terminal) launch the TUI with the prompt as its positional argument.\n // Reasoning effort has no dedicated flag — it travels as a `-c` config\n // override (see {{feature:reasoningEffortConfig}}). Both `exec` and the\n // TUI accept `-m`, `-c`, and `--sandbox`.\n argsTemplate: [\n '{{if headlessSession}}', 'exec', '--skip-git-repo-check', '{{/if}}',\n '{{if model}}', '-m', '{{model}}', '{{/if}}',\n '{{if thinking}}', '{{feature:reasoningEffortConfig}}', '{{/if}}',\n '--sandbox', '{{feature:permissionModeVal}}',\n '{{prompt}}',\n ],\n promptInArgs: true,\n },\n\n features: {\n modelSelection: true,\n thinkingEffort: true,\n planMode: true,\n planModeFlag: '--sandbox',\n permissionModeValues: {\n // Map mode IDs to --sandbox CLI values. `codex exec` is non-interactive\n // and has no approval flag, so the sandbox axis is the whole permission\n // story for headless runs.\n 'agent': 'workspace-write',\n 'plan': 'read-only',\n 'fullAccess': 'danger-full-access',\n // Legacy alias used by older tasks\n 'build': 'workspace-write',\n },\n },\n\n modelDiscovery: {\n // Codex has no `codex models` subcommand (see docs/adr/0004). Discovery\n // tries three sources in order, each falling through to the next:\n //\n // 1. `codex app-server` stdio JSON-RPC (`initialize` → `model/list`) —\n // the live catalog: ids, display names, hidden flags, and per-model\n // supported reasoning efforts (the variants).\n // 2. `~/.codex/models_cache.json` — the same catalog, written by Codex\n // itself on its own runs; fresh as of the user's last Codex session.\n // 3. canonicalAliases — stable `-m` slugs as the last resort, with the\n // static common-denominator variants below.\n method: 'hardcoded',\n appServer: {\n command: 'codex',\n args: ['app-server'],\n cacheFile: '~/.codex/models_cache.json',\n },\n canonicalAliases: [\n { modelId: 'gpt-5.6-sol', modelLabel: 'GPT-5.6-Sol' },\n { modelId: 'gpt-5.6-terra', modelLabel: 'GPT-5.6-Terra' },\n { modelId: 'gpt-5.6-luna', modelLabel: 'GPT-5.6-Luna' },\n { modelId: 'gpt-5.5', modelLabel: 'GPT-5.5' },\n { modelId: 'gpt-5.4', modelLabel: 'GPT-5.4' },\n { modelId: 'gpt-5.4-mini', modelLabel: 'GPT-5.4-Mini' },\n ],\n // Fallback-only common denominator: every current Codex model supports at\n // least these four rungs. Live discovery replaces them with each model's\n // real supportedReasoningEfforts (which may add max/ultra).\n variants: [\n { id: 'low', label: 'Low' },\n { id: 'medium', label: 'Medium' },\n { id: 'high', label: 'High' },\n { id: 'xhigh', label: 'Xhigh' },\n ],\n },\n\n contextFile: 'AGENTS.md',\n\n modes: [\n { id: 'agent', label: 'Agent', description: 'Workspace-write sandbox: edits files inside the workspace', cliValue: 'workspace-write', safe: true },\n { id: 'plan', label: 'Plan', description: 'Read-only sandbox for analysis and exploration', cliValue: 'read-only' },\n { id: 'fullAccess', label: 'Full access', description: 'No sandbox — full disk and network access for autonomous runs', cliValue: 'danger-full-access', autonomous: true },\n ],\n};\n","import type { RunnerPluginManifest } from '../types';\n\nexport const OPENCODE_MANIFEST: RunnerPluginManifest = {\n name: 'opencode',\n displayName: 'OpenCode',\n description: 'OpenCode CLI - open-source AI coding agent',\n version: '1.0.0',\n\n runner: {\n command: 'opencode',\n // Interactive surfaces (VS Code terminal) launch the full TUI with\n // `--prompt`; headless surfaces (CLI/web) use the streaming `run`\n // subcommand. `--variant` is ONLY accepted by `run` — the TUI rejects it\n // as an unknown flag and exits before any work, which Ordewell reads as\n // task completion. The TUI receives the variant through\n // OPENCODE_CONFIG_CONTENT instead (see below).\n argsTemplate: [\n '{{if headlessSession}}', 'run', '{{/if}}',\n '{{if model}}', '--model', '{{model}}', '{{/if}}',\n '--agent', '{{mode}}',\n '{{if variant}}', '--variant', '{{thinkingEffort}}', '{{/if}}',\n '{{if buildMode}}', '--auto', '{{/if}}',\n '{{if interactive}}', '--prompt', '{{/if}}',\n '{{prompt}}',\n ],\n // Deep-merged over the user's opencode.json for this process only. An\n // agent-scoped variant alone is NOT enough for the TUI — its remembered\n // last-used variant silently wins — so the config also disables the\n // model's other variants (see resolveOpencodeVariantConfig). Never set a\n // top-level `model`/`variant` here: that can switch the active provider\n // and make sessions fail while still exiting 0.\n env: {\n OPENCODE_CONFIG_CONTENT: '{{if interactiveVariant}}{{opencodeVariantConfig}}{{/if}}',\n },\n promptInArgs: true,\n requiresTty: true,\n },\n\n features: {\n modelSelection: true,\n thinkingEffort: true,\n planMode: true,\n planModeFlag: 'plan',\n buildModeFlag: 'build',\n headlessFlag: '--auto',\n },\n\n modelDiscovery: {\n method: 'command',\n discoveryCommands: [\n { command: 'opencode', args: ['models', '--verbose'], parser: 'opencode-models-verbose' },\n { command: 'opencode', args: ['models'], parser: 'opencode-models' },\n ],\n // No fallbackModels: the list must always reflect what `opencode models`\n // actually reports for THIS user (their configured providers only). A\n // hardcoded fallback previously leaked models the user didn't have.\n // No static variants — per-model variants are fetched from opencode models --verbose\n },\n\n contextFile: 'AGENTS.md',\n contextFileAltPath: '.opencode/AGENTS.md',\n\n modes: [\n { id: 'build', label: 'Build', description: 'Full access agent for development work', cliValue: 'build', autonomous: true, safe: true },\n { id: 'plan', label: 'Plan', description: 'Read-only agent for analysis and exploration', cliValue: 'plan' },\n ],\n};\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport { LegacyPlanState } from '../models/Task';\nimport { defaultLogger, type ILogger } from '../interfaces/ILogger';\nimport { getStateDir, ensureDir } from './fsHelpers';\n\nconst STATE_FILE = 'state.json';\n\nfunction getStatePath(baseDir: string): string {\n return path.join(getStateDir(baseDir), STATE_FILE);\n}\n\nexport function saveState(plan: LegacyPlanState, baseDir?: string): void {\n const statePath = getStatePath(baseDir ?? process.cwd());\n ensureDir(path.dirname(statePath));\n plan.lastUpdated = new Date().toISOString();\n fs.writeFileSync(statePath, JSON.stringify(plan, null, 2));\n}\n\nexport function loadState(baseDir?: string, logger: ILogger = defaultLogger): LegacyPlanState | null {\n const dir = baseDir ?? process.cwd();\n const statePath = getStatePath(dir);\n if (!fs.existsSync(statePath)) return null;\n try {\n const raw = fs.readFileSync(statePath, 'utf-8');\n const parsed = JSON.parse(raw);\n if (!Array.isArray(parsed.runners)) {\n logger.warn('stateStore', `rejecting state from ${statePath}: old format (scalar \"runner\" instead of \"runners\" array). Please re-plan.`);\n return null;\n }\n return parsed as LegacyPlanState;\n } catch (err: unknown) {\n logger.warn('stateStore', `failed to load state from ${statePath}; falling back to empty state`, err);\n return null;\n }\n}\n\nexport function clearState(baseDir?: string): void {\n const dir = baseDir ?? process.cwd();\n const statePath = getStatePath(dir);\n if (fs.existsSync(statePath)) fs.unlinkSync(statePath);\n}\n\nexport function stateExists(baseDir?: string): boolean {\n const dir = baseDir ?? process.cwd();\n return fs.existsSync(getStatePath(dir));\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\n\nexport interface UserSettings {\n grillMe: { enabled: boolean };\n tdd: { enabled: boolean };\n prd: { enabled: boolean };\n review: { enabled: boolean };\n verification: { enabled: boolean };\n researchSubagents: { enabled: boolean };\n modelAllowlist?: Record<string, string[]>;\n}\n\nconst DEFAULTS: UserSettings = {\n grillMe: { enabled: false },\n tdd: { enabled: true },\n prd: { enabled: false },\n review: { enabled: false },\n verification: { enabled: false },\n researchSubagents: { enabled: false },\n};\n\n/**\n * Where the user's toggles live. `ORDEWELL_SETTINGS_PATH` overrides it so several\n * Ordewell processes on one machine can hold *different* settings at the same\n * time. Without it the file is a single shared mutable global: the benchmark\n * harness runs parallel lanes that each pin the mode toggles, and because\n * `getAll()` re-reads whenever the mtime moves, a lane needing\n * `researchSubagents: true` would silently plan with `false` the moment another\n * lane pinned its own — turning an A/B of that toggle into a comparison of one\n * condition against itself.\n */\nexport function getSettingsPath(): string {\n const override = process.env.ORDEWELL_SETTINGS_PATH;\n if (override && override.trim()) return override.trim();\n return path.join(os.homedir(), '.config', 'ordewell', 'settings.json');\n}\n\nexport class SettingsService {\n private filePath: string;\n private cache: UserSettings | null = null;\n private cachedMtimeMs: number | null = null;\n\n constructor(filePath: string = getSettingsPath()) {\n this.filePath = filePath;\n }\n\n // Several processes share the settings file (VS Code extension host, web\n // server, CLI), so the cache is keyed on the file's mtime: a write from any\n // other process invalidates it. A stale cache here previously meant an\n // allowlist set in one surface never reached another's planner.\n getAll(): UserSettings {\n const mtime = this.fileMtimeMs();\n if (this.cache && mtime === this.cachedMtimeMs) return this.cache;\n this.cache = this.load();\n this.cachedMtimeMs = mtime;\n return this.cache;\n }\n\n private fileMtimeMs(): number | null {\n try {\n return fs.statSync(this.filePath).mtimeMs;\n } catch {\n return null;\n }\n }\n\n getGrillMe(): boolean {\n return this.getAll().grillMe.enabled;\n }\n\n getTdd(): boolean {\n return this.getAll().tdd.enabled;\n }\n\n getPrd(): boolean {\n return this.getAll().prd.enabled;\n }\n\n setGrillMe(enabled: boolean): void {\n this.getAll();\n this.cache!.grillMe.enabled = enabled;\n this.persist();\n }\n\n setTdd(enabled: boolean): void {\n this.getAll();\n this.cache!.tdd.enabled = enabled;\n this.persist();\n }\n\n setPrd(enabled: boolean): void {\n this.getAll();\n this.cache!.prd.enabled = enabled;\n this.persist();\n }\n\n getReview(): boolean {\n return this.getAll().review.enabled;\n }\n\n setReview(enabled: boolean): void {\n this.getAll();\n this.cache!.review.enabled = enabled;\n this.persist();\n }\n\n getVerification(): boolean {\n return this.getAll().verification.enabled;\n }\n\n setVerification(enabled: boolean): void {\n this.getAll();\n this.cache!.verification.enabled = enabled;\n this.persist();\n }\n\n getResearchSubagents(): boolean {\n return this.getAll().researchSubagents.enabled;\n }\n\n setResearchSubagents(enabled: boolean): void {\n this.getAll();\n this.cache!.researchSubagents.enabled = enabled;\n this.persist();\n }\n\n getModelAllowlist(runner: string): string[] | undefined {\n return this.getAll().modelAllowlist?.[runner];\n }\n\n setModelAllowlist(runner: string, ids: string[] | undefined): void {\n this.getAll();\n if (ids === undefined) {\n if (this.cache!.modelAllowlist) {\n delete this.cache!.modelAllowlist[runner];\n if (Object.keys(this.cache!.modelAllowlist).length === 0) {\n this.cache!.modelAllowlist = undefined;\n }\n }\n } else {\n if (!this.cache!.modelAllowlist) {\n this.cache!.modelAllowlist = {};\n }\n this.cache!.modelAllowlist[runner] = ids;\n }\n this.persist();\n }\n\n private load(): UserSettings {\n try {\n if (fs.existsSync(this.filePath)) {\n const raw = JSON.parse(fs.readFileSync(this.filePath, 'utf-8'));\n const settings: UserSettings = {\n grillMe: { enabled: raw.grillMe?.enabled ?? DEFAULTS.grillMe.enabled },\n tdd: { enabled: raw.tdd?.enabled ?? DEFAULTS.tdd.enabled },\n prd: { enabled: raw.prd?.enabled ?? DEFAULTS.prd.enabled },\n // `verify` is the legacy key for review mode; keep reading it so old settings files survive the rename.\n // The evidence-based verification mode uses the distinct `verification` key to avoid colliding with it.\n review: { enabled: raw.review?.enabled ?? raw.verify?.enabled ?? DEFAULTS.review.enabled },\n verification: { enabled: raw.verification?.enabled ?? DEFAULTS.verification.enabled },\n researchSubagents: { enabled: raw.researchSubagents?.enabled ?? DEFAULTS.researchSubagents.enabled },\n };\n if (raw.modelAllowlist !== undefined) {\n settings.modelAllowlist = raw.modelAllowlist;\n }\n return settings;\n }\n } catch {\n // corrupted file — use defaults\n }\n return { ...DEFAULTS, grillMe: { ...DEFAULTS.grillMe }, tdd: { ...DEFAULTS.tdd }, prd: { ...DEFAULTS.prd }, review: { ...DEFAULTS.review }, verification: { ...DEFAULTS.verification }, researchSubagents: { ...DEFAULTS.researchSubagents } };\n }\n\n private persist(): void {\n const dir = path.dirname(this.filePath);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n fs.writeFileSync(this.filePath, JSON.stringify(this.cache, null, 2));\n this.cachedMtimeMs = this.fileMtimeMs();\n }\n}\n"],"mappings":"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,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAEA,SAAS,sBACP,MACA,SACA,YACA,SACA,WACA,cACA,aACA,cACA,UACA,aACA,mBACQ;AACR,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,mBAAmB,WAAW;AAAA,IAC9B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,8BAA8B,QAAQ,KAAK,GAAG,IAAI;AAAA,IAClD,wBAAwB,eAAe;AAAA,IACvC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,kBAAkB,OAAO;AAAA,IACzB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU;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","names":["path","resolve","path","path","path","slug","fs","fs","fs","fs","MAX_JSON_REPAIRS","step","fs","fs","path","exec","promisify","fsSync","os","path","join","fsSync","path","defaultExists","length","execAsync","promisify","exec","defaultExec","resolve","cached","id","fs","path","os","cached","models","exec","promisify","execAsync","promisify","exec","defaultExec","resolve","resolve","resolve","STDERR_TAIL_CHARS","resolve","path","refused","fs","DEFAULT_TIMEOUT_MS","fs","path","fs","path","Block","nodeSpawn","nodeSpawn","execFile","promisify","join","existsSync","readFileSync","unlinkSync","writeFileSync","execSync","promisify","execFile","defaultExecFile","writeFileSync","existsSync","readFileSync","unlinkSync","join","fs","path","os","execSync","fs","path","os","path","execSync","fs","path","fs","path","os"]}
1
+ {"version":3,"sources":["../src/interfaces/IFileSystem.ts","../src/interfaces/IApproval.ts","../src/services/commandPolicy.ts","../src/services/researchShell.ts","../src/services/pathScope.ts","../src/services/symbolPatterns.ts","../src/services/BaseFileSystem.ts","../src/services/ApprovalPolicy.ts","../src/services/PendingApprovals.ts","../src/services/ripgrepArgs.ts","../src/interfaces/IConfig.ts","../src/services/ProviderRegistry.ts","../src/interfaces/BaseConfig.ts","../src/interfaces/EnvConfig.ts","../src/interfaces/ILogger.ts","../src/services/BaseAiService.ts","../src/services/plannerModes.ts","../src/services/PlanPrompts.ts","../src/services/PlanRepair.ts","../src/services/researchTools.ts","../src/services/contextCompaction.ts","../src/utils/prdStore.ts","../src/services/ContextCollector.ts","../src/services/executeTool.ts","../src/services/ResearchSubagents.ts","../src/services/GeminiService.ts","../src/services/OpenAiService.ts","../src/services/promptAugment.ts","../src/services/VerdictEngine.ts","../src/services/PlanStore.ts","../src/services/TaskOrchestrator.ts","../src/services/ModelAllowlistResolver.ts","../src/services/Planner.ts","../src/services/ModelDiscovery.ts","../src/utils/shellPath.ts","../src/utils/launch.ts","../src/utils/shell.ts","../src/utils/processTree.ts","../src/services/ModelCatalog.ts","../src/services/ModelShortcuts.ts","../src/services/ProviderRouting.ts","../src/services/ModelResolver.ts","../src/services/RunnerInstallation.ts","../src/services/harness/CliAgentAiService.ts","../src/services/harness/AgentAdapter.ts","../src/services/harness/StdioAgentAdapter.ts","../src/services/harness/ClaudeCodeAdapter.ts","../src/services/harness/codexSandbox.ts","../src/services/harness/CodexAdapter.ts","../src/services/harness/OpenCodeAdapter.ts","../src/services/harness/agentTools.ts","../src/services/AiService.ts","../src/services/HttpWebFetcher.ts","../src/services/TaskRetarget.ts","../src/services/SessionMessage.ts","../src/utils/sessionStore.ts","../src/utils/fsHelpers.ts","../src/services/createSession.ts","../src/plugins/resolveArgs.ts","../src/services/buildRunnerArgs.ts","../src/services/HeadlessRunner.ts","../src/services/AbstractRunner.ts","../src/services/TmuxRunner.ts","../src/utils/tmux.ts","../src/plugins/RunnerRegistry.ts","../src/plugins/FsPluginStore.ts","../src/plugins/builtin/claude-code.manifest.ts","../src/plugins/builtin/codex.manifest.ts","../src/plugins/builtin/opencode.manifest.ts","../src/utils/stateStore.ts","../src/services/SettingsService.ts"],"sourcesContent":["export interface ToolOutcome {\n success: boolean;\n output: string;\n truncated: boolean;\n}\n\nexport interface ReadFileOpts {\n maxBytes?: number;\n offset?: number;\n limit?: number;\n}\n\n/**\n * `content` returns matching lines, `files` only the paths that matched, and\n * `count` a per-file tally. Cheap models otherwise grep and then read whole\n * files to answer \"which files touch this\", burning rounds against the budget.\n */\nexport type GrepOutputMode = 'content' | 'files' | 'count';\n\nexport interface GrepOptions {\n /** File glob filter, e.g. `*.ts`. */\n include?: string;\n /** Search root. Relative to the workspace unless approved as external. */\n path?: string;\n outputMode?: GrepOutputMode;\n /** Lines of context around each match (`content` mode only). */\n contextBefore?: number;\n contextAfter?: number;\n /** Treat the pattern as a literal string rather than a regex. */\n literal?: boolean;\n caseInsensitive?: boolean;\n /** Global cap on returned rows. Defaults to {@link GREP_DEFAULT_HEAD_LIMIT}. */\n headLimit?: number;\n}\n\nexport interface GlobOptions {\n /** Search root. Relative to the workspace unless approved as external. */\n path?: string;\n headLimit?: number;\n}\n\nexport interface FindSymbolOptions {\n /** Language id or file extension, e.g. `typescript` or `.go`. Narrows the keyword set. */\n language?: string;\n /** Search root. Relative to the workspace unless approved as external. */\n path?: string;\n}\n\n/** Global row cap for grep. A per-file cap is not a budget — see PoolFileSystem. */\nexport const GREP_DEFAULT_HEAD_LIMIT = 100;\n\n/**\n * Directories that are never interesting to a planner and would otherwise eat\n * the result budget. Applied by every search entry point, not just `glob` —\n * `dist/` and `.ordewell/` are frequently not gitignored.\n */\nexport const SEARCH_EXCLUSIONS = [\n 'node_modules', '.git', '.ordewell', 'dist', 'build', 'out', 'target',\n '.next', '.nuxt', '.venv', 'venv', '__pycache__', '.mypy_cache', '.pytest_cache',\n 'vendor', 'coverage', '.turbo', '.cache', '.gradle', 'Pods', '.terraform',\n];\n\nexport interface IFileSystem {\n readFile(path: string, opts?: ReadFileOpts): Promise<ToolOutcome>;\n readFiles(paths: string[]): Promise<ToolOutcome>;\n glob(pattern: string, opts?: GlobOptions): Promise<ToolOutcome>;\n grep(pattern: string, opts?: GrepOptions): Promise<ToolOutcome>;\n listDir(path: string, depth?: number): Promise<ToolOutcome>;\n bash(command: string): Promise<ToolOutcome>;\n /** Definition-first lookup for one symbol. See `symbolPatterns.ts`. */\n findSymbol(symbol: string, opts?: FindSymbolOptions): Promise<ToolOutcome>;\n getWorkspaceRoot(): string;\n /**\n * Inject the human-approval channel for out-of-envelope access. Optional so\n * test doubles stay small; every adapter extending `BaseFileSystem` has it.\n */\n setApproval?(approval: import('./IApproval').IApproval): void;\n}\n","/**\n * The planner's single approval seam. Every capability that reaches beyond the\n * default read-only, in-workspace envelope — a path outside the workspace root,\n * a shell command outside the auto-allowed set, a URL fetch — routes through\n * one `request()` so the policy has exactly one owner (the same \"one repair\n * owner\" shape as PlanRepair).\n *\n * Surfaces supply the human channel. VS Code answers with a modal; the web\n * server currently has no prompt UI, so it denies unless the scope was\n * pre-approved through config. Denial is always a visible, actionable tool\n * result — never a silent success.\n */\n\nexport type ApprovalKind = 'external_path' | 'shell_command' | 'url_fetch';\n\nexport interface ApprovalRequest {\n kind: ApprovalKind;\n /** The concrete thing being asked about: an absolute path, a command line, a URL. */\n subject: string;\n /**\n * What a grant covers. Approving remembers this, not `subject`, so reading a\n * second file from an already-approved directory does not prompt again.\n */\n scope: string;\n /** One-line context for the prompt. */\n detail?: string;\n}\n\nexport interface IApproval {\n request(req: ApprovalRequest): Promise<boolean>;\n}\n\n/** Denies everything. The safe default when a surface wires no approval channel. */\nexport const DENY_ALL: IApproval = {\n async request() { return false; },\n};\n","/**\n * Tiered classification for the planner's `bash` tool.\n *\n * The planner is a read-only researcher: it never edits files, and the runners\n * do the real work. But research legitimately means running things — querying a\n * cloud control plane (`az`, `gh`), reproducing a failure (`npm test`), or\n * shaping output (`jq`). The old allowlist refused all of that, so the model's\n * only escape was to guess.\n *\n * Three tiers replace the flat allowlist:\n *\n * auto read-only inspection — runs with no prompt (the historical list)\n * ask anything else that is not obviously destructive — one approval,\n * remembered for the rest of the session at `scope` granularity\n * refuse writes, privilege escalation, and anything that would smuggle\n * arbitrary code past this classifier — never runs, never prompts\n *\n * `refuse` is deliberately not promptable. A planner that can `rm` is a planner\n * that can silently break the workspace it was asked to reason about, and the\n * architecture already says mutation belongs to the runners.\n *\n * Classification walks every segment of the command line (pipes, `&&`, `;`, and\n * command substitution) rather than matching substrings against the raw string.\n * The old substring denylist both over-matched (`ls docs/removed` tripped `rm`)\n * and under-matched (`$(rm -rf /)` was invisible once chaining was allowed).\n *\n * The lexer is dialect-aware, because the interpreter that will actually run\n * the command decides what the tokens are, and getting that wrong is not a\n * cosmetic error here — it is the difference between classifying what runs and\n * classifying something else. See {@link Dialect}.\n */\n\nimport type { ShellDialect } from './researchShell';\n\nexport const AUTO_COMMANDS = [\n 'ls', 'tree', 'git', 'wc', 'du', 'df', 'file', 'head', 'tail', 'cat', 'sort', 'uniq',\n 'echo', 'printf', 'date', 'stat', 'basename', 'dirname', 'realpath', 'pwd',\n 'which', 'type', 'env', 'uname', 'whoami', 'cut', 'nl', 'rg', 'grep', 'find', 'jq', 'yq',\n];\n\nexport const GIT_READONLY_SUBCOMMANDS = [\n 'log', 'status', 'diff', 'show', 'ls-files', 'ls-remote', 'ls-tree', 'branch', 'tag',\n 'rev-parse', 'rev-list', 'describe', 'blame', 'grep', 'shortlog', 'whatchanged', 'cat-file',\n];\n\n/**\n * Never runs, with or without approval.\n *\n * The `cmd.exe` builtins at the end matter as much as the POSIX names above\n * them. `del`, `rd`, `move`, and friends mutate exactly what `rm` and `mv` do,\n * and on Windows they are what a model reaches for — so without them the whole\n * refusal tier was bypassable on that platform by writing the command the way\n * the platform spells it. Listed unconditionally rather than per-platform: a\n * POSIX box has no `del` to refuse, so the extra names cost nothing there.\n */\nexport const REFUSED_COMMANDS = [\n 'rm', 'rmdir', 'unlink', 'shred', 'truncate', 'dd', 'mkfs', 'fdisk', 'parted',\n 'mv', 'cp', 'install', 'ln', 'chmod', 'chown', 'chgrp', 'chattr',\n 'mount', 'umount', 'sudo', 'doas', 'su', 'passwd',\n 'kill', 'killall', 'pkill', 'shutdown', 'reboot', 'halt', 'poweroff',\n 'systemctl', 'service', 'crontab', 'tee', 'dput', 'mkdir', 'touch',\n // Windows: destructive cmd.exe builtins and their utility equivalents.\n 'del', 'erase', 'rd', 'md', 'move', 'copy', 'xcopy', 'robocopy', 'ren', 'rename',\n 'mklink', 'attrib', 'icacls', 'cacls', 'takeown', 'format', 'diskpart',\n 'taskkill', 'tskill', 'reg', 'regedit', 'sc', 'net', 'runas', 'schtasks',\n];\n\n/** Destructive or outward-facing subcommands of otherwise-permitted multiplexers. */\nconst REFUSED_SUBCOMMANDS: Record<string, string[]> = {\n git: ['push', 'reset', 'clean', 'checkout', 'switch', 'restore', 'rebase', 'merge', 'commit',\n 'am', 'apply', 'cherry-pick', 'revert', 'stash', 'gc', 'prune', 'filter-branch',\n 'update-ref', 'remote', 'config', 'init', 'clone', 'fetch', 'pull', 'submodule'],\n npm: ['publish', 'unpublish', 'deprecate', 'owner', 'access', 'token', 'login', 'logout'],\n yarn: ['publish', 'npm'],\n pnpm: ['publish'],\n docker: ['push', 'rm', 'rmi', 'kill', 'stop', 'prune', 'system'],\n kubectl: ['delete', 'apply', 'create', 'patch', 'replace', 'edit', 'drain', 'cordon', 'scale'],\n gh: ['release', 'secret', 'auth'],\n az: ['login', 'logout'],\n terraform: ['apply', 'destroy'],\n};\n\n/** Binaries that execute whatever they are handed — refused when given inline code or fed from a pipe. */\nconst INTERPRETERS = ['sh', 'bash', 'zsh', 'fish', 'dash', 'ksh', 'csh', 'tcsh', 'pwsh', 'powershell',\n 'python', 'python2', 'python3', 'node', 'deno', 'bun', 'ruby', 'perl', 'php', 'eval', 'exec', 'xargs',\n // Windows interpreters. `cmd /c \"…\"` is the platform's spelling of `sh -c`.\n 'cmd', 'wscript', 'cscript', 'mshta', 'rundll32', 'regsvr32'];\n\n/**\n * Flags that hand an interpreter code to run. Compared case-insensitively:\n * cmd.exe and PowerShell both accept their switches in any casing, so a\n * case-sensitive list refused `-Command` and waved `-command` through.\n */\nconst INLINE_CODE_FLAGS = ['-c', '-e', '--eval', '--command', '-Command', '--exec', '/c', '/k', '/r'];\n\nfunction isInlineCodeFlag(arg: string): boolean {\n const lower = arg.toLowerCase();\n return INLINE_CODE_FLAGS.some((f) => f.toLowerCase() === lower);\n}\n\n/** Multiplexers whose first non-flag argument is meaningful enough to scope a grant. */\nconst MULTIPLEXERS = ['git', 'npm', 'yarn', 'pnpm', 'npx', 'cargo', 'go', 'dotnet', 'docker', 'podman',\n 'kubectl', 'helm', 'az', 'aws', 'gcloud', 'gh', 'glab', 'terraform', 'make', 'mvn', 'gradle',\n 'composer', 'pip', 'pip3', 'poetry', 'uv', 'bundle', 'rake', 'swift', 'flutter', 'dart'];\n\n/**\n * What the interpreter that will run this command treats as syntax.\n *\n * `BaseFileSystem.execBashImpl` runs the command through `shell: true`, which\n * means `/bin/sh` on POSIX and `cmd.exe` on Windows — two different languages.\n * Lexing cmd.exe input with POSIX rules is not a near-miss, it inverts specific\n * answers: `\\` is an escape in sh and an ordinary path separator in cmd, so\n * `rg pattern C:\\repo\\src` tokenized to `C:reposrc`, which then failed\n * containment against the very workspace it named. And `'` is a quote in sh and\n * a literal character in cmd, so `echo it's & del x` hid the `del` inside what\n * the lexer believed was a quoted string.\n *\n * Only the four rules that actually diverge are modeled. Constructs cmd.exe\n * lacks (`$(…)`, backticks) are still recognized on Windows: over-splitting\n * costs a needless approval prompt, under-splitting costs the gate.\n */\nexport interface Dialect {\n /** The character that escapes the next one outside quotes. */\n escape: string;\n /**\n * Whether {@link escape} still escapes inside a double-quoted run.\n *\n * POSIX `\\` does; cmd.exe `^` does not. Getting this wrong is not cosmetic:\n * with `^` honoured inside quotes, `echo \"a^\"& del b` lexed as one `echo`\n * segment — the escape swallowed the closing quote, so the `&` looked quoted\n * and the `del` cmd.exe would actually run became an argument nobody\n * classified.\n */\n escapeInQuotes: boolean;\n /** Characters that open a quoted run. */\n quotes: string[];\n /** Matches a variable reference the interpreter will expand. */\n expansion: RegExp;\n /** Executable extensions stripped before a binary is matched against the tiers. */\n strippedExtensions: string[];\n}\n\nconst POSIX_DIALECT: Dialect = {\n escape: '\\\\',\n escapeInQuotes: true,\n quotes: [\"'\", '\"'],\n expansion: /^\\$[A-Za-z_{]/,\n strippedExtensions: [],\n};\n\nconst CMD_DIALECT: Dialect = {\n escape: '^',\n escapeInQuotes: false,\n quotes: ['\"'],\n // `%VAR%` and delayed-expansion `!VAR!`.\n expansion: /^[%!][A-Za-z_]/,\n // Without this, `del.exe` and `C:\\bin\\del.exe` both missed the refusal list.\n strippedExtensions: ['.exe', '.cmd', '.bat', '.com', '.ps1', '.msc'],\n};\n\nfunction dialectFor(dialect: ShellDialect | undefined): Dialect {\n const resolved = dialect ?? (process.platform === 'win32' ? 'cmd' : 'posix');\n return resolved === 'cmd' ? CMD_DIALECT : POSIX_DIALECT;\n}\n\n/**\n * Options threaded through classification.\n *\n * `dialect` is keyed to the interpreter rather than the OS on purpose: a Windows\n * host that has Git Bash runs the planner's commands in a POSIX shell (see\n * {@link resolveResearchShell}), and classifying those under cmd.exe rules\n * would be the same mismatch in the other direction. Callers pass the dialect of\n * the shell they are actually going to use; omitting it falls back to the host\n * default.\n */\nexport interface CommandPolicyOptions {\n dialect?: ShellDialect;\n}\n\nexport type CommandTier = 'auto' | 'ask' | 'refuse';\n\nexport interface CommandClassification {\n tier: CommandTier;\n /** What a grant covers, for `ask`. Derived from the non-auto segments only. */\n scope: string;\n /** Populated for `refuse`: why, in a sentence the model can act on. */\n reason?: string;\n}\n\ninterface Segment {\n binary: string;\n args: string[];\n /** True when this segment consumes another command's output (`… | seg`). */\n piped: boolean;\n /**\n * A token contains a `$var` the shell will expand. Tracked at lex time\n * because only the lexer knows a `$` inside single quotes is literal.\n */\n expandable: boolean;\n}\n\ninterface Lexed {\n segments: Segment[];\n /** An unquoted `>`/`>>` writes a file. */\n redirect: boolean;\n /** An unquoted `<(…)`/`>(…)` spawns a process this classifier never tokenizes. */\n processSubstitution: boolean;\n /** Lexing ran off the end inside a quote or a substitution — nothing here is trustworthy. */\n unbalanced: boolean;\n}\n\n/** Index of the `)` closing the `(` at `open`, or -1. */\nfunction matchParen(s: string, open: number): number {\n let depth = 0;\n for (let i = open; i < s.length; i++) {\n if (s[i] === '(') depth++;\n else if (s[i] === ')' && --depth === 0) return i;\n }\n return -1;\n}\n\n/**\n * Tokenize one command line the way a shell would: quotes and backslashes are\n * consumed, and only *unquoted* metacharacters are operators.\n *\n * This is the whole difference between the classifier seeing what will run and\n * seeing the raw string. Splitting on a bare `/[|;&]/` made `rg \"error|warn\"`\n * two segments (so the planner's commonest search asked for approval, scoped to\n * the nonsense binary `warn\"`), while leaving quotes on argument tokens hid\n * `cat \"/etc/passwd\"` from the path-confinement check entirely.\n *\n * Substitution bodies are lifted out into `nested` and classified as their own\n * command lines, so `$(rm -rf /)` cannot hide inside an `echo`.\n */\nfunction lex(command: string, nested: string[], dialect: Dialect): Lexed {\n const segments: Segment[] = [];\n let redirect = false;\n let processSubstitution = false;\n let unbalanced = false;\n\n let tokens: string[] = [];\n let expandable = false;\n let current = '';\n let started = false;\n let piped = false;\n let quote = '';\n\n const endToken = () => {\n if (started) tokens.push(current);\n current = '';\n started = false;\n };\n const endSegment = (nextPiped: boolean) => {\n endToken();\n if (tokens.length > 0) segments.push({ ...toSegment(tokens, piped, dialect), expandable });\n tokens = [];\n expandable = false;\n piped = nextPiped;\n };\n\n let i = 0;\n while (i < command.length) {\n const c = command[i];\n\n // A single-quoted run is literal end to end — no escapes, no expansion.\n // Only POSIX has one; `CMD_DIALECT.quotes` omits `'` so this never fires\n // there, and an apostrophe stays an ordinary character.\n if (quote === \"'\") {\n if (c === \"'\") { quote = ''; i++; continue; }\n current += c; started = true; i++; continue;\n }\n\n // `quote` is '' or '\"' here — the single-quote run returned above.\n if (c === dialect.escape && (quote === '' || dialect.escapeInQuotes)) {\n const next = command[i + 1];\n if (next !== undefined) { current += next; started = true; }\n i += 2; continue;\n }\n\n // Substitutions expand inside double quotes too, so these precede the\n // double-quote passthrough below.\n if (c === '$' && command[i + 1] === '(') {\n const close = matchParen(command, i + 1);\n if (close < 0) { unbalanced = true; break; }\n nested.push(command.slice(i + 2, close));\n started = true;\n i = close + 1; continue;\n }\n if (c === '`') {\n const close = command.indexOf('`', i + 1);\n if (close < 0) { unbalanced = true; break; }\n nested.push(command.slice(i + 1, close));\n started = true;\n i = close + 1; continue;\n }\n if (dialect.expansion.test(command.slice(i, i + 2))) {\n expandable = true;\n current += c; started = true; i++; continue;\n }\n\n if (quote === '\"') {\n if (c === '\"') { quote = ''; started = true; i++; continue; }\n current += c; started = true; i++; continue;\n }\n\n if (dialect.quotes.includes(c)) { quote = c; started = true; i++; continue; }\n\n if (c === '<' || c === '>') {\n if (command[i + 1] === '(') { processSubstitution = true; i += 2; continue; }\n if (c === '>') redirect = true;\n endToken();\n i += command[i + 1] === c ? 2 : 1;\n continue;\n }\n\n // Subshell grouping is not part of any token: `(rm -rf /)` must lex to `rm`.\n if (c === '(' || c === ')') { endToken(); i++; continue; }\n\n if (c === '|') {\n const double = command[i + 1] === '|';\n endSegment(!double);\n i += double ? 2 : 1;\n continue;\n }\n if (c === '&' || c === ';' || c === '\\n') {\n endSegment(false);\n i += command[i + 1] === c ? 2 : 1;\n continue;\n }\n\n if (/\\s/.test(c)) { endToken(); i++; continue; }\n\n current += c; started = true; i++;\n }\n\n if (quote !== '') unbalanced = true;\n endSegment(false);\n\n return { segments, redirect, processSubstitution, unbalanced };\n}\n\n/**\n * The name a segment's binary is matched against the tiers under.\n *\n * `path.basename` alone is not enough: Node's POSIX `path` does not split on\n * `\\`, so `C:\\Windows\\System32\\del.exe` came back whole and matched nothing in\n * `REFUSED_COMMANDS`. Both separators are stripped regardless of host, and the\n * dialect decides whether an executable extension comes off too.\n */\nfunction binaryName(token: string, dialect: Dialect): string {\n const base = token.split(/[/\\\\]/).pop() ?? '';\n // `dot > 0`, not `>= 0`: `lastIndexOf` returns -1 for a name with no dot, and\n // `slice(-1)` would then make the last character look like the extension.\n const dot = base.lastIndexOf('.');\n if (dot <= 0) return base;\n return dialect.strippedExtensions.includes(base.slice(dot).toLowerCase()) ? base.slice(0, dot) : base;\n}\n\nfunction toSegment(tokens: string[], piped: boolean, dialect: Dialect): Segment {\n const rest = [...tokens];\n // `FOO=bar cmd` — assignments precede the binary.\n while (rest.length > 0 && /^[A-Za-z_][A-Za-z0-9_]*=/.test(rest[0])) rest.shift();\n return { binary: rest.length > 0 ? binaryName(rest[0], dialect) : '', args: rest.slice(1), piped, expandable: false };\n}\n\n/** Lex a command line and every substitution body nested inside it. */\nfunction lexAll(command: string, dialect: Dialect): Lexed {\n const queue: string[] = [];\n const top = lex(command, queue, dialect);\n const all: Lexed = { ...top, segments: top.segments.filter((s) => s.binary) };\n\n // Bounded: a pathological `$($($(…)))` must not spin here.\n for (let depth = 0; depth < 32 && queue.length > 0; depth++) {\n const inner = lex(queue.shift()!, queue, dialect);\n all.segments.push(...inner.segments.filter((s) => s.binary));\n all.redirect ||= inner.redirect;\n all.processSubstitution ||= inner.processSubstitution;\n all.unbalanced ||= inner.unbalanced;\n }\n return all;\n}\n\n/**\n * Path-shaped arguments, in every spelling a host might use.\n *\n * The Windows forms are not cosmetic. `pathLikeArgs` feeds\n * `BaseFileSystem.authorizeCommandPaths`, so an argument this function fails to\n * recognize is one the workspace-confinement prompt never sees. With only the\n * POSIX forms, `cat C:\\Users\\me\\.ssh\\id_rsa` matched nothing and ran\n * unprompted — ADR-0008's escape gate silently absent on that platform rather\n * than merely weaker.\n */\nfunction looksLikePath(arg: string): boolean {\n if (arg.startsWith('--') && arg.includes('=')) return looksLikePath(arg.slice(arg.indexOf('=') + 1));\n return arg.startsWith('/')\n || arg.startsWith('~')\n || arg.startsWith('../')\n || arg === '..'\n || arg.startsWith('./')\n // Windows: drive-absolute (`C:\\x`, `C:/x`), drive-relative (`C:x`), UNC\n // (`\\\\server\\share`), and root-relative (`\\x`).\n || /^[A-Za-z]:/.test(arg)\n || arg.startsWith('\\\\')\n || arg.startsWith('..\\\\')\n || arg.startsWith('.\\\\');\n}\n\n/**\n * Every path-shaped argument across every segment (including inside `$(…)`),\n * for the workspace-confinement check `bash()` runs before an `auto`-tier\n * command reaches the shell. `auto` classification only ever looked at the\n * binary — `cat`, `find`, `rg` and friends are auto because *reading* is\n * read-only, but their arguments can still point anywhere on disk, which is\n * exactly the escape path confinement closes for `readFile`/`glob`/`grep`.\n */\nexport function pathLikeArgs(command: string, opts: CommandPolicyOptions = {}): string[] {\n const dialect = dialectFor(opts.dialect);\n return lexAll(command, dialect).segments.flatMap((seg) => seg.args.flatMap((a) => {\n // `--flag=value` is excluded by the leading-dash filter but its value can\n // still name an external path, so split it and check the value.\n if (a.startsWith('--') && a.includes('=')) {\n const v = a.slice(a.indexOf('=') + 1);\n return looksLikePath(v) ? [v] : [];\n }\n return (!a.startsWith('-') && looksLikePath(a)) ? [a] : [];\n }));\n}\n\nfunction scopeFor(seg: Segment): string {\n if (!MULTIPLEXERS.includes(seg.binary)) return seg.binary;\n const sub = seg.args.find((a) => !a.startsWith('-'));\n return sub ? `${seg.binary} ${sub}` : seg.binary;\n}\n\nfunction isAuto(seg: Segment): boolean {\n if (!AUTO_COMMANDS.includes(seg.binary)) return false;\n // `x=/etc/passwd; cat $x` gives `cat` the lone argument `$x`, which\n // `pathLikeArgs`/`looksLikePath` cannot see is a path at all — the shell\n // resolves it to whatever the variable holds. An auto-tier command whose\n // arguments are not fully visible at classification time is exactly the\n // confinement escape this file exists to close, so treat any variable\n // reference as disqualifying the fast path rather than trying to resolve it.\n if (seg.expandable) return false;\n if (seg.binary !== 'git') return true;\n const sub = seg.args.find((a) => !a.startsWith('-'));\n return sub !== undefined && GIT_READONLY_SUBCOMMANDS.includes(sub);\n}\n\nfunction refusalFor(seg: Segment): string | undefined {\n if (REFUSED_COMMANDS.includes(seg.binary)) {\n return `\"${seg.binary}\" modifies state. You are a read-only planner — describe the change as a task instead, and the runner executing the plan will make it.`;\n }\n // `eval`/`exec` exist only to run a string as a command — the whole point of\n // this classifier is to inspect those strings, so they are never promptable.\n if (seg.binary === 'eval' || seg.binary === 'exec') {\n return `\"${seg.binary}\" runs a string as a command, which this classifier cannot inspect. Use the read-only research tools, or describe it as a task.`;\n }\n const subs = REFUSED_SUBCOMMANDS[seg.binary];\n if (subs) {\n const sub = seg.args.find((a) => !a.startsWith('-'));\n if (sub && subs.includes(sub)) {\n return `\"${seg.binary} ${sub}\" changes state or reaches outward. You are a read-only planner — put it in the plan and let the runner do it.`;\n }\n }\n // `git branch`/`git tag` are read-only subcommands, but their delete/move\n // flag forms mutate refs. The readonly-subcommand allowlist only inspects\n // the first non-flag argument, so these have to be caught here.\n if (seg.binary === 'git') {\n const sub = seg.args.find((a) => !a.startsWith('-'));\n if (sub === 'branch' || sub === 'tag') {\n if (seg.args.some((a) => ['-D', '-d', '-m', '-M', '--delete', '--move'].includes(a))) {\n return `\"git ${sub}\" with a delete/move flag mutates refs. You are a read-only planner — describe the change as a task instead.`;\n }\n }\n }\n // `find` is auto because listing is read-only, but `-exec`/`-delete` make it\n // run an arbitrary inner command — the exact bypass this classifier exists\n // to close. Refuse rather than prompt: the inner command is unauditable.\n if (seg.binary === 'find') {\n const flag = seg.args.find((a) => ['-exec', '-execdir', '-ok', '-okdir', '-delete'].includes(a));\n if (flag) {\n return `find with \"${flag}\" runs an inner command this classifier cannot inspect. Use the read-only research tools on find's output, or describe the change as a task.`;\n }\n }\n // `sed -i`/`awk -i inplace` rewrite files in place — mutation, not research.\n if (seg.binary === 'sed' && seg.args.some((a) => a === '-i' || a === '--in-place' || /^-i./.test(a))) {\n return `\"sed -i\" edits files in place. You are a read-only planner — describe the change as a task instead.`;\n }\n if (seg.binary === 'awk' && seg.args.some((a) => a === 'inplace')) {\n return `\"awk -i inplace\" edits files in place. You are a read-only planner — describe the change as a task instead.`;\n }\n if (INTERPRETERS.includes(seg.binary)) {\n if (seg.piped) {\n return `Piping into \"${seg.binary}\" would run code this classifier cannot inspect. Run the producing command on its own and read its output.`;\n }\n if (seg.args.some(isInlineCodeFlag)) {\n return `Inline code via \"${seg.binary} ${seg.args.find(isInlineCodeFlag)}\" is not available to the planner. Use the read-only research tools, or describe it as a task.`;\n }\n }\n return undefined;\n}\n\n/**\n * Classify one command line. Output redirection is refused outright: a planner\n * that writes files has stopped being a planner.\n */\nexport function classifyCommand(command: string, opts: CommandPolicyOptions = {}): CommandClassification {\n const trimmed = command.trim();\n if (!trimmed) return { tier: 'refuse', scope: '', reason: 'Empty command.' };\n\n const dialect = dialectFor(opts.dialect);\n const { segments, redirect, processSubstitution, unbalanced } = lexAll(trimmed, dialect);\n\n if (unbalanced) {\n return {\n tier: 'refuse',\n scope: '',\n reason: 'Unterminated quote or command substitution — this classifier cannot tell what would actually run. Rewrite the command with balanced quotes.',\n };\n }\n\n // Process substitution `<(…)`/`>(…)` spawns a process this classifier never\n // tokenizes — `cat <(rm -rf /)` would otherwise run `rm` with no prompt.\n if (processSubstitution) {\n return {\n tier: 'refuse',\n scope: '',\n reason: 'Process substitution runs another command this classifier cannot inspect. Run the command on its own and read its output, or describe it as a task.',\n };\n }\n\n if (redirect) {\n return {\n tier: 'refuse',\n scope: '',\n reason: 'Output redirection writes files. You are a read-only planner — read the output instead, or describe the write as a task.',\n };\n }\n\n if (segments.length === 0) return { tier: 'refuse', scope: '', reason: 'No command found.' };\n\n for (const seg of segments) {\n const reason = refusalFor(seg);\n if (reason) return { tier: 'refuse', scope: '', reason };\n }\n\n const nonAuto = segments.filter((s) => !isAuto(s));\n if (nonAuto.length === 0) return { tier: 'auto', scope: '' };\n\n // A grant covers only the parts that actually needed one, so\n // `az group list | head` is remembered as `az group`, not the whole line.\n const scope = [...new Set(nonAuto.map(scopeFor))].sort().join(' + ');\n return { tier: 'ask', scope };\n}\n","import * as fsSync from 'fs';\nimport * as path from 'path';\n\n/**\n * Which interpreter runs the planner's `bash` tool, and in which language.\n *\n * `AUTO_COMMANDS` — the read-only tier that runs with no prompt — is `ls`, `cat`,\n * `wc`, `head`, `tail`, `du`, `df`, `file`, `sort`, `uniq`, `basename`, `find`,\n * `grep`. That set is POSIX, and passing it to `shell: true` on Windows means\n * cmd.exe, where most of those names do not exist and `find` is an unrelated\n * program that returns plausible wrong output instead of an error. The planner's\n * whole research surface degraded to guessing, quietly.\n *\n * Rather than write a Windows dialect of every research command — a second\n * behavior to keep in step forever — this finds a POSIX shell to run the\n * existing ones in. Git for Windows ships a full one, and git is already a\n * prerequisite for everything Ordewell does, so in practice it is there. Failing\n * that, cmd.exe is used and the classifier is told so, because the one thing\n * that must never happen is classifying a command in one language and running it\n * in another: `commandPolicy` reads {@link ResearchShell.dialect} for exactly\n * that reason.\n *\n * POSIX resolves to `{ file: null }`, meaning \"use `shell: true`\" — byte for\n * byte what the adapters did before this module existed.\n *\n * Windows paths are built with `path.win32` explicitly, not the host-flavoured\n * `path`, so the probe is the same on a Windows host as it is under a Linux\n * test runner.\n */\n\nexport type ShellDialect = 'posix' | 'cmd';\n\nexport interface ResearchShell {\n /**\n * Executable that takes a command string, or null to use the host default\n * via `shell: true`.\n */\n file: string | null;\n /** Arguments preceding the command string. */\n args: string[];\n /** The language the command string will be interpreted in. */\n dialect: ShellDialect;\n /**\n * Directory holding this shell's POSIX utilities, when it brings its own.\n * Prepended to PATH for the search subprocesses (`grep`, `tree`) that\n * `execFile` starts without a shell, so they resolve too.\n */\n utilsDir: string | null;\n}\n\nconst POSIX_SHELL: ResearchShell = { file: null, args: [], dialect: 'posix', utilsDir: null };\nconst CMD_SHELL: ResearchShell = { file: null, args: [], dialect: 'cmd', utilsDir: null };\n\nexport interface ResearchShellDeps {\n platform?: NodeJS.Platform;\n exists?: (candidate: string) => boolean;\n env?: NodeJS.ProcessEnv;\n}\n\nfunction defaultExists(candidate: string): boolean {\n try {\n return fsSync.statSync(candidate).isFile();\n } catch {\n return false;\n }\n}\n\n/**\n * Where Git for Windows puts its shell, per install flavour. `bin/bash.exe` is\n * the wrapper users get on PATH; `usr/bin/bash.exe` is the same shell in the\n * MSYS tree, listed because a minimal/portable install may omit the former.\n *\n * `C:\\Windows\\System32\\bash.exe` is deliberately absent and must stay absent:\n * that is the WSL launcher. It runs commands inside a Linux VM with its own\n * filesystem view (`/mnt/c/...`), so a workspace path means something different\n * there — which would put every command outside the root that path confinement\n * is checking against, and every relative path against the wrong tree.\n */\nfunction gitBashRoots(env: NodeJS.ProcessEnv): string[] {\n const roots = [\n env.ProgramFiles && path.win32.join(env.ProgramFiles, 'Git'),\n env['ProgramFiles(x86)'] && path.win32.join(env['ProgramFiles(x86)'], 'Git'),\n env.LOCALAPPDATA && path.win32.join(env.LOCALAPPDATA, 'Programs', 'Git'),\n 'C:\\\\Program Files\\\\Git',\n 'C:\\\\Program Files (x86)\\\\Git',\n ].filter((r): r is string => !!r);\n return [...new Set(roots)];\n}\n\nlet cached: ResearchShell | null = null;\n\n/**\n * The shell the planner's `bash` tool should use on this host. Resolved once per\n * process — the answer cannot change while Ordewell runs, and the probe costs a\n * handful of `stat` calls.\n */\nexport function resolveResearchShell(deps: ResearchShellDeps = {}): ResearchShell {\n if (cached && !deps.platform && !deps.exists && !deps.env) return cached;\n\n const platform = deps.platform ?? process.platform;\n if (platform !== 'win32') {\n if (!deps.platform && !deps.exists && !deps.env) cached = POSIX_SHELL;\n return POSIX_SHELL;\n }\n\n const exists = deps.exists ?? defaultExists;\n const env = deps.env ?? process.env;\n\n for (const root of gitBashRoots(env)) {\n for (const rel of [['bin', 'bash.exe'], ['usr', 'bin', 'bash.exe']]) {\n const file = path.win32.join(root, ...rel);\n if (!exists(file)) continue;\n const utilsDir = path.win32.join(root, 'usr', 'bin');\n const resolved: ResearchShell = {\n file,\n // `-c`, not `-lc`: a login shell sources the user's profile, which can\n // change directory out from under a command whose cwd is the workspace.\n args: ['-c'],\n dialect: 'posix',\n utilsDir: exists(path.win32.join(utilsDir, 'grep.exe')) ? utilsDir : null,\n };\n if (!deps.platform && !deps.exists && !deps.env) cached = resolved;\n return resolved;\n }\n }\n\n if (!deps.platform && !deps.exists && !deps.env) cached = CMD_SHELL;\n return CMD_SHELL;\n}\n\n/** Test seam: drop the per-process cache so the next call re-probes. */\nexport function clearResearchShellCache(): void {\n cached = null;\n}\n\n/**\n * PATH for the search subprocesses the adapters start without a shell, with the\n * research shell's own utilities in front. Without this, `grep` — the fallback\n * when ripgrep is absent — is unresolvable on a Windows box even when a\n * perfectly good `grep.exe` sits in the Git tree beside the shell.\n */\nexport function researchToolsPath(shell: ResearchShell, basePath: string | undefined): string {\n // `utilsDir` is only ever set on the Windows branch, so the delimiter is `;`.\n if (!shell.utilsDir) return basePath ?? '';\n const segments = [shell.utilsDir, ...(basePath ?? '').split(path.win32.delimiter)].filter(Boolean);\n return [...new Set(segments)].join(path.win32.delimiter);\n}\n\n/**\n * A message explaining a degraded research surface, or null when there is\n * nothing to explain. Surfaced by the adapters on the first refused command so\n * the limitation is visible rather than inferred from bad answers.\n */\nexport function researchShellWarning(shell: ResearchShell): string | null {\n if (shell.dialect !== 'cmd') return null;\n return 'No POSIX shell was found on this machine, so research commands run through cmd.exe, '\n + 'where most read-only tools (ls, cat, wc, head, grep, find) do not exist. '\n + 'Installing Git for Windows provides one and restores the full research toolset.';\n}\n","import * as os from 'os';\nimport * as path from 'path';\n\n/**\n * Workspace containment, in one place. Both the filesystem policy layer\n * (which may ask the user to approve an escape) and the research-subagent\n * wrapper (which may not, because nothing can prompt on its behalf) need the\n * same answer to \"is this path inside the workspace\", so neither re-derives it.\n *\n * Symlinks are resolved lexically, not on disk: a symlink inside the workspace\n * pointing outward still reads as inside. Closing that would mean a `realpath`\n * syscall on every path check, and the threat model here is an LLM wandering,\n * not an adversary planting links in a repo the user already trusts enough to\n * point Ordewell at.\n */\nexport interface ResolvedPath {\n abs: string;\n inside: boolean;\n}\n\n/**\n * `~` is expanded here because the *shell* will expand it later. Left alone,\n * `path.resolve(root, '~/.ssh/id_rsa')` yields `<root>/~/.ssh/id_rsa`, which\n * reads as inside the workspace — so `cat ~/.ssh/id_rsa` passed confinement\n * unprompted and then read the real file once the shell got hold of it.\n */\nfunction expandHome(target: string): string {\n if (!target.startsWith('~')) return target;\n const home = os.homedir();\n if (target === '~' || target.startsWith('~/')) return path.join(home, target.slice(1));\n // `~otheruser/…` resolved as a sibling of this user's home. Wrong on exotic\n // layouts, but it reliably lands outside the workspace, so the access\n // prompts rather than silently passing.\n return path.join(path.dirname(home), target.slice(1));\n}\n\nexport function resolveWithin(root: string, target: string): ResolvedPath {\n const abs = path.resolve(root, expandHome(target));\n const rel = path.relative(root, abs);\n return { abs, inside: rel === '' || (!rel.startsWith('..') && !path.isAbsolute(rel)) };\n}\n\n/** The directory a grant covers for `target` — its parent for files, itself for directories. */\nexport function grantScopeFor(abs: string, kind: 'file' | 'directory'): string {\n if (kind === 'directory') return path.join(abs, '*');\n const parent = path.dirname(abs);\n // A path immediately under the filesystem root (e.g. `/etc`) has the root as\n // its parent; scoping to `/*` would approve every top-level directory, so\n // scope to the directory itself instead.\n if (parent === path.parse(abs).root) return path.join(abs, '*');\n return path.join(parent, '*');\n}\n","/**\n * Definition-shaped search patterns for the `find_symbol` tool.\n *\n * Plain `grep` is bad at the question the planner actually asks. Searching for\n * `VerdictEngine` returns every import, call site, comment and string alongside\n * the one line that defines it, and with a hard result cap the definition is\n * often not even in the returned page. `find_symbol` spends the budget on\n * declarations first and reports references as a count plus a sample.\n *\n * This is deliberately regex over a real parser. An LSP-grade answer would mean\n * shipping per-language servers and waiting for them to index — the wrong trade\n * for the half of the architecture whose whole point is being cheap and fast.\n * The planner needs to scope tasks (\"defined here, used across ~14 files in 3\n * packages\"), not to prove rename-safety; that is the runner's job, and runners\n * have their own tools.\n *\n * Patterns target the Rust regex syntax ripgrep uses: non-capturing groups and\n * `\\b` are available, lookaround and backreferences are not.\n */\n\nexport interface SymbolLanguage {\n id: string;\n extensions: string[];\n /** Keywords that introduce a declaration in `kw Name` position. */\n keywords: string[];\n}\n\nexport const SYMBOL_LANGUAGES: SymbolLanguage[] = [\n {\n id: 'typescript',\n extensions: ['.ts', '.tsx', '.mts', '.cts', '.js', '.jsx', '.mjs', '.cjs'],\n keywords: ['function', 'class', 'interface', 'type', 'enum', 'const', 'let', 'var', 'namespace', 'module'],\n },\n { id: 'python', extensions: ['.py', '.pyi'], keywords: ['def', 'class'] },\n { id: 'go', extensions: ['.go'], keywords: ['func', 'type', 'var', 'const', 'package'] },\n {\n id: 'rust',\n extensions: ['.rs'],\n keywords: ['fn', 'struct', 'enum', 'trait', 'type', 'const', 'static', 'mod', 'impl', 'union', 'macro_rules!'],\n },\n {\n id: 'jvm',\n extensions: ['.java', '.kt', '.kts', '.scala', '.groovy'],\n keywords: ['class', 'interface', 'enum', 'record', 'object', 'trait', 'val', 'var', 'fun', 'def'],\n },\n {\n id: 'csharp',\n extensions: ['.cs', '.fs', '.fsi'],\n keywords: ['class', 'interface', 'enum', 'struct', 'record', 'namespace', 'delegate', 'let', 'type'],\n },\n {\n id: 'c',\n extensions: ['.c', '.h', '.cc', '.cpp', '.cxx', '.hpp', '.hh', '.hxx', '.m', '.mm'],\n keywords: ['struct', 'class', 'enum', 'union', 'typedef', 'namespace', 'define'],\n },\n { id: 'ruby', extensions: ['.rb', '.rake', '.gemspec'], keywords: ['def', 'class', 'module'] },\n { id: 'php', extensions: ['.php'], keywords: ['function', 'class', 'interface', 'trait', 'enum', 'const'] },\n {\n id: 'swift',\n extensions: ['.swift'],\n keywords: ['func', 'class', 'struct', 'enum', 'protocol', 'extension', 'var', 'let', 'typealias'],\n },\n { id: 'elixir', extensions: ['.ex', '.exs'], keywords: ['def', 'defp', 'defmodule', 'defstruct', 'defmacro'] },\n { id: 'shell', extensions: ['.sh', '.bash', '.zsh'], keywords: ['function'] },\n { id: 'lua', extensions: ['.lua'], keywords: ['function', 'local'] },\n { id: 'dart', extensions: ['.dart'], keywords: ['class', 'enum', 'mixin', 'typedef', 'extension', 'var', 'final'] },\n];\n\n/** Escape a symbol so it is matched literally inside a generated pattern. */\nexport function escapeRegex(literal: string): string {\n return literal.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nexport function languageForId(id: string): SymbolLanguage | undefined {\n const wanted = id.trim().toLowerCase();\n return SYMBOL_LANGUAGES.find((l) => l.id === wanted)\n ?? SYMBOL_LANGUAGES.find((l) => l.extensions.includes(wanted.startsWith('.') ? wanted : `.${wanted}`));\n}\n\n/** The `--glob` filter that narrows a search to one language's files. */\nexport function includeGlobFor(language: SymbolLanguage): string {\n return language.extensions.length === 1\n ? `*${language.extensions[0]}`\n : `*{${language.extensions.map((e) => e.slice(1)).join(',')}}`;\n}\n\nfunction allKeywords(): string[] {\n return [...new Set(SYMBOL_LANGUAGES.flatMap((l) => l.keywords))];\n}\n\n/**\n * Build the definition pattern for `symbol`. Three shapes cover essentially\n * every mainstream language:\n *\n * 1. `keyword Name` — declarations across all of them\n * 2. `Name = function|(` — assigned function expressions and arrows\n * 3. `… Name(args) {` — C/Java/Go-style bodies with a return type\n *\n * Passing a `language` narrows shape 1 to that language's keywords, which cuts\n * cross-language noise in polyglot repos.\n */\nexport function definitionPattern(symbol: string, language?: SymbolLanguage): string {\n const name = escapeRegex(symbol);\n const keywords = (language?.keywords ?? allKeywords()).map(escapeRegex).join('|');\n\n const declaration = `(?:^|[\\\\s(,;])(?:${keywords})\\\\s+${name}\\\\b`;\n const assignment = `\\\\b${name}\\\\s*[:=]\\\\s*(?:async\\\\s+)?(?:function\\\\b|\\\\()`;\n const body = `^[\\\\t ]*(?:[\\\\w<>\\\\[\\\\]*&:.~]+[\\\\t ]+)*${name}[\\\\t ]*\\\\([^;{]*\\\\)[\\\\t ]*(?:const[\\\\t ]*)?\\\\{`;\n\n return `${declaration}|${assignment}|${body}`;\n}\n\n/** Every mention of the symbol as a whole word — the reference side of the report. */\nexport function referencePattern(symbol: string): string {\n return `\\\\b${escapeRegex(symbol)}\\\\b`;\n}\n","import {\n IFileSystem,\n ReadFileOpts,\n GrepOptions,\n GlobOptions,\n FindSymbolOptions,\n ToolOutcome,\n GREP_DEFAULT_HEAD_LIMIT,\n} from '../interfaces/IFileSystem';\nimport { IApproval, DENY_ALL } from '../interfaces/IApproval';\nimport { classifyCommand, pathLikeArgs } from './commandPolicy';\nimport { resolveResearchShell, researchShellWarning, type ResearchShell } from './researchShell';\nimport { resolveWithin, grantScopeFor } from './pathScope';\nimport { definitionPattern, referencePattern, languageForId, includeGlobFor } from './symbolPatterns';\n\nexport { AUTO_COMMANDS, GIT_READONLY_SUBCOMMANDS, REFUSED_COMMANDS, classifyCommand, pathLikeArgs } from './commandPolicy';\n\n/**\n * The policy half of the planner's filesystem: path confinement, the tiered\n * `bash` gate, and the definition-first symbol lookup. Adapters supply only the\n * mechanics (`*Impl`), so the rules live in one place across the web server and\n * the VS Code extension rather than being re-derived per surface.\n *\n * Every public method resolves and authorizes before delegating, and every\n * `*Impl` therefore receives an absolute, already-approved path. Previously\n * each adapter did its own resolution, and `path.isAbsolute(p) ? p : …` meant\n * an absolute path walked straight out of the workspace with no prompt and no\n * record.\n */\nexport abstract class BaseFileSystem implements IFileSystem {\n private approval: IApproval = DENY_ALL;\n\n /**\n * The interpreter `execBashImpl` will hand the command to. Owned here rather\n * than per-adapter because {@link classifyCommand} has to be told the same\n * answer: a command lexed under POSIX rules and then run by cmd.exe is a\n * command this class did not actually classify.\n */\n protected readonly researchShell: ResearchShell = resolveResearchShell();\n\n /** Surfaces inject the human channel here; without it, external access is denied. */\n setApproval(approval: IApproval): void {\n this.approval = approval;\n }\n\n abstract getWorkspaceRoot(): string;\n\n protected abstract readFileImpl(absPath: string, opts?: ReadFileOpts): Promise<ToolOutcome>;\n protected abstract globImpl(pattern: string, absRoot: string, headLimit: number): Promise<ToolOutcome>;\n protected abstract grepImpl(pattern: string, absRoot: string, opts: GrepOptions): Promise<ToolOutcome>;\n protected abstract listDirImpl(absPath: string, depth: number): Promise<ToolOutcome>;\n protected abstract execBashImpl(command: string): Promise<ToolOutcome>;\n\n /**\n * Resolve `p` and confirm the planner may touch it. In-workspace paths pass\n * silently; anything else needs one approval, remembered per containing\n * directory so a second file in the same place does not prompt again.\n */\n protected async authorizePath(\n p: string,\n kind: 'file' | 'directory' = 'file',\n ): Promise<{ ok: true; abs: string } | { ok: false; outcome: ToolOutcome }> {\n const root = this.getWorkspaceRoot();\n const { abs, inside } = resolveWithin(root, p);\n if (inside) return { ok: true, abs };\n\n const granted = await this.approval.request({\n kind: 'external_path',\n subject: abs,\n scope: grantScopeFor(abs, kind),\n detail: `Planner research wants to read ${abs}, outside the workspace (${root}).`,\n });\n if (granted) return { ok: true, abs };\n\n return {\n ok: false,\n outcome: {\n success: false,\n output: `Access denied: \"${abs}\" is outside the workspace root (${root}) and was not approved. Keep research inside the workspace, or ask the user to approve this location.`,\n truncated: false,\n },\n };\n }\n\n async readFile(p: string, opts?: ReadFileOpts): Promise<ToolOutcome> {\n const auth = await this.authorizePath(p, 'file');\n return auth.ok ? this.readFileImpl(auth.abs, opts) : auth.outcome;\n }\n\n async readFiles(paths: string[]): Promise<ToolOutcome> {\n const results: string[] = [];\n let truncated = false;\n for (const p of paths) {\n const r = await this.readFile(p);\n // Denials are reported inline: silently dropping them would let the model\n // believe a file was empty rather than out of bounds.\n if (r.success) {\n results.push(`--- ${p} ---\\n${r.output}`);\n if (r.truncated) truncated = true;\n } else if (r.output) {\n results.push(`--- ${p} ---\\n[not read] ${r.output}`);\n }\n }\n if (results.length === 0) return { success: false, output: 'No files read.', truncated: false };\n return { success: true, output: results.join('\\n\\n'), truncated };\n }\n\n async glob(pattern: string, opts?: GlobOptions): Promise<ToolOutcome> {\n const auth = await this.authorizePath(opts?.path ?? '.', 'directory');\n if (!auth.ok) return auth.outcome;\n return this.globImpl(pattern, auth.abs, opts?.headLimit ?? 200);\n }\n\n async grep(pattern: string, opts?: GrepOptions): Promise<ToolOutcome> {\n const auth = await this.authorizePath(opts?.path ?? '.', 'directory');\n if (!auth.ok) return auth.outcome;\n return this.grepImpl(pattern, auth.abs, {\n ...opts,\n headLimit: opts?.headLimit ?? GREP_DEFAULT_HEAD_LIMIT,\n outputMode: opts?.outputMode ?? 'content',\n });\n }\n\n async listDir(p: string, depth?: number): Promise<ToolOutcome> {\n const auth = await this.authorizePath(p, 'directory');\n return auth.ok ? this.listDirImpl(auth.abs, depth ?? 1) : auth.outcome;\n }\n\n /**\n * Definitions first, then a reference tally. Two bounded searches beat one\n * unbounded `grep` because the 100-row budget gets spent on the rows that\n * answer the question.\n */\n async findSymbol(symbol: string, opts?: FindSymbolOptions): Promise<ToolOutcome> {\n const name = symbol.trim();\n if (!name) {\n return { success: false, output: 'find_symbol requires a non-empty \"symbol\".', truncated: false };\n }\n\n const auth = await this.authorizePath(opts?.path ?? '.', 'directory');\n if (!auth.ok) return auth.outcome;\n\n const language = opts?.language ? languageForId(opts.language) : undefined;\n if (opts?.language && !language) {\n return {\n success: false,\n output: `Unknown language \"${opts.language}\". Omit it to search every language, or pass a file extension such as \".go\".`,\n truncated: false,\n };\n }\n const include = language ? includeGlobFor(language) : undefined;\n\n const [defs, refs] = await Promise.all([\n this.grepImpl(definitionPattern(name, language), auth.abs, { include, outputMode: 'content', headLimit: 40 }),\n this.grepImpl(referencePattern(name), auth.abs, { include, outputMode: 'count', headLimit: 40 }),\n ]);\n\n const sections: string[] = [];\n const foundDefs = defs.success && defs.output.trim() && !/^No matches/i.test(defs.output.trim());\n sections.push(foundDefs\n ? `=== Definitions of \"${name}\" ===\\n${defs.output.trim()}`\n : `=== Definitions of \"${name}\" ===\\nNone matched the definition patterns. The symbol may be generated, re-exported, or defined in a language find_symbol does not cover — fall back to grep.`);\n\n if (refs.success && refs.output.trim() && !/^No matches/i.test(refs.output.trim())) {\n sections.push(`=== References by file (match count) ===\\n${refs.output.trim()}`);\n }\n\n return {\n success: true,\n output: sections.join('\\n\\n'),\n truncated: defs.truncated || refs.truncated,\n };\n }\n\n /**\n * Path confinement for `bash`: an `auto`-tier binary (`cat`, `find`, `rg`, …)\n * is only auto because *reading* is read-only — its arguments can still\n * name a path outside the workspace, which is the exact escape confinement\n * closes for `readFile`/`glob`/`grep`. Each escaping path needs its own\n * approval (scoped to its containing directory); approving one does not\n * approve another, so a single command touching two external dirs prompts\n * once per distinct scope rather than carrying the first grant to the rest.\n */\n private async authorizeCommandPaths(command: string): Promise<ToolOutcome | null> {\n const root = this.getWorkspaceRoot();\n const escaping = pathLikeArgs(command, { dialect: this.researchShell.dialect })\n .filter((p) => !resolveWithin(root, p).inside);\n if (escaping.length === 0) return null;\n\n for (const p of escaping) {\n const abs = resolveWithin(root, p).abs;\n const granted = await this.approval.request({\n kind: 'external_path',\n subject: abs,\n scope: grantScopeFor(abs, 'file'),\n detail: `Planner research wants to run \"${command}\", which touches ${abs}, outside the workspace (${root}).`,\n });\n if (!granted) {\n return {\n success: false,\n output: `Access denied: \"${command}\" touches ${abs}, outside the workspace root (${root}), and was not approved. Keep research inside the workspace, or ask the user to approve this location.`,\n truncated: false,\n };\n }\n }\n return null;\n }\n\n /**\n * Three tiers (see `commandPolicy.ts`): read-only inspection runs silently,\n * anything else asks once and is remembered, and writes are refused outright\n * because a planner that mutates the workspace has stopped being a planner.\n */\n async bash(command: string): Promise<ToolOutcome> {\n const { tier, scope, reason } = classifyCommand(command, { dialect: this.researchShell.dialect });\n\n if (tier === 'refuse') {\n return { success: false, output: `Command refused: ${reason}`, truncated: false };\n }\n\n const pathDenial = await this.authorizeCommandPaths(command);\n if (pathDenial) return pathDenial;\n\n if (tier === 'ask') {\n const granted = await this.approval.request({\n kind: 'shell_command',\n subject: command,\n scope,\n detail: `Planner research wants to run: ${command}`,\n });\n if (!granted) {\n return {\n success: false,\n output: `Command not approved: ${command}\\nIt is outside the auto-allowed read-only set (${scope}). Continue with the read-only research tools, or ask the user to approve it.`,\n truncated: false,\n };\n }\n }\n\n const outcome = await this.execBashImpl(command);\n if (outcome.success) return outcome;\n\n // A command that failed under cmd.exe most likely failed because the tool\n // does not exist there. Saying so turns \"exited 1\" into something the model\n // can act on — and, per the fail-visibly contract, keeps a degraded research\n // surface from reading as a repository that simply had no answer.\n const warning = researchShellWarning(this.researchShell);\n return warning ? { ...outcome, output: `${outcome.output}\\n\\n[${warning}]` } : outcome;\n }\n}\n","import type { IApproval, ApprovalRequest } from '../interfaces/IApproval';\n\n/**\n * Decides whether one out-of-envelope capability may run, and remembers the\n * answer for the rest of the session.\n *\n * Grants are keyed on {@link ApprovalRequest.scope}, never on the concrete\n * subject: approving a read of `/tmp/foo/a.log` grants `/tmp/foo/*`, and\n * approving `az group list` grants `az group`. Without that, a planner doing\n * real research would prompt on every single call and the feature would be\n * unusable.\n *\n * `mode` is the policy floor:\n * ask consult the human channel; no channel means deny (headless, web)\n * allow grant everything the tier system did not already refuse\n * deny grant nothing beyond `preApproved`\n *\n * Note the ordering: `preApproved` is honored under every mode including\n * `deny`, because it is an explicit operator decision rather than a default.\n */\nexport type ApprovalMode = 'ask' | 'allow' | 'deny';\n\nexport interface ApprovalPolicyOptions {\n mode?: ApprovalMode;\n /** Scopes granted up front from config. A trailing `*` matches by prefix. */\n preApproved?: string[];\n /** The human channel. Absent means there is nobody to ask. */\n ask?: (req: ApprovalRequest) => Promise<boolean>;\n /** Called whenever a decision is reached, for surfacing in a UI or a log. */\n onDecision?: (req: ApprovalRequest, granted: boolean, source: ApprovalSource) => void;\n}\n\nexport type ApprovalSource = 'pre-approved' | 'remembered' | 'mode' | 'asked' | 'no-channel';\n\nfunction scopeMatches(pattern: string, scope: string): boolean {\n if (pattern === scope) return true;\n if (pattern.endsWith('*')) return scope.startsWith(pattern.slice(0, -1));\n return false;\n}\n\nexport class ApprovalPolicy implements IApproval {\n private readonly mode: ApprovalMode;\n private readonly preApproved: string[];\n private readonly asker?: (req: ApprovalRequest) => Promise<boolean>;\n private readonly onDecision?: ApprovalPolicyOptions['onDecision'];\n\n private readonly granted = new Set<string>();\n private readonly refused = new Set<string>();\n /** One in-flight ask per scope: a parallel tool round must not prompt twice for the same thing. */\n private readonly inFlight = new Map<string, Promise<boolean>>();\n // Bumped on reset so an in-flight ask whose promise settles AFTER reset\n // cannot re-populate granted/refused — the continuation checks the\n // generation it was started under and bails if reset has intervened.\n private generation = 0;\n\n constructor(opts: ApprovalPolicyOptions = {}) {\n this.mode = opts.mode ?? 'ask';\n this.preApproved = opts.preApproved ?? [];\n this.asker = opts.ask;\n this.onDecision = opts.onDecision;\n }\n\n async request(req: ApprovalRequest): Promise<boolean> {\n const decide = (granted: boolean, source: ApprovalSource) => {\n this.onDecision?.(req, granted, source);\n return granted;\n };\n\n if (this.preApproved.some((p) => scopeMatches(p, req.scope))) return decide(true, 'pre-approved');\n if (this.granted.has(req.scope)) return decide(true, 'remembered');\n if (this.refused.has(req.scope)) return decide(false, 'remembered');\n\n if (this.mode === 'allow') { this.granted.add(req.scope); return decide(true, 'mode'); }\n if (this.mode === 'deny') { this.refused.add(req.scope); return decide(false, 'mode'); }\n if (!this.asker) return decide(false, 'no-channel');\n\n const existing = this.inFlight.get(req.scope);\n if (existing) return decide(await existing, 'asked');\n\n const gen = this.generation;\n const pending = this.asker(req)\n .catch(() => false)\n .finally(() => { if (this.generation === gen) this.inFlight.delete(req.scope); });\n this.inFlight.set(req.scope, pending);\n\n const answer = await pending;\n // A denial is remembered too, so a model that retries the same blocked\n // lookup burns one tool round instead of re-prompting the user each time.\n if (this.generation === gen) (answer ? this.granted : this.refused).add(req.scope);\n return decide(answer, 'asked');\n }\n\n /** Scopes the user has granted this session — for display and for persistence. */\n grantedScopes(): string[] { return [...this.granted]; }\n\n /** Drop every session-scoped decision. Called on session reset. */\n reset(): void {\n this.generation++;\n this.granted.clear();\n this.refused.clear();\n this.inFlight.clear();\n }\n}\n","import type { ApprovalRequest } from '../interfaces/IApproval';\n\n/**\n * The bridge between \"core needs an answer\" and \"a human somewhere is looking\n * at a UI\". Core cannot prompt: the human may be at a browser, a TUI, a CLI\n * stream, or a VS Code webview, and on the web server they are on the far end\n * of a socket. So the Session parks a promise here, announces the request\n * through the normal broadcast seam, and every surface answers through the\n * same `resolve(id, granted)` call.\n *\n * Timeouts are load-bearing rather than defensive: a planner turn that blocks\n * forever on an unanswered prompt would hang the whole research loop with no\n * visible cause. On expiry the request resolves to denied and the model gets a\n * normal, actionable tool result.\n */\n\nexport interface PendingApproval {\n id: string;\n request: ApprovalRequest;\n createdAt: string;\n}\n\nexport interface PendingApprovalsOptions {\n /** Denies and resolves after this long with no answer. Default 5 minutes. */\n timeoutMs?: number;\n /** Announce a new request to the surfaces. */\n onRequest?: (pending: PendingApproval) => void;\n /** Announce that a request is no longer actionable (answered or expired). */\n onSettled?: (id: string, granted: boolean) => void;\n}\n\nconst DEFAULT_TIMEOUT_MS = 5 * 60_000;\n\nlet counter = 0;\n\nexport class PendingApprovals {\n private readonly entries = new Map<string, {\n pending: PendingApproval;\n settle: (granted: boolean) => void;\n timer: ReturnType<typeof setTimeout>;\n }>();\n\n constructor(private readonly opts: PendingApprovalsOptions = {}) {}\n\n /** Park a request and return the promise the approval policy awaits. */\n ask(request: ApprovalRequest): Promise<boolean> {\n const id = `ap-${Date.now()}-${counter++}`;\n const pending: PendingApproval = { id, request, createdAt: new Date().toISOString() };\n\n return new Promise<boolean>((resolve) => {\n const settle = (granted: boolean) => {\n const entry = this.entries.get(id);\n if (!entry) return;\n clearTimeout(entry.timer);\n this.entries.delete(id);\n this.opts.onSettled?.(id, granted);\n resolve(granted);\n };\n\n const timer = setTimeout(() => settle(false), this.opts.timeoutMs ?? DEFAULT_TIMEOUT_MS);\n // Never hold the process open on a prompt nobody is watching.\n (timer as unknown as { unref?: () => void }).unref?.();\n\n this.entries.set(id, { pending, settle, timer });\n this.opts.onRequest?.(pending);\n });\n }\n\n /** Answer one request. Returns false when the id is unknown or already settled. */\n resolve(id: string, granted: boolean): boolean {\n const entry = this.entries.get(id);\n if (!entry) return false;\n entry.settle(granted);\n return true;\n }\n\n /** Everything still awaiting an answer — replayed to a surface that connects late. */\n outstanding(): PendingApproval[] {\n return [...this.entries.values()].map((e) => e.pending);\n }\n\n /** Deny everything in flight. Called on abort and on session reset. */\n clear(): void {\n for (const id of [...this.entries.keys()]) this.resolve(id, false);\n }\n}\n","import path from 'node:path';\nimport { GrepOptions, SEARCH_EXCLUSIONS } from '../interfaces/IFileSystem';\n\n/**\n * Argument construction for the search tools, shared by every filesystem\n * adapter. Two reasons this is core and not per-adapter:\n *\n * 1. The exclusion set and the result cap are policy. `glob` used to pass\n * `--iglob '!node_modules'` and friends while `grep` passed nothing, so a\n * repo that did not gitignore `dist/` spent its whole result budget on\n * build output in one tool but not the other.\n *\n * 2. Arguments are returned as an array for `execFile`, never as a shell\n * string. The previous string interpolation escaped only double quotes,\n * which meant a pattern containing a backtick or `$(` was a command\n * injection through the planner's own search box.\n */\n\n/** Ordering is part of the result quality: with a hard cap, what you drop matters. */\nconst SORT_BY_RECENCY = ['--sortr', 'modified'];\n\nfunction exclusionArgs(): string[] {\n return SEARCH_EXCLUSIONS.flatMap((dir) => ['--glob', `!**/${dir}/**`]);\n}\n\nexport interface GrepInvocation {\n args: string[];\n /** Rows beyond this are dropped by the caller — see `applyHeadLimit`. */\n headLimit: number;\n}\n\n/**\n * Build the ripgrep invocation for one grep call.\n *\n * `--max-count` is deliberately absent. It caps matches *per file*, so the old\n * `--max-count 100` on a 300-file hit returned ~30 000 lines, blew the 1 MB\n * exec buffer, and surfaced as `{ success: false, output: '' }` — a silent\n * empty result on exactly the broad searches where the model most needed a\n * signal. The cap belongs at the row level, applied after the fact.\n */\nexport function buildGrepArgs(pattern: string, opts: GrepOptions, root: string): GrepInvocation {\n // ripgrep applies `--glob` in order with last-wins, so the include must come\n // before the exclusions — otherwise `--glob '*.ts'` would override the\n // `!**/node_modules/**` negations and search build output.\n const args = ['--no-heading', '--color', 'never', ...SORT_BY_RECENCY];\n if (opts.include) args.push('--glob', opts.include);\n args.push(...exclusionArgs());\n\n if (opts.literal) args.push('--fixed-strings');\n if (opts.caseInsensitive) args.push('--ignore-case');\n\n switch (opts.outputMode) {\n case 'files':\n args.push('--files-with-matches');\n break;\n case 'count':\n args.push('--count-matches');\n break;\n default:\n args.push('--line-number');\n if (opts.contextBefore) args.push('--before-context', String(opts.contextBefore));\n if (opts.contextAfter) args.push('--after-context', String(opts.contextAfter));\n }\n\n // `-e` and `--` keep a pattern or path that begins with `-` from being read as a flag.\n args.push('-e', pattern, '--', root);\n return { args, headLimit: opts.headLimit ?? 100 };\n}\n\n/** Build the ripgrep invocation that lists files matching a glob. */\nexport function buildGlobArgs(pattern: string, root: string): string[] {\n // Include before exclusions: ripgrep's `--glob` is last-wins, so the include\n // must precede the negations or it would override them.\n return ['--files', ...SORT_BY_RECENCY, '--glob', pattern, ...exclusionArgs(), '--', root];\n}\n\n/**\n * The POSIX-grep fallback for machines without ripgrep. Ordering and `--sort`\n * are unavailable.\n *\n * `-P` (PCRE) is required, not optional: patterns built in core — most\n * notably `find_symbol`'s `definitionPattern` — use non-capturing groups and\n * `\\b`, which BRE has no syntax for and ERE (`-E`) still cannot express\n * ((?:...) is a PCRE construct). Without `-P`, GNU grep either errors\n * (\"Unmatched \\{\") or, worse, silently treats `(`/`)`/`|` as literal\n * characters and reports a confident empty result. `-P` and `-F` are\n * mutually exclusive, so literal mode skips it.\n */\nexport function buildFallbackGrepArgs(pattern: string, opts: GrepOptions, root: string): string[] {\n const args = ['-r', '-n'];\n if (opts.literal) args.push('-F');\n else args.push('-P');\n if (opts.caseInsensitive) args.push('-i');\n if (opts.outputMode === 'files') args.push('-l');\n if (opts.outputMode === 'count') args.push('-c');\n if (opts.outputMode !== 'files' && opts.outputMode !== 'count') {\n if (opts.contextBefore) args.push('-B', String(opts.contextBefore));\n if (opts.contextAfter) args.push('-A', String(opts.contextAfter));\n }\n if (opts.include) args.push(`--include=${opts.include}`);\n for (const dir of SEARCH_EXCLUSIONS) args.push(`--exclude-dir=${dir}`);\n args.push('-e', pattern, root);\n return args;\n}\n\nfunction globSegmentToRegex(segment: string): string {\n return segment.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&').replace(/\\*/g, '[^/]*').replace(/\\?/g, '.');\n}\n\n/** `subdir/*.txt`-style glob match against a path relative to the search root. */\nfunction matchesAnchoredGlob(relPath: string, pattern: string): boolean {\n const regex = pattern.split('/').map((seg) => (seg === '**' ? '.*' : globSegmentToRegex(seg))).join('/');\n return new RegExp(`^${regex}$`).test(relPath);\n}\n\nfunction extractFallbackGrepPath(line: string, outputMode?: GrepOptions['outputMode']): string {\n if (outputMode === 'files') return line;\n if (outputMode === 'count') return line.slice(0, line.lastIndexOf(':'));\n // content mode: \"path:lineNumber:content\" — cut before the line-number marker.\n const match = line.match(/^(.*?):\\d+:/);\n return match ? match[1] : line;\n}\n\n/**\n * GNU grep's own `--include` glob only ever matches a basename, so it silently\n * matches nothing against an anchored pattern like `subdir/*.txt` (there is no\n * `/` in a basename to match against). The fallback path drops such patterns\n * from the grep invocation and filters matches by relative path here instead.\n */\nexport function filterFallbackByAnchoredInclude(stdout: string, include: string, anchor: string, outputMode?: GrepOptions['outputMode']): string {\n return stdout\n .split('\\n')\n .filter((line) => {\n if (!line) return false;\n const reportedPath = extractFallbackGrepPath(line, outputMode);\n const relPath = path.isAbsolute(reportedPath) ? path.relative(anchor, reportedPath) : reportedPath;\n return matchesAnchoredGlob(relPath, include);\n })\n .join('\\n');\n}\n\nexport interface CappedRows {\n rows: string[];\n truncated: boolean;\n total: number;\n}\n\n/** Apply the global row cap and report honestly whether anything was dropped. */\nexport function applyHeadLimit(stdout: string, headLimit: number): CappedRows {\n const all = stdout.split('\\n').filter((line) => line.length > 0);\n return { rows: all.slice(0, headLimit), truncated: all.length > headLimit, total: all.length };\n}\n\n/**\n * Render capped rows for the model, with paths made workspace-relative and an\n * explicit note when rows were dropped — a silently truncated list reads as a\n * complete answer and the model plans against it.\n */\nexport function formatSearchOutput(\n capped: CappedRows,\n root: string,\n opts: { emptyMessage: string; hint?: string; sep?: string },\n): string {\n if (capped.rows.length === 0) return opts.emptyMessage;\n\n // Only strip the workspace prefix; the filesystem root (`/`) has no useful\n // prefix to strip and dropping a leading slash would keep the model from\n // passing the path back to read_file.\n //\n // The separator is the host's, not `/`. ripgrep on Windows emits\n // `C:\\repo\\src\\a.ts:12:…` against a root of `C:\\repo`, so a hardcoded `/`\n // built the prefix `C:\\repo/`, matched nothing, and left every row absolute —\n // paying full path length for every result on every search.\n const sep = opts.sep ?? path.sep;\n const prefix = root === sep || root.endsWith(sep) ? root : `${root}${sep}`;\n const body = prefix === sep ? capped.rows.join('\\n') : capped.rows.map((row) => (row.startsWith(prefix) ? row.slice(prefix.length) : row)).join('\\n');\n if (!capped.truncated) return body;\n\n const hint = opts.hint ? ` ${opts.hint}` : '';\n return `${body}\\n\\n[showing ${capped.rows.length} of ${capped.total} results.${hint}]`;\n}\n","import type { RunnerId } from '../models/Task';\nimport type { ApprovalMode } from '../services/ApprovalPolicy';\nimport type { ProviderModelLists } from '../services/ProviderRouting';\n\n/**\n * Who plans. Mostly LLM vendors reached over HTTP; the last three are *harness\n * planners* (ADR-0009) — a coding agent CLI already installed on the machine,\n * driven as the planner over its own programmatic transport and authenticated\n * by the subscription the user already holds. They are runners in the provider\n * axis, deliberately: \"what plans for me?\" is one question, and it belongs in\n * one setting. `isCliProvider` is the single guard that tells the two kinds\n * apart.\n */\nexport type AiProvider = 'google' | 'openrouter' | 'openai_compatible' | 'openai' | 'xai' | 'groq' | 'deepseek' | 'together' | 'mistral' | 'anthropic' | 'fireworks' | 'perplexity' | 'zhipu' | 'kimi' | 'cerebras' | 'deepinfra' | 'doubao' | 'qwen' | 'hunyuan' | 'baichuan' | 'minimax' | 'yi' | 'stepfun' | 'siliconflow' | 'cohere' | 'novita' | 'claude-code' | 'codex' | 'opencode';\n\nexport interface IConfig {\n aiProvider: AiProvider;\n apiKey: string;\n planningModel: string;\n enabledRunners: string[];\n maxParallelSessions: number;\n researchEnabled: boolean;\n researchMaxSteps: number;\n researchMaxFileSize: number;\n\n openAiBaseUrl: string;\n openAiApiKey: string;\n /** Provider keys + base URL the ModelResolver uses to fetch the picker catalogs. */\n openrouterKey: string;\n geminiKey: string;\n geminiBaseUrl?: string;\n /** Base URL + API key for a user-provided OpenAI-compatible endpoint (ollama, vLLM, LM Studio, etc.). */\n openaiCompatibleBaseUrl: string;\n openaiCompatibleApiKey: string;\n orchestratorModel: string;\n geminiModel: string;\n /** Model for research subagents (issue #34); defaults to the (cheap) planner model. */\n researchSubagentModel: string;\n /**\n * Thinking effort / model variant for a harness planner (ADR-0009), chosen\n * from the agent's own discovered variants. Separate from the per-task\n * efforts the plan carries — this one is the planner's own dial.\n */\n plannerThinkingEffort?: string;\n\n planMapEnabled: boolean;\n autonomousMode: boolean;\n\n /**\n * What to do when planner research reaches outside its default envelope — an\n * out-of-workspace path, or a shell command beyond the auto-allowed read-only\n * set. `ask` prompts the user (and denies where no surface can prompt, such as\n * headless runs); `allow` and `deny` skip the prompt entirely.\n */\n approvalMode: ApprovalMode;\n /** Scopes granted up front, so CI and power users never see a prompt. Trailing `*` matches by prefix. */\n approvalPreApproved: string[];\n\n /** Get the base URL for an OpenAI-compatible provider. */\n getProviderBaseUrl(provider: AiProvider): string;\n /** Get the API key for a provider. */\n getProviderApiKey(provider: AiProvider): string;\n\n /**\n * Push the canonical provider routing lists in (sole producer: ModelResolver).\n * Config consumes them when resolving a chosen model id to its serving API.\n */\n setProviderModelLists(lists: ProviderModelLists): void;\n}\n\nexport function enabledRunners(cfg: IConfig): RunnerId[] {\n return cfg.enabledRunners;\n}\n","import type { AiProvider } from '../interfaces/IConfig';\n\nexport const PROVIDER_LABEL: Record<AiProvider, string> = {\n openrouter: 'OpenRouter',\n google: 'Google Gemini',\n openai_compatible: 'Custom',\n openai: 'OpenAI',\n xai: 'xAI',\n groq: 'Groq',\n deepseek: 'DeepSeek',\n together: 'Together AI',\n mistral: 'Mistral',\n anthropic: 'Anthropic',\n fireworks: 'Fireworks AI',\n perplexity: 'Perplexity',\n zhipu: 'Zhipu / GLM',\n kimi: 'Moonshot / Kimi',\n cerebras: 'Cerebras',\n deepinfra: 'DeepInfra',\n doubao: 'ByteDance / Doubao',\n qwen: 'Alibaba / Qwen',\n hunyuan: 'Tencent Hunyuan',\n baichuan: 'Baichuan',\n minimax: 'MiniMax',\n yi: '01.AI / Yi',\n stepfun: 'StepFun',\n siliconflow: 'SiliconFlow',\n cohere: 'Cohere',\n novita: 'Novita AI',\n 'claude-code': 'Claude Code',\n codex: 'Codex',\n opencode: 'OpenCode',\n};\n\nexport const PROVIDER_SHORT_LABEL: Record<AiProvider, string> = {\n openrouter: 'OpenRouter',\n google: 'Gemini',\n openai_compatible: 'Custom',\n openai: 'OpenAI',\n xai: 'xAI',\n groq: 'Groq',\n deepseek: 'DeepSeek',\n together: 'Together',\n mistral: 'Mistral',\n anthropic: 'Anthropic',\n fireworks: 'Fireworks',\n perplexity: 'Perplexity',\n zhipu: 'Zhipu',\n kimi: 'Kimi',\n cerebras: 'Cerebras',\n deepinfra: 'DeepInfra',\n doubao: 'Doubao',\n qwen: 'Qwen',\n hunyuan: 'Hunyuan',\n baichuan: 'Baichuan',\n minimax: 'MiniMax',\n yi: 'Yi',\n stepfun: 'StepFun',\n siliconflow: 'SiliconFlow',\n cohere: 'Cohere',\n novita: 'Novita',\n 'claude-code': 'Claude Code',\n codex: 'Codex',\n opencode: 'OpenCode',\n};\n\nexport interface ProviderRegistration {\n id: AiProvider;\n label: string;\n shortLabel: string;\n /** `cli` is a harness planner (ADR-0009): a local coding agent, not an HTTP vendor. */\n serviceType: 'openai' | 'google' | 'cli';\n /** Harness planners only: the runner id whose manifest, models and binary this provider drives. */\n runnerId?: string;\n defaultBaseUrl: string;\n apiKeyEnvVar: string;\n detectEnvVars: string[];\n baseUrlEnvVar?: string;\n secretStoreKey?: string;\n vscodeBaseUrlKey?: string;\n vscodeApiKeyKey?: string;\n discoversModels: boolean;\n modelPrefix?: string;\n}\n\nexport const ALL_PROVIDERS: Record<AiProvider, ProviderRegistration> = {\n openrouter: {\n id: 'openrouter', label: 'OpenRouter', shortLabel: 'OpenRouter',\n serviceType: 'openai',\n defaultBaseUrl: 'https://openrouter.ai/api/v1',\n apiKeyEnvVar: 'OPENROUTER_API_KEY',\n // Intentionally NOT OPENAI_API_KEY: that belongs to the dedicated `openai`\n // provider (api.openai.com). Sharing it made a bare OPENAI_API_KEY resolve\n // to OpenRouter and marked both providers configured. The legacy\n // openrouterKey/openAiApiKey getters still fall back to OPENAI_API_KEY for\n // pre-existing setups; only provider detection/routing is de-coupled here.\n detectEnvVars: ['OPENROUTER_API_KEY'],\n baseUrlEnvVar: 'OPENROUTER_BASE_URL',\n secretStoreKey: 'openrouterKey',\n vscodeBaseUrlKey: 'openAiBaseUrl', vscodeApiKeyKey: 'openAiApiKey',\n discoversModels: true,\n },\n google: {\n id: 'google', label: 'Google Gemini', shortLabel: 'Gemini',\n serviceType: 'google',\n defaultBaseUrl: '',\n apiKeyEnvVar: 'GEMINI_API_KEY',\n detectEnvVars: ['GEMINI_API_KEY'],\n baseUrlEnvVar: 'GEMINI_BASE_URL',\n secretStoreKey: 'geminiKey',\n vscodeApiKeyKey: 'apiKey',\n discoversModels: true,\n modelPrefix: 'gemini:',\n },\n openai_compatible: {\n id: 'openai_compatible', label: 'Custom', shortLabel: 'Custom',\n serviceType: 'openai',\n defaultBaseUrl: 'http://localhost:11434/v1',\n apiKeyEnvVar: 'OPENAI_COMPATIBLE_API_KEY',\n detectEnvVars: [],\n baseUrlEnvVar: 'OPENAI_COMPATIBLE_BASE_URL',\n secretStoreKey: 'openaiCompatibleKey',\n vscodeBaseUrlKey: 'openaiCompatibleBaseUrl', vscodeApiKeyKey: 'openaiCompatibleApiKey',\n discoversModels: true,\n modelPrefix: 'openai_compat:',\n },\n openai: {\n id: 'openai', label: 'OpenAI', shortLabel: 'OpenAI',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.openai.com/v1',\n apiKeyEnvVar: 'OPENAI_API_KEY',\n detectEnvVars: ['OPENAI_API_KEY'],\n secretStoreKey: 'openaiKey',\n vscodeBaseUrlKey: 'openaiBaseUrl', vscodeApiKeyKey: 'openaiApiKey',\n discoversModels: true,\n modelPrefix: 'openai:',\n },\n xai: {\n id: 'xai', label: 'xAI', shortLabel: 'xAI',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.x.ai/v1',\n apiKeyEnvVar: 'XAI_API_KEY',\n detectEnvVars: ['XAI_API_KEY'],\n secretStoreKey: 'xaiKey',\n vscodeBaseUrlKey: 'xaiBaseUrl', vscodeApiKeyKey: 'xaiApiKey',\n discoversModels: true,\n modelPrefix: 'xai:',\n },\n groq: {\n id: 'groq', label: 'Groq', shortLabel: 'Groq',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.groq.com/openai/v1',\n apiKeyEnvVar: 'GROQ_API_KEY',\n detectEnvVars: ['GROQ_API_KEY'],\n secretStoreKey: 'groqKey',\n vscodeBaseUrlKey: 'groqBaseUrl', vscodeApiKeyKey: 'groqApiKey',\n discoversModels: true,\n modelPrefix: 'groq:',\n },\n deepseek: {\n id: 'deepseek', label: 'DeepSeek', shortLabel: 'DeepSeek',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.deepseek.com/v1',\n apiKeyEnvVar: 'DEEPSEEK_API_KEY',\n detectEnvVars: ['DEEPSEEK_API_KEY'],\n secretStoreKey: 'deepseekKey',\n vscodeBaseUrlKey: 'deepseekBaseUrl', vscodeApiKeyKey: 'deepseekApiKey',\n discoversModels: true,\n modelPrefix: 'deepseek:',\n },\n together: {\n id: 'together', label: 'Together AI', shortLabel: 'Together',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.together.xyz/v1',\n apiKeyEnvVar: 'TOGETHER_API_KEY',\n detectEnvVars: ['TOGETHER_API_KEY'],\n secretStoreKey: 'togetherKey',\n vscodeBaseUrlKey: 'togetherBaseUrl', vscodeApiKeyKey: 'togetherApiKey',\n discoversModels: true,\n modelPrefix: 'together:',\n },\n mistral: {\n id: 'mistral', label: 'Mistral', shortLabel: 'Mistral',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.mistral.ai/v1',\n apiKeyEnvVar: 'MISTRAL_API_KEY',\n detectEnvVars: ['MISTRAL_API_KEY'],\n secretStoreKey: 'mistralKey',\n vscodeBaseUrlKey: 'mistralBaseUrl', vscodeApiKeyKey: 'mistralApiKey',\n discoversModels: true,\n modelPrefix: 'mistral:',\n },\n anthropic: {\n id: 'anthropic', label: 'Anthropic', shortLabel: 'Anthropic',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.anthropic.com/v1',\n apiKeyEnvVar: 'ANTHROPIC_API_KEY',\n detectEnvVars: ['ANTHROPIC_API_KEY'],\n secretStoreKey: 'anthropicKey',\n vscodeBaseUrlKey: 'anthropicBaseUrl', vscodeApiKeyKey: 'anthropicApiKey',\n discoversModels: true,\n modelPrefix: 'anthropic:',\n },\n fireworks: {\n id: 'fireworks', label: 'Fireworks AI', shortLabel: 'Fireworks',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.fireworks.ai/inference/v1',\n apiKeyEnvVar: 'FIREWORKS_API_KEY',\n detectEnvVars: ['FIREWORKS_API_KEY'],\n secretStoreKey: 'fireworksKey',\n vscodeBaseUrlKey: 'fireworksBaseUrl', vscodeApiKeyKey: 'fireworksApiKey',\n discoversModels: true,\n modelPrefix: 'fireworks:',\n },\n perplexity: {\n id: 'perplexity', label: 'Perplexity', shortLabel: 'Perplexity',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.perplexity.ai',\n apiKeyEnvVar: 'PERPLEXITY_API_KEY',\n detectEnvVars: ['PERPLEXITY_API_KEY'],\n secretStoreKey: 'perplexityKey',\n vscodeBaseUrlKey: 'perplexityBaseUrl', vscodeApiKeyKey: 'perplexityApiKey',\n // Perplexity exposes no OpenAI-style GET /models list endpoint, so catalog\n // discovery always fails. Users set a perplexity model id explicitly\n // (AI_PROVIDER=perplexity + orchestratorModel=sonar-…) instead.\n discoversModels: false,\n modelPrefix: 'perplexity:',\n },\n zhipu: {\n id: 'zhipu', label: 'Zhipu / GLM', shortLabel: 'Zhipu',\n serviceType: 'openai',\n defaultBaseUrl: 'https://open.bigmodel.cn/api/paas/v4',\n apiKeyEnvVar: 'ZHIPU_API_KEY',\n detectEnvVars: ['ZHIPU_API_KEY'],\n secretStoreKey: 'zhipuKey',\n vscodeBaseUrlKey: 'zhipuBaseUrl', vscodeApiKeyKey: 'zhipuApiKey',\n discoversModels: true,\n modelPrefix: 'zhipu:',\n },\n kimi: {\n id: 'kimi', label: 'Moonshot / Kimi', shortLabel: 'Kimi',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.moonshot.cn/v1',\n apiKeyEnvVar: 'MOONSHOT_API_KEY',\n detectEnvVars: ['MOONSHOT_API_KEY'],\n secretStoreKey: 'kimiKey',\n vscodeBaseUrlKey: 'kimiBaseUrl', vscodeApiKeyKey: 'kimiApiKey',\n discoversModels: true,\n modelPrefix: 'kimi:',\n },\n cerebras: {\n id: 'cerebras', label: 'Cerebras', shortLabel: 'Cerebras',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.cerebras.ai/v1',\n apiKeyEnvVar: 'CEREBRAS_API_KEY',\n detectEnvVars: ['CEREBRAS_API_KEY'],\n secretStoreKey: 'cerebrasKey',\n vscodeBaseUrlKey: 'cerebrasBaseUrl', vscodeApiKeyKey: 'cerebrasApiKey',\n discoversModels: true,\n modelPrefix: 'cerebras:',\n },\n deepinfra: {\n id: 'deepinfra', label: 'DeepInfra', shortLabel: 'DeepInfra',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.deepinfra.com/v1/openai',\n apiKeyEnvVar: 'DEEPINFRA_API_KEY',\n detectEnvVars: ['DEEPINFRA_API_KEY'],\n secretStoreKey: 'deepinfraKey',\n vscodeBaseUrlKey: 'deepinfraBaseUrl', vscodeApiKeyKey: 'deepinfraApiKey',\n discoversModels: true,\n modelPrefix: 'deepinfra:',\n },\n doubao: {\n id: 'doubao', label: 'ByteDance / Doubao', shortLabel: 'Doubao',\n serviceType: 'openai',\n defaultBaseUrl: 'https://ark.cn-beijing.volces.com/api/v3',\n apiKeyEnvVar: 'ARK_API_KEY',\n detectEnvVars: ['ARK_API_KEY'],\n secretStoreKey: 'doubaoKey',\n vscodeBaseUrlKey: 'doubaoBaseUrl', vscodeApiKeyKey: 'doubaoApiKey',\n discoversModels: true,\n modelPrefix: 'doubao:',\n },\n qwen: {\n id: 'qwen', label: 'Alibaba / Qwen', shortLabel: 'Qwen',\n serviceType: 'openai',\n defaultBaseUrl: 'https://dashscope.aliyuncs.com/compatible-mode/v1',\n apiKeyEnvVar: 'DASHSCOPE_API_KEY',\n detectEnvVars: ['DASHSCOPE_API_KEY'],\n secretStoreKey: 'qwenKey',\n vscodeBaseUrlKey: 'qwenBaseUrl', vscodeApiKeyKey: 'qwenApiKey',\n discoversModels: true,\n modelPrefix: 'qwen:',\n },\n hunyuan: {\n id: 'hunyuan', label: 'Tencent Hunyuan', shortLabel: 'Hunyuan',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.hunyuan.cloud.tencent.com/v1',\n apiKeyEnvVar: 'HUNYUAN_API_KEY',\n detectEnvVars: ['HUNYUAN_API_KEY'],\n secretStoreKey: 'hunyuanKey',\n vscodeBaseUrlKey: 'hunyuanBaseUrl', vscodeApiKeyKey: 'hunyuanApiKey',\n discoversModels: true,\n modelPrefix: 'hunyuan:',\n },\n baichuan: {\n id: 'baichuan', label: 'Baichuan', shortLabel: 'Baichuan',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.baichuan-ai.com/v1',\n apiKeyEnvVar: 'BAICHUAN_API_KEY',\n detectEnvVars: ['BAICHUAN_API_KEY'],\n secretStoreKey: 'baichuanKey',\n vscodeBaseUrlKey: 'baichuanBaseUrl', vscodeApiKeyKey: 'baichuanApiKey',\n discoversModels: true,\n modelPrefix: 'baichuan:',\n },\n minimax: {\n id: 'minimax', label: 'MiniMax', shortLabel: 'MiniMax',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.minimax.chat/v1',\n apiKeyEnvVar: 'MINIMAX_API_KEY',\n detectEnvVars: ['MINIMAX_API_KEY'],\n secretStoreKey: 'minimaxKey',\n vscodeBaseUrlKey: 'minimaxBaseUrl', vscodeApiKeyKey: 'minimaxApiKey',\n discoversModels: true,\n modelPrefix: 'minimax:',\n },\n yi: {\n id: 'yi', label: '01.AI / Yi', shortLabel: 'Yi',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.lingyiwanwu.com/v1',\n apiKeyEnvVar: 'YI_API_KEY',\n detectEnvVars: ['YI_API_KEY'],\n secretStoreKey: 'yiKey',\n vscodeBaseUrlKey: 'yiBaseUrl', vscodeApiKeyKey: 'yiApiKey',\n discoversModels: true,\n modelPrefix: 'yi:',\n },\n stepfun: {\n id: 'stepfun', label: 'StepFun', shortLabel: 'StepFun',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.stepfun.com/v1',\n apiKeyEnvVar: 'STEPFUN_API_KEY',\n detectEnvVars: ['STEPFUN_API_KEY'],\n secretStoreKey: 'stepfunKey',\n vscodeBaseUrlKey: 'stepfunBaseUrl', vscodeApiKeyKey: 'stepfunApiKey',\n discoversModels: true,\n modelPrefix: 'stepfun:',\n },\n siliconflow: {\n id: 'siliconflow', label: 'SiliconFlow', shortLabel: 'SiliconFlow',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.siliconflow.cn/v1',\n apiKeyEnvVar: 'SILICONFLOW_API_KEY',\n detectEnvVars: ['SILICONFLOW_API_KEY'],\n secretStoreKey: 'siliconflowKey',\n vscodeBaseUrlKey: 'siliconflowBaseUrl', vscodeApiKeyKey: 'siliconflowApiKey',\n discoversModels: true,\n modelPrefix: 'siliconflow:',\n },\n cohere: {\n id: 'cohere', label: 'Cohere', shortLabel: 'Cohere',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.cohere.com/v1',\n apiKeyEnvVar: 'COHERE_API_KEY',\n detectEnvVars: ['COHERE_API_KEY'],\n secretStoreKey: 'cohereKey',\n vscodeBaseUrlKey: 'cohereBaseUrl', vscodeApiKeyKey: 'cohereApiKey',\n discoversModels: true,\n modelPrefix: 'cohere:',\n },\n novita: {\n id: 'novita', label: 'Novita AI', shortLabel: 'Novita',\n serviceType: 'openai',\n defaultBaseUrl: 'https://api.novita.ai/v3/openai',\n apiKeyEnvVar: 'NOVITA_API_KEY',\n detectEnvVars: ['NOVITA_API_KEY'],\n secretStoreKey: 'novitaKey',\n vscodeBaseUrlKey: 'novitaBaseUrl', vscodeApiKeyKey: 'novitaApiKey',\n discoversModels: true,\n modelPrefix: 'novita:',\n },\n\n // Harness planners (ADR-0009). No key, no base URL, no HTTP catalog: the\n // binary is local, the credential is the user's existing subscription, and\n // the model list comes from the runner's own discovery. `apiKeyEnvVar` is\n // empty on purpose — anything that resolves keys must skip these, which is\n // what `isCliProvider` is for.\n 'claude-code': {\n id: 'claude-code', label: 'Claude Code', shortLabel: 'Claude Code',\n serviceType: 'cli', runnerId: 'claude-code',\n defaultBaseUrl: '',\n apiKeyEnvVar: '',\n detectEnvVars: [],\n discoversModels: false,\n },\n codex: {\n id: 'codex', label: 'Codex', shortLabel: 'Codex',\n serviceType: 'cli', runnerId: 'codex',\n defaultBaseUrl: '',\n apiKeyEnvVar: '',\n detectEnvVars: [],\n discoversModels: false,\n },\n opencode: {\n id: 'opencode', label: 'OpenCode', shortLabel: 'OpenCode',\n serviceType: 'cli', runnerId: 'opencode',\n defaultBaseUrl: '',\n apiKeyEnvVar: '',\n detectEnvVars: [],\n discoversModels: false,\n },\n};\n\nexport function getProviderMeta(id: AiProvider): ProviderRegistration {\n return ALL_PROVIDERS[id];\n}\n\nexport function prefixModelId(provider: AiProvider, modelId: string): string {\n const meta = getProviderMeta(provider);\n return meta?.modelPrefix ? `${meta.modelPrefix}${modelId}` : modelId;\n}\n\nexport function stripModelPrefix(id: string, provider: AiProvider): string {\n const meta = getProviderMeta(provider);\n if (meta?.modelPrefix && id.startsWith(meta.modelPrefix)) {\n return id.slice(meta.modelPrefix.length);\n }\n return id;\n}\n\nexport function resolveProviderFromPrefix(id: string): AiProvider | null {\n for (const provider of PROVIDER_PRIORITY) {\n const meta = ALL_PROVIDERS[provider];\n if (meta.modelPrefix && id.startsWith(meta.modelPrefix)) return provider as AiProvider;\n }\n return null;\n}\n\n/**\n * The harness planners, in display order. Deliberately NOT part of\n * `PROVIDER_PRIORITY`: that list means \"vendors that take an API key\", and\n * every consumer of it — key prompts, catalog fetches, base-URL cache clearing\n * — would be asking a local binary for a credential it does not have. Surfaces\n * that offer a planner picker concatenate the two lists and gate these on\n * `RunnerInstallation.plannerUsability`.\n */\nexport const CLI_PROVIDERS: AiProvider[] = ['claude-code', 'codex', 'opencode'];\n\nexport const PROVIDER_PRIORITY: AiProvider[] = [\n 'openrouter', 'google',\n 'openai', 'anthropic', 'mistral', 'xai', 'groq', 'deepseek',\n 'together', 'fireworks', 'perplexity', 'cerebras', 'deepinfra', 'cohere', 'novita',\n 'zhipu', 'kimi', 'doubao', 'qwen', 'hunyuan', 'baichuan', 'minimax', 'yi', 'stepfun', 'siliconflow',\n 'openai_compatible',\n];\n\nexport const PROVIDER_DETECT_PRIORITY: AiProvider[] = [\n 'google', 'openrouter',\n 'openai', 'anthropic', 'mistral', 'xai', 'groq', 'deepseek',\n 'together', 'fireworks', 'perplexity', 'cerebras', 'deepinfra', 'cohere', 'novita',\n 'zhipu', 'kimi', 'doubao', 'qwen', 'hunyuan', 'baichuan', 'minimax', 'yi', 'stepfun', 'siliconflow',\n 'openai_compatible',\n];\n\nexport function isOpenAiProvider(id: AiProvider): boolean {\n return ALL_PROVIDERS[id]?.serviceType === 'openai';\n}\n\n/**\n * The one guard that separates a harness planner from an LLM vendor (ADR-0009).\n * Three places consult it: API-key resolution (skipped — the subscription is\n * the credential), provider routing (skipped — there is no HTTP endpoint), and\n * the planner-model picker (fed by per-runner discovery, not the vendor\n * catalog).\n */\nexport function isCliProvider(id: AiProvider): boolean {\n return ALL_PROVIDERS[id]?.serviceType === 'cli';\n}\n\n/** The runner a harness planner drives, or null for a vendor provider. */\nexport function runnerForProvider(id: AiProvider): string | null {\n return ALL_PROVIDERS[id]?.runnerId ?? null;\n}\n\n/** The harness planner that wraps a given runner, or null when none does. */\nexport function providerForRunner(runner: string): AiProvider | null {\n return CLI_PROVIDERS.find((p) => ALL_PROVIDERS[p].runnerId === runner) ?? null;\n}\n\n/**\n * The single definition of which providers count as \"configured\" — one API\n * key each, or (for `openai_compatible`) an explicit base URL. Every surface\n * (CLI listing, VS Code picker gating) derives its configured-provider set\n * from here so they can never diverge on what a user has set up. Order follows\n * PROVIDER_PRIORITY.\n */\nexport function configuredProviders(config: {\n getProviderApiKey(provider: AiProvider): string;\n openaiCompatibleBaseUrl: string;\n}): AiProvider[] {\n const out: AiProvider[] = [];\n for (const provider of PROVIDER_PRIORITY) {\n if (provider === 'openai_compatible') {\n if (config.openaiCompatibleBaseUrl) out.push(provider);\n } else if (config.getProviderApiKey(provider)) {\n out.push(provider);\n }\n }\n return out;\n}\n","import { IConfig, AiProvider } from './IConfig';\nimport type { ApprovalMode } from '../services/ApprovalPolicy';\nimport type { ProviderModelLists } from '../services/ProviderRouting';\nimport { ALL_PROVIDERS, getProviderMeta, PROVIDER_DETECT_PRIORITY } from '../services/ProviderRegistry';\n\nexport function normalizeGeminiModel(id: string): string {\n return id.replace(/^gemini:/, '').replace(/^google\\//, '');\n}\n\nexport abstract class BaseConfig implements IConfig {\n abstract aiProvider: AiProvider;\n abstract apiKey: string;\n abstract planningModel: string;\n abstract enabledRunners: string[];\n\n abstract setProviderModelLists(lists: ProviderModelLists): void;\n\n // --- Legacy named getters (backward compat) ---\n\n get openAiBaseUrl(): string { return process.env.OPENROUTER_BASE_URL || process.env.OPENAI_BASE_URL || 'https://openrouter.ai/api/v1'; }\n get openAiApiKey(): string { return process.env.OPENROUTER_API_KEY || process.env.OPENAI_API_KEY || ''; }\n get openrouterKey(): string { return process.env.OPENROUTER_API_KEY || process.env.OPENAI_API_KEY || ''; }\n get geminiKey(): string { return process.env.GEMINI_API_KEY || ''; }\n get geminiBaseUrl(): string | undefined { return process.env.GEMINI_BASE_URL || undefined; }\n get openaiCompatibleBaseUrl(): string { return process.env.OPENAI_COMPATIBLE_BASE_URL || ''; }\n get openaiCompatibleApiKey(): string { return process.env.OPENAI_COMPATIBLE_API_KEY || ''; }\n get orchestratorModel(): string { return process.env.ORCHESTRATOR_MODEL || ''; }\n // Grunt reading must never cost strong-model prices: subagents follow the\n // (cheap) planner model unless explicitly pinned elsewhere.\n get researchSubagentModel(): string { return process.env.ORDEWELL_SUBAGENT_MODEL || this.orchestratorModel; }\n get geminiModel(): string { return normalizeGeminiModel(process.env.GEMINI_MODEL || ''); }\n get plannerThinkingEffort(): string | undefined { return process.env.ORDEWELL_PLANNER_EFFORT || undefined; }\n\n // --- New preset getters ---\n\n get openaiBaseUrl(): string { return process.env.OPENAI_BASE_URL || 'https://api.openai.com/v1'; }\n get openaiApiKey(): string { return process.env.OPENAI_API_KEY || ''; }\n get xaiBaseUrl(): string { return process.env.XAI_BASE_URL || 'https://api.x.ai/v1'; }\n get xaiApiKey(): string { return process.env.XAI_API_KEY || ''; }\n get groqBaseUrl(): string { return process.env.GROQ_BASE_URL || 'https://api.groq.com/openai/v1'; }\n get groqApiKey(): string { return process.env.GROQ_API_KEY || ''; }\n get deepseekBaseUrl(): string { return process.env.DEEPSEEK_BASE_URL || 'https://api.deepseek.com/v1'; }\n get deepseekApiKey(): string { return process.env.DEEPSEEK_API_KEY || ''; }\n\n get togetherBaseUrl(): string { return process.env.TOGETHER_BASE_URL || 'https://api.together.xyz/v1'; }\n get togetherApiKey(): string { return process.env.TOGETHER_API_KEY || ''; }\n get mistralBaseUrl(): string { return process.env.MISTRAL_BASE_URL || 'https://api.mistral.ai/v1'; }\n get mistralApiKey(): string { return process.env.MISTRAL_API_KEY || ''; }\n get anthropicBaseUrl(): string { return process.env.ANTHROPIC_BASE_URL || 'https://api.anthropic.com/v1'; }\n get anthropicApiKey(): string { return process.env.ANTHROPIC_API_KEY || ''; }\n get fireworksBaseUrl(): string { return process.env.FIREWORKS_BASE_URL || 'https://api.fireworks.ai/inference/v1'; }\n get fireworksApiKey(): string { return process.env.FIREWORKS_API_KEY || ''; }\n get perplexityBaseUrl(): string { return process.env.PERPLEXITY_BASE_URL || 'https://api.perplexity.ai'; }\n get perplexityApiKey(): string { return process.env.PERPLEXITY_API_KEY || ''; }\n get zhipuBaseUrl(): string { return process.env.ZHIPU_BASE_URL || 'https://open.bigmodel.cn/api/paas/v4'; }\n get zhipuApiKey(): string { return process.env.ZHIPU_API_KEY || ''; }\n get kimiBaseUrl(): string { return process.env.KIMI_BASE_URL || 'https://api.moonshot.cn/v1'; }\n get kimiApiKey(): string { return process.env.MOONSHOT_API_KEY || ''; }\n get cerebrasBaseUrl(): string { return process.env.CEREBRAS_BASE_URL || 'https://api.cerebras.ai/v1'; }\n get cerebrasApiKey(): string { return process.env.CEREBRAS_API_KEY || ''; }\n get deepinfraBaseUrl(): string { return process.env.DEEPINFRA_BASE_URL || 'https://api.deepinfra.com/v1/openai'; }\n get deepinfraApiKey(): string { return process.env.DEEPINFRA_API_KEY || ''; }\n get doubaoBaseUrl(): string { return process.env.DOUBAO_BASE_URL || 'https://ark.cn-beijing.volces.com/api/v3'; }\n get doubaoApiKey(): string { return process.env.ARK_API_KEY || ''; }\n get qwenBaseUrl(): string { return process.env.QWEN_BASE_URL || 'https://dashscope.aliyuncs.com/compatible-mode/v1'; }\n get qwenApiKey(): string { return process.env.DASHSCOPE_API_KEY || ''; }\n get hunyuanBaseUrl(): string { return process.env.HUNYUAN_BASE_URL || 'https://api.hunyuan.cloud.tencent.com/v1'; }\n get hunyuanApiKey(): string { return process.env.HUNYUAN_API_KEY || ''; }\n get baichuanBaseUrl(): string { return process.env.BAICHUAN_BASE_URL || 'https://api.baichuan-ai.com/v1'; }\n get baichuanApiKey(): string { return process.env.BAICHUAN_API_KEY || ''; }\n get minimaxBaseUrl(): string { return process.env.MINIMAX_BASE_URL || 'https://api.minimax.chat/v1'; }\n get minimaxApiKey(): string { return process.env.MINIMAX_API_KEY || ''; }\n get yiBaseUrl(): string { return process.env.YI_BASE_URL || 'https://api.lingyiwanwu.com/v1'; }\n get yiApiKey(): string { return process.env.YI_API_KEY || ''; }\n get stepfunBaseUrl(): string { return process.env.STEPFUN_BASE_URL || 'https://api.stepfun.com/v1'; }\n get stepfunApiKey(): string { return process.env.STEPFUN_API_KEY || ''; }\n get siliconflowBaseUrl(): string { return process.env.SILICONFLOW_BASE_URL || 'https://api.siliconflow.cn/v1'; }\n get siliconflowApiKey(): string { return process.env.SILICONFLOW_API_KEY || ''; }\n get cohereBaseUrl(): string { return process.env.COHERE_BASE_URL || 'https://api.cohere.com/v1'; }\n get cohereApiKey(): string { return process.env.COHERE_API_KEY || ''; }\n get novitaBaseUrl(): string { return process.env.NOVITA_BASE_URL || 'https://api.novita.ai/v3/openai'; }\n get novitaApiKey(): string { return process.env.NOVITA_API_KEY || ''; }\n\n // --- Registry-driven generic getters ---\n\n getProviderBaseUrl(provider: AiProvider): string {\n const meta = getProviderMeta(provider);\n if (!meta) return '';\n if (meta.baseUrlEnvVar && process.env[meta.baseUrlEnvVar]) return process.env[meta.baseUrlEnvVar]!;\n return meta.defaultBaseUrl;\n }\n\n getProviderApiKey(provider: AiProvider): string {\n const meta = getProviderMeta(provider);\n if (!meta) return '';\n for (const envVar of [meta.apiKeyEnvVar, ...meta.detectEnvVars]) {\n const val = process.env[envVar];\n if (val) return val;\n }\n return '';\n }\n\n get maxParallelSessions(): number { return parseInt(process.env.ORDEWELL_MAX_PARALLEL || '3', 10); }\n get researchEnabled(): boolean { return process.env.ORDEWELL_RESEARCH_ENABLED !== 'false'; }\n get researchMaxSteps(): number { return parseInt(process.env.ORDEWELL_RESEARCH_MAX_STEPS || '48', 10); }\n get researchMaxFileSize(): number { return parseInt(process.env.ORDEWELL_RESEARCH_MAX_FILE_SIZE || '50', 10); }\n\n get planMapEnabled(): boolean { return process.env.ORDEWELL_PLAN_MAP_ENABLED !== 'false' && process.env.ORDEWELL_PLAN_MAP_ENABLED !== '0'; }\n\n get autonomousMode(): boolean { return process.env.ORDEWELL_AUTONOMOUS_MODE !== 'false' && process.env.ORDEWELL_AUTONOMOUS_MODE !== '0'; }\n\n get approvalMode(): ApprovalMode {\n const raw = (process.env.ORDEWELL_APPROVAL_MODE || '').trim().toLowerCase();\n return raw === 'allow' || raw === 'deny' ? raw : 'ask';\n }\n\n get approvalPreApproved(): string[] {\n // Comma- or newline-separated so a CI env var and a shell export both read naturally.\n return (process.env.ORDEWELL_APPROVAL_ALLOW || '')\n .split(/[,\\n]/)\n .map((s) => s.trim())\n .filter(Boolean);\n }\n\n protected static detectProvider(fallback: AiProvider): AiProvider {\n const env = process.env.AI_PROVIDER;\n if (env && ALL_PROVIDERS[env as AiProvider]) return env as AiProvider;\n\n for (const provider of PROVIDER_DETECT_PRIORITY) {\n const meta = ALL_PROVIDERS[provider];\n if (!meta) continue;\n if (meta.detectEnvVars.some((v) => process.env[v])) return provider as AiProvider;\n if (meta.baseUrlEnvVar && process.env[meta.baseUrlEnvVar]) return provider as AiProvider;\n }\n\n return fallback;\n }\n}\n","import { BaseConfig } from './BaseConfig';\nimport type { AiProvider } from './IConfig';\n\n/**\n * A fully `process.env`-backed IConfig for headless callers (e.g. the CLI's\n * `ordewell models` command) that need provider keys/base URLs but have no\n * editor settings or secret store. All resolution lives in BaseConfig; this\n * subclass only supplies the abstract members from the environment.\n */\nexport class EnvConfig extends BaseConfig {\n get aiProvider(): AiProvider {\n return BaseConfig.detectProvider('openrouter');\n }\n\n get apiKey(): string {\n return this.getProviderApiKey(this.aiProvider) || this.openrouterKey || this.geminiKey || '';\n }\n\n get planningModel(): string {\n return this.orchestratorModel;\n }\n\n get enabledRunners(): string[] {\n const raw = process.env.ORDEWELL_RUNNERS || process.env.ENABLED_RUNNERS || '';\n return raw.split(',').map((s) => s.trim()).filter(Boolean);\n }\n\n // The CLI does not persist routing lists; resolution happens per-invocation.\n setProviderModelLists(): void {}\n}\n","export interface ILogger {\n warn(scope: string, message: string, err?: unknown): void;\n}\n\nexport class ConsoleLogger implements ILogger {\n warn(scope: string, message: string, err?: unknown): void {\n const detail = err === undefined ? '' : ` :: ${formatError(err)}`;\n console.warn(`[${scope}] ${message}${detail}`);\n }\n}\n\nfunction formatError(err: unknown): string {\n if (err instanceof Error) return err.message;\n if (typeof err === 'string') return err;\n try { return JSON.stringify(err); } catch { return String(err); }\n}\n\nexport const defaultLogger: ILogger = new ConsoleLogger();\n","import { v4 as uuidv4 } from 'uuid';\nimport { Task, DiscoveredModel, ResearchStep, ResearchLogEntry, ResearchProgress, RunnerId } from '../models/Task';\nimport { IConfig } from '../interfaces/IConfig';\nimport { IFileSystem } from '../interfaces/IFileSystem';\nimport { IWebFetcher } from '../interfaces/IWebFetcher';\nimport { buildPlanWithResults } from './PlanPrompts';\nimport { DEFAULT_PLANNER_MODES, type PlannerModes } from './plannerModes';\nimport { generatePlanWithRepair, classifyPlannerReply, reEmitPlanPrompt, reEmitTaskOpsPrompt, truncatedPlanReEmitPrompt } from './PlanRepair';\nimport { compactResearchResults, withProactiveCompaction } from './contextCompaction';\nimport { extractPrdBlock } from '../utils/prdStore';\nimport type { RunnerModeInfo } from './ModeResolver';\nimport { collectResearchContext } from './ContextCollector';\nimport { executeTool } from './executeTool';\nimport { runResearchAgent, mapWithConcurrency, SUBAGENT_LIMITS } from './ResearchSubagents';\nimport { SPAWN_RESEARCH_AGENT } from './researchTools';\nimport { classifyOutcome } from './researchStepSummary';\nimport type { ConversationTurn } from './AiService';\n\n/**\n * Read-only, side-effect-free tools that can share a round. Deliberately a\n * denylist's opposite: `bash`, `fetch` and `web_search` are excluded because\n * they can pause on a user approval prompt, and an unknown tool is excluded\n * because we cannot reason about it.\n */\nconst PARALLEL_SAFE_TOOLS = new Set(['read_file', 'read_files', 'glob', 'grep', 'find_symbol', 'list_dir']);\n\n/** Concurrency for the read-only pre-pass. Bounded so a wide round cannot exhaust file handles. */\nconst TOOL_ROUND_CONCURRENCY = 8;\n\nexport interface ToolCall {\n name: string;\n args: Record<string, unknown>;\n id?: string;\n}\n\nexport interface ToolResult {\n name: string;\n output: string;\n truncated: boolean;\n totalChars: number;\n id?: string;\n}\n\nexport interface ResearchTurn {\n text: string;\n toolCalls: ToolCall[];\n hasToolCalls: boolean;\n /** Reasoning/chain-of-thought captured separately from `text` so it never pollutes plan JSON. */\n reasoning?: string;\n /** Provider finish reason, normalized: 'length' means the output-token limit cut the reply mid-stream. */\n finishReason?: string;\n /** Exact prompt tokens this turn consumed, when the provider reports usage — drives proactive compaction. */\n promptTokens?: number;\n}\n\nexport interface ResearchChat {\n sendMessage(text: string, signal?: AbortSignal): Promise<ResearchTurn>;\n sendToolResults(results: ToolResult[], signal?: AbortSignal): Promise<ResearchTurn>;\n /**\n * Optional: prune bulky raw tool outputs from the history in place (subagent\n * digests are kept) so a follow-up emission has context to spend on output.\n * Returns the number of characters removed. Providers whose SDK owns the\n * history (Gemini) may not support it.\n */\n compactHistory?(): number;\n}\n\n/** Everything one conversation turn needs beyond the user message itself. */\nexport interface ConversationTurnContext {\n chat: ResearchChat;\n fs: IFileSystem;\n runners: RunnerId[];\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>;\n autonomousDefault?: boolean;\n fetcher?: IWebFetcher;\n /** PRD toggle: a plan must not commit before a PRD block has appeared. */\n prdEnabled?: boolean;\n /** Set once any turn carries an ORDEWELL_PRD block; gates the missing-PRD nudge. */\n prdCaptured?: boolean;\n /** The missing-PRD corrective nudge is sent at most once per conversation. */\n prdNudgeSent?: boolean;\n}\n\nexport abstract class BaseAiService {\n protected conversation: { ctx: ConversationTurnContext; setProgress: (fn: (p: ResearchProgress) => void) => void } | null = null;\n protected activeAbort: AbortController | null = null;\n /** researchSubagents toggle (issue #34): set per operation from the live settings snapshot; off means bit-for-bit sequential behavior. */\n protected researchSubagentsEnabled = false;\n\n constructor(protected config: IConfig) {}\n\n abstract reset(): void;\n abstract ensureInit(): void;\n\n hasActiveConversation(): boolean { return this.conversation !== null; }\n\n protected startAbortScope(callerSignal?: AbortSignal): AbortSignal | undefined {\n this.activeAbort = new AbortController();\n if (!callerSignal) return this.activeAbort.signal;\n if (callerSignal.aborted) { this.activeAbort.abort(); return this.activeAbort.signal; }\n callerSignal.addEventListener('abort', () => this.activeAbort?.abort(), { once: true });\n return this.activeAbort.signal;\n }\n\n protected stopAbortScope(): void {\n this.activeAbort = null;\n }\n\n async sendPlanningPrompt(\n prompt: string,\n runners: RunnerId[],\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n autonomousDefault = true,\n ): Promise<Task[]> {\n this.ensureInit();\n return generatePlanWithRepair(\n (repairHint) => this.streamPlanText(prompt, repairHint, () => {}),\n runners, 2, runnerModes, autonomousDefault,\n );\n }\n\n async continueConversation(\n userMessage: string,\n onProgress: (progress: ResearchProgress) => void,\n signal?: AbortSignal,\n ): Promise<ConversationTurn> {\n this.ensureInit();\n if (!this.conversation) throw new Error('No active planner conversation. Start planning first.');\n this.conversation.setProgress(onProgress);\n const combinedSignal = this.startAbortScope(signal);\n try {\n const result = await this.runConversationTurn(this.conversation.ctx, userMessage, onProgress, combinedSignal);\n if (result.kind === 'plan') this.conversation = null;\n return result;\n } finally {\n this.stopAbortScope();\n }\n }\n\n protected abstract streamPlanText(\n prompt: string,\n repairHint: string | undefined,\n onToken: (token: string) => void,\n onReasoning?: (token: string) => void,\n signal?: AbortSignal,\n ): Promise<string>;\n\n /**\n * Build a fresh chat for one research subagent (own history, subagent system\n * prompt, cheap model). Null means the provider does not support subagents —\n * the spawn tool then degrades to a steering message. `onReasoning` streams\n * live reasoning deltas on models that expose them, same as the top-level loop.\n */\n protected createSubagentChat(_onReasoning?: (delta: string) => void): ResearchChat | null { return null; }\n\n /**\n * One spawn_research_agent tool call, executed at the service layer (not in\n * executeTool — that would cycle the imports). Every failure path returns a\n * steering/failed result and the loop continues sequentially: a subagent can\n * never fail a plan or a turn.\n */\n private async executeSpawnAgent(\n args: Record<string, unknown>,\n fs: IFileSystem,\n onProgress: (progress: ResearchProgress) => void,\n signal: AbortSignal | undefined,\n subagentId: string,\n ): Promise<{ success: boolean; output: string; truncated: boolean }> {\n if (!this.researchSubagentsEnabled) {\n return { success: false, output: 'spawn_research_agent is not available in this session. Continue researching sequentially with your other tools (read_file, glob, grep, list_dir, bash).', truncated: false };\n }\n const prompt = typeof args.prompt === 'string' ? args.prompt.trim() : '';\n if (!prompt) {\n return { success: false, output: 'spawn_research_agent requires a non-empty \"prompt\" string: a self-contained task for the agent, including what its digest must report back.', truncated: false };\n }\n return runResearchAgent(prompt, {\n createChat: (onReasoning) => {\n const chat = this.createSubagentChat(onReasoning);\n if (!chat) throw new Error('subagent chats are not available for this provider');\n return chat;\n },\n fs,\n signal,\n onProgress: (progress) => onProgress({ ...progress, subagentId }),\n });\n }\n\n /** Collect project context for the planning phase. Shared with the harness backend. */\n protected static async collectResearchContext(fs: IFileSystem, runners: RunnerId[]): Promise<string> {\n return collectResearchContext(fs, runners);\n }\n\n /**\n * Execute one round of tool calls and report each through onProgress.\n * Returns the results to feed back plus the log entries produced.\n */\n private async executeToolCalls(\n toolCalls: ToolCall[],\n fs: IFileSystem,\n onProgress: (progress: ResearchProgress) => void,\n fetcher: IWebFetcher | undefined,\n stepIndex: number,\n thinking: string,\n signal?: AbortSignal,\n ): Promise<{ toolResults: ToolResult[]; logEntries: ResearchStep[]; resultsText: string }> {\n const toolResults: ToolResult[] = [];\n const logEntries: ResearchStep[] = [];\n let resultsText = '';\n let thinkingAttached = false;\n\n // Two concurrent pre-passes, then one ordered merge.\n //\n // Spawn calls have always run in parallel. The pure reads now do too: when\n // a model asks for six files in one round, six serial HTTP-free round trips\n // was simply latency we were choosing to pay. They are side-effect free and\n // order-independent, so the only thing sequencing bought was the illusion\n // of determinism — results are still merged back in call order below.\n //\n // Everything else (bash, fetch, web_search, unknown tools) stays serial:\n // those can block on a user approval prompt, and firing several prompts at\n // once would be hostile in every surface.\n const precomputed = new Map<number, { success: boolean; output: string; truncated: boolean }>();\n const spawnSubagentIds = new Map<number, string>();\n const normalizedArgs = toolCalls.map((tc) => {\n const args = { ...tc.args };\n if (tc.name === 'read_file' && !('maxBytes' in args) && !('limit' in args)) args.limit = 2000;\n return args;\n });\n\n const spawnIndexes = toolCalls.flatMap((tc, i) => (tc.name === SPAWN_RESEARCH_AGENT ? [i] : []));\n const parallelIndexes = toolCalls.flatMap((tc, i) => (PARALLEL_SAFE_TOOLS.has(tc.name) ? [i] : []));\n\n await Promise.all([\n spawnIndexes.length > 0\n ? mapWithConcurrency(spawnIndexes, SUBAGENT_LIMITS.maxConcurrent, async (i) => {\n const subagentId = uuidv4();\n spawnSubagentIds.set(i, subagentId);\n onProgress({ type: 'tool_call', tool: toolCalls[i].name, toolArgs: JSON.stringify(toolCalls[i].args), subagentId, toolCallId: toolCalls[i].id });\n precomputed.set(i, await this.executeSpawnAgent({ ...toolCalls[i].args }, fs, onProgress, signal, subagentId));\n })\n : Promise.resolve(),\n parallelIndexes.length > 1\n ? mapWithConcurrency(parallelIndexes, TOOL_ROUND_CONCURRENCY, async (i) => {\n onProgress({ type: 'tool_call', tool: toolCalls[i].name, toolArgs: JSON.stringify(toolCalls[i].args), toolCallId: toolCalls[i].id });\n precomputed.set(i, await executeTool(toolCalls[i].name, normalizedArgs[i], fs, fetcher));\n })\n : Promise.resolve(),\n ]);\n\n for (const [index, tc] of toolCalls.entries()) {\n const toolArgs = normalizedArgs[index];\n\n const preResult = precomputed.get(index);\n if (!preResult) onProgress({ type: 'tool_call', tool: tc.name, toolArgs: JSON.stringify(tc.args), toolCallId: tc.id });\n\n const toolResult = preResult ?? await executeTool(tc.name, toolArgs, fs, fetcher);\n\n const MAX_RESPONSE_CHARS = 50000;\n const truncatedResponse = toolResult.success && (toolResult.truncated || toolResult.output.length > MAX_RESPONSE_CHARS);\n const llmOutput = toolResult.output.length > MAX_RESPONSE_CHARS\n ? toolResult.output.slice(0, MAX_RESPONSE_CHARS) + `\\n[... truncated to ${MAX_RESPONSE_CHARS} chars, total ${toolResult.output.length}]`\n : toolResult.output;\n\n const LOG_MAX = 10000;\n const outcome = classifyOutcome(toolResult.success, toolResult.output);\n const stepEntry: ResearchStep = {\n id: `rs-${Date.now()}-${stepIndex}-${logEntries.length}`,\n tool: tc.name as ResearchStep['tool'],\n args: JSON.stringify(tc.args),\n result: toolResult.output.length > LOG_MAX\n ? toolResult.output.slice(0, LOG_MAX) + `\\n[... truncated, total ${toolResult.output.length} chars]`\n : toolResult.output,\n success: toolResult.success,\n outcome,\n toolCallId: tc.id,\n timestamp: new Date().toISOString(),\n ...(thinking && !thinkingAttached ? { thinkingText: thinking } : {}),\n };\n if (thinking && !thinkingAttached) thinkingAttached = true;\n logEntries.push(stepEntry);\n\n if (toolResult.success) {\n // llmOutput, not the raw output: the fallback plan prompt must not\n // carry text the conversation itself never saw.\n resultsText += `\\n[${tc.name}(${JSON.stringify(tc.args)})]\\n${llmOutput}\\n`;\n }\n\n onProgress({ type: 'tool_result', toolResult: toolResult.output, step: stepEntry, subagentId: spawnSubagentIds.get(index), toolCallId: tc.id });\n\n toolResults.push({ name: tc.name, output: llmOutput, truncated: truncatedResponse, totalChars: toolResult.output.length, id: tc.id });\n }\n\n return { toolResults, logEntries, resultsText };\n }\n\n /**\n * Countdown appended to the last tool result of the final few rounds, so the\n * model lands the turn on its own terms instead of being cut off exactly at\n * the budget boundary mid-exploration.\n */\n private static appendBudgetCountdown(toolResults: ToolResult[], remaining: number, wrapUpAction: string): void {\n if (remaining <= 0 || remaining > 3 || toolResults.length === 0) return;\n const note = `\\n\\n[research budget: only ${remaining} tool round${remaining === 1 ? '' : 's'} left this turn — prioritize the most important remaining lookups, then ${wrapUpAction}.]`;\n const last = toolResults[toolResults.length - 1];\n last.output += note;\n last.totalChars += note.length;\n }\n\n /**\n * Run one planner conversation turn (ADR-0002): send the message, satisfy\n * tool calls until the model answers in prose or JSON, then classify the\n * result. The model decides transitions — there are no sentinels, no\n * question tags, and no correction nags. A turn whose final text parses as\n * a `{tasks:[...]}` object commits the plan; anything else is a message to\n * the user.\n */\n protected async runConversationTurn(\n ctx: ConversationTurnContext,\n message: string,\n onProgress: (progress: ResearchProgress) => void,\n signal?: AbortSignal,\n ): Promise<ConversationTurn> {\n const researchLog: ResearchLogEntry[] = [];\n const MAX_STEPS = this.config.researchMaxSteps;\n\n // Turns reporting prompt-token pressure compact the underlying history\n // before the next call — the plan emission should never be the first\n // moment the context problem surfaces.\n const chat = withProactiveCompaction(ctx.chat);\n\n let pending = message;\n let emptyNudgeSent = false;\n // Broken JSON (a plan or task-ops attempt that failed to parse) gets a\n // bounded number of corrective re-emits before degrading to prose.\n let jsonRepairAttempts = 0;\n const MAX_JSON_REPAIRS = 2;\n for (;;) {\n let turn = await chat.sendMessage(pending, signal);\n\n // Wrap-up rounds after the tool budget runs out: the pending calls are\n // answered synthetically (never executed) so the API history stays\n // valid and the model is pushed to reply in prose. Bounded, because a\n // model could keep requesting tools forever.\n let wrapUpRounds = 0;\n for (let step = 0; turn.hasToolCalls; step++) {\n if (signal?.aborted) {\n onProgress({ type: 'interrupted' });\n return { kind: 'message', text: turn.text, researchLog };\n }\n if (step >= MAX_STEPS) {\n // Budget exhausted while the model still wants tools. Dropping the\n // calls here used to surface the model's preamble (\"Let me read…\")\n // as the reply and leave dangling tool_calls in the API history.\n if (wrapUpRounds >= 2) break;\n wrapUpRounds++;\n const notice = `Research tool budget for this turn is exhausted (${MAX_STEPS} rounds) — this call was NOT executed and no further tool calls will be. Reply to the user now using what you already learned: summarize your findings and ask how to proceed, ask your next question, or emit the plan JSON.`;\n // These calls are answered without running. Reporting them as\n // not-executed steps keeps the budget boundary visible; dropping\n // them silently made a whole refused round look like it never\n // happened on every surface.\n for (const tc of turn.toolCalls) {\n const step: ResearchStep = {\n id: `rs-${Date.now()}-budget-${researchLog.length}`,\n tool: tc.name as ResearchStep['tool'],\n args: JSON.stringify(tc.args),\n result: notice,\n success: false,\n outcome: 'not_executed',\n toolCallId: tc.id,\n timestamp: new Date().toISOString(),\n };\n researchLog.push(step);\n onProgress({ type: 'tool_call', tool: tc.name, toolArgs: step.args, toolCallId: tc.id });\n onProgress({ type: 'tool_result', toolResult: notice, step, toolCallId: tc.id });\n }\n turn = await chat.sendToolResults(\n turn.toolCalls.map((tc) => ({ name: tc.name, output: notice, truncated: false, totalChars: notice.length, id: tc.id })),\n signal,\n );\n continue;\n }\n const thinking = turn.reasoning ? turn.reasoning.slice(-200) : '';\n const { toolResults, logEntries } = await this.executeToolCalls(\n turn.toolCalls, ctx.fs, onProgress, ctx.fetcher, step, thinking, signal,\n );\n researchLog.push(...logEntries);\n BaseAiService.appendBudgetCountdown(toolResults, MAX_STEPS - step - 1, 'reply to the user (summary, question, or plan JSON)');\n turn = await chat.sendToolResults(toolResults, signal);\n }\n\n // A plain-reply turn (no tool calls) never passes through the loop\n // above, so this is the first point it can notice an abort raised\n // while its HTTP call was already in flight — without it, a stale\n // turn classifies and returns as a normal plan/message after reset().\n if (signal?.aborted) {\n onProgress({ type: 'interrupted' });\n return { kind: 'message', text: turn.text, researchLog };\n }\n\n // Forced break with nothing to show: degrade to a visible failure\n // instead of an empty planner bubble.\n if (turn.hasToolCalls && !turn.text.trim()) {\n return {\n kind: 'message',\n text: `I hit the research tool budget for this turn (${MAX_STEPS} rounds) before finishing. Tell me to continue, or narrow the request.`,\n researchLog,\n };\n }\n\n // An empty turn (no text, no tool calls — flash-lite does this) would\n // leave the user staring at silence. Nudge the model once; if it comes\n // back empty again, degrade to a visible failure.\n if (!turn.text.trim()) {\n if (!emptyNudgeSent && !signal?.aborted) {\n emptyNudgeSent = true;\n pending = 'Your last reply was empty. Respond to the user now: answer their last message directly, ask your next question, or emit the plan JSON.';\n continue;\n }\n return {\n kind: 'message',\n text: 'The planner returned an empty reply twice. Please rephrase or try again.',\n researchLog,\n };\n }\n\n if (extractPrdBlock(turn.text)) ctx.prdCaptured = true;\n\n // What did the model emit? PlanRepair owns the classification (envelope\n // keys, attempt-detection) and the corrective prompt texts; this loop\n // only applies its policies: the repair budget, the abort guard, and\n // the PRD gate.\n const reply = classifyPlannerReply(turn.text, {\n runners: ctx.runners,\n runnerModes: ctx.runnerModes,\n autonomousDefault: ctx.autonomousDefault,\n });\n\n switch (reply.kind) {\n case 'task_ops':\n return { kind: 'task_ops', ops: reply.ops, text: turn.text, researchLog };\n\n case 'plan':\n // PRD mode fail-safe: a cheap model that skips the PRD and jumps to\n // JSON would otherwise commit a plan with no PRD on record. Bounce\n // once with a corrective message; if it still refuses, accept the\n // plan rather than trap the user in a loop.\n if (ctx.prdEnabled && !ctx.prdCaptured && !ctx.prdNudgeSent && !signal?.aborted) {\n ctx.prdNudgeSent = true;\n pending = [\n 'PRD mode is enabled but no PRD has been produced yet, so the plan was NOT committed.',\n 'In your next reply: first output the full markdown PRD wrapped EXACTLY in',\n '<!-- ORDEWELL_PRD_START slug=\"<feature-slug>\" --> and <!-- ORDEWELL_PRD_END -->,',\n 'then re-emit the exact same task plan JSON after the PRD block.',\n ].join(' ');\n continue;\n }\n return { kind: 'plan', tasks: reply.tasks, text: turn.text, researchLog };\n\n // Botched attempts get a bounded corrective retry — otherwise the\n // broken JSON would surface as a prose bubble and the edit or plan\n // would silently fail to commit.\n case 'broken_task_ops':\n if (jsonRepairAttempts < MAX_JSON_REPAIRS && !signal?.aborted) {\n jsonRepairAttempts++;\n pending = reEmitTaskOpsPrompt(reply.error.message);\n continue;\n }\n break;\n\n case 'broken_plan':\n if (jsonRepairAttempts < MAX_JSON_REPAIRS && !signal?.aborted) {\n jsonRepairAttempts++;\n if (reply.error.truncated || turn.finishReason === 'length') {\n // Output-limit truncation: re-asking in the same context would be\n // cut at the same point. Free input space first (raw transcripts\n // pruned, digests kept), then ask for a terser re-emit.\n const removed = chat.compactHistory?.() ?? 0;\n pending = truncatedPlanReEmitPrompt(removed > 0);\n } else {\n pending = reEmitPlanPrompt(reply.error.message);\n }\n continue;\n }\n break;\n\n case 'prose':\n break;\n }\n\n return { kind: 'message', text: turn.text, researchLog };\n }\n }\n\n /**\n * Run the LLM tool-calling research loop for one-shot planning. Returns\n * parsed tasks if a plan was emitted mid-loop, or null if the loop\n * exhausted without a valid plan.\n */\n protected async runResearchLoop(\n chat: ResearchChat,\n firstMessage: string,\n fs: IFileSystem,\n onProgress: (progress: ResearchProgress) => void,\n runners: RunnerId[],\n initialLog?: ResearchLogEntry[],\n fetcher?: IWebFetcher,\n userGoal?: string,\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n autonomousDefault?: boolean,\n signal?: AbortSignal,\n ): Promise<{ tasks: Task[] | null; researchLog: ResearchLogEntry[]; researchResults: string }> {\n const researchLog: ResearchLogEntry[] = initialLog ? [...initialLog] : [];\n if (!initialLog && userGoal) {\n researchLog.push({\n id: `up-${Date.now()}`,\n type: 'user_prompt',\n content: userGoal,\n timestamp: new Date().toISOString(),\n });\n }\n let researchResults = '';\n const MAX_STEPS = this.config.researchMaxSteps;\n\n chat = withProactiveCompaction(chat);\n let turn = await chat.sendMessage(firstMessage, signal);\n\n for (let step = 0; step < MAX_STEPS; step++) {\n if (signal?.aborted) {\n onProgress({ type: 'interrupted' });\n return { tasks: null, researchLog, researchResults };\n }\n // Prefer the model's reasoning channel for the live thinking trace; fall back to\n // the answer content when a model doesn't expose reasoning separately.\n const thinking = turn.reasoning ? turn.reasoning.slice(-200) : turn.text.slice(-200);\n\n // A research turn is a candidate plan whenever its (reasoning-free) content\n // carries a tasks key — not only when it starts with `{`. Reasoning models often\n // emit a short preamble before the JSON; throwing that away forced a wasteful\n // second LLM call even when the plan was already in hand.\n const reply = classifyPlannerReply(turn.text, { runners, runnerModes, autonomousDefault });\n if (reply.kind === 'plan') {\n return { tasks: reply.tasks, researchLog, researchResults };\n }\n\n if (!turn.hasToolCalls) break;\n\n const { toolResults, logEntries, resultsText } = await this.executeToolCalls(\n turn.toolCalls, fs, onProgress, fetcher, step, thinking, signal,\n );\n researchLog.push(...logEntries);\n researchResults += resultsText;\n\n BaseAiService.appendBudgetCountdown(toolResults, MAX_STEPS - step - 1, 'emit the plan JSON');\n turn = await chat.sendToolResults(toolResults, signal);\n }\n\n if (turn.text) {\n researchResults += `\\n[LLM response]\\n${turn.text}\\n`;\n }\n\n return { tasks: null, researchLog, researchResults };\n }\n\n protected async generatePlanFallback(\n userDescription: string,\n contextStr: string,\n researchResults: string,\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n runners: RunnerId[],\n onProgress: (progress: ResearchProgress) => void,\n researchLog: ResearchLogEntry[] = [],\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n autonomousDefault = true,\n signal?: AbortSignal,\n modes: PlannerModes = DEFAULT_PLANNER_MODES,\n ): Promise<{ tasks: Task[]; researchLog: ResearchLogEntry[] }> {\n // A long research phase (especially with subagents) can outgrow what one\n // prompt can carry alongside a full plan emission — bound it, digests first.\n const prompt = buildPlanWithResults(userDescription, contextStr, compactResearchResults(researchResults), modelsByRunner, runners, runnerModes, modes);\n const tasks = await generatePlanWithRepair((repairHint) =>\n this.streamPlanText(\n prompt,\n repairHint,\n (token) => onProgress({ type: 'plan_token', planToken: token }),\n (reasoning) => onProgress({ type: 'thinking', text: reasoning }),\n signal,\n ),\n runners,\n 2,\n runnerModes,\n autonomousDefault,\n );\n return { tasks, researchLog };\n }\n}\n","import type { UserSettings } from './SettingsService';\n\n/**\n * The mode toggles, as data, and which planner entry points honour each one.\n *\n * A toggle used to be a boolean threaded by hand down every path, which made an\n * intentional omission indistinguishable from a dropped one: the one-shot\n * planner honoured `verification` and silently ignored `review`, while every\n * surface still displayed review as ON. Declaring the scope is what makes the\n * difference visible — `modesFor` applies it, so a path cannot quietly diverge\n * from what this table says.\n */\n\n/** The id a surface shows and a user types. Deliberately not the settings key. */\nexport type ModeToggleId = 'grill-me' | 'tdd' | 'prd' | 'review' | 'verify' | 'research-subagents';\n\n/**\n * Where a toggle can take effect. `chat` is the conversation loop (ADR-0002),\n * `one-shot` the non-conversational planners (`ordewell plan --goal`, web REST),\n * `task` a runner task's prompt rather than the planner's.\n */\nexport type ModeScope = 'chat' | 'one-shot' | 'task';\n\n/** The settings-file keys that hold a toggle, as opposed to `modelAllowlist` and friends. */\ntype ToggleSettingsKey = {\n // `-?` because an optional member (`modelAllowlist`) otherwise widens the\n // lookup to include `undefined`, which cannot index anything.\n [K in keyof UserSettings]-?: UserSettings[K] extends { enabled: boolean } ? K : never;\n}[keyof UserSettings];\n\n/** How the same toggle is named once a host has read it off disk. */\nexport interface PlannerRuntimeToggles {\n grillMeEnabled: boolean;\n tddEnabled: boolean;\n prdEnabled: boolean;\n reviewEnabled: boolean;\n verificationEnabled: boolean;\n researchSubagentsEnabled: boolean;\n}\n\nexport interface ModeToggle {\n id: ModeToggleId;\n /** Key in the persisted settings file. `verify` maps to `verification`. */\n settingsKey: ToggleSettingsKey;\n /** Key a host passes to the Session. `review` on disk is `reviewEnabled` here. */\n runtimeKey: keyof PlannerRuntimeToggles;\n scopes: readonly ModeScope[];\n}\n\nexport const MODE_TOGGLES: readonly ModeToggle[] = [\n // Both of these interview the user, and a one-shot run has nobody to ask —\n // its prompt says so outright. Their absence there is a decision, not a gap.\n { id: 'grill-me', settingsKey: 'grillMe', runtimeKey: 'grillMeEnabled', scopes: ['chat'] },\n { id: 'prd', settingsKey: 'prd', runtimeKey: 'prdEnabled', scopes: ['chat'] },\n // Structural: append a final review task. Nothing about it needs a dialogue.\n { id: 'review', settingsKey: 'review', runtimeKey: 'reviewEnabled', scopes: ['chat', 'one-shot'] },\n { id: 'verify', settingsKey: 'verification', runtimeKey: 'verificationEnabled', scopes: ['chat', 'one-shot'] },\n { id: 'research-subagents', settingsKey: 'researchSubagents', runtimeKey: 'researchSubagentsEnabled', scopes: ['chat', 'one-shot'] },\n { id: 'tdd', settingsKey: 'tdd', runtimeKey: 'tddEnabled', scopes: ['task'] },\n];\n\n/**\n * Read every toggle off the settings file under the name a Session expects.\n *\n * Both hosts used to hand-map `getReview()` to `reviewEnabled` and its five\n * siblings, in two identical blocks that nothing kept in step — which is how a\n * toggle came to have three unrelated names and how one of them got dropped.\n * Callers add whatever else `SessionRuntimeSettings` carries (`modelAllowlist`).\n */\nexport function plannerRuntimeToggles(settings: UserSettings): PlannerRuntimeToggles {\n const toggles = {} as PlannerRuntimeToggles;\n for (const toggle of MODE_TOGGLES) toggles[toggle.runtimeKey] = settings[toggle.settingsKey].enabled;\n return toggles;\n}\n\n/**\n * The planner-facing mode set for one operation. Replaces the boolean tail that\n * every planner signature used to carry positionally — where a thirteenth\n * parameter was the only place left to put a new toggle.\n */\nexport interface PlannerModes {\n autonomousDefault: boolean;\n grillMe: boolean;\n prd: boolean;\n review: boolean;\n verification: boolean;\n researchSubagents: boolean;\n}\n\nexport const DEFAULT_PLANNER_MODES: PlannerModes = {\n autonomousDefault: true,\n grillMe: false,\n prd: false,\n review: false,\n verification: false,\n researchSubagents: false,\n};\n\n/** Read the toggles a planner cares about off whatever the settings callback returned. */\nexport function plannerModesFrom(\n settings: {\n grillMeEnabled?: boolean;\n prdEnabled?: boolean;\n reviewEnabled?: boolean;\n verificationEnabled?: boolean;\n researchSubagentsEnabled?: boolean;\n },\n autonomousDefault: boolean,\n): PlannerModes {\n return {\n autonomousDefault,\n grillMe: settings.grillMeEnabled ?? false,\n prd: settings.prdEnabled ?? false,\n review: settings.reviewEnabled ?? false,\n verification: settings.verificationEnabled ?? false,\n researchSubagents: settings.researchSubagentsEnabled ?? false,\n };\n}\n\nconst MODE_FIELD: Record<ModeToggleId, keyof PlannerModes | null> = {\n 'grill-me': 'grillMe',\n prd: 'prd',\n review: 'review',\n verify: 'verification',\n 'research-subagents': 'researchSubagents',\n tdd: null,\n};\n\n/**\n * Clear the toggles this scope does not honour, so a prompt builder reads a\n * mode set that already tells the truth about the path it is on.\n */\nexport function modesFor(scope: ModeScope, modes: PlannerModes): PlannerModes {\n const scoped = { ...modes };\n for (const toggle of MODE_TOGGLES) {\n const field = MODE_FIELD[toggle.id];\n if (field && !toggle.scopes.includes(scope)) scoped[field] = false;\n }\n return scoped;\n}\n","import { DiscoveredModel, RunnerId, type TaskSnapshot, type Task } from '../models/Task';\nimport type { LegacyPlanState } from '../models/Task';\nimport { buildModeGuide, filteredBuildModes, type RunnerModeInfo } from './ModeResolver';\nimport { DEFAULT_PLANNER_MODES, modesFor, type PlannerModes } from './plannerModes';\n\nexport function buildResearchToolsPrompt(subagentsEnabled = false): string {\n const lines = [\n 'You have access to the following tools to explore the workspace:',\n '',\n 'read_file(path: string, offset?: number, limit?: number) - Read file contents with line numbers and optional pagination. offset is a 0-based line number (default 0). limit is max lines (default 2000). Output lines are prefixed with their line numbers. When a file has more lines than requested, a hint shows the offset to use next. Files larger than ~1 MB are rejected — use grep instead.',\n 'read_files(paths: string[]) - Read multiple files at once. Batch reads when you have several known paths — this is faster than calling read_file repeatedly.',\n 'glob(pattern: string) - Find files matching a glob pattern (e.g. \"src/**/*.ts\"). Use for finding files by name/path. Results sorted by modification time, newest first.',\n 'grep(pattern: string, include?: string) - Search for a regex pattern inside file contents. Use for finding code patterns, function definitions, imports, etc. Use \"include\" to filter by file type (e.g. \"*.ts\").',\n 'list_dir(path: string, depth?: number) - List directory contents as a tree. Use for orientation — to see what directories and files exist. Use depth=2 or depth=3 for a tree view.',\n 'bash(command: string) - Run a read-only shell command (ls, tree, git log/status/diff, cat, head, wc, etc.). Do NOT use bash for file search — use the dedicated glob and grep tools instead.',\n '',\n 'TOOL CHOICE GUIDE:',\n '- list_dir: for browsing/orientation and understanding project structure',\n '- glob: for finding files by name/path pattern',\n '- grep: for searching inside file contents',\n '',\n 'When multiple independent tool calls are needed, batch them in a single response to save round-trips. For example, if you need to read README.md and AGENTS.md, call read_files with both paths at once.',\n ];\n if (subagentsEnabled) {\n lines.push(\n '',\n 'spawn_research_agent(prompt: string) - Launch a stateless read-only research agent that explores the workspace with its own tools and returns a digest. Use it to delegate an open-ended exploration thread — a subsystem to map, or a \"how does X work here\" question — whenever one emerges during research. To explore several independent areas, launch the agents CONCURRENTLY: put multiple spawn_research_agent calls in one reply and they run in parallel.',\n 'The agent sees nothing of this conversation, so its prompt must be self-contained: the area or question, the paths/symbols to start from, and exactly what the digest must report back. Do NOT use it on small or single-subsystem repos, or to read one known file — direct tools are faster there.',\n );\n }\n return lines.join('\\n');\n}\n\n/**\n * System prompt for one read-only research subagent (issue #34). The digest\n * contract matters: the reply goes back to the planner as a tool result, so it\n * must be dense, self-contained, and carry exact file paths — never questions,\n * never a task plan.\n */\nexport function buildSubagentSystemPrompt(): string {\n return [\n 'You are a read-only research subagent working for a project planner. You receive one self-contained research task, explore the workspace with your tools, and reply with a single digest. You never modify files, never fetch URLs, and cannot spawn further agents.',\n '',\n 'Work efficiently: batch independent tool calls in one reply; prefer glob/grep to locate, then read only what matters. Your tool budget is small — stop exploring when you can answer the task.',\n '',\n 'Your final reply IS the digest — it goes straight back to the planner, not to a human. It must contain:',\n '- The exact file paths (and key line references) relevant to the task',\n '- The key symbols/functions involved and how they connect',\n '- Constraints, gotchas, or conventions the planner must respect',\n '- Direct answers to every question the task asked',\n 'Plain prose/markdown only. No questions, no task plans, no JSON. Be dense and specific; vague summaries are useless to the planner.',\n ].join('\\n');\n}\n\nfunction buildModeGuideForRunners(runners: RunnerId[], _autonomousDefault: boolean): string {\n const lines = ['Assign a \"taskMode\" to each AI task based on the runner:'];\n for (const r of runners) {\n if (r === 'claude-code') {\n lines.push('- For claude-code: \"acceptEdits\" (edit automatically, recommended), \"default\" (ask before edits), \"plan\" (read-only analysis), \"bypassPermissions\" (skip all prompts, CI only).');\n } else if (r === 'opencode') {\n lines.push('- For opencode: \"build\" (full access agent), \"plan\" (read-only analysis).');\n } else {\n lines.push(`- For ${r}: use the modes from the runner's manifest.`);\n }\n }\n lines.push('Use the recommended mode for implementation. Use \"plan\" for analysis-only requests.');\n return lines.join('\\n');\n}\n\nfunction buildModeExamplesForRunners(runners: RunnerId[]): string {\n return runners.map(r => {\n if (r === 'claude-code') return 'claude-code: acceptEdits|default|plan|bypassPermissions';\n if (r === 'opencode') return 'opencode: build|plan';\n return `${r}: default|plan`;\n }).join(', ');\n}\n\n/**\n * Verification mode (evidence-based, AFK) is the counterpart to review mode\n * (opinion-based, HITL): a final task whose verdict comes from running the\n * suite, closing the \"every task passed but the feature is short\" gap that\n * per-task exit codes cannot see.\n */\nfunction verificationModeBlock(reviewAlsoEnabled = false): string {\n return [\n '',\n 'VERIFICATION MODE:',\n reviewAlsoEnabled\n ? 'Add a FINAL verification task immediately before the review task. The review task keeps the highest order number and must list the verification task among its dependencies.'\n : 'Add a FINAL verification task to the end of the plan (highest order number).',\n 'This task closes the gap between \"every task finished\" and \"the feature is correct\": tasks executed in isolated sessions can each pass while the integrated feature is still short. Its outcome must come from commands and exit codes, never from judgement.',\n 'This task must:',\n '- Have type \"ai\" and autonomy \"AFK\" — it needs no human input',\n '- Have dependencies on ALL other AI tasks in the plan',\n '- Use the same runner as the other tasks; a mid-tier model is fine (the work is running and writing tests, not architecture)',\n '- Its prompt should instruct the agent to:',\n ' * Re-read the ORIGINAL goal (and the PRD at `.scratch/<slug>/PRD.md` if one exists) — the whole feature spec, not any single task\\'s slice',\n ' * Run the project\\'s full test suite and typecheck/build, and fix any failure it finds',\n ' * If the project has NO test infrastructure, do not bootstrap a framework just for verification (unless an earlier task already added one) — instead write a standalone verification script that exercises the feature end-to-end through its public interface and exits non-zero on any failed check, and run it',\n ' * Walk the spec requirement by requirement — including every edge case the spec mentions — and check each one is covered by an executable test; write the missing tests at the public interface and make them pass',\n ' * Exercise the feature END-TO-END: integration gaps between task boundaries are this task\\'s responsibility',\n ' * Succeed ONLY when the full suite, including the newly written tests, is green; if a check cannot be made to pass, fail the task loudly — never skip, weaken, or delete a check to get green',\n ].join('\\n');\n}\n\n/**\n * The research-phase instructions, in the two variants the planner ships\n * (ADR-0009).\n *\n * The API variant names Ordewell's own tools because Ordewell is the one running\n * them. A harness planner brings its own toolbox, so naming `list_dir` or\n * `glob` there would be telling a coding agent to call tools it does not have.\n *\n * Only this block and the tool-envelope appendix differ between the two: the\n * plan schema, the runner and mode vocabulary, the model catalog, the\n * conversational protocol and every mode-toggle block are shared verbatim. A\n * forked prompt would mean each future toggle gets written twice, or silently\n * works on one backend only.\n */\nfunction researchPhaseBlock(harnessMode: boolean): string {\n const shared = [\n 'RESEARCH PHASE:',\n '- Start by reading README.md and any agent config files (AGENTS.md, CLAUDE.md)',\n ];\n const toolSpecific = harnessMode\n ? [\n '- Explore the repository with your own tools until you understand its architecture',\n '- You are planning, not implementing: do NOT edit, create, or delete any file, and do not run commands that change the workspace',\n ]\n : [\n '- Use list_dir with depth=2-3 for a tree overview',\n '- Use glob and grep to find relevant source files',\n '- Read key source files to understand architecture',\n ];\n return [\n ...shared,\n ...toolSpecific,\n '- Synthesize tool findings into your messages. The user does not see raw tool output; only your synthesis reaches them.',\n '- Research and questions can interleave — you can explore a file, then ask a question grounded in it, in one response',\n ].join('\\n');\n}\n\nexport function buildConversationSystemPrompt(\n goal: string,\n context: string,\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n runners: RunnerId[],\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n autonomousDefault = true,\n grillMeEnabled = false,\n prdEnabled = false,\n reviewEnabled = false,\n verificationEnabled = false,\n /** Harness planner (ADR-0009): the agent owns its own tools and research budget. */\n harnessMode = false,\n): string {\n const modelsJson = modelsJsonFor(modelsByRunner, runners);\n const modeGuide = runnerModes ? buildModeGuide(runnerModes, autonomousDefault) : buildModeGuideForRunners(runners, autonomousDefault);\n\n const modeExamples = runnerModes\n ? Object.entries(runnerModes).map(([r, ms]) => {\n const filtered = filteredBuildModes(ms, autonomousDefault);\n return `${r}: ${filtered.map(m => m.id).join('|')}${ms.some(m => m.id === 'plan') ? '|plan' : ''}`;\n }).join(', ')\n : buildModeExamplesForRunners(runners);\n\n const grillMeBlock = grillMeEnabled ? [\n '',\n 'INTERVIEW MODE — GRILL-ME:',\n 'Interview the user relentlessly about every aspect of their goal until you reach a shared understanding. Walk down each branch of the design tree, resolving dependencies between decisions one-by-one.',\n 'Ask one question at a time, waiting for the user\\'s answer before continuing. For each question, propose your recommended answer so they can confirm or correct it. Asking multiple questions at once is bewildering.',\n 'If a fact can be found by exploring the codebase, look it up instead of asking. The decisions, though, are the user\\'s — put each one to them and wait.',\n 'Only propose an outline after the user has answered enough questions that you genuinely understand the goal. Then present the prose outline and wait for explicit confirmation before emitting the task plan JSON.',\n ].join('\\n') : '';\n\n const prdBlock = prdEnabled ? [\n '',\n 'PRD MODE: Before producing the outline, generate a PRD in two steps.',\n 'Step 1 — Propose a short prose preview containing: the problem statement, the proposed approach, the testing seams, and the main risks. Prefer existing seams over new ones; propose new seams at the highest point possible. The fewer seams across the codebase, the better — the ideal number is one. Propose a feature-slug for saving the PRD (e.g. `my-feature`). Ask the user whether they agree.',\n 'Step 2 — Only after the user explicitly agrees, write the full markdown PRD using the standard PRD format (problem, user stories, implementation decisions, testing seams, out of scope). The user may edit the proposed feature-slug before you write the PRD; use the agreed slug in the final output.',\n 'PRD content rules: user stories are an extensive numbered list, each \"As an <actor>, I want <feature>, so that <benefit>\". Record implementation decisions as decisions (modules, interfaces, schema changes, API contracts) — do NOT include specific file paths or code snippets; they go stale fast. Exception: a snippet from a prototype that encodes a decision more precisely than prose (state machine, reducer, schema, type shape) may be inlined, trimmed to the decision-rich parts.',\n 'When writing the full PRD, wrap it EXACTLY with these markers so the system can save it automatically:',\n '<!-- ORDEWELL_PRD_START slug=\"<feature-slug>\" -->',\n '... full markdown PRD ...',\n '<!-- ORDEWELL_PRD_END -->',\n 'Do NOT emit the full PRD before the user agrees to the preview. Do NOT emit task plan JSON before the PRD is agreed and the outline is confirmed.',\n ].join('\\n') : '';\n\n const reviewBlock = reviewEnabled ? reviewModeBlock() : '';\n const verificationBlock = verificationEnabled ? verificationModeBlock(reviewEnabled) : '';\n\n return buildConversationBody(\n goal, context, modelsJson, runners, modeGuide, modeExamples, harnessMode,\n grillMeBlock, prdBlock, reviewBlock, verificationBlock,\n );\n}\n\n/**\n * The review-mode instruction. Structural rather than conversational — it only\n * appends a task — so both the conversation loop and the one-shot planners emit\n * it; keeping one copy is what stopped them diverging.\n */\nfunction reviewModeBlock(): string {\n return [\n '',\n 'REVIEW MODE:',\n 'Add a FINAL review task to the end of the plan (highest order number).',\n 'This task must:',\n '- Have type \"ai\" and use the STRONGEST available model',\n '- Have dependencies on ALL other AI/user tasks in the plan',\n '- Be assigned appropriately as HITL (human review) since the results need human sign-off',\n '- Its prompt should instruct the agent to:',\n ' * Review every completed task\\'s outputs and verify the original goal was met',\n ' * Check that each task delivers what its description promised',\n ' * Review the work on two axes, reported SEPARATELY so one cannot mask the other:',\n ' - SPEC axis: if a PRD exists for this plan (`.scratch/<slug>/PRD.md`), verify against it: (a) requirements asked for but missing or partial; (b) behaviour delivered that the PRD never asked for (scope creep); (c) requirements that look implemented but wrongly. Quote the PRD line for each finding. With no PRD, review against the original goal.',\n ' - STANDARDS axis: check the diff against the repo\\'s documented coding standards (CONTRIBUTING.md, CLAUDE.md, etc.) plus this smell baseline: Mysterious Name (rename), Duplicated Code (extract shared shape), Feature Envy (move method to the data), Data Clumps (bundle into a type), Primitive Obsession (give the concept a type), Repeated Switches (polymorphism or shared map), Shotgun Surgery (gather into one module), Divergent Change (split by reason to change), Speculative Generality (delete it), Message Chains (hide the walk), Middle Man (call the target direct), Refused Bequest (composition over inheritance). Smell findings are always judgement calls, never hard failures; documented repo standards override the baseline; skip anything tooling already enforces.',\n ' * Produce a structured review report listing what was checked and whether each check passed',\n ' * Flag any gaps, bugs, or incomplete work',\n ' * Output a final PASS/FAIL conclusion with evidence (standards-axis judgement calls alone must not fail the verification)',\n '- Use the same runner as the other tasks',\n ].join('\\n');\n}\n\nfunction buildConversationBody(\n goal: string,\n context: string,\n modelsJson: string,\n runners: RunnerId[],\n modeGuide: string,\n modeExamples: string,\n harnessMode: boolean,\n grillMeBlock: string,\n prdBlock: string,\n reviewBlock: string,\n verificationBlock: string,\n): string {\n return [\n 'You are Ordewell\\'s project planner. You explore the codebase, ask concise clarifying questions grounded in your findings, and produce structured task plans as JSON. Be direct: avoid unnecessary preamble, summaries, or explanations unless the user asks for detail.',\n '',\n 'WORKFLOW:',\n '1. Explore the workspace with tools to understand the codebase.',\n '2. Ask clarifying questions grounded in your findings. Reference actual files. When the goal is vague, or a decision would materially change the outcome (storage engine, library choice, scope, API shape), ask the user BEFORE planning — never silently assume. Clear, fully-specified goals need no questions.',\n '3. When you have enough context, produce a prose outline — a short list describing each vertical slice in order.',\n '4. After the user confirms the outline, emit the final task plan as a JSON object with a \"tasks\" array.',\n '',\n researchPhaseBlock(harnessMode),\n grillMeBlock,\n prdBlock,\n reviewBlock,\n verificationBlock,\n '',\n 'OUTLINE PHASE:',\n '- When you are ready to propose a plan, first show a prose outline. DO NOT jump straight to JSON.',\n '- Format: a numbered list describing each vertical tracer-bullet slice, with the files/layers each slice touches.',\n '- Example: \"1. Set up database schema (src/db/schema.ts) — creates tables for users and sessions\\n2. Add auth middleware (src/auth/middleware.ts) — validates JWTs on protected routes\\n3. Build login page (src/ui/Login.tsx) — form component with validation\"',\n '- The user may reply with adjustments. Revise the outline and re-present it.',\n '- When the user confirms the outline, emit the task plan JSON.',\n '',\n 'PLAN FORMAT:',\n 'Generate a task plan using this JSON format:',\n '',\n '{',\n ' \"tasks\": [',\n ' {',\n ' \"id\": \"unique-task-id (any short unique string, e.g. task-1)\",',\n ' \"order\": 1,',\n ' \"title\": \"Concise title\",',\n ' \"description\": \"What this task accomplishes\",',\n ' \"type\": \"ai|user\",',\n ' \"dependencies\": [\"task-id-string\"],',\n ' \"prompt\": \"Detailed instructions for the AI assistant (ai tasks only)\",',\n ' \"userSteps\": [{ \"order\": 1, \"instruction\": \"Step description\", \"completed\": false }],',\n ' \"assignedModel\": { \"modelId\": \"model-id\", \"modelLabel\": \"Model Label\", \"thinkingEffort\": \"a variant id from that model\\'s variants list — omit if the model has none\" },',\n ' \"assignedRunner\": \"' + runners.join('|') + '\",',\n ' \"taskMode\": \"' + modeExamples + '\",',\n ' \"autonomy\": \"AFK|HITL\",',\n ' \"sliceType\": \"AFK|HITL\",',\n ' \"userStoriesCovered\": [\"user story text\"],',\n ' \"subtasks\": [{ \"id\": \"sub-id-string\", \"order\": 1, \"title\": \"Sub-step title\", \"description\": \"What it accomplishes\", \"type\": \"ai\", \"dependencies\": [], \"prompt\": \"Detailed instructions\", \"autonomy\": \"AFK|HITL\", \"sliceType\": \"AFK|HITL\", \"subtasks\": [] }]',\n ' }',\n ' ]',\n '}',\n '',\n 'VERTICAL SLICE PLANNING:',\n 'Design each task as a VERTICAL TRACER-BULLET SLICE — a narrow but complete, independently demoable path. Do NOT create horizontal layer-by-layer tasks.',\n '- Size each slice to fit a single fresh agent session\\'s context window — if a slice is too big, split it.',\n '- If preparatory refactoring would make the feature easier, make it its own leading task (\"make the change easy, then make the easy change\") and have dependent slices declare it as a dependency.',\n '- Wide mechanical refactors (rename a shared symbol, retype a column) whose blast radius spans the codebase are the exception to vertical slicing: sequence them as EXPAND-CONTRACT — one task adds the new form beside the old, parallel migration tasks (each depending on it) move call sites over in batches, and a final contract task depending on all migrations deletes the old form.',\n '',\n 'SLICE CLASSIFICATION:',\n '- \"autonomy\": AFK (agent works autonomously) or HITL (needs user confirmation)',\n '- \"sliceType\": Same vocabulary as autonomy.',\n '- AFK tasks MUST NOT contain \"userSteps\". HITL tasks MAY contain userSteps.',\n '- User tasks (type \"user\") always have sliceType \"HITL\".',\n '- \"sliceType\" is REQUIRED on every task, and \"autonomy\" on every \"ai\" task, at every depth — a \"subtasks\" entry is a full task object with all the same required fields, not a bare label.',\n '',\n 'DEPENDENCY & PARALLELISM:',\n '- Independent slices should have NO dependencies — they run in parallel.',\n '- Only add dependencies when a slice truly depends on artifacts another slice creates.',\n '',\n 'RULES:',\n '- Do NOT wrap the JSON in markdown code blocks. Output ONLY the JSON object when committing the plan.',\n '- Emit the outline BEFORE the JSON. Do not skip the outline.',\n '- Reference specific files and patterns from your research in task prompts.',\n '- For parallel tasks, specify different target files to avoid merge conflicts.',\n '',\n 'CONVENTIONS:',\n '- When suggesting libraries, frameworks, or patterns, first verify they already exist in the codebase. NEVER assume a library is available just because it is well-known. Check package.json, imports, or surrounding files first.',\n '- Follow the existing code style, naming conventions, and architectural patterns of the project.',\n '',\n 'MODEL ASSIGNMENT:',\n 'Available models:',\n modelsJson,\n '',\n runnerInstruction(runners),\n 'MODEL SELECTION GUIDELINES:',\n '- Use stronger models for complex refactoring, architecture changes, security-critical code.',\n '- Use weaker/faster models for simple file operations, test generation, config changes, documentation.',\n '- Assign thinkingEffort based on task complexity, choosing ONLY from the assigned model\\'s \"variants\" list above (e.g. low for simple tasks, high for complex ones). Omit thinkingEffort if the model has no variants.',\n '',\n 'TASK MODE:',\n modeGuide,\n '',\n context ? `PROJECT CONTEXT:\\n${context}\\n` : '',\n `USER GOAL: ${goal}`,\n ].join('\\n');\n}\n\nconst RESEARCH_SECTION = [\n 'PHASE 1 - RESEARCH:',\n 'First, use the available tools to explore the workspace thoroughly. You can combine independent steps into a single response to save round-trips — for instance, read README.md and AGENTS.md simultaneously.',\n '- Start by reading README.md and any agent config files (AGENTS.md, CLAUDE.md)',\n '- Use list_dir with depth=3 for a tree overview of the project structure',\n '- Use glob to find relevant source files by pattern',\n '- Use grep to search for code patterns related to the user\\'s goal',\n '- Read key source files to understand existing architecture',\n '- Do NOT use bash for file search — use glob/grep/list_dir instead',\n '- Only generate the plan AFTER you have enough context',\n '{{CLARIFICATION_INSTRUCTIONS}}',\n].join('\\n');\n\nconst ONE_SHOT_INSTRUCTIONS = [\n '',\n 'This is a ONE-SHOT run: there is no user to ask questions to. Where the request is ambiguous, make the most reasonable assumption grounded in your research and record it in the relevant task description.',\n '',\n].join('\\n');\n\nexport const CORE_PLANNER_PROMPT = [\n 'You are a software project planner that produces structured task plans as JSON.',\n 'Given a user\\'s goal, create an ordered list of tasks that accomplish it.',\n '',\n 'Generate a task plan using this JSON format:',\n '',\n '{',\n ' \"tasks\": [',\n ' {',\n ' \"id\": \"unique-task-id (any short unique string, e.g. task-1)\",',\n ' \"order\": 1,',\n ' \"title\": \"Concise title summarizing the task\",',\n ' \"description\": \"What this task accomplishes\",',\n ' \"type\": \"ai|user\",',\n ' \"dependencies\": [\"task-id-string\"],',\n ' \"prompt\": \"Detailed instructions for the AI assistant (ai tasks only)\",',\n ' \"userSteps\": [{ \"order\": 1, \"instruction\": \"Step description\", \"completed\": false }],',\n ' \"assignedModel\": { \"modelId\": \"model-id\", \"modelLabel\": \"Model Label\", \"thinkingEffort\": \"a variant id from that model\\'s variants list — omit if the model has none\" },',\n ' \"assignedRunner\": \"{{RUNNER_CHOICES}}\",',\n ' \"taskMode\": \"{{MODE_EXAMPLES}}\",',\n ' \"autonomy\": \"AFK|HITL\",',\n ' \"sliceType\": \"AFK|HITL\",',\n ' \"userStoriesCovered\": [\"user story text\"],',\n ' \"subtasks\": [{ \"id\": \"sub-id-string\", \"order\": 1, \"title\": \"Sub-step title\", \"description\": \"What it accomplishes\", \"type\": \"ai\", \"dependencies\": [], \"prompt\": \"Detailed instructions\", \"autonomy\": \"AFK|HITL\", \"sliceType\": \"AFK|HITL\", \"subtasks\": [] }]',\n ' }',\n ' ]',\n '}',\n '',\n 'VERTICAL SLICE PLANNING:',\n 'Design each task as a VERTICAL TRACER-BULLET SLICE — a narrow but complete, independently demoable path that cuts through all layers (schema → backend logic → API/route → UI/consumer → tests). Do NOT create horizontal layer-by-layer tasks (e.g. \"build all models\", then \"build all routes\", then \"build all tests\"). Each slice should stand alone as a working end-to-end increment.',\n '- Size each slice to fit a single fresh agent session\\'s context window — if a slice is too big, split it.',\n '- If preparatory refactoring would make the feature easier, make it its own leading task (\"make the change easy, then make the easy change\") and have dependent slices declare it as a dependency.',\n '- Wide mechanical refactors (rename a shared symbol, retype a column) whose blast radius spans the codebase are the exception to vertical slicing: sequence them as EXPAND-CONTRACT — one task adds the new form beside the old, parallel migration tasks (each depending on it) move call sites over in batches, and a final contract task depending on all migrations deletes the old form.',\n '',\n 'SLICE CLASSIFICATION:',\n '- \"autonomy\": Classify each AI task as AFK (Away From Keyboard — the agent works autonomously with no user interaction needed) or HITL (Human In The Loop — the agent needs user confirmation, review, or input partway through).',\n '- \"sliceType\": Same vocabulary as autonomy. Use HITL for tasks that contain user-facing touchpoints (manual verification, approval gates, UI decisions a human must make). Use AFK for fully autonomous slices.',\n '- \"userStoriesCovered\": Link each task to the specific user story/stories from the PRD that it delivers. Copy the exact user story text.',\n '- AFK tasks MUST NOT contain \"userSteps\" — they are fully autonomous. HITL tasks MAY contain userSteps for the human touchpoints.',\n '- User tasks (type \"user\") always have sliceType \"HITL\" and must include \"userSteps\".',\n '- \"sliceType\" is REQUIRED on every task, and \"autonomy\" on every \"ai\" task, at every depth — a \"subtasks\" entry is a full task object with all the same required fields, not a bare label.',\n '',\n 'DEPENDENCY & PARALLELISM RULES:',\n '- Independent vertical slices (no shared files/modules) should have NO dependencies between them — they can run in parallel.',\n '- Only add dependencies when the second slice truly depends on artifacts (files, APIs) that the first slice creates.',\n '- Prefer parallelism over serial chains. A plan with 3 independent slices running in parallel is better than 3 sequential tasks.',\n '- Slices that touch different areas of the codebase are naturally parallel.',\n '',\n 'RULES:',\n '- Mark as type \"ai\" any task the coding assistant can do autonomously.',\n '- Mark as type \"user\" any task requiring manual action outside the codebase.',\n '- Each AI task must have a detailed \"prompt\" field with clear, specific instructions. Include the exact files to create/modify.',\n '- Each user task must have \"userSteps\" with an ordered array of step-by-step instructions.',\n '- Tasks can have \"subtasks\" for finer-grained sub-steps.',\n '- Use concise but clear titles and descriptions.',\n '',\n 'PROMPT QUALITY RULES:',\n '- Include specific file paths discovered during research in prompts (e.g. \"In src/components/Settings.tsx\").',\n '- Reference existing patterns and hooks found in the codebase (e.g. \"Use the existing useLocalStorage hook from src/hooks/useLocalStorage.ts\").',\n '- For parallel tasks, specify different target files to avoid merge conflicts.',\n '',\n 'Do NOT wrap the JSON in markdown code blocks. Output ONLY the JSON object.',\n].join('\\n');\n\nfunction getPlanTemplate(): string {\n return [\n CORE_PLANNER_PROMPT,\n '',\n '{{RESEARCH_SECTION}}',\n 'MODEL ASSIGNMENT:',\n 'You must assign an \"assignedModel\" to each AI task. Available models:',\n '',\n '{{MODELS_JSON}}',\n '',\n '{{RUNNER_INSTRUCTION}}',\n 'MODEL SELECTION GUIDELINES:',\n '- Use stronger models (Opus, DeepSeek V4 Pro, Kimi 2.6) for: complex refactoring, architecture changes, security-critical code, performance optimization, large-scale changes.',\n '- Use weaker/faster models (Sonnet, DeepSeek V4 Flash) for: simple file operations, test generation, config changes, documentation, straightforward bug fixes.',\n '- Assign thinkingEffort based on task complexity: \"low\" for simple tasks, \"medium\" or \"high\" for moderate/complex tasks.',\n ' For OpenCode models that support variants (e.g. deepseek-v4-pro), use the variant IDs from the models list.',\n ' For Claude Code, use the variant IDs listed for each model in the models list (adaptive, low, medium, high, xhigh, max — per-model).',\n ' Omit thinkingEffort if the model has no variants.',\n '',\n 'TASK MODE:',\n '{{MODE_GUIDE}}',\n '{{REVIEW_BLOCK}}',\n '{{VERIFICATION_BLOCK}}',\n '',\n 'CONTEXT:',\n '{{CONTEXT}}',\n '{{RESEARCH_RESULTS}}',\n ].join('\\n');\n}\n\nfunction serializeModels(models: DiscoveredModel[]) {\n return models.map((m) => ({ modelId: m.modelId, modelLabel: m.modelLabel, variants: m.variants }));\n}\n\nfunction modelsJsonFor(\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n runners: RunnerId[]\n): string {\n const out: Record<string, ReturnType<typeof serializeModels>> = {};\n for (const r of runners) {\n out[r] = serializeModels(modelsByRunner[r] ?? []);\n }\n return JSON.stringify(out, null, 2);\n}\n\nfunction runnerInstruction(runners: RunnerId[]): string {\n const modelList = runners.map(r => `\"${r}\"`).join(' or ');\n if (runners.length > 1) {\n return [\n 'RUNNER ASSIGNMENT (MULTI-RUNNER MODE):',\n `Multiple runners are enabled. The MODELS object above is keyed by runner.`,\n `For EACH AI task, set \"assignedRunner\" to ${modelList},`,\n 'then pick \"assignedModel\" from THAT runner\\'s list (modelId must match exactly).',\n 'IMPORTANT: Only the runners and models listed above may be used. Do not reference any other runner.',\n '',\n ].join('\\n');\n }\n return [\n `RUNNER ASSIGNMENT: All AI tasks run on \"${runners[0]}\". Set \"assignedRunner\" to \"${runners[0]}\" on each task.`,\n 'IMPORTANT: Only the runner and models listed above may be used. Do not reference any other runner or model.',\n '',\n ].join('\\n');\n}\n\nfunction buildPlanPromptBase(\n userGoal: string,\n context: string,\n researchResults: string,\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n runners: RunnerId[],\n includeResearchSection: boolean,\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n modes: PlannerModes = DEFAULT_PLANNER_MODES,\n): string {\n // Scoping here, once, is what keeps a one-shot prompt honest: grill-me and\n // PRD interview the user, and this path has told the model there is nobody\n // to ask. Review is structural, so it belongs.\n const scoped = modesFor('one-shot', modes);\n const { autonomousDefault } = scoped;\n const template = getPlanTemplate();\n const researchReplacement = includeResearchSection ? RESEARCH_SECTION : '';\n const modelsJson = modelsJsonFor(modelsByRunner, runners);\n\n const modeGuide = runnerModes ? buildModeGuide(runnerModes, autonomousDefault) : buildModeGuideForRunners(runners, autonomousDefault);\n\n const modeExamples = runnerModes\n ? Object.entries(runnerModes).map(([r, ms]) => {\n const filtered = filteredBuildModes(ms, autonomousDefault);\n return `${r}: ${filtered.map(m => m.id).join('|')}${ms.some(m => m.id === 'plan') ? '|plan' : ''}`;\n }).join(', ')\n : buildModeExamplesForRunners(runners);\n\n return template\n .replace('{{RESEARCH_SECTION}}', researchReplacement)\n .replace('{{CLARIFICATION_INSTRUCTIONS}}', ONE_SHOT_INSTRUCTIONS)\n .replace('{{MODELS_JSON}}', modelsJson)\n .replace('{{RUNNER_CHOICES}}', runners.join('|'))\n .replace('{{RUNNER_INSTRUCTION}}', runnerInstruction(runners))\n .replace('{{MODE_GUIDE}}', modeGuide)\n .replace('{{REVIEW_BLOCK}}', scoped.review ? `\\n${reviewModeBlock()}\\n` : '')\n .replace('{{VERIFICATION_BLOCK}}', scoped.verification ? `\\n${verificationModeBlock(scoped.review)}\\n` : '')\n .replace('{{MODE_EXAMPLES}}', modeExamples)\n .replace('{{CONTEXT}}', context || '(no additional context)')\n .replace('{{RESEARCH_RESULTS}}', researchResults ? `\\n\\nRESEARCH FINDINGS:\\n${researchResults}` : '')\n + `\\n\\nUser goal: ${userGoal}`;\n}\n\nexport function buildResearchPrompt(\n userGoal: string,\n context: string,\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n runners: RunnerId[],\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n modes: PlannerModes = DEFAULT_PLANNER_MODES,\n): string {\n return buildPlanPromptBase(userGoal, context, '', modelsByRunner, runners, true, runnerModes, modes);\n}\n\nexport function buildPlanWithResults(\n userGoal: string,\n context: string,\n researchResults: string,\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n runners: RunnerId[],\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n modes: PlannerModes = DEFAULT_PLANNER_MODES,\n): string {\n return buildPlanPromptBase(userGoal, context, researchResults, modelsByRunner, runners, false, runnerModes, modes);\n}\n\nexport function buildModifyPlanPrompt(\n existingPlan: LegacyPlanState,\n userRequest: string,\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n aiflowContext?: string,\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n autonomousDefault = true,\n): string {\n const modelsJson = modelsJsonFor(modelsByRunner, existingPlan.runners);\n const planJson = JSON.stringify(existingPlan.tasks, null, 2);\n const aiflowBlock = aiflowContext\n ? `<aiflow_context>\\n${aiflowContext}\\n</aiflow_context>\\n\\n`\n : '';\n\n const modeGuide = runnerModes ? buildModeGuide(runnerModes, autonomousDefault) : '';\n\n return [\n 'You are a software project planner. You previously generated a task plan and the user now wants to modify it.',\n '',\n 'Here is the CURRENT plan as JSON:',\n planJson,\n '',\n 'Available models:',\n modelsJson,\n '',\n `${aiflowBlock}USER MODIFICATION REQUEST:`,\n userRequest,\n '',\n 'Modify the plan according to the user request. You may add, remove, reorder, or change any task properties.',\n 'Return the COMPLETE modified plan as a JSON object with a single \"tasks\" array.',\n '',\n 'RULES:',\n '- For each task, preserve these exact fields: id, order, title, description, type, status, dependencies, prompt, userSteps, subtasks, assignedModel, thinkingEffort, taskMode.',\n '- DO NOT modify or delete completed tasks UNLESS the user explicitly asks to redo or replace them. If the user asks to redo a completed task, change its status from \"completed\" to \"pending\" and update its properties as requested.',\n '- DO NOT modify or delete tasks with status \"in_progress\" — they are currently executing.',\n '- DO NOT modify or delete tasks with status \"failed\" UNLESS the user asks to fix them — then update the prompt and change status from \"failed\" to \"pending\".',\n '- DO NOT modify or delete tasks with status \"blocked\" UNLESS the user asks to unblock them. If unblocking, remove the failed dependency from the blocked task\\'s dependencies array.',\n '- When the user fixes a failed task, also update any blocked tasks that depend on it: change their status from \"blocked\" to \"pending\".',\n '- Preserve existing task IDs for all unchanged, completed, and in-progress tasks.',\n '- Only create new IDs for newly added tasks.',\n '- When removing a task, update all other tasks that reference the deleted ID in their dependencies.',\n '- Ensure dependency chains remain valid — no dangling references to deleted IDs.',\n '- Renumber task \"order\" fields sequentially starting from 1 after insertions or deletions.',\n '- When adding new tasks, assign appropriate models and thinking efforts based on complexity.',\n ...(modeGuide ? ['', modeGuide] : []),\n '- Do NOT wrap the JSON in markdown code blocks. Output ONLY the JSON object.',\n ].join('\\n');\n}\n\n\n\n\nexport function modelContextBlock(\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n runners: RunnerId[],\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n autonomousDefault = true,\n): string {\n const modelsJson = modelsJsonFor(modelsByRunner, runners);\n const modeGuide = runnerModes ? buildModeGuide(runnerModes, autonomousDefault) : buildModeGuideForRunners(runners, autonomousDefault);\n\n return [\n 'MODEL ASSIGNMENT:',\n 'You must assign an \"assignedModel\" to each AI task. Available models:',\n '',\n modelsJson,\n '',\n runnerInstruction(runners),\n 'MODEL SELECTION GUIDELINES:',\n '- Use stronger models (Opus, DeepSeek V4 Pro, Kimi 2.6) for: complex refactoring, architecture changes, security-critical code, performance optimization, large-scale changes.',\n '- Use weaker/faster models (Sonnet, DeepSeek V4 Flash) for: simple file operations, test generation, config changes, documentation, straightforward bug fixes.',\n '- Assign thinkingEffort based on task complexity: \"low\" for simple tasks, \"medium\" or \"high\" for moderate/complex tasks.',\n '',\n 'TASK MODE:',\n modeGuide,\n '',\n ].join('\\n');\n}\n\nexport function executionLogBlock(executionLog: TaskSnapshot[]): string {\n if (executionLog.length === 0) return '';\n\n const completed = executionLog.filter((t) => t.status === 'completed');\n const failed = executionLog.filter((t) => t.status === 'failed');\n\n const lines = ['EXECUTION LOG SUMMARY:'];\n lines.push(`Total entries: ${executionLog.length} (${completed.length} completed, ${failed.length} failed)`);\n\n if (completed.length > 0) {\n lines.push('');\n lines.push('COMPLETED TASKS:');\n for (const t of completed) {\n const verdict = t.verdict ? ` — ${t.verdict.outcome.toUpperCase()}: ${t.verdict.reason}` : '';\n lines.push(`- [${t.id}] ${t.title}${verdict}`);\n }\n }\n\n if (failed.length > 0) {\n lines.push('');\n lines.push('FAILED TASKS (eligible for retry):');\n for (const t of failed) {\n const verdict = t.verdict ? ` — ${t.verdict.reason}` : '';\n lines.push(`- [${t.id}] ${t.title} (retry #${t.retryCount})${verdict}`);\n }\n }\n\n return lines.join('\\n');\n}\n\nexport function pendingEditRulesBlock(): string {\n return [\n 'MODIFICATION RULES:',\n '- Preserve existing task IDs for all unchanged tasks. Only create new IDs for newly added tasks.',\n '- DO NOT modify completed tasks from the execution log UNLESS the user explicitly asks to retry them. If retrying a completed task, assign it the SAME id as the original and set its status to \"pending\".',\n '- DO NOT modify or remove tasks that are currently in_progress — they are being executed by an active agent session.',\n '- When removing a task, update all other tasks that reference the deleted ID in their dependencies.',\n '- Ensure dependency chains remain valid — no dangling references to deleted IDs.',\n '- Renumber task \"order\" fields sequentially starting from 1 after insertions or deletions.',\n '- When adding new tasks, assign appropriate models and thinking efforts based on complexity.',\n '- For failed tasks being retried: use the same ID, update the prompt to address the failure reason, and set status to \"pending\".',\n '- Only modify the tasks the user asked to change. Return ALL pending tasks, not just the modified ones.',\n '',\n ].join('\\n');\n}\n\nexport function buildModifyDuringExecutionPrompt(\n executionLog: TaskSnapshot[],\n pendingTasks: string,\n userMessage: string,\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n runners: RunnerId[],\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n autonomousDefault = true,\n): string {\n const execLogBlock = executionLogBlock(executionLog);\n const rulesBlock = pendingEditRulesBlock();\n const modelBlock = modelContextBlock(modelsByRunner, runners, runnerModes, autonomousDefault);\n\n const sections = [\n CORE_PLANNER_PROMPT,\n '',\n 'You are modifying a plan that is currently executing. Some tasks have already been completed or failed.',\n '',\n ];\n\n if (execLogBlock) {\n sections.push(execLogBlock);\n sections.push('');\n }\n\n sections.push('CURRENT PENDING TASKS (these are NOT yet executed):');\n sections.push(pendingTasks);\n sections.push('');\n sections.push(rulesBlock);\n sections.push(modelBlock);\n sections.push('');\n sections.push('USER REQUEST:');\n sections.push(userMessage);\n sections.push('');\n sections.push('Return the COMPLETE modified pending tasks as a JSON object with a single \"tasks\" array. Include all pending tasks, not just the modified ones.\\nDo NOT wrap the JSON in markdown code blocks. Output ONLY the JSON object.');\n\n return sections.join('\\n');\n}\n\n/**\n * User-message prompt for a planner-driven merge: asks the model to combine the\n * selected tasks into one. Routed through the conversation loop, so the\n * task-ops protocol (with the \"merge\" op) is injected alongside it by\n * `planContextBlock`. The model emits a single taskOps merge op.\n */\nexport function buildMergePrompt(taskIds: string[], tasks: Task[]): string {\n const idSet = new Set(taskIds);\n const selected = tasks.filter((t) => idSet.has(t.id)).sort((a, b) => a.order - b.order);\n const refs = selected.map((t) => `#${t.order} \"${t.title}\" (id=${t.id})`).join(', ');\n return [\n `Merge these tasks into ONE combined task: ${refs}.`,\n 'Write a clear combined title, description, and prompt that cover all of their work.',\n 'The merged task takes the union of their dependencies (excluding the merged tasks themselves) and preserves their user stories.',\n 'Set \"assignedRunner\" and \"assignedModel\" on the merged task — use one of the runners and models listed in <available_models> above. Prefer the strongest model if the merged work is complex.',\n 'Reply with ONLY a taskOps JSON object using a single \"merge\" op:',\n ` {\"taskOps\":[{\"op\":\"merge\",\"taskIds\":[${selected.map((t) => `\"${t.id}\"`).join(', ')}],\"merged\":{\"title\":\"...\",\"description\":\"...\",\"prompt\":\"...\",\"assignedRunner\":\"...\",\"assignedModel\":{\"modelId\":\"...\",\"modelLabel\":\"...\"}}}]}`,\n ].join('\\n');\n}\n\n/**\n * User-message prompt for a planner-driven split: asks the model to decompose\n * one task into a sequence of smaller tasks. The model decides the breakdown —\n * the user does not hand-type the parts.\n */\nexport function buildSplitPrompt(taskId: string, tasks: Task[]): string {\n const task = tasks.find((t) => t.id === taskId);\n if (!task) return `Split task ${taskId} into smaller tasks.`;\n return [\n `Split task #${task.order} \"${task.title}\" (id=${task.id}) into multiple smaller tasks that together accomplish the same work.`,\n 'Decompose it into a sensible ordered sequence. Write a clear title, description, and prompt for each part.',\n 'The first part inherits the original task\\'s dependencies. Each later part depends on the previous part. Tasks that depended on the original now depend on the LAST part.',\n 'Set \"assignedRunner\" and \"assignedModel\" on each part — use the runners and models listed in <available_models> above. You may assign different models to different parts (e.g. a stronger model for a complex part, a faster one for a simple part).',\n 'Reply with ONLY a taskOps JSON object using a single \"split\" op:',\n ` {\"taskOps\":[{\"op\":\"split\",\"taskId\":\"${task.id}\",\"parts\":[{\"title\":\"...\",\"description\":\"...\",\"prompt\":\"...\",\"assignedRunner\":\"...\",\"assignedModel\":{\"modelId\":\"...\",\"modelLabel\":\"...\"}},...]}]}`,\n ].join('\\n');\n}\n","import type { Task, RunnerId } from '../models/Task';\nimport {\n PlanParseError, extractObjectsWithKey,\n PLAN_ENVELOPE_KEY, TASK_OPS_ENVELOPE_KEY,\n} from './JsonExtractor';\nimport { parsePlanJson, looksLikePlanAttempt } from './PlanValidator';\nimport { parseTaskOpsJson, textHasTaskOps, type TaskOp } from './TaskOps';\nimport type { RunnerModeInfo } from './ModeResolver';\n\n/**\n * The one owner of \"the model emitted something unusable — correct it and\n * retry\". Every repair path in the planner routes through this module:\n *\n * - {@link repairLoop} is the bounded driver (first reply → interpret →\n * corrective re-send), used by plan generation ({@link generatePlanWithRepair}),\n * the Session's task-ops settlement, and Planner.modifyDuringExecution.\n * - {@link classifyPlannerReply} decides what a planner reply *is* — a plan,\n * targeted task edits, a botched attempt at either (worth a corrective\n * retry), or prose. The conversation loop in BaseAiService keeps its own\n * driver (it also runs the tool rounds) but delegates classification here.\n * - The corrective prompt texts live here, once.\n *\n * Policies stay at the call sites (PRD nudge, ops validation, abort guards) —\n * they are inputs to the loop, not part of it.\n */\n\nexport type RepairVerdict<T> =\n | { done: T }\n | { retry: { errors: string[]; corrective: string; cause?: unknown } };\n\nexport interface RepairLoopOpts<R, T> {\n /** Produce the first reply (attempt 0) — often already in hand. */\n first: () => R | Promise<R>;\n /** Ask the model again with a corrective prompt after a retryable failure. */\n resend: (corrective: string) => Promise<R>;\n /**\n * Judge one reply: `done` with the settled value, or `retry` with the\n * errors and the corrective prompt to send. Throw for non-retryable\n * failures — those propagate immediately.\n */\n interpret: (reply: R) => RepairVerdict<T> | Promise<RepairVerdict<T>>;\n /** Corrective re-sends allowed after the first attempt (N repairs = N+1 attempts). */\n maxRepairs: number;\n /** Budget exhausted: receives the last reply and its errors; return a fallback or throw. */\n onExhausted: (last: { reply: R; errors: string[]; cause?: unknown }) => T;\n}\n\nexport async function repairLoop<R, T>(opts: RepairLoopOpts<R, T>): Promise<T> {\n let reply = await opts.first();\n for (let repairs = 0; ; repairs++) {\n const verdict = await opts.interpret(reply);\n if ('done' in verdict) return verdict.done;\n if (repairs >= opts.maxRepairs) {\n return opts.onExhausted({ reply, errors: verdict.retry.errors, cause: verdict.retry.cause });\n }\n reply = await opts.resend(verdict.retry.corrective);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Corrective prompts — the texts the model sees when it must re-emit.\n// ---------------------------------------------------------------------------\n\n/** Instruction appended to a follow-up request asking the model to re-emit strict JSON. */\nexport const JSON_REPAIR_INSTRUCTION =\n 'Your previous response could not be parsed as JSON. Re-send ONLY the JSON object — ' +\n 'no prose before or after, no explanation, no markdown code fences.';\n\n/**\n * The emission hit the output-token limit: a plain \"re-send the JSON\" retry\n * would be cut off at the same point, so this one asks for terser output.\n */\nexport const TRUNCATED_PLAN_REPAIR_INSTRUCTION =\n 'Your previous response was cut off by the output length limit before the JSON finished. ' +\n `Re-send the COMPLETE plan as a single {\"${PLAN_ENVELOPE_KEY}\":[...]} JSON object — no prose, no code fences — ` +\n 'and keep every task description and prompt brief so the whole object fits within the limit.';\n\n/** A plan attempt was botched (invalid or truncated JSON): re-emit the whole plan. */\nexport function reEmitPlanPrompt(detail: string): string {\n return `Your plan JSON could not be committed: ${detail}. Re-emit the COMPLETE corrected plan as a single {\"${PLAN_ENVELOPE_KEY}\":[...]} JSON object — every task included, no prose, no code fences.`;\n}\n\n/** A plan emission was truncated mid-JSON; the caller may also have compacted the history to free input context. */\nexport function truncatedPlanReEmitPrompt(historyCompacted: boolean): string {\n return (historyCompacted\n ? 'Older raw research transcripts have been trimmed from this conversation to free space (subagent digests are intact). '\n : '') + TRUNCATED_PLAN_REPAIR_INSTRUCTION;\n}\n\n/** A task-ops attempt was botched (unparseable JSON): re-emit the ops object. */\nexport function reEmitTaskOpsPrompt(detail: string): string {\n return `Your task edits could not be applied: ${detail}. Re-emit ONLY a corrected {\"${TASK_OPS_ENVELOPE_KEY}\":[...]} JSON object — no prose, no code fences — or reply in prose if you did not intend to edit tasks.`;\n}\n\n/** Task ops parsed but failed semantic validation (cycles, unknown refs, locked tasks). */\nexport function taskOpsRejectedPrompt(errors: string[]): string {\n return `Those task edits were rejected:\\n- ${errors.join('\\n- ')}\\nRe-emit a corrected {\"${TASK_OPS_ENVELOPE_KEY}\":[...]} JSON object, or reply in prose if something is unclear.`;\n}\n\n/** A modified plan failed validation during execution: full re-prompt feedback block. */\nexport function modifyValidationFeedback(errors: string[]): string {\n return [\n '',\n '=== VALIDATION ERRORS FROM PREVIOUS ATTEMPT ===',\n 'Your previous plan modification was rejected by validation. Fix these issues:',\n ...errors.map((e, i) => `${i + 1}. ${e}`),\n '',\n 'Resubmit the corrected plan. Do NOT wrap in markdown code blocks.',\n ].join('\\n');\n}\n\n// ---------------------------------------------------------------------------\n// Reply classification — what did the planner actually emit?\n// ---------------------------------------------------------------------------\n\nexport type PlannerReplyClassification =\n | { kind: 'plan'; tasks: Task[] }\n | { kind: 'task_ops'; ops: TaskOp[] }\n /** Clearly attempted a plan (tasks-keyed object, or JSON cut off mid-stream) and botched it — worth a corrective retry. */\n | { kind: 'broken_plan'; error: PlanParseError }\n /** Clearly attempted an ops object and botched it — worth a corrective retry. */\n | { kind: 'broken_task_ops'; error: PlanParseError }\n | { kind: 'prose' };\n\n/**\n * Classify one planner reply. Task ops are checked before the plan key — an\n * ops object never carries a top-level tasks array, but a model may mention\n * the word in prose around it. \"Broken\" is deliberately narrower than \"failed\n * to parse\": prose that merely mentions the envelope key is left alone.\n */\nexport function classifyPlannerReply(\n text: string,\n opts: {\n runners: RunnerId[];\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>;\n autonomousDefault?: boolean;\n },\n): PlannerReplyClassification {\n if (textHasTaskOps(text)) {\n try {\n return { kind: 'task_ops', ops: parseTaskOpsJson(text) };\n } catch (err) {\n if (!(err instanceof PlanParseError)) throw err;\n // Repairable only when the reply carries a real ops object and no plan\n // to fall through to; otherwise it may still be a plan, else prose.\n if (\n !text.includes(`\"${PLAN_ENVELOPE_KEY}\"`) &&\n extractObjectsWithKey(text, TASK_OPS_ENVELOPE_KEY).matches.length > 0\n ) {\n return { kind: 'broken_task_ops', error: err };\n }\n }\n }\n\n // A reply is a candidate plan whenever its content carries a tasks key —\n // models often emit a short preamble before the JSON.\n if (text.includes(`\"${PLAN_ENVELOPE_KEY}\"`)) {\n try {\n return { kind: 'plan', tasks: parsePlanJson(text, opts.runners, opts.runnerModes, opts.autonomousDefault) };\n } catch (err) {\n if (!(err instanceof PlanParseError)) throw err;\n if (looksLikePlanAttempt(text)) return { kind: 'broken_plan', error: err };\n }\n }\n\n return { kind: 'prose' };\n}\n\n// ---------------------------------------------------------------------------\n// Plan-stream adapter — one-shot generation with JSON repair.\n// ---------------------------------------------------------------------------\n\n/**\n * Generate a plan, retrying on unparseable JSON. `generate` is called with an\n * optional repair hint (undefined on the first attempt, {@link JSON_REPAIR_INSTRUCTION}\n * thereafter) and must return the model's raw text. Only {@link PlanParseError} is\n * retried; transport/other errors propagate immediately. The last parse error is\n * re-thrown if every attempt fails.\n */\nexport async function generatePlanWithRepair(\n generate: (repairHint?: string) => Promise<string>,\n runners: RunnerId[],\n maxAttempts = 2,\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n autonomousDefault = true,\n): Promise<Task[]> {\n return repairLoop<string, Task[]>({\n first: () => generate(undefined),\n resend: (corrective) => generate(corrective),\n interpret: (text) => {\n try {\n return { done: parsePlanJson(text, runners, runnerModes, autonomousDefault) };\n } catch (err) {\n if (!(err instanceof PlanParseError)) throw err;\n // A shape rejection is not a parse failure: telling the model its JSON\n // \"could not be parsed\" spends the one retry on a problem that does not\n // exist, and it re-sends the same object. Name the rule instead — the\n // conversational path has always done this.\n const corrective = err.truncated\n ? TRUNCATED_PLAN_REPAIR_INSTRUCTION\n : err.semantic\n ? reEmitPlanPrompt(err.message)\n : JSON_REPAIR_INSTRUCTION;\n return { retry: { errors: [err.message], corrective, cause: err } };\n }\n },\n maxRepairs: maxAttempts - 1,\n onExhausted: ({ cause }) => {\n throw cause ?? new PlanParseError('Plan generation produced no parseable output', '');\n },\n });\n}\n","import type OpenAI from 'openai';\nimport { SchemaType, type FunctionDeclaration, type Schema } from '@google/generative-ai';\n\n/**\n * Canonical definition of the read-only research tools the planner uses to\n * explore a workspace. Both the OpenAI- and Gemini-backed services drive the\n * same loop over the same tools, so the names, descriptions, and parameter\n * shapes live here once and are projected into each SDK's tool format. Keeping\n * a single source of truth stops the two provider lists from drifting apart.\n */\n\ntype ParamType = 'string' | 'number' | 'array' | 'boolean';\n\ninterface ResearchToolParam {\n type: ParamType;\n description: string;\n /** Element type for `array` parameters. */\n items?: { type: ParamType };\n /** Closed value set, projected as a JSON-schema enum. */\n enum?: string[];\n}\n\nexport interface ResearchToolSpec {\n name: string;\n description: string;\n properties: Record<string, ResearchToolParam>;\n required: string[];\n}\n\nexport const SPAWN_RESEARCH_AGENT = 'spawn_research_agent';\n\n/**\n * Optional subagent tool (issue #34), opencode-style: one stateless read-only\n * research agent per call. Only declared when the researchSubagents toggle is\n * on AND the active service can build subagent chats. Kept out of\n * RESEARCH_TOOLS so the default projections stay bit-for-bit today's list.\n */\nexport const SPAWN_RESEARCH_AGENT_SPEC: ResearchToolSpec = {\n name: SPAWN_RESEARCH_AGENT,\n description: 'Launch a read-only research agent that explores the workspace with its own tools (read_file, read_files, glob, grep, find_symbol, list_dir, bash) and returns a single digest. When to use: an open-ended exploration thread you want answered without doing every lookup yourself — a subsystem to map, a question like \"how does X flow through this codebase\". Launch a new agent whenever such a thread emerges during research. To explore several independent areas, launch multiple agents CONCURRENTLY by putting several spawn_research_agent calls in one reply — they run in parallel. When NOT to use: reading a specific known file (read it directly), or small single-subsystem repos where direct exploration is already fast. Each agent is stateless: it sees nothing of this conversation and you cannot message it again. Its prompt must be self-contained — name the area or question, the paths or symbols to start from, and exactly what the digest must report back. Agents are read-only, cannot spawn further agents, and only their final digest returns to you.',\n properties: {\n prompt: { type: 'string', description: 'Self-contained task for the research agent, including what the digest must contain.' },\n },\n required: ['prompt'],\n};\n\nexport const RESEARCH_TOOLS: ResearchToolSpec[] = [\n {\n name: 'read_file',\n description: 'Read the contents of a file with line-numbered output and optional offset/limit for pagination. Path is relative to the workspace root; a path outside it requires user approval. When to use: read a file you already know the path of (from glob/grep/find_symbol results). When NOT to use: to find files — use glob or grep first to locate the right files.',\n properties: {\n path: { type: 'string', description: 'Relative path to the file' },\n offset: { type: 'number', description: '0-based line number to start reading from (default: 0)' },\n limit: { type: 'number', description: 'Maximum number of lines to return (default: 2000). Files larger than ~1 MB are rejected with an error — use grep instead for those.' },\n },\n required: ['path'],\n },\n {\n name: 'read_files',\n description: 'Read multiple known files at once. When to use: batch-read several files whose paths you already know. When NOT to use: discovering which files to read — use glob/grep first.',\n properties: {\n paths: { type: 'array', items: { type: 'string' }, description: 'Array of relative file paths to read' },\n },\n required: ['paths'],\n },\n {\n name: 'glob',\n description: 'Find files matching a glob pattern (e.g. \"src/**/*.ts\"). Uses ripgrep for speed. When to use: find files by name/path pattern. When NOT to use: searching file contents (use grep) or browsing directory layout (use list_dir).',\n properties: {\n pattern: { type: 'string', description: 'Glob pattern' },\n path: { type: 'string', description: 'Directory to search under (default: workspace root). Paths outside the workspace require user approval.' },\n },\n required: ['pattern'],\n },\n {\n name: 'grep',\n description: 'Search file contents with ripgrep. When to use: find code patterns, imports, or any text within files. When NOT to use: finding files by name (use glob), or locating where a named symbol is DEFINED (use find_symbol — it filters out the call sites that would otherwise fill this tool\\'s result budget). Results are capped globally; use output_mode=\"files\" to survey breadth cheaply, then re-run with output_mode=\"content\" on a narrower path.',\n properties: {\n pattern: { type: 'string', description: 'Regex pattern to search for (set literal=true to match it as plain text instead)' },\n include: { type: 'string', description: 'Optional file glob to filter (e.g. \"*.ts\")' },\n path: { type: 'string', description: 'Directory to search under (default: workspace root). Paths outside the workspace require user approval.' },\n output_mode: { type: 'string', enum: ['content', 'files', 'count'], description: '\"content\" (default) returns matching lines; \"files\" returns only file paths; \"count\" returns per-file match counts. Prefer \"files\" or \"count\" when surveying breadth.' },\n context_before: { type: 'number', description: 'Lines of context before each match (content mode only)' },\n context_after: { type: 'number', description: 'Lines of context after each match (content mode only)' },\n literal: { type: 'boolean', description: 'Treat the pattern as a literal string rather than a regex' },\n case_insensitive: { type: 'boolean', description: 'Case-insensitive match' },\n head_limit: { type: 'number', description: 'Maximum rows returned (default 100)' },\n },\n required: ['pattern'],\n },\n {\n name: 'find_symbol',\n description: 'Locate where a named symbol is DEFINED, plus a per-file count of where it is referenced. Understands declaration syntax across TypeScript, Python, Go, Rust, JVM languages, C#, C/C++, Ruby, PHP, Swift, Elixir and more. When to use: \"where is X defined\", \"what would changing X affect\", scoping the blast radius of a task. When NOT to use: free-text or pattern search (use grep), or finding files by name (use glob). Strongly preferred over grep for named symbols — grep returns every import and call site, so the definition often falls outside the result cap.',\n properties: {\n symbol: { type: 'string', description: 'Exact symbol name (function, class, type, constant, …)' },\n language: { type: 'string', description: 'Optional language id or file extension (\"typescript\", \"go\", \".rs\") to narrow the search in polyglot repos' },\n path: { type: 'string', description: 'Directory to search under (default: workspace root)' },\n },\n required: ['symbol'],\n },\n {\n name: 'list_dir',\n description: 'List directory contents as a tree. Use depth > 1 for nested tree view. When to use: getting oriented with project structure, seeing what directories exist. When NOT to use: finding specific files by name (use glob) or searching file contents (use grep).',\n properties: {\n path: { type: 'string', description: 'Relative path to the directory' },\n depth: { type: 'number', description: 'Directory depth for tree view (default: 1, flat listing)' },\n },\n required: ['path'],\n },\n {\n name: 'bash',\n description: 'Run a shell command for research. Read-only inspection (ls, tree, git log/status/diff/show, wc, find, rg, jq, …) runs immediately. Anything else — test suites, package managers, cloud CLIs like az/gh/aws/kubectl — pauses for one user approval and is then remembered for the rest of the session. Commands that write or mutate (rm, mv, cp, chmod, sudo, mkdir, git push/commit, output redirection, piping into a shell) are always refused: you are a planner, so describe the change as a task and let the runner make it. When to use: diagnosing before planning — reproduce a failure, query a remote environment, inspect build config. When NOT to use: file search (use glob/grep/find_symbol/list_dir instead).',\n properties: {\n command: { type: 'string', description: 'The shell command to run' },\n },\n required: ['command'],\n },\n {\n name: 'fetch',\n description: 'Fetch content from a URL (HTTP/HTTPS). Use for reading API documentation, library references, or package docs. URL confirmation is required — the tool may pause while awaiting approval.',\n properties: {\n url: { type: 'string', description: 'The URL to fetch' },\n },\n required: ['url'],\n },\n {\n name: 'web_search',\n description: 'Search the web for result titles, URLs and snippets. When to use: you need docs for an unfamiliar library or API and have no URL yet — search first, then fetch the most promising result. When NOT to use: anything answerable from the workspace itself (use grep or find_symbol).',\n properties: {\n query: { type: 'string', description: 'Search query' },\n },\n required: ['query'],\n },\n];\n\n/**\n * The toolset a research subagent gets: the read-only exploration tools minus\n * the network tools (`fetch`/`web_search` can pause on user confirmation, which\n * a background subagent must never do) and minus the spawn tool itself (no\n * recursion). `bash` stays, but its own approval gate means a subagent can only\n * ever run the auto-tier read-only commands — an ask-tier command from a\n * background agent resolves to denied rather than prompting.\n */\nconst SUBAGENT_EXCLUDED = new Set(['fetch', 'web_search']);\n\nexport function subagentToolSpecs(): ResearchToolSpec[] {\n return RESEARCH_TOOLS.filter((t) => !SUBAGENT_EXCLUDED.has(t.name));\n}\n\nfunction withSpawn(includeSubagents: boolean): ResearchToolSpec[] {\n return includeSubagents ? [...RESEARCH_TOOLS, SPAWN_RESEARCH_AGENT_SPEC] : RESEARCH_TOOLS;\n}\n\nfunction projectOpenAi(specs: ResearchToolSpec[]): OpenAI.Chat.Completions.ChatCompletionTool[] {\n return specs.map((t) => ({\n type: 'function',\n function: {\n name: t.name,\n description: t.description,\n parameters: {\n type: 'object',\n properties: Object.fromEntries(Object.entries(t.properties).map(([key, param]) => [key, {\n type: param.type,\n description: param.description,\n ...(param.items ? { items: param.items } : {}),\n ...(param.enum ? { enum: param.enum } : {}),\n }])),\n required: t.required,\n },\n },\n }));\n}\n\n/** Project the canonical tools into OpenAI's chat-completions tool format. */\nexport function toOpenAiTools(includeSubagents = false): OpenAI.Chat.Completions.ChatCompletionTool[] {\n return projectOpenAi(withSpawn(includeSubagents));\n}\n\n/** The subagent's own tool list in OpenAI format. */\nexport function toOpenAiSubagentTools(): OpenAI.Chat.Completions.ChatCompletionTool[] {\n return projectOpenAi(subagentToolSpecs());\n}\n\nconst SCHEMA_TYPE: Record<ParamType, SchemaType> = {\n string: SchemaType.STRING,\n number: SchemaType.NUMBER,\n array: SchemaType.ARRAY,\n boolean: SchemaType.BOOLEAN,\n};\n\n/** Project the canonical tools into Gemini's function-declaration format. */\nexport function toGeminiToolDeclarations(includeSubagents = false): FunctionDeclaration[] {\n return withSpawn(includeSubagents).map((t) => {\n const properties: Record<string, Schema> = {};\n for (const [key, param] of Object.entries(t.properties)) {\n properties[key] = {\n type: SCHEMA_TYPE[param.type],\n description: param.description,\n ...(param.items ? { items: { type: SCHEMA_TYPE[param.items.type] } } : {}),\n ...(param.enum ? { format: 'enum', enum: param.enum } : {}),\n };\n }\n return {\n name: t.name,\n description: t.description,\n parameters: { type: SchemaType.OBJECT, properties, required: t.required },\n };\n });\n}\n","import { RESEARCH_TOOLS, SPAWN_RESEARCH_AGENT } from './researchTools';\nimport type { ResearchChat, ResearchTurn } from './BaseAiService';\n\n/**\n * Research-context compaction (Option 1 for the truncated-plan bug): a long\n * research phase — especially with parallel subagents — can bloat the planner\n * context enough that the final plan-JSON emission runs out of output tokens\n * mid-object. The fix is on the input side: raw tool transcripts are pruned\n * to stubs while subagent digests are preserved — a digest is already the\n * compressed form of a whole research thread; the raw outputs are what it\n * summarized.\n */\n\nexport const COMPACTION_LIMITS = {\n /** Pruned outputs keep this much leading text so the model still sees what was there. */\n keepHeadChars: 400,\n /** Outputs at or below this size are never pruned — the savings would not pay for the loss. */\n minPrunableChars: 1500,\n /** Aggregate research-findings budget for the one-shot fallback plan prompt. */\n researchResultsMaxChars: 60_000,\n /**\n * Prompt-token level at which history is compacted proactively, before an\n * emission ever truncates: ~80% of a 128k context, the smallest window in\n * common planner use. Bigger-window models just compact earlier — that only\n * stubs bulky raw transcripts (digests are kept), a mild loss taken for\n * predictability.\n */\n proactivePromptTokens: 100_000,\n};\n\n/** Structural subset of an OpenAI-style chat message that compaction reads and rewrites. */\nexport interface CompactableMessage {\n role: string;\n content?: unknown;\n tool_call_id?: string;\n tool_calls?: Array<{ id?: string; function?: { name?: string } }>;\n}\n\n/**\n * Prune bulky raw tool outputs from a chat history in place so a follow-up\n * plan emission gets its context back. Subagent digests are kept whole.\n * Returns the number of characters removed.\n */\nexport function compactToolMessages(\n messages: CompactableMessage[],\n preserveToolNames: ReadonlySet<string> = new Set([SPAWN_RESEARCH_AGENT]),\n): number {\n const nameById = new Map<string, string>();\n for (const m of messages) {\n for (const tc of m.tool_calls ?? []) {\n if (tc.id && tc.function?.name) nameById.set(tc.id, tc.function.name);\n }\n }\n\n let removed = 0;\n for (const m of messages) {\n if (m.role !== 'tool' || typeof m.content !== 'string') continue;\n const name = m.tool_call_id ? nameById.get(m.tool_call_id) : undefined;\n if (name && preserveToolNames.has(name)) continue;\n if (m.content.length <= COMPACTION_LIMITS.minPrunableChars) continue;\n const stub = m.content.slice(0, COMPACTION_LIMITS.keepHeadChars)\n + `\\n[... ${name ?? 'tool'} output pruned (${m.content.length} chars) to free context for the plan — re-run the tool if needed]`;\n removed += m.content.length - stub.length;\n m.content = stub;\n }\n return removed;\n}\n\n/**\n * Wrap a chat so that any turn reporting prompt tokens past the threshold\n * compacts the history immediately — the next call (tool round or the plan\n * emission itself) then runs against a pruned context instead of a saturated\n * one. Opencode-style auto-compact, but deterministic: no summarizer model.\n * Reactive truncation repair stays as the backstop for whatever this misses.\n */\nexport function withProactiveCompaction(chat: ResearchChat): ResearchChat {\n const check = (turn: ResearchTurn): ResearchTurn => {\n if ((turn.promptTokens ?? 0) >= COMPACTION_LIMITS.proactivePromptTokens) chat.compactHistory?.();\n return turn;\n };\n return {\n sendMessage: (text, signal) => chat.sendMessage(text, signal).then(check),\n sendToolResults: (results, signal) => chat.sendToolResults(results, signal).then(check),\n compactHistory: chat.compactHistory?.bind(chat),\n };\n}\n\ninterface ResultsBlock {\n tool: string | null;\n lines: string[];\n}\n\nconst PRESERVED_BLOCKS = new Set([SPAWN_RESEARCH_AGENT, 'llm_response']);\n\n/**\n * Bound the accumulated research-findings text embedded in the one-shot\n * fallback plan prompt. Blocks are pruned oldest-first: raw tool transcripts\n * before subagent digests and the model's own closing synthesis, which only\n * shrink if the budget still cannot be met without them.\n */\nexport function compactResearchResults(\n resultsText: string,\n maxChars = COMPACTION_LIMITS.researchResultsMaxChars,\n): string {\n if (resultsText.length <= maxChars) return resultsText;\n\n // Blocks are delimited by the headers executeToolCalls writes:\n // \"[toolName({...args})]\" or \"[LLM response]\", always at line start.\n const knownNames = new Set(RESEARCH_TOOLS.map((t) => t.name)).add(SPAWN_RESEARCH_AGENT);\n const headerRe = /^\\[([a-z_]+)\\(/;\n const blocks: ResultsBlock[] = [{ tool: null, lines: [] }];\n for (const line of resultsText.split('\\n')) {\n const m = headerRe.exec(line);\n const tool = m && knownNames.has(m[1]) ? m[1] : line === '[LLM response]' ? 'llm_response' : null;\n if (tool) blocks.push({ tool, lines: [line] });\n else blocks[blocks.length - 1].lines.push(line);\n }\n\n // Splitting the line list into blocks and re-joining is the identity, so\n // untouched blocks survive byte-for-byte.\n const texts = blocks.map((b) => b.lines.join('\\n'));\n let total = texts.reduce((n, t) => n + t.length, 0);\n const prunePasses: Array<(b: ResultsBlock) => boolean> = [\n (b) => b.tool !== null && !PRESERVED_BLOCKS.has(b.tool),\n (b) => b.tool !== null && PRESERVED_BLOCKS.has(b.tool),\n ];\n for (const shouldPrune of prunePasses) {\n for (const [i, b] of blocks.entries()) {\n if (total <= maxChars) break;\n if (!shouldPrune(b) || texts[i].length <= COMPACTION_LIMITS.minPrunableChars) continue;\n const stub = texts[i].slice(0, COMPACTION_LIMITS.keepHeadChars)\n + `\\n[... pruned ${texts[i].length} chars to fit the research budget]`;\n total -= texts[i].length - stub.length;\n texts[i] = stub;\n }\n }\n\n // Blocks partition the split lines, so joining block texts with '\\n' undoes\n // the split exactly — except the synthetic empty first block, which must not\n // inject a leading newline when the text opened with a header line.\n return (blocks[0].lines.length === 0 ? texts.slice(1) : texts).join('\\n');\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\n\nconst PRD_BLOCK_RE = /<!--\\s*ORDEWELL_PRD_START\\s+slug=\"([^\"]+)\"\\s*-->\\s*([\\s\\S]*?)\\s*<!--\\s*ORDEWELL_PRD_END\\s*-->/;\n\nexport interface PrdBlock {\n slug: string;\n markdown: string;\n}\n\n/**\n * Detect a full markdown PRD in a planner message. The markers are the only\n * structured artifact left in the conversation loop — they exist so the PRD\n * can be saved to disk, not to drive any state machine.\n */\nexport function extractPrdBlock(text: string): PrdBlock | null {\n const match = PRD_BLOCK_RE.exec(text);\n if (!match) return null;\n const slug = sanitizeSlug(match[1]);\n const markdown = match[2].trim();\n if (!slug || !markdown) return null;\n return { slug, markdown };\n}\n\n/** Kebab-case, path-safe feature slug. */\nexport function sanitizeSlug(raw: string): string {\n return raw\n .toLowerCase()\n .replace(/[^a-z0-9-_]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 80);\n}\n\n/** Save the PRD to `<workspace>/.scratch/<slug>/PRD.md` (to-prd native convention). */\nexport function savePrdMarkdown(workspace: string, slug: string, markdown: string): string {\n const dir = path.join(workspace, '.scratch', sanitizeSlug(slug));\n fs.mkdirSync(dir, { recursive: true });\n const file = path.join(dir, 'PRD.md');\n fs.writeFileSync(file, markdown.endsWith('\\n') ? markdown : markdown + '\\n', 'utf8');\n return file;\n}\n","import { IFileSystem } from '../interfaces/IFileSystem';\nimport type { RunnerRegistry } from '../plugins/RunnerRegistry';\n\nexport interface CollectedContext {\n agentConfig: string | null;\n agentConfigPath: string | null;\n dirStructure: string | null;\n aiflowContext: string | null;\n}\n\nconst ORDEWELL_CONTEXT_MAX = 8000;\n\n/**\n * The project-context preamble every planner backend puts in front of its\n * system prompt: ORDEWELL.md, each runner's own agent config, and the directory\n * structure. Lives here rather than on a service base class because both\n * transports need it and only one of them has a base class (ADR-0009).\n */\nexport async function collectResearchContext(fs: IFileSystem, runners: string[]): Promise<string> {\n const collector = new ContextCollector(fs);\n\n let contextStr = '';\n let firstContext: CollectedContext | null = null;\n for (const r of runners) {\n const ctx = await collector.collect(r);\n if (!firstContext) firstContext = ctx;\n if (ctx.agentConfig && ctx.agentConfigPath) {\n contextStr += `\\n=== ${ctx.agentConfigPath} (${r}) ===\\n${ctx.agentConfig.slice(0, 3000)}\\n`;\n }\n }\n if (firstContext?.aiflowContext) {\n contextStr = `\\n<aiflow_context>\\n${firstContext.aiflowContext}\\n</aiflow_context>\\n` + contextStr;\n }\n if (firstContext?.dirStructure) contextStr += `\\n=== Directory Structure ===\\n${firstContext.dirStructure}\\n`;\n return contextStr;\n}\n\nexport class ContextCollector {\n constructor(private fs: IFileSystem, private registry?: RunnerRegistry) {}\n\n setRegistry(registry: RunnerRegistry): void {\n this.registry = registry;\n }\n\n async collect(runner: string): Promise<CollectedContext> {\n const context: CollectedContext = {\n agentConfig: null,\n agentConfigPath: null,\n dirStructure: null,\n aiflowContext: null,\n };\n\n const aiflowResult = await this.readIfExists('ORDEWELL.md');\n if (aiflowResult) context.aiflowContext = aiflowResult.output.slice(0, ORDEWELL_CONTEXT_MAX);\n\n const plugin = this.registry?.getManifest(runner);\n if (plugin?.contextFile) {\n const configResult = await this.readIfExists(plugin.contextFile)\n || (plugin.contextFileAltPath ? await this.readIfExists(plugin.contextFileAltPath) : null);\n if (configResult) {\n context.agentConfig = configResult.output;\n context.agentConfigPath = plugin.contextFile;\n }\n }\n\n const dirResult = await this.fs.listDir('.', 3);\n if (dirResult.success) context.dirStructure = dirResult.output;\n\n return context;\n }\n\n private async readIfExists(filePath: string) {\n const result = await this.fs.readFile(filePath);\n if (result.success && result.output.length > 0) return result;\n return null;\n }\n}\n","import { IFileSystem, GrepOptions, GrepOutputMode, ToolOutcome } from '../interfaces/IFileSystem';\nimport { IWebFetcher } from '../interfaces/IWebFetcher';\n\nconst GREP_OUTPUT_MODES: GrepOutputMode[] = ['content', 'files', 'count'];\n\nfunction num(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction bool(value: unknown): boolean | undefined {\n return typeof value === 'boolean' ? value : undefined;\n}\n\nfunction str(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\n/**\n * Models emit these in snake_case (that is how the schema declares them), so\n * the mapping to the camelCase {@link GrepOptions} lives here rather than being\n * re-derived in every filesystem adapter.\n */\nfunction grepOptions(args: Record<string, unknown>): GrepOptions {\n const mode = str(args.output_mode ?? args.outputMode);\n return {\n include: str(args.include),\n path: str(args.path),\n outputMode: GREP_OUTPUT_MODES.includes(mode as GrepOutputMode) ? (mode as GrepOutputMode) : undefined,\n contextBefore: num(args.context_before ?? args.contextBefore),\n contextAfter: num(args.context_after ?? args.contextAfter),\n literal: bool(args.literal),\n caseInsensitive: bool(args.case_insensitive ?? args.caseInsensitive),\n headLimit: num(args.head_limit ?? args.headLimit),\n };\n}\n\nexport async function executeTool(\n name: string,\n args: Record<string, unknown>,\n fs: IFileSystem,\n fetcher?: IWebFetcher,\n): Promise<ToolOutcome> {\n switch (name) {\n case 'read_file': {\n const offset = num(args.offset);\n const limit = num(args.limit);\n const maxBytes = num(args.maxBytes);\n return fs.readFile(String(args.path ?? ''), { offset, limit, maxBytes });\n }\n case 'read_files': {\n const paths = Array.isArray(args.paths) ? args.paths.map(String) : [];\n return fs.readFiles(paths);\n }\n case 'glob': return fs.glob(String(args.pattern ?? ''), { path: str(args.path), headLimit: num(args.head_limit ?? args.headLimit) });\n case 'grep': return fs.grep(String(args.pattern ?? ''), grepOptions(args));\n case 'find_symbol': return fs.findSymbol(String(args.symbol ?? ''), { language: str(args.language), path: str(args.path) });\n case 'list_dir': return fs.listDir(String(args.path ?? ''), num(args.depth));\n case 'bash': return fs.bash(String(args.command ?? ''));\n case 'fetch': {\n if (!fetcher) return { success: false, output: 'Web fetching is not available in this environment.', truncated: false };\n const url = String(args.url ?? '');\n const allowed = await fetcher.confirm(url);\n if (!allowed) return { success: false, output: `URL fetch denied by user: ${url}`, truncated: false };\n return fetcher.fetch(url);\n }\n case 'web_search': {\n if (!fetcher?.search) {\n return { success: false, output: 'Web search is not available in this environment. If you already know a documentation URL, use the fetch tool instead.', truncated: false };\n }\n const query = String(args.query ?? '').trim();\n if (!query) return { success: false, output: 'web_search requires a non-empty \"query\".', truncated: false };\n return fetcher.search(query);\n }\n // Budget models hallucinate two kinds of tools: plan-committing ones\n // (create_task, submit_plan) and implementation ones (create_file,\n // write_file). Steer both back: you are a planner, tasks run later,\n // and the commit channel is raw JSON in the reply text.\n default: return {\n success: false,\n output: `Unknown tool: ${name}. You are a PLANNER — you never create or edit files yourself; the coding agents executing the plan will do that later. Your tools are read-only research tools: read_file, read_files, glob, grep, find_symbol, list_dir, bash, fetch, web_search. To commit the final plan, output it as a raw JSON object with a \"tasks\" array directly in your reply text (no tool call).`,\n truncated: false,\n };\n }\n}\n","import { executeTool } from './executeTool';\nimport { subagentToolSpecs } from './researchTools';\nimport { classifyCommand, pathLikeArgs } from './commandPolicy';\nimport { resolveResearchShell } from './researchShell';\nimport { resolveWithin } from './pathScope';\nimport { classifyOutcome } from './researchStepSummary';\nimport type { IFileSystem, ToolOutcome } from '../interfaces/IFileSystem';\nimport type { ResearchChat, ToolResult } from './BaseAiService';\nimport type { ResearchProgress, ResearchStep } from '../models/Task';\n\n/**\n * Read-only research subagents (issue #34), opencode-style: one stateless\n * subagent per spawn_research_agent tool call, so the planner can follow\n * threads as they emerge; parallelism comes from the planner batching several\n * spawn calls in one message (the service layer runs them concurrently).\n * This module owns one subagent's mini research loop — it never imports\n * BaseAiService/OpenAiService (the chat factory comes in as a dependency), so\n * the service → executeTool import chain stays acyclic.\n */\n\nexport const SUBAGENT_LIMITS = {\n /** Max spawn calls in flight at once; extra calls in the same turn wait for a slot. */\n maxConcurrent: 3,\n maxSteps: 10,\n digestMaxChars: 6000,\n toolOutputMaxChars: 20000,\n};\n\nexport interface SubagentDeps {\n /**\n * Builds a fresh chat (own history, subagent system prompt, cheap model).\n * Receives a reasoning-delta callback to wire into the chat, so a\n * reasoning-capable subagent model streams its own live thinking too.\n */\n createChat: (onReasoning: (delta: string) => void) => ResearchChat;\n fs: IFileSystem;\n signal?: AbortSignal;\n /** Structured thinking/tool_call/tool_result events for the UI while the subagent works (caller tags with subagentId). */\n onProgress?: (progress: ResearchProgress) => void;\n}\n\nexport interface SubagentToolOutcome {\n success: boolean;\n output: string;\n truncated: boolean;\n}\n\nconst ALLOWED_TOOL_NAMES = new Set(subagentToolSpecs().map((t) => t.name));\n\nfunction refused(output: string): ToolOutcome {\n return { success: false, output, truncated: false };\n}\n\n/**\n * A subagent runs in the background with nobody watching it, so it must never\n * reach a code path that pauses for approval — a prompt attributed to no\n * visible action, or three prompts at once from three concurrent agents, is\n * worse than a refusal. This wrapper enforces that at the capability boundary\n * rather than trusting the agent's prompt: the auto-tier read-only commands\n * still work, and anything that would ask is refused with an actionable\n * message telling the agent to report the gap in its digest instead.\n *\n * Delegation is explicit rather than a spread — `fs` is a class instance, so\n * its methods live on the prototype and would not survive being copied.\n */\nfunction nonPromptingFs(fs: IFileSystem): IFileSystem {\n const withinWorkspace = (p: string | undefined): boolean =>\n resolveWithin(fs.getWorkspaceRoot(), p ?? '.').inside;\n\n const outsideRefusal = (p: string) => refused(\n `Path \"${p}\" is outside the workspace. Research agents are confined to the workspace root — note the gap in your digest and let the planner request it directly.`,\n );\n\n return {\n getWorkspaceRoot: () => fs.getWorkspaceRoot(),\n readFile: (p, opts) => (withinWorkspace(p) ? fs.readFile(p, opts) : Promise.resolve(outsideRefusal(p))),\n readFiles: (paths) => {\n const escaping = paths.find((p) => !withinWorkspace(p));\n return escaping ? Promise.resolve(outsideRefusal(escaping)) : fs.readFiles(paths);\n },\n glob: (pattern, opts) => (withinWorkspace(opts?.path) ? fs.glob(pattern, opts) : Promise.resolve(outsideRefusal(opts!.path!))),\n grep: (pattern, opts) => (withinWorkspace(opts?.path) ? fs.grep(pattern, opts) : Promise.resolve(outsideRefusal(opts!.path!))),\n findSymbol: (symbol, opts) => (withinWorkspace(opts?.path) ? fs.findSymbol(symbol, opts) : Promise.resolve(outsideRefusal(opts!.path!))),\n listDir: (p, depth) => (withinWorkspace(p) ? fs.listDir(p, depth) : Promise.resolve(outsideRefusal(p))),\n bash: async (command) => {\n // Same dialect the wrapped filesystem will execute under — a subagent\n // must not classify under different rules than the parent.\n const dialect = resolveResearchShell().dialect;\n const { tier, reason } = classifyCommand(command, { dialect });\n if (tier !== 'auto') {\n return refused(\n tier === 'refuse'\n ? `Command refused: ${reason}`\n : `\"${command}\" needs user approval, and research agents run in the background where nothing can be approved. Use the read-only research tools, and note in your digest that this command would answer the question.`,\n );\n }\n // An `auto` binary (cat, find, rg, …) is only auto because reading is\n // read-only — its arguments can still name a path outside the\n // workspace, and a subagent can never prompt to approve one.\n const escaping = pathLikeArgs(command, { dialect }).find((p) => !withinWorkspace(p));\n if (escaping) return outsideRefusal(escaping);\n return fs.bash(command);\n },\n };\n}\n\nasync function runLoop(prompt: string, deps: SubagentDeps): Promise<string> {\n if (deps.signal?.aborted) return '[research agent aborted before starting]';\n const fs = nonPromptingFs(deps.fs);\n const chat = deps.createChat((delta) => deps.onProgress?.({ type: 'thinking', text: delta }));\n let turn = await chat.sendMessage(prompt, deps.signal);\n\n for (let step = 0; turn.hasToolCalls && step < SUBAGENT_LIMITS.maxSteps; step++) {\n if (deps.signal?.aborted) return `[research agent aborted] Partial findings:\\n${turn.text}`;\n const results: ToolResult[] = [];\n for (const tc of turn.toolCalls) {\n // Anything outside the read-only allowlist (fetch, recursive spawn,\n // hallucinated write tools) is refused with a synthetic result — never\n // dispatched — so the API history stays valid and nothing executes.\n if (!ALLOWED_TOOL_NAMES.has(tc.name)) {\n const refusal = `Tool \"${tc.name}\" is not available. You are a read-only research subagent: your only tools are ${[...ALLOWED_TOOL_NAMES].join(', ')}. You cannot fetch URLs, spawn further agents, or modify files. If a specific URL or resource would have answered your question, name it in your digest so the planner can fetch it directly. Otherwise continue with the available tools, then reply with your digest.`;\n results.push({ name: tc.name, output: refusal, truncated: false, totalChars: refusal.length, id: tc.id });\n continue;\n }\n const args = { ...tc.args };\n if (tc.name === 'read_file' && !('maxBytes' in args) && !('limit' in args)) args.limit = 2000;\n const toolArgs = JSON.stringify(tc.args);\n deps.onProgress?.({ type: 'tool_call', tool: tc.name, toolArgs, toolCallId: tc.id });\n const res = await executeTool(tc.name, args, fs);\n const output = res.output.length > SUBAGENT_LIMITS.toolOutputMaxChars\n ? res.output.slice(0, SUBAGENT_LIMITS.toolOutputMaxChars) + `\\n[... truncated to ${SUBAGENT_LIMITS.toolOutputMaxChars} chars, total ${res.output.length}]`\n : res.output;\n const stepEntry: ResearchStep = {\n id: `subrs-${Date.now()}-${step}`,\n tool: tc.name as ResearchStep['tool'],\n args: toolArgs,\n result: output,\n success: res.success,\n outcome: classifyOutcome(res.success, res.output),\n toolCallId: tc.id,\n timestamp: new Date().toISOString(),\n };\n deps.onProgress?.({ type: 'tool_result', toolResult: output, step: stepEntry, toolCallId: tc.id });\n results.push({ name: tc.name, output, truncated: res.truncated || output.length < res.output.length, totalChars: res.output.length, id: tc.id });\n }\n turn = await chat.sendToolResults(results, deps.signal);\n }\n\n // Step budget exhausted while the model still wants tools: answer the\n // pending calls synthetically (history stays valid, nothing executes) and\n // push for the digest — mirrors the parent loop's wrap-up rounds.\n if (turn.hasToolCalls && !deps.signal?.aborted) {\n const notice = `Research budget exhausted (${SUBAGENT_LIMITS.maxSteps} tool rounds) — this call was NOT executed and no further tool calls will be. Reply now with your digest of everything learned so far.`;\n turn = await chat.sendToolResults(\n turn.toolCalls.map((tc) => ({ name: tc.name, output: notice, truncated: false, totalChars: notice.length, id: tc.id })),\n deps.signal,\n );\n }\n\n const digest = turn.text;\n return digest.length > SUBAGENT_LIMITS.digestMaxChars\n ? digest.slice(0, SUBAGENT_LIMITS.digestMaxChars) + `\\n[... digest truncated to ${SUBAGENT_LIMITS.digestMaxChars} chars, total ${digest.length}]`\n : digest;\n}\n\n/**\n * Run one research agent to completion. Never throws: any failure becomes a\n * failed tool result telling the planner to continue sequentially — a subagent\n * can never fail a plan or a turn.\n */\nexport async function runResearchAgent(prompt: string, deps: SubagentDeps): Promise<SubagentToolOutcome> {\n try {\n return { success: true, output: await runLoop(prompt, deps), truncated: false };\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err);\n return { success: false, output: `[research agent failed: ${reason}] Continue researching this area yourself with your own tools.`, truncated: false };\n }\n}\n\n/**\n * Bounded-concurrency helper for a turn that carries several spawn calls:\n * chunks of maxConcurrent run in parallel, later chunks wait — nothing is\n * refused. Results come back in input order.\n */\nexport async function mapWithConcurrency<T, R>(items: T[], limit: number, fn: (item: T, index: number) => Promise<R>): Promise<R[]> {\n const results: R[] = new Array(items.length);\n for (let start = 0; start < items.length; start += limit) {\n const chunk = items.slice(start, start + limit);\n await Promise.all(chunk.map(async (item, offset) => {\n results[start + offset] = await fn(item, start + offset);\n }));\n }\n return results;\n}\n","import {\n GoogleGenerativeAI,\n GenerativeModel,\n Part,\n} from '@google/generative-ai';\nimport { Task, DiscoveredModel, ResearchLogEntry, ResearchProgress, RunnerId } from '../models/Task';\nimport { IConfig } from '../interfaces/IConfig';\nimport { IFileSystem } from '../interfaces/IFileSystem';\nimport { IWebFetcher } from '../interfaces/IWebFetcher';\nimport {\n buildResearchPrompt,\n buildPlanWithResults,\n buildModifyPlanPrompt,\n buildResearchToolsPrompt,\n buildConversationSystemPrompt,\n} from './PlanPrompts';\nimport { generatePlanWithRepair } from './PlanRepair';\nimport type { RunnerModeInfo } from './ModeResolver';\nimport { ContextCollector } from './ContextCollector';\nimport { DEFAULT_PLANNER_MODES, type PlannerModes } from './plannerModes';\nimport { IAiService, ConversationRequest, ConversationTurn } from './AiService';\nimport { BaseAiService, ResearchChat, ResearchTurn, ToolResult, ConversationTurnContext } from './BaseAiService';\nimport { toGeminiToolDeclarations } from './researchTools';\nimport type { LegacyPlanState } from '../models/Task';\n\nconst TOOL_DEFINITIONS = toGeminiToolDeclarations();\n\ninterface GeminiResult {\n response: {\n candidates?: Array<{\n content?: { parts?: Array<Record<string, unknown>> };\n finishReason?: string;\n }>;\n usageMetadata?: { promptTokenCount?: number };\n };\n}\n\nfunction parseGeminiTurn(resultRaw: unknown): ResearchTurn {\n const result = resultRaw as GeminiResult;\n const candidate = result.response.candidates?.[0];\n if (!candidate) return { text: '', toolCalls: [], hasToolCalls: false };\n const parts = candidate.content?.parts || [];\n let text = '';\n let reasoning = '';\n const toolCalls: ResearchTurn['toolCalls'] = [];\n for (const part of parts) {\n if ('text' in part) {\n if ((part as { thought?: boolean }).thought) reasoning += (part as { text: string }).text;\n else text += (part as { text: string }).text;\n }\n if ('functionCall' in part) {\n const fc = part.functionCall as { name: string; args: Record<string, unknown> };\n toolCalls.push({ name: fc.name, args: fc.args });\n }\n }\n // Normalize Gemini's MAX_TOKENS to the OpenAI-style 'length' the\n // conversation loop keys its truncation recovery on.\n const finishReason = candidate.finishReason === 'MAX_TOKENS' ? 'length' : undefined;\n const promptTokens = result.response.usageMetadata?.promptTokenCount;\n return { text, toolCalls, hasToolCalls: toolCalls.length > 0, reasoning: reasoning || undefined, finishReason, promptTokens };\n}\n\nclass GeminiResearchChat implements ResearchChat {\n constructor(\n private chat: ReturnType<GenerativeModel['startChat']>,\n /** Gemini's chat API is non-streaming here, so reasoning/content are emitted once per turn. */\n private onReasoning?: (text: string) => void,\n private onContent?: (text: string) => void,\n ) {}\n\n async sendMessage(text: string, signal?: AbortSignal): Promise<ResearchTurn> {\n if (signal?.aborted) throw new DOMException('Aborted', 'AbortError');\n const result = await this.chat.sendMessage(text);\n return this.emit(parseGeminiTurn(result));\n }\n\n async sendToolResults(results: ToolResult[], signal?: AbortSignal): Promise<ResearchTurn> {\n if (signal?.aborted) throw new DOMException('Aborted', 'AbortError');\n const funcResponses = results.map(r => ({\n functionResponse: {\n name: r.name,\n response: { output: r.output, truncated: r.truncated, totalChars: r.totalChars },\n },\n }));\n const result = await this.chat.sendMessage(funcResponses);\n return this.emit(parseGeminiTurn(result));\n }\n\n private emit(turn: ResearchTurn): ResearchTurn {\n if (turn.reasoning) this.onReasoning?.(turn.reasoning);\n if (turn.text && !turn.hasToolCalls) this.onContent?.(turn.text);\n return turn;\n }\n}\n\nexport class GeminiService extends BaseAiService implements IAiService {\n private genAI: GoogleGenerativeAI | null = null;\n private model: GenerativeModel | null = null;\n\n constructor(config: IConfig) { super(config); }\n\n private init(): boolean {\n if (!this.config.apiKey) return false;\n if (!this.genAI) this.genAI = new GoogleGenerativeAI(this.config.apiKey);\n return true;\n }\n\n private getPlanningModel(): GenerativeModel {\n if (!this.genAI) this.init();\n if (!this.model || this.model.model !== this.config.planningModel) {\n this.model = this.genAI!.getGenerativeModel({\n model: this.config.planningModel,\n generationConfig: { temperature: 0.3, topP: 0.95, maxOutputTokens: 16384 },\n });\n }\n return this.model;\n }\n\n ensureInit(): void {\n if (!this.init()) throw new Error('Gemini API key not configured. Set GEMINI_API_KEY or ordewell.apiKey.');\n }\n\n reset(): void {\n this.activeAbort?.abort();\n this.genAI = null;\n this.model = null;\n this.conversation = null;\n }\n\n async startConversation(req: ConversationRequest): Promise<ConversationTurn> {\n this.ensureInit();\n const genModel = this.getPlanningModel();\n\n const contextStr = await BaseAiService.collectResearchContext(req.fs, req.runners);\n const systemPrompt = buildConversationSystemPrompt(\n req.goal,\n contextStr,\n req.modelsByRunner,\n req.runners,\n req.runnerModes,\n req.autonomousDefault ?? true,\n req.grillMeEnabled ?? false,\n req.prdEnabled ?? false,\n req.reviewEnabled ?? false,\n req.verificationEnabled ?? false,\n );\n\n // Gemini requires strict user/model alternation, so consecutive same-role\n // persisted turns are merged. A leading assistant turn is also absorbed by\n // the system-prompt user message never being followed by a model reply —\n // hence history seeding starts with a synthetic model ack when needed.\n const seededHistory: { role: 'user' | 'model'; parts: Part[] }[] = [\n { role: 'user', parts: [{ text: `${systemPrompt}\\n\\n${buildResearchToolsPrompt()}` }] },\n ];\n for (const m of req.priorHistory ?? []) {\n const role = m.role === 'assistant' ? 'model' : 'user';\n const last = seededHistory[seededHistory.length - 1];\n if (last.role === role) {\n last.parts.push({ text: `\\n\\n${m.content}` });\n } else {\n seededHistory.push({ role, parts: [{ text: m.content }] });\n }\n }\n // A seeded history must end on a model turn so the next sendMessage is a\n // user turn (only relevant on resume; the fresh path keeps its old shape).\n if ((req.priorHistory?.length ?? 0) > 0 && seededHistory[seededHistory.length - 1].role === 'user') {\n seededHistory.push({ role: 'model', parts: [{ text: 'Understood.' }] });\n }\n\n const chat = genModel.startChat({\n history: seededHistory,\n tools: [{ functionDeclarations: TOOL_DEFINITIONS }],\n generationConfig: { temperature: 0.3, topP: 0.95, maxOutputTokens: 16384 },\n });\n\n let currentProgress = req.onProgress;\n const researchChat = new GeminiResearchChat(\n chat,\n (text) => currentProgress({ type: 'thinking', text }),\n (text) => currentProgress({ type: 'plan_token', planToken: text }),\n );\n\n const ctx: ConversationTurnContext = {\n chat: researchChat,\n fs: req.fs,\n runners: req.runners,\n runnerModes: req.runnerModes,\n autonomousDefault: req.autonomousDefault,\n fetcher: req.fetcher,\n prdEnabled: req.prdEnabled ?? false,\n };\n\n this.conversation = { ctx, setProgress: (onProgress) => { currentProgress = onProgress; } };\n\n const combinedSignal = this.startAbortScope(req.signal);\n try {\n const result = await this.runConversationTurn(ctx, req.initialMessage ?? req.goal, req.onProgress, combinedSignal);\n if (result.kind === 'plan') this.conversation = null;\n return result;\n } finally {\n this.stopAbortScope();\n }\n }\n\n\n // --- BaseAiService abstract methods ---\n\n protected async streamPlanText(\n prompt: string,\n repairHint: string | undefined,\n onToken: (token: string) => void,\n onReasoning?: (token: string) => void,\n _signal?: AbortSignal,\n ): Promise<string> {\n const model = this.getPlanningModel();\n const finalParts: Part[] = repairHint\n ? [{ text: prompt }, { text: `\\n\\n${repairHint}` }]\n : [{ text: prompt }];\n const result = await model.generateContentStream({\n contents: [{ role: 'user', parts: finalParts }],\n });\n return this.consumePlanStream(result, onToken, onReasoning);\n }\n\n /**\n * Drain a Gemini content stream, routing \"thought\" parts to the reasoning channel\n * and answer text to the parser. `chunk.text()` throws when a chunk is reasoning-only,\n * so parts are inspected directly.\n */\n private async consumePlanStream(\n result: Awaited<ReturnType<GenerativeModel['generateContentStream']>>,\n onToken: (token: string) => void,\n onReasoning?: (token: string) => void,\n ): Promise<string> {\n let fullResponse = '';\n for await (const chunk of result.stream) {\n const parts = chunk.candidates?.[0]?.content?.parts ?? [];\n for (const part of parts) {\n const text = (part as { text?: string }).text;\n if (!text) continue;\n if ((part as { thought?: boolean }).thought) onReasoning?.(text);\n else { fullResponse += text; onToken(text); }\n }\n }\n return fullResponse;\n }\n\n /** Gemini-specific stream over raw Parts for generatePlanDirect / modifyPlan. */\n private async streamPlanTextWithParts(parts: Part[], repairHint: string | undefined, onToken: (token: string) => void): Promise<string> {\n const model = this.getPlanningModel();\n const finalParts: Part[] = repairHint ? [...parts, { text: `\\n\\n${repairHint}` }] : parts;\n const result = await model.generateContentStream({\n contents: [{ role: 'user', parts: finalParts }],\n });\n return this.consumePlanStream(result, onToken);\n }\n\n // --- IAiService implementation ---\n\n async researchAndPlan(\n userDescription: string,\n runners: RunnerId[],\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n fs: IFileSystem,\n onProgress: (progress: ResearchProgress) => void,\n fetcher?: IWebFetcher,\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n modes: PlannerModes = DEFAULT_PLANNER_MODES,\n signal?: AbortSignal,\n ): Promise<{ tasks: Task[]; researchLog: ResearchLogEntry[]; researchResults: string }> {\n this.ensureInit();\n const { autonomousDefault } = modes;\n const genModel = this.getPlanningModel();\n\n const contextStr = await BaseAiService.collectResearchContext(fs, runners);\n const systemPrompt = buildResearchPrompt(userDescription, contextStr, modelsByRunner, runners, runnerModes, modes);\n const firstMessage = `${buildResearchToolsPrompt()}\\n\\nExplore the workspace to understand the codebase, then generate the plan.`;\n\n const chat = genModel.startChat({\n history: [{ role: 'user', parts: [{ text: systemPrompt }] }],\n tools: [{ functionDeclarations: TOOL_DEFINITIONS }],\n generationConfig: { temperature: 0.3, topP: 0.95, maxOutputTokens: 16384 },\n });\n\n const researchChat: ResearchChat = new GeminiResearchChat(chat);\n\n const result = await this.runResearchLoop(researchChat, firstMessage, fs, onProgress, runners, undefined, fetcher, userDescription, runnerModes, autonomousDefault, signal);\n if (result.tasks) return { tasks: result.tasks, researchLog: result.researchLog, researchResults: result.researchResults };\n const fallback = await this.generatePlanFallback(userDescription, contextStr, result.researchResults, modelsByRunner, runners, onProgress, result.researchLog, runnerModes, autonomousDefault, signal, modes);\n return { tasks: fallback.tasks, researchLog: fallback.researchLog, researchResults: result.researchResults };\n }\n\n async generatePlanDirect(\n userDescription: string,\n runners: RunnerId[] = ['claude-code'],\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>> = {},\n onToken?: (token: string) => void,\n fs?: IFileSystem,\n _fetcher?: IWebFetcher,\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n modes: PlannerModes = DEFAULT_PLANNER_MODES,\n _signal?: AbortSignal,\n ): Promise<Task[]> {\n this.ensureInit();\n const { autonomousDefault } = modes;\n let ctx = '';\n if (fs) {\n const collected = await new ContextCollector(fs).collect(runners[0] ?? 'claude-code');\n if (collected.aiflowContext) ctx = `\\n<aiflow_context>\\n${collected.aiflowContext}\\n</aiflow_context>\\n`;\n }\n const prompt = buildPlanWithResults(userDescription, ctx, '', modelsByRunner, runners, runnerModes, modes);\n return generatePlanWithRepair((repairHint) =>\n this.streamPlanTextWithParts([{ text: prompt }], repairHint, (token) => onToken?.(token)),\n runners,\n 2,\n runnerModes,\n autonomousDefault,\n );\n }\n\n async modifyPlan(\n existingPlan: LegacyPlanState,\n userRequest: string,\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n onProgress?: (progress: ResearchProgress) => void,\n fs?: IFileSystem,\n _fetcher?: IWebFetcher,\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n modes: PlannerModes = DEFAULT_PLANNER_MODES,\n _signal?: AbortSignal,\n ): Promise<{ tasks: Task[] }> {\n this.ensureInit();\n const { autonomousDefault } = modes;\n let aiflowContext: string | undefined;\n if (fs) {\n const collected = await new ContextCollector(fs).collect(existingPlan.runners[0] ?? 'claude-code');\n if (collected.aiflowContext) aiflowContext = collected.aiflowContext;\n }\n const prompt = buildModifyPlanPrompt(existingPlan, userRequest, modelsByRunner, aiflowContext, runnerModes, autonomousDefault);\n try {\n const tasks = await generatePlanWithRepair((repairHint) =>\n this.streamPlanTextWithParts([{ text: prompt }], repairHint, (token) =>\n onProgress?.({ type: 'plan_token', planToken: token })\n ),\n existingPlan.runners,\n 2,\n runnerModes,\n autonomousDefault,\n );\n return { tasks };\n } catch (err) {\n throw new Error(`Plan modification failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n}\n","import OpenAI from 'openai';\nimport {\n Task,\n DiscoveredModel,\n ResearchLogEntry,\n ResearchProgress,\n RunnerId,\n} from '../models/Task';\nimport { IConfig } from '../interfaces/IConfig';\nimport { IFileSystem } from '../interfaces/IFileSystem';\nimport { IWebFetcher } from '../interfaces/IWebFetcher';\nimport {\n buildResearchPrompt,\n buildPlanWithResults,\n buildModifyPlanPrompt,\n buildResearchToolsPrompt,\n buildConversationSystemPrompt,\n buildSubagentSystemPrompt,\n} from './PlanPrompts';\nimport { generatePlanWithRepair } from './PlanRepair';\nimport type { RunnerModeInfo } from './ModeResolver';\nimport { ContextCollector } from './ContextCollector';\nimport { DEFAULT_PLANNER_MODES, type PlannerModes } from './plannerModes';\nimport { IAiService, ConversationRequest, ConversationTurn } from './AiService';\nimport { BaseAiService, ResearchChat, ResearchTurn, ToolResult, ConversationTurnContext } from './BaseAiService';\nimport { toOpenAiTools, toOpenAiSubagentTools } from './researchTools';\nimport { stripModelPrefix } from './ProviderRegistry';\nimport { compactToolMessages, type CompactableMessage } from './contextCompaction';\nimport type { LegacyPlanState } from '../models/Task';\n\nclass OpenAiResearchChat implements ResearchChat {\n constructor(\n private messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[],\n private client: OpenAI,\n private model: string,\n private tools: OpenAI.Chat.Completions.ChatCompletionTool[],\n /** Live reasoning deltas during a turn, so the UI isn't frozen while a reasoning\n * model thinks for tens of seconds before it emits any tool call or content. */\n private onReasoning?: (delta: string) => void,\n /** Live answer-content deltas, so planner messages stream into the chat as they\n * are produced instead of appearing all at once when the turn completes. */\n private onContent?: (delta: string) => void,\n ) {}\n\n async sendMessage(text: string, signal?: AbortSignal): Promise<ResearchTurn> {\n this.messages.push({ role: 'user', content: text });\n return this.callApi(signal);\n }\n\n async sendToolResults(results: ToolResult[], signal?: AbortSignal): Promise<ResearchTurn> {\n for (const r of results) {\n this.messages.push({ role: 'tool', tool_call_id: r.id!, content: r.output });\n }\n return this.callApi(signal);\n }\n\n compactHistory(): number {\n return compactToolMessages(this.messages as CompactableMessage[]);\n }\n\n private async callApi(signal?: AbortSignal): Promise<ResearchTurn> {\n // Stream the turn so reasoning surfaces live. A non-streamed completion blocks\n // for the model's entire think time with no signal — the \"0 steps / nothing for\n // a long time\" symptom on reasoning models. Tool-call deltas are reassembled by\n // index into the final message the loop acts on.\n const stream = await this.client.chat.completions.create({\n model: this.model,\n messages: this.messages,\n tools: this.tools,\n tool_choice: 'auto',\n stream: true,\n // Explicit cap, matching streamPlanText: with max_tokens unset, some\n // OpenRouter providers default far lower and silently cut long plan\n // emissions mid-JSON.\n max_tokens: 32000,\n // Exact prompt-token usage arrives in the final chunk — the signal\n // proactive history compaction keys on.\n stream_options: { include_usage: true },\n }, signal ? { signal } : undefined);\n\n let content = '';\n let reasoning = '';\n let finishReason: string | undefined;\n let promptTokens: number | undefined;\n const toolAcc = new Map<number, { id: string; name: string; args: string }>();\n\n for await (const chunk of stream) {\n if (chunk.usage) promptTokens = chunk.usage.prompt_tokens;\n const fr = chunk.choices[0]?.finish_reason;\n if (fr) finishReason = fr;\n const delta = chunk.choices[0]?.delta as\n | { content?: string; reasoning?: string; tool_calls?: Array<{ index: number; id?: string; function?: { name?: string; arguments?: string } }> }\n | undefined;\n if (!delta) continue;\n if (delta.reasoning) { reasoning += delta.reasoning; this.onReasoning?.(delta.reasoning); }\n if (delta.content) { content += delta.content; this.onContent?.(delta.content); }\n for (const tc of delta.tool_calls ?? []) {\n const acc = toolAcc.get(tc.index) ?? { id: '', name: '', args: '' };\n if (tc.id) acc.id = tc.id;\n if (tc.function?.name) acc.name = tc.function.name;\n if (tc.function?.arguments) acc.args += tc.function.arguments;\n toolAcc.set(tc.index, acc);\n }\n }\n\n const accepted = [...toolAcc.entries()].sort((a, b) => a[0] - b[0]).map(([, v]) => v).filter((v) => v.name);\n\n // Rebuild the assistant message so subsequent turns (which reference tool_call_id)\n // stay consistent with what we executed.\n const assistantMsg: OpenAI.Chat.Completions.ChatCompletionMessageParam = accepted.length > 0\n ? { role: 'assistant', content: content || null, tool_calls: accepted.map((v) => ({ id: v.id, type: 'function', function: { name: v.name, arguments: v.args } })) }\n : { role: 'assistant', content };\n this.messages.push(assistantMsg);\n\n const toolCalls: ResearchTurn['toolCalls'] = accepted.map((v) => {\n let args: Record<string, unknown> = {};\n try { args = JSON.parse(v.args); } catch { /* empty */ }\n return { name: v.name, args, id: v.id };\n });\n return { text: content, toolCalls, hasToolCalls: toolCalls.length > 0, reasoning: reasoning || undefined, finishReason, promptTokens };\n }\n}\n\nexport class OpenAiService extends BaseAiService implements IAiService {\n private client: OpenAI | null = null;\n\n constructor(config: IConfig) { super(config); }\n\n private getClient(): OpenAI {\n if (!this.client) {\n const baseUrl = this.config.getProviderBaseUrl(this.config.aiProvider);\n const apiKey = this.config.getProviderApiKey(this.config.aiProvider);\n this.client = new OpenAI({ baseURL: baseUrl, apiKey });\n }\n return this.client;\n }\n\n ensureInit(): void {\n if (this.config.aiProvider === 'openai_compatible' && !this.config.openaiCompatibleBaseUrl) {\n throw new Error('OpenAI-compatible base URL not configured. Set OPENAI_COMPATIBLE_BASE_URL.');\n }\n const apiKey = this.config.getProviderApiKey(this.config.aiProvider);\n if (!apiKey) {\n throw new Error('OpenAI API key not configured. Set OPENAI_API_KEY.');\n }\n }\n\n private requireModel(field: string, value: string | undefined | null): string {\n // Picker/stored ids carry a provider qualifier (e.g. `openai:gpt-4o`,\n // `openai_compat:llama3`); the serving API only knows the bare model name.\n const id = stripModelPrefix((value ?? '').trim(), this.config.aiProvider);\n if (!id) throw new Error(`OpenAI model not configured: \"${field}\" is empty.`);\n return id;\n }\n\n reset(): void { this.activeAbort?.abort(); this.client = null; this.conversation = null; }\n\n // --- BaseAiService abstract methods ---\n\n protected async streamPlanText(\n prompt: string,\n repairHint: string | undefined,\n onToken: (token: string) => void,\n onReasoning?: (token: string) => void,\n signal?: AbortSignal,\n ): Promise<string> {\n const client = this.getClient();\n const messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[] = [{ role: 'user', content: prompt }];\n if (repairHint) messages.push({ role: 'user', content: repairHint });\n const stream = await client.chat.completions.create({\n model: this.requireModel('orchestratorModel', this.config.orchestratorModel),\n messages,\n stream: true,\n max_tokens: 32000,\n }, { signal });\n let fullResponse = '';\n for await (const chunk of stream) {\n const delta = chunk.choices[0]?.delta as { content?: string; reasoning?: string } | undefined;\n // Only content contributes to the text handed to the parser; reasoning is routed\n // to the thinking trace so chain-of-thought can never pollute the JSON.\n const reasoning = delta?.reasoning;\n if (reasoning) onReasoning?.(reasoning);\n const token = delta?.content;\n if (token) { fullResponse += token; onToken(token); }\n }\n return fullResponse;\n }\n\n /** A research subagent: fresh history, digest contract, cheap model, read-only tools. */\n protected createSubagentChat(onReasoning?: (delta: string) => void): ResearchChat | null {\n const client = this.getClient();\n const messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[] = [\n { role: 'system', content: buildSubagentSystemPrompt() },\n ];\n return new OpenAiResearchChat(\n messages,\n client,\n this.requireModel('researchSubagentModel', this.config.researchSubagentModel),\n toOpenAiSubagentTools(),\n onReasoning,\n );\n }\n\n // --- Conversation loop (ADR-0002) ---\n\n async startConversation(req: ConversationRequest): Promise<ConversationTurn> {\n this.ensureInit();\n const client = this.getClient();\n this.researchSubagentsEnabled = req.researchSubagentsEnabled ?? false;\n\n const contextStr = await BaseAiService.collectResearchContext(req.fs, req.runners);\n const systemPrompt = buildConversationSystemPrompt(\n req.goal,\n contextStr,\n req.modelsByRunner,\n req.runners,\n req.runnerModes,\n req.autonomousDefault ?? true,\n req.grillMeEnabled ?? false,\n req.prdEnabled ?? false,\n req.reviewEnabled ?? false,\n req.verificationEnabled ?? false,\n );\n\n const userText = req.goal;\n\n const messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[] = [\n { role: 'system', content: `${systemPrompt}\\n\\n${buildResearchToolsPrompt(this.researchSubagentsEnabled)}` },\n ];\n for (const m of req.priorHistory ?? []) {\n messages.push({ role: m.role, content: m.content });\n }\n\n let currentProgress = req.onProgress;\n const chat = new OpenAiResearchChat(\n messages,\n client,\n this.requireModel('orchestratorModel', this.config.orchestratorModel),\n toOpenAiTools(this.researchSubagentsEnabled),\n (delta) => currentProgress({ type: 'thinking', text: delta }),\n (delta) => currentProgress({ type: 'plan_token', planToken: delta }),\n );\n\n const ctx: ConversationTurnContext = {\n chat,\n fs: req.fs,\n runners: req.runners,\n runnerModes: req.runnerModes,\n autonomousDefault: req.autonomousDefault,\n fetcher: req.fetcher,\n prdEnabled: req.prdEnabled ?? false,\n };\n\n this.conversation = {\n ctx,\n setProgress: (onProgress) => { currentProgress = onProgress; },\n };\n\n const combinedSignal = this.startAbortScope(req.signal);\n try {\n const result = await this.runConversationTurn(ctx, req.initialMessage ?? userText, req.onProgress, combinedSignal);\n if (result.kind === 'plan') this.conversation = null;\n return result;\n } finally {\n this.stopAbortScope();\n }\n }\n\n // --- IAiService implementation ---\n\n async researchAndPlan(\n userDescription: string,\n runners: RunnerId[],\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n fs: IFileSystem,\n onProgress: (progress: ResearchProgress) => void,\n fetcher?: IWebFetcher,\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n modes: PlannerModes = DEFAULT_PLANNER_MODES,\n signal?: AbortSignal,\n ): Promise<{ tasks: Task[]; researchLog: ResearchLogEntry[]; researchResults: string }> {\n this.ensureInit();\n const client = this.getClient();\n const { autonomousDefault, researchSubagents: researchSubagentsEnabled } = modes;\n this.researchSubagentsEnabled = researchSubagentsEnabled;\n\n const contextStr = await BaseAiService.collectResearchContext(fs, runners);\n const systemPrompt = buildResearchPrompt(userDescription, contextStr, modelsByRunner, runners, runnerModes, modes);\n\n const userText = `User goal: ${userDescription}`;\n const firstMessage = `${buildResearchToolsPrompt(researchSubagentsEnabled)}\\n\\nExplore the workspace to understand the codebase, then generate the plan.\\n\\n${userText}`;\n\n const messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[] = [\n { role: 'system', content: systemPrompt },\n ];\n\n const researchChat: ResearchChat = new OpenAiResearchChat(\n messages,\n client,\n this.requireModel('orchestratorModel', this.config.orchestratorModel),\n toOpenAiTools(researchSubagentsEnabled),\n (delta) => onProgress({ type: 'thinking', text: delta }),\n );\n\n const result = await this.runResearchLoop(researchChat, firstMessage, fs, onProgress, runners, undefined, fetcher, userDescription, runnerModes, autonomousDefault, signal);\n if (result.tasks) return { tasks: result.tasks, researchLog: result.researchLog, researchResults: result.researchResults };\n const fallback = await this.generatePlanFallback(userDescription, contextStr, result.researchResults, modelsByRunner, runners, onProgress, result.researchLog, runnerModes, autonomousDefault, signal, modes);\n return { tasks: fallback.tasks, researchLog: fallback.researchLog, researchResults: result.researchResults };\n }\n\n async generatePlanDirect(\n userDescription: string,\n runners: RunnerId[] = ['claude-code'],\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>> = {},\n onToken?: (token: string) => void,\n fs?: IFileSystem,\n _fetcher?: IWebFetcher,\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n modes: PlannerModes = DEFAULT_PLANNER_MODES,\n signal?: AbortSignal,\n ): Promise<Task[]> {\n this.ensureInit();\n const { autonomousDefault } = modes;\n let ctx = '';\n if (fs) {\n const collected = await new ContextCollector(fs).collect(runners[0] ?? 'claude-code');\n if (collected.aiflowContext) ctx = `\\n<aiflow_context>\\n${collected.aiflowContext}\\n</aiflow_context>\\n`;\n }\n const prompt = buildPlanWithResults(userDescription, ctx, '', modelsByRunner, runners, runnerModes, modes);\n return generatePlanWithRepair((repairHint) =>\n this.streamPlanText(prompt, repairHint, (token) => onToken?.(token), undefined, signal),\n runners,\n 2,\n runnerModes,\n autonomousDefault,\n );\n }\n\n async modifyPlan(\n existingPlan: LegacyPlanState,\n userRequest: string,\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n onProgress?: (progress: ResearchProgress) => void,\n fs?: IFileSystem,\n _fetcher?: IWebFetcher,\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n modes: PlannerModes = DEFAULT_PLANNER_MODES,\n signal?: AbortSignal,\n ): Promise<{ tasks: Task[] }> {\n this.ensureInit();\n const { autonomousDefault } = modes;\n let aiflowContext: string | undefined;\n if (fs) {\n const collected = await new ContextCollector(fs).collect(existingPlan.runners[0] ?? 'claude-code');\n if (collected.aiflowContext) aiflowContext = collected.aiflowContext;\n }\n const prompt = buildModifyPlanPrompt(existingPlan, userRequest, modelsByRunner, aiflowContext, runnerModes, autonomousDefault);\n try {\n const tasks = await generatePlanWithRepair((repairHint) =>\n this.streamPlanText(prompt, repairHint, (token) => onProgress?.({ type: 'plan_token', planToken: token }), undefined, signal),\n existingPlan.runners,\n 2,\n runnerModes,\n autonomousDefault,\n );\n return { tasks };\n } catch (err) {\n throw new Error(`Plan modification failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n}\n","import type { Task } from '../models/Task';\n\nconst MAX_TAIL_CHARS = 500;\nconst DEFAULT_PLAN_MAP_MAX_ENTRIES = 30;\nconst PLAN_MAP_MIN_TASKS = 3;\n\nexport interface PriorOutput {\n order: number;\n title: string;\n reviewReason: string;\n logTail: string;\n}\n\nexport function summarizeOutput(reviewReason: string | undefined, output: string): { reviewReason: string; logTail: string; capturedAt: string } {\n return {\n reviewReason: (reviewReason ?? '').trim(),\n logTail: (output ?? '').slice(-MAX_TAIL_CHARS).trim(),\n capturedAt: new Date().toISOString(),\n };\n}\n\nexport function collectDirectDependencyOutputs(task: Task, allTasks: Task[]): PriorOutput[] {\n const byId = new Map(allTasks.map((t) => [t.id, t]));\n const out: PriorOutput[] = [];\n for (const depId of task.dependencies ?? []) {\n const dep = byId.get(depId);\n if (!dep || !dep.outputSummary) continue;\n out.push({\n order: dep.order,\n title: dep.title,\n reviewReason: dep.outputSummary.reviewReason,\n logTail: dep.outputSummary.logTail,\n });\n }\n return out;\n}\n\n/**\n * Break marker tokens carried in a predecessor's captured output. Interactive\n * runners echo the prompt they are given, and the watcher scans that terminal\n * output — a quoted marker would settle this task on the previous one's\n * evidence. Hyphenated rather than spaced: the scanner also reads a\n * whitespace-flattened view of the terminal, which would rejoin a space.\n */\nfunction defuseMarkers(text: string): string {\n return text.replace(/<<<ORDEWELL_/g, '<<<ORDEWELL-');\n}\n\nexport function renderPriorOutputs(outputs: PriorOutput[]): string {\n if (outputs.length === 0) return '';\n const blocks = outputs\n .sort((a, b) => a.order - b.order)\n .map((o) => {\n const tail = o.logTail\n ? defuseMarkers(o.logTail).split('\\n').map((l) => ' ' + l).join('\\n')\n : ' (no output captured)';\n const reason = defuseMarkers(o.reviewReason) || '(no review note)';\n return `### Task ${o.order}: ${o.title}\\n- Review: ${reason}\\n- Tail:\\n${tail}`;\n });\n return `## Prior task outputs\\n\\n${blocks.join('\\n\\n')}`;\n}\n\nexport function augmentPromptWithPriorOutputs(task: Task, allTasks: Task[]): string {\n const basePrompt = task.prompt ?? '';\n const outputs = collectDirectDependencyOutputs(task, allTasks);\n if (outputs.length === 0) return basePrompt;\n return `${renderPriorOutputs(outputs)}\\n\\n${basePrompt}`;\n}\n\nfunction planMapStatus(task: Task, isCurrent: boolean): string {\n if (isCurrent) return 'NOW';\n if (task.status === 'completed') return 'done';\n if (task.status === 'failed') return 'failed';\n if (task.status === 'blocked') return 'blocked';\n if (task.status === 'in_progress') return 'running';\n if (task.type === 'user') return 'user';\n return 'next';\n}\n\nfunction pickWindow(sorted: Task[], currentIdx: number, max: number): { window: Task[]; omitted: number } {\n if (sorted.length <= max) return { window: sorted, omitted: 0 };\n if (currentIdx < 0) return { window: sorted.slice(0, max), omitted: sorted.length - max };\n const lookBack = Math.min(currentIdx, Math.floor(max / 3));\n let start = currentIdx - lookBack;\n if (start + max > sorted.length) start = sorted.length - max;\n if (start < 0) start = 0;\n const window = sorted.slice(start, start + max);\n return { window, omitted: sorted.length - window.length };\n}\n\nexport function renderPlanMap(allTasks: Task[], currentTaskId: string, opts?: { maxEntries?: number }): string {\n if (allTasks.length < PLAN_MAP_MIN_TASKS) return '';\n\n const sorted = [...allTasks].sort((a, b) => a.order - b.order);\n const max = opts?.maxEntries ?? DEFAULT_PLAN_MAP_MAX_ENTRIES;\n const currentIdx = sorted.findIndex((t) => t.id === currentTaskId);\n const { window, omitted } = pickWindow(sorted, currentIdx, max);\n\n const currentTask = sorted.find((t) => t.id === currentTaskId);\n\n const widthOrder = Math.max(2, String(sorted[sorted.length - 1]?.order ?? sorted.length).length);\n const lines = window.map((t) => {\n const isCurrent = t.id === currentTaskId;\n const tag = planMapStatus(t, isCurrent);\n const order = String(t.order).padStart(widthOrder, ' ');\n const arrow = isCurrent ? ' ← you are here' : '';\n const runner = t.assignedRunner ? ` (${t.assignedRunner})` : '';\n return `${order}. [${tag.padEnd(7, ' ')}] ${t.title}${runner}${arrow}`;\n });\n\n const footer = omitted > 0 ? `\\n(${omitted} task${omitted === 1 ? '' : 's'} omitted from this view)` : '';\n const runnerNote = currentTask?.assignedRunner\n ? `\\nYou are running as: ${currentTask.assignedRunner}`\n : '';\n\n return [\n '## Plan map',\n '',\n 'This is for context only — do ONLY the task marked `← you are here`. Future tasks will handle their own scope; do not preempt them.',\n '',\n lines.join('\\n') + footer + runnerNote,\n ].join('\\n');\n}\n\nexport interface ComposeOptions {\n planMapEnabled?: boolean;\n planMapMaxEntries?: number;\n tddEnabled?: boolean;\n}\n\nfunction renderCompletionMarker(task: Task): string {\n // The marker is given in two halves so the assembled token never appears in\n // this prompt. Interactive TUIs echo the prompt into the terminal, and the\n // watcher scans terminal output for the token — a literal marker here would\n // complete the task the moment the session starts.\n return `\\n\\nWhen you have fully completed this task, print one final line containing only the completion marker. Build it by writing \\`<<<ORDEWELL_\\` immediately followed by \\`DONE_${task.completionMarker}>>>\\` — joined into a single unbroken token, with no space, quote, or any other character between the two parts.`;\n}\n\nfunction renderTddInstruction(): string {\n return [\n '## Implementation workflow (TDD)',\n '',\n 'Work test-first in vertical slices at the seams your task prompt names. A seam is the public boundary you test at — if the prompt names none, identify the highest public interface and test there, never against internals.',\n '',\n '1. RED: Write ONE failing test for the next behavior, through the public interface',\n '2. GREEN: Write minimal production code to make that test pass',\n '',\n 'Rules:',\n '- One test per RED-GREEN cycle — do not write all tests first',\n '- Expected values must come from an independent source of truth (spec, worked example, known-good literal), never recomputed the way the code computes them',\n '- Prefer integration-style tests over unit tests with mocks; tests should survive internal refactors',\n '- Use the project\\'s existing test framework and patterns',\n '- While iterating, run the typechecker and the single test file you are touching frequently; run the full test suite once at the end of the task',\n '- Refactoring is not part of the red-green cycle: only once all tests are green, tidy what this task touched, keeping tests green',\n ].join('\\n');\n}\n\nfunction renderCheckpointInstruction(): string {\n return [\n '## Human-in-the-loop checkpoints',\n '',\n 'When you reach a decision point that requires human judgment — before destructive',\n 'operations, after major design decisions, or when multiple viable paths exist — pause',\n 'and request input:',\n '',\n // Two halves, for the same reason as the completion marker above: the\n // watcher scans terminal output for this token, and interactive runners echo\n // the prompt — a literal marker here checkpointed the task (dropping it out\n // of `in_progress`) the moment the session started.\n '1. Print one line holding only the checkpoint marker. Build it by writing `<<<ORDEWELL_` immediately followed by `CHECKPOINT:` — no space, quote, or any other character between those two parts — then a brief summary of what you are about to do and why human input is needed, closed with `>>>`',\n '2. Wait for the human to respond (they will send ORDEWELL_CONTINUE or ORDEWELL_REJECT)',\n '3. On CONTINUE: proceed with the action you described',\n '4. On REJECT: adjust your approach and re-emit a checkpoint if needed',\n ].join('\\n');\n}\n\nfunction isHitlTask(task: Task): boolean {\n return task.autonomy === 'HITL' || task.sliceType === 'HITL';\n}\n\nexport function composeAugmentedPrompt(task: Task, allTasks: Task[], opts?: ComposeOptions): string {\n const basePrompt = task.prompt ?? '';\n const blocks: string[] = [];\n\n if (opts?.planMapEnabled !== false) {\n const map = renderPlanMap(allTasks, task.id, { maxEntries: opts?.planMapMaxEntries });\n if (map) blocks.push(map);\n }\n\n const outputs = collectDirectDependencyOutputs(task, allTasks);\n if (outputs.length > 0) blocks.push(renderPriorOutputs(outputs));\n\n if (opts?.tddEnabled) {\n blocks.push(renderTddInstruction());\n }\n\n if (isHitlTask(task)) {\n blocks.push(renderCheckpointInstruction());\n }\n\n const marker = renderCompletionMarker(task);\n\n if (blocks.length === 0) return basePrompt + marker;\n return `${blocks.join('\\n\\n')}\\n\\n${basePrompt}${marker}`;\n}\n","import type { Task, Verdict, VerificationCheck } from '../models/Task';\nimport type { ITerminalSession } from '../interfaces/ITerminalRunner';\n\nexport type VerdictListener = (taskId: string, verdict: Verdict, output: string) => void;\nexport type CheckpointListener = (taskId: string, summary: string) => void;\n\nconst CHECKPOINT_RE = /<<<ORDEWELL_CHECKPOINT:\\s*(.*?)>>>/gs;\n\n// eslint-disable-next-line no-control-regex\nconst ANSI_OR_CTRL_RE = /\\x1b\\[[0-9;?]*[A-Za-z]|\\x1b\\][^\\x07\\x1b]*(?:\\x07|\\x1b\\\\)?|\\x1b[()][AB012]|\\x1b[=>]|[\\x00-\\x08\\x0b-\\x1f\\x7f]/g;\n\n/**\n * Collapse terminal rendering out of raw PTY output: strip ANSI/OSC escape\n * sequences, box-drawing gutter characters, and ALL whitespace. Interactive\n * TUIs soft-wrap long lines, so a completion marker arrives split across\n * lines with escapes interleaved — a raw `includes()` never matches it.\n * Markers contain no whitespace, so this flattened view is safe to scan.\n */\nexport function flattenTerminalOutput(raw: string): string {\n return raw\n .replace(ANSI_OR_CTRL_RE, '')\n .replace(/[─-▟]/g, '') // box-drawing + block elements (TUI borders/gutters)\n .replace(/\\s+/g, '');\n}\n\n/**\n * Reconstruct the small terminal screen represented by a PTY output tail.\n *\n * Full-screen TUIs do not emit answer text as one chronological stream. They\n * paint fragments at absolute cursor positions and repaint unrelated widgets\n * between those writes. OpenCode, for example, may emit:\n *\n * row 9: \"<<<ORDEW\"\n * row 23: spinner repaint\n * row 9: \"ELL_DONE_...\"\n *\n * Flattening that byte stream inserts the spinner inside the marker. Rendering\n * the cursor-positioned writes first recovers the token the user actually sees.\n * This intentionally implements only the common cursor/erase subset used by\n * coding-agent TUIs; the chronological scanner remains the fallback for plain\n * output and soft-wrapped lines.\n */\nexport function renderTerminalOutput(raw: string): string {\n const rows = new Map<number, string[]>();\n let row = 1;\n let col = 1;\n let savedRow = 1;\n let savedCol = 1;\n\n const cells = (r: number): string[] => {\n let line = rows.get(r);\n if (!line) {\n line = [];\n rows.set(r, line);\n }\n return line;\n };\n const firstParam = (params: number[], fallback = 1): number => params[0] || fallback;\n const eraseLine = (mode: number): void => {\n const line = cells(row);\n if (mode === 2) {\n rows.set(row, []);\n } else if (mode === 1) {\n for (let c = 0; c < col; c++) line[c] = ' ';\n } else {\n line.length = Math.max(0, col - 1);\n }\n };\n\n for (let i = 0; i < raw.length;) {\n const ch = raw[i];\n if (ch === '\\x1b') {\n const kind = raw[i + 1];\n if (kind === '[') {\n let end = i + 2;\n while (end < raw.length) {\n const code = raw.charCodeAt(end);\n if (code >= 0x40 && code <= 0x7e) break;\n end++;\n }\n if (end >= raw.length) break;\n const final = raw[end];\n const body = raw.slice(i + 2, end).replace(/^[?<>=!]+/, '');\n const params = body.split(';').map((p) => Number.parseInt(p, 10) || 0);\n switch (final) {\n case 'H':\n case 'f':\n row = params[0] || 1;\n col = params[1] || 1;\n break;\n case 'G': col = firstParam(params); break;\n case 'd': row = firstParam(params); break;\n case 'A': row = Math.max(1, row - firstParam(params)); break;\n case 'B': row += firstParam(params); break;\n case 'C': col += firstParam(params); break;\n case 'D': col = Math.max(1, col - firstParam(params)); break;\n case 'E': row += firstParam(params); col = 1; break;\n case 'F': row = Math.max(1, row - firstParam(params)); col = 1; break;\n case 's': savedRow = row; savedCol = col; break;\n case 'u': row = savedRow; col = savedCol; break;\n case 'K': eraseLine(params[0] || 0); break;\n case 'J':\n if ((params[0] || 0) === 2 || (params[0] || 0) === 3) rows.clear();\n break;\n case 'X': {\n const line = cells(row);\n for (let c = 0; c < firstParam(params); c++) line[col - 1 + c] = ' ';\n break;\n }\n case 'P': {\n cells(row).splice(col - 1, firstParam(params));\n break;\n }\n case '@': {\n cells(row).splice(col - 1, 0, ...Array(firstParam(params)).fill(' '));\n break;\n }\n default:\n break;\n }\n i = end + 1;\n continue;\n }\n if (kind === ']' || kind === 'P' || kind === '^' || kind === '_') {\n let end = i + 2;\n while (end < raw.length && raw[end] !== '\\x07' && !(raw[end] === '\\x1b' && raw[end + 1] === '\\\\')) end++;\n if (end >= raw.length) break;\n i = raw[end] === '\\x07' ? end + 1 : end + 2;\n continue;\n }\n if (kind === '7') {\n savedRow = row;\n savedCol = col;\n } else if (kind === '8') {\n row = savedRow;\n col = savedCol;\n } else if (kind === 'c') {\n rows.clear();\n row = 1;\n col = 1;\n }\n // Character-set selection sequences carry one extra byte.\n i += kind === '(' || kind === ')' ? 3 : 2;\n continue;\n }\n if (ch === '\\r') {\n col = 1;\n i++;\n continue;\n }\n if (ch === '\\n') {\n row++;\n i++;\n continue;\n }\n if (ch === '\\b') {\n col = Math.max(1, col - 1);\n i++;\n continue;\n }\n if (ch === '\\t') {\n col += 8 - ((col - 1) % 8);\n i++;\n continue;\n }\n if (ch < ' ' || ch === '\\x7f') {\n i++;\n continue;\n }\n cells(row)[col - 1] = ch;\n col++;\n i++;\n }\n\n const populated = [...rows.keys()].sort((a, b) => a - b);\n return populated.map((r) => cells(r).join('')).join('\\n');\n}\n\n/** Only the tail of the buffer is flattened per chunk — markers are short and\n * recent, and re-flattening an unbounded buffer on every write is O(n²). */\nconst MARKER_SCAN_TAIL = 16384;\n\nexport class VerdictEngine {\n private markerSeen = new Set<string>();\n private buffers = new Map<string, string>();\n private checkpointCounts = new Map<string, number>();\n private pausedSessions = new Map<string, ITerminalSession>();\n private listeners: VerdictListener[] = [];\n private checkpointListeners: CheckpointListener[] = [];\n /**\n * Per-task generation counter. Incremented on every watch() and clear().\n * Stale callbacks (from a prior session whose generation doesn't match\n * the current one) bail out instead of delivering a verdict for the\n * wrong session.\n */\n private generations = new Map<string, number>();\n\n onVerdict(listener: VerdictListener): void {\n this.listeners.push(listener);\n }\n\n onCheckpoint(listener: CheckpointListener): void {\n this.checkpointListeners.push(listener);\n }\n\n approveCheckpoint(taskId: string): void {\n const session = this.pausedSessions.get(taskId);\n if (session) {\n session.write('\\nORDEWELL_CONTINUE\\n');\n this.pausedSessions.delete(taskId);\n }\n }\n\n rejectCheckpoint(taskId: string, reason: string): void {\n const session = this.pausedSessions.get(taskId);\n if (session) {\n session.write(`\\nORDEWELL_REJECT: ${reason}\\n`);\n this.pausedSessions.delete(taskId);\n }\n }\n\n /**\n * Attach to a spawned session: buffer output, scan for the task's completion\n * marker (delivering a verdict immediately while leaving interactive sessions\n * open), scan for checkpoint markers, and on exit produce a failed verdict\n * when the marker was never observed.\n */\n watch(task: Task, session: ITerminalSession): void {\n const doneToken = `<<<ORDEWELL_DONE_${task.completionMarker}>>>`;\n const gen = (this.generations.get(task.id) ?? 0) + 1;\n this.generations.set(task.id, gen);\n this.buffers.set(task.id, '');\n this.checkpointCounts.set(task.id, 0);\n session.onOutput((text: string) => {\n if (this.generations.get(task.id) !== gen) return;\n if (this.markerSeen.has(task.id)) return;\n const buf = (this.buffers.get(task.id) ?? '') + text;\n this.buffers.set(task.id, buf);\n const tail = buf.slice(-MARKER_SCAN_TAIL);\n const markerVisible = flattenTerminalOutput(tail).includes(doneToken)\n || flattenTerminalOutput(renderTerminalOutput(tail)).includes(doneToken);\n if (markerVisible) {\n this.markerSeen.add(task.id);\n // Deliver verdict immediately instead of killing the session.\n // The terminal stays open so the user can read output or keep chatting\n // with the AI runner. Bump the generation so the onExit callback\n // (which will fire when the terminal eventually closes) bails out.\n const output = buf;\n this.buffers.delete(task.id);\n this.checkpointCounts.delete(task.id);\n this.pausedSessions.delete(task.id);\n this.generations.set(task.id, gen + 1);\n const verdict = this.decide(task, 0);\n for (const l of this.listeners) l(task.id, verdict, output);\n return;\n }\n const matches = [...buf.matchAll(CHECKPOINT_RE)];\n const prevCount = this.checkpointCounts.get(task.id) ?? 0;\n for (let i = prevCount; i < matches.length; i++) {\n const summary = matches[i][1].trim();\n this.pausedSessions.set(task.id, session);\n for (const l of this.checkpointListeners) l(task.id, summary);\n }\n this.checkpointCounts.set(task.id, matches.length);\n });\n session.onExit((exitCode: number) => {\n if (this.generations.get(task.id) !== gen) return;\n const output = session.getOutput();\n const tail = output.slice(-MARKER_SCAN_TAIL);\n if (\n flattenTerminalOutput(tail).includes(doneToken)\n || flattenTerminalOutput(renderTerminalOutput(tail)).includes(doneToken)\n ) {\n this.markerSeen.add(task.id);\n }\n this.buffers.delete(task.id);\n this.checkpointCounts.delete(task.id);\n this.pausedSessions.delete(task.id);\n const verdict = this.decide(task, exitCode);\n for (const l of this.listeners) l(task.id, verdict, output);\n });\n }\n\n /** Manual \"Mark complete\" override: a pass verdict that bypasses evidence. */\n markComplete(task: Task): Verdict {\n this.markerSeen.delete(task.id);\n this.buffers.delete(task.id);\n this.checkpointCounts.delete(task.id);\n this.pausedSessions.delete(task.id);\n this.generations.set(task.id, (this.generations.get(task.id) ?? 0) + 1);\n return {\n outcome: 'pass',\n reason: 'Manually marked complete by user.',\n checks: [\n {\n name: 'manual',\n passed: true,\n skipped: false,\n detail: 'Task was manually marked complete by the user; no automatic verification was performed.',\n },\n ],\n decidedAt: new Date().toISOString(),\n };\n }\n\n /** Clear verification state for a task (used on retry). */\n clear(task: Task): void {\n this.markerSeen.delete(task.id);\n this.buffers.delete(task.id);\n this.checkpointCounts.delete(task.id);\n this.pausedSessions.delete(task.id);\n this.generations.set(task.id, (this.generations.get(task.id) ?? 0) + 1);\n }\n\n /** Drop all tracking state (used on stop / loadPlan). */\n reset(): void {\n this.markerSeen.clear();\n this.buffers.clear();\n this.checkpointCounts.clear();\n this.pausedSessions.clear();\n this.generations.clear();\n }\n\n private decide(task: Task, exitCode: number): Verdict {\n const normalized = exitCode == null ? 0 : exitCode;\n const markerWasSeen = this.markerSeen.has(task.id);\n if (markerWasSeen) this.markerSeen.delete(task.id);\n\n const checks: VerificationCheck[] = [];\n if (markerWasSeen) {\n checks.push({\n name: 'completion_marker',\n passed: true,\n skipped: false,\n detail: 'task completion marker was seen in agent output',\n });\n checks.push({\n name: 'exit_code',\n passed: true,\n skipped: true,\n detail: 'bypassed — completion marker was seen in agent output',\n });\n return {\n outcome: 'pass',\n reason: 'Verified: completion marker detected in agent output. Task completed successfully.',\n checks,\n decidedAt: new Date().toISOString(),\n };\n }\n\n const exitOk = normalized === 0;\n checks.push({\n name: 'completion_marker',\n passed: false,\n skipped: false,\n detail: 'agent exited before Ordewell detected the task completion marker',\n });\n checks.push({\n name: 'exit_code',\n passed: exitOk,\n skipped: false,\n detail: exitOk ? 'agent exited cleanly (code 0)' : `agent exited with code ${normalized}`,\n });\n\n return {\n outcome: 'fail',\n reason: exitOk\n ? 'Failed verification: agent exited cleanly but did not emit the completion marker.'\n : `Failed verification: completion marker missing; agent exited with code ${normalized}.`,\n checks,\n decidedAt: new Date().toISOString(),\n };\n }\n}\n","import {\n Task, TaskSnapshot, RunnerId, flattenTasks,\n addTaskToPlan, removeTaskFromPlan, updateTaskInPlan,\n createTask, renumberTasks,\n} from '../models/Task';\n\n/**\n * The deep module owning all plan-shaped state. Holds `planTasks` (the ordered\n * tree the user edits), the flattened `allTasks` view, the `taskMap` index, and\n * the `completedTasks`/`failedTasks` sets the scheduler reads. The orchestrator\n * calls `markCompleted`/`markFailed`/`markInProgress`/`retry` to update task\n * status — it never mutates task state directly.\n *\n * `rebuild` is the internal seam that keeps the flat views in sync with the\n * tree. Structural removals (remove/merge/split) additionally prune\n * `completedTasks`/`failedTasks` for ids that no longer exist; `removeFromActive`\n * deliberately does not, so a completed task that leaves the active list still\n * satisfies its dependents' dependency checks.\n *\n * `planRunners` lives here because it's part of the plan's identity (the runner\n * set, carried on the plan). `validateAssignedRunners` is pure store logic.\n */\nexport class PlanStore {\n private _planTasks: Task[] = [];\n private _allTasks: Task[] = [];\n private _taskMap = new Map<string, Task>();\n private _completedTasks = new Set<string>();\n private _failedTasks = new Set<string>();\n private _planRunners: RunnerId[] = ['claude-code'];\n private _onMutate: (() => void) | null = null;\n private _executionLog: TaskSnapshot[] = [];\n\n /** Hook called after every structural mutation (add/remove/update/merge/split/load). */\n set onMutate(cb: (() => void) | null) { this._onMutate = cb; }\n\n get planTasks(): Task[] { return this._planTasks; }\n get allTasks(): Task[] { return this._allTasks; }\n get planRunners(): RunnerId[] { return this._planRunners; }\n get completedCount(): number { return this._completedTasks.size; }\n get failedCount(): number { return this._failedTasks.size; }\n\n isAllComplete(): boolean { return this._allTasks.every((t) => t.status === 'completed'); }\n isAnyFailed(): boolean { return this._failedTasks.size > 0; }\n isCompleted(id: string): boolean { return this._completedTasks.has(id); }\n isFailed(id: string): boolean { return this._failedTasks.has(id); }\n\n get(taskId: string): Task | undefined { return this._taskMap.get(taskId); }\n\n getExecutionLog(): TaskSnapshot[] { return this._executionLog; }\n\n appendToLog(snapshot: TaskSnapshot): void {\n const idx = this._executionLog.findIndex((s) => s.id === snapshot.id);\n if (idx >= 0) {\n this._executionLog[idx] = snapshot;\n } else {\n this._executionLog.push(snapshot);\n }\n }\n\n /**\n * Drop a task's archived snapshot. Un-marking a completion has to erase the\n * \"finished\" record too — dependent tasks are prompted from the log, so a\n * left-behind snapshot would keep feeding them a result that no longer exists.\n */\n removeFromLog(taskId: string): void {\n this._executionLog = this._executionLog.filter((s) => s.id !== taskId);\n }\n\n removeFromActive(taskId: string): void {\n this._planTasks = this._planTasks.filter((t) => t.id !== taskId);\n this.rebuild();\n this.notifyMutate();\n }\n\n clearLog(): void {\n this._executionLog = [];\n }\n\n private notifyMutate(): void { this._onMutate?.(); }\n\n load(tasks: Task[], runners: RunnerId[]): void {\n this._planTasks = tasks;\n this._planRunners = runners;\n this._completedTasks.clear();\n this._failedTasks.clear();\n this.rebuild();\n // Completed tasks survive a reload so a half-finished plan resumes the\n // remainder (their output summaries still feed dependents). Failed tasks\n // get a fresh chance. In-progress is left alone — load() also runs while\n // a task's terminal session is live (forceStartTask); orphaned in_progress\n // from a saved session is normalized at the disk-load boundary instead.\n for (const task of this._allTasks) {\n if (task.status === 'completed') {\n this._completedTasks.add(task.id);\n } else if (task.status === 'failed') {\n task.status = 'pending';\n }\n }\n this.validateAssignedRunners();\n }\n\n add(partial: Partial<Task>): Task {\n const oldIds = new Set(this._taskMap.keys());\n this._planTasks = addTaskToPlan(this._planTasks, partial);\n this.rebuild();\n this.notifyMutate();\n return this._allTasks.find(t => !oldIds.has(t.id))!;\n }\n\n remove(taskId: string): void {\n if (!this._taskMap.has(taskId)) return;\n this._planTasks = removeTaskFromPlan(this._planTasks, taskId);\n this.rebuild();\n this.pruneTerminalSets();\n this.notifyMutate();\n }\n\n update(taskId: string, changes: Partial<Task>): Task | undefined {\n if (!this._taskMap.has(taskId)) return undefined;\n const safe: Partial<Task> = { ...changes };\n delete safe.id;\n delete safe.order;\n this._planTasks = updateTaskInPlan(this._planTasks, taskId, safe);\n this.rebuild();\n this.notifyMutate();\n return this._taskMap.get(taskId);\n }\n\n mergeMultiple(taskIds: string[]): Task {\n if (taskIds.length < 2) throw new Error('Must provide at least two task IDs to merge');\n const sorted = [...new Set(taskIds)]\n .map(id => ({ id, task: this._taskMap.get(id) }))\n .filter(x => x.task)\n .sort((a, b) => (a.task?.order ?? 0) - (b.task?.order ?? 0));\n\n if (sorted.length < 2) throw new Error('At least two valid tasks required for merge');\n\n let current = sorted[0].id;\n for (let i = 1; i < sorted.length; i++) {\n const merged = this.merge(current, sorted[i].id);\n current = merged.id;\n }\n return this._taskMap.get(current)!;\n }\n\n merge(taskIdA: string, taskIdB: string): Task {\n const taskA = this._taskMap.get(taskIdA);\n const taskB = this._taskMap.get(taskIdB);\n if (!taskA) throw new Error(`Task ${taskIdA} not found`);\n if (!taskB) throw new Error(`Task ${taskIdB} not found`);\n\n const mergedDeps = [...new Set([...taskA.dependencies, ...taskB.dependencies])]\n .filter(depId => depId !== taskIdA && depId !== taskIdB);\n\n const mergedStories = [...new Set([...(taskA.userStoriesCovered ?? []), ...(taskB.userStoriesCovered ?? [])])];\n\n const mergedPrompt = [taskA.prompt, taskB.prompt].filter(Boolean).join('\\n\\n---\\n\\n');\n\n const merged = createTask({\n title: `${taskA.title} + ${taskB.title}`,\n description: `${taskA.description}\\n\\n${taskB.description}`,\n type: taskA.type === 'user' || taskB.type === 'user' ? 'user' : 'ai',\n dependencies: mergedDeps,\n prompt: mergedPrompt || undefined,\n autonomy: taskA.autonomy ?? taskB.autonomy,\n sliceType: taskA.sliceType ?? taskB.sliceType,\n userStoriesCovered: mergedStories.length > 0 ? mergedStories : undefined,\n assignedRunner: taskA.assignedRunner,\n assignedModel: taskA.assignedModel,\n taskMode: taskA.taskMode,\n order: Math.min(taskA.order, taskB.order),\n });\n\n const mergedId = merged.id;\n const userIds = new Set([taskIdA, taskIdB]);\n const sanitized = this._planTasks\n .filter(t => !userIds.has(t.id))\n .map(t => ({\n ...t,\n dependencies: t.dependencies.map(depId =>\n depId === taskIdA || depId === taskIdB ? mergedId : depId\n ),\n }));\n\n this._planTasks = renumberTasks([...sanitized, merged]);\n this.rebuild();\n this.pruneTerminalSets();\n this.notifyMutate();\n return merged;\n }\n\n split(taskId: string, newTaskSpecs: Partial<Task>[]): Task[] {\n const original = this._taskMap.get(taskId);\n if (!original) throw new Error(`Task ${taskId} not found`);\n if (!newTaskSpecs.length) throw new Error('Must provide at least one new task spec');\n\n const newTasks = newTaskSpecs.map((spec, i) =>\n createTask({\n ...spec,\n order: original.order + i,\n dependencies: i === 0 ? [...original.dependencies] : [newTaskSpecs[0].id ?? `split-${taskId}-0`],\n type: spec.type ?? original.type,\n assignedRunner: spec.assignedRunner ?? original.assignedRunner,\n assignedModel: spec.assignedModel ?? original.assignedModel,\n taskMode: spec.taskMode ?? original.taskMode,\n autonomy: spec.autonomy ?? original.autonomy,\n sliceType: spec.sliceType ?? original.sliceType,\n userStoriesCovered: spec.userStoriesCovered ?? original.userStoriesCovered,\n })\n );\n\n const newTaskIds = new Map<number, string>();\n newTasks.forEach((t, i) => newTaskIds.set(i, t.id));\n\n const finalized = newTasks.map((t) => {\n const deps = t.dependencies.map(depId => {\n const idx = newTaskSpecs.findIndex(s => (s.id ?? '') === depId);\n if (idx >= 0) return newTaskIds.get(idx) ?? depId;\n return depId;\n });\n return { ...t, dependencies: deps };\n });\n\n const tailId = finalized[finalized.length - 1].id;\n\n const updatedOthers = this._planTasks\n .filter(t => t.id !== taskId)\n .map(t => ({\n ...t,\n dependencies: t.dependencies.map(depId => depId === taskId ? tailId : depId),\n }));\n\n this._planTasks = renumberTasks([...updatedOthers, ...finalized]);\n this.rebuild();\n this.pruneTerminalSets();\n this.notifyMutate();\n return finalized;\n }\n\n /**\n * Run preparation as one named op: flip every AI task to 'approved'. By\n * default completed tasks keep their status so a reloaded half-finished plan\n * resumes the remainder instead of re-running work that already succeeded;\n * `preserveCompleted: false` is for a freshly committed plan, where\n * everything starts over.\n */\n resetForRun(opts: { preserveCompleted?: boolean } = {}): void {\n const preserveCompleted = opts.preserveCompleted ?? true;\n for (const t of this._allTasks) {\n if (t.type !== 'ai') continue;\n if (preserveCompleted && t.status === 'completed') continue;\n t.status = 'approved';\n }\n }\n\n markCompleted(id: string): void {\n this._failedTasks.delete(id);\n this._completedTasks.add(id);\n const task = this._taskMap.get(id);\n if (task) task.status = 'completed';\n }\n\n markFailed(id: string): void {\n this._completedTasks.delete(id);\n this._failedTasks.add(id);\n const task = this._taskMap.get(id);\n if (task) task.status = 'failed';\n }\n\n markInProgress(id: string): void {\n this._completedTasks.delete(id);\n this._failedTasks.delete(id);\n const task = this._taskMap.get(id);\n if (task) task.status = 'in_progress';\n }\n\n markAwaitingUser(id: string): void {\n const task = this._taskMap.get(id);\n if (task) task.status = 'awaiting_user';\n }\n\n markPending(id: string): void {\n this._completedTasks.delete(id);\n this._failedTasks.delete(id);\n const task = this._taskMap.get(id);\n if (task) task.status = 'pending';\n }\n\n retry(id: string): void {\n this._failedTasks.delete(id);\n this._completedTasks.delete(id);\n const task = this._taskMap.get(id);\n if (task) {\n task.status = 'pending';\n task.verdict = undefined;\n task.outputSummary = undefined;\n }\n }\n\n blockDependents(id: string): void {\n for (const t of this._allTasks) {\n if (t.dependencies.includes(id) && t.status !== 'completed') {\n t.status = 'blocked';\n }\n }\n }\n\n unblockDependents(id: string): void {\n for (const t of this._allTasks) {\n if (t.status === 'blocked' && t.dependencies.includes(id)) {\n t.status = 'pending';\n }\n }\n }\n\n setTaskVerdict(id: string, verdict: Task['verdict']): void {\n const task = this._taskMap.get(id);\n if (task) task.verdict = verdict;\n }\n\n setTaskOutputSummary(id: string, summary: Task['outputSummary']): void {\n const task = this._taskMap.get(id);\n if (task) task.outputSummary = summary;\n }\n\n getPlanVisualization(): { tasks: { id: string; title: string; dependencies: string[]; parallelGroups: number[][] }[]; parallelGroups: number[][] } {\n const unscheduled = new Set(this._planTasks.map(t => t.id));\n const completed = new Set<string>();\n const parallelGroups: number[][] = [];\n\n while (unscheduled.size > 0) {\n const batch: string[] = [];\n for (const t of this._planTasks) {\n if (!unscheduled.has(t.id)) continue;\n if (t.dependencies.length > 0 && t.dependencies.some(depId => !completed.has(depId))) continue;\n batch.push(t.id);\n }\n if (batch.length === 0) break;\n for (const id of batch) {\n unscheduled.delete(id);\n completed.add(id);\n }\n parallelGroups.push(batch.map(id => this._taskMap.get(id)?.order ?? 0).sort((a, b) => a - b));\n }\n\n return {\n tasks: this._planTasks.map(t => ({ id: t.id, title: t.title, dependencies: t.dependencies, parallelGroups: [] })),\n parallelGroups,\n };\n }\n\n /**\n * Widen the plan's runner set. Retargeting a task onto a runner the plan has\n * not used before has to land here as well as on the plan state, or\n * {@link resolveTaskRunner} reads the new runner as foreign and spawns the\n * plan's first one instead.\n */\n admitRunner(runner: RunnerId): void {\n if (!this._planRunners.includes(runner)) this._planRunners = [...this._planRunners, runner];\n }\n\n resolveTaskRunner(task: Task): RunnerId {\n if (task.assignedRunner && this._planRunners.includes(task.assignedRunner)) return task.assignedRunner;\n const fallback = this._planRunners[0] ?? 'claude-code';\n if (task.assignedRunner) {\n console.warn(\n `[PlanStore] Task \"${task.title}\" is assigned to \"${task.assignedRunner}\", which is not in this plan's ` +\n `runner set [${this._planRunners.join(', ')}] — spawning \"${fallback}\" instead.`,\n );\n }\n return fallback;\n }\n\n private rebuild(): void {\n this._allTasks = flattenTasks(this._planTasks);\n this._taskMap.clear();\n for (const task of this._allTasks) {\n this._taskMap.set(task.id, task);\n }\n }\n\n /**\n * Drop completed/failed ids that no longer exist in the plan. Called by the\n * structural removals (remove/merge/split) — but NOT by removeFromActive,\n * where a completed task leaves the active list yet must still satisfy its\n * dependents' dependency checks.\n */\n private pruneTerminalSets(): void {\n for (const id of [...this._completedTasks]) {\n if (!this._taskMap.has(id)) this._completedTasks.delete(id);\n }\n for (const id of [...this._failedTasks]) {\n if (!this._taskMap.has(id)) this._failedTasks.delete(id);\n }\n }\n\n private validateAssignedRunners(): void {\n for (const task of this._allTasks) {\n if (task.type !== 'ai') continue;\n if (!this._planRunners.includes(task.assignedRunner)) {\n throw new Error(\n `Task \"${task.title}\" has assignedRunner \"${task.assignedRunner}\" ` +\n `which is not in the plan's runner set: [${this._planRunners.join(', ')}]`\n );\n }\n }\n }\n}\n","import { Task, TaskSnapshot, Verdict, QueuedMessage, RunnerId } from '../models/Task';\nimport { IConfig } from '../interfaces/IConfig';\nimport { INotification } from '../interfaces/INotification';\nimport { ITerminalRunner } from '../interfaces/ITerminalRunner';\nimport { composeAugmentedPrompt, summarizeOutput } from './promptAugment';\nimport { VerdictEngine } from './VerdictEngine';\nimport { PlanStore } from './PlanStore';\nimport type { RunnerRegistry } from '../plugins/RunnerRegistry';\n\n/**\n * The one notification channel out of the orchestrator. Everything that used\n * to travel over separate callbacks (onRefresh, onQueueReady) is an observer\n * event; the Session subscribes once and turns these into SessionMessages.\n */\nexport interface OrchestratorObserver {\n /** Any task-shaped state changed (store mutation, checkpoint, retry, …). */\n onTaskChanged?(): void;\n onTick?(): void;\n onExecutionComplete?(): void;\n /** Queued user messages are ready to be processed by the planner. */\n onQueueReady?(): void;\n onReviewNeeded?(data: { tasks: Task[]; planRunners: RunnerId[] }): void;\n onReviewApproved?(data: { tasks: Task[] }): void;\n onCheckpoint?(data: { taskId: string; taskTitle: string; summary: string }): void;\n}\n\n/**\n * The pure scheduler. Owns execution state (`running`, `planStatus`,\n * `reviewApproved`, `activeTaskSessions`, `messageQueue`) and the verifier.\n * All task-shaped state — the plan tree, the flat index, the completed set\n * — lives in {@link PlanStore}, injected at construction. The orchestrator\n * calls `store.markCompleted(id)` / `store.markFailed(id)` instead of mutating\n * task state directly. A task completes only after the runner emits its\n * per-task completion marker; process exit without that evidence is a visible\n * failure and does not unblock dependent work.\n */\nexport class TaskOrchestrator {\n private store: PlanStore;\n private activeTaskSessions = new Map<string, string>();\n private startingTaskIds = new Set<string>();\n private verifier = new VerdictEngine();\n private running = false;\n private planStatus: 'approved' | 'running' | 'completed' = 'approved';\n private messageQueue: QueuedMessage[] = [];\n private reviewApproved = false;\n private retryCounts = new Map<string, number>();\n /**\n * Tasks pulled out of auto-scheduling (user-cancelled or failed to spawn).\n * They stay 'pending' — \"not executed\" — but the scheduler skips them until\n * the user retries or force-starts, which would otherwise loop forever on a\n * task whose spawn always throws.\n */\n private onHold = new Set<string>();\n\n private registry: RunnerRegistry | null = null;\n private workspaceRootFn: () => string = () => process.cwd();\n private observers: OrchestratorObserver[] = [];\n private tddEnabled: () => boolean = () => false;\n\n constructor(\n private config: IConfig,\n private notifications: INotification,\n private terminalRunner: ITerminalRunner,\n store?: PlanStore,\n ) {\n this.store = store ?? new PlanStore();\n this.store.onMutate = () => this.emit('onTaskChanged');\n this.verifier.onVerdict((taskId, verdict, output) => this.onVerdict(taskId, verdict, output));\n this.verifier.onCheckpoint((taskId, summary) => {\n const task = this.store.get(taskId);\n if (!task) return;\n this.store.markAwaitingUser(taskId);\n this.emit('onCheckpoint', { taskId, taskTitle: task.title, summary });\n });\n }\n\n get storeInstance(): PlanStore { return this.store; }\n\n setWorkspaceRoot(fn: () => string): void {\n this.workspaceRootFn = fn;\n }\n\n setRegistry(registry: RunnerRegistry): void {\n this.registry = registry;\n }\n\n /**\n * A getter rather than a value where the caller has one: every task gets its\n * prompt composed at spawn time, but only a full-plan run passes through a\n * point where a snapshot could be refreshed — so \"Run task\", force-start and\n * retry would compose against whatever the last run happened to set.\n */\n setTddEnabled(enabled: boolean | (() => boolean)): void {\n this.tddEnabled = typeof enabled === 'function' ? enabled : () => enabled;\n }\n\n approveCheckpoint(taskId: string): void {\n this.verifier.approveCheckpoint(taskId);\n this.store.markInProgress(taskId);\n this.emit('onTaskChanged');\n }\n\n rejectCheckpoint(taskId: string, reason?: string): void {\n this.verifier.rejectCheckpoint(taskId, reason ?? 'Checkpoint rejected by user');\n this.store.markInProgress(taskId);\n this.emit('onTaskChanged');\n }\n\n subscribe(observer: OrchestratorObserver): () => void {\n this.observers.push(observer);\n return () => {\n this.observers = this.observers.filter(o => o !== observer);\n };\n }\n\n private emit(event: keyof OrchestratorObserver, ...args: unknown[]): void {\n for (const o of this.observers) {\n const fn = o[event] as (...args: unknown[]) => void;\n if (fn) fn(...args);\n }\n }\n\n get isRunning(): boolean {\n return this.running || this.startingTaskIds.size > 0 || this.activeTaskSessions.size > 0;\n }\n get isReviewApproved(): boolean { return this.reviewApproved; }\n get status(): 'approved' | 'running' | 'completed' { return this.planStatus; }\n get activeTaskIds(): string[] { return [...this.activeTaskSessions.keys()]; }\n get activeSessionMap(): Map<string, string> { return new Map(this.activeTaskSessions); }\n get queuedCount(): number { return this.messageQueue.length; }\n\n queueMessage(text: string): void {\n this.messageQueue.push({\n id: `q-${Date.now()}`,\n text,\n timestamp: new Date().toISOString(),\n });\n this.emit('onTaskChanged');\n }\n\n getQueuedMessages(): QueuedMessage[] {\n return [...this.messageQueue];\n }\n\n setQueuedMessages(messages: QueuedMessage[]): void {\n this.messageQueue = [...messages];\n }\n\n clearQueuedMessages(): void {\n this.messageQueue = [];\n }\n\n processNextQueuedMessage(): QueuedMessage | null {\n if (this.messageQueue.length === 0) return null;\n return this.messageQueue.shift() ?? null;\n }\n\n loadPlan(tasks: Task[], planRunners: RunnerId[] = ['claude-code']): void {\n this.store.load(tasks, planRunners);\n this.activeTaskSessions.clear();\n this.startingTaskIds.clear();\n this.verifier.reset();\n this.planStatus = 'approved';\n this.reviewApproved = false;\n this.retryCounts.clear();\n this.onHold.clear();\n }\n\n reconcilePlan(newTasks: Task[], planRunners: RunnerId[] = ['claude-code']): void {\n for (const taskId of this.activeTaskSessions.keys()) {\n const task = this.store.get(taskId);\n if (!task) continue;\n\n const inNewPlan = newTasks.find((t) => t.id === taskId);\n if (!inNewPlan) {\n newTasks.push({ ...task });\n } else if (inNewPlan.status !== 'in_progress') {\n console.warn(`[TaskOrchestrator] Running task \"${task.title}\" status changed to \"${inNewPlan.status}\" in modified plan, using orchestrator truth`);\n }\n }\n\n this.store.load(newTasks, planRunners);\n this.planStatus = 'running';\n }\n\n async start(): Promise<void> {\n if (this.running) {\n console.error('[TaskOrchestrator] start() called but already running — no-op');\n return;\n }\n if (!this.reviewApproved) {\n console.log('[TaskOrchestrator] start() blocked — plan review not yet approved. Emitting onReviewNeeded.');\n this.emit('onReviewNeeded', { tasks: this.store.planTasks, planRunners: this.store.planRunners });\n return;\n }\n console.log(`[TaskOrchestrator] Starting with ${this.store.allTasks.length} tasks (${this.store.allTasks.filter(t => t.type === 'ai' && t.prompt).length} AI ready)`);\n this.running = true;\n this.planStatus = 'running';\n this.emit('onTaskChanged');\n await this.tick();\n }\n\n stop(): void {\n this.running = false;\n this.planStatus = 'approved';\n this.terminalRunner.stopAll();\n this.activeTaskSessions.clear();\n this.startingTaskIds.clear();\n this.verifier.reset();\n this.onHold.clear();\n this.emit('onTaskChanged');\n }\n\n async onUserTaskComplete(taskId: string): Promise<void> {\n return this.markTaskComplete(taskId);\n }\n\n private async onVerdict(taskId: string, verdict: Verdict, output: string): Promise<void> {\n const task = this.store.get(taskId);\n if (!task) return;\n this.activeTaskSessions.delete(taskId);\n\n console.error(`[TaskOrchestrator] Task #${task.order} \"${task.title}\" verdict=${verdict.outcome}`);\n console.error(`[TaskOrchestrator] Runner: ${task.assignedRunner}, Model: ${task.assignedModel?.modelId ?? 'default'}`);\n console.error(`[TaskOrchestrator] Prompt preview: ${(task.prompt ?? '').slice(0, 200)}`);\n if (output && output.length > 0) {\n console.error(`[TaskOrchestrator] Output (last 3000 chars):\\n${output.slice(-3000)}`);\n } else {\n console.error(`[TaskOrchestrator] Output: (empty — no stdout/stderr captured)`);\n }\n\n this.store.setTaskVerdict(taskId, verdict);\n\n if (verdict.outcome === 'pass') {\n this.store.markCompleted(taskId);\n this.notifications.info(`Task \"${task.title}\" completed.`);\n } else {\n this.store.markFailed(taskId);\n // Missing completion evidence is a hard boundary: do not launch more\n // work from a full-plan run until the user retries/resumes explicitly.\n // Already-active parallel tasks may finish, but no new task is spawned.\n this.running = false;\n this.planStatus = 'approved';\n this.notifications.error(`Task \"${task.title}\" failed verification: ${verdict.reason}`);\n }\n\n this.store.setTaskOutputSummary(taskId, summarizeOutput(verdict.reason, output));\n\n this.logAndArchive(task, verdict);\n\n this.emit('onTaskChanged');\n if (!this.running) {\n if (this.activeTaskSessions.size === 0 && this.startingTaskIds.size === 0) {\n if (this.store.isAllComplete()) this.planStatus = 'completed';\n this.emit('onTick');\n this.emit('onExecutionComplete');\n }\n return;\n }\n await this.tick();\n }\n\n getReadyTasks(): Task[] {\n if (!this.running) return [];\n const maxParallel = this.config.maxParallelSessions;\n const currentActive = this.activeTaskSessions.size;\n if (currentActive >= maxParallel) return [];\n const availableSlots = maxParallel - currentActive;\n\n const candidates = this.store.allTasks.filter((t) => {\n if (t.status !== 'pending' && t.status !== 'approved') return false;\n if (t.type === 'user') return false;\n if (!t.prompt) return false;\n if (this.onHold.has(t.id)) return false;\n if (this.isBlocked(t)) return false;\n if (t.dependencies.length > 0 && !t.dependencies.every((depId) => this.store.isCompleted(depId))) return false;\n return true;\n });\n\n const excluded = this.store.allTasks.filter(t => t.type === 'ai' && t.prompt && !candidates.includes(t));\n if (excluded.length > 0) {\n for (const t of excluded) {\n const reasons: string[] = [];\n if (t.status !== 'pending' && t.status !== 'approved') reasons.push(`status=${t.status}`);\n if (this.onHold.has(t.id)) reasons.push('on-hold');\n if (this.isBlocked(t)) reasons.push('blocked');\n if (t.dependencies.length > 0 && !t.dependencies.every((depId) => this.store.isCompleted(depId))) reasons.push('deps');\n console.log(`[TaskOrchestrator] excluded: #${t.order} \"${t.title}\" — ${reasons.join(', ')}`);\n }\n }\n\n console.log(`[TaskOrchestrator] getReadyTasks: ${candidates.length} candidates, ${availableSlots} slots, maxParallel=${maxParallel}`);\n return candidates.sort((a, b) => a.order - b.order).slice(0, availableSlots);\n }\n\n isBlocked(task: Task): boolean {\n if (task.status === 'blocked') return true;\n if (task.dependencies.length > 0) return task.dependencies.some((depId) => this.store.isFailed(depId));\n return false;\n }\n\n /**\n * Cancel a running (or scheduled) task: kill its session and return it to\n * 'pending' — \"not executed\". The task is put on hold so the scheduler\n * doesn't immediately restart it; Retry / Force Start release the hold.\n */\n async cancelTask(taskId: string): Promise<void> {\n const task = this.store.get(taskId);\n if (!task) return;\n // Bump the verifier's generation *before* stopping the runner: some\n // runners (e.g. tmux) fire onExit synchronously from stop(), and if that\n // exit reaches VerdictEngine under the still-valid generation it delivers\n // a verdict that marks this cancelled task 'completed' for one tick —\n // long enough for the scheduler to synchronously start a dependent task.\n this.verifier.clear(task);\n const sessionId = this.activeTaskSessions.get(taskId);\n if (sessionId) {\n this.terminalRunner.stop(sessionId);\n this.activeTaskSessions.delete(taskId);\n }\n this.store.markPending(taskId);\n this.onHold.add(taskId);\n this.emit('onTaskChanged');\n await this.tick();\n }\n\n async markTaskComplete(taskId: string): Promise<void> {\n const task = this.store.get(taskId);\n if (!task || task.status === 'completed') return;\n\n const sessionId = this.activeTaskSessions.get(taskId);\n if (sessionId) {\n this.terminalRunner.stop(sessionId);\n this.activeTaskSessions.delete(taskId);\n }\n\n this.verifier.clear(task);\n const verdict = this.verifier.markComplete(task);\n\n this.store.markCompleted(taskId);\n this.store.setTaskVerdict(taskId, verdict);\n this.store.setTaskOutputSummary(taskId, summarizeOutput(verdict.reason, ''));\n this.logAndArchive(task, verdict);\n this.store.unblockDependents(taskId);\n this.onHold.delete(taskId);\n\n this.notifications.info(`Task \"${task.title}\" marked complete.`);\n this.emit('onTaskChanged');\n await this.tick();\n }\n\n async markAiTaskComplete(taskId: string): Promise<void> {\n return this.markTaskComplete(taskId);\n }\n\n /**\n * Undo a completion: return the task to \"not executed\" — pending, verdict and\n * summary dropped, archive entry removed. It is put on hold like a cancel, so\n * a running plan does not immediately re-spawn the work the user just\n * un-marked; Retry / Force Start / Run release the hold. Dependents fall back\n * to waiting on their own, because the scheduler gates on `isCompleted`.\n */\n async markTaskIncomplete(taskId: string): Promise<void> {\n const task = this.store.get(taskId);\n if (!task || task.status !== 'completed') return;\n\n this.verifier.clear(task);\n this.store.retry(taskId);\n this.store.removeFromLog(taskId);\n this.onHold.add(taskId);\n // A finished plan is no longer finished — leaving 'completed' would tell\n // every surface the run is over while a task sits pending.\n if (this.planStatus === 'completed') this.planStatus = 'approved';\n\n this.notifications.info(`Task \"${task.title}\" marked not done.`);\n this.emit('onTaskChanged');\n await this.tick();\n }\n\n private logAndArchive(task: Task, verdict: Verdict): void {\n const snapshot: TaskSnapshot = {\n ...task,\n completedAt: Date.now(),\n verdict,\n retryCount: this.retryCounts.get(task.id) ?? 0,\n finalized: true,\n };\n this.store.appendToLog(snapshot);\n // Completed tasks remain in the active plan tree so the UI can keep\n // showing them alongside pending and running work.\n }\n\n async retryTask(taskId: string): Promise<void> {\n const task = this.store.get(taskId);\n if (!task) return;\n this.retryCounts.set(taskId, (this.retryCounts.get(taskId) ?? 0) + 1);\n this.store.retry(taskId);\n this.verifier.clear(task);\n this.store.unblockDependents(taskId);\n this.onHold.delete(taskId);\n this.emit('onTaskChanged');\n await this.tick();\n }\n\n /**\n * Manually start a single AI task right now, bypassing dependency/readiness\n * gating (the \"force start\" affordance on a task card). Reuses the scheduler's\n * own startTask so a force-started task gets the same augmented prompt, session\n * tracking, and exit handling — callers must not re-spawn the runner themselves.\n * No-op if the task is unknown, not an AI task, or already running.\n */\n async forceStartTask(taskId: string): Promise<void> {\n const task = this.store.get(taskId);\n if (!task || task.type !== 'ai') return;\n if (this.activeTaskSessions.has(taskId)) return;\n this.onHold.delete(taskId);\n await this.startTask(task);\n }\n\n /**\n * Run exactly one task outside full-plan scheduling. The active/starting\n * session still contributes to isRunning so every surface exposes Stop and\n * disables Execute Plan, but onVerdict cannot auto-schedule other tasks\n * because the plan scheduler's `running` flag remains false.\n */\n async runTask(taskId: string): Promise<void> {\n if (this.isRunning) return;\n const task = this.store.get(taskId);\n if (!task || task.type !== 'ai') return;\n this.onHold.delete(taskId);\n await this.startTask(task);\n }\n\n getCompletedCount(): number { return this.store.completedCount; }\n getTotalCount(): number { return this.store.allTasks.length; }\n isAllComplete(): boolean { return this.store.isAllComplete(); }\n isAnyFailed(): boolean { return this.store.isAnyFailed(); }\n\n async approveReview(): Promise<void> {\n if (this.reviewApproved) {\n console.log('[TaskOrchestrator] approveReview() called but already approved — no-op');\n return;\n }\n this.reviewApproved = true;\n this.planStatus = 'approved';\n this.emit('onTaskChanged');\n this.emit('onReviewApproved', { tasks: this.store.planTasks });\n await this.start();\n }\n\n getPlanVisualization() { return this.store.getPlanVisualization(); }\n\n async tick(): Promise<void> {\n if (!this.running) return;\n\n if (this.messageQueue.length > 0) {\n if (this.activeTaskSessions.size === 0) {\n this.emit('onQueueReady');\n }\n return;\n }\n\n const ready = this.getReadyTasks();\n console.log(`[TaskOrchestrator] tick(): ${ready.length} ready, ${this.activeTaskSessions.size} active, queue=${this.messageQueue.length}`);\n\n if (ready.length === 0 && this.activeTaskSessions.size === 0) {\n const remaining = this.store.allTasks.filter(t => t.status !== 'completed');\n console.log(`[TaskOrchestrator] tick(): no work. remaining=${remaining.length}, completed=${this.store.isAllComplete()}`);\n for (const t of remaining) {\n console.log(` - ${t.order}. ${t.title} [${t.type}/${t.status}] prompt=${!!t.prompt}`);\n }\n if (this.store.isAllComplete()) {\n // Genuinely done — stop the loop so a fresh Execute click can start it again.\n this.running = false;\n this.planStatus = 'completed';\n this.notifications.info('All tasks completed!');\n this.emit('onTaskChanged');\n this.emit('onTick');\n this.emit('onExecutionComplete');\n } else {\n // Not done — just waiting on a user task, checkpoint, or held task.\n // Keep `running` true: markTaskComplete/retryTask/forceStartTask/cancelTask\n // all re-tick() afterward, and that only ever schedules new work while\n // `running` is true. Flipping it false here would silently kill the\n // scheduler and leave dependents unblocked-but-never-started.\n // Do NOT emit onExecutionComplete here: a paused run is not a finished\n // one, and every surface treats that signal as terminal (the TUI closes\n // its execution stream on receipt, so a later fan-out from completing the\n // user task would arrive to a closed socket and be invisible).\n this.notifications.info('Remaining tasks require user action or are on hold.');\n this.emit('onTaskChanged');\n this.emit('onTick');\n }\n return;\n }\n\n for (const task of ready) await this.startTask(task);\n this.emit('onTick');\n }\n\n private async startTask(task: Task): Promise<void> {\n if (this.activeTaskSessions.has(task.id) || this.startingTaskIds.has(task.id)) return;\n this.startingTaskIds.add(task.id);\n this.store.markInProgress(task.id);\n this.emit('onTaskChanged');\n try {\n const cwd = this.workspaceRootFn();\n const runner = this.store.resolveTaskRunner(task);\n const finalPrompt = composeAugmentedPrompt(task, this.store.allTasks, {\n planMapEnabled: this.config.planMapEnabled,\n tddEnabled: this.tddEnabled(),\n });\n const session = await this.terminalRunner.spawn({\n taskId: task.id,\n runner,\n prompt: finalPrompt,\n modelId: task.assignedModel?.modelId,\n thinkingEffort: task.assignedModel?.thinkingEffort,\n modelVariants: task.assignedModel?.availableVariants,\n mode: task.taskMode ?? 'build',\n cwd,\n registry: this.registry ?? undefined,\n order: task.order,\n title: task.title,\n });\n\n // Stop/load can invalidate a spawn while the async adapter is starting.\n // Do not resurrect that execution after the surface already went idle.\n if (!this.startingTaskIds.delete(task.id)) {\n session.kill();\n this.store.markPending(task.id);\n this.emit('onTaskChanged');\n return;\n }\n this.activeTaskSessions.set(task.id, session.id);\n\n this.verifier.watch(task, session);\n\n this.emit('onTaskChanged');\n this.notifications.info(`Task \"${task.title}\" started (${runner})`);\n } catch (err) {\n this.startingTaskIds.delete(task.id);\n // Couldn't spawn — the task was never executed, so it stays \"to do\".\n // Held out of auto-scheduling to avoid a spawn-throw retry loop.\n this.store.markPending(task.id);\n this.onHold.add(task.id);\n this.notifications.error(`Failed to start task \"${task.title}\": ${err}`);\n this.emit('onTaskChanged');\n await this.tick();\n }\n }\n}\n","import type { DiscoveredModel, RunnerId, Task } from '../models/Task';\n\n/**\n * The ids a runner may actually run: the user's allowlist with the ids that\n * provably belong to a *different* runner dropped. `undefined` means no\n * restriction.\n *\n * Model ids are scoped to the agent that lists them, so an OpenRouter slug\n * allowlisted for Claude Code does not limit it — it points it at something it\n * cannot spawn, and the plan only dies once a task is already running. But\n * \"this runner didn't list it\" is not enough to call an id wrong: discovery can\n * be stale, and a plugin runner may have no list at all. What settles it is\n * whether *another* runner listed the id. So:\n *\n * - listed for this runner → keep;\n * - listed for no runner → unknown, and the user said it explicitly, so keep it\n * and let the runner validate last (the same call `coerceAssignments` and\n * `TaskRetarget` make);\n * - listed only for other runners → provably not this runner's, so drop it.\n *\n * When that leaves nothing, the whole allowlist was about some other runner\n * (a settings file written before a surface scoped its picker to one). No\n * restriction is the only safe reading — the alternative is handing the planner\n * a list of models that cannot run.\n */\nexport function effectiveAllowlist(\n allowlist: string[] | undefined,\n runner: string,\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>> | undefined,\n): string[] | undefined {\n if (!allowlist || allowlist.length === 0) return undefined;\n if (!modelsByRunner) return allowlist;\n\n const own = new Set((modelsByRunner[runner] ?? []).map((m) => m.modelId));\n const elsewhere = new Set<string>();\n for (const [other, models] of Object.entries(modelsByRunner)) {\n if (other === runner) continue;\n for (const m of models ?? []) elsewhere.add(m.modelId);\n }\n\n const kept = allowlist.filter((id) => own.has(id) || !elsewhere.has(id));\n return kept.length > 0 ? kept : undefined;\n}\n\nexport function filterModelsForPrompt(\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n perRunnerAllowlist: Partial<Record<RunnerId, string[]>>,\n): Partial<Record<RunnerId, DiscoveredModel[]>> {\n const result: Partial<Record<RunnerId, DiscoveredModel[]>> = {};\n for (const [runner, models] of Object.entries(modelsByRunner)) {\n if (!models) continue;\n const allowed = effectiveAllowlist(perRunnerAllowlist[runner], runner, modelsByRunner);\n if (!allowed) {\n result[runner] = models;\n continue;\n }\n const allowedSet = new Set(allowed);\n const intersection = models.filter((m) => allowedSet.has(m.modelId));\n // A set allowlist is a hard constraint: the planner must never see models\n // outside it. An allowed id no runner has listed is one discovery doesn't\n // cover, so synthesize an entry rather than leaking the full list.\n const covered = new Set(intersection.map((m) => m.modelId));\n const missing = allowed\n .filter((id) => !covered.has(id))\n .map((id) => ({ modelId: id, modelLabel: id.split('/').pop() || id, variants: [] }));\n result[runner] = [...intersection, ...missing];\n }\n return result;\n}\n\n/** Canonical low→high ordering of the well-known effort ladder. */\nconst EFFORT_LADDER = ['none', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max', 'ultra'];\n/** Runner-specific spellings mapped onto the ladder. */\nconst EFFORT_ALIASES: Record<string, string> = { disabled: 'none', adaptive: 'medium' };\n\n/**\n * Clamp a planner/user-supplied thinking effort to what the model actually\n * offers. Invalid values map to the nearest rung the model supports (so a\n * Claude-style \"xhigh\" on a low/medium/high model becomes \"high\") and fall\n * back to undefined — the runner's own default — when no mapping exists.\n */\nexport function clampThinkingEffort(\n effort: string | undefined,\n variants: { id: string }[],\n): string | undefined {\n if (!effort) return undefined;\n if (variants.length === 0) return undefined;\n const ids = new Set(variants.map((v) => v.id));\n if (ids.has(effort)) return effort;\n const canon = EFFORT_ALIASES[effort] ?? effort;\n if (ids.has(canon)) return canon;\n const idx = EFFORT_LADDER.indexOf(canon);\n if (idx < 0) return undefined;\n for (let d = 1; d < EFFORT_LADDER.length; d++) {\n const lower = EFFORT_LADDER[idx - d];\n if (lower && ids.has(lower)) return lower;\n const higher = EFFORT_LADDER[idx + d];\n if (higher && ids.has(higher)) return higher;\n }\n return undefined;\n}\n\nexport function coerceAssignments(\n tasks: Task[],\n perRunnerAllowlist: Partial<Record<RunnerId, string[]>>,\n allowedRunners?: RunnerId[],\n modelsByRunner?: Partial<Record<RunnerId, DiscoveredModel[]>>,\n): Task[] {\n // When the discovered catalog is available, snap each assignment's\n // thinkingEffort to a variant the model really has and stamp the model's\n // variant ids on the assignment (runners need them at spawn time); a model\n // we can't find in the catalog keeps its effort untouched (the runner\n // validates last).\n const clampVariant = (task: Task): Task => {\n if (!task.assignedModel || !modelsByRunner) return task;\n const model = modelsByRunner[task.assignedRunner]?.find(\n (m) => m.modelId === task.assignedModel!.modelId,\n );\n if (!model) return task;\n const clamped = clampThinkingEffort(task.assignedModel.thinkingEffort, model.variants);\n return {\n ...task,\n assignedModel: {\n ...task.assignedModel,\n thinkingEffort: clamped,\n availableVariants: model.variants.map((v) => v.id),\n },\n };\n };\n\n // One reading of the allowlist for the whole pass, so the models a task is\n // snapped to are the same ones the planner was shown (`filterModelsForPrompt`).\n const allowedFor = (runner: RunnerId): string[] | undefined =>\n effectiveAllowlist(perRunnerAllowlist[runner], runner, modelsByRunner);\n\n // A snapped-to model keeps the catalog's label and variant list where we have\n // one — an id alone reads as the model's name in every surface, and leaves the\n // effort picker with nothing to offer.\n const assignmentFor = (runner: RunnerId, modelId: string): NonNullable<Task['assignedModel']> => {\n const known = modelsByRunner?.[runner]?.find((m) => m.modelId === modelId);\n return {\n modelId,\n modelLabel: known?.modelLabel ?? modelId,\n thinkingEffort: undefined,\n ...(known ? { availableVariants: known.variants.map((v) => v.id) } : {}),\n };\n };\n\n return tasks.map((task) => {\n if (task.type === 'user') return task;\n\n if (allowedRunners && !allowedRunners.includes(task.assignedRunner)) {\n const fallbackRunner = allowedRunners[0];\n const fallbackModels = allowedFor(fallbackRunner);\n const fallbackModel = fallbackModels?.length\n ? assignmentFor(fallbackRunner, fallbackModels[0])\n : modelsByRunner?.[fallbackRunner]?.[0]\n ? assignmentFor(fallbackRunner, modelsByRunner[fallbackRunner]![0].modelId)\n : task.assignedModel;\n return clampVariant({\n ...task,\n assignedRunner: fallbackRunner,\n assignedModel: fallbackModel,\n });\n }\n\n const allowlist = allowedFor(task.assignedRunner);\n // No model assigned: fill in from the allowlist or discovered catalog so\n // merge/split/add outputs (which may omit assignedModel) always land with a\n // valid model for the task's runner.\n if (!task.assignedModel) {\n if (allowlist && allowlist.length > 0) {\n return clampVariant({ ...task, assignedModel: assignmentFor(task.assignedRunner, allowlist[0]) });\n }\n const discovered = modelsByRunner?.[task.assignedRunner]?.[0];\n if (discovered) {\n return clampVariant({ ...task, assignedModel: assignmentFor(task.assignedRunner, discovered.modelId) });\n }\n return task;\n }\n if (!allowlist || allowlist.length === 0) return clampVariant(task);\n if (allowlist.includes(task.assignedModel.modelId)) return clampVariant(task);\n return { ...task, assignedModel: assignmentFor(task.assignedRunner, allowlist[0]) };\n });\n}\n","import { Task, TaskSnapshot, RunnerId, DiscoveredModel, ResearchLogEntry, ResearchProgress, LegacyPlanState, type ActiveTaskSession } from '../models/Task';\nimport { IConfig } from '../interfaces/IConfig';\nimport { IFileSystem } from '../interfaces/IFileSystem';\nimport { IWebFetcher } from '../interfaces/IWebFetcher';\nimport { IAiService } from './AiService';\nimport type { RunnerModeInfo } from './ModeResolver';\nimport { validatePlanModification } from './PlanValidator';\nimport { repairLoop, modifyValidationFeedback } from './PlanRepair';\nimport { buildModifyDuringExecutionPrompt } from './PlanPrompts';\nimport { filterModelsForPrompt, coerceAssignments } from './ModelAllowlistResolver';\nimport { DEFAULT_PLANNER_MODES, type PlannerModes } from './plannerModes';\n\n/**\n * `autonomousDefault` still arrives on its own — it is not a user toggle but a\n * property of the run — so it wins over whatever the mode set carried.\n */\nfunction plannerModesWith(req: { modes?: PlannerModes; autonomousDefault?: boolean }): PlannerModes {\n const modes = req.modes ?? DEFAULT_PLANNER_MODES;\n return { ...modes, autonomousDefault: req.autonomousDefault ?? modes.autonomousDefault };\n}\n\n/**\n * Everything needed to produce a plan from a goal. Carries the planning context\n * that previously threaded through the scheduler as positional args.\n */\nexport interface PlanRequest {\n goal: string;\n runners: RunnerId[];\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>;\n fs?: IFileSystem;\n fetcher?: IWebFetcher;\n onProgress?: (progress: ResearchProgress) => void;\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>;\n autonomousDefault?: boolean;\n signal?: AbortSignal;\n perRunnerAllowlist?: Partial<Record<RunnerId, string[]>>;\n /** The mode toggles this run honours. `modesFor('one-shot', …)` decides which apply. */\n modes?: PlannerModes;\n}\n\nexport interface ModifyPlanRequest {\n existingPlan: LegacyPlanState;\n userRequest: string;\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>;\n fs?: IFileSystem;\n fetcher?: IWebFetcher;\n onProgress?: (progress: ResearchProgress) => void;\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>;\n autonomousDefault?: boolean;\n perRunnerAllowlist?: Partial<Record<RunnerId, string[]>>;\n modes?: PlannerModes;\n}\n\nexport interface ModifyDuringExecutionRequest {\n executionLog: TaskSnapshot[];\n pendingTasks: Task[];\n activeSessions: Map<string, ActiveTaskSession>;\n userMessage: string;\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>;\n runners: RunnerId[];\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>;\n autonomousDefault?: boolean;\n perRunnerAllowlist?: Partial<Record<RunnerId, string[]>>;\n}\n\nexport interface ModifyDuringExecutionResult {\n pendingTasks: Task[];\n message: string;\n}\n\n/**\n * Owns one-shot plan generation and plan modification — the \"planning is a\n * different workload from execution\" thesis, as a module. The conversational\n * planning loop (ADR-0002) lives on {@link Session}, which talks to the AI\n * service directly because the conversation state is held there.\n */\nexport class Planner {\n /**\n * Resolved per call, never captured: the planner backend can change while a\n * surface is open (`/planner`, the webview pills), and a Planner holding the\n * service it was built with would keep planning on the backend the host has\n * already switched away from.\n */\n private readonly resolveAiService: () => IAiService;\n\n constructor(private config: IConfig, aiService: IAiService | (() => IAiService)) {\n this.resolveAiService = typeof aiService === 'function' ? aiService : () => aiService;\n }\n\n private get aiService(): IAiService { return this.resolveAiService(); }\n\n /** One-shot plan generation for non-conversational surfaces. Never asks questions. */\n async generate(req: PlanRequest): Promise<LegacyPlanState> {\n const now = new Date().toISOString();\n let tasks: Task[];\n let researchLog: ResearchLogEntry[] | undefined;\n\n const filteredModels = filterModelsForPrompt(req.modelsByRunner, req.perRunnerAllowlist ?? {});\n\n if (this.config.researchEnabled) {\n const result = await this.aiService.researchAndPlan(\n req.goal,\n req.runners,\n filteredModels,\n req.fs!,\n req.onProgress ?? (() => {}),\n req.fetcher,\n req.runnerModes,\n plannerModesWith(req),\n req.signal,\n );\n tasks = result.tasks;\n researchLog = result.researchLog;\n } else {\n const onProgress = req.onProgress;\n tasks = await this.aiService.generatePlanDirect(\n req.goal,\n req.runners,\n filteredModels,\n onProgress ? (token: string) => onProgress({ type: 'plan_token', planToken: token }) : undefined,\n req.fs,\n req.fetcher,\n req.runnerModes,\n plannerModesWith(req),\n req.signal,\n );\n }\n\n return {\n tasks: coerceAssignments(tasks, req.perRunnerAllowlist ?? {}, req.runners, req.modelsByRunner),\n generatedAt: now,\n status: 'draft',\n runners: req.runners,\n lastUpdated: now,\n researchLog,\n };\n }\n\n async modify(req: ModifyPlanRequest): Promise<{ tasks: Task[] }> {\n const filteredModels = filterModelsForPrompt(req.modelsByRunner, req.perRunnerAllowlist ?? {});\n const result = await this.aiService.modifyPlan(\n req.existingPlan,\n req.userRequest,\n filteredModels,\n req.onProgress,\n req.fs,\n req.fetcher,\n req.runnerModes,\n plannerModesWith(req),\n );\n return { tasks: coerceAssignments(result.tasks, req.perRunnerAllowlist ?? {}, req.existingPlan.runners, req.modelsByRunner) };\n }\n\n async modifyDuringExecution(req: ModifyDuringExecutionRequest): Promise<ModifyDuringExecutionResult> {\n const pendingJson = JSON.stringify(req.pendingTasks, null, 2);\n const filteredModels = filterModelsForPrompt(req.modelsByRunner, req.perRunnerAllowlist ?? {});\n const allowlist = req.perRunnerAllowlist ?? {};\n\n const basePrompt = buildModifyDuringExecutionPrompt(\n req.executionLog,\n pendingJson,\n req.userMessage,\n filteredModels,\n req.runners,\n req.runnerModes,\n req.autonomousDefault ?? true,\n );\n const send = (corrective?: string) => this.aiService.sendPlanningPrompt(\n corrective ? basePrompt + corrective : basePrompt,\n req.runners,\n req.runnerModes,\n req.autonomousDefault ?? true,\n );\n\n return repairLoop<Task[], ModifyDuringExecutionResult>({\n first: () => send(),\n resend: (corrective) => send(corrective),\n interpret: (tasks) => {\n const coerced = coerceAssignments(tasks, allowlist, req.runners, req.modelsByRunner);\n const validation = validatePlanModification({\n executionLog: req.executionLog,\n oldPending: req.pendingTasks,\n newPending: coerced,\n activeSessions: req.activeSessions,\n });\n if (validation.valid) {\n return { done: { pendingTasks: coerced, message: `Plan modified: ${coerced.length} pending task(s)` } };\n }\n return { retry: { errors: validation.errors, corrective: modifyValidationFeedback(validation.errors) } };\n },\n maxRepairs: 2,\n onExhausted: ({ errors }) => {\n throw new Error(\n `Plan modification validation exhausted after 3 attempts. Last errors:\\n${errors.map((e) => `- ${e}`).join('\\n')}`,\n );\n },\n });\n }\n}\n","import * as path from 'path';\nimport { exec, spawn } from 'child_process';\nimport { promisify } from 'util';\nimport * as fsSync from 'fs';\nimport * as osMod from 'os';\nimport { DiscoveredModel } from '../models/Task';\nimport type { RunnerRegistry } from '../plugins/RunnerRegistry';\nimport type { RunnerPluginManifest, DiscoveryCommand, ApiDiscoveryConfig, ApiAuthMethod } from '../plugins/types';\nimport { augmentedPath, withPath } from '../utils/shellPath';\nimport { planDirectLaunch } from '../utils/launch';\nimport { killTree } from '../utils/processTree';\n\nconst execAsync = promisify(exec);\n\n/**\n * Injectable command runner. Defaults to the real `child_process` exec wrapper;\n * tests pass a fake so discovery never spawns a process.\n */\nexport type ExecImpl = (\n command: string,\n options?: { timeout?: number }\n) => Promise<{ stdout: string }>;\n\n// Discovery must find `claude`/`opencode` wherever the user installed them,\n// even when the host process (GUI-launched VS Code, service-launched web\n// server) inherits a minimal PATH — hence the augmented PATH.\nconst defaultExec: ExecImpl = async (command, options) => {\n const PATH = await augmentedPath();\n // `opencode models --verbose` emits a JSON block per model and grows with\n // every provider the user enables (~0.5MB with three providers today);\n // node's default 1MB maxBuffer would kill the child mid-stream and silently\n // degrade discovery to the variant-less plain parser.\n const { stdout } = await execAsync(command, { ...options, maxBuffer: 32 * 1024 * 1024, env: withPath(process.env, PATH) });\n return { stdout: String(stdout) };\n};\n\n/**\n * One raw model entry from an app-server `model/list` response (Codex's stdio\n * JSON-RPC protocol). Field names are the protocol's, not Ordewell's.\n */\nexport interface AppServerModel {\n id: string;\n displayName?: string;\n hidden?: boolean;\n defaultReasoningEffort?: string;\n supportedReasoningEfforts?: { reasoningEffort: string; description?: string }[];\n}\n\n/**\n * Injectable app-server JSON-RPC client: spawn the command, drive\n * `initialize` → `model/list` over stdio, return the raw model list. Returns\n * null on any failure (spawn error, timeout, malformed response) so discovery\n * falls through to the on-disk cache file. Tests inject a fake so discovery\n * never spawns a real app-server.\n */\nexport type AppServerClientImpl = (\n command: string,\n args: string[],\n options?: { timeout?: number }\n) => Promise<AppServerModel[] | null>;\n\nconst defaultAppServerClient: AppServerClientImpl = async (command, args, options) => {\n const PATH = await augmentedPath();\n // No shell here, so on Windows the command has to be resolved against\n // PATHEXT first — `codex` alone is a `.cmd` shim that CreateProcess cannot\n // start. A resolution failure returns the command unchanged, and the spawn's\n // own error still routes discovery to the on-disk cache.\n const launch = await planDirectLaunch(command, args).catch(() => null);\n if (!launch) return null;\n return new Promise((resolve) => {\n let child: import('child_process').ChildProcess;\n try {\n child = spawn(launch.file, launch.args, {\n env: withPath(process.env, PATH),\n stdio: ['pipe', 'pipe', 'ignore'],\n windowsVerbatimArguments: launch.verbatim,\n });\n } catch {\n resolve(null);\n return;\n }\n let settled = false;\n const finish = (value: AppServerModel[] | null) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n // Tree-wide, for the same reason every other dispose path is: when\n // `codex` resolved to a shim the direct child is the interpreter, and\n // killing it leaves the app-server alive — holding its port, and\n // outliving the discovery call that started it.\n killTree(child);\n resolve(value);\n };\n const timer = setTimeout(() => finish(null), options?.timeout ?? 20000);\n child.on('error', () => finish(null));\n child.on('exit', () => finish(null));\n\n let buffer = '';\n const send = (id: number, method: string, params: unknown) => {\n try {\n child.stdin!.write(JSON.stringify({ jsonrpc: '2.0', id, method, params }) + '\\n');\n } catch {\n finish(null);\n }\n };\n child.stdout!.on('data', (chunk: Buffer) => {\n buffer += chunk.toString();\n let newline: number;\n while ((newline = buffer.indexOf('\\n')) >= 0) {\n const line = buffer.slice(0, newline);\n buffer = buffer.slice(newline + 1);\n let msg: { id?: number; result?: { data?: AppServerModel[] } };\n try { msg = JSON.parse(line); } catch { continue; }\n if (msg.id === 1) {\n send(2, 'model/list', {});\n } else if (msg.id === 2) {\n finish(Array.isArray(msg.result?.data) ? msg.result!.data! : null);\n }\n }\n });\n send(1, 'initialize', { clientInfo: { name: 'ordewell', title: 'Ordewell', version: '0.1.0' } });\n });\n};\n\nfunction effortVariant(effort: string): { id: string; label: string } {\n return { id: effort, label: effort.charAt(0).toUpperCase() + effort.slice(1) };\n}\n\n/** Map app-server `model/list` entries to DiscoveredModels, dropping hidden ones. */\nexport function parseAppServerModels(raw: AppServerModel[]): DiscoveredModel[] {\n return raw\n .filter((m) => m.id && !m.hidden)\n .map((m) => ({\n modelId: m.id,\n modelLabel: m.displayName || m.id,\n runnerProvider: 'openai',\n variants: (m.supportedReasoningEfforts ?? []).map((e) => effortVariant(e.reasoningEffort)),\n }));\n}\n\n/**\n * Parse the runner's own on-disk catalog cache (Codex `models_cache.json`).\n * Same catalog as `model/list` but in the cache file's snake_case shape, with\n * `visibility: \"hide\"` in place of the protocol's `hidden` flag.\n */\nexport function parseCodexModelsCache(content: string): DiscoveredModel[] {\n try {\n const data = JSON.parse(content) as {\n models?: Array<{\n slug?: string;\n display_name?: string;\n visibility?: string;\n supported_reasoning_levels?: { effort: string; description?: string }[];\n }>;\n };\n if (!Array.isArray(data.models)) return [];\n return data.models\n .filter((m) => m.slug && m.visibility !== 'hide')\n .map((m) => ({\n modelId: m.slug!,\n modelLabel: m.display_name || m.slug!,\n runnerProvider: 'openai',\n variants: (m.supported_reasoning_levels ?? []).map((l) => effortVariant(l.effort)),\n }));\n } catch {\n return [];\n }\n}\n\nconst GEMINI_MODELS_CACHE_TTL_MS = 24 * 60 * 60 * 1000;\n\ninterface GeminiApiModel {\n name: string;\n displayName: string;\n supportedGenerationMethods?: string[];\n}\n\nfunction geminiDiscoveryCacheKey(apiKey: string): { key: string; dir: string; file: string } {\n const dir = path.join(osMod.homedir(), '.config', 'ordewell');\n const hash = apiKey.slice(-8);\n return {\n key: `gemini-models:${hash}`,\n dir,\n file: path.join(dir, `gemini_models_${hash}.json`),\n };\n}\n\nfunction readGeminiCache(apiKey: string): DiscoveredModel[] | null {\n try {\n const { file } = geminiDiscoveryCacheKey(apiKey);\n if (!fsSync.existsSync(file)) return null;\n const raw = fsSync.readFileSync(file, 'utf8');\n const data = JSON.parse(raw);\n if (Date.now() - data.cachedAt > GEMINI_MODELS_CACHE_TTL_MS) return null;\n return data.models as DiscoveredModel[];\n } catch {\n return null;\n }\n}\n\nfunction writeGeminiCache(apiKey: string, models: DiscoveredModel[]): void {\n try {\n const { dir, file } = geminiDiscoveryCacheKey(apiKey);\n fsSync.mkdirSync(dir, { recursive: true });\n fsSync.writeFileSync(\n file,\n JSON.stringify({ models, cachedAt: Date.now() }, null, 2)\n );\n } catch { /* empty */ }\n}\n\n/**\n * Delete the on-disk Gemini discovery cache for an API key so the next\n * discovery re-runs. Used by the resolver's `invalidate()` in production (no\n * injected fetch); best-effort — a missing file is a no-op.\n */\nexport function clearGeminiCache(apiKey: string): void {\n if (!apiKey) return;\n try {\n const { file } = geminiDiscoveryCacheKey(apiKey);\n if (fsSync.existsSync(file)) fsSync.rmSync(file);\n } catch { /* empty */ }\n}\n\nexport async function discoverGeminiModels(apiKey: string, baseUrl?: string, fetchImpl?: typeof fetch): Promise<DiscoveredModel[]> {\n if (!apiKey) return [];\n\n // An injected fetch means the resolver owns caching — bypass the file cache.\n const useFileCache = !fetchImpl;\n if (useFileCache) {\n const cached = readGeminiCache(apiKey);\n if (cached && cached.length > 0) return cached;\n }\n\n const url = (baseUrl || 'https://generativelanguage.googleapis.com').replace(/\\/+$/, '');\n\n try {\n const models: DiscoveredModel[] = [];\n let pageToken: string | undefined;\n\n do {\n const params = new URLSearchParams({ key: apiKey });\n if (pageToken) params.set('pageToken', pageToken);\n const response = await (fetchImpl ?? fetch)(`${url}/v1beta/models?${params}`, {\n headers: { 'Content-Type': 'application/json' },\n });\n\n if (!response.ok) return [];\n\n const data = (await response.json()) as { models?: GeminiApiModel[]; nextPageToken?: string };\n for (const m of data.models ?? []) {\n const methods = m.supportedGenerationMethods ?? [];\n if (methods.includes('generateContent')) {\n const modelId = m.name.replace(/^models\\//, '');\n models.push({\n modelId,\n modelLabel: m.displayName || modelId,\n runnerProvider: 'gemini',\n variants: [],\n });\n }\n }\n\n pageToken = data.nextPageToken || undefined;\n } while (pageToken);\n\n models.sort((a, b) => {\n const aPro = a.modelId.includes('-pro');\n const bPro = b.modelId.includes('-pro');\n if (aPro && !bPro) return -1;\n if (!aPro && bPro) return 1;\n return b.modelId.localeCompare(a.modelId);\n });\n\n if (useFileCache && models.length > 0) writeGeminiCache(apiKey, models);\n return models;\n } catch {\n return [];\n }\n}\n\nfunction applyVariants(models: DiscoveredModel[], manifest: RunnerPluginManifest): DiscoveredModel[] {\n const variants = manifest.modelDiscovery.variants;\n if (!variants || variants.length === 0) return models;\n // Only fill in models whose variants are empty (e.g. --help parsing or\n // canonical-alias fallback). Models that already carry per-model variants\n // from the API must keep them — the static list is a fallback, not an override.\n return models.map((m) => (m.variants.length > 0 ? m : { ...m, variants }));\n}\n\n/**\n * Resolve an auth token from a manifest's `apiDiscovery.auth` list. Each method\n * is tried in order; the first that yields a non-empty token wins.\n *\n * - `env`: reads `process.env[varName]`\n * - `file`: reads a JSON file at `path` (with `~` expansion) and extracts the\n * value at `jsonPath` (dot-notation, e.g. `claudeAiOauth.accessToken`)\n *\n * Returns `{ header, value }` ready to set on the fetch `headers` object, or\n * `null` when no auth method yields a token.\n */\nfunction resolveApiAuth(authMethods: ApiAuthMethod[]): { header: string; value: string } | null {\n for (const method of authMethods) {\n try {\n let token: string | undefined;\n if (method.type === 'env') {\n token = process.env[method.varName];\n } else {\n const filePath = method.path.replace(/^~/, osMod.homedir());\n if (!fsSync.existsSync(filePath)) continue;\n const data = JSON.parse(fsSync.readFileSync(filePath, 'utf8'));\n token = method.jsonPath.split('.').reduce((obj: unknown, key: string) => {\n if (obj && typeof obj === 'object') return (obj as Record<string, unknown>)[key] as unknown;\n return undefined;\n }, data) as string | undefined;\n }\n if (token) {\n const value = method.prefix ? `${method.prefix}${token}` : token;\n return { header: method.header, value };\n }\n } catch { /* try next auth method */ }\n }\n return null;\n}\n\n/**\n * Query an HTTP API endpoint for the model list. Used when the runner's CLI\n * has no model-listing subcommand (Claude Code). Returns the parsed models, or\n * `null` when no auth token is available or the request fails — in both cases\n * the caller falls through to command-based discovery.\n */\nasync function discoverFromApi(\n config: ApiDiscoveryConfig,\n fetchImpl?: typeof fetch\n): Promise<DiscoveredModel[] | null> {\n const auth = resolveApiAuth(config.auth);\n if (!auth) return null;\n\n try {\n const headers: Record<string, string> = { ...config.headers, [auth.header]: auth.value };\n const response = await (fetchImpl ?? fetch)(config.url, { headers });\n if (!response.ok) return null;\n const data = await response.json();\n const text = JSON.stringify(data);\n return parseModelOutput(text, config.parser, {} as RunnerPluginManifest);\n } catch {\n return null;\n }\n}\n\n/**\n * Parse the Anthropic Models API response (`GET /v1/models`). The API returns\n * full model IDs (e.g. `claude-haiku-4-5-20251001`) sorted most-recent first.\n * We derive the short family alias (`haiku`, `opus`, `sonnet`, `fable`) that\n * the Claude Code CLI's `--model` flag accepts, deduplicating by family to\n * keep only the latest (first in the API's ordering).\n *\n * Per-model thinking variants come from two independent capabilities:\n * `capabilities.thinking.types.adaptive` (the model reasons without being told\n * how hard) and `capabilities.effort.{level}` (the rungs `--effort` accepts).\n * They are read separately because they are separate axes — the current model\n * line reports `thinking.types.enabled: false` alongside all five effort rungs,\n * so treating `enabled` as the gate for effort hid every rung on exactly the\n * models a user is most likely to plan with. A model with no capabilities gets\n * an empty variants array — the caller's static fallback fills in only when\n * variants are empty (see `applyVariants`).\n */\nconst ANTHROPIC_EFFORT_LEVELS = ['low', 'medium', 'high', 'xhigh', 'max'] as const;\nconst ANTHROPIC_VARIANT_LABELS: Record<string, string> = {\n adaptive: 'Adaptive',\n low: 'Low effort',\n medium: 'Medium effort',\n high: 'High effort',\n xhigh: 'Extra high effort',\n max: 'Max effort',\n};\n\nfunction anthropicCapabilitiesToVariants(\n caps?:\n | {\n thinking?: {\n supported?: boolean;\n types?: {\n adaptive?: { supported?: boolean };\n enabled?: { supported?: boolean };\n };\n };\n effort?: {\n supported?: boolean;\n low?: { supported?: boolean };\n medium?: { supported?: boolean };\n high?: { supported?: boolean };\n xhigh?: { supported?: boolean };\n max?: { supported?: boolean };\n };\n }\n | undefined,\n): { id: string; label: string }[] {\n const variants: { id: string; label: string }[] = [];\n if (caps?.thinking?.supported && caps.thinking.types?.adaptive?.supported) {\n variants.push({ id: 'adaptive', label: ANTHROPIC_VARIANT_LABELS.adaptive });\n }\n if (caps?.effort?.supported) {\n for (const level of ANTHROPIC_EFFORT_LEVELS) {\n if (caps.effort[level]?.supported) {\n variants.push({ id: level, label: ANTHROPIC_VARIANT_LABELS[level] });\n }\n }\n }\n return variants;\n}\n\nfunction parseAnthropicModels(stdout: string): DiscoveredModel[] {\n try {\n const data = JSON.parse(stdout) as {\n data?: Array<{\n id: string;\n display_name?: string;\n capabilities?: Parameters<typeof anthropicCapabilitiesToVariants>[0];\n }>;\n };\n const models = data.data;\n if (!Array.isArray(models)) return [];\n\n const seen = new Set<string>();\n const result: DiscoveredModel[] = [];\n\n for (const m of models) {\n if (!m.id || typeof m.id !== 'string') continue;\n if (!m.id.startsWith('claude-')) continue;\n const segments = m.id.split('-');\n const family = segments[1];\n if (!family || !['opus', 'sonnet', 'haiku', 'fable'].includes(family)) continue;\n if (seen.has(family)) continue;\n seen.add(family);\n const label = m.display_name || family.charAt(0).toUpperCase() + family.slice(1);\n result.push({\n modelId: family,\n modelLabel: label,\n runnerProvider: 'anthropic',\n variants: anthropicCapabilitiesToVariants(m.capabilities),\n });\n }\n\n return result;\n } catch {\n return [];\n }\n}\n\nasync function discoverFromCommand(manifest: RunnerPluginManifest, execImpl: ExecImpl): Promise<{ models: DiscoveredModel[]; fromFallback: boolean }> {\n const discovery = manifest.modelDiscovery;\n const commands: DiscoveryCommand[] = discovery.discoveryCommands ?? [\n { command: discovery.command!, args: discovery.args || [], parser: discovery.parser || 'line-by-line' },\n ];\n\n const runCommands = async (): Promise<DiscoveredModel[] | null> => {\n for (const cmd of commands) {\n try {\n // Generous timeout: a cold runner CLI may spawn its server, install\n // plugins, and fetch its catalog on first invocation after boot.\n const { stdout } = await execImpl(`${cmd.command} ${cmd.args.join(' ')}`, { timeout: 45000 });\n const models = parseModelOutput(stdout, cmd.parser || 'line-by-line', manifest);\n if (models.length > 0) return applyVariants(mergeCanonicalAliases(models, manifest), manifest);\n } catch { /* try next command */ }\n }\n return null;\n };\n\n // First pass. If every command timed out or came back empty, the CLI was\n // likely cold — it just spawned its server and hadn't fetched its catalog\n // yet. Retry once (the server is now warm) before degrading to the manifest\n // fallback, so a cold start never silently produces a short/empty list.\n const first = await runCommands();\n if (first) return { models: first, fromFallback: false };\n const second = await runCommands();\n if (second) return { models: second, fromFallback: false };\n\n return { models: applyVariants(buildFallbackModels(manifest), manifest), fromFallback: true };\n}\n\n/**\n * Merge `manifest.modelDiscovery.canonicalAliases` into a successful discovery\n * result. Discovered models take precedence (they reflect the installed CLI);\n * any canonical alias NOT already present is appended, so stable `--model`\n * contracts that the CLI's help text omits (e.g. Claude's 'haiku') are always\n * offered. Only applies when `canonicalAliases` is declared.\n */\nfunction mergeCanonicalAliases(discovered: DiscoveredModel[], manifest: RunnerPluginManifest): DiscoveredModel[] {\n const canonical = manifest.modelDiscovery.canonicalAliases;\n if (!canonical || canonical.length === 0) return discovered;\n const seen = new Set(discovered.map((m) => m.modelId));\n const gaps = canonical\n .filter((f) => !seen.has(f.modelId))\n .map((f) => ({\n modelId: f.modelId,\n modelLabel: f.modelLabel,\n runnerProvider: f.modelId.includes('/') ? f.modelId.split('/')[0] : undefined,\n variants: [],\n }));\n return gaps.length > 0 ? [...discovered, ...gaps] : discovered;\n}\n\nfunction buildFallbackModels(manifest: RunnerPluginManifest): DiscoveredModel[] {\n // Prefer canonicalAliases (stable CLI contracts, e.g. Claude's opus/sonnet/\n // haiku) when declared; fall back to the generic fallbackModels list for\n // user plugins that have no canonical alias concept.\n const list = manifest.modelDiscovery.canonicalAliases ?? manifest.modelDiscovery.fallbackModels ?? [];\n return list.map((m) => ({\n modelId: m.modelId,\n modelLabel: m.modelLabel,\n runnerProvider: m.modelId.includes('/') ? m.modelId.split('/')[0] : undefined,\n variants: manifest.modelDiscovery.variants || [],\n }));\n}\n\nfunction parseModelOutput(stdout: string, parser: string, manifest: RunnerPluginManifest): DiscoveredModel[] {\n switch (parser) {\n case 'claude-help':\n return parseClaudeHelp(stdout);\n case 'opencode-models':\n return parseOpencodeModels(stdout, manifest);\n case 'opencode-models-verbose':\n return parseOpencodeModelsVerbose(stdout, manifest);\n case 'anthropic-models':\n return parseAnthropicModels(stdout);\n case 'line-by-line':\n return parseLineByLine(stdout);\n case 'json':\n return parseJson(stdout, manifest);\n case 'json-table':\n return parseJsonTable(stdout);\n default:\n return parseLineByLine(stdout);\n }\n}\n\nfunction parseClaudeHelp(stdout: string): DiscoveredModel[] {\n const models: DiscoveredModel[] = [];\n const seen = new Set<string>();\n\n const extractIds = (text: string) => {\n for (const line of text.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n const words = trimmed.split(/\\s+/);\n for (const w of words) {\n const cleaned = w.replace(/[\",()]/g, '');\n if (cleaned.length < 5) continue;\n if (cleaned.includes('-') && cleaned.length > 10 && !seen.has(cleaned)) {\n seen.add(cleaned);\n let label = cleaned.replace(/-20\\d{6}/, '').replace(/-/g, ' ');\n label = label.replace(/\\b\\w/g, (c) => c.toUpperCase());\n if (cleaned.includes('sonnet')) label = 'Sonnet';\n else if (cleaned.includes('opus')) label = 'Opus';\n else if (cleaned.includes('haiku')) label = 'Haiku';\n models.push({ modelId: cleaned, modelLabel: label, variants: [] });\n }\n }\n }\n };\n\n // Prefer an explicit enumeration of model IDs when present, e.g.\n // --model <model> Available values: claude-opus-..., claude-sonnet-...\n const modelMatch = stdout.match(/--model\\s+<model>\\s+(?:.*?\\n)*?\\s*(?:Available|valid)(?:\\s+values?|:\\s*options?)\\s*:\\s*([\\s\\S]*?)(?:\\n\\s*\\n|$)/i);\n\n if (modelMatch) {\n extractIds(modelMatch[1]);\n }\n if (models.length > 0) return models;\n\n // Modern `claude --help` describes --model in prose with quoted example\n // aliases: \"Provide an alias for the latest model (e.g. 'fable', 'opus', or\n // 'sonnet') or a model's full name (e.g. 'claude-fable-5').\" Those aliases\n // are the CLI's own contract for what --model accepts, so they ARE the model\n // list — extracted from the installed binary, never hardcoded here.\n // The option block: the `--model` line plus its indented continuation lines\n // (a line whose first non-space char is `-` starts the next option).\n const optionBlock = stdout.match(/--model\\s+<model>[^\\n]*(?:\\n(?!\\s*-)[^\\n]*)*/);\n if (optionBlock) {\n const quoted = [...optionBlock[0].matchAll(/'([a-z][a-z0-9._/-]*)'/gi)].map((m) => m[1]);\n // Aliases (no separator, e.g. 'opus') resolve to the latest model of their\n // family and are always valid; full-name examples (e.g. 'claude-fable-5')\n // duplicate an alias, so only use them when no alias was found.\n const aliases = quoted.filter((q) => /^[a-z][a-z0-9]{2,19}$/.test(q));\n const chosen = aliases.length > 0 ? aliases : quoted.filter((q) => q.length >= 5);\n for (const id of chosen) {\n if (seen.has(id)) continue;\n seen.add(id);\n const label = id.replace(/-20\\d{6}$/, '').split(/[-_]/).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(' ');\n models.push({ modelId: id, modelLabel: label, variants: [] });\n }\n }\n\n return models;\n}\n\nfunction parseOpencodeModels(stdout: string, manifest: RunnerPluginManifest): DiscoveredModel[] {\n // The CLI output is the source of truth: accept ANY `provider/model` line\n // (custom providers included) rather than a hand-listed charset. Structure\n // required: a plain provider segment (no colon — excludes URLs), a slash,\n // and a whitespace-free remainder.\n const lines = stdout.split('\\n').map((l) => l.trim()).filter((l) => /^[A-Za-z0-9._-]+\\/[^\\s\"{}]+$/.test(l));\n if (lines.length === 0) return [];\n\n const preferred = manifest.modelDiscovery.preferredPatterns;\n const prefLabels = new Map<string, string>();\n if (preferred) {\n for (const { id, label } of preferred) {\n prefLabels.set(id, label);\n }\n }\n\n const seen = new Set<string>();\n const models: DiscoveredModel[] = [];\n\n for (const id of lines) {\n if (prefLabels.has(id) && !seen.has(id)) {\n seen.add(id);\n const provider = id.split('/')[0];\n models.push({ modelId: id, modelLabel: prefLabels.get(id)!, runnerProvider: provider, variants: [] });\n }\n }\n\n for (const id of lines) {\n if (!seen.has(id)) {\n seen.add(id);\n const provider = id.split('/')[0];\n models.push({ modelId: id, modelLabel: id.split('/').pop() || id, runnerProvider: provider, variants: [] });\n }\n }\n\n return models;\n}\n\n/**\n * Parse `opencode models --verbose` output.\n *\n * The format alternates between a `provider/model-id` line and a JSON block:\n * opencode/claude-sonnet-4-6\n * { \"id\": \"claude-sonnet-4-6\", ... \"variants\": { \"low\": {...}, \"high\": {...} } }\n * opencode-go/deepseek-v4-pro\n * { ... \"variants\": {} }\n *\n * Per-model variants are extracted directly from the JSON; models with no\n * variants get an empty array (the old static manifest variants are NOT applied).\n */\nfunction parseOpencodeModelsVerbose(stdout: string, manifest: RunnerPluginManifest): DiscoveredModel[] {\n // Ensure trailing newline so the last model-id line is always captured by the split regex.\n // The CLI output is the source of truth: accept ANY `provider/model` id line\n // (custom providers, uppercase, version pins, multi-segment models). The only\n // structure required is a plain provider segment (no colon — excludes URLs)\n // followed by a whitespace-free remainder; JSON block lines never match\n // because they start with `{`, `}`, `\"` or indentation.\n const normalized = stdout.endsWith('\\n') ? stdout : stdout + '\\n';\n const parts = normalized.split(/^([A-Za-z0-9._-]+\\/[^\\s\"{}]+)\\n/m);\n\n const preferred = manifest.modelDiscovery.preferredPatterns;\n const prefLabels = new Map<string, string>();\n if (preferred) {\n for (const { id, label } of preferred) prefLabels.set(id, label);\n }\n\n const seen = new Set<string>();\n const models: DiscoveredModel[] = [];\n\n for (let i = 1; i < parts.length - 1; i += 2) {\n const fullId = parts[i].trim();\n const jsonText = parts[i + 1].trim();\n if (seen.has(fullId)) continue;\n\n let variantIds: string[] = [];\n let modelLabel = prefLabels.get(fullId) || fullId.split('/').pop() || fullId;\n // The provider IS the printed prefix before the first `/` — exactly as\n // the CLI lists it (`opencode/…`, `opencode-go/…`, `openrouter/…`, or any\n // future provider). The JSON's providerID never overrides it.\n const runnerProvider = fullId.split('/')[0];\n\n try {\n const data = JSON.parse(jsonText) as {\n name?: string;\n variants?: Record<string, unknown>;\n };\n if (data.name) modelLabel = prefLabels.get(fullId) || data.name;\n variantIds = Object.keys(data.variants ?? {});\n } catch {\n // No parseable JSON block — keep the id-derived label, no variants.\n }\n\n seen.add(fullId);\n models.push({\n modelId: fullId,\n modelLabel,\n runnerProvider,\n variants: variantIds.map((id) => ({ id, label: id.charAt(0).toUpperCase() + id.slice(1) })),\n });\n }\n\n if (models.length === 0) return [];\n\n // Put preferred patterns first, then the rest alphabetically\n const prefOrder = preferred?.map((p) => p.id) ?? [];\n models.sort((a, b) => {\n const ai = prefOrder.indexOf(a.modelId);\n const bi = prefOrder.indexOf(b.modelId);\n if (ai >= 0 && bi >= 0) return ai - bi;\n if (ai >= 0) return -1;\n if (bi >= 0) return 1;\n return a.modelId.localeCompare(b.modelId);\n });\n\n return models;\n}\n\nfunction parseLineByLine(stdout: string): DiscoveredModel[] {\n return stdout\n .split('\\n')\n .map((l) => l.trim())\n .filter(Boolean)\n .slice(0, 50)\n .map((line) => {\n const parts = line.split(/\\s+/);\n const id = parts[0];\n const label = parts.slice(1).join(' ') || id;\n return { modelId: id, modelLabel: label, runnerProvider: id.includes('/') ? id.split('/')[0] : undefined, variants: [] };\n });\n}\n\nfunction parseJson(stdout: string, manifest: RunnerPluginManifest): DiscoveredModel[] {\n try {\n let data = JSON.parse(stdout);\n const jsonPath = manifest.modelDiscovery.jsonPath;\n if (jsonPath) {\n for (const key of jsonPath.split('.')) {\n if (data && typeof data === 'object') {\n data = (data as Record<string, unknown>)[key];\n }\n }\n }\n const arr = Array.isArray(data) ? data : [];\n return arr.map((item: unknown) => {\n if (typeof item === 'string') {\n const id = item;\n return { modelId: id, modelLabel: id, runnerProvider: id.includes('/') ? id.split('/')[0] : undefined, variants: [] };\n }\n if (typeof item === 'object' && item !== null) {\n const obj = item as Record<string, unknown>;\n const modelId = String(obj.id || obj.modelId || obj.model || '');\n return {\n modelId,\n modelLabel: String(obj.label || obj.name || obj.modelLabel || obj.id || ''),\n runnerProvider: modelId.includes('/') ? modelId.split('/')[0] : undefined,\n variants: [],\n };\n }\n const id = String(item);\n return { modelId: id, modelLabel: id, runnerProvider: id.includes('/') ? id.split('/')[0] : undefined, variants: [] };\n });\n } catch {\n return [];\n }\n}\n\nfunction parseJsonTable(stdout: string): DiscoveredModel[] {\n try {\n const data = JSON.parse(stdout);\n if (typeof data === 'object' && data !== null && !Array.isArray(data)) {\n const outer = Object.values(data)[0];\n const arr = Array.isArray(outer) ? outer : [];\n return arr.map((item: unknown) => {\n if (typeof item === 'string') {\n const id = item;\n return { modelId: id, modelLabel: id, runnerProvider: id.includes('/') ? id.split('/')[0] : undefined, variants: [] };\n }\n if (typeof item === 'object' && item !== null) {\n const obj = item as Record<string, unknown>;\n const modelId = String(obj.id || obj.modelId || obj.model || '');\n return {\n modelId,\n modelLabel: String(obj.label || obj.name || obj.modelLabel || obj.id || ''),\n runnerProvider: modelId.includes('/') ? modelId.split('/')[0] : undefined,\n variants: [],\n };\n }\n const id = String(item);\n return { modelId: id, modelLabel: id, runnerProvider: id.includes('/') ? id.split('/')[0] : undefined, variants: [] };\n });\n }\n } catch { /* fall through */ }\n return [];\n}\n\n/**\n * @internal Per-runner executor-model discovery. This is the *implementation*\n * behind ModelResolver, not part of the public package API — construct it only\n * through ModelResolver (see CONTEXT.md \"ModelResolver\"). The resolver owns the\n * cache lifecycle via `discover()` + `clear()`.\n */\nexport class ModelDiscovery {\n private cache: Map<string, DiscoveredModel[]> = new Map();\n private registry: RunnerRegistry;\n private execImpl: ExecImpl;\n private fetchImpl?: typeof fetch;\n private appServerClient: AppServerClientImpl;\n private readFileImpl: (path: string) => string | null;\n\n constructor(\n registry: RunnerRegistry,\n execImpl: ExecImpl = defaultExec,\n fetchImpl?: typeof fetch,\n appServerClient: AppServerClientImpl = defaultAppServerClient,\n readFileImpl?: (path: string) => string | null,\n ) {\n this.registry = registry;\n this.execImpl = execImpl;\n this.fetchImpl = fetchImpl;\n this.appServerClient = appServerClient;\n this.readFileImpl = readFileImpl ?? ((filePath: string) => {\n try {\n return fsSync.readFileSync(filePath.replace(/^~/, osMod.homedir()), 'utf8');\n } catch {\n return null;\n }\n });\n }\n\n /**\n * App-server discovery chain (ADR-0004): live `model/list` over stdio\n * JSON-RPC first, the runner's own on-disk catalog cache second. Returns\n * null when both fail so `discover()` falls through to the remaining\n * methods.\n */\n private async discoverFromAppServer(manifest: RunnerPluginManifest): Promise<DiscoveredModel[] | null> {\n const config = manifest.modelDiscovery.appServer;\n if (!config) return null;\n\n const raw = await this.appServerClient(config.command, config.args);\n if (raw) {\n const models = parseAppServerModels(raw);\n if (models.length > 0) return models;\n }\n\n if (config.cacheFile) {\n const content = this.readFileImpl(config.cacheFile);\n if (content) {\n const models = parseCodexModelsCache(content);\n if (models.length > 0) return models;\n }\n }\n\n return null;\n }\n\n /**\n * Every model this runner offers, each stamped with the runner it came from.\n * The stamp lives here rather than in the parsers because this is the only\n * place that knows both — a parser sees output, not which agent produced it.\n */\n async discover(runner: string): Promise<DiscoveredModel[]> {\n const models = await this.discoverRaw(runner);\n const manifest = this.registry.getManifest(runner);\n if (!manifest) return models;\n const runnerLabel = manifest.displayName || runner;\n return models.map((m) => ({ ...m, runnerId: runner, runnerLabel }));\n }\n\n private async discoverRaw(runner: string): Promise<DiscoveredModel[]> {\n if (this.cache.has(runner)) {\n return this.cache.get(runner)!;\n }\n\n const manifest = this.registry.getManifest(runner);\n if (!manifest) {\n return [];\n }\n\n let models: DiscoveredModel[];\n let cacheable = true;\n const discovery = manifest.modelDiscovery;\n\n // 0. App-server JSON-RPC discovery (Codex). Live catalog first, the\n // runner's own cache file second; falls through on total failure.\n if (discovery.appServer) {\n const appServerModels = await this.discoverFromAppServer(manifest);\n if (appServerModels && appServerModels.length > 0) {\n this.cache.set(runner, appServerModels);\n return appServerModels;\n }\n // Both live and cache-file sources failed — whatever the remaining\n // methods produce is a degraded fallback; don't cache it, so a\n // transient failure heals on the next lookup.\n cacheable = false;\n }\n\n // 1. Try API discovery first (e.g. Anthropic Models API for Claude Code).\n // Returns null when no auth token is available or the request fails —\n // in both cases we fall through to command-based discovery.\n if (discovery.apiDiscovery) {\n const apiModels = await discoverFromApi(discovery.apiDiscovery, this.fetchImpl);\n if (apiModels && apiModels.length > 0) {\n models = applyVariants(mergeCanonicalAliases(apiModels, manifest), manifest);\n if (cacheable && models.length > 0) this.cache.set(runner, models);\n return models;\n }\n }\n\n // 2. Command-based discovery (CLI subcommand or --help parsing).\n if (discovery.method === 'command' && (discovery.command || discovery.discoveryCommands?.length)) {\n const result = await discoverFromCommand(manifest, this.execImpl);\n models = result.models;\n // A fallback-only result means the CLI wasn't reachable — don't cache\n // it, so a transient failure (PATH, network, cold start) heals on the\n // next lookup instead of persisting until an explicit refresh.\n cacheable = !result.fromFallback;\n } else {\n models = buildFallbackModels(manifest);\n }\n\n if (cacheable && models.length > 0) this.cache.set(runner, models);\n return models;\n }\n\n clear(): void {\n this.cache.clear();\n }\n}\n","import { exec } from 'child_process';\nimport { promisify } from 'util';\nimport * as os from 'os';\nimport * as path from 'path';\n\nconst execAsync = promisify(exec);\n\n/**\n * GUI-launched processes (the VS Code extension host, a desktop-spawned web\n * server) often inherit a minimal PATH that misses user-level install dirs\n * (~/.local/bin, ~/.opencode/bin, nvm shims, …), so spawning `claude` or\n * `opencode` fails even though the user has them installed. This module\n * resolves an augmented PATH once per process: the interactive login shell's\n * PATH (which runs the user's profile, covering nvm/volta/asdf and friends)\n * merged over the current PATH, plus the well-known per-user bin dirs as a\n * final safety net when the login shell itself can't be queried. On Windows\n * there is no login shell to query, so the well-known dirs are the whole net —\n * see {@link windowsBinDirs}.\n *\n * {@link withPath} is the other half: handing the resolved PATH to a child\n * without accidentally giving it two.\n */\n\nconst LOGIN_SHELL_TIMEOUT_MS = 5000;\nconst PATH_MARKER = '__ORDEWELL_PATH__';\n\ntype ExecFn = (command: string, options?: { timeout?: number }) => Promise<{ stdout: string }>;\n\nconst defaultExec: ExecFn = async (command, options) => {\n const { stdout } = await execAsync(command, options);\n return { stdout: String(stdout) };\n};\n\nfunction posixBinDirs(): string[] {\n const home = os.homedir();\n return [\n path.join(home, '.local', 'bin'),\n path.join(home, '.opencode', 'bin'),\n path.join(home, '.claude', 'bin'),\n path.join(home, '.bun', 'bin'),\n path.join(home, '.volta', 'bin'),\n path.join(home, '.npm-global', 'bin'),\n path.join(home, 'bin'),\n '/usr/local/bin',\n '/opt/homebrew/bin',\n ];\n}\n\n/**\n * The Windows counterpart of {@link posixBinDirs}. There is no login shell to\n * ask on Windows, so this list is the only safety net when a runner was\n * installed after the host process started (the registry PATH a GUI-launched\n * VS Code inherited is a snapshot from launch time) or by an installer that\n * writes its own directory rather than amending PATH.\n *\n * The three built-in runners can each arrive by several routes, and the list\n * has to cover all of them or the picker greys out a CLI the user just\n * installed:\n *\n * - **PowerShell one-liner installers.** `irm https://claude.ai/install.ps1 |\n * iex` writes a native `claude.exe` to `%USERPROFILE%\\.local\\bin`, and\n * OpenCode's writes to `%USERPROFILE%\\.opencode\\bin`. `.local\\bin` was the\n * conspicuous omission — it is in {@link posixBinDirs}, where the same\n * installer puts the same binary, and its absence here meant the officially\n * documented Windows install of the flagship runner was the one Ordewell\n * could not find.\n * - **Node package managers.** npm's global prefix, and pnpm's and Yarn's,\n * which are not under it.\n * - **Windows package managers.** Scoop and Chocolatey shim directories, and\n * WinGet's `Links` folder for portable packages (distinct from\n * `WindowsApps`, which is MSIX only).\n * - **Version managers.** Volta spells its home `%LOCALAPPDATA%\\Volta` here,\n * not `~/.volta` as it does on POSIX.\n */\nfunction windowsBinDirs(env: NodeJS.ProcessEnv, home: string): string[] {\n const join = (...parts: string[]) => path.win32.join(...parts);\n const under = (base: string | undefined, ...parts: string[]) => (base ? [join(base, ...parts)] : []);\n const appData = env.APPDATA;\n const localAppData = env.LOCALAPPDATA;\n const programData = env.ProgramData;\n\n return [\n // Native per-user installers, PowerShell-driven and otherwise.\n join(home, '.local', 'bin'),\n join(home, '.opencode', 'bin'),\n join(home, '.claude', 'bin'),\n join(home, '.codex', 'bin'),\n ...under(localAppData, 'Programs', 'claude'),\n\n // Node package managers. npm's global prefix is `%APPDATA%\\npm`; the\n // literal spelling is kept as a fallback for a host that does not export\n // APPDATA (a service account, a stripped CI container).\n ...under(appData, 'npm'),\n join(home, 'AppData', 'Roaming', 'npm'),\n ...under(localAppData, 'pnpm'),\n ...under(localAppData, 'Yarn', 'bin'),\n join(home, '.bun', 'bin'),\n\n // Windows package managers.\n join(home, 'scoop', 'shims'),\n ...under(env.SCOOP, 'shims'),\n ...under(env.SCOOP_GLOBAL ?? programData, 'scoop', 'shims'),\n ...under(programData, 'chocolatey', 'bin'),\n // WinGet portable packages land here; `WindowsApps` only ever holds MSIX\n // aliases, so both are needed and neither substitutes for the other.\n ...under(localAppData, 'Microsoft', 'WinGet', 'Links'),\n ...under(localAppData, 'Microsoft', 'WindowsApps'),\n\n // Version managers. Volta's Windows home is not the POSIX `~/.volta`.\n ...under(localAppData, 'Volta', 'bin'),\n join(home, '.volta', 'bin'),\n ];\n}\n\n/**\n * Exported for test: the Windows arm cannot be exercised from a Linux CI box\n * through {@link augmentedPath}, which reads `process.platform` and the real\n * environment. Production always calls it through the no-argument form.\n */\nexport function wellKnownBinDirs(deps: { platform?: NodeJS.Platform; env?: NodeJS.ProcessEnv; home?: string } = {}): string[] {\n const platform = deps.platform ?? process.platform;\n if (platform !== 'win32') return posixBinDirs();\n return [...new Set(windowsBinDirs(deps.env ?? process.env, deps.home ?? os.homedir()))];\n}\n\nasync function loginShellPath(execImpl: ExecFn): Promise<string | null> {\n if (process.platform === 'win32') return null;\n const shell = process.env.SHELL || '/bin/sh';\n try {\n // Markers isolate $PATH from any profile noise (motd, echo in .zprofile…).\n const { stdout } = await execImpl(\n `${shell} -l -c 'echo \"${PATH_MARKER}$PATH${PATH_MARKER}\"'`,\n { timeout: LOGIN_SHELL_TIMEOUT_MS },\n );\n const match = stdout.match(new RegExp(`${PATH_MARKER}([^\\\\n]*)${PATH_MARKER}`));\n return match?.[1] || null;\n } catch {\n return null;\n }\n}\n\nlet cachedPath: Promise<string> | null = null;\n\n/**\n * The augmented PATH for spawning user-installed CLI tools. Resolved once per\n * process and cached (the login shell query costs ~50-200ms).\n */\nexport function augmentedPath(execImpl: ExecFn = defaultExec): Promise<string> {\n if (!cachedPath) {\n cachedPath = (async () => {\n const segments: string[] = [];\n const push = (p: string | null | undefined) => {\n if (!p) return;\n for (const seg of p.split(path.delimiter)) {\n if (seg && !segments.includes(seg)) segments.push(seg);\n }\n };\n push(process.env.PATH);\n push(await loginShellPath(execImpl));\n for (const dir of wellKnownBinDirs()) push(dir);\n return segments.join(path.delimiter);\n })();\n }\n return cachedPath;\n}\n\n/** Test seam: drop the per-process cache so the next call re-resolves. */\nexport function clearAugmentedPathCache(): void {\n cachedPath = null;\n}\n\n/**\n * Build a child environment whose PATH is `resolvedPath`, with exactly one\n * PATH-ish key in it.\n *\n * `{ ...process.env, PATH }` is the obvious spelling and it is wrong on\n * Windows. Node's `process.env` is a case-insensitive proxy, but spreading it\n * yields the OS's actual casing — `Path` — so adding `PATH` produces an\n * environment block carrying both. Which one the child sees is undefined, and\n * the loser is silently discarded. Every existing site passed the same value\n * under both keys, so the bug was latent rather than live; this makes it\n * impossible instead of unlikely.\n */\nexport function withPath(\n base: NodeJS.ProcessEnv,\n resolvedPath: string,\n overrides: Record<string, string> = {},\n): NodeJS.ProcessEnv {\n const env: NodeJS.ProcessEnv = {};\n // Both sources are filtered, not just `base`: an `overrides` map carrying its\n // own PATH is exactly how the duplicate reappears.\n for (const source of [base, overrides]) {\n for (const [key, value] of Object.entries(source)) {\n if (key.toLowerCase() === 'path') continue;\n env[key] = value;\n }\n }\n // Windows canonically spells it `Path`; POSIX requires `PATH`. Matching the\n // platform keeps anything downstream that reads the raw block unsurprised.\n env[process.platform === 'win32' ? 'Path' : 'PATH'] = resolvedPath;\n return env;\n}\n","import * as fsSync from 'fs';\nimport * as path from 'path';\nimport { buildShellInvocation } from './shell';\nimport { augmentedPath } from './shellPath';\n\n/**\n * How a runner or planner CLI is started on this operating system.\n *\n * Every surface that starts an external agent — the VS Code terminal, the\n * headless runner, each harness-planner adapter, Codex model discovery — asks\n * this module rather than deciding for itself. Before it existed, four call\n * sites each did `spawn('claude', args)`, which is correct on POSIX (execvp\n * searches PATH) and broken on Windows, where CreateProcess performs no PATHEXT\n * lookup: an npm-installed `claude` is `claude.cmd`, so the spawn failed with\n * ENOENT while `RunnerInstallation`'s `exec` probe — which does go through\n * cmd.exe — reported the runner installed and healthy.\n *\n * Every path operation in the Windows branch goes through `path.win32`\n * explicitly rather than the host-flavoured `path`. On a real Windows host they\n * are the same object, so production is unaffected — but it makes the Windows\n * logic independent of where the process runs, which is the only way the\n * behavior can be pinned by a test on a Linux CI box. Host `path` is used for\n * nothing here.\n *\n * There are three Windows routes, tried in this order because it is the order\n * that gets to a directly-spawnable file soonest: a native `.exe`, a `.cmd`\n * shim through cmd.exe, a `.ps1` shim through `powershell.exe -File`. The\n * ordering is what keeps the common case off an interpreter, and off the\n * 8191-character buffer cmd.exe brings with it.\n *\n * The batch route is skipped outright for a multi-line argument: cmd.exe stops\n * reading at the first line break and discards the rest without an error — see\n * {@link EmbeddedNewlineError}.\n *\n * `-File` is chosen over `-Command` for the PowerShell tier because it evaluates\n * nothing: the script path and the arguments after it are strings, so a prompt\n * containing `$(…)` is data rather than PowerShell source. Argument fidelity\n * there — embedded newlines, backticks, `%VAR%` — is verified on a Windows host.\n *\n * POSIX behavior is deliberately identity. `planDirectLaunch` hands back the\n * command and args untouched, and `planShellLaunch` produces exactly the\n * `bash -lc` invocation it always did, so nothing about macOS or Linux changes.\n * All of the machinery below is reached only when `platform === 'win32'`.\n */\n\n/** Extensions CreateProcess can start on its own, in preference order. */\nconst DIRECT_EXTENSIONS = ['.exe', '.com'];\n\n/**\n * Extensions only a command interpreter can start. Node refuses to spawn these\n * without `shell: true` (CVE-2024-27980), so they route through cmd.exe.\n */\nconst BATCH_EXTENSIONS = ['.cmd', '.bat'];\n\n/**\n * Extensions only PowerShell can start. Reached last, and only when neither a\n * native executable nor a batch shim exists.\n *\n * Every Node package manager that writes a `.ps1` shim writes a `.cmd` beside\n * it, so on those installs this tier is never selected — it is here for the\n * install shapes that do not: a PowerShell installer that dropped a script\n * rather than a binary, a hand-rolled shim, a tool distributed as a module.\n * The alternative for those is a bare `spawn ENOENT` naming a command the user\n * can plainly see is installed.\n *\n * `.ps1` is deliberately not filtered against PATHEXT. Windows' default\n * PATHEXT does not list it — PowerShell resolves scripts itself rather than\n * through CreateProcess — so honouring PATHEXT here would exclude the tier on\n * exactly the machines it exists for.\n */\nconst POWERSHELL_EXTENSIONS = ['.ps1'];\n\n/**\n * cmd.exe's command-line buffer. A longer line is truncated rather than\n * rejected, which would corrupt a planner's system prompt or a task's prompt\n * mid-sentence and produce a confident answer to half a question — so the\n * batch route refuses instead. See {@link CommandLineTooLongError}.\n */\nexport const CMD_EXE_MAX_COMMAND_LINE = 8191;\n\n/**\n * CreateProcess's own ceiling, which the native and PowerShell routes are\n * bounded by instead. Windows truncates here too, so the same refusal applies —\n * it is simply four times further away.\n */\nexport const WINDOWS_MAX_COMMAND_LINE = 32767;\n\nexport interface LaunchPlan {\n /** The executable handed to `spawn()` or `vscode.window.createTerminal`. */\n file: string;\n /** Arguments for `file`. Pass verbatim when {@link verbatim} is set. */\n args: string[];\n /**\n * Windows batch route only: `args` is already a quoted command line and must\n * not be re-quoted. Maps to `windowsVerbatimArguments` for `spawn`, and to\n * the string form of `shellArgs` for a VS Code terminal.\n */\n verbatim?: boolean;\n}\n\n/** Test seam: every OS touchpoint is injectable, and production uses the defaults. */\nexport interface LaunchDeps {\n platform?: NodeJS.Platform;\n /** The PATH executables are looked up on. Defaults to the augmented PATH. */\n resolvePath?: () => Promise<string>;\n /** True when `candidate` names an existing file. */\n exists?: (candidate: string) => boolean;\n /** Absolute path to the Windows command interpreter. */\n comSpec?: () => string;\n /** Absolute path to Windows PowerShell. */\n powerShell?: () => string;\n /** PATHEXT, as the environment reports it. */\n pathExt?: () => string;\n}\n\n/**\n * Windows PowerShell's fixed location. Resolved absolutely rather than by name\n * because this is a fallback route reached when PATH lookup has already\n * disappointed us once; `powershell.exe` remains as a last resort for a host\n * that does not export SystemRoot.\n */\nfunction defaultPowerShell(): string {\n const root = process.env.SystemRoot || process.env.windir;\n return root\n ? path.win32.join(root, 'System32', 'WindowsPowerShell', 'v1.0', 'powershell.exe')\n : 'powershell.exe';\n}\n\n/**\n * The flags every PowerShell shim invocation carries.\n *\n * `-NoProfile` is not a nicety: a user profile can print a banner into stdout,\n * which for the harness planners is a JSON-RPC stream. `-ExecutionPolicy\n * Bypass` applies to this process only and is what lets a shim run on the\n * default `Restricted` policy at all. `-File` must stay last — everything\n * after it is the script and its arguments.\n */\nconst POWERSHELL_FLAGS = ['-NoLogo', '-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', '-File'];\n\n/**\n * Thrown when a command's arguments do not fit the buffer of the only\n * interpreter that can start it. Windows truncates rather than rejecting, and a\n * system prompt cut off mid-sentence makes the planner answer half a question\n * confidently — the silent success this repo refuses — so this is raised\n * instead. `TaskOrchestrator.startTask` catches it and holds the task, so the\n * message is what the user reads: it names the fix, because they cannot infer\n * it from a truncated prompt.\n */\nexport class CommandLineTooLongError extends Error {\n constructor(readonly command: string, readonly length: number, readonly limit: number = CMD_EXE_MAX_COMMAND_LINE) {\n super(\n limit === CMD_EXE_MAX_COMMAND_LINE\n ? `Cannot start \"${command}\" on Windows: its arguments are ${length} characters, over cmd.exe's ${limit}-character limit.\\n\\n` +\n `Only a batch shim (${command}.cmd) was found on PATH, and a shim has to be started through cmd.exe. ` +\n `Install the native executable — Claude Code's Windows installer, Codex's release binary, or OpenCode's install script all provide one — ` +\n `and Ordewell will launch it directly, with no buffer in the way.`\n : `Cannot start \"${command}\" on Windows: its arguments are ${length} characters, over the ${limit}-character limit Windows places on any command line.\\n\\n` +\n `This is the OS ceiling rather than a shim's, so no reinstall avoids it. ` +\n `Shorten the task prompt, or turn off some planner mode toggles — each one appends to the system prompt the runner is started with.`,\n );\n this.name = 'CommandLineTooLongError';\n }\n}\n\n/**\n * Thrown when only a batch shim resolved for a multi-line argument. cmd.exe\n * reads up to the first CR/LF and discards the rest with no error and exit code\n * 0 — quoting does not help — so the agent would get the first paragraph of its\n * prompt without the completion marker instruction, then exit looking successful.\n */\nexport class EmbeddedNewlineError extends Error {\n constructor(readonly command: string) {\n super(\n `Cannot start \"${command}\" on Windows: its prompt spans multiple lines, and the only launcher found on PATH was a batch shim (${command}.cmd).\\n\\n` +\n `cmd.exe stops reading a command line at the first line break and silently discards the rest, so the agent would be handed a prompt cut off at its first blank line — no plan map, no prior task output, and no completion marker, which is what Ordewell watches for to know the task finished.\\n\\n` +\n `Install the native executable — Claude Code's Windows installer, Codex's release binary, or OpenCode's install script all provide one — and Ordewell will launch it directly, with no interpreter in the way. A PowerShell shim (${command}.ps1) beside the batch one is also enough.`,\n );\n this.name = 'EmbeddedNewlineError';\n }\n}\n\nfunction hasLineBreak(parts: string[]): boolean {\n return parts.some((part) => /[\\r\\n]/.test(part));\n}\n\nfunction defaultExists(candidate: string): boolean {\n try {\n return fsSync.statSync(candidate).isFile();\n } catch {\n return false;\n }\n}\n\n/**\n * Quote one argument for cmd.exe.\n *\n * The backslash rule is the documented CommandLineToArgvW inverse: a run of\n * backslashes is only doubled when it precedes a quote we are adding or\n * escaping, which is why a trailing `C:\\repo\\` has to be handled separately\n * from one in the middle of an argument.\n *\n * `%` is NOT escaped, because in a `cmd /c` context it cannot be: `%%` is a\n * batch-file construct, and `^%` still expands. An argument naming a defined\n * environment variable (`%PATH%`) is therefore expanded by cmd.exe on the batch\n * route. Preferring a native executable — which this module always does — skips\n * cmd.exe and the hazard with it.\n */\nfunction quoteForCmd(arg: string): string {\n if (arg === '') return '\"\"';\n if (!/[\\s\"^&|<>()]/.test(arg)) return arg;\n\n let quoted = '\"';\n let backslashes = 0;\n for (const ch of arg) {\n if (ch === '\\\\') {\n backslashes++;\n continue;\n }\n if (ch === '\"') {\n quoted += '\\\\'.repeat(backslashes * 2 + 1) + '\"';\n backslashes = 0;\n continue;\n }\n quoted += '\\\\'.repeat(backslashes) + ch;\n backslashes = 0;\n }\n return `${quoted}${'\\\\'.repeat(backslashes * 2)}\"`;\n}\n\n/** The verbatim command line cmd.exe receives after `/d /s /c`, before wrapping. */\nexport function windowsCommandLine(file: string, args: string[]): string {\n return [file, ...args].map(quoteForCmd).join(' ');\n}\n\n/**\n * The `/d /s /c` argument list for a command line, wrapped the one way cmd.exe\n * can be relied on to unwrap.\n *\n * The outer quote pair is not decoration. With `/s`, cmd's documented rule is:\n * if the first character after `/c` is a quote, strip that quote and the *last*\n * quote on the whole line, then take everything between them verbatim. Handing\n * it a bare line whose first token is a quoted path — `\"C:\\Program\n * Files\\nodejs\\claude.cmd\" -p \"go\"` — therefore strips the opening quote of the\n * executable and the closing quote of the final argument, leaving cmd to run\n * `C:\\Program`. Any user whose name has a space in it hits this on the first\n * task. Wrapping the whole line makes the two quotes cmd removes the two we\n * added, which is what Node's own `shell: true` does for the same reason.\n */\nfunction cmdArgs(line: string): string[] {\n return ['/d', '/s', '/c', `\"${line}\"`];\n}\n\n/**\n * The extensions to try for `command`, in the order that gets us to a\n * directly-spawnable file soonest.\n *\n * Windows itself resolves per-directory (every PATHEXT tried in dir 1 before\n * dir 2), so a `claude.cmd` early on PATH would shadow a `claude.exe` later.\n * This searches by extension class instead — every directory for a `.exe`,\n * then every directory for a `.cmd`. Two installs of the same CLI are the same\n * program, so the global preference never selects a different tool, and it is\n * what keeps the common case off the batch route.\n */\nfunction candidateExtensions(command: string, pathExt: string): Record<Route, string[]> {\n const declared = pathExt.split(path.win32.delimiter).map((e) => e.trim().toLowerCase()).filter(Boolean);\n const known = new Set([...DIRECT_EXTENSIONS, ...BATCH_EXTENSIONS, ...POWERSHELL_EXTENSIONS, ...declared]);\n const ext = path.win32.extname(command).toLowerCase();\n\n // An explicit extension is a request, not a hint: honour it and search no other.\n if (ext && known.has(ext)) {\n const route: Route = BATCH_EXTENSIONS.includes(ext) ? 'cmd'\n : POWERSHELL_EXTENSIONS.includes(ext) ? 'powershell'\n : 'direct';\n return { direct: [], cmd: [], powershell: [], [route]: [''] };\n }\n\n const declaredOr = (extensions: string[]) => {\n const filtered = extensions.filter((e) => declared.length === 0 || declared.includes(e));\n return filtered.length > 0 ? filtered : extensions;\n };\n return {\n direct: declaredOr(DIRECT_EXTENSIONS),\n cmd: declaredOr(BATCH_EXTENSIONS),\n // Not filtered: `.ps1` is absent from Windows' default PATHEXT by design.\n powershell: POWERSHELL_EXTENSIONS,\n };\n}\n\n/** How a resolved file has to be started. */\ntype Route = 'direct' | 'cmd' | 'powershell';\n\n/** Tried in this order — soonest to a directly-spawnable file wins. */\nconst ROUTES: Route[] = ['direct', 'cmd', 'powershell'];\n\ninterface FoundExecutable {\n file: string;\n route: Route;\n}\n\n/**\n * Every route `command` can be reached by on this host, best first.\n *\n * All of them rather than just the first, because the best route is not only a\n * function of preference: a batch shim that would overflow cmd.exe's buffer is\n * no route at all, and knowing a PowerShell shim sits beside it is what\n * separates a held task from a running one.\n */\nasync function findWindowsExecutables(command: string, deps: LaunchDeps): Promise<FoundExecutable[]> {\n const exists = deps.exists ?? defaultExists;\n const pathExt = (deps.pathExt ?? (() => process.env.PATHEXT ?? ''))();\n const byRoute = candidateExtensions(command, pathExt);\n\n // A command that already names a location is not a PATH lookup.\n const dirs = path.win32.basename(command) !== command\n ? [path.win32.dirname(path.win32.resolve(command))]\n : ((await (deps.resolvePath ?? augmentedPath)()) || '')\n .split(path.win32.delimiter)\n .map((d) => d.trim().replace(/^\"|\"$/g, ''))\n .filter(Boolean);\n\n const base = path.win32.basename(command);\n const found: FoundExecutable[] = [];\n for (const route of ROUTES) {\n outer: for (const ext of byRoute[route]) {\n for (const dir of dirs) {\n const candidate = path.win32.join(dir, `${base}${ext}`);\n if (exists(candidate)) {\n found.push({ file: candidate, route });\n break outer;\n }\n }\n }\n }\n return found;\n}\n\n/** Why a candidate was rejected: `tooLong` is fatal, `lineBreak` falls through to the next route. */\ntype Disqualified = { tooLong: number; limit: number } | { lineBreak: true };\n\nfunction planFor(found: FoundExecutable, args: string[], deps: LaunchDeps): LaunchPlan | Disqualified {\n if (found.route === 'direct') {\n const length = windowsCommandLine(found.file, args).length;\n return length > WINDOWS_MAX_COMMAND_LINE\n ? { tooLong: length, limit: WINDOWS_MAX_COMMAND_LINE }\n : { file: found.file, args };\n }\n\n if (found.route === 'cmd') {\n if (hasLineBreak([found.file, ...args])) return { lineBreak: true };\n\n const comSpec = (deps.comSpec ?? (() => process.env.ComSpec || 'cmd.exe'))();\n const cmdLine = cmdArgs(windowsCommandLine(found.file, args));\n // The budget is the line cmd.exe receives, so it is measured after wrapping\n // and with the interpreter's own path in it — not just the inner command.\n const length = [comSpec, ...cmdLine].join(' ').length;\n return length > CMD_EXE_MAX_COMMAND_LINE\n ? { tooLong: length, limit: CMD_EXE_MAX_COMMAND_LINE }\n : { file: comSpec, args: cmdLine, verbatim: true };\n }\n\n // PowerShell takes an ordinary argument vector, so Node's own quoting applies\n // and nothing here is verbatim. `-File` is the mode with no expression\n // evaluation: the script path and the arguments after it are strings, never\n // PowerShell source, so a prompt containing `$(…)` or a backtick is data.\n const shell = (deps.powerShell ?? defaultPowerShell)();\n const psArgs = [...POWERSHELL_FLAGS, found.file, ...args];\n const length = windowsCommandLine(shell, psArgs).length;\n return length > WINDOWS_MAX_COMMAND_LINE\n ? { tooLong: length, limit: WINDOWS_MAX_COMMAND_LINE }\n : { file: shell, args: psArgs };\n}\n\n/**\n * How to start `command` with `args` through `spawn()`, with no shell.\n *\n * POSIX returns its input unchanged — execvp already searches PATH, and adding\n * a resolution step there would be a new way for a working setup to break.\n *\n * Windows resolves the command against PATH × PATHEXT, preferring a native\n * executable (spawned directly) over a batch shim (through cmd.exe) over a\n * PowerShell script shim (through `powershell.exe -File`). A command that\n * resolves to nothing is returned unchanged, so the caller's existing ENOENT —\n * which names what the user typed — is what surfaces rather than a second,\n * vaguer error from here.\n *\n * The tiers are tried in preference order and the first that *fits* wins, with\n * one deliberate exception: an overflowing batch shim does not fall through to\n * PowerShell. Overflow means a very large prompt, which is precisely where\n * `-File` argument fidelity is least worth betting on, and where a clear held\n * task beats a plausibly-mangled one. So capacity does not reorder the tiers —\n * a `.ps1` beside a too-long `.cmd` still raises.\n *\n * A line break does reorder them: cmd.exe cannot carry one at any length, so a\n * `.ps1` beside a `.cmd` wins, and a lone `.cmd` raises.\n *\n * @throws {CommandLineTooLongError} when the selected route's buffer cannot\n * carry the arguments.\n * @throws {EmbeddedNewlineError} when the arguments span lines and only the\n * batch route resolved.\n */\nexport async function planDirectLaunch(\n command: string,\n args: string[],\n deps: LaunchDeps = {},\n): Promise<LaunchPlan> {\n if ((deps.platform ?? process.platform) !== 'win32') return { file: command, args };\n\n const found = await findWindowsExecutables(command, deps);\n if (found.length === 0) return { file: command, args };\n\n for (const candidate of found) {\n const plan = planFor(candidate, args, deps);\n if ('lineBreak' in plan) continue;\n if ('tooLong' in plan) throw new CommandLineTooLongError(command, plan.tooLong, plan.limit);\n return plan;\n }\n // Only the batch route declines for a line break, so exhausting the loop means\n // every candidate was that route.\n throw new EmbeddedNewlineError(command);\n}\n\n/**\n * How to start `command` for a surface that hands an executable and arguments\n * to a terminal — the VS Code runner today, a Windows TUI later.\n *\n * On POSIX this is the login shell, unchanged: `bash -lc` runs the user's\n * profile, which is how nvm/volta/asdf-managed runner binaries resolve at all.\n * Windows has no login-shell equivalent (its PATH comes from the registry and\n * is already inherited), so it takes the direct route instead. That is not just\n * a simplification: it means the runner's own exit code is the terminal's exit\n * code, rather than a `$LASTEXITCODE` that PowerShell propagates unreliably —\n * and the exit code is half of what {@link VerdictEngine} judges a task on.\n */\nexport async function planShellLaunch(\n command: string,\n args: string[],\n deps: LaunchDeps = {},\n): Promise<LaunchPlan> {\n if ((deps.platform ?? process.platform) === 'win32') return planDirectLaunch(command, args, deps);\n const { shellPath, shellArgs } = buildShellInvocation(command, args);\n return { file: shellPath, args: shellArgs };\n}\n","// eslint-disable-next-line no-control-regex\nconst ANSI_RE = /\\x1b\\[[0-9;]*[A-Za-z]|\\x1b\\][^\\x07]*\\x07|\\x1b[()][AB012]|\\r/g;\n\nexport function stripAnsi(text: string): string {\n return text.replace(ANSI_RE, '');\n}\n\nexport function posixShellQuote(s: string): string {\n return `'${s.replace(/'/g, `'\\\\''`)}'`;\n}\n\n/**\n * Wrap a command for execution inside a POSIX login shell, which is what\n * resolves runner binaries managed by nvm/volta/asdf.\n *\n * Deliberately POSIX-only. This used to take a `platform` and emit\n * `powershell.exe -Command \"'claude' '-p' '…'\"` for Windows, which PowerShell\n * cannot run at all: a quoted string in leading position is parsed in\n * expression mode, so the invocation died with a parse error before the runner\n * started — a task that failed instantly, every time, on that platform. Windows\n * has no login-shell equivalent to emulate (its PATH comes from the registry\n * and is already inherited), so {@link planShellLaunch} starts the runner\n * directly there instead of routing it through a shell. Platform choice belongs\n * to that function; this one only knows how to phrase the POSIX half.\n */\nexport function buildShellInvocation(\n command: string,\n args: string[],\n): { shellPath: string; shellArgs: string[] } {\n const inner = [command, ...args].map(posixShellQuote).join(' ');\n return { shellPath: '/bin/bash', shellArgs: ['-lc', inner] };\n}\n\n/**\n * Wrap a command in `script` to allocate the PTY some runners require when\n * headless; `-e` propagates the child's exit code so verification still works.\n *\n * POSIX-only by nature — there is no `script` on Windows, which\n * `HeadlessRunner`'s `hasScriptCmd` probe already discovers, so this is never\n * reached there.\n */\nexport function wrapWithPty(command: string, args: string[]): { command: string; args: string[] } {\n const inner = [command, ...args].map(posixShellQuote).join(' ');\n return { command: 'script', args: ['-q', '-e', '-f', '-c', inner, '/dev/null'] };\n}\n","import { execFile } from 'child_process';\nimport type { ChildProcess } from 'child_process';\n\n/**\n * Stopping an agent process, on every platform.\n *\n * POSIX gets the escalation it always had: SIGTERM, then SIGKILL after a grace\n * period. Windows has no signals — `ChildProcess.kill` calls TerminateProcess\n * on the direct child only — and on Windows the direct child is frequently not\n * the agent. A `claude.cmd` shim launched through cmd.exe puts an interpreter\n * between Ordewell and the `node cli.js` doing the work, so terminating the child\n * left the real agent running: still holding the workspace, still spending the\n * user's subscription, invisible to the surface that thought it had stopped.\n * `taskkill /T` walks the tree instead.\n *\n * Both paths are best-effort and idempotent by construction. A process that has\n * already exited is not an error here — every caller is on a dispose path.\n */\n\n/** Grace period between the polite stop and the forced one. */\nconst HARD_KILL_DELAY_MS = 5000;\n\nexport interface KillTreeDeps {\n platform?: NodeJS.Platform;\n /** Runs `taskkill`. Injected so the Windows path is testable off Windows. */\n execFileImpl?: (file: string, args: string[], cb: (err: Error | null) => void) => void;\n /** Schedules the forced kill. Injected so tests need no timers. */\n setTimeoutImpl?: (fn: () => void, ms: number) => { unref?: () => void };\n clearTimeoutImpl?: (handle: unknown) => void;\n}\n\nfunction defaultExecFile(file: string, args: string[], cb: (err: Error | null) => void): void {\n execFile(file, args, (err) => cb(err ?? null));\n}\n\n/**\n * Terminate `proc` and everything it started.\n *\n * Returns immediately; the forced follow-up (SIGKILL, or `taskkill /F`) is\n * scheduled and unref'd, so a disposed session is never the reason the host\n * process refuses to exit.\n */\nexport function killTree(proc: ChildProcess | null, deps: KillTreeDeps = {}): void {\n // `typeof … === 'number'`, not `!== null`: only a numeric exit code is\n // positive evidence the process is gone. A running child reports null, and an\n // object that reports neither is treated as running — the cost of a redundant\n // kill is nothing, the cost of skipping a live one is an orphaned agent.\n if (!proc || proc.killed || typeof proc.exitCode === 'number') return;\n\n const platform = deps.platform ?? process.platform;\n const setTimeoutImpl = deps.setTimeoutImpl ?? ((fn, ms) => setTimeout(fn, ms) as unknown as { unref?: () => void });\n const clearTimeoutImpl = deps.clearTimeoutImpl ?? ((h) => clearTimeout(h as NodeJS.Timeout));\n\n if (platform === 'win32') {\n // No pid means the process never started; there is no tree to walk.\n if (typeof proc.pid !== 'number') return;\n const pid = proc.pid;\n const run = deps.execFileImpl ?? defaultExecFile;\n\n // `/T` is the whole point: without it this is the TerminateProcess call\n // that already failed to reach the agent. The unforced pass first gives a\n // console app a chance to flush; `/F` follows if it did not take.\n run('taskkill', ['/pid', String(pid), '/T'], () => { /* exit code is not news */ });\n const hardKill = setTimeoutImpl(() => {\n run('taskkill', ['/pid', String(pid), '/T', '/F'], () => { /* already gone */ });\n }, HARD_KILL_DELAY_MS);\n hardKill.unref?.();\n proc.once('exit', () => clearTimeoutImpl(hardKill));\n return;\n }\n\n try {\n proc.kill('SIGTERM');\n const hardKill = setTimeoutImpl(() => {\n try { proc.kill('SIGKILL'); } catch { /* already gone */ }\n }, HARD_KILL_DELAY_MS);\n hardKill.unref?.();\n proc.once('exit', () => clearTimeoutImpl(hardKill));\n } catch {\n // Process already gone — nothing to clean up.\n }\n}\n","import * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as os from \"os\";\nexport interface CatalogModel {\n id: string;\n name: string;\n description: string;\n pricing: { prompt: string; completion: string };\n contextLength: number;\n}\n\ninterface OpenRouterModel {\n id: string;\n name: string;\n description?: string;\n pricing?: { prompt: string; completion: string };\n context_length?: number;\n}\n\nconst CACHE_KEY = 'model-catalog';\nconst CACHE_TTL_MS = 60 * 60 * 1000; // 1 hour\n\nfunction storageKey(baseUrl: string): string {\n return `${CACHE_KEY}:${baseUrl}`;\n}\n\nexport class ModelCatalog {\n static async fetchModels(apiKey: string, baseUrl?: string, fetchImpl?: typeof fetch): Promise<CatalogModel[]> {\n const url = (baseUrl || 'https://openrouter.ai/api/v1').replace(/\\/+$/, '');\n // An injected fetch means the resolver owns caching — bypass the file cache\n // so callers (and tests) get exactly what the seam returns.\n const useFileCache = !fetchImpl;\n if (useFileCache) {\n const cached = this.readCache(storageKey(url));\n if (cached) {\n try {\n return JSON.parse(cached) as CatalogModel[];\n } catch { /* empty */ }\n }\n }\n\n // OpenRouter's /models endpoint is public, so the catalog can be fetched\n // without a key. Only send Authorization when we actually have one.\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n if (apiKey) headers.Authorization = `Bearer ${apiKey}`;\n const response = await (fetchImpl ?? fetch)(`${url}/models`, { headers });\n\n if (!response.ok) {\n throw new Error(`Failed to fetch models: ${response.status} ${response.statusText}`);\n }\n\n const data = (await response.json()) as { data?: OpenRouterModel[] };\n const models: CatalogModel[] = (data.data ?? []).map((m) => ({\n id: m.id,\n name: m.name,\n description: m.description ?? '',\n pricing: {\n prompt: m.pricing?.prompt ?? '?',\n completion: m.pricing?.completion ?? '?',\n },\n contextLength: m.context_length ?? 0,\n }));\n\n if (useFileCache) this.writeCache(storageKey(url), models);\n return models;\n }\n\n /**\n * Delete the on-disk catalog cache for a base URL so the next fetch re-runs.\n * Used by the resolver's `invalidate()` in production (no injected fetch);\n * best-effort — a missing file or unreadable dir is a no-op.\n */\n static clearCache(baseUrl?: string): void {\n try {\n const url = (baseUrl || 'https://openrouter.ai/api/v1').replace(/\\/+$/, '');\n const key = storageKey(url);\n const cacheDir = path.join(os.homedir(), '.config', 'ordewell');\n const cacheFile = path.join(cacheDir, `${key.replace(/[:/]/g, '_')}.json`);\n if (fs.existsSync(cacheFile)) fs.rmSync(cacheFile);\n } catch { /* empty */ }\n }\n\n private static readCache(key: string): string | null {\n try {\n const cacheDir = path.join(os.homedir(), '.config', 'ordewell');\n const cacheFile = path.join(cacheDir, `${key.replace(/[:/]/g, '_')}.json`);\n if (!fs.existsSync(cacheFile)) return null;\n const raw = fs.readFileSync(cacheFile, 'utf8');\n const data = JSON.parse(raw);\n if (Date.now() - data.cachedAt > CACHE_TTL_MS) return null;\n return JSON.stringify(data.models);\n } catch {\n return null;\n }\n }\n\n private static writeCache(key: string, models: CatalogModel[]): void {\n try {\n const cacheDir = path.join(os.homedir(), '.config', 'ordewell');\n fs.mkdirSync(cacheDir, { recursive: true });\n const cacheFile = path.join(cacheDir, `${key.replace(/[:/]/g, '_')}.json`);\n fs.writeFileSync(\n cacheFile,\n JSON.stringify({ models, cachedAt: Date.now() }, null, 2)\n );\n } catch { /* empty */ }\n }\n}\n","export interface ModelShortcut {\n label: string;\n id: string;\n provider: string;\n description: string;\n pricing?: string;\n}\n\nexport function extractProvider(modelId: string): string {\n const slash = modelId.indexOf('/');\n if (slash < 0) return '';\n return modelId.slice(0, slash);\n}\n\nexport function groupByProvider<T extends { id: string }>(items: T[], extract?: (item: T) => string): Map<string, T[]> {\n const grouped = new Map<string, T[]>();\n for (const item of items) {\n const provider = extract ? extract(item) : extractProvider(item.id);\n const key = provider || 'Other';\n if (!grouped.has(key)) grouped.set(key, []);\n grouped.get(key)!.push(item);\n }\n return grouped;\n}\n\nexport const ORCHESTRATOR_SHORTCUTS: ModelShortcut[] = [\n { label: 'DeepSeek V4 Flash', id: 'deepseek/deepseek-v4-flash', provider: 'OpenRouter', description: 'Best all-around — strong coding, cheap', pricing: '0.09/0.18' },\n { label: 'DeepSeek R1', id: 'deepseek/deepseek-r1', provider: 'OpenRouter', description: 'Reasoning model — complex logic, zero-cost thinking tokens', pricing: '0.55/2.19' },\n { label: 'Claude Sonnet 4', id: 'anthropic/claude-sonnet-4', provider: 'OpenRouter', description: 'Top-tier reasoning, careful editing', pricing: '3/15' },\n { label: 'Claude Opus 4', id: 'anthropic/claude-opus-4.7', provider: 'OpenRouter', description: 'Strongest overall — complex refactoring, architecture', pricing: '15/75' },\n { label: 'GPT-4o', id: 'openai/gpt-4o', provider: 'OpenRouter', description: 'General purpose, strong multimodal', pricing: '2.50/10' },\n { label: 'GPT-4.1', id: 'openai/gpt-4.1', provider: 'OpenRouter', description: 'Latest GPT — strong coding, 1M context', pricing: '2/8' },\n { label: 'Kimi K2.6', id: 'moonshot/kimi-k2.6', provider: 'OpenRouter', description: 'Strong coding, cheap', pricing: '0.60/2.40' },\n { label: 'Qwen 3 Max', id: 'qwen/qwen3-max', provider: 'OpenRouter', description: 'Strong open model', pricing: '0.80/3.20' },\n];\n\nexport function resolveModelShortcut(input: string, shortcuts: ModelShortcut[]): string | null {\n for (const s of shortcuts) {\n if (s.id === input) return s.id;\n if (s.label.toLowerCase() === input.toLowerCase()) return s.id;\n }\n return null;\n}\n\n/**\n * Resolves a value to a model id ONLY when it is in the supplied catalog\n * option list — either directly or via a shortcut label. Free-typed, unknown,\n * or not-currently-available values return null, so callers never store an id\n * the user couldn't have selected from the list. Keeps model-setting list-only.\n */\nexport function knownModelId(value: string, optionIds: string[], shortcuts: ModelShortcut[]): string | null {\n if (!value) return null;\n const viaShortcut = resolveModelShortcut(value, shortcuts);\n if (viaShortcut && optionIds.includes(viaShortcut)) return viaShortcut;\n return optionIds.includes(value) ? value : null;\n}\n","import type { AiProvider } from '../interfaces/IConfig';\nimport { PROVIDER_PRIORITY, getProviderMeta, prefixModelId } from './ProviderRegistry';\n\nexport type ProviderModelLists = Record<string, string[]>;\n\nexport interface OrchestratorOption {\n id: string;\n label: string;\n provider: string;\n apiProvider: AiProvider;\n description?: string;\n pricing?: string;\n}\n\nimport type { CatalogModel } from './ModelCatalog';\nimport type { DiscoveredModel } from '../models/Task';\nimport type { ModelShortcut } from './ModelShortcuts';\nimport { extractProvider } from './ModelShortcuts';\nimport { ModelCatalog } from './ModelCatalog';\nimport { discoverGeminiModels } from './ModelDiscovery';\n\nexport interface FetchAllProviderModelsOptions {\n apiKeys: Record<string, string>;\n baseUrls: Record<string, string>;\n fetchImpl?: typeof fetch;\n}\n\nexport type AllProviderModels = Record<string, CatalogModel[]>;\n\n/**\n * Result of a picker-catalog fetch fan-out: the per-provider model lists plus\n * the per-provider failures. `errors` is keyed by provider id and holds the\n * failure message for any provider whose catalog fetch rejected — the seam the\n * surfaces (CLI, VS Code) use to flag \"this configured provider didn't work\"\n * rather than silently showing a short list.\n */\nexport interface ProviderModelsResult {\n models: AllProviderModels;\n errors: Record<string, string>;\n}\n\n/** The provider config fields the discovery fan-out needs. */\nexport interface ProviderCredentialSource {\n getProviderApiKey(provider: AiProvider): string;\n getProviderBaseUrl(provider: AiProvider): string;\n openaiCompatibleBaseUrl: string;\n}\n\n/**\n * Collect the API keys and base URLs the picker fan-out should probe, applying\n * the single \"configured\" policy shared by every surface (CLI + VS Code):\n * - a preset is discovered only when it has an API key (OpenRouter included —\n * its public catalog is not probed keyless, matching the product rule that\n * only key-configured providers appear);\n * - `openai_compatible` is discovered only when an explicit endpoint is set\n * (keyless local servers like ollama / LM Studio).\n * Base URLs are handed through only for providers that pass the gate, so the\n * fan-out never touches an unconfigured third-party endpoint.\n */\nexport function collectProviderCredentials(config: ProviderCredentialSource): {\n apiKeys: Record<string, string>;\n baseUrls: Record<string, string>;\n} {\n const apiKeys: Record<string, string> = {};\n const baseUrls: Record<string, string> = {};\n for (const provider of PROVIDER_PRIORITY) {\n const key = config.getProviderApiKey(provider);\n if (key) apiKeys[provider] = key;\n }\n for (const provider of PROVIDER_PRIORITY) {\n const url = config.getProviderBaseUrl(provider);\n if (!url) continue;\n if (provider === 'openai_compatible') {\n if (config.openaiCompatibleBaseUrl) baseUrls[provider] = url;\n } else if (apiKeys[provider]) {\n baseUrls[provider] = url;\n }\n }\n return { apiKeys, baseUrls };\n}\n\nfunction discoveredToCatalog(m: DiscoveredModel): CatalogModel {\n return {\n id: m.modelId,\n name: m.modelLabel,\n description: '',\n pricing: { prompt: '?', completion: '?' },\n contextLength: 0,\n };\n}\n\nexport async function fetchAllProviderModels(\n opts: FetchAllProviderModelsOptions,\n): Promise<ProviderModelsResult> {\n const entries: [string, () => Promise<CatalogModel[]>][] = [];\n\n for (const provider of PROVIDER_PRIORITY) {\n const meta = getProviderMeta(provider);\n if (!meta || !meta.discoversModels) continue;\n\n if (provider === 'google') {\n if (!opts.apiKeys[provider]) continue;\n entries.push([\n provider,\n async () => {\n const models = await discoverGeminiModels(\n opts.apiKeys[provider],\n opts.baseUrls[provider] || undefined,\n opts.fetchImpl,\n );\n return models.map(discoveredToCatalog);\n },\n ]);\n } else if (provider === 'openrouter') {\n // OpenRouter's catalog is technically public, but the product rule is\n // \"only providers with a key set are shown\", so it needs a key like any\n // other preset.\n if (!opts.apiKeys[provider]) continue;\n entries.push([\n provider,\n async () =>\n ModelCatalog.fetchModels(\n opts.apiKeys[provider],\n opts.baseUrls[provider] || undefined,\n opts.fetchImpl,\n ),\n ]);\n } else {\n const baseUrl = opts.baseUrls[provider];\n const apiKey = opts.apiKeys[provider];\n if (!baseUrl) continue;\n entries.push([\n provider,\n async () =>\n ModelCatalog.fetchModels(\n apiKey ?? '',\n baseUrl,\n opts.fetchImpl,\n ),\n ]);\n }\n }\n\n const results = await Promise.allSettled(entries.map(([, fn]) => fn()));\n const models: AllProviderModels = {};\n const errors: Record<string, string> = {};\n\n for (let i = 0; i < entries.length; i++) {\n const [provider] = entries[i];\n const result = results[i];\n if (result.status === 'fulfilled') {\n models[provider] = result.value;\n } else {\n models[provider] = [];\n const reason = result.reason;\n errors[provider] = reason instanceof Error ? reason.message : String(reason);\n }\n }\n\n return { models, errors };\n}\n\nexport function resolveProvider(\n modelId: string,\n providerModelLists: Record<string, string[]>,\n): AiProvider | null {\n for (const provider of PROVIDER_PRIORITY) {\n const list = providerModelLists[provider];\n if (list && list.includes(modelId)) return provider;\n }\n return null;\n}\n\nfunction perMTok(prompt: string, completion: string): string | undefined {\n const p = parseFloat(prompt);\n const c = parseFloat(completion);\n if (!isFinite(p) || !isFinite(c)) return undefined;\n const fmt = (n: number) => String(+(n * 1_000_000).toFixed(2));\n return `${fmt(p)}/${fmt(c)}`;\n}\n\nexport function toOrchestratorOptions(\n providerModels: AllProviderModels,\n shortcuts: ModelShortcut[],\n): OrchestratorOption[] {\n const seen = new Set<string>();\n const options: OrchestratorOption[] = [];\n const shortcutById = new Map(shortcuts.map((s) => [s.id, s]));\n\n for (const provider of PROVIDER_PRIORITY) {\n const models = providerModels[provider];\n if (!models || models.length === 0) continue;\n\n for (const m of models) {\n const id = prefixModelId(provider, m.id);\n if (seen.has(id)) continue;\n seen.add(id);\n\n const s = shortcutById.get(id);\n let providerLabel: string;\n let pricing: string | undefined;\n\n if (provider === 'openrouter') {\n const rawProvider = extractProvider(m.id);\n providerLabel = s?.provider\n || (rawProvider ? rawProvider.charAt(0).toUpperCase() + rawProvider.slice(1) : 'OpenRouter');\n const livePricing = m.pricing?.prompt && m.pricing?.completion\n ? perMTok(m.pricing.prompt, m.pricing.completion)\n : undefined;\n pricing = livePricing ?? s?.pricing;\n } else {\n const meta = getProviderMeta(provider);\n providerLabel = s?.provider || meta?.shortLabel || provider;\n pricing = s?.pricing;\n }\n\n options.push({\n id,\n label: s?.label || m.name || m.id,\n provider: providerLabel,\n apiProvider: provider,\n description: s?.description || m.description || undefined,\n pricing,\n });\n }\n }\n\n const shortcutOrder = new Map(shortcuts.map((s, i) => [s.id, i]));\n return [\n ...options.filter((o) => shortcutOrder.has(o.id)).sort((a, b) => shortcutOrder.get(a.id)! - shortcutOrder.get(b.id)!),\n ...options.filter((o) => !shortcutOrder.has(o.id)),\n ];\n}\n","import { ModelDiscovery, clearGeminiCache, type ExecImpl } from './ModelDiscovery';\nimport { ModelCatalog } from './ModelCatalog';\nimport type { RunnerRegistry } from '../plugins/RunnerRegistry';\nimport type { IConfig } from '../interfaces/IConfig';\nimport type { DiscoveredModel, RunnerId } from '../models/Task';\nimport { fetchAllProviderModels, collectProviderCredentials, toOrchestratorOptions, type OrchestratorOption, type ProviderModelLists } from './ProviderRouting';\nimport { ORCHESTRATOR_SHORTCUTS } from './ModelShortcuts';\nimport { PROVIDER_PRIORITY } from './ProviderRegistry';\n\nexport interface ModelResolverDeps {\n fetchImpl?: typeof fetch;\n execImpl?: ExecImpl;\n}\n\nexport class ModelResolver {\n private discovery: ModelDiscovery;\n private fetchImpl?: typeof fetch;\n private cachedPickerOptions: OrchestratorOption[] | null = null;\n private lastDiscoveryErrors: Record<string, string> = {};\n\n constructor(\n private registry: RunnerRegistry,\n private config: IConfig,\n deps: ModelResolverDeps = {}\n ) {\n this.discovery = new ModelDiscovery(registry, deps.execImpl, deps.fetchImpl);\n this.fetchImpl = deps.fetchImpl;\n }\n\n static builtinOptions(): OrchestratorOption[] {\n return toOrchestratorOptions({}, ORCHESTRATOR_SHORTCUTS);\n }\n\n async modelsForRunners(runners: RunnerId[]): Promise<Partial<Record<RunnerId, DiscoveredModel[]>>> {\n const out: Partial<Record<RunnerId, DiscoveredModel[]>> = {};\n for (const runner of runners) {\n try {\n out[runner] = await this.discovery.discover(runner);\n } catch {\n out[runner] = [];\n }\n }\n return out;\n }\n\n async pickerOptions(): Promise<OrchestratorOption[]> {\n if (this.cachedPickerOptions) return this.cachedPickerOptions;\n\n // Which endpoints to probe is one policy shared with every other surface —\n // see collectProviderCredentials (only key-configured providers, plus an\n // explicitly-pointed openai_compatible endpoint).\n const { apiKeys, baseUrls } = collectProviderCredentials(this.config);\n\n const { models, errors } = await fetchAllProviderModels({\n apiKeys,\n baseUrls,\n fetchImpl: this.fetchImpl,\n });\n this.lastDiscoveryErrors = errors;\n this.cachedPickerOptions = toOrchestratorOptions(models, ORCHESTRATOR_SHORTCUTS);\n return this.cachedPickerOptions;\n }\n\n /**\n * Per-provider failures from the most recent `pickerOptions()` fetch, keyed\n * by provider id. Empty when every configured provider's catalog loaded (or\n * before the first fetch). Surfaces consume this to flag a provider whose\n * key/endpoint is set but whose catalog could not be reached.\n */\n getDiscoveryErrors(): Record<string, string> {\n return this.lastDiscoveryErrors;\n }\n\n async refresh(): Promise<ProviderModelLists> {\n const options = await this.pickerOptions();\n const lists: ProviderModelLists = {};\n for (const provider of PROVIDER_PRIORITY) {\n lists[provider] = options.filter((o) => o.apiProvider === provider).map((o) => o.id);\n }\n this.config.setProviderModelLists(lists);\n return lists;\n }\n\n refreshRunnerModels(): void {\n this.discovery.clear();\n }\n\n invalidate(): void {\n this.discovery.clear();\n this.cachedPickerOptions = null;\n this.lastDiscoveryErrors = {};\n if (!this.fetchImpl) {\n for (const provider of PROVIDER_PRIORITY) {\n const baseUrl = this.config.getProviderBaseUrl(provider);\n if (baseUrl) ModelCatalog.clearCache(baseUrl);\n }\n clearGeminiCache(this.config.geminiKey);\n }\n }\n}\n","import { exec } from 'child_process';\nimport { promisify } from 'util';\nimport type { RunnerRegistry } from '../plugins/RunnerRegistry';\nimport { augmentedPath, withPath } from '../utils/shellPath';\nimport { planDirectLaunch } from '../utils/launch';\nimport type { ExecImpl } from './ModelDiscovery';\n\nconst execAsync = promisify(exec);\n\n// Installation checks must find `claude`/`opencode` wherever the user installed\n// them, even under the minimal PATH a GUI-launched host inherits — same\n// augmented-PATH rationale as ModelDiscovery.\nconst defaultExec: ExecImpl = async (command, options) => {\n const PATH = await augmentedPath();\n const { stdout } = await execAsync(command, { ...options, env: withPath(process.env, PATH) });\n return { stdout: String(stdout) };\n};\n\nconst CHECK_TIMEOUT_MS = 8000;\n\n/**\n * Runners with a harness-planner adapter (ADR-0009). Plugin runners are\n * deliberately absent: a manifest-level planner capability block, so user\n * plugins can declare themselves plannable, is a follow-up.\n */\nconst PLANNER_CAPABLE_RUNNERS = new Set(['claude-code', 'codex', 'opencode']);\n\n/**\n * Detects whether a runner's underlying CLI is actually installed on the host,\n * by invoking `<command> --version`. Mirrors ModelDiscovery: injectable exec,\n * augmented PATH, per-process cache. A runner that isn't installed should never\n * be offered for selection in any surface.\n */\nexport class RunnerInstallation {\n private cache: Map<string, boolean> = new Map();\n private inflight: Map<string, Promise<boolean>> = new Map();\n private registry: RunnerRegistry;\n private execImpl: ExecImpl;\n\n constructor(registry: RunnerRegistry, execImpl: ExecImpl = defaultExec) {\n this.registry = registry;\n this.execImpl = execImpl;\n }\n\n /** True if the runner's CLI responds to `--version`. Cached per process. */\n async isInstalled(runner: string): Promise<boolean> {\n if (this.cache.has(runner)) return this.cache.get(runner)!;\n\n const existing = this.inflight.get(runner);\n if (existing) return existing;\n\n const manifest = this.registry.getManifest(runner);\n const command = manifest?.runner.command;\n if (!command) {\n this.cache.set(runner, false);\n return false;\n }\n\n const probe = (async () => {\n try {\n await this.execImpl(`${command} --version`, { timeout: CHECK_TIMEOUT_MS });\n return true;\n } catch {\n return false;\n }\n })().then((installed) => {\n this.cache.set(runner, installed);\n this.inflight.delete(runner);\n return installed;\n });\n\n this.inflight.set(runner, probe);\n return probe;\n }\n\n /**\n * Whether this runner can serve as a harness planner (ADR-0009, T9), and why\n * not when it cannot. Surfaces call this to grey out an unusable agent in the\n * planner picker with the reason attached — discovering a missing CLI after\n * typing a real goal is the failure this exists to prevent.\n *\n * \"Usable\" is deliberately shallow: the binary answers `--version`, and the\n * runner declares a planner transport. Whether the user's subscription is\n * live cannot be known without spending a turn on it, so an expired login\n * surfaces where it actually bites — as the agent's own error text on the\n * first turn.\n */\n async plannerUsability(runner: string): Promise<{ usable: boolean; reason?: string }> {\n const manifest = this.registry.getManifest(runner);\n if (!manifest) return { usable: false, reason: `No runner manifest is registered for \"${runner}\".` };\n if (!PLANNER_CAPABLE_RUNNERS.has(runner)) {\n return { usable: false, reason: `${manifest.displayName ?? runner} has no planner transport yet.` };\n }\n if (!(await this.isInstalled(runner))) {\n return { usable: false, reason: `${manifest.runner.command} is not installed or is not on PATH.` };\n }\n const spawnable = await this.isSpawnable(manifest.runner.command);\n if (!spawnable) {\n return {\n usable: false,\n reason: `${manifest.runner.command} answers --version through a shell, but no file Ordewell can start directly was found on PATH. ` +\n `The planner speaks to the agent over stdio with no shell in between, so it needs a real executable or a .cmd/.bat shim. ` +\n `Reinstall with the CLI's own installer, or add its install directory to PATH.`,\n };\n }\n return { usable: true };\n }\n\n /**\n * Whether the CLI can be started the way the harness planner actually starts\n * it: `spawn` with no shell.\n *\n * `isInstalled` probes through `exec`, which goes through cmd.exe on Windows\n * and so happily resolves a `.cmd` shim — while the planner's own spawn does\n * not, because CreateProcess performs no PATHEXT lookup. That gap produced\n * the worst failure shape available: the picker reported the runner healthy,\n * then the session died on ENOENT with nothing to act on. POSIX has no such\n * split (`execvp` and `exec` search PATH identically), so this always agrees\n * with `isInstalled` there.\n */\n private async isSpawnable(command: string): Promise<boolean> {\n if (process.platform !== 'win32') return true;\n try {\n const plan = await planDirectLaunch(command, []);\n // An unresolvable command is handed back verbatim; anything else means a\n // real file was found, directly or behind the interpreter.\n return plan.file !== command;\n } catch {\n // A CommandLineTooLongError cannot happen with no arguments; anything\n // else here is a resolution failure, which is the answer.\n return false;\n }\n }\n\n /** Subset of the given runner ids whose CLI is installed. */\n async filterInstalled(runners: string[]): Promise<string[]> {\n const results = await Promise.all(\n runners.map(async (r) => ({ r, ok: await this.isInstalled(r) })),\n );\n return results.filter((x) => x.ok).map((x) => x.r);\n }\n\n clear(): void {\n this.cache.clear();\n this.inflight.clear();\n }\n}\n","import { spawn as nodeSpawn } from 'child_process';\nimport {\n type Task,\n type DiscoveredModel,\n type ResearchLogEntry,\n type ResearchProgress,\n type ResearchStep,\n type RunnerId,\n type LegacyPlanState,\n} from '../../models/Task';\nimport type { IConfig } from '../../interfaces/IConfig';\nimport type { IFileSystem } from '../../interfaces/IFileSystem';\nimport type { IWebFetcher } from '../../interfaces/IWebFetcher';\nimport type { RunnerModeInfo } from '../ModeResolver';\nimport type { IAiService, ConversationRequest, ConversationTurn } from '../AiService';\nimport {\n buildConversationSystemPrompt,\n buildPlanWithResults,\n buildModifyPlanPrompt,\n} from '../PlanPrompts';\nimport {\n classifyPlannerReply,\n generatePlanWithRepair,\n reEmitPlanPrompt,\n reEmitTaskOpsPrompt,\n} from '../PlanRepair';\nimport { extractPrdBlock } from '../../utils/prdStore';\nimport { runnerForProvider } from '../ProviderRegistry';\nimport { collectResearchContext } from '../ContextCollector';\nimport type { AgentAdapter, AgentEvent, AgentProcessDeps, AgentStartOptions } from './AgentAdapter';\nimport { ClaudeCodeAdapter } from './ClaudeCodeAdapter';\nimport { CodexAdapter } from './CodexAdapter';\nimport { OpenCodeAdapter } from './OpenCodeAdapter';\nimport { mapAgentTool, normalizeAgentArgs } from './agentTools';\nimport { DEFAULT_PLANNER_MODES, type PlannerModes } from '../plannerModes';\n\n/** Corrective re-emits allowed for botched JSON, matching the API backend. */\nconst MAX_JSON_REPAIRS = 2;\n\n/** Kept out of the reply text and the log; a long trace would drown both. */\nconst LOG_MAX_CHARS = 10000;\n\nexport interface CliAgentAiServiceDeps extends Partial<AgentProcessDeps> {\n /** Overrides adapter construction. Tests supply a fake agent; production picks by runner id. */\n createAdapter?: (runner: string, deps: AgentProcessDeps) => AgentAdapter | null;\n /** Workspace root the agent explores. Defaults to the host process's cwd. */\n workspaceRoot?: () => string;\n}\n\nfunction defaultAdapter(runner: string, deps: AgentProcessDeps): AgentAdapter | null {\n switch (runner) {\n case 'claude-code': return new ClaudeCodeAdapter(deps);\n case 'codex': return new CodexAdapter(deps);\n case 'opencode': return new OpenCodeAdapter(deps);\n default: return null;\n }\n}\n\n/** One completed harness turn, before classification. */\ninterface HarnessTurn {\n text: string;\n researchLog: ResearchStep[];\n /** The agent's own failure, verbatim. Present means the turn did not complete. */\n error?: string;\n aborted?: boolean;\n}\n\n/**\n * A coding agent driven as Ordewell's planner (ADR-0009).\n *\n * The second transport behind `IAiService`, sitting beside `OpenAiService` and\n * `GeminiService`. It deliberately does **not** extend {@link BaseAiService}:\n * that class's body is Ordewell executing research tools on a model's behalf,\n * which is precisely the part a coding agent replaces. What it reuses instead\n * is everything above the transport — `classifyPlannerReply`, the bounded\n * corrective re-emit loop, `parsePlanJson`, the `ResearchProgress` events the\n * four surfaces already render. That is why this backend reaches VS Code, the\n * web UI, the CLI and the TUI without any of them learning a coding agent is\n * on the other end.\n */\nexport class CliAgentAiService implements IAiService {\n private readonly runner: string;\n private readonly processDeps: AgentProcessDeps;\n private readonly makeAdapter: (runner: string, deps: AgentProcessDeps) => AgentAdapter | null;\n private readonly workspaceRoot: () => string;\n\n private adapter: AgentAdapter | null = null;\n /**\n * The agent's own session id, kept across a process death so the next turn\n * can resume warm context instead of re-reading the repository. Cleared at\n * every session boundary — nothing from one goal may reach the next.\n */\n private lastNativeSessionId: string | null = null;\n private conversation: { startOptions: AgentStartOptions; runners: RunnerId[]; runnerModes?: Record<RunnerId, RunnerModeInfo[]>; autonomousDefault?: boolean; prdEnabled: boolean; prdCaptured: boolean; prdNudgeSent: boolean } | null = null;\n private activeAbort: AbortController | null = null;\n\n constructor(private config: IConfig, deps: CliAgentAiServiceDeps = {}) {\n const runner = runnerForProvider(config.aiProvider);\n if (!runner) throw new Error(`${config.aiProvider} is not a coding-agent planner.`);\n this.runner = runner;\n this.processDeps = {\n spawn: deps.spawn ?? nodeSpawn,\n fetch: deps.fetch ?? globalThis.fetch,\n resolvePath: deps.resolvePath,\n platform: deps.platform,\n };\n this.makeAdapter = deps.createAdapter ?? defaultAdapter;\n this.workspaceRoot = deps.workspaceRoot ?? (() => process.cwd());\n }\n\n hasActiveConversation(): boolean { return this.conversation !== null; }\n\n /**\n * False when the running agent process was spawned under a model/effort the\n * user has since changed in the picker. Unlike a vendor backend, the model\n * is a spawn-time argument to the agent CLI (`--model`), not a per-request\n * field — `continueConversation` sends the next turn to whatever process is\n * already running, so a plain config read here would silently keep planning\n * on the old model. No conversation yet is vacuously \"current\".\n */\n conversationMatchesConfig(): boolean {\n if (!this.conversation) return true;\n return this.conversation.startOptions.model === this.plannerModel()\n && this.conversation.startOptions.effort === this.config.plannerThinkingEffort;\n }\n\n /** The agent's own session id, a resumption hint only — Ordewell's transcript is authoritative (T4). */\n nativeSessionId(): string | null { return this.adapter?.nativeSessionId() ?? null; }\n\n reset(): void {\n this.activeAbort?.abort();\n this.activeAbort = null;\n this.adapter?.dispose();\n this.adapter = null;\n // Session boundaries are hard (ADR-0008): the next goal must not resume\n // the previous goal's agent session.\n this.lastNativeSessionId = null;\n this.conversation = null;\n }\n\n // --- Conversation (ADR-0002) ---\n\n async startConversation(req: ConversationRequest): Promise<ConversationTurn> {\n this.reset();\n\n const contextStr = await collectResearchContext(req.fs, req.runners);\n const systemPrompt = buildConversationSystemPrompt(\n req.goal,\n contextStr,\n req.modelsByRunner,\n req.runners,\n req.runnerModes,\n req.autonomousDefault ?? true,\n req.grillMeEnabled ?? false,\n req.prdEnabled ?? false,\n req.reviewEnabled ?? false,\n req.verificationEnabled ?? false,\n true,\n );\n\n const startOptions: AgentStartOptions = {\n cwd: this.workspaceRoot(),\n systemPrompt,\n model: this.plannerModel(),\n effort: this.config.plannerThinkingEffort,\n };\n\n await this.startAdapter(startOptions);\n\n this.conversation = {\n startOptions,\n runners: req.runners,\n runnerModes: req.runnerModes,\n autonomousDefault: req.autonomousDefault,\n prdEnabled: req.prdEnabled ?? false,\n prdCaptured: false,\n prdNudgeSent: false,\n };\n\n // A reloaded session replays its transcript instead of re-running the\n // research the agent already paid for. The agent gets it as context, not\n // as turns: the reply we act on is the one the user's new message opens.\n const opening = this.openingMessage(req);\n return this.runConversation(opening, req.onProgress, req.signal);\n }\n\n async continueConversation(\n userMessage: string,\n onProgress: (progress: ResearchProgress) => void,\n signal?: AbortSignal,\n ): Promise<ConversationTurn> {\n if (!this.conversation) throw new Error('No active planner conversation. Start planning first.');\n return this.runConversation(userMessage, onProgress, signal);\n }\n\n private openingMessage(req: ConversationRequest): string {\n const history = req.priorHistory ?? [];\n if (history.length === 0) return req.initialMessage ?? req.goal;\n const transcript = history\n .map((m) => `${m.role === 'user' ? 'User' : 'You'}: ${m.content}`)\n .join('\\n\\n');\n return [\n 'This planning conversation is being resumed. Here is what has been said so far:',\n '',\n '<previous_conversation>',\n transcript,\n '</previous_conversation>',\n '',\n 'Continue from there. The user now says:',\n '',\n req.initialMessage ?? req.goal,\n ].join('\\n');\n }\n\n /**\n * Drive one user message to a settled planner turn. Same shape as the API\n * backend's conversation loop minus the tool rounds — those belong to the\n * agent now — and with the same three policies layered on top: the PRD gate,\n * the empty-reply nudge, and a bounded corrective re-emit for botched JSON.\n */\n private async runConversation(\n message: string,\n onProgress: (progress: ResearchProgress) => void,\n signal?: AbortSignal,\n ): Promise<ConversationTurn> {\n const conversation = this.conversation!;\n const combined = this.startAbortScope(signal);\n const researchLog: ResearchLogEntry[] = [];\n let pending = message;\n let emptyNudgeSent = false;\n let jsonRepairAttempts = 0;\n\n try {\n for (;;) {\n const turn = await this.runTurn(pending, onProgress, combined);\n researchLog.push(...turn.researchLog);\n\n if (turn.aborted || combined?.aborted) {\n onProgress({ type: 'interrupted' });\n return { kind: 'message', text: turn.text, researchLog };\n }\n\n // Fail visibly, per the repo's fail-safe contract: an agent that died,\n // hit its rate limit, or lost its login must say so in the chat rather\n // than leave an empty planner bubble.\n if (turn.error) {\n return { kind: 'message', text: turn.error, researchLog };\n }\n\n if (!turn.text.trim()) {\n // An agent whose tool was refused can end its turn on the refusal,\n // saying nothing. Naming it keeps the failure visible instead of\n // reporting a blank reply the user cannot act on.\n const refused = turn.researchLog.find((step) => step.outcome === 'denied');\n if (!emptyNudgeSent) {\n emptyNudgeSent = true;\n pending = refused\n ? `Your last reply was empty because \"${refused.toolLabel ?? refused.tool}\" was refused: you are planning read-only and confined to this workspace. Do not retry it. Answer the user now with what you already know, or ask your next question.`\n : 'Your last reply was empty. Respond to the user now: answer their last message directly, ask your next question, or emit the plan JSON.';\n continue;\n }\n return {\n kind: 'message',\n text: refused\n ? `The planner stopped without replying: \"${refused.toolLabel ?? refused.tool}\" was refused because planning is read-only and confined to this workspace.`\n : 'The planner returned an empty reply twice. Please rephrase or try again.',\n researchLog,\n };\n }\n\n if (extractPrdBlock(turn.text)) conversation.prdCaptured = true;\n\n const reply = classifyPlannerReply(turn.text, {\n runners: conversation.runners,\n runnerModes: conversation.runnerModes,\n autonomousDefault: conversation.autonomousDefault,\n });\n\n switch (reply.kind) {\n case 'task_ops':\n return { kind: 'task_ops', ops: reply.ops, text: turn.text, researchLog };\n\n case 'plan':\n if (conversation.prdEnabled && !conversation.prdCaptured && !conversation.prdNudgeSent && !combined?.aborted) {\n conversation.prdNudgeSent = true;\n pending = [\n 'PRD mode is enabled but no PRD has been produced yet, so the plan was NOT committed.',\n 'In your next reply: first output the full markdown PRD wrapped EXACTLY in',\n '<!-- ORDEWELL_PRD_START slug=\"<feature-slug>\" --> and <!-- ORDEWELL_PRD_END -->,',\n 'then re-emit the exact same task plan JSON after the PRD block.',\n ].join(' ');\n continue;\n }\n // A committed plan closes the conversation, matching the API\n // backend: post-plan chat re-enters through `startConversation`\n // with the plan's own transcript rather than inheriting this\n // session's context.\n this.conversation = null;\n return { kind: 'plan', tasks: reply.tasks, text: turn.text, researchLog };\n\n case 'broken_task_ops':\n if (jsonRepairAttempts < MAX_JSON_REPAIRS && !combined?.aborted) {\n jsonRepairAttempts++;\n pending = reEmitTaskOpsPrompt(reply.error.message);\n continue;\n }\n break;\n\n case 'broken_plan':\n if (jsonRepairAttempts < MAX_JSON_REPAIRS && !combined?.aborted) {\n jsonRepairAttempts++;\n pending = reEmitPlanPrompt(reply.error.message);\n continue;\n }\n break;\n\n case 'prose':\n break;\n }\n\n return { kind: 'message', text: turn.text, researchLog };\n }\n } finally {\n this.activeAbort = null;\n }\n }\n\n /**\n * Run one agent turn: stream its events into `ResearchProgress`, collect the\n * reply text, and return the research steps produced. Tool calls are matched\n * to their results by the agent's own call id — matching by tool name puts\n * one file's body on another file's row the moment an agent runs two reads\n * at once, which all three of these do routinely.\n */\n private async runTurn(\n message: string,\n onProgress: (progress: ResearchProgress) => void,\n signal?: AbortSignal,\n ): Promise<HarnessTurn> {\n const adapter = await this.ensureAdapter();\n const pendingCalls = new Map<string, { tool: ResearchStep['tool']; toolLabel?: string; args: string }>();\n const researchLog: ResearchStep[] = [];\n let text = '';\n let error: string | undefined;\n let stepIndex = 0;\n\n const truncate = (value: string) =>\n value.length > LOG_MAX_CHARS ? `${value.slice(0, LOG_MAX_CHARS)}\\n[... truncated, total ${value.length} chars]` : value;\n\n const settle = (id: string, output: string, success: boolean, outcome: ResearchStep['outcome']) => {\n const call = pendingCalls.get(id);\n pendingCalls.delete(id);\n const step: ResearchStep = {\n id: `rs-${Date.now()}-${stepIndex++}`,\n tool: call?.tool ?? 'agent_tool',\n toolLabel: call?.toolLabel,\n args: call?.args ?? '{}',\n result: truncate(output),\n success,\n outcome,\n toolCallId: id,\n timestamp: new Date().toISOString(),\n };\n researchLog.push(step);\n onProgress({ type: 'tool_result', toolResult: output, step, toolCallId: id });\n };\n\n await adapter.send(message, (event: AgentEvent) => {\n switch (event.type) {\n case 'assistant_text':\n text += event.text;\n onProgress({ type: 'plan_token', planToken: event.text });\n return;\n\n case 'thinking':\n onProgress({ type: 'thinking', text: event.text });\n return;\n\n case 'tool_call': {\n const mapped = mapAgentTool(event.name);\n const args = JSON.stringify(normalizeAgentArgs(mapped.tool, event.args));\n pendingCalls.set(event.id, { tool: mapped.tool, toolLabel: mapped.toolLabel, args });\n onProgress({ type: 'tool_call', tool: mapped.tool, toolLabel: mapped.toolLabel, toolArgs: args, toolCallId: event.id });\n return;\n }\n\n case 'tool_result':\n settle(event.id, event.output, event.success, event.success ? 'success' : 'failure');\n return;\n\n case 'permission_request': {\n // Auto-denied, always (T1). The request is still announced so the\n // user can see the planner reached for something it may not have —\n // a silently swallowed denial reads as the agent losing interest.\n const mapped = mapAgentTool(event.name);\n const args = JSON.stringify({ detail: event.detail });\n if (!pendingCalls.has(event.id)) {\n pendingCalls.set(event.id, { tool: mapped.tool, toolLabel: mapped.toolLabel, args });\n onProgress({ type: 'tool_call', tool: mapped.tool, toolLabel: mapped.toolLabel, toolArgs: args, toolCallId: event.id });\n }\n settle(\n event.id,\n `Access denied: the planner runs read-only, so \"${event.name}\" was refused. Mutation belongs to the runners that execute the plan.`,\n false,\n 'denied',\n );\n return;\n }\n\n case 'error':\n error = event.message;\n return;\n\n case 'turn_end':\n return;\n }\n }, signal);\n\n // Anything still pending when the turn ended never produced a result —\n // report it rather than leaving a spinner running in every surface.\n for (const id of [...pendingCalls.keys()]) {\n settle(id, 'The agent ended the turn without reporting this call\\'s result.', false, 'not_executed');\n }\n\n this.lastNativeSessionId = adapter.nativeSessionId() ?? this.lastNativeSessionId;\n // A failed turn usually means the process is gone, and an aborted one kills\n // the process by contract. Either way the adapter cannot be sent to again —\n // `dispose()` is terminal — so drop it and let the next turn restart from\n // the session id rather than throwing into a dead stdin.\n if (error || signal?.aborted) { adapter.dispose(); this.adapter = null; }\n\n return { text, researchLog, error, aborted: signal?.aborted };\n }\n\n // --- Process lifecycle ---\n\n private async startAdapter(opts: AgentStartOptions): Promise<AgentAdapter> {\n const adapter = this.makeAdapter(this.runner, this.processDeps);\n if (!adapter) throw new Error(`No planner adapter is available for \"${this.runner}\".`);\n await adapter.start(opts);\n this.adapter = adapter;\n return adapter;\n }\n\n /**\n * The live agent process, restarted from its own session id if it died\n * between turns. Resume is a hint: when it fails, the caller's next\n * `startConversation` reseeds from Ordewell's transcript, which is the same\n * degradation `restoreChat` already performs on every surface.\n */\n private async ensureAdapter(): Promise<AgentAdapter> {\n if (this.adapter) return this.adapter;\n const conversation = this.conversation;\n if (!conversation) throw new Error('No active planner conversation.');\n await this.startAdapter({ ...conversation.startOptions, resumeSessionId: this.lastNativeSessionId ?? undefined });\n return this.adapter!;\n }\n\n private startAbortScope(callerSignal?: AbortSignal): AbortSignal | undefined {\n this.activeAbort = new AbortController();\n if (!callerSignal) return this.activeAbort.signal;\n if (callerSignal.aborted) { this.activeAbort.abort(); return this.activeAbort.signal; }\n callerSignal.addEventListener('abort', () => this.activeAbort?.abort(), { once: true });\n return this.activeAbort.signal;\n }\n\n private plannerModel(): string | undefined {\n const id = (this.config.orchestratorModel ?? '').trim();\n return id || undefined;\n }\n\n // --- One-shot paths (CLI `plan --goal`, web REST, plan modification) ---\n\n /**\n * A single agent session that answers one prompt and exits. Used by every\n * non-conversational entry point; the plan is parsed from the reply text by\n * the same extractor the conversational path uses.\n */\n private async oneShot(prompt: string, onProgress?: (p: ResearchProgress) => void, signal?: AbortSignal): Promise<{ text: string; researchLog: ResearchLogEntry[] }> {\n const previous = this.adapter;\n const previousConversation = this.conversation;\n const previousSessionId = this.lastNativeSessionId;\n this.adapter = null;\n\n const startOptions: AgentStartOptions = {\n cwd: this.workspaceRoot(),\n systemPrompt: prompt,\n model: this.plannerModel(),\n effort: this.config.plannerThinkingEffort,\n };\n let oneShotAdapter: AgentAdapter | null = null;\n try {\n oneShotAdapter = await this.startAdapter(startOptions);\n this.conversation = {\n startOptions,\n runners: [],\n prdEnabled: false,\n prdCaptured: false,\n prdNudgeSent: false,\n };\n const turn = await this.runTurn(\n 'Follow the instructions in your system prompt and produce the plan now.',\n onProgress ?? (() => {}),\n signal,\n );\n if (turn.error) throw new Error(turn.error);\n return { text: turn.text, researchLog: turn.researchLog };\n } finally {\n // A one-shot never leaves a process behind, and never disturbs a\n // conversational session that happened to be open around it — including\n // when its own agent failed to start, which happens before there is\n // anything to dispose.\n oneShotAdapter?.dispose();\n this.adapter = previous;\n this.conversation = previousConversation;\n // The one-shot's own agent session must not become the conversation's\n // resume hint: restarting the chat into a plan-generation session would\n // cross two sessions that never shared a goal.\n this.lastNativeSessionId = previousSessionId;\n }\n }\n\n async researchAndPlan(\n userDescription: string,\n runners: RunnerId[],\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n fs: IFileSystem,\n onProgress: (progress: ResearchProgress) => void,\n _fetcher?: IWebFetcher,\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n modes: PlannerModes = DEFAULT_PLANNER_MODES,\n signal?: AbortSignal,\n ): Promise<{ tasks: Task[]; researchLog: ResearchLogEntry[]; researchResults: string }> {\n const contextStr = await collectResearchContext(fs, runners);\n const researchLog: ResearchLogEntry[] = [\n { id: `up-${Date.now()}`, type: 'user_prompt', content: userDescription, timestamp: new Date().toISOString() },\n ];\n let lastText = '';\n const tasks = await generatePlanWithRepair(\n async (repairHint) => {\n const prompt = buildPlanWithResults(userDescription, contextStr, '', modelsByRunner, runners, runnerModes, modes);\n const result = await this.oneShot(repairHint ? `${prompt}\\n\\n${repairHint}` : prompt, onProgress, signal);\n researchLog.push(...result.researchLog);\n lastText = result.text;\n return result.text;\n },\n runners, 2, runnerModes, modes.autonomousDefault,\n );\n return { tasks, researchLog, researchResults: lastText };\n }\n\n async generatePlanDirect(\n userDescription: string,\n runners: RunnerId[] = ['claude-code'],\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>> = {},\n onToken?: (token: string) => void,\n _fs?: IFileSystem,\n _fetcher?: IWebFetcher,\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n modes: PlannerModes = DEFAULT_PLANNER_MODES,\n signal?: AbortSignal,\n ): Promise<Task[]> {\n const prompt = buildPlanWithResults(userDescription, '', '', modelsByRunner, runners, runnerModes, modes);\n return generatePlanWithRepair(\n async (repairHint) => {\n const result = await this.oneShot(\n repairHint ? `${prompt}\\n\\n${repairHint}` : prompt,\n (p) => { if (p.type === 'plan_token' && p.planToken) onToken?.(p.planToken); },\n signal,\n );\n return result.text;\n },\n runners, 2, runnerModes, modes.autonomousDefault,\n );\n }\n\n async modifyPlan(\n existingPlan: LegacyPlanState,\n userRequest: string,\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n onProgress?: (progress: ResearchProgress) => void,\n _fs?: IFileSystem,\n _fetcher?: IWebFetcher,\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n modes: PlannerModes = DEFAULT_PLANNER_MODES,\n signal?: AbortSignal,\n ): Promise<{ tasks: Task[] }> {\n const prompt = buildModifyPlanPrompt(existingPlan, userRequest, modelsByRunner, undefined, runnerModes, modes.autonomousDefault);\n try {\n const tasks = await generatePlanWithRepair(\n async (repairHint) => {\n const result = await this.oneShot(repairHint ? `${prompt}\\n\\n${repairHint}` : prompt, onProgress, signal);\n return result.text;\n },\n existingPlan.runners, 2, runnerModes, modes.autonomousDefault,\n );\n return { tasks };\n } catch (err) {\n throw new Error(`Plan modification failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n async sendPlanningPrompt(\n prompt: string,\n runners: RunnerId[],\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n autonomousDefault = true,\n ): Promise<Task[]> {\n return generatePlanWithRepair(\n async (repairHint) => {\n const result = await this.oneShot(repairHint ? `${prompt}\\n\\n${repairHint}` : prompt);\n return result.text;\n },\n runners, 2, runnerModes, autonomousDefault,\n );\n }\n}\n","import type { SpawnFn } from '../HeadlessRunner';\n\n\n/**\n * The harness-planner transport contract (ADR-0009).\n *\n * One adapter per coding agent, each speaking that agent's own programmatic\n * protocol and normalizing it to the event union below. Everything above this\n * line — reply classification, the repair loop, plan validation, the four\n * surfaces — is already provider-agnostic, so an adapter is the entire cost of\n * teaching Ordewell to plan with another agent.\n */\n\n/**\n * One normalized event from a running agent turn. Deliberately smaller than\n * any single agent's native protocol: this is the intersection Ordewell can act\n * on, not a lossless re-encoding. Event fidelity differs by agent — `thinking`\n * is rich on Claude Code and absent elsewhere — so consumers must tolerate a\n * turn that emits nothing but `assistant_text` and `turn_end`.\n */\nexport type AgentEvent =\n /** A chunk of the assistant's reply. Concatenated in order to form the turn's text. */\n | { type: 'assistant_text'; text: string }\n /** Reasoning the agent chose to expose. Never contributes to the reply text. */\n | { type: 'thinking'; text: string }\n | { type: 'tool_call'; id: string; name: string; args: Record<string, unknown> }\n | { type: 'tool_result'; id: string; name: string; output: string; success: boolean }\n /**\n * The agent asked to do something its read-only mode does not cover. Always\n * auto-denied (T1) — a planner that can mutate is not a planner. The adapter\n * is responsible for answering the agent so the turn does not hang.\n */\n | { type: 'permission_request'; id: string; name: string; detail: string }\n /** The agent finished its turn and is waiting for the next user message. */\n | { type: 'turn_end' }\n /** The turn failed. Carries the agent's own words — never a Ordewell paraphrase. */\n | { type: 'error'; message: string };\n\nexport interface AgentStartOptions {\n /** Workspace root. The agent explores from here and, in read-only mode, cannot leave it. */\n cwd: string;\n /** The planner system prompt, in its harness variant. */\n systemPrompt: string;\n /** Model id from the runner's own discovery catalog. Omitted means the agent's default. */\n model?: string;\n /** Variant / reasoning effort id from that model's `variants` list. */\n effort?: string;\n /**\n * The agent's own session id from a previous run. A hint only: Ordewell's\n * transcript is the source of truth (T4), so a failed resume degrades to a\n * fresh session seeded from the stored history rather than an error.\n */\n resumeSessionId?: string;\n}\n\nexport interface AgentAdapter {\n /** The runner id this adapter drives — `claude-code`, `codex`, `opencode`. */\n readonly agentId: string;\n\n /** Spawn the agent in its read-only mode and get it ready to receive messages. */\n start(opts: AgentStartOptions): Promise<void>;\n\n /**\n * Send one user message and stream the turn's events until it ends. Resolves\n * when the agent yields the floor; rejects only when the transport itself\n * failed in a way no `error` event could describe.\n */\n send(message: string, onEvent: (event: AgentEvent) => void, signal?: AbortSignal): Promise<void>;\n\n /** The agent's native session id once it has announced one. Resumption hint only. */\n nativeSessionId(): string | null;\n\n /** Kill the process and release its resources. Idempotent. */\n dispose(): void;\n}\n\n/**\n * The single injected boundary between Ordewell and the operating system —\n * the same pattern `HeadlessRunnerDeps` uses for task execution. Tests feed\n * recorded agent output through `spawn` (and, for HTTP-transport agents,\n * `fetch`) so one test exercises adapter parsing, event mapping, reply\n * classification and the repair loop as a single observable behavior.\n */\nexport interface AgentProcessDeps {\n spawn: SpawnFn;\n fetch: typeof globalThis.fetch;\n /** Resolves the PATH agents are spawned under. Defaults to the augmented PATH. */\n resolvePath?: () => Promise<string>;\n /** Host platform. Defaults to the real one; injected so OS-specific behavior is testable anywhere. */\n platform?: NodeJS.Platform;\n}\n\n/** Builds the adapter for one runner id, or null when that runner cannot plan. */\nexport type AgentAdapterFactory = (runner: string, deps: AgentProcessDeps) => AgentAdapter | null;\n\n/**\n * Split a stream of chunks into complete lines. Every agent transport here is\n * newline-delimited JSON of some shape, and a chunk boundary lands mid-object\n * often enough that parsing per-chunk silently drops events.\n */\nexport class LineBuffer {\n private buffer = '';\n\n push(chunk: string, onLine: (line: string) => void): void {\n this.buffer += chunk;\n let newline: number;\n while ((newline = this.buffer.indexOf('\\n')) >= 0) {\n const line = this.buffer.slice(0, newline).trim();\n this.buffer = this.buffer.slice(newline + 1);\n if (line) onLine(line);\n }\n }\n\n /** Anything left unterminated when the stream closed. */\n flush(): string {\n const rest = this.buffer.trim();\n this.buffer = '';\n return rest;\n }\n}\n","import type { ChildProcess } from 'child_process';\nimport { augmentedPath, withPath } from '../../utils/shellPath';\nimport { planDirectLaunch } from '../../utils/launch';\nimport { killTree } from '../../utils/processTree';\nimport { LineBuffer, type AgentAdapter, type AgentEvent, type AgentProcessDeps, type AgentStartOptions } from './AgentAdapter';\n\n/** Stderr kept for the failure message; a dying CLI's last words are the only useful diagnostic. */\nconst STDERR_TAIL_CHARS = 4000;\n/** An idle agent that chatters must not grow the between-turn buffer without bound. */\nconst BETWEEN_TURN_EVENT_CAP = 50;\n\n/**\n * Event kinds never carried across a turn boundary. Reply text belongs to the\n * turn that produced it, and the two terminal kinds would settle the *next*\n * turn the moment it opened — a trailing `turn/completed` after a fatal error\n * would leave the following message answered by nothing at all.\n */\nconst TURN_SCOPED_EVENTS = new Set(['assistant_text', 'turn_end', 'error']);\n\nexport interface SpawnSpec {\n command: string;\n args: string[];\n env?: Record<string, string>;\n}\n\n/**\n * Shared plumbing for the agents that speak newline-delimited JSON over stdio.\n *\n * One long-lived process per planner session (ADR-0009, T3): spawned at\n * `start`, fed one message per turn, disposed at the session boundary. The\n * alternative — respawning per turn — pays a cold start on every message\n * *including each corrective re-emit*, and re-reads the repository from\n * scratch when it cannot resume.\n *\n * Subclasses own their agent's protocol: what to spawn, how to phrase a user\n * turn, and how to read one protocol line. Everything below — line framing,\n * turn lifecycle, abort, stderr capture, premature-exit detection — is the\n * same for all of them.\n */\nexport abstract class StdioAgentAdapter implements AgentAdapter {\n abstract readonly agentId: string;\n\n protected process: ChildProcess | null = null;\n protected sessionId: string | null = null;\n private readonly stdout = new LineBuffer();\n private stderrTail = '';\n private exited: { code: number | null; signal: string | null } | null = null;\n /** Set for the duration of a turn. Outside one, events are buffered rather than dropped. */\n private turnEmit: ((event: AgentEvent) => void) | null = null;\n /**\n * Events the agent produced between turns — in practice the startup warnings\n * that arrive during the handshake. Dropping them hid the one diagnostic\n * that explains a planner which cannot read the workspace, so they are held\n * until a turn exists to show them in.\n */\n private betweenTurns: AgentEvent[] = [];\n private disposed = false;\n /** Resolves when the process ends, so a handshake can lose the race instead of waiting out its timeout. */\n protected processEnded!: Promise<void>;\n /** The environment the agent was spawned under, for any side process a handshake needs. */\n protected spawnEnv: NodeJS.ProcessEnv = {};\n private markEnded: (() => void) | null = null;\n\n constructor(protected deps: AgentProcessDeps) {}\n\n /** The command line that starts this agent in its read-only mode. */\n protected abstract spawnSpec(opts: AgentStartOptions): SpawnSpec;\n\n /** The bytes written to stdin to open one user turn. Must end with a newline. */\n protected abstract turnPayload(message: string): string;\n\n /**\n * Interpret one line of the agent's protocol, emitting normalized events.\n * Emitting `turn_end` ends the turn; emitting `error` ends it as a failure.\n */\n protected abstract handleLine(line: string, emit: (event: AgentEvent) => void): void;\n\n /** Protocol handshake, if the agent needs one before it accepts a turn. */\n protected async handshake(_opts: AgentStartOptions): Promise<void> {}\n\n async start(opts: AgentStartOptions): Promise<void> {\n this.processEnded = new Promise<void>((resolve) => { this.markEnded = resolve; });\n const spec = this.spawnSpec(opts);\n const resolvePath = this.deps.resolvePath ?? augmentedPath;\n // Same PATH treatment as model discovery and the headless runner: the\n // agent binary must resolve wherever the user installed it, even under the\n // minimal PATH a GUI-launched host inherits.\n const PATH = await resolvePath();\n\n this.spawnEnv = withPath(process.env, PATH, spec.env);\n // On POSIX this hands back `spec` untouched; on Windows it resolves the\n // agent's `.exe` (or routes its `.cmd` shim through cmd.exe), because\n // CreateProcess performs no PATHEXT lookup of its own.\n const launch = await planDirectLaunch(spec.command, spec.args, {\n platform: this.deps.platform,\n resolvePath,\n });\n this.process = this.deps.spawn(launch.file, launch.args, {\n env: this.spawnEnv,\n stdio: ['pipe', 'pipe', 'pipe'],\n cwd: opts.cwd,\n windowsVerbatimArguments: launch.verbatim,\n });\n\n // Every protocol line goes to `handleLine`, turn or no turn: an agent's\n // handshake and its session-id announcement both arrive before the first\n // message is sent, and dropping them left the handshake waiting on a reply\n // that had already come and gone.\n this.process.stdout?.on('data', (chunk: Buffer) => {\n this.stdout.push(chunk.toString(), (line) => this.handleLine(line, (event) => {\n if (this.turnEmit) this.turnEmit(event);\n else if (!TURN_SCOPED_EVENTS.has(event.type) && this.betweenTurns.length < BETWEEN_TURN_EVENT_CAP) {\n this.betweenTurns.push(event);\n }\n }));\n });\n this.process.stderr?.on('data', (chunk: Buffer) => {\n this.stderrTail = (this.stderrTail + chunk.toString()).slice(-STDERR_TAIL_CHARS);\n });\n this.process.on('exit', (code, signal) => { this.exited = { code, signal }; this.markEnded?.(); });\n this.process.on('error', (err) => {\n this.stderrTail = (this.stderrTail + `\\n${err.message}`).slice(-STDERR_TAIL_CHARS);\n this.exited = { code: -1, signal: null };\n this.markEnded?.();\n });\n\n await this.handshake(opts);\n }\n\n async send(message: string, onEvent: (event: AgentEvent) => void, signal?: AbortSignal): Promise<void> {\n if (!this.process) throw new Error(`${this.agentId} planner session is not started`);\n if (this.exited) {\n onEvent({ type: 'error', message: this.exitMessage() });\n return;\n }\n\n await new Promise<void>((resolve) => {\n let settled = false;\n const finish = () => {\n if (settled) return;\n settled = true;\n this.turnEmit = null;\n signal?.removeEventListener('abort', onAbort);\n this.process?.removeListener('exit', onExit);\n this.process?.removeListener('error', onExit);\n resolve();\n };\n\n const emit = (event: AgentEvent) => {\n onEvent(event);\n if (event.type === 'turn_end' || event.type === 'error') finish();\n };\n\n // A process that dies mid-turn must surface its stderr, not hang the\n // planner behind a `turn_end` that will never come.\n const onExit = () => {\n if (settled) return;\n onEvent({ type: 'error', message: this.exitMessage() });\n finish();\n };\n const onAbort = () => {\n if (settled) return;\n // Stop means stop: the agent is holding real context we are abandoning,\n // so the process goes with the turn rather than being left running.\n this.dispose();\n finish();\n };\n\n this.turnEmit = emit;\n this.process!.once('exit', onExit);\n this.process!.once('error', onExit);\n if (signal?.aborted) { onAbort(); return; }\n signal?.addEventListener('abort', onAbort, { once: true });\n\n const buffered = this.betweenTurns;\n this.betweenTurns = [];\n for (const event of buffered) {\n emit(event);\n if (settled) return;\n }\n\n try {\n this.process!.stdin!.write(this.turnPayload(message));\n } catch (err) {\n onEvent({ type: 'error', message: `Could not send to ${this.agentId}: ${err instanceof Error ? err.message : String(err)}` });\n finish();\n }\n });\n }\n\n nativeSessionId(): string | null { return this.sessionId; }\n\n dispose(): void {\n if (this.disposed) return;\n this.disposed = true;\n this.turnEmit = null;\n const proc = this.process;\n this.process = null;\n // Tree-wide, because on Windows the direct child may be the cmd.exe shim\n // rather than the agent. The forced follow-up is scheduled and unref'd, so\n // a disposed planner is never the reason the host refuses to exit.\n killTree(proc, { platform: this.deps.platform });\n }\n\n /** Write one raw protocol line to the agent. */\n protected writeLine(payload: unknown): void {\n this.process?.stdin?.write(`${JSON.stringify(payload)}\\n`);\n }\n\n /** Fail-safe contract: a dead agent reports its own last words, never an empty bubble. */\n protected exitMessage(): string {\n const how = this.exited?.signal\n ? `was killed (${this.exited.signal})`\n : `exited with code ${this.exited?.code ?? 'unknown'}`;\n const tail = this.stderrTail.trim();\n return `The ${this.agentId} planner ${how}.${tail ? `\\n\\n${tail}` : ''}`;\n }\n\n /** Parse a protocol line, ignoring the non-JSON banners some CLIs print. */\n protected static parse<T>(line: string): T | null {\n try {\n const value = JSON.parse(line);\n return typeof value === 'object' && value !== null ? (value as T) : null;\n } catch {\n return null;\n }\n }\n}\n","import type { AgentEvent, AgentStartOptions } from './AgentAdapter';\nimport { StdioAgentAdapter, type SpawnSpec } from './StdioAgentAdapter';\n\n/**\n * Tools a planning Claude Code session may use. `--permission-mode plan`\n * already refuses edits; naming the write tools explicitly means a future\n * permission-mode change cannot quietly hand the planner a `Write` (T1).\n */\nconst DISALLOWED_TOOLS = ['Edit', 'Write', 'MultiEdit', 'NotebookEdit', 'KillShell'];\n\ninterface ClaudeBlock {\n type: string;\n text?: string;\n thinking?: string;\n id?: string;\n name?: string;\n input?: Record<string, unknown>;\n tool_use_id?: string;\n content?: unknown;\n is_error?: boolean;\n}\n\ninterface ClaudeLine {\n type: string;\n subtype?: string;\n session_id?: string;\n result?: string;\n is_error?: boolean;\n request_id?: string;\n request?: { subtype?: string; tool_name?: string; input?: Record<string, unknown> };\n message?: { content?: ClaudeBlock[] | string };\n}\n\n/** Tool results arrive as a string, or as a content-block array. Flatten both. */\nfunction flattenContent(content: unknown): string {\n if (typeof content === 'string') return content;\n if (Array.isArray(content)) {\n return content\n .map((block) => (typeof block === 'string' ? block : typeof (block as ClaudeBlock)?.text === 'string' ? (block as ClaudeBlock).text : ''))\n .filter(Boolean)\n .join('\\n');\n }\n return '';\n}\n\n/**\n * Claude Code as a planner, over its bidirectional streaming-JSON transport\n * (ADR-0009).\n *\n * `-p --input-format stream-json --output-format stream-json` keeps one process\n * alive across turns: user messages go in as JSON lines, and the session's\n * assistant blocks, tool uses, tool results and turn boundaries come back the\n * same way. It is the richest of the three streams — partial messages and\n * separate thinking blocks — which is why this agent went first.\n */\nexport class ClaudeCodeAdapter extends StdioAgentAdapter {\n readonly agentId = 'claude-code';\n\n protected spawnSpec(opts: AgentStartOptions): SpawnSpec {\n const args = [\n '-p',\n '--input-format', 'stream-json',\n '--output-format', 'stream-json',\n // stream-json output is rejected without it.\n '--verbose',\n '--include-partial-messages',\n // The read-only guarantee, enforced at spawn rather than by prompt.\n '--permission-mode', 'plan',\n '--disallowedTools', DISALLOWED_TOOLS.join(','),\n '--append-system-prompt', opts.systemPrompt,\n ];\n if (opts.model) args.push('--model', opts.model);\n // `adaptive` is a thinking *type*, not an effort rung: `--effort adaptive`\n // is warned about and ignored, and adaptive is the default for every model\n // that offers it. Passing nothing is the same run without the warning on\n // stderr.\n if (opts.effort && opts.effort !== 'adaptive') args.push('--effort', opts.effort);\n if (opts.resumeSessionId) args.push('--resume', opts.resumeSessionId);\n return { command: 'claude', args };\n }\n\n protected turnPayload(message: string): string {\n return `${JSON.stringify({\n type: 'user',\n message: { role: 'user', content: [{ type: 'text', text: message }] },\n })}\\n`;\n }\n\n protected handleLine(line: string, emit: (event: AgentEvent) => void): void {\n const msg = StdioAgentAdapter.parse<ClaudeLine>(line);\n if (!msg) return;\n\n if (msg.session_id) this.sessionId = msg.session_id;\n\n switch (msg.type) {\n // The control channel: Claude asks whether a tool may run when its mode\n // cannot decide alone. A read-only planner answers \"deny\", every time —\n // and must answer, because an unacknowledged request stalls the turn.\n case 'control_request': {\n if (msg.request?.subtype !== 'can_use_tool') return;\n this.writeLine({\n type: 'control_response',\n response: {\n subtype: 'success',\n request_id: msg.request_id,\n response: { behavior: 'deny', message: 'The Ordewell planner is read-only. Mutation belongs to the runners that execute the plan.' },\n },\n });\n emit({\n type: 'permission_request',\n id: msg.request_id ?? '',\n name: msg.request?.tool_name ?? 'unknown',\n detail: JSON.stringify(msg.request?.input ?? {}),\n });\n return;\n }\n\n case 'assistant':\n for (const block of Array.isArray(msg.message?.content) ? msg.message!.content as ClaudeBlock[] : []) {\n if (block.type === 'text' && block.text) emit({ type: 'assistant_text', text: block.text });\n else if (block.type === 'thinking' && block.thinking) emit({ type: 'thinking', text: block.thinking });\n else if (block.type === 'tool_use' && block.name) {\n emit({ type: 'tool_call', id: block.id ?? block.name, name: block.name, args: block.input ?? {} });\n }\n }\n return;\n\n case 'user':\n // The transport echoes tool results back as a synthetic user message.\n for (const block of Array.isArray(msg.message?.content) ? msg.message!.content as ClaudeBlock[] : []) {\n if (block.type !== 'tool_result') continue;\n emit({\n type: 'tool_result',\n id: block.tool_use_id ?? '',\n name: '',\n output: flattenContent(block.content),\n success: block.is_error !== true,\n });\n }\n return;\n\n case 'result':\n // `result` closes every turn — success or failure. The final assistant\n // text (which carries the plan JSON) already arrived as assistant\n // blocks, so this only settles the turn.\n if (msg.is_error || (msg.subtype && msg.subtype !== 'success')) {\n emit({ type: 'error', message: msg.result?.trim() || `Claude Code ended the turn: ${msg.subtype ?? 'error'}` });\n } else {\n emit({ type: 'turn_end' });\n }\n return;\n\n // `system`/`stream_event` carry init metadata and partial deltas. The\n // session id is picked up above; partials are ignored because the\n // complete blocks follow and would otherwise be counted twice.\n default:\n return;\n }\n }\n}\n","import type { AgentProcessDeps } from './AgentAdapter';\n\n/** A probe that hangs must not hold up session start; an unclear answer means \"change nothing\". */\nconst PROBE_TIMEOUT_MS = 10000;\n\n/**\n * The bubblewrap failure this module exists for, as the sandbox itself reports\n * it. Matching the message — rather than treating any non-zero exit as a broken\n * sandbox — keeps an older `codex` without the `sandbox` subcommand, or a probe\n * that fails for some unrelated reason, from being \"fixed\" by a workaround it\n * does not need.\n */\nconst USERNS_FAILURE = /bwrap|bubblewrap|user namespace|RTM_NEWADDR/i;\n\nexport type CodexSandboxDecision =\n /** Leave Codex alone: its sandbox works, or nothing recognizable is wrong with it. */\n | 'default'\n /** Bubblewrap cannot start; Codex's pre-bubblewrap Landlock backend can. */\n | 'legacy-landlock'\n /** Both backends failed. Codex can run no command at all, so it cannot explore. */\n | 'unavailable';\n\n/**\n * Decide which sandbox backend Codex should plan under on this machine.\n *\n * Codex's Linux sandbox is bubblewrap, which needs unprivileged user\n * namespaces. Ubuntu 24.04 restricts those through AppArmor\n * (`kernel.apparmor_restrict_unprivileged_userns=1`) and ships no `bwrap`\n * profile, so every command the planner runs dies with `bwrap: loopback:\n * Failed RTM_NEWADDR: Operation not permitted` — and Codex answers anyway,\n * from memory and web search, which is exactly the confident uninformed plan\n * this repo treats as a silent success (openai/codex#15496, #16334).\n *\n * `use_legacy_landlock` selects the backend Codex used before bubblewrap.\n * Landlock is an LSM, needs no namespace, and still denies the writes that make\n * read-only planning read-only. It is deprecated upstream, which is why it is\n * opted into only on a machine that has been observed to need it, and why its\n * own failure is not special-cased: an unrecognized outcome leaves Codex\n * configured exactly as it configures itself.\n *\n * Asking the binary beats inferring from `/proc` and `/etc/apparmor.d`: it is\n * the same question, put to the thing that will have to answer it, and it costs\n * one ~40ms process.\n */\nexport async function probeCodexSandbox(\n deps: AgentProcessDeps,\n cwd: string,\n env: NodeJS.ProcessEnv,\n): Promise<CodexSandboxDecision> {\n // Bubblewrap is the Linux backend only, so there is nothing here to probe\n // elsewhere: macOS uses Seatbelt, which cannot fail this way.\n //\n // Windows is a weaker statement and deliberately not dressed up as a stronger\n // one. Codex's own sandboxing there is not the OS-enforced equivalent of\n // Seatbelt or Landlock, so `sandbox: 'read-only'` in `CodexAdapter.startThread`\n // may be honoured by Codex's tool layer rather than by the kernel. The\n // approvals side of the invariant still holds by construction\n // (`approvalPolicy: 'never'`, and the whole server→client request surface is\n // refused), and the planner prompt never asks for a write — but \"read-only by\n // construction\" (ADR-0009) is a Linux/macOS guarantee, not yet a verified\n // Windows one. Returning 'default' declines to invent a workaround for a\n // failure mode nobody has observed; it does not claim the guarantee is proven.\n if ((deps.platform ?? process.platform) !== 'linux') return 'default';\n\n const bubblewrap = await runProbe(deps, cwd, env, []);\n if (bubblewrap.code === 0) return 'default';\n if (!USERNS_FAILURE.test(bubblewrap.output)) return 'default';\n\n const landlock = await runProbe(deps, cwd, env, ['--enable', 'use_legacy_landlock']);\n return landlock.code === 0 ? 'legacy-landlock' : 'unavailable';\n}\n\n/** The message shown when Codex has no working sandbox, naming both documented fixes. */\nexport function codexSandboxUnavailableMessage(): string {\n return [\n 'Codex cannot start a sandbox on this machine, so it can run no command and cannot read the workspace.',\n '',\n \"Its Linux sandbox needs unprivileged user namespaces, which this kernel restricts (Ubuntu 24.04's AppArmor default), and the legacy Landlock backend did not work either.\",\n '',\n 'Either allow them:',\n ' sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0',\n '',\n 'or install an AppArmor profile for bwrap, then plan with Codex again.',\n ].join('\\n');\n}\n\nfunction runProbe(\n deps: AgentProcessDeps,\n cwd: string,\n env: NodeJS.ProcessEnv,\n flags: string[],\n): Promise<{ code: number | null; output: string }> {\n return new Promise((resolve) => {\n let output = '';\n let settled = false;\n const finish = (code: number | null) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n resolve({ code, output });\n };\n\n const timer = setTimeout(() => finish(null), PROBE_TIMEOUT_MS);\n timer.unref?.();\n\n let proc;\n try {\n proc = deps.spawn('codex', ['sandbox', ...flags, '--', '/bin/true'], {\n env, stdio: ['pipe', 'pipe', 'pipe'], cwd,\n });\n } catch {\n finish(null);\n return;\n }\n\n proc.stdout?.on('data', (chunk: Buffer) => { output += chunk.toString(); });\n proc.stderr?.on('data', (chunk: Buffer) => { output += chunk.toString(); });\n proc.on('error', () => finish(null));\n proc.on('exit', (code) => finish(code));\n });\n}\n","import type { AgentEvent, AgentStartOptions } from './AgentAdapter';\nimport { StdioAgentAdapter, type SpawnSpec } from './StdioAgentAdapter';\nimport { probeCodexSandbox, codexSandboxUnavailableMessage, type CodexSandboxDecision } from './codexSandbox';\n\nconst HANDSHAKE_TIMEOUT_MS = 30000;\n\ninterface RpcMessage {\n id?: number | string;\n method?: string;\n params?: Record<string, unknown>;\n result?: Record<string, unknown>;\n error?: { message?: string };\n}\n\n/**\n * One entry of a Codex turn. Field names are the app-server protocol's, taken\n * from `codex app-server generate-json-schema`, not invented here.\n */\ninterface ThreadItem {\n id?: string;\n type?: string;\n text?: string;\n /** Reasoning carries arrays of blocks, not a string — see `flattenText`. */\n summary?: unknown;\n content?: unknown;\n command?: string | string[];\n cwd?: string;\n aggregatedOutput?: string;\n exitCode?: number;\n server?: string;\n tool?: string;\n arguments?: Record<string, unknown>;\n result?: unknown;\n error?: string;\n status?: string;\n success?: boolean;\n query?: string;\n /** `final_answer` vs `commentary`; both are prose the user should see. */\n phase?: string;\n}\n\n/**\n * Codex carries prose as arrays of blocks — `reasoning.summary`, and the\n * `content` of an MCP tool result — where each block is a string or an object\n * with a `text` field. Reading them as plain strings produced empty thinking\n * events against the real CLI, which is why this exists.\n */\nfunction flattenText(value: unknown): string {\n if (typeof value === 'string') return value;\n if (Array.isArray(value)) return value.map(flattenText).filter(Boolean).join('\\n');\n if (value && typeof value === 'object') {\n const text = (value as { text?: unknown }).text;\n if (typeof text === 'string') return text;\n const content = (value as { content?: unknown }).content;\n if (content !== undefined) return flattenText(content);\n }\n return '';\n}\n\n/**\n * Server→client requests that carry a refusal in their own result schema, and\n * the exact payload that expresses it. Anything not listed here is refused with\n * a JSON-RPC error instead — see {@link CodexAdapter.answerServerRequest}.\n */\nconst DECLINE_RESULTS: Record<string, Record<string, unknown>> = {\n 'item/commandExecution/requestApproval': { decision: 'decline' },\n 'item/fileChange/requestApproval': { decision: 'decline' },\n 'mcpServer/elicitation/request': { action: 'decline' },\n // The pre-`item/*` spellings, still emitted by older app-servers.\n execCommandApproval: { decision: 'denied' },\n applyPatchApproval: { decision: 'denied' },\n};\n\nconst LANDLOCK_FALLBACK_NOTE = [\n \"Codex's bubblewrap sandbox cannot create user namespaces on this machine, so planning fell back to its legacy Landlock backend.\",\n 'Exploration works and writes are still denied, but that backend is deprecated upstream. To fix the host:',\n ' sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0',\n].join('\\n');\n\n/** Requests worth showing in the timeline: the planner reached for something it may not have. */\nconst ANNOUNCED_REQUESTS = new Set([\n ...Object.keys(DECLINE_RESULTS),\n 'item/permissions/requestApproval',\n 'item/tool/requestUserInput',\n 'item/tool/call',\n]);\n\n/**\n * Codex as a planner, over its `app-server` stdio JSON-RPC transport\n * (ADR-0009).\n *\n * Ordewell already speaks a slice of this protocol — `ModelDiscovery` drives\n * `initialize` → `model/list` to build the Codex model catalog — so the\n * handshake here is that one continued into a thread.\n *\n * Codex's own CLI marks `app-server` experimental, and it is the transport\n * most likely to drift: the method names below (`thread/start`, `turn/start`,\n * `item/completed`) come from the schema the installed binary generates, and a\n * version that renames them will surface as a visible dead turn rather than a\n * hang, because the base class watches the process as well as the protocol.\n */\nexport class CodexAdapter extends StdioAgentAdapter {\n readonly agentId = 'codex';\n\n private threadId: string | null = null;\n private nextRequestId = 100;\n private settleHandshake: ((ok: boolean) => void) | null = null;\n private handshakeError: string | null = null;\n private startOpts: AgentStartOptions | null = null;\n /** Whether this turn has already emitted prose — see the `agentMessage` case. */\n private turnHasText = false;\n private resumeAttempted = false;\n private resumeFallbackSent = false;\n private sandbox: CodexSandboxDecision = 'default';\n\n protected spawnSpec(opts: AgentStartOptions): SpawnSpec {\n this.startOpts = opts;\n return { command: 'codex', args: ['app-server'] };\n }\n\n /**\n * `initialize`, then `thread/start`, both before the first user message. The\n * thread is pinned to the read-only sandbox with approvals set to `never` —\n * with nobody watching a planner's prompts, \"ask\" would mean \"hang\", which is\n * ADR-0008's absent-is-denial invariant kept by construction.\n */\n protected async handshake(opts: AgentStartOptions): Promise<void> {\n // Before the protocol, the machine: a Codex whose sandbox cannot start runs\n // no command and plans from imagination instead of from the repository.\n this.sandbox = await probeCodexSandbox(this.deps, opts.cwd, this.spawnEnv);\n if (this.sandbox === 'unavailable') throw new Error(codexSandboxUnavailableMessage());\n\n const ready = new Promise<boolean>((resolve) => { this.settleHandshake = resolve; });\n this.writeLine({\n jsonrpc: '2.0', id: 1, method: 'initialize',\n params: { clientInfo: { name: 'ordewell', title: 'Ordewell', version: '0.1.0' } },\n });\n\n const ok = await Promise.race([\n ready,\n // A binary that rejects `app-server` outright dies immediately; waiting\n // out the timeout would turn a one-line diagnostic into a 30s stall.\n this.processEnded.then(() => false),\n new Promise<boolean>((resolve) => { const t = setTimeout(() => resolve(false), HANDSHAKE_TIMEOUT_MS); t.unref?.(); }),\n ]);\n this.settleHandshake = null;\n if (!ok) {\n throw new Error(this.handshakeError ?? `The Codex app-server did not complete its handshake.\\n\\n${this.exitMessage()}`);\n }\n void opts;\n }\n\n /**\n * Open the thread this session plans in. A resume id means the previous\n * process died mid-session: `thread/resume` puts the agent back in front of\n * the context it already paid to read. A failed resume is not an error — the\n * response handler falls back to a fresh thread, which is the same\n * degradation `restoreChat` performs on every surface (T4).\n */\n private startThread(resumeSessionId?: string): void {\n const opts = this.startOpts;\n this.resumeAttempted = this.resumeAttempted || !!resumeSessionId;\n this.writeLine({\n jsonrpc: '2.0',\n id: 2,\n method: resumeSessionId ? 'thread/resume' : 'thread/start',\n params: {\n ...(resumeSessionId ? { threadId: resumeSessionId } : {}),\n cwd: opts?.cwd,\n ...(opts?.model ? { model: opts.model } : {}),\n sandbox: 'read-only',\n approvalPolicy: 'never',\n ...(this.sandbox === 'legacy-landlock'\n ? { config: { features: { use_legacy_landlock: true } } }\n : {}),\n // `developerInstructions` layers on top of Codex's own base prompt, the\n // way Claude Code's `--append-system-prompt` does. `baseInstructions`\n // replaces it — which takes Codex's description of its own tools with\n // it, and a planner that has forgotten it can read the workspace\n // answers from a web search instead.\n developerInstructions: opts?.systemPrompt,\n },\n });\n }\n\n protected turnPayload(message: string): string {\n const opts = this.startOpts;\n return `${JSON.stringify({\n jsonrpc: '2.0',\n id: this.nextRequestId++,\n method: 'turn/start',\n params: {\n threadId: this.threadId,\n input: [{ type: 'text', text: message }],\n ...(opts?.effort ? { effort: opts.effort } : {}),\n },\n })}\\n`;\n }\n\n protected handleLine(line: string, emit: (event: AgentEvent) => void): void {\n const msg = StdioAgentAdapter.parse<RpcMessage>(line);\n if (!msg) return;\n\n if (msg.id === 1 && !msg.method) {\n if (msg.error) {\n this.handshakeError = `The Codex app-server rejected initialize: ${msg.error.message ?? 'unknown error'}`;\n this.settleHandshake?.(false);\n return;\n }\n this.startThread(this.startOpts?.resumeSessionId);\n return;\n }\n\n if (msg.id === 2 && !msg.method) {\n const thread = msg.result?.thread as { id?: string } | undefined;\n if (msg.error || !thread?.id) {\n if (this.resumeAttempted && !this.resumeFallbackSent) {\n this.resumeFallbackSent = true;\n this.startThread();\n return;\n }\n this.handshakeError = `The Codex app-server could not start a thread: ${msg.error?.message ?? 'no thread id returned'}`;\n this.settleHandshake?.(false);\n return;\n }\n this.threadId = thread.id;\n this.sessionId = thread.id;\n this.settleHandshake?.(true);\n return;\n }\n\n // Every server→client request — one that carries both a method and an id —\n // gets an answer, because an unanswered one stalls the turn forever. That\n // is ADR-0008's absent-is-denial invariant applied to the whole request\n // surface rather than to the three approval methods that happened to be\n // known when this adapter was written.\n if (msg.method && msg.id !== undefined) {\n this.answerServerRequest(msg, emit);\n return;\n }\n\n switch (msg.method) {\n case 'item/started':\n this.emitItemStart(msg.params?.item as ThreadItem | undefined, emit);\n return;\n case 'item/completed':\n this.emitItemDone(msg.params?.item as ThreadItem | undefined, emit);\n return;\n case 'turn/started':\n this.turnHasText = false;\n return;\n // Codex reports a setup problem once, at startup, and then plans anyway.\n // Surfacing it is enough: the warning is not always fatal, and refusing to\n // plan on an unrecognized one would be worse than showing it.\n case 'configWarning': {\n const warning = msg.params as { summary?: string; details?: string } | undefined;\n const text = [warning?.summary, warning?.details].filter(Boolean).join('\\n');\n // Codex emits the bubblewrap warning from its default config, before the\n // thread picks a backend, so it arrives even on the Landlock fallback\n // that just fixed it. Passing it through would be a false alarm, and\n // dropping it would hide a host that still needs fixing — Landlock is\n // deprecated upstream, so this is a reprieve, not a repair.\n if (this.sandbox === 'legacy-landlock' && /bubblewrap|user namespace/i.test(text)) {\n emit({ type: 'thinking', text: LANDLOCK_FALLBACK_NOTE });\n return;\n }\n if (text) emit({ type: 'thinking', text: `Codex configuration warning: ${text}` });\n return;\n }\n // A turn that fails without retry may never reach `turn/completed` — a\n // rate limit or an exhausted context window would otherwise hang until\n // the process died.\n case 'error': {\n const failure = msg.params as { error?: { message?: string }; willRetry?: boolean } | undefined;\n if (failure?.willRetry) return;\n emit({ type: 'error', message: failure?.error?.message || 'Codex ended the turn with an error.' });\n return;\n }\n case 'turn/completed': {\n const turn = msg.params?.turn as { status?: string; error?: { message?: string } } | undefined;\n if (turn?.status === 'failed') {\n emit({ type: 'error', message: turn.error?.message || 'Codex ended the turn with an error.' });\n } else {\n emit({ type: 'turn_end' });\n }\n return;\n }\n // Deltas (`item/agentMessage/delta`, `item/reasoning/*Delta`) are skipped:\n // the completed item follows and would otherwise be counted twice.\n default:\n return;\n }\n }\n\n /**\n * Refuse one server→client request. Requests whose result schema can express\n * a refusal get that payload; everything else — a permission grant, a\n * question for a user who is not watching, a tool call the client is supposed\n * to run — gets a JSON-RPC error, which Codex surfaces to the model as a\n * failed request and plans around, rather than waiting on.\n */\n private answerServerRequest(msg: RpcMessage, emit: (e: AgentEvent) => void): void {\n const method = msg.method!;\n const result = DECLINE_RESULTS[method];\n if (result) {\n this.writeLine({ jsonrpc: '2.0', id: msg.id, result });\n } else if (method === 'currentTime/read') {\n // Answered rather than refused: it is not a capability request, and\n // failing it would break a tool for no reason.\n this.writeLine({ jsonrpc: '2.0', id: msg.id, result: { currentTimeAt: Math.floor(Date.now() / 1000) } });\n return;\n } else {\n this.writeLine({\n jsonrpc: '2.0',\n id: msg.id,\n error: { code: -32601, message: 'The Ordewell planner is read-only and has no user to consult. Mutation belongs to the runners that execute the plan.' },\n });\n }\n if (!ANNOUNCED_REQUESTS.has(method)) return;\n emit({\n type: 'permission_request',\n id: String(msg.id ?? ''),\n name: method.split('/').pop() ?? method,\n detail: JSON.stringify(msg.params ?? {}),\n });\n }\n\n /** A tool item entering `inProgress` — announce the call so the timeline moves. */\n private emitItemStart(item: ThreadItem | undefined, emit: (e: AgentEvent) => void): void {\n if (!item?.id) return;\n switch (item.type) {\n case 'commandExecution':\n emit({ type: 'tool_call', id: item.id, name: 'shell', args: { command: item.command, cwd: item.cwd } });\n return;\n case 'mcpToolCall':\n emit({ type: 'tool_call', id: item.id, name: item.tool ?? 'mcp_tool', args: item.arguments ?? {} });\n return;\n case 'dynamicToolCall':\n emit({ type: 'tool_call', id: item.id, name: item.tool ?? 'tool', args: item.arguments ?? {} });\n return;\n case 'webSearch':\n emit({ type: 'tool_call', id: item.id, name: 'web_search', args: { query: item.query } });\n return;\n default:\n return;\n }\n }\n\n private emitItemDone(item: ThreadItem | undefined, emit: (e: AgentEvent) => void): void {\n if (!item?.type) return;\n const id = item.id ?? '';\n switch (item.type) {\n // A Codex turn is several whole messages — progress commentary, then the\n // final answer — not a token stream. Concatenated raw they run together\n // (\"…as requested.`head` failed because…\"), so each one after the first\n // opens a paragraph.\n case 'agentMessage':\n if (!item.text) return;\n emit({ type: 'assistant_text', text: this.turnHasText ? `\\n\\n${item.text}` : item.text });\n this.turnHasText = true;\n return;\n case 'reasoning': {\n const text = flattenText(item.summary) || flattenText(item.content) || item.text || '';\n if (text.trim()) emit({ type: 'thinking', text });\n return;\n }\n case 'commandExecution':\n emit({\n type: 'tool_result', id, name: 'shell',\n output: item.aggregatedOutput ?? '',\n success: (item.exitCode ?? 0) === 0,\n });\n return;\n case 'mcpToolCall':\n case 'dynamicToolCall':\n emit({\n type: 'tool_result', id, name: item.tool ?? 'tool',\n output: item.error ?? flattenText(item.result) ?? '',\n success: item.status !== 'error' && item.success !== false && !item.error,\n });\n return;\n // The query is empty when the search starts and filled when it lands, so\n // the result — not the call — is what carries what was actually searched.\n case 'webSearch':\n emit({ type: 'tool_result', id, name: 'web_search', output: item.query ?? '', success: true });\n return;\n // `fileChange` can only appear if the read-only sandbox was bypassed;\n // reporting it keeps that visible rather than silent.\n case 'fileChange':\n emit({ type: 'tool_result', id, name: 'file_change', output: JSON.stringify(item), success: false });\n return;\n default:\n return;\n }\n }\n}\n","import type { ChildProcess } from 'child_process';\nimport { augmentedPath, withPath } from '../../utils/shellPath';\nimport { planDirectLaunch } from '../../utils/launch';\nimport { killTree } from '../../utils/processTree';\nimport type { AgentAdapter, AgentEvent, AgentProcessDeps, AgentStartOptions } from './AgentAdapter';\n\nconst SERVER_READY_TIMEOUT_MS = 30000;\nconst STDERR_TAIL_CHARS = 4000;\n/** How long a turn waits for `/event` before posting anyway. See {@link OpenCodeAdapter.send}. */\nconst STREAM_CONNECT_TIMEOUT_MS = 5000;\n\n/**\n * Tools withheld from a planning session (T1). `question` is the load-bearing\n * one: it blocks the turn on an answer from a user who is not watching, and the\n * message POST then never returns — an absent answer has to mean denial, not a\n * hung planner. The rest are the write tools, withheld for the same reason\n * {@link ClaudeCodeAdapter} names them despite `--permission-mode plan`: the\n * `plan` agent already refuses them, and a future default must not quietly\n * hand the planner an edit.\n */\nconst DISABLED_TOOLS: Record<string, boolean> = {\n question: false,\n edit: false,\n write: false,\n apply_patch: false,\n todowrite: false,\n};\n\ninterface OpenCodePart {\n id?: string;\n type?: string;\n text?: string;\n tool?: string;\n callID?: string;\n messageID?: string;\n state?: { status?: string; input?: Record<string, unknown>; output?: string; error?: string };\n}\n\n/** `permission.asked` (and its v2 spelling) — the only server→client request OpenCode makes. */\ninterface OpenCodePermissionAsk {\n id?: string;\n sessionID?: string;\n permission?: string;\n action?: string;\n patterns?: string[];\n resources?: string[];\n metadata?: Record<string, unknown>;\n}\n\ninterface OpenCodeMessageResponse {\n parts?: OpenCodePart[];\n /** `AssistantMessage.error` is a tagged union: `{ name, data: { message } }`. */\n info?: { id?: string; error?: { name?: string; data?: { message?: string } } };\n error?: { message?: string } | string;\n}\n\n/**\n * OpenCode addresses a model as `{providerID, modelID}`; discovery and the\n * plan artifact carry the flat `provider/model` id the CLI's `--model` flag\n * takes. Split on the first slash — provider ids never contain one, model ids\n * sometimes do (`openrouter/anthropic/claude-sonnet-4`).\n */\nfunction splitModelId(id: string): { providerID: string; modelID: string } | null {\n const slash = id.indexOf('/');\n if (slash <= 0 || slash === id.length - 1) return null;\n return { providerID: id.slice(0, slash), modelID: id.slice(slash + 1) };\n}\n\n/**\n * OpenCode as a planner, over its headless HTTP server (ADR-0009).\n *\n * The odd one out: `opencode serve` is a real server rather than a stdio\n * protocol, so this adapter owns both halves of the boundary — it spawns the\n * process through the same injected `spawn` every other adapter uses, then\n * talks to it through the injected `fetch`. Both are part of the one seam the\n * tests drive.\n *\n * The turn ends when the message POST resolves. Live events stream from the\n * server's `/event` channel, but the POST is what settles the turn: an event\n * name that changes between OpenCode versions then costs liveness, not\n * correctness.\n */\nexport class OpenCodeAdapter implements AgentAdapter {\n readonly agentId = 'opencode';\n\n private process: ChildProcess | null = null;\n private baseUrl: string | null = null;\n private sessionId: string | null = null;\n private stderrTail = '';\n private exited = false;\n private disposed = false;\n private opts: AgentStartOptions | null = null;\n\n constructor(private deps: AgentProcessDeps) {}\n\n async start(opts: AgentStartOptions): Promise<void> {\n this.opts = opts;\n const resolvePath = this.deps.resolvePath ?? augmentedPath;\n const PATH = await resolvePath();\n\n // On POSIX this is `opencode` unchanged; on Windows it resolves the real\n // executable, because CreateProcess performs no PATHEXT lookup.\n const launch = await planDirectLaunch('opencode', ['serve', '--hostname', '127.0.0.1', '--port', '0'], {\n platform: this.deps.platform,\n resolvePath,\n });\n this.process = this.deps.spawn(launch.file, launch.args, {\n env: withPath(process.env, PATH),\n stdio: ['pipe', 'pipe', 'pipe'],\n cwd: opts.cwd,\n windowsVerbatimArguments: launch.verbatim,\n });\n\n const banner = new Promise<string | null>((resolve) => {\n let seen = '';\n const scan = (chunk: Buffer) => {\n seen += chunk.toString();\n const match = seen.match(/https?:\\/\\/[^\\s]+/);\n if (match) resolve(match[0].replace(/[.,)]$/, ''));\n };\n this.process!.stdout?.on('data', scan);\n this.process!.stderr?.on('data', (chunk: Buffer) => {\n this.stderrTail = (this.stderrTail + chunk.toString()).slice(-STDERR_TAIL_CHARS);\n scan(chunk);\n });\n this.process!.on('exit', () => { this.exited = true; resolve(null); });\n this.process!.on('error', (err) => {\n this.exited = true;\n this.stderrTail = (this.stderrTail + `\\n${err.message}`).slice(-STDERR_TAIL_CHARS);\n resolve(null);\n });\n const timer = setTimeout(() => resolve(null), SERVER_READY_TIMEOUT_MS);\n timer.unref?.();\n });\n\n this.baseUrl = await banner;\n if (!this.baseUrl) {\n throw new Error(`The OpenCode planner server did not start.${this.stderrTail.trim() ? `\\n\\n${this.stderrTail.trim()}` : ''}`);\n }\n\n // A resume id names a session on disk, not on this process — so it is\n // checked rather than trusted. A stale one degrades to a fresh session\n // (T4), where the caller reseeds from Ordewell's own transcript.\n if (opts.resumeSessionId) {\n const existing = await this.json<{ id?: string }>('GET', `/session/${opts.resumeSessionId}`).catch(() => null);\n if (existing?.id) {\n this.sessionId = existing.id;\n return;\n }\n }\n const created = await this.json<{ id?: string }>('POST', '/session', {});\n if (!created?.id) throw new Error('The OpenCode planner server did not return a session id.');\n this.sessionId = created.id;\n }\n\n async send(message: string, onEvent: (event: AgentEvent) => void, signal?: AbortSignal): Promise<void> {\n if (!this.baseUrl || !this.sessionId) throw new Error('OpenCode planner session is not started');\n if (this.exited) {\n onEvent({ type: 'error', message: this.exitMessage() });\n return;\n }\n\n const seen = new Set<string>();\n const streamAbort = new AbortController();\n let connected: () => void = () => {};\n const streamReady = new Promise<void>((resolve) => { connected = resolve; });\n // The live stream carries tool activity only. It also replays the user's\n // own message back as text parts, and the event frame gives no role to\n // filter on — so prose is taken from the settled response instead, where\n // `info.id` says exactly which message is the assistant's. Letting the\n // echo through would put the user's goal into the planner's reply text,\n // and a goal containing JSON would then be parsed as the plan.\n const live = this.streamEvents(\n streamAbort.signal,\n (part) => { if (part.type === 'tool') this.emitPart(part, seen, onEvent); },\n (ask) => this.denyPermission(ask, seen, onEvent),\n connected,\n );\n\n // The stream stopped being best-effort the moment permission denial moved\n // onto it: a request raised before we connect is one nobody answers, and\n // the message POST then hangs until its own timeout. Waiting is bounded so\n // a server that never opens `/event` still gets its turn.\n await Promise.race([streamReady, new Promise<void>((r) => { const t = setTimeout(r, STREAM_CONNECT_TIMEOUT_MS); t.unref?.(); })]);\n\n try {\n const model = this.opts?.model ? splitModelId(this.opts.model) : null;\n const body = {\n parts: [{ type: 'text', text: message }],\n // The read-only guarantee: OpenCode's own plan agent has no write tools.\n agent: 'plan',\n tools: DISABLED_TOOLS,\n ...(model ? { model } : {}),\n ...(this.opts?.effort ? { variant: this.opts.effort } : {}),\n ...(this.opts?.systemPrompt ? { system: this.opts.systemPrompt } : {}),\n };\n const reply = await this.json<OpenCodeMessageResponse>('POST', `/session/${this.sessionId}/message`, body, signal);\n\n if (signal?.aborted) { this.dispose(); return; }\n\n const failure = typeof reply?.error === 'string'\n ? reply.error\n : (reply?.error as { message?: string } | undefined)?.message ?? reply?.info?.error?.data?.message;\n if (failure) {\n onEvent({ type: 'error', message: failure });\n return;\n }\n // The settled response is authoritative: it names the assistant message,\n // so its parts are the ones that make up the reply. Tool parts already\n // seen live are deduplicated by call id; anything the stream missed\n // (including a stream that never connected) arrives here.\n const assistantId = reply?.info?.id;\n for (const part of reply?.parts ?? []) {\n if (part.type !== 'tool' && assistantId && part.messageID !== assistantId) continue;\n this.emitPart(part, seen, onEvent);\n }\n onEvent({ type: 'turn_end' });\n } catch (err) {\n if (signal?.aborted) { this.dispose(); return; }\n onEvent({ type: 'error', message: `The OpenCode planner turn failed: ${err instanceof Error ? err.message : String(err)}` });\n } finally {\n streamAbort.abort();\n await live.catch(() => { /* the stream is best-effort */ });\n }\n }\n\n /**\n * Emit one message part, once. OpenCode reports a tool part repeatedly as it\n * moves through pending → running → completed, so parts are keyed by id and\n * only the terminal state produces a result.\n */\n private emitPart(part: OpenCodePart, seen: Set<string>, onEvent: (e: AgentEvent) => void): void {\n if (!part?.type) return;\n const id = part.id ?? part.callID ?? '';\n\n if (part.type === 'text' && part.text) {\n if (seen.has(`text:${id}`)) return;\n seen.add(`text:${id}`);\n onEvent({ type: 'assistant_text', text: part.text });\n return;\n }\n if (part.type === 'reasoning' && part.text) {\n if (seen.has(`reasoning:${id}`)) return;\n seen.add(`reasoning:${id}`);\n onEvent({ type: 'thinking', text: part.text });\n return;\n }\n if (part.type !== 'tool') return;\n\n const callId = part.callID ?? id;\n const name = part.tool ?? 'tool';\n const status = part.state?.status;\n const input = part.state?.input;\n // A `pending` tool part carries no input yet, so announcing it there gave\n // every call an empty arg summary. Waiting for the first state that has\n // input costs a moment of liveness and buys a readable timeline.\n if (!seen.has(`call:${callId}`) && (status !== 'pending' || (input && Object.keys(input).length > 0))) {\n seen.add(`call:${callId}`);\n onEvent({ type: 'tool_call', id: callId, name, args: input ?? {} });\n }\n if ((status === 'completed' || status === 'error') && !seen.has(`result:${callId}`)) {\n seen.add(`result:${callId}`);\n onEvent({\n type: 'tool_result',\n id: callId,\n name,\n output: part.state?.output ?? part.state?.error ?? '',\n success: status === 'completed',\n });\n }\n }\n\n /**\n * Deny one permission request (T1). OpenCode blocks the turn until the\n * request is answered, so this must answer — `reject` rather than a silent\n * drop, which is the same \"absent answer is a denial\" invariant ADR-0008\n * states for Ordewell's own tools. The refusal is announced so the timeline\n * shows the planner reaching for something it may not have.\n */\n private denyPermission(ask: OpenCodePermissionAsk, seen: Set<string>, onEvent: (e: AgentEvent) => void): void {\n const id = ask.id;\n if (!id || seen.has(`perm:${id}`)) return;\n seen.add(`perm:${id}`);\n const name = ask.permission ?? ask.action ?? 'permission';\n const scope = (ask.patterns ?? ask.resources ?? []).join(', ');\n onEvent({\n type: 'permission_request',\n id,\n name,\n detail: JSON.stringify({ ...(scope ? { scope } : {}), ...(ask.metadata ?? {}) }),\n });\n void this.json('POST', `/session/${ask.sessionID ?? this.sessionId}/permissions/${id}`, { response: 'reject' })\n .catch(() => { /* a server that forgot the request will not hang on it either */ });\n }\n\n /**\n * Server-sent events from `/event`. Tool activity on it is liveness only —\n * the settled POST repeats it — but permission requests arrive nowhere else,\n * so the stream is load-bearing for {@link denyPermission}.\n */\n private async streamEvents(\n signal: AbortSignal,\n onPart: (part: OpenCodePart) => void,\n onPermission: (ask: OpenCodePermissionAsk) => void,\n onConnected: () => void,\n ): Promise<void> {\n const response = await this.deps.fetch(`${this.baseUrl}/event`, { signal }).catch(() => null);\n const body = response?.body;\n if (!body) { onConnected(); return; }\n onConnected();\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n for (;;) {\n const { done, value } = await reader.read().catch(() => ({ done: true, value: undefined }));\n if (done) return;\n buffer += decoder.decode(value, { stream: true });\n let newline: number;\n while ((newline = buffer.indexOf('\\n')) >= 0) {\n const line = buffer.slice(0, newline).trim();\n buffer = buffer.slice(newline + 1);\n if (!line.startsWith('data:')) continue;\n try {\n const event = JSON.parse(line.slice(5).trim()) as {\n type?: string;\n properties?: (OpenCodePermissionAsk & { part?: OpenCodePart });\n };\n const props = event.properties;\n if (!props) continue;\n if (props.sessionID && props.sessionID !== this.sessionId) continue;\n if (event.type === 'permission.asked' || event.type === 'permission.v2.asked') onPermission(props);\n else if (props.part) onPart(props.part);\n } catch {\n // A partial or unrecognized frame costs one event, not the turn.\n }\n }\n }\n }\n\n private async json<T>(method: string, path: string, body?: unknown, signal?: AbortSignal): Promise<T | null> {\n const response = await this.deps.fetch(`${this.baseUrl}${path}`, {\n method,\n headers: { 'content-type': 'application/json' },\n ...(body === undefined ? {} : { body: JSON.stringify(body) }),\n ...(signal ? { signal } : {}),\n });\n if (!response.ok) throw new Error(`${method} ${path} failed: ${response.status} ${response.statusText}`);\n return (await response.json().catch(() => null)) as T | null;\n }\n\n nativeSessionId(): string | null { return this.sessionId; }\n\n dispose(): void {\n if (this.disposed) return;\n this.disposed = true;\n const proc = this.process;\n this.process = null;\n this.baseUrl = null;\n // Tree-wide: `opencode serve` is a server, and on Windows it may sit behind\n // a cmd.exe shim. A surviving server keeps the port and the session.\n killTree(proc, { platform: this.deps.platform });\n }\n\n private exitMessage(): string {\n const tail = this.stderrTail.trim();\n return `The OpenCode planner server exited.${tail ? `\\n\\n${tail}` : ''}`;\n }\n}\n","import type { ResearchToolType } from '../../models/Task';\n\n/**\n * Map a coding agent's own tool name onto Ordewell's research vocabulary\n * (ADR-0009, T5).\n *\n * A harness planner brings its own toolbox, and most of it overlaps ours: a\n * `Read` is a `read_file`, a `Grep` is a `grep`. Those map onto existing\n * members and render in every surface through the code path that is already\n * there. Everything else — `Edit`, `WebFetch`, `TodoWrite`, `Task`, whatever\n * ships next — becomes `agent_tool` carrying its real name.\n *\n * Nothing is relabelled as a tool it is not. Calling a web fetch a `bash` to\n * avoid adding a union member would put a lie in the timeline, which is the\n * point ADR-0008 spent its effort establishing.\n */\nconst KNOWN_TOOLS: Record<string, ResearchToolType> = {\n // Claude Code\n read: 'read_file',\n grep: 'grep',\n glob: 'glob',\n bash: 'bash',\n ls: 'list_dir',\n webfetch: 'fetch',\n websearch: 'web_search',\n // Codex — its sandboxed command tool is a shell by another name\n shell: 'bash',\n exec_command: 'bash',\n local_shell: 'bash',\n // OpenCode\n list: 'list_dir',\n fetch: 'fetch',\n};\n\nexport interface MappedTool {\n tool: ResearchToolType;\n /** The agent's own name, kept whenever it differs from the member it mapped to. */\n toolLabel?: string;\n}\n\n/**\n * Classify one agent tool name. Case- and separator-insensitive, because the\n * three agents disagree on `Read` vs `read` vs `read_file` for the same thing.\n */\nexport function mapAgentTool(name: string): MappedTool {\n const normalized = name.trim().toLowerCase().replace(/[_-]/g, '');\n const direct = KNOWN_TOOLS[normalized] ?? KNOWN_TOOLS[name.trim().toLowerCase()];\n if (direct) {\n // The label survives even on a mapped tool: `Read` and `read_file` render\n // the same way, but the transcript should still say which one ran.\n return { tool: direct, toolLabel: name };\n }\n return { tool: 'agent_tool', toolLabel: name };\n}\n\n/**\n * Normalize an agent's tool arguments into the shapes `summarizeToolCall`\n * already knows how to read, so a harness `Read` gets a one-line summary\n * instead of a bare tool name. Unknown keys are preserved — the raw args stay\n * visible under the surfaces' output chevron.\n */\nexport function normalizeAgentArgs(tool: ResearchToolType, args: Record<string, unknown>): Record<string, unknown> {\n const out = { ...args };\n const alias = (from: string, to: string) => {\n if (out[to] === undefined && out[from] !== undefined) out[to] = out[from];\n };\n if (tool === 'read_file' || tool === 'list_dir') {\n alias('filePath', 'path');\n alias('file_path', 'path');\n alias('target', 'path');\n }\n if (tool === 'bash') {\n alias('cmd', 'command');\n alias('script', 'command');\n // Codex hands the command over as an argv array; the summary wants a string.\n if (typeof out.command !== 'string' && Array.isArray(out.command)) {\n out.command = (out.command as unknown[]).join(' ');\n }\n }\n if (tool === 'fetch') alias('uri', 'url');\n if (tool === 'web_search') alias('q', 'query');\n return out;\n}\n","import { Task, ConversationMessage, DiscoveredModel, ResearchLogEntry, ResearchProgress, RunnerId } from '../models/Task';\nimport { IConfig } from '../interfaces/IConfig';\nimport { IFileSystem } from '../interfaces/IFileSystem';\nimport { IWebFetcher } from '../interfaces/IWebFetcher';\nimport type { LegacyPlanState } from '../models/Task';\nimport type { RunnerModeInfo } from './ModeResolver';\nimport { GeminiService } from './GeminiService';\nimport { OpenAiService } from './OpenAiService';\nimport { isCliProvider } from './ProviderRegistry';\nimport { CliAgentAiService, type CliAgentAiServiceDeps } from './harness/CliAgentAiService';\nimport type { PlannerModes } from './plannerModes';\n\n/**\n * Everything the conversation loop needs to start planning (ADR-0002).\n * The AI service keeps the tool-use message history internally across turns;\n * the surfaces only exchange user/assistant messages with it.\n */\nexport interface ConversationRequest {\n goal: string;\n runners: RunnerId[];\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>;\n fs: IFileSystem;\n onProgress: (progress: ResearchProgress) => void;\n fetcher?: IWebFetcher;\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>;\n autonomousDefault?: boolean;\n grillMeEnabled?: boolean;\n prdEnabled?: boolean;\n reviewEnabled?: boolean;\n verificationEnabled?: boolean;\n /** Declare the spawn_research_agent tool to the planner (issue #34, default off). */\n researchSubagentsEnabled?: boolean;\n signal?: AbortSignal;\n /**\n * Persisted dialogue to seed a resumed conversation (session reload). The\n * turns are injected into the message history verbatim — no LLM call happens\n * for them; the first call is the turn opened by `initialMessage`.\n */\n priorHistory?: ConversationMessage[];\n /**\n * The user message that opens this turn. Defaults to `goal` — set it when\n * resuming so the system prompt keeps the original goal while the turn\n * carries the user's new message.\n */\n initialMessage?: string;\n}\n\n/**\n * One planner turn's outcome. The planner talks to the user (`message`),\n * commits a full plan (`plan`, a `{tasks:[...]}` JSON object), or emits\n * targeted task edits (`task_ops`, a `{taskOps:[...]}` JSON object). The\n * Session validates and applies task ops atomically; the AI service only\n * parses them.\n */\nexport type ConversationTurn =\n | { kind: 'message'; text: string; researchLog: ResearchLogEntry[] }\n | { kind: 'plan'; tasks: Task[]; text: string; researchLog: ResearchLogEntry[] }\n | { kind: 'task_ops'; ops: import('./TaskOps').TaskOp[]; text: string; researchLog: ResearchLogEntry[] };\n\nexport interface IAiService {\n /**\n * Begin the planner conversation: collect workspace context, run the\n * research/tool loop, and return the first planner turn. The service\n * retains the full API message history for subsequent\n * {@link continueConversation} calls.\n */\n startConversation(req: ConversationRequest): Promise<ConversationTurn>;\n\n /**\n * Feed the user's reply into the active conversation and return the next\n * planner turn. Throws if no conversation is active.\n */\n continueConversation(\n userMessage: string,\n onProgress: (progress: ResearchProgress) => void,\n signal?: AbortSignal,\n ): Promise<ConversationTurn>;\n\n /**\n * Whether a planner conversation is currently held in memory. A branching\n * predicate only — never a test for whether there is anything to release.\n * The harness backend holds an OS process that outlives its conversation, so\n * guarding {@link reset} with this leaks an agent process; call `reset`\n * unconditionally instead.\n */\n hasActiveConversation(): boolean;\n\n /**\n * Whether the active conversation (if any) still matches the planner\n * model/effort currently configured. Optional, and true when absent: a\n * vendor backend re-reads its model from config on every turn, so there is\n * nothing to drift. A harness planner (ADR-0009) is the exception — its\n * model is baked into the agent process at spawn — so only\n * {@link CliAgentAiService} answers this for real. False tells the caller\n * the same thing an absent conversation would: don't call\n * `continueConversation`, restart instead so the new model takes effect.\n */\n conversationMatchesConfig?(): boolean;\n\n /**\n * One-shot research + plan for non-conversational surfaces (CLI `plan --goal`,\n * web REST). Never asks questions — it plans with what it can find.\n */\n researchAndPlan(\n userDescription: string,\n runners: RunnerId[],\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n fs: IFileSystem,\n onProgress: (progress: ResearchProgress) => void,\n fetcher?: IWebFetcher,\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n modes?: PlannerModes,\n signal?: AbortSignal,\n ): Promise<{ tasks: Task[]; researchLog: ResearchLogEntry[]; researchResults: string }>;\n\n generatePlanDirect(\n userDescription: string,\n runners: RunnerId[],\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n onToken?: (token: string) => void,\n fs?: IFileSystem,\n fetcher?: IWebFetcher,\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n modes?: PlannerModes,\n signal?: AbortSignal,\n ): Promise<Task[]>;\n\n modifyPlan(\n existingPlan: LegacyPlanState,\n userRequest: string,\n modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>,\n onProgress?: (progress: ResearchProgress) => void,\n fs?: IFileSystem,\n fetcher?: IWebFetcher,\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n modes?: PlannerModes,\n signal?: AbortSignal,\n ): Promise<{ tasks: Task[] }>;\n\n /**\n * Release everything this service holds: the conversation, any in-flight\n * turn, and — on the harness backend — the agent process itself. Idempotent\n * and cheap in every implementation, so callers never gate it.\n */\n reset(): void;\n\n sendPlanningPrompt(\n prompt: string,\n runners: RunnerId[],\n runnerModes?: Record<RunnerId, RunnerModeInfo[]>,\n autonomousDefault?: boolean,\n ): Promise<Task[]>;\n}\n\n/**\n * The single branch point between planner transports. Two of them talk HTTP to\n * an LLM vendor; the third (ADR-0009) drives a coding agent already installed\n * on the machine. Everything downstream — the plan contract, the research-step\n * stream, the four surfaces — is shared.\n */\nexport function createAiService(config: IConfig, deps?: CliAgentAiServiceDeps): IAiService {\n if (isCliProvider(config.aiProvider)) {\n return new CliAgentAiService(config, deps);\n }\n if (config.aiProvider === 'google') {\n return new GeminiService(config);\n }\n return new OpenAiService(config);\n}\n","import { lookup } from 'node:dns/promises';\nimport type { IWebFetcher } from '../interfaces/IWebFetcher';\nimport type { IApproval } from '../interfaces/IApproval';\nimport type { ToolOutcome } from '../interfaces/IFileSystem';\n\n/**\n * The concrete `fetch`/`web_search` implementation, in core so the web server\n * and the VS Code extension share one behavior. Until now `IWebFetcher` had no\n * implementation anywhere, which meant the `fetch` tool was declared to every\n * planner and always answered \"not available in this environment\" — a tool the\n * model could see, choose, and never use.\n *\n * Approval is per origin, not per URL: reading three pages of one library's\n * docs is one decision, not three.\n */\n\nexport interface HttpWebFetcherOptions {\n approval: IApproval;\n /** Injected in tests; defaults to the platform `fetch`. */\n fetchImpl?: typeof fetch;\n maxChars?: number;\n timeoutMs?: number;\n /** Override the SSRF / private-host guard in tests. */\n isBlockedHost?: (host: string, port: string) => Promise<boolean>;\n /** Override DNS resolution in tests. */\n resolveHost?: (host: string) => Promise<string[]>;\n}\n\nconst DEFAULT_MAX_CHARS = 40_000;\nconst DEFAULT_TIMEOUT_MS = 20_000;\nconst MAX_BODY_BYTES = 2_000_000;\nconst MAX_REDIRECTS = 5;\n/** A default UA gets refused by enough sites that it is not worth the confusing failures. */\nconst USER_AGENT = 'Mozilla/5.0 (compatible; Ordewell-Planner/1.0; +https://github.com/ordewell)';\n\n/**\n * DuckDuckGo's lite endpoint: no API key, no account, and stable enough for\n * \"find me the docs URL\". It is HTML scraping, so it is the most brittle thing\n * here by construction — every failure path degrades to a tool result that\n * tells the planner to fall back to `fetch` with a known URL.\n */\nconst SEARCH_ENDPOINT = 'https://lite.duckduckgo.com/lite/?q=';\n\nfunction decodeEntities(text: string): string {\n return text\n .replace(/&nbsp;/g, ' ')\n .replace(/&amp;/g, '&')\n .replace(/&lt;/g, '<')\n .replace(/&gt;/g, '>')\n .replace(/&quot;/g, '\"')\n .replace(/&#39;/g, \"'\")\n .replace(/&#x27;/g, \"'\");\n}\n\nfunction htmlToText(html: string): string {\n return decodeEntities(\n html\n .replace(/<script\\b[^>]*>[\\s\\S]*?<\\/script>/gi, ' ')\n .replace(/<style\\b[^>]*>[\\s\\S]*?<\\/style>/gi, ' ')\n .replace(/<noscript\\b[^>]*>[\\s\\S]*?<\\/noscript>/gi, ' ')\n .replace(/<\\/(p|div|li|h[1-6]|tr|section|article)>/gi, '\\n')\n .replace(/<br\\s*\\/?>/gi, '\\n')\n .replace(/<[^>]+>/g, ' '),\n )\n .replace(/[ \\t\\f\\v]+/g, ' ')\n .replace(/\\n\\s*\\n\\s*\\n+/g, '\\n\\n')\n .split('\\n')\n .map((line) => line.trim())\n .join('\\n')\n .trim();\n}\n\ninterface SearchHit { title: string; url: string; snippet?: string }\n\n/** Pull result links out of the lite endpoint's markup. */\nfunction parseSearchHits(html: string): SearchHit[] {\n const hits: SearchHit[] = [];\n const linkPattern = /<a\\b[^>]*class=\"[^\"]*result(?:-link|__a)[^\"]*\"[^>]*href=\"([^\"]+)\"[^>]*>([\\s\\S]*?)<\\/a>/gi;\n const snippetPattern = /class=\"[^\"]*result(?:-snippet|__snippet)[^\"]*\"[^>]*>([\\s\\S]*?)</gi;\n\n const snippets: string[] = [];\n for (let m = snippetPattern.exec(html); m; m = snippetPattern.exec(html)) {\n snippets.push(decodeEntities(m[1].replace(/<[^>]+>/g, ' ')).replace(/\\s+/g, ' ').trim());\n }\n\n for (let m = linkPattern.exec(html); m; m = linkPattern.exec(html)) {\n const title = decodeEntities(m[2].replace(/<[^>]+>/g, ' ')).replace(/\\s+/g, ' ').trim();\n if (!title) continue;\n hits.push({ title, url: decodeEntities(m[1]), snippet: snippets[hits.length] });\n }\n return hits;\n}\n\n/**\n * Reject hosts that resolve to (or literally name) loopback, link-local, or\n * RFC1918 private space — the SSRF surface. `fetch` is the one capability that\n * leaves the machine, so an unguarded `http://169.254.169.254/` would hand a\n * prompt-injected planner the cloud metadata credentials.\n */\nfunction isPrivateIp(ip: string): boolean {\n // `dns.lookup('')` resolves rather than rejecting, with `address: null` —\n // fail closed instead of letting a falsy/non-string address slip past every\n // regex below untested.\n if (!ip) return true;\n if (ip === '0.0.0.0' || ip === '::' || ip === '::1' || ip === '::ffff:127.0.0.1') return true;\n if (/^127\\./.test(ip)) return true;\n if (/^169\\.254\\./.test(ip)) return true;\n if (/^10\\./.test(ip)) return true;\n if (/^192\\.168\\./.test(ip)) return true;\n // 172.16.0.0/12 = 172.16.0.0 – 172.31.255.255\n const m172 = /^172\\.(\\d+)\\./.exec(ip);\n if (m172 && Number(m172[1]) >= 16 && Number(m172[1]) <= 31) return true;\n // fe80::/10 link-local IPv6\n if (/^fe[89ab][0-9a-f]/i.test(ip)) return true;\n return false;\n}\n\nfunction isIpLiteral(host: string): boolean {\n return /^\\d{1,3}(\\.\\d{1,3}){3}$/.test(host) || /^\\[?[0-9a-fA-F:]+\\]?$/i.test(host);\n}\n\nfunction sanitizeError(err: unknown): string {\n const msg = err instanceof Error ? err.message : String(err);\n if (/abort/i.test(msg)) return 'timed out';\n if (/ECONNREFUSED|ECONNRESET|EHOSTUNREACH|ENETUNREACH/i.test(msg)) return 'host not reachable';\n if (/ENOTFOUND|getaddrinfo/i.test(msg)) return 'host not found';\n return msg.replace(/https?:\\/\\/\\S+/g, '<url>');\n}\n\nexport class HttpWebFetcher implements IWebFetcher {\n private readonly approval: IApproval;\n private readonly fetchImpl: typeof fetch;\n private readonly maxChars: number;\n private readonly timeoutMs: number;\n private readonly isBlockedHost: (host: string, port: string) => Promise<boolean>;\n private readonly resolveHost: (host: string) => Promise<string[]>;\n\n constructor(opts: HttpWebFetcherOptions) {\n this.approval = opts.approval;\n this.fetchImpl = opts.fetchImpl ?? globalThis.fetch;\n this.maxChars = opts.maxChars ?? DEFAULT_MAX_CHARS;\n this.timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n this.isBlockedHost = opts.isBlockedHost ?? this.defaultIsBlocked.bind(this);\n this.resolveHost = opts.resolveHost ?? (async (h) => { const r = await lookup(h); return [r.address]; });\n }\n\n private async defaultIsBlocked(host: string, port: string): Promise<boolean> {\n if (!['', '80', '443'].includes(port)) return true;\n if (isIpLiteral(host)) return isPrivateIp(host.startsWith('[') ? host.slice(1, -1) : host);\n const lower = host.toLowerCase();\n if (lower === 'localhost' || lower === 'ip6-localhost' || lower === 'ip6-loopback') return true;\n try {\n const addrs = await this.resolveHost(host);\n if (addrs.some((a) => isPrivateIp(a))) return true;\n } catch {\n return true;\n }\n return false;\n }\n\n async confirm(url: string): Promise<boolean> {\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n return false;\n }\n // Only the two network schemes. `file:` would turn this into a second,\n // unconfined path reader that bypasses the filesystem's confinement.\n if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') return false;\n\n if (await this.isBlockedHost(parsed.hostname, parsed.port)) return false;\n\n return this.approval.request({\n kind: 'url_fetch',\n subject: url,\n scope: `${parsed.origin}/*`,\n detail: `Planner research wants to fetch ${parsed.origin}`,\n });\n }\n\n async fetch(url: string): Promise<ToolOutcome> {\n // Gate on the same confirm search uses, so the SSRF guard and the\n // per-origin approval both run even when a caller invokes fetch directly\n // rather than through executeTool.\n if (!await this.confirm(url)) {\n return { success: false, output: `Fetch denied (blocked host or not approved): ${url}`, truncated: false };\n }\n return this.get(url, 'Fetch');\n }\n\n async search(query: string): Promise<ToolOutcome> {\n const url = SEARCH_ENDPOINT + encodeURIComponent(query);\n if (!await this.confirm(url)) {\n return { success: false, output: `Web search denied by user for query: ${query}`, truncated: false };\n }\n\n const page = await this.request(url);\n if (!page.ok) return { success: false, output: `Web search failed: ${page.error}`, truncated: false };\n\n const hits = parseSearchHits(page.body).slice(0, 10);\n if (hits.length === 0) {\n return {\n success: false,\n output: `No results could be parsed for \"${query}\". Search is best-effort; if you already know a documentation URL, use the fetch tool directly.`,\n truncated: false,\n };\n }\n\n const output = hits\n .map((hit, i) => `${i + 1}. ${hit.title}\\n ${hit.url}${hit.snippet ? `\\n ${hit.snippet}` : ''}`)\n .join('\\n\\n');\n return { success: true, output, truncated: false };\n }\n\n private async get(url: string, label: string): Promise<ToolOutcome> {\n const page = await this.request(url);\n if (!page.ok) return { success: false, output: `${label} failed: ${page.error}`, truncated: false };\n\n const text = page.isHtml ? htmlToText(page.body) : page.body;\n if (page.truncated || text.length > this.maxChars) {\n const sliced = text.slice(0, this.maxChars);\n return {\n success: true,\n output: `${sliced}\\n\\n[... truncated to ${this.maxChars} chars, total ${text.length}${page.truncated ? '+, body was byte-capped at the source' : ''}]`,\n truncated: true,\n };\n }\n return { success: true, output: text, truncated: false };\n }\n\n private async request(url: string): Promise<{ ok: true; body: string; isHtml: boolean; truncated: boolean } | { ok: false; error: string }> {\n let current = url;\n for (let hop = 0; hop <= MAX_REDIRECTS; hop++) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n try {\n const res = await this.fetchImpl(current, {\n signal: controller.signal,\n headers: { 'user-agent': USER_AGENT, accept: 'text/html,application/xhtml+xml,application/json;q=0.9,*/*;q=0.8' },\n redirect: 'manual',\n });\n if (res.status >= 300 && res.status < 400) {\n const location = res.headers.get('location');\n if (!location) return { ok: false, error: `redirect (${res.status}) with no Location` };\n const next = new URL(location, current).href;\n // Re-check the destination the same way `confirm` checked the origin:\n // a redirect to a private IP, or to a non-http(s) scheme like\n // `file:`, would otherwise bypass both guards `confirm` applies to\n // the initial URL.\n const nextParsed = new URL(next);\n if (nextParsed.protocol !== 'https:' && nextParsed.protocol !== 'http:') {\n return { ok: false, error: 'redirect to a non-HTTP scheme' };\n }\n if (await this.isBlockedHost(nextParsed.hostname, nextParsed.port)) {\n return { ok: false, error: 'redirect to a blocked host' };\n }\n current = next;\n continue;\n }\n if (!res.ok) return { ok: false, error: `HTTP ${res.status}` };\n\n const contentType = res.headers.get('content-type') ?? '';\n const { body, truncated } = await readBounded(res, MAX_BODY_BYTES);\n return { ok: true, body, isHtml: /html|xml/i.test(contentType), truncated };\n } catch (err) {\n return { ok: false, error: sanitizeError(err) };\n } finally {\n clearTimeout(timer);\n }\n }\n return { ok: false, error: `too many redirects (>${MAX_REDIRECTS})` };\n }\n}\n\nasync function readBounded(res: Response, maxBytes: number): Promise<{ body: string; truncated: boolean }> {\n const reader = res.body?.[Symbol.asyncIterator]\n ? readFromIterable(res.body as unknown as AsyncIterable<Uint8Array>, maxBytes)\n : readFromText(res, maxBytes);\n return reader;\n}\n\nasync function readFromIterable(source: AsyncIterable<Uint8Array>, maxBytes: number): Promise<{ body: string; truncated: boolean }> {\n const chunks: Buffer[] = [];\n let total = 0;\n let truncated = false;\n for await (const chunk of source) {\n const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);\n if (total + buf.length > maxBytes) {\n chunks.push(buf.subarray(0, maxBytes - total));\n total = maxBytes;\n truncated = true;\n break;\n }\n chunks.push(buf);\n total += buf.length;\n }\n return { body: Buffer.concat(chunks).toString('utf8'), truncated };\n}\n\nasync function readFromText(res: Response, maxBytes: number): Promise<{ body: string; truncated: boolean }> {\n const text = await res.text();\n if (Buffer.byteLength(text, 'utf8') <= maxBytes) return { body: text, truncated: false };\n return { body: Buffer.from(text, 'utf8').subarray(0, maxBytes).toString('utf8'), truncated: true };\n}\n","import type { DiscoveredModel, RunnerId, Task } from '../models/Task';\nimport { clampThinkingEffort } from './ModelAllowlistResolver';\nimport type { RunnerModeInfo } from './ModeResolver';\n\n/** What a runner offers a task: the models discovered for it and the modes its manifest declares. */\nexport interface RunnerCatalog {\n models: DiscoveredModel[];\n modes: RunnerModeInfo[];\n}\n\n/**\n * The model, thinking effort and mode a runner offers for a task.\n *\n * A task's model, effort and mode are all scoped to its runner:\n * `claude-sonnet-4-5` on Codex, or `acceptEdits` on OpenCode, are not degraded\n * choices but unspawnable ones. So this is where any task acquires a runnable\n * assignment — a runner change (below) and a hand-added task derive it the same\n * way. Each field in `current` is preserved when the runner also offers it, and\n * otherwise snapped to that runner's preferred entry (discovery already sorts\n * models by the manifest's `preferredPatterns`; `modes[0]` is the manifest's own\n * first choice).\n *\n * An empty catalog means discovery failed or the runner is a plugin we have no\n * list for — not that the runner offers nothing. That field is left out of the\n * patch and the runner validates last, matching `coerceAssignments`.\n */\nexport function runnerAssignment(\n catalog: RunnerCatalog,\n current?: Pick<Task, 'assignedModel' | 'taskMode'>,\n): Partial<Task> {\n const changes: Partial<Task> = {};\n\n const kept = current?.assignedModel && catalog.models.find((m) => m.modelId === current.assignedModel!.modelId);\n const model = kept ?? catalog.models[0];\n if (model) {\n const thinkingEffort = clampThinkingEffort(current?.assignedModel?.thinkingEffort, model.variants);\n changes.assignedModel = {\n modelId: model.modelId,\n modelLabel: model.modelLabel,\n thinkingEffort,\n availableVariants: model.variants.map((v) => v.id),\n };\n // Task.thinkingEffort predates assignedModel.thinkingEffort and is still\n // read by migration and task_ops. Left behind it would name an effort the\n // new model has no variant for.\n changes.thinkingEffort = thinkingEffort;\n }\n\n if (catalog.modes.length > 0) {\n changes.taskMode = catalog.modes.some((m) => m.id === current?.taskMode) ? current!.taskMode : catalog.modes[0].id;\n }\n\n return changes;\n}\n\n/**\n * Move a task onto a different runner, carrying its model, thinking effort and\n * mode over to values that runner actually offers. A runner change is never a\n * single-field edit — it either brings the other three with it or leaves the\n * task unrunnable.\n *\n * Returns the patch to apply, or `{}` when there is nothing to change.\n */\nexport function retargetTaskRunner(task: Task, runner: RunnerId, catalog: RunnerCatalog): Partial<Task> {\n if (task.type === 'user') return {};\n if (task.assignedRunner === runner) return {};\n return { assignedRunner: runner, ...runnerAssignment(catalog, task) };\n}\n","import type { LegacyPlanState, QueuedMessage, ResearchStep, RunnerId, Task, Verdict } from '../models/Task';\nimport type { ApprovalKind } from '../interfaces/IApproval';\nimport type { ApprovalSource } from './ApprovalPolicy';\n\nexport type SerializedTaskStatus = {\n id: string;\n status: string;\n verdict: { outcome: 'pass' | 'fail'; reason: string; checks: Verdict['checks'] } | null;\n};\n\nexport type SerializedTask = {\n id: string;\n order: number;\n title: string;\n type: string;\n description: string;\n dependencies: string[];\n assignedRunner: RunnerId;\n assignedModel: Task['assignedModel'] | null;\n taskMode: string;\n prompt: string | null;\n subtasks: SerializedTask[];\n userSteps: Task['userSteps'];\n thinkingEffort: Task['thinkingEffort'];\n autonomy: Task['autonomy'];\n sliceType: Task['sliceType'];\n userStoriesCovered: Task['userStoriesCovered'];\n};\n\nexport type SerializedPlan = {\n tasks: SerializedTask[];\n runners: RunnerId[];\n generatedAt: string;\n conversationHistory?: LegacyPlanState['conversationHistory'];\n prdMarkdown?: string;\n queuedMessages?: QueuedMessage[];\n};\n\nexport type SessionMessage =\n | { type: 'plan_generated'; plan: SerializedPlan; goal: string; runners: RunnerId[] }\n | { type: 'planner_message'; content: string; timestamp: string }\n | { type: 'status_update'; tasks: SerializedTaskStatus[] }\n | { type: 'review_needed'; tasks: SerializedTask[] }\n | { type: 'review_approved' }\n | { type: 'checkpoint'; taskId: string; taskTitle: string; summary: string }\n | { type: 'execution_complete'; summary: { total: number; completed: number; failed: number } }\n | { type: 'execution_stopped' }\n | { type: 'queue_ready' }\n | { type: 'task_updated'; taskId: string; changes: Record<string, unknown> }\n | { type: 'task_started'; taskId: string; order: number; title: string; runner: RunnerId; modelId?: string }\n | { type: 'task_output'; taskId: string; text: string }\n | { type: 'plan_thinking'; text: string }\n // `toolLabel` carries a harness planner's own name for the tool (ADR-0009) —\n // always set when `tool` is `agent_tool`, so no surface has to render the\n // catch-all member name at the user.\n | { type: 'research_step'; tool: string; toolLabel?: string; args: string; subagentId?: string; toolCallId?: string }\n | { type: 'plan_token'; token: string }\n | { type: 'research_step_done'; step: ResearchStep; subagentId?: string }\n // Planner research wants something outside its default envelope and is\n // blocked until a human answers. Broadcast rather than returned, because the\n // human may be on any surface (or several at once) and the request outlives\n // whichever HTTP call triggered it.\n | { type: 'approval_request'; id: string; kind: ApprovalKind; subject: string; scope: string; detail?: string }\n | { type: 'approval_settled'; id: string; granted: boolean }\n // A decision reached with no round-trip prompt: pre-approved via config,\n // remembered from earlier in this session, or the operator's mode floor\n // (allow/deny skipping the human entirely). The interactive path above\n // already has full visibility via approval_request/approval_settled; this\n // is the one that previously had none — a model silently auto-running\n // `npm test` because the scope was already granted looked identical, from\n // every UI, to it never having been asked in the first place.\n | {\n type: 'approval_decided';\n kind: ApprovalKind;\n subject: string;\n scope: string;\n detail?: string;\n granted: boolean;\n source: Exclude<ApprovalSource, 'asked'>;\n };\n\nexport type SessionBroadcaster = (msg: SessionMessage) => void;\n\nexport function serializeTask(t: Task): SerializedTask {\n return {\n id: t.id,\n order: t.order,\n title: t.title,\n type: t.type,\n description: t.description,\n dependencies: t.dependencies || [],\n assignedRunner: t.assignedRunner,\n assignedModel: t.assignedModel || null,\n taskMode: t.taskMode || 'build',\n prompt: t.prompt || null,\n subtasks: (t.subtasks || []).map(serializeTask),\n userSteps: t.userSteps || undefined,\n thinkingEffort: t.thinkingEffort || undefined,\n autonomy: t.autonomy || undefined,\n sliceType: t.sliceType || undefined,\n userStoriesCovered: t.userStoriesCovered || undefined,\n };\n}\n\nexport function serializeTaskStatus(t: Task): SerializedTaskStatus {\n return {\n id: t.id,\n status: t.status,\n verdict: t.verdict\n ? { outcome: t.verdict.outcome, reason: t.verdict.reason, checks: t.verdict.checks || [] }\n : null,\n };\n}\n\nexport function serializePlan(plan: LegacyPlanState): SerializedPlan {\n return {\n tasks: plan.tasks.map(serializeTask),\n runners: plan.runners,\n generatedAt: plan.generatedAt,\n conversationHistory: plan.conversationHistory,\n prdMarkdown: plan.prdMarkdown,\n queuedMessages: plan.queuedMessages,\n };\n}\n\nexport function executionSummary(tasks: Task[]): { total: number; completed: number; failed: number } {\n return {\n total: tasks.length,\n completed: tasks.filter((t) => t.status === 'completed').length,\n failed: tasks.filter((t) => t.status === 'failed').length,\n };\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport type { LegacyPlanState, PlanState } from '../models/Task';\nimport { migratePlanState } from '../models/Task';\nimport type { SessionMeta, SessionData } from '../models/Session';\nimport { defaultLogger, type ILogger } from '../interfaces/ILogger';\nimport { getStateDir, ensureDir } from './fsHelpers';\n\nconst SESSIONS_SUBDIR = 'sessions';\n\nfunction getSessionsDir(baseDir?: string): string {\n return path.join(getStateDir(baseDir), SESSIONS_SUBDIR);\n}\n\nconst REJECTION_MESSAGE = 'This session was created with an older version of Ordewell. Please re-plan.';\n\nfunction hasScalarRunner(parsed: Record<string, unknown>): boolean {\n const meta = parsed.meta as Record<string, unknown> | undefined;\n const plan = parsed.plan as Record<string, unknown> | undefined;\n return (typeof meta?.runner === 'string') || (typeof plan?.runner === 'string');\n}\n\nfunction sanitizeName(goal: string): string {\n return goal\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 40);\n}\n\nfunction sessionFilename(session: SessionMeta): string {\n const date = new Date(session.createdAt).toISOString().replace(/:/g, '-').replace(/\\..+/, '');\n const name = sanitizeName(session.goal);\n return `${date}_${name || 'session'}_${session.id.slice(0, 8)}.json`;\n}\n\nexport function saveSession(plan: LegacyPlanState, goal: string, baseDir?: string, id?: string): SessionMeta {\n const sessionsDir = getSessionsDir(baseDir);\n ensureDir(sessionsDir);\n\n const now = new Date().toISOString();\n\n const meta: SessionMeta = {\n id: id || `session-${Date.now()}`,\n goal: goal || '(untitled)',\n runners: plan.runners,\n taskCount: plan.tasks.flatMap((t) => [t, ...(((t as unknown) as { subtasks?: unknown[] }).subtasks || [])]).length,\n status: plan.status,\n createdAt: plan.generatedAt || now,\n updatedAt: now,\n };\n\n const session: SessionData = {\n meta,\n plan: JSON.parse(JSON.stringify(plan)),\n };\n\n const filename = sessionFilename(meta);\n const filePath = path.join(sessionsDir, filename);\n\n fs.writeFileSync(filePath, JSON.stringify(session, null, 2));\n\n return meta;\n}\n\nexport function listSessions(baseDir?: string, logger: ILogger = defaultLogger): SessionMeta[] {\n const sessionsDir = getSessionsDir(baseDir);\n if (!fs.existsSync(sessionsDir)) return [];\n\n const files = fs.readdirSync(sessionsDir).filter((f) => f.endsWith('.json'));\n\n return files\n .map((f) => {\n try {\n const raw = fs.readFileSync(path.join(sessionsDir, f), 'utf-8');\n const parsed = JSON.parse(raw);\n if (hasScalarRunner(parsed)) {\n logger.warn('sessionStore', `session file ${f}: ${REJECTION_MESSAGE}`);\n return null;\n }\n const session = parsed as SessionData;\n return session.meta;\n } catch (err: unknown) {\n logger.warn('sessionStore', `failed to read session file ${f}; skipping`, err);\n return null;\n }\n })\n .filter((m): m is SessionMeta => m !== null)\n .sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());\n}\n\nfunction findSessionFile(sessionsDir: string, sessionId: string, logger: ILogger): string | null {\n const files = fs.readdirSync(sessionsDir).filter((f) => f.endsWith('.json'));\n for (const f of files) {\n try {\n const raw = fs.readFileSync(path.join(sessionsDir, f), 'utf-8');\n const session = JSON.parse(raw) as SessionData;\n if (session.meta.id === sessionId) return f;\n } catch (err: unknown) {\n logger.warn('sessionStore', `failed to read session file ${f}; skipping`, err);\n }\n }\n return null;\n}\n\nexport function loadSession(sessionId: string, baseDir?: string, logger: ILogger = defaultLogger): { meta: SessionMeta; plan: LegacyPlanState } | null {\n const sessionsDir = getSessionsDir(baseDir);\n if (!fs.existsSync(sessionsDir)) return null;\n try {\n const file = findSessionFile(sessionsDir, sessionId, logger);\n if (file) {\n const raw = fs.readFileSync(path.join(sessionsDir, file), 'utf-8');\n const parsed = JSON.parse(raw);\n if (hasScalarRunner(parsed)) {\n logger.warn('sessionStore', `session file ${file}: ${REJECTION_MESSAGE}`);\n return null;\n }\n const session = parsed as SessionData;\n const plan = session.plan as LegacyPlanState;\n // Nothing is running when a session comes off disk — an in_progress\n // status is an orphan from an interrupted run; give it a fresh chance.\n for (const t of plan.tasks.flatMap((task) => [task, ...(task.subtasks ?? [])])) {\n if (t.status === 'in_progress') t.status = 'pending';\n }\n return { meta: session.meta, plan };\n }\n } catch (err: unknown) {\n logger.warn('sessionStore', `failed to list sessions directory while searching for ${sessionId}`, err);\n }\n return null;\n}\n\nexport function loadSessionPlanState(sessionId: string, baseDir?: string, logger: ILogger = defaultLogger): { meta: SessionMeta; plan: PlanState } | null {\n const result = loadSession(sessionId, baseDir, logger);\n if (!result) return null;\n return { meta: result.meta, plan: migratePlanState(result.plan) };\n}\n\nexport function getLatestSession(baseDir?: string, logger: ILogger = defaultLogger): { meta: SessionMeta; plan: LegacyPlanState } | null {\n const sessions = listSessions(baseDir, logger);\n if (sessions.length === 0) return null;\n return loadSession(sessions[0].id, baseDir, logger);\n}\n\nexport function deleteSession(sessionId: string, baseDir?: string, logger: ILogger = defaultLogger): boolean {\n const sessionsDir = getSessionsDir(baseDir);\n if (!fs.existsSync(sessionsDir)) return false;\n try {\n const file = findSessionFile(sessionsDir, sessionId, logger);\n if (file) { fs.unlinkSync(path.join(sessionsDir, file)); return true; }\n } catch (err: unknown) {\n logger.warn('sessionStore', `failed to list sessions directory for deletion of ${sessionId}`, err);\n }\n return false;\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\n\nexport const STATE_DIR = '.ordewell';\n\nexport function ensureDir(dir: string): void {\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n}\n\nexport function getStateDir(baseDir?: string): string {\n return path.join(baseDir ?? process.cwd(), STATE_DIR);\n}\n","import { createAiService, type IAiService, type ConversationTurn } from './AiService';\nimport { applyTaskOps, canMergeTasks, canSetDependencies, canSplitTask } from './TaskOps';\nimport { repairLoop, taskOpsRejectedPrompt } from './PlanRepair';\nimport { Planner } from './Planner';\nimport { TaskOrchestrator } from './TaskOrchestrator';\nimport type { OrchestratorObserver } from './TaskOrchestrator';\nimport { PlanStore } from './PlanStore';\nimport { ApprovalPolicy } from './ApprovalPolicy';\nimport { PendingApprovals, type PendingApproval } from './PendingApprovals';\nimport { HttpWebFetcher } from './HttpWebFetcher';\nimport { ModelResolver } from './ModelResolver';\nimport { filterModelsForPrompt, coerceAssignments, effectiveAllowlist } from './ModelAllowlistResolver';\nimport { retargetTaskRunner, runnerAssignment, type RunnerCatalog } from './TaskRetarget';\nimport { plannerModesFrom, plannerRuntimeToggles } from './plannerModes';\nimport type { UserSettings } from './SettingsService';\nimport { buildMergePrompt, buildSplitPrompt } from './PlanPrompts';\nimport {\n serializeTask,\n serializeTaskStatus,\n serializePlan,\n executionSummary,\n type SessionBroadcaster,\n} from './SessionMessage';\nimport { saveSession } from '../utils/sessionStore';\nimport { savePrdMarkdown, extractPrdBlock } from '../utils/prdStore';\nimport { type ConversationMessage, type DiscoveredModel, type LegacyPlanState, type PlanState, type Task, type TaskSnapshot, type RunnerId, type ResearchProgress } from '../models/Task';\nimport type { AiProvider, IConfig } from '../interfaces/IConfig';\nimport type { IFileSystem } from '../interfaces/IFileSystem';\nimport type { INotification } from '../interfaces/INotification';\nimport type { ITerminalRunner } from '../interfaces/ITerminalRunner';\nimport type { RunnerRegistry } from '../plugins/RunnerRegistry';\nimport { runnerModesFrom, type RunnerModeInfo } from './ModeResolver';\n\n/**\n * Options for plan generation. Progress is not overridable: every planner\n * progress event is translated to a SessionMessage inside the Session and\n * emitted through the broadcast seam, so all surfaces consume one union.\n */\nexport interface GeneratePlanOptions {\n signal?: AbortSignal;\n}\n\n/** The slice of Planner the Session drives — the injection seam for tests. */\nexport type SessionPlanner = Pick<Planner, 'generate' | 'modify' | 'modifyDuringExecution'>;\n\n/** Runtime prefs read live — may toggle between operations. */\nexport interface SessionRuntimeSettings {\n tddEnabled: boolean;\n grillMeEnabled: boolean;\n prdEnabled?: boolean;\n reviewEnabled?: boolean;\n verificationEnabled?: boolean;\n researchSubagentsEnabled?: boolean;\n modelAllowlist?: Record<string, string[]>;\n}\n\n/**\n * The whole of what a host reads off disk for a Session. Both hosts used to\n * assemble this by hand, mapping each toggle's settings key to its runtime key\n * in two blocks nothing kept in step — which is how one toggle came to be\n * dropped. `MODE_TOGGLES` holds the mapping now; this adds the one field that\n * is not a toggle.\n */\nexport function sessionRuntimeSettings(settings: UserSettings): SessionRuntimeSettings {\n return { ...plannerRuntimeToggles(settings), modelAllowlist: settings.modelAllowlist };\n}\n\n/**\n * Everything a delivery surface constructs to host a session. Structural config\n * (enabledRunners, orchestratorModel, providerModelLists) is snapshotted inside\n * `config` at construction and never re-read from the environment. Runtime\n * settings (tdd, grillMe) are read live via the `settings` callback so a toggle\n * between generate and execute takes effect.\n */\nexport interface SessionDeps {\n config: IConfig;\n notifications: INotification;\n runner: ITerminalRunner;\n registry: RunnerRegistry;\n /** Resolves the workspace root for the orchestrator (lazy — VS Code can change it). */\n workspaceRoot: () => string;\n /** Filesystem adapter for planner research. */\n fsAdapter: IFileSystem;\n /** Emits plan-lifecycle events to the surface. Transport-agnostic. */\n broadcast: SessionBroadcaster;\n /** Shared across sessions — sole producer of model catalogs and routing lists. */\n modelResolver: ModelResolver;\n /** Live runtime settings (tdd, grillMe). Read at each operation that needs them. */\n settings: () => SessionRuntimeSettings;\n /**\n * Host-assigned session id. When set, every persist writes under this id so\n * the host's REST/UI ids match the saved-session store. When omitted, the\n * Session mints a fresh id per plan (generatePlan/startPlanning).\n */\n sessionId?: string;\n /**\n * Planner-conversation seam. Defaults to the provider service for\n * `config.aiProvider`; inject a fake to test the conversation half without\n * an LLM.\n */\n aiService?: IAiService;\n /** Plan-generation seam. Defaults to a Planner over the session's aiService. */\n planner?: SessionPlanner;\n}\n\n// Session ids are timestamp-based; two mints inside the same millisecond\n// (e.g. reset() right after construction) must still differ or they'd share\n// one persisted session file.\nlet lastMintedAt = 0;\nfunction mintSessionId(): string {\n lastMintedAt = Math.max(Date.now(), lastMintedAt + 1);\n return `session-${lastMintedAt}`;\n}\n\n/**\n * The per-session execution stack — deepened from a wiring bag into the\n * lifecycle owner. Owns plan generation, execution, mutation, persistence, and\n * the orchestrator observer wiring. The orchestrator's observer is subscribed\n * once for the session's lifetime (not per-operation), which kills the\n * double-subscribe class of bug. Persistence is an internal seam: every plan\n * mutation routes through `persist()`, so the obligation has a home instead of\n * being scattered across 11 call sites.\n *\n * The broadcast seam carries {@link SessionMessage} — the 15 plan-lifecycle\n * events. Catalog/config messages (setModels, setRunnerList, …) stay on the\n * host; Session never emits them.\n */\nexport class Session {\n /** Injected by a test; when present it is the service, forever. */\n private readonly pinnedAiService?: IAiService;\n private liveAiService: IAiService | null = null;\n private liveAiProvider: AiProvider | null = null;\n private readonly workspaceRootFn: () => string;\n private planner: SessionPlanner;\n private orchestrator: TaskOrchestrator;\n private store: PlanStore;\n private config: IConfig;\n private registry: RunnerRegistry;\n private plan: LegacyPlanState | null = null;\n private goal = '';\n private workspace: string;\n private broadcast: SessionBroadcaster;\n private modelResolver: ModelResolver;\n private fsAdapter: IFileSystem;\n private approvals: PendingApprovals;\n private approvalPolicy: ApprovalPolicy;\n private fetcher: HttpWebFetcher;\n private settingsFn: () => SessionRuntimeSettings;\n private currentAllowlist: Record<string, string[]> = {};\n /** Last discovered model catalog — lets sync plan commits clamp thinking efforts to real variants. */\n private modelsCache: Partial<Record<RunnerId, DiscoveredModel[]>> = {};\n private unsubObserver: (() => void) | null = null;\n private readonly hostSessionId?: string;\n private currentSessionId: string;\n\n constructor(deps: SessionDeps) {\n this.config = deps.config;\n this.registry = deps.registry;\n this.pinnedAiService = deps.aiService;\n this.workspaceRootFn = deps.workspaceRoot;\n this.planner = deps.planner ?? new Planner(deps.config, () => this.aiService);\n this.store = new PlanStore();\n this.orchestrator = new TaskOrchestrator(deps.config, deps.notifications, deps.runner, this.store);\n this.orchestrator.setRegistry(deps.registry);\n this.orchestrator.setWorkspaceRoot(deps.workspaceRoot);\n this.orchestrator.setTddEnabled(() => this.settingsFn().tddEnabled);\n this.workspace = deps.workspaceRoot();\n this.broadcast = deps.broadcast;\n this.modelResolver = deps.modelResolver;\n this.fsAdapter = deps.fsAdapter;\n this.settingsFn = deps.settings;\n this.hostSessionId = deps.sessionId;\n this.currentSessionId = deps.sessionId ?? mintSessionId();\n\n // The approval chain, wired once per session: the filesystem asks the\n // policy, the policy asks the registry, the registry announces on the same\n // broadcast seam every other planner event uses, and any surface answers\n // through `resolveApproval`. Nothing in core knows which UI is listening.\n this.approvals = new PendingApprovals({\n onRequest: ({ id, request }) => this.broadcast({\n type: 'approval_request',\n id,\n kind: request.kind,\n subject: request.subject,\n scope: request.scope,\n detail: request.detail,\n }),\n onSettled: (id, granted) => this.broadcast({ type: 'approval_settled', id, granted }),\n });\n this.approvalPolicy = new ApprovalPolicy({\n mode: this.config.approvalMode,\n preApproved: this.config.approvalPreApproved,\n ask: (req) => this.approvals.ask(req),\n // The interactive path (`asked`) already broadcasts approval_request +\n // approval_settled; only the silent sources need a signal, or a\n // remembered/pre-approved/mode grant is invisible to every surface.\n onDecision: (req, granted, source) => {\n if (source === 'asked') return;\n this.broadcast({\n type: 'approval_decided',\n kind: req.kind,\n subject: req.subject,\n scope: req.scope,\n detail: req.detail,\n granted,\n source,\n });\n },\n });\n this.fsAdapter.setApproval?.(this.approvalPolicy);\n // `fetch`/`web_search` route through the same approval channel as paths and\n // commands — one decision surface for everything that leaves the workspace.\n this.fetcher = new HttpWebFetcher({ approval: this.approvalPolicy });\n\n this.attachObserver();\n }\n\n /**\n * The planner transport for the provider configured *right now* (ADR-0009).\n *\n * Resolved on every read rather than once in the constructor, because a\n * Session outlives the choice: VS Code hosts exactly one for the whole\n * window, and the webview pills and `/planner` switch backends underneath it.\n * The model id was already read live, so a service captured at construction\n * meant a switched planner kept the old backend and got handed the new one's\n * model — an OpenCode model id spawned as `claude --model opencode/…`, which\n * the agent rejects as nonexistent.\n *\n * Switching releases the outgoing service: a harness planner holds an OS\n * process, so dropping the reference without `reset()` leaks an agent.\n */\n private get aiService(): IAiService {\n if (this.pinnedAiService) return this.pinnedAiService;\n const provider = this.config.aiProvider;\n if (this.liveAiService && this.liveAiProvider === provider) return this.liveAiService;\n this.liveAiService?.reset();\n this.liveAiService = createAiService(this.config, { workspaceRoot: this.workspaceRootFn });\n this.liveAiProvider = provider;\n return this.liveAiService;\n }\n\n /**\n * Answer an outstanding approval. Every surface funnels here — the web\n * server's HTTP route, the VS Code webview, the TUI prompt — so the decision\n * path is identical regardless of who is looking.\n */\n resolveApproval(id: string, granted: boolean): boolean {\n return this.approvals.resolve(id, granted);\n }\n\n /** Requests still waiting for an answer, replayed to a surface that connects mid-prompt. */\n outstandingApprovals(): PendingApproval[] {\n return this.approvals.outstanding();\n }\n\n /** Scopes the user granted this session — surfaced so a UI can show what is already allowed. */\n approvedScopes(): string[] {\n return this.approvalPolicy.grantedScopes();\n }\n\n /** The stable id this session persists under — matches the host's id when one was provided. */\n get sessionId(): string { return this.currentSessionId; }\n get executionLog(): TaskSnapshot[] { return this.store.getExecutionLog(); }\n /** Tasks always read from PlanStore — the single source of truth. */\n get planTasks(): Task[] { return this.store.planTasks; }\n\n private attachObserver(): void {\n if (this.unsubObserver) this.unsubObserver();\n this.unsubObserver = this.orchestrator.subscribe(this.buildObserver());\n }\n\n private buildObserver(): OrchestratorObserver {\n return {\n onTaskChanged: () => {\n if (!this.plan) return;\n const tasks = this.store.allTasks;\n this.broadcast({ type: 'status_update', tasks: tasks.map(serializeTaskStatus) });\n },\n onQueueReady: () => {\n this.broadcast({ type: 'queue_ready' });\n },\n onReviewNeeded: () => {\n const tasks = this.store.allTasks;\n this.broadcast({ type: 'review_needed', tasks: tasks.map(serializeTask) });\n },\n onReviewApproved: () => {\n this.broadcast({ type: 'review_approved' });\n },\n onCheckpoint: (data) => {\n this.broadcast({ type: 'checkpoint', taskId: data.taskId, taskTitle: data.taskTitle, summary: data.summary });\n },\n onTick: () => {\n if (!this.plan) return;\n const tasks = this.store.allTasks;\n this.broadcast({ type: 'status_update', tasks: tasks.map(serializeTaskStatus) });\n },\n onExecutionComplete: () => {\n if (!this.plan) return;\n const tasks = this.store.allTasks;\n this.broadcast({ type: 'execution_complete', summary: executionSummary(tasks) });\n this.persist();\n },\n };\n }\n\n private translateProgress(progress: ResearchProgress): void {\n if (progress.type === 'thinking' && progress.text) {\n this.broadcast({ type: 'plan_thinking', text: progress.text });\n }\n if (progress.type === 'tool_call' && progress.tool) {\n this.broadcast({ type: 'research_step', tool: progress.tool, toolLabel: progress.toolLabel, args: progress.toolArgs || '', subagentId: progress.subagentId, toolCallId: progress.toolCallId });\n }\n if (progress.type === 'plan_token' && progress.planToken) {\n this.broadcast({ type: 'plan_token', token: progress.planToken });\n }\n if (progress.type === 'tool_result' && progress.step) {\n this.broadcast({ type: 'research_step_done', step: progress.step, subagentId: progress.subagentId });\n }\n }\n\n /** Persists PlanStore state to disk. PlanStore is the single authority;\n * LegacyPlanState.tasks is populated only here, at persist time. */\n private persist(): void {\n if (!this.plan) return;\n this.plan.tasks = this.store.planTasks;\n this.plan.lastUpdated = new Date().toISOString();\n saveSession(this.plan, this.goal, this.workspace, this.currentSessionId);\n }\n\n /** A new plan on a long-lived Session gets its own persisted identity (unless the host fixed one). */\n private remintSessionId(): void {\n if (!this.hostSessionId) this.currentSessionId = mintSessionId();\n }\n\n /**\n * A new plan starts from zero: drop the live planner conversation and every\n * task, log, and queued message left over from a previous plan on this\n * Session. Without this, a long-lived Session (VS Code hosts exactly one)\n * leaks the previous session's tasks into `planContextBlock()` — the model\n * is told they are the CURRENT plan and re-presents them as its draft.\n */\n private beginFreshPlan(): void {\n if (this.isExecuting) this.stopExecution();\n this.aiService.reset();\n // A prompt raised by the turn we are abandoning has nobody left to serve;\n // denying it unblocks the old research loop instead of stranding it.\n this.approvals.clear();\n this.orchestrator.clearQueuedMessages();\n this.store.clearLog();\n this.orchestrator.loadPlan([]);\n }\n\n /**\n * Return the Session to a blank slate — hosts call this on \"new session\".\n * Everything scoped to the old session goes: the live AI conversation, plan,\n * goal, tasks, execution log, queued messages, model cache, and (unless the\n * host fixed one) the persisted identity, so nothing can bleed into the next\n * session.\n */\n reset(): void {\n // Null the plan first so orchestrator-stop observer callbacks\n // (onTaskChanged → status_update) no-op instead of broadcasting the\n // dying session's tasks.\n this.plan = null;\n this.goal = '';\n this.beginFreshPlan();\n // Session boundaries are hard (see ADR-0008): a path or command the user\n // approved for the previous goal must not stay approved for the next one.\n this.approvalPolicy.reset();\n this.modelsCache = {};\n this.currentAllowlist = {};\n this.remintSessionId();\n }\n\n private runnerModesFor(runners: RunnerId[]): Record<RunnerId, RunnerModeInfo[]> {\n return runnerModesFrom(this.registry, runners);\n }\n\n get planState(): LegacyPlanState | null { return this.plan; }\n\n /**\n * The live plan in the shape a saved session is read back as. The disk\n * boundary rewrites `in_progress` to `pending` — nothing is running when a\n * session comes off a file — so a surface that re-reads the plan mid-run must\n * come here instead, or every task it is watching reads as never started.\n */\n get currentPlanState(): PlanState | null {\n if (!this.plan) return null;\n const executionLog = this.store.getExecutionLog();\n const logged = new Set(executionLog.map((s) => s.id));\n const pendingTasks = this.store.planTasks.filter((t) => !logged.has(t.id));\n if (executionLog.length === 0 && !this.orchestrator.isRunning) {\n return { phase: 'planning', history: [], message: '', pendingTasks };\n }\n return {\n phase: 'executing',\n history: [],\n message: '',\n executionLog,\n pendingTasks,\n goal: this.goal,\n runners: this.plan.runners,\n status: this.plan.status,\n };\n }\n\n get currentGoal(): string { return this.goal; }\n get isPlanning(): boolean { return !this.orchestrator.isRunning; }\n get isExecuting(): boolean { return this.orchestrator.isRunning; }\n get status(): 'approved' | 'running' | 'completed' { return this.orchestrator.status; }\n get sessionConfig(): IConfig { return this.config; }\n\n async startExecution(): Promise<void> {\n if (!this.plan || !this.store.planTasks.length) throw new Error('No plan to execute');\n this.store.clearLog();\n this.plan.status = 'approved';\n this.store.resetForRun();\n this.orchestrator.loadPlan(this.store.planTasks, this.plan.runners);\n await this.orchestrator.start();\n }\n\n async generatePlan(goal: string, runners: RunnerId[], options?: GeneratePlanOptions): Promise<LegacyPlanState> {\n this.plan = null;\n this.goal = goal;\n this.remintSessionId();\n this.beginFreshPlan();\n const enabled = this.config.enabledRunners;\n const chosenRunners = runners.filter((r) => enabled.includes(r));\n if (chosenRunners.length === 0) throw new Error('None of the requested runners are enabled');\n\n const modelsByRunner = await this.modelResolver.modelsForRunners(chosenRunners);\n this.modelsCache = modelsByRunner;\n const runnerModes = this.runnerModesFor(chosenRunners);\n // Every planner toggle, not the two this path used to remember: `modesFor`\n // drops the ones a one-shot run cannot honour, so review — which only\n // appends a task — stops being silently lost between here and the prompt.\n const settings = this.settingsFn();\n const { modelAllowlist } = settings;\n const modes = plannerModesFrom(settings, this.config.autonomousMode);\n\n const plan = await this.planner.generate({\n goal,\n runners: chosenRunners,\n modelsByRunner,\n runnerModes,\n autonomousDefault: this.config.autonomousMode,\n fs: this.fsAdapter,\n fetcher: this.fetcher,\n onProgress: (p) => this.translateProgress(p),\n signal: options?.signal,\n perRunnerAllowlist: modelAllowlist,\n modes,\n });\n\n this.plan = plan;\n this.orchestrator.loadPlan(plan.tasks, plan.runners);\n this.store.resetForRun({ preserveCompleted: false });\n this.persist();\n this.broadcastPlan();\n return plan;\n }\n\n /**\n * Kick off the planner conversation (ADR-0002): research + the first planner\n * message. The AI service retains the tool-use history; the Session persists\n * the user/assistant dialogue on the plan state.\n */\n async startPlanning(goal: string, runners: RunnerId[], options?: GeneratePlanOptions): Promise<LegacyPlanState> {\n this.plan = null;\n this.goal = goal;\n this.remintSessionId();\n this.beginFreshPlan();\n const enabled = this.config.enabledRunners;\n const chosenRunners = runners.filter((r) => enabled.includes(r));\n if (chosenRunners.length === 0) throw new Error('None of the requested runners are enabled');\n\n const modelsByRunner = await this.modelResolver.modelsForRunners(chosenRunners);\n this.modelsCache = modelsByRunner;\n const runnerModes = this.runnerModesFor(chosenRunners);\n const { grillMeEnabled, prdEnabled, reviewEnabled, verificationEnabled, researchSubagentsEnabled, modelAllowlist } = this.settingsFn();\n this.currentAllowlist = modelAllowlist ?? {};\n const filteredModels = filterModelsForPrompt(modelsByRunner, this.currentAllowlist);\n\n const now = new Date().toISOString();\n this.plan = {\n tasks: [],\n generatedAt: now,\n status: 'draft',\n runners: chosenRunners,\n lastUpdated: now,\n researchLog: [{ id: `up-${Date.now()}`, type: 'user_prompt', content: goal, timestamp: now }],\n conversationHistory: [{ role: 'user', content: goal, timestamp: now }],\n };\n\n const turn = await this.aiService.startConversation({\n goal,\n runners: chosenRunners,\n modelsByRunner: filteredModels,\n runnerModes,\n autonomousDefault: this.config.autonomousMode,\n grillMeEnabled: grillMeEnabled ?? false,\n prdEnabled: prdEnabled ?? false,\n reviewEnabled: reviewEnabled ?? false,\n verificationEnabled: verificationEnabled ?? false,\n researchSubagentsEnabled: researchSubagentsEnabled ?? false,\n fs: this.fsAdapter,\n fetcher: this.fetcher,\n onProgress: (p) => this.translateProgress(p),\n signal: options?.signal,\n });\n\n return this.settleTurn(turn, options);\n }\n\n /**\n * Every subsequent user reply in the planning conversation — grill-me\n * answers, PRD accept/adjust, outline confirm. One branch, no phase ladder.\n */\n async continueConversation(userMessage: string, options?: GeneratePlanOptions): Promise<LegacyPlanState> {\n if (!this.plan) throw new Error('No planning conversation to continue');\n const priorHistory = this.plan.conversationHistory ?? [];\n const now = new Date().toISOString();\n this.appendTranscript('user', userMessage, now);\n this.plan.researchLog = [...(this.plan.researchLog ?? []), { id: `up-${Date.now()}`, type: 'user_prompt', content: userMessage, timestamp: now }];\n\n // The persisted transcript keeps the raw user message; the model gets the\n // current plan (tasks, statuses, edit protocol) alongside it.\n const contextBlock = this.planContextBlock();\n const outgoing = contextBlock ? `${contextBlock}\\n\\n${userMessage}` : userMessage;\n\n // A live conversation is only safe to continue in-place when it also\n // matches the model/effort configured right now — a harness planner's\n // running process was spawned with the old one baked in and cannot pick\n // up a switch (ADR-0009). `resumeConversation` handles both cases the\n // same way: tear down and restart, folding the transcript so far into the\n // opening message.\n const aiService = this.aiService;\n const canContinueLive = aiService.hasActiveConversation() && (aiService.conversationMatchesConfig?.() ?? true);\n let turn = canContinueLive\n ? await aiService.continueConversation(\n outgoing,\n (p) => this.translateProgress(p),\n options?.signal,\n )\n : await this.resumeConversation(outgoing, priorHistory, options);\n\n // Structural changes while tasks execute are queued, never applied live —\n // the orchestrator must not have the plan mutated under a running batch.\n if ((turn.kind === 'task_ops' || turn.kind === 'plan') && this.isExecuting) {\n this.queueMessage(userMessage);\n this.plan.queuedMessages = this.getQueuedMessages();\n turn = {\n kind: 'message',\n text: `Execution is running, so I queued your change — it will be applied between task batches (${this.queuedCount} queued).`,\n researchLog: turn.researchLog,\n };\n }\n\n return this.settleTurn(turn, options);\n }\n\n /**\n * Drive a planner turn to a persisted, broadcast outcome. Task edits apply\n * atomically; validation failures are fed back to the model for up to 2\n * silent retries, then surfaced as a message with the plan untouched. The\n * first turn (startPlanning) and every later turn route through here — one\n * path, not two.\n */\n private async settleTurn(turn: ConversationTurn, options?: GeneratePlanOptions): Promise<LegacyPlanState> {\n type Settled = { plan: LegacyPlanState } | { turn: Exclude<ConversationTurn, { kind: 'task_ops' }> };\n const invalidOps = (errors: string[], researchLog: ConversationTurn['researchLog']): Settled => ({\n turn: {\n kind: 'message',\n text: `I tried to modify the tasks, but the changes were invalid:\\n- ${errors.join('\\n- ')}\\n\\nThe plan is unchanged. Rephrase the request, or adjust the tasks manually.`,\n researchLog,\n },\n });\n\n const settled = await repairLoop<ConversationTurn, Settled>({\n first: () => turn,\n resend: (corrective) => this.aiService.continueConversation(\n corrective,\n (p) => this.translateProgress(p),\n options?.signal,\n ),\n interpret: (t) => {\n if (t.kind !== 'task_ops') return { done: { turn: t } };\n const applied = this.applyTaskOpsTurn(t);\n if ('plan' in applied) return { done: { plan: applied.plan } };\n // No live conversation (or an abort) means no corrective re-send is\n // possible — surface the failure instead of retrying into the void.\n if (!this.aiService.hasActiveConversation() || options?.signal?.aborted) {\n return { done: invalidOps(applied.errors, t.researchLog) };\n }\n return { retry: { errors: applied.errors, corrective: taskOpsRejectedPrompt(applied.errors) } };\n },\n maxRepairs: 2,\n onExhausted: ({ reply, errors }) => invalidOps(errors, reply.researchLog),\n });\n\n if ('plan' in settled) return settled.plan;\n return this.applyConversationTurn(settled.turn);\n }\n\n /**\n * The \"you are here\" block for post-plan chat: current tasks with stable\n * references, plus the task-ops protocol. Injected per turn (never\n * persisted) so the model always sees live statuses — including which tasks\n * are locked by a running execution.\n */\n private planContextBlock(): string | null {\n if (!this.plan || this.store.planTasks.length === 0) return null;\n const orderOf = new Map(this.store.planTasks.map((t) => [t.id, `#${t.order}`]));\n const lines = this.store.planTasks.map((t) =>\n `#${t.order} id=${t.id} \"${t.title}\" [${t.status}] runner:${t.assignedRunner}${t.assignedModel ? ` model:${t.assignedModel.modelId}` : ''} deps:[${t.dependencies.map((d) => orderOf.get(d) ?? d).join(', ')}]`,\n );\n const running = this.store.planTasks.filter((t) => t.status === 'in_progress');\n const execNote = this.isExecuting\n ? `\\nExecution is RUNNING${running.length ? ` — these tasks are locked: ${running.map((t) => `#${t.order}`).join(', ')}` : ''}. Any task edits you emit will be queued and applied between batches.`\n : '';\n // Compact model availability so any task edit (add/merge/split/update) can\n // assign a valid runner + model without scrolling back to the system prompt.\n const modelLines: string[] = [];\n for (const runner of this.plan.runners) {\n const models = this.modelsCache[runner] ?? [];\n const ids = models.map((m) => m.modelId).join(', ');\n modelLines.push(`${runner}: ${ids || '(no models discovered)'}`);\n }\n const modelBlock = modelLines.length > 0\n ? ['<available_models>', ...modelLines, '</available_models>'].join('\\n')\n : '';\n return [\n '<current_plan>',\n ...lines,\n '</current_plan>',\n modelBlock,\n 'The block above is the CURRENT task plan. Choose how to respond:',\n '- To answer a question or discuss, reply in plain prose (no JSON).',\n '- To modify specific tasks, reply with ONLY this JSON object:',\n ' {\"taskOps\": [',\n ' {\"op\":\"update\",\"taskId\":\"<id or #order>\",\"changes\":{\"title\"?,\"description\"?,\"prompt\"?,\"dependencies\"?:[\"<id or #order>\"],\"assignedRunner\"?,\"assignedModel\"?,\"taskMode\"?}},',\n ' {\"op\":\"add\",\"task\":{\"title\",\"description\",\"prompt\",\"dependencies\":[\"<id or #order>\"],\"assignedRunner\"?,\"assignedModel\"?}},',\n ' {\"op\":\"remove\",\"taskId\":\"<id or #order>\"},',\n ' {\"op\":\"reorder\",\"taskIds\":[\"<id or #order>\", \"... every task exactly once\"]},',\n ' {\"op\":\"merge\",\"taskIds\":[\"<id or #order>\", \"...\"],\"merged\":{\"title\",\"description\",\"prompt\"?,\"assignedRunner\"?,\"assignedModel\"?,...}},',\n ' {\"op\":\"split\",\"taskId\":\"<id or #order>\",\"parts\":[{\"title\",\"description\",\"prompt\"?,\"assignedRunner\"?,\"assignedModel\"?,...}, ...]}',\n ' ]}',\n '- For sweeping changes, you may instead emit a full {\"tasks\":[...]} plan JSON.',\n 'When creating or changing tasks, set \"assignedRunner\" and \"assignedModel\" ({\"modelId\",\"modelLabel\",\"thinkingEffort\"?}) using only the runners and models listed in <available_models>.',\n 'Keep dependencies consistent: no cycles, no references to removed tasks, dependencies must come before dependents, and never touch running or completed tasks.' + execNote,\n ].filter(Boolean).join('\\n');\n }\n\n /** Validate + commit a task_ops turn atomically. Returns the errors on rejection (plan untouched). */\n private applyTaskOpsTurn(turn: Extract<ConversationTurn, { kind: 'task_ops' }>): { plan: LegacyPlanState } | { errors: string[] } {\n if (!this.plan) throw new Error('No active plan state');\n const result = applyTaskOps(this.store.planTasks, turn.ops, this.plan.runners);\n if (!result.ok) return { errors: result.errors };\n\n const now = new Date().toISOString();\n const content = `Tasks updated:\\n- ${result.summary.join('\\n- ')}`;\n const plan = this.mutatePlan(\n () => {\n this.plan!.researchLog = [...(this.plan!.researchLog ?? []), ...turn.researchLog];\n const allowlist = this.settingsFn().modelAllowlist ?? this.currentAllowlist;\n const coerced = coerceAssignments(result.tasks, allowlist, this.plan!.runners, this.modelsCache);\n this.orchestrator.loadPlan(coerced, this.plan!.runners);\n this.store.resetForRun();\n this.appendTranscript('assistant', content, now);\n return true;\n },\n () => {\n this.broadcast({ type: 'planner_message', content, timestamp: now });\n this.broadcastPlan();\n },\n );\n return { plan: plan! };\n }\n\n /**\n * Resume a persisted dialogue onto a fresh AI-service conversation — either\n * because the in-memory one is gone (session reload, extension restart), or\n * because {@link continueConversation} found it stale against the planner\n * config now in effect (a harness planner's model/effort switched mid-chat).\n * The saved transcript seeds the new conversation; no LLM call happens\n * before the user's message is sent.\n */\n private async resumeConversation(\n userMessage: string,\n priorHistory: ConversationMessage[],\n options?: GeneratePlanOptions,\n ): Promise<Awaited<ReturnType<IAiService['startConversation']>>> {\n if (!this.plan) throw new Error('No active plan state');\n const runners = this.plan.runners;\n const modelsByRunner = await this.modelResolver.modelsForRunners(runners);\n this.modelsCache = modelsByRunner;\n const runnerModes = this.runnerModesFor(runners);\n const { grillMeEnabled, prdEnabled, reviewEnabled, verificationEnabled, researchSubagentsEnabled, modelAllowlist } = this.settingsFn();\n this.currentAllowlist = modelAllowlist ?? {};\n const filteredModels = filterModelsForPrompt(modelsByRunner, this.currentAllowlist);\n const goal = this.goal || priorHistory.find((m) => m.role === 'user')?.content || userMessage;\n\n return this.aiService.startConversation({\n goal,\n runners,\n modelsByRunner: filteredModels,\n runnerModes,\n autonomousDefault: this.config.autonomousMode,\n grillMeEnabled: grillMeEnabled ?? false,\n prdEnabled: prdEnabled ?? false,\n reviewEnabled: reviewEnabled ?? false,\n verificationEnabled: verificationEnabled ?? false,\n researchSubagentsEnabled: researchSubagentsEnabled ?? false,\n fs: this.fsAdapter,\n fetcher: this.fetcher,\n onProgress: (p) => this.translateProgress(p),\n signal: options?.signal,\n priorHistory,\n initialMessage: userMessage,\n });\n }\n\n /** Whether the planner conversation is live (started and not yet committed to a plan). */\n get isConversationActive(): boolean {\n return this.aiService.hasActiveConversation();\n }\n\n /** Append one dialogue entry to the persisted transcript. Callers persist via the mutatePlan ritual. */\n private appendTranscript(role: 'user' | 'assistant', content: string, timestamp: string, kind?: 'plan_generated'): void {\n if (!this.plan) return;\n this.plan.conversationHistory = [\n ...(this.plan.conversationHistory ?? []),\n { role, content, timestamp, ...(kind ? { kind } : {}) },\n ];\n }\n\n /** Commit a settled (non-task_ops) turn. Both branches run the mutatePlan ritual. */\n private applyConversationTurn(turn: Exclude<ConversationTurn, { kind: 'task_ops' }>): LegacyPlanState {\n if (!this.plan) throw new Error('No active plan state');\n const now = new Date().toISOString();\n\n if (turn.kind === 'plan') {\n return this.mutatePlan(() => {\n this.plan!.researchLog = [...(this.plan!.researchLog ?? []), ...turn.researchLog];\n // A cheap model may emit the PRD block and the plan JSON in one turn —\n // capture the PRD here too so it isn't dropped with the plan preamble.\n this.capturePrd(turn.text);\n // Read the allowlist live: it may have changed since startPlanning, and\n // committed tasks must respect the current one.\n const allowlist = this.settingsFn().modelAllowlist ?? this.currentAllowlist;\n const coerced = coerceAssignments(turn.tasks, allowlist, this.plan!.runners, this.modelsCache);\n this.orchestrator.loadPlan(coerced, this.plan!.runners);\n this.store.resetForRun({ preserveCompleted: false });\n this.appendTranscript('assistant', `Plan generated with ${coerced.length} task${coerced.length === 1 ? '' : 's'}.`, now, 'plan_generated');\n return true;\n })!;\n }\n\n // A message turn: persist it in the dialogue; the UI re-renders from here.\n // Budget models occasionally return an empty content turn after tool use —\n // surface that visibly instead of rendering a blank bubble.\n const text = turn.text.trim()\n ? turn.text\n : '(The planner returned an empty response. Reply to continue, or rephrase your goal.)';\n return this.mutatePlan(\n () => {\n this.plan!.researchLog = [...(this.plan!.researchLog ?? []), ...turn.researchLog];\n this.appendTranscript('assistant', text, now);\n this.capturePrd(text);\n return true;\n },\n () => this.broadcast({ type: 'planner_message', content: text, timestamp: now }),\n )!;\n }\n\n /**\n * PRD mode: when the planner writes the full markdown PRD, save it to\n * .scratch/<slug>/PRD.md (Matt Pocock to-prd convention) and keep it on the plan.\n */\n private capturePrd(text: string): void {\n if (!this.plan) return;\n const prd = extractPrdBlock(text);\n if (!prd) return;\n this.plan.prdMarkdown = prd.markdown;\n try {\n savePrdMarkdown(this.workspace, prd.slug, prd.markdown);\n } catch {\n // Saving the PRD file is best-effort; the markdown stays on the plan state.\n }\n }\n\n async executePlan(): Promise<void> {\n if (!this.plan || !this.store.planTasks.length) throw new Error('No plan to execute');\n if (this.orchestrator.isRunning) throw new Error('Session already executing');\n\n this.plan.status = 'approved';\n this.store.clearLog();\n this.store.resetForRun();\n\n this.orchestrator.loadPlan(this.store.planTasks, this.plan.runners);\n await this.orchestrator.approveReview();\n\n if (!this.orchestrator.isRunning) {\n const tasks = this.store.allTasks;\n this.broadcast({ type: 'execution_complete', summary: executionSummary(tasks) });\n this.persist();\n }\n }\n\n async approveReview(): Promise<LegacyPlanState> {\n if (!this.plan) throw new Error('No plan to review');\n await this.orchestrator.approveReview();\n return this.plan;\n }\n\n async forceStartTask(taskId: string): Promise<void> {\n if (!this.plan) return;\n if (!this.store.get(taskId)) {\n this.orchestrator.loadPlan(this.store.planTasks, this.plan.runners);\n }\n await this.orchestrator.forceStartTask(taskId);\n }\n\n async runTask(taskId: string): Promise<void> {\n if (!this.plan) return;\n if (!this.store.get(taskId)) {\n this.orchestrator.loadPlan(this.store.planTasks, this.plan.runners);\n }\n await this.orchestrator.runTask(taskId);\n }\n\n async retryTask(taskId: string): Promise<void> {\n await this.orchestrator.retryTask(taskId);\n this.persist();\n }\n\n async cancelTask(taskId: string): Promise<void> {\n await this.orchestrator.cancelTask(taskId);\n this.persist();\n }\n\n async markAiTaskComplete(taskId: string): Promise<void> {\n await this.orchestrator.markAiTaskComplete(taskId);\n this.persist();\n }\n\n async markTaskComplete(taskId: string): Promise<void> {\n await this.orchestrator.markTaskComplete(taskId);\n this.persist();\n }\n\n async markTaskIncomplete(taskId: string): Promise<void> {\n await this.orchestrator.markTaskIncomplete(taskId);\n this.persist();\n }\n\n async tick(): Promise<void> {\n await this.orchestrator.tick();\n this.persist();\n }\n\n async processQueuedMessages(): Promise<void> {\n const messages = this.orchestrator.getQueuedMessages();\n if (messages.length === 0) return;\n\n this.orchestrator.clearQueuedMessages();\n\n const batchText = messages.map((m) => m.text).join('\\n');\n const activeSessions = new Map(\n [...this.orchestrator.activeSessionMap.entries()].map(([taskId, sessionId]) => [\n taskId,\n { id: sessionId, taskId },\n ])\n );\n\n const modelsByRunner = await this.modelResolver.modelsForRunners(this.config.enabledRunners);\n const runnerModes = this.runnerModesFor(this.plan?.runners ?? ['claude-code']);\n const { modelAllowlist } = this.settingsFn();\n\n const result = await this.planner.modifyDuringExecution({\n executionLog: this.store.getExecutionLog(),\n pendingTasks: this.store.planTasks,\n activeSessions,\n userMessage: batchText,\n modelsByRunner,\n runners: this.plan?.runners ?? ['claude-code'],\n runnerModes,\n autonomousDefault: this.config.autonomousMode,\n perRunnerAllowlist: modelAllowlist,\n });\n\n this.orchestrator.reconcilePlan(result.pendingTasks, this.plan?.runners ?? ['claude-code']);\n this.persist();\n\n // Re-schedule. `onQueueReady` only fires when no task is active, so a paused\n // run still has `running === true` — `start()` would no-op (it early-returns\n // when already running). Ticking directly spawns the dependents that became\n // ready after reconcile. `start()` covers the halted case (`running === false`,\n // e.g. a retry that cleared the queue), re-entering approval-free.\n if (this.orchestrator.isRunning) {\n await this.orchestrator.tick();\n } else {\n await this.orchestrator.start();\n }\n }\n\n approveCheckpoint(taskId: string): void {\n this.orchestrator.approveCheckpoint(taskId);\n }\n\n rejectCheckpoint(taskId: string, reason?: string): void {\n this.orchestrator.rejectCheckpoint(taskId, reason);\n }\n\n queueMessage(text: string): void {\n this.orchestrator.queueMessage(text);\n }\n\n getQueuedMessages() { return this.orchestrator.getQueuedMessages(); }\n setQueuedMessages(msgs: ReturnType<TaskOrchestrator['getQueuedMessages']>): void {\n this.orchestrator.setQueuedMessages(msgs);\n }\n processNextQueuedMessage() { return this.orchestrator.processNextQueuedMessage(); }\n get queuedCount(): number { return this.orchestrator.queuedCount; }\n getTask(taskId: string) { return this.store.get(taskId); }\n get isReviewApproved(): boolean { return this.orchestrator.isReviewApproved; }\n\n stopExecution(): void {\n this.orchestrator.stop();\n this.broadcast({ type: 'execution_stopped' });\n }\n\n /**\n * The one mutation seam: every structural plan mutation runs the same\n * ritual — store op → persist (which snapshots tasks from PlanStore) →\n * broadcast — in that order, once. A store op returning false aborts\n * before anything is persisted. PlanStore is the single authority for\n * task state; LegacyPlanState.tasks is populated only at persist time.\n */\n private mutatePlan(op: () => boolean, notify: () => void = () => this.broadcastPlan()): LegacyPlanState | null {\n if (!this.plan) return null;\n if (!op()) return null;\n this.persist();\n notify();\n return this.plan;\n }\n\n updateTask(taskId: string, changes: Partial<Task>): LegacyPlanState | null {\n return this.mutatePlan(\n () => Boolean(this.store.update(taskId, changes)),\n () => this.broadcast({ type: 'task_updated', taskId, changes: changes as Record<string, unknown> }),\n );\n }\n\n /**\n * Move one task onto a different runner. Distinct from {@link updateTask}\n * because a runner change is never a single-field edit: the task's model,\n * thinking effort and mode are all scoped to its runner, so they are\n * re-derived from the new runner's catalog (see {@link retargetTaskRunner}).\n * That needs discovery, which is async — hence a method of its own rather\n * than a branch inside the sync `updateTask`.\n *\n * The runner is also admitted into `plan.runners` — see {@link admitRunner}.\n */\n async setTaskRunner(taskId: string, runner: RunnerId): Promise<LegacyPlanState | null> {\n if (!this.plan) return null;\n const task = this.store.get(taskId);\n if (!task) return null;\n // Guard before discovery, not after: `modelsForRunners` spawns the runner's\n // own CLI to list models, which is far too expensive for a no-op re-pick.\n if (task.assignedRunner === runner || task.type === 'user') return this.plan;\n\n const catalog = await this.catalogFor(runner);\n const changes = retargetTaskRunner(task, runner, this.allowedCatalog(catalog, runner));\n if (Object.keys(changes).length === 0) return this.plan;\n\n return this.mutatePlan(() => {\n if (!this.store.update(taskId, changes)) return false;\n this.admitRunner(runner, catalog.models);\n return true;\n });\n }\n\n /** What a runner offers, as {@link runnerAssignment} needs it. Spawns the runner's CLI to list models. */\n private async catalogFor(runner: RunnerId): Promise<RunnerCatalog> {\n return {\n models: (await this.modelResolver.modelsForRunners([runner]))[runner] ?? [],\n modes: this.runnerModesFor([runner])[runner],\n };\n }\n\n /**\n * What a *derived* assignment may draw from: the runner's catalog narrowed to\n * the user's allowlist. Deriving from the full catalog would hand a task the\n * runner's first model regardless of a restriction the user set — the next\n * planner turn's `coerceAssignments` would snap it back anyway, so the user\n * would see their pick silently change instead of never being offered.\n *\n * `catalogFor` stays unnarrowed because {@link admitRunner} caches it as what\n * the runner really offers, which is what effort clamping needs.\n */\n private allowedCatalog(catalog: RunnerCatalog, runner: RunnerId): RunnerCatalog {\n // The other runners' catalogs are what lets `effectiveAllowlist` tell an id\n // this runner hasn't listed yet from one that belongs to a different runner.\n const allowed = effectiveAllowlist(\n this.settingsFn().modelAllowlist?.[runner],\n runner,\n { ...this.modelsCache, [runner]: catalog.models },\n );\n if (!allowed) return catalog;\n const models = catalog.models.filter((m) => allowed.includes(m.modelId));\n // Nothing left means the allowlist named only ids this runner hasn't\n // listed. An empty catalog reads as \"discovery failed\" to\n // `runnerAssignment`, which then leaves the task on the *old* runner's\n // model — a worse outcome than ignoring the restriction for this derivation.\n return models.length > 0 ? { ...catalog, models } : catalog;\n }\n\n /**\n * Make a runner a first-class member of this plan. Without this, the next\n * planner turn's `coerceAssignments` would treat it as disallowed and snap\n * every task on it back, silently undoing the user's choice; and that same\n * pass clamps efforts against `modelsCache`, so a catalog missing from there\n * makes the effort we just derived read as unverifiable.\n */\n private admitRunner(runner: RunnerId, models: DiscoveredModel[]): void {\n if (!this.plan) return;\n if (!this.plan.runners.includes(runner)) this.plan.runners = [...this.plan.runners, runner];\n // The store is what the orchestrator resolves a spawn against, and nothing\n // reloads it between this edit and a single-task run.\n this.store.admitRunner(runner);\n if (models.length > 0) this.modelsCache = { ...this.modelsCache, [runner]: models };\n }\n\n /**\n * Replace one task's dependency list. Separate from {@link updateTask}\n * because a hand-edited graph is the one task edit that can leave a plan\n * unschedulable: `canSetDependencies` is the guard, and it lives behind this\n * one method so the API and both surfaces' pickers reject the same edits\n * rather than each carrying a copy of the rule. Throws so a surface can say\n * why the edit was refused.\n */\n setTaskDependencies(taskId: string, dependencies: string[]): LegacyPlanState | null {\n if (!this.plan) return null;\n const check = canSetDependencies(this.store.planTasks, taskId, dependencies);\n if (!check.ok) throw new Error(check.error ?? 'Those dependencies are not valid');\n return this.updateTask(taskId, { dependencies });\n }\n\n async completeTask(taskId: string): Promise<void> {\n await this.markTaskComplete(taskId);\n }\n\n removeTask(taskId: string): LegacyPlanState | null {\n return this.mutatePlan(() => (this.store.remove(taskId), true));\n }\n\n /**\n * Add one task, filling in whatever the caller left unset. A task with no\n * runnable assignment is not a lighter task but an unspawnable one, so the\n * runner falls back to the plan's first and the model, effort and mode are\n * derived from that runner's catalog — the same derivation a runner change\n * uses ({@link runnerAssignment}), which is why this is async like\n * {@link setTaskRunner}. Anything the caller did choose survives when the\n * runner offers it.\n *\n * Dependencies naming tasks that don't exist are dropped rather than rejected:\n * the caller is a picker over the current plan, so a stale id means the plan\n * moved on, not that the whole task should be refused.\n */\n async addTask(draft: Partial<Task>): Promise<LegacyPlanState | null> {\n if (!this.plan) return null;\n const runner = draft.assignedRunner ?? this.plan.runners[0];\n const dependencies = (draft.dependencies ?? []).filter((id) => this.store.get(id));\n const catalog = draft.type === 'user' ? null : await this.catalogFor(runner);\n\n return this.mutatePlan(() => {\n this.store.add({ ...draft, ...(catalog ? runnerAssignment(this.allowedCatalog(catalog, runner), draft) : {}), assignedRunner: runner, dependencies });\n if (catalog) this.admitRunner(runner, catalog.models);\n return true;\n });\n }\n\n mergeTasks(taskIdA: string, taskIdB: string): LegacyPlanState | null {\n return this.mutatePlan(() => (this.store.merge(taskIdA, taskIdB), true));\n }\n\n mergeMultipleTasks(taskIds: string[]): LegacyPlanState | null {\n return this.mutatePlan(() => (this.store.mergeMultiple(taskIds), true));\n }\n\n splitTask(taskId: string, newTasks: Partial<Task>[]): LegacyPlanState | null {\n return this.mutatePlan(() => (this.store.split(taskId, newTasks), true));\n }\n\n /**\n * Planner-driven merge: validate compatibility up front, then ask the planner\n * LLM to produce a single \"merge\" taskOps op combining the selected tasks.\n * Goes through the same conversation loop + validated-atomic-edit + corrective\n * retry flow as every other task_ops edit (ADR-0002). Throws on a\n * pre-flight compatibility failure so the host surfaces an inline error\n * before any LLM call.\n */\n async requestMerge(taskIds: string[], options?: GeneratePlanOptions): Promise<LegacyPlanState> {\n if (!this.plan) throw new Error('No active plan state');\n const check = canMergeTasks(this.store.planTasks, taskIds);\n if (!check.ok) throw new Error(check.error ?? 'These tasks cannot be merged');\n const prompt = buildMergePrompt(taskIds, this.store.planTasks);\n return this.continueConversation(prompt, options);\n }\n\n /**\n * Planner-driven split: ask the planner LLM to decompose one task into a\n * sequence of smaller tasks. The model generates the breakdown (no manual\n * per-task specs from the user). Same conversation-loop/repair path as merge.\n */\n async requestSplit(taskId: string, options?: GeneratePlanOptions): Promise<LegacyPlanState> {\n if (!this.plan) throw new Error('No active plan state');\n const check = canSplitTask(this.store.planTasks, taskId);\n if (!check.ok) throw new Error(check.error ?? 'This task cannot be split');\n const prompt = buildSplitPrompt(taskId, this.store.planTasks);\n return this.continueConversation(prompt, options);\n }\n\n loadPlan(plan: LegacyPlanState, goal: string, workspace: string, opts?: { sessionId?: string; persist?: boolean }): void {\n // A live planner conversation belongs to the plan it was started for.\n // Adopting a different plan (session load/switch) must drop it — otherwise\n // the next user message continues the OLD session's LLM thread and the\n // planner re-emits that session's plan here. The same-object case (e.g.\n // re-adopting the current plan on approval) keeps the conversation; after\n // a drop, the first user send reseeds it from this plan's own transcript.\n if (plan !== this.plan) {\n this.aiService.reset();\n // The execution log and queued messages are scoped to the outgoing plan;\n // callers restoring a saved queue re-apply it after adoption.\n this.store.clearLog();\n this.orchestrator.clearQueuedMessages();\n // Approval scopes are equally session-scoped: a path or command approved\n // for the previous plan must not stay approved for the newly adopted one.\n this.approvals.clear();\n this.approvalPolicy.reset();\n }\n this.plan = plan;\n this.goal = goal;\n this.workspace = workspace;\n // Adopting the saved session's id keeps subsequent persists writing to the\n // same file instead of forking the session under a fresh identity.\n if (opts?.sessionId) this.currentSessionId = opts.sessionId;\n this.orchestrator.loadPlan(plan.tasks, plan.runners);\n if (opts?.persist !== false) this.persist();\n }\n\n async modifyPlan(userRequest: string): Promise<Task[]> {\n if (!this.plan) throw new Error('No plan to modify');\n const now = new Date().toISOString();\n this.appendTranscript('user', userRequest, now);\n const modelsByRunner = await this.modelResolver.modelsForRunners(this.plan.runners);\n const runnerModes = this.runnerModesFor(this.plan.runners);\n const { modelAllowlist } = this.settingsFn();\n const result = await this.planner.modify({\n existingPlan: this.plan,\n userRequest,\n modelsByRunner,\n runnerModes,\n autonomousDefault: this.config.autonomousMode,\n fs: this.fsAdapter,\n fetcher: this.fetcher,\n perRunnerAllowlist: modelAllowlist,\n });\n this.orchestrator.loadPlan(result.tasks, this.plan.runners);\n this.appendTranscript('assistant', `Plan updated — now ${result.tasks.length} task${result.tasks.length === 1 ? '' : 's'}.`, new Date().toISOString(), 'plan_generated');\n this.persist();\n return result.tasks;\n }\n\n destroy(): void {\n this.stopExecution();\n // Planning research runs on a separate conduit from task execution — a\n // live spawn_research_agent/bash tool call would otherwise keep running\n // server-side after the client has already moved on to a new session.\n this.aiService.reset();\n // Deny any still-pending approval prompts so their timers and awaited\n // continuations settle before the Session goes away.\n this.approvals.clear();\n this.approvalPolicy.reset();\n this.unsubObserver?.();\n this.unsubObserver = null;\n }\n\n private broadcastPlan(): void {\n if (!this.plan) return;\n this.broadcast({\n type: 'plan_generated',\n plan: serializePlan(this.plan),\n goal: this.goal,\n runners: this.plan.runners,\n });\n }\n\n get aiServiceInstance(): IAiService { return this.aiService; }\n}\n\n","import type { RunnerPluginManifest, ResolveContext, RunnerInvocation } from './types';\n\nexport class ResolveError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ResolveError';\n }\n}\n\nenum Block {\n None,\n IfModel,\n IfThinking,\n IfPlanMode,\n IfBuildMode,\n IfHeadless,\n IfVariant,\n IfInteractive,\n IfHeadlessSession,\n IfInteractiveVariant,\n}\n\nexport function resolveArgs(manifest: RunnerPluginManifest, ctx: ResolveContext): RunnerInvocation {\n const args: string[] = [];\n const env: Record<string, string> = {};\n\n if (manifest.runner.env) {\n for (const [key, value] of Object.entries(manifest.runner.env)) {\n const resolved = substituteSimple(value, ctx);\n // An env value that resolves to nothing (e.g. its {{if …}} condition is\n // false) is omitted entirely rather than exported as an empty string.\n if (resolved.length > 0) env[key] = resolved;\n }\n }\n\n let block = Block.None;\n let include = true;\n\n for (let i = 0; i < manifest.runner.argsTemplate.length; i++) {\n const raw = manifest.runner.argsTemplate[i];\n\n const blockOpen = parseBlockOpen(raw);\n if (blockOpen !== null) {\n if (block !== Block.None) throw new ResolveError(`Nested conditional block at position ${i}: \"${raw}\"`);\n block = blockOpen;\n include = shouldIncludeBlock(block, ctx);\n continue;\n }\n\n if (raw === '{{/if}}') {\n if (block === Block.None) throw new ResolveError(`Unmatched {{/if}} at position ${i}`);\n block = Block.None;\n include = true;\n continue;\n }\n\n if (!include) continue;\n\n const resolved = resolveToken(raw, manifest, ctx);\n if (resolved.length === 0) continue;\n\n if (isFeatureToken(raw)) {\n const parts = resolved.split(/(?<!\\\\) /);\n for (const part of parts) {\n if (part.length > 0) args.push(part);\n }\n } else {\n args.push(resolved);\n }\n }\n\n if (block !== Block.None) {\n throw new ResolveError(`Unclosed conditional block: ${Block[block]}`);\n }\n\n return {\n command: manifest.runner.command,\n args,\n env,\n promptInArgs: manifest.runner.promptInArgs,\n };\n}\n\nfunction parseBlockOpen(raw: string): Block | null {\n switch (raw) {\n case '{{if model}}': return Block.IfModel;\n case '{{if thinking}}': return Block.IfThinking;\n case '{{if planMode}}': return Block.IfPlanMode;\n case '{{if buildMode}}': return Block.IfBuildMode;\n case '{{if headless}}': return Block.IfHeadless;\n case '{{if variant}}': return Block.IfVariant;\n case '{{if interactive}}': return Block.IfInteractive;\n case '{{if headlessSession}}': return Block.IfHeadlessSession;\n case '{{if interactiveVariant}}': return Block.IfInteractiveVariant;\n default: return null;\n }\n}\n\nfunction shouldIncludeBlock(block: Block, ctx: ResolveContext): boolean {\n switch (block) {\n case Block.IfModel: return !!ctx.model;\n case Block.IfThinking: return !!ctx.thinkingEffort && !!ctx.model;\n case Block.IfPlanMode: return ctx.mode === 'plan';\n case Block.IfBuildMode: return ctx.mode !== 'plan';\n // Headless skip-permission flags only make sense for build-mode (write) tasks;\n // plan mode is read-only and the flag can conflict with --permission-mode plan.\n case Block.IfHeadless: return !!ctx.headless && ctx.mode !== 'plan';\n // `--variant` is a headless-only flag: it exists on `opencode run` but not\n // on the interactive TUI, which exits immediately if handed an unknown flag.\n case Block.IfVariant: return !!ctx.thinkingEffort && !!ctx.headless;\n // Session-shape blocks: unlike IfHeadless (a permission-flag gate with a\n // plan-mode carve-out), these pick the CLI invocation shape — e.g.\n // opencode's `run` subcommand vs its interactive TUI — so no mode carve-out.\n case Block.IfInteractive: return !ctx.headless;\n case Block.IfHeadlessSession: return !!ctx.headless;\n // Interactive counterpart of IfVariant, for runners whose TUI has no\n // variant flag and must receive the variant via env config instead.\n // Requires a provider-prefixed model: the config pins variant per model.\n case Block.IfInteractiveVariant:\n return !!ctx.thinkingEffort && !!ctx.model?.includes('/') && !ctx.headless;\n default: return true;\n }\n}\n\nfunction isFeatureToken(token: string): boolean {\n return token.startsWith('{{feature:') && token.endsWith('}}');\n}\n\n/**\n * Map a thinking effort variant ID to the Claude Code CLI flags string.\n * Effort IDs: adaptive, low, medium, high, xhigh, max (per-model from the\n * Anthropic API). `disabled` is handled as a legacy value for old tasks.\n * Returns a space-separated string that will be split into separate args.\n */\nfunction resolveClaudeThinkingFlags(effort: string): string {\n if (effort === 'disabled') return '--thinking disabled';\n if (effort === 'adaptive') return '--thinking adaptive';\n // low/medium/high/xhigh/max all use --thinking enabled + --effort <level>\n if (['low', 'medium', 'high', 'xhigh', 'max'].includes(effort)) {\n return `--thinking enabled --effort ${effort}`;\n }\n // Legacy: old variant IDs — map to adaptive\n return '--thinking adaptive';\n}\n\nfunction resolveToken(token: string, manifest: RunnerPluginManifest, ctx: ResolveContext): string {\n if (token === '{{prompt}}') return ctx.prompt;\n if (token === '{{model}}') return ctx.model || '';\n if (token === '{{thinkingEffort}}') return ctx.thinkingEffort || '';\n if (token === '{{mode}}') return ctx.mode || 'build';\n\n if (token === '{{feature:thinking}}') {\n return manifest.features.thinkingFlag || '';\n }\n\n if (token === '{{feature:thinkingVal}}') {\n const effort = ctx.thinkingEffort || 'medium';\n if (effort === 'high') return manifest.features.thinkingValueEnabled || 'enabled';\n if (effort === 'low') return manifest.features.thinkingValueDisabled || 'disabled';\n return manifest.features.thinkingValueAdaptive || 'adaptive';\n }\n\n // Combined thinking flags: --thinking MODE [--effort LEVEL]\n // Used by Claude Code's new argsTemplate.\n if (token === '{{feature:thinkingFlags}}') {\n const effort = ctx.thinkingEffort;\n if (!effort) return '';\n return resolveClaudeThinkingFlags(effort);\n }\n\n // Reasoning effort as a config override: `-c model_reasoning_effort=<level>`.\n // Used by Codex, whose CLI has no dedicated effort flag. Left unquoted on\n // purpose: bare levels fail TOML parsing and fall back to the raw string,\n // which is what codex expects — quoting would diverge between shell-mediated\n // (interactive terminal) and direct-spawn (headless) invocations.\n if (token === '{{feature:reasoningEffortConfig}}') {\n const effort = ctx.thinkingEffort;\n if (!effort) return '';\n return `-c model_reasoning_effort=${effort}`;\n }\n\n // Maps the current mode to the runner's --permission-mode CLI value.\n if (token === '{{feature:permissionModeVal}}') {\n const mode = ctx.mode || 'default';\n const map = manifest.features.permissionModeValues;\n if (map && map[mode] !== undefined) return map[mode];\n // Fallback: use mode ID directly as CLI value\n return mode;\n }\n\n if (token === '{{feature:planMode}}') {\n return manifest.features.planModeFlag || '';\n }\n\n if (token === '{{feature:buildMode}}') {\n return manifest.features.buildModeFlag || '';\n }\n\n if (token === '{{feature:headless}}') {\n return manifest.features.headlessFlag || '';\n }\n\n if (token.startsWith('{{feature:') && token.endsWith('}}')) {\n return '';\n }\n\n return token;\n}\n\n/**\n * The OPENCODE_CONFIG_CONTENT payload that pins a variant for a TUI session:\n * agent-scoped model+variant (opencode applies an agent's variant only when\n * the session uses that agent's configured model) PLUS disabling the model's\n * other variants — without the disables, the TUI's remembered last-used\n * variant silently wins over the agent config.\n */\nfunction resolveOpencodeVariantConfig(ctx: ResolveContext): string {\n const model = ctx.model;\n const effort = ctx.thinkingEffort;\n if (!model || !effort) return '';\n const slash = model.indexOf('/');\n if (slash <= 0) return '';\n const provider = model.slice(0, slash);\n const bareModel = model.slice(slash + 1);\n const config: Record<string, unknown> = {\n agent: { [ctx.mode || 'build']: { model, variant: effort } },\n };\n const others = (ctx.modelVariants ?? []).filter((v) => v !== effort);\n if (others.length > 0) {\n config.provider = {\n [provider]: {\n models: {\n [bareModel]: {\n variants: Object.fromEntries(others.map((v) => [v, { disabled: true }])),\n },\n },\n },\n };\n }\n return JSON.stringify(config);\n}\n\nfunction substituteSimple(value: string, ctx: ResolveContext): string {\n // Env values support the same (non-nested) {{if X}}…{{/if}} conditions as\n // the args template: the wrapped text is kept or dropped as a whole.\n const conditioned = value.replace(/\\{\\{if (\\w+)\\}\\}([\\s\\S]*?)\\{\\{\\/if\\}\\}/g, (match, name, body) => {\n const block = parseBlockOpen(`{{if ${name}}}`);\n if (block === null) return match;\n return shouldIncludeBlock(block, ctx) ? body : '';\n });\n return conditioned\n .replace(/\\{\\{opencodeVariantConfig\\}\\}/g, () => resolveOpencodeVariantConfig(ctx))\n .replace(/\\{\\{prompt\\}\\}/g, ctx.prompt)\n .replace(/\\{\\{model\\}\\}/g, ctx.model || '')\n .replace(/\\{\\{thinkingEffort\\}\\}/g, ctx.thinkingEffort || '')\n .replace(/\\{\\{mode\\}\\}/g, ctx.mode || 'build');\n}\n","import type { RunnerRegistry } from '../plugins/RunnerRegistry';\nimport { resolveArgs } from '../plugins/resolveArgs';\nimport type { RunnerInvocation } from '../plugins/types';\n\nexport type RunnerMode = string;\n\nexport type { RunnerInvocation } from '../plugins/types';\n\nexport function buildRunnerInvocation(opts: {\n runner: string;\n prompt: string;\n modelId?: string;\n thinkingEffort?: string;\n modelVariants?: string[];\n mode?: RunnerMode;\n headless?: boolean;\n registry: RunnerRegistry;\n}): RunnerInvocation {\n const entry = opts.registry.get(opts.runner);\n if (!entry) {\n throw new Error(`Unknown runner: ${opts.runner}. Use \\`ordewell plugins list\\` to see registered runners.`);\n }\n\n const manifest = entry.manifest;\n\n return resolveArgs(manifest, {\n prompt: opts.prompt,\n model: opts.modelId,\n thinkingEffort: opts.thinkingEffort,\n modelVariants: opts.modelVariants,\n mode: opts.mode ?? 'build',\n headless: opts.headless,\n });\n}\n","import { spawn as nodeSpawn, execSync, ChildProcess } from 'child_process';\nimport { ITerminalRunner, ITerminalSession } from '../interfaces/ITerminalRunner';\nimport { buildRunnerInvocation } from './buildRunnerArgs';\nimport { AbstractTerminalSession, AbstractRunner } from './AbstractRunner';\nimport { augmentedPath, withPath } from '../utils/shellPath';\nimport { stripAnsi, wrapWithPty } from '../utils/shell';\nimport { planDirectLaunch, type LaunchDeps, type LaunchPlan } from '../utils/launch';\nimport { killTree } from '../utils/processTree';\n\nexport type SpawnFn = (\n command: string,\n args: string[],\n options: {\n env: NodeJS.ProcessEnv;\n stdio: ['pipe', 'pipe', 'pipe'];\n cwd: string;\n /** Set by the Windows batch route, where `args` is already a quoted command line. */\n windowsVerbatimArguments?: boolean;\n },\n) => ChildProcess;\n\n/** Test seam: every OS touchpoint is injectable; production uses the defaults. */\nexport interface HeadlessRunnerDeps {\n spawnImpl?: SpawnFn;\n hasScriptCmd?: () => boolean;\n resolvePath?: () => Promise<string>;\n /**\n * Overrides for executable resolution ({@link planDirectLaunch}). Only the\n * Windows branch consults them, so a POSIX test never needs to pass anything.\n */\n launchDeps?: LaunchDeps;\n}\n\n/**\n * `script` is POSIX-only, and the probe reflects that: `which` does not exist\n * on Windows, so `execSync` throws and the answer is a correct `false`. The\n * PTY wrapper (`wrapWithPty`) is therefore never reached there — which is the\n * intended outcome, not a lucky one.\n */\nfunction defaultHasScriptCmd(): boolean {\n if (process.platform === 'win32') return false;\n try { execSync('which script', { stdio: 'ignore' }); return true; } catch { return false; }\n}\n\nexport class HeadlessSession extends AbstractTerminalSession {\n private process: ChildProcess | null = null;\n private outputBuffer = '';\n\n constructor(id: string, taskId: string, private spawnImpl: SpawnFn) {\n super(id, taskId);\n }\n\n get isStarted(): boolean { return this.process !== null; }\n\n start(launch: LaunchPlan, cwd: string, resolvedPath: string, env?: Record<string, string>): void {\n // Killed while the spawn was still in flight — starting now leaks an agent\n // nobody is watching.\n if (this.exited || this.process) return;\n\n this.process = this.spawnImpl(launch.file, launch.args, {\n env: withPath(process.env, resolvedPath, env),\n stdio: ['pipe', 'pipe', 'pipe'],\n cwd,\n windowsVerbatimArguments: launch.verbatim,\n });\n\n const onData = (data: Buffer) => {\n const raw = data.toString();\n this.outputBuffer += stripAnsi(raw);\n this.outputEmitter.emit('output', raw);\n };\n this.process.stdout?.on('data', onData);\n this.process.stderr?.on('data', onData);\n\n this.process.on('close', (code) => { this.baseHandleExit(code ?? -1); });\n this.process.on('error', (err) => {\n this.outputBuffer += `\\nProcess error: ${err.message}\\n`;\n this.outputEmitter.emit('output', `\\nProcess error: ${err.message}\\n`);\n this.baseHandleExit(-1);\n });\n }\n\n kill(): void {\n // Tree-wide: on Windows the direct child may be a cmd.exe shim, and killing\n // it would leave the runner itself alive and still editing the workspace.\n killTree(this.process);\n // No child means no 'close' event, so watchers would never settle.\n if (!this.process) this.baseHandleExit(-1);\n }\n\n getOutput(): string { return this.outputBuffer; }\n\n write(text: string): void {\n if (this.process?.stdin && !this.process.killed) {\n this.process.stdin.write(text);\n }\n }\n}\n\nexport type RunnerSpawnOptions = Parameters<ITerminalRunner['spawn']>[0];\n\n/** Everything needed to start one runner process, resolved before any child exists. */\nexport interface PreparedLaunch {\n launch: LaunchPlan;\n resolvedPath: string;\n env: Record<string, string>;\n /** True when the invocation was wrapped in `script` to allocate a PTY. */\n pty: boolean;\n}\n\nexport class HeadlessRunner extends AbstractRunner<HeadlessSession> {\n private spawnImpl: SpawnFn;\n private hasScriptCmd: () => boolean;\n private resolvePath: () => Promise<string>;\n private launchDeps: LaunchDeps;\n\n /** Session shape when the caller names none; the VS Code runner overrides it to interactive. */\n protected readonly defaultHeadless: boolean = true;\n\n constructor(deps: HeadlessRunnerDeps = {}) {\n super();\n this.spawnImpl = deps.spawnImpl ?? nodeSpawn;\n this.hasScriptCmd = deps.hasScriptCmd ?? defaultHasScriptCmd;\n this.resolvePath = deps.resolvePath ?? augmentedPath;\n this.launchDeps = { resolvePath: this.resolvePath, ...deps.launchDeps };\n }\n\n protected createSession(id: string, taskId: string): HeadlessSession {\n return new HeadlessSession(id, taskId, this.spawnImpl);\n }\n\n /** Everything up to, but not including, spawning — so a surface that owns its own child reaches the same decisions. */\n protected async prepareLaunch(opts: RunnerSpawnOptions): Promise<PreparedLaunch> {\n const headless = opts.headless ?? this.defaultHeadless;\n\n const invocation = buildRunnerInvocation({\n runner: opts.runner,\n prompt: opts.prompt,\n modelId: opts.modelId,\n thinkingEffort: opts.thinkingEffort,\n modelVariants: opts.modelVariants,\n mode: opts.mode,\n headless,\n registry: opts.registry!,\n });\n\n // Manifest `requiresTty` means \"needs one even headless\"; an interactive\n // session is the agent's TUI, so it needs one without declaring it. Both\n // gated on `script`, which does not exist on Windows.\n const manifest = opts.registry?.get(opts.runner)?.manifest;\n const pty = (manifest?.runner.requiresTty === true || !headless) && this.hasScriptCmd();\n\n // Same PATH treatment as model discovery: the runner binary must resolve\n // wherever the user installed it, even under a GUI-minimal PATH.\n const resolvedPath = await this.resolvePath();\n\n const { command, args } = pty\n ? wrapWithPty(invocation.command, invocation.args)\n : { command: invocation.command, args: invocation.args };\n\n return {\n launch: await planDirectLaunch(command, args, this.launchDeps),\n resolvedPath,\n env: invocation.env,\n pty,\n };\n }\n\n async spawn(opts: RunnerSpawnOptions): Promise<ITerminalSession> {\n const id = `ordewell-${opts.taskId.slice(0, 8)}`;\n const session = this.createSession(id, opts.taskId);\n const prepared = await this.prepareLaunch(opts);\n\n const modeStr = opts.mode === 'plan' ? 'plan' : 'build';\n console.error(`[headless] Starting ${opts.runner} [${modeStr}] (${opts.modelId || 'default'}) for task ${opts.taskId.slice(0, 8)}${prepared.pty ? ' (PTY)' : ''}`);\n\n session.start(prepared.launch, opts.cwd, prepared.resolvedPath, prepared.env);\n this.registerSession(id, session);\n return session;\n }\n}\n","import { EventEmitter } from 'events';\nimport { ITerminalRunner, ITerminalSession } from '../interfaces/ITerminalRunner';\n\nexport abstract class AbstractTerminalSession implements ITerminalSession {\n public id: string;\n public taskId: string;\n protected exited = false;\n protected outputEmitter = new EventEmitter();\n protected exitEmitter = new EventEmitter();\n\n constructor(id: string, taskId: string) {\n this.id = id;\n this.taskId = taskId;\n }\n\n protected baseHandleExit(code: number): void {\n if (this.exited) return;\n this.exited = true;\n this.exitEmitter.emit('exit', code);\n }\n\n onOutput(callback: (text: string) => void): void {\n this.outputEmitter.on('output', callback);\n }\n\n onExit(callback: (code: number) => void): void {\n this.exitEmitter.on('exit', callback);\n }\n\n abstract kill(): void;\n abstract getOutput(): string;\n abstract write(text: string): void;\n}\n\nexport abstract class AbstractRunner<S extends ITerminalSession> implements ITerminalRunner {\n protected sessions: Map<string, S> = new Map();\n\n get activeCount(): number { return this.sessions.size; }\n\n stop(sessionId: string): void {\n const session = this.sessions.get(sessionId);\n if (!session) return;\n session.kill();\n this.sessions.delete(sessionId);\n }\n\n stopAll(): void {\n for (const [, session] of this.sessions) {\n session.kill();\n }\n this.sessions.clear();\n }\n\n protected registerSession(id: string, session: S): void {\n this.sessions.set(id, session);\n session.onExit(() => this.sessions.delete(id));\n }\n\n abstract spawn(opts: {\n taskId: string;\n runner: string;\n prompt: string;\n modelId?: string;\n thinkingEffort?: string;\n mode?: string;\n headless?: boolean;\n cwd: string;\n registry?: import('../plugins/RunnerRegistry').RunnerRegistry;\n }): Promise<ITerminalSession>;\n}\n","import { execFile } from 'child_process';\nimport { promisify } from 'util';\nimport { tmpdir } from 'os';\nimport { join } from 'path';\nimport { existsSync, readFileSync, unlinkSync, writeFileSync } from 'fs';\nimport { ITerminalSession } from '../interfaces/ITerminalRunner';\nimport { buildRunnerInvocation } from './buildRunnerArgs';\nimport { AbstractTerminalSession, AbstractRunner } from './AbstractRunner';\nimport { augmentedPath } from '../utils/shellPath';\nimport { posixShellQuote, stripAnsi } from '../utils/shell';\nimport { tmuxSessionName, tmuxSocketName, tmuxWindowName } from '../utils/tmux';\n\nconst EXIT_RE = /<<<ORDEWELL_TMUX_EXIT:(\\d+)>>>/;\n\nexport type ExecFileFn = (command: string, args: string[]) => Promise<{ stdout: string; stderr: string }>;\n\nconst execFileAsync = promisify(execFile);\nconst defaultExecFile: ExecFileFn = async (command, args) => {\n const { stdout, stderr } = await execFileAsync(command, args);\n return { stdout: String(stdout), stderr: String(stderr) };\n};\n\n/** Test seam: every OS touchpoint is injectable; production uses the defaults. */\nexport interface TmuxRunnerDeps {\n port: number;\n execFileImpl?: ExecFileFn;\n resolvePath?: () => Promise<string>;\n pollIntervalMs?: number;\n logDir?: string;\n}\n\nclass TmuxSession extends AbstractTerminalSession {\n private outputBuffer = '';\n private offset = 0;\n private timer: ReturnType<typeof setInterval> | null = null;\n\n constructor(\n id: string,\n taskId: string,\n private tmuxSession: string,\n private windowName: string,\n private execFileImpl: ExecFileFn,\n private pollIntervalMs: number,\n private logPath: string,\n private socket: string,\n ) {\n super(id, taskId);\n }\n\n private get target(): string {\n return `${this.tmuxSession}:${this.windowName}`;\n }\n\n /** Every tmux call must name the daemon's own socket; an unprefixed one\n * silently targets the shared default server (see `tmuxSocketName`). */\n private tmux(args: string[]): Promise<{ stdout: string; stderr: string }> {\n return this.execFileImpl('tmux', ['-L', this.socket, ...args]);\n }\n\n /**\n * Runs the invocation in a fresh tmux window, tailed via `pipe-pane` into a\n * log file rather than polling `capture-pane` snapshots — a byte-exact\n * stream needs no diff/resync heuristics. The command is wrapped so the\n * window survives its own exit (an `exec`'d login shell), which is what\n * lets the user keep poking at a finished task's terminal.\n */\n async start(command: string, args: string[], cwd: string, env?: Record<string, string>): Promise<void> {\n writeFileSync(this.logPath, '');\n\n const envAssignments = Object.entries(env ?? {})\n .map(([k, v]) => `${k}=${posixShellQuote(v)}`)\n .join(' ');\n const inner = [command, ...args].map(posixShellQuote).join(' ');\n const prefix = envAssignments ? `env ${envAssignments} ` : '';\n const loginShell = process.env.SHELL || '/bin/bash';\n const shellCmd = `${prefix}${inner}; printf '\\\\n<<<ORDEWELL_TMUX_EXIT:%s>>>\\\\n' \"$?\"; exec ${posixShellQuote(loginShell)} -l`;\n\n await this.tmux(['new-window', '-t', this.tmuxSession, '-n', this.windowName, '-c', cwd, shellCmd]);\n await this.tmux(['pipe-pane', '-t', this.target, `cat >> ${posixShellQuote(this.logPath)}`]);\n\n this.timer = setInterval(() => this.poll(), this.pollIntervalMs);\n }\n\n private poll(): void {\n if (this.exited) return;\n let content: string;\n try {\n content = existsSync(this.logPath) ? readFileSync(this.logPath, 'utf8') : '';\n } catch {\n return;\n }\n if (content.length <= this.offset) return;\n\n const diff = content.slice(this.offset);\n this.offset = content.length;\n this.outputBuffer += stripAnsi(diff);\n this.outputEmitter.emit('output', diff);\n\n // Scan the accumulated tail, not just this read: pipe-pane can flush half\n // the sentinel in one write and the rest in the next, and a marker split\n // across two reads must still be seen exactly once.\n const match = this.outputBuffer.slice(-4096).match(EXIT_RE);\n if (match) this.finish(Number(match[1]));\n }\n\n /**\n * A task finishing (or being killed) stops observation, but never the\n * window itself on the sentinel path — only `kill()` closes the window.\n * Piping is turned off and the log file removed either way, so a finished\n * task doesn't leave a `cat` process appending to it for the rest of the\n * daemon's life.\n */\n private finish(code: number): void {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n this.tmux(['pipe-pane', '-t', this.target]).catch(() => {});\n try {\n unlinkSync(this.logPath);\n } catch {\n /* already gone */\n }\n this.baseHandleExit(code);\n }\n\n kill(): void {\n this.tmux(['kill-window', '-t', this.target]).catch(() => {});\n this.finish(-1);\n }\n\n getOutput(): string {\n return this.outputBuffer;\n }\n\n write(text: string): void {\n this.tmux(['send-keys', '-t', this.target, '-l', text]).catch(() => {});\n }\n}\n\n/**\n * Runs tasks in a real tmux window instead of a piped subprocess, so a user\n * can open a genuine, interactive terminal on any task (running or\n * finished) from outside Ordewell's own process. `ITerminalSession` hides the\n * transport from `VerdictEngine`/`PoolAwareRunner`, so orchestration is\n * unchanged — this is a drop-in replacement for `HeadlessRunner`.\n */\nexport class TmuxRunner extends AbstractRunner<TmuxSession> {\n private sessionName: string;\n private socket: string;\n private execFileImpl: ExecFileFn;\n private resolvePath: () => Promise<string>;\n private pollIntervalMs: number;\n private logDir: string;\n /** Retries get a freshly named window so a failed attempt's output stays inspectable. */\n private attempts = new Map<string, number>();\n private ready: Promise<void> | null = null;\n\n constructor(deps: TmuxRunnerDeps) {\n super();\n this.sessionName = tmuxSessionName(deps.port);\n this.socket = tmuxSocketName(deps.port);\n this.execFileImpl = deps.execFileImpl ?? defaultExecFile;\n this.resolvePath = deps.resolvePath ?? augmentedPath;\n this.pollIntervalMs = deps.pollIntervalMs ?? 500;\n this.logDir = deps.logDir ?? tmpdir();\n }\n\n /**\n * Reaps a session orphaned by a crashed prior daemon on the same port, then\n * creates a fresh one. Memoized: `spawn` awaits it too, so a task spawned\n * before startup's own call has settled never lands in a missing session —\n * and a settled failure clears the memo so the next spawn can retry.\n */\n ensureSession(): Promise<void> {\n this.ready ??= this.createFreshSession().catch((err) => {\n this.ready = null;\n throw err;\n });\n return this.ready;\n }\n\n /** Every tmux call must name this daemon's socket; see `tmuxSocketName`. */\n private tmux(args: string[]): Promise<{ stdout: string; stderr: string }> {\n return this.execFileImpl('tmux', ['-L', this.socket, ...args]);\n }\n\n private async createFreshSession(): Promise<void> {\n try {\n await this.tmux(['has-session', '-t', this.sessionName]);\n await this.tmux(['kill-session', '-t', this.sessionName]);\n } catch {\n /* no stale session */\n }\n await this.tmux(['new-session', '-d', '-s', this.sessionName]);\n await this.configureScrolling();\n }\n\n /**\n * Makes an attached runner terminal scrollable with the mouse wheel and\n * Page Up/Down. A fresh tmux session ships with `mouse off`, a 2000-line\n * scrollback, and no PageUp binding — none of which lets a user page back\n * through a finished task's output, which is the whole point of opening its\n * window. Scoping is harmless: the daemon owns a private socket\n * (`tmuxSocketName`), so these server-wide options touch nothing but its\n * own session. Best-effort so an ancient or stripped tmux cannot stop tasks\n * from spawning — the session still works without the scroll comforts.\n */\n private async configureScrolling(): Promise<void> {\n try {\n // `history-limit` only governs windows created after it is set, so it\n // must run before any `new-window` — once, here at session creation.\n await this.tmux(['set-option', '-g', 'history-limit', '100000']);\n // Wheel-aware copy mode: with `mouse on`, wheel-up enters copy mode and\n // scrolls the pane's scrollback instead of going to the inner app.\n await this.tmux(['set-option', '-g', 'mouse', 'on']);\n // PageUp enters copy mode scrolled up one page; without a root binding it\n // is delivered to the inner app and never reaches tmux's scrollback.\n await this.tmux(['bind-key', '-n', 'PageUp', 'copy-mode', '-u']);\n // PageUp/PageDown then page through the scrollback inside copy mode, in\n // both key tables so the bindings hold regardless of `mode-keys`.\n await this.tmux(['bind-key', '-T', 'copy-mode', 'PageUp', 'send-keys', '-X', 'page-up']);\n await this.tmux(['bind-key', '-T', 'copy-mode', 'PageDown', 'send-keys', '-X', 'page-down']);\n await this.tmux(['bind-key', '-T', 'copy-mode-vi', 'PageUp', 'send-keys', '-X', 'page-up']);\n await this.tmux(['bind-key', '-T', 'copy-mode-vi', 'PageDown', 'send-keys', '-X', 'page-down']);\n } catch {\n /* scroll comforts unavailable — session still usable */\n }\n }\n\n /**\n * Called on daemon shutdown — the one guarantee against leaked tmux\n * processes. Kills the whole server, not just the session: the socket\n * belongs to this daemon alone, so nothing else can be on it, and a runner\n * that somehow escaped its session would otherwise keep running (and keep\n * billing) unattached for as long as the server lived.\n */\n async killSession(): Promise<void> {\n this.ready = null;\n try {\n await this.tmux(['kill-server']);\n } catch {\n /* already gone */\n }\n }\n\n async spawn(opts: {\n taskId: string;\n runner: string;\n prompt: string;\n modelId?: string;\n thinkingEffort?: string;\n modelVariants?: string[];\n mode?: string;\n headless?: boolean;\n cwd: string;\n registry?: import('../plugins/RunnerRegistry').RunnerRegistry;\n planSessionId?: string;\n }): Promise<ITerminalSession> {\n const invocation = buildRunnerInvocation({\n runner: opts.runner,\n prompt: opts.prompt,\n modelId: opts.modelId,\n thinkingEffort: opts.thinkingEffort,\n modelVariants: opts.modelVariants,\n mode: opts.mode,\n headless: opts.headless ?? true,\n registry: opts.registry!,\n });\n\n await this.ensureSession();\n\n // Attempts are counted per plan-scoped task: task ids like \"task-1\" repeat\n // across plans, and mixing their counters would mislabel retry windows.\n const attemptKey = `${opts.planSessionId ?? ''}:${opts.taskId}`;\n const attempt = (this.attempts.get(attemptKey) ?? 0) + 1;\n this.attempts.set(attemptKey, attempt);\n const base = tmuxWindowName(opts.taskId, opts.planSessionId);\n const windowName = attempt > 1 ? `${base}-${attempt}` : base;\n\n // The window name is already unique per plan, task and attempt, so it also\n // keys the session registry and the log file — two live sessions must\n // never share a log, or their output streams would cross-contaminate.\n const id = `ordewell-${windowName}`;\n const session = new TmuxSession(\n id,\n opts.taskId,\n this.sessionName,\n windowName,\n this.execFileImpl,\n this.pollIntervalMs,\n join(this.logDir, `${id}.log`),\n this.socket,\n );\n\n invocation.env = { ...invocation.env, PATH: await this.resolvePath() };\n await session.start(invocation.command, invocation.args, opts.cwd, invocation.env);\n this.registerSession(id, session);\n return session;\n }\n}\n","import { execSync } from 'child_process';\n\n/** One shared tmux session per daemon, scoped by port so multiple daemons never collide. */\nexport function tmuxSessionName(port: number): string {\n return `ordewell-${port}`;\n}\n\n/**\n * Each daemon gets its own tmux *server*, not just its own session name.\n *\n * A plain `tmux new-session` attaches to whatever server already owns the\n * default socket, and a session created on an existing server inherits that\n * **server's** environment — not the environment of the process that asked for\n * it (tmux only refreshes `update-environment` vars, and only on attach). So a\n * daemon started with, say, a particular provider API key would silently hand\n * its runners a stale key left behind by whoever started the server first,\n * possibly hours earlier under a different configuration entirely.\n *\n * A private socket makes the server a child of this daemon, so the runner\n * inherits the daemon's environment the way any child process would, and\n * `kill-server` at shutdown is authoritative — a runner cannot outlive the\n * daemon by hiding on a shared server. Users attaching by hand need the same\n * flag: `tmux -L ordewell-<port> attach -t ordewell-<port>`.\n */\nexport function tmuxSocketName(port: number): string {\n return `ordewell-${port}`;\n}\n\nconst slug = (text: string) => text.replace(/[^a-zA-Z0-9]/g, '');\n\n/**\n * tmux window targeting breaks on `:` and other punctuation, so ids are\n * slugged. Task ids are only unique within one plan (\"task-1\" is every\n * planner's favourite), so the window is also scoped by the plan session id —\n * without it, the second plan run in a daemon's lifetime would collide with\n * the first plan's still-open windows and pipe its output into the wrong one.\n */\nexport function tmuxWindowName(taskId: string, planSessionId?: string): string {\n const scope = planSessionId ? `${slug(planSessionId).slice(-6)}-` : '';\n return `t-${scope}${slug(taskId).slice(0, 16)}`;\n}\n\nexport type ProbeFn = () => void;\n\nconst defaultProbe: ProbeFn = () => {\n execSync(process.platform === 'win32' ? 'where tmux' : 'which tmux', { stdio: 'ignore' });\n};\n\n/** Feature-detects tmux the same way `HeadlessRunner` detects `script`. */\nexport function hasTmux(probe: ProbeFn = defaultProbe): boolean {\n try {\n probe();\n return true;\n } catch {\n return false;\n }\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\nimport { execSync } from 'child_process';\nimport type { RunnerPluginManifest, PluginEntry, IPluginStore } from './types';\nimport { FsPluginStore } from './FsPluginStore';\nimport { CLAUDE_CODE_MANIFEST } from './builtin/claude-code.manifest';\nimport { CODEX_MANIFEST } from './builtin/codex.manifest';\nimport { OPENCODE_MANIFEST } from './builtin/opencode.manifest';\nimport type { IConfig } from '../interfaces/IConfig';\n\n// Insertion order is picker order on every surface (registry.list() preserves it).\nconst BUILTIN_MANIFESTS: RunnerPluginManifest[] = [\n CLAUDE_CODE_MANIFEST,\n CODEX_MANIFEST,\n OPENCODE_MANIFEST,\n];\n\nexport class RunnerRegistry {\n private plugins: Map<string, PluginEntry> = new Map();\n private store: IPluginStore;\n\n constructor(store?: IPluginStore) {\n this.store = store ?? new FsPluginStore();\n this.loadBuiltins();\n }\n\n private loadBuiltins(): void {\n for (const manifest of BUILTIN_MANIFESTS) {\n this.plugins.set(manifest.name, { manifest, source: 'builtin' });\n }\n }\n\n loadUserPlugins(): void {\n const names = this.store.listUserPluginDirs();\n for (const name of names) {\n const pluginDir = path.join(this.store.getUserPluginsDir(), name);\n const manifest = this.store.loadManifest(pluginDir);\n if (!manifest) continue;\n this.plugins.set(manifest.name, {\n manifest,\n source: 'user',\n installPath: pluginDir,\n });\n }\n }\n\n get(id: string): PluginEntry | undefined {\n return this.plugins.get(id);\n }\n\n getManifest(id: string): RunnerPluginManifest | undefined {\n return this.plugins.get(id)?.manifest;\n }\n\n list(): PluginEntry[] {\n return [...this.plugins.values()];\n }\n\n listEnabled(config: IConfig): PluginEntry[] {\n const enabled = config.enabledRunners;\n return this.list().filter((p) => enabled.includes(p.manifest.name));\n }\n\n listEnabledIds(config: IConfig): string[] {\n return this.listEnabled(config).map((p) => p.manifest.name);\n }\n\n isBuiltIn(id: string): boolean {\n const entry = this.plugins.get(id);\n return entry?.source === 'builtin';\n }\n\n installFromPath(sourcePath: string): RunnerPluginManifest {\n const absPath = path.resolve(sourcePath);\n if (!this.store.dirExists(absPath)) {\n throw new Error(`Plugin source must be a directory: ${absPath}`);\n }\n\n const manifest = this.store.loadManifest(absPath);\n if (!manifest) {\n throw new Error(`No valid manifest.json found in: ${absPath}`);\n }\n\n const destDir = path.join(this.store.getUserPluginsDir(), manifest.name);\n this.store.ensureDir(destDir);\n this.store.copyDir(absPath, destDir);\n\n this.plugins.set(manifest.name, {\n manifest,\n source: 'user',\n installPath: destDir,\n });\n\n return manifest;\n }\n\n installFromGit(url: string): RunnerPluginManifest {\n const repoName = url.split('/').pop()?.replace(/\\.git$/, '') || 'plugin';\n const tmpDir = path.join(os.tmpdir(), `ordewell-plugin-${Date.now()}`);\n this.store.ensureDir(tmpDir);\n\n try {\n execSync(`git clone --depth 1 \"${url}\" \"${tmpDir}\"`, { stdio: 'pipe', timeout: 30000 });\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(`Failed to clone repository: ${message}`);\n }\n\n const contents = fsReaddirSync(tmpDir);\n const hasManifest = contents.some((f) => f === 'manifest.json');\n\n if (!hasManifest && contents.length === 1 && this.store.dirExists(path.join(tmpDir, contents[0]))) {\n const subDir = path.join(tmpDir, contents[0]);\n return this.finishInstall(subDir, repoName, tmpDir);\n }\n\n if (!hasManifest) {\n this.store.removeDir(tmpDir);\n throw new Error(`No manifest.json found in repository: ${url}`);\n }\n\n return this.finishInstall(tmpDir, repoName, tmpDir);\n }\n\n private finishInstall(sourceDir: string, repoName: string, tmpDir: string): RunnerPluginManifest {\n const manifest = this.store.loadManifest(sourceDir);\n if (!manifest) {\n this.store.removeDir(tmpDir);\n throw new Error(`No valid manifest.json found in cloned repository`);\n }\n\n const destDir = path.join(this.store.getUserPluginsDir(), manifest.name);\n this.store.ensureDir(destDir);\n this.store.copyDir(sourceDir, destDir);\n this.store.removeDir(tmpDir);\n\n this.plugins.set(manifest.name, {\n manifest,\n source: 'user',\n installPath: destDir,\n });\n\n return manifest;\n }\n\n remove(name: string): void {\n const entry = this.plugins.get(name);\n if (!entry) throw new Error(`Plugin not found: ${name}`);\n if (entry.source === 'builtin') throw new Error(`Cannot remove built-in plugin: ${name}`);\n\n if (entry.installPath) {\n try {\n this.store.removeDir(entry.installPath);\n } catch { /* ignore cleanup errors */ }\n }\n\n this.plugins.delete(name);\n }\n\n createSkeleton(name: string, outputDir: string): string {\n const dir = path.resolve(outputDir, name);\n this.store.ensureDir(dir);\n\n const manifest: RunnerPluginManifest = {\n name,\n displayName: name.replace(/-/g, ' ').replace(/\\b\\w/g, (c) => c.toUpperCase()),\n description: `Custom runner plugin: ${name}`,\n version: '0.1.0',\n runner: {\n command: 'bash',\n argsTemplate: [\n '{{if model}}', '--model', '{{model}}', '{{/if}}',\n '--prompt', '{{prompt}}',\n ],\n promptInArgs: true,\n },\n features: {\n modelSelection: false,\n thinkingEffort: false,\n planMode: false,\n planModeFlag: '',\n },\n modelDiscovery: {\n method: 'hardcoded',\n fallbackModels: [\n { modelId: 'gpt-4o', modelLabel: 'GPT-4o' },\n ],\n },\n };\n\n this.store.writeFile(path.join(dir, 'manifest.json'), JSON.stringify(manifest, null, 2) + '\\n');\n\n const runSh = path.join(dir, 'run.sh');\n const scriptContent = `#!/usr/bin/env bash\n# Custom runner script for ${name}\n# Receives:\n# $1 = prompt text\n# $2 = model ID (optional)\n#\n# This script should invoke your desired CLI tool with the prompt.\n# Replace the echo below with your actual command.\n\nprompt=\"$1\"\nmodel=\"$2\"\n\necho \"Running ${name} with prompt: $prompt\"\n# Example: your-cli-tool --message \"$prompt\"\n`;\n this.store.writeFile(runSh, scriptContent);\n try { fsChmodSync(runSh, 0o755); } catch { /* ignore */ }\n\n return dir;\n }\n}\n\nfunction fsReaddirSync(dir: string): string[] {\n try {\n return fs.readdirSync(dir);\n } catch {\n return [];\n }\n}\n\nfunction fsChmodSync(fpath: string, mode: number): void {\n try {\n fs.chmodSync(fpath, mode);\n } catch { /* ignore */ }\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\nimport { ensureDir } from '../utils/fsHelpers';\nimport type { RunnerPluginManifest, IPluginStore } from './types';\n\nfunction userPluginsDir(): string {\n return path.join(os.homedir(), '.config', 'ordewell', 'plugins');\n}\n\nfunction isValidManifest(obj: unknown): obj is RunnerPluginManifest {\n if (!obj || typeof obj !== 'object') return false;\n const m = obj as Record<string, unknown>;\n return (\n typeof m.name === 'string' &&\n typeof m.displayName === 'string' &&\n typeof m.description === 'string' &&\n typeof m.version === 'string' &&\n typeof m.runner === 'object' && m.runner !== null &&\n typeof (m.runner as Record<string, unknown>).command === 'string' &&\n Array.isArray((m.runner as Record<string, unknown>).argsTemplate) &&\n typeof m.features === 'object' && m.features !== null &&\n typeof m.modelDiscovery === 'object' && m.modelDiscovery !== null\n );\n}\n\nfunction loadManifestFromDir(dir: string): RunnerPluginManifest | null {\n const manifestPath = path.join(dir, 'manifest.json');\n if (!fs.existsSync(manifestPath)) return null;\n try {\n const raw = fs.readFileSync(manifestPath, 'utf8');\n const parsed = JSON.parse(raw);\n if (!isValidManifest(parsed)) return null;\n return parsed as RunnerPluginManifest;\n } catch {\n return null;\n }\n}\n\nfunction copyDirSync(src: string, dest: string): void {\n ensureDir(dest);\n const entries = fs.readdirSync(src, { withFileTypes: true });\n for (const entry of entries) {\n const srcPath = path.join(src, entry.name);\n const destPath = path.join(dest, entry.name);\n if (entry.isDirectory()) {\n copyDirSync(srcPath, destPath);\n } else {\n fs.copyFileSync(srcPath, destPath);\n }\n }\n}\n\nfunction rmDirSync(dir: string): void {\n if (!fs.existsSync(dir)) return;\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n for (const entry of entries) {\n const p = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n rmDirSync(p);\n } else {\n fs.unlinkSync(p);\n }\n }\n fs.rmdirSync(dir);\n}\n\nexport class FsPluginStore implements IPluginStore {\n getUserPluginsDir(): string {\n return userPluginsDir();\n }\n\n listUserPluginDirs(): string[] {\n const dir = userPluginsDir();\n if (!fs.existsSync(dir)) return [];\n let entries: fs.Dirent[];\n try {\n entries = fs.readdirSync(dir, { withFileTypes: true });\n } catch {\n return [];\n }\n return entries.filter((e) => e.isDirectory()).map((e) => e.name);\n }\n\n loadManifest(pluginDir: string): RunnerPluginManifest | null {\n return loadManifestFromDir(pluginDir);\n }\n\n copyDir(sourceDir: string, destDir: string): void {\n copyDirSync(sourceDir, destDir);\n }\n\n removeDir(dir: string): void {\n rmDirSync(dir);\n }\n\n ensureDir(dir: string): void {\n ensureDir(dir);\n }\n\n writeFile(filePath: string, content: string): void {\n fs.writeFileSync(filePath, content);\n }\n\n readFile(filePath: string): string | null {\n try {\n return fs.readFileSync(filePath, 'utf8');\n } catch {\n return null;\n }\n }\n\n dirExists(path: string): boolean {\n return fs.existsSync(path) && fs.statSync(path).isDirectory();\n }\n\n exists(path: string): boolean {\n return fs.existsSync(path);\n }\n}\n","import type { RunnerPluginManifest } from '../types';\n\nexport const CLAUDE_CODE_MANIFEST: RunnerPluginManifest = {\n name: 'claude-code',\n displayName: 'Claude Code',\n description: 'Anthropic Claude Code - AI coding assistant in your terminal',\n version: '1.0.0',\n\n runner: {\n command: 'claude',\n argsTemplate: [\n '{{if model}}', '--model', '{{model}}', '{{/if}}',\n '{{if thinking}}', '{{feature:thinkingFlags}}', '{{/if}}',\n '--permission-mode', '{{feature:permissionModeVal}}',\n '{{if headless}}', '{{feature:headless}}', '{{/if}}',\n '{{prompt}}',\n ],\n promptInArgs: true,\n },\n\n features: {\n modelSelection: true,\n thinkingEffort: true,\n planMode: true,\n planModeFlag: '--permission-mode',\n headlessFlag: '--dangerously-skip-permissions',\n thinkingFlag: '--thinking',\n thinkingValueEnabled: 'enabled',\n thinkingValueDisabled: 'disabled',\n thinkingValueAdaptive: 'adaptive',\n permissionModeValues: {\n // Map mode IDs to --permission-mode CLI values\n 'default': 'default',\n 'acceptEdits': 'acceptEdits',\n 'plan': 'plan',\n 'bypassPermissions': 'bypassPermissions',\n // Legacy aliases used by older tasks\n 'build': 'acceptEdits',\n },\n },\n\n modelDiscovery: {\n method: 'command',\n // Claude Code has no `claude models` subcommand. Discovery tries three\n // sources in order, each falling through to the next on failure:\n //\n // 1. Anthropic Models API (apiDiscovery) — GET /v1/models returns the\n // authoritative live list of models the user's account can access,\n // including aliases the --help prose omits (e.g. haiku). Auth works for\n // both API-key users (ANTHROPIC_API_KEY → X-Api-Key) and OAuth/claude.ai\n // users (token from ~/.claude/.credentials.json → Authorization: Bearer).\n // Short aliases (opus, sonnet, haiku, fable) are derived from the full\n // model IDs, deduplicated by family keeping the latest.\n //\n // 2. `claude --help` prose (discoveryCommands) — the CLI's --model\n // description lists example aliases. Fragile (uses \"e.g.\", not\n // exhaustive) but works offline and needs no auth.\n //\n // 3. canonicalAliases — stable --model contracts (opus/sonnet/haiku/fable)\n // merged into any successful result to fill gaps, and used as the full\n // last-resort list when both API and CLI are unavailable.\n apiDiscovery: {\n url: 'https://api.anthropic.com/v1/models?limit=100',\n headers: { 'anthropic-version': '2023-06-01' },\n auth: [\n { type: 'env', varName: 'ANTHROPIC_API_KEY', header: 'X-Api-Key' },\n { type: 'file', path: '~/.claude/.credentials.json', jsonPath: 'claudeAiOauth.accessToken', header: 'Authorization', prefix: 'Bearer ' },\n ],\n parser: 'anthropic-models',\n },\n discoveryCommands: [\n { command: 'claude', args: ['--help'], parser: 'claude-help' },\n ],\n canonicalAliases: [\n { modelId: 'opus', modelLabel: 'Opus' },\n { modelId: 'sonnet', modelLabel: 'Sonnet' },\n { modelId: 'haiku', modelLabel: 'Haiku' },\n { modelId: 'fable', modelLabel: 'Fable' },\n ],\n variants: [\n { id: 'adaptive', label: 'Adaptive' },\n { id: 'low', label: 'Low effort' },\n { id: 'medium', label: 'Medium effort' },\n { id: 'high', label: 'High effort' },\n { id: 'xhigh', label: 'Extra high effort' },\n { id: 'max', label: 'Max effort' },\n ],\n },\n\n contextFile: 'CLAUDE.md',\n contextFileAltPath: '.claude/CLAUDE.md',\n\n modes: [\n { id: 'default', label: 'Ask before edits', description: 'Standard mode: asks permission before editing files', cliValue: 'default', safe: true },\n { id: 'acceptEdits', label: 'Edit automatically', description: 'Edits files without asking, still asks for risky operations', cliValue: 'acceptEdits' },\n { id: 'plan', label: 'Plan mode', description: 'Read-only analysis, no edits allowed', cliValue: 'plan' },\n { id: 'bypassPermissions', label: 'Auto mode', description: 'Skips all permission prompts — use for AI-driven autonomous runs', cliValue: 'bypassPermissions', autonomous: true },\n ],\n};\n","import type { RunnerPluginManifest } from '../types';\n\nexport const CODEX_MANIFEST: RunnerPluginManifest = {\n name: 'codex',\n displayName: 'Codex',\n description: 'OpenAI Codex CLI - AI coding agent in your terminal',\n version: '1.0.0',\n\n runner: {\n command: 'codex',\n // Headless surfaces (CLI/web) use the non-interactive `exec` subcommand\n // (`--skip-git-repo-check`: task workspaces aren't always git repos, and\n // exec hard-fails outside one by default); interactive surfaces (VS Code\n // terminal) launch the TUI with the prompt as its positional argument.\n // Reasoning effort has no dedicated flag — it travels as a `-c` config\n // override (see {{feature:reasoningEffortConfig}}). Both `exec` and the\n // TUI accept `-m`, `-c`, and `--sandbox`.\n argsTemplate: [\n '{{if headlessSession}}', 'exec', '--skip-git-repo-check', '{{/if}}',\n '{{if model}}', '-m', '{{model}}', '{{/if}}',\n '{{if thinking}}', '{{feature:reasoningEffortConfig}}', '{{/if}}',\n '--sandbox', '{{feature:permissionModeVal}}',\n '{{prompt}}',\n ],\n promptInArgs: true,\n },\n\n features: {\n modelSelection: true,\n thinkingEffort: true,\n planMode: true,\n planModeFlag: '--sandbox',\n permissionModeValues: {\n // Map mode IDs to --sandbox CLI values. `codex exec` is non-interactive\n // and has no approval flag, so the sandbox axis is the whole permission\n // story for headless runs.\n 'agent': 'workspace-write',\n 'plan': 'read-only',\n 'fullAccess': 'danger-full-access',\n // Legacy alias used by older tasks\n 'build': 'workspace-write',\n },\n },\n\n modelDiscovery: {\n // Codex has no `codex models` subcommand (see docs/adr/0004). Discovery\n // tries three sources in order, each falling through to the next:\n //\n // 1. `codex app-server` stdio JSON-RPC (`initialize` → `model/list`) —\n // the live catalog: ids, display names, hidden flags, and per-model\n // supported reasoning efforts (the variants).\n // 2. `~/.codex/models_cache.json` — the same catalog, written by Codex\n // itself on its own runs; fresh as of the user's last Codex session.\n // 3. canonicalAliases — stable `-m` slugs as the last resort, with the\n // static common-denominator variants below.\n method: 'hardcoded',\n appServer: {\n command: 'codex',\n args: ['app-server'],\n cacheFile: '~/.codex/models_cache.json',\n },\n canonicalAliases: [\n { modelId: 'gpt-5.6-sol', modelLabel: 'GPT-5.6-Sol' },\n { modelId: 'gpt-5.6-terra', modelLabel: 'GPT-5.6-Terra' },\n { modelId: 'gpt-5.6-luna', modelLabel: 'GPT-5.6-Luna' },\n { modelId: 'gpt-5.5', modelLabel: 'GPT-5.5' },\n { modelId: 'gpt-5.4', modelLabel: 'GPT-5.4' },\n { modelId: 'gpt-5.4-mini', modelLabel: 'GPT-5.4-Mini' },\n ],\n // Fallback-only common denominator: every current Codex model supports at\n // least these four rungs. Live discovery replaces them with each model's\n // real supportedReasoningEfforts (which may add max/ultra).\n variants: [\n { id: 'low', label: 'Low' },\n { id: 'medium', label: 'Medium' },\n { id: 'high', label: 'High' },\n { id: 'xhigh', label: 'Xhigh' },\n ],\n },\n\n contextFile: 'AGENTS.md',\n\n modes: [\n { id: 'agent', label: 'Agent', description: 'Workspace-write sandbox: edits files inside the workspace', cliValue: 'workspace-write', safe: true },\n { id: 'plan', label: 'Plan', description: 'Read-only sandbox for analysis and exploration', cliValue: 'read-only' },\n { id: 'fullAccess', label: 'Full access', description: 'No sandbox — full disk and network access for autonomous runs', cliValue: 'danger-full-access', autonomous: true },\n ],\n};\n","import type { RunnerPluginManifest } from '../types';\n\nexport const OPENCODE_MANIFEST: RunnerPluginManifest = {\n name: 'opencode',\n displayName: 'OpenCode',\n description: 'OpenCode CLI - open-source AI coding agent',\n version: '1.0.0',\n\n runner: {\n command: 'opencode',\n // Interactive surfaces (VS Code terminal) launch the full TUI with\n // `--prompt`; headless surfaces (CLI/web) use the streaming `run`\n // subcommand. `--variant` is ONLY accepted by `run` — the TUI rejects it\n // as an unknown flag and exits before any work, which Ordewell reads as\n // task completion. The TUI receives the variant through\n // OPENCODE_CONFIG_CONTENT instead (see below).\n argsTemplate: [\n '{{if headlessSession}}', 'run', '{{/if}}',\n '{{if model}}', '--model', '{{model}}', '{{/if}}',\n '--agent', '{{mode}}',\n '{{if variant}}', '--variant', '{{thinkingEffort}}', '{{/if}}',\n '{{if buildMode}}', '--auto', '{{/if}}',\n '{{if interactive}}', '--prompt', '{{/if}}',\n '{{prompt}}',\n ],\n // Deep-merged over the user's opencode.json for this process only. An\n // agent-scoped variant alone is NOT enough for the TUI — its remembered\n // last-used variant silently wins — so the config also disables the\n // model's other variants (see resolveOpencodeVariantConfig). Never set a\n // top-level `model`/`variant` here: that can switch the active provider\n // and make sessions fail while still exiting 0.\n env: {\n OPENCODE_CONFIG_CONTENT: '{{if interactiveVariant}}{{opencodeVariantConfig}}{{/if}}',\n },\n promptInArgs: true,\n requiresTty: true,\n },\n\n features: {\n modelSelection: true,\n thinkingEffort: true,\n planMode: true,\n planModeFlag: 'plan',\n buildModeFlag: 'build',\n headlessFlag: '--auto',\n },\n\n modelDiscovery: {\n method: 'command',\n discoveryCommands: [\n { command: 'opencode', args: ['models', '--verbose'], parser: 'opencode-models-verbose' },\n { command: 'opencode', args: ['models'], parser: 'opencode-models' },\n ],\n // No fallbackModels: the list must always reflect what `opencode models`\n // actually reports for THIS user (their configured providers only). A\n // hardcoded fallback previously leaked models the user didn't have.\n // No static variants — per-model variants are fetched from opencode models --verbose\n },\n\n contextFile: 'AGENTS.md',\n contextFileAltPath: '.opencode/AGENTS.md',\n\n modes: [\n { id: 'build', label: 'Build', description: 'Full access agent for development work', cliValue: 'build', autonomous: true, safe: true },\n { id: 'plan', label: 'Plan', description: 'Read-only agent for analysis and exploration', cliValue: 'plan' },\n ],\n};\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport { LegacyPlanState } from '../models/Task';\nimport { defaultLogger, type ILogger } from '../interfaces/ILogger';\nimport { getStateDir, ensureDir } from './fsHelpers';\n\nconst STATE_FILE = 'state.json';\n\nfunction getStatePath(baseDir: string): string {\n return path.join(getStateDir(baseDir), STATE_FILE);\n}\n\nexport function saveState(plan: LegacyPlanState, baseDir?: string): void {\n const statePath = getStatePath(baseDir ?? process.cwd());\n ensureDir(path.dirname(statePath));\n plan.lastUpdated = new Date().toISOString();\n fs.writeFileSync(statePath, JSON.stringify(plan, null, 2));\n}\n\nexport function loadState(baseDir?: string, logger: ILogger = defaultLogger): LegacyPlanState | null {\n const dir = baseDir ?? process.cwd();\n const statePath = getStatePath(dir);\n if (!fs.existsSync(statePath)) return null;\n try {\n const raw = fs.readFileSync(statePath, 'utf-8');\n const parsed = JSON.parse(raw);\n if (!Array.isArray(parsed.runners)) {\n logger.warn('stateStore', `rejecting state from ${statePath}: old format (scalar \"runner\" instead of \"runners\" array). Please re-plan.`);\n return null;\n }\n return parsed as LegacyPlanState;\n } catch (err: unknown) {\n logger.warn('stateStore', `failed to load state from ${statePath}; falling back to empty state`, err);\n return null;\n }\n}\n\nexport function clearState(baseDir?: string): void {\n const dir = baseDir ?? process.cwd();\n const statePath = getStatePath(dir);\n if (fs.existsSync(statePath)) fs.unlinkSync(statePath);\n}\n\nexport function stateExists(baseDir?: string): boolean {\n const dir = baseDir ?? process.cwd();\n return fs.existsSync(getStatePath(dir));\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\n\nexport interface UserSettings {\n grillMe: { enabled: boolean };\n tdd: { enabled: boolean };\n prd: { enabled: boolean };\n review: { enabled: boolean };\n verification: { enabled: boolean };\n researchSubagents: { enabled: boolean };\n modelAllowlist?: Record<string, string[]>;\n}\n\nconst DEFAULTS: UserSettings = {\n grillMe: { enabled: false },\n tdd: { enabled: true },\n prd: { enabled: false },\n review: { enabled: false },\n verification: { enabled: false },\n researchSubagents: { enabled: false },\n};\n\n/**\n * Where the user's toggles live. `ORDEWELL_SETTINGS_PATH` overrides it so several\n * Ordewell processes on one machine can hold *different* settings at the same\n * time. Without it the file is a single shared mutable global: the benchmark\n * harness runs parallel lanes that each pin the mode toggles, and because\n * `getAll()` re-reads whenever the mtime moves, a lane needing\n * `researchSubagents: true` would silently plan with `false` the moment another\n * lane pinned its own — turning an A/B of that toggle into a comparison of one\n * condition against itself.\n */\nexport function getSettingsPath(): string {\n const override = process.env.ORDEWELL_SETTINGS_PATH;\n if (override && override.trim()) return override.trim();\n return path.join(os.homedir(), '.config', 'ordewell', 'settings.json');\n}\n\nexport class SettingsService {\n private filePath: string;\n private cache: UserSettings | null = null;\n private cachedMtimeMs: number | null = null;\n\n constructor(filePath: string = getSettingsPath()) {\n this.filePath = filePath;\n }\n\n // Several processes share the settings file (VS Code extension host, web\n // server, CLI), so the cache is keyed on the file's mtime: a write from any\n // other process invalidates it. A stale cache here previously meant an\n // allowlist set in one surface never reached another's planner.\n getAll(): UserSettings {\n const mtime = this.fileMtimeMs();\n if (this.cache && mtime === this.cachedMtimeMs) return this.cache;\n this.cache = this.load();\n this.cachedMtimeMs = mtime;\n return this.cache;\n }\n\n private fileMtimeMs(): number | null {\n try {\n return fs.statSync(this.filePath).mtimeMs;\n } catch {\n return null;\n }\n }\n\n getGrillMe(): boolean {\n return this.getAll().grillMe.enabled;\n }\n\n getTdd(): boolean {\n return this.getAll().tdd.enabled;\n }\n\n getPrd(): boolean {\n return this.getAll().prd.enabled;\n }\n\n setGrillMe(enabled: boolean): void {\n this.getAll();\n this.cache!.grillMe.enabled = enabled;\n this.persist();\n }\n\n setTdd(enabled: boolean): void {\n this.getAll();\n this.cache!.tdd.enabled = enabled;\n this.persist();\n }\n\n setPrd(enabled: boolean): void {\n this.getAll();\n this.cache!.prd.enabled = enabled;\n this.persist();\n }\n\n getReview(): boolean {\n return this.getAll().review.enabled;\n }\n\n setReview(enabled: boolean): void {\n this.getAll();\n this.cache!.review.enabled = enabled;\n this.persist();\n }\n\n getVerification(): boolean {\n return this.getAll().verification.enabled;\n }\n\n setVerification(enabled: boolean): void {\n this.getAll();\n this.cache!.verification.enabled = enabled;\n this.persist();\n }\n\n getResearchSubagents(): boolean {\n return this.getAll().researchSubagents.enabled;\n }\n\n setResearchSubagents(enabled: boolean): void {\n this.getAll();\n this.cache!.researchSubagents.enabled = enabled;\n this.persist();\n }\n\n getModelAllowlist(runner: string): string[] | undefined {\n return this.getAll().modelAllowlist?.[runner];\n }\n\n setModelAllowlist(runner: string, ids: string[] | undefined): void {\n this.getAll();\n if (ids === undefined) {\n if (this.cache!.modelAllowlist) {\n delete this.cache!.modelAllowlist[runner];\n if (Object.keys(this.cache!.modelAllowlist).length === 0) {\n this.cache!.modelAllowlist = undefined;\n }\n }\n } else {\n if (!this.cache!.modelAllowlist) {\n this.cache!.modelAllowlist = {};\n }\n this.cache!.modelAllowlist[runner] = ids;\n }\n this.persist();\n }\n\n private load(): UserSettings {\n try {\n if (fs.existsSync(this.filePath)) {\n const raw = JSON.parse(fs.readFileSync(this.filePath, 'utf-8'));\n const settings: UserSettings = {\n grillMe: { enabled: raw.grillMe?.enabled ?? DEFAULTS.grillMe.enabled },\n tdd: { enabled: raw.tdd?.enabled ?? DEFAULTS.tdd.enabled },\n prd: { enabled: raw.prd?.enabled ?? DEFAULTS.prd.enabled },\n // `verify` is the legacy key for review mode; keep reading it so old settings files survive the rename.\n // The evidence-based verification mode uses the distinct `verification` key to avoid colliding with it.\n review: { enabled: raw.review?.enabled ?? raw.verify?.enabled ?? DEFAULTS.review.enabled },\n verification: { enabled: raw.verification?.enabled ?? DEFAULTS.verification.enabled },\n researchSubagents: { enabled: raw.researchSubagents?.enabled ?? DEFAULTS.researchSubagents.enabled },\n };\n if (raw.modelAllowlist !== undefined) {\n settings.modelAllowlist = raw.modelAllowlist;\n }\n return settings;\n }\n } catch {\n // corrupted file — use defaults\n }\n return { ...DEFAULTS, grillMe: { ...DEFAULTS.grillMe }, tdd: { ...DEFAULTS.tdd }, prd: { ...DEFAULTS.prd }, review: { ...DEFAULTS.review }, verification: { ...DEFAULTS.verification }, researchSubagents: { ...DEFAULTS.researchSubagents } };\n }\n\n private persist(): void {\n const dir = path.dirname(this.filePath);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n fs.writeFileSync(this.filePath, JSON.stringify(this.cache, null, 2));\n this.cachedMtimeMs = this.fileMtimeMs();\n }\n}\n"],"mappings":"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,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAEA,SAAS,sBACP,MACA,SACA,YACA,SACA,WACA,cACA,aACA,cACA,UACA,aACA,mBACQ;AACR,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,mBAAmB,WAAW;AAAA,IAC9B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,8BAA8B,QAAQ,KAAK,GAAG,IAAI;AAAA,IAClD,wBAAwB,eAAe;AAAA,IACvC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,kBAAkB,OAAO;AAAA,IACzB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU;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","names":["path","resolve","path","path","path","slug","fs","fs","fs","fs","MAX_JSON_REPAIRS","step","fs","fs","path","exec","promisify","fsSync","os","path","join","fsSync","path","defaultExists","length","execAsync","promisify","exec","defaultExec","resolve","cached","id","fs","path","os","cached","models","exec","promisify","execAsync","promisify","exec","defaultExec","resolve","resolve","resolve","STDERR_TAIL_CHARS","resolve","path","refused","fs","DEFAULT_TIMEOUT_MS","fs","path","fs","path","Block","nodeSpawn","nodeSpawn","execFile","promisify","join","existsSync","readFileSync","unlinkSync","writeFileSync","execSync","promisify","execFile","defaultExecFile","writeFileSync","existsSync","readFileSync","unlinkSync","join","fs","path","os","execSync","fs","path","os","path","execSync","fs","path","fs","path","os"]}