@pruddiman/dispatch 1.4.4 → 1.5.0-beta.07e10a8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -12
- package/dist/cli.js +9210 -10117
- package/dist/cli.js.map +1 -1
- package/dist/mcp/dispatch-worker.js +7343 -0
- package/dist/mcp/dispatch-worker.js.map +1 -0
- package/package.json +21 -9
- package/skills/dispatch/SKILL.md +144 -0
- package/skills/dispatch/references/ordering-reference.md +215 -0
- package/skills/dispatch/references/troubleshooting.md +34 -0
- package/skills/dispatch/references/workflow-recipes.md +105 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/helpers/format.ts","../../src/helpers/ink-prompts.tsx","../../src/mcp/state/database.ts","../../src/mcp/state/manager.ts","../../src/orchestrator/runner.ts","../../src/config.ts","../../src/providers/interface.ts","../../src/providers/opencode.ts","../../src/providers/progress.ts","../../src/helpers/logger.ts","../../src/helpers/file-logger.ts","../../src/helpers/guards.ts","../../src/helpers/timeout.ts","../../src/providers/copilot.ts","../../src/providers/claude.ts","../../src/providers/codex.ts","../../src/providers/registry.ts","../../src/providers/detect.ts","../../src/providers/index.ts","../../src/datasources/index.ts","../../src/datasources/interface.ts","../../src/datasources/github.ts","../../src/helpers/branch-validation.ts","../../src/helpers/auth.ts","../../src/constants.ts","../../node_modules/@octokit/request-error/dist-src/index.js","../../src/datasources/azdevops.ts","../../src/datasources/md.ts","../../src/helpers/slugify.ts","../../src/config-prompts.tsx","../../src/providers/auth-setup.tsx","../../src/spec-generator.ts","../../src/helpers/confirm-large-batch.tsx","../../src/helpers/prereqs.ts","../../src/helpers/gitignore.ts","../../src/queue/fork-run.ts","../../src/queue/run-queue.ts","../../src/orchestrator/cli-config.ts","../../src/orchestrator/spec-pipeline.ts","../../src/providers/router.ts","../../src/skills/spec.ts","../../src/helpers/environment.ts","../../src/dispatcher.ts","../../src/helpers/cleanup.ts","../../src/tui.tsx","../../src/helpers/retry.ts","../../src/helpers/concurrency.ts","../../src/orchestrator/datasource-helpers.ts","../../src/orchestrator/dispatch-pipeline.ts","../../src/parser.ts","../../src/skills/planner.ts","../../src/skills/executor.ts","../../src/skills/commit.ts","../../src/helpers/worktree.ts","../../src/providers/errors.ts","../../src/providers/pool.ts","../../src/helpers/run-state.ts","../../src/mcp/dispatch-worker.ts"],"sourcesContent":["/**\n * Shared formatting utilities used across the CLI.\n */\n\nimport chalk from \"chalk\";\n\n/** Shared color palette for terminal UI elements (hex values for chalk/Ink). */\nexport const PALETTE = {\n brand: \"#58A6FF\",\n subtitle: \"#484F58\",\n chrome: \"#30363D\",\n text: \"#C9D1D9\",\n muted: \"#484F58\",\n success: \"#56D364\",\n error: \"#F85149\",\n warn: \"#D29922\",\n accent: \"#79C0FF\",\n planning: \"#D2A8FF\",\n} as const;\n\n/**\n * Format a duration in milliseconds into a human-readable string.\n *\n * Examples:\n * elapsed(0) → \"0s\"\n * elapsed(45000) → \"45s\"\n * elapsed(133000) → \"2m 13s\"\n */\nexport function elapsed(ms: number): string {\n const s = Math.floor(ms / 1000);\n const m = Math.floor(s / 60);\n const sec = s % 60;\n if (m > 0) return `${m}m ${sec}s`;\n return `${sec}s`;\n}\n\n/** Options for the shared header renderer. */\nexport interface HeaderInfo {\n provider?: string;\n model?: string;\n source?: string;\n}\n\n/**\n * Build the standard dispatch header lines used by both the TUI and\n * the spec-generation banner.\n *\n * Returns an array of chalk-formatted strings (one per line).\n * Each metadata field (provider, model, source) is rendered on its own line.\n */\nexport function renderHeaderLines(info: HeaderInfo): string[] {\n const lines: string[] = [];\n lines.push(chalk.bold.white(\" ⚡ dispatch\") + chalk.dim(` — AI task orchestration`));\n if (info.provider) {\n lines.push(chalk.dim(` provider: ${info.provider}`));\n }\n if (info.model) {\n lines.push(chalk.dim(` model: ${info.model}`));\n }\n if (info.source) {\n lines.push(chalk.dim(` source: ${info.source}`));\n }\n return lines;\n}\n","/**\n * Ink-based interactive prompt functions.\n *\n * These replace @inquirer/prompts with Ink (React for CLI) components.\n * They are extracted into a separate module so tests can mock them\n * via `vi.mock(\"../helpers/ink-prompts.js\", ...)`.\n */\n\nimport React, { useState, useRef, useEffect } from \"react\";\nimport { render, Box, Text, useInput, useApp } from \"ink\";\nimport SelectInput from \"ink-select-input\";\nimport TextInput from \"ink-text-input\";\nimport { PALETTE } from \"./format.js\";\n\n/**\n * Ink-based select prompt. Returns the selected value.\n */\nexport function select<T>(opts: {\n message: string;\n choices: Array<{ name: string; value: T; description?: string }>;\n default?: T;\n /** Max visible items before scrolling. Defaults to terminal height - 4. */\n limit?: number;\n}): Promise<T> {\n return new Promise((resolve) => {\n function SelectPrompt() {\n const { exit } = useApp();\n const items = opts.choices.map((c) => ({ label: c.name, value: c.value }));\n const initialIndex = opts.default !== undefined\n ? opts.choices.findIndex((c) => c.value === opts.default)\n : 0;\n const visibleLimit = opts.limit ?? Math.max(5, (process.stdout.rows ?? 24) - 4);\n\n return (\n <Box flexDirection=\"column\">\n <Box>\n <Text color={PALETTE.accent} bold>{opts.message}</Text>\n </Box>\n <SelectInput\n items={items}\n initialIndex={Math.max(0, initialIndex)}\n limit={visibleLimit}\n onSelect={(item) => {\n resolve(item.value as T);\n exit();\n }}\n />\n </Box>\n );\n }\n\n const instance = render(<SelectPrompt />);\n instance.waitUntilExit().catch(() => {});\n });\n}\n\n/**\n * Ink-based confirm prompt (y/N). Returns boolean.\n */\nexport function confirm(opts: {\n message: string;\n default?: boolean;\n}): Promise<boolean> {\n const defaultVal = opts.default ?? true;\n\n return new Promise((resolve) => {\n function ConfirmPrompt() {\n const { exit } = useApp();\n const hint = defaultVal ? \"(Y/n)\" : \"(y/N)\";\n\n useInput((input) => {\n const lower = input.toLowerCase();\n if (lower === \"y\") { resolve(true); exit(); }\n else if (lower === \"n\") { resolve(false); exit(); }\n else if (input === \"\\r\" || input === \"\\n\" || input === \"\") { resolve(defaultVal); exit(); }\n });\n\n return (\n <Box>\n <Text color={PALETTE.accent} bold>? </Text>\n <Text>{opts.message} </Text>\n <Text color={PALETTE.muted}>{hint} </Text>\n </Box>\n );\n }\n\n const instance = render(<ConfirmPrompt />);\n instance.waitUntilExit().catch(() => {});\n });\n}\n\n/**\n * Ink-based multi-select prompt. Returns an array of selected values.\n * Use space to toggle, enter to confirm.\n */\nexport function multiSelect<T>(opts: {\n message: string;\n choices: Array<{ name: string; value: T; description?: string; default?: boolean }>;\n}): Promise<T[]> {\n return new Promise((resolve) => {\n function MultiSelectPrompt() {\n const { exit } = useApp();\n const [cursor, setCursor] = useState(0);\n const [selected, setSelected] = useState<Set<number>>(() => {\n const initial = new Set<number>();\n opts.choices.forEach((c, i) => { if (c.default) initial.add(i); });\n return initial;\n });\n const selectedRef = useRef(selected);\n useEffect(() => { selectedRef.current = selected; }, [selected]);\n\n useInput((input, key) => {\n if (key.upArrow) {\n setCursor((prev) => (prev > 0 ? prev - 1 : opts.choices.length - 1));\n } else if (key.downArrow) {\n setCursor((prev) => (prev < opts.choices.length - 1 ? prev + 1 : 0));\n } else if (input === \" \") {\n setSelected((prev) => {\n const next = new Set(prev);\n if (next.has(cursor)) next.delete(cursor);\n else next.add(cursor);\n return next;\n });\n } else if (key.return) {\n const result = opts.choices\n .filter((_, i) => selectedRef.current.has(i))\n .map((c) => c.value);\n resolve(result);\n exit();\n }\n });\n\n return (\n <Box flexDirection=\"column\">\n <Box>\n <Text color={PALETTE.accent} bold>? </Text>\n <Text>{opts.message}</Text>\n <Text color={PALETTE.muted}> (space to toggle, enter to confirm)</Text>\n </Box>\n {opts.choices.map((choice, i) => {\n const isSelected = selected.has(i);\n const isCursor = i === cursor;\n const checkbox = isSelected ? \"◉\" : \"◯\";\n const pointer = isCursor ? \"❯\" : \" \";\n return (\n <Box key={choice.name}>\n <Text color={isCursor ? PALETTE.accent : undefined}>\n {pointer} {checkbox} {choice.name}\n </Text>\n {choice.description && isCursor && (\n <Text color={PALETTE.muted}> — {choice.description}</Text>\n )}\n </Box>\n );\n })}\n </Box>\n );\n }\n\n const instance = render(<MultiSelectPrompt />);\n instance.waitUntilExit().catch(() => {});\n });\n}\n\n/**\n * Ink-based text input prompt. Returns the user's text input.\n */\nexport function input(opts: {\n message: string;\n default?: string;\n}): Promise<string> {\n return new Promise((resolve) => {\n function InputPrompt() {\n const { exit } = useApp();\n const [value, setValue] = useState(opts.default ?? \"\");\n\n return (\n <Box>\n <Text color={PALETTE.accent} bold>? </Text>\n <Text>{opts.message} </Text>\n <TextInput\n value={value}\n onChange={setValue}\n onSubmit={(val) => {\n resolve(val);\n exit();\n }}\n />\n </Box>\n );\n }\n\n const instance = render(<InputPrompt />);\n instance.waitUntilExit().catch(() => {});\n });\n}\n","/**\n * SQLite database layer for the MCP server.\n *\n * Manages the persistent store for:\n * - dispatch runs (runId, status, timestamps)\n * - per-run task records (taskId, status, error, branch)\n * - spec runs\n *\n * Schema is created on first open and is forward-compatible via\n * simple ADD COLUMN migrations tracked in the `schema_version` table.\n */\n\nimport Database from \"better-sqlite3\";\nimport { join } from \"node:path\";\nimport { mkdirSync } from \"node:fs\";\n\n// ── Record types ──────────────────────────────────────────────\n\nexport const RUN_STATUSES = [\"queued\", \"running\", \"completed\", \"failed\", \"cancelled\"] as const;\nexport const TASK_STATUSES = [\"pending\", \"running\", \"success\", \"failed\", \"skipped\"] as const;\nexport const SPEC_STATUSES = [\"queued\", \"running\", \"completed\", \"failed\"] as const;\n\nexport type RunStatus = typeof RUN_STATUSES[number];\nexport type TaskStatus = typeof TASK_STATUSES[number];\nexport type SpecStatus = typeof SPEC_STATUSES[number];\n\nexport interface RunRecord {\n runId: string;\n cwd: string;\n issueIds: string; // JSON array string, e.g. '[\"1\",\"2\"]'\n status: RunStatus;\n startedAt: number; // unix ms\n finishedAt: number | null;\n total: number;\n completed: number;\n failed: number;\n error: string | null;\n workerMessage: string | null; // serialized fork message for queue\n queuedAt: number | null; // unix ms, set when status = \"queued\"\n sessionId: string | null; // groups runs from a single CLI invocation\n}\n\nexport interface TaskRecord {\n rowId?: number;\n runId: string;\n taskId: string;\n taskText: string;\n file: string;\n line: number;\n status: TaskStatus;\n branch: string | null;\n error: string | null;\n startedAt: number | null;\n finishedAt: number | null;\n}\n\nexport interface SpecRunRecord {\n runId: string;\n cwd: string;\n issues: string; // JSON string of issues value (string or string[])\n status: SpecStatus;\n startedAt: number;\n finishedAt: number | null;\n total: number;\n generated: number;\n failed: number;\n error: string | null;\n workerMessage: string | null; // serialized fork message for queue\n queuedAt: number | null; // unix ms, set when status = \"queued\"\n sessionId: string | null; // groups runs from a single CLI invocation\n}\n\n// ── Database singleton ────────────────────────────────────────\n\nlet _db: Database.Database | null = null;\n\nconst CURRENT_SCHEMA_VERSION = 3;\n\nfunction createSchema(db: Database.Database): void {\n // Step 1: Create tables (IF NOT EXISTS is a no-op for existing tables)\n db.exec(`\n CREATE TABLE IF NOT EXISTS schema_version (\n version INTEGER NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS runs (\n run_id TEXT PRIMARY KEY,\n cwd TEXT NOT NULL,\n issue_ids TEXT NOT NULL DEFAULT '[]',\n status TEXT NOT NULL DEFAULT 'running',\n started_at INTEGER NOT NULL,\n finished_at INTEGER,\n total INTEGER NOT NULL DEFAULT 0,\n completed INTEGER NOT NULL DEFAULT 0,\n failed INTEGER NOT NULL DEFAULT 0,\n error TEXT,\n worker_message TEXT,\n queued_at INTEGER,\n session_id TEXT\n );\n\n CREATE TABLE IF NOT EXISTS tasks (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n run_id TEXT NOT NULL,\n task_id TEXT NOT NULL,\n task_text TEXT NOT NULL DEFAULT '',\n file TEXT NOT NULL DEFAULT '',\n line INTEGER NOT NULL DEFAULT 0,\n status TEXT NOT NULL DEFAULT 'pending',\n branch TEXT,\n error TEXT,\n started_at INTEGER,\n finished_at INTEGER,\n FOREIGN KEY (run_id) REFERENCES runs(run_id)\n );\n\n CREATE TABLE IF NOT EXISTS spec_runs (\n run_id TEXT PRIMARY KEY,\n cwd TEXT NOT NULL,\n issues TEXT NOT NULL DEFAULT '',\n status TEXT NOT NULL DEFAULT 'running',\n started_at INTEGER NOT NULL,\n finished_at INTEGER,\n total INTEGER NOT NULL DEFAULT 0,\n generated INTEGER NOT NULL DEFAULT 0,\n failed INTEGER NOT NULL DEFAULT 0,\n error TEXT,\n worker_message TEXT,\n queued_at INTEGER,\n session_id TEXT\n );\n `);\n\n // Step 2: Run migrations BEFORE creating indexes on migrated columns.\n // Existing DBs may lack columns added in later versions (e.g. session_id).\n // Migrations must add those columns before we can create indexes on them.\n const row = db.prepare(\"SELECT version FROM schema_version LIMIT 1\").get() as { version: number } | undefined;\n if (!row) {\n db.prepare(\"INSERT INTO schema_version (version) VALUES (?)\").run(CURRENT_SCHEMA_VERSION);\n } else {\n if (row.version < 2) migrateToV2(db);\n if (row.version < 3) migrateToV3(db);\n if (row.version < CURRENT_SCHEMA_VERSION) {\n db.prepare(\"UPDATE schema_version SET version = ?\").run(CURRENT_SCHEMA_VERSION);\n }\n }\n\n // Step 3: Create indexes (safe now that migrations have ensured all columns exist)\n db.exec(`\n CREATE INDEX IF NOT EXISTS idx_runs_session_id ON runs(session_id);\n CREATE INDEX IF NOT EXISTS idx_tasks_run_id ON tasks(run_id);\n CREATE INDEX IF NOT EXISTS idx_tasks_task_id ON tasks(task_id);\n CREATE INDEX IF NOT EXISTS idx_spec_runs_session_id ON spec_runs(session_id);\n `);\n}\n\nfunction migrateToV2(db: Database.Database): void {\n // Add queue columns to runs table\n const runCols = db.prepare(\"PRAGMA table_info(runs)\").all() as Array<{ name: string }>;\n const runColNames = new Set(runCols.map((c) => c.name));\n if (!runColNames.has(\"worker_message\")) {\n db.exec(\"ALTER TABLE runs ADD COLUMN worker_message TEXT\");\n }\n if (!runColNames.has(\"queued_at\")) {\n db.exec(\"ALTER TABLE runs ADD COLUMN queued_at INTEGER\");\n }\n\n // Add queue columns to spec_runs table\n const specCols = db.prepare(\"PRAGMA table_info(spec_runs)\").all() as Array<{ name: string }>;\n const specColNames = new Set(specCols.map((c) => c.name));\n if (!specColNames.has(\"worker_message\")) {\n db.exec(\"ALTER TABLE spec_runs ADD COLUMN worker_message TEXT\");\n }\n if (!specColNames.has(\"queued_at\")) {\n db.exec(\"ALTER TABLE spec_runs ADD COLUMN queued_at INTEGER\");\n }\n}\n\nfunction migrateToV3(db: Database.Database): void {\n // Add session_id column to runs table\n const runCols = db.prepare(\"PRAGMA table_info(runs)\").all() as Array<{ name: string }>;\n if (!runCols.some((c) => c.name === \"session_id\")) {\n db.exec(\"ALTER TABLE runs ADD COLUMN session_id TEXT\");\n db.exec(\"CREATE INDEX IF NOT EXISTS idx_runs_session_id ON runs(session_id)\");\n }\n\n // Add session_id column to spec_runs table\n const specCols = db.prepare(\"PRAGMA table_info(spec_runs)\").all() as Array<{ name: string }>;\n if (!specCols.some((c) => c.name === \"session_id\")) {\n db.exec(\"ALTER TABLE spec_runs ADD COLUMN session_id TEXT\");\n db.exec(\"CREATE INDEX IF NOT EXISTS idx_spec_runs_session_id ON spec_runs(session_id)\");\n }\n}\n\n/**\n * Open (or return the already-open) SQLite database.\n * The DB file is placed at `{cwd}/.dispatch/dispatch.db`.\n */\nexport function openDatabase(cwd: string): Database.Database {\n if (_db) return _db;\n\n const dispatchDir = join(cwd, \".dispatch\");\n mkdirSync(dispatchDir, { recursive: true });\n\n const dbPath = join(dispatchDir, \"dispatch.db\");\n const db = new Database(dbPath);\n\n // Performance settings\n db.pragma(\"journal_mode = WAL\");\n db.pragma(\"synchronous = NORMAL\");\n db.pragma(\"foreign_keys = ON\");\n\n createSchema(db);\n\n _db = db;\n return db;\n}\n\n/** Close the database (for graceful shutdown). */\nexport function closeDatabase(): void {\n if (_db) {\n _db.close();\n _db = null;\n }\n}\n\n/** Reset the singleton (for testing). */\nexport function resetDatabase(): void {\n _db = null;\n}\n\n// ── Prepared-statement helpers ────────────────────────────────\n\nexport function getDb(): Database.Database {\n if (!_db) {\n throw new Error(\"Database not open. Call openDatabase(cwd) first.\");\n }\n return _db;\n}\n","/**\n * DispatchStateManager — CRUD layer on top of the SQLite database.\n *\n * Provides:\n * - Run lifecycle management (create, update status, finish)\n * - Task tracking per run\n * - Spec-run tracking\n * - In-memory live-run registry (used by MCP tools to emit log notifications)\n *\n * All writes are synchronous (better-sqlite3 API), which is intentional for\n * simplicity and data integrity.\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport { getDb, RUN_STATUSES, TASK_STATUSES, SPEC_STATUSES } from \"./database.js\";\nimport type {\n RunRecord,\n TaskRecord,\n RunStatus,\n TaskStatus,\n SpecRunRecord,\n SpecStatus,\n} from \"./database.js\";\n\n// Re-export types for convenience\nexport type { RunRecord, TaskRecord, SpecRunRecord, RunStatus, TaskStatus, SpecStatus };\n\n// ── Live run registry ─────────────────────────────────────────\n// Tracks in-flight runs keyed by runId so MCP notification\n// callbacks can be registered and invoked as the pipeline progresses.\n\nexport type LogCallback = (message: string, level?: \"info\" | \"warn\" | \"error\") => void;\n\ninterface LiveRun {\n runId: string;\n callbacks: LogCallback[];\n completionCallbacks: Array<() => void>;\n}\n\nconst liveRuns = new Map<string, LiveRun>();\n\nexport function registerLiveRun(runId: string): void {\n liveRuns.set(runId, { runId, callbacks: [], completionCallbacks: [] });\n}\n\nexport function unregisterLiveRun(runId: string): void {\n const run = liveRuns.get(runId);\n if (run) {\n for (const cb of run.completionCallbacks) {\n try { cb(); } catch { /* swallow */ }\n }\n }\n liveRuns.delete(runId);\n}\n\nexport function addLogCallback(runId: string, cb: LogCallback): void {\n const run = liveRuns.get(runId);\n if (run) {\n run.callbacks.push(cb);\n }\n}\n\nexport function emitLog(runId: string, message: string, level: \"info\" | \"warn\" | \"error\" = \"info\"): void {\n const run = liveRuns.get(runId);\n if (run) {\n for (const cb of run.callbacks) {\n try {\n cb(message, level);\n } catch (err) {\n // Don't let notification errors crash the pipeline; log at debug level\n if (process.env[\"DEBUG\"]) console.error(\"[dispatch-mcp] log callback error:\", err);\n }\n }\n }\n}\n\n/** Check whether a run is currently registered as live (in-flight). */\nexport function isLiveRun(runId: string): boolean {\n return liveRuns.has(runId);\n}\n\n/** Register a callback that fires when unregisterLiveRun is called for this run. */\nexport function addCompletionCallback(runId: string, cb: () => void): void {\n const run = liveRuns.get(runId);\n if (run) {\n run.completionCallbacks.push(cb);\n }\n}\n\n/**\n * Wait for a run to leave the \"running\" state.\n *\n * 1. Checks DB immediately — if already terminal, returns true.\n * 2. If live, registers a completion callback for instant wakeup.\n * 3. Polls DB every 2s as safety net (race conditions, orphaned runs).\n * 4. Times out after waitMs (capped at 120s), returning false.\n */\nexport function waitForRunCompletion(\n runId: string,\n waitMs: number,\n getStatus: () => string | null,\n): Promise<boolean> {\n const effectiveWait = Math.min(Math.max(waitMs, 0), 120_000);\n if (effectiveWait <= 0) return Promise.resolve(false);\n\n // Immediate check — only return early if status is terminal (not queued or running)\n const currentStatus = getStatus();\n if (currentStatus !== null && currentStatus !== \"running\" && currentStatus !== \"queued\") {\n return Promise.resolve(true);\n }\n\n return new Promise<boolean>((resolve) => {\n let settled = false;\n let pollTimer: ReturnType<typeof setInterval> | undefined;\n let timeoutTimer: ReturnType<typeof setTimeout> | undefined;\n\n const cleanup = () => {\n if (pollTimer) clearInterval(pollTimer);\n if (timeoutTimer) clearTimeout(timeoutTimer);\n };\n\n const settle = (completed: boolean) => {\n if (settled) return;\n settled = true;\n cleanup();\n resolve(completed);\n };\n\n // Event-driven wakeup via completion callback\n if (isLiveRun(runId)) {\n addCompletionCallback(runId, () => settle(true));\n }\n\n // DB poll safety net (every 2s)\n pollTimer = setInterval(() => {\n const s = getStatus();\n if (s !== null && s !== \"running\" && s !== \"queued\") {\n settle(true);\n }\n }, 2_000);\n\n // Overall timeout\n timeoutTimer = setTimeout(() => settle(false), effectiveWait);\n });\n}\n\n// ── Status field runtime validators ──────────────────────────\n\nfunction assertRunStatus(value: string): RunStatus {\n if ((RUN_STATUSES as readonly string[]).includes(value)) return value as RunStatus;\n throw new Error(`Invalid RunStatus from database: \"${value}\"`);\n}\n\nfunction assertTaskStatus(value: string): TaskStatus {\n if ((TASK_STATUSES as readonly string[]).includes(value)) return value as TaskStatus;\n throw new Error(`Invalid TaskStatus from database: \"${value}\"`);\n}\n\nfunction assertSpecStatus(value: string): SpecStatus {\n if ((SPEC_STATUSES as readonly string[]).includes(value)) return value as SpecStatus;\n throw new Error(`Invalid SpecStatus from database: \"${value}\"`);\n}\n\n// ── Row ↔ record mappers ──────────────────────────────────────\n\ninterface RunRow {\n run_id: string;\n cwd: string;\n issue_ids: string;\n status: string;\n started_at: number;\n finished_at: number | null;\n total: number;\n completed: number;\n failed: number;\n error: string | null;\n worker_message: string | null;\n queued_at: number | null;\n session_id: string | null;\n}\n\ninterface TaskRow {\n id: number;\n run_id: string;\n task_id: string;\n task_text: string;\n file: string;\n line: number;\n status: string;\n branch: string | null;\n error: string | null;\n started_at: number | null;\n finished_at: number | null;\n}\n\ninterface SpecRunRow {\n run_id: string;\n cwd: string;\n issues: string;\n status: string;\n started_at: number;\n finished_at: number | null;\n total: number;\n generated: number;\n failed: number;\n error: string | null;\n worker_message: string | null;\n queued_at: number | null;\n session_id: string | null;\n}\n\nfunction rowToRun(row: RunRow): RunRecord {\n return {\n runId: row.run_id,\n cwd: row.cwd,\n issueIds: row.issue_ids,\n status: assertRunStatus(row.status),\n startedAt: row.started_at,\n finishedAt: row.finished_at,\n total: row.total,\n completed: row.completed,\n failed: row.failed,\n error: row.error,\n workerMessage: row.worker_message,\n queuedAt: row.queued_at,\n sessionId: row.session_id,\n };\n}\n\nfunction rowToTask(row: TaskRow): TaskRecord {\n return {\n rowId: row.id,\n runId: row.run_id,\n taskId: row.task_id,\n taskText: row.task_text,\n file: row.file,\n line: row.line,\n status: assertTaskStatus(row.status),\n branch: row.branch,\n error: row.error,\n startedAt: row.started_at,\n finishedAt: row.finished_at,\n };\n}\n\nfunction rowToSpecRun(row: SpecRunRow): SpecRunRecord {\n return {\n runId: row.run_id,\n cwd: row.cwd,\n issues: row.issues,\n status: assertSpecStatus(row.status),\n startedAt: row.started_at,\n finishedAt: row.finished_at,\n total: row.total,\n generated: row.generated,\n failed: row.failed,\n error: row.error,\n workerMessage: row.worker_message,\n queuedAt: row.queued_at,\n sessionId: row.session_id,\n };\n}\n\n// ── Run CRUD ──────────────────────────────────────────────────\n\n/** Create a new dispatch run record. Returns the generated runId. */\nexport function createRun(opts: {\n cwd: string;\n issueIds: string[];\n status?: \"queued\" | \"running\";\n workerMessage?: string;\n sessionId?: string;\n}): string {\n const runId = randomUUID();\n const db = getDb();\n const now = Date.now();\n const status = opts.status ?? \"running\";\n db.prepare(`\n INSERT INTO runs (run_id, cwd, issue_ids, status, started_at, worker_message, queued_at, session_id)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n `).run(runId, opts.cwd, JSON.stringify(opts.issueIds), status, now, opts.workerMessage ?? null, status === \"queued\" ? now : null, opts.sessionId ?? null);\n registerLiveRun(runId);\n return runId;\n}\n\n/** Update the status counters for a run. */\nexport function updateRunCounters(runId: string, total: number, completed: number, failed: number): void {\n getDb().prepare(`\n UPDATE runs SET total = ?, completed = ?, failed = ? WHERE run_id = ?\n `).run(total, completed, failed, runId);\n}\n\n/** Mark a run as finished. */\nexport function finishRun(runId: string, status: RunStatus, error?: string): void {\n getDb().prepare(`\n UPDATE runs SET status = ?, finished_at = ?, error = ? WHERE run_id = ?\n `).run(status, Date.now(), error ?? null, runId);\n unregisterLiveRun(runId);\n}\n\n/** Get a single run by ID. */\nexport function getRun(runId: string): RunRecord | null {\n const row = getDb().prepare(\"SELECT * FROM runs WHERE run_id = ?\").get(runId) as RunRow | undefined;\n return row ? rowToRun(row) : null;\n}\n\n/** Get all runs, newest first. */\nexport function listRuns(limit = 50): RunRecord[] {\n const rows = getDb().prepare(\n \"SELECT * FROM runs ORDER BY started_at DESC LIMIT ?\"\n ).all(limit) as RunRow[];\n return rows.map(rowToRun);\n}\n\n/** Get recent runs with a given status. */\nexport function listRunsByStatus(status: RunStatus, limit = 20): RunRecord[] {\n const rows = getDb().prepare(\n \"SELECT * FROM runs WHERE status = ? ORDER BY started_at DESC LIMIT ?\"\n ).all(status, limit) as RunRow[];\n return rows.map(rowToRun);\n}\n\n// ── Task CRUD ─────────────────────────────────────────────────\n\n/** Insert a task record for a run. */\nexport function createTask(opts: {\n runId: string;\n taskId: string;\n taskText: string;\n file: string;\n line: number;\n}): void {\n getDb().prepare(`\n INSERT INTO tasks (run_id, task_id, task_text, file, line, status)\n VALUES (?, ?, ?, ?, ?, 'pending')\n `).run(opts.runId, opts.taskId, opts.taskText, opts.file, opts.line);\n}\n\n/** Update task status. */\nexport function updateTaskStatus(\n runId: string,\n taskId: string,\n status: TaskStatus,\n opts?: { error?: string; branch?: string },\n): void {\n const now = Date.now();\n const isTerminal = status === \"success\" || status === \"failed\" || status === \"skipped\";\n const isStart = status === \"running\";\n\n if (isStart) {\n getDb().prepare(`\n UPDATE tasks SET status = ?, started_at = ?, error = NULL\n WHERE run_id = ? AND task_id = ?\n `).run(status, now, runId, taskId);\n } else if (isTerminal) {\n getDb().prepare(`\n UPDATE tasks SET status = ?, finished_at = ?, error = ?, branch = ?\n WHERE run_id = ? AND task_id = ?\n `).run(status, now, opts?.error ?? null, opts?.branch ?? null, runId, taskId);\n } else {\n getDb().prepare(`\n UPDATE tasks SET status = ?, error = ?\n WHERE run_id = ? AND task_id = ?\n `).run(status, opts?.error ?? null, runId, taskId);\n }\n}\n\n/** Get all tasks for a run. */\nexport function getTasksForRun(runId: string): TaskRecord[] {\n const rows = getDb().prepare(\n \"SELECT * FROM tasks WHERE run_id = ? ORDER BY id ASC\"\n ).all(runId) as TaskRow[];\n return rows.map(rowToTask);\n}\n\n// ── Spec run CRUD ─────────────────────────────────────────────\n\n/** Create a new spec run record. Returns the generated runId. */\nexport function createSpecRun(opts: {\n cwd: string;\n issues: string | string[];\n status?: \"queued\" | \"running\";\n workerMessage?: string;\n sessionId?: string;\n}): string {\n const runId = randomUUID();\n const db = getDb();\n const now = Date.now();\n const status = opts.status ?? \"running\";\n db.prepare(`\n INSERT INTO spec_runs (run_id, cwd, issues, status, started_at, worker_message, queued_at, session_id)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n `).run(runId, opts.cwd, JSON.stringify(opts.issues), status, now, opts.workerMessage ?? null, status === \"queued\" ? now : null, opts.sessionId ?? null);\n registerLiveRun(runId);\n return runId;\n}\n\n/** Mark a spec run as finished. */\nexport function finishSpecRun(\n runId: string,\n status: SpecStatus,\n counters: { total: number; generated: number; failed: number },\n error?: string,\n): void {\n getDb().prepare(`\n UPDATE spec_runs\n SET status = ?, finished_at = ?, total = ?, generated = ?, failed = ?, error = ?\n WHERE run_id = ?\n `).run(status, Date.now(), counters.total, counters.generated, counters.failed, error ?? null, runId);\n unregisterLiveRun(runId);\n}\n\n/** Get all spec runs, newest first. */\nexport function listSpecRuns(limit = 50): SpecRunRecord[] {\n const rows = getDb().prepare(\n \"SELECT * FROM spec_runs ORDER BY started_at DESC LIMIT ?\"\n ).all(limit) as SpecRunRow[];\n return rows.map(rowToSpecRun);\n}\n\n/** Get a single spec run. */\nexport function getSpecRun(runId: string): SpecRunRecord | null {\n const row = getDb().prepare(\"SELECT * FROM spec_runs WHERE run_id = ?\").get(runId) as SpecRunRow | undefined;\n return row ? rowToSpecRun(row) : null;\n}\n\n// ── Queue helpers ────────────────────────────────────────────\n\n/** Queued run entry returned by getNextQueued*. */\nexport interface QueuedEntry {\n runId: string;\n workerMessage: string;\n table: \"runs\" | \"spec_runs\";\n}\n\n/** Transition a dispatch run from \"queued\" → \"running\". */\nexport function markRunStarted(runId: string): void {\n getDb().prepare(`\n UPDATE runs SET status = 'running', started_at = ? WHERE run_id = ? AND status = 'queued'\n `).run(Date.now(), runId);\n}\n\n/** Transition a spec run from \"queued\" → \"running\". */\nexport function markSpecRunStarted(runId: string): void {\n getDb().prepare(`\n UPDATE spec_runs SET status = 'running', started_at = ? WHERE run_id = ? AND status = 'queued'\n `).run(Date.now(), runId);\n}\n\n/**\n * Get the next queued entry (dispatch or spec), ordered by queued_at ASC.\n * Returns the oldest queued run across both tables, or null if none.\n */\nexport function getNextQueued(): QueuedEntry | null {\n const db = getDb();\n const runRow = db.prepare(\n \"SELECT run_id, worker_message FROM runs WHERE status = 'queued' AND worker_message IS NOT NULL ORDER BY queued_at ASC LIMIT 1\"\n ).get() as { run_id: string; worker_message: string } | undefined;\n\n const specRow = db.prepare(\n \"SELECT run_id, worker_message FROM spec_runs WHERE status = 'queued' AND worker_message IS NOT NULL ORDER BY queued_at ASC LIMIT 1\"\n ).get() as { run_id: string; worker_message: string } | undefined;\n\n if (!runRow && !specRow) return null;\n\n // If both exist, pick the one with the earlier queued_at\n if (runRow && specRow) {\n const runQueuedAt = (db.prepare(\"SELECT queued_at FROM runs WHERE run_id = ?\").get(runRow.run_id) as { queued_at: number }).queued_at;\n const specQueuedAt = (db.prepare(\"SELECT queued_at FROM spec_runs WHERE run_id = ?\").get(specRow.run_id) as { queued_at: number }).queued_at;\n if (specQueuedAt < runQueuedAt) {\n return { runId: specRow.run_id, workerMessage: specRow.worker_message, table: \"spec_runs\" };\n }\n return { runId: runRow.run_id, workerMessage: runRow.worker_message, table: \"runs\" };\n }\n\n if (runRow) return { runId: runRow.run_id, workerMessage: runRow.worker_message, table: \"runs\" };\n return { runId: specRow!.run_id, workerMessage: specRow!.worker_message, table: \"spec_runs\" };\n}\n\n/** Count active (running) runs across both dispatch and spec tables. */\nexport function countActiveRuns(): number {\n const db = getDb();\n const r1 = db.prepare(\"SELECT COUNT(*) as cnt FROM runs WHERE status = 'running'\").get() as { cnt: number };\n const r2 = db.prepare(\"SELECT COUNT(*) as cnt FROM spec_runs WHERE status = 'running'\").get() as { cnt: number };\n return r1.cnt + r2.cnt;\n}\n\n/** Get the 1-based queue position for a run, or null if not queued. */\nexport function getQueuePosition(runId: string): number | null {\n const db = getDb();\n\n // Check runs table\n const runRow = db.prepare(\"SELECT queued_at FROM runs WHERE run_id = ? AND status = 'queued'\").get(runId) as { queued_at: number } | undefined;\n if (runRow) {\n const pos = db.prepare(\n \"SELECT COUNT(*) as cnt FROM runs WHERE status = 'queued' AND queued_at <= ?\"\n ).get(runRow.queued_at) as { cnt: number };\n // Also count spec_runs queued before this one\n const specBefore = db.prepare(\n \"SELECT COUNT(*) as cnt FROM spec_runs WHERE status = 'queued' AND queued_at < ?\"\n ).get(runRow.queued_at) as { cnt: number };\n return pos.cnt + specBefore.cnt;\n }\n\n // Check spec_runs table\n const specRow = db.prepare(\"SELECT queued_at FROM spec_runs WHERE run_id = ? AND status = 'queued'\").get(runId) as { queued_at: number } | undefined;\n if (specRow) {\n const pos = db.prepare(\n \"SELECT COUNT(*) as cnt FROM spec_runs WHERE status = 'queued' AND queued_at <= ?\"\n ).get(specRow.queued_at) as { cnt: number };\n const runsBefore = db.prepare(\n \"SELECT COUNT(*) as cnt FROM runs WHERE status = 'queued' AND queued_at < ?\"\n ).get(specRow.queued_at) as { cnt: number };\n return pos.cnt + runsBefore.cnt;\n }\n\n return null;\n}\n\n/**\n * Mark all orphaned runs (status \"queued\" or \"running\") as failed.\n * Called on startup to clean up from prior crashes.\n * If `exceptSessionId` is provided, runs in that session are skipped\n * (used by CLI --resume to avoid clobbering the session being resumed).\n */\nexport function markOrphanedRunsFailed(opts?: { exceptSessionId?: string }): void {\n const db = getDb();\n const now = Date.now();\n if (opts?.exceptSessionId) {\n db.prepare(`\n UPDATE runs SET status = 'failed', finished_at = ?, error = 'Server restarted'\n WHERE status IN ('queued', 'running') AND (session_id IS NULL OR session_id != ?)\n `).run(now, opts.exceptSessionId);\n db.prepare(`\n UPDATE spec_runs SET status = 'failed', finished_at = ?, error = 'Server restarted'\n WHERE status IN ('queued', 'running') AND (session_id IS NULL OR session_id != ?)\n `).run(now, opts.exceptSessionId);\n } else {\n db.prepare(`\n UPDATE runs SET status = 'failed', finished_at = ?, error = 'Server restarted'\n WHERE status IN ('queued', 'running')\n `).run(now);\n db.prepare(`\n UPDATE spec_runs SET status = 'failed', finished_at = ?, error = 'Server restarted'\n WHERE status IN ('queued', 'running')\n `).run(now);\n }\n}\n\n/** Mark all queued runs as failed (for graceful shutdown). */\nexport function failAllQueuedRuns(): void {\n const db = getDb();\n const now = Date.now();\n db.prepare(`\n UPDATE runs SET status = 'failed', finished_at = ?, error = 'Server shutting down'\n WHERE status = 'queued'\n `).run(now);\n db.prepare(`\n UPDATE spec_runs SET status = 'failed', finished_at = ?, error = 'Server shutting down'\n WHERE status = 'queued'\n `).run(now);\n}\n\n// ── Session helpers ──────────────────────────────────────────\n\n/** Summary of a resumable session. */\nexport interface SessionSummary {\n sessionId: string;\n startedAt: number;\n totalRuns: number;\n incompleteRuns: number;\n issueIds: string; // JSON array from first run, for display\n}\n\n/**\n * List sessions with incomplete (queued/failed) runs for a given cwd.\n * Returns newest first.\n */\nexport function listResumableSessions(cwd: string): SessionSummary[] {\n const db = getDb();\n const rows = db.prepare(`\n SELECT session_id, MIN(started_at) as started_at,\n COUNT(*) as total_runs,\n SUM(CASE WHEN status IN ('queued', 'failed') THEN 1 ELSE 0 END) as incomplete,\n (SELECT issue_ids FROM runs r2 WHERE r2.session_id = runs.session_id ORDER BY started_at ASC LIMIT 1) as issue_ids\n FROM runs\n WHERE session_id IS NOT NULL AND cwd = ?\n AND session_id IN (\n SELECT DISTINCT session_id FROM runs\n WHERE status IN ('queued', 'failed') AND session_id IS NOT NULL AND cwd = ?\n )\n GROUP BY session_id\n ORDER BY MIN(started_at) DESC\n `).all(cwd, cwd) as Array<{\n session_id: string;\n started_at: number;\n total_runs: number;\n incomplete: number;\n issue_ids: string;\n }>;\n\n return rows.map((r) => ({\n sessionId: r.session_id,\n startedAt: r.started_at,\n totalRuns: r.total_runs,\n incompleteRuns: r.incomplete,\n issueIds: r.issue_ids,\n }));\n}\n\n/**\n * Requeue incomplete (failed/queued) runs for a session.\n * Resets their status to \"queued\" with a fresh queued_at timestamp.\n * Returns the run IDs that were requeued.\n */\nexport function requeueSessionRuns(sessionId: string): string[] {\n const db = getDb();\n const now = Date.now();\n\n // Get run IDs before updating\n const runRows = db.prepare(`\n SELECT run_id FROM runs\n WHERE session_id = ? AND status IN ('failed', 'queued')\n AND worker_message IS NOT NULL\n `).all(sessionId) as Array<{ run_id: string }>;\n\n const specRows = db.prepare(`\n SELECT run_id FROM spec_runs\n WHERE session_id = ? AND status IN ('failed', 'queued')\n AND worker_message IS NOT NULL\n `).all(sessionId) as Array<{ run_id: string }>;\n\n // Reset to queued\n if (runRows.length > 0) {\n db.prepare(`\n UPDATE runs SET status = 'queued', queued_at = ?, finished_at = NULL, error = NULL\n WHERE session_id = ? AND status IN ('failed', 'queued') AND worker_message IS NOT NULL\n `).run(now, sessionId);\n }\n\n if (specRows.length > 0) {\n db.prepare(`\n UPDATE spec_runs SET status = 'queued', queued_at = ?, finished_at = NULL, error = NULL\n WHERE session_id = ? AND status IN ('failed', 'queued') AND worker_message IS NOT NULL\n `).run(now, sessionId);\n }\n\n const runIds = [...runRows.map((r) => r.run_id), ...specRows.map((r) => r.run_id)];\n\n // Register live runs so completion callbacks work\n for (const runId of runIds) {\n registerLiveRun(runId);\n }\n\n return runIds;\n}\n","/**\n * Runner — thin coordinator that delegates to extracted pipeline modules.\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport type { DispatchResult } from \"../dispatcher.js\";\nimport type { ProviderModelConfig, DispatchConfig } from \"../config.js\";\nimport { CONFIG_BOUNDS } from \"../config.js\";\nimport type { ProviderName } from \"../providers/interface.js\";\nimport type { DatasourceName } from \"../datasources/interface.js\";\nimport type { SpecOptions, SpecSummary } from \"../spec-generator.js\";\nimport { defaultConcurrency, DEFAULT_SPEC_TIMEOUT_MIN, resolveSource } from \"../spec-generator.js\";\nimport { getDatasource } from \"../datasources/index.js\";\nimport { log } from \"../helpers/logger.js\";\nimport { confirmLargeBatch } from \"../helpers/confirm-large-batch.js\";\nimport { checkPrereqs } from \"../helpers/prereqs.js\";\nimport { ensureGitignoreEntry } from \"../helpers/gitignore.js\";\nimport { openDatabase } from \"../mcp/state/database.js\";\nimport {\n createRun, createSpecRun, getRun, getTasksForRun,\n markOrphanedRunsFailed, listResumableSessions, requeueSessionRuns,\n waitForRunCompletion,\n} from \"../mcp/state/manager.js\";\nimport { initRunQueue, getRunQueue } from \"../queue/run-queue.js\";\nimport { resolveCliConfig } from \"./cli-config.js\";\nimport { runSpecPipeline } from \"./spec-pipeline.js\";\nimport { runDispatchPipeline } from \"./dispatch-pipeline.js\";\n\n/** Progress event emitted by the dispatch pipeline for MCP monitoring. */\nexport type DispatchProgressEvent =\n | { type: \"task_start\"; runId?: string; taskId: string; taskText: string; phase?: string; file?: string; line?: number }\n | { type: \"task_done\"; runId?: string; taskId: string; taskText: string }\n | { type: \"task_failed\"; runId?: string; taskId: string; taskText: string; error: string }\n | { type: \"phase_change\"; runId?: string; phase: string; message?: string }\n | { type: \"log\"; runId?: string; message: string };\n\n/** Runtime options passed to `orchestrate()`. */\nexport interface OrchestrateRunOptions {\n issueIds: string[];\n concurrency?: number;\n dryRun: boolean;\n noPlan?: boolean;\n noBranch?: boolean;\n noWorktree?: boolean;\n force?: boolean;\n /** Force a specific provider for all roles (CLI --provider override). */\n provider?: ProviderName;\n /** Authenticated providers from config — router uses these for auto-selection. */\n enabledProviders?: ProviderName[];\n /** Per-provider model overrides from config. */\n providerModels?: Partial<Record<ProviderName, ProviderModelConfig>>;\n serverUrl?: string;\n source?: DatasourceName;\n org?: string;\n project?: string;\n workItemType?: string;\n iteration?: string;\n area?: string;\n /** Configured username prefix for branch naming. */\n username?: string;\n planTimeout?: number;\n planRetries?: number;\n retries?: number;\n feature?: string | boolean;\n /** Optional callback for MCP progress notifications. */\n progressCallback?: (event: DispatchProgressEvent) => void;\n}\n\n/** Raw CLI arguments before config resolution. */\nexport interface RawCliArgs {\n issueIds: string[];\n dryRun: boolean;\n noPlan: boolean;\n noBranch: boolean;\n noWorktree: boolean;\n force: boolean;\n concurrency?: number;\n /** Force a specific provider for all roles (CLI --provider override). */\n provider?: ProviderName;\n /** Authenticated providers from config. */\n enabledProviders?: ProviderName[];\n /** Per-provider model overrides from config. */\n providerModels?: Partial<Record<ProviderName, ProviderModelConfig>>;\n serverUrl?: string;\n cwd: string;\n verbose: boolean;\n spec?: string | string[];\n respec?: string | string[];\n issueSource?: DatasourceName;\n org?: string;\n project?: string;\n workItemType?: string;\n iteration?: string;\n area?: string;\n /** Configured username prefix for branch naming. */\n username?: string;\n planTimeout?: number;\n specTimeout?: number;\n specWarnTimeout?: number;\n specKillTimeout?: number;\n planRetries?: number;\n retries?: number;\n feature?: string | boolean;\n resume?: string | boolean;\n outputDir?: string;\n explicitFlags: Set<string>;\n}\n\nexport interface DispatchSummary {\n total: number;\n completed: number;\n failed: number;\n skipped: number;\n results: DispatchResult[];\n}\n\n/** Dispatch-mode run options with explicit mode discriminator. */\nexport interface DispatchRunOptions extends OrchestrateRunOptions {\n mode: \"dispatch\";\n}\n\n/** Spec-mode run options with explicit mode discriminator. */\nexport interface SpecRunOptions extends Omit<SpecOptions, \"cwd\"> {\n mode: \"spec\";\n}\n\n/** Discriminated union of all runner run options. */\nexport type UnifiedRunOptions = DispatchRunOptions | SpecRunOptions;\n\n/** Unified result type — DispatchSummary or SpecSummary depending on mode. */\nexport type RunResult = DispatchSummary | SpecSummary;\n\n/** A booted runner that coordinates dispatch and spec pipelines. */\nexport interface OrchestratorAgent {\n orchestrate(opts: OrchestrateRunOptions): Promise<DispatchSummary>;\n generateSpecs(opts: SpecOptions): Promise<SpecSummary>;\n run(opts: UnifiedRunOptions): Promise<RunResult>;\n runFromCli(args: RawCliArgs): Promise<RunResult>;\n}\n\n/** Boot a runner. */\nexport async function boot(opts: { cwd: string }): Promise<OrchestratorAgent> {\n const { cwd } = opts;\n\n const runner: OrchestratorAgent = {\n orchestrate: (runOpts) => runDispatchPipeline(runOpts, cwd),\n\n generateSpecs: (specOpts) => runSpecPipeline(specOpts),\n\n async run(opts: UnifiedRunOptions): Promise<RunResult> {\n switch (opts.mode) {\n case \"spec\": {\n const { mode: _, ...rest } = opts;\n return runner.generateSpecs({ ...rest, cwd });\n }\n case \"dispatch\": {\n const { mode: _, ...rest } = opts;\n return runner.orchestrate(rest);\n }\n default: {\n const _exhaustive: never = opts;\n throw new Error(`Unhandled run mode: ${JSON.stringify(_exhaustive)}`);\n }\n }\n },\n\n async runFromCli(args: RawCliArgs): Promise<RunResult> {\n const m = await resolveCliConfig(args);\n\n // ── Prerequisite checks ───────────────────────────────────\n const prereqFailures = await checkPrereqs();\n if (prereqFailures.length > 0) {\n for (const msg of prereqFailures) {\n log.error(msg);\n }\n process.exit(1);\n }\n\n // Ensure .dispatch/worktrees/ is gitignored in the main repo\n await ensureGitignoreEntry(m.cwd, \".dispatch/worktrees/\");\n\n // ── Mutual exclusion: --spec, --respec, --feature ──────\n const modeFlags = [\n m.spec !== undefined && \"--spec\",\n m.respec !== undefined && \"--respec\",\n m.feature && \"--feature\",\n ].filter((f): f is string => typeof f === \"string\");\n\n if (modeFlags.length > 1) {\n log.error(`${modeFlags.join(\" and \")} are mutually exclusive`);\n process.exit(1);\n }\n\n // --feature requires branching — mutually exclusive with --no-branch\n if (m.feature && m.noBranch) {\n log.error(\"--feature and --no-branch are mutually exclusive\");\n process.exit(1);\n }\n\n // ── Dry-run: run in-process without queue ─────────────────\n if (m.dryRun) {\n if (m.spec || m.respec) {\n // Resolve respec issues if needed\n let issues: string | string[];\n if (m.spec) {\n issues = m.spec;\n } else {\n const respecArgs = m.respec!;\n const isEmpty = Array.isArray(respecArgs) && respecArgs.length === 0;\n if (isEmpty) {\n const source = await resolveSource(respecArgs, m.issueSource, m.cwd);\n if (!source) process.exit(1);\n const datasource = getDatasource(source);\n const existing = await datasource.list({ cwd: m.cwd, org: m.org, project: m.project, workItemType: m.workItemType, iteration: m.iteration, area: m.area });\n if (existing.length === 0) { log.error(\"No existing specs found to regenerate\"); process.exit(1); }\n const identifiers = existing.map((item) => item.number);\n const allNumeric = identifiers.every((id) => /^\\d+$/.test(id));\n issues = allNumeric ? identifiers.join(\",\") : identifiers;\n const confirmed = await confirmLargeBatch(existing.length);\n if (!confirmed) process.exit(0);\n } else {\n issues = respecArgs;\n }\n }\n return this.generateSpecs({\n issues, issueSource: m.issueSource, provider: m.provider,\n enabledProviders: m.enabledProviders, providerModels: m.providerModels,\n serverUrl: m.serverUrl, cwd: m.cwd, outputDir: m.outputDir,\n org: m.org, project: m.project, workItemType: m.workItemType, iteration: m.iteration, area: m.area, concurrency: m.concurrency,\n dryRun: true, retries: m.retries,\n specTimeout: m.specTimeout ?? DEFAULT_SPEC_TIMEOUT_MIN,\n specWarnTimeout: m.specWarnTimeout,\n specKillTimeout: m.specKillTimeout,\n });\n }\n return this.orchestrate({\n issueIds: m.issueIds, concurrency: m.concurrency ?? defaultConcurrency(),\n dryRun: true, noPlan: m.noPlan, noBranch: m.noBranch, noWorktree: m.noWorktree,\n provider: m.provider, enabledProviders: m.enabledProviders, providerModels: m.providerModels,\n serverUrl: m.serverUrl, source: m.issueSource, org: m.org, project: m.project,\n workItemType: m.workItemType, iteration: m.iteration, area: m.area, planTimeout: m.planTimeout, planRetries: m.planRetries, retries: m.retries,\n force: m.force, feature: m.feature, username: m.username,\n });\n }\n\n // ── Queue-based execution ─────────────────────────────────\n openDatabase(cwd);\n const concurrency = m.concurrency ?? defaultConcurrency();\n const maxRuns = Math.min(Math.max(4, defaultConcurrency() * 2), CONFIG_BOUNDS.maxRuns.max);\n\n // Handle --resume\n if (m.resume !== undefined) {\n return runResumeFlow(m.resume, cwd, maxRuns);\n }\n\n const sessionId = randomUUID();\n markOrphanedRunsFailed({ exceptSessionId: sessionId });\n initRunQueue(maxRuns);\n\n if (m.spec || m.respec) {\n // Resolve spec issues (same as before)\n let issues: string | string[];\n if (m.spec) {\n issues = m.spec;\n } else {\n const respecArgs = m.respec!;\n const isEmpty = Array.isArray(respecArgs) && respecArgs.length === 0;\n if (isEmpty) {\n const source = await resolveSource(respecArgs, m.issueSource, m.cwd);\n if (!source) process.exit(1);\n const datasource = getDatasource(source);\n const existing = await datasource.list({ cwd: m.cwd, org: m.org, project: m.project, workItemType: m.workItemType, iteration: m.iteration, area: m.area });\n if (existing.length === 0) { log.error(\"No existing specs found to regenerate\"); process.exit(1); }\n const identifiers = existing.map((item) => item.number);\n const allNumeric = identifiers.every((id) => /^\\d+$/.test(id));\n issues = allNumeric ? identifiers.join(\",\") : identifiers;\n const confirmed = await confirmLargeBatch(existing.length);\n if (!confirmed) process.exit(0);\n } else {\n issues = respecArgs;\n }\n }\n\n const workerMessage = {\n type: \"spec\",\n cwd,\n opts: {\n issues,\n enabledProviders: m.enabledProviders, providerModels: m.providerModels,\n issueSource: m.issueSource,\n org: m.org, project: m.project, workItemType: m.workItemType, iteration: m.iteration, area: m.area,\n concurrency,\n specTimeout: m.specTimeout ?? DEFAULT_SPEC_TIMEOUT_MIN,\n specWarnTimeout: m.specWarnTimeout, specKillTimeout: m.specKillTimeout,\n dryRun: false, cwd,\n },\n };\n\n const runId = createSpecRun({\n cwd, issues, sessionId, status: \"queued\",\n workerMessage: JSON.stringify(workerMessage),\n });\n\n return awaitQueuedRuns([runId], sessionId, cwd, \"spec\");\n }\n\n // Dispatch mode\n const workerMessage = {\n type: \"dispatch\",\n cwd,\n opts: {\n issueIds: m.issueIds, dryRun: false,\n provider: m.provider,\n enabledProviders: m.enabledProviders, providerModels: m.providerModels,\n source: m.issueSource, org: m.org, project: m.project,\n workItemType: m.workItemType, iteration: m.iteration, area: m.area,\n username: m.username, planTimeout: m.planTimeout,\n concurrency,\n noPlan: m.noPlan, noBranch: m.noBranch, noWorktree: m.noWorktree,\n retries: m.retries, feature: m.feature, planRetries: m.planRetries,\n force: m.force,\n },\n };\n\n const runId = createRun({\n cwd, issueIds: m.issueIds, sessionId, status: \"queued\",\n workerMessage: JSON.stringify(workerMessage),\n });\n\n return awaitQueuedRuns([runId], sessionId, cwd, \"dispatch\");\n },\n };\n\n return runner;\n}\n\n// ── CLI queue helpers ────────────────────────────────────────\n\n/** CLI log callback that writes progress to the logger. */\nfunction cliLogCallback(message: string, level?: \"info\" | \"warn\" | \"error\"): void {\n if (level === \"error\") log.error(message);\n else if (level === \"warn\") log.warn(message);\n else log.info(message);\n}\n\n/**\n * Enqueue runs and block until all reach a terminal status.\n * Returns a summary derived from the DB state.\n */\nasync function awaitQueuedRuns(\n runIds: string[],\n sessionId: string,\n cwd: string,\n mode: \"dispatch\" | \"spec\",\n): Promise<RunResult> {\n const queue = getRunQueue();\n\n // Enqueue all runs\n for (const runId of runIds) {\n queue.enqueue(runId, cliLogCallback);\n }\n\n // Wait for all runs to reach terminal status\n await Promise.all(runIds.map((runId) =>\n waitForRunCompletion(runId, 600_000, () => getRun(runId)?.status ?? null),\n ));\n\n // Build summary from DB\n if (mode === \"spec\") {\n let total = 0, generated = 0, failed = 0;\n for (const runId of runIds) {\n const { getSpecRun } = await import(\"../mcp/state/manager.js\");\n const run = getSpecRun(runId);\n if (run) {\n total += run.total;\n generated += run.generated;\n failed += run.failed;\n }\n }\n return { total, generated, failed } as SpecSummary;\n }\n\n // Dispatch summary\n let total = 0, completed = 0, failed = 0;\n const results: DispatchResult[] = [];\n for (const runId of runIds) {\n const run = getRun(runId);\n if (run) {\n total += run.total;\n completed += run.completed;\n failed += run.failed;\n }\n const tasks = getTasksForRun(runId);\n for (const task of tasks) {\n results.push({\n task: { file: task.file, line: task.line, text: task.taskText },\n success: task.status === \"success\",\n error: task.error ?? undefined,\n } as DispatchResult);\n }\n }\n return { total, completed, failed, skipped: 0, results };\n}\n\n/**\n * Handle --resume flow: list resumable sessions, prompt if needed, requeue.\n */\nasync function runResumeFlow(\n resumeArg: string | boolean,\n cwd: string,\n maxRuns: number,\n): Promise<RunResult> {\n const sessions = listResumableSessions(cwd);\n\n if (sessions.length === 0) {\n log.info(\"No incomplete sessions found to resume.\");\n process.exit(0);\n }\n\n let sessionId: string;\n\n if (typeof resumeArg === \"string\") {\n // Specific session ID provided\n const match = sessions.find((s) => s.sessionId === resumeArg);\n if (!match) {\n log.error(`Session ${resumeArg} not found or has no incomplete runs.`);\n log.info(\"Available sessions:\");\n for (const s of sessions) {\n const date = new Date(s.startedAt).toLocaleString();\n log.info(` ${s.sessionId} (${date}, ${s.incompleteRuns} incomplete)`);\n }\n process.exit(1);\n }\n sessionId = resumeArg;\n } else if (sessions.length === 1) {\n // Auto-select the only session\n sessionId = sessions[0].sessionId;\n log.info(`Resuming session ${sessionId} (${sessions[0].incompleteRuns} incomplete run(s))`);\n } else {\n // Prompt user to pick\n const { select } = await import(\"../helpers/ink-prompts.js\");\n sessionId = await select<string>({\n message: \"Multiple incomplete sessions found. Which one would you like to resume?\",\n choices: sessions.map((s) => {\n const date = new Date(s.startedAt).toLocaleString();\n let issueLabel = \"\";\n try {\n const ids = JSON.parse(s.issueIds) as string[];\n issueLabel = ids.length > 3 ? `issues ${ids.slice(0, 3).join(\", \")}...` : `issues ${ids.join(\", \")}`;\n } catch { issueLabel = \"unknown issues\"; }\n return {\n name: `${s.sessionId.slice(0, 8)} ${date} ${issueLabel} (${s.incompleteRuns} incomplete)`,\n value: s.sessionId,\n };\n }),\n });\n }\n\n markOrphanedRunsFailed({ exceptSessionId: sessionId });\n initRunQueue(maxRuns);\n\n const runIds = requeueSessionRuns(sessionId);\n if (runIds.length === 0) {\n log.info(\"No runs to resume in this session.\");\n process.exit(0);\n }\n\n log.info(`Resuming ${runIds.length} run(s) from session ${sessionId.slice(0, 8)}...`);\n return awaitQueuedRuns(runIds, sessionId, cwd, \"dispatch\");\n}\n\nexport { parseIssueFilename } from \"./datasource-helpers.js\";\n","/**\n * Configuration data layer for Dispatch.\n *\n * Manages persistent user configuration stored in {CWD}/.dispatch/config.json.\n * Provides functions for loading, saving, and validating config values.\n */\nimport { readFile, writeFile, mkdir } from \"node:fs/promises\";\nimport { join, dirname } from \"node:path\";\nimport { PROVIDER_NAMES } from \"./providers/index.js\";\nimport { DATASOURCE_NAMES } from \"./datasources/index.js\";\nimport type { ProviderName } from \"./providers/interface.js\";\nimport type { DatasourceName } from \"./datasources/interface.js\";\nimport { runInteractiveConfigWizard } from \"./config-prompts.js\";\n\n/** Per-provider model overrides. Absent roles fall back to registry defaults. */\nexport interface ProviderModelConfig {\n strong?: string;\n fast?: string;\n}\n\n/**\n * Persistent configuration options for Dispatch.\n * All fields are optional since the config file may contain any subset.\n */\nexport interface DispatchConfig {\n /**\n * Providers the user has authenticated and enabled.\n * Populated by the config wizard during auth setup.\n * The router uses this list to decide which providers to route to.\n */\n enabledProviders?: ProviderName[];\n /** Per-provider model overrides for strong/fast roles. */\n providerModels?: Partial<Record<ProviderName, ProviderModelConfig>>;\n source?: DatasourceName;\n planTimeout?: number;\n specTimeout?: number;\n specWarnTimeout?: number;\n specKillTimeout?: number;\n concurrency?: number;\n org?: string;\n project?: string;\n workItemType?: string;\n iteration?: string;\n area?: string;\n /** Short username prefix for branch names (e.g. \"pr\" instead of \"patrick-ruddiman\"). */\n username?: string;\n /** Internal auto-increment counter for MD datasource issue IDs. Defaults to 1 when absent. */\n nextIssueId?: number;\n /** Maximum number of concurrent MCP runs (child processes). Defaults to defaultConcurrency(). */\n maxRuns?: number;\n /** Preferred provider for `dispatch shell` orchestrator mode. */\n orchestratorProvider?: ProviderName;\n}\n\n/** Minimum and maximum bounds for numeric configuration values. */\nexport const CONFIG_BOUNDS = {\n planTimeout: { min: 1, max: 120 },\n specTimeout: { min: 1, max: 120 },\n specWarnTimeout: { min: 1, max: 120 },\n specKillTimeout: { min: 1, max: 120 },\n concurrency: { min: 1, max: 64 },\n maxRuns: { min: 1, max: 32 },\n} as const;\n\n/** Valid configuration key names. */\nexport const CONFIG_KEYS = [\"enabledProviders\", \"providerModels\", \"source\", \"planTimeout\", \"specTimeout\", \"specWarnTimeout\", \"specKillTimeout\", \"concurrency\", \"maxRuns\", \"org\", \"project\", \"workItemType\", \"iteration\", \"area\", \"username\", \"orchestratorProvider\"] as const;\n\n/** A valid configuration key name. */\nexport type ConfigKey = (typeof CONFIG_KEYS)[number];\n\n/**\n * Get the path to the config file.\n * Accepts an optional `configDir` override for testing.\n */\nexport function getConfigPath(configDir?: string): string {\n const dir = configDir ?? join(process.cwd(), \".dispatch\");\n return join(dir, \"config.json\");\n}\n\n/**\n * Load the config from disk.\n * Returns `{}` if the file doesn't exist or contains invalid JSON.\n * Migrates legacy configs that used `provider`/`model`/`agents` fields.\n * Accepts an optional `configDir` override for testing.\n */\nexport async function loadConfig(configDir?: string): Promise<DispatchConfig> {\n const configPath = getConfigPath(configDir);\n try {\n const raw = await readFile(configPath, \"utf-8\");\n const parsed = JSON.parse(raw) as Record<string, unknown>;\n return migrateConfig(parsed);\n } catch {\n return {};\n }\n}\n\n/**\n * Migrate legacy config format to the new schema.\n *\n * Old configs had: provider, model, fastProvider, fastModel, agents\n * New configs have: enabledProviders\n *\n * Legacy fields are silently dropped. The provider name is extracted\n * into enabledProviders if not already set.\n */\nfunction migrateConfig(raw: Record<string, unknown>): DispatchConfig {\n const config: DispatchConfig = {};\n\n // Migrate legacy provider field into enabledProviders\n if (!raw.enabledProviders && raw.provider) {\n const providers = new Set<ProviderName>();\n const legacyProvider = raw.provider as ProviderName;\n if (PROVIDER_NAMES.includes(legacyProvider)) {\n providers.add(legacyProvider);\n }\n // Also pick up fastProvider if different\n if (raw.fastProvider) {\n const fastProvider = raw.fastProvider as ProviderName;\n if (PROVIDER_NAMES.includes(fastProvider)) {\n providers.add(fastProvider);\n }\n }\n // Pick up per-agent providers\n if (raw.agents && typeof raw.agents === \"object\") {\n for (const agentCfg of Object.values(raw.agents as Record<string, { provider?: string }>)) {\n if (agentCfg?.provider && PROVIDER_NAMES.includes(agentCfg.provider as ProviderName)) {\n providers.add(agentCfg.provider as ProviderName);\n }\n }\n }\n if (providers.size > 0) {\n config.enabledProviders = [...providers];\n }\n } else if (Array.isArray(raw.enabledProviders)) {\n config.enabledProviders = (raw.enabledProviders as string[]).filter((p) =>\n PROVIDER_NAMES.includes(p as ProviderName),\n ) as ProviderName[];\n }\n\n // Copy over providerModels (validate shape)\n if (raw.providerModels !== undefined && typeof raw.providerModels === \"object\" && raw.providerModels !== null) {\n const validated: Partial<Record<ProviderName, ProviderModelConfig>> = {};\n for (const [providerName, modelCfg] of Object.entries(raw.providerModels as Record<string, unknown>)) {\n if (!PROVIDER_NAMES.includes(providerName as ProviderName)) continue;\n if (typeof modelCfg !== \"object\" || modelCfg === null) continue;\n const cfg = modelCfg as Record<string, unknown>;\n const entry: ProviderModelConfig = {};\n if (typeof cfg.strong === \"string\") entry.strong = cfg.strong;\n if (typeof cfg.fast === \"string\") entry.fast = cfg.fast;\n if (entry.strong !== undefined || entry.fast !== undefined) {\n validated[providerName as ProviderName] = entry;\n }\n }\n if (Object.keys(validated).length > 0) {\n config.providerModels = validated;\n }\n }\n\n // Copy over non-legacy fields with runtime type guards\n if (typeof raw.source === \"string\" && DATASOURCE_NAMES.includes(raw.source as DatasourceName)) {\n config.source = raw.source as DatasourceName;\n }\n if (typeof raw.planTimeout === \"number\") config.planTimeout = raw.planTimeout;\n if (typeof raw.specTimeout === \"number\") config.specTimeout = raw.specTimeout;\n if (typeof raw.specWarnTimeout === \"number\") config.specWarnTimeout = raw.specWarnTimeout;\n if (typeof raw.specKillTimeout === \"number\") config.specKillTimeout = raw.specKillTimeout;\n if (typeof raw.concurrency === \"number\") config.concurrency = raw.concurrency;\n if (typeof raw.maxRuns === \"number\") config.maxRuns = raw.maxRuns;\n if (typeof raw.org === \"string\") config.org = raw.org;\n if (typeof raw.project === \"string\") config.project = raw.project;\n if (typeof raw.workItemType === \"string\") config.workItemType = raw.workItemType;\n if (typeof raw.iteration === \"string\") config.iteration = raw.iteration;\n if (typeof raw.area === \"string\") config.area = raw.area;\n if (typeof raw.username === \"string\") config.username = raw.username;\n if (typeof raw.nextIssueId === \"number\") config.nextIssueId = raw.nextIssueId;\n\n return config;\n}\n\n/**\n * Save the config to disk as pretty-printed JSON.\n * Creates the parent directory if it doesn't exist.\n * Accepts an optional `configDir` override for testing.\n */\nexport async function saveConfig(\n config: DispatchConfig,\n configDir?: string,\n): Promise<void> {\n const configPath = getConfigPath(configDir);\n await mkdir(dirname(configPath), { recursive: true });\n await writeFile(configPath, JSON.stringify(config, null, 2) + \"\\n\", \"utf-8\");\n}\n\n/**\n * Validate a value for a given config key.\n * Returns `null` if valid, or an error message string if invalid.\n */\nexport function validateConfigValue(key: ConfigKey, value: string): string | null {\n switch (key) {\n case \"enabledProviders\":\n case \"providerModels\":\n // Complex fields — skip string-level validation.\n return null;\n\n case \"source\":\n if (!DATASOURCE_NAMES.includes(value as DatasourceName)) {\n return `Invalid source \"${value}\". Available: ${DATASOURCE_NAMES.join(\", \")}`;\n }\n return null;\n\n case \"planTimeout\": {\n const num = Number(value);\n if (!Number.isFinite(num) || num < CONFIG_BOUNDS.planTimeout.min || num > CONFIG_BOUNDS.planTimeout.max) {\n return `Invalid planTimeout \"${value}\". Must be a number between ${CONFIG_BOUNDS.planTimeout.min} and ${CONFIG_BOUNDS.planTimeout.max} (minutes)`;\n }\n return null;\n }\n\n case \"specTimeout\": {\n const num = Number(value);\n if (!Number.isFinite(num) || num < CONFIG_BOUNDS.specTimeout.min || num > CONFIG_BOUNDS.specTimeout.max) {\n return `Invalid specTimeout \"${value}\". Must be a number between ${CONFIG_BOUNDS.specTimeout.min} and ${CONFIG_BOUNDS.specTimeout.max} (minutes)`;\n }\n return null;\n }\n\n case \"specWarnTimeout\": {\n const num = Number(value);\n if (!Number.isFinite(num) || num < CONFIG_BOUNDS.specWarnTimeout.min || num > CONFIG_BOUNDS.specWarnTimeout.max) {\n return `Invalid specWarnTimeout \"${value}\". Must be a number between ${CONFIG_BOUNDS.specWarnTimeout.min} and ${CONFIG_BOUNDS.specWarnTimeout.max} (minutes)`;\n }\n return null;\n }\n\n case \"specKillTimeout\": {\n const num = Number(value);\n if (!Number.isFinite(num) || num < CONFIG_BOUNDS.specKillTimeout.min || num > CONFIG_BOUNDS.specKillTimeout.max) {\n return `Invalid specKillTimeout \"${value}\". Must be a number between ${CONFIG_BOUNDS.specKillTimeout.min} and ${CONFIG_BOUNDS.specKillTimeout.max} (minutes)`;\n }\n return null;\n }\n\n case \"concurrency\": {\n const num = Number(value);\n if (!Number.isInteger(num) || num < CONFIG_BOUNDS.concurrency.min || num > CONFIG_BOUNDS.concurrency.max) {\n return `Invalid concurrency \"${value}\". Must be an integer between ${CONFIG_BOUNDS.concurrency.min} and ${CONFIG_BOUNDS.concurrency.max}`;\n }\n return null;\n }\n\n case \"maxRuns\": {\n const num = Number(value);\n if (!Number.isInteger(num) || num < CONFIG_BOUNDS.maxRuns.min || num > CONFIG_BOUNDS.maxRuns.max) {\n return `Invalid maxRuns \"${value}\". Must be an integer between ${CONFIG_BOUNDS.maxRuns.min} and ${CONFIG_BOUNDS.maxRuns.max}`;\n }\n return null;\n }\n\n case \"org\":\n case \"project\":\n case \"workItemType\":\n case \"iteration\":\n case \"area\":\n if (!value || value.trim() === \"\") {\n return `Invalid ${key}: value must not be empty`;\n }\n return null;\n\n case \"username\": {\n if (!value || value.trim() === \"\") {\n return `Invalid username: value must not be empty`;\n }\n if (value.length > 20) {\n return `Invalid username \"${value}\". Must be at most 20 characters`;\n }\n if (!/^[a-zA-Z0-9-]+$/.test(value)) {\n return `Invalid username \"${value}\". Must contain only alphanumeric characters and hyphens`;\n }\n return null;\n }\n\n case \"orchestratorProvider\": {\n if (!PROVIDER_NAMES.includes(value as ProviderName)) {\n return `Invalid orchestratorProvider \"${value}\". Available: ${PROVIDER_NAMES.join(\", \")}`;\n }\n return null;\n }\n\n default: {\n const _exhaustive: never = key;\n return `Unknown config key \"${_exhaustive}\"`;\n }\n }\n}\n\n/**\n * Handle the `dispatch config` subcommand.\n *\n * Launches the interactive configuration wizard.\n */\nexport async function handleConfigCommand(_argv: string[], configDir?: string): Promise<void> {\n await runInteractiveConfigWizard(configDir);\n}\n","/**\n * Provider interface — abstracts the underlying AI agent runtime so that\n * new code agents (OpenCode, Copilot, Claude Code, etc.) can be added by\n * implementing a single interface.\n *\n * Each provider manages its own server lifecycle, session isolation, and\n * prompt/response serialization. The orchestrator interacts exclusively\n * through this contract.\n */\n\nexport const PROVIDER_NAMES = [\"opencode\", \"copilot\", \"claude\", \"codex\"] as const;\n\n/** Valid provider backend names. */\nexport type ProviderName = typeof PROVIDER_NAMES[number];\n\nexport interface ProviderProgressSnapshot {\n text: string;\n}\n\n/**\n * Options passed when booting a provider.\n */\nexport interface ProviderBootOptions {\n /** Connect to an already-running server at this URL instead of spawning one */\n url?: string;\n /** Working directory for the agent */\n cwd?: string;\n /**\n * Model to use, overriding the provider's default.\n * Format is provider-specific:\n * - Copilot: bare model ID (e.g. \"claude-sonnet-4-5\")\n * - OpenCode: \"provider/model\" (e.g. \"anthropic/claude-sonnet-4\")\n * When omitted the provider uses its auto-detected default.\n */\n model?: string;\n}\n\nexport interface ProviderPromptOptions {\n onProgress?: (snapshot: ProviderProgressSnapshot) => void;\n}\n\n/**\n * A booted provider instance that can create sessions and send prompts.\n *\n * To add support for a new agent backend:\n * 1. Create `src/providers/<name>.ts`\n * 2. Export an async `boot` function that returns a `ProviderInstance`\n * 3. Register it in `src/providers/index.ts`\n */\nexport interface ProviderInstance {\n /** Human-readable provider name (e.g. \"opencode\", \"copilot\") */\n readonly name: string;\n\n /**\n * Full model identifier in \"provider/model\" format as reported by the\n * underlying AI backend (e.g. \"anthropic/claude-sonnet-4\"), if available.\n */\n readonly model?: string;\n\n /**\n * Create a new isolated session for a single task.\n * Returns an opaque session identifier.\n */\n createSession(): Promise<string>;\n\n /**\n * Send a prompt to an existing session and wait for the agent to finish.\n * Returns the agent's text response, or null if no response was produced.\n */\n prompt(\n sessionId: string,\n text: string,\n options?: ProviderPromptOptions,\n ): Promise<string | null>;\n\n /**\n * Inject a follow-up message into a running session without blocking\n * for a response. Used to send time-warning nudges to the agent.\n * Optional — providers that don't support mid-session messaging can omit this.\n */\n send?(sessionId: string, text: string): Promise<void>;\n\n /**\n * Tear down the provider — stop servers, release resources.\n * Safe to call multiple times.\n */\n cleanup(): Promise<void>;\n}\n","/**\n * OpenCode provider — wraps the @opencode-ai/sdk to conform to the\n * generic ProviderInstance interface.\n *\n * Uses the asynchronous prompt API (`promptAsync`) combined with SSE\n * event streaming to avoid HTTP timeout issues. The blocking `prompt()`\n * SDK method sends a single long-lived HTTP request that can exceed\n * Node.js/undici's default headers timeout for slow LLM responses.\n *\n * Flow:\n * 1. `promptAsync()` — fire-and-forget POST that returns 204 immediately\n * 2. `event.subscribe()` — SSE stream that yields session lifecycle events\n * 3. Wait for `session.idle` (success) or `session.error` (failure)\n * 4. `session.messages()` — fetch the completed response\n */\n\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport {\n createOpencode,\n createOpencodeClient,\n type OpencodeClient,\n type Part,\n type TextPart,\n type Event as SdkEvent,\n} from \"@opencode-ai/sdk\";\nimport type {\n ProviderInstance,\n ProviderBootOptions,\n ProviderPromptOptions,\n} from \"./interface.js\";\nimport { createProgressReporter } from \"./progress.js\";\nimport { log } from \"../helpers/logger.js\";\nimport { hasProperty } from \"../helpers/guards.js\";\nimport { withTimeout } from \"../helpers/timeout.js\";\n\n/** Maximum time (ms) to wait for an OpenCode session to become idle after sending a prompt. */\nconst SESSION_READY_TIMEOUT_MS = 600_000;\n\n/**\n * List available OpenCode models.\n *\n * Uses the `opencode models` CLI command to fetch available models.\n * Returns model IDs in \"provider/model\" format (e.g. \"github-copilot/claude-sonnet-4\").\n */\nexport async function listModels(_opts?: ProviderBootOptions): Promise<string[]> {\n try {\n const exec = promisify(execFile);\n const { stdout } = await exec(\"opencode\", [\"models\"], { timeout: 10_000 });\n return stdout\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line.length > 0)\n .sort();\n } catch (err) {\n log.debug(`listModels: failed to list OpenCode models: ${log.formatErrorChain(err)}`);\n return [];\n }\n}\n\n/**\n * Boot an OpenCode instance — either connect to a running server\n * or start a new one.\n */\nexport async function boot(opts?: ProviderBootOptions): Promise<ProviderInstance> {\n let client: OpencodeClient;\n let stopServer: (() => void) | undefined;\n let cleaned = false;\n\n if (opts?.url) {\n log.debug(`Connecting to existing OpenCode server at ${opts.url}`);\n client = createOpencodeClient({ baseUrl: opts.url });\n } else {\n log.debug(\"No --server-url provided, spawning local OpenCode server...\");\n // NOTE: The @opencode-ai/sdk `createOpencodeServer` spawns the `opencode`\n // process via `child_process.spawn()` without a `cwd` option — the server\n // inherits `process.cwd()`. There is no `ServerOptions.cwd` or `Config`\n // field to control the working directory. When a worktree `cwd` is needed,\n // the prompt-level cwd (set by the executor/dispatcher) ensures the agent\n // operates in the correct directory.\n if (opts?.cwd) {\n log.debug(`Requested cwd \"${opts.cwd}\" — OpenCode SDK does not support spawn-level cwd; relying on prompt-level cwd`);\n }\n try {\n const oc = await createOpencode({ port: 0 });\n client = oc.client;\n stopServer = () => oc.server.close();\n log.debug(\"OpenCode server started successfully\");\n } catch (err) {\n log.debug(`Failed to start OpenCode server: ${log.formatErrorChain(err)}`);\n throw err;\n }\n }\n\n // ── Parse model override from boot options ────────────────────\n // Format: \"providerID/modelID\" (e.g. \"anthropic/claude-sonnet-4\")\n let modelOverride: { providerID: string; modelID: string } | undefined;\n if (opts?.model) {\n const slash = opts.model.indexOf(\"/\");\n if (slash > 0) {\n modelOverride = {\n providerID: opts.model.slice(0, slash),\n modelID: opts.model.slice(slash + 1),\n };\n log.debug(`Model override: ${opts.model}`);\n } else {\n log.debug(`Ignoring model override \"${opts.model}\": must be in \"provider/model\" format`);\n }\n }\n\n // ── Retrieve the active model (best-effort) ──────────────────\n let model: string | undefined = opts?.model;\n if (!model) {\n try {\n const { data: config } = await client.config.get();\n if (config?.model) {\n // model is in \"provider/model\" format (e.g. \"anthropic/claude-sonnet-4\")\n model = config.model;\n log.debug(`Detected model: ${model}`);\n }\n } catch (err) {\n log.debug(`Failed to retrieve model from config: ${log.formatErrorChain(err)}`);\n }\n }\n\n return {\n name: \"opencode\",\n model,\n\n async createSession(): Promise<string> {\n log.debug(\"Creating OpenCode session...\");\n try {\n const { data: session } = await client.session.create();\n if (!session) {\n throw new Error(\"Failed to create OpenCode session\");\n }\n log.debug(`Session created: ${session.id}`);\n return session.id;\n } catch (err) {\n log.debug(`Session creation failed: ${log.formatErrorChain(err)}`);\n throw err;\n }\n },\n\n async prompt(\n sessionId: string,\n text: string,\n options?: ProviderPromptOptions,\n ): Promise<string | null> {\n log.debug(`Sending async prompt to session ${sessionId} (${text.length} chars)...`);\n\n let controller: AbortController | undefined;\n const reporter = createProgressReporter(options?.onProgress);\n\n try {\n // ── 1. Fire-and-forget: start the LLM processing ──────────\n const { error: promptError } = await client.session.promptAsync({\n path: { id: sessionId },\n body: {\n parts: [{ type: \"text\", text }],\n ...(modelOverride ? { model: modelOverride } : {}),\n },\n });\n\n if (promptError) {\n throw new Error(`OpenCode promptAsync failed: ${JSON.stringify(promptError)}`);\n }\n\n log.debug(\"Async prompt accepted, subscribing to events...\");\n\n // ── 2. Subscribe to SSE events ────────────────────────────\n controller = new AbortController();\n try {\n const { stream } = await client.event.subscribe({\n signal: controller.signal,\n });\n\n // ── 3. Wait for session to become idle or error ───────────\n await withTimeout(\n waitForSessionReady(stream, sessionId, reporter),\n SESSION_READY_TIMEOUT_MS,\n \"opencode session ready\",\n );\n } finally {\n if (controller && !controller.signal.aborted) controller.abort();\n }\n\n log.debug(\"Session went idle, fetching result...\");\n\n // ── 4. Fetch the completed message ────────────────────────\n const { data: messages } = await client.session.messages({\n path: { id: sessionId },\n });\n\n if (!messages || messages.length === 0) {\n log.debug(\"No messages found in session\");\n return null;\n }\n\n const lastAssistant = [...messages]\n .reverse()\n .find((m) => m.info.role === \"assistant\");\n\n if (!lastAssistant) {\n log.debug(\"No assistant message found in session\");\n return null;\n }\n\n // Check for errors on the assistant message\n if (hasProperty(lastAssistant.info, \"error\") && lastAssistant.info.error) {\n throw new Error(\n `OpenCode assistant error: ${JSON.stringify(lastAssistant.info.error)}`\n );\n }\n\n // ── 5. Extract text parts ─────────────────────────────────\n const textParts = lastAssistant.parts.filter(\n (p: Part): p is TextPart => p.type === \"text\" && \"text\" in p\n );\n const result = textParts.map((p: TextPart) => p.text).join(\"\\n\") || null;\n log.debug(`Prompt response received (${result?.length ?? 0} chars)`);\n return result;\n } catch (err) {\n log.debug(`Prompt failed: ${log.formatErrorChain(err)}`);\n throw err;\n }\n },\n\n async send(sessionId: string, text: string): Promise<void> {\n log.debug(`Sending follow-up message to session ${sessionId} (${text.length} chars)...`);\n const { error } = await client.session.promptAsync({\n path: { id: sessionId },\n body: {\n parts: [{ type: \"text\", text }],\n ...(modelOverride ? { model: modelOverride } : {}),\n },\n });\n if (error) {\n throw new Error(`OpenCode send failed: ${JSON.stringify(error)}`);\n }\n log.debug(\"Follow-up message sent successfully\");\n },\n\n async cleanup(): Promise<void> {\n if (cleaned) return;\n cleaned = true;\n log.debug(\"Cleaning up OpenCode provider...\");\n try {\n stopServer?.();\n } catch (err) {\n log.debug(`Failed to stop OpenCode server: ${log.formatErrorChain(err)}`);\n }\n },\n };\n}\n\nasync function waitForSessionReady(\n stream: AsyncIterable<SdkEvent>,\n sessionId: string,\n reporter?: { emit: (delta: string) => void },\n): Promise<void> {\n for await (const event of stream) {\n if (!isSessionEvent(event, sessionId)) continue;\n\n if (\n event.type === \"message.part.updated\" &&\n event.properties.part.type === \"text\"\n ) {\n const delta = event.properties.delta;\n if (delta) {\n log.debug(`Streaming text (+${delta.length} chars)...`);\n reporter?.emit(delta);\n }\n continue;\n }\n\n if (event.type === \"session.error\") {\n const err = event.properties.error;\n throw new Error(\n `OpenCode session error: ${err ? JSON.stringify(err) : \"unknown error\"}`\n );\n }\n\n if (event.type === \"session.idle\") {\n return;\n }\n }\n\n throw new Error(\"OpenCode event stream ended before session became idle\");\n}\n\n/**\n * Check whether an SSE event belongs to the given session.\n *\n * Different event types store the session ID in different places:\n * - `session.*` events → `properties.sessionID`\n * - `message.*` events → `properties.info.sessionID` or `properties.part.sessionID`\n */\nfunction isSessionEvent(event: SdkEvent, sessionId: string): boolean {\n const props: unknown = event.properties;\n\n if (!hasProperty(props, \"sessionID\") && !hasProperty(props, \"info\") && !hasProperty(props, \"part\")) {\n return false;\n }\n\n // Direct sessionID on the event (session.idle, session.error, session.status, etc.)\n if (hasProperty(props, \"sessionID\") && props.sessionID === sessionId) return true;\n\n // Nested in .info (message.updated)\n if (hasProperty(props, \"info\") && hasProperty(props.info, \"sessionID\") && props.info.sessionID === sessionId) {\n return true;\n }\n\n // Nested in .part (message.part.updated)\n if (hasProperty(props, \"part\") && hasProperty(props.part, \"sessionID\") && props.part.sessionID === sessionId) {\n return true;\n }\n\n return false;\n}\n","import type { ProviderPromptOptions } from \"./interface.js\";\n\nconst ANSI_PATTERN = /(?:\\u001B\\[[0-?]*[ -/]*[@-~]|\\u009B[0-?]*[ -/]*[@-~]|\\u001B\\][^\\u0007]*(?:\\u0007|\\u001B\\\\))/g;\nconst CONTROL_PATTERN = /[\\u0000-\\u0008\\u000B-\\u001F\\u007F]/g;\n\nexport function sanitizeProgressText(raw: string, maxLength = 120): string {\n const text = raw\n .replace(ANSI_PATTERN, \"\")\n .replace(CONTROL_PATTERN, \"\")\n .replace(/\\s+/g, \" \")\n .trim();\n\n if (!text) return \"\";\n if (text.length <= maxLength) return text;\n if (maxLength <= 1) return maxLength <= 0 ? \"\" : \"…\";\n return `${text.slice(0, maxLength - 1).trimEnd()}…`;\n}\n\n/** A lightweight progress reporter that de-duplicates successive identical messages. */\nexport interface ProgressReporter {\n /** Emit a progress text snapshot, de-duplicating against the previous value. */\n emit(raw?: string | null): void;\n /** Reset the last-emitted value so the next identical message is re-emitted. */\n reset(): void;\n}\n\nexport function createProgressReporter(onProgress?: ProviderPromptOptions[\"onProgress\"]): ProgressReporter {\n let last: string | undefined;\n\n return {\n emit(raw?: string | null) {\n if (!onProgress) return;\n\n const text = sanitizeProgressText(raw ?? \"\");\n if (!text || text === last) return;\n\n last = text;\n try {\n onProgress({ text });\n } catch {\n // Ignore callback errors from callers.\n }\n },\n\n reset() {\n last = undefined;\n },\n };\n}\n","/**\n * Minimal structured logger for CLI output.\n *\n * The initial log level is resolved at module load from environment variables:\n * 1. `LOG_LEVEL` env var — one of `\"debug\"`, `\"info\"`, `\"warn\"`, `\"error\"`\n * 2. `DEBUG` env var — any truthy value sets the level to `\"debug\"`\n * 3. Default: `\"info\"`\n *\n * At runtime, `log.verbose` (or the `--verbose` CLI flag) can override the\n * env-resolved level — setting it to `true` forces `\"debug\"`, and `false`\n * resets to `\"info\"` regardless of the original env value.\n */\n\nimport chalk from \"chalk\";\nimport { fileLoggerStorage } from \"./file-logger.js\";\n\n/** Supported log levels, ordered from most to least verbose. */\nexport type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\nconst LOG_LEVEL_SEVERITY: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n};\n\n/** Type predicate: returns true if `level` is a valid `LogLevel` key. */\nfunction isLogLevel(level: string): level is LogLevel {\n return Object.hasOwn(LOG_LEVEL_SEVERITY, level);\n}\n\n/**\n * Resolve the effective log level from environment variables.\n * Priority: LOG_LEVEL > DEBUG > default (\"info\").\n */\nfunction resolveLogLevel(): LogLevel {\n const envLevel = process.env.LOG_LEVEL?.toLowerCase();\n if (envLevel && isLogLevel(envLevel)) {\n return envLevel;\n }\n if (process.env.DEBUG) {\n return \"debug\";\n }\n return \"info\";\n}\n\n/** Current effective log level. */\nlet currentLevel: LogLevel = resolveLogLevel();\n\n/** Returns the current effective log level. */\nexport function getLogLevel(): LogLevel {\n return currentLevel;\n}\n\nfunction shouldLog(level: LogLevel): boolean {\n return LOG_LEVEL_SEVERITY[level] >= LOG_LEVEL_SEVERITY[currentLevel];\n}\n\n/** Strip ANSI escape codes from a string for plain-text file logging. */\nfunction stripAnsi(str: string): string {\n return str.replace(/\\x1B\\[[0-9;]*m/g, \"\");\n}\n\n/** Maximum depth to traverse when unwinding nested error `.cause` chains. */\nconst MAX_CAUSE_CHAIN_DEPTH = 5;\n\nexport const log = {\n verbose: false as boolean,\n\n info(msg: string) {\n if (!shouldLog(\"info\")) return;\n console.log(chalk.blue(\"ℹ\"), msg);\n fileLoggerStorage.getStore()?.info(stripAnsi(msg));\n },\n success(msg: string) {\n if (!shouldLog(\"info\")) return;\n console.log(chalk.green(\"✔\"), msg);\n fileLoggerStorage.getStore()?.success(stripAnsi(msg));\n },\n warn(msg: string) {\n if (!shouldLog(\"warn\")) return;\n console.error(chalk.yellow(\"⚠\"), msg);\n fileLoggerStorage.getStore()?.warn(stripAnsi(msg));\n },\n error(msg: string) {\n if (!shouldLog(\"error\")) return;\n console.error(chalk.red(\"✖\"), msg);\n fileLoggerStorage.getStore()?.error(stripAnsi(msg));\n },\n task(index: number, total: number, msg: string) {\n if (!shouldLog(\"info\")) return;\n console.log(chalk.cyan(`[${index + 1}/${total}]`), msg);\n fileLoggerStorage.getStore()?.task(stripAnsi(`[${index + 1}/${total}] ${msg}`));\n },\n dim(msg: string) {\n if (!shouldLog(\"info\")) return;\n console.log(chalk.dim(msg));\n fileLoggerStorage.getStore()?.dim(stripAnsi(msg));\n },\n\n /**\n * Print a debug/verbose message. Only visible when the log level is\n * `\"debug\"`. Messages are prefixed with a dim arrow to visually nest\n * them under the preceding info/error line.\n */\n debug(msg: string) {\n if (!shouldLog(\"debug\")) return;\n console.log(chalk.dim(` ⤷ ${msg}`));\n fileLoggerStorage.getStore()?.debug(stripAnsi(msg));\n },\n\n /**\n * Extract and format the full error cause chain. Node.js network errors\n * (e.g. `TypeError: fetch failed`) bury the real reason in nested `.cause`\n * properties — this helper surfaces them all.\n */\n formatErrorChain(err: unknown): string {\n const parts: string[] = [];\n let current: unknown = err;\n let depth = 0;\n\n while (current && depth < MAX_CAUSE_CHAIN_DEPTH) {\n if (current instanceof Error) {\n const prefix = depth === 0 ? \"Error\" : \"Cause\";\n parts.push(`${prefix}: ${current.message}`);\n if (current.cause) {\n current = current.cause;\n } else {\n break;\n }\n } else {\n parts.push(`${depth === 0 ? \"Error\" : \"Cause\"}: ${String(current)}`);\n break;\n }\n depth++;\n }\n\n return parts.join(\"\\n ⤷ \");\n },\n\n /**\n * Extract the raw error message string from an unknown thrown value.\n * Returns `err.message` for Error instances, `String(err)` for other\n * truthy values, and `\"\"` for null/undefined.\n */\n extractMessage(err: unknown): string {\n if (err instanceof Error) return err.message;\n if (err != null) return String(err);\n return \"\";\n },\n};\n\nObject.defineProperty(log, \"verbose\", {\n get(): boolean {\n return currentLevel === \"debug\";\n },\n set(value: boolean) {\n currentLevel = value ? \"debug\" : \"info\";\n },\n enumerable: true,\n configurable: true,\n});\n","/**\n * Per-issue file logger for detailed, structured log output.\n *\n * Writes timestamped, plain-text log entries to `.dispatch/logs/issue-{id}.log`.\n * Each log line is prefixed with an ISO 8601 timestamp. The logger provides\n * standard level methods (`info`, `debug`, `warn`, `error`) plus structured\n * methods for prompts, responses, phase transitions, and skill lifecycle events.\n *\n * An `AsyncLocalStorage<FileLogger>` instance is exported for scoping file\n * loggers to async contexts, allowing each issue processed in parallel to\n * maintain its own log file without threading parameters through call stacks.\n */\n\nimport { mkdirSync, writeFileSync, appendFileSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { AsyncLocalStorage } from \"node:async_hooks\";\n\nexport const fileLoggerStorage = new AsyncLocalStorage<FileLogger>();\n\nexport class FileLogger {\n readonly filePath: string;\n\n private static sanitizeIssueId(issueId: string | number): string {\n const raw = String(issueId);\n return raw.replace(/[^a-zA-Z0-9._-]/g, \"_\");\n }\n\n constructor(issueId: string | number, cwd: string) {\n const safeIssueId = FileLogger.sanitizeIssueId(issueId);\n this.filePath = join(cwd, \".dispatch\", \"logs\", `issue-${safeIssueId}.log`);\n mkdirSync(dirname(this.filePath), { recursive: true });\n writeFileSync(this.filePath, \"\", \"utf-8\");\n }\n\n private write(level: string, message: string): void {\n const timestamp = new Date().toISOString();\n const line = `[${timestamp}] [${level}] ${message}\\n`;\n appendFileSync(this.filePath, line, \"utf-8\");\n }\n\n info(message: string): void {\n this.write(\"INFO\", message);\n }\n\n debug(message: string): void {\n this.write(\"DEBUG\", message);\n }\n\n warn(message: string): void {\n this.write(\"WARN\", message);\n }\n\n error(message: string): void {\n this.write(\"ERROR\", message);\n }\n\n success(message: string): void {\n this.write(\"SUCCESS\", message);\n }\n\n task(message: string): void {\n this.write(\"TASK\", message);\n }\n\n dim(message: string): void {\n this.write(\"DIM\", message);\n }\n\n prompt(label: string, content: string): void {\n const separator = \"─\".repeat(40);\n this.write(\"PROMPT\", `${label}\\n${separator}\\n${content}\\n${separator}`);\n }\n\n response(label: string, content: string): void {\n const separator = \"─\".repeat(40);\n this.write(\"RESPONSE\", `${label}\\n${separator}\\n${content}\\n${separator}`);\n }\n\n phase(name: string): void {\n const banner = \"═\".repeat(40);\n this.write(\"PHASE\", `${banner}\\n${name}\\n${banner}`);\n }\n\n skillEvent(skill: string, event: string, detail?: string): void {\n const msg = detail ? `[${skill}] ${event}: ${detail}` : `[${skill}] ${event}`;\n this.write(\"SKILL\", msg);\n }\n\n close(): void {\n // no-op for sync writes; provides a cleanup hook for future use\n }\n}\n","/**\n * Runtime type guard utilities.\n *\n * Provides small, reusable type predicates that validate unknown values\n * at runtime, enabling safe property access without unsafe `as` casts.\n */\n\n/**\n * Check whether an unknown value is a non-null object that contains\n * the specified key.\n *\n * Narrows the value to `Record<K, unknown>` so the caller can safely\n * access `value[key]` without an `as` cast.\n *\n * @param value - The value to inspect (may be any type).\n * @param key - The property name to look for.\n * @returns `true` when `value` is an object with the given key.\n */\nexport function hasProperty<K extends string>(\n value: unknown,\n key: K,\n): value is Record<K, unknown> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n Object.prototype.hasOwnProperty.call(value, key)\n );\n}\n","/**\n * Generic promise timeout utility.\n *\n * Provides a reusable `withTimeout` wrapper that races a promise against\n * a `setTimeout` rejection. Used by the dispatch pipeline to bound\n * planning and execution durations. Timeout failures are distinguished\n * from other errors via the custom `TimeoutError` class.\n */\n\n/**\n * Thrown when a `withTimeout` call exceeds the specified duration.\n *\n * The `label` property (if set) identifies which operation timed out,\n * making log output and error messages more diagnosable.\n */\nexport class TimeoutError extends Error {\n /** Optional label identifying the operation that timed out. */\n readonly label?: string;\n\n constructor(ms: number, label?: string) {\n const suffix = label ? ` [${label}]` : \"\";\n super(`Timed out after ${ms}ms${suffix}`);\n this.name = \"TimeoutError\";\n this.label = label;\n }\n}\n\n/** Default planning timeout in minutes when not specified by the user. */\nexport const DEFAULT_PLAN_TIMEOUT_MIN = 30;\n\n/**\n * Race a promise against a timeout.\n *\n * If the promise resolves or rejects before `ms` milliseconds, its\n * result is returned (or its error re-thrown). If the timeout fires\n * first, a `TimeoutError` is thrown.\n *\n * The timer is always cleaned up to avoid leaking handles, regardless\n * of which branch wins the race.\n *\n * @param promise - The async operation to time-bound\n * @param ms - Timeout duration in milliseconds\n * @param label - Optional label included in the `TimeoutError` message\n * @returns The resolved value of `promise`\n * @throws {TimeoutError} If the timeout fires before the promise settles\n */\nexport function withTimeout<T>(\n promise: Promise<T>,\n ms: number,\n label?: string,\n): Promise<T> {\n const p = new Promise<T>((resolve, reject) => {\n let settled = false;\n\n const timer = setTimeout(() => {\n if (settled) return;\n settled = true;\n reject(new TimeoutError(ms, label));\n }, ms);\n\n promise.then(\n (value) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n resolve(value);\n },\n (err) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n reject(err);\n },\n );\n });\n\n // Attach a no-op handler so the rejection is never briefly \"unhandled\"\n // when the losing side of the race fires during fake-timer advancement.\n p.catch(() => {});\n\n return p;\n}\n","/**\n * GitHub Copilot provider — wraps the @github/copilot-sdk to conform\n * to the generic ProviderInstance interface.\n *\n * Requires the `copilot` CLI to be installed and available on PATH\n * (or specify the path via COPILOT_CLI_PATH).\n *\n * Authentication options:\n * - Logged-in Copilot CLI user (default)\n * - COPILOT_GITHUB_TOKEN / GH_TOKEN / GITHUB_TOKEN env vars\n */\n\nimport type { AssistantMessageEvent, CopilotSession } from \"@github/copilot-sdk\";\nimport type {\n ProviderInstance,\n ProviderBootOptions,\n ProviderPromptOptions,\n} from \"./interface.js\";\nimport { createProgressReporter } from \"./progress.js\";\nimport { log } from \"../helpers/logger.js\";\nimport { withTimeout } from \"../helpers/timeout.js\";\n\n/** Maximum time (ms) to wait for a copilot session to become idle after sending a prompt. */\nconst SESSION_READY_TIMEOUT_MS = 600_000;\n\n/**\n * Lazily load the Copilot SDK.\n *\n * Using a dynamic import defers resolution to runtime so that only code\n * paths that actually exercise the Copilot provider pay the cost of loading\n * the SDK, keeping startup fast for users of other providers.\n */\nasync function loadCopilotSdk(): Promise<typeof import(\"@github/copilot-sdk\")> {\n return import(\"@github/copilot-sdk\");\n}\n\n/**\n * List available Copilot models.\n *\n * Starts a temporary client, fetches the model list, then stops it.\n * Returns bare model IDs (e.g. \"claude-sonnet-4-5\").\n */\nexport async function listModels(opts?: ProviderBootOptions): Promise<string[]> {\n const { CopilotClient } = await loadCopilotSdk();\n const client = new CopilotClient({\n ...(opts?.url ? { cliUrl: opts.url } : {}),\n });\n try {\n await client.start();\n const models = await client.listModels();\n return models.map((m) => m.id).sort();\n } finally {\n // Intentional fire-and-forget teardown: errors stopping a temporary\n // list-models client are not actionable, but log them for debugging.\n await client.stop().catch((err) => {\n log.debug(`Failed to stop Copilot list-models client: ${log.formatErrorChain(err)}`);\n });\n }\n}\n\n/**\n * Boot a Copilot provider instance — starts or connects to a Copilot CLI server.\n */\nexport async function boot(opts?: ProviderBootOptions): Promise<ProviderInstance> {\n log.debug(opts?.url ? `Connecting to Copilot CLI at ${opts.url}` : \"Starting Copilot CLI...\");\n\n const { CopilotClient, approveAll } = await loadCopilotSdk();\n\n const client = new CopilotClient({\n ...(opts?.url ? { cliUrl: opts.url } : {}),\n ...(opts?.cwd ? { cwd: opts.cwd } : {}),\n });\n\n try {\n await client.start();\n log.debug(\"Copilot CLI started successfully\");\n } catch (err) {\n log.debug(`Failed to start Copilot CLI: ${log.formatErrorChain(err)}`);\n throw err;\n }\n\n // Model is detected lazily after the first session is created\n let model: string | undefined;\n let modelDetected = false;\n\n // Track live sessions for prompt routing and cleanup\n const sessions = new Map<string, CopilotSession>();\n\n return {\n name: \"copilot\",\n get model() {\n return model;\n },\n\n async createSession(): Promise<string> {\n log.debug(\"Creating Copilot session...\");\n try {\n const session = await client.createSession({\n ...(opts?.model ? { model: opts.model } : {}),\n ...(opts?.cwd ? { workingDirectory: opts.cwd } : {}),\n onPermissionRequest: approveAll,\n });\n sessions.set(session.sessionId, session);\n log.debug(`Session created: ${session.sessionId}`);\n\n // Detect actual default model from the first session (best-effort, once only)\n if (!modelDetected) {\n modelDetected = true;\n try {\n const result = await session.rpc.model.getCurrent();\n if (result.modelId) {\n model = result.modelId;\n log.debug(`Detected model: ${model}`);\n }\n } catch (err) {\n log.debug(`Failed to detect model from session: ${log.formatErrorChain(err)}`);\n }\n }\n\n return session.sessionId;\n } catch (err) {\n log.debug(`Session creation failed: ${log.formatErrorChain(err)}`);\n throw err;\n }\n },\n\n async prompt(\n sessionId: string,\n text: string,\n options?: ProviderPromptOptions,\n ): Promise<string | null> {\n const session = sessions.get(sessionId);\n if (!session) {\n throw new Error(`Copilot session ${sessionId} not found`);\n }\n\n log.debug(`Sending prompt to session ${sessionId} (${text.length} chars)...`);\n const reporter = createProgressReporter(options?.onProgress);\n let unsubIdle: (() => void) | undefined;\n let unsubErr: (() => void) | undefined;\n try {\n // ── 1. Fire-and-forget: start LLM processing ──────────────\n await session.send({ prompt: text });\n log.debug(\"Async prompt accepted, waiting for session to become idle...\");\n reporter.emit(\"Waiting for Copilot response\");\n\n // ── 2. Stream progress and wait for idle or error ─────────\n let unsubDelta: (() => void) | undefined;\n await withTimeout(\n new Promise<void>((resolve, reject) => {\n unsubIdle = session.on(\"session.idle\", () => {\n resolve();\n });\n\n unsubErr = session.on(\"session.error\", (event) => {\n reject(new Error(`Copilot session error: ${event.data.message}`));\n });\n\n unsubDelta = session.on(\"assistant.message_delta\", (event) => {\n if (event.data.deltaContent) {\n reporter.emit(event.data.deltaContent);\n }\n });\n }),\n SESSION_READY_TIMEOUT_MS,\n \"copilot session ready\",\n );\n\n unsubDelta?.();\n log.debug(\"Session went idle, fetching result...\");\n reporter.emit(\"Finalizing response\");\n\n // ── 3. Fetch the completed messages ───────────────────────\n const events = await session.getMessages();\n const last = [...events]\n .reverse()\n .find((e): e is AssistantMessageEvent => e.type === \"assistant.message\");\n\n const result = last?.data?.content ?? null;\n log.debug(`Prompt response received (${result?.length ?? 0} chars)`);\n return result;\n } catch (err) {\n log.debug(`Prompt failed: ${log.formatErrorChain(err)}`);\n throw err;\n } finally {\n unsubIdle?.();\n unsubErr?.();\n }\n },\n\n async send(sessionId: string, text: string): Promise<void> {\n const session = sessions.get(sessionId);\n if (!session) {\n throw new Error(`Copilot session ${sessionId} not found`);\n }\n\n log.debug(`Sending follow-up to session ${sessionId} (${text.length} chars)...`);\n try {\n await session.send({ prompt: text });\n log.debug(\"Follow-up message sent\");\n } catch (err) {\n log.debug(`Follow-up send failed: ${log.formatErrorChain(err)}`);\n throw err;\n }\n },\n\n async cleanup(): Promise<void> {\n log.debug(\"Cleaning up Copilot provider...\");\n // Destroy all active sessions before stopping the server\n const destroyOps = [...sessions.values()].map((s) =>\n s.destroy().catch((err) => {\n log.debug(`Failed to destroy Copilot session: ${log.formatErrorChain(err)}`);\n })\n );\n await Promise.all(destroyOps);\n sessions.clear();\n\n await client.stop().catch((err) => {\n log.debug(`Failed to stop Copilot client: ${log.formatErrorChain(err)}`);\n });\n },\n };\n}\n","/**\n * Claude provider — wraps the @anthropic-ai/claude-agent-sdk V2 preview\n * to conform to the generic ProviderInstance interface.\n *\n * Uses the V2 session-based API: `unstable_v2_createSession` for session\n * creation, `session.send()`/`session.stream()` for prompting, and manual\n * `session.close()` for cleanup (the project targets ES2022 which does not\n * include the Disposable lib required for `await using`).\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport { readFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { unstable_v2_createSession, type SDKSession } from \"@anthropic-ai/claude-agent-sdk\";\nimport type {\n ProviderInstance,\n ProviderBootOptions,\n ProviderPromptOptions,\n} from \"./interface.js\";\nimport { createProgressReporter } from \"./progress.js\";\nimport { log } from \"../helpers/logger.js\";\nimport { withTimeout } from \"../helpers/timeout.js\";\n\n/** Maximum time (ms) to wait for a Claude session stream to complete after sending a prompt. */\nconst SESSION_READY_TIMEOUT_MS = 600_000;\n\n/**\n * Resolve an Anthropic API key from env var or Claude CLI OAuth credentials.\n */\nasync function resolveAnthropicKey(): Promise<string | null> {\n if (process.env.ANTHROPIC_API_KEY) return process.env.ANTHROPIC_API_KEY;\n try {\n const credPath = join(homedir(), \".claude\", \".credentials.json\");\n const raw = JSON.parse(await readFile(credPath, \"utf-8\"));\n return raw?.claudeAiOauth?.accessToken ?? null;\n } catch (err) {\n log.debug(`resolveAnthropicKey: ${err instanceof Error ? err.message : String(err)}`);\n return null;\n }\n}\n\n/**\n * List available Claude models.\n *\n * Fetches from the Anthropic /v1/models API using either ANTHROPIC_API_KEY\n * or the Claude CLI's OAuth access token. Falls back to empty list on failure.\n */\nexport async function listModels(_opts?: ProviderBootOptions): Promise<string[]> {\n try {\n const apiKey = await resolveAnthropicKey();\n if (!apiKey) return [];\n\n const resp = await fetch(\"https://api.anthropic.com/v1/models?limit=100\", {\n headers: {\n \"x-api-key\": apiKey,\n \"anthropic-version\": \"2023-06-01\",\n },\n signal: AbortSignal.timeout(8_000),\n });\n if (!resp.ok) return [];\n\n const data = (await resp.json()) as { data: Array<{ id: string }> };\n return data.data.map((m) => m.id).sort();\n } catch (err) {\n log.debug(`Failed to list models: ${log.formatErrorChain(err)}`);\n return [];\n }\n}\n\n/**\n * Boot a Claude provider instance using the V2 preview API.\n */\nexport async function boot(opts?: ProviderBootOptions): Promise<ProviderInstance> {\n const model = opts?.model ?? \"claude-sonnet-4\";\n const cwd = opts?.cwd;\n log.debug(`Booting Claude provider with model ${model}`);\n\n const sessions = new Map<string, SDKSession>();\n\n return {\n name: \"claude\",\n model,\n\n async createSession(): Promise<string> {\n log.debug(\"Creating Claude session...\");\n try {\n const sessionOpts = {\n model,\n permissionMode: \"bypassPermissions\" as const,\n allowDangerouslySkipPermissions: true,\n ...(cwd ? { cwd } : {}),\n };\n const session = unstable_v2_createSession(sessionOpts);\n const sessionId = randomUUID();\n sessions.set(sessionId, session);\n log.debug(`Session created: ${sessionId}`);\n return sessionId;\n } catch (err) {\n log.debug(`Session creation failed: ${log.formatErrorChain(err)}`);\n throw err;\n }\n },\n\n async prompt(\n sessionId: string,\n text: string,\n options?: ProviderPromptOptions,\n ): Promise<string | null> {\n const session = sessions.get(sessionId);\n if (!session) {\n throw new Error(`Claude session ${sessionId} not found`);\n }\n\n log.debug(`Sending prompt to session ${sessionId} (${text.length} chars)...`);\n const reporter = createProgressReporter(options?.onProgress);\n try {\n await session.send(text);\n\n const parts: string[] = [];\n let receivedAssistant = false;\n\n await withTimeout(\n (async () => {\n for await (const msg of session.stream()) {\n if (msg.type === \"assistant\") {\n receivedAssistant = true;\n const msgText = msg.message.content\n .filter((block) => block.type === \"text\")\n .map((block) => (block as { text: string }).text)\n .join(\"\");\n if (msgText) {\n reporter.emit(msgText);\n parts.push(msgText);\n }\n }\n }\n })(),\n SESSION_READY_TIMEOUT_MS,\n \"claude session stream\",\n );\n\n if (!receivedAssistant) {\n throw new Error(\"Claude stream ended before receiving an assistant message\");\n }\n\n const result = parts.join(\"\") || null;\n log.debug(`Prompt response received (${result?.length ?? 0} chars)`);\n return result;\n } catch (err) {\n log.debug(`Prompt failed: ${log.formatErrorChain(err)}`);\n throw err;\n }\n },\n\n async send(sessionId: string, text: string): Promise<void> {\n const session = sessions.get(sessionId);\n if (!session) {\n throw new Error(`Claude session ${sessionId} not found`);\n }\n\n log.debug(`Sending follow-up to session ${sessionId} (${text.length} chars)...`);\n try {\n await session.send(text);\n } catch (err) {\n log.debug(`Follow-up send failed: ${log.formatErrorChain(err)}`);\n throw err;\n }\n },\n\n async cleanup(): Promise<void> {\n log.debug(\"Cleaning up Claude provider...\");\n for (const session of sessions.values()) {\n try {\n // session.close() may return a promise — await it so cleanup errors\n // are surfaced in debug logs rather than becoming unhandled rejections.\n await Promise.resolve(session.close());\n } catch (err) {\n log.debug(`Failed to close Claude session: ${log.formatErrorChain(err)}`);\n }\n }\n sessions.clear();\n },\n };\n}\n","/**\n * Codex provider — wraps the @openai/codex-sdk to conform to the\n * generic ProviderInstance interface.\n *\n * Uses the Codex class for agent lifecycle and Thread for per-session\n * conversation management. Each session starts a new Thread with\n * \"never\" approval policy so file edits and shell commands are\n * auto-approved.\n *\n * Supports both blocking (`thread.run()`) and streaming\n * (`thread.runStreamed()`) execution modes — streaming is used when\n * an `onProgress` callback is provided, falling back to blocking\n * otherwise.\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport { readFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type {\n ProviderInstance,\n ProviderBootOptions,\n ProviderPromptOptions,\n} from \"./interface.js\";\nimport { createProgressReporter } from \"./progress.js\";\nimport { log } from \"../helpers/logger.js\";\nimport { withTimeout } from \"../helpers/timeout.js\";\n\n/** Maximum time (ms) to wait for a Codex thread.run() to complete. */\nconst SESSION_READY_TIMEOUT_MS = 600_000;\n\n/**\n * Lazily load the @openai/codex-sdk.\n *\n * Using a dynamic import defers resolution to runtime so that only code\n * paths that actually exercise the Codex provider pay the cost of loading\n * the SDK, keeping startup fast for users of other providers.\n */\nasync function loadCodexSdk(): Promise<typeof import(\"@openai/codex-sdk\")> {\n return import(\"@openai/codex-sdk\");\n}\n\n/**\n * Resolve an API bearer token for OpenAI.\n *\n * Checks OPENAI_API_KEY env var first, then reads the Codex CLI's\n * OAuth access_token from ~/.codex/auth.json (set by `codex login`).\n */\nasync function resolveOpenAIToken(): Promise<string | null> {\n if (process.env.OPENAI_API_KEY) return process.env.OPENAI_API_KEY;\n try {\n const authPath = join(homedir(), \".codex\", \"auth.json\");\n const raw = JSON.parse(await readFile(authPath, \"utf-8\"));\n return raw?.tokens?.access_token ?? null;\n } catch (err) {\n log.debug(`resolveOpenAIToken: ${err instanceof Error ? err.message : String(err)}`);\n return null;\n }\n}\n\n/**\n * List available Codex models.\n *\n * Tries the OpenAI /v1/models endpoint first (works with API keys).\n * Falls back to a known model list when using ChatGPT OAuth (which\n * lacks the api.model.read scope needed for the models endpoint).\n */\nexport async function listModels(_opts?: ProviderBootOptions): Promise<string[]> {\n try {\n const token = await resolveOpenAIToken();\n if (!token) return [];\n\n const resp = await fetch(\"https://api.openai.com/v1/models\", {\n headers: { Authorization: `Bearer ${token}` },\n signal: AbortSignal.timeout(8_000),\n });\n\n if (resp.ok) {\n const data = (await resp.json()) as { data: Array<{ id: string }> };\n return data.data.map((m) => m.id).sort();\n }\n } catch {\n // Fall through to known models\n }\n\n // ChatGPT OAuth tokens lack api.model.read scope — return known models\n return [\n \"codex-mini-latest\",\n \"gpt-4.1\",\n \"gpt-4.1-mini\",\n \"gpt-4.1-nano\",\n \"gpt-5.2\",\n \"gpt-5.3-codex\",\n \"gpt-5.4\",\n \"gpt-5.4-mini\",\n \"o3\",\n \"o3-mini\",\n \"o3-pro\",\n \"o4-mini\",\n ];\n}\n\n/**\n * Boot a Codex provider instance.\n */\nexport async function boot(opts?: ProviderBootOptions): Promise<ProviderInstance> {\n const model = opts?.model ?? \"o4-mini\";\n log.debug(`Booting Codex provider with model ${model}`);\n\n const { Codex, Thread } = await loadCodexSdk();\n\n const codex = new Codex();\n\n type ThreadInstance = InstanceType<typeof Thread>;\n\n const sessions = new Map<string, ThreadInstance>();\n\n return {\n name: \"codex\",\n model,\n\n async createSession(): Promise<string> {\n log.debug(\"Creating Codex session...\");\n try {\n const sessionId = randomUUID();\n const thread = codex.startThread({\n model,\n approvalPolicy: \"never\",\n sandboxMode: \"workspace-write\",\n ...(opts?.cwd ? { workingDirectory: opts.cwd } : {}),\n });\n sessions.set(sessionId, thread);\n log.debug(`Session created: ${sessionId}`);\n return sessionId;\n } catch (err) {\n log.debug(`Session creation failed: ${log.formatErrorChain(err)}`);\n throw err;\n }\n },\n\n async prompt(\n sessionId: string,\n text: string,\n options?: ProviderPromptOptions,\n ): Promise<string | null> {\n const thread = sessions.get(sessionId);\n if (!thread) {\n throw new Error(`Codex session ${sessionId} not found`);\n }\n\n log.debug(`Sending prompt to session ${sessionId} (${text.length} chars)...`);\n const reporter = createProgressReporter(options?.onProgress);\n try {\n reporter.emit(\"Waiting for Codex response\");\n\n if (options?.onProgress) {\n // ── Streaming mode: emit progress as events arrive ──────\n const { events } = await withTimeout(\n thread.runStreamed(text),\n SESSION_READY_TIMEOUT_MS,\n \"codex thread runStreamed\",\n );\n\n let lastAgentMessage: string | null = null;\n\n for await (const event of events) {\n if (event.type === \"item.updated\" || event.type === \"item.completed\") {\n if (event.item.type === \"agent_message\") {\n lastAgentMessage = event.item.text;\n reporter.emit(event.item.text);\n }\n }\n\n if (event.type === \"turn.failed\") {\n throw new Error(`Codex turn failed: ${event.error.message}`);\n }\n\n if (event.type === \"item.completed\" && event.item.type === \"error\") {\n throw new Error(`Codex error: ${event.item.message}`);\n }\n }\n\n reporter.emit(\"Finalizing response\");\n log.debug(`Prompt response received (${lastAgentMessage?.length ?? 0} chars, streaming)`);\n return lastAgentMessage;\n }\n\n // ── Blocking mode: wait for completed turn ─────────────\n const turn = await withTimeout(\n thread.run(text),\n SESSION_READY_TIMEOUT_MS,\n \"codex thread run\",\n );\n\n // Check for error items\n for (const item of turn.items) {\n if (item.type === \"error\") {\n throw new Error(`Codex error: ${item.message}`);\n }\n }\n\n reporter.emit(\"Finalizing response\");\n const result = turn.finalResponse || null;\n log.debug(`Prompt response received (${result?.length ?? 0} chars)`);\n return result;\n } catch (err) {\n log.debug(`Prompt failed: ${log.formatErrorChain(err)}`);\n throw err;\n }\n },\n\n async send(sessionId: string, text: string): Promise<void> {\n const thread = sessions.get(sessionId);\n if (!thread) {\n throw new Error(`Codex session ${sessionId} not found`);\n }\n\n // Threads support multiple turns — send a follow-up as a new turn.\n // Fire-and-forget: start the turn but don't wait for completion.\n log.debug(`Sending follow-up to session ${sessionId} (${text.length} chars)...`);\n thread.run(text).catch((err) => {\n log.debug(`Follow-up turn failed: ${log.formatErrorChain(err)}`);\n });\n },\n\n async cleanup(): Promise<void> {\n log.debug(\"Cleaning up Codex provider...\");\n sessions.clear();\n },\n };\n}\n","/**\n * Provider metadata registry — centralized source of truth for each provider's\n * characteristics, authentication requirements, and routing metadata.\n *\n * Used by the smart router to select providers per agent role, and by the\n * config wizard to walk users through auth setup.\n */\n\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport type { ProviderName } from \"./interface.js\";\n\nconst exec = promisify(execFile);\n\n/** Timeout (ms) for auth probe commands. */\nconst AUTH_PROBE_TIMEOUT_MS = 10_000;\n\n/** Authentication status for a provider. */\nexport type AuthStatus =\n | { status: \"authenticated\" }\n | { status: \"not-configured\"; hint: string }\n | { status: \"expired\"; hint: string };\n\n/** Provider tier — determines cost and access characteristics. */\nexport type ProviderTier = \"free\" | \"api-key\";\n\n/** Static metadata for a provider, used for routing and auth. */\nexport interface ProviderMeta {\n name: ProviderName;\n displayName: string;\n tier: ProviderTier;\n /** Default model for strong/capable tasks (executor, spec). */\n defaultStrongModel: string;\n /** Default model for fast/cheap tasks (planner, commit). */\n defaultFastModel: string;\n /** Relative cost scores (1 = cheapest, 10 = most expensive). */\n costScore: { strong: number; fast: number };\n /** Check whether auth credentials are available. */\n checkAuth: () => Promise<AuthStatus>;\n}\n\n// ── Auth check implementations ──────────────────────────────────\n\nasync function checkCopilotAuth(): Promise<AuthStatus> {\n // Check environment variables first\n if (\n process.env.COPILOT_GITHUB_TOKEN ||\n process.env.GH_TOKEN ||\n process.env.GITHUB_TOKEN\n ) {\n return { status: \"authenticated\" };\n }\n // Fall back to copilot CLI auth status, then gh CLI\n try {\n await exec(\"copilot\", [\"auth\", \"status\"], { timeout: AUTH_PROBE_TIMEOUT_MS });\n return { status: \"authenticated\" };\n } catch {\n // Try gh CLI as a secondary fallback\n try {\n await exec(\"gh\", [\"auth\", \"status\"], { timeout: AUTH_PROBE_TIMEOUT_MS });\n return { status: \"authenticated\" };\n } catch {\n return {\n status: \"not-configured\",\n hint: \"Run 'copilot login' or set GITHUB_TOKEN\",\n };\n }\n }\n}\n\nasync function checkClaudeAuth(): Promise<AuthStatus> {\n if (process.env.ANTHROPIC_API_KEY) {\n return { status: \"authenticated\" };\n }\n // Try claude CLI auth check\n try {\n await exec(\"claude\", [\"auth\", \"status\"], { timeout: AUTH_PROBE_TIMEOUT_MS });\n return { status: \"authenticated\" };\n } catch {\n return {\n status: \"not-configured\",\n hint: \"Run 'claude auth login' or set ANTHROPIC_API_KEY\",\n };\n }\n}\n\nasync function checkCodexAuth(): Promise<AuthStatus> {\n if (process.env.OPENAI_API_KEY) {\n return { status: \"authenticated\" };\n }\n // Try codex CLI auth check\n try {\n await exec(\"codex\", [\"login\", \"status\"], { timeout: AUTH_PROBE_TIMEOUT_MS });\n return { status: \"authenticated\" };\n } catch {\n return {\n status: \"not-configured\",\n hint: \"Run 'codex login --device-auth' or set OPENAI_API_KEY\",\n };\n }\n}\n\nasync function checkOpencodeAuth(): Promise<AuthStatus> {\n // Check if the binary exists\n try {\n await exec(\"opencode\", [\"--version\"], { timeout: AUTH_PROBE_TIMEOUT_MS });\n } catch {\n return {\n status: \"not-configured\",\n hint: \"Install OpenCode (https://opencode.ai)\",\n };\n }\n // Try opencode CLI auth check\n try {\n await exec(\"opencode\", [\"auth\", \"list\"], { timeout: AUTH_PROBE_TIMEOUT_MS });\n return { status: \"authenticated\" };\n } catch {\n return {\n status: \"not-configured\",\n hint: \"OpenCode is installed but no credentials configured. Run 'opencode auth login' or set provider API keys\",\n };\n }\n}\n\n// ── Registry ────────────────────────────────────────────────────\n\nexport const PROVIDER_REGISTRY: Record<ProviderName, ProviderMeta> = {\n copilot: {\n name: \"copilot\",\n displayName: \"GitHub Copilot\",\n tier: \"free\",\n defaultStrongModel: \"claude-sonnet-4-5\",\n defaultFastModel: \"claude-haiku-4\",\n costScore: { strong: 1, fast: 1 },\n checkAuth: checkCopilotAuth,\n },\n claude: {\n name: \"claude\",\n displayName: \"Claude Code\",\n tier: \"api-key\",\n defaultStrongModel: \"claude-sonnet-4\",\n defaultFastModel: \"claude-haiku-3-5\",\n costScore: { strong: 5, fast: 2 },\n checkAuth: checkClaudeAuth,\n },\n codex: {\n name: \"codex\",\n displayName: \"OpenAI Codex\",\n tier: \"api-key\",\n defaultStrongModel: \"o4-mini\",\n defaultFastModel: \"codex-mini-latest\",\n costScore: { strong: 4, fast: 1 },\n checkAuth: checkCodexAuth,\n },\n opencode: {\n name: \"opencode\",\n displayName: \"OpenCode\",\n tier: \"api-key\",\n defaultStrongModel: \"anthropic/claude-sonnet-4\",\n defaultFastModel: \"anthropic/claude-haiku-3-5\",\n costScore: { strong: 5, fast: 3 },\n checkAuth: checkOpencodeAuth,\n },\n};\n\n/**\n * Get metadata for all providers, with current auth status.\n */\nexport async function getProviderStatuses(): Promise<\n Array<ProviderMeta & { authStatus: AuthStatus }>\n> {\n const entries = Object.values(PROVIDER_REGISTRY);\n const statuses = await Promise.all(entries.map((e) => e.checkAuth()));\n return entries.map((entry, i) => ({ ...entry, authStatus: statuses[i] }));\n}\n","/**\n * Provider authentication detection — checks whether each provider has\n * valid credentials configured.\n *\n * Replaces the old binary-detection approach since providers are now\n * bundled as dependencies (no external CLI binary required).\n */\n\nimport type { ProviderName } from \"./interface.js\";\nimport { PROVIDER_REGISTRY, type AuthStatus } from \"./registry.js\";\n\n/**\n * Check whether a provider has valid authentication configured.\n *\n * Returns `true` if the provider is ready to use, `false` otherwise.\n * Never rejects.\n */\nexport async function checkProviderAuthenticated(\n name: ProviderName,\n): Promise<boolean> {\n const meta = PROVIDER_REGISTRY[name];\n const status = await meta.checkAuth();\n return status.status === \"authenticated\";\n}\n\n/**\n * Get the detailed auth status for a provider.\n */\nexport async function getProviderAuthStatus(\n name: ProviderName,\n): Promise<AuthStatus> {\n const meta = PROVIDER_REGISTRY[name];\n return meta.checkAuth();\n}\n\n/**\n * Get all authenticated provider names.\n */\nexport async function getAuthenticatedProviders(\n providers: readonly ProviderName[],\n): Promise<ProviderName[]> {\n const results = await Promise.all(\n providers.map(async (name) => ({\n name,\n authenticated: await checkProviderAuthenticated(name),\n })),\n );\n return results.filter((r) => r.authenticated).map((r) => r.name);\n}\n","/**\n * Provider registry — maps provider names to their boot functions.\n *\n * To add a new agent backend:\n * 1. Create `src/providers/<name>.ts` exporting an async `boot()` function\n * 2. Import and register it in the `PROVIDERS` map below\n * 3. Add the name to the `ProviderName` union in `src/providers/interface.ts`\n */\n\nimport type { ProviderName, ProviderInstance, ProviderBootOptions } from \"./interface.js\";\nimport { PROVIDER_NAMES } from \"./interface.js\";\nimport { boot as bootOpencode, listModels as listOpencodeModels } from \"./opencode.js\";\nimport { boot as bootCopilot, listModels as listCopilotModels } from \"./copilot.js\";\nimport { boot as bootClaude, listModels as listClaudeModels } from \"./claude.js\";\nimport { boot as bootCodex, listModels as listCodexModels } from \"./codex.js\";\n\ntype BootFn = (opts?: ProviderBootOptions) => Promise<ProviderInstance>;\ntype ListModelsFn = (opts?: ProviderBootOptions) => Promise<string[]>;\n\nconst PROVIDERS: Record<ProviderName, BootFn> = {\n opencode: bootOpencode,\n copilot: bootCopilot,\n claude: bootClaude,\n codex: bootCodex,\n};\n\nconst LIST_MODELS: Record<ProviderName, ListModelsFn> = {\n opencode: listOpencodeModels,\n copilot: listCopilotModels,\n claude: listClaudeModels,\n codex: listCodexModels,\n};\n\n/**\n * All registered provider names — re-exported from the canonical definition in interface.ts.\n */\nexport { PROVIDER_NAMES } from \"./interface.js\";\n\n/**\n * Boot a provider by name.\n *\n * @throws if the provider name is not registered.\n */\nexport async function bootProvider(\n name: ProviderName,\n opts?: ProviderBootOptions\n): Promise<ProviderInstance> {\n const bootFn = PROVIDERS[name];\n if (!bootFn) {\n throw new Error(\n `Unknown provider \"${name}\". Available: ${PROVIDER_NAMES.join(\", \")}`\n );\n }\n return bootFn(opts);\n}\n\n/**\n * List available models for a provider by name.\n *\n * Starts a temporary provider instance (or connects to an existing server),\n * fetches the model list, and tears down. Returns model IDs as strings.\n * Throws if the provider is unavailable (caller should handle gracefully).\n *\n * @throws if the provider name is not registered or the provider is unavailable.\n */\nexport async function listProviderModels(\n name: ProviderName,\n opts?: ProviderBootOptions\n): Promise<string[]> {\n const fn = LIST_MODELS[name];\n if (!fn) {\n throw new Error(\n `Unknown provider \"${name}\". Available: ${PROVIDER_NAMES.join(\", \")}`\n );\n }\n return fn(opts);\n}\n\nexport type { ProviderName, ProviderInstance, ProviderBootOptions } from \"./interface.js\";\nexport { checkProviderAuthenticated, getProviderAuthStatus, getAuthenticatedProviders } from \"./detect.js\";\n","/**\n * Datasource registry — maps datasource names to their implementations\n * and provides auto-detection of the datasource from the git remote URL.\n *\n * To add a new datasource:\n * 1. Create `src/datasources/<name>.ts` exporting a `datasource` object\n * 2. Import and register it in the `DATASOURCES` map below\n * 3. Add the name to the `DatasourceName` type in `src/datasources/interface.ts`\n * 4. Add a URL pattern to `detectDatasource` if auto-detection is possible\n */\n\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport type { Datasource, DatasourceName } from \"./interface.js\";\nimport { DATASOURCE_NAMES } from \"./interface.js\";\nimport { datasource as githubDatasource } from \"./github.js\";\nimport { datasource as azdevopsDatasource } from \"./azdevops.js\";\nimport { datasource as mdDatasource } from \"./md.js\";\nexport type { Datasource, DatasourceName, IssueDetails, IssueFetchOptions, DispatchLifecycleOptions } from \"./interface.js\";\n\nconst exec = promisify(execFile);\n\nconst DATASOURCES: Partial<Record<DatasourceName, Datasource>> = {\n github: githubDatasource,\n azdevops: azdevopsDatasource,\n md: mdDatasource,\n};\n\n/**\n * All registered datasource names — re-exported from the canonical definition in interface.ts.\n */\nexport { DATASOURCE_NAMES } from \"./interface.js\";\n\n/**\n * Get a datasource by name.\n *\n * @throws if the datasource name is not registered.\n */\nexport function getDatasource(name: DatasourceName): Datasource {\n const datasource = DATASOURCES[name];\n if (!datasource) {\n throw new Error(\n `Unknown datasource \"${name}\". Available: ${DATASOURCE_NAMES.join(\", \")}`\n );\n }\n return datasource;\n}\n\n/**\n * Get the git remote URL for the `origin` remote.\n *\n * @param cwd - Working directory to run the git command in\n * @returns The remote URL string, or `null` if unavailable\n */\nexport async function getGitRemoteUrl(cwd: string): Promise<string | null> {\n try {\n const { stdout } = await exec(\"git\", [\"remote\", \"get-url\", \"origin\"], {\n cwd,\n shell: process.platform === \"win32\",\n });\n return stdout.trim() || null;\n } catch {\n return null;\n }\n}\n\n/**\n * URL patterns used to detect the datasource from a git remote.\n *\n * Each entry maps a regex (tested against the remote URL) to the\n * corresponding `DatasourceName`. Patterns are tested in order;\n * the first match wins.\n */\nconst SOURCE_PATTERNS: { pattern: RegExp; source: DatasourceName }[] = [\n { pattern: /github\\.com/i, source: \"github\" },\n { pattern: /dev\\.azure\\.com/i, source: \"azdevops\" },\n { pattern: /visualstudio\\.com/i, source: \"azdevops\" },\n];\n\n/**\n * Auto-detect the datasource by inspecting the `origin` remote URL.\n *\n * Returns the detected `DatasourceName`, or `null` if the remote URL\n * does not match any known pattern.\n */\n/**\n * Derive a short username from git config.\n * - Multi-word name: first 2 chars of first name + first 6 of last name\n * - Single word or no name: first 8 chars of email local part\n * - Falls back to the provided `fallback` value\n */\nexport async function deriveShortUsername(cwd: string, fallback: string): Promise<string> {\n try {\n const { stdout: nameOut } = await exec(\"git\", [\"config\", \"user.name\"], { cwd, shell: process.platform === \"win32\" });\n const raw = nameOut.trim();\n if (raw) {\n const parts = raw.toLowerCase().replace(/[^a-z\\s]/g, \"\").trim().split(/\\s+/);\n if (parts.length >= 2) {\n return (parts[0].slice(0, 2) + parts[parts.length - 1].slice(0, 6)) || fallback;\n }\n }\n } catch {\n // fall through to email\n }\n\n try {\n const { stdout: emailOut } = await exec(\"git\", [\"config\", \"user.email\"], { cwd, shell: process.platform === \"win32\" });\n const raw = emailOut.trim();\n if (raw) {\n const localPart = raw.split(\"@\")[0].toLowerCase().replace(/[^a-z0-9]/g, \"\");\n if (localPart) {\n return localPart.slice(0, 8);\n }\n }\n } catch {\n // fall through\n }\n\n return fallback;\n}\n\nexport async function detectDatasource(\n cwd: string\n): Promise<DatasourceName | null> {\n const url = await getGitRemoteUrl(cwd);\n if (!url) return null;\n\n for (const { pattern, source } of SOURCE_PATTERNS) {\n if (pattern.test(url)) {\n return source;\n }\n }\n\n return null;\n}\n\n/**\n * Parse an Azure DevOps git remote URL and extract the organization URL and project name.\n *\n * Supports all three Azure DevOps remote URL formats:\n * - **HTTPS:** `https://dev.azure.com/{org}/{project}/_git/{repo}`\n * - **SSH:** `git@ssh.dev.azure.com:v3/{org}/{project}/{repo}`\n * - **Legacy HTTPS:** `https://{org}.visualstudio.com/{project}/_git/{repo}`\n *\n * The org URL is always normalized to `https://dev.azure.com/{org}`.\n *\n * @param url - The git remote URL to parse\n * @returns The parsed org URL and project name, or `null` if the URL is not a recognized Azure DevOps format\n */\nexport function parseAzDevOpsRemoteUrl(\n url: string\n): { orgUrl: string; project: string } | null {\n // HTTPS: https://[user@]dev.azure.com/{org}/{project}/_git/{repo}\n const httpsMatch = url.match(\n /^https?:\\/\\/(?:[^@]+@)?dev\\.azure\\.com\\/([^/]+)\\/([^/]+)\\/_git\\//i\n );\n if (httpsMatch) {\n return {\n orgUrl: `https://dev.azure.com/${decodeURIComponent(httpsMatch[1])}`,\n project: decodeURIComponent(httpsMatch[2]),\n };\n }\n\n // SSH: git@ssh.dev.azure.com:v3/{org}/{project}/{repo}\n const sshMatch = url.match(\n /^git@ssh\\.dev\\.azure\\.com:v3\\/([^/]+)\\/([^/]+)\\//i\n );\n if (sshMatch) {\n return {\n orgUrl: `https://dev.azure.com/${decodeURIComponent(sshMatch[1])}`,\n project: decodeURIComponent(sshMatch[2]),\n };\n }\n\n // Legacy: https://{org}.visualstudio.com/[DefaultCollection/]{project}/_git/{repo}\n const legacyMatch = url.match(\n /^https?:\\/\\/([^.]+)\\.visualstudio\\.com\\/(?:DefaultCollection\\/)?([^/]+)\\/_git\\//i\n );\n if (legacyMatch) {\n return {\n orgUrl: `https://dev.azure.com/${decodeURIComponent(legacyMatch[1])}`,\n project: decodeURIComponent(legacyMatch[2]),\n };\n }\n\n return null;\n}\n\n/**\n * Parse a GitHub git remote URL and extract the owner and repository name.\n *\n * Supports both GitHub remote URL formats:\n * - **HTTPS:** `https://github.com/{owner}/{repo}[.git]`\n * - **SSH:** `git@github.com:{owner}/{repo}[.git]`\n *\n * @param url - The git remote URL to parse\n * @returns The parsed owner and repo, or `null` if the URL is not a recognized GitHub format\n */\nexport function parseGitHubRemoteUrl(\n url: string\n): { owner: string; repo: string } | null {\n // HTTPS: https://[user@]github.com/{owner}/{repo}[.git]\n const httpsMatch = url.match(\n /^https?:\\/\\/(?:[^@]+@)?github\\.com\\/([^/]+)\\/([^/]+?)\\/?$/i\n );\n if (httpsMatch) {\n const owner = decodeURIComponent(httpsMatch[1]);\n const rawRepo = decodeURIComponent(httpsMatch[2]);\n const repo = rawRepo.endsWith(\".git\") ? rawRepo.slice(0, -4) : rawRepo;\n return { owner, repo };\n }\n\n // SSH (scp-style): git@github.com:{owner}/{repo}[.git]\n const sshMatch = url.match(\n /^git@github\\.com:([^/]+)\\/([^/]+?)\\/?$/i\n );\n if (sshMatch) {\n const owner = decodeURIComponent(sshMatch[1]);\n const rawRepo = decodeURIComponent(sshMatch[2]);\n const repo = rawRepo.endsWith(\".git\") ? rawRepo.slice(0, -4) : rawRepo;\n return { owner, repo };\n }\n\n // SSH (url-style): ssh://git@github.com/{owner}/{repo}[.git]\n const sshUrlMatch = url.match(\n /^ssh:\\/\\/git@github\\.com\\/([^/]+)\\/([^/]+?)\\/?$/i\n );\n if (sshUrlMatch) {\n const owner = decodeURIComponent(sshUrlMatch[1]);\n const rawRepo = decodeURIComponent(sshUrlMatch[2]);\n const repo = rawRepo.endsWith(\".git\") ? rawRepo.slice(0, -4) : rawRepo;\n return { owner, repo };\n }\n\n return null;\n}\n","/**\n * Datasource interface — unifies how issues and specs are read and written\n * regardless of backend (GitHub, Azure DevOps, local markdown files).\n *\n * Each datasource handles authentication and data access for its platform.\n * The plan generator and orchestrator interact exclusively through this\n * contract.\n *\n * To add a new datasource:\n * 1. Create `src/datasources/<name>.ts`\n * 2. Export an implementation that satisfies `Datasource`\n * 3. Register it in `src/datasources/index.ts`\n * 4. Add the name to the `DatasourceName` union below\n */\n\n/**\n * Structured representation of a work item / issue from any tracker.\n */\nexport interface IssueDetails {\n /** Issue / work-item number or ID */\n number: string;\n /** Title of the issue */\n title: string;\n /** Full description / body (may contain HTML or markdown) */\n body: string;\n /** Labels, tags, or categories */\n labels: string[];\n /** Current state (open, closed, active, resolved, etc.) */\n state: string;\n /** URL to the issue in the tracker's web UI */\n url: string;\n /** Discussion comments */\n comments: string[];\n /** Acceptance criteria (if the tracker supports it) */\n acceptanceCriteria: string;\n /** Iteration path / sprint (Azure DevOps) */\n iterationPath?: string;\n /** Area path / team (Azure DevOps) */\n areaPath?: string;\n /** Assignee display name */\n assignee?: string;\n /** Priority (1 = Critical … 4 = Low) */\n priority?: number;\n /** Story points / effort / size */\n storyPoints?: number;\n /** Work item type (e.g. \"User Story\", \"Bug\") */\n workItemType?: string;\n}\n\n/**\n * Options passed when fetching an issue.\n */\nexport interface IssueFetchOptions {\n /** Working directory (for CLI repo context) */\n cwd?: string;\n /** Organization URL (e.g. Azure DevOps org) */\n org?: string;\n /** Project name (e.g. Azure DevOps project) */\n project?: string;\n /** Work item type (e.g. \"User Story\", \"Product Backlog Item\") */\n workItemType?: string;\n /** Iteration path filter (e.g. \"MyProject\\\\Sprint 1\" or \"@CurrentIteration\") */\n iteration?: string;\n /** Area path filter (e.g. \"MyProject\\\\Team A\") */\n area?: string;\n /** Glob pattern(s) for filtering items in list() */\n pattern?: string | string[];\n}\n\n/**\n * Options for dispatch lifecycle operations (branching, pushing, PRs).\n */\nexport interface DispatchLifecycleOptions {\n /** Working directory (git repo root) */\n cwd: string;\n /** Optional short username prefix from config, overrides git-derived username */\n username?: string;\n}\n\nexport const DATASOURCE_NAMES = [\"github\", \"azdevops\", \"md\"] as const;\n\n/** Valid datasource backend names. */\nexport type DatasourceName = typeof DATASOURCE_NAMES[number];\n\n/**\n * Interface that all datasource implementations must satisfy.\n *\n * Each datasource is responsible for communicating with a single backend\n * and returning normalized `IssueDetails` objects.\n */\nexport interface Datasource {\n /** Human-readable datasource name (e.g. \"github\", \"azdevops\", \"md\") */\n readonly name: DatasourceName;\n\n /**\n * Whether this datasource supports git operations (branching, pushing, PRs).\n *\n * @returns `true` if git lifecycle methods are functional, `false` otherwise\n */\n supportsGit(): boolean;\n\n /**\n * List available issues or specs.\n *\n * @param opts - Platform-specific options (org, project, cwd)\n * @returns Array of issue details\n */\n list(opts?: IssueFetchOptions): Promise<IssueDetails[]>;\n\n /**\n * Fetch a single issue or spec by its identifier.\n *\n * @param issueId - The issue number, work item ID, or filename\n * @param opts - Platform-specific options (org, project, cwd)\n * @returns Normalized issue details\n * @throws If the issue cannot be found or the underlying tool fails\n */\n fetch(issueId: string, opts?: IssueFetchOptions): Promise<IssueDetails>;\n\n /**\n * Update the title and/or body of an issue or spec.\n *\n * @param issueId - The issue number, work item ID, or filename\n * @param title - New title\n * @param body - New body/description\n * @param opts - Platform-specific options\n */\n update(issueId: string, title: string, body: string, opts?: IssueFetchOptions): Promise<void>;\n\n /**\n * Close or resolve an issue or spec.\n *\n * @param issueId - The issue number, work item ID, or filename\n * @param opts - Platform-specific options\n */\n close(issueId: string, opts?: IssueFetchOptions): Promise<void>;\n\n /**\n * Create a new issue or spec.\n *\n * @param title - Title of the new issue or spec\n * @param body - Body/description content\n * @param opts - Platform-specific options\n * @returns The created issue details\n */\n create(title: string, body: string, opts?: IssueFetchOptions): Promise<IssueDetails>;\n\n /**\n * Get the default branch name (e.g. \"main\" or \"master\").\n *\n * @param opts - Lifecycle options (cwd)\n * @returns The default branch name\n */\n getDefaultBranch(opts: DispatchLifecycleOptions): Promise<string>;\n\n /**\n * Get the name of the currently checked-out branch.\n *\n * Falls back to {@link getDefaultBranch} when the working tree is in\n * detached-HEAD state (e.g. `git rev-parse --abbrev-ref HEAD` returns\n * `\"HEAD\"`).\n *\n * @param opts - Lifecycle options (cwd)\n * @returns The current branch name\n */\n getCurrentBranch(opts: DispatchLifecycleOptions): Promise<string>;\n\n /**\n * Resolve the current git username for branch namespacing.\n *\n * @param opts - Lifecycle options (cwd)\n * @returns A slugified, branch-safe username\n */\n getUsername(opts: DispatchLifecycleOptions): Promise<string>;\n\n /**\n * Build a branch name from an issue number, title, and username.\n *\n * @param issueNumber - The issue number/ID\n * @param title - The issue title\n * @param username - The branch-safe username prefix\n * @returns A sanitized branch name\n */\n buildBranchName(issueNumber: string, title: string, username?: string): string;\n\n /**\n * Create and switch to a feature branch for an issue.\n * If the branch already exists, switch to it instead.\n *\n * @param branchName - The branch name to create\n * @param opts - Lifecycle options (cwd)\n */\n createAndSwitchBranch(branchName: string, opts: DispatchLifecycleOptions): Promise<void>;\n\n /**\n * Switch to an existing branch.\n *\n * @param branchName - The branch name to switch to\n * @param opts - Lifecycle options (cwd)\n */\n switchBranch(branchName: string, opts: DispatchLifecycleOptions): Promise<void>;\n\n /**\n * Push the current branch to the remote.\n *\n * @param branchName - The branch name to push\n * @param opts - Lifecycle options (cwd)\n */\n pushBranch(branchName: string, opts: DispatchLifecycleOptions): Promise<void>;\n\n /**\n * Stage all changes and create a commit with the given message.\n * This is the safety-net commit after all tasks for an issue complete.\n *\n * @param message - The commit message\n * @param opts - Lifecycle options (cwd)\n */\n commitAllChanges(message: string, opts: DispatchLifecycleOptions): Promise<void>;\n\n /**\n * Create a pull request linking the branch to the issue.\n *\n * @param branchName - The source branch name\n * @param issueNumber - The issue number to reference\n * @param title - PR title\n * @param body - PR body/description content\n * @param opts - Lifecycle options (cwd)\n * @param baseBranch - Optional target branch for the PR. When omitted the\n * datasource falls back to {@link getDefaultBranch}.\n * @returns The URL of the created PR, or the existing PR URL if one already exists\n */\n createPullRequest(\n branchName: string,\n issueNumber: string,\n title: string,\n body: string,\n opts: DispatchLifecycleOptions,\n baseBranch?: string,\n ): Promise<string>;\n}\n","/**\n * GitHub datasource — reads and writes issues using the Octokit SDK.\n *\n * Requires:\n * - A GitHub OAuth token (obtained via device flow on first use)\n * - Working directory inside a GitHub repository with an `origin` remote\n */\n\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport type { Datasource, IssueDetails, IssueFetchOptions, DispatchLifecycleOptions } from \"./interface.js\";\nimport { slugify } from \"../helpers/slugify.js\";\nimport { log } from \"../helpers/logger.js\";\nimport { InvalidBranchNameError, isValidBranchName } from \"../helpers/branch-validation.js\";\nimport { getGithubOctokit } from \"../helpers/auth.js\";\nimport { getGitRemoteUrl, parseGitHubRemoteUrl, deriveShortUsername } from \"./index.js\";\nimport { RequestError } from \"@octokit/request-error\";\n\nexport { InvalidBranchNameError } from \"../helpers/branch-validation.js\";\n\nconst exec = promisify(execFile);\n\n/** Execute a git command and return stdout. */\nasync function git(args: string[], cwd: string): Promise<string> {\n const { stdout } = await exec(\"git\", args, { cwd, shell: process.platform === \"win32\" });\n return stdout;\n}\n\n/**\n * Redact userinfo (credentials) from a URL for safe inclusion in error messages.\n */\nfunction redactUrl(url: string): string {\n return url.replace(/\\/\\/[^@/]+@/, \"//***@\");\n}\n\n/** Cache for getOwnerRepo results, keyed by cwd. Exported for testing only. */\nexport const ownerRepoCache = new Map<string, { owner: string; repo: string }>();\n\n/** Resolve the GitHub owner and repo from the git remote URL (cached per cwd). */\nasync function getOwnerRepo(cwd: string): Promise<{ owner: string; repo: string }> {\n const cached = ownerRepoCache.get(cwd);\n if (cached) return cached;\n\n const remoteUrl = await getGitRemoteUrl(cwd);\n if (!remoteUrl) {\n throw new Error(\"Could not determine git remote URL. Is this a git repository with an origin remote?\");\n }\n const parsed = parseGitHubRemoteUrl(remoteUrl);\n if (!parsed) {\n throw new Error(`Could not parse GitHub owner/repo from remote URL: ${redactUrl(remoteUrl)}`);\n }\n ownerRepoCache.set(cwd, parsed);\n return parsed;\n}\n\n/**\n * Build a branch name from an issue number, title, and username.\n * Produces: `<username>/dispatch/<number>-<slugified-title>`\n *\n * @param issueNumber - The issue number/ID\n * @param title - The issue title (will be slugified)\n * @param username - The slugified git username to namespace the branch\n */\nfunction buildBranchName(issueNumber: string, _title: string, username: string = \"unknown\"): string {\n return `${username}/dispatch/issue-${issueNumber}`;\n}\n\n/**\n * Detect the default branch of the repository.\n * Tries `git symbolic-ref refs/remotes/origin/HEAD` first,\n * falls back to checking if \"main\" or \"master\" exists.\n */\nasync function getDefaultBranch(cwd: string): Promise<string> {\n const PREFIX = \"refs/remotes/origin/\";\n try {\n const ref = await git([\"symbolic-ref\", \"refs/remotes/origin/HEAD\"], cwd);\n // ref looks like \"refs/remotes/origin/main\" or \"refs/remotes/origin/release/2024\"\n const trimmed = ref.trim();\n const branch = trimmed.startsWith(PREFIX)\n ? trimmed.slice(PREFIX.length)\n : trimmed;\n if (!isValidBranchName(branch)) {\n throw new InvalidBranchNameError(branch, \"from symbolic-ref output\");\n }\n return branch;\n } catch (err) {\n if (err instanceof InvalidBranchNameError) {\n throw err;\n }\n // Fallback: check if \"main\" branch exists\n try {\n await git([\"rev-parse\", \"--verify\", \"main\"], cwd);\n return \"main\";\n } catch {\n return \"master\";\n }\n }\n}\n\n/**\n * Gather commit messages from the current branch relative to the default branch.\n * Uses `git log` to list commits that exist on the current branch but not on\n * the default branch, returning each commit's subject line.\n *\n * @param defaultBranch - The default branch name to compare against (e.g. \"main\")\n * @param cwd - The working directory (git repo root)\n * @returns An array of commit message subject lines\n */\nexport async function getCommitMessages(defaultBranch: string, cwd: string): Promise<string[]> {\n try {\n const output = await git(\n [\"log\", `origin/${defaultBranch}..HEAD`, \"--pretty=format:%s\"],\n cwd,\n );\n return output.trim().split(\"\\n\").filter(Boolean);\n } catch {\n return [];\n }\n}\n\nexport const datasource: Datasource = {\n name: \"github\",\n\n supportsGit(): boolean {\n return true;\n },\n\n async list(opts: IssueFetchOptions = {}): Promise<IssueDetails[]> {\n const cwd = opts.cwd || process.cwd();\n const { owner, repo } = await getOwnerRepo(cwd);\n const octokit = await getGithubOctokit();\n\n const issues = await octokit.paginate(\n octokit.rest.issues.listForRepo,\n {\n owner,\n repo,\n state: \"open\",\n },\n );\n\n return issues\n .filter((issue) => !issue.pull_request)\n .map((issue): IssueDetails => ({\n number: String(issue.number),\n title: issue.title ?? \"\",\n body: issue.body ?? \"\",\n labels: (issue.labels ?? []).map((l) => (typeof l === \"string\" ? l : l.name ?? \"\")).filter(Boolean),\n state: issue.state ?? \"open\",\n url: issue.html_url ?? \"\",\n comments: [],\n acceptanceCriteria: \"\",\n }));\n },\n\n async fetch(issueId: string, opts: IssueFetchOptions = {}): Promise<IssueDetails> {\n const cwd = opts.cwd || process.cwd();\n const { owner, repo } = await getOwnerRepo(cwd);\n const octokit = await getGithubOctokit();\n\n const { data: issue } = await octokit.rest.issues.get({\n owner,\n repo,\n issue_number: Number(issueId),\n });\n\n const issueComments = await octokit.paginate(\n octokit.rest.issues.listComments,\n {\n owner,\n repo,\n issue_number: Number(issueId),\n },\n );\n\n const comments: string[] = issueComments.map(\n (c) => `**${c.user?.login ?? \"unknown\"}:** ${c.body ?? \"\"}`\n );\n\n return {\n number: String(issue.number),\n title: issue.title ?? \"\",\n body: issue.body ?? \"\",\n labels: (issue.labels ?? []).map((l) => (typeof l === \"string\" ? l : l.name ?? \"\")).filter(Boolean),\n state: issue.state ?? \"open\",\n url: issue.html_url ?? \"\",\n comments,\n acceptanceCriteria: \"\",\n };\n },\n\n async update(issueId: string, title: string, body: string, opts: IssueFetchOptions = {}): Promise<void> {\n const cwd = opts.cwd || process.cwd();\n const { owner, repo } = await getOwnerRepo(cwd);\n const octokit = await getGithubOctokit();\n\n await octokit.rest.issues.update({\n owner,\n repo,\n issue_number: Number(issueId),\n title,\n body,\n });\n },\n\n async close(issueId: string, opts: IssueFetchOptions = {}): Promise<void> {\n const cwd = opts.cwd || process.cwd();\n const { owner, repo } = await getOwnerRepo(cwd);\n const octokit = await getGithubOctokit();\n\n await octokit.rest.issues.update({\n owner,\n repo,\n issue_number: Number(issueId),\n state: \"closed\",\n });\n },\n\n async create(title: string, body: string, opts: IssueFetchOptions = {}): Promise<IssueDetails> {\n const cwd = opts.cwd || process.cwd();\n const { owner, repo } = await getOwnerRepo(cwd);\n const octokit = await getGithubOctokit();\n\n const { data: issue } = await octokit.rest.issues.create({\n owner,\n repo,\n title,\n body,\n });\n\n return {\n number: String(issue.number),\n title: issue.title ?? \"\",\n body: issue.body ?? \"\",\n labels: (issue.labels ?? []).map((l) => (typeof l === \"string\" ? l : l.name ?? \"\")).filter(Boolean),\n state: issue.state ?? \"open\",\n url: issue.html_url ?? \"\",\n comments: [],\n acceptanceCriteria: \"\",\n };\n },\n\n async getUsername(opts: DispatchLifecycleOptions): Promise<string> {\n if (opts.username) return opts.username;\n return deriveShortUsername(opts.cwd, \"unknown\");\n },\n\n getDefaultBranch(opts) {\n return getDefaultBranch(opts.cwd);\n },\n\n async getCurrentBranch(opts) {\n try {\n const branch = (await git([\"rev-parse\", \"--abbrev-ref\", \"HEAD\"], opts.cwd)).trim();\n // Detached HEAD returns the literal string \"HEAD\"\n if (branch && branch !== \"HEAD\") return branch;\n } catch { /* fall through */ }\n return this.getDefaultBranch(opts);\n },\n\n buildBranchName(issueNumber: string, title: string, username?: string): string {\n return buildBranchName(issueNumber, title, username ?? \"unknown\");\n },\n\n async createAndSwitchBranch(branchName, opts) {\n const cwd = opts.cwd;\n try {\n await git([\"checkout\", \"-b\", branchName], cwd);\n } catch (err) {\n // Branch may already exist — switch to it instead\n const message = log.extractMessage(err);\n if (message.includes(\"already exists\")) {\n try {\n await git([\"checkout\", branchName], cwd);\n } catch (checkoutErr) {\n const checkoutMessage = log.extractMessage(checkoutErr);\n if (checkoutMessage.includes(\"already used by worktree\")) {\n await git([\"worktree\", \"prune\"], cwd);\n await git([\"checkout\", branchName], cwd);\n } else {\n throw checkoutErr;\n }\n }\n } else {\n throw err;\n }\n }\n },\n\n async switchBranch(branchName, opts) {\n await git([\"checkout\", branchName], opts.cwd);\n },\n\n async pushBranch(branchName, opts) {\n await git([\"push\", \"--set-upstream\", \"origin\", branchName], opts.cwd);\n },\n\n async commitAllChanges(message, opts) {\n const cwd = opts.cwd;\n await git([\"add\", \"-A\"], cwd);\n const status = await git([\"diff\", \"--cached\", \"--stat\"], cwd);\n if (!status.trim()) {\n return; // nothing to commit\n }\n await git([\"commit\", \"-m\", message], cwd);\n },\n\n async createPullRequest(branchName, issueNumber, title, body, opts, baseBranch?) {\n const cwd = opts.cwd;\n const { owner, repo } = await getOwnerRepo(cwd);\n const octokit = await getGithubOctokit();\n const prBody = body || `Closes #${issueNumber}`;\n\n try {\n const target = baseBranch ?? await getDefaultBranch(cwd);\n const { data: pr } = await octokit.rest.pulls.create({\n owner,\n repo,\n title,\n body: prBody,\n head: branchName,\n base: target,\n });\n return pr.html_url;\n } catch (err: unknown) {\n // If a PR already exists for this branch, retrieve its URL.\n // Octokit throws a RequestError with status 422 for validation\n // failures, including \"A pull request already exists\".\n const isValidationError = err instanceof RequestError && err.status === 422;\n\n if (isValidationError) {\n const { data: prs } = await octokit.rest.pulls.list({\n owner,\n repo,\n head: `${owner}:${branchName}`,\n state: \"open\",\n });\n if (prs.length > 0) {\n return prs[0].html_url;\n }\n }\n throw err;\n }\n },\n};\n","/**\n * Shared branch-name validation utilities.\n *\n * Provides a strict validator (`isValidBranchName`) and a typed error class\n * (`InvalidBranchNameError`) that enforce git refname rules. Extracted from\n * the GitHub datasource so every datasource can share the same logic.\n */\n\n/**\n * Thrown when a branch name fails validation.\n * Provides reliable `instanceof` detection instead of brittle message-string checks.\n */\nexport class InvalidBranchNameError extends Error {\n constructor(branch: string, reason?: string) {\n const detail = reason ? ` (${reason})` : \"\";\n super(`Invalid branch name: \"${branch}\"${detail}`);\n this.name = \"InvalidBranchNameError\";\n }\n}\n\n/** Strict pattern for valid git branch name character set. */\nexport const VALID_BRANCH_NAME_RE = /^[a-zA-Z0-9._\\-/]+$/;\n\n/**\n * Check whether a branch name is safe to use in git/gh commands.\n * Enforces git refname rules beyond simple character validation:\n * - Must be 1–255 characters of allowed characters\n * - Cannot start or end with \"/\"\n * - Cannot contain \"..\" (parent traversal)\n * - Cannot end with \".lock\"\n * - Cannot contain \"@{\" (reflog syntax)\n * - Cannot contain \"//\" (empty path component)\n */\nexport function isValidBranchName(name: string): boolean {\n if (name.length === 0 || name.length > 255) return false;\n if (!VALID_BRANCH_NAME_RE.test(name)) return false;\n if (name.startsWith(\"/\") || name.endsWith(\"/\")) return false;\n if (name.includes(\"..\")) return false;\n if (name.endsWith(\".lock\")) return false;\n if (name.includes(\"@{\")) return false;\n if (name.includes(\"//\")) return false;\n return true;\n}\n","/**\n * OAuth device-flow authentication helpers for GitHub and Azure DevOps.\n *\n * Tokens are cached at ~/.dispatch/auth.json (mode 0o600) so users only\n * need to authenticate once per platform until tokens expire.\n */\n\nimport { readFile, writeFile, mkdir, chmod } from \"node:fs/promises\";\nimport { join, dirname } from \"node:path\";\nimport { homedir } from \"node:os\";\n\nimport { Octokit } from \"@octokit/rest\";\nimport { createOAuthDeviceAuth } from \"@octokit/auth-oauth-device\";\nimport { DeviceCodeCredential } from \"@azure/identity\";\nimport * as azdev from \"azure-devops-node-api\";\nimport open from \"open\";\n\nimport { log } from \"./logger.js\";\nimport {\n GITHUB_CLIENT_ID,\n AZURE_CLIENT_ID,\n AZURE_TENANT_ID,\n AZURE_DEVOPS_SCOPE,\n} from \"../constants.js\";\nimport {\n getGitRemoteUrl,\n parseGitHubRemoteUrl,\n parseAzDevOpsRemoteUrl,\n} from \"../datasources/index.js\";\nimport type { DatasourceName } from \"../datasources/interface.js\";\n\ninterface AuthCache {\n github?: { token: string };\n azure?: { token: string; expiresAt: string };\n}\n\nconst AUTH_PATH = join(homedir(), \".dispatch\", \"auth.json\");\n\n/** Five-minute buffer (ms) used to refresh Azure tokens before they expire. */\nconst EXPIRY_BUFFER_MS = 5 * 60 * 1000;\n\n/** Optional callback for routing auth prompts into the TUI. */\nlet authPromptHandler: ((message: string) => void) | null = null;\n\n/**\n * Register a handler for auth device-code prompts.\n * When set, prompts are routed to this handler instead of `log.info()`.\n * Pass `null` to clear the handler.\n */\nexport function setAuthPromptHandler(handler: ((message: string) => void) | null): void {\n authPromptHandler = handler;\n}\n\nasync function loadAuthCache(): Promise<AuthCache> {\n try {\n const raw = await readFile(AUTH_PATH, \"utf-8\");\n return JSON.parse(raw) as AuthCache;\n } catch {\n return {};\n }\n}\n\nasync function saveAuthCache(cache: AuthCache): Promise<void> {\n await mkdir(dirname(AUTH_PATH), { recursive: true });\n await writeFile(AUTH_PATH, JSON.stringify(cache, null, 2) + \"\\n\", \"utf-8\");\n if (process.platform !== \"win32\") {\n try {\n await chmod(AUTH_PATH, 0o600);\n } catch {\n // chmod may fail on restricted filesystems; token was already written\n }\n }\n}\n\n/**\n * Return an authenticated Octokit instance for the GitHub API.\n *\n * On first use the user is guided through the OAuth device-flow; the\n * resulting token is cached for subsequent calls.\n */\nexport async function getGithubOctokit(): Promise<Octokit> {\n const cache = await loadAuthCache();\n\n if (cache.github?.token) {\n return new Octokit({ auth: cache.github.token });\n }\n\n const auth = createOAuthDeviceAuth({\n clientId: GITHUB_CLIENT_ID,\n clientType: \"oauth-app\",\n scopes: [\"repo\"],\n onVerification(verification) {\n const msg = `Enter code ${verification.user_code} at ${verification.verification_uri}`;\n if (authPromptHandler) {\n authPromptHandler(msg);\n } else {\n log.info(msg);\n }\n open(verification.verification_uri).catch(() => {});\n },\n });\n\n const authentication = await auth({ type: \"oauth\" });\n\n cache.github = { token: authentication.token };\n await saveAuthCache(cache);\n\n return new Octokit({ auth: authentication.token });\n}\n\n/**\n * Return an authenticated Azure DevOps `WebApi` connection for the given org.\n *\n * On first use (or when the cached token is about to expire) the user is\n * guided through the Azure device-code flow; the token is cached for\n * subsequent calls.\n */\nexport async function getAzureConnection(\n orgUrl: string,\n): Promise<azdev.WebApi> {\n const cache = await loadAuthCache();\n\n if (cache.azure?.token && cache.azure.expiresAt) {\n const expiresAt = new Date(cache.azure.expiresAt).getTime();\n if (expiresAt - Date.now() > EXPIRY_BUFFER_MS) {\n return new azdev.WebApi(\n orgUrl,\n azdev.getBearerHandler(cache.azure.token),\n );\n }\n }\n\n const credential = new DeviceCodeCredential({\n tenantId: AZURE_TENANT_ID,\n clientId: AZURE_CLIENT_ID,\n userPromptCallback(deviceCodeInfo) {\n // Azure DevOps only supports work/school accounts — prepend a note\n // so users don't attempt to sign in with a personal Microsoft account.\n const note = \"Azure DevOps requires a work or school account (personal Microsoft accounts are not supported).\";\n const msg = `${note}\\n${deviceCodeInfo.message}`;\n if (authPromptHandler) {\n authPromptHandler(msg);\n } else {\n log.info(msg);\n }\n open(deviceCodeInfo.verificationUri).catch(() => {});\n },\n });\n\n const accessToken = await credential.getToken(AZURE_DEVOPS_SCOPE);\n if (!accessToken) {\n throw new Error(\n \"Azure device-code authentication did not return a token. Please try again.\",\n );\n }\n\n cache.azure = {\n token: accessToken.token,\n expiresAt: new Date(accessToken.expiresOnTimestamp).toISOString(),\n };\n await saveAuthCache(cache);\n\n return new azdev.WebApi(\n orgUrl,\n azdev.getBearerHandler(accessToken.token),\n );\n}\n\n/**\n * Ensure the user is authenticated for the given datasource before pipeline\n * work begins. For cached/valid tokens this resolves instantly; for new or\n * expired credentials it triggers the device-code flow while stdout is still\n * free (before the TUI or batch output takes over).\n *\n * This is a shared entry point used by both the dispatch and spec pipelines.\n */\nexport async function ensureAuthReady(\n source: DatasourceName | undefined,\n cwd: string,\n org?: string,\n): Promise<void> {\n if (source === \"github\") {\n const remoteUrl = await getGitRemoteUrl(cwd);\n if (remoteUrl && parseGitHubRemoteUrl(remoteUrl)) {\n await getGithubOctokit();\n } else if (!remoteUrl) {\n log.warn(\"No git remote found — skipping GitHub pre-authentication\");\n } else {\n log.warn(\"Remote URL is not a GitHub repository — skipping GitHub pre-authentication\");\n }\n } else if (source === \"azdevops\") {\n let orgUrl = org;\n if (!orgUrl) {\n const remoteUrl = await getGitRemoteUrl(cwd);\n if (remoteUrl) {\n const parsed = parseAzDevOpsRemoteUrl(remoteUrl);\n if (parsed) orgUrl = parsed.orgUrl;\n else log.warn(\"Remote URL is not an Azure DevOps repository — skipping Azure pre-authentication\");\n } else {\n log.warn(\"No git remote found — skipping Azure DevOps pre-authentication\");\n }\n }\n if (orgUrl) await getAzureConnection(orgUrl);\n }\n}\n","/**\n * OAuth client IDs and related constants for device-flow authentication.\n *\n * These are public client identifiers — not secrets — bundled so that users\n * do not need to register their own OAuth applications.\n */\n\n/** GitHub OAuth App client ID. */\nexport const GITHUB_CLIENT_ID = \"Ov23liUMP1Oyg811IF58\";\n\n/** Azure AD application (client) ID. */\nexport const AZURE_CLIENT_ID = \"150a3098-01dd-4126-8b10-5e7f77492e5c\";\n\n/**\n * Azure AD tenant ID — \"organizations\" restricts sign-in to work/school\n * (Entra ID) accounts. Azure DevOps does not support personal Microsoft\n * accounts for API access, so \"common\" cannot be used here.\n */\nexport const AZURE_TENANT_ID = \"organizations\";\n\n/** Azure DevOps default API scope. */\nexport const AZURE_DEVOPS_SCOPE = \"499b84ac-1321-427f-aa17-267ca6975798/.default\";\n","class RequestError extends Error {\n name;\n /**\n * http status code\n */\n status;\n /**\n * Request options that lead to the error.\n */\n request;\n /**\n * Response object if a response was received\n */\n response;\n constructor(message, statusCode, options) {\n super(message);\n this.name = \"HttpError\";\n this.status = Number.parseInt(statusCode);\n if (Number.isNaN(this.status)) {\n this.status = 0;\n }\n if (\"response\" in options) {\n this.response = options.response;\n }\n const requestCopy = Object.assign({}, options.request);\n if (options.request.headers.authorization) {\n requestCopy.headers = Object.assign({}, options.request.headers, {\n authorization: options.request.headers.authorization.replace(\n /(?<! ) .*$/,\n \" [REDACTED]\"\n )\n });\n }\n requestCopy.url = requestCopy.url.replace(/\\bclient_secret=\\w+/g, \"client_secret=[REDACTED]\").replace(/\\baccess_token=\\w+/g, \"access_token=[REDACTED]\");\n this.request = requestCopy;\n }\n}\nexport {\n RequestError\n};\n","/**\n * Azure DevOps datasource — reads and writes work items using the\n * `azure-devops-node-api` SDK with OAuth device-flow authentication.\n *\n * Requires:\n * - Working directory inside an Azure DevOps git repository with an\n * `origin` remote\n * - User will be prompted to authenticate via device code on first use\n */\n\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport type { Datasource, IssueDetails, IssueFetchOptions, DispatchLifecycleOptions } from \"./interface.js\";\nimport { slugify } from \"../helpers/slugify.js\";\nimport { log } from \"../helpers/logger.js\";\nimport { InvalidBranchNameError, isValidBranchName } from \"../helpers/branch-validation.js\";\nimport { getAzureConnection } from \"../helpers/auth.js\";\nimport { getGitRemoteUrl, parseAzDevOpsRemoteUrl, deriveShortUsername } from \"./index.js\";\nimport type { WebApi } from \"azure-devops-node-api\";\nimport type { TeamContext } from \"azure-devops-node-api/interfaces/CoreInterfaces.js\";\nimport type { JsonPatchDocument } from \"azure-devops-node-api/interfaces/common/VSSInterfaces.js\";\nimport { PullRequestStatus } from \"azure-devops-node-api/interfaces/GitInterfaces.js\";\n\nconst exec = promisify(execFile);\nconst doneStateCache = new Map<string, string>();\n\n/** Execute a git command and return stdout. */\nasync function git(args: string[], cwd: string): Promise<string> {\n const { stdout } = await exec(\"git\", args, { cwd, shell: process.platform === \"win32\" });\n return stdout;\n}\n\n/**\n * Redact userinfo (credentials) from a URL for safe inclusion in error messages.\n * Replaces `https://user:pass@host/...` or `https://user@host/...` with `https://***@host/...`.\n */\nfunction redactUrl(url: string): string {\n return url.replace(/\\/\\/[^@/]+@/, \"//***@\");\n}\n\n/**\n * Resolve the Azure DevOps org URL, project name, and an authenticated\n * WebApi connection from the git remote URL.\n *\n * If `opts.org` and `opts.project` are already provided they are used\n * directly; otherwise they are parsed from the `origin` remote.\n */\nasync function getOrgAndProject(\n opts: IssueFetchOptions = {}\n): Promise<{ orgUrl: string; project: string; connection: WebApi }> {\n let orgUrl = opts.org;\n let project = opts.project;\n\n if (!orgUrl || !project) {\n const cwd = opts.cwd || process.cwd();\n const remoteUrl = await getGitRemoteUrl(cwd);\n if (!remoteUrl) {\n throw new Error(\n \"Could not determine git remote URL. Is this a git repository with an origin remote?\"\n );\n }\n const parsed = parseAzDevOpsRemoteUrl(remoteUrl);\n if (!parsed) {\n throw new Error(\n `Could not parse Azure DevOps org/project from remote URL: ${redactUrl(remoteUrl)}`\n );\n }\n orgUrl = orgUrl || parsed.orgUrl;\n project = project || parsed.project;\n }\n\n const connection = await getAzureConnection(orgUrl);\n return { orgUrl, project, connection };\n}\n\n/**\n * Map a raw Azure DevOps work item JSON object to an IssueDetails.\n */\nfunction mapWorkItemToIssueDetails(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n item: any,\n id: string,\n comments: string[],\n defaults?: { title?: string; body?: string; state?: string; workItemType?: string }\n): IssueDetails {\n const fields = item.fields ?? {};\n return {\n number: String(item.id ?? id),\n title: fields[\"System.Title\"] ?? defaults?.title ?? \"\",\n body: fields[\"System.Description\"] ?? defaults?.body ?? \"\",\n labels: (fields[\"System.Tags\"] ?? \"\")\n .split(\";\")\n .map((t: string) => t.trim())\n .filter(Boolean),\n state: fields[\"System.State\"] ?? defaults?.state ?? \"\",\n url: item._links?.html?.href ?? item.url ?? \"\",\n comments,\n acceptanceCriteria:\n fields[\"Microsoft.VSTS.Common.AcceptanceCriteria\"] ?? \"\",\n iterationPath: fields[\"System.IterationPath\"] || undefined,\n areaPath: fields[\"System.AreaPath\"] || undefined,\n assignee: fields[\"System.AssignedTo\"]?.displayName || undefined,\n priority: fields[\"Microsoft.VSTS.Common.Priority\"] ?? undefined,\n storyPoints:\n fields[\"Microsoft.VSTS.Scheduling.StoryPoints\"] ??\n fields[\"Microsoft.VSTS.Scheduling.Effort\"] ??\n fields[\"Microsoft.VSTS.Scheduling.Size\"] ??\n undefined,\n workItemType: fields[\"System.WorkItemType\"] || defaults?.workItemType || undefined,\n };\n}\n\nexport async function detectWorkItemType(\n opts: IssueFetchOptions = {}\n): Promise<string | null> {\n try {\n const { project, connection } = await getOrgAndProject(opts);\n const witApi = await connection.getWorkItemTrackingApi();\n const types = await witApi.getWorkItemTypes(project);\n\n if (!Array.isArray(types) || types.length === 0) return null;\n\n const names = types.map((t) => t.name).filter((n): n is string => !!n);\n const preferred = [\"User Story\", \"Product Backlog Item\", \"Requirement\", \"Issue\"] as const;\n for (const p of preferred) {\n if (names.includes(p)) return p;\n }\n return names[0] ?? null;\n } catch {\n return null;\n }\n}\n\nexport async function detectDoneState(\n workItemType: string,\n opts: IssueFetchOptions = {}\n): Promise<string> {\n const { orgUrl, project, connection } = await getOrgAndProject(opts);\n const cacheKey = `${orgUrl}|${project}|${workItemType}`;\n const cached = doneStateCache.get(cacheKey);\n if (cached) return cached;\n\n try {\n const witApi = await connection.getWorkItemTrackingApi();\n const states = await witApi.getWorkItemTypeStates(project, workItemType);\n\n // Primary: find state with \"Completed\" category\n if (Array.isArray(states)) {\n const completed = states.find((s) => s.category === \"Completed\");\n if (completed?.name) {\n doneStateCache.set(cacheKey, completed.name);\n return completed.name;\n }\n\n // Fallback: check for known terminal states in priority order\n const names = states.map((s) => s.name).filter((n): n is string => !!n);\n const fallbacks = [\"Done\", \"Closed\", \"Resolved\", \"Completed\"] as const;\n for (const f of fallbacks) {\n if (names.includes(f)) {\n doneStateCache.set(cacheKey, f);\n return f;\n }\n }\n }\n } catch {\n // Fall through to default\n }\n\n // Don't cache the default — a transient error should not\n // prevent subsequent calls from retrying the detection.\n return \"Closed\";\n}\n\n/**\n * Fetch comments for an Azure DevOps work item.\n * Non-fatal — returns empty array on failure.\n */\nasync function fetchComments(\n workItemId: number,\n project: string,\n connection: WebApi\n): Promise<string[]> {\n try {\n const witApi = await connection.getWorkItemTrackingApi();\n const commentList = await witApi.getComments(project, workItemId);\n\n if (commentList.comments && Array.isArray(commentList.comments)) {\n return commentList.comments.map((c) => {\n const author = c.createdBy?.displayName ?? \"unknown\";\n return `**${author}:** ${c.text ?? \"\"}`;\n });\n }\n return [];\n } catch {\n return [];\n }\n}\n\nexport const datasource: Datasource = {\n name: \"azdevops\",\n\n supportsGit(): boolean {\n return true;\n },\n\n async list(opts: IssueFetchOptions = {}): Promise<IssueDetails[]> {\n const { project, connection } = await getOrgAndProject(opts);\n const witApi = await connection.getWorkItemTrackingApi();\n\n const conditions = [\n \"[System.State] <> 'Closed'\",\n \"[System.State] <> 'Done'\",\n \"[System.State] <> 'Removed'\",\n ];\n\n if (opts.iteration) {\n const iterValue = String(opts.iteration).trim();\n if (iterValue === \"@CurrentIteration\") {\n conditions.push(`[System.IterationPath] UNDER @CurrentIteration`);\n } else {\n const escaped = iterValue.replace(/'/g, \"''\");\n if (escaped) conditions.push(`[System.IterationPath] UNDER '${escaped}'`);\n }\n }\n\n if (opts.area) {\n const area = String(opts.area).trim().replace(/'/g, \"''\");\n if (area) {\n conditions.push(`[System.AreaPath] UNDER '${area}'`);\n }\n }\n\n const wiql = `SELECT [System.Id] FROM workitems WHERE ${conditions.join(\" AND \")} ORDER BY [System.CreatedDate] DESC`;\n\n // The SDK's queryByWiql accepts a partial TeamContext with only `project` set.\n // Cast is safe: we only use the project field for routing, matching SDK usage patterns.\n const queryResult = await witApi.queryByWiql({ query: wiql }, { project } as TeamContext);\n const workItemRefs = queryResult.workItems ?? [];\n if (workItemRefs.length === 0) return [];\n\n const ids = workItemRefs\n .map((ref) => ref.id)\n .filter((id): id is number => id != null);\n\n if (ids.length === 0) return [];\n\n try {\n const items = await witApi.getWorkItems(ids);\n const itemsArray = Array.isArray(items) ? items : [items];\n\n // Fetch comments with bounded concurrency (batches of 5)\n const commentsArray: string[][] = [];\n const CONCURRENCY = 5;\n for (let i = 0; i < itemsArray.length; i += CONCURRENCY) {\n const batch = itemsArray.slice(i, i + CONCURRENCY);\n const batchResults = await Promise.all(\n // item.id is guaranteed non-null here: the ids array was built by filtering\n // out null ids from workItemRefs, and itemsArray came from getWorkItems(ids).\n batch.map((item) => fetchComments(item.id!, project, connection))\n );\n commentsArray.push(...batchResults);\n }\n\n return itemsArray.map((item, i) =>\n mapWorkItemToIssueDetails(item, String(item.id), commentsArray[i])\n );\n } catch (err) {\n log.debug(`Batch getWorkItems failed, falling back to individual fetches: ${log.extractMessage(err)}`);\n // Fallback: fetch items individually in parallel\n const results = await Promise.all(\n ids.map((id) => datasource.fetch(String(id), opts))\n );\n return results;\n }\n },\n\n async fetch(\n issueId: string,\n opts: IssueFetchOptions = {}\n ): Promise<IssueDetails> {\n const { project, connection } = await getOrgAndProject(opts);\n const witApi = await connection.getWorkItemTrackingApi();\n\n const item = await witApi.getWorkItem(Number(issueId));\n const comments = await fetchComments(Number(issueId), project, connection);\n\n return mapWorkItemToIssueDetails(item, issueId, comments);\n },\n\n async update(\n issueId: string,\n title: string,\n body: string,\n opts: IssueFetchOptions = {}\n ): Promise<void> {\n const { connection } = await getOrgAndProject(opts);\n const witApi = await connection.getWorkItemTrackingApi();\n\n const document = [\n { op: \"add\", path: \"/fields/System.Title\", value: title },\n { op: \"add\", path: \"/fields/System.Description\", value: body },\n ];\n // The azure-devops-node-api SDK's updateWorkItem signature requires a `customHeaders`\n // first argument; passing null is the documented way to omit it (no typed alternative).\n await witApi.updateWorkItem(null as any, document as JsonPatchDocument, Number(issueId));\n },\n\n async close(\n issueId: string,\n opts: IssueFetchOptions = {}\n ): Promise<void> {\n const { connection } = await getOrgAndProject(opts);\n const witApi = await connection.getWorkItemTrackingApi();\n\n let workItemType = opts.workItemType;\n if (!workItemType) {\n const item = await witApi.getWorkItem(Number(issueId));\n workItemType = item.fields?.[\"System.WorkItemType\"] ?? undefined;\n }\n\n const state = workItemType\n ? await detectDoneState(workItemType, opts)\n : \"Closed\";\n\n const document = [\n { op: \"add\", path: \"/fields/System.State\", value: state },\n ];\n // null as any: SDK customHeaders param — passing null is the documented way to omit it.\n await witApi.updateWorkItem(null as any, document as JsonPatchDocument, Number(issueId));\n },\n\n async create(\n title: string,\n body: string,\n opts: IssueFetchOptions = {}\n ): Promise<IssueDetails> {\n const workItemType =\n opts.workItemType ?? (await detectWorkItemType(opts));\n\n if (!workItemType) {\n throw new Error(\n \"Could not determine work item type. Set workItemType in your config (for example via `dispatch config`).\"\n );\n }\n\n const { project, connection } = await getOrgAndProject(opts);\n const witApi = await connection.getWorkItemTrackingApi();\n\n const document = [\n { op: \"add\", path: \"/fields/System.Title\", value: title },\n { op: \"add\", path: \"/fields/System.Description\", value: body },\n ];\n\n const item = await witApi.createWorkItem(\n // null as any: SDK customHeaders param — passing null is the documented way to omit it.\n null as any,\n document as JsonPatchDocument,\n project,\n workItemType\n );\n\n return mapWorkItemToIssueDetails(item, String(item.id), [], {\n title,\n body,\n state: \"New\",\n workItemType,\n });\n },\n\n async getDefaultBranch(opts: DispatchLifecycleOptions): Promise<string> {\n const PREFIX = \"refs/remotes/origin/\";\n try {\n const ref = await git([\"symbolic-ref\", \"refs/remotes/origin/HEAD\"], opts.cwd);\n const trimmed = ref.trim();\n const branch = trimmed.startsWith(PREFIX)\n ? trimmed.slice(PREFIX.length)\n : trimmed;\n if (!isValidBranchName(branch)) {\n throw new InvalidBranchNameError(branch, \"from symbolic-ref output\");\n }\n return branch;\n } catch (err) {\n if (err instanceof InvalidBranchNameError) {\n throw err;\n }\n try {\n await git([\"rev-parse\", \"--verify\", \"main\"], opts.cwd);\n return \"main\";\n } catch {\n return \"master\";\n }\n }\n },\n\n async getCurrentBranch(opts: DispatchLifecycleOptions): Promise<string> {\n try {\n const branch = (await git([\"rev-parse\", \"--abbrev-ref\", \"HEAD\"], opts.cwd)).trim();\n if (branch && branch !== \"HEAD\") return branch;\n } catch { /* fall through */ }\n return this.getDefaultBranch(opts);\n },\n\n async getUsername(opts: DispatchLifecycleOptions): Promise<string> {\n if (opts.username) return opts.username;\n return deriveShortUsername(opts.cwd, \"unknown\");\n },\n\n buildBranchName(issueNumber: string, _title: string, username: string): string {\n const branch = `${username}/dispatch/issue-${issueNumber}`;\n if (!isValidBranchName(branch)) {\n throw new InvalidBranchNameError(branch);\n }\n return branch;\n },\n\n async createAndSwitchBranch(branchName: string, opts: DispatchLifecycleOptions): Promise<void> {\n if (!isValidBranchName(branchName)) {\n throw new InvalidBranchNameError(branchName);\n }\n try {\n await git([\"checkout\", \"-b\", branchName], opts.cwd);\n } catch (err) {\n const message = log.extractMessage(err);\n if (message.includes(\"already exists\")) {\n try {\n await git([\"checkout\", branchName], opts.cwd);\n } catch (checkoutErr) {\n const checkoutMessage = log.extractMessage(checkoutErr);\n if (checkoutMessage.includes(\"already used by worktree\")) {\n await git([\"worktree\", \"prune\"], opts.cwd);\n await git([\"checkout\", branchName], opts.cwd);\n } else {\n throw checkoutErr;\n }\n }\n } else {\n throw err;\n }\n }\n },\n\n async switchBranch(branchName: string, opts: DispatchLifecycleOptions): Promise<void> {\n await git([\"checkout\", branchName], opts.cwd);\n },\n\n async pushBranch(branchName: string, opts: DispatchLifecycleOptions): Promise<void> {\n await git([\"push\", \"--set-upstream\", \"origin\", branchName], opts.cwd);\n },\n\n async commitAllChanges(message: string, opts: DispatchLifecycleOptions): Promise<void> {\n await git([\"add\", \"-A\"], opts.cwd);\n const status = await git([\"diff\", \"--cached\", \"--stat\"], opts.cwd);\n if (!status.trim()) {\n return; // nothing to commit\n }\n await git([\"commit\", \"-m\", message], opts.cwd);\n },\n\n async createPullRequest(\n branchName: string,\n issueNumber: string,\n title: string,\n body: string,\n opts: DispatchLifecycleOptions,\n baseBranch?: string,\n ): Promise<string> {\n const cwd = opts.cwd;\n const { orgUrl, project, connection } = await getOrgAndProject(opts);\n const gitApi = await connection.getGitApi();\n\n // Resolve the remote URL for repo matching\n const remoteUrl = await getGitRemoteUrl(cwd);\n if (!remoteUrl) {\n throw new Error(\"Could not determine git remote URL.\");\n }\n\n // Find the repository by matching remote URL\n const repos = await gitApi.getRepositories(project);\n const normalizeUrl = (u: string) => u.replace(/\\/\\/[^@/]+@/, \"//\").replace(/\\.git$/, \"\").replace(/\\/$/, \"\").toLowerCase();\n const normalizedRemote = normalizeUrl(remoteUrl);\n const repo = repos.find(\n (r) =>\n (r.remoteUrl && normalizeUrl(r.remoteUrl) === normalizedRemote) ||\n (r.sshUrl && normalizeUrl(r.sshUrl) === normalizedRemote) ||\n (r.webUrl && normalizeUrl(r.webUrl) === normalizedRemote)\n );\n\n if (!repo || !repo.id) {\n throw new Error(`Could not find Azure DevOps repository matching remote URL: ${redactUrl(remoteUrl)}`);\n }\n\n const target = baseBranch ?? await this.getDefaultBranch(opts);\n\n try {\n const pr = await gitApi.createPullRequest(\n {\n sourceRefName: `refs/heads/${branchName}`,\n targetRefName: `refs/heads/${target}`,\n title,\n description: body || `Resolves AB#${issueNumber}`,\n workItemRefs: [{ id: issueNumber }],\n },\n repo.id,\n project\n );\n\n // Construct web UI URL (SDK url is REST API URL, not browser URL)\n const webUrl = repo.webUrl\n ? `${repo.webUrl}/pullrequest/${pr.pullRequestId}`\n : pr.url ?? \"\";\n return webUrl;\n } catch (err) {\n // If a PR already exists for this branch, retrieve its URL\n const message = log.extractMessage(err);\n if (message.includes(\"already exists\")) {\n const prs = await gitApi.getPullRequests(\n repo.id,\n {\n sourceRefName: `refs/heads/${branchName}`,\n status: PullRequestStatus.Active,\n },\n project\n );\n if (Array.isArray(prs) && prs.length > 0) {\n const existingPr = prs[0];\n const webUrl = repo.webUrl\n ? `${repo.webUrl}/pullrequest/${existingPr.pullRequestId}`\n : existingPr.url ?? \"\";\n return webUrl;\n }\n return \"\";\n }\n throw err;\n }\n },\n};\n","/**\n * Local markdown datasource — reads and writes `.md` files from a configurable\n * directory, treating each file as a work item / spec.\n *\n * Default directory: `.dispatch/specs/` (relative to the working directory).\n *\n * This datasource enables fully offline operation and local-first workflows\n * where markdown files serve as the source of truth.\n */\n\nimport { execFile } from \"node:child_process\";\nimport { readFile, writeFile, readdir, mkdir, rename } from \"node:fs/promises\";\nimport { basename, dirname, isAbsolute, join, parse as parsePath, resolve } from \"node:path\";\nimport { promisify } from \"node:util\";\nimport { glob } from \"glob\";\n\n/** Simple async mutex to serialize create() calls and prevent duplicate IDs. */\nlet createLock: Promise<void> = Promise.resolve();\nfunction withCreateLock<T>(fn: () => Promise<T>): Promise<T> {\n const prev = createLock;\n let resolve: () => void;\n createLock = new Promise<void>((r) => { resolve = r; });\n return prev.then(fn).finally(() => resolve!());\n}\nimport type { Datasource, IssueDetails, IssueFetchOptions, DispatchLifecycleOptions } from \"./interface.js\";\nimport { deriveShortUsername } from \"./index.js\";\nimport { slugify } from \"../helpers/slugify.js\";\nimport { loadConfig, saveConfig } from \"../config.js\";\nimport { log } from \"../helpers/logger.js\";\nimport { InvalidBranchNameError, isValidBranchName } from \"../helpers/branch-validation.js\";\n\nconst exec = promisify(execFile);\n\n/** Execute a git command and return stdout. */\nasync function git(args: string[], cwd: string): Promise<string> {\n const { stdout } = await exec(\"git\", args, { cwd, shell: process.platform === \"win32\" });\n return stdout;\n}\n\n/** Default directory for markdown specs, relative to cwd. */\nconst DEFAULT_DIR = \".dispatch/specs\";\n\n/**\n * Resolve the specs directory from options.\n * Uses `opts.cwd` joined with `DEFAULT_DIR`, or just `DEFAULT_DIR`\n * relative to `process.cwd()`.\n */\nfunction resolveDir(opts?: IssueFetchOptions): string {\n const cwd = opts?.cwd ?? process.cwd();\n return join(cwd, DEFAULT_DIR);\n}\n\n/**\n * Normalize an issue ID to a `.md` filename and resolve its full path.\n * - Absolute paths → returned as-is\n * - Relative paths (contain `/`, `\\`, or start with `./` / `../`) → resolved\n * relative to `opts.cwd` (or `process.cwd()`)\n * - Plain filenames → joined with the specs directory (existing behavior)\n */\nfunction resolveFilePath(issueId: string, opts?: IssueFetchOptions): string {\n const filename = issueId.endsWith(\".md\") ? issueId : `${issueId}.md`;\n if (isAbsolute(filename)) return filename;\n if (/[/\\\\]/.test(filename)) {\n const cwd = opts?.cwd ?? process.cwd();\n return resolve(cwd, filename);\n }\n return join(resolveDir(opts), filename);\n}\n\n/**\n * Resolve a potentially numeric issue ID to its full file path.\n * If `issueId` is purely numeric (e.g. \"1\"), scans the specs directory for\n * a file matching `{id}-*.md` and returns its path. Falls back to the\n * standard `resolveFilePath` when no match is found or the ID is not numeric.\n */\nasync function resolveNumericFilePath(issueId: string, opts?: IssueFetchOptions): Promise<string> {\n if (/^\\d+$/.test(issueId)) {\n const dir = resolveDir(opts);\n const entries = await readdir(dir);\n const match = entries.find((f) => f.startsWith(`${issueId}-`) && f.endsWith(\".md\"));\n if (match) {\n return join(dir, match);\n }\n }\n return resolveFilePath(issueId, opts);\n}\n\n/**\n * Extract a title from markdown content.\n * Looks for the first `# Heading` line; if not found, derives a title from the\n * first meaningful line of content (stripping markdown formatting and truncating\n * to ~80 characters at a word boundary). Falls back to the filename when the\n * content has no usable text.\n */\nexport function extractTitle(content: string, filename: string): string {\n // Primary: H1 heading\n const match = content.match(/^#\\s+(.+)$/m);\n if (match) return match[1].trim();\n\n // Secondary: first meaningful content line\n const lines = content.split(\"\\n\");\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n\n // Strip leading markdown prefixes (##, -, *, >, or combinations)\n const cleaned = trimmed.replace(/^[#>*\\-]+\\s*/, \"\").trim();\n if (!cleaned) continue;\n\n // Truncate to ~80 chars at a word boundary\n if (cleaned.length <= 80) return cleaned;\n const truncated = cleaned.slice(0, 80);\n const lastSpace = truncated.lastIndexOf(\" \");\n return lastSpace > 0 ? truncated.slice(0, lastSpace) : truncated;\n }\n\n // Fallback: filename without extension\n return parsePath(filename).name;\n}\n\n/**\n * Build an `IssueDetails` object from a markdown file's content and filename.\n */\nfunction toIssueDetails(filename: string, content: string, dir: string): IssueDetails {\n const idMatch = /^(\\d+)-/.exec(filename);\n return {\n number: idMatch ? idMatch[1] : filename,\n title: extractTitle(content, filename),\n body: content,\n labels: [],\n state: \"open\",\n url: join(dir, filename),\n comments: [],\n acceptanceCriteria: \"\",\n };\n}\n\nexport const datasource: Datasource = {\n name: \"md\",\n\n supportsGit(): boolean {\n return true;\n },\n\n async list(opts?: IssueFetchOptions): Promise<IssueDetails[]> {\n if (opts?.pattern) {\n const cwd = opts.cwd ?? process.cwd();\n const files = await glob(opts.pattern, { cwd, absolute: true });\n const mdFiles = files.filter((f) => f.endsWith(\".md\")).sort();\n const results: IssueDetails[] = [];\n\n for (const filePath of mdFiles) {\n const content = await readFile(filePath, \"utf-8\");\n const filename = basename(filePath);\n const dir = dirname(filePath);\n results.push(toIssueDetails(filename, content, dir));\n }\n\n return results;\n }\n\n const dir = resolveDir(opts);\n let entries: string[];\n try {\n entries = await readdir(dir);\n } catch {\n return [];\n }\n\n const mdFiles = entries.filter((f) => f.endsWith(\".md\")).sort();\n const results: IssueDetails[] = [];\n\n for (const filename of mdFiles) {\n const filePath = join(dir, filename);\n const content = await readFile(filePath, \"utf-8\");\n results.push(toIssueDetails(filename, content, dir));\n }\n\n return results;\n },\n\n async fetch(issueId: string, opts?: IssueFetchOptions): Promise<IssueDetails> {\n if (/^\\d+$/.test(issueId)) {\n const dir = resolveDir(opts);\n const entries = await readdir(dir);\n const match = entries.find((f) => f.startsWith(`${issueId}-`) && f.endsWith(\".md\"));\n if (match) {\n const content = await readFile(join(dir, match), \"utf-8\");\n return toIssueDetails(match, content, dir);\n }\n }\n const filePath = resolveFilePath(issueId, opts);\n const content = await readFile(filePath, \"utf-8\");\n const filename = basename(filePath);\n const dir = dirname(filePath);\n return toIssueDetails(filename, content, dir);\n },\n\n async update(issueId: string, _title: string, body: string, opts?: IssueFetchOptions): Promise<void> {\n const filePath = await resolveNumericFilePath(issueId, opts);\n await writeFile(filePath, body, \"utf-8\");\n },\n\n async close(issueId: string, opts?: IssueFetchOptions): Promise<void> {\n const filePath = await resolveNumericFilePath(issueId, opts);\n const filename = basename(filePath);\n const archiveDir = join(dirname(filePath), \"archive\");\n await mkdir(archiveDir, { recursive: true });\n await rename(filePath, join(archiveDir, filename));\n },\n\n async create(title: string, body: string, opts?: IssueFetchOptions): Promise<IssueDetails> {\n return withCreateLock(async () => {\n const cwd = opts?.cwd ?? process.cwd();\n const configDir = join(cwd, \".dispatch\");\n const config = await loadConfig(configDir);\n const id = config.nextIssueId ?? 1;\n\n const dir = resolveDir(opts);\n await mkdir(dir, { recursive: true });\n const filename = `${id}-${slugify(title)}.md`;\n const filePath = join(dir, filename);\n await writeFile(filePath, body, \"utf-8\");\n\n config.nextIssueId = id + 1;\n await saveConfig(config, configDir);\n\n return {\n ...toIssueDetails(filename, body, dir),\n number: String(id),\n };\n });\n },\n\n async getDefaultBranch(opts: DispatchLifecycleOptions): Promise<string> {\n const PREFIX = \"refs/remotes/origin/\";\n try {\n const ref = await git([\"symbolic-ref\", \"refs/remotes/origin/HEAD\"], opts.cwd);\n const trimmed = ref.trim();\n const branch = trimmed.startsWith(PREFIX)\n ? trimmed.slice(PREFIX.length)\n : trimmed;\n if (!isValidBranchName(branch)) {\n throw new InvalidBranchNameError(branch, \"from symbolic-ref output\");\n }\n return branch;\n } catch (err) {\n if (err instanceof InvalidBranchNameError) {\n throw err;\n }\n try {\n await git([\"rev-parse\", \"--verify\", \"main\"], opts.cwd);\n return \"main\";\n } catch {\n return \"master\";\n }\n }\n },\n\n async getCurrentBranch(opts: DispatchLifecycleOptions): Promise<string> {\n try {\n const { stdout } = await exec(\"git\", [\"rev-parse\", \"--abbrev-ref\", \"HEAD\"], {\n cwd: opts.cwd,\n shell: process.platform === \"win32\",\n });\n const branch = stdout.trim();\n if (branch && branch !== \"HEAD\") return branch;\n } catch { /* fall through */ }\n return this.getDefaultBranch(opts);\n },\n\n async getUsername(opts: DispatchLifecycleOptions): Promise<string> {\n if (opts.username) return opts.username;\n return deriveShortUsername(opts.cwd, \"local\");\n },\n\n buildBranchName(issueNumber: string, _title: string, username: string): string {\n // When issueNumber is a file path, extract a clean identifier from the filename\n if (issueNumber.includes(\"/\") || issueNumber.includes(\"\\\\\")) {\n // Normalize backslashes so basename() works correctly on POSIX\n const normalized = issueNumber.replaceAll(\"\\\\\", \"/\");\n const filename = basename(normalized);\n const idMatch = /^(\\d+)-(.+)\\.md$/.exec(filename);\n if (idMatch) {\n return `${username}/dispatch/issue-${idMatch[1]}`;\n }\n // Fallback: use slugified basename without extension\n const nameWithoutExt = parsePath(filename).name;\n const slugifiedName = slugify(nameWithoutExt, 50);\n return `${username}/dispatch/file-${slugifiedName}`;\n }\n\n return `${username}/dispatch/issue-${issueNumber}`;\n },\n\n async createAndSwitchBranch(branchName: string, opts: DispatchLifecycleOptions): Promise<void> {\n try {\n await git([\"checkout\", \"-b\", branchName], opts.cwd);\n } catch (err) {\n const message = log.extractMessage(err);\n if (message.includes(\"already exists\")) {\n try {\n await git([\"checkout\", branchName], opts.cwd);\n } catch (checkoutErr) {\n const checkoutMessage = log.extractMessage(checkoutErr);\n if (checkoutMessage.includes(\"already used by worktree\")) {\n await git([\"worktree\", \"prune\"], opts.cwd);\n await git([\"checkout\", branchName], opts.cwd);\n } else {\n throw checkoutErr;\n }\n }\n } else {\n throw err;\n }\n }\n },\n\n async switchBranch(branchName: string, opts: DispatchLifecycleOptions): Promise<void> {\n await git([\"checkout\", branchName], opts.cwd);\n },\n\n async pushBranch(_branchName: string, _opts: DispatchLifecycleOptions): Promise<void> {\n // No-op: MD datasource does not push to a remote\n },\n\n async commitAllChanges(message: string, opts: DispatchLifecycleOptions): Promise<void> {\n const cwd = opts.cwd;\n await git([\"add\", \"-A\"], cwd);\n const status = await git([\"diff\", \"--cached\", \"--stat\"], cwd);\n if (!status.trim()) {\n return;\n }\n await git([\"commit\", \"-m\", message], cwd);\n },\n\n async createPullRequest(\n _branchName: string,\n _issueNumber: string,\n _title: string,\n _body: string,\n _opts: DispatchLifecycleOptions,\n _baseBranch?: string,\n ): Promise<string> {\n // No-op: MD datasource does not create pull requests\n return \"\";\n },\n};\n","/**\n * Shared slug generation utility.\n *\n * Converts an arbitrary string into a URL/filename-safe slug by lowercasing,\n * replacing non-alphanumeric runs with hyphens, stripping leading/trailing\n * hyphens, and optionally truncating to a maximum length.\n *\n * Consolidates the identical slugification pattern previously duplicated\n * across datasource and orchestrator modules.\n */\n\n/** Default max slug length for filenames. */\nexport const MAX_SLUG_LENGTH = 60;\n\n/**\n * Convert a string into a lowercase, hyphen-separated slug.\n *\n * Applies the following transformations in order:\n * 1. Lowercase the entire string\n * 2. Replace runs of non-alphanumeric characters with a single hyphen\n * 3. Strip leading and trailing hyphens\n * 4. Truncate to `maxLength` characters (if provided)\n *\n * @param input - The string to slugify\n * @param maxLength - Optional maximum length of the resulting slug\n * @returns The slugified string\n */\nexport function slugify(input: string, maxLength?: number): string {\n const slug = input\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-|-$/g, \"\");\n return maxLength != null ? slug.slice(0, maxLength) : slug;\n}\n","/**\n * Interactive configuration wizard for Dispatch.\n *\n * Walks users through provider auth setup and datasource selection.\n * Provider/model selection is handled automatically by the smart router —\n * the user just needs to authenticate the providers they want to use.\n */\n\nimport chalk from \"chalk\";\nimport { select, confirm, input, multiSelect } from \"./helpers/ink-prompts.js\";\nimport { log } from \"./helpers/logger.js\";\nimport { PALETTE } from \"./helpers/format.js\";\nimport {\n loadConfig,\n saveConfig,\n type DispatchConfig,\n type ProviderModelConfig,\n} from \"./config.js\";\nimport {\n DATASOURCE_NAMES,\n detectDatasource,\n getGitRemoteUrl,\n parseAzDevOpsRemoteUrl,\n} from \"./datasources/index.js\";\nimport type { DatasourceName } from \"./datasources/interface.js\";\nimport { ensureAuthReady } from \"./helpers/auth.js\";\nimport type { ProviderName } from \"./providers/interface.js\";\nimport { listProviderModels } from \"./providers/index.js\";\nimport { getProviderStatuses, type AuthStatus, PROVIDER_REGISTRY } from \"./providers/registry.js\";\nimport { setupProviderAuth } from \"./providers/auth-setup.js\";\n\n/** Timeout for fetching provider model lists (ms). */\nconst MODEL_LIST_TIMEOUT_MS = 8_000;\n\n/** Format auth status with a colored indicator. */\nfunction formatAuthStatus(status: AuthStatus): string {\n switch (status.status) {\n case \"authenticated\":\n return \"authenticated\";\n case \"not-configured\":\n return \"not configured\";\n case \"expired\":\n return \"expired\";\n }\n}\n\n/**\n * Run the interactive configuration wizard.\n *\n * Detects provider auth status, guides through auth setup,\n * then handles datasource selection and saves the config.\n */\nexport async function runInteractiveConfigWizard(configDir?: string): Promise<void> {\n console.log();\n log.info(\"Dispatch Setup\");\n console.log();\n\n // ── Load existing config ───────────────────────────────────\n const existing = await loadConfig(configDir);\n const hasExisting = Object.keys(existing).length > 0;\n\n if (hasExisting) {\n log.dim(\"Current configuration:\");\n for (const [key, value] of Object.entries(existing)) {\n if (value !== undefined) {\n if (key === \"enabledProviders\" && Array.isArray(value)) {\n log.dim(` ${key} = ${(value as string[]).join(\", \")}`);\n } else {\n log.dim(` ${key} = ${value}`);\n }\n }\n }\n console.log();\n\n const reconfigure = await confirm({\n message: \"Do you want to reconfigure?\",\n default: true,\n });\n\n if (!reconfigure) {\n log.dim(\"Configuration unchanged.\");\n return;\n }\n console.log();\n }\n\n // ── Provider auth detection ───────────────────────────────\n log.info(\"Detecting provider authentication status...\");\n console.log();\n\n let providerStatuses = await getProviderStatuses();\n\n // Display status table\n for (const ps of providerStatuses) {\n const tierLabel = ps.tier === \"free\" ? \"(free tier)\" : \"(API key)\";\n const statusLabel = formatAuthStatus(ps.authStatus);\n const indicator = ps.authStatus.status === \"authenticated\" ? \" ✓\" : \" ✗\";\n console.log(`${indicator} ${ps.displayName.padEnd(18)} ${statusLabel} ${tierLabel}`);\n }\n console.log();\n\n // ── Provider selection ─────────────────────────────────────\n const selectedProviders = await multiSelect<ProviderName>({\n message: \"Select providers to enable:\",\n choices: providerStatuses.map((ps) => {\n const isAuth = ps.authStatus.status === \"authenticated\";\n return {\n name: ps.displayName,\n value: ps.name,\n description: isAuth ? \"authenticated\" : \"not yet authenticated\",\n default: isAuth,\n };\n }),\n });\n\n if (selectedProviders.length === 0) {\n log.error(\"At least one provider must be enabled to use Dispatch.\");\n log.dim(\"Re-run 'dispatch config' to enable providers.\");\n return;\n }\n\n // ── Auth setup for selected-but-unauthenticated providers ──\n const needsAuth = selectedProviders.filter((name) => {\n const ps = providerStatuses.find((p) => p.name === name);\n return ps && ps.authStatus.status !== \"authenticated\";\n });\n\n if (needsAuth.length > 0) {\n console.log();\n for (const name of needsAuth) {\n console.log();\n await setupProviderAuth(name);\n console.log();\n }\n\n // Re-check status after setup\n providerStatuses = await getProviderStatuses();\n }\n\n // Final enabled list = selected providers that are now authenticated\n const enabledProviders = selectedProviders.filter((name) => {\n const ps = providerStatuses.find((p) => p.name === name);\n return ps && ps.authStatus.status === \"authenticated\";\n });\n\n if (enabledProviders.length === 0) {\n log.error(\"At least one provider must be authenticated to use Dispatch.\");\n log.dim(\"Re-run 'dispatch config' after setting up provider credentials.\");\n return;\n }\n\n // Show final status\n console.log();\n log.info(\"Provider status:\");\n for (const ps of providerStatuses) {\n const isEnabled = enabledProviders.includes(ps.name);\n const indicator = isEnabled ? \"✓\" : \"✗\";\n console.log(` ${indicator} ${ps.displayName}`);\n }\n console.log();\n\n log.info(\n `${enabledProviders.length} provider(s) enabled. ` +\n `Dispatch will automatically route tasks to the best available provider.`,\n );\n console.log();\n\n // ── Per-provider model selection (opt-in) ─────────────────\n const providerModels: Partial<Record<ProviderName, ProviderModelConfig>> =\n existing.providerModels ? { ...existing.providerModels } : {};\n\n const configureModels = await confirm({\n message: `Configure model selection for ${enabledProviders.length} provider(s)?`,\n default: false,\n });\n\n if (configureModels) {\n for (const name of enabledProviders) {\n const meta = PROVIDER_REGISTRY[name];\n const existingOverride = providerModels[name];\n console.clear();\n log.info(`${meta.displayName} models:`);\n\n // Fetch available models with timeout\n let models: string[];\n let timeoutId: ReturnType<typeof setTimeout> | undefined;\n try {\n log.dim(` Fetching available models...`);\n models = await Promise.race([\n listProviderModels(name),\n new Promise<string[]>((_, reject) => {\n timeoutId = setTimeout(() => reject(new Error(\"timeout\")), MODEL_LIST_TIMEOUT_MS);\n }),\n ]);\n } catch {\n log.warn(` Could not fetch model list — showing defaults only`);\n models = [meta.defaultStrongModel, meta.defaultFastModel];\n } finally {\n clearTimeout(timeoutId);\n }\n\n // Deduplicate and ensure defaults are in the list\n const modelSet = new Set(models);\n modelSet.add(meta.defaultStrongModel);\n modelSet.add(meta.defaultFastModel);\n const allModels = [...modelSet].sort();\n\n // Strong model selection\n console.clear();\n console.log();\n console.log(chalk.hex(PALETTE.brand).bold(\" ⚡ Dispatch — Model Configuration\"));\n console.log();\n const strongDefault = existingOverride?.strong ?? meta.defaultStrongModel;\n const strongChoice = await select<string | undefined>({\n message: `${meta.displayName} ── Strong model (executor, spec)`,\n choices: [\n { name: `(default) ${meta.defaultStrongModel}`, value: undefined },\n ...allModels.map((m) => ({ name: m, value: m })),\n ],\n default: strongDefault === meta.defaultStrongModel ? undefined : strongDefault,\n });\n\n // Fast model selection\n console.clear();\n console.log();\n console.log(chalk.hex(PALETTE.brand).bold(\" ⚡ Dispatch — Model Configuration\"));\n console.log();\n const fastDefault = existingOverride?.fast ?? meta.defaultFastModel;\n const fastChoice = await select<string | undefined>({\n message: `${meta.displayName} ── Fast model (planner, commit)`,\n choices: [\n { name: `(default) ${meta.defaultFastModel}`, value: undefined },\n ...allModels.map((m) => ({ name: m, value: m })),\n ],\n default: fastDefault === meta.defaultFastModel ? undefined : fastDefault,\n });\n\n // Save overrides (omit if user chose default)\n const entry: ProviderModelConfig = {};\n if (strongChoice !== undefined) entry.strong = strongChoice;\n if (fastChoice !== undefined) entry.fast = fastChoice;\n if (entry.strong !== undefined || entry.fast !== undefined) {\n providerModels[name] = entry;\n } else {\n delete providerModels[name];\n }\n }\n }\n console.log();\n\n // ── Auto-detect datasource from git remote ─────────────────\n const detectedSource = await detectDatasource(process.cwd());\n const datasourceDefault: DatasourceName | \"auto\" = existing.source ?? \"auto\";\n if (detectedSource) {\n log.info(`Detected datasource ${detectedSource} from git remote`);\n }\n\n // ── Datasource selection ───────────────────────────────────\n const selectedSource = await select<DatasourceName | \"auto\">({\n message: \"Select a datasource:\",\n choices: [\n {\n name: \"auto\",\n value: \"auto\" as const,\n description: \"detect from git remote at runtime\",\n },\n ...DATASOURCE_NAMES.map((name) => ({ name, value: name })),\n ],\n default: datasourceDefault,\n });\n const source: DatasourceName | undefined =\n selectedSource === \"auto\" ? undefined : selectedSource;\n\n // ── Azure DevOps-specific fields ───────────────────────────\n let org: string | undefined;\n let project: string | undefined;\n let workItemType: string | undefined;\n let iteration: string | undefined;\n let area: string | undefined;\n\n const effectiveSource = source ?? detectedSource;\n if (effectiveSource === \"azdevops\") {\n // Try to pre-fill org and project from git remote\n let defaultOrg = existing.org ?? \"\";\n let defaultProject = existing.project ?? \"\";\n try {\n const remoteUrl = await getGitRemoteUrl(process.cwd());\n if (remoteUrl) {\n const parsed = parseAzDevOpsRemoteUrl(remoteUrl);\n if (parsed) {\n if (!defaultOrg) defaultOrg = parsed.orgUrl;\n if (!defaultProject) defaultProject = parsed.project;\n }\n }\n } catch {\n // ignore — pre-fill is best-effort\n }\n\n console.log();\n log.info(\"Azure DevOps settings (leave empty to skip):\");\n\n const orgInput = await input({\n message: \"Organization URL:\",\n default: defaultOrg || undefined,\n });\n if (orgInput.trim()) org = orgInput.trim();\n\n const projectInput = await input({\n message: \"Project name:\",\n default: defaultProject || undefined,\n });\n if (projectInput.trim()) project = projectInput.trim();\n\n const workItemTypeInput = await input({\n message: \"Work item type (e.g. User Story, Bug):\",\n default: existing.workItemType ?? undefined,\n });\n if (workItemTypeInput.trim()) workItemType = workItemTypeInput.trim();\n\n const iterationInput = await input({\n message: \"Iteration path (e.g. MyProject\\\\Sprint 1, or @CurrentIteration):\",\n default: existing.iteration ?? undefined,\n });\n if (iterationInput.trim()) iteration = iterationInput.trim();\n\n const areaInput = await input({\n message: \"Area path (e.g. MyProject\\\\Team A):\",\n default: existing.area ?? undefined,\n });\n if (areaInput.trim()) area = areaInput.trim();\n }\n\n // ── Authenticate tracker-backed datasource ────────────────\n try {\n await ensureAuthReady(effectiveSource ?? undefined, process.cwd(), org);\n } catch (err) {\n log.warn(`Authentication failed: ${err instanceof Error ? err.message : String(err)}`);\n log.warn(\"You can re-run 'dispatch config' or authenticate later at runtime.\");\n }\n\n // ── Build new config ──────────────────────────────────────\n const existingConfig = await loadConfig(configDir);\n const newConfig: DispatchConfig = {\n ...existingConfig,\n enabledProviders,\n source,\n };\n\n // Save provider model overrides (or clear if empty)\n if (Object.keys(providerModels).length > 0) {\n newConfig.providerModels = providerModels;\n } else {\n delete newConfig.providerModels;\n }\n\n if (org !== undefined) newConfig.org = org;\n if (project !== undefined) newConfig.project = project;\n if (workItemType !== undefined) newConfig.workItemType = workItemType;\n if (iteration !== undefined) newConfig.iteration = iteration;\n if (area !== undefined) newConfig.area = area;\n\n // ── Summary ────────────────────────────────────────────────\n console.log();\n log.info(\"Configuration summary:\");\n for (const [key, value] of Object.entries(newConfig)) {\n if (value !== undefined) {\n if (key === \"enabledProviders\" && Array.isArray(value)) {\n console.log(` ${key} = ${(value as string[]).join(\", \")}`);\n } else if (key === \"providerModels\" && typeof value === \"object\") {\n for (const [provider, models] of Object.entries(value as Record<string, ProviderModelConfig>)) {\n const parts: string[] = [];\n if (models.strong) parts.push(`strong=${models.strong}`);\n if (models.fast) parts.push(`fast=${models.fast}`);\n if (parts.length) console.log(` ${provider} models = ${parts.join(\", \")}`);\n }\n } else {\n console.log(` ${key} = ${value}`);\n }\n }\n }\n if (selectedSource === \"auto\") {\n console.log(` source = auto (detect from git remote at runtime)`);\n }\n console.log();\n\n // ── Confirm and save ───────────────────────────────────────\n const shouldSave = await confirm({\n message: \"Save this configuration?\",\n default: true,\n });\n\n if (shouldSave) {\n await saveConfig(newConfig, configDir);\n log.success(\"Configuration saved.\");\n } else {\n log.dim(\"Configuration not saved.\");\n }\n}\n","/**\n * Interactive auth setup per provider — walks users through configuring\n * credentials for each AI provider during `dispatch config`.\n *\n * Every provider offers two standardized auth methods:\n * - OAuth / CLI login (device flow or browser-based)\n * - API key / environment variable\n */\n\nimport { spawn } from \"node:child_process\";\nimport { select } from \"../helpers/ink-prompts.js\";\nimport { log } from \"../helpers/logger.js\";\nimport type { ProviderName } from \"./interface.js\";\nimport { PROVIDER_REGISTRY } from \"./registry.js\";\n\n/** Timeout for spawned auth commands. */\nconst AUTH_CMD_TIMEOUT_MS = 120_000;\n\n/**\n * Run the interactive auth setup for a single provider.\n * Returns true if auth was successfully configured.\n */\nexport async function setupProviderAuth(name: ProviderName): Promise<boolean> {\n switch (name) {\n case \"copilot\":\n return setupCopilotAuth();\n case \"claude\":\n return setupClaudeAuth();\n case \"codex\":\n return setupCodexAuth();\n case \"opencode\":\n return setupOpencodeAuth();\n default: {\n const _exhaustive: never = name;\n log.warn(`No auth setup for provider \"${_exhaustive}\"`);\n return false;\n }\n }\n}\n\n/**\n * Spawn a CLI auth command with inherited stdio and verify auth afterwards.\n * Returns true if auth was successfully configured.\n */\nasync function runCliLogin(\n provider: ProviderName,\n label: string,\n cmd: string,\n args: string[],\n): Promise<boolean> {\n try {\n log.info(`Running '${label}'...`);\n await new Promise<void>((resolve, reject) => {\n const child = spawn(cmd, args, {\n stdio: \"inherit\",\n timeout: AUTH_CMD_TIMEOUT_MS,\n });\n child.on(\"close\", (code) =>\n code === 0 ? resolve() : reject(new Error(`${label} exited with code ${code}`)),\n );\n child.on(\"error\", reject);\n });\n return await verifyAuth(provider);\n } catch (err) {\n log.warn(`${PROVIDER_REGISTRY[provider].displayName} CLI auth failed: ${err instanceof Error ? err.message : String(err)}`);\n return false;\n }\n}\n\n/** Print env-var setup instructions and return false (user must restart). */\nfunction printEnvVarInstructions(lines: string[]): false {\n for (const line of lines) log.info(line);\n console.log();\n log.dim(\"After setting the variable, restart your terminal and re-run 'dispatch config'.\");\n return false;\n}\n\nasync function setupCopilotAuth(): Promise<boolean> {\n log.info(\"GitHub Copilot Authentication\");\n console.log();\n\n const method = await select({\n message: \"How would you like to authenticate?\",\n choices: [\n { name: \"Copilot CLI login\", value: \"cli-login\" as const, description: \"Run 'copilot login' — device code flow\" },\n { name: \"API key (environment variable)\", value: \"env-var\" as const, description: \"Set GITHUB_TOKEN or GH_TOKEN manually\" },\n ],\n });\n\n if (method === \"cli-login\") {\n return runCliLogin(\"copilot\", \"copilot login\", \"copilot\", [\"login\"]);\n }\n\n return printEnvVarInstructions([\n \"Set one of these environment variables in your shell profile:\",\n \" GITHUB_TOKEN=<your token>\",\n \" GH_TOKEN=<your token>\",\n ]);\n}\n\nasync function setupClaudeAuth(): Promise<boolean> {\n log.info(\"Claude Code Authentication\");\n console.log();\n\n const method = await select({\n message: \"How would you like to authenticate?\",\n choices: [\n { name: \"Claude CLI login\", value: \"cli-login\" as const, description: \"Run 'claude auth login' — opens a browser\" },\n { name: \"API key (environment variable)\", value: \"env-var\" as const, description: \"Set ANTHROPIC_API_KEY manually\" },\n ],\n });\n\n if (method === \"cli-login\") {\n return runCliLogin(\"claude\", \"claude auth login\", \"claude\", [\"auth\", \"login\"]);\n }\n\n return printEnvVarInstructions([\n \"Set the following environment variable in your shell profile:\",\n \" ANTHROPIC_API_KEY=<your API key>\",\n ]);\n}\n\nasync function setupCodexAuth(): Promise<boolean> {\n log.info(\"OpenAI Codex Authentication\");\n console.log();\n\n const method = await select({\n message: \"How would you like to authenticate?\",\n choices: [\n { name: \"ChatGPT sign-in\", value: \"cli-login\" as const, description: \"Run 'codex login --device-auth' — device code flow\" },\n { name: \"API key (environment variable)\", value: \"env-var\" as const, description: \"Set OPENAI_API_KEY manually\" },\n ],\n });\n\n if (method === \"cli-login\") {\n return runCliLogin(\"codex\", \"codex login --device-auth\", \"codex\", [\"login\", \"--device-auth\"]);\n }\n\n return printEnvVarInstructions([\n \"Set the following environment variable in your shell profile:\",\n \" OPENAI_API_KEY=<your API key>\",\n ]);\n}\n\nasync function setupOpencodeAuth(): Promise<boolean> {\n log.info(\"OpenCode Authentication\");\n console.log();\n\n const method = await select({\n message: \"How would you like to authenticate?\",\n choices: [\n { name: \"OpenCode CLI login\", value: \"cli-login\" as const, description: \"Run 'opencode auth login' interactively\" },\n { name: \"API key (environment variable)\", value: \"env-var\" as const, description: \"Set provider API keys manually\" },\n ],\n });\n\n if (method === \"cli-login\") {\n return runCliLogin(\"opencode\", \"opencode auth login\", \"opencode\", [\"auth\", \"login\"]);\n }\n\n return printEnvVarInstructions([\n \"Set the relevant API key environment variable in your shell profile.\",\n \"For example:\",\n \" ANTHROPIC_API_KEY=<your API key>\",\n \" OPENAI_API_KEY=<your API key>\",\n ]);\n}\n\n/**\n * Verify that auth is working for a provider after setup.\n */\nasync function verifyAuth(name: ProviderName): Promise<boolean> {\n const meta = PROVIDER_REGISTRY[name];\n const status = await meta.checkAuth();\n if (status.status === \"authenticated\") {\n log.success(`${meta.displayName} authentication verified.`);\n return true;\n }\n log.warn(`${meta.displayName} authentication could not be verified: ${status.hint}`);\n return false;\n}\n","/**\n * Spec generator — fetches issue details from a configured datasource\n * (GitHub, Azure DevOps, or local markdown files), sends them to the AI\n * provider along with instructions to explore the codebase and research\n * the approach, then writes high-level markdown spec files.\n *\n * Pipeline:\n * 1. Resolve the datasource (explicit or auto-detected)\n * 2. Fetch issue/file details via the datasource\n * 3. Boot the AI provider\n * 4. For each item, tell the AI the target filepath and prompt it\n * to explore the codebase and write the spec directly to disk\n * 5. Verify the spec file was written\n * 6. Push spec content back to the datasource via update()\n *\n * The generated specs stay high-level (WHAT, WHY, HOW) because the\n * planner in the dispatch pipeline handles detailed, line-level\n * implementation planning for each individual task.\n */\n\nimport { cpus, freemem } from \"node:os\";\nimport type { DatasourceName } from \"./datasources/interface.js\";\nimport { getDatasource, detectDatasource, DATASOURCE_NAMES } from \"./datasources/index.js\";\nimport type { ProviderModelConfig } from \"./config.js\";\nimport type { ProviderName } from \"./providers/interface.js\";\nimport { log } from \"./helpers/logger.js\";\n\n/** Estimated memory (in MB) required per concurrent spec-generation task. */\nexport const MB_PER_CONCURRENT_TASK = 500;\n\n/** Default spec-generation timeout in minutes when not specified by the user. */\nexport const DEFAULT_SPEC_TIMEOUT_MIN = 10;\n\n/** Default spec-generation warn-phase duration in minutes (AI receives a \"wrap up\" message). */\nexport const DEFAULT_SPEC_WARN_MIN = 10;\n\n/** Default spec-generation kill-phase duration in minutes (hard termination after warn). */\nexport const DEFAULT_SPEC_KILL_MIN = 10;\n\n/** Recognized H2 section headings used to detect spec structure boundaries. */\nexport const RECOGNIZED_H2 = new Set([\n \"## Context\",\n \"## Why\",\n \"## Approach\",\n \"## Integration Points\",\n \"## Tasks\",\n \"## References\",\n \"## Key Guidelines\",\n]);\n\n/** Progress event emitted by the spec pipeline for MCP monitoring. */\nexport type SpecProgressEvent =\n | { type: \"item_start\"; runId?: string; itemId: string; itemTitle?: string }\n | { type: \"item_done\"; runId?: string; itemId: string; itemTitle?: string }\n | { type: \"item_failed\"; runId?: string; itemId: string; itemTitle?: string; error: string }\n | { type: \"log\"; runId?: string; message: string };\n\nexport interface SpecOptions {\n /** Comma-separated issue numbers, glob pattern(s), or \"list\" to use datasource.list() */\n issues: string | string[];\n /** Explicit datasource override (auto-detected if omitted) */\n issueSource?: DatasourceName;\n /** Force a specific provider for all roles (CLI --provider override). */\n provider?: ProviderName;\n /** Authenticated providers from config — router uses these for auto-selection. */\n enabledProviders?: ProviderName[];\n /** Per-provider model overrides from config. */\n providerModels?: Partial<Record<ProviderName, ProviderModelConfig>>;\n /** URL of a running provider server */\n serverUrl?: string;\n /** Working directory */\n cwd: string;\n /** Output directory for spec files (default: .dispatch/specs) */\n outputDir?: string;\n /** Azure DevOps organization URL */\n org?: string;\n /** Azure DevOps project name */\n project?: string;\n /** Azure DevOps work item type (e.g. \"User Story\", \"Product Backlog Item\") */\n workItemType?: string;\n /** Azure DevOps iteration path filter (e.g. \"MyProject\\\\Sprint 1\" or \"@CurrentIteration\") */\n iteration?: string;\n /** Azure DevOps area path filter (e.g. \"MyProject\\\\Team A\") */\n area?: string;\n /** Max parallel fetches/generations (default: min(cpuCount, freeMB/500)) */\n concurrency?: number;\n /** When true, log a preview of what would be generated without booting the provider or writing files. */\n dryRun?: boolean;\n /** Number of retry attempts for spec generation (default: 3) */\n retries?: number;\n /** Spec generation timeout in minutes (default: 10) */\n specTimeout?: number;\n /** Warn-phase timeout in minutes — AI receives a \"wrap up\" message after this duration (default: 10) */\n specWarnTimeout?: number;\n /** Kill-phase timeout in minutes — hard termination after the warn phase expires (default: 10) */\n specKillTimeout?: number;\n /** Optional callback for MCP progress notifications. */\n progressCallback?: (event: SpecProgressEvent) => void;\n}\n\n/**\n * Returns a safe default concurrency: min(cpuCount, freeMB/500), at least 1.\n *\n * Each concurrent provider process (provider runtime) is estimated to consume\n * roughly 500 MB of resident memory. The formula caps parallelism at the\n * lesser of the available CPU count and the number of 500 MB slots that fit\n * in current free memory, ensuring the host is not over-committed. The\n * result is floored to at least 1 so that the pipeline always makes progress.\n *\n * Users can override this computed value via the `--concurrency` CLI flag\n * or the `concurrency` key in `.dispatch/config.json`.\n */\nexport function defaultConcurrency(): number {\n return Math.max(1, Math.min(cpus().length, Math.floor(freemem() / 1024 / 1024 / MB_PER_CONCURRENT_TASK)));\n}\n\n/**\n * Returns `true` when the input string consists solely of comma-separated\n * issue numbers (digits, commas, and optional whitespace). Anything else\n * — paths, globs, filenames — returns `false`.\n *\n * This is the branching point for the two spec-generation code paths:\n * issue-tracker mode vs. local-file/glob mode.\n */\nexport function isIssueNumbers(input: string | string[]): input is string {\n if (Array.isArray(input)) return false;\n return /^\\d+(,\\s*\\d+)*$/.test(input);\n}\n\n/**\n * Returns `true` when the input looks like a glob pattern or file path\n * rather than free-form inline text.\n *\n * Checks for:\n * - Glob metacharacters: `*`, `?`, `[`, `{`\n * - Path separators: `/`, `\\`\n * - Dot-prefix relative paths: `./`, `../`\n * - Common file extensions: `.md`, `.txt`, `.yaml`, `.yml`, `.json`, `.ts`,\n * `.js`, `.tsx`, `.jsx`\n *\n * This is a pure function intended to be called *after* `isIssueNumbers()`\n * has already returned `false`, providing the second level of input\n * discrimination for the spec pipeline.\n */\nexport function isGlobOrFilePath(input: string | string[]): boolean {\n if (Array.isArray(input)) return true;\n // Glob metacharacters\n if (/[*?\\[{]/.test(input)) return true;\n\n // Path separators (forward slash or backslash)\n if (/[/\\\\]/.test(input)) return true;\n\n // Dot-prefix relative paths (./something, ../something, .\\something, ..\\something)\n if (/^\\.\\.?[\\/\\\\]/.test(input)) return true;\n\n // Common file extensions at end of string\n if (/\\.(md|txt|yaml|yml|json|ts|js|tsx|jsx)$/i.test(input)) return true;\n\n return false;\n}\n\n/**\n * Post-process raw spec file content written by the AI.\n *\n * Strips code-fence wrapping, preamble text before the first H1 heading,\n * and postamble text after the last recognized spec section. Returns the\n * content unchanged when no recognizable spec structure is found.\n *\n * Pure function — no I/O, no side-effects.\n */\nexport function extractSpecContent(raw: string): string {\n let content = raw;\n\n // 1. Strip code-fence wrapping (``` or ```markdown around entire content)\n // The fence may wrap the entire input or may appear after preamble text,\n // so we search for a fenced block containing an H1 heading.\n const fenceMatch = content.match(/^\\s*```(?:markdown)?\\s*\\n([\\s\\S]*?)\\n\\s*```\\s*$/);\n if (fenceMatch) {\n content = fenceMatch[1];\n } else {\n // Try to find a fenced block that contains an H1, even with surrounding text\n const innerFenceMatch = content.match(/```(?:markdown)?\\s*\\n([\\s\\S]*?)\\n\\s*```/);\n if (innerFenceMatch && /^# /m.test(innerFenceMatch[1])) {\n content = innerFenceMatch[1];\n }\n }\n\n // 2. Remove preamble — everything before the first H1 heading\n const h1Index = content.search(/^# /m);\n if (h1Index === -1) {\n // No H1 found — return original content unchanged\n return raw;\n }\n content = content.slice(h1Index);\n\n // 3. Remove postamble — trim after the last recognized H2 section's content\n const lines = content.split(\"\\n\");\n let lastRecognizedSectionEnd = lines.length;\n\n // Walk backwards to find the last recognized H2 and its content extent\n let foundLastRecognized = false;\n for (let i = lines.length - 1; i >= 0; i--) {\n const trimmed = lines[i].trimEnd();\n if (trimmed.startsWith(\"## \")) {\n if (RECOGNIZED_H2.has(trimmed)) {\n // This is the last recognized H2 — everything up to end is the section content\n foundLastRecognized = true;\n break;\n } else {\n // Unrecognized H2 — this and everything after it is postamble\n lastRecognizedSectionEnd = i;\n }\n }\n }\n\n if (foundLastRecognized || lastRecognizedSectionEnd < lines.length) {\n // Trim trailing blank lines from the kept portion\n let end = lastRecognizedSectionEnd;\n while (end > 0 && lines[end - 1].trim() === \"\") {\n end--;\n }\n content = lines.slice(0, end).join(\"\\n\");\n }\n\n // Ensure trailing newline\n if (!content.endsWith(\"\\n\")) {\n content += \"\\n\";\n }\n\n return content;\n}\n\nexport type ValidationResult =\n | { valid: true }\n | { valid: false; reason: string };\n\n/**\n * Validate that spec content has the expected structural markers.\n *\n * Checks:\n * 1. Content starts with an H1 heading (`# `)\n * 2. Contains a `## Tasks` section with at least one `- [ ]` checkbox\n *\n * This is a guardrail, not a gate — validation failures are warned but\n * do not block the pipeline. Returns a structured result so callers can\n * act on it.\n */\nexport function validateSpecStructure(content: string): ValidationResult {\n const trimmed = content.trimStart();\n\n // Check 1: Must start with an H1 heading\n if (!trimmed.startsWith(\"# \")) {\n const reason = \"Spec does not start with an H1 heading (expected \\\"# \\\")\";\n log.warn(reason);\n return { valid: false, reason };\n }\n\n // Check 2: Must contain a ## Tasks section\n const tasksIndex = content.search(/^## Tasks\\s*$/m);\n if (tasksIndex === -1) {\n const reason = \"Spec is missing a \\\"## Tasks\\\" section\";\n log.warn(reason);\n return { valid: false, reason };\n }\n\n // Check 3: Must have at least one checkbox after ## Tasks\n const afterTasks = content.slice(tasksIndex);\n if (!/- \\[ \\]/.test(afterTasks)) {\n const reason = \"\\\"## Tasks\\\" section contains no unchecked tasks (expected at least one \\\"- [ ]\\\")\";\n log.warn(reason);\n return { valid: false, reason };\n }\n\n return { valid: true };\n}\n\n/**\n * Resolve the datasource name for a spec-generation run.\n *\n * Priority:\n * 1. Explicit `issueSource` (from --source flag or config) — always wins.\n * 2. Auto-detect from the git remote URL.\n * 3. For glob/file inputs, fall back to `\"md\"` when auto-detection fails.\n * 4. For issue-number inputs, return `null` when auto-detection fails (caller should abort).\n */\nexport async function resolveSource(\n issues: string | string[],\n issueSource: DatasourceName | undefined,\n cwd: string\n): Promise<DatasourceName | null> {\n if (issueSource) {\n return issueSource;\n }\n log.info(\"Detecting datasource from git remote...\");\n const detected = await detectDatasource(cwd);\n if (detected) {\n log.info(`Detected datasource: ${detected}`);\n return detected;\n }\n if (!isIssueNumbers(issues)) {\n return \"md\";\n }\n log.error(\n `Could not detect datasource from the repository remote URL.\\n` +\n ` Supported sources: ${DATASOURCE_NAMES.join(\", \")}\\n` +\n ` Use --source <name> to specify explicitly, or ensure the git remote\\n` +\n ` points to a supported platform (github.com, dev.azure.com).`\n );\n return null;\n}\n\nexport interface SpecSummary {\n /** Total issues requested */\n total: number;\n /** Successfully generated spec files */\n generated: number;\n /** Failed to generate */\n failed: number;\n /** Paths of generated spec files */\n files: string[];\n /** Issue numbers created or updated during spec generation (empty when datasource is md) */\n issueNumbers: string[];\n /** Dispatch identifiers for the \"Run these specs with\" hint (issue numbers or file paths) */\n identifiers?: string[];\n /** Total pipeline wall-clock duration in milliseconds */\n durationMs: number;\n /** Per-file generation durations in milliseconds (filepath → ms) */\n fileDurationsMs: Record<string, number>;\n}\n","/**\n * Large-batch confirmation prompt.\n *\n * Asks the user to explicitly type \"yes\" before proceeding when a\n * spec or respec operation targets more items than the safety threshold.\n * Extracted into its own module so both the runner and spec-pipeline\n * call sites can share the logic and tests can mock it via `vi.mock()`.\n */\n\nimport { input } from \"./ink-prompts.js\";\nimport { log } from \"./logger.js\";\n\n/** Default threshold above which confirmation is required. */\nexport const LARGE_BATCH_THRESHOLD = 100;\n\n/**\n * Prompt the user to confirm a large batch operation.\n *\n * If `count` is at or below `threshold`, returns `true` immediately.\n * Otherwise, warns the user and requires them to type \"yes\" to proceed.\n *\n * @param count - Number of specs that will be processed\n * @param threshold - Minimum count that triggers the prompt (default {@link LARGE_BATCH_THRESHOLD})\n * @returns `true` if the user confirmed (or count ≤ threshold), `false` otherwise\n */\nexport async function confirmLargeBatch(\n count: number,\n threshold: number = LARGE_BATCH_THRESHOLD,\n): Promise<boolean> {\n if (count <= threshold) return true;\n\n log.warn(\n `This operation will process ${count} specs, which exceeds the safety threshold of ${threshold}.`,\n );\n\n const answer = await input({\n message: 'Type \"yes\" to proceed:',\n });\n\n return answer.trim().toLowerCase() === \"yes\";\n}\n","/**\n * Startup prerequisite checker.\n *\n * Verifies that required external tools and runtime versions are available\n * before any pipeline logic runs. Returns an array of human-readable failure\n * messages — an empty array means all checks pass.\n */\n\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\n\nconst exec = promisify(execFile);\n\n/** Minimum supported Node.js version (matches package.json engines field). */\nconst MIN_NODE_VERSION = \"20.12.0\";\n\n/**\n * Parse a semver-style version string into [major, minor, patch] numbers.\n */\nfunction parseSemver(version: string): [number, number, number] {\n const [major, minor, patch] = version.split(\".\").map(Number);\n return [major ?? 0, minor ?? 0, patch ?? 0];\n}\n\n/**\n * Return true if `current` is greater than or equal to `minimum`\n * using major.minor.patch comparison.\n */\nfunction semverGte(current: string, minimum: string): boolean {\n const [cMaj, cMin, cPat] = parseSemver(current);\n const [mMaj, mMin, mPat] = parseSemver(minimum);\n if (cMaj !== mMaj) return cMaj > mMaj;\n if (cMin !== mMin) return cMin > mMin;\n return cPat >= mPat;\n}\n\n/**\n * Verify that required external tools and runtime versions are available.\n *\n * Checks performed:\n * 1. `git` is available on PATH (via `git --version`)\n * 2. Node.js version meets the `>=20.12.0` minimum\n *\n * @returns An array of human-readable failure message strings.\n * An empty array means all checks passed.\n */\nexport async function checkPrereqs(): Promise<string[]> {\n const failures: string[] = [];\n\n // Check git availability\n try {\n await exec(\"git\", [\"--version\"], { shell: process.platform === \"win32\" });\n } catch {\n failures.push(\"git is required but was not found on PATH. Install it from https://git-scm.com\");\n }\n\n // Check Node.js version\n const nodeVersion = process.versions.node;\n if (!semverGte(nodeVersion, MIN_NODE_VERSION)) {\n failures.push(\n `Node.js >= ${MIN_NODE_VERSION} is required but found ${nodeVersion}. Please upgrade Node.js`,\n );\n }\n\n return failures;\n}\n","/**\n * Utility for ensuring entries exist in a repository's .gitignore file.\n */\n\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { log } from \"./logger.js\";\n\n/**\n * Ensure `entry` appears as a line in `<repoRoot>/.gitignore`.\n *\n * Creates the file if it doesn't exist. No-ops if the entry (with or without\n * a trailing slash) is already present. Logs a warning and continues on\n * failure — this is non-fatal so a permissions issue won't abort the run.\n *\n * @param repoRoot - Absolute path to the repository root\n * @param entry - The gitignore pattern to add (e.g. `.dispatch/worktrees/`)\n */\nexport async function ensureGitignoreEntry(repoRoot: string, entry: string): Promise<void> {\n const gitignorePath = join(repoRoot, \".gitignore\");\n\n let contents = \"\";\n try {\n contents = await readFile(gitignorePath, \"utf8\");\n } catch (err: unknown) {\n // \"code\" in err is a runtime guard that proves the property exists\n if (err instanceof Error && \"code\" in err && (err as { code?: unknown }).code === \"ENOENT\") {\n // File doesn't exist — will be created below\n } else {\n log.warn(`Could not read .gitignore: ${String(err)}`);\n return;\n }\n }\n\n const lines = contents.split(/\\r?\\n/);\n // Match with or without trailing slash to avoid adding a duplicate when\n // the user already has the bare form (e.g. `.dispatch/worktrees`) or the\n // slash form (e.g. `.dispatch/worktrees/`).\n const bare = entry.replace(/\\/$/, \"\");\n const withSlash = bare + \"/\";\n if (lines.includes(entry) || lines.includes(bare) || lines.includes(withSlash)) {\n return;\n }\n\n try {\n const separator = contents.length > 0 && !contents.endsWith(\"\\n\") ? \"\\n\" : \"\";\n await writeFile(gitignorePath, `${contents}${separator}${entry}\\n`, \"utf8\");\n log.debug(`Added '${entry}' to .gitignore`);\n } catch (err) {\n log.warn(`Could not update .gitignore: ${String(err)}`);\n }\n}\n","/**\n * Forks a dispatch-worker child process and wires:\n * - IPC messages -> DB updates (createTask, updateTaskStatus, updateRunCounters, finishRun)\n * - IPC messages -> log callback notifications\n * - Periodic heartbeat (every 30s)\n * - Cleanup on exit\n *\n * This module is transport-agnostic — it accepts a plain logCallback instead\n * of an McpServer reference, so both MCP and CLI can use it.\n */\n\nimport { fork, type ChildProcess } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { dirname, join } from \"node:path\";\nimport {\n createTask, updateTaskStatus, updateRunCounters, finishRun,\n emitLog,\n} from \"../mcp/state/manager.js\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n// When bundled by tsup, this file is inlined into dist/cli.js (__dirname = dist/).\n// The worker lives at dist/mcp/dispatch-worker.js, so try multiple possible locations.\nconst WORKER_PATH = [\n join(__dirname, \"mcp\", \"dispatch-worker.js\"), // bundled: __dirname = dist/\n join(__dirname, \"..\", \"mcp\", \"dispatch-worker.js\"), // unbundled: __dirname = dist/queue/\n join(__dirname, \"..\", \"dispatch-worker.js\"), // legacy unbundled: __dirname = dist/mcp/tools/\n].find((p) => existsSync(p)) ?? join(__dirname, \"mcp\", \"dispatch-worker.js\");\nconst HEARTBEAT_INTERVAL_MS = 30_000;\n\n/** Callback for log messages emitted during a run. */\nexport type LogCallback = (message: string, level?: \"info\" | \"warn\" | \"error\") => void;\n\nexport interface ForkRunOptions {\n /** Called when the worker sends a \"done\" message. */\n onDone?: (result: Record<string, unknown>) => void;\n /** Called when the worker process exits (after internal cleanup). */\n onExit?: (code: number | null) => void;\n /** Optional log callback wired before forking. */\n logCallback?: LogCallback;\n}\n\nexport function forkDispatchRun(\n runId: string,\n workerMessage: Record<string, unknown>,\n options?: ForkRunOptions,\n): ChildProcess {\n // 1. Verify the compiled worker exists before attempting to fork\n if (!existsSync(WORKER_PATH)) {\n throw new Error(\n `Dispatch worker not found at ${WORKER_PATH}. Run 'npm run build' to compile the project before using MCP tools.`,\n );\n }\n\n // 2. Fork worker\n const worker = fork(WORKER_PATH, [], { stdio: [\"pipe\", \"pipe\", \"pipe\", \"ipc\"] });\n worker.send(workerMessage);\n\n // 3. Heartbeat\n const heartbeat = setInterval(() => {\n emitLog(runId, `Run ${runId} still in progress...`);\n }, HEARTBEAT_INTERVAL_MS);\n\n // 4. Handle IPC messages\n worker.on(\"message\", (msg: Record<string, unknown>) => {\n const msgType = msg[\"type\"] as string;\n switch (msgType) {\n case \"progress\": {\n const event = msg[\"event\"] as Record<string, unknown>;\n const eventType = event[\"type\"] as string;\n switch (eventType) {\n case \"task_start\":\n createTask({\n runId,\n taskId: event[\"taskId\"] as string,\n taskText: event[\"taskText\"] as string,\n file: (event[\"file\"] as string) ?? (event[\"taskId\"] as string).split(\":\")[0] ?? \"\",\n line: (event[\"line\"] as number) ?? parseInt((event[\"taskId\"] as string).split(\":\")[1] ?? \"0\", 10),\n });\n updateTaskStatus(runId, event[\"taskId\"] as string, \"running\");\n emitLog(runId, `Task started: ${event[\"taskText\"] as string}`);\n break;\n case \"task_done\":\n updateTaskStatus(runId, event[\"taskId\"] as string, \"success\");\n emitLog(runId, `Task done: ${event[\"taskText\"] as string}`);\n break;\n case \"task_failed\":\n updateTaskStatus(runId, event[\"taskId\"] as string, \"failed\", { error: event[\"error\"] as string });\n emitLog(runId, `Task failed: ${event[\"taskText\"] as string} — ${event[\"error\"] as string}`, \"error\");\n break;\n case \"phase_change\":\n emitLog(runId, (event[\"message\"] as string) ?? `Phase: ${event[\"phase\"] as string}`);\n break;\n case \"log\":\n emitLog(runId, event[\"message\"] as string);\n break;\n }\n break;\n }\n case \"spec_progress\": {\n const event = msg[\"event\"] as Record<string, unknown>;\n const eventType = event[\"type\"] as string;\n switch (eventType) {\n case \"item_start\":\n emitLog(runId, `Generating spec for: ${(event[\"itemTitle\"] as string) ?? (event[\"itemId\"] as string)}`);\n break;\n case \"item_done\":\n emitLog(runId, `Spec done: ${(event[\"itemTitle\"] as string) ?? (event[\"itemId\"] as string)}`);\n break;\n case \"item_failed\":\n emitLog(runId, `Spec failed: ${(event[\"itemTitle\"] as string) ?? (event[\"itemId\"] as string)} — ${event[\"error\"] as string}`, \"error\");\n break;\n case \"log\":\n emitLog(runId, event[\"message\"] as string);\n break;\n }\n break;\n }\n case \"done\": {\n const result = msg[\"result\"] as Record<string, unknown>;\n if (options?.onDone) {\n options.onDone(result);\n } else if (\"completed\" in result) {\n // Dispatch result\n updateRunCounters(runId, result[\"total\"] as number, result[\"completed\"] as number, result[\"failed\"] as number);\n finishRun(runId, (result[\"failed\"] as number) > 0 ? \"failed\" : \"completed\");\n emitLog(runId, `Dispatch complete: ${result[\"completed\"] as number}/${result[\"total\"] as number} tasks succeeded`);\n }\n break;\n }\n case \"error\": {\n finishRun(runId, \"failed\", msg[\"message\"] as string);\n emitLog(runId, `Run error: ${msg[\"message\"] as string}`, \"error\");\n break;\n }\n }\n });\n\n // 5. Cleanup on exit\n worker.on(\"exit\", (code) => {\n clearInterval(heartbeat);\n if (code !== 0 && code !== null) {\n finishRun(runId, \"failed\", `Worker process exited with code ${code}`);\n emitLog(runId, `Worker process exited unexpectedly (code ${code})`, \"error\");\n }\n options?.onExit?.(code);\n });\n\n return worker;\n}\n","/**\n * SQLite-backed run queue.\n *\n * Gates how many child processes (dispatch runs + spec runs) can execute\n * simultaneously. The database is the source of truth: runs are inserted\n * with status \"queued\", and the RunQueue drains them into forked child\n * processes as slots become available.\n *\n * This module is transport-agnostic — both MCP and CLI can use it.\n */\n\nimport { forkDispatchRun, type ForkRunOptions, type LogCallback } from \"./fork-run.js\";\nimport {\n countActiveRuns,\n getNextQueued,\n markRunStarted,\n markSpecRunStarted,\n failAllQueuedRuns,\n emitLog,\n addLogCallback,\n} from \"../mcp/state/manager.js\";\n\n/**\n * Per-run metadata kept in memory so we can fork with the right callbacks\n * (not serializable to DB).\n */\ninterface RunContext {\n logCallback?: LogCallback;\n options?: ForkRunOptions;\n}\n\nexport class RunQueue {\n private readonly limit: number;\n /** In-memory map of runId → context needed to fork (callbacks). */\n private readonly contexts = new Map<string, RunContext>();\n\n constructor(limit: number) {\n this.limit = Math.max(1, limit);\n }\n\n /**\n * Enqueue a run for execution. The run must already exist in the DB with\n * status \"queued\" and a serialized workerMessage.\n *\n * If a slot is available the run is forked immediately; otherwise it waits\n * in the DB queue until a running child exits.\n */\n enqueue(runId: string, logCallback?: LogCallback, options?: ForkRunOptions): void {\n this.contexts.set(runId, { logCallback, options });\n // Wire the log callback into the live-run registry so emitLog() reaches it\n if (logCallback) {\n addLogCallback(runId, logCallback);\n }\n this.drain();\n }\n\n /**\n * Drain the queue: fork queued runs while slots are available.\n * Called on enqueue and whenever a child process exits.\n */\n drain(): void {\n let active = countActiveRuns();\n\n while (active < this.limit) {\n const next = getNextQueued();\n if (!next) break;\n\n const { runId, workerMessage, table } = next;\n\n // Transition to \"running\" in the DB\n if (table === \"runs\") {\n markRunStarted(runId);\n } else {\n markSpecRunStarted(runId);\n }\n\n // Deserialize the worker message\n let parsedMessage: Record<string, unknown>;\n try {\n parsedMessage = JSON.parse(workerMessage) as Record<string, unknown>;\n } catch {\n emitLog(runId, `Failed to parse queued worker message`, \"error\");\n continue;\n }\n\n // Retrieve in-memory context (callbacks)\n const ctx = this.contexts.get(runId);\n if (!ctx) {\n // This can happen if the server restarted — the DB has queued runs\n // but we lost the in-memory context. These runs were already\n // marked failed by markOrphanedRunsFailed() on startup.\n continue;\n }\n this.contexts.delete(runId);\n\n emitLog(runId, `Run started (${active + 1}/${this.limit} slots used)`);\n\n // Fork the child process\n const userOnExit = ctx.options?.onExit;\n forkDispatchRun(runId, parsedMessage, {\n ...ctx.options,\n logCallback: ctx.logCallback,\n onExit: (code) => {\n userOnExit?.(code);\n // When a child exits, try to drain the next queued run\n this.drain();\n },\n });\n\n active++;\n }\n }\n\n /** Mark all queued runs as failed (for graceful shutdown). */\n abort(): void {\n failAllQueuedRuns();\n this.contexts.clear();\n }\n\n /** Current concurrency limit. */\n get maxRuns(): number {\n return this.limit;\n }\n}\n\n// ── Singleton ────────────────────────────────────────────────\n\nlet _queue: RunQueue | null = null;\n\n/** Initialize the global RunQueue. Call once during startup. */\nexport function initRunQueue(limit: number): void {\n _queue = new RunQueue(limit);\n}\n\n/** Get the global RunQueue instance. */\nexport function getRunQueue(): RunQueue {\n if (!_queue) {\n throw new Error(\"RunQueue not initialized. Call initRunQueue(limit) first.\");\n }\n return _queue;\n}\n\n/** Reset the singleton (for testing). */\nexport function resetRunQueue(): void {\n _queue = null;\n}\n","/**\n * CLI config resolution — loads the config file, merges config defaults\n * beneath CLI flags, validates mandatory configuration, and enables\n * verbose logging.\n *\n * Extracted from the orchestrator's `runFromCli()` method to keep the\n * coordinator thin and this logic independently testable.\n */\n\nimport { join } from \"node:path\";\nimport { access } from \"node:fs/promises\";\nimport { constants } from \"node:fs\";\nimport { log } from \"../helpers/logger.js\";\nimport { loadConfig, CONFIG_KEYS, type DispatchConfig, type ConfigKey } from \"../config.js\";\nimport type { RawCliArgs } from \"./runner.js\";\nimport { detectDatasource, DATASOURCE_NAMES } from \"../datasources/index.js\";\n\n/**\n * Config key → RawCliArgs field mapping.\n *\n * Maps persistent config keys (from `{cwd}/.dispatch/config.json`) to their\n * corresponding field names on `RawCliArgs`. Used during the merge step\n * to fill in CLI flag defaults from the config file.\n */\nconst CONFIG_TO_CLI: Partial<Record<ConfigKey, keyof RawCliArgs>> = {\n enabledProviders: \"enabledProviders\",\n providerModels: \"providerModels\",\n source: \"issueSource\",\n planTimeout: \"planTimeout\",\n specTimeout: \"specTimeout\",\n specWarnTimeout: \"specWarnTimeout\",\n specKillTimeout: \"specKillTimeout\",\n concurrency: \"concurrency\",\n org: \"org\",\n project: \"project\",\n workItemType: \"workItemType\",\n iteration: \"iteration\",\n area: \"area\",\n username: \"username\",\n};\n\n/** Type-safe indexed write into a RawCliArgs object. */\nfunction setCliField<K extends keyof RawCliArgs>(\n target: RawCliArgs,\n key: K,\n value: RawCliArgs[K],\n): void {\n target[key] = value;\n}\n\n/**\n * Resolve raw CLI arguments into a fully-merged and validated options\n * object, ready for pipeline delegation.\n *\n * 1. Loads the persistent config file (`{cwd}/.dispatch/config.json`)\n * 2. Merges config defaults beneath CLI flags (CLI wins when explicit)\n * 3. Validates that providers are available (via enabledProviders or --provider)\n * 4. Auto-detects the datasource from the git remote when not explicitly set\n * — skipped for spec/respec modes, which defer source resolution to the\n * pipeline's own `resolveSource()` (context-aware fallback logic)\n * 5. Enables verbose logging if requested\n *\n * @param args - Raw CLI arguments as parsed by the CLI entry point\n * @returns The merged `RawCliArgs` with config defaults applied\n */\nexport async function resolveCliConfig(args: RawCliArgs): Promise<RawCliArgs> {\n const { explicitFlags } = args;\n\n // ── Load and merge config-file defaults beneath CLI flags ───\n const configDir = join(args.cwd, \".dispatch\");\n const config = await loadConfig(configDir);\n\n const merged = { ...args };\n for (const configKey of CONFIG_KEYS) {\n const cliField = CONFIG_TO_CLI[configKey];\n if (!cliField) continue; // config-only keys (maxRuns, orchestratorProvider) have no CLI equivalent\n const configValue = config[configKey];\n if (configValue !== undefined && !explicitFlags.has(cliField)) {\n setCliField(merged, cliField, configValue);\n }\n }\n\n // ── Provider validation ───────────────────────────────────\n // Either --provider CLI flag or enabledProviders from config must be present.\n // The router will auto-detect authenticated providers as a fallback.\n const hasProvider = explicitFlags.has(\"provider\") && merged.provider;\n const hasEnabledProviders = merged.enabledProviders && merged.enabledProviders.length > 0;\n\n if (!hasProvider && !hasEnabledProviders) {\n log.warn(\"No providers configured. The router will attempt to auto-detect authenticated providers.\");\n log.dim(\" Run 'dispatch config' to set up providers, or pass --provider <name>.\");\n }\n\n // ── Output-dir validation ─────────────────────────────────\n if (merged.outputDir) {\n try {\n await access(merged.outputDir, constants.W_OK);\n } catch {\n log.error(\n `--output-dir path does not exist or is not writable: ${merged.outputDir}`,\n );\n process.exit(1);\n }\n }\n\n // ── Auto-detect datasource when not explicitly set ─────────\n const sourceConfigured =\n explicitFlags.has(\"issueSource\") || config.source !== undefined;\n const needsSource = !merged.spec && !merged.respec;\n\n if (needsSource && !sourceConfigured) {\n const detected = await detectDatasource(merged.cwd);\n if (detected) {\n log.info(`Auto-detected datasource from git remote: ${detected}`);\n merged.issueSource = detected;\n } else {\n log.error(\"Datasource auto-detection failed — could not determine issue source from git remote.\");\n log.dim(` Available datasources: ${DATASOURCE_NAMES.join(\", \")}`);\n log.dim(\" Run 'dispatch config' to configure defaults interactively.\");\n log.dim(\" Or pass it as a CLI flag: --source <name>\");\n process.exit(1);\n }\n }\n\n // ── Enable verbose logging ─────────────────────────────────\n log.verbose = merged.verbose;\n\n return merged;\n}\n","/**\n * Spec generation pipeline — extracted from the orchestrator to keep the\n * coordinator thin and this pipeline independently testable.\n *\n * Handles: datasource resolution, issue fetching (tracker and file/glob\n * modes), provider/skill booting, batch spec generation, datasource sync\n * (update existing issues or create new ones), and cleanup.\n */\n\nimport { join, resolve } from \"node:path\";\nimport { mkdir, readFile, rename, unlink } from \"node:fs/promises\";\nimport { randomUUID } from \"node:crypto\";\nimport { glob } from \"glob\";\nimport type { SpecOptions, SpecSummary, SpecProgressEvent } from \"../spec-generator.js\";\nimport { isIssueNumbers, isGlobOrFilePath, resolveSource, defaultConcurrency, DEFAULT_SPEC_WARN_MIN, DEFAULT_SPEC_KILL_MIN } from \"../spec-generator.js\";\nimport type { IssueDetails, IssueFetchOptions, Datasource, DatasourceName } from \"../datasources/interface.js\";\nimport { getDatasource } from \"../datasources/index.js\";\nimport { extractTitle } from \"../datasources/md.js\";\nimport type { ProviderInstance, ProviderName } from \"../providers/interface.js\";\nimport { PROVIDER_NAMES } from \"../providers/interface.js\";\nimport { bootProvider, getAuthenticatedProviders } from \"../providers/index.js\";\nimport { routeSkill } from \"../providers/router.js\";\nimport { specSkill, type SpecInput } from \"../skills/spec.js\";\nimport { dispatch, type DispatchOptions } from \"../dispatcher.js\";\nimport { registerCleanup } from \"../helpers/cleanup.js\";\nimport { log } from \"../helpers/logger.js\";\nimport { FileLogger, fileLoggerStorage } from \"../helpers/file-logger.js\";\nimport { confirmLargeBatch } from \"../helpers/confirm-large-batch.js\";\nimport chalk from \"chalk\";\nimport { createTui, type TuiState } from \"../tui.js\";\nimport type { Task } from \"../parser.js\";\nimport { elapsed, renderHeaderLines } from \"../helpers/format.js\";\nimport { ensureAuthReady } from \"../helpers/auth.js\";\nimport { DEFAULT_RETRY_COUNT, withRetry } from \"../helpers/retry.js\";\nimport { withTimeout } from \"../helpers/timeout.js\";\nimport { runWithConcurrency } from \"../helpers/concurrency.js\";\nimport { slugify, MAX_SLUG_LENGTH } from \"../helpers/slugify.js\";\nimport { parseIssueFilename } from \"./datasource-helpers.js\";\n\n/** Per-item timeout for datasource fetch calls (ms). */\nconst FETCH_TIMEOUT_MS = 30_000;\n\n// ── Shared types for pipeline stages ──────────────────────────\n\n/** An item resolved from any input mode (tracker, file, or inline text). */\ninterface ResolvedItem {\n id: string;\n details: IssueDetails | null;\n error?: string;\n}\n\n/** A successfully resolved item with non-null details. */\ninterface ValidItem {\n id: string;\n details: IssueDetails;\n}\n\n/** Result of the datasource resolution stage. */\ninterface ResolvedSource {\n source: DatasourceName;\n datasource: Datasource;\n fetchOpts: IssueFetchOptions;\n}\n\n/** Accumulated state from the batch generation loop. */\ninterface GenerationResults {\n generatedFiles: string[];\n issueNumbers: string[];\n dispatchIdentifiers: string[];\n failed: number;\n fileDurationsMs: Record<string, number>;\n}\n\n// ── Pipeline stage functions ──────────────────────────────────\n\n/**\n * Resolve the datasource from options.\n * Returns null when resolution fails (caller should return early).\n */\nasync function resolveDatasource(\n issues: string | string[],\n issueSource: DatasourceName | undefined,\n specCwd: string,\n org?: string,\n project?: string,\n workItemType?: string,\n iteration?: string,\n area?: string,\n): Promise<ResolvedSource | null> {\n const source = await resolveSource(issues, issueSource, specCwd);\n if (!source) return null;\n\n const datasource = getDatasource(source);\n const fetchOpts: IssueFetchOptions = { cwd: specCwd, org, project, workItemType, iteration, area };\n return { source, datasource, fetchOpts };\n}\n\n/**\n * Fetch items from an issue tracker by number.\n * Returns an empty array if no issue numbers were provided.\n */\nasync function fetchTrackerItems(\n issues: string,\n datasource: Datasource,\n fetchOpts: IssueFetchOptions,\n concurrency: number,\n source: DatasourceName,\n): Promise<ResolvedItem[]> {\n const issueNumbers = issues\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean);\n\n if (issueNumbers.length === 0) {\n log.error(\"No issue numbers provided. Use --spec 1,2,3\");\n return [];\n }\n\n const fetchStart = Date.now();\n log.info(`Fetching ${issueNumbers.length} issue(s) from ${source} (concurrency: ${concurrency})...`);\n\n const items: ResolvedItem[] = [];\n const fetchQueue = [...issueNumbers];\n\n while (fetchQueue.length > 0) {\n const batch = fetchQueue.splice(0, concurrency);\n log.debug(`Fetching batch of ${batch.length}: #${batch.join(\", #\")}`);\n const batchResults = await Promise.all(\n batch.map(async (id) => {\n try {\n const details = await withTimeout(datasource.fetch(id, fetchOpts), FETCH_TIMEOUT_MS, \"datasource fetch\");\n log.success(`Fetched #${id}: ${details.title}`);\n log.debug(`Body: ${details.body?.length ?? 0} chars, Labels: ${details.labels.length}, Comments: ${details.comments.length}`);\n return { id, details };\n } catch (err) {\n const message = log.extractMessage(err);\n log.error(`Failed to fetch #${id}: ${log.formatErrorChain(err)}`);\n log.debug(log.formatErrorChain(err));\n return { id, details: null, error: message };\n }\n })\n );\n items.push(...batchResults);\n }\n log.debug(`Issue fetching completed in ${elapsed(Date.now() - fetchStart)}`);\n return items;\n}\n\n/** Construct a single item from inline text input. */\nfunction buildInlineTextItem(\n issues: string | string[],\n outputDir: string,\n): ResolvedItem[] {\n const text = Array.isArray(issues) ? issues.join(\" \") : issues;\n const title = text.length > 80 ? text.slice(0, 80).trimEnd() + \"…\" : text;\n const slug = slugify(text, MAX_SLUG_LENGTH);\n const filename = `${slug}.md`;\n const filepath = join(outputDir, filename);\n\n const details: IssueDetails = {\n number: filepath,\n title,\n body: text,\n labels: [],\n state: \"open\",\n url: filepath,\n comments: [],\n acceptanceCriteria: \"\",\n };\n\n log.info(`Inline text spec: \"${title}\"`);\n return [{ id: filepath, details }];\n}\n\n/** Resolve items from a glob pattern or file paths. */\nasync function resolveFileItems(\n issues: string | string[],\n specCwd: string,\n concurrency: number,\n): Promise<ResolvedItem[] | null> {\n const files = await glob(issues, { cwd: specCwd, absolute: true });\n\n if (files.length === 0) {\n log.error(`No files matched the pattern \"${Array.isArray(issues) ? issues.join(\", \") : issues}\".`);\n return null;\n }\n\n log.info(`Matched ${files.length} file(s) for spec generation (concurrency: ${concurrency})...`);\n\n const items: ResolvedItem[] = [];\n for (const filePath of files) {\n try {\n const content = await readFile(filePath, \"utf-8\");\n const title = extractTitle(content, filePath);\n const details: IssueDetails = {\n number: filePath,\n title,\n body: content,\n labels: [],\n state: \"open\",\n url: filePath,\n comments: [],\n acceptanceCriteria: \"\",\n };\n items.push({ id: filePath, details });\n } catch (err) {\n items.push({ id: filePath, details: null, error: log.extractMessage(err) });\n }\n }\n return items;\n}\n\n/** Filter items to those with non-null details. */\nfunction filterValidItems(\n items: ResolvedItem[],\n isTrackerMode: boolean,\n isInlineText: boolean,\n): ValidItem[] | null {\n const validItems = items.filter(\n (i): i is ValidItem => i.details !== null,\n );\n if (validItems.length === 0) {\n const noun = isTrackerMode ? \"issues\" : isInlineText ? \"inline specs\" : \"files\";\n log.error(`No ${noun} could be loaded. Aborting spec generation.`);\n return null;\n }\n return validItems;\n}\n\n/** Log a dry-run preview of what would be generated. */\nfunction previewDryRun(\n validItems: ValidItem[],\n items: ResolvedItem[],\n isTrackerMode: boolean,\n isInlineText: boolean,\n outputDir: string,\n pipelineStart: number,\n): SpecSummary {\n const mode = isTrackerMode ? \"tracker\" : isInlineText ? \"inline\" : \"file\";\n log.info(`[DRY RUN] Would generate ${validItems.length} spec(s) (mode: ${mode}):\\n`);\n\n for (const { id, details } of validItems) {\n let filepath: string;\n if (isTrackerMode) {\n const slug = slugify(details.title, 60);\n filepath = join(outputDir, `${id}-${slug}.md`);\n } else {\n filepath = id;\n }\n\n const label = isTrackerMode ? `#${id}` : filepath;\n log.info(`[DRY RUN] Would generate spec for ${label}: \"${details.title}\"`);\n log.dim(` → ${filepath}`);\n }\n\n return {\n total: items.length,\n generated: 0,\n failed: items.filter((i) => i.details === null).length,\n files: [],\n issueNumbers: [],\n durationMs: Date.now() - pipelineStart,\n fileDurationsMs: {},\n };\n}\n\n/** Boot the AI provider and render the header banner. */\nasync function bootPipeline(\n provider: ProviderName,\n serverUrl: string | undefined,\n specCwd: string,\n model: string | undefined,\n source: DatasourceName,\n): Promise<{ instance: ProviderInstance }> {\n const bootStart = Date.now();\n log.info(`Booting ${provider} provider...`);\n log.debug(serverUrl ? `Using server URL: ${serverUrl}` : \"No --server-url, will spawn local server\");\n const instance = await bootProvider(provider, { url: serverUrl, cwd: specCwd, model });\n registerCleanup(() => instance.cleanup());\n log.debug(`Provider booted in ${elapsed(Date.now() - bootStart)}`);\n\n const headerLines = renderHeaderLines({\n provider,\n model: instance.model,\n source,\n });\n console.log(\"\");\n for (const line of headerLines) {\n console.log(line);\n }\n console.log(chalk.dim(\" ─\".repeat(24)));\n console.log(\"\");\n\n return { instance };\n}\n\n/** Generate specs in parallel batches, sync to datasource, and track results. */\nasync function generateSpecsBatch(\n validItems: ValidItem[],\n items: ResolvedItem[],\n provider: ProviderInstance,\n isTrackerMode: boolean,\n isInlineText: boolean,\n datasource: Datasource,\n fetchOpts: IssueFetchOptions,\n outputDir: string,\n specCwd: string,\n concurrency: number,\n retries: number,\n specWarnMs: number,\n specKillMs: number,\n tuiState?: TuiState,\n tuiUpdate?: () => void,\n progressCallback?: (event: SpecProgressEvent) => void,\n): Promise<GenerationResults> {\n await mkdir(outputDir, { recursive: true });\n const quiet = !!tuiState && !log.verbose;\n\n const generatedFiles: string[] = [];\n const issueNumbers: string[] = [];\n const dispatchIdentifiers: string[] = [];\n let failed = items.filter((i) => i.details === null).length;\n const fileDurationsMs: Record<string, number> = {};\n\n const genQueue = [...validItems];\n let modelLoggedInBanner = !!provider.model;\n\n async function processItem({ id, details }: ValidItem): Promise<void> {\n const specStart = Date.now();\n const tuiTask = tuiState?.tasks.find(t => t.task.file === id);\n if (tuiTask) {\n tuiTask.status = \"generating\";\n tuiTask.elapsed = specStart;\n tuiUpdate?.();\n }\n progressCallback?.({ type: \"item_start\", itemId: id, itemTitle: details?.title });\n\n if (!details) {\n log.error(`Skipping item ${id}: missing issue details`);\n failed++;\n return;\n }\n\n const itemBody = async (): Promise<{ filepath: string; identifier: string } | null> => {\n let filepath: string;\n if (isTrackerMode) {\n const slug = slugify(details.title, MAX_SLUG_LENGTH);\n const filename = `${id}-${slug}.md`;\n filepath = join(outputDir, filename);\n } else if (isInlineText) {\n filepath = id;\n } else {\n filepath = id;\n }\n\n fileLoggerStorage.getStore()?.info(`Output path: ${filepath}`);\n\n try {\n fileLoggerStorage.getStore()?.info(`Starting spec generation for ${isTrackerMode ? `#${id}` : filepath}`);\n if (!quiet) log.info(`Generating spec for ${isTrackerMode ? `#${id}` : filepath}: ${details.title}...`);\n const generateLabel = `dispatch(spec, ${isTrackerMode ? `#${id}` : filepath})`;\n\n const tmpDir = join(resolve(specCwd), \".dispatch\", \"tmp\");\n await mkdir(tmpDir, { recursive: true });\n const tmpPath = join(tmpDir, `spec-${randomUUID()}.md`);\n\n const specInput: SpecInput = {\n issue: isTrackerMode ? details : undefined,\n filePath: isTrackerMode ? undefined : id,\n fileContent: isTrackerMode ? undefined : details.body,\n cwd: specCwd,\n outputPath: filepath,\n tmpPath,\n };\n\n const dispatchOpts: DispatchOptions = {\n promptOptions: {\n onProgress: tuiTask ? (snapshot) => {\n tuiTask.feedback = snapshot.text;\n tuiUpdate?.();\n } : undefined,\n },\n timebox: {\n warnMs: specWarnMs,\n killMs: specKillMs,\n warnMessage: `Your spec generation time is done. You have exceeded the ${Math.round(specWarnMs / 60_000)}-minute limit. You MUST write the spec file to \"${filepath}\" immediately. If you do not comply within ${Math.round(specKillMs / 1000)} seconds, you will be terminated.`,\n },\n };\n\n const result = await withRetry(\n () => dispatch(specSkill, specInput, provider, dispatchOpts),\n retries,\n { label: generateLabel },\n );\n\n if (!result.success) {\n throw new Error(result.error ?? \"Spec generation failed\");\n }\n\n fileLoggerStorage.getStore()?.info(`Spec generated successfully`);\n\n if (isTrackerMode || isInlineText) {\n const h1Title = extractTitle(result.data.content, filepath);\n const h1Slug = slugify(h1Title, MAX_SLUG_LENGTH);\n const finalFilename = isTrackerMode ? `${id}-${h1Slug}.md` : `${h1Slug}.md`;\n const finalFilepath = join(outputDir, finalFilename);\n if (finalFilepath !== filepath) {\n await rename(filepath, finalFilepath);\n filepath = finalFilepath;\n }\n }\n\n const specDuration = Date.now() - specStart;\n fileDurationsMs[filepath] = specDuration;\n if (!quiet) log.success(`Spec written: ${filepath} (${elapsed(specDuration)})`);\n if (tuiTask) {\n tuiTask.status = \"done\";\n tuiTask.elapsed = specDuration;\n tuiTask.feedback = undefined;\n tuiUpdate?.();\n }\n progressCallback?.({ type: \"item_done\", itemId: id, itemTitle: details?.title });\n\n let identifier = filepath;\n\n fileLoggerStorage.getStore()?.phase(\"Datasource sync\");\n if (tuiTask) {\n tuiTask.status = \"syncing\";\n tuiTask.elapsed = Date.now();\n tuiTask.feedback = undefined;\n tuiUpdate?.();\n }\n try {\n if (isTrackerMode) {\n await datasource.update(id, details.title, result.data.content, fetchOpts);\n if (!quiet) log.success(`Updated issue #${id} with spec content`);\n await unlink(filepath);\n if (!quiet) log.success(`Deleted local spec ${filepath} (now tracked as issue #${id})`);\n identifier = id;\n issueNumbers.push(id);\n } else if (datasource.name === \"md\") {\n const parsed = parseIssueFilename(filepath);\n if (parsed) {\n await datasource.update(parsed.issueId, details.title, result.data.content, fetchOpts);\n if (!quiet) log.success(`Updated spec #${parsed.issueId} in-place`);\n identifier = parsed.issueId;\n issueNumbers.push(parsed.issueId);\n } else {\n const created = await datasource.create(details.title, result.data.content, fetchOpts);\n if (!quiet) log.success(`Created spec #${created.number} from ${filepath}`);\n identifier = created.number;\n issueNumbers.push(created.number);\n try {\n await unlink(filepath);\n if (!quiet) log.success(`Deleted local spec ${filepath} (now tracked as spec #${created.number})`);\n } catch (unlinkErr) {\n log.warn(`Could not delete local spec ${filepath}: ${log.formatErrorChain(unlinkErr)}`);\n }\n // Update filepath to the newly created spec so\n // generatedFiles / fileDurationsMs reference the\n // correct (existing) file, not the deleted original.\n const oldDuration = fileDurationsMs[filepath];\n delete fileDurationsMs[filepath];\n filepath = created.url;\n fileDurationsMs[filepath] = oldDuration;\n }\n } else {\n const created = await datasource.create(details.title, result.data.content, fetchOpts);\n if (!quiet) log.success(`Created issue #${created.number} from ${filepath}`);\n await unlink(filepath);\n if (!quiet) log.success(`Deleted local spec ${filepath} (now tracked as issue #${created.number})`);\n identifier = created.number;\n issueNumbers.push(created.number);\n }\n } catch (err) {\n const label = isTrackerMode ? `issue #${id}` : filepath;\n log.warn(`Could not sync ${label} to datasource: ${log.formatErrorChain(err)}`);\n }\n\n return { filepath, identifier };\n } catch (err) {\n fileLoggerStorage.getStore()?.error(`Spec generation failed for ${id}: ${log.extractMessage(err)}${err instanceof Error && err.stack ? `\\n${err.stack}` : \"\"}`);\n log.error(`Failed to generate spec for ${isTrackerMode ? `#${id}` : filepath}: ${log.formatErrorChain(err)}`);\n log.debug(log.formatErrorChain(err));\n if (tuiTask) {\n tuiTask.status = \"failed\";\n tuiTask.elapsed = Date.now() - specStart;\n tuiTask.error = log.extractMessage(err);\n tuiTask.feedback = undefined;\n tuiUpdate?.();\n }\n progressCallback?.({ type: \"item_failed\", itemId: id, itemTitle: details?.title, error: log.extractMessage(err) });\n return null;\n }\n };\n\n let itemResult: { filepath: string; identifier: string } | null;\n const fileLogger = log.verbose ? new FileLogger(id, specCwd) : null;\n if (fileLogger) {\n itemResult = await fileLoggerStorage.run(fileLogger, async () => {\n try {\n fileLogger.phase(`Spec generation: ${id}`);\n return await itemBody();\n } finally {\n fileLogger.close();\n }\n });\n } else {\n itemResult = await itemBody();\n }\n\n if (itemResult !== null) {\n generatedFiles.push(itemResult.filepath);\n dispatchIdentifiers.push(itemResult.identifier);\n } else {\n failed++;\n }\n\n if (!modelLoggedInBanner && provider.model) {\n if (!quiet) log.info(`Detected model: ${provider.model}`);\n modelLoggedInBanner = true;\n }\n }\n\n // Sliding-window concurrency — delegate to the shared utility for\n // consistency with dispatch-pipeline.ts.\n await runWithConcurrency({\n items: genQueue,\n concurrency,\n worker: async (item) => processItem(item),\n });\n\n return { generatedFiles, issueNumbers, dispatchIdentifiers, failed, fileDurationsMs };\n}\n\n/** Clean up the provider, logging warnings on failure. */\nasync function cleanupPipeline(\n instance: ProviderInstance,\n): Promise<void> {\n try {\n await instance.cleanup();\n } catch (err) {\n log.warn(`Provider cleanup failed: ${log.formatErrorChain(err)}`);\n }\n}\n\n/** Log the final summary and dispatch hint. */\nfunction logSummary(\n generatedFiles: string[],\n dispatchIdentifiers: string[],\n failed: number,\n totalDuration: number,\n): void {\n log.info(\n `Spec generation complete: ${generatedFiles.length} generated, ${failed} failed in ${elapsed(totalDuration)}`\n );\n\n if (generatedFiles.length > 0) {\n log.dim(`\\n Run these specs with:`);\n const allNumeric = dispatchIdentifiers.every((id) => /^\\d+$/.test(id));\n if (allNumeric) {\n log.dim(` dispatch ${dispatchIdentifiers.join(\",\")}\\n`);\n } else {\n log.dim(` dispatch ${dispatchIdentifiers.map((f) => '\"' + f + '\"').join(\" \")}\\n`);\n }\n }\n}\n\n// ── Public API ────────────────────────────────────────────────\n\n/**\n * Run the spec-generation pipeline end-to-end.\n *\n * This is the extracted core of the orchestrator's `generateSpecs()` method.\n * It accepts `SpecOptions` and returns a `SpecSummary`.\n */\nexport async function runSpecPipeline(opts: SpecOptions): Promise<SpecSummary> {\n const {\n issues,\n provider: forceProvider,\n enabledProviders,\n providerModels,\n serverUrl,\n cwd: specCwd,\n outputDir = join(specCwd, \".dispatch\", \"specs\"),\n org,\n project,\n workItemType,\n iteration,\n area,\n concurrency = defaultConcurrency(),\n dryRun,\n retries = DEFAULT_RETRY_COUNT,\n progressCallback,\n } = opts;\n\n const pipelineStart = Date.now();\n const specWarnMs = (opts.specWarnTimeout ?? DEFAULT_SPEC_WARN_MIN) * 60_000;\n const specKillMs = (opts.specKillTimeout ?? DEFAULT_SPEC_KILL_MIN) * 60_000;\n log.debug(`Spec timebox: warn=${opts.specWarnTimeout ?? DEFAULT_SPEC_WARN_MIN}m, kill=${opts.specKillTimeout ?? DEFAULT_SPEC_KILL_MIN}m, total=${specWarnMs + specKillMs}ms`);\n\n // ── Resolve datasource ─────────────────────────────────────\n const resolved = await resolveDatasource(issues, opts.issueSource, specCwd, org, project, workItemType, iteration, area);\n if (!resolved) {\n return { total: 0, generated: 0, failed: 0, files: [], issueNumbers: [], durationMs: Date.now() - pipelineStart, fileDurationsMs: {} };\n }\n const { source, datasource, fetchOpts } = resolved;\n\n // Pre-authenticate so device-code prompts appear before batch processing.\n await ensureAuthReady(source, specCwd, org);\n\n // ── Determine items to process ─────────────────────────────\n const isTrackerMode = isIssueNumbers(issues);\n const isInlineText = !isTrackerMode && !isGlobOrFilePath(issues);\n let items: ResolvedItem[];\n\n if (isTrackerMode) {\n items = await fetchTrackerItems(issues, datasource, fetchOpts, concurrency, source);\n if (items.length === 0) {\n return { total: 0, generated: 0, failed: 0, files: [], issueNumbers: [], durationMs: Date.now() - pipelineStart, fileDurationsMs: {} };\n }\n } else if (isInlineText) {\n items = buildInlineTextItem(issues, outputDir);\n } else {\n const fileItems = await resolveFileItems(issues, specCwd, concurrency);\n if (!fileItems) {\n return { total: 0, generated: 0, failed: 0, files: [], issueNumbers: [], durationMs: Date.now() - pipelineStart, fileDurationsMs: {} };\n }\n items = fileItems;\n }\n\n // ── Filter valid items ─────────────────────────────────────\n const validItems = filterValidItems(items, isTrackerMode, isInlineText);\n if (!validItems) {\n return { total: items.length, generated: 0, failed: items.length, files: [], issueNumbers: [], durationMs: Date.now() - pipelineStart, fileDurationsMs: {} };\n }\n\n // ── Dry-run preview ────────────────────────────────────────\n if (dryRun) {\n return previewDryRun(validItems, items, isTrackerMode, isInlineText, outputDir, pipelineStart);\n }\n\n // ── Confirm large batch ────────────────────────────────────\n const confirmed = await confirmLargeBatch(validItems.length);\n if (!confirmed) {\n return { total: 0, generated: 0, failed: 0, files: [], issueNumbers: [], durationMs: Date.now() - pipelineStart, fileDurationsMs: {} };\n }\n\n // ── Resolve provider via router ────────────────────────────\n const available = enabledProviders?.length\n ? enabledProviders\n : await getAuthenticatedProviders(PROVIDER_NAMES);\n\n if (available.length === 0) {\n throw new Error(\"No authenticated providers available. Run 'dispatch config' to set up providers.\");\n }\n\n const specRoute = routeSkill(\"spec\", available, forceProvider, providerModels);\n const resolvedProvider = specRoute[0].provider;\n const resolvedModel = specRoute[0].model;\n\n // ── Boot provider ──────────────────────────────────────────\n const { instance } = await bootPipeline(resolvedProvider, serverUrl, specCwd, resolvedModel, source);\n\n // ── Start TUI ──────────────────────────────────────────────\n const verbose = log.verbose;\n let tui: ReturnType<typeof createTui>;\n\n if (verbose) {\n // Silent state container — no animated rendering (header already printed by bootPipeline)\n const state: TuiState = {\n tasks: [],\n phase: \"booting\",\n mode: \"spec\",\n startTime: Date.now(),\n filesFound: 0,\n provider: resolvedProvider,\n model: instance.model,\n source,\n };\n tui = {\n state,\n update: () => {},\n stop: () => {},\n waitForRecoveryAction: async () => \"quit\" as const,\n };\n } else {\n tui = createTui();\n tui.state.mode = \"spec\";\n tui.state.provider = resolvedProvider;\n tui.state.model = instance.model;\n tui.state.source = source;\n }\n\n tui.state.tasks = validItems.map((item, index) => ({\n task: {\n index,\n text: item.details?.title ?? `Item ${item.id}`,\n line: 0,\n raw: item.details?.title ?? item.id,\n file: item.id,\n } satisfies Task,\n status: \"pending\" as const,\n }));\n\n tui.state.phase = \"dispatching\";\n tui.update();\n\n // ── Generate specs in batches ──────────────────────────────\n try {\n const results = await generateSpecsBatch(\n validItems, items, instance,\n isTrackerMode, isInlineText,\n datasource, fetchOpts, outputDir, specCwd,\n concurrency, retries, specWarnMs, specKillMs,\n tui.state, tui.update,\n progressCallback,\n );\n\n // ── Cleanup ────────────────────────────────────────────────\n await cleanupPipeline(instance);\n\n // ── Stop TUI ───────────────────────────────────────────────\n tui.state.phase = \"done\";\n tui.stop();\n\n // ── Summary ────────────────────────────────────────────────\n const totalDuration = Date.now() - pipelineStart;\n logSummary(results.generatedFiles, results.dispatchIdentifiers, results.failed, totalDuration);\n\n return {\n total: items.length,\n generated: results.generatedFiles.length,\n failed: results.failed,\n files: results.generatedFiles,\n issueNumbers: results.issueNumbers,\n identifiers: results.dispatchIdentifiers,\n durationMs: totalDuration,\n fileDurationsMs: results.fileDurationsMs,\n };\n } catch (err) {\n tui.state.phase = \"done\";\n tui.stop();\n throw err;\n }\n}\n","/**\n * Smart provider router — automatically selects the best provider for each\n * skill role based on task requirements, cost, and provider availability.\n *\n * Produces `PoolEntry[]` arrays for direct consumption by ProviderPool.\n */\n\nimport type { ProviderModelConfig } from \"../config.js\";\nimport type { SkillName } from \"../skills/interface.js\";\nimport type { ProviderName } from \"./interface.js\";\nimport type { PoolEntry } from \"./pool.js\";\nimport { PROVIDER_REGISTRY, type ProviderMeta } from \"./registry.js\";\n\n/** Resolve model for a provider, preferring config overrides over registry defaults. */\nfunction resolveModel(\n meta: ProviderMeta,\n isFast: boolean,\n overrides?: Partial<Record<ProviderName, ProviderModelConfig>>,\n): string {\n const override = overrides?.[meta.name];\n if (isFast) return override?.fast ?? meta.defaultFastModel;\n return override?.strong ?? meta.defaultStrongModel;\n}\n\n/** Skill roles that need fast/cheap models. */\nconst FAST_ROLES: ReadonlySet<SkillName> = new Set([\"planner\", \"commit\"]);\n\n/** Skill roles that need strong/capable models. */\nconst STRONG_ROLES: ReadonlySet<SkillName> = new Set([\"executor\", \"spec\"]);\n\n/**\n * Route a skill role to a prioritized list of provider+model entries.\n *\n * The returned entries are ordered by preference (cheapest/best first)\n * and can be passed directly to `new ProviderPool({ entries })`.\n *\n * @param role - The skill role to route (planner, executor, spec, commit)\n * @param authenticatedProviders - Provider names that are installed and authenticated\n * @param forceProvider - Optional CLI override that forces a specific provider for all roles\n */\nexport function routeSkill(\n role: SkillName,\n authenticatedProviders: ProviderName[],\n forceProvider?: ProviderName,\n modelOverrides?: Partial<Record<ProviderName, ProviderModelConfig>>,\n): PoolEntry[] {\n // CLI --provider override: use that provider for everything\n if (forceProvider) {\n const meta = PROVIDER_REGISTRY[forceProvider];\n const isFast = FAST_ROLES.has(role);\n return [\n {\n provider: forceProvider,\n model: resolveModel(meta, isFast, modelOverrides),\n priority: 0,\n },\n ];\n }\n\n if (authenticatedProviders.length === 0) {\n throw new Error(\n \"No authenticated providers available. Run 'dispatch config' to set up providers.\",\n );\n }\n\n // Single provider: use it for everything\n if (authenticatedProviders.length === 1) {\n const meta = PROVIDER_REGISTRY[authenticatedProviders[0]];\n const isFast = FAST_ROLES.has(role);\n return [\n {\n provider: meta.name,\n model: resolveModel(meta, isFast, modelOverrides),\n priority: 0,\n },\n ];\n }\n\n const isFast = FAST_ROLES.has(role);\n const metas = authenticatedProviders.map((name) => PROVIDER_REGISTRY[name]);\n\n // Score and sort providers for this role\n const scored = metas\n .map((meta) => ({\n meta,\n score: isFast ? meta.costScore.fast : meta.costScore.strong,\n // Prefer free tier for fast roles, prefer strong capability for strong roles\n tierBonus: isFast\n ? meta.tier === \"free\" ? -10 : 0\n : 0,\n }))\n .sort((a, b) => {\n // For fast roles: free tier first, then cheapest\n // For strong roles: lowest cost score = best value for strong capability\n const aTotal = a.score + a.tierBonus;\n const bTotal = b.score + b.tierBonus;\n return aTotal - bTotal;\n });\n\n return scored.map(({ meta }, i) => ({\n provider: meta.name,\n model: resolveModel(meta, isFast, modelOverrides),\n priority: i,\n }));\n}\n\n/**\n * Route all skill roles at once, returning a map of role -> PoolEntry[].\n *\n * Convenience wrapper around `routeSkill()` for pipeline setup.\n */\nexport function routeAllSkills(\n authenticatedProviders: ProviderName[],\n forceProvider?: ProviderName,\n modelOverrides?: Partial<Record<ProviderName, ProviderModelConfig>>,\n): Record<\"planner\" | \"executor\" | \"commit\", PoolEntry[]> {\n return {\n planner: routeSkill(\"planner\", authenticatedProviders, forceProvider, modelOverrides),\n executor: routeSkill(\"executor\", authenticatedProviders, forceProvider, modelOverrides),\n commit: routeSkill(\"commit\", authenticatedProviders, forceProvider, modelOverrides),\n };\n}\n","/**\n * Spec skill — generates high-level markdown spec files from issue details,\n * file content, or inline text.\n *\n * Stateless data object: defines prompt construction and result parsing\n * without coupling to any provider. The dispatcher handles execution,\n * timebox management, and provider interaction.\n */\n\nimport { readFile, writeFile, unlink } from \"node:fs/promises\";\nimport type { Skill } from \"./interface.js\";\nimport type { SpecData } from \"./types.js\";\nimport type { IssueDetails } from \"../datasources/interface.js\";\nimport { extractSpecContent, validateSpecStructure, DEFAULT_SPEC_WARN_MIN } from \"../spec-generator.js\";\nimport { extractTitle } from \"../datasources/md.js\";\nimport { formatEnvironmentPrompt } from \"../helpers/environment.js\";\n\n// ---------------------------------------------------------------------------\n// Input / Output types\n// ---------------------------------------------------------------------------\n\n/** Runtime input for the spec skill. */\nexport interface SpecInput {\n /** Issue details (for tracker mode) — mutually exclusive with fileContent */\n issue?: IssueDetails;\n /** File path (for file/glob mode) — used as source file reference */\n filePath?: string;\n /** File content (for file/glob mode) — mutually exclusive with issue */\n fileContent?: string;\n /** Inline text (for inline text mode) — mutually exclusive with issue and fileContent */\n inlineText?: string;\n /** Working directory */\n cwd: string;\n /** Final output path where the spec should be written */\n outputPath: string;\n /** Temp file path the provider writes to (caller generates it) */\n tmpPath: string;\n}\n\n// ---------------------------------------------------------------------------\n// Stateless skill definition\n// ---------------------------------------------------------------------------\n\n/** The spec skill — stateless, no provider coupling. */\nexport const specSkill: Skill<SpecInput, SpecData> = {\n name: \"spec\",\n\n buildPrompt(input: SpecInput): string {\n const { issue, filePath, fileContent, inlineText, cwd, tmpPath } = input;\n\n if (issue) {\n return buildSpecPrompt(issue, cwd, tmpPath);\n }\n if (inlineText) {\n return buildInlineTextSpecPrompt(inlineText, cwd, tmpPath);\n }\n if (filePath && fileContent !== undefined) {\n return buildFileSpecPrompt(filePath, fileContent, cwd, tmpPath);\n }\n\n throw new Error(\"Either issue, inlineText, or filePath+fileContent must be provided\");\n },\n\n async parseResult(response: string | null, input: SpecInput): Promise<SpecData> {\n if (response === null) {\n throw new Error(\"AI returned no response\");\n }\n\n // 1. Read the temp file written by the provider\n let rawContent: string;\n try {\n rawContent = await readFile(input.tmpPath, \"utf-8\");\n } catch {\n throw new Error(\n `Spec skill did not write the file to ${input.tmpPath}. Response: ${response.slice(0, 300)}`\n );\n }\n\n // 2. Apply extractSpecContent post-processing\n const cleanedContent = extractSpecContent(rawContent);\n\n // 3. Run validateSpecStructure\n const validation = validateSpecStructure(cleanedContent);\n\n // 4. Write the cleaned content to the final output path\n await writeFile(input.outputPath, cleanedContent, \"utf-8\");\n\n // 5. Clean up the temp file\n try {\n await unlink(input.tmpPath);\n } catch {\n // Ignore cleanup errors — temp file may already be gone\n }\n\n // 6. Return SpecData\n if (validation.valid) {\n return { content: cleanedContent, valid: true };\n }\n return { content: cleanedContent, valid: false, validationReason: validation.reason };\n },\n};\n\n// ---------------------------------------------------------------------------\n// Source section builders (private)\n// ---------------------------------------------------------------------------\n\nfunction buildIssueSourceSection(issue: IssueDetails): string[] {\n const lines: string[] = [\n ``,\n `## Issue Details`,\n ``,\n `- **Number:** #${issue.number}`,\n `- **Title:** ${issue.title}`,\n `- **State:** ${issue.state}`,\n `- **URL:** ${issue.url}`,\n ];\n\n if (issue.labels.length > 0) {\n lines.push(`- **Labels:** ${issue.labels.join(\", \")}`);\n }\n\n if (issue.body) {\n lines.push(``, `### Description`, ``, issue.body);\n }\n\n if (issue.acceptanceCriteria) {\n lines.push(``, `### Acceptance Criteria`, ``, issue.acceptanceCriteria);\n }\n\n if (issue.comments.length > 0) {\n lines.push(``, `### Discussion`, ``);\n for (const comment of issue.comments) {\n lines.push(comment, ``);\n }\n }\n\n return lines;\n}\n\nfunction buildFileSourceSection(filePath: string, content: string, title: string): string[] {\n const lines: string[] = [\n ``,\n `## File Details`,\n ``,\n `- **Title:** ${title}`,\n `- **Source file:** ${filePath}`,\n ];\n\n if (content) {\n lines.push(``, `### Content`, ``, content);\n }\n\n return lines;\n}\n\nfunction buildInlineTextSourceSection(title: string, text: string): string[] {\n return [\n ``,\n `## Inline Text`,\n ``,\n `- **Title:** ${title}`,\n ``,\n `### Description`,\n ``,\n text,\n ];\n}\n\n// ---------------------------------------------------------------------------\n// Common spec instructions builder (private)\n// ---------------------------------------------------------------------------\n\nfunction buildCommonSpecInstructions(params: {\n subject: string;\n sourceSection: string[];\n cwd: string;\n outputPath: string;\n understandStep: string;\n titleTemplate: string;\n summaryTemplate: string;\n whyLines: string[];\n}): string[] {\n const {\n subject,\n sourceSection,\n cwd,\n outputPath,\n understandStep,\n titleTemplate,\n summaryTemplate,\n whyLines,\n } = params;\n\n return [\n `Explore the codebase, understand ${subject}, and write a high-level **markdown spec file** to disk that will drive an automated implementation pipeline.`,\n ``,\n `**Time limit:** You have ${DEFAULT_SPEC_WARN_MIN} minutes to complete this spec. Work efficiently and focus on delivering a complete, well-structured spec within this window.`,\n ``,\n `**Important:** This file will be consumed by a two-stage pipeline:`,\n `1. A **planner** reads each task together with the prose context in this file, then explores the codebase to produce a detailed, line-level implementation plan.`,\n `2. A **coder** follows that detailed plan to make the actual code changes.`,\n ``,\n `Because the planner handles low-level details, your spec must stay **high-level and strategic**. Focus on the WHAT, WHY, and HOW — not exact code or line numbers.`,\n ``,\n `**Scope:** Each invocation is scoped to exactly one source item. The source item for this invocation is the single passed issue, file, or inline request shown below.`,\n `Treat other repository materials — including existing spec files, sibling issues, and future work — as context only unless the passed source explicitly references them as required context.`,\n `Do not merge unrelated specs, issues, files, or requests into the generated output.`,\n ``,\n `**CRITICAL — Output constraints (read carefully):**`,\n `The file you write must contain ONLY the structured spec content described below. You MUST NOT include:`,\n `- **No preamble:** Do not add any text before the H1 heading (e.g., \"Here's the spec:\", \"I've written the spec file to...\")`,\n `- **No postamble:** Do not add any text after the last spec section (e.g., \"Let me know if you'd like changes\", \"Here's a summary of...\")`,\n `- **No summaries:** Do not append a summary or recap of what you wrote`,\n `- **No code fences:** Do not wrap the spec content in \\`\\`\\`markdown ... \\`\\`\\` or any other code fence`,\n `- **No conversational text:** Do not include any explanations, commentary, or dialogue — the file is consumed by an automated pipeline, not a human`,\n `The file content must start with \\`# \\` (the H1 heading) and contain nothing before or after the structured spec sections.`,\n ...sourceSection,\n ``,\n `## Working Directory`,\n ``,\n `\\`${cwd}\\``,\n ``,\n formatEnvironmentPrompt(),\n ``,\n `## Instructions`,\n ``,\n `1. **Explore the codebase** — read relevant files, search for symbols, understand the project structure, language, frameworks, conventions, and patterns. Identify the tech stack (languages, package managers, frameworks, test runners) so your spec aligns with the project's actual standards.`,\n ``,\n understandStep,\n ``,\n `3. **Research the approach** — look up relevant documentation, libraries, and patterns. Consider how the change integrates with the existing architecture, standards, and technologies already in use. For example, if the project is TypeScript, do not propose a Python solution; if it uses Vitest, do not suggest Jest.`,\n ``,\n `4. **Identify integration points** — determine which existing modules, interfaces, patterns, and conventions the implementation must align with. Note the key files and modules involved, but do NOT prescribe exact code changes — the planner will handle that.`,\n ``,\n `5. **DO NOT make any code changes** — you are only producing a spec, not implementing.`,\n ``,\n `## Output`,\n ``,\n `Write the complete spec as a markdown file to this exact path:`,\n ``,\n `\\`${outputPath}\\``,\n ``,\n `Use your Write tool to save the file. The file content MUST begin with the H1 heading — no preamble, no code fences, no conversational text before it. Do not add any text after the final spec section — no postamble, no summary, no commentary. The file must follow this structure exactly:`,\n ``,\n titleTemplate,\n ``,\n summaryTemplate,\n ``,\n `## Context`,\n ``,\n `<Describe the relevant parts of the codebase: key modules, directory structure,`,\n `language/framework, and architectural patterns. Name specific files and modules`,\n `that are involved so the planner knows where to look, but do not include`,\n `code snippets or line-level details.>`,\n ``,\n `## Why`,\n ``,\n `<Explain the motivation — why this change is needed, what problem it solves,`,\n ...whyLines,\n ``,\n `## Approach`,\n ``,\n `<High-level description of the implementation strategy. Explain the overall`,\n `approach, which patterns to follow, what to extend vs. create new, and how`,\n `the change fits into the existing architecture. Mention relevant standards,`,\n `technologies, and conventions the implementation MUST align with.>`,\n ``,\n `## Integration Points`,\n ``,\n `<List the specific modules, interfaces, configurations, and conventions that`,\n `the implementation must integrate with. For example: existing provider`,\n `interfaces to implement, CLI argument patterns to follow, test framework`,\n `and conventions to match, build system requirements, etc.>`,\n ``,\n `## Tasks`,\n ``,\n `Each task MUST be prefixed with an execution-mode tag:`,\n ``,\n `- \\`(P)\\` — **Parallel-safe.** This task has no dependency on the output of a prior task and can run concurrently with other \\`(P)\\` tasks.`,\n `- \\`(S)\\` — **Serial / dependent.** This task depends on a prior task's output or modifies shared state that conflicts with concurrent work. It acts as a barrier: all preceding tasks complete before it starts, and it completes before subsequent tasks begin.`,\n `- \\`(I)\\` — **Isolated / barrier.** This task must run alone after all preceding tasks complete and before any subsequent tasks begin. Use for validation tasks like running tests, linting, or builds that read the output of prior tasks.`,\n ``,\n `**Default to \\`(P)\\`.** Most tasks are independent (e.g., adding a function in one module, writing tests in another). Only use \\`(S)\\` when a task genuinely depends on the result of a prior task (e.g., \"refactor module X\" followed by \"update callers of module X\"). Use \\`(I)\\` for validation or barrier tasks that must run alone after all prior work completes (e.g., \"run tests\", \"run linting\", \"build the project\").`,\n ``,\n `If a task has no \\`(P)\\`, \\`(S)\\`, or \\`(I)\\` prefix, the system treats it as serial, so always tag explicitly.`,\n ``,\n `Example:`,\n ``,\n `- [ ] (P) Add validation helper to the form utils module`,\n `- [ ] (P) Add unit tests for the new validation helper`,\n `- [ ] (S) Refactor the form component to use the new validation helper`,\n `- [ ] (P) Update documentation for the form utils module`,\n `- [ ] (I) Run the full test suite to verify all changes pass`,\n ``,\n ``,\n `## References`,\n ``,\n `- <Links to relevant docs, related issues, or external resources>`,\n ``,\n `## Key Guidelines`,\n ``,\n `- **Stay high-level.** Do NOT include code snippets, exact line numbers, diffs, or step-by-step coding instructions. A dedicated planner will produce those details for each task at execution time.`,\n `- **Respect the project's stack.** Your spec must align with the languages, frameworks, libraries, test tools, and conventions already in use. Never suggest technologies that conflict with the existing project.`,\n `- **Explain WHAT, WHY, and HOW (strategically).** Each task should say what needs to happen, why it's needed, and which part of the codebase it touches — but leave the tactical \"how\" to the planner.`,\n `- **Detail integration points.** The prose sections (Context, Approach, Integration Points) are critical — they tell the planner where to look and what constraints to respect.`,\n `- **Keep tasks atomic and ordered.** Each \\`- [ ]\\` task must be a single, clear unit of work. Order them so dependencies come first.`,\n `- **Tag every task with \\`(P)\\`, \\`(S)\\`, or \\`(I)\\`.** Default to \\`(P)\\` (parallel) unless the task depends on a prior task's output. Use \\`(I)\\` for validation/barrier tasks. Group related serial dependencies together and prefer parallelism to maximize throughput.`,\n `- **Embed commit instructions within task descriptions.** You control when commits happen. Instead of creating standalone commit tasks (which would fail — each task runs in an isolated session), include commit instructions at the end of implementation task descriptions at logical boundaries. For example: \"Implement the validation helper and commit with a conventional commit message.\" Group related changes into a single commit where it makes logical sense, and use the project's conventional commit types: \\`feat\\`, \\`fix\\`, \\`docs\\`, \\`refactor\\`, \\`test\\`, \\`chore\\`, \\`style\\`, \\`perf\\`, \\`ci\\`. Not every task needs a commit instruction — use your judgment to place them at logical boundaries.`,\n `- **Keep the markdown clean** — it will be parsed by an automated tool.`,\n ];\n}\n\n// ---------------------------------------------------------------------------\n// Public prompt builders (exported — tests use them directly)\n// ---------------------------------------------------------------------------\n\n/**\n * Build the prompt for tracker/issue mode.\n */\nexport function buildSpecPrompt(issue: IssueDetails, cwd: string, outputPath: string): string {\n return buildCommonSpecInstructions({\n subject: \"the issue below\",\n sourceSection: buildIssueSourceSection(issue),\n cwd,\n outputPath,\n understandStep: `2. **Understand the issue** — analyze the issue description, acceptance criteria, and discussion comments to fully understand what needs to be done and why.`,\n titleTemplate: `# <Issue title> (#<number>)`,\n summaryTemplate: `> <One-line summary: what this issue achieves and why it matters>`,\n whyLines: [\n `what user or system benefit it provides. Pull from the issue description,`,\n `acceptance criteria, and discussion.>`,\n ],\n }).join(\"\\n\");\n}\n\n/**\n * Build a spec prompt from a local markdown file.\n */\nexport function buildFileSpecPrompt(filePath: string, content: string, cwd: string, outputPath?: string): string {\n const title = extractTitle(content, filePath);\n const writePath = outputPath ?? filePath;\n\n return buildCommonSpecInstructions({\n subject: \"the content below\",\n sourceSection: buildFileSourceSection(filePath, content, title),\n cwd,\n outputPath: writePath,\n understandStep: `2. **Understand the content** — analyze the file content to fully understand what needs to be done and why.`,\n titleTemplate: `# <Title>`,\n summaryTemplate: `> <One-line summary: what this achieves and why it matters>`,\n whyLines: [\n `what user or system benefit it provides. Pull from the file content.>`,\n ],\n }).join(\"\\n\");\n}\n\n/**\n * Build a spec prompt from inline text.\n */\nexport function buildInlineTextSpecPrompt(text: string, cwd: string, outputPath: string): string {\n const title = text.length > 80 ? text.slice(0, 80).trimEnd() + \"\\u2026\" : text;\n\n return buildCommonSpecInstructions({\n subject: \"the request below\",\n sourceSection: buildInlineTextSourceSection(title, text),\n cwd,\n outputPath,\n understandStep: `2. **Understand the request** — analyze the inline text to fully understand what needs to be done and why. Since this is a brief description rather than a detailed issue or document, you may need to infer details from the codebase.`,\n titleTemplate: `# <Title>`,\n summaryTemplate: `> <One-line summary: what this achieves and why it matters>`,\n whyLines: [\n `what user or system benefit it provides. Pull from the inline text description.>`,\n ],\n }).join(\"\\n\");\n}\n","/**\n * Runtime environment detection for OS-aware agent prompts.\n *\n * Detects the host operating system and produces a formatted text block\n * that can be injected into agent system prompts so they know to run\n * commands directly instead of writing intermediate scripts.\n */\n\nexport interface EnvironmentInfo {\n /** Raw Node.js platform string (e.g. \"win32\", \"linux\", \"darwin\"). */\n platform: string;\n /** Human-readable OS name. */\n os: string;\n /** Default shell description for the platform. */\n shell: string;\n}\n\n/**\n * Detect the runtime environment from `process.platform`.\n */\nexport function getEnvironmentInfo(): EnvironmentInfo {\n const platform = process.platform;\n switch (platform) {\n case \"win32\":\n return { platform, os: \"Windows\", shell: \"cmd.exe/PowerShell\" };\n case \"darwin\":\n return { platform, os: \"macOS\", shell: \"zsh/bash\" };\n default:\n return { platform, os: \"Linux\", shell: \"bash\" };\n }\n}\n\n/**\n * Format environment information as a prompt text block.\n *\n * Returns a multi-line string describing the host OS, default shell,\n * and an instruction to run commands directly.\n */\nexport function formatEnvironmentPrompt(): string {\n const env = getEnvironmentInfo();\n return [\n `## Environment`,\n `- **Operating System:** ${env.os}`,\n `- **Default Shell:** ${env.shell}`,\n `- Always run commands directly in the shell. Do NOT write intermediate scripts (e.g. .bat, .ps1, .py files) unless the task explicitly requires creating a script.`,\n ].join(\"\\n\");\n}\n\n/** Alias used by the dispatcher module. */\nexport const getEnvironmentBlock = formatEnvironmentPrompt;\n","/**\n * Dispatcher — executes skills by sending their prompts to a provider\n * and processing the results. Each dispatch creates a fresh session\n * for context isolation.\n */\n\nimport type { Skill } from \"./skills/interface.js\";\nimport type { SkillResult } from \"./skills/types.js\";\nimport type { ProviderInstance, ProviderPromptOptions } from \"./providers/interface.js\";\nimport type { Task } from \"./parser.js\";\nimport { log } from \"./helpers/logger.js\";\nimport { fileLoggerStorage } from \"./helpers/file-logger.js\";\nimport { TimeoutError } from \"./helpers/timeout.js\";\n\n// ---------------------------------------------------------------------------\n// Shared types\n// ---------------------------------------------------------------------------\n\nexport interface DispatchResult {\n task: Task;\n success: boolean;\n error?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Dispatch options\n// ---------------------------------------------------------------------------\n\n/** Configuration for two-phase timebox (warn then kill). */\nexport interface TimeboxConfig {\n /** Duration in ms before sending a warning message. */\n warnMs: number;\n /** Duration in ms after the warning before hard-killing the prompt. */\n killMs: number;\n /** Warning message sent to the provider mid-session. */\n warnMessage: string;\n}\n\n/** Options for the generic `dispatch()` function. */\nexport interface DispatchOptions {\n /** Provider prompt options (e.g. onProgress callback). */\n promptOptions?: ProviderPromptOptions;\n /** Two-phase timebox: warn then kill. */\n timebox?: TimeboxConfig;\n}\n\n// ---------------------------------------------------------------------------\n// Generic dispatch\n// ---------------------------------------------------------------------------\n\n/**\n * Execute a skill by sending its prompt to a provider and parsing the result.\n *\n * 1. Calls `skill.buildPrompt(input)` to construct the prompt\n * 2. Creates a fresh provider session\n * 3. Sends the prompt (optionally with timebox)\n * 4. Calls `skill.parseResult(response, input)` to process the output\n * 5. Wraps everything in a `SkillResult<TOutput>`\n */\nexport async function dispatch<TInput, TOutput>(\n skill: Skill<TInput, TOutput>,\n input: TInput,\n provider: ProviderInstance,\n options?: DispatchOptions,\n): Promise<SkillResult<TOutput>> {\n const startTime = Date.now();\n try {\n const prompt = skill.buildPrompt(input);\n fileLoggerStorage.getStore()?.prompt(skill.name, prompt);\n\n const sessionId = await provider.createSession();\n log.debug(`[${skill.name}] Prompt built (${prompt.length} chars)`);\n\n let response: string | null;\n if (options?.timebox) {\n response = await promptWithTimebox(provider, sessionId, prompt, options.timebox, options.promptOptions);\n } else {\n response = await provider.prompt(sessionId, prompt, options?.promptOptions);\n }\n\n if (response) fileLoggerStorage.getStore()?.response(skill.name, response);\n\n const data = await skill.parseResult(response, input);\n\n fileLoggerStorage.getStore()?.skillEvent(skill.name, \"completed\", `${Date.now() - startTime}ms`);\n return { data, success: true, durationMs: Date.now() - startTime };\n } catch (err) {\n const message = log.extractMessage(err);\n fileLoggerStorage.getStore()?.error(`${skill.name} error: ${message}${err instanceof Error && err.stack ? `\\n${err.stack}` : \"\"}`);\n return { data: null, success: false, error: message, durationMs: Date.now() - startTime };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Timebox support\n// ---------------------------------------------------------------------------\n\n/**\n * Send a prompt with a two-phase timebox:\n * 1. After `warnMs`, send a warning message via `provider.send()`\n * 2. After an additional `killMs`, reject with a TimeoutError\n */\nasync function promptWithTimebox(\n provider: ProviderInstance,\n sessionId: string,\n prompt: string,\n timebox: TimeboxConfig,\n promptOptions?: ProviderPromptOptions,\n): Promise<string | null> {\n const { warnMs, killMs, warnMessage } = timebox;\n\n return new Promise<string | null>((resolve, reject) => {\n let settled = false;\n let warnTimer: ReturnType<typeof setTimeout> | undefined;\n let killTimer: ReturnType<typeof setTimeout> | undefined;\n\n const cleanup = () => {\n if (warnTimer) clearTimeout(warnTimer);\n if (killTimer) clearTimeout(killTimer);\n };\n\n // Start the warn timer\n warnTimer = setTimeout(() => {\n if (settled) return;\n log.warn(`Timebox warn fired for session ${sessionId} — sending wrap-up message`);\n\n if (provider.send) {\n provider.send(sessionId, warnMessage).catch((err) => {\n log.warn(`Failed to send timebox warning: ${log.extractMessage(err)}`);\n });\n } else {\n log.warn(`Provider does not support send() — cannot deliver timebox warning`);\n }\n\n // Start the kill timer\n killTimer = setTimeout(() => {\n if (settled) return;\n settled = true;\n cleanup();\n reject(new TimeoutError(warnMs + killMs, \"dispatch timebox\"));\n }, killMs);\n }, warnMs);\n\n // Run the prompt\n provider.prompt(sessionId, prompt, promptOptions).then(\n (value) => {\n if (settled) return;\n settled = true;\n cleanup();\n resolve(value);\n },\n (err) => {\n if (settled) return;\n settled = true;\n cleanup();\n reject(err);\n },\n );\n });\n}\n","/**\n * Process-level cleanup registry.\n *\n * Sub-modules (orchestrator, spec-generator) register their provider's\n * `cleanup()` here when the provider boots. The CLI signal handlers and\n * error handler drain the registry before exiting.\n *\n * All registered functions are invoked once; the registry is cleared\n * after each drain so repeated calls are harmless.\n */\n\nconst cleanups: Array<() => Promise<void>> = [];\n\n/**\n * Register an async cleanup function to be called on process shutdown.\n */\nexport function registerCleanup(fn: () => Promise<void>): void {\n cleanups.push(fn);\n}\n\n/**\n * Run all registered cleanup functions, then clear the registry.\n * Errors are swallowed to prevent cleanup failures from masking the\n * original error or blocking process exit.\n */\nexport async function runCleanup(): Promise<void> {\n const fns = cleanups.splice(0);\n for (const fn of fns) {\n try {\n await fn();\n } catch {\n // swallow — cleanup must not throw\n }\n }\n}\n","/**\n * TUI renderer — Ink (React for CLI) based real-time dashboard showing\n * dispatch progress, current task, and results.\n */\n\nimport React, { useState, useEffect, useCallback, useRef } from \"react\";\nimport { render, Box, Text, Spacer, useInput, useApp } from \"ink\";\nimport Spinner from \"ink-spinner\";\nimport { elapsed } from \"./helpers/format.js\";\nimport type { Task } from \"./parser.js\";\n\n// ── Types ─────────────────────────────────────────────────────────\n\nexport type TaskStatus = \"pending\" | \"planning\" | \"running\" | \"generating\" | \"syncing\" | \"paused\" | \"done\" | \"failed\";\ntype RecoveryAction = \"rerun\" | \"quit\";\n\nexport interface TaskState {\n task: Task;\n status: TaskStatus;\n elapsed?: number;\n error?: string;\n feedback?: string;\n worktree?: string;\n}\n\nexport interface TuiRecoveryState {\n taskIndex: number;\n taskText: string;\n error: string;\n issue?: { number: string; title: string };\n worktree?: string;\n selectedAction: RecoveryAction;\n}\n\nexport interface TuiState {\n tasks: TaskState[];\n phase: \"discovering\" | \"parsing\" | \"booting\" | \"dispatching\" | \"paused\" | \"done\";\n mode?: \"dispatch\" | \"spec\";\n startTime: number;\n filesFound: number;\n serverUrl?: string;\n provider?: string;\n model?: string;\n source?: string;\n currentIssue?: { number: string; title: string };\n notification?: string;\n recovery?: TuiRecoveryState;\n}\n\n// ── Color Palette ─────────────────────────────────────────────────\n\nconst PALETTE = {\n brand: \"#58A6FF\",\n subtitle: \"#484F58\",\n chrome: \"#30363D\",\n text: \"#C9D1D9\",\n muted: \"#484F58\",\n success: \"#56D364\",\n error: \"#F85149\",\n warn: \"#D29922\",\n accent: \"#79C0FF\",\n planning: \"#D2A8FF\",\n};\n\n// ── Helpers ───────────────────────────────────────────────────────\n\nfunction isActiveStatus(status: TaskStatus): boolean {\n return status === \"planning\" || status === \"running\" || status === \"generating\" || status === \"syncing\";\n}\n\nfunction sanitizeSubordinateText(text: string): string {\n return text\n .replace(/\\x1B\\[[0-?]*[ -/]*[@-~]/g, \"\")\n .replace(/[\\r\\n]+/g, \" \")\n .replace(/[\\u0000-\\u0008\\u000B\\u000C\\u000E-\\u001F\\u007F]+/g, \"\")\n .replace(/\\s+/g, \" \")\n .trim();\n}\n\nfunction truncateText(text: string, maxLen: number): string {\n if (text.length <= maxLen) return text;\n return text.slice(0, Math.max(0, maxLen - 1)) + \"…\";\n}\n\n// ── Components ────────────────────────────────────────────────────\n\nfunction Header({ provider, model, source, currentIssue }: {\n provider?: string;\n model?: string;\n source?: string;\n currentIssue?: { number: string; title: string };\n}) {\n const metaParts: string[] = [];\n if (provider) metaParts.push(`provider: ${provider}`);\n if (model) metaParts.push(`model: ${model}`);\n if (source) metaParts.push(`source: ${source}`);\n\n return (\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor={PALETTE.chrome} paddingLeft={1} paddingRight={1}>\n <Text bold color={PALETTE.brand}>⚡ dispatch</Text>\n <Text color={PALETTE.subtitle}>AI task orchestration</Text>\n {metaParts.length > 0 && (\n <>\n <Box marginTop={0}>\n <Text color={PALETTE.chrome}>{\"─\".repeat(60)}</Text>\n </Box>\n <Text color={PALETTE.text}>{metaParts.join(\" · \")}</Text>\n </>\n )}\n {currentIssue && (\n <Text>\n <Text color={PALETTE.muted}>issue: </Text>\n <Text color=\"white\">#{currentIssue.number}</Text>\n <Text color={PALETTE.muted}> — {currentIssue.title}</Text>\n </Text>\n )}\n </Box>\n );\n}\n\nfunction NotificationBanner({ notification }: { notification?: string }) {\n if (!notification) return null;\n return (\n <Box marginLeft={2} marginTop={1}>\n <Text color={PALETTE.warn}>⚠ {notification}</Text>\n </Box>\n );\n}\n\nfunction PhaseLabel({ phase, provider, mode, startTime }: {\n phase: TuiState[\"phase\"];\n provider?: string;\n mode?: TuiState[\"mode\"];\n startTime: number;\n}) {\n const [now, setNow] = useState(Date.now());\n useEffect(() => {\n const timer = setInterval(() => setNow(Date.now()), 1000);\n return () => clearInterval(timer);\n }, []);\n\n const totalElapsed = elapsed(now - startTime);\n let label: string;\n let showSpinner = false;\n\n switch (phase) {\n case \"discovering\":\n label = \"Discovering task files\";\n showSpinner = true;\n break;\n case \"parsing\":\n label = \"Parsing tasks\";\n showSpinner = true;\n break;\n case \"booting\":\n label = `Connecting to ${provider ?? \"provider\"}`;\n showSpinner = true;\n break;\n case \"dispatching\":\n label = mode === \"spec\" ? \"Generating specs\" : \"Dispatching tasks\";\n showSpinner = true;\n break;\n case \"paused\":\n label = \"Waiting for rerun\";\n break;\n case \"done\":\n label = \"Complete\";\n break;\n default:\n label = phase;\n }\n\n return (\n <Box marginLeft={2} marginTop={1}>\n {showSpinner ? (\n <Text color={PALETTE.accent}><Spinner type=\"dots\" /> </Text>\n ) : phase === \"paused\" ? (\n <Text color={PALETTE.warn}>◐ </Text>\n ) : phase === \"done\" ? (\n <Text color={PALETTE.success}>✔ </Text>\n ) : null}\n <Text>{label}</Text>\n <Spacer />\n <Text color={PALETTE.muted}>{totalElapsed}</Text>\n </Box>\n );\n}\n\nfunction ProgressBar({ done, total }: { done: number; total: number }) {\n const BAR_WIDTH = 30;\n const filled = total === 0 ? 0 : Math.round((done / total) * BAR_WIDTH);\n const empty = BAR_WIDTH - filled;\n const pct = total === 0 ? 0 : Math.round((done / total) * 100);\n\n return (\n <Box marginLeft={2} marginTop={1}>\n <Text color={PALETTE.muted}>▐</Text>\n <Text color={PALETTE.success}>{\"█\".repeat(filled)}</Text>\n <Text color={PALETTE.muted}>{\"░\".repeat(empty)}</Text>\n <Text color={PALETTE.muted}>▌</Text>\n <Text> {pct}% {done}/{total} tasks</Text>\n </Box>\n );\n}\n\nfunction StatusIcon({ status }: { status: TaskStatus }) {\n switch (status) {\n case \"pending\":\n return <Text color={PALETTE.muted}>○</Text>;\n case \"planning\":\n return <Text color={PALETTE.planning}><Spinner type=\"dots\" /></Text>;\n case \"running\":\n case \"generating\":\n case \"syncing\":\n return <Text color={PALETTE.accent}><Spinner type=\"dots\" /></Text>;\n case \"paused\":\n return <Text color={PALETTE.warn}>◐</Text>;\n case \"done\":\n return <Text color={PALETTE.success}>●</Text>;\n case \"failed\":\n return <Text color={PALETTE.error}>✖</Text>;\n default:\n return <Text color={PALETTE.muted}>{status}</Text>;\n }\n}\n\nfunction statusLabelText(status: TaskStatus): { text: string; color: string } {\n switch (status) {\n case \"pending\": return { text: \"pending\", color: PALETTE.muted };\n case \"planning\": return { text: \"planning\", color: PALETTE.planning };\n case \"running\": return { text: \"executing\", color: PALETTE.accent };\n case \"generating\": return { text: \"generating\", color: PALETTE.accent };\n case \"syncing\": return { text: \"syncing\", color: PALETTE.accent };\n case \"paused\": return { text: \"paused\", color: PALETTE.warn };\n case \"done\": return { text: \"done\", color: PALETTE.success };\n case \"failed\": return { text: \"failed\", color: PALETTE.error };\n default: return { text: status, color: PALETTE.muted };\n }\n}\n\nfunction TaskRow({ ts, index, totalTasks }: { ts: TaskState; index: number; totalTasks: number }) {\n const [now, setNow] = useState(Date.now());\n useEffect(() => {\n if (isActiveStatus(ts.status)) {\n const timer = setInterval(() => setNow(Date.now()), 1000);\n return () => clearInterval(timer);\n }\n }, [ts.status]);\n\n const { text: labelText, color: labelColor } = statusLabelText(ts.status);\n const elapsedStr = isActiveStatus(ts.status)\n ? elapsed(now - (ts.elapsed || now))\n : ts.status === \"done\" && ts.elapsed\n ? elapsed(ts.elapsed)\n : \"\";\n\n const isDone = ts.status === \"done\" || ts.status === \"failed\";\n const textColor = isDone ? PALETTE.muted : PALETTE.text;\n\n return (\n <Box flexDirection=\"column\">\n <Box marginLeft={4}>\n <StatusIcon status={ts.status} />\n <Text color={PALETTE.muted}> #{index + 1} </Text>\n <Text color={textColor}>{truncateText(ts.task.text, 50)}</Text>\n <Spacer />\n <Text color={labelColor}>{labelText}</Text>\n {elapsedStr ? <Text color={PALETTE.muted}> {elapsedStr}</Text> : null}\n </Box>\n {ts.status === \"generating\" && ts.feedback && (\n <Box marginLeft={11}>\n <Text color={PALETTE.muted}>└─ {truncateText(sanitizeSubordinateText(ts.feedback), 60)}</Text>\n </Box>\n )}\n {ts.error && (\n <Box marginLeft={11}>\n <Text color={PALETTE.error}>└─ {ts.error}</Text>\n </Box>\n )}\n </Box>\n );\n}\n\nfunction TaskList({ tasks, phase }: { tasks: TaskState[]; phase: TuiState[\"phase\"] }) {\n if (phase !== \"dispatching\" && phase !== \"paused\" && phase !== \"done\") return null;\n\n const activeWorktrees = new Set(tasks.map((t) => t.worktree).filter(Boolean));\n const showWorktree = activeWorktrees.size > 1;\n\n if (showWorktree) {\n return <WorktreeGroupedList tasks={tasks} />;\n }\n\n return <FlatTaskList tasks={tasks} />;\n}\n\nfunction FlatTaskList({ tasks }: { tasks: TaskState[] }) {\n const paused = tasks.filter((t) => t.status === \"paused\");\n const running = tasks.filter((t) => isActiveStatus(t.status));\n const completed = tasks.filter((t) => t.status === \"done\" || t.status === \"failed\");\n const pending = tasks.filter((t) => t.status === \"pending\");\n\n const visibleRunning = running.slice(0, 8);\n const visible: TaskState[] = [\n ...completed.slice(-3),\n ...paused.slice(0, 3),\n ...visibleRunning,\n ...pending.slice(0, 3),\n ];\n\n return (\n <Box flexDirection=\"column\" marginTop={1}>\n {completed.length > 3 && (\n <Box marginLeft={4}>\n <Text color={PALETTE.muted}>··· {completed.length - 3} earlier task(s) completed</Text>\n </Box>\n )}\n {visible.map((ts) => {\n const idx = tasks.indexOf(ts);\n return <TaskRow key={idx} ts={ts} index={idx} totalTasks={tasks.length} />;\n })}\n {running.length > 8 && (\n <Box marginLeft={4}>\n <Text color={PALETTE.muted}>··· {running.length - 8} more running</Text>\n </Box>\n )}\n {pending.length > 3 && (\n <Box marginLeft={4}>\n <Text color={PALETTE.muted}>··· {pending.length - 3} more task(s) pending</Text>\n </Box>\n )}\n </Box>\n );\n}\n\nfunction WorktreeGroupedList({ tasks }: { tasks: TaskState[] }) {\n const [now, setNow] = useState(Date.now());\n useEffect(() => {\n const timer = setInterval(() => setNow(Date.now()), 1000);\n return () => clearInterval(timer);\n }, []);\n\n const groups = new Map<string, TaskState[]>();\n const ungrouped: TaskState[] = [];\n for (const ts of tasks) {\n if (ts.worktree) {\n const arr = groups.get(ts.worktree) ?? [];\n arr.push(ts);\n groups.set(ts.worktree, arr);\n } else {\n ungrouped.push(ts);\n }\n }\n\n const doneGroups: [string, TaskState[]][] = [];\n const activeGroups: [string, TaskState[]][] = [];\n for (const [wt, wtTasks] of groups) {\n const allDone = wtTasks.every((t) => t.status === \"done\" || t.status === \"failed\");\n if (allDone) {\n doneGroups.push([wt, wtTasks]);\n } else {\n activeGroups.push([wt, wtTasks]);\n }\n }\n\n return (\n <Box flexDirection=\"column\" marginTop={1}>\n {doneGroups.length > 3 && (\n <Box marginLeft={4}>\n <Text color={PALETTE.muted}>··· {doneGroups.length - 3} earlier issue(s) completed</Text>\n </Box>\n )}\n {doneGroups.slice(-3).map(([wt, wtTasks]) => {\n const issueNum = wt.match(/^(\\d+)/)?.[1] ?? wt.slice(0, 12);\n const anyFailed = wtTasks.some((t) => t.status === \"failed\");\n const doneCount = wtTasks.filter((t) => t.status === \"done\").length;\n const maxElapsed = Math.max(...wtTasks.map((t) => t.elapsed ?? 0));\n return (\n <Box key={wt} marginLeft={4}>\n {anyFailed\n ? <Text color={PALETTE.error}>✖</Text>\n : <Text color={PALETTE.success}>●</Text>}\n <Text color={PALETTE.muted}> #{issueNum} {doneCount}/{wtTasks.length} tasks {elapsed(maxElapsed)}</Text>\n </Box>\n );\n })}\n {activeGroups.map(([wt, wtTasks]) => {\n const issueNum = wt.match(/^(\\d+)/)?.[1] ?? wt.slice(0, 12);\n const activeTasks = wtTasks.filter((t) => isActiveStatus(t.status) || t.status === \"paused\");\n const firstActive = activeTasks[0];\n const displayStatus = firstActive?.status ?? \"pending\";\n const text = firstActive?.task.text ?? wtTasks[0]?.task.text ?? \"\";\n const earliest = activeTasks.length > 0\n ? Math.min(...activeTasks.map((t) => t.elapsed ?? now))\n : now;\n const elapsedStr = elapsed(now - earliest);\n const countLabel = activeTasks.length > 0\n ? `${activeTasks.length} active`\n : `${wtTasks.length} pending`;\n return (\n <Box key={wt} marginLeft={4}>\n <StatusIcon status={displayStatus} />\n <Text color=\"white\"> #{issueNum} </Text>\n <Text>{countLabel} {truncateText(text, 40)}</Text>\n <Spacer />\n <Text color={PALETTE.muted}>{elapsedStr}</Text>\n </Box>\n );\n })}\n {ungrouped.filter((ts) => isActiveStatus(ts.status) || ts.status === \"paused\").map((ts) => {\n const idx = tasks.indexOf(ts);\n return <TaskRow key={idx} ts={ts} index={idx} totalTasks={tasks.length} />;\n })}\n </Box>\n );\n}\n\nfunction RecoveryPrompt({ recovery, onAction }: {\n recovery: TuiRecoveryState;\n onAction: (action: RecoveryAction) => void;\n}) {\n const [selected, setSelected] = useState<RecoveryAction>(recovery.selectedAction);\n\n useInput((input, key) => {\n if (key.ctrl && input === \"c\") {\n onAction(\"quit\");\n return;\n }\n if (input === \"r\" || input === \"R\") {\n onAction(\"rerun\");\n return;\n }\n if (input === \"q\" || input === \"Q\") {\n onAction(\"quit\");\n return;\n }\n if (key.tab || key.leftArrow || key.rightArrow) {\n setSelected((prev) => (prev === \"rerun\" ? \"quit\" : \"rerun\"));\n return;\n }\n if (key.return || input === \" \") {\n onAction(selected);\n }\n });\n\n // Keep external state in sync\n useEffect(() => {\n if (recovery.selectedAction !== selected) {\n recovery.selectedAction = selected;\n }\n }, [selected]);\n\n return (\n <Box flexDirection=\"column\" marginLeft={2} marginTop={1} borderStyle=\"round\" borderColor={PALETTE.error} paddingLeft={1} paddingRight={1}>\n <Box>\n <Text color={PALETTE.warn}>Recovery: </Text>\n <Text color=\"white\">#{recovery.taskIndex + 1} </Text>\n <Text>{recovery.taskText}</Text>\n </Box>\n <Text color={PALETTE.error}>{recovery.error}</Text>\n {recovery.issue && (\n <Text color={PALETTE.muted}>Issue #{recovery.issue.number} - {recovery.issue.title}</Text>\n )}\n {recovery.worktree && (\n <Text color={PALETTE.muted}>Worktree: {recovery.worktree}</Text>\n )}\n <Box marginTop={1}>\n <Text color={PALETTE.error}>✖ </Text>\n {selected === \"rerun\"\n ? <Text color={PALETTE.success} bold>[▶ rerun]</Text>\n : <Text color={PALETTE.muted}>▶ rerun</Text>}\n <Text> </Text>\n {selected === \"quit\"\n ? <Text color={PALETTE.error} bold>[q quit]</Text>\n : <Text color={PALETTE.muted}>q quit</Text>}\n </Box>\n <Text color={PALETTE.muted}>Tab/←/→ switch · Enter/Space runs selection · r reruns · q quits</Text>\n </Box>\n );\n}\n\nfunction Summary({ tasks }: { tasks: TaskState[] }) {\n const done = tasks.filter((t) => t.status === \"done\").length;\n const failed = tasks.filter((t) => t.status === \"failed\").length;\n const remaining = tasks.length - done - failed;\n\n if (tasks.length === 0) return null;\n\n return (\n <Box flexDirection=\"column\" marginLeft={2} marginTop={1}>\n <Text color={PALETTE.chrome}>{\"─\".repeat(60)}</Text>\n <Box>\n {done > 0 && <Text color={PALETTE.success}>{done} passed</Text>}\n {done > 0 && (failed > 0 || remaining > 0) && <Text color={PALETTE.muted}> · </Text>}\n {failed > 0 && <Text color={PALETTE.error}>{failed} failed</Text>}\n {failed > 0 && remaining > 0 && <Text color={PALETTE.muted}> · </Text>}\n {remaining > 0 && <Text color={PALETTE.muted}>{remaining} remaining</Text>}\n </Box>\n </Box>\n );\n}\n\nfunction FilesFound({ count, phase }: { count: number; phase: TuiState[\"phase\"] }) {\n if (phase === \"dispatching\" || phase === \"paused\" || phase === \"done\" || count === 0) return null;\n return (\n <Box marginLeft={2}>\n <Text color={PALETTE.muted}>Found {count} file(s)</Text>\n </Box>\n );\n}\n\n// ── Main App Component ────────────────────────────────────────────\n\ninterface AppProps {\n stateRef: React.MutableRefObject<TuiState>;\n onRecoveryAction?: (action: RecoveryAction) => void;\n}\n\nfunction App({ stateRef, onRecoveryAction }: AppProps) {\n const [state, setState] = useState<TuiState>(stateRef.current);\n\n // Expose setState for external callers\n useEffect(() => {\n (stateRef as any).__setState = setState;\n }, []);\n\n const s = state;\n const showProgress = s.phase === \"dispatching\" || s.phase === \"paused\" || s.phase === \"done\";\n const done = s.tasks.filter((t) => t.status === \"done\").length;\n const failed = s.tasks.filter((t) => t.status === \"failed\").length;\n\n return (\n <Box flexDirection=\"column\">\n <Header\n provider={s.provider}\n model={s.model}\n source={s.source}\n currentIssue={s.currentIssue}\n />\n <NotificationBanner notification={s.notification} />\n <PhaseLabel phase={s.phase} provider={s.provider} mode={s.mode} startTime={s.startTime} />\n {showProgress && (\n <>\n <ProgressBar done={done + failed} total={s.tasks.length} />\n <TaskList tasks={s.tasks} phase={s.phase} />\n {s.phase === \"paused\" && s.recovery && onRecoveryAction && (\n <RecoveryPrompt recovery={s.recovery} onAction={onRecoveryAction} />\n )}\n <Summary tasks={s.tasks} />\n </>\n )}\n <FilesFound count={s.filesFound} phase={s.phase} />\n </Box>\n );\n}\n\n// ── Public API ────────────────────────────────────────────────────\n\nexport function createTui(options?: {\n input?: NodeJS.ReadStream;\n output?: Pick<NodeJS.WriteStream, \"write\"> & { columns?: number };\n}): {\n state: TuiState;\n update: () => void;\n stop: () => void;\n waitForRecoveryAction: () => Promise<RecoveryAction>;\n} {\n const state: TuiState = {\n tasks: [],\n phase: \"discovering\",\n mode: \"dispatch\",\n startTime: Date.now(),\n filesFound: 0,\n };\n\n const stateRef = { current: state } as React.MutableRefObject<TuiState> & {\n __setState?: React.Dispatch<React.SetStateAction<TuiState>>;\n };\n\n let recoveryResolver: ((action: RecoveryAction) => void) | null = null;\n let activeRecoveryPromise: Promise<RecoveryAction> | null = null;\n\n const onRecoveryAction = (action: RecoveryAction) => {\n if (recoveryResolver) {\n recoveryResolver(action);\n recoveryResolver = null;\n activeRecoveryPromise = null;\n }\n };\n\n // Use Ink only when explicitly requested AND in a real TTY terminal.\n // Default to plain text renderer for backward compat (tests, non-TTY, verbose).\n const useInk = !options?.output && !options?.input\n && process.stdout.isTTY === true\n && !process.env.VITEST;\n\n let inkInstance: ReturnType<typeof render> | null = null;\n\n const plainOutput = options?.output ?? process.stdout;\n\n let plainInterval: ReturnType<typeof setInterval> | null = null;\n let spinnerIndex = 0;\n let lastLineCount = 0;\n\n if (useInk) {\n // Real terminal rendering with Ink\n inkInstance = render(\n <App stateRef={stateRef} onRecoveryAction={onRecoveryAction} />,\n {\n stdout: process.stdout,\n stdin: options?.input ?? process.stdin,\n },\n );\n } else {\n // Plain text renderer for tests, non-TTY, verbose mode\n renderPlainText(state, plainOutput);\n }\n\n if (!useInk) {\n const SPINNER_FRAMES = [\"⠋\", \"⠙\", \"⠹\", \"⠸\", \"⠼\", \"⠴\", \"⠦\", \"⠧\", \"⠇\", \"⠏\"];\n plainInterval = setInterval(() => {\n spinnerIndex++;\n renderPlainText(state, plainOutput, SPINNER_FRAMES, spinnerIndex);\n }, 80);\n }\n\n function renderPlainText(\n s: TuiState,\n output: Pick<NodeJS.WriteStream, \"write\"> & { columns?: number },\n frames: string[] = [\"⠋\", \"⠙\", \"⠹\", \"⠸\", \"⠼\", \"⠴\", \"⠦\", \"⠧\", \"⠇\", \"⠏\"],\n sIdx: number = 0,\n ) {\n const cols = output.columns || 80;\n const sp = frames[sIdx % frames.length];\n const lines: string[] = [];\n const now = Date.now();\n\n // Header\n lines.push(\"\");\n lines.push(` ⚡ dispatch — AI task orchestration`);\n if (s.provider) lines.push(` provider: ${s.provider}`);\n if (s.model) lines.push(` model: ${s.model}`);\n if (s.source) lines.push(` source: ${s.source}`);\n if (s.currentIssue) lines.push(` issue: #${s.currentIssue.number} — ${s.currentIssue.title}`);\n lines.push(` ${\"─\".repeat(48)}`);\n\n // Notification\n if (s.notification) {\n lines.push(\"\");\n for (const l of s.notification.split(\"\\n\")) lines.push(` ⚠ ${l}`);\n }\n\n // Phase\n const totalElapsed = elapsed(now - s.startTime);\n switch (s.phase) {\n case \"discovering\": lines.push(` ${sp} Discovering task files... ${totalElapsed}`); break;\n case \"parsing\": lines.push(` ${sp} Parsing tasks... ${totalElapsed}`); break;\n case \"booting\": lines.push(` ${sp} Connecting to ${s.provider ?? \"provider\"}... ${totalElapsed}`); break;\n case \"dispatching\": lines.push(` ${sp} ${s.mode === \"spec\" ? \"Generating specs\" : \"Dispatching tasks\"}... ${totalElapsed}`); break;\n case \"paused\": lines.push(` ◐ Waiting for rerun... ${totalElapsed}`); break;\n case \"done\": lines.push(` ✔ Complete ${totalElapsed}`); break;\n }\n\n const showProgress = s.phase === \"dispatching\" || s.phase === \"paused\" || s.phase === \"done\";\n\n if (showProgress) {\n const done = s.tasks.filter((t) => t.status === \"done\").length;\n const failed = s.tasks.filter((t) => t.status === \"failed\").length;\n const total = s.tasks.length;\n const BAR_WIDTH = 30;\n const filled = total === 0 ? 0 : Math.round(((done + failed) / total) * BAR_WIDTH);\n const empty = BAR_WIDTH - filled;\n const pct = total === 0 ? 0 : Math.round(((done + failed) / total) * 100);\n\n lines.push(\"\");\n lines.push(` ${\"█\".repeat(filled)}${\"░\".repeat(empty)} ${pct}% ${done + failed}/${total} tasks`);\n lines.push(\"\");\n\n // Task list\n const activeWorktrees = new Set(s.tasks.map((t) => t.worktree).filter(Boolean));\n const showWorktree = activeWorktrees.size > 1;\n const maxTextLen = cols - 30;\n\n if (showWorktree) {\n const groups = new Map<string, TaskState[]>();\n const ungrouped: TaskState[] = [];\n for (const ts of s.tasks) {\n if (ts.worktree) {\n const arr = groups.get(ts.worktree) ?? [];\n arr.push(ts);\n groups.set(ts.worktree, arr);\n } else {\n ungrouped.push(ts);\n }\n }\n const doneGroups: [string, TaskState[]][] = [];\n const activeGroups: [string, TaskState[]][] = [];\n for (const [wt, tasks] of groups) {\n if (tasks.every((t) => t.status === \"done\" || t.status === \"failed\")) {\n doneGroups.push([wt, tasks]);\n } else {\n activeGroups.push([wt, tasks]);\n }\n }\n if (doneGroups.length > 3) {\n lines.push(` ··· ${doneGroups.length - 3} earlier issue(s) completed`);\n }\n for (const [wt, tasks] of doneGroups.slice(-3)) {\n const issueNum = wt.match(/^(\\d+)/)?.[1] ?? wt.slice(0, 12);\n const anyFailed = tasks.some((t) => t.status === \"failed\");\n const icon = anyFailed ? \"✖\" : \"●\";\n const doneCount = tasks.filter((t) => t.status === \"done\").length;\n const maxEl = Math.max(...tasks.map((t) => t.elapsed ?? 0));\n lines.push(` ${icon} #${issueNum} ${doneCount}/${tasks.length} tasks ${elapsed(maxEl)}`);\n }\n for (const [wt, tasks] of activeGroups) {\n const issueNum = wt.match(/^(\\d+)/)?.[1] ?? wt.slice(0, 12);\n const activeTasks = tasks.filter((t) => isActiveStatus(t.status) || t.status === \"paused\");\n const firstActive = activeTasks[0];\n const displayStatus = firstActive?.status ?? \"pending\";\n let text = firstActive?.task.text ?? tasks[0]?.task.text ?? \"\";\n if (text.length > 60) text = text.slice(0, 59) + \"…\";\n const earliest = activeTasks.length > 0 ? Math.min(...activeTasks.map((t) => t.elapsed ?? now)) : now;\n const elapsedStr = elapsed(now - earliest);\n const countLabel = activeTasks.length > 0 ? `${activeTasks.length} active` : `${tasks.length} pending`;\n const sIcon = displayStatus === \"pending\" ? \"○\"\n : displayStatus === \"done\" ? \"●\"\n : displayStatus === \"failed\" ? \"✖\"\n : displayStatus === \"paused\" ? \"◐\"\n : sp;\n lines.push(` ${sIcon} #${issueNum} ${countLabel} ${text} ${elapsedStr}`);\n }\n for (const ts of ungrouped) {\n if (!isActiveStatus(ts.status) && ts.status !== \"paused\") continue;\n const idx = s.tasks.indexOf(ts);\n const icon = isActiveStatus(ts.status) ? sp : ts.status === \"paused\" ? \"◐\" : \"○\";\n const text = truncateText(ts.task.text, maxTextLen);\n const elapsedStr = isActiveStatus(ts.status) ? ` ${elapsed(now - (ts.elapsed || now))}` : \"\";\n const label = statusLabelPlain(ts.status);\n lines.push(` ${icon} #${idx + 1} ${text} ${label}${elapsedStr}`);\n if (ts.status === \"generating\" && ts.feedback) {\n const sanitized = sanitizeSubordinateText(ts.feedback);\n if (sanitized) lines.push(` └─ ${truncateText(sanitized, Math.max(16, cols - 10))}`);\n }\n if (ts.error) lines.push(` └─ ${ts.error}`);\n }\n } else {\n const paused = s.tasks.filter((t) => t.status === \"paused\");\n const running = s.tasks.filter((t) => isActiveStatus(t.status));\n const completed = s.tasks.filter((t) => t.status === \"done\" || t.status === \"failed\");\n const pending = s.tasks.filter((t) => t.status === \"pending\");\n const visibleRunning = running.slice(0, 8);\n const visible = [...completed.slice(-3), ...paused.slice(0, 3), ...visibleRunning, ...pending.slice(0, 3)];\n\n if (completed.length > 3) lines.push(` ··· ${completed.length - 3} earlier task(s) completed`);\n\n for (const ts of visible) {\n const idx = s.tasks.indexOf(ts);\n const icon = ts.status === \"done\" ? \"●\"\n : ts.status === \"failed\" ? \"✖\"\n : ts.status === \"paused\" ? \"◐\"\n : ts.status === \"pending\" ? \"○\"\n : sp;\n const text = truncateText(ts.task.text, maxTextLen);\n const elapsedStr = isActiveStatus(ts.status)\n ? ` ${elapsed(now - (ts.elapsed || now))}`\n : ts.status === \"done\" && ts.elapsed ? ` ${elapsed(ts.elapsed)}` : \"\";\n const label = statusLabelPlain(ts.status);\n lines.push(` ${icon} #${idx + 1} ${text} ${label}${elapsedStr}`);\n if (ts.status === \"generating\" && ts.feedback) {\n const sanitized = sanitizeSubordinateText(ts.feedback);\n if (sanitized) lines.push(` └─ ${truncateText(sanitized, Math.max(16, cols - 10))}`);\n }\n if (ts.error) lines.push(` └─ ${ts.error}`);\n }\n\n if (running.length > 8) lines.push(` ··· ${running.length - 8} more running`);\n if (pending.length > 3) lines.push(` ··· ${pending.length - 3} more task(s) pending`);\n }\n\n // Recovery\n if (s.phase === \"paused\" && s.recovery) {\n const sel = s.recovery.selectedAction ?? \"rerun\";\n lines.push(\"\");\n lines.push(` Recovery: #${s.recovery.taskIndex + 1} ${s.recovery.taskText}`);\n lines.push(` ${s.recovery.error}`);\n if (s.recovery.issue) lines.push(` Issue #${s.recovery.issue.number} - ${s.recovery.issue.title}`);\n if (s.recovery.worktree) lines.push(` Worktree: ${s.recovery.worktree}`);\n const rerunLabel = sel === \"rerun\" ? \"[▶ rerun]\" : \"▶ rerun\";\n const quitLabel = sel === \"quit\" ? \"[q quit]\" : \"q quit\";\n lines.push(` ✖ ${rerunLabel} ${quitLabel}`);\n lines.push(` Tab/←/→ switch · Enter/Space runs selection · r reruns · q quits`);\n }\n\n // Summary\n lines.push(\"\");\n const parts: string[] = [];\n const doneCount = s.tasks.filter((t) => t.status === \"done\").length;\n const failedCount = s.tasks.filter((t) => t.status === \"failed\").length;\n if (doneCount > 0) parts.push(`${doneCount} passed`);\n if (failedCount > 0) parts.push(`${failedCount} failed`);\n if (s.tasks.length - doneCount - failedCount > 0) parts.push(`${s.tasks.length - doneCount - failedCount} remaining`);\n lines.push(` ${parts.join(\" · \")}`);\n } else if (s.filesFound > 0) {\n lines.push(` Found ${s.filesFound} file(s)`);\n }\n\n lines.push(\"\");\n const rendered = lines.join(\"\\n\");\n\n // ANSI cursor control for in-place updates\n const newLineCount = countVisualRows(rendered, cols);\n let buffer = \"\";\n if (lastLineCount > 0) buffer += `\\x1B[${lastLineCount}A`;\n buffer += rendered.split(\"\\n\").map((line) => line + \"\\x1B[K\").join(\"\\n\");\n const leftover = lastLineCount - newLineCount;\n if (leftover > 0) {\n for (let i = 0; i < leftover; i++) buffer += \"\\n\\x1B[K\";\n buffer += `\\x1B[${leftover}A`;\n }\n output.write(buffer);\n lastLineCount = newLineCount;\n }\n\n function countVisualRows(text: string, cols: number): number {\n const stripped = text.replace(/\\x1B\\[[0-9;]*m/g, \"\");\n const safeCols = Math.max(1, cols);\n return stripped.split(\"\\n\").reduce((sum, line) => sum + Math.max(1, Math.ceil(line.length / safeCols)), 0);\n }\n\n function statusLabelPlain(status: TaskStatus): string {\n switch (status) {\n case \"pending\": return \"pending\";\n case \"planning\": return \"planning\";\n case \"running\": return \"executing\";\n case \"generating\": return \"generating\";\n case \"syncing\": return \"syncing\";\n case \"paused\": return \"paused\";\n case \"done\": return \"done\";\n case \"failed\": return \"failed\";\n default: return status;\n }\n }\n\n const update = () => {\n if (!useInk) {\n renderPlainText(state, plainOutput, [\"⠋\", \"⠙\", \"⠹\", \"⠸\", \"⠼\", \"⠴\", \"⠦\", \"⠧\", \"⠇\", \"⠏\"], spinnerIndex);\n } else if ((stateRef as any).__setState) {\n // Trigger React re-render by creating a new state snapshot\n (stateRef as any).__setState({ ...state });\n }\n };\n\n const stop = () => {\n if (plainInterval) {\n clearInterval(plainInterval);\n plainInterval = null;\n }\n if (!useInk) {\n renderPlainText(state, plainOutput, [\"⠋\", \"⠙\", \"⠹\", \"⠸\", \"⠼\", \"⠴\", \"⠦\", \"⠧\", \"⠇\", \"⠏\"], spinnerIndex);\n }\n if (inkInstance) {\n inkInstance.unmount();\n inkInstance = null;\n }\n };\n\n const waitForRecoveryAction = (): Promise<RecoveryAction> => {\n if (activeRecoveryPromise) return activeRecoveryPromise;\n\n if (!useInk) {\n // For test/custom output: use raw keypress handling (same as old TUI)\n const input = options?.input ?? process.stdin;\n activeRecoveryPromise = new Promise<RecoveryAction>((resolve) => {\n const { emitKeypressEvents } = require(\"node:readline\");\n const ttyInput = input as NodeJS.ReadStream & {\n isRaw?: boolean;\n isTTY?: boolean;\n setRawMode?: (mode: boolean) => void;\n };\n const wasRaw = ttyInput.isRaw ?? false;\n const canToggleRawMode = ttyInput.isTTY === true && typeof ttyInput.setRawMode === \"function\";\n if (state.recovery) {\n state.recovery.selectedAction = state.recovery.selectedAction ?? \"rerun\";\n update();\n }\n\n emitKeypressEvents(input);\n if (canToggleRawMode) {\n (ttyInput.setRawMode as (mode: boolean) => void)(true);\n }\n\n let cleanupFn: (() => void) | null = null;\n\n const finish = (action: RecoveryAction) => {\n cleanupFn?.();\n resolve(action);\n };\n\n const updateSelection = (nextAction: RecoveryAction) => {\n if (!state.recovery || state.recovery.selectedAction === nextAction) return;\n state.recovery.selectedAction = nextAction;\n update();\n };\n\n const toggleAction = (current: RecoveryAction): RecoveryAction =>\n current === \"rerun\" ? \"quit\" : \"rerun\";\n\n const onKeypress = (str: string | undefined, key: { name?: string; ctrl?: boolean } | undefined) => {\n const name = key?.name ?? str;\n if (key?.ctrl && name === \"c\") { finish(\"quit\"); return; }\n if (name === \"r\" || name === \"R\") { finish(\"rerun\"); return; }\n if (name === \"q\" || name === \"Q\") { finish(\"quit\"); return; }\n if (name === \"tab\" || name === \"left\" || name === \"right\") {\n updateSelection(toggleAction(state.recovery?.selectedAction ?? \"rerun\"));\n return;\n }\n if (name === \"return\" || name === \"enter\" || name === \"space\" || str === \" \") {\n finish(state.recovery?.selectedAction ?? \"rerun\");\n }\n };\n\n cleanupFn = () => {\n input.off(\"keypress\", onKeypress);\n if (canToggleRawMode) {\n (ttyInput.setRawMode as (mode: boolean) => void)(wasRaw);\n }\n cleanupFn = null;\n activeRecoveryPromise = null;\n };\n\n input.on(\"keypress\", onKeypress);\n });\n return activeRecoveryPromise;\n }\n\n // For Ink mode: use promise that resolves via onRecoveryAction callback\n activeRecoveryPromise = new Promise<RecoveryAction>((resolve) => {\n recoveryResolver = resolve;\n });\n update();\n return activeRecoveryPromise;\n };\n\n return { state, update, stop, waitForRecoveryAction };\n}\n","/**\n * Generic retry utility.\n *\n * Provides a reusable `withRetry` wrapper that retries an async function\n * on any thrown error up to a configurable number of times. Used by the\n * dispatch pipeline to add resilience to agent calls.\n */\n\nimport { log } from \"./logger.js\";\n\n/** Default retry count used across shared agent retry flows. */\nexport const DEFAULT_RETRY_COUNT = 3;\n\n/** Options for `withRetry`. */\nexport interface RetryOptions {\n /** Label for log messages identifying the operation being retried. */\n label?: string;\n /** Base delay in milliseconds for exponential backoff (default: 500). */\n baseDelayMs?: number;\n}\n\n/**\n * Retry an async function up to `maxRetries` times on failure.\n *\n * Calls `fn` and returns its result on the first success. If `fn` throws,\n * it is retried up to `maxRetries` additional times. If all attempts fail,\n * the last error is re-thrown.\n *\n * @param fn - Async function to execute (called with no arguments)\n * @param maxRetries - Number of retry attempts (0 = no retries, 1 = one retry, etc.)\n * @param options - Optional label for log output\n * @returns The resolved value of `fn`\n * @throws The last error if all attempts are exhausted\n */\nexport async function withRetry<T>(\n fn: () => Promise<T>,\n maxRetries: number,\n options?: RetryOptions,\n): Promise<T> {\n const maxAttempts = maxRetries + 1;\n const label = options?.label;\n const baseDelay = options?.baseDelayMs ?? 500;\n let lastError: unknown;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n return await fn();\n } catch (err) {\n lastError = err;\n const suffix = label ? ` [${label}]` : \"\";\n if (attempt < maxAttempts) {\n log.warn(\n `Attempt ${attempt}/${maxAttempts} failed${suffix}: ${log.extractMessage(err)}`,\n );\n // Exponential backoff with jitter: baseDelay * 2^(attempt-1) + random jitter\n const delay = baseDelay * Math.pow(2, attempt - 1);\n const jitter = Math.floor(Math.random() * baseDelay);\n log.debug(`Retrying${suffix} in ${delay + jitter}ms (attempt ${attempt + 1}/${maxAttempts})`);\n await new Promise((resolve) => setTimeout(resolve, delay + jitter));\n }\n }\n }\n\n throw lastError;\n}\n","/**\n * Sliding-window concurrency utility.\n *\n * Provides a reusable `runWithConcurrency` function that processes a queue\n * of work items with a fixed concurrency limit. Unlike batch-then-await\n * (`Promise.all` on N items), this starts a new task as soon as any\n * running task completes, keeping the number of active tasks pinned to\n * `min(limit, remaining)` at all times.\n */\n\n/** Options for {@link runWithConcurrency}. */\nexport interface ConcurrencyOptions<T, R> {\n /** Work items to process. */\n items: T[];\n /** Maximum number of concurrent workers. */\n concurrency: number;\n /** Async function invoked once per item. */\n worker: (item: T, index: number) => Promise<R>;\n /**\n * Optional signal that, when it returns `true`, prevents new items from\n * being launched. Already-running tasks are allowed to finish.\n */\n shouldStop?: () => boolean;\n}\n\n/** Result of a single work item. */\nexport type ConcurrencyResult<R> =\n | { status: \"fulfilled\"; value: R }\n | { status: \"rejected\"; reason: unknown }\n | { status: \"skipped\" };\n\n/**\n * Process `items` through `worker` with sliding-window concurrency.\n *\n * At most `concurrency` invocations of `worker` run simultaneously.\n * When any running worker settles, the next queued item is started\n * immediately, keeping utilisation at the concurrency limit until the\n * queue is drained.\n *\n * If `shouldStop` is provided and returns `true`, no new items are\n * launched, but already-running workers are awaited before returning.\n *\n * Returns an array of per-item results in the same order as `items`,\n * each wrapped in a `{ status, value/reason }` discriminated union\n * (similar to `Promise.allSettled`).\n *\n * @returns Per-item results in input order.\n */\nexport async function runWithConcurrency<T, R>(\n options: ConcurrencyOptions<T, R>,\n): Promise<ConcurrencyResult<R>[]> {\n const { items, concurrency, worker, shouldStop } = options;\n\n if (items.length === 0) return [];\n\n const limit = Math.max(1, concurrency);\n const results: ConcurrencyResult<R>[] = new Array(items.length);\n let nextIndex = 0;\n\n return new Promise<ConcurrencyResult<R>[]>((resolve) => {\n let active = 0;\n\n const launch = (): void => {\n while (active < limit && nextIndex < items.length) {\n if (shouldStop?.()) break;\n\n const idx = nextIndex++;\n active++;\n\n worker(items[idx], idx).then(\n (value) => {\n results[idx] = { status: \"fulfilled\", value };\n active--;\n launch();\n },\n (reason) => {\n results[idx] = { status: \"rejected\", reason };\n active--;\n launch();\n },\n );\n }\n\n if (active === 0) {\n // Fill slots for items that were never launched (due to shouldStop)\n for (let i = 0; i < results.length; i++) {\n if (!(i in results)) {\n results[i] = { status: \"skipped\" };\n }\n }\n resolve(results);\n }\n };\n\n launch();\n });\n}\n","import { basename, join } from \"node:path\";\nimport { mkdtemp, writeFile } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { log } from \"../helpers/logger.js\";\nimport type { Datasource, DatasourceName, IssueDetails, IssueFetchOptions } from \"../datasources/interface.js\";\nimport type { Task } from \"../parser.js\";\nimport type { DispatchResult } from \"../dispatcher.js\";\nimport { slugify, MAX_SLUG_LENGTH } from \"../helpers/slugify.js\";\n\nconst exec = promisify(execFile);\n\n/** Result of writing issue items to a temp directory. */\nexport interface WriteItemsResult {\n /** Sorted list of written file paths */\n files: string[];\n /** Mapping from file path to the original IssueDetails */\n issueDetailsByFile: Map<string, IssueDetails>;\n}\n\n/**\n * Parse an issue ID and slug from a `<id>-<slug>.md` filename.\n *\n * Returns the numeric issue ID and slug, or `null` if the filename\n * does not match the expected `<id>-<slug>.md` pattern.\n */\nexport function parseIssueFilename(filePath: string): { issueId: string; slug: string } | null {\n const filename = basename(filePath);\n const match = /^(\\d+)-(.+)\\.md$/.exec(filename);\n if (!match) return null;\n return { issueId: match[1], slug: match[2] };\n}\n\n/**\n * Fetch specific issues by ID from a datasource.\n * Logs a warning and skips any ID that fails to fetch.\n */\nexport async function fetchItemsById(\n issueIds: string[],\n datasource: Datasource,\n fetchOpts: IssueFetchOptions,\n): Promise<IssueDetails[]> {\n const ids = issueIds.flatMap((id) =>\n id.split(\",\").map((s) => s.trim()).filter(Boolean)\n );\n const items = [];\n for (const id of ids) {\n try {\n const item = await datasource.fetch(id, fetchOpts);\n items.push(item);\n } catch (err) {\n const prefix = id.includes(\"/\") || id.includes(\"\\\\\") || id.endsWith(\".md\") ? \"\" : \"#\";\n log.warn(`Could not fetch issue ${prefix}${id}: ${log.formatErrorChain(err)}`);\n }\n }\n return items;\n}\n\n/**\n * Write a list of IssueDetails to a temp directory as `{number}-{slug}.md` files.\n * Returns the sorted file paths and a mapping from each path to its original IssueDetails.\n */\nexport async function writeItemsToTempDir(items: IssueDetails[]): Promise<WriteItemsResult> {\n const tempDir = await mkdtemp(join(tmpdir(), \"dispatch-\"));\n const files: string[] = [];\n const issueDetailsByFile = new Map<string, IssueDetails>();\n\n for (const item of items) {\n const slug = slugify(item.title, MAX_SLUG_LENGTH);\n // When item.number is a file path, extract just the basename without extension\n const id = item.number.includes(\"/\") || item.number.includes(\"\\\\\")\n ? basename(item.number, \".md\")\n : item.number;\n const filename = `${id}-${slug}.md`;\n const filepath = join(tempDir, filename);\n await writeFile(filepath, item.body, \"utf-8\");\n files.push(filepath);\n issueDetailsByFile.set(filepath, item);\n }\n\n files.sort((a, b) => {\n const numA = parseInt(basename(a).match(/^(\\d+)/)?.[1] ?? \"0\", 10);\n const numB = parseInt(basename(b).match(/^(\\d+)/)?.[1] ?? \"0\", 10);\n if (numA !== numB) return numA - numB;\n return a.localeCompare(b);\n });\n\n return { files, issueDetailsByFile };\n}\n\n/**\n * Retrieve one-line commit summaries for commits on the current branch\n * that are not on the given default branch.\n *\n * @param defaultBranch - The base branch to compare against (e.g. \"main\")\n * @param cwd - Working directory (git repo root)\n * @returns Array of commit summary strings, one per commit\n */\nasync function getCommitSummaries(defaultBranch: string, cwd: string): Promise<string[]> {\n try {\n const { stdout } = await exec(\n \"git\",\n [\"log\", `${defaultBranch}..HEAD`, \"--pretty=format:%s\"],\n { cwd, shell: process.platform === \"win32\" },\n );\n return stdout\n .trim()\n .split(\"\\n\")\n .filter(Boolean);\n } catch {\n return [];\n }\n}\n\n/**\n * Retrieve the full diff of the current branch relative to the default branch.\n *\n * @param defaultBranch - The base branch to compare against (e.g. \"main\")\n * @param cwd - Working directory (git repo root)\n * @returns The diff output as a string, or an empty string on failure\n */\nexport async function getBranchDiff(defaultBranch: string, cwd: string): Promise<string> {\n try {\n const { stdout } = await exec(\n \"git\",\n [\"diff\", `${defaultBranch}..HEAD`],\n { cwd, maxBuffer: 10 * 1024 * 1024, shell: process.platform === \"win32\" },\n );\n return stdout;\n } catch {\n return \"\";\n }\n}\n\n/**\n * Amend the most recent commit's message without changing its content.\n *\n * @param message - The new commit message\n * @param cwd - Working directory (git repo root)\n */\nexport async function amendCommitMessage(message: string, cwd: string): Promise<void> {\n await exec(\n \"git\",\n [\"commit\", \"--amend\", \"-m\", message],\n { cwd, shell: process.platform === \"win32\" },\n );\n}\n\n/**\n * Squash all commits on the current branch (relative to the default branch)\n * into a single commit with the given message.\n *\n * Uses a soft reset to the merge-base followed by a fresh commit, which\n * avoids interactive rebase complexity.\n *\n * @param defaultBranch - The base branch to compare against (e.g. \"main\")\n * @param message - The commit message for the squashed commit\n * @param cwd - Working directory (git repo root)\n */\nexport async function squashBranchCommits(\n defaultBranch: string,\n message: string,\n cwd: string,\n): Promise<void> {\n const { stdout } = await exec(\n \"git\",\n [\"merge-base\", defaultBranch, \"HEAD\"],\n { cwd, shell: process.platform === \"win32\" },\n );\n const mergeBase = stdout.trim();\n await exec(\"git\", [\"reset\", \"--soft\", mergeBase], { cwd, shell: process.platform === \"win32\" });\n await exec(\"git\", [\"commit\", \"-m\", message], { cwd, shell: process.platform === \"win32\" });\n}\n\n/**\n * Assemble a descriptive pull request body from pipeline data.\n *\n * Includes:\n * - A summary section with commit messages from the branch\n * - The list of completed tasks\n * - Labels from the issue (if any)\n * - An issue-close reference appropriate for the datasource\n *\n * @param details - The issue details (title, body, labels, number)\n * @param tasks - The tasks that were dispatched for this issue\n * @param results - The dispatch results for all tasks\n * @param defaultBranch - The base branch to compare commits against\n * @param datasourceName - The datasource backend name (\"github\", \"azdevops\", \"md\")\n * @param cwd - Working directory (git repo root)\n * @returns The assembled PR body as a markdown string\n */\nexport async function buildPrBody(\n details: IssueDetails,\n tasks: Task[],\n results: DispatchResult[],\n defaultBranch: string,\n datasourceName: DatasourceName,\n cwd: string,\n): Promise<string> {\n const sections: string[] = [];\n\n // ── Commit summary section ──────────────────────────────────\n const commits = await getCommitSummaries(defaultBranch, cwd);\n if (commits.length > 0) {\n sections.push(\"## Summary\\n\");\n for (const commit of commits) {\n sections.push(`- ${commit}`);\n }\n sections.push(\"\");\n }\n\n // ── Completed tasks section ─────────────────────────────────\n const taskResults = new Map(\n results\n .filter((r) => tasks.includes(r.task))\n .map((r) => [r.task, r]),\n );\n\n const completedTasks = tasks.filter((t) => taskResults.get(t)?.success);\n const failedTasks = tasks.filter((t) => {\n const r = taskResults.get(t);\n return r && !r.success;\n });\n\n if (completedTasks.length > 0 || failedTasks.length > 0) {\n sections.push(\"## Tasks\\n\");\n for (const task of completedTasks) {\n sections.push(`- [x] ${task.text}`);\n }\n for (const task of failedTasks) {\n sections.push(`- [ ] ${task.text}`);\n }\n sections.push(\"\");\n }\n\n // ── Labels section ──────────────────────────────────────────\n if (details.labels.length > 0) {\n sections.push(`**Labels:** ${details.labels.join(\", \")}\\n`);\n }\n\n // ── Issue-close reference ───────────────────────────────────\n if (datasourceName === \"github\") {\n sections.push(`Closes #${details.number}`);\n } else if (datasourceName === \"azdevops\") {\n sections.push(`Resolves AB#${details.number}`);\n }\n\n return sections.join(\"\\n\");\n}\n\n/**\n * Generate a descriptive PR title from commit messages on the branch.\n *\n * If a single commit exists, its message is used as the title.\n * If multiple commits exist, a summary title is generated that\n * captures the scope, prefixed with the issue title.\n * Falls back to the issue title if no commits are found.\n *\n * @param issueTitle - The original issue title (used as fallback)\n * @param defaultBranch - The base branch to compare commits against\n * @param cwd - Working directory (git repo root)\n * @returns A descriptive PR title string\n */\nexport async function buildPrTitle(\n issueTitle: string,\n defaultBranch: string,\n cwd: string,\n): Promise<string> {\n const commits = await getCommitSummaries(defaultBranch, cwd);\n\n if (commits.length === 0) {\n return issueTitle;\n }\n\n if (commits.length === 1) {\n return commits[0];\n }\n\n // Multiple commits — use the newest commit message with a count suffix\n return `${commits[0]} (+${commits.length - 1} more)`;\n}\n\n/**\n * Build an aggregated PR title for feature mode.\n *\n * When a single issue is processed, the PR title is just that issue's title.\n * For multiple issues, the title includes the feature branch name and\n * references to all issues.\n *\n * @param featureBranchName - The feature branch name (e.g. \"dispatch/feature-a1b2c3d4\")\n * @param issues - All issue details processed in this feature run\n * @returns An aggregated PR title string\n */\nexport function buildFeaturePrTitle(featureBranchName: string, issues: IssueDetails[]): string {\n if (issues.length === 1) {\n return issues[0].title;\n }\n const issueRefs = issues.map((d) => `#${d.number}`).join(\", \");\n return `feat: ${featureBranchName} (${issueRefs})`;\n}\n\n/**\n * Build an aggregated PR body for feature mode that references all issues,\n * their tasks, and completion status.\n *\n * Includes:\n * - An issues section listing all issues addressed\n * - A tasks section with completion checkboxes\n * - Issue-close references appropriate for the datasource\n *\n * @param issues - All issue details processed in this feature run\n * @param tasks - All tasks dispatched across all issues\n * @param results - The dispatch results for all tasks\n * @param datasourceName - The datasource backend name (\"github\", \"azdevops\", \"md\")\n * @returns The assembled aggregated PR body as a markdown string\n */\nexport function buildFeaturePrBody(\n issues: IssueDetails[],\n tasks: Task[],\n results: DispatchResult[],\n datasourceName: DatasourceName,\n): string {\n const sections: string[] = [];\n\n sections.push(\"## Issues\\n\");\n for (const issue of issues) {\n sections.push(`- #${issue.number}: ${issue.title}`);\n }\n sections.push(\"\");\n\n const taskResults = new Map(results.map((r) => [r.task, r]));\n const completedTasks = tasks.filter((t) => taskResults.get(t)?.success);\n const failedTasks = tasks.filter((t) => {\n const r = taskResults.get(t);\n return r && !r.success;\n });\n\n if (completedTasks.length > 0 || failedTasks.length > 0) {\n sections.push(\"## Tasks\\n\");\n for (const task of completedTasks) {\n sections.push(`- [x] ${task.text}`);\n }\n for (const task of failedTasks) {\n sections.push(`- [ ] ${task.text}`);\n }\n sections.push(\"\");\n }\n\n for (const issue of issues) {\n if (datasourceName === \"github\") {\n sections.push(`Closes #${issue.number}`);\n } else if (datasourceName === \"azdevops\") {\n sections.push(`Resolves AB#${issue.number}`);\n }\n }\n\n return sections.join(\"\\n\");\n}\n","/**\n * Dispatch pipeline — the core execution pipeline that discovers tasks,\n * optionally plans them via the planner, executes them via the\n * executor, syncs completion state back to the datasource, and\n * cleans up resources.\n */\n\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { readFile } from \"node:fs/promises\";\nimport { glob } from \"glob\";\nimport { parseTaskFile, buildTaskContext, groupTasksByMode, type TaskFile, type Task } from \"../parser.js\";\nimport { dispatch, type DispatchResult } from \"../dispatcher.js\";\nimport { plannerSkill } from \"../skills/planner.js\";\nimport type { SkillResult, PlannerData, ExecutorData } from \"../skills/types.js\";\nimport { executorSkill } from \"../skills/executor.js\";\nimport { commitSkill, type CommitOutput } from \"../skills/commit.js\";\nimport { markTaskComplete } from \"../parser.js\";\nimport { log } from \"../helpers/logger.js\";\nimport { registerCleanup } from \"../helpers/cleanup.js\";\nimport { createWorktree, removeWorktree, worktreeName, generateFeatureBranchName } from \"../helpers/worktree.js\";\nimport { isValidBranchName } from \"../helpers/branch-validation.js\";\nimport { createTui, type TuiState } from \"../tui.js\";\nimport type { ProviderName } from \"../providers/interface.js\";\nimport { ProviderPool, type PoolEntry } from \"../providers/pool.js\";\nimport { routeAllSkills } from \"../providers/router.js\";\nimport { getAuthenticatedProviders } from \"../providers/index.js\";\nimport { PROVIDER_NAMES } from \"../providers/interface.js\";\nimport { getDatasource } from \"../datasources/index.js\";\nimport type { DatasourceName, DispatchLifecycleOptions, IssueDetails, IssueFetchOptions } from \"../datasources/interface.js\";\nimport { ensureAuthReady, setAuthPromptHandler } from \"../helpers/auth.js\";\nimport type { OrchestrateRunOptions, DispatchSummary, DispatchProgressEvent } from \"./runner.js\";\nimport {\n fetchItemsById,\n writeItemsToTempDir,\n parseIssueFilename,\n buildPrBody,\n buildPrTitle,\n buildFeaturePrTitle,\n buildFeaturePrBody,\n getBranchDiff,\n squashBranchCommits,\n} from \"./datasource-helpers.js\";\nimport { DEFAULT_PLAN_TIMEOUT_MIN, withTimeout, TimeoutError } from \"../helpers/timeout.js\";\nimport { DEFAULT_RETRY_COUNT, withRetry } from \"../helpers/retry.js\";\nimport { runWithConcurrency } from \"../helpers/concurrency.js\";\nimport { isGlobOrFilePath } from \"../spec-generator.js\";\nimport { extractTitle } from \"../datasources/md.js\";\nimport chalk from \"chalk\";\nimport { elapsed, renderHeaderLines } from \"../helpers/format.js\";\nimport { FileLogger, fileLoggerStorage } from \"../helpers/file-logger.js\";\nimport { buildTaskId } from \"../helpers/run-state.js\";\n\nconst exec = promisify(execFile);\n\n/**\n * Expand glob patterns / file paths into IssueDetails[].\n * Mirrors resolveFileItems() from the spec pipeline.\n */\nasync function resolveGlobItems(\n patterns: string[],\n cwd: string,\n): Promise<IssueDetails[]> {\n const files = await glob(patterns, { cwd, absolute: true });\n\n if (files.length === 0) {\n log.warn(`No files matched the pattern(s): ${patterns.join(\", \")}`);\n return [];\n }\n\n log.info(`Matched ${files.length} file(s) from glob pattern(s)`);\n\n const items: IssueDetails[] = [];\n for (const filePath of files) {\n try {\n const content = await readFile(filePath, \"utf-8\");\n const title = extractTitle(content, filePath);\n items.push({\n number: filePath,\n title,\n body: content,\n labels: [],\n state: \"open\",\n url: filePath,\n comments: [],\n acceptanceCriteria: \"\",\n });\n } catch (err) {\n log.warn(`Could not read file ${filePath}: ${log.formatErrorChain(err)}`);\n }\n }\n return items;\n}\n\n/**\n * Run the full dispatch pipeline: discover tasks from a datasource,\n * optionally plan them via the planner agent, execute via the executor\n * agent, sync completion state, and clean up.\n */\nexport async function runDispatchPipeline(\n opts: OrchestrateRunOptions,\n cwd: string,\n): Promise<DispatchSummary> {\n const {\n issueIds,\n concurrency = 1,\n dryRun,\n serverUrl,\n noPlan,\n noBranch: noBranchOpt,\n noWorktree,\n feature,\n provider,\n enabledProviders,\n providerModels,\n source,\n org,\n project,\n workItemType,\n iteration,\n area,\n planTimeout,\n planRetries,\n retries,\n username: usernameOverride,\n progressCallback,\n } = opts;\n let noBranch = noBranchOpt;\n\n // Determine authenticated providers for routing\n const available = enabledProviders?.length\n ? enabledProviders\n : await getAuthenticatedProviders(PROVIDER_NAMES);\n\n if (available.length === 0) {\n throw new Error(\"No authenticated providers available. Run 'dispatch config' to set up providers.\");\n }\n\n // Route agents to providers via the smart router\n const agentRoutes = routeAllSkills(available, provider, providerModels);\n\n /** Create a ProviderPool for an agent role using router-produced entries. */\n function createPool(entries: PoolEntry[], bootCwd: string): ProviderPool {\n return new ProviderPool({ entries, bootOpts: { url: serverUrl, cwd: bootCwd } });\n }\n\n // Planning timeout/retry defaults\n const resolvedRetries = retries ?? DEFAULT_RETRY_COUNT;\n const resolvedPlanTimeoutMin = planTimeout ?? DEFAULT_PLAN_TIMEOUT_MIN;\n const planTimeoutMs = resolvedPlanTimeoutMin * 60_000;\n const resolvedPlanRetries = planRetries ?? resolvedRetries;\n const maxPlanAttempts = resolvedPlanRetries + 1; // retries + initial attempt\n\n log.debug(`Plan timeout: ${resolvedPlanTimeoutMin}m (${planTimeoutMs}ms), max attempts: ${maxPlanAttempts}`);\n\n // Dry-run mode uses simple log output\n if (dryRun) {\n return dryRunMode(issueIds, cwd, source, org, project, workItemType, iteration, area, usernameOverride);\n }\n\n // Pre-authenticate before TUI starts so device codes are visible in the terminal.\n // For cached tokens this is instant; for new auth it runs the device flow\n // while stdout is still free.\n await ensureAuthReady(source, cwd, org);\n\n // ── Start TUI (or inline logging for verbose mode) ──────────\n const verbose = log.verbose;\n const canRecoverInteractively = !verbose && process.stdin.isTTY === true && process.stdout.isTTY === true;\n let tui: ReturnType<typeof createTui>;\n\n if (verbose) {\n // Print inline header banner (same pattern as spec pipeline)\n const primaryProvider = agentRoutes.executor[0]?.provider;\n const headerLines = renderHeaderLines({ provider: primaryProvider, source });\n console.log(\"\");\n for (const line of headerLines) console.log(line);\n console.log(chalk.dim(\" ─\".repeat(24)));\n console.log(\"\");\n log.info(\"Discovering task files...\");\n\n // Silent state container — no animated rendering\n const state: TuiState = {\n tasks: [],\n phase: \"discovering\",\n startTime: Date.now(),\n filesFound: 0,\n provider: primaryProvider,\n source,\n };\n tui = {\n state,\n update: () => {},\n stop: () => {},\n waitForRecoveryAction: async () => \"quit\",\n };\n } else {\n tui = createTui();\n tui.state.provider = agentRoutes.executor[0]?.provider;\n tui.state.source = source;\n\n // Route auth device-code prompts into the TUI notification banner\n setAuthPromptHandler((msg) => {\n tui.state.notification = msg;\n tui.update();\n });\n }\n\n try {\n // ── 1. Discover task files ──────────────────────────────────\n tui.state.phase = \"discovering\";\n\n if (!source) {\n tui.state.phase = \"done\";\n setAuthPromptHandler(null);\n tui.stop();\n log.error(\"No datasource configured. Use --source or run 'dispatch config' to set up defaults.\");\n return { total: 0, completed: 0, failed: 0, skipped: 0, results: [] };\n }\n\n const datasource = getDatasource(source);\n\n // When using the md datasource, git operations are optional — they only\n // work when dispatch is run from inside a git repository. If no repo is\n // found, disable branching so the pipeline can still complete its work.\n if (source === \"md\" && !noBranch) {\n try {\n await exec(\"git\", [\"rev-parse\", \"--git-dir\"], { cwd, shell: process.platform === \"win32\" });\n } catch {\n noBranch = true;\n if (verbose) log.debug(\"No git repository found — skipping git operations for md datasource\");\n }\n }\n\n const fetchOpts: IssueFetchOptions = { cwd, org, project, workItemType, iteration, area };\n let items: IssueDetails[];\n if (issueIds.length > 0 && source === \"md\" && issueIds.some(id => isGlobOrFilePath(id))) {\n items = await resolveGlobItems(issueIds, cwd);\n } else if (issueIds.length > 0) {\n items = await fetchItemsById(issueIds, datasource, fetchOpts);\n } else {\n items = await datasource.list(fetchOpts);\n }\n\n // Auth is complete — clear the notification banner and handler\n tui.state.notification = undefined;\n setAuthPromptHandler(null);\n\n if (items.length === 0) {\n tui.state.phase = \"done\";\n tui.stop();\n const label = issueIds.length > 0 ? `issue(s) ${issueIds.join(\", \")}` : `datasource: ${source}`;\n log.warn(\"No work items found from \" + label);\n return { total: 0, completed: 0, failed: 0, skipped: 0, results: [] };\n }\n\n const { files, issueDetailsByFile } = await writeItemsToTempDir(items);\n tui.state.filesFound = files.length;\n if (verbose) log.debug(`Found ${files.length} task file(s)`);\n\n // ── 2. Parse all tasks ──────────────────────────────────────\n tui.state.phase = \"parsing\";\n if (verbose) log.info(\"Parsing tasks...\");\n const taskFiles: TaskFile[] = [];\n\n for (const file of files) {\n const tf = await parseTaskFile(file);\n if (tf.tasks.length > 0) {\n taskFiles.push(tf);\n }\n }\n\n const allTasks = taskFiles.flatMap((tf) => tf.tasks);\n\n // Build a lookup from file path → raw content for filtered planner context\n const fileContentMap = new Map<string, string>();\n for (const tf of taskFiles) {\n fileContentMap.set(tf.path, tf.content);\n }\n\n if (allTasks.length === 0) {\n tui.state.phase = \"done\";\n tui.stop();\n log.warn(\"No unchecked tasks found\");\n return { total: 0, completed: 0, failed: 0, skipped: 0, results: [] };\n }\n\n // Populate TUI task list\n tui.state.tasks = allTasks.map((task) => ({\n task,\n status: \"pending\" as const,\n }));\n\n // Group tasks by their source file (each file = one issue)\n const tasksByFile = new Map<string, typeof allTasks>();\n for (const task of allTasks) {\n const list = tasksByFile.get(task.file) ?? [];\n list.push(task);\n tasksByFile.set(task.file, list);\n }\n\n // Determine whether to use worktree-based parallel execution.\n // Worktrees are used when: not opted out, branching is enabled, and\n // there are multiple issues to process (single-issue runs use serial\n // mode to avoid unnecessary worktree overhead).\n const useWorktrees = !noWorktree && (feature || (!noBranch && tasksByFile.size > 1));\n\n // ── 3. Boot provider ────────────────────────────────────────\n tui.state.phase = \"booting\";\n if (verbose) log.info(`Booting ${provider} provider...`);\n if (serverUrl) {\n tui.state.serverUrl = serverUrl;\n }\n if (verbose && serverUrl) log.debug(`Server URL: ${serverUrl}`);\n\n // When using worktrees, providers are booted per-worktree inside\n // processIssueFile. Otherwise, boot a single shared provider pool.\n let plannerPool: ProviderPool | null = null;\n let executorPool: ProviderPool | undefined;\n let commitPool: ProviderPool | undefined;\n const sharedPools: ProviderPool[] = [];\n\n if (!useWorktrees) {\n // Create per-agent pools with failover support\n const sharedExecutorPool = createPool(agentRoutes.executor, cwd);\n const sharedPlannerPool = createPool(agentRoutes.planner, cwd);\n const sharedCommitPool = createPool(agentRoutes.commit, cwd);\n sharedPools.push(sharedExecutorPool, sharedPlannerPool, sharedCommitPool);\n for (const pool of sharedPools) registerCleanup(() => pool.cleanup());\n\n // Populate TUI model display from executor pool's primary entry\n if (sharedExecutorPool.model) {\n tui.state.model = sharedExecutorPool.model;\n }\n if (verbose) {\n const fmtRoute = (entries: PoolEntry[]) => entries.map((e) => `${e.provider}${e.model ? ` (${e.model})` : \"\"}`).join(\" > \");\n log.debug(`Executor route: ${fmtRoute(agentRoutes.executor)}`);\n log.debug(`Planner route: ${fmtRoute(agentRoutes.planner)}`);\n log.debug(`Commit route: ${fmtRoute(agentRoutes.commit)}`);\n }\n\n // ── 4. Assign pools (stateless skills — no booting needed) ──\n plannerPool = noPlan ? null : sharedPlannerPool;\n executorPool = sharedExecutorPool;\n commitPool = sharedCommitPool;\n }\n\n // ── 5. Dispatch tasks ───────────────────────────────────────\n tui.state.phase = \"dispatching\";\n if (verbose) log.info(`Dispatching ${allTasks.length} task(s)...`);\n progressCallback?.({ type: \"phase_change\", phase: \"dispatching\", message: `Dispatching ${allTasks.length} task(s)` });\n const results: DispatchResult[] = [];\n let halted = false;\n\n const lifecycleOpts: DispatchLifecycleOptions = { cwd, username: usernameOverride };\n\n // ── Capture the branch the user is currently on ────────────────\n // This is used as the base for new branches, PR targets, and the\n // branch to return to after completion. When the user is on main\n // this naturally resolves to main; when on release/1.4.3 it uses\n // that branch instead.\n const startingBranch = await datasource.getCurrentBranch(lifecycleOpts);\n\n // ── Feature-branch setup (when --feature) ──────────────────────\n let featureBranchName: string | undefined;\n let featureDefaultBranch: string | undefined;\n\n if (feature) {\n // Resolve the feature branch name\n if (typeof feature === \"string\") {\n if (!isValidBranchName(feature)) {\n log.error(`Invalid feature branch name: \"${feature}\"`);\n tui.state.phase = \"done\";\n tui.stop();\n return { total: allTasks.length, completed: 0, failed: allTasks.length, skipped: 0, results: [] };\n }\n featureBranchName = feature.includes(\"/\") ? feature : `dispatch/${feature}`;\n } else {\n featureBranchName = generateFeatureBranchName();\n }\n\n try {\n featureDefaultBranch = startingBranch;\n\n // Ensure we are on the starting branch so the feature branch starts from the correct commit\n await datasource.switchBranch(featureDefaultBranch, lifecycleOpts);\n\n // Create the feature branch from the starting branch (or switch to it if it already exists)\n try {\n await datasource.createAndSwitchBranch(featureBranchName, lifecycleOpts);\n log.debug(`Created feature branch ${featureBranchName} from ${featureDefaultBranch}`);\n } catch (createErr) {\n const message = log.extractMessage(createErr);\n if (message.includes(\"already exists\")) {\n await datasource.switchBranch(featureBranchName, lifecycleOpts);\n log.debug(`Switched to existing feature branch ${featureBranchName}`);\n } else {\n throw createErr;\n }\n }\n\n // Register cleanup for the feature branch\n registerCleanup(async () => {\n try {\n await datasource.switchBranch(featureDefaultBranch!, lifecycleOpts);\n } catch { /* swallow */ }\n });\n\n // Switch back to starting branch so worktrees can be created from the main repo\n await datasource.switchBranch(featureDefaultBranch, lifecycleOpts);\n log.debug(`Switched back to ${featureDefaultBranch} for worktree creation`);\n } catch (err) {\n log.error(`Feature branch creation failed: ${log.extractMessage(err)}`);\n tui.state.phase = \"done\";\n tui.stop();\n return { total: allTasks.length, completed: 0, failed: allTasks.length, skipped: 0, results: [] };\n }\n }\n\n // Resolve git username once for branch naming\n let username = \"\";\n try {\n username = await datasource.getUsername(lifecycleOpts);\n } catch (err) {\n log.warn(`Could not resolve git username for branch naming: ${log.formatErrorChain(err)}`);\n }\n\n // Process a single issue file's tasks — handles both worktree and\n // serial branch modes, parameterised by useWorktrees.\n const processIssueFile = async (file: string, fileTasks: typeof allTasks): Promise<{ halted: boolean }> => {\n const details = issueDetailsByFile.get(file);\n const fileLogger = verbose && details ? new FileLogger(details.number, cwd) : null;\n\n const body = async () => {\n let defaultBranch: string | undefined;\n let branchName: string | undefined;\n let worktreePath: string | undefined;\n let issueCwd = cwd;\n let preserveContext = false;\n\n const upsertResult = (collection: DispatchResult[], result: DispatchResult) => {\n const index = collection.findIndex((entry) => entry.task === result.task);\n if (index >= 0) {\n collection[index] = result;\n } else {\n collection.push(result);\n }\n };\n\n // ── Branch / worktree setup (unless --no-branch) ────────────\n if (!noBranch && details) {\n fileLogger?.phase(\"Branch/worktree setup\");\n try {\n defaultBranch = feature ? featureBranchName! : startingBranch;\n branchName = datasource.buildBranchName(details.number, details.title, username);\n\n if (useWorktrees) {\n worktreePath = await createWorktree(cwd, file, branchName, ...(feature && featureBranchName ? [featureBranchName] : []));\n registerCleanup(async () => { await removeWorktree(cwd, file); });\n issueCwd = worktreePath;\n log.debug(`Created worktree for issue #${details.number} at ${worktreePath}`);\n fileLogger?.info(`Worktree created at ${worktreePath}`);\n\n const wtName = worktreeName(file);\n for (const task of fileTasks) {\n const tuiTask = tui.state.tasks.find((t) => t.task === task);\n if (tuiTask) tuiTask.worktree = wtName;\n }\n } else if (datasource.supportsGit()) {\n await datasource.createAndSwitchBranch(branchName, lifecycleOpts);\n log.debug(`Switched to branch ${branchName}`);\n fileLogger?.info(`Switched to branch ${branchName}`);\n }\n } catch (err) {\n const errorMsg = `Branch creation failed for issue #${details.number}: ${log.extractMessage(err)}`;\n fileLogger?.error(`Branch creation failed: ${log.extractMessage(err)}${err instanceof Error && err.stack ? `\\n${err.stack}` : \"\"}`);\n log.error(errorMsg);\n for (const task of fileTasks) {\n const tuiTask = tui.state.tasks.find((t) => t.task === task);\n if (tuiTask) {\n tuiTask.status = \"failed\";\n tuiTask.error = errorMsg;\n }\n upsertResult(results, { task, success: false, error: errorMsg });\n }\n return { halted: false };\n }\n }\n\n const worktreeRoot = useWorktrees ? worktreePath : undefined;\n const issueLifecycleOpts: DispatchLifecycleOptions = { cwd: issueCwd, username: usernameOverride };\n\n fileLogger?.phase(\"Provider/agent boot\");\n let localPlannerPool: ProviderPool | null;\n let localExecutorPool: ProviderPool;\n let localCommitPool: ProviderPool;\n\n if (useWorktrees) {\n // Create per-agent pools for this worktree\n const wtExecutorPool = createPool(agentRoutes.executor, issueCwd);\n const wtPlannerPool = createPool(agentRoutes.planner, issueCwd);\n const wtCommitPool = createPool(agentRoutes.commit, issueCwd);\n registerCleanup(() => wtExecutorPool.cleanup());\n registerCleanup(() => wtPlannerPool.cleanup());\n registerCleanup(() => wtCommitPool.cleanup());\n\n if (!tui.state.model && wtExecutorPool.model) {\n tui.state.model = wtExecutorPool.model;\n }\n if (verbose) {\n log.debug(`Worktree executor route: ${agentRoutes.executor.map((e) => e.provider).join(\" > \")}`);\n }\n\n localPlannerPool = noPlan ? null : wtPlannerPool;\n localExecutorPool = wtExecutorPool;\n localCommitPool = wtCommitPool;\n fileLogger?.info(`Provider pools booted: executor=${agentRoutes.executor[0]?.provider}, planner=${agentRoutes.planner[0]?.provider}, commit=${agentRoutes.commit[0]?.provider}`);\n } else {\n localPlannerPool = plannerPool;\n localExecutorPool = executorPool!;\n localCommitPool = commitPool!;\n }\n\n const issueResults: DispatchResult[] = [];\n\n const pauseTask = (task: Task, error: string) => {\n const tuiTask = tui.state.tasks.find((entry) => entry.task === task)!;\n tuiTask.status = \"paused\";\n tuiTask.error = error;\n tui.state.phase = \"paused\";\n tui.state.recovery = {\n taskIndex: tui.state.tasks.indexOf(tuiTask),\n taskText: task.text,\n error,\n issue: details ? { number: details.number, title: details.title } : undefined,\n worktree: tuiTask.worktree ?? worktreeRoot,\n selectedAction: \"rerun\",\n };\n tui.update();\n return tuiTask;\n };\n\n const clearRecovery = () => {\n tui.state.recovery = undefined;\n tui.state.phase = \"dispatching\";\n tui.update();\n };\n\n const runTaskLifecycle = async (task: Task): Promise<\n | { kind: \"success\"; result: DispatchResult }\n | { kind: \"paused\"; error: string }\n > => {\n const tuiTask = tui.state.tasks.find((entry) => entry.task === task)!;\n const startTime = Date.now();\n let plan: string | undefined;\n\n tuiTask.elapsed = startTime;\n tuiTask.error = undefined;\n\n const emitProgress = (type: \"task_start\" | \"task_done\" | \"task_failed\", extra?: { phase?: string; error?: string }) => {\n if (!progressCallback) return;\n const taskId = buildTaskId(task);\n const taskText = task.text;\n if (type === \"task_start\") {\n progressCallback({ type, taskId, taskText, phase: extra?.phase, file: task.file, line: task.line });\n } else if (type === \"task_done\") {\n progressCallback({ type, taskId, taskText });\n } else {\n progressCallback({ type, taskId, taskText, error: extra?.error ?? \"unknown error\" });\n }\n };\n\n if (localPlannerPool) {\n tuiTask.status = \"planning\";\n fileLogger?.phase(`Planning task: ${task.text}`);\n if (verbose) log.info(`Task #${tui.state.tasks.indexOf(tuiTask) + 1}: planning — \"${task.text}\"`);\n const rawContent = fileContentMap.get(task.file);\n const fileContext = rawContent ? buildTaskContext(rawContent, task) : undefined;\n\n let planResult: SkillResult<PlannerData> | undefined;\n\n for (let attempt = 1; attempt <= maxPlanAttempts; attempt++) {\n try {\n planResult = await withTimeout(\n dispatch(plannerSkill, { task, cwd: issueCwd, fileContext, worktreeRoot }, localPlannerPool!),\n planTimeoutMs,\n \"planner.plan()\",\n );\n break;\n } catch (err) {\n if (err instanceof TimeoutError) {\n log.warn(`Planning timed out for task \"${task.text}\" (attempt ${attempt}/${maxPlanAttempts})`);\n fileLogger?.warn(`Planning timeout (attempt ${attempt}/${maxPlanAttempts})`);\n if (attempt < maxPlanAttempts) {\n log.debug(`Retrying planning (attempt ${attempt + 1}/${maxPlanAttempts})`);\n fileLogger?.info(`Retrying planning (attempt ${attempt + 1}/${maxPlanAttempts})`);\n }\n } else {\n planResult = {\n data: null,\n success: false,\n error: log.extractMessage(err),\n durationMs: 0,\n };\n break;\n }\n }\n }\n\n if (!planResult) {\n planResult = {\n data: null,\n success: false,\n error: `Planning timed out after ${resolvedPlanTimeoutMin}m (${maxPlanAttempts} attempts)`,\n durationMs: 0,\n };\n }\n\n if (!planResult.success) {\n const error = `Planning failed: ${planResult.error}`;\n fileLogger?.error(error);\n tuiTask.elapsed = Date.now() - startTime;\n pauseTask(task, error);\n if (verbose) log.error(`Task #${tui.state.tasks.indexOf(tuiTask) + 1}: paused — ${error} (${elapsed(tuiTask.elapsed)})`);\n return { kind: \"paused\", error };\n }\n\n plan = planResult.data.prompt;\n fileLogger?.info(`Planning completed (${planResult.durationMs ?? 0}ms)`);\n }\n\n tuiTask.status = \"running\";\n fileLogger?.phase(`Executing task: ${task.text}`);\n if (verbose) log.info(`Task #${tui.state.tasks.indexOf(tuiTask) + 1}: executing — \"${task.text}\"`);\n emitProgress(\"task_start\", { phase: \"executing\" });\n const execResult = await withRetry(\n async () => {\n const result = await dispatch(executorSkill, {\n task,\n cwd: issueCwd,\n plan: plan ?? null,\n worktreeRoot,\n }, localExecutorPool);\n if (!result.success) {\n throw new Error(result.error ?? \"Execution failed\");\n }\n return result;\n },\n resolvedRetries,\n { label: `executor \"${task.text}\"` },\n ).catch((err): SkillResult<ExecutorData> => ({\n data: null,\n success: false,\n error: log.extractMessage(err),\n durationMs: 0,\n }));\n\n if (!execResult.success) {\n const error = execResult.error ?? \"Executor failed without returning a dispatch result.\";\n fileLogger?.error(`Execution failed: ${error}`);\n tuiTask.elapsed = Date.now() - startTime;\n pauseTask(task, error);\n emitProgress(\"task_failed\", { error });\n if (verbose) log.error(`Task #${tui.state.tasks.indexOf(tuiTask) + 1}: paused — \"${task.text}\" (${elapsed(tuiTask.elapsed)})${error ? `: ${error}` : \"\"}`);\n return { kind: \"paused\", error };\n }\n\n fileLogger?.info(`Execution completed successfully (${Date.now() - startTime}ms)`);\n await markTaskComplete(task);\n try {\n const parsed = parseIssueFilename(task.file);\n const updatedContent = await readFile(task.file, \"utf-8\");\n if (parsed) {\n const issueDetails = issueDetailsByFile.get(task.file);\n const title = issueDetails?.title ?? parsed.slug;\n await datasource.update(parsed.issueId, title, updatedContent, fetchOpts);\n log.success(`Synced task completion to issue #${parsed.issueId}`);\n } else {\n const issueDetails = issueDetailsByFile.get(task.file);\n if (issueDetails) {\n await datasource.update(issueDetails.number, issueDetails.title, updatedContent, fetchOpts);\n log.success(`Synced task completion to issue #${issueDetails.number}`);\n }\n }\n } catch (err) {\n log.warn(`Could not sync task completion to datasource: ${log.formatErrorChain(err)}`);\n }\n\n tuiTask.status = \"done\";\n tuiTask.error = undefined;\n tuiTask.elapsed = Date.now() - startTime;\n emitProgress(\"task_done\");\n if (verbose) log.success(`Task #${tui.state.tasks.indexOf(tuiTask) + 1}: done — \"${task.text}\" (${elapsed(tuiTask.elapsed)})`);\n return { kind: \"success\", result: execResult.data.dispatchResult };\n };\n\n const recoverPausedTask = async (task: Task, error: string): Promise<{ halted: boolean; result: DispatchResult }> => {\n while (true) {\n const tuiTask = pauseTask(task, error);\n\n if (!canRecoverInteractively) {\n log.warn(\"Manual rerun requires an interactive terminal; verbose or non-TTY runs will not wait for input, and the current branch/worktree will be left intact.\");\n tuiTask.status = \"failed\";\n clearRecovery();\n return { halted: true, result: { task, success: false, error } };\n }\n\n const action = await tui.waitForRecoveryAction();\n if (action === \"quit\") {\n tuiTask.status = \"failed\";\n clearRecovery();\n return { halted: true, result: { task, success: false, error } };\n }\n\n clearRecovery();\n const rerun = await runTaskLifecycle(task);\n if (rerun.kind === \"success\") {\n return { halted: false, result: rerun.result };\n }\n error = rerun.error;\n }\n };\n\n const groups = groupTasksByMode(fileTasks);\n let stopAfterIssue = false;\n\n for (const group of groups) {\n const groupResults = await runWithConcurrency({\n items: group,\n concurrency,\n worker: async (task) => runTaskLifecycle(task),\n shouldStop: () => stopAfterIssue,\n });\n\n const pausedTasks: Array<{ task: Task; error: string }> = [];\n\n for (let i = 0; i < group.length; i++) {\n const result = groupResults[i];\n if (result.status === \"skipped\") continue;\n if (result.status === \"rejected\") {\n // Unexpected rejection — treat as a paused task\n pausedTasks.push({ task: group[i], error: String(result.reason) });\n continue;\n }\n const outcome = result.value;\n if (outcome.kind === \"success\") {\n upsertResult(issueResults, outcome.result);\n upsertResult(results, outcome.result);\n } else {\n pausedTasks.push({ task: group[i], error: outcome.error });\n }\n }\n\n for (const pausedTask of pausedTasks) {\n const resolution = await recoverPausedTask(pausedTask.task, pausedTask.error);\n upsertResult(issueResults, resolution.result);\n upsertResult(results, resolution.result);\n if (resolution.halted) {\n preserveContext = true;\n stopAfterIssue = true;\n halted = true;\n break;\n }\n }\n\n // TUI model is populated at pool creation time\n\n if (stopAfterIssue) break;\n }\n\n if (!preserveContext) {\n if (!noBranch && branchName && defaultBranch && details && datasource.supportsGit()) {\n try {\n await datasource.commitAllChanges(\n `chore: stage uncommitted changes for issue #${details.number}`,\n issueLifecycleOpts,\n );\n log.debug(`Staged uncommitted changes for issue #${details.number}`);\n } catch (err) {\n log.warn(`Could not commit uncommitted changes for issue #${details.number}: ${log.formatErrorChain(err)}`);\n }\n }\n\n fileLogger?.phase(\"Commit generation\");\n let commitSkillResult: SkillResult<CommitOutput> | undefined;\n if (!noBranch && branchName && defaultBranch && details && datasource.supportsGit()) {\n try {\n const branchDiff = await getBranchDiff(defaultBranch, issueCwd);\n if (branchDiff) {\n const result = await dispatch(commitSkill, {\n branchDiff,\n issue: details,\n taskResults: issueResults,\n cwd: issueCwd,\n worktreeRoot,\n }, localCommitPool);\n if (result.success) {\n commitSkillResult = result;\n fileLogger?.info(`Commit message generated for issue #${details.number}`);\n try {\n await squashBranchCommits(defaultBranch, result.data.commitMessage, issueCwd);\n log.debug(`Rewrote commit message for issue #${details.number}`);\n fileLogger?.info(`Rewrote commit history for issue #${details.number}`);\n } catch (err) {\n log.warn(`Could not rewrite commit message for issue #${details.number}: ${log.formatErrorChain(err)}`);\n }\n } else {\n log.warn(`Commit agent failed for issue #${details.number}: ${result.error}`);\n fileLogger?.warn(`Commit agent failed: ${result.error}`);\n }\n }\n } catch (err) {\n log.warn(`Commit agent error for issue #${details.number}: ${log.formatErrorChain(err)}`);\n }\n }\n\n fileLogger?.phase(\"PR lifecycle\");\n if (!noBranch && branchName && defaultBranch && details) {\n if (feature && featureBranchName) {\n if (worktreePath) {\n try {\n await removeWorktree(cwd, file);\n } catch (err) {\n log.warn(`Could not remove worktree for issue #${details.number}: ${log.formatErrorChain(err)}`);\n }\n }\n\n try {\n await datasource.switchBranch(featureBranchName, lifecycleOpts);\n await exec(\"git\", [\"merge\", branchName, \"--no-ff\", \"-m\", `merge: issue #${details.number}`], { cwd, shell: process.platform === \"win32\" });\n log.debug(`Merged ${branchName} into ${featureBranchName}`);\n } catch (err) {\n const mergeError = `Could not merge ${branchName} into feature branch: ${log.formatErrorChain(err)}`;\n log.warn(mergeError);\n try {\n await exec(\"git\", [\"merge\", \"--abort\"], { cwd, shell: process.platform === \"win32\" });\n } catch { }\n for (const task of fileTasks) {\n const tuiTask = tui.state.tasks.find((t) => t.task === task);\n if (tuiTask) {\n tuiTask.status = \"failed\";\n tuiTask.error = mergeError;\n }\n upsertResult(results, { task, success: false, error: mergeError });\n }\n return { halted: false };\n }\n\n try {\n await exec(\"git\", [\"branch\", \"-d\", branchName], { cwd, shell: process.platform === \"win32\" });\n log.debug(`Deleted local branch ${branchName}`);\n } catch (err) {\n log.warn(`Could not delete local branch ${branchName}: ${log.formatErrorChain(err)}`);\n }\n\n try {\n await datasource.switchBranch(featureDefaultBranch!, lifecycleOpts);\n } catch (err) {\n log.warn(`Could not switch back to ${featureDefaultBranch}: ${log.formatErrorChain(err)}`);\n }\n } else {\n if (datasource.supportsGit()) {\n try {\n await datasource.pushBranch(branchName, issueLifecycleOpts);\n log.debug(`Pushed branch ${branchName}`);\n fileLogger?.info(`Pushed branch ${branchName}`);\n } catch (err) {\n log.warn(`Could not push branch ${branchName}: ${log.formatErrorChain(err)}`);\n }\n }\n\n if (datasource.supportsGit()) {\n try {\n const prTitle = (commitSkillResult?.success && commitSkillResult.data.prTitle) || await buildPrTitle(details.title, defaultBranch, issueLifecycleOpts.cwd);\n const prBody = (commitSkillResult?.success && commitSkillResult.data.prDescription) || await buildPrBody(\n details,\n fileTasks,\n issueResults,\n defaultBranch,\n datasource.name,\n issueLifecycleOpts.cwd,\n );\n const prUrl = await datasource.createPullRequest(\n branchName,\n details.number,\n prTitle,\n prBody,\n issueLifecycleOpts,\n startingBranch,\n );\n if (prUrl) {\n log.success(`Created PR for issue #${details.number}: ${prUrl}`);\n fileLogger?.info(`Created PR: ${prUrl}`);\n }\n } catch (err) {\n log.warn(`Could not create PR for issue #${details.number}: ${log.formatErrorChain(err)}`);\n fileLogger?.warn(`PR creation failed: ${log.extractMessage(err)}`);\n }\n }\n\n if (useWorktrees && worktreePath) {\n try {\n await removeWorktree(cwd, file);\n } catch (err) {\n log.warn(`Could not remove worktree for issue #${details.number}: ${log.formatErrorChain(err)}`);\n }\n } else if (!useWorktrees && datasource.supportsGit()) {\n try {\n await datasource.switchBranch(defaultBranch, lifecycleOpts);\n log.debug(`Switched back to ${defaultBranch}`);\n } catch (err) {\n log.warn(`Could not switch back to ${defaultBranch}: ${log.formatErrorChain(err)}`);\n }\n }\n }\n }\n }\n\n fileLogger?.phase(\"Resource cleanup\");\n // Stateless skills have no cleanup — pool cleanup is handled via registerCleanup()\n\n return { halted: stopAfterIssue };\n };\n\n if (fileLogger) {\n return fileLoggerStorage.run(fileLogger, async () => {\n try {\n return await body();\n } finally {\n fileLogger.close();\n }\n });\n }\n\n return body();\n };\n\n // Execute issues: parallel via worktrees, or serial fallback\n // Feature mode forces serial execution to avoid merge conflicts\n if (useWorktrees && !feature) {\n // Sliding-window concurrency: up to `concurrency` issues in parallel\n const issueEntries = Array.from(tasksByFile.entries());\n const concurrencyResults = await runWithConcurrency({\n items: issueEntries,\n concurrency,\n worker: async ([file, fileTasks]) => processIssueFile(file, fileTasks),\n shouldStop: () => halted,\n });\n for (const result of concurrencyResults) {\n if (result.status === \"fulfilled\" && result.value?.halted) {\n halted = true;\n }\n }\n } else {\n // Sequential: non-worktree mode or feature mode\n for (const [file, fileTasks] of tasksByFile) {\n const issueResult = await processIssueFile(file, fileTasks);\n if (issueResult?.halted) {\n halted = true;\n break;\n }\n }\n }\n\n // ── Feature branch finalization (push + aggregated PR) ──────\n if (!halted && feature && featureBranchName && featureDefaultBranch) {\n try {\n await datasource.switchBranch(featureBranchName, lifecycleOpts);\n log.debug(`Switched to feature branch ${featureBranchName}`);\n } catch (err) {\n log.warn(`Could not switch to feature branch: ${log.formatErrorChain(err)}`);\n }\n\n try {\n await datasource.pushBranch(featureBranchName, lifecycleOpts);\n log.debug(`Pushed feature branch ${featureBranchName}`);\n } catch (err) {\n log.warn(`Could not push feature branch: ${log.formatErrorChain(err)}`);\n }\n\n try {\n const allIssueDetails = Array.from(issueDetailsByFile.values());\n const prTitle = buildFeaturePrTitle(featureBranchName, allIssueDetails);\n const prBody = buildFeaturePrBody(allIssueDetails, allTasks, results, source!);\n const primaryIssue = allIssueDetails[0]?.number ?? \"\";\n const prUrl = await datasource.createPullRequest(\n featureBranchName,\n primaryIssue,\n prTitle,\n prBody,\n lifecycleOpts,\n startingBranch,\n );\n if (prUrl) {\n log.success(`Created feature PR: ${prUrl}`);\n }\n } catch (err) {\n log.warn(`Could not create feature PR: ${log.formatErrorChain(err)}`);\n }\n\n try {\n await datasource.switchBranch(featureDefaultBranch, lifecycleOpts);\n } catch (err) {\n log.warn(`Could not switch back to ${featureDefaultBranch}: ${log.formatErrorChain(err)}`);\n }\n }\n\n // ── 6. Cleanup ──────────────────────────────────────────────\n // Stateless skills have no cleanup. Pool cleanup is handled via registerCleanup() above.\n\n const completed = results.filter((result) => result.success).length;\n const failed = results.filter((result) => !result.success).length;\n\n tui.state.phase = \"done\";\n setAuthPromptHandler(null);\n tui.stop();\n if (verbose) log.success(`Done — ${completed} completed, ${failed} failed (${elapsed(Date.now() - tui.state.startTime)})`);\n\n return { total: allTasks.length, completed, failed, skipped: 0, results };\n } catch (err) {\n setAuthPromptHandler(null);\n tui.stop();\n throw err;\n }\n}\n\n/**\n * Dry-run mode — discovers and parses tasks, logs them, but does not\n * execute anything.\n */\nexport async function dryRunMode(\n issueIds: string[],\n cwd: string,\n source?: DatasourceName,\n org?: string,\n project?: string,\n workItemType?: string,\n iteration?: string,\n area?: string,\n username?: string,\n): Promise<DispatchSummary> {\n if (!source) {\n log.error(\"No datasource configured. Use --source or run 'dispatch config' to set up defaults.\");\n return { total: 0, completed: 0, failed: 0, skipped: 0, results: [] };\n }\n\n const datasource = getDatasource(source);\n const fetchOpts: IssueFetchOptions = { cwd, org, project, workItemType, iteration, area };\n\n const lifecycleOpts: DispatchLifecycleOptions = { cwd, username };\n let resolvedUsername = \"\";\n try {\n resolvedUsername = await datasource.getUsername(lifecycleOpts);\n } catch {\n // Fall back to empty prefix if username resolution fails\n }\n\n let items: IssueDetails[];\n if (issueIds.length > 0 && source === \"md\" && issueIds.some(id => isGlobOrFilePath(id))) {\n items = await resolveGlobItems(issueIds, cwd);\n } else if (issueIds.length > 0) {\n items = await fetchItemsById(issueIds, datasource, fetchOpts);\n } else {\n items = await datasource.list(fetchOpts);\n }\n\n if (items.length === 0) {\n const label = issueIds.length > 0 ? `issue(s) ${issueIds.join(\", \")}` : `datasource: ${source}`;\n log.warn(\"No work items found from \" + label);\n return { total: 0, completed: 0, failed: 0, skipped: 0, results: [] };\n }\n\n const { files, issueDetailsByFile } = await writeItemsToTempDir(items);\n\n const taskFiles: TaskFile[] = [];\n for (const file of files) {\n const tf = await parseTaskFile(file);\n if (tf.tasks.length > 0) {\n taskFiles.push(tf);\n }\n }\n\n const allTasks = taskFiles.flatMap((tf) => tf.tasks);\n\n if (allTasks.length === 0) {\n log.warn(\"No unchecked tasks found\");\n return { total: 0, completed: 0, failed: 0, skipped: 0, results: [] };\n }\n\n log.info(`Dry run — ${allTasks.length} task(s) across ${taskFiles.length} file(s):\\n`);\n for (const task of allTasks) {\n const parsed = parseIssueFilename(task.file);\n const details = parsed\n ? items.find((item) => item.number === parsed.issueId)\n : issueDetailsByFile.get(task.file);\n const branchInfo = details\n ? ` [branch: ${datasource.buildBranchName(details.number, details.title, resolvedUsername)}]`\n : \"\";\n log.task(allTasks.indexOf(task), allTasks.length, `${task.file}:${task.line} — ${task.text}${branchInfo}`);\n }\n\n return {\n total: allTasks.length,\n completed: 0,\n failed: 0,\n skipped: allTasks.length,\n results: [],\n };\n}\n","/**\n * Markdown task parser — extracts unchecked `[ ]` tasks from markdown files\n * and provides utilities to mark them as complete `[x]`.\n *\n * Non-task content (headings, prose, notes) is preserved in `TaskFile.context`\n * so the planner can use it for implementation guidance.\n */\n\nimport { readFile, writeFile } from \"node:fs/promises\";\n\nexport interface Task {\n /** Zero-based index within the file */\n index: number;\n /** The raw text after `- [ ] `, with any (P)/(S) prefix stripped */\n text: string;\n /** Line number in the file (1-based) */\n line: number;\n /** Full original line content */\n raw: string;\n /** The source file path */\n file: string;\n /** Execution mode — \"parallel\", \"serial\", or \"isolated\". Defaults to \"serial\" when unspecified. */\n mode?: \"parallel\" | \"serial\" | \"isolated\";\n}\n\nexport interface TaskFile {\n path: string;\n tasks: Task[];\n /** Full file content — includes non-task prose, headings, and notes */\n content: string;\n}\n\n/** Matches an unchecked markdown task item, e.g. `- [ ] Implement feature` */\nconst UNCHECKED_RE = /^(\\s*[-*]\\s)\\[ \\]\\s+(.+)$/;\n/** Matches a checked markdown task item, e.g. `- [x] Implement feature` */\nconst CHECKED_RE = /^(\\s*[-*]\\s)\\[[xX]\\]\\s+/;\n/** Replacement string used with UNCHECKED_RE to mark a task complete, e.g. `- [ ] task` → `- [x] task` */\nconst CHECKED_SUB = \"$1[x] $2\";\n/** Matches a mode prefix at the start of task text, e.g. `(P) Run tests in parallel` */\nconst MODE_PREFIX_RE = /^\\(([PSI])\\)\\s+/;\n\n/**\n * Build a filtered view of the file content for a single task's planner context.\n * Keeps:\n * - All non-task lines (headings, prose, notes, blank lines, checked tasks)\n * - The specific unchecked task line being planned\n * Removes:\n * - All *other* unchecked `[ ]` task lines\n *\n * This prevents the planner (and downstream executor) from being confused\n * by sibling tasks that belong to different agents.\n */\nexport function buildTaskContext(content: string, task: Task): string {\n const normalized = content.replace(/\\r\\n/g, \"\\n\");\n const lines = normalized.split(\"\\n\");\n\n const filtered = lines.filter((line, i) => {\n // Always keep the line that matches the current task\n if (i + 1 === task.line) return true;\n // Remove other unchecked task lines\n if (UNCHECKED_RE.test(line)) return false;\n // Keep everything else (headings, prose, checked tasks, blank lines)\n return true;\n });\n\n return filtered.join(\"\\n\");\n}\n\n/**\n * Parse markdown content (string) and return all unchecked tasks.\n * Pure function — no file I/O. Useful for testing and reuse.\n */\nexport function parseTaskContent(content: string, filePath: string): TaskFile {\n // Normalize CRLF → LF so the regex anchors work consistently\n const normalized = content.replace(/\\r\\n/g, \"\\n\");\n const lines = normalized.split(\"\\n\");\n const tasks: Task[] = [];\n\n for (let i = 0; i < lines.length; i++) {\n const match = lines[i].match(UNCHECKED_RE);\n if (match) {\n let text = match[2].trim();\n let mode: \"parallel\" | \"serial\" | \"isolated\" = \"serial\";\n\n const modeMatch = text.match(MODE_PREFIX_RE);\n if (modeMatch) {\n const modeMap: Record<string, \"parallel\" | \"serial\" | \"isolated\"> = {\n P: \"parallel\",\n S: \"serial\",\n I: \"isolated\",\n };\n mode = modeMap[modeMatch[1]] ?? \"serial\";\n text = text.slice(modeMatch[0].length);\n }\n\n tasks.push({\n index: tasks.length,\n text,\n line: i + 1,\n raw: lines[i],\n file: filePath,\n mode,\n });\n }\n }\n\n return { path: filePath, tasks, content };\n}\n\n/**\n * Parse a single markdown file and return all unchecked tasks.\n */\nexport async function parseTaskFile(filePath: string): Promise<TaskFile> {\n const content = await readFile(filePath, \"utf-8\");\n return parseTaskContent(content, filePath);\n}\n\n/**\n * Mark a specific task as complete in its source file by replacing `[ ]` with `[x]`.\n */\nexport async function markTaskComplete(task: Task): Promise<void> {\n const content = await readFile(task.file, \"utf-8\");\n const eol = content.includes(\"\\r\\n\") ? \"\\r\\n\" : \"\\n\";\n const normalized = content.replace(/\\r\\n/g, \"\\n\");\n const lines = normalized.split(\"\\n\");\n const lineIndex = task.line - 1;\n\n if (lineIndex < 0 || lineIndex >= lines.length) {\n throw new Error(\n `Line ${task.line} out of range in ${task.file} (${lines.length} lines)`\n );\n }\n\n const original = lines[lineIndex];\n const updated = original.replace(UNCHECKED_RE, CHECKED_SUB);\n\n if (original === updated) {\n throw new Error(\n `Line ${task.line} in ${task.file} does not match expected unchecked pattern: \"${original}\"`\n );\n }\n\n lines[lineIndex] = updated;\n await writeFile(task.file, lines.join(eol), \"utf-8\");\n}\n\n/**\n * Group a flat task list into ordered execution groups.\n *\n * - Consecutive parallel tasks accumulate into the current group.\n * - A serial task caps the current group (is appended to it), then a new group begins.\n * - A lone serial task (no preceding parallel tasks) forms a solo group.\n * - An isolated task flushes the current group (if non-empty) as its own group,\n * then creates a solo group containing only the isolated task, then resets\n * the accumulator. This guarantees the isolated task runs alone.\n *\n * The orchestrator runs each group concurrently, waiting for the group to\n * complete before starting the next one.\n */\nexport function groupTasksByMode(tasks: Task[]): Task[][] {\n if (tasks.length === 0) return [];\n\n const groups: Task[][] = [];\n let current: Task[] = [];\n\n for (const task of tasks) {\n const mode = task.mode ?? \"serial\";\n\n if (mode === \"parallel\") {\n current.push(task);\n } else if (mode === \"isolated\") {\n // Flush accumulated tasks as their own group\n if (current.length > 0) {\n groups.push(current);\n current = [];\n }\n // Push a solo group for the isolated task\n groups.push([task]);\n } else {\n // Serial task caps the current group\n current.push(task);\n groups.push(current);\n current = [];\n }\n }\n\n // Flush any remaining parallel tasks that weren't capped by a serial task\n if (current.length > 0) {\n groups.push(current);\n }\n\n return groups;\n}\n","/**\n * Planner skill — explores the codebase and researches the implementation\n * for a task, then produces a focused system prompt for the executor.\n *\n * Stateless data object: defines prompt construction and result parsing\n * without coupling to any provider. The dispatcher handles execution.\n */\n\nimport type { Skill } from \"./interface.js\";\nimport type { Task } from \"../parser.js\";\nimport type { PlannerData } from \"./types.js\";\nimport { formatEnvironmentPrompt } from \"../helpers/environment.js\";\n\n// ---------------------------------------------------------------------------\n// Input / Output types\n// ---------------------------------------------------------------------------\n\n/** Runtime input for the planner skill. */\nexport interface PlannerInput {\n task: Task;\n cwd: string;\n fileContext?: string;\n worktreeRoot?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Stateless skill definition\n// ---------------------------------------------------------------------------\n\n/** The planner skill — stateless, no provider coupling. */\nexport const plannerSkill: Skill<PlannerInput, PlannerData> = {\n name: \"planner\",\n\n buildPrompt(input: PlannerInput): string {\n return buildPlannerPrompt(input.task, input.cwd, input.fileContext, input.worktreeRoot);\n },\n\n parseResult(response: string | null): PlannerData {\n if (!response?.trim()) {\n throw new Error(\"Planner returned empty plan\");\n }\n return { prompt: response };\n },\n};\n\n// ---------------------------------------------------------------------------\n// Prompt builder (private)\n// ---------------------------------------------------------------------------\n\nfunction buildPlannerPrompt(task: Task, cwd: string, fileContext?: string, worktreeRoot?: string): string {\n const sections: string[] = [\n `Explore the codebase, understand the task below, and produce a detailed execution prompt that will be followed to implement the changes.`,\n ``,\n `## Task`,\n `- **Working directory:** ${cwd}`,\n `- **Source file:** ${task.file}`,\n `- **Task (line ${task.line}):** ${task.text}`,\n ];\n\n if (fileContext) {\n sections.push(\n ``,\n `## Task File Contents`,\n ``,\n `The task comes from a markdown file that may contain important implementation`,\n `details, requirements, and context in its non-task content (headings, prose,`,\n `notes). Review this carefully — it may describe conventions, constraints, or`,\n `technical details that are critical for the implementation.`,\n ``,\n `\\`\\`\\`markdown`,\n fileContext,\n `\\`\\`\\``,\n );\n }\n\n if (worktreeRoot) {\n sections.push(\n ``,\n `## Worktree Isolation`,\n ``,\n `You are operating inside a git worktree. All file operations MUST be confined`,\n `to the following directory tree:`,\n ``,\n ` ${worktreeRoot}`,\n ``,\n `- Do NOT read, write, or execute commands that access files outside this directory.`,\n `- Do NOT reference or modify files in the main repository working tree or other worktrees.`,\n `- All relative paths must resolve within the worktree root above.`,\n );\n }\n\n sections.push(\n ``,\n formatEnvironmentPrompt(),\n );\n\n sections.push(\n ``,\n `## Instructions`,\n ``,\n `1. **Explore the codebase** — read relevant files, search for symbols, and understand the project structure, conventions, and patterns.`,\n `2. **Review the task file contents above** — pay close attention to non-task text (headings, prose, notes) as it often contains important implementation details, requirements, and constraints.`,\n `3. **Identify the files** that need to be created or modified to complete this task.`,\n `4. **Research the implementation** — understand the existing code patterns, imports, types, and APIs involved.`,\n `5. **DO NOT make any changes** — you are only planning, not executing.`,\n ``,\n `## Output Format`,\n ``,\n `Produce your response as a **system prompt for the executor**. The executor will receive your output verbatim as its instructions. Write it in second person (\"You will...\", \"Modify the file...\").`,\n ``,\n `Your output MUST include:`,\n ``,\n `1. **Context** — A brief summary of the relevant project structure, conventions, and patterns the executor needs to know. Include any important details from the task file's non-task content.`,\n `2. **Files to modify** — The exact file paths that need to be created or changed, with the rationale for each.`,\n `3. **Step-by-step implementation** — Precise, ordered steps the executor should follow. Include:`,\n ` - Exact file paths`,\n ` - What to add, change, or remove`,\n ` - Code snippets, type signatures, or patterns to follow (based on existing code you read)`,\n ` - Import statements needed`,\n `4. **Constraints** — Any important constraints:`,\n ` - If the task description includes a commit instruction, include a final step in the plan to commit the changes using conventional commit conventions (supported types: feat, fix, docs, refactor, test, chore, style, perf, ci). If the task does not mention committing, instruct the executor to NOT commit changes.`,\n ` - Make minimal, correct changes — do not refactor unrelated code.`,\n ` - Follow existing code style and conventions found in the project.`,\n ``,\n `Be specific and concrete. Reference actual code you found during exploration. The executor has no prior context about this codebase — your prompt is all it gets.`,\n );\n\n return sections.join(\"\\n\");\n}\n","/**\n * Executor skill — executes a single task by constructing the appropriate\n * prompt (planned or generic) and parsing the provider response.\n *\n * Stateless data object: defines prompt construction and result parsing\n * without coupling to any provider. The dispatcher handles execution.\n */\n\nimport type { Skill } from \"./interface.js\";\nimport type { Task } from \"../parser.js\";\nimport type { ExecutorData } from \"./types.js\";\nimport { getEnvironmentBlock } from \"../helpers/environment.js\";\n\n// ---------------------------------------------------------------------------\n// Input / Output types\n// ---------------------------------------------------------------------------\n\n/**\n * Input to the executor for a single task.\n *\n * `plan` is the planner's output prompt string, or `null` when planning\n * was skipped (--no-plan). The executor uses this to decide whether to\n * build a planned prompt or a generic prompt.\n */\nexport interface ExecutorInput {\n /** The task to execute */\n task: Task;\n /** Working directory */\n cwd: string;\n /** Planner output prompt, or null if planning was skipped */\n plan: string | null;\n /** Worktree root directory for isolation, if operating in a worktree */\n worktreeRoot?: string;\n}\n\n/** @deprecated Alias for ExecutorInput — kept for backward compatibility. */\nexport type ExecuteInput = ExecutorInput;\n\n// ---------------------------------------------------------------------------\n// Rate-limit detection\n// ---------------------------------------------------------------------------\n\n/** Patterns that indicate the response is a rate-limit error. */\nconst rateLimitPatterns = [\n /you[''\\u2019]?ve hit your (rate )?limit/i,\n /rate limit exceeded/i,\n /too many requests/i,\n /quota exceeded/i,\n];\n\n// ---------------------------------------------------------------------------\n// Stateless skill definition\n// ---------------------------------------------------------------------------\n\n/** The executor skill — stateless, no provider coupling. */\nexport const executorSkill: Skill<ExecutorInput, ExecutorData> = {\n name: \"executor\",\n\n buildPrompt(input: ExecutorInput): string {\n return input.plan\n ? buildPlannedPrompt(input.task, input.cwd, input.plan, input.worktreeRoot)\n : buildPrompt(input.task, input.cwd, input.worktreeRoot);\n },\n\n parseResult(response: string | null, input: ExecutorInput): ExecutorData {\n if (response === null) {\n throw new Error(\"No response\");\n }\n\n const isRateLimited = rateLimitPatterns.some((p) => p.test(response));\n if (isRateLimited) {\n const truncated = response.slice(0, 200);\n throw new Error(`Rate limit: ${truncated}`);\n }\n\n return { dispatchResult: { task: input.task, success: true } };\n },\n};\n\n// ---------------------------------------------------------------------------\n// Prompt builders (private)\n// ---------------------------------------------------------------------------\n\nfunction buildCommitInstruction(taskText: string): string {\n if (/\\bcommit\\b/i.test(taskText)) {\n return (\n `- The task description includes a commit instruction. After completing the implementation, ` +\n `stage all changes and create a conventional commit. Use one of these types: ` +\n `feat, fix, docs, refactor, test, chore, style, perf, ci.`\n );\n }\n return `- Do NOT commit changes — the orchestrator handles commits.`;\n}\n\nfunction buildWorktreeIsolation(worktreeRoot?: string): string[] {\n if (!worktreeRoot) return [];\n return [\n `- **Worktree isolation:** You are operating inside a git worktree at \\`${worktreeRoot}\\`. ` +\n `You MUST NOT read, write, or execute commands that access files outside this directory. ` +\n `All file paths must resolve within \\`${worktreeRoot}\\`.`,\n ];\n}\n\nfunction buildPrompt(task: Task, cwd: string, worktreeRoot?: string): string {\n return [\n `Complete the following task from a markdown task file.`,\n ``,\n `**Working directory:** ${cwd}`,\n `**Source file:** ${task.file}`,\n `**Task (line ${task.line}):** ${task.text}`,\n ``,\n getEnvironmentBlock(),\n ``,\n `Instructions:`,\n `- Complete ONLY this specific task — do not work on other tasks.`,\n `- Make the minimal, correct changes needed.`,\n buildCommitInstruction(task.text),\n ...buildWorktreeIsolation(worktreeRoot),\n `- When finished, confirm by saying \"Task complete.\"`,\n ].join(\"\\n\");\n}\n\nfunction buildPlannedPrompt(task: Task, cwd: string, plan: string, worktreeRoot?: string): string {\n return [\n `Complete the task below by following the pre-planned execution instructions. The codebase has already been explored and a detailed plan has been produced.`,\n ``,\n `**Working directory:** ${cwd}`,\n `**Source file:** ${task.file}`,\n `**Task (line ${task.line}):** ${task.text}`,\n ``,\n getEnvironmentBlock(),\n ``,\n `---`,\n ``,\n `## Execution Plan`,\n ``,\n plan,\n ``,\n `---`,\n ``,\n `## Executor Constraints`,\n `- Follow the plan above precisely — do not deviate, skip steps, or reorder.`,\n `- Complete ONLY this specific task — do not work on other tasks.`,\n `- Make the minimal, correct changes needed — do not refactor unrelated code.`,\n `- Do NOT explore the codebase. The planner has already done all necessary research. Only read or modify the files explicitly referenced in the plan.`,\n `- Do NOT re-plan, question, or revise the plan. Trust it as given and execute it faithfully.`,\n `- Do NOT search for additional context using grep, find, or similar tools unless the plan explicitly instructs you to.`,\n buildCommitInstruction(task.text),\n ...buildWorktreeIsolation(worktreeRoot),\n `- When finished, confirm by saying \"Task complete.\"`,\n ].join(\"\\n\");\n}\n","/**\n * Commit skill — analyzes branch changes and generates meaningful\n * conventional-commit-compliant commit messages, PR titles, and PR\n * descriptions.\n *\n * Stateless data object: defines prompt construction and result parsing\n * without coupling to any provider. The dispatcher handles execution.\n */\n\nimport type { Skill } from \"./interface.js\";\nimport type { IssueDetails } from \"../datasources/interface.js\";\nimport type { DispatchResult } from \"../dispatcher.js\";\nimport { formatEnvironmentPrompt } from \"../helpers/environment.js\";\n\n// ---------------------------------------------------------------------------\n// Input / Output types\n// ---------------------------------------------------------------------------\n\n/** Runtime input for the commit skill. */\nexport interface CommitInput {\n /** Git diff of the branch relative to the default branch */\n branchDiff: string;\n /** Issue details for context */\n issue: IssueDetails;\n /** Task dispatch results */\n taskResults: DispatchResult[];\n /** Working directory */\n cwd: string;\n /** Worktree root directory for isolation, if operating in a worktree */\n worktreeRoot?: string;\n}\n\n/** @deprecated Alias for CommitInput — kept for backward compatibility. */\nexport type CommitGenerateOptions = CommitInput;\n\n/** Structured output from the commit skill. */\nexport interface CommitOutput {\n /** The generated conventional commit message */\n commitMessage: string;\n /** The generated PR title */\n prTitle: string;\n /** The generated PR description */\n prDescription: string;\n}\n\n// ---------------------------------------------------------------------------\n// Stateless skill definition\n// ---------------------------------------------------------------------------\n\n/** The commit skill — stateless, no provider coupling. */\nexport const commitSkill: Skill<CommitInput, CommitOutput> = {\n name: \"commit\",\n\n buildPrompt(input: CommitInput): string {\n return buildCommitPrompt(input);\n },\n\n parseResult(response: string | null): CommitOutput {\n if (!response?.trim()) {\n throw new Error(\"Commit skill returned empty response\");\n }\n\n const parsed = parseCommitResponse(response);\n\n if (!parsed.commitMessage || !parsed.prTitle) {\n throw new Error(\"Failed to parse commit response: no commit message or PR title found\");\n }\n\n return parsed;\n },\n};\n\n// ---------------------------------------------------------------------------\n// Prompt builder (exported — tests use it directly)\n// ---------------------------------------------------------------------------\n\n/**\n * Build the prompt that instructs the AI to analyze the branch diff and\n * generate a conventional commit message, PR title, and PR description.\n */\nexport function buildCommitPrompt(opts: CommitInput): string {\n const { branchDiff, issue, taskResults } = opts;\n\n const sections: string[] = [\n `Analyze the git diff below and generate a meaningful, conventional-commit-compliant commit message, a PR title, and a PR description.`,\n ``,\n formatEnvironmentPrompt(),\n ``,\n `## Conventional Commit Guidelines`,\n ``,\n `Follow the Conventional Commits specification (https://www.conventionalcommits.org/):`,\n `- Format: \\`<type>(<optional scope>): <description>\\``,\n `- Types: \\`feat\\`, \\`fix\\`, \\`docs\\`, \\`refactor\\`, \\`test\\`, \\`chore\\`, \\`style\\`, \\`perf\\`, \\`ci\\``,\n `- The description should be concise, imperative mood, lowercase first letter, no period at the end`,\n `- If the change includes breaking changes, add \\`!\\` after the type/scope (e.g., \\`feat!: ...\\`)`,\n ``,\n `## Issue Context`,\n ``,\n `- **Issue #${issue.number}:** ${issue.title}`,\n ];\n\n if (issue.body) {\n sections.push(\n `- **Description:** ${issue.body.slice(0, 500)}${issue.body.length > 500 ? \"...\" : \"\"}`\n );\n }\n\n if (issue.labels.length > 0) {\n sections.push(`- **Labels:** ${issue.labels.join(\", \")}`);\n }\n\n const completed = taskResults.filter((r) => r.success);\n const failed = taskResults.filter((r) => !r.success);\n\n if (taskResults.length > 0) {\n sections.push(``, `## Tasks`);\n if (completed.length > 0) {\n sections.push(``, `### Completed`);\n for (const r of completed) {\n sections.push(`- ${r.task.text}`);\n }\n }\n if (failed.length > 0) {\n sections.push(``, `### Failed`);\n for (const r of failed) {\n sections.push(\n `- ${r.task.text}${r.error ? ` (error: ${r.error})` : \"\"}`\n );\n }\n }\n }\n\n const maxDiffLength = 50_000;\n const truncatedDiff =\n branchDiff.length > maxDiffLength\n ? branchDiff.slice(0, maxDiffLength) +\n \"\\n\\n... (diff truncated due to size)\"\n : branchDiff;\n\n sections.push(\n ``,\n `## Git Diff`,\n ``,\n `\\`\\`\\`diff`,\n truncatedDiff,\n `\\`\\`\\``,\n ``,\n `## Required Output Format`,\n ``,\n `You MUST respond with exactly the following three sections, using these exact headers:`,\n ``,\n `### COMMIT_MESSAGE`,\n `<your conventional commit message here>`,\n ``,\n `### PR_TITLE`,\n `<your PR title here>`,\n ``,\n `### PR_DESCRIPTION`,\n `<your PR description in markdown here>`,\n ``,\n `**Rules:**`,\n `- The commit message MUST follow conventional commit format`,\n `- The PR title should be a concise, descriptive summary of the overall change`,\n `- The PR description should explain what changed and why, referencing the issue context`,\n `- Do NOT include any text outside these three sections`\n );\n\n return sections.join(\"\\n\");\n}\n\n// ---------------------------------------------------------------------------\n// Response parser (exported — tests use it directly)\n// ---------------------------------------------------------------------------\n\n/**\n * Parse the structured response into commit message, PR title,\n * and PR description. Uses robust matching to handle minor formatting\n * variations.\n */\nexport function parseCommitResponse(response: string): {\n commitMessage: string;\n prTitle: string;\n prDescription: string;\n} {\n const result = {\n commitMessage: \"\",\n prTitle: \"\",\n prDescription: \"\",\n };\n\n const commitMatch = response.match(\n /###\\s*COMMIT_MESSAGE\\s*\\n([\\s\\S]*?)(?=###\\s*PR_TITLE|$)/i\n );\n const titleMatch = response.match(\n /###\\s*PR_TITLE\\s*\\n([\\s\\S]*?)(?=###\\s*PR_DESCRIPTION|$)/i\n );\n const descMatch = response.match(\n /###\\s*PR_DESCRIPTION\\s*\\n([\\s\\S]*?)$/i\n );\n\n if (commitMatch?.[1]) {\n result.commitMessage = commitMatch[1].trim();\n }\n if (titleMatch?.[1]) {\n result.prTitle = titleMatch[1].trim();\n }\n if (descMatch?.[1]) {\n result.prDescription = descMatch[1].trim();\n }\n\n return result;\n}\n","/**\n * Git worktree lifecycle manager.\n *\n * Creates, removes, and lists git worktrees in `.dispatch/worktrees/`.\n * Worktree directory names are derived from the leading numeric ID of the\n * issue filename (e.g., `123-fix-auth-bug.md` → `issue-123`).\n */\n\nimport { join, basename } from \"node:path\";\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { randomUUID } from \"node:crypto\";\nimport { existsSync } from \"node:fs\";\nimport { rm } from \"node:fs/promises\";\nimport { slugify } from \"./slugify.js\";\nimport { log } from \"./logger.js\";\n\nconst exec = promisify(execFile);\n\n/** Base directory for worktrees, relative to the repository root. */\nconst WORKTREE_DIR = \".dispatch/worktrees\";\n\n/** Execute a git command in the given working directory and return stdout. */\nasync function git(args: string[], cwd: string): Promise<string> {\n const { stdout } = await exec(\"git\", args, { cwd, shell: process.platform === \"win32\" });\n return stdout;\n}\n\n/**\n * Derive a worktree directory name from an issue filename.\n *\n * Extracts the leading numeric ID and returns `issue-{id}`.\n * Example: `123-fix-auth-bug.md` → `issue-123`\n *\n * @param issueFilename - The issue filename (basename or full path)\n * @returns A directory name suitable for a worktree\n */\nexport function worktreeName(issueFilename: string): string {\n const base = basename(issueFilename);\n const withoutExt = base.replace(/\\.md$/i, \"\");\n const match = withoutExt.match(/^(\\d+)/);\n return match ? `issue-${match[1]}` : slugify(withoutExt);\n}\n\n/**\n * Create a git worktree for the given issue file.\n *\n * The worktree is placed at `.dispatch/worktrees/<name>` (relative to `repoRoot`)\n * and checks out a new branch with the specified `branchName`.\n *\n * @param repoRoot - Absolute path to the repository root\n * @param issueFilename - The issue filename used to derive the worktree directory name\n * @param branchName - The branch name to create and check out in the worktree\n * @returns The absolute path to the created worktree directory\n */\nexport async function createWorktree(\n repoRoot: string,\n issueFilename: string,\n branchName: string,\n startPoint?: string,\n): Promise<string> {\n const name = worktreeName(issueFilename);\n const worktreePath = join(repoRoot, WORKTREE_DIR, name);\n\n if (existsSync(worktreePath)) {\n try {\n const listOutput = await git([\"worktree\", \"list\", \"--porcelain\"], repoRoot);\n const isRegistered = listOutput.includes(`worktree ${worktreePath}\\n`);\n if (isRegistered) {\n // Reset to clean state\n try {\n await git([\"checkout\", \"--force\", branchName], worktreePath);\n await git([\"clean\", \"-fd\"], worktreePath);\n log.debug(`Reusing validated worktree at ${worktreePath}`);\n return worktreePath;\n } catch {\n // Checkout failed (wrong branch, etc.) — remove and recreate\n log.debug(`Worktree checkout failed, removing and recreating: ${worktreePath}`);\n }\n } else {\n log.debug(`Directory exists but not a registered worktree: ${worktreePath}`);\n }\n } catch {\n log.debug(`Worktree validation failed for ${worktreePath}`);\n }\n // Remove stale directory and fall through to creation\n await rm(worktreePath, { recursive: true, force: true });\n // Also prune to clean up any stale git refs\n await git([\"worktree\", \"prune\"], repoRoot).catch(() => {});\n }\n\n const MAX_RETRIES = 5;\n const BASE_DELAY_MS = 200;\n\n let lastError: unknown;\n\n for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {\n try {\n const args = [\"worktree\", \"add\", worktreePath, \"-b\", branchName];\n if (startPoint) args.push(startPoint);\n await git(args, repoRoot);\n log.debug(`Created worktree at ${worktreePath} on branch ${branchName}`);\n return worktreePath;\n } catch (err) {\n lastError = err;\n const message = log.extractMessage(err);\n\n // Handle \"branch already exists\" — retry without -b\n if (message.includes(\"already exists\")) {\n try {\n await git([\"worktree\", \"add\", worktreePath, branchName], repoRoot);\n log.debug(`Created worktree at ${worktreePath} using existing branch ${branchName}`);\n return worktreePath;\n } catch (retryErr) {\n lastError = retryErr;\n const retryMsg = log.extractMessage(retryErr);\n if (retryMsg.includes(\"already used by worktree\")) {\n await git([\"worktree\", \"prune\"], repoRoot);\n try {\n await git([\"worktree\", \"add\", worktreePath, branchName], repoRoot);\n log.debug(`Created worktree at ${worktreePath} after pruning stale ref`);\n return worktreePath;\n } catch (pruneRetryErr) {\n lastError = pruneRetryErr;\n }\n } else {\n throw retryErr;\n }\n }\n } else if (message.includes(\"already used by worktree\")) {\n await git([\"worktree\", \"prune\"], repoRoot);\n try {\n await git([\"worktree\", \"add\", worktreePath, branchName], repoRoot);\n log.debug(`Created worktree at ${worktreePath} after pruning stale ref`);\n return worktreePath;\n } catch (pruneRetryErr) {\n lastError = pruneRetryErr;\n }\n } else if (!message.includes(\"lock\") && !message.includes(\"already\")) {\n // Non-retryable error — throw immediately\n throw err;\n }\n\n // Retryable error (lock contention, race condition) — backoff and retry\n if (attempt < MAX_RETRIES) {\n const delay = BASE_DELAY_MS * Math.pow(2, attempt - 1);\n log.debug(`Worktree creation attempt ${attempt}/${MAX_RETRIES} failed (${message}), retrying in ${delay}ms...`);\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n }\n\n throw lastError;\n}\n\n/**\n * Remove a git worktree.\n *\n * Attempts a normal removal first, falling back to `--force` if needed.\n * Runs `git worktree prune` afterwards to clean up stale references.\n * Logs a warning instead of throwing on failure so execution can continue.\n *\n * @param repoRoot - Absolute path to the repository root\n * @param issueFilename - The issue filename used to derive the worktree directory name\n */\nexport async function removeWorktree(\n repoRoot: string,\n issueFilename: string,\n): Promise<void> {\n const name = worktreeName(issueFilename);\n const worktreePath = join(repoRoot, WORKTREE_DIR, name);\n\n try {\n await git([\"worktree\", \"remove\", worktreePath], repoRoot);\n } catch {\n // Force removal as fallback\n try {\n await git([\"worktree\", \"remove\", \"--force\", worktreePath], repoRoot);\n } catch (err) {\n log.warn(`Could not remove worktree ${name}: ${log.formatErrorChain(err)}`);\n return;\n }\n }\n\n // Prune stale worktree references\n try {\n await git([\"worktree\", \"prune\"], repoRoot);\n } catch (err) {\n log.warn(`Could not prune worktrees: ${log.formatErrorChain(err)}`);\n }\n}\n\n/**\n * List all current git worktrees in the repository.\n *\n * Returns the raw `git worktree list` output for diagnostic purposes.\n *\n * @param repoRoot - Absolute path to the repository root\n * @returns The worktree list output string\n */\nexport async function listWorktrees(repoRoot: string): Promise<string> {\n try {\n return await git([\"worktree\", \"list\"], repoRoot);\n } catch (err) {\n log.warn(`Could not list worktrees: ${log.formatErrorChain(err)}`);\n return \"\";\n }\n}\n\n/**\n * Generate a unique feature branch name.\n *\n * Produces a name in the format `dispatch/feature-{octet}`, where `{octet}`\n * is the first 8 hex characters of a random UUID.\n *\n * @returns A feature branch name like `dispatch/feature-a1b2c3d4`\n */\nexport function generateFeatureBranchName(): string {\n const uuid = randomUUID();\n const octet = uuid.split(\"-\")[0];\n return `dispatch/feature-${octet}`;\n}\n","/**\n * Provider error classification utilities.\n *\n * Provides heuristic-based detection of throttle/rate-limit errors from\n * provider SDKs. All four providers surface errors as `throw new Error(msg)`\n * with messages containing HTTP status codes or human-readable throttle language.\n */\n\n/**\n * Detect whether an error indicates throttling or rate-limiting by the provider.\n *\n * Uses pattern matching on error messages since provider SDKs don't expose\n * structured error codes. Covers common patterns across OpenAI-style APIs (429),\n * Copilot SDK error events, Claude API errors, and generic service unavailability.\n *\n * False positive = unnecessary failover (costs a retry, not data loss).\n * False negative = existing `withRetry` handles it (3 retries on any error).\n */\nexport function isThrottleError(err: unknown): boolean {\n const msg = (err instanceof Error ? err.message : String(err)).toLowerCase();\n return /rate.limit|429|503|throttl|capacity|overloaded|too many requests|service unavailable/.test(msg);\n}\n","/**\n * ProviderPool — a transparent failover wrapper that implements ProviderInstance.\n *\n * Agents receive a pool instead of a raw provider instance. The pool routes\n * requests to the cheapest available provider and automatically fails over\n * to alternatives when throttling is detected.\n *\n * Key design decisions:\n * - Lazy boots: only the primary provider is booted upfront; fallbacks are\n * booted on first failover to avoid wasting resources.\n * - Cooldowns: throttled providers are skipped for a configurable period.\n * - Session tracking: maps session IDs to owning instances so prompt()\n * calls route correctly.\n * - Single-entry pool: identical behavior to a bare ProviderInstance —\n * zero overhead for users who don't configure fallbacks.\n */\n\nimport type { ProviderName, ProviderInstance, ProviderBootOptions, ProviderPromptOptions } from \"./interface.js\";\nimport { bootProvider } from \"./index.js\";\nimport { isThrottleError } from \"./errors.js\";\nimport { log } from \"../helpers/logger.js\";\n\n/** A provider+model entry in the pool, ordered by priority. */\nexport interface PoolEntry {\n /** Provider name (e.g. \"copilot\", \"claude\") */\n provider: ProviderName;\n /** Model override in provider-specific format */\n model?: string;\n /** Lower = preferred (cheaper). Entries are tried in priority order. */\n priority: number;\n}\n\n/** Options for constructing a ProviderPool. */\nexport interface ProviderPoolOptions {\n /** Provider entries ordered by priority (cheapest first). */\n entries: PoolEntry[];\n /** Boot options shared by all providers (url, cwd). Model is per-entry. */\n bootOpts: Omit<ProviderBootOptions, \"model\">;\n /** How long (ms) to avoid a throttled provider. Default: 60000. */\n cooldownMs?: number;\n}\n\n/** Generate a deduplication key for a provider+model combo. */\nfunction entryKey(provider: ProviderName, model?: string): string {\n return `${provider}:${model ?? \"default\"}`;\n}\n\n/**\n * A pool of providers that implements ProviderInstance with transparent failover.\n *\n * Agents use this exactly like a normal provider — they never know about\n * the pool or failover mechanics.\n */\nexport class ProviderPool implements ProviderInstance {\n readonly name: string;\n readonly model?: string;\n\n private instances = new Map<string, ProviderInstance>();\n private cooldowns = new Map<string, number>();\n private sessionOwner = new Map<string, { instance: ProviderInstance; key: string }>();\n private entries: PoolEntry[];\n private bootOpts: Omit<ProviderBootOptions, \"model\">;\n private cooldownMs: number;\n\n constructor(opts: ProviderPoolOptions) {\n if (opts.entries.length === 0) {\n throw new Error(\"ProviderPool requires at least one entry\");\n }\n // Sort by priority (stable sort preserves insertion order for equal priorities)\n this.entries = [...opts.entries].sort((a, b) => a.priority - b.priority);\n this.bootOpts = opts.bootOpts;\n this.cooldownMs = opts.cooldownMs ?? 60_000;\n\n // Name and model reflect the primary (highest-priority) entry\n const primary = this.entries[0];\n this.name = primary.provider;\n this.model = primary.model;\n }\n\n /**\n * Get the best available provider instance (not cooled down).\n * Boots the provider lazily if not yet started.\n */\n private async getProvider(excludeKey?: string): Promise<{ instance: ProviderInstance; key: string }> {\n const now = Date.now();\n\n for (const entry of this.entries) {\n const key = entryKey(entry.provider, entry.model);\n\n // Skip if this is the excluded provider (the one that just failed)\n if (key === excludeKey) continue;\n\n // Skip if still in cooldown\n const cooldownUntil = this.cooldowns.get(key);\n if (cooldownUntil && now < cooldownUntil) continue;\n\n // Boot if not yet started\n if (!this.instances.has(key)) {\n log.debug(`Pool: booting ${entry.provider}${entry.model ? ` (${entry.model})` : \"\"}`);\n const instance = await bootProvider(entry.provider, {\n ...this.bootOpts,\n model: entry.model,\n });\n this.instances.set(key, instance);\n }\n\n return { instance: this.instances.get(key)!, key };\n }\n\n throw new Error(\"ProviderPool: all providers are throttled or unavailable\");\n }\n\n /** Mark a provider as throttled — it will be skipped until cooldown expires. */\n private markThrottled(key: string): void {\n this.cooldowns.set(key, Date.now() + this.cooldownMs);\n log.debug(`Pool: marked ${key} as throttled for ${this.cooldownMs}ms`);\n }\n\n async createSession(): Promise<string> {\n const { instance, key } = await this.getProvider();\n const sessionId = await instance.createSession();\n this.sessionOwner.set(sessionId, { instance, key });\n return sessionId;\n }\n\n async prompt(\n sessionId: string,\n text: string,\n options?: ProviderPromptOptions,\n ): Promise<string | null> {\n const owner = this.sessionOwner.get(sessionId);\n if (!owner) {\n throw new Error(`ProviderPool: session \"${sessionId}\" not found`);\n }\n\n try {\n return await owner.instance.prompt(sessionId, text, options);\n } catch (err) {\n // Only failover on throttle errors — all other errors propagate normally\n if (!isThrottleError(err) || this.entries.length <= 1) {\n throw err;\n }\n\n log.debug(`Pool: throttle detected on ${owner.key}, failing over...`);\n this.markThrottled(owner.key);\n\n // Get next available provider (excluding the one that just failed)\n const fallback = await this.getProvider(owner.key);\n\n // Create a new session on the fallback and retry the prompt\n const newSessionId = await fallback.instance.createSession();\n // Remap the original session ID to the fallback so any future calls route correctly\n this.sessionOwner.set(sessionId, fallback);\n\n return fallback.instance.prompt(newSessionId, text, options);\n }\n }\n\n async send(sessionId: string, text: string): Promise<void> {\n const owner = this.sessionOwner.get(sessionId);\n if (!owner) return;\n if (owner.instance.send) {\n await owner.instance.send(sessionId, text);\n }\n }\n\n async cleanup(): Promise<void> {\n const cleanups = [...this.instances.values()].map((i) => i.cleanup());\n await Promise.allSettled(cleanups);\n this.instances.clear();\n this.sessionOwner.clear();\n this.cooldowns.clear();\n }\n}\n","/**\n * Run-state persistence layer.\n *\n * Provides the same public API as the previous JSON-file implementation\n * but stores data in the SQLite database managed by `src/mcp/state/database.ts`.\n *\n * Migration: on first access the old `.dispatch/run-state.json` is read,\n * its data is imported into the database, and the file is left in place\n * (for safety — it will simply be ignored after that).\n *\n * Public API (preserved from the original implementation):\n * loadRunState(cwd) → RunState | null\n * saveRunState(cwd, state) → void\n * buildTaskId(task) → string\n * shouldSkipTask(id, state) → boolean\n */\n\nimport { readFile, mkdir } from \"node:fs/promises\";\nimport { join, basename } from \"node:path\";\nimport { z } from \"zod\";\nimport type { Task } from \"../parser.js\";\n\n// ── Public types (unchanged) ──────────────────────────────────\n\n// ── Zod schema for RunState (used at JSON parse boundaries) ───\n\n/** Reused by both the schema and the SQLite row parser below. */\nconst RunStateTaskStatusSchema = z.enum([\"pending\", \"running\", \"success\", \"failed\"]);\n\nconst RunStateTaskSchema = z.object({\n id: z.string(),\n status: RunStateTaskStatusSchema,\n branch: z.string().optional(),\n});\n\nconst RunStateSchema = z.object({\n runId: z.string(),\n preRunSha: z.string(),\n tasks: z.array(RunStateTaskSchema),\n});\n\n/** Derives from Zod schema — single source of truth for the shape. */\nexport type RunStateTask = z.infer<typeof RunStateTaskSchema>;\n\n/** Derives from Zod schema — single source of truth for the shape. */\nexport type RunState = z.infer<typeof RunStateSchema>;\n\n// ── SQLite helpers (lazy-loaded to avoid circular deps at module init) ──\n\nasync function getDb(cwd: string) {\n const { openDatabase } = await import(\"../mcp/state/database.js\");\n return openDatabase(cwd);\n}\n\n// ── Table bootstrap (idempotent) ──────────────────────────────\n\nasync function ensureRunStateTable(cwd: string): Promise<void> {\n const db = await getDb(cwd);\n db.exec(`\n CREATE TABLE IF NOT EXISTS run_state (\n run_id TEXT PRIMARY KEY,\n pre_run_sha TEXT NOT NULL DEFAULT '',\n updated_at INTEGER NOT NULL\n );\n CREATE TABLE IF NOT EXISTS run_state_tasks (\n run_id TEXT NOT NULL,\n task_id TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'pending',\n branch TEXT,\n PRIMARY KEY (run_id, task_id),\n FOREIGN KEY (run_id) REFERENCES run_state(run_id)\n );\n `);\n}\n\n// ── Migration from JSON (runs once) ──────────────────────────\n\nconst _migratedCwds = new Set<string>();\n\nasync function migrateFromJson(cwd: string): Promise<void> {\n if (_migratedCwds.has(cwd)) return;\n _migratedCwds.add(cwd);\n\n const jsonPath = join(cwd, \".dispatch\", \"run-state.json\");\n try {\n const raw = await readFile(jsonPath, \"utf-8\");\n const parsed = RunStateSchema.safeParse(JSON.parse(raw));\n if (!parsed.success) return; // malformed JSON file — skip migration\n const state = parsed.data;\n // Only import if there's no existing record in the DB\n const db = await getDb(cwd);\n const existing = db.prepare(\"SELECT run_id FROM run_state WHERE run_id = ?\").get(state.runId);\n if (!existing) {\n await saveRunState(cwd, state);\n }\n } catch {\n // No JSON file or invalid — nothing to migrate\n }\n}\n\n// ── Public API ────────────────────────────────────────────────\n\nexport async function loadRunState(cwd: string): Promise<RunState | null> {\n await ensureRunStateTable(cwd);\n await migrateFromJson(cwd);\n\n const db = await getDb(cwd);\n // SQLite returns plain objects; shape matches the table schema defined above\n const row = db.prepare(\n \"SELECT run_id, pre_run_sha FROM run_state ORDER BY updated_at DESC LIMIT 1\"\n ).get() as { run_id: string; pre_run_sha: string } | undefined;\n\n if (!row) return null;\n\n // SQLite returns plain objects; shape matches the run_state_tasks schema above\n const taskRows = db.prepare(\n \"SELECT task_id, status, branch FROM run_state_tasks WHERE run_id = ?\"\n ).all(row.run_id) as { task_id: string; status: string; branch: string | null }[];\n\n return {\n runId: row.run_id,\n preRunSha: row.pre_run_sha,\n tasks: taskRows.map((t) => {\n // Validate the status column value against the known enum at runtime\n const statusResult = RunStateTaskStatusSchema.safeParse(t.status);\n return {\n id: t.task_id,\n status: statusResult.success ? statusResult.data : \"pending\" as const,\n branch: t.branch ?? undefined,\n };\n }),\n };\n}\n\nexport async function saveRunState(cwd: string, state: RunState): Promise<void> {\n const dir = join(cwd, \".dispatch\");\n await mkdir(dir, { recursive: true });\n await ensureRunStateTable(cwd);\n\n const db = await getDb(cwd);\n const now = Date.now();\n\n const upsertRun = db.prepare(`\n INSERT INTO run_state (run_id, pre_run_sha, updated_at)\n VALUES (?, ?, ?)\n ON CONFLICT(run_id) DO UPDATE SET pre_run_sha = excluded.pre_run_sha, updated_at = excluded.updated_at\n `);\n\n const upsertTask = db.prepare(`\n INSERT INTO run_state_tasks (run_id, task_id, status, branch)\n VALUES (?, ?, ?, ?)\n ON CONFLICT(run_id, task_id) DO UPDATE SET status = excluded.status, branch = excluded.branch\n `);\n\n const tx = db.transaction((s: RunState) => {\n upsertRun.run(s.runId, s.preRunSha, now);\n for (const task of s.tasks) {\n upsertTask.run(s.runId, task.id, task.status, task.branch ?? null);\n }\n });\n\n tx(state);\n}\n\nexport function buildTaskId(task: Task): string {\n return `${basename(task.file)}:${task.line}`;\n}\n\nexport function shouldSkipTask(taskId: string, state: RunState | null): boolean {\n if (!state) return false;\n const entry = state.tasks.find((t) => t.id === taskId);\n return entry?.status === \"success\";\n}\n","/**\n * Child process entry point for dispatch/spec pipelines.\n *\n * Receives configuration via IPC, runs the appropriate pipeline,\n * and sends progress events back to the parent via process.send().\n */\n\nimport { boot as bootOrchestrator } from \"../orchestrator/runner.js\";\nimport { runSpecPipeline } from \"../orchestrator/spec-pipeline.js\";\n\ninterface StartDispatchMessage {\n type: \"dispatch\";\n cwd: string;\n opts: Record<string, unknown>;\n}\n\ninterface StartSpecMessage {\n type: \"spec\";\n cwd: string;\n opts: Record<string, unknown>;\n}\n\ntype WorkerMessage = StartDispatchMessage | StartSpecMessage;\n\nprocess.on(\"message\", (msg: WorkerMessage) => {\n void handleMessage(msg);\n});\n\nasync function handleMessage(msg: WorkerMessage): Promise<void> {\n try {\n if (msg.type === \"dispatch\") {\n const orchestrator = await bootOrchestrator({ cwd: msg.cwd });\n const result = await orchestrator.orchestrate({\n ...msg.opts,\n progressCallback: (event: Record<string, unknown>) => {\n process.send!({ type: \"progress\", event });\n },\n } as never);\n process.send!({ type: \"done\", result });\n } else if (msg.type === \"spec\") {\n const result = await runSpecPipeline({\n ...msg.opts,\n progressCallback: (event: Record<string, unknown>) => {\n process.send!({ type: \"spec_progress\", event });\n },\n } as never);\n process.send!({ type: \"done\", result });\n }\n } catch (err) {\n process.send!({ type: \"error\", message: err instanceof Error ? err.message : String(err) });\n }\n process.exit(0);\n}\n"],"mappings":"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","names":["chalk","resolve","input","join","mkdirSync","randomUUID","resolve","randomUUID","readFile","writeFile","mkdir","join","dirname","resolve","SESSION_READY_TIMEOUT_MS","boot","resolve","SESSION_READY_TIMEOUT_MS","join","SESSION_READY_TIMEOUT_MS","boot","SESSION_READY_TIMEOUT_MS","randomUUID","readFile","homedir","join","SESSION_READY_TIMEOUT_MS","boot","randomUUID","SESSION_READY_TIMEOUT_MS","execFile","promisify","boot","execFile","promisify","execFile","promisify","readFile","join","dirname","homedir","join","homedir","readFile","dirname","exec","promisify","execFile","execFile","promisify","exec","promisify","execFile","git","redactUrl","datasource","execFile","readFile","writeFile","mkdir","dirname","join","promisify","input","resolve","exec","promisify","execFile","git","join","datasource","mdFiles","results","readFile","dir","dirname","content","writeFile","mkdir","exec","promisify","execFile","datasource","chalk","join","readFile","mkdir","dirname","writeFile","input","execFile","promisify","exec","readFile","writeFile","join","join","readFile","writeFile","dirname","join","join","join","join","resolve","mkdir","readFile","rename","unlink","randomUUID","glob","isFast","readFile","writeFile","input","readFile","writeFile","input","resolve","chalk","useState","useEffect","render","Box","Text","useInput","jsx","jsxs","PALETTE","input","doneCount","resolve","resolve","resolve","basename","join","writeFile","execFile","promisify","exec","promisify","execFile","basename","datasource","join","writeFile","exec","datasource","join","glob","readFile","chalk","mkdir","resolve","randomUUID","rename","unlink","execFile","promisify","readFile","glob","readFile","writeFile","readFile","writeFile","input","input","input","join","basename","execFile","promisify","randomUUID","existsSync","exec","promisify","execFile","git","basename","join","existsSync","resolve","randomUUID","cleanups","chalk","readFile","mkdir","join","basename","basename","exec","promisify","execFile","glob","readFile","chalk","datasource","boot","opts","datasource","randomUUID","workerMessage","runId","total","failed","getSpecRun","select","boot"]}
|