nightralph 0.0.53 → 0.0.56
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 +181 -19
- package/dist/blockers.js +149 -0
- package/dist/blockers.js.map +7 -0
- package/dist/display.js +12 -4
- package/dist/display.js.map +2 -2
- package/dist/docs-templates/issue-tracker.md +9 -1
- package/dist/index.js +2735 -415
- package/dist/index.js.map +4 -4
- package/dist/learnings.js +360 -0
- package/dist/learnings.js.map +7 -0
- package/dist/meta.json +289 -16
- package/dist/orchestrator.js +753 -188
- package/dist/orchestrator.js.map +3 -3
- package/dist/preflight.js +34 -0
- package/dist/preflight.js.map +7 -0
- package/dist/progress.js +5 -4
- package/dist/progress.js.map +2 -2
- package/dist/resolve.js +98 -9
- package/dist/resolve.js.map +2 -2
- package/dist/retry.js +83 -0
- package/dist/retry.js.map +7 -0
- package/dist/review.js +669 -0
- package/dist/review.js.map +7 -0
- package/dist/rules.js +67 -0
- package/dist/rules.js.map +7 -0
- package/dist/skills/to-tickets/SKILL.md +5 -5
- package/dist/src/blockers.d.ts +45 -0
- package/dist/src/blockers.d.ts.map +1 -0
- package/dist/src/display.d.ts +9 -0
- package/dist/src/display.d.ts.map +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/learnings.d.ts +70 -0
- package/dist/src/learnings.d.ts.map +1 -0
- package/dist/src/orchestrator.d.ts +85 -28
- package/dist/src/orchestrator.d.ts.map +1 -1
- package/dist/src/preflight.d.ts +6 -0
- package/dist/src/preflight.d.ts.map +1 -0
- package/dist/src/progress.d.ts +1 -1
- package/dist/src/progress.d.ts.map +1 -1
- package/dist/src/resolve.d.ts +24 -0
- package/dist/src/resolve.d.ts.map +1 -1
- package/dist/src/retry.d.ts +26 -0
- package/dist/src/retry.d.ts.map +1 -0
- package/dist/src/review.d.ts +131 -0
- package/dist/src/review.d.ts.map +1 -0
- package/dist/src/rules.d.ts +11 -0
- package/dist/src/rules.d.ts.map +1 -0
- package/dist/src/stats.d.ts +43 -0
- package/dist/src/stats.d.ts.map +1 -0
- package/dist/src/testcmd.d.ts +1 -0
- package/dist/src/testcmd.d.ts.map +1 -1
- package/dist/src/worktree.d.ts +30 -1
- package/dist/src/worktree.d.ts.map +1 -1
- package/dist/stats.js +111 -0
- package/dist/stats.js.map +7 -0
- package/dist/testcmd.js +13 -0
- package/dist/testcmd.js.map +2 -2
- package/dist/worktree.js +236 -32
- package/dist/worktree.js.map +2 -2
- package/package.json +3 -2
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/index.ts", "../src/setup.ts", "../src/orchestrator.ts", "../src/worktree.ts", "../src/progress.ts", "../src/merge.ts", "../src/display.ts", "../src/testcmd.ts", "../src/resolve.ts"],
|
|
4
|
-
"sourcesContent": ["#!/usr/bin/env node\n\nimport { existsSync, readFileSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport yargs from 'yargs'\nimport { hideBin } from 'yargs/helpers'\nimport { select } from '@inquirer/prompts'\nimport { setup, checkGhAuth, type TrackerKind } from './setup.js'\nimport {\n scanTickets,\n dryRun,\n dryRunIsolated,\n runWaves,\n runWavesIsolated,\n stripSpecSection,\n ALL_EFFORT_LEVELS,\n DEFAULT_RETRIES,\n DEFAULT_RETRY_DELAY,\n DEFAULT_CONCURRENCY,\n killRunningAgents,\n type EffortLevel,\n type Ticket,\n} from './orchestrator.js'\nimport { detectTestCmd } from './testcmd.js'\nimport { createDisplay } from './display.js'\nimport { findFeatureDirs, resolveIssuesDir, getScriptDir } from './resolve.js'\nimport { getRepoRoot, getRepoName } from './worktree.js'\n\nexport { findFeatureDirs, resolveIssuesDir }\n\nconst scriptDir = getScriptDir(import.meta.url)\n\nyargs(hideBin(process.argv))\n .scriptName('nightralph')\n .usage('$0 <command>')\n .command(\n 'init',\n 'Install bundled skills and doc templates',\n y => y,\n async () => {\n const tracker = await select<TrackerKind>({\n message:'Issue tracker format',\n choices:[\n {\n name:'Local Markdown',\n value:'local' as const,\n description:'Issues as .md files in ' +\n '.scratch/',\n },\n {\n name:'GitHub Issues',\n value:'github' as const,\n description:'Issues via gh CLI',\n },\n ],\n })\n\n if (tracker === 'github') {\n if (!checkGhAuth()) {\n console.error(\n 'GitHub Issues requires the gh CLI, ' +\n 'authenticated.\\n' +\n 'Install: https://cli.github.com\\n' +\n 'Then run: gh auth login'\n )\n process.exit(2)\n }\n }\n\n setup({\n bundledSkillsDir:join(scriptDir, 'skills'),\n docsTemplatesDir:join(\n scriptDir, 'docs-templates'\n ),\n projectDir:process.cwd(),\n tracker,\n })\n }\n )\n .command(\n '$0 <provider> [turns]',\n 'Execute tickets with the given provider',\n y => y\n .positional('provider', {\n type:'string',\n describe:'Agent CLI to spawn ' +\n '(e.g. claude, codex, pi)',\n demandOption:true,\n })\n .positional('turns', {\n type:'number',\n describe:'Max agentic turns per ' +\n 'ticket (shorthand for ' +\n '--max-turns)',\n })\n .option('m', {\n alias:'model',\n type:'string',\n describe:'Model passed to the agent',\n })\n .option('spec', {\n type:'string',\n describe:'Feature name ' +\n '(resolves .scratch/<name>/)',\n })\n .option('dry-run', {\n type:'boolean',\n describe:'Show wave order without running',\n default:false,\n })\n .option('timeout', {\n type:'number',\n describe:'Kill agent after N seconds',\n default:3600,\n })\n .option('test-cmd', {\n type:'string',\n describe:'Command run in each worktree ' +\n 'after the agent exits; non-zero ' +\n 'exit rejects the ticket. Defaults ' +\n 'to \"npm test\".',\n })\n .option('X', {\n type:'boolean',\n describe:'Stop on merge conflict instead of ' +\n 're-spawning',\n default:false,\n })\n .option('max-turns', {\n type:'number',\n describe:'Max agentic turns per ticket ' +\n '(forwarded to the agent CLI)',\n })\n .option('effort', {\n type:'string',\n choices:ALL_EFFORT_LEVELS,\n describe:'Starting effort level. ' +\n 'Omitted = provider default. ' +\n 'Retries step up from here.',\n })\n .option('retries', {\n type:'number',\n default:DEFAULT_RETRIES,\n describe:'Extra attempts per ticket ' +\n 'after a failed run, each with a ' +\n 'higher effort level. 0 ' +\n 'disables retries.',\n })\n .option('retry-delay', {\n type:'number',\n default:DEFAULT_RETRY_DELAY,\n describe:'Seconds to wait before the ' +\n 'first retry; doubles each further ' +\n 'retry. 0 disables the wait.',\n })\n .option('concurrency', {\n type:'number',\n default:DEFAULT_CONCURRENCY,\n describe:'Max agents running at once ' +\n 'within a wave.',\n }),\n async argv => {\n await runExecute({\n provider:argv.provider as string,\n model:argv.model as string|undefined,\n spec:argv.spec as string|undefined,\n dryRun:argv.dryRun as boolean|undefined,\n timeout:argv.timeout as\n number|undefined,\n testCmd:argv.testCmd as string|undefined,\n stopOnConflict:argv.X as\n boolean|undefined,\n maxTurns:(argv.maxTurns ??\n argv.turns) as number|undefined,\n effort:argv.effort as\n EffortLevel|undefined,\n retries:argv.retries as\n number|undefined,\n retryDelay:argv.retryDelay as\n number|undefined,\n concurrency:argv.concurrency as\n number|undefined,\n })\n }\n )\n .strict()\n .demandCommand(1, 'Specify a command or provider')\n .help()\n .parse()\n\nfunction isGitRepo ():boolean {\n try {\n getRepoRoot()\n return true\n } catch {\n return false\n }\n}\n\nfunction extractFeatureName (spec:string):string {\n const parts = spec.split(\n /[\\\\/]/\n )\n const scratchIndex = parts.indexOf('.scratch')\n if (scratchIndex >= 0 && scratchIndex < parts.length - 1) {\n return parts[scratchIndex + 1]\n }\n return parts[parts.length - 2] ??\n parts[parts.length - 1] ?? 'feature'\n}\n\nasync function runExecute (argv:{\n provider:string\n model?:string\n spec?:string\n dryRun?:boolean\n timeout?:number\n testCmd?:string\n stopOnConflict?:boolean\n maxTurns?:number\n effort?:EffortLevel\n retries?:number\n retryDelay?:number\n concurrency?:number\n}):Promise<void> {\n const selections = await resolveIssuesDir(\n argv.spec\n )\n\n const allTickets:Ticket[] = []\n const specBodies = new Map<string, string>()\n const progressPaths = new Map<string, string>()\n let firstFeatureName = ''\n let firstLogsDir = ''\n\n for (const selection of selections) {\n const { dir, spec, name } = selection\n\n if (!existsSync(dir)) {\n console.error(\n `Directory not found: ${dir}`\n )\n process.exit(2)\n }\n if (!existsSync(spec)) {\n console.error(\n `Spec file not found: ${spec}`\n )\n process.exit(2)\n }\n\n const specBody = stripSpecSection(\n readFileSync(spec, 'utf8'),\n 'User Stories'\n )\n const tickets = scanTickets(dir, name)\n\n if (tickets.length === 0) {\n console.log(\n 'No ticket files found for ' +\n `${name}. Skipping.`\n )\n continue\n }\n\n console.log(\n `[${name}] Found ${tickets.length} tickets`\n )\n\n const knownNums = new Set(\n tickets.map(t => t.num)\n )\n for (const t of tickets) {\n const unknown = t.blockers.filter(\n b => !knownNums.has(b)\n )\n if (unknown.length > 0) {\n console.warn(\n `${t.filename}: blockers ` +\n `[${unknown.join(', ')}] ` +\n 'not found in directory'\n )\n }\n t.blockers = t.blockers.filter(\n b => knownNums.has(b)\n )\n }\n\n specBodies.set(name, specBody)\n progressPaths.set(\n name, join(dirname(dir), 'progress.md')\n )\n allTickets.push(...tickets)\n\n if (!firstFeatureName) {\n firstFeatureName = extractFeatureName(spec)\n firstLogsDir = join(dirname(dir), 'logs')\n }\n }\n\n if (allTickets.length === 0) return\n\n const timeout = argv.timeout ?? 900\n const testCmd = argv.testCmd || detectTestCmd(\n isGitRepo() ?\n getRepoRoot() :\n process.cwd()\n ) || 'npm test'\n const conflictStrategy = argv.stopOnConflict ?\n 'stop' :\n 'respawn'\n const logsDir = firstLogsDir\n const fallbackSpec = specBodies.values().next().value!\n\n if (argv.dryRun) {\n if (isGitRepo()) {\n const repoName = getRepoName()\n dryRunIsolated({\n tickets:allTickets,\n specBody:fallbackSpec,\n repoName,\n conflictStrategy,\n progressPath:progressPaths.values()\n .next().value!,\n testCmd,\n effort:argv.effort,\n retries:argv.retries,\n retryDelay:argv.retryDelay,\n concurrency:argv.concurrency,\n })\n } else {\n dryRun(allTickets, fallbackSpec, testCmd)\n }\n return\n }\n\n const display = createDisplay()\n\n function onSignal (exitCode:number):void {\n killRunningAgents()\n display.cleanup()\n process.exit(exitCode)\n }\n process.on('SIGINT', () => onSignal(130))\n process.on('SIGTERM', () => onSignal(143))\n\n let result:{ allDone:boolean }\n\n if (isGitRepo()) {\n result = await runWavesIsolated({\n tickets:allTickets,\n specBody:fallbackSpec,\n specBodies,\n agentCmd:argv.provider,\n model:argv.model ?? null,\n timeout,\n logsDir,\n featureName:firstFeatureName,\n conflictStrategy,\n display,\n testCmd,\n maxTurns:argv.maxTurns,\n effort:argv.effort,\n retries:argv.retries,\n retryDelay:argv.retryDelay,\n concurrency:argv.concurrency,\n progressPaths,\n })\n } else {\n result = await runWaves(\n allTickets, fallbackSpec,\n argv.provider, argv.model ?? null,\n timeout,\n logsDir,\n testCmd,\n display,\n argv.maxTurns,\n argv.effort,\n argv.retries,\n argv.retryDelay,\n argv.concurrency,\n )\n }\n\n if (!result.allDone) {\n process.exit(1)\n }\n}\n", "import {\n cpSync,\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n symlinkSync,\n writeFileSync,\n} from 'node:fs'\nimport { join } from 'node:path'\nimport { execSync } from 'node:child_process'\n\nexport const SKILL_DIRS = [\n 'grill', 'grilling', 'domain-modeling',\n 'to-spec', 'to-tickets', 'tdd',\n 'codebase-design',\n] as const\n\nexport const DOC_TEMPLATES = [\n 'triage-labels.md',\n 'domain.md',\n] as const\n\nconst START_MARKER = '<!-- nightralph:start -->'\nconst END_MARKER = '<!-- nightralph:end -->'\n\nexport function writeManagedSection (\n filePath:string,\n content:string,\n):void {\n const block = [\n START_MARKER,\n content,\n END_MARKER,\n ].join('\\n')\n\n if (!existsSync(filePath)) {\n writeFileSync(filePath, block + '\\n')\n return\n }\n\n const existing = readFileSync(filePath, 'utf8')\n const startIdx = existing.indexOf(START_MARKER)\n const endIdx = existing.indexOf(END_MARKER)\n\n if (startIdx !== -1 && endIdx !== -1) {\n const before = existing.slice(0, startIdx)\n const after = existing.slice(\n endIdx + END_MARKER.length\n )\n writeFileSync(filePath, before + block + after)\n } else {\n const sep = existing.endsWith('\\n') ? '\\n' : '\\n\\n'\n writeFileSync(filePath, existing + sep + block + '\\n')\n }\n}\n\nfunction ensureGitAttribute (\n filePath:string,\n line:string,\n):void {\n if (!existsSync(filePath)) {\n writeFileSync(filePath, line + '\\n')\n return\n }\n const existing = readFileSync(filePath, 'utf8')\n if (existing.split('\\n').includes(line)) return\n const sep = existing.endsWith('\\n') ? '' : '\\n'\n writeFileSync(filePath, existing + sep + line + '\\n')\n}\n\nexport function checkGhAuth ():boolean {\n try {\n execSync('gh auth status', { stdio:'ignore' })\n return true\n } catch {\n return false\n }\n}\n\nexport type TrackerKind = 'github'|'local'\n\nexport type SetupOpts = {\n bundledSkillsDir:string\n docsTemplatesDir:string\n projectDir:string\n tracker:TrackerKind\n}\n\nconst TRACKER_TEMPLATES:Record<TrackerKind, string> = {\n local:'issue-tracker.md',\n github:'issue-tracker-github.md',\n}\n\nexport function setup (opts:SetupOpts):void {\n const {\n bundledSkillsDir,\n docsTemplatesDir,\n projectDir,\n tracker,\n } = opts\n const agentsSkillsDir = join(\n projectDir, '.agents', 'skills'\n )\n\n const upstream = JSON.parse(\n readFileSync(\n join(bundledSkillsDir, 'upstream.json'),\n 'utf8'\n )\n ) as { repo:string; commit:string }\n\n console.log('Installing skills to .agents/skills/\\n')\n\n for (const skill of SKILL_DIRS) {\n const src = join(bundledSkillsDir, skill)\n const dest = join(agentsSkillsDir, skill)\n mkdirSync(dest, { recursive:true })\n cpSync(src, dest, { recursive:true })\n const files = readdirSync(src)\n console.log(\n ` ${skill}/ (${files.join(', ')})`\n )\n }\n\n const claudeSkillsDir = join(\n projectDir, '.claude', 'skills'\n )\n mkdirSync(claudeSkillsDir, { recursive:true })\n\n for (const skill of SKILL_DIRS) {\n const linkPath = join(claudeSkillsDir, skill)\n const target = join(\n '..', '..', '.agents', 'skills', skill\n )\n if (existsSync(linkPath)) continue\n symlinkSync(target, linkPath)\n }\n\n console.log(\n '\\nCreated symlinks in .claude/skills/'\n )\n\n const docsAgentsDir = join(\n projectDir, 'docs', 'agents'\n )\n mkdirSync(docsAgentsDir, { recursive:true })\n\n console.log('')\n for (const tmpl of DOC_TEMPLATES) {\n const dest = join(docsAgentsDir, tmpl)\n if (existsSync(dest)) {\n console.log(\n ` docs/agents/${tmpl} (already exists)`\n )\n continue\n }\n const src = join(docsTemplatesDir, tmpl)\n writeFileSync(dest, readFileSync(src, 'utf8'))\n console.log(` docs/agents/${tmpl} (created)`)\n }\n\n const trackerSrc = join(\n docsTemplatesDir, TRACKER_TEMPLATES[tracker]\n )\n const trackerDest = join(docsAgentsDir, 'issue-tracker.md')\n writeFileSync(trackerDest, readFileSync(trackerSrc, 'utf8'))\n console.log(\n ` docs/agents/issue-tracker.md (${tracker})`\n )\n\n const trackerLine = tracker === 'github' ?\n 'Issues are tracked via GitHub Issues using the `gh` ' +\n 'CLI.' :\n 'Issues are tracked as local markdown files under ' +\n '`.scratch/`.'\n\n const managedContent = [\n '## Agent skills',\n '',\n '### Issue tracker',\n '',\n `${trackerLine} See \\`docs/agents/issue-tracker.md\\`.`,\n '',\n '### Triage labels',\n '',\n 'Default label vocabulary. See ' +\n '`docs/agents/triage-labels.md`.',\n '',\n '### Domain docs',\n '',\n 'Single-context layout. See `docs/agents/domain.md`.',\n ].join('\\n')\n\n const agentsPath = join(projectDir, 'AGENTS.md')\n writeManagedSection(agentsPath, managedContent)\n console.log('\\n AGENTS.md (updated)')\n\n ensureGitAttribute(\n join(projectDir, '.gitattributes'),\n 'AGENTS.md merge=union',\n )\n console.log(' .gitattributes (AGENTS.md merge=union)')\n\n console.log(\n `\\nSource: ${upstream.repo} @ ${upstream.commit}`\n )\n}\n", "import { spawn, execFile } from 'node:child_process'\nimport {\n createWriteStream,\n mkdirSync,\n readFileSync,\n writeFileSync,\n unlinkSync,\n readdirSync,\n} from 'node:fs'\nimport { tmpdir } from 'node:os'\nimport { join, dirname, basename } from 'node:path'\nimport { createInterface } from 'node:readline'\nimport { promisify } from 'node:util'\n\nconst execFileAsync = promisify(execFile)\nimport {\n getRepoRoot,\n getRepoName,\n getCurrentBranch,\n createWorktree,\n removeWorktree,\n buildBranchName,\n hasNewCommits,\n isDirty,\n commitDirty,\n} from './worktree.js'\nimport {\n generateProgress,\n generateMultiFeatureProgress,\n createProgressTracker,\n readProgress,\n mergeProgress,\n writeProgress,\n commitProgress,\n checkTicket,\n type ProgressData,\n type ProgressTracker,\n} from './progress.js'\nimport {\n mergeBranch,\n mergeWave,\n updateWorktreeFromBase,\n type MergeConflictStrategy,\n} from './merge.js'\nimport {\n createDisplay,\n ticketLabel,\n type RunProgress,\n type Display,\n type TicketRef,\n} from './display.js'\nimport { runTestCmd } from './testcmd.js'\n\nexport type Ticket = {\n num:number\n slug:string\n filename:string\n filepath:string\n body:string\n status:string\n blockers:number[]\n feature:string\n}\n\nexport function formatErrorMessage (error:unknown):string {\n return error instanceof Error ?\n error.message :\n String(error)\n}\n\n// Removes a ticket's worktree, logging and swallowing any\n// failure instead of letting it interrupt the wave.\nasync function removeWorktreeQuietly (\n worktreePath:string,\n d:Display\n):Promise<void> {\n try {\n await removeWorktree(worktreePath, { force:true })\n } catch (err) {\n d.log(\n ' Failed to remove worktree ' +\n `${worktreePath}: ` +\n formatErrorMessage(err)\n )\n }\n}\n\nasync function commitTicketFiles (\n repoRoot:string,\n tickets:Ticket[],\n d:Display\n):Promise<void> {\n const paths = tickets.map(t => t.filepath)\n if (paths.length === 0) return\n try {\n await execFileAsync(\n 'git',\n ['add', '--force', ...paths],\n { cwd:repoRoot }\n )\n try {\n await execFileAsync(\n 'git',\n ['diff', '--cached', '--quiet',\n '--', ...paths],\n { cwd:repoRoot }\n )\n return\n } catch {\n // staged files differ from HEAD\n }\n await execFileAsync(\n 'git',\n ['commit', '-m',\n 'nightralph: update ticket checklists',\n '--', ...paths],\n { cwd:repoRoot }\n )\n } catch (err) {\n d.log(\n ' Failed to commit ticket updates: ' +\n formatErrorMessage(err)\n )\n }\n}\n\nexport const TICKET_RE = /^(\\d+)-(.+)\\.md$/\n\nexport function parseTicketFilename (\n filename:string\n):{ num:number; slug:string }|null {\n const m = filename.match(TICKET_RE)\n if (!m) return null\n return { num:Number(m[1]), slug:m[2] }\n}\n\nexport function parseStatus (body:string):string {\n const m = body.match(/\\*\\*Status:\\*\\*\\s*(.+)/i)\n return m ? m[1].trim().toLowerCase() : ''\n}\n\nexport function parseBlockers (body:string):number[] {\n const m = body.match(/\\*\\*Blocked by:\\*\\*\\s*(.+)/i)\n if (!m) return []\n const text = m[1]\n if (/none/i.test(text)) return []\n const nums:number[] = []\n const re = /(\\d+)/g\n let match\n while ((match = re.exec(text))) {\n nums.push(Number(match[1]))\n }\n return nums\n}\n\nexport function scanTickets (\n dir:string,\n feature:string = ''\n):Ticket[] {\n const files = readdirSync(dir)\n .filter(f => TICKET_RE.test(f))\n .sort((a, b) => a.localeCompare(\n b,\n undefined,\n { numeric:true, sensitivity:'base' }\n ))\n\n return files.map(filename => {\n const parsed = parseTicketFilename(filename)!\n const filepath = join(dir, filename)\n const body = readFileSync(filepath, 'utf8')\n return {\n num:parsed.num,\n slug:parsed.slug,\n filename,\n filepath,\n body,\n status:parseStatus(body),\n blockers:parseBlockers(body),\n feature,\n }\n })\n}\n\nexport function ticketKey (feature:string, num:number):string {\n return `${feature}:${num}`\n}\n\nexport function findReadyTickets (\n tickets:ReadonlyArray<Ticket>\n):Ticket[] {\n const doneKeys = new Set(\n tickets\n .filter(t => t.status === 'done')\n .map(t => ticketKey(t.feature, t.num))\n )\n return tickets.filter(t => {\n if (t.status !== 'ready-for-agent') return false\n return t.blockers.every(b =>\n doneKeys.has(ticketKey(t.feature, b))\n )\n })\n}\n\n/**\n * Tickets that cannot run this session because a ticket they\n * depend on (directly or through a chain, within their own\n * feature) is dead: in `failedKeys`, or in a status that is\n * neither done nor ready-for-agent, e.g. ready-for-human.\n * Returns ticketKey -> dead upstream ticketKeys. Only\n * ready-for-agent tickets that have not failed are keys. A\n * blocker number with no matching ticket is not dead.\n */\nexport function findBlockedTickets (\n tickets:ReadonlyArray<Ticket>,\n failedKeys:ReadonlySet<string>,\n):Map<string, Array<string>> {\n const byKey = new Map(\n tickets.map(t => [ticketKey(t.feature, t.num), t])\n )\n\n function collectDead (\n ticket:Ticket,\n visited:Set<string>,\n found:Set<string>,\n ):void {\n for (const b of ticket.blockers) {\n const key = ticketKey(ticket.feature, b)\n if (visited.has(key)) continue\n visited.add(key)\n const blocker = byKey.get(key)\n if (!blocker || blocker.status === 'done') continue\n if (\n failedKeys.has(key) ||\n blocker.status !== 'ready-for-agent'\n ) {\n found.add(key)\n continue\n }\n collectDead(blocker, visited, found)\n }\n }\n\n const blocked = new Map<string, Array<string>>()\n for (const t of tickets) {\n const key = ticketKey(t.feature, t.num)\n if (t.status !== 'ready-for-agent') continue\n if (failedKeys.has(key)) continue\n const found = new Set<string>()\n collectDead(t, new Set([key]), found)\n if (found.size > 0) blocked.set(key, [...found])\n }\n return blocked\n}\n\n// Matches an agent-reported completed item. Agents echo items\n// as markdown checklist lines (`- [x] item`) as often as bare\n// `[x] item` lines, so the bullet prefix is optional.\nexport const COMPLETED_RE = /^\\s*[-*+]?\\s*\\[x\\]\\s+(.+)$/i\nexport const TOOL_USE_RE = /^\\[[\\w.]+\\]/\n\n// Matches one checklist line in a ticket file: optional indent\n// and bullet, the `[ ]` / `[x]` box, and the item text.\nconst CHECKBOX_RE = /^(\\s*[-*+] )\\[( |x|X)\\]( .*)$/\n\n// The unchecked-box variant, used for the actual flip to [x].\nconst UNCHECKED_BOX_RE = /^(\\s*[-*+] )\\[( )\\]/\n\n// Normalizes checklist text for matching: agents echo an item as\n// one logical line while ticket files wrap items across lines,\n// so compare with whitespace runs collapsed, case-insensitively.\nfunction normalizeItemText (s:string):string {\n return s.replace(/\\s+/g, ' ').trim().toLowerCase()\n}\n\n// Drops an optional markdown bullet/checkbox prefix so items match\n// whether or not the caller already stripped the `[x]` marker.\nfunction stripCheckboxPrefix (s:string):string {\n return s.replace(/^\\s*[-*+]?\\s*\\[[ xX]\\]\\s+/, '')\n}\n\ntype ParsedItem = { start:number; text:string }\n\n// Parses the checklist items out of a ticket body. An item is its\n// checkbox line plus any immediately following indented lines\n// (wrapped text), so items written across multiple lines can be\n// matched by their full text. Code fences are skipped.\nfunction parseChecklistItems (\n lines:string[]\n):ParsedItem[] {\n const items:ParsedItem[] = []\n let inFence = false\n let i = 0\n while (i < lines.length) {\n if (/^\\s*```/.test(lines[i])) {\n inFence = !inFence\n i++\n continue\n }\n if (inFence) {\n i++\n continue\n }\n const m = lines[i].match(CHECKBOX_RE)\n if (!m) {\n i++\n continue\n }\n const start = i\n let text = m[3]\n i++\n while (\n i < lines.length &&\n /^\\s+\\S/.test(lines[i]) &&\n !CHECKBOX_RE.test(lines[i])\n ) {\n text += ' ' + lines[i].trim()\n i++\n }\n items.push({\n start,\n text:normalizeItemText(text),\n })\n }\n return items\n}\n\nexport function checkItems (\n ticket:Ticket,\n completedItems:string[]\n):void {\n if (completedItems.length === 0) return\n // Read from disk: a merge or respawn may have changed the\n // file since the ticket was scanned, and writing the stale\n // body would drop those edits.\n let body:string\n try {\n body = readFileSync(ticket.filepath, 'utf8')\n } catch {\n body = ticket.body\n }\n const wanted = new Set(\n completedItems.map(item =>\n normalizeItemText(stripCheckboxPrefix(item))\n )\n )\n const lines = body.split('\\n')\n let changed = false\n for (const item of parseChecklistItems(lines)) {\n if (!wanted.has(item.text)) continue\n const flipped = lines[item.start].replace(\n UNCHECKED_BOX_RE,\n '$1[x]'\n )\n if (flipped !== lines[item.start]) {\n lines[item.start] = flipped\n changed = true\n }\n }\n if (!changed) return\n body = lines.join('\\n')\n writeFileSync(ticket.filepath, body)\n ticket.body = body\n}\n\n// Checks off every remaining unchecked item in a ticket body,\n// ignoring fenced code blocks.\nfunction checkAllItems (body:string):string {\n const lines = body.split('\\n')\n let inFence = false\n for (let i = 0; i < lines.length; i++) {\n if (/^\\s*```/.test(lines[i])) {\n inFence = !inFence\n continue\n }\n if (inFence) continue\n lines[i] = lines[i].replace(\n UNCHECKED_BOX_RE,\n '$1[x]'\n )\n }\n return lines.join('\\n')\n}\n\nexport function markDone (ticket:Ticket):void {\n // Re-read from disk: the merge may have brought the agent's\n // own edits to the ticket file into the repo, and writing\n // the body scanned at startup would drop them.\n let body:string\n try {\n body = readFileSync(ticket.filepath, 'utf8')\n } catch {\n body = ticket.body\n }\n // A done ticket's items are complete by definition, so check\n // off anything the agent did not report instead of leaving\n // the file claiming done with unchecked items.\n body = checkAllItems(body)\n const updated = body.replace(\n /\\*\\*Status:\\*\\*\\s*.+/i,\n '**Status:** done'\n )\n writeFileSync(ticket.filepath, updated)\n ticket.status = 'done'\n ticket.body = updated\n}\n\n// Drops one markdown section from a spec. Used to keep the\n// per-ticket prompt short: the User Stories list is useful\n// to humans and to to-tickets but not to an implementing agent.\nexport function stripSpecSection (\n specBody:string,\n heading:string\n):string {\n const out:string[] = []\n let skipping = false\n let skipLevel = 0\n let inFence = false\n\n for (const line of specBody.split('\\n')) {\n // Toggle fence state on lines starting with ``` (after\n // optional whitespace)\n if (/^\\s*```/.test(line)) {\n inFence = !inFence\n }\n\n // Only check for headings outside of code fences\n if (!inFence) {\n const m = /^(#{1,6})\\s+(.*?)\\s*$/.exec(line)\n if (m) {\n const level = m[1].length\n if (skipping && level <= skipLevel) {\n skipping = false\n }\n if (!skipping && m[2] === heading) {\n skipping = true\n skipLevel = level\n continue\n }\n }\n }\n if (!skipping) out.push(line)\n }\n\n return out.join('\\n')\n}\n\nexport function lookupSpec (\n specBodies:Map<string, string>|undefined,\n fallback:string,\n feature:string\n):string {\n if (!feature || !specBodies) return fallback\n return specBodies.get(feature) ?? fallback\n}\n\nexport function renderPrompt (\n specBody:string,\n ticket:Ticket,\n opts:{ testCmd:string }\n):string {\n return [\n '---- SPEC CONTEXT ----',\n specBody,\n '',\n '---- TICKET ----',\n ticket.filename,\n ticket.body,\n '',\n '---- AGENT INSTRUCTIONS ----',\n 'You are an autonomous coding agent. ' +\n 'Implement the ticket using /tdd.',\n '',\n 'Follow these rules:',\n '- Read the files directly relevant to the ' +\n 'ticket before writing code. Also read any ' +\n 'AGENTS.md in or above the directories you ' +\n 'will touch, plus CONTEXT.md and the ' +\n 'relevant docs/adr/ entries if they exist. ' +\n 'If they do not exist, proceed silently.',\n '- Work ONLY on this ticket. Do not fix ' +\n 'unrelated problems you notice.',\n '- Do NOT research external APIs or services ' +\n 'via web search. Use the spec and ticket ' +\n 'body as your sole reference for API shapes.',\n '- Use /tdd for every checklist item. For ' +\n 'each item, write a failing test at the ' +\n 'seams named in the spec\\'s Testing ' +\n 'Decisions section, then write only ' +\n 'enough code to make it pass, then ' +\n 'refactor.',\n '- While iterating, run only the tests ' +\n 'relevant to what you changed. Run ' +\n `\\`${opts.testCmd}\\` in full once, as the ` +\n 'final gate before your last commit. Do ' +\n 'not commit with failing tests. The ' +\n 'orchestrator runs the same command after ' +\n 'you exit and rejects the ticket if it ' +\n 'fails.',\n '- If the project has a lint script, run it ' +\n 'and fix what it reports.',\n '- INTEGRITY: never delete, skip, weaken, or ' +\n 'write tautological tests to force a green ' +\n 'result. Only report a checklist item done ' +\n 'when its real tests genuinely pass. If an ' +\n 'item cannot be completed honestly, leave ' +\n 'it unchecked and say what blocked you.',\n '- Do NOT read or modify files outside ' +\n 'your current directory (the worktree).',\n '- Do NOT run git push.',\n '- Commit after each checklist item, and make ' +\n 'sure everything is committed when finished.',\n '- After completing each checklist item in the ' +\n 'ticket, print a line: [x] <item text> ' +\n '(matching the checklist text exactly).',\n '- Before your final commit, record reusable ' +\n 'learnings in the nearest AGENTS.md (in or ' +\n 'above the directories you modified; ' +\n 'prefer that over the repo root). Good ' +\n 'additions: module conventions, gotchas, ' +\n 'files that must change together, how to ' +\n 'test that area, environment requirements. ' +\n 'Do NOT add ticket-specific details or ' +\n 'temporary debugging notes. Only write ' +\n 'when you have knowledge that would help ' +\n 'future work in that directory.',\n '',\n ].join('\\n')\n}\n\nexport function renderMergePrompt (\n specBody:string,\n ticket:Ticket\n):string {\n return [\n '---- SPEC CONTEXT ----',\n specBody,\n '',\n '---- TICKET ----',\n ticket.filename,\n ticket.body,\n '',\n '---- AGENT INSTRUCTIONS ----',\n 'You are an autonomous coding agent resolving ' +\n 'a merge conflict.',\n '',\n 'Another agent already implemented this ticket ' +\n 'on a feature branch. The branch was then ' +\n 'merged with the base branch, but conflicts ' +\n 'arose. The working tree may contain conflict ' +\n 'markers that need resolution.',\n '',\n 'Your task:',\n '1. Find and resolve all conflict markers ' +\n '(<<<<<<< / ======= / >>>>>>>).',\n '2. When AGENTS.md or other docs conflict, ' +\n 'keep both sides\\' additions rather than ' +\n 'picking one.',\n '3. Make sure the code compiles and tests pass.',\n '4. Commit the resolved files.',\n '',\n 'Do NOT re-implement the ticket from scratch.',\n 'Do NOT read or modify files outside your ' +\n 'current directory (the worktree).',\n 'Do NOT run git push.',\n ].join('\\n')\n}\n\nfunction listTickets (tickets:ReadonlyArray<Ticket>):void {\n console.log('\\nTickets:')\n for (const t of tickets) {\n const blockerStr = t.blockers.length > 0 ?\n `blocked by [${t.blockers.join(', ')}]` :\n 'no blockers'\n console.log(\n ` ${t.filename} ` +\n `(${t.status}) ${blockerStr}`\n )\n }\n}\n\nfunction * simulateWaves (\n tickets:ReadonlyArray<Ticket>\n):Generator<{ wave:number; ready:Array<Ticket> }> {\n const sim = new Map(\n tickets.map(t => [\n ticketKey(t.feature, t.num),\n t.status,\n ])\n )\n let wave = 1\n while (true) {\n const doneKeys = new Set(\n [...sim.entries()]\n .filter(([, s]) => s === 'done')\n .map(([k]) => k)\n )\n const ready = [...tickets].filter(t => {\n const key = ticketKey(t.feature, t.num)\n if (sim.get(key) !== 'ready-for-agent') {\n return false\n }\n return t.blockers.every(b =>\n doneKeys.has(\n ticketKey(t.feature, b)\n )\n )\n })\n if (ready.length === 0) break\n yield { wave, ready }\n for (const t of ready) {\n sim.set(\n ticketKey(t.feature, t.num),\n 'done'\n )\n }\n wave++\n }\n}\n\nfunction detectDeadlocks (\n tickets:ReadonlyArray<Ticket>\n):Array<Ticket> {\n const doneKeys = new Set<string>()\n const readyKeys = new Set<string>()\n\n for (const t of tickets) {\n const key = ticketKey(t.feature, t.num)\n if (t.status === 'ready-for-agent') {\n readyKeys.add(key)\n } else if (t.status === 'done') {\n doneKeys.add(key)\n }\n }\n\n let changed = true\n while (changed) {\n changed = false\n for (const key of readyKeys) {\n const ticket = tickets.find(t =>\n ticketKey(t.feature, t.num) === key\n )!\n if (ticket.blockers.every(b =>\n doneKeys.has(\n ticketKey(ticket.feature, b)\n )\n )) {\n doneKeys.add(key)\n readyKeys.delete(key)\n changed = true\n }\n }\n }\n\n return [...readyKeys].map(key =>\n tickets.find(t =>\n ticketKey(t.feature, t.num) === key\n )!\n )\n}\n\nconst PROVIDER_ARGS:Record<string, string[]> = {\n claude:[\n '--print', '--verbose',\n '--output-format', 'stream-json',\n '--dangerously-skip-permissions',\n ],\n // codex removed --full-auto; this is the counterpart\n // of claude's --dangerously-skip-permissions, and the\n // workspace-write sandbox would block commits because\n // a worktree's .git link points outside the tree\n codex:['exec', '--dangerously-bypass-approvals-and-sandbox'],\n pi:[\n '-p', '--verbose',\n '--approve', '--no-session',\n '--mode', 'json',\n ],\n}\n\nexport function getProviderArgs (cmd:string):string[] {\n const name = basename(cmd)\n return PROVIDER_ARGS[name] ?? []\n}\n\n// Per-provider effort ladders.\nexport const EFFORT_LADDERS = {\n pi:['off', 'minimal', 'low', 'medium',\n 'high', 'xhigh', 'max'],\n claude:['low', 'medium', 'high',\n 'xhigh', 'max'],\n codex:['low', 'medium', 'high'],\n} as const\n\nexport type ProviderName =\n keyof typeof EFFORT_LADDERS\n\nexport type EffortLevel =\n typeof EFFORT_LADDERS[ProviderName][number]\n\nexport const ALL_EFFORT_LEVELS:EffortLevel[] = [\n 'off', 'minimal', 'low', 'medium',\n 'high', 'xhigh', 'max',\n]\n\n// Step up the effort ladder for a given provider.\n// Without a starting level, the first retry jumps to high.\n// Otherwise, step one rung up and stop at the provider's max.\nexport function escalateEffort (\n provider:ProviderName,\n level?:EffortLevel\n):EffortLevel {\n if (!level) return 'high'\n const ladder = EFFORT_LADDERS[provider]\n const i = (ladder as readonly string[])\n .indexOf(level)\n if (i === -1) return level\n return ladder[\n Math.min(i + 1, ladder.length - 1)\n ] as EffortLevel\n}\n\nexport function formatStreamLine (\n line:string\n):string|null {\n let obj:Record<string, unknown>\n try {\n obj = JSON.parse(line) as Record<string, unknown>\n } catch {\n return line\n }\n\n if (obj.type === 'assistant') {\n const msg = obj.message as\n Record<string, unknown>|undefined\n const content = msg?.content as\n Array<Record<string, unknown>>|undefined\n if (!content) return null\n for (const block of content) {\n if (block.type === 'text') {\n return String(block.text)\n }\n }\n return null\n }\n\n if (obj.type === 'result') {\n const sub = obj.subtype as string|undefined ?? 'done'\n const cost = obj.total_cost_usd as number|undefined\n const costStr = cost != null ?\n ` ($${cost.toFixed(2)})` :\n ''\n return `${sub}${costStr}`\n }\n\n if (obj.type === 'system') {\n const sub = obj.subtype as string|undefined\n if (sub === 'api_retry') {\n const error = obj.error as string|undefined\n return `retry: ${error ?? 'unknown'}`\n }\n }\n\n return null\n}\n\nexport type PiStreamFormatter = {\n process:(line:string) => string[]\n flush:() => string[]\n}\n\nexport function createPiStreamFormatter (\n):PiStreamFormatter {\n const calls = new Map<\n number, { name:string; buf:string }\n >()\n let textBuf = ''\n\n function drainLines ():string[] {\n const parts = textBuf.split('\\n')\n if (parts.length === 1) return []\n textBuf = parts[parts.length - 1]\n return parts.slice(0, -1)\n }\n\n function flushBuf ():string[] {\n if (textBuf.length === 0) return []\n const out = textBuf\n textBuf = ''\n return [out]\n }\n\n function process (line:string):string[] {\n let obj:Record<string, unknown>\n try {\n obj = JSON.parse(line) as\n Record<string, unknown>\n } catch {\n return [line]\n }\n\n const evt = obj.assistantMessageEvent as\n Record<string, unknown>|undefined\n if (!evt) return []\n\n const type = evt.type as string|undefined\n const ci = evt.contentIndex as\n number|undefined ?? -1\n\n if (type === 'text_delta') {\n const delta =\n (evt.delta as string|undefined) ?? ''\n textBuf += delta\n return drainLines()\n }\n\n if (type === 'toolcall_start') {\n const flushed = flushBuf()\n calls.set(ci, {\n name:(evt.toolName as\n string|undefined) ?? '?',\n buf:'',\n })\n return flushed\n }\n\n if (\n type === 'toolcall_delta' &&\n calls.has(ci)\n ) {\n calls.get(ci)!.buf +=\n (evt.delta as string|undefined) ?? ''\n return []\n }\n\n if (\n type === 'toolcall_end' &&\n calls.has(ci)\n ) {\n const call = calls.get(ci)!\n calls.delete(ci)\n let label = ''\n try {\n const args = JSON.parse(call.buf) as\n Record<string, unknown>\n label = String(\n args.command ??\n args.file_path ??\n args.query ?? ''\n ).split('\\n')[0].slice(0, 72)\n } catch {\n // unparseable tool args\n }\n return [`[${call.name}] ${label}`]\n }\n\n return []\n }\n\n return { process, flush:flushBuf }\n}\n\nfunction writePromptFile (prompt:string):string {\n const name = `nightralph-${Date.now()}-` +\n `${Math.random().toString(36).slice(2)}.md`\n const filePath = join(tmpdir(), name)\n writeFileSync(filePath, prompt)\n return filePath\n}\n\nfunction cleanupPromptFile (filePath:string):void {\n try {\n unlinkSync(filePath)\n } catch {\n // already removed\n }\n}\n\nexport type AgentResult = {\n exitCode:number\n completedItems:string[]\n // true when the orchestrator killed the agent at\n // the timeout; exitCode is non-zero in that case\n timedOut:boolean\n}\n\n// How long to wait after the process exits before giving up on a\n// graceful pipe close and forcing the streams shut. A grandchild\n// (dev server, watcher) that inherited the agent's stdout can keep\n// the pipe open after the agent itself has been killed, which would\n// otherwise leave spawnAgent's promise pending forever.\nconst CLOSE_GRACE_MS = 2000\n\n// Agents are spawned with detached:true so they become their own\n// process group leader; this lets us kill the whole tree (agent +\n// any children it spawned, like dev servers) with one signal to\n// -pid instead of leaving orphans behind. Exported for reuse by\n// signal handling (Ctrl-C / SIGTERM).\nexport function killProcessGroup (pid:number|undefined):void {\n if (pid === undefined) return\n try {\n process.kill(-pid, 'SIGKILL')\n } catch {\n // The group kill failed (e.g. the group was already\n // reaped, or the pid is not a group leader). Fall back\n // to killing the process directly so a still-running\n // pid never escapes the kill.\n try {\n process.kill(pid, 'SIGKILL')\n } catch {\n // Process is already gone.\n }\n }\n}\n\n// Tracks every agent process spawnAgent currently has running, so\n// a Ctrl-C or SIGTERM to the orchestrator itself can kill them all\n// instead of leaving them running after the orchestrator exits.\nconst runningAgents = new Set<number>()\n\nexport function killRunningAgents ():number {\n let killed = 0\n for (const pid of runningAgents) {\n killProcessGroup(pid)\n killed++\n }\n return killed\n}\n\nexport function spawnAgent (opts:{\n prompt:string\n agentCmd:string\n model:string|null\n timeout:number\n logPath:string\n cwd?:string\n label?:string\n maxTurns?:number\n effort?:EffortLevel\n onLine?:(line:string) => void\n}):Promise<AgentResult> {\n const args:string[] = [\n ...getProviderArgs(opts.agentCmd),\n ]\n if (opts.model) {\n args.push('--model', opts.model)\n }\n const providerName = basename(opts.agentCmd)\n const isClaude = providerName === 'claude'\n const isPi = providerName === 'pi'\n\n if (opts.maxTurns) {\n if (isClaude) {\n args.push(\n '--max-turns',\n String(opts.maxTurns)\n )\n } else if (opts.onLine) {\n opts.onLine(\n 'Warning: --max-turns not ' +\n `supported by ${providerName}, ` +\n 'skipping'\n )\n }\n }\n if (opts.effort && providerName in EFFORT_LADDERS) {\n const ladder = EFFORT_LADDERS[\n providerName as ProviderName\n ]\n if (\n !(ladder as readonly string[])\n .includes(opts.effort)\n ) {\n if (opts.onLine) {\n opts.onLine(\n 'Warning: effort ' +\n `'${opts.effort}' not ` +\n 'supported by ' +\n `${providerName}, skipping`\n )\n }\n } else if (isPi) {\n args.push('--thinking', opts.effort)\n } else if (isClaude) {\n args.push('--effort', opts.effort)\n } else if (providerName === 'codex') {\n args.push(\n '-c',\n `model_reasoning_effort=${opts.effort}`\n )\n }\n }\n const prefix = opts.label ?\n ` [${opts.label}] ` :\n ' '\n\n let promptFile:string|null = null\n if (isPi) {\n promptFile = writePromptFile(opts.prompt)\n args.push(`@${promptFile}`)\n }\n\n const logStream = createWriteStream(\n opts.logPath,\n { flags:'w' }\n )\n const proc = spawn(opts.agentCmd, args, {\n stdio:['pipe', 'pipe', 'pipe'],\n cwd:opts.cwd,\n detached:true,\n })\n\n if (proc.pid !== undefined) runningAgents.add(proc.pid)\n\n // stdout and stderr share one log, so neither pipe may end\n // it: the first to reach EOF would end the log while the\n // other still has data, which drops that output or crashes\n // the run with ERR_STREAM_WRITE_AFTER_END. finish() ends it.\n proc.stdout.pipe(logStream, { end:false })\n\n const piFormatter = isPi ?\n createPiStreamFormatter() :\n null\n\n const completedItems:string[] = []\n const seenItems = new Set<string>()\n\n function collectCompleted (text:string):void {\n // Reported items arrive as one multi-line text block\n // (claude), as drained single lines (pi), or as raw\n // lines (other providers); matching per line covers all\n // three, including summaries with several [x] lines.\n for (const line of text.split('\\n')) {\n const match = line.match(COMPLETED_RE)\n if (!match) continue\n const item = match[1].trim()\n if (!item || seenItems.has(item)) continue\n seenItems.add(item)\n completedItems.push(item)\n }\n }\n\n const rl = createInterface({ input:proc.stdout })\n rl.on('line', line => {\n if (isClaude) {\n const formatted = formatStreamLine(line)\n if (formatted !== null) {\n collectCompleted(formatted)\n const output = `${prefix}${formatted}`\n if (opts.onLine) {\n opts.onLine(output)\n } else {\n console.log(output)\n }\n }\n } else if (piFormatter) {\n const lines = piFormatter.process(line)\n for (const formatted of lines) {\n collectCompleted(formatted)\n const output = `${prefix}${formatted}`\n if (opts.onLine) {\n opts.onLine(output)\n } else {\n console.log(output)\n }\n }\n } else {\n collectCompleted(line)\n const output = `${prefix}${line}`\n if (opts.onLine) {\n opts.onLine(output)\n } else {\n console.log(output)\n }\n }\n })\n\n proc.stderr.pipe(logStream, { end:false })\n const rlErr = createInterface({ input:proc.stderr })\n rlErr.on('line', line => {\n if (isClaude && !TOOL_USE_RE.test(line)) return\n const output = `${prefix}${line}`\n if (opts.onLine) {\n opts.onLine(output)\n } else {\n console.error(output)\n }\n })\n\n let timedOut = false\n const timeout = setTimeout(() => {\n if (proc.killed) return\n timedOut = true\n const msg = 'agent timed out after ' +\n `${opts.timeout}s; killing it`\n // The status display repaints the screen, so a\n // bare console.warn would be painted over. Route\n // the reason through onLine and into the ticket\n // log so it is visible in both places.\n logStream.write(`nightralph: ${msg}\\n`)\n if (opts.onLine) {\n opts.onLine(`${prefix}${msg}`)\n } else {\n console.warn(`${prefix}${msg}`)\n }\n killProcessGroup(proc.pid)\n }, opts.timeout * 1000)\n\n // An agent that exits before draining stdin (bad flags,\n // auth failure) closes its end of the pipe; writing to it\n // then raises EPIPE on proc.stdin. Without a listener that\n // is an uncaught 'error' event that kills the orchestrator.\n proc.stdin.on('error', err => {\n logStream.write(\n 'nightralph: stdin write failed: ' +\n `${formatErrorMessage(err)}\\n`\n )\n })\n\n if (!promptFile) {\n proc.stdin.write(opts.prompt)\n }\n proc.stdin.end()\n\n return new Promise<AgentResult>(resolve => {\n let settled = false\n let graceTimer:ReturnType<typeof setTimeout>|undefined\n\n function finish (exitCode:number):void {\n if (settled) return\n settled = true\n clearTimeout(timeout)\n if (graceTimer) clearTimeout(graceTimer)\n if (proc.pid !== undefined) {\n runningAgents.delete(proc.pid)\n }\n if (piFormatter) {\n for (const line of piFormatter.flush()) {\n collectCompleted(line)\n const output = `${prefix}${line}`\n if (opts.onLine) {\n opts.onLine(output)\n } else {\n console.log(output)\n }\n }\n }\n rl.close()\n rlErr.close()\n logStream.end()\n if (promptFile) cleanupPromptFile(promptFile)\n resolve({ exitCode, completedItems, timedOut })\n }\n\n // The process itself has exited, but 'close' waits for its\n // stdio streams to close too -- a grandchild that inherited\n // stdout/stderr can hold those pipes open indefinitely. Give\n // it a grace period, then destroy the streams ourselves so\n // the run does not hang forever on someone else's fd.\n proc.on('exit', code => {\n graceTimer = setTimeout(() => {\n killProcessGroup(proc.pid)\n proc.stdout.destroy()\n proc.stderr.destroy()\n finish(code ?? 1)\n }, CLOSE_GRACE_MS)\n })\n\n proc.on('close', code => {\n finish(code ?? 1)\n })\n proc.on('error', err => {\n if (settled) return\n settled = true\n if (graceTimer) clearTimeout(graceTimer)\n clearTimeout(timeout)\n if (proc.pid !== undefined) {\n runningAgents.delete(proc.pid)\n }\n rl.close()\n rlErr.close()\n logStream.end()\n if (promptFile) cleanupPromptFile(promptFile)\n console.error(\n 'Agent process error:',\n formatErrorMessage(err)\n )\n resolve({\n exitCode:1,\n completedItems,\n timedOut,\n })\n })\n })\n}\n\nexport function dryRun (\n tickets:Array<Ticket>,\n specBody:string,\n testCmd:string\n):void {\n listTickets(tickets)\n\n console.log('\\nSimulated wave order:')\n for (const { wave, ready } of simulateWaves(tickets)) {\n console.log(\n ` Wave ${wave}: ` +\n ready.map(t => t.filename).join(', ')\n )\n }\n\n const stuck = detectDeadlocks(tickets)\n if (stuck.length > 0) {\n console.log(\n '\\nDeadlocked tickets: ' +\n stuck.map(t => t.filename).join(', ')\n )\n }\n\n const firstReady = findReadyTickets(tickets)\n if (firstReady.length > 0) {\n console.log(\n '\\nPrompt for first ready ticket ' +\n `(${firstReady[0].filename}):\\n`\n )\n console.log(\n renderPrompt(specBody, firstReady[0],\n { testCmd })\n )\n }\n}\n\nexport function dryRunIsolated (opts:{\n tickets:Array<Ticket>\n specBody:string\n repoName:string\n conflictStrategy:MergeConflictStrategy\n progressPath:string\n testCmd:string\n effort?:EffortLevel\n retries?:number\n retryDelay?:number\n concurrency?:number\n}):void {\n listTickets(opts.tickets)\n\n console.log('\\nSimulated wave order:')\n for (const { wave, ready } of simulateWaves(\n opts.tickets\n )) {\n console.log(\n ` Wave ${wave}: ` +\n ready.map(t => t.filename).join(', ')\n )\n for (const t of ready) {\n const num = String(t.num).padStart(2, '0')\n const branchName = buildBranchName(\n opts.repoName, t\n )\n const prefix = t.feature ?\n `${t.feature}.` : ''\n const worktreePath =\n `../${opts.repoName}.${prefix}${num}-${t.slug}`\n console.log(` worktree: ${worktreePath}`)\n console.log(` branch: ${branchName}`)\n }\n }\n\n const stuck = detectDeadlocks(opts.tickets)\n if (stuck.length > 0) {\n console.log(\n '\\nDeadlocked tickets: ' +\n stuck.map(t => t.filename).join(', ')\n )\n }\n\n const firstReady = findReadyTickets(opts.tickets)\n if (firstReady.length > 0) {\n console.log(\n '\\nPrompt for first ready ticket ' +\n `(${firstReady[0].filename}):\\n`\n )\n console.log(\n renderPrompt(\n opts.specBody, firstReady[0],\n { testCmd:opts.testCmd }\n )\n )\n }\n\n const strategyDesc =\n opts.conflictStrategy === 'respawn' ?\n 'respawn (re-run agent on conflict)' :\n 'stop (stop merging on conflict)'\n console.log(\n `\\nTest command: ${opts.testCmd}`\n )\n console.log(\n `Effort: ${opts.effort ?? '(provider default)'}`\n )\n console.log(\n `Retries: ${opts.retries ?? DEFAULT_RETRIES}`\n )\n console.log(\n 'Retry delay: ' +\n `${opts.retryDelay ?? 0}s`\n )\n console.log(\n 'Concurrency: ' +\n `${opts.concurrency ?? DEFAULT_CONCURRENCY}`\n )\n console.log(\n `\\nMerge strategy: ${strategyDesc}`\n )\n console.log(`Progress file: ${opts.progressPath}`)\n}\n\n// Runs the project's test command in a ticket's worktree.\n// Writes the output to a per-ticket log either way, and\n// returns true only when the suite is green.\nasync function runTestGate (opts:{\n testCmd:string\n ticket:Ticket\n worktreePath:string\n timeout:number\n logsDir:string\n attempt?:number\n log:(msg:string) => void\n registry?:Set<number>\n}):Promise<boolean> {\n const result = await runTestCmd({\n cmd:opts.testCmd,\n cwd:opts.worktreePath,\n timeout:opts.timeout,\n registry:opts.registry,\n })\n const testLogPath = attemptLogPath(\n opts.logsDir, opts.ticket, opts.attempt ?? 1,\n '.test.log'\n )\n writeFileSync(testLogPath, result.output)\n\n if (result.exitCode !== 0) {\n opts.log(\n ` ${opts.ticket.filename}: tests failed ` +\n `(exit ${result.exitCode}); ` +\n `see ${testLogPath}`\n )\n return false\n }\n\n opts.log(` ${opts.ticket.filename}: tests passed`)\n return true\n}\n\n// Re-runs the agent in a ticket's existing worktree\n// after a merge conflict, then retries the merge once.\n// Called at most once per ticket per wave.\nasync function respawnAndRetryMerge (opts:{\n repoRoot:string\n baseBranch:string\n branch:string\n ticket:Ticket\n worktreePath:string\n specBody:string\n agentCmd:string\n model:string|null\n timeout:number\n logsDir:string\n testCmd:string\n maxTurns?:number\n onLine?:(msg:string) => void\n}):Promise<boolean> {\n const log = (msg:string):void => {\n if (opts.onLine) {\n opts.onLine(msg)\n } else {\n console.log(msg)\n }\n }\n\n await updateWorktreeFromBase(\n opts.worktreePath, opts.baseBranch\n )\n\n const msg1 = ` ${opts.ticket.filename}: respawning agent ` +\n 'to resolve merge conflict'\n if (opts.onLine) {\n opts.onLine(msg1)\n } else {\n console.log(msg1)\n }\n\n const prompt = renderMergePrompt(\n opts.specBody, opts.ticket\n )\n const logPath = join(\n opts.logsDir,\n opts.ticket.filename.replace(/\\.md$/, '.respawn.log')\n )\n const label = opts.ticket.filename.replace(\n /\\.md$/, ''\n )\n const result = await spawnAgent({\n prompt,\n agentCmd:opts.agentCmd,\n model:opts.model,\n timeout:opts.timeout,\n logPath,\n cwd:opts.worktreePath,\n label,\n maxTurns:opts.maxTurns,\n onLine:opts.onLine,\n })\n\n if (result.exitCode !== 0) {\n const msg2 = ` ${opts.ticket.filename}: respawned agent ` +\n `exited ${result.exitCode}`\n if (opts.onLine) {\n opts.onLine(msg2)\n } else {\n console.log(msg2)\n }\n return false\n }\n\n const passed = await runTestGate({\n testCmd:opts.testCmd,\n ticket:opts.ticket,\n worktreePath:opts.worktreePath,\n timeout:opts.timeout,\n logsDir:opts.logsDir,\n log,\n registry:runningAgents,\n })\n if (!passed) {\n log(\n ` ${opts.ticket.filename}: tests failed ` +\n 'after conflict respawn; not merging'\n )\n return false\n }\n\n const mergeResult = await mergeBranch(\n opts.repoRoot, opts.branch\n )\n if (!mergeResult.success) {\n const msg3 = ` ${opts.ticket.filename}: merge still ` +\n 'conflicted after respawn'\n if (opts.onLine) {\n opts.onLine(msg3)\n } else {\n console.log(msg3)\n }\n if (mergeResult.stderr) {\n const stderrMsg =\n ` git: ${mergeResult.stderr.trim()}`\n if (opts.onLine) {\n opts.onLine(stderrMsg)\n } else {\n console.log(stderrMsg)\n }\n }\n }\n return mergeResult.success\n}\n\nexport const DEFAULT_RETRIES = 3\n\n// Seconds to wait before the first retry; each later retry\n// doubles the wait so a provider outage is waited out instead\n// of burning every attempt back to back.\nexport const DEFAULT_RETRY_DELAY = 30\n\n// Max agents running at the same time within a wave.\nexport const DEFAULT_CONCURRENCY = 5\n\n// Runs `fn` over `items`, at most `limit` at a time, and\n// resolves with the results in item order. Each call is\n// settled individually so one rejection does not stop\n// the others.\nexport async function runPool<T, R> (\n items:T[],\n limit:number,\n fn:(item:T) => Promise<R>,\n):Promise<PromiseSettledResult<R>[]> {\n const size = Math.max(1, Math.floor(limit))\n const results:PromiseSettledResult<R>[] = new Array(\n items.length\n )\n let next = 0\n async function worker ():Promise<void> {\n while (next < items.length) {\n const i = next++\n try {\n results[i] = {\n status:'fulfilled',\n value:await fn(items[i]),\n }\n } catch (reason) {\n results[i] = { status:'rejected', reason }\n }\n }\n }\n const workers = Array.from(\n { length:Math.min(size, items.length) },\n () => worker()\n )\n await Promise.all(workers)\n return results\n}\n\nexport function retryDelayFor (base:number, attempt:number):number {\n return base * 2 ** (attempt - 2)\n}\n\nfunction sleep (ms:number):Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms))\n}\n\n// Log file for one attempt: the first attempt keeps the\n// plain name so existing tooling still finds it, later\n// attempts get their own file instead of overwriting it.\nfunction attemptLogPath (\n logsDir:string,\n ticket:Ticket,\n attempt:number,\n ext:string\n):string {\n const stem = ticket.filename.replace(/\\.md$/, '')\n const suffix = attempt > 1 ? `.attempt${attempt}` : ''\n return join(logsDir, `${stem}${suffix}${ext}`)\n}\n\ntype TicketOutcome =\n | { kind:'worktree-error'; error:unknown }\n | {\n kind:'error'\n error:unknown\n worktreePath?:string\n branchName?:string\n }\n | {\n kind:'no-commits'\n worktreePath:string\n branchName:string\n }\n | {\n kind:'failed'\n reason:'exit'|'tests'\n branchName:string\n exitCode:number\n completedItems:string[]\n }\n | {\n kind:'ready'\n worktreePath:string\n branchName:string\n completedItems:string[]\n }\n\ntype TicketAttemptOpts = {\n ticket:Ticket\n repoRoot:string\n repoName:string\n baseBranch:string\n specBody:string\n specBodies?:Map<string, string>\n agentCmd:string\n model:string|null\n timeout:number\n logsDir:string\n testCmd:string\n maxTurns?:number\n effort?:EffortLevel\n d:Display\n}\n\n// One attempt at a ticket: a fresh worktree, one agent run,\n// and the checks that decide whether the branch can merge.\n// A failed attempt removes its worktree before returning.\nasync function runTicketAttempt (\n opts:TicketAttemptOpts&{ attempt:number }\n):Promise<TicketOutcome> {\n const { ticket, d } = opts\n\n let worktree:{ worktreePath:string; branchName:string }\n try {\n worktree = await createWorktree({\n repoRoot:opts.repoRoot,\n repoName:opts.repoName,\n baseBranch:opts.baseBranch,\n ticket,\n })\n } catch (error) {\n return { kind:'worktree-error', error }\n }\n\n d.setTicketStatus(\n ticket.num, 'in-progress', ticket.feature\n )\n const ticketSpec = lookupSpec(\n opts.specBodies, opts.specBody, ticket.feature\n )\n const agentResult = await spawnAgent({\n prompt:renderPrompt(\n ticketSpec, ticket,\n { testCmd:opts.testCmd }\n ),\n agentCmd:opts.agentCmd,\n model:opts.model,\n timeout:opts.timeout,\n logPath:attemptLogPath(\n opts.logsDir, ticket, opts.attempt, '.log'\n ),\n cwd:worktree.worktreePath,\n label:ticket.filename.replace(/\\.md$/, ''),\n maxTurns:opts.maxTurns,\n effort:opts.effort,\n onLine:(line) => d.log(line),\n })\n\n // A timeout kill is not the agent reporting failure.\n // Keep whatever it committed and let the test gate and\n // merge decide, instead of discarding the worktree.\n if (agentResult.timedOut) {\n d.log(\n ` ${ticket.filename}: timed out; ` +\n 'keeping the work it committed'\n )\n } else if (agentResult.exitCode !== 0) {\n d.log(\n ` ${ticket.filename}: ` +\n `agent exited ${agentResult.exitCode}`\n )\n await removeWorktreeQuietly(worktree.worktreePath, d)\n return {\n kind:'failed',\n reason:'exit',\n branchName:worktree.branchName,\n exitCode:agentResult.exitCode,\n completedItems:agentResult.completedItems,\n }\n }\n\n if (isDirty(worktree.worktreePath)) {\n const committed = await commitDirty(\n worktree.worktreePath,\n 'nightralph: auto-commit ' +\n `${ticket.filename} remaining changes`\n )\n if (committed) {\n d.log(\n ` ${ticket.filename}: ` +\n 'auto-committed remaining changes'\n )\n }\n }\n\n if (!hasNewCommits(\n opts.repoRoot, opts.baseBranch, worktree.branchName\n )) {\n await removeWorktreeQuietly(worktree.worktreePath, d)\n return {\n kind:'no-commits',\n worktreePath:worktree.worktreePath,\n branchName:worktree.branchName,\n }\n }\n\n const passed = await runTestGate({\n testCmd:opts.testCmd,\n ticket,\n worktreePath:worktree.worktreePath,\n timeout:opts.timeout,\n logsDir:opts.logsDir,\n attempt:opts.attempt,\n log:(msg) => d.log(msg),\n registry:runningAgents,\n })\n if (!passed) {\n await removeWorktreeQuietly(\n worktree.worktreePath, d\n )\n return {\n kind:'failed',\n reason:'tests',\n branchName:worktree.branchName,\n exitCode:1,\n completedItems:agentResult.completedItems,\n }\n }\n\n return {\n kind:'ready',\n worktreePath:worktree.worktreePath,\n branchName:worktree.branchName,\n completedItems:agentResult.completedItems,\n }\n}\n\n// Runs a ticket until an attempt is ready to merge or the\n// retry cap is hit. Each retry starts from a fresh worktree\n// and a higher effort level.\nasync function runTicketAttempts (\n opts:TicketAttemptOpts&{ retries:number; retryDelay:number }\n):Promise<TicketOutcome> {\n const { ticket, d } = opts\n const maxAttempts = opts.retries + 1\n const providerName = basename(opts.agentCmd)\n const isKnown = providerName in EFFORT_LADDERS\n let effort = opts.effort\n let outcome:TicketOutcome = {\n kind:'no-commits', worktreePath:'', branchName:'',\n }\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n if (attempt === 1) {\n d.log(` Starting ${ticket.filename}`)\n } else {\n if (isKnown) {\n effort = escalateEffort(\n providerName as ProviderName,\n effort\n )\n }\n const delay = retryDelayFor(opts.retryDelay, attempt)\n d.log(\n ` ${ticket.filename}: retrying ` +\n `(attempt ${attempt}/${maxAttempts}` +\n (isKnown && effort ?\n `, effort ${effort}` : '') +\n (delay > 0 ?\n `, waiting ${delay}s` : '') +\n ')'\n )\n if (delay > 0) await sleep(delay * 1000)\n }\n try {\n outcome = await runTicketAttempt({\n ...opts, attempt, effort,\n })\n } catch (error) {\n d.log(\n ` ${ticket.filename}: attempt ${attempt} ` +\n `threw: ${formatErrorMessage(error)}`\n )\n return { kind:'error', error }\n }\n if (outcome.kind === 'ready') {\n // The agent is no longer running, but the branch is\n // only merged once the whole wave has finished.\n d.setTicketStatus(\n ticket.num, 'awaiting-merge',\n ticket.feature,\n )\n return outcome\n }\n if (outcome.kind === 'worktree-error') return outcome\n }\n return outcome\n}\n\n// Wraps writeProgress + commitProgress so callers do not each\n// need to guard against a commit failure (e.g. a git lock held\n// by a concurrent process) crashing the run.\nasync function saveProgress (\n repoRoot:string,\n progressPath:string,\n progress:ProgressData,\n message:string,\n d:Display\n):Promise<void> {\n writeProgress(progressPath, progress)\n try {\n await commitProgress(repoRoot, progressPath, message)\n } catch (err) {\n d.log(\n ' Failed to commit progress: ' +\n formatErrorMessage(err)\n )\n }\n}\n\nexport const HUMAN_STATUS = 'ready-for-human'\n\nfunction indentFilenames (tickets:ReadonlyArray<Ticket>):string {\n return tickets.map(t => ` ${t.filename}`).join('\\n')\n}\n\n/**\n * The text logged when a run ends. The first line is the\n * count summary. When tickets marked ready-for-human are\n * still open, further lines name them and say that an\n * agent cannot finish them, so a run that exits with open\n * tickets never looks like it silently gave up.\n */\nexport function renderFinishSummary (\n tickets:ReadonlyArray<Ticket>,\n totalCompleted:number,\n failedKeys:ReadonlySet<string>,\n):string {\n const remaining = tickets.filter(\n t => t.status === 'ready-for-agent'\n )\n const human = tickets.filter(t => t.status === HUMAN_STATUS)\n const humanNums = new Set(human.map(t => t.num))\n const blockedByHuman = remaining.filter(t =>\n !failedKeys.has(ticketKey(t.feature, t.num)) &&\n t.blockers.some(b => humanNums.has(b))\n )\n\n const counts = `Finished: ${totalCompleted} completed` +\n (remaining.length > 0 ?\n `, ${remaining.length} remaining` :\n '') +\n (failedKeys.size > 0 ?\n `, ${failedKeys.size} failed` :\n '') +\n (human.length > 0 ?\n `, ${human.length} need a human` :\n '')\n\n const lines:string[] = [counts]\n\n const features = new Set(\n tickets.map(t => t.feature).filter(Boolean)\n )\n if (features.size > 1) {\n lines.push('')\n for (const feat of [...features].sort()) {\n const ft = tickets.filter(\n t => t.feature === feat\n )\n const done = ft.filter(\n t => t.status === 'done'\n ).length\n const failed = ft.filter(\n t => failedKeys.has(\n ticketKey(t.feature, t.num)\n )\n ).length\n const rem = ft.filter(\n t => t.status === 'ready-for-agent'\n ).length\n let detail = ` ${feat}: ${done} completed`\n if (rem > 0) detail += `, ${rem} remaining`\n if (failed > 0) detail += `, ${failed} failed`\n lines.push(detail)\n }\n }\n\n if (human.length === 0) return lines.join('\\n')\n\n const noun = human.length === 1 ?\n 'ticket is' :\n 'tickets are'\n lines.push(\n '',\n (remaining.length === 0 && failedKeys.size === 0 ?\n `All remaining ${noun} marked ${HUMAN_STATUS}. ` :\n `${human.length} ${noun} marked ${HUMAN_STATUS}. `) +\n 'nightralph only runs ready-for-agent tickets, ' +\n 'so an agent cannot finish these:',\n indentFilenames(human),\n )\n if (blockedByHuman.length > 0) {\n const n = blockedByHuman.length\n lines.push(\n `${n} ready-for-agent ticket${n === 1 ? ' is' : 's are'} ` +\n 'blocked until they are done:',\n indentFilenames(blockedByHuman),\n )\n }\n lines.push(\n 'Do that work by hand, then set each ticket\\'s ' +\n '**Status:** to done' +\n (blockedByHuman.length > 0 ?\n ' and run nightralph again.' :\n '.')\n )\n return lines.join('\\n')\n}\n\nfunction sessionTickets (\n tickets:ReadonlyArray<Ticket>,\n):Array<Ticket> {\n return [...tickets]\n .filter(t => t.status === 'ready-for-agent')\n .sort((a, b) => (\n a.feature.localeCompare(b.feature) || a.num - b.num\n ))\n}\n\nfunction toRef (t:Ticket):TicketRef {\n return { num:t.num, filename:t.filename, feature:t.feature }\n}\n\nfunction reportBlocked (\n d:Display,\n tickets:ReadonlyArray<Ticket>,\n failedKeys:ReadonlySet<string>,\n):void {\n const byKey = new Map(\n tickets.map(t => [ticketKey(t.feature, t.num), t])\n )\n for (const [key, dead] of findBlockedTickets(\n tickets, failedKeys\n )) {\n const ticket = byKey.get(key)\n if (!ticket) continue\n const labels = dead\n .map(k => byKey.get(k))\n .filter((t):t is Ticket => t !== undefined)\n .map(t => ticketLabel(toRef(t)))\n d.setBlocked(ticket.num, ticket.feature, labels)\n }\n}\n\nfunction runProgress (tickets:ReadonlyArray<Ticket>):RunProgress {\n return {\n completed:tickets.filter(t => t.status === 'done').length,\n total:tickets.length,\n }\n}\n\nexport async function runWaves (\n tickets:Ticket[],\n specBody:string,\n agentCmd:string,\n model:string|null,\n timeout:number,\n logsDir:string,\n testCmd:string,\n display?:Display,\n maxTurns?:number,\n effort?:EffortLevel,\n retries?:number,\n retryDelay?:number,\n concurrency?:number,\n):Promise<{ allDone:boolean }> {\n mkdirSync(logsDir, { recursive:true })\n\n const d = display ?? createDisplay()\n const maxAttempts = (retries ?? DEFAULT_RETRIES) + 1\n const delayBase = retryDelay ?? 0\n const poolSize = concurrency ?? DEFAULT_CONCURRENCY\n const providerName = basename(agentCmd)\n const isKnown = providerName in EFFORT_LADDERS\n let totalWaves = 0\n for (const _ of simulateWaves(tickets)) totalWaves++\n\n let totalCompleted = 0\n let waveNum = 0\n const failedKeys = new Set<string>()\n const session = sessionTickets(tickets)\n\n while (true) {\n if (waveNum > 0) reportBlocked(d, tickets, failedKeys)\n\n const ready = findReadyTickets(tickets).filter(\n t => !failedKeys.has(\n ticketKey(t.feature, t.num)\n )\n )\n if (ready.length === 0) break\n\n waveNum++\n if (waveNum === 1) {\n d.startRun(session.map(toRef))\n reportBlocked(d, tickets, failedKeys)\n }\n d.startWave(\n waveNum,\n totalWaves,\n ready.map(t => ({\n num:t.num,\n filename:t.filename,\n feature:t.feature,\n })),\n runProgress(session),\n )\n\n const results = await runPool(\n ready, poolSize, async t => {\n const prompt = renderPrompt(specBody, t,\n { testCmd })\n const label = t.filename.replace(\n /\\.md$/, ''\n )\n d.setTicketStatus(\n t.num, 'in-progress', t.feature\n )\n d.log(` Starting ${t.filename}`)\n let level = effort\n let result = await spawnAgent({\n prompt,\n agentCmd,\n model,\n timeout,\n logPath:attemptLogPath(logsDir, t, 1, '.log'),\n label,\n maxTurns,\n effort:level,\n onLine:(line) => d.log(line),\n })\n // In-place runs have no worktree or test\n // gate, so a non-zero exit is the only\n // failure that can be retried here.\n for (\n let attempt = 2;\n result.exitCode !== 0 &&\n !result.timedOut &&\n attempt <= maxAttempts;\n attempt++\n ) {\n if (isKnown) {\n level = escalateEffort(\n providerName as ProviderName,\n level\n )\n }\n const delay = retryDelayFor(delayBase, attempt)\n d.log(\n ` ${t.filename}: agent exited ` +\n `${result.exitCode}; retrying ` +\n `(attempt ${attempt}/${maxAttempts}` +\n (isKnown && level ?\n `, effort ${level}` : '') +\n (delay > 0 ?\n `, waiting ${delay}s` : '') +\n ')'\n )\n if (delay > 0) await sleep(delay * 1000)\n result = await spawnAgent({\n prompt,\n agentCmd,\n model,\n timeout,\n logPath:attemptLogPath(\n logsDir, t, attempt, '.log'\n ),\n label,\n maxTurns,\n effort:level,\n onLine:(line) => d.log(line),\n })\n }\n return { ticket:t, result }\n }\n )\n\n let waveCompleted = 0\n for (const r of results) {\n if (r.status === 'rejected') continue\n const { ticket, result } = r.value\n if (result.exitCode !== 0) {\n failedKeys.add(\n ticketKey(ticket.feature, ticket.num)\n )\n d.setTicketStatus(\n ticket.num, 'failed', ticket.feature\n )\n d.log(\n ` ${ticket.filename}: ` +\n `agent exited ${result.exitCode}`\n )\n continue\n }\n\n checkItems(ticket, result.completedItems)\n markDone(ticket)\n waveCompleted++\n totalCompleted++\n d.setTicketStatus(\n ticket.num, 'done', ticket.feature\n )\n d.log(\n ` ${ticket.filename}: done`\n )\n }\n\n if (waveCompleted === 0) {\n const remaining = findReadyTickets(tickets)\n .filter(t => !failedKeys.has(\n ticketKey(t.feature, t.num)\n ))\n if (remaining.length === 0) {\n d.log(\n '\\nNo tickets completed this wave ' +\n 'and no ready tickets remain. ' +\n 'Stopping.'\n )\n break\n }\n d.log(\n '\\nNo tickets completed this wave. ' +\n `${remaining.length} ready ticket` +\n `${remaining.length === 1 ? '' : 's'} ` +\n 'remain; continuing.'\n )\n }\n }\n\n if (waveNum > 0) reportBlocked(d, tickets, failedKeys)\n\n const remaining = tickets.filter(\n t => t.status === 'ready-for-agent'\n )\n d.log('\\n' + renderFinishSummary(\n tickets, totalCompleted, failedKeys\n ))\n d.cleanup()\n\n return { allDone:remaining.length === 0 }\n}\n\nexport async function runWavesIsolated (opts:{\n tickets:Array<Ticket>\n specBody:string\n specBodies?:Map<string, string>\n agentCmd:string\n model:string|null\n timeout:number\n logsDir:string\n featureName:string\n conflictStrategy:MergeConflictStrategy\n display?:Display\n testCmd:string\n maxTurns?:number\n // starting effort level; unset = provider's default\n effort?:EffortLevel\n // extra attempts per ticket after a failure; default 3\n retries?:number\n // seconds to wait before the first retry; default 30\n retryDelay?:number\n // max agents running at once within a wave; default 5\n concurrency?:number\n // per-feature progress paths for multi-feature runs\n progressPaths?:Map<string, string>\n}):Promise<{ allDone:boolean }> {\n mkdirSync(opts.logsDir, { recursive:true })\n\n const d = opts.display ?? createDisplay()\n const retries = opts.retries ?? DEFAULT_RETRIES\n const retryDelay = opts.retryDelay ?? 0\n const poolSize = opts.concurrency ?? DEFAULT_CONCURRENCY\n let totalWaves = 0\n for (const _ of simulateWaves(opts.tickets)) totalWaves++\n\n const repoRoot = getRepoRoot()\n const repoName = getRepoName()\n const baseBranch = getCurrentBranch()\n\n if (isDirty(repoRoot)) {\n throw new Error(\n 'Working tree is dirty; commit or stash ' +\n 'changes before running'\n )\n }\n\n const features = new Set(\n opts.tickets.map(t => t.feature).filter(Boolean)\n )\n const multiFeature = features.size > 1 &&\n opts.progressPaths !== undefined\n\n const fallbackProgressPath = join(\n dirname(opts.logsDir), 'progress.md'\n )\n\n let tracker:ProgressTracker\n if (multiFeature) {\n const multiData = generateMultiFeatureProgress(\n opts.tickets\n )\n const dataMap = new Map<string, ProgressData>()\n for (const [feat, fresh] of multiData) {\n const path = opts.progressPaths!.get(feat) ??\n fallbackProgressPath\n const merged = mergeProgress(\n fresh, readProgress(path)\n )\n dataMap.set(feat, merged)\n await saveProgress(\n repoRoot, path, merged,\n `nightralph: start ${feat}`, d,\n )\n }\n tracker = createProgressTracker({\n progressPaths:opts.progressPaths!,\n dataMap,\n fallbackPath:fallbackProgressPath,\n fallbackData:generateProgress(\n opts.featureName, []\n ),\n })\n } else {\n const progressPath = fallbackProgressPath\n const progress:ProgressData = mergeProgress(\n generateProgress(\n opts.featureName, opts.tickets\n ),\n readProgress(progressPath)\n )\n await saveProgress(\n repoRoot, progressPath, progress,\n `nightralph: start ${opts.featureName}`, d,\n )\n tracker = createProgressTracker({\n progressPaths:new Map(),\n dataMap:new Map(),\n fallbackPath:progressPath,\n fallbackData:progress,\n })\n }\n\n let totalCompleted = 0\n let waveNum = 0\n const failedKeys = new Set<string>()\n const session = sessionTickets(opts.tickets)\n\n while (true) {\n if (waveNum > 0) reportBlocked(d, opts.tickets, failedKeys)\n\n const ready = findReadyTickets(opts.tickets).filter(\n t => !failedKeys.has(\n ticketKey(t.feature, t.num)\n )\n )\n if (ready.length === 0) break\n\n waveNum++\n if (waveNum === 1) {\n d.startRun(session.map(toRef))\n reportBlocked(d, opts.tickets, failedKeys)\n }\n d.startWave(\n waveNum,\n totalWaves,\n ready.map(t => ({\n num:t.num,\n filename:t.filename,\n feature:t.feature,\n })),\n runProgress(session),\n )\n\n // Each ticket runs its own attempt loop, at most\n // `poolSize` at a time. Progress is recorded\n // afterwards, sequentially, so commits on the base\n // branch never race each other.\n const settled = await runPool(\n ready, poolSize, t => runTicketAttempts({\n ticket:t,\n repoRoot,\n repoName,\n baseBranch,\n specBody:opts.specBody,\n specBodies:opts.specBodies,\n agentCmd:opts.agentCmd,\n model:opts.model,\n timeout:opts.timeout,\n logsDir:opts.logsDir,\n testCmd:opts.testCmd,\n maxTurns:opts.maxTurns,\n effort:opts.effort,\n retries,\n retryDelay,\n d,\n })\n )\n // runTicketAttempts never rejects (a throw inside an\n // attempt becomes an 'error' outcome), so every\n // result here is fulfilled.\n const outcomes:TicketOutcome[] = settled.map(r =>\n r.status === 'fulfilled' ?\n r.value :\n { kind:'error', error:r.reason }\n )\n\n let waveCompleted = 0\n const successfulBranches:Array<{\n branch:string\n ticketNum:number\n worktreePath:string\n }> = []\n const ticketsByKey = new Map<string, Ticket>()\n const worktreePathsByKey = new Map<string, string>()\n const branchToKey = new Map<string, string>()\n\n for (let i = 0; i < outcomes.length; i++) {\n const outcome = outcomes[i]\n const ticket = ready[i]\n const key = ticketKey(ticket.feature, ticket.num)\n\n if (outcome.kind === 'worktree-error') {\n failedKeys.add(key)\n d.setTicketStatus(\n ticket.num, 'failed', ticket.feature\n )\n d.log(\n ` ${ticket.filename}: failed to create ` +\n `worktree: ${formatErrorMessage(outcome.error)}`\n )\n checkTicket(tracker.dataFor(ticket.feature), ticket.num, {\n branch:'',\n exitCode:-1,\n done:false,\n })\n await saveProgress(\n repoRoot,\n tracker.pathFor(ticket.feature),\n tracker.dataFor(ticket.feature),\n `nightralph: ${ticket.filename} ` +\n 'worktree error',\n d,\n )\n continue\n }\n\n if (outcome.kind === 'error') {\n failedKeys.add(key)\n d.setTicketStatus(\n ticket.num, 'failed', ticket.feature\n )\n d.log(\n ` ${ticket.filename}: attempt error: ` +\n formatErrorMessage(outcome.error)\n )\n checkTicket(tracker.dataFor(ticket.feature), ticket.num, {\n branch:outcome.branchName ?? '',\n exitCode:-1,\n done:false,\n })\n await saveProgress(\n repoRoot,\n tracker.pathFor(ticket.feature),\n tracker.dataFor(ticket.feature),\n `nightralph: ${ticket.filename} error`,\n d,\n )\n continue\n }\n\n if (outcome.kind === 'no-commits') {\n failedKeys.add(key)\n d.setTicketStatus(\n ticket.num, 'failed', ticket.feature\n )\n d.log(\n ` ${ticket.filename}: agent exited 0 ` +\n 'but made no changes; leaving ticket ' +\n 'ready-for-agent'\n )\n checkTicket(tracker.dataFor(ticket.feature), ticket.num, {\n branch:outcome.branchName,\n exitCode:0,\n done:false,\n })\n await saveProgress(\n repoRoot,\n tracker.pathFor(ticket.feature),\n tracker.dataFor(ticket.feature),\n `nightralph: ${ticket.filename} ` +\n 'no commits',\n d,\n )\n continue\n }\n\n if (outcome.kind === 'failed') {\n failedKeys.add(key)\n d.setTicketStatus(\n ticket.num, 'failed', ticket.feature\n )\n if (outcome.reason === 'exit') {\n checkItems(ticket, outcome.completedItems)\n }\n checkTicket(tracker.dataFor(ticket.feature), ticket.num, {\n branch:outcome.branchName,\n exitCode:outcome.exitCode,\n done:false,\n })\n await saveProgress(\n repoRoot,\n tracker.pathFor(ticket.feature),\n tracker.dataFor(ticket.feature),\n `nightralph: ${ticket.filename} ` +\n (outcome.reason === 'tests' ?\n 'tests failed' :\n 'failed'),\n d,\n )\n continue\n }\n\n checkItems(ticket, outcome.completedItems)\n d.log(\n ` ${ticket.filename}: agent finished, ` +\n 'awaiting merge'\n )\n ticketsByKey.set(key, ticket)\n worktreePathsByKey.set(\n key, outcome.worktreePath\n )\n branchToKey.set(outcome.branchName, key)\n successfulBranches.push({\n branch:outcome.branchName,\n ticketNum:ticket.num,\n worktreePath:outcome.worktreePath,\n })\n }\n\n if (successfulBranches.length > 0) {\n await commitTicketFiles(\n repoRoot,\n successfulBranches\n .map(sb => {\n const k = branchToKey.get(sb.branch)!\n return ticketsByKey.get(k)!\n }),\n d,\n )\n\n const mergeResult = await mergeWave({\n repoRoot,\n baseBranch,\n branches:successfulBranches,\n strategy:opts.conflictStrategy,\n })\n\n for (const branchResult of mergeResult.merged) {\n const bk = branchToKey.get(\n branchResult.branch\n )\n const ticket = bk ?\n ticketsByKey.get(bk) :\n undefined\n if (!ticket) continue\n\n if (branchResult.merged) {\n markDone(ticket)\n waveCompleted++\n totalCompleted++\n d.setTicketStatus(\n ticket.num, 'done', ticket.feature\n )\n d.log(\n ` ${ticket.filename}: done`\n )\n checkTicket(tracker.dataFor(ticket.feature), ticket.num, {\n branch:branchResult.branch,\n exitCode:0,\n })\n await saveProgress(\n repoRoot,\n tracker.pathFor(ticket.feature),\n tracker.dataFor(ticket.feature),\n `nightralph: ${ticket.filename} done`,\n d,\n )\n\n const worktreePath = bk ?\n worktreePathsByKey.get(bk) :\n undefined\n if (worktreePath) {\n await removeWorktreeQuietly(\n worktreePath, d\n )\n }\n } else {\n const wtKey = branchToKey.get(\n branchResult.branch\n )\n const worktreePath = wtKey ?\n worktreePathsByKey.get(wtKey) :\n undefined\n const recovered =\n opts.conflictStrategy === 'respawn' &&\n worktreePath ?\n await respawnAndRetryMerge({\n repoRoot,\n baseBranch,\n branch:branchResult.branch,\n ticket,\n worktreePath,\n specBody:lookupSpec(\n opts.specBodies,\n opts.specBody,\n ticket.feature,\n ),\n agentCmd:opts.agentCmd,\n model:opts.model,\n timeout:opts.timeout,\n logsDir:opts.logsDir,\n testCmd:opts.testCmd,\n maxTurns:opts.maxTurns,\n onLine:(msg) => d.log(msg),\n }) :\n false\n\n if (recovered) {\n markDone(ticket)\n waveCompleted++\n totalCompleted++\n d.setTicketStatus(\n ticket.num, 'done',\n ticket.feature,\n )\n d.log(\n ` ${ticket.filename}: done ` +\n '(resolved via respawn)'\n )\n checkTicket(tracker.dataFor(ticket.feature), ticket.num, {\n branch:branchResult.branch,\n exitCode:0,\n })\n await saveProgress(\n repoRoot,\n tracker.pathFor(ticket.feature),\n tracker.dataFor(ticket.feature),\n `nightralph: ${ticket.filename} ` +\n 'done (respawn)',\n d,\n )\n\n if (worktreePath) {\n try {\n await removeWorktree(\n worktreePath,\n { force:true }\n )\n } catch (err) {\n d.log(\n ' Failed to remove worktree ' +\n `${worktreePath}: ` +\n formatErrorMessage(err)\n )\n }\n }\n } else {\n failedKeys.add(\n ticketKey(ticket.feature, ticket.num)\n )\n d.setTicketStatus(\n ticket.num, 'failed', ticket.feature\n )\n d.log(\n ` ${ticket.filename}: merge failed, ` +\n 'staying ready-for-agent'\n )\n if (branchResult.stderr) {\n d.log(\n ' git: ' +\n branchResult.stderr.trim()\n )\n }\n checkTicket(tracker.dataFor(ticket.feature), ticket.num, {\n branch:branchResult.branch,\n exitCode:0,\n done:false,\n })\n await saveProgress(\n repoRoot,\n tracker.pathFor(ticket.feature),\n tracker.dataFor(ticket.feature),\n `nightralph: ${ticket.filename} ` +\n 'merge failed',\n d,\n )\n }\n }\n }\n\n if (mergeResult.stoppedAt) {\n d.log(\n '\\nMerge stopped at ' +\n `${mergeResult.stoppedAt.branch}`\n )\n\n for (const sb of successfulBranches) {\n const sbk = branchToKey.get(sb.branch)\n const ticket = sbk ?\n ticketsByKey.get(sbk) :\n undefined\n if (ticket && ticket.status === 'done') continue\n try {\n await removeWorktree(\n sb.worktreePath,\n { force:true }\n )\n } catch (err) {\n d.log(\n ' Failed to remove worktree ' +\n `${sb.worktreePath}: ` +\n formatErrorMessage(err)\n )\n }\n }\n\n break\n }\n }\n\n if (waveCompleted === 0) {\n const remaining = findReadyTickets(\n opts.tickets\n ).filter(t => !failedKeys.has(\n ticketKey(t.feature, t.num)\n ))\n if (remaining.length === 0) {\n d.log(\n '\\nNo tickets completed this wave ' +\n 'and no ready tickets remain. ' +\n 'Stopping.'\n )\n break\n }\n d.log(\n '\\nNo tickets completed this wave. ' +\n `${remaining.length} ready ticket` +\n `${remaining.length === 1 ? '' : 's'} ` +\n 'remain; continuing.'\n )\n }\n }\n\n if (waveNum > 0) reportBlocked(d, opts.tickets, failedKeys)\n\n const remaining = opts.tickets.filter(\n t => t.status === 'ready-for-agent'\n )\n d.log('\\n' + renderFinishSummary(\n opts.tickets, totalCompleted, failedKeys\n ))\n d.cleanup()\n\n return { allDone:remaining.length === 0 }\n}\n", "import { execFile, execFileSync } from 'node:child_process'\nimport { promisify } from 'node:util'\nimport { basename, dirname, join, resolve } from 'node:path'\nimport { existsSync } from 'node:fs'\nimport type { Ticket } from './orchestrator.js'\n\nconst execFileAsync = promisify(execFile)\n\nexport function getRepoRoot ():string {\n const stdout = execFileSync(\n 'git',\n ['rev-parse', '--show-toplevel'],\n { encoding:'utf8' }\n )\n return stdout.trim()\n}\n\nexport function getRepoName ():string {\n const commonDir = execFileSync(\n 'git',\n ['rev-parse', '--git-common-dir'],\n { encoding:'utf8' }\n ).trim()\n return basename(dirname(resolve(commonDir)))\n}\n\nexport function getCurrentBranch ():string {\n const stdout = execFileSync(\n 'git',\n ['rev-parse', '--abbrev-ref', 'HEAD'],\n { encoding:'utf8' }\n )\n return stdout.trim()\n}\n\nasync function branchExists (\n repoRoot:string,\n branchName:string\n):Promise<boolean> {\n try {\n await execFileAsync(\n 'git',\n ['show-ref', '--verify', '--quiet', `refs/heads/${branchName}`],\n { cwd:repoRoot }\n )\n return true\n } catch {\n return false\n }\n}\n\nexport function buildBranchName (\n repoName:string,\n ticket:Ticket\n):string {\n const num = String(ticket.num).padStart(2, '0')\n const prefix = ticket.feature ?\n `${ticket.feature}-` :\n ''\n return `${repoName}--${prefix}${num}-${ticket.slug}`\n}\n\nasync function createWorktreeNow (\n opts:{\n repoRoot:string\n repoName:string\n baseBranch:string\n ticket:Ticket\n }\n):Promise<{ worktreePath:string; branchName:string }> {\n const { repoRoot, repoName, baseBranch, ticket } = opts\n const branchName = buildBranchName(repoName, ticket)\n const num = String(ticket.num).padStart(2, '0')\n const prefix = ticket.feature ?\n `${ticket.feature}-` :\n ''\n const worktreePath = join(\n repoRoot,\n '..',\n `${repoName}.${prefix}${num}-${ticket.slug}`\n )\n\n if (existsSync(worktreePath)) {\n try {\n await execFileAsync(\n 'git',\n ['worktree', 'remove', '--force', worktreePath],\n { cwd:repoRoot }\n )\n } catch {\n // directory may not be a registered worktree anymore;\n // prune stale entries below and let worktree add fail\n // loudly if the path is still unusable\n }\n }\n\n try {\n await execFileAsync(\n 'git',\n ['worktree', 'prune'],\n { cwd:repoRoot }\n )\n } catch {\n // best-effort cleanup of stale worktree metadata\n }\n\n if (await branchExists(repoRoot, branchName)) {\n await execFileAsync(\n 'git',\n ['branch', '-D', branchName],\n { cwd:repoRoot }\n )\n }\n\n await execFileAsync(\n 'git',\n [\n 'worktree',\n 'add',\n '-b',\n branchName,\n worktreePath,\n baseBranch,\n ],\n { cwd:repoRoot }\n )\n\n return { worktreePath, branchName }\n}\n\nlet worktreeQueue:Promise<unknown> = Promise.resolve()\n\nexport function createWorktree (\n opts:{\n repoRoot:string\n repoName:string\n baseBranch:string\n ticket:Ticket\n }\n):Promise<{ worktreePath:string; branchName:string }> {\n const result = worktreeQueue.then(() => createWorktreeNow(opts))\n worktreeQueue = result.catch(() => {})\n return result\n}\n\nasync function removeWorktreeNow (\n worktreePath:string,\n opts?:{ force?:boolean }\n):Promise<void> {\n const args = [\n '-C', worktreePath,\n 'worktree', 'remove',\n ]\n if (opts?.force) args.push('--force')\n args.push(worktreePath)\n await execFileAsync('git', args)\n}\n\nexport function removeWorktree (\n worktreePath:string,\n opts?:{ force?:boolean }\n):Promise<void> {\n const result = worktreeQueue.then(\n () => removeWorktreeNow(worktreePath, opts)\n )\n worktreeQueue = result.catch(() => {})\n return result\n}\n\nexport function hasNewCommits (\n repoRoot:string,\n base:string,\n branch:string\n):boolean {\n const stdout = execFileSync(\n 'git',\n ['rev-list', '--count', `${base}..${branch}`],\n { cwd:repoRoot, encoding:'utf8' }\n )\n return Number(stdout.trim()) > 0\n}\n\nexport function isDirty (cwd:string):boolean {\n const stdout = execFileSync(\n 'git',\n ['status', '--porcelain'],\n { cwd, encoding:'utf8' }\n )\n return stdout.trim().length > 0\n}\n\nexport async function commitDirty (\n cwd:string,\n message?:string\n):Promise<boolean> {\n if (!isDirty(cwd)) return false\n await execFileAsync(\n 'git',\n ['add', '-A'],\n { cwd }\n )\n try {\n await execFileAsync(\n 'git',\n [\n 'commit', '-m',\n message ??\n 'nightralph: auto-commit ' +\n 'remaining changes',\n ],\n { cwd }\n )\n return true\n } catch {\n return false\n }\n}\n\nexport async function listWorktrees (\n repoRoot:string\n):Promise<Array<string>> {\n const { stdout } = await execFileAsync(\n 'git',\n ['worktree', 'list', '--porcelain'],\n { cwd:repoRoot }\n )\n return stdout\n .trim()\n .split('\\n')\n .filter(line => line.startsWith('worktree '))\n .map(line => line.substring('worktree '.length))\n}\n", "import { execFile } from 'node:child_process'\nimport { readFileSync, writeFileSync } from 'node:fs'\nimport { promisify } from 'node:util'\nimport type { Ticket } from './orchestrator.js'\n\nconst TICKET_FILENAME_RE = /^(\\d+)-(.+)\\.md$/\n\nconst execFileAsync = promisify(execFile)\n\nexport type TicketProgress = {\n num:number\n slug:string\n filename:string\n done:boolean\n branch:string|null\n exitCode:number|null\n completedAt:string|null\n}\n\nexport type ProgressData = {\n feature:string\n startedAt:string\n tickets:Array<TicketProgress>\n}\n\nexport function generateProgress (\n feature:string,\n tickets:ReadonlyArray<Ticket>\n):ProgressData {\n return {\n feature,\n startedAt:new Date().toISOString(),\n tickets:tickets.map((ticket) => ({\n num:ticket.num,\n slug:ticket.slug,\n filename:ticket.filename,\n done:false,\n branch:null,\n exitCode:null,\n completedAt:null,\n })),\n }\n}\n\nexport function generateMultiFeatureProgress (\n tickets:ReadonlyArray<Ticket>\n):Map<string, ProgressData> {\n const byFeature = new Map<string, Ticket[]>()\n for (const t of tickets) {\n const key = t.feature || ''\n const arr = byFeature.get(key) ?? []\n arr.push(t)\n byFeature.set(key, arr)\n }\n const result = new Map<string, ProgressData>()\n for (const [feat, ft] of byFeature) {\n result.set(feat, generateProgress(feat, ft))\n }\n return result\n}\n\nexport type ProgressTracker = {\n dataFor:(feature:string) => ProgressData\n pathFor:(feature:string) => string\n}\n\nexport function createProgressTracker (opts:{\n progressPaths:Map<string, string>\n dataMap:Map<string, ProgressData>\n fallbackPath:string\n fallbackData:ProgressData\n}):ProgressTracker {\n return {\n dataFor (feature:string):ProgressData {\n return opts.dataMap.get(feature) ??\n opts.fallbackData\n },\n pathFor (feature:string):string {\n return opts.progressPaths.get(feature) ??\n opts.fallbackPath\n },\n }\n}\n\nexport function isSpecComplete (\n progressPath:string\n):boolean {\n const data = readProgress(progressPath)\n if (!data) return false\n if (data.tickets.length === 0) return false\n return data.tickets.every(t => t.done)\n}\n\nexport function readProgress (\n progressPath:string\n):ProgressData|null {\n let content:string\n try {\n content = readFileSync(progressPath, 'utf8')\n } catch {\n return null\n }\n\n const featureMatch = content.match(/^# Progress: (.*)$/m)\n const startedMatch = content.match(/^Started: (.*)$/m)\n\n const tickets:Array<TicketProgress> = []\n let current:TicketProgress|null = null\n\n for (const line of content.split('\\n')) {\n const ticketMatch = line.match(/^- \\[( |x)\\] (.+)$/)\n if (ticketMatch) {\n if (current) tickets.push(current)\n const filename = ticketMatch[2]\n const parsed = filename.match(TICKET_FILENAME_RE)\n current = {\n num:parsed ? Number(parsed[1]) : NaN,\n slug:parsed ? parsed[2] : '',\n filename,\n done:ticketMatch[1] === 'x',\n branch:null,\n exitCode:null,\n completedAt:null,\n }\n continue\n }\n if (!current) continue\n\n const branchMatch = line.match(/^ {2}branch: (.*)$/)\n if (branchMatch) {\n current.branch = branchMatch[1]\n continue\n }\n const exitMatch = line.match(/^ {2}exit: (-?\\d+)$/)\n if (exitMatch) {\n current.exitCode = Number(exitMatch[1])\n continue\n }\n const completedMatch = line.match(/^ {2}completed: (.*)$/)\n if (completedMatch) {\n current.completedAt = completedMatch[1]\n continue\n }\n }\n if (current) tickets.push(current)\n\n return {\n feature:featureMatch ? featureMatch[1] : '',\n startedAt:startedMatch ? startedMatch[1] : '',\n tickets,\n }\n}\n\nexport function mergeProgress (\n fresh:ProgressData,\n existing:ProgressData|null\n):ProgressData {\n if (!existing) return fresh\n\n const existingByFilename = new Map(\n existing.tickets.map((t) => [t.filename, t])\n )\n\n return {\n ...fresh,\n tickets:fresh.tickets.map((ticket) => {\n const prior = existingByFilename.get(ticket.filename)\n return (prior && prior.done) ? { ...prior } : ticket\n }),\n }\n}\n\nexport function renderProgress (data:ProgressData):string {\n const lines:Array<string> = [\n `# Progress: ${data.feature}`,\n '',\n `Started: ${data.startedAt}`,\n '',\n ]\n\n for (const ticket of data.tickets) {\n const checkbox = ticket.done ? '[x]' : '[ ]'\n lines.push(`- ${checkbox} ${ticket.filename}`)\n\n if (ticket.done || ticket.exitCode !== null) {\n if (ticket.branch) {\n lines.push(\n ` branch: ${ticket.branch}`\n )\n }\n if (ticket.exitCode !== null) {\n lines.push(\n ` exit: ${ticket.exitCode}`\n )\n }\n if (ticket.completedAt) {\n lines.push(\n ` completed: ${ticket.completedAt}`\n )\n }\n }\n }\n\n return lines.join('\\n') + '\\n'\n}\n\nexport function checkTicket (\n data:ProgressData,\n ticketNum:number,\n result:{ branch:string; exitCode:number; done?:boolean }\n):void {\n const ticket = data.tickets.find(\n (t) => t.num === ticketNum\n )\n if (!ticket) return\n\n ticket.done = result.done ?? true\n ticket.branch = result.branch\n ticket.exitCode = result.exitCode\n if (ticket.done) {\n ticket.completedAt = new Date().toISOString()\n }\n}\n\nexport function writeProgress (\n progressPath:string,\n data:ProgressData\n):void {\n writeFileSync(\n progressPath,\n renderProgress(data)\n )\n}\n\nexport async function commitProgress (\n repoRoot:string,\n progressPath:string,\n message:string\n):Promise<boolean> {\n await execFileAsync(\n 'git',\n ['add', '--force', progressPath],\n { cwd:repoRoot }\n )\n\n try {\n await execFileAsync(\n 'git',\n ['diff', '--cached', '--quiet', '--', progressPath],\n { cwd:repoRoot }\n )\n return false\n } catch {\n // non-zero exit means the staged file differs from HEAD\n }\n\n await execFileAsync(\n 'git',\n ['commit', '-m', message, '--', progressPath],\n { cwd:repoRoot }\n )\n return true\n}\n", "import { execFile } from 'node:child_process'\nimport { promisify } from 'node:util'\n\nconst execFileAsync = promisify(execFile)\n\nexport type MergeConflictStrategy = 'respawn'|'stop'\n\nexport type MergeResult = {\n branch:string\n ticketNum:number\n merged:boolean\n conflicted:boolean\n stderr?:string\n}\n\nexport type WaveMergeResult = {\n merged:Array<MergeResult>\n stoppedAt:MergeResult|null\n}\n\nexport type GitOpResult = {\n success:boolean\n stderr?:string\n}\n\nexport async function mergeBranch (\n repoRoot:string,\n branch:string\n):Promise<GitOpResult> {\n if (!repoRoot || typeof repoRoot !== 'string') {\n throw new Error('repoRoot must be a non-empty string')\n }\n if (!branch || typeof branch !== 'string') {\n throw new Error('branch must be a non-empty string')\n }\n\n try {\n await execFileAsync(\n 'git',\n ['merge', branch, '--no-edit'],\n { cwd:repoRoot }\n )\n return { success:true }\n } catch (err) {\n const execErr = err as {\n stdout?:string; stderr?:string\n }\n const stderr =\n execErr.stderr || execErr.stdout\n try {\n await execFileAsync(\n 'git',\n ['merge', '--abort'],\n { cwd:repoRoot }\n )\n } catch {\n // no merge in progress to abort\n }\n return { success:false, stderr }\n }\n}\n\nexport async function rebaseBranch (\n repoRoot:string,\n branch:string,\n onto:string,\n worktreePath?:string\n):Promise<GitOpResult> {\n if (!repoRoot || typeof repoRoot !== 'string') {\n throw new Error('repoRoot must be a non-empty string')\n }\n if (!branch || typeof branch !== 'string') {\n throw new Error('branch must be a non-empty string')\n }\n if (!onto || typeof onto !== 'string') {\n throw new Error('onto must be a non-empty string')\n }\n\n // When the branch has its own worktree, it is already checked\n // out there -- checking it out in repoRoot too would fail with\n // \"already used by worktree\", so rebase in place instead.\n if (worktreePath) {\n try {\n await execFileAsync(\n 'git',\n ['rebase', onto],\n { cwd:worktreePath }\n )\n return { success:true }\n } catch (err) {\n const execErr = err as {\n stdout?:string; stderr?:string\n }\n const stderr =\n execErr.stderr || execErr.stdout\n try {\n await execFileAsync(\n 'git',\n ['rebase', '--abort'],\n { cwd:worktreePath }\n )\n } catch {\n // ignore abort errors\n }\n return { success:false, stderr }\n }\n }\n\n try {\n await execFileAsync(\n 'git',\n ['checkout', branch],\n { cwd:repoRoot }\n )\n\n await execFileAsync(\n 'git',\n ['rebase', onto],\n { cwd:repoRoot }\n )\n\n await execFileAsync(\n 'git',\n ['checkout', onto],\n { cwd:repoRoot }\n )\n\n return { success:true }\n } catch (err) {\n const stderr =\n (err as { stderr?:string }).stderr\n try {\n await execFileAsync(\n 'git',\n ['rebase', '--abort'],\n { cwd:repoRoot }\n )\n } catch {\n // ignore abort errors\n }\n try {\n await execFileAsync(\n 'git',\n ['checkout', onto],\n { cwd:repoRoot }\n )\n } catch {\n // ignore checkout errors\n }\n return { success:false, stderr }\n }\n}\n\n// Merges baseBranch into the worktree's branch so a\n// respawned agent sees the latest code. Conflicts are\n// left in place (not aborted) so the agent can resolve\n// and commit them.\nexport async function updateWorktreeFromBase (\n worktreePath:string,\n baseBranch:string\n):Promise<void> {\n try {\n await execFileAsync(\n 'git',\n ['merge', baseBranch, '--no-edit'],\n { cwd:worktreePath }\n )\n } catch {\n // conflict markers intentionally left for the\n // respawned agent to resolve\n }\n}\n\nexport async function mergeWave (\n opts:Readonly<{\n repoRoot:string\n baseBranch:string\n branches:ReadonlyArray<{\n branch:string\n ticketNum:number\n worktreePath?:string\n }>\n strategy:MergeConflictStrategy\n }>\n):Promise<WaveMergeResult> {\n const { repoRoot, baseBranch, branches, strategy } = opts\n\n if (!repoRoot || typeof repoRoot !== 'string') {\n throw new Error('repoRoot must be a non-empty string')\n }\n if (!baseBranch || typeof baseBranch !== 'string') {\n throw new Error('baseBranch must be a non-empty string')\n }\n\n const merged:Array<MergeResult> = []\n let stoppedAt:MergeResult|null = null\n\n for (let i = 0; i < branches.length; i++) {\n const { branch, ticketNum, worktreePath } = branches[i]\n const mergingResult:MergeResult = {\n branch,\n ticketNum,\n merged:false,\n conflicted:false,\n }\n\n if (i === 0) {\n const result = await mergeBranch(\n repoRoot,\n branch\n )\n mergingResult.merged = result.success\n mergingResult.conflicted = !result.success\n if (!result.success) {\n mergingResult.stderr = result.stderr\n }\n\n if (!result.success) {\n if (strategy === 'stop') {\n stoppedAt = mergingResult\n merged.push(mergingResult)\n break\n }\n merged.push(mergingResult)\n continue\n }\n } else {\n const rebaseResult = await rebaseBranch(\n repoRoot,\n branch,\n baseBranch,\n worktreePath\n )\n\n if (!rebaseResult.success) {\n mergingResult.conflicted = true\n mergingResult.stderr = rebaseResult.stderr\n\n if (strategy === 'stop') {\n stoppedAt = mergingResult\n merged.push(mergingResult)\n break\n } else {\n // strategy === 'respawn'\n merged.push(mergingResult)\n continue\n }\n }\n\n const mergeResult = await mergeBranch(\n repoRoot,\n branch\n )\n mergingResult.merged = mergeResult.success\n mergingResult.conflicted = !mergeResult.success\n if (!mergeResult.success) {\n mergingResult.stderr = mergeResult.stderr\n }\n\n if (!mergeResult.success) {\n if (strategy === 'stop') {\n stoppedAt = mergingResult\n merged.push(mergingResult)\n break\n }\n merged.push(mergingResult)\n continue\n }\n }\n\n merged.push(mergingResult)\n }\n\n return {\n merged,\n stoppedAt,\n }\n}\n", "export type TicketStatus =\n | 'pending'\n | 'in-progress'\n | 'awaiting-merge'\n | 'done'\n | 'failed'\n | 'blocked'\n\nexport type DisplayTicket = {\n readonly num:number\n readonly filename:string\n readonly feature?:string\n status:TicketStatus\n blockedBy?:ReadonlyArray<string>\n}\n\nexport type TicketRef = {\n readonly num:number\n readonly filename:string\n readonly feature?:string\n}\n\nexport type WaveState = {\n readonly waveNum:number\n readonly totalWaves:number\n}\n\nexport type DisplayConfig = {\n readonly stream:NodeJS.WriteStream\n}\n\n/**\n * Progress across the whole run, not just the current wave.\n * `completed` counts this run's tickets done before the wave\n * started; `total` is the size of this run's ticket list. Only\n * PlainDisplay prints it; StatusDisplay counts from its own list.\n */\nexport type RunProgress = {\n readonly completed:number\n readonly total:number\n}\n\nexport type Display = {\n /**\n * Called once at the start of the run, fixes the ticket list\n * for the entire session.\n */\n startRun(tickets:ReadonlyArray<TicketRef>):void\n startWave(\n waveNum:number,\n totalWaves:number,\n tickets:ReadonlyArray<TicketRef>,\n progress?:RunProgress,\n ):void\n setTicketStatus(\n num:number,\n status:TicketStatus,\n feature?:string,\n ):void\n /**\n * Mark a ticket as blocked; `blockedBy` holds display labels\n * of the upstream tickets that failed or need a human.\n */\n setBlocked(\n num:number,\n feature:string|undefined,\n blockedBy:ReadonlyArray<string>,\n ):void\n log(message:string):void\n cleanup():void\n}\n\nconst ESC = '\\x1b['\n\nexport const ansi = {\n cursorUp (n:number):string {\n return `${ESC}${n}A`\n },\n cursorTo (col:number):string {\n return `${ESC}${col}G`\n },\n eraseLine ():string {\n return `${ESC}2K`\n },\n eraseLines (n:number):string {\n let out = ''\n for (let i = 0; i < n; i++) {\n out += ansi.eraseLine()\n if (i < n - 1) out += ansi.cursorUp(1)\n }\n return out\n },\n cursorHide ():string {\n return `${ESC}?25l`\n },\n cursorShow ():string {\n return `${ESC}?25h`\n },\n} as const\n\nexport const color = {\n green (text:string):string {\n return `${ESC}32m${text}${ESC}0m`\n },\n yellow (text:string):string {\n return `${ESC}33m${text}${ESC}0m`\n },\n red (text:string):string {\n return `${ESC}31m${text}${ESC}0m`\n },\n cyan (text:string):string {\n return `${ESC}36m${text}${ESC}0m`\n },\n dim (text:string):string {\n return `${ESC}2m${text}${ESC}0m`\n },\n} as const\n\nexport function ticketLabel (\n ticket:{ num:number; filename:string; feature?:string },\n):string {\n if (ticket.feature) {\n const padded = String(ticket.num).padStart(2, '0')\n return `${ticket.feature}/${padded}`\n }\n return ticket.filename\n}\n\nconst FILLED_DOT = '\u25CF'\nconst EMPTY_DOT = '\u25CB'\nconst SEPARATOR_WIDTH = 50\nconst DEFAULT_COLUMNS = 80\nconst MIN_LOG_ROWS = 1\nconst MAX_MESSAGE_BUFFER = 200\n\n// eslint-disable-next-line no-control-regex\nconst ANSI_RE = /\\x1b\\[[0-9;?]*[A-Za-z]/g\n\nfunction rowText (ticket:DisplayTicket):string {\n const label = ticketLabel(ticket)\n if (ticket.status !== 'blocked' || !ticket.blockedBy?.length) {\n return label\n }\n return `${label} (blocked by ${ticket.blockedBy.join(', ')})`\n}\n\n/**\n * Clamp a line to `width` visible columns so it can never wrap.\n * A wrapped line occupies more terminal rows than `render`\n * counts, which leaves stale rows behind on the next erase.\n */\nexport function fitLine (line:string, width:number):string {\n const visible = line.replace(ANSI_RE, '')\n if (visible.length <= width) return line\n return visible.slice(0, width)\n}\n\n/**\n * Split a line into rows of at most `width` visible columns,\n * the way a terminal would wrap it. Short lines keep their\n * ANSI styling; long lines are wrapped on visible text only,\n * so `render` can count every row it emits.\n */\nexport function wrapLine (line:string, width:number):Array<string> {\n const visible = line.replace(ANSI_RE, '')\n if (visible.length <= width) return [line]\n const rows:Array<string> = []\n for (let i = 0; i < visible.length; i += width) {\n rows.push(visible.slice(i, i + width))\n }\n return rows\n}\n\nexport function renderDot (status:TicketStatus):string {\n switch (status) {\n case 'pending':\n return color.dim(EMPTY_DOT)\n case 'in-progress':\n return color.yellow(FILLED_DOT)\n // The agent and its test gate are finished; the branch\n // waits for the rest of the wave before it is merged. It\n // stays cyan through the merge and any conflict respawn.\n case 'awaiting-merge':\n return color.cyan(FILLED_DOT)\n case 'done':\n return color.green(FILLED_DOT)\n case 'failed':\n return color.red(FILLED_DOT)\n case 'blocked':\n // Ticket cannot run this session because an upstream\n // ticket failed or needs a human.\n return color.dim(FILLED_DOT)\n }\n}\n\nexport class StatusDisplay implements Display {\n private wave:WaveState|null = null\n private tickets:Array<DisplayTicket> = []\n private hasRun:boolean = false\n private messages:Array<string> = []\n private renderedLines:number = 0\n private config:DisplayConfig\n private viewportStart:number = 0\n private resizeListener:(() => void)|null = null\n\n constructor (config?:Readonly<Partial<DisplayConfig>>) {\n this.config = {\n stream:config?.stream ?? process.stdout,\n }\n }\n\n private getAvailableRows ():number {\n const termHeight = this.config.stream.rows ?? 24\n const overhead = 2 + MIN_LOG_ROWS\n const available = termHeight - overhead\n return Math.max(1, available)\n }\n\n private findTicket (\n num:number,\n feature?:string,\n ):DisplayTicket|null {\n const found = feature ?\n this.tickets.find(\n t => t.num === num && t.feature === feature,\n ) :\n this.tickets.find(t => t.num === num)\n return found ?? null\n }\n\n startRun (tickets:ReadonlyArray<TicketRef>):void {\n this.tickets = tickets.map(t => ({\n ...t,\n status:'pending' as const,\n }))\n this.hasRun = true\n this.viewportStart = 0\n }\n\n startWave (\n waveNum:number,\n totalWaves:number,\n tickets:ReadonlyArray<TicketRef>,\n _progress?:RunProgress,\n ):void {\n if (!this.hasRun) {\n this.startRun(tickets)\n }\n\n this.wave = {\n waveNum,\n totalWaves,\n }\n this.messages = []\n this.viewportStart = 0\n this.config.stream.write(ansi.cursorHide())\n\n if (this.config.stream.isTTY) {\n if (this.resizeListener) {\n this.config.stream.removeListener(\n 'resize', this.resizeListener,\n )\n }\n this.resizeListener = () => this.render()\n this.config.stream.on(\n 'resize', this.resizeListener,\n )\n }\n\n this.render()\n }\n\n setTicketStatus (\n num:number,\n status:TicketStatus,\n feature?:string,\n ):void {\n const ticket = this.findTicket(num, feature)\n if (!ticket) return\n\n ticket.status = status\n\n if (status === 'in-progress') {\n const ticketIndex = this.tickets.indexOf(ticket)\n const availableRows = this.getAvailableRows()\n const totalTickets = this.tickets.length\n\n if (ticketIndex < this.viewportStart) {\n this.viewportStart = ticketIndex\n } else if (ticketIndex >= this.viewportStart + availableRows) {\n // offset by 3 to keep context visible below\n // the active ticket\n this.viewportStart = ticketIndex - availableRows + 3\n }\n this.viewportStart = Math.max(\n 0,\n Math.min(this.viewportStart, totalTickets - 1),\n )\n }\n\n this.render()\n }\n\n setBlocked (\n num:number,\n feature:string|undefined,\n blockedBy:ReadonlyArray<string>,\n ):void {\n const ticket = this.findTicket(num, feature)\n if (!ticket) return\n\n ticket.status = 'blocked'\n ticket.blockedBy = [...blockedBy]\n this.render()\n }\n\n log (message:string):void {\n // Before the first wave there is no grid to repaint,\n // so a message would otherwise be dropped. Write it\n // straight to the stream instead. A later render\n // never erases these rows, since renderedLines is 0.\n if (!this.wave) {\n this.config.stream.write(message + '\\n')\n return\n }\n for (const line of message.split('\\n')) {\n this.messages.push(line)\n }\n while (this.messages.length > MAX_MESSAGE_BUFFER) {\n this.messages.shift()\n }\n this.render()\n }\n\n cleanup ():void {\n // Remove resize listener if it exists\n if (this.resizeListener && this.config.stream.isTTY) {\n this.config.stream.removeListener('resize', this.resizeListener)\n }\n this.config.stream.write(ansi.cursorShow())\n }\n\n private render ():void {\n if (!this.wave) return\n\n let output = ''\n\n if (this.renderedLines > 0) {\n output += ansi.eraseLines(this.renderedLines + 1)\n }\n\n const done = this.tickets.filter(\n t => t.status === 'done',\n ).length\n const total = this.tickets.length\n const pct = total === 0 ? 0 : Math.round((done / total) * 100)\n const width = Math.max(\n 1,\n (this.config.stream.columns ?? DEFAULT_COLUMNS) - 1,\n )\n\n const header = `Wave ${this.wave.waveNum}/` +\n `${this.wave.totalWaves} - ` +\n `${done}/${total} done - ${pct}%`\n output += fitLine(header, width) + '\\n'\n\n // Pagination logic\n const availableRows = this.getAvailableRows()\n let renderedTicketCount = 0\n\n if (this.tickets.length <= availableRows) {\n // All tickets fit, no pagination\n for (const ticket of this.tickets) {\n const dot = renderDot(ticket.status)\n const text = rowText(ticket)\n const name = fitLine(text, width - 2)\n output += `${dot} ${name}\\n`\n }\n renderedTicketCount = this.tickets.length\n } else {\n // Need pagination -- iterative clamp\n this.viewportStart = Math.max(\n 0,\n Math.min(\n this.viewportStart,\n this.tickets.length - 1,\n ),\n )\n\n let hasMoreAbove = this.viewportStart > 0\n let tentativeCount =\n availableRows - (hasMoreAbove ? 1 : 0)\n let hasMoreBelow =\n this.viewportStart + tentativeCount <\n this.tickets.length\n let ticketsToShow = Math.max(\n 0,\n tentativeCount - (hasMoreBelow ? 1 : 0),\n )\n\n const maxStart = Math.max(\n 0,\n this.tickets.length - Math.max(1, ticketsToShow),\n )\n if (this.viewportStart > maxStart) {\n this.viewportStart = maxStart\n hasMoreAbove = this.viewportStart > 0\n tentativeCount = availableRows - (hasMoreAbove ? 1 : 0)\n hasMoreBelow = (\n this.viewportStart +\n tentativeCount < this.tickets.length\n )\n ticketsToShow = Math.max(\n 0,\n tentativeCount - (hasMoreBelow ? 1 : 0)\n )\n }\n\n // Show \"more above\" indicator if needed\n if (hasMoreAbove) {\n const moreCount = this.viewportStart\n output += ` ... ${moreCount} more above\\n`\n }\n\n // Get visible tickets and render them\n const visibleTickets = this.tickets.slice(\n this.viewportStart,\n this.viewportStart + ticketsToShow,\n )\n\n for (const ticket of visibleTickets) {\n const dot = renderDot(ticket.status)\n const text = rowText(ticket)\n const name = fitLine(text, width - 2)\n output += `${dot} ${name}\\n`\n }\n\n // Show \"more below\" indicator if needed\n if (hasMoreBelow) {\n const moreCount = (\n this.tickets.length -\n (this.viewportStart + ticketsToShow)\n )\n output += ` ... ${moreCount} more below\\n`\n }\n\n renderedTicketCount = (hasMoreAbove ? 1 : 0) +\n visibleTickets.length +\n (hasMoreBelow ? 1 : 0)\n }\n\n output += '-'.repeat(Math.min(SEPARATOR_WIDTH, width)) + '\\n'\n\n const termHeight = this.config.stream.rows ?? 24\n const logRows = Math.max(\n 0,\n termHeight - 3 - renderedTicketCount,\n )\n const wrapped = this.messages.flatMap(\n msg => wrapLine(msg, width),\n )\n const visibleMessages = wrapped.slice(-logRows)\n for (const row of visibleMessages) {\n output += `${row}\\n`\n }\n const emptyRows = logRows - visibleMessages.length\n for (let i = 0; i < emptyRows; i++) {\n output += '\\n'\n }\n\n this.renderedLines = 2 + renderedTicketCount + logRows\n this.config.stream.write(output)\n }\n}\n\nexport class PlainDisplay implements Display {\n startRun (_tickets:ReadonlyArray<TicketRef>):void {\n // no-op: plain mode has no fixed list\n }\n\n startWave (\n waveNum:number,\n _totalWaves:number,\n tickets:ReadonlyArray<TicketRef>,\n progress?:RunProgress,\n ):void {\n const pct = progress && progress.total > 0 ?\n ` (${progress.completed}/${progress.total} done)` :\n ''\n console.log(\n `\\nWave ${waveNum}${pct}: ` +\n tickets.map(t => ticketLabel(t)).join(', ')\n )\n }\n\n setTicketStatus (\n _num:number,\n _status:TicketStatus,\n _feature?:string,\n ):void {\n // no-op: plain mode reports via log()\n }\n\n setBlocked (\n _num:number,\n _feature:string|undefined,\n _blockedBy:ReadonlyArray<string>,\n ):void {\n // no-op: plain mode has no fixed list\n }\n\n log (message:string):void {\n console.log(message)\n }\n\n cleanup ():void {\n // no-op\n }\n}\n\nexport function createDisplay (stream?:NodeJS.WriteStream):Display {\n const s = stream ?? process.stdout\n if (s.isTTY) {\n return new StatusDisplay({ stream:s })\n }\n\n return new PlainDisplay()\n}\n", "import { spawn } from 'node:child_process'\nimport { existsSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\nexport type TestResult = {\n exitCode:number\n output:string\n}\n\n// Returns the command to run the project's tests, or null\n// when the project does not declare one.\nexport function detectTestCmd (projectDir:string):string|null {\n const pkgPath = join(projectDir, 'package.json')\n if (!existsSync(pkgPath)) return null\n try {\n const pkg = JSON.parse(\n readFileSync(pkgPath, 'utf8')\n ) as { scripts?:Record<string, string> }\n return pkg.scripts?.test ?\n 'npm test' :\n null\n } catch {\n return null\n }\n}\n\nexport function runTestCmd (opts:{\n cmd:string\n cwd:string\n timeout:number\n registry?:Set<number>\n}):Promise<TestResult> {\n return new Promise(resolve => {\n let settled = false\n const child = spawn('sh', ['-c', opts.cmd], {\n cwd:opts.cwd,\n stdio:['ignore', 'pipe', 'pipe'],\n detached:true,\n })\n\n if (child.pid !== undefined && opts.registry) {\n opts.registry.add(child.pid)\n }\n\n const chunks:string[] = []\n child.stdout.on('data', d => chunks.push(String(d)))\n child.stderr.on('data', d => chunks.push(String(d)))\n\n const timer = setTimeout(() => {\n if (child.pid) {\n try {\n process.kill(-child.pid, 'SIGKILL')\n } catch {\n child.kill('SIGKILL')\n }\n } else {\n child.kill('SIGKILL')\n }\n }, opts.timeout * 1000)\n\n child.on('error', err => {\n if (settled) return\n settled = true\n clearTimeout(timer)\n if (child.pid !== undefined && opts.registry) {\n opts.registry.delete(child.pid)\n }\n chunks.push(String(err))\n resolve({\n exitCode:1,\n output:chunks.join(''),\n })\n })\n\n child.on('close', code => {\n if (settled) return\n settled = true\n clearTimeout(timer)\n if (child.pid !== undefined && opts.registry) {\n opts.registry.delete(child.pid)\n }\n resolve({\n exitCode:code ?? 1,\n output:chunks.join(''),\n })\n })\n })\n}\n", "import { existsSync, readdirSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { checkbox, Separator } from '@inquirer/prompts'\nimport { isSpecComplete } from './progress.js'\nimport { scanTickets, findReadyTickets } from './orchestrator.js'\n\nexport type FeatureSelection = {\n dir:string;\n spec:string;\n name:string;\n}\n\nexport function getScriptDir (metaUrl:string):string {\n return dirname(fileURLToPath(metaUrl))\n}\n\nexport function findFeatureDirs (cwd:string):{\n name:string;\n dir:string;\n spec:string\n}[] {\n const scratchDir = join(cwd, '.scratch')\n if (!existsSync(scratchDir)) return []\n const entries = readdirSync(\n scratchDir, { withFileTypes:true }\n )\n const results:{ name:string; dir:string; spec:string }[] = []\n for (const entry of entries) {\n if (!entry.isDirectory()) continue\n const issuesDir = join(\n scratchDir, entry.name, 'issues'\n )\n const specFile = join(\n scratchDir, entry.name, 'spec.md'\n )\n if (!existsSync(issuesDir)) continue\n const progressFile = join(\n scratchDir, entry.name, 'progress.md'\n )\n if (isSpecComplete(progressFile)) continue\n results.push({\n name:entry.name,\n dir:issuesDir,\n spec:specFile,\n })\n }\n results.sort((a, b) => a.name.localeCompare(b.name))\n return results\n}\n\nconst ALL_VALUE = '__all__'\n\nexport async function resolveIssuesDir (\n specName:string|undefined,\n cwd:string = process.cwd(),\n):Promise<FeatureSelection[]> {\n if (specName) {\n const featureDir = join(cwd, '.scratch', specName)\n return [{\n dir:join(featureDir, 'issues'),\n spec:join(featureDir, 'spec.md'),\n name:specName,\n }]\n }\n\n const features = findFeatureDirs(cwd)\n\n if (features.length === 0) {\n console.error(\n 'No .scratch/<feature>/issues/ directories ' +\n 'found.\\nProvide --spec <feature-name>.'\n )\n process.exit(2)\n }\n\n if (features.length === 1) {\n const f = features[0]\n console.log(`Using feature: ${f.name}`)\n return [{ dir:f.dir, spec:f.spec, name:f.name }]\n }\n\n const featureChoices = features.map(f => {\n const tickets = scanTickets(f.dir)\n const ready = findReadyTickets(tickets).length\n return {\n name:`${f.name} (${ready}/${tickets.length} ready)`,\n value:f.name,\n }\n })\n\n while (true) {\n const selected = await checkbox({\n message:'Which features?',\n choices:[\n { name:'All', value:ALL_VALUE },\n new Separator(),\n ...featureChoices,\n ],\n })\n\n if (selected.length === 0) {\n console.log('Select at least one feature')\n continue\n }\n\n const names = selected.includes(ALL_VALUE) ?\n features.map(f => f.name) :\n selected\n\n return names.map(name => {\n const f = features.find(\n ff => ff.name === name\n )!\n return { dir:f.dir, spec:f.spec, name:f.name }\n })\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["existsSync", "readFileSync", "dirname", "join", "spawn", "execFile", "mkdirSync", "readFileSync", "writeFileSync", "readdirSync", "join", "dirname", "basename", "promisify", "join", "existsSync", "
|
|
3
|
+
"sources": ["../src/index.ts", "../src/setup.ts", "../src/orchestrator.ts", "../src/worktree.ts", "../src/progress.ts", "../src/merge.ts", "../src/stats.ts", "../src/display.ts", "../src/testcmd.ts", "../src/learnings.ts", "../src/rules.ts", "../src/review.ts", "../src/retry.ts", "../src/blockers.ts", "../src/preflight.ts", "../src/resolve.ts"],
|
|
4
|
+
"sourcesContent": ["#!/usr/bin/env node\n\nimport { execFileSync } from 'node:child_process'\nimport { existsSync, readFileSync } from 'node:fs'\nimport { basename, dirname, join } from 'node:path'\nimport yargs from 'yargs'\nimport { hideBin } from 'yargs/helpers'\nimport { select } from '@inquirer/prompts'\nimport { setup, checkGhAuth, type TrackerKind } from './setup.js'\nimport {\n dryRun,\n dryRunIsolated,\n runWaves,\n runWavesIsolated,\n stripSpecSection,\n ALL_EFFORT_LEVELS,\n DEFAULT_RETRIES,\n DEFAULT_RETRY_DELAY,\n DEFAULT_CONCURRENCY,\n killRunningAgents,\n formatErrorMessage,\n nothingReady,\n renderNothingReady,\n type EffortLevel,\n type Ticket,\n} from './orchestrator.js'\nimport { detectTestCmd, detectInstallCmd } from './testcmd.js'\nimport { resolveExecutable } from './preflight.js'\nimport { createDisplay } from './display.js'\nimport {\n findFeatureDirs,\n resolveIssuesDir,\n getScriptDir,\n loadSelection,\n type FeatureSelection,\n type BlockerWarning,\n} from './resolve.js'\nimport {\n getRepoRoot,\n getRepoName,\n getCurrentBranch,\n getDefaultBranch,\n planIntegrationBranch,\n localBranchExists,\n prepareIntegrationBranch,\n describeIntegrationBranch,\n type IntegrationPlan,\n} from './worktree.js'\n\nexport { findFeatureDirs, resolveIssuesDir }\n\nconst scriptDir = getScriptDir(import.meta.url)\n\nyargs(hideBin(process.argv))\n .scriptName('nightralph')\n .usage('$0 <command>')\n .command(\n 'init',\n 'Install bundled skills and doc templates',\n y => y,\n async () => {\n const tracker = await select<TrackerKind>({\n message:'Issue tracker format',\n choices:[\n {\n name:'Local Markdown',\n value:'local' as const,\n description:'Issues as .md files in ' +\n '.scratch/',\n },\n {\n name:'GitHub Issues',\n value:'github' as const,\n description:'Issues via gh CLI',\n },\n ],\n })\n\n if (tracker === 'github') {\n if (!checkGhAuth()) {\n console.error(\n 'GitHub Issues requires the gh CLI, ' +\n 'authenticated.\\n' +\n 'Install: https://cli.github.com\\n' +\n 'Then run: gh auth login'\n )\n process.exit(2)\n }\n }\n\n setup({\n bundledSkillsDir:join(scriptDir, 'skills'),\n docsTemplatesDir:join(\n scriptDir, 'docs-templates'\n ),\n projectDir:process.cwd(),\n tracker,\n })\n }\n )\n .command(\n '$0 <provider> [turns]',\n 'Execute tickets with the given provider',\n y => y\n .positional('provider', {\n type:'string',\n describe:'Agent CLI to spawn ' +\n '(e.g. claude, codex, pi)',\n demandOption:true,\n })\n .positional('turns', {\n type:'number',\n describe:'Max agentic turns per ' +\n 'ticket (shorthand for ' +\n '--max-turns)',\n })\n .option('m', {\n alias:'model',\n type:'string',\n describe:'Model passed to the agent',\n })\n .option('spec', {\n type:'string',\n describe:'Feature name ' +\n '(resolves .scratch/<name>/)',\n })\n .option('dry-run', {\n type:'boolean',\n describe:'Show wave order without running',\n default:false,\n })\n .option('timeout', {\n type:'number',\n describe:'Kill agent after N seconds',\n default:3600,\n })\n .option('test-cmd', {\n type:'string',\n describe:'Command run in each worktree ' +\n 'after the agent exits; non-zero ' +\n 'exit rejects the ticket. Defaults ' +\n 'to \"npm test\" when package.json has ' +\n 'a test script; otherwise the run ' +\n 'has no test gate. \"\" disables it.',\n })\n .option('install-cmd', {\n type:'string',\n describe:'Command run in each fresh ' +\n 'worktree before the agent starts. ' +\n 'Defaults to the install command ' +\n 'for the project\\'s lockfile (npm ci ' +\n 'or pnpm install); \"\" disables it.',\n })\n .option('X', {\n type:'boolean',\n describe:'Stop on merge conflict instead of ' +\n 're-spawning',\n default:false,\n })\n .option('max-turns', {\n type:'number',\n describe:'Max agentic turns per ticket ' +\n '(forwarded to the agent CLI)',\n })\n .option('effort', {\n type:'string',\n choices:ALL_EFFORT_LEVELS,\n describe:'Starting effort level. ' +\n 'Omitted = provider default. ' +\n 'Retries step up from here.',\n })\n .option('prefer-subagent', {\n type:'string',\n describe:'claude only: model that subagents ' +\n 'default to (CLAUDE_CODE_SUBAGENT_MODEL), ' +\n 'plus a prompt rule to hand read-only work ' +\n 'to them. \"\" disables it.',\n })\n .option('retries', {\n type:'number',\n default:DEFAULT_RETRIES,\n describe:'Extra attempts per ticket ' +\n 'after a failed run, each with a ' +\n 'higher effort level. 0 ' +\n 'disables retries.',\n })\n .option('retry-delay', {\n type:'number',\n default:DEFAULT_RETRY_DELAY,\n describe:'Seconds to wait before the ' +\n 'first retry; doubles each further ' +\n 'retry. 0 disables the wait.',\n })\n .option('concurrency', {\n type:'number',\n default:DEFAULT_CONCURRENCY,\n describe:'Max agents running at once ' +\n 'within a wave.',\n })\n .option('review', {\n type:'boolean',\n default:true,\n describe:'Review the merged work and run one ' +\n 'fix pass at the end. --no-review skips it.',\n }),\n async argv => {\n await runExecute({\n provider:argv.provider as string,\n model:argv.model as string|undefined,\n spec:argv.spec as string|undefined,\n dryRun:argv.dryRun as boolean|undefined,\n timeout:argv.timeout as\n number|undefined,\n testCmd:argv.testCmd as string|undefined,\n installCmd:argv.installCmd as\n string|undefined,\n stopOnConflict:argv.X as\n boolean|undefined,\n maxTurns:(argv.maxTurns ??\n argv.turns) as number|undefined,\n effort:argv.effort as\n EffortLevel|undefined,\n preferSubagent:argv.preferSubagent as\n string|undefined,\n retries:argv.retries as\n number|undefined,\n retryDelay:argv.retryDelay as\n number|undefined,\n concurrency:argv.concurrency as\n number|undefined,\n review:argv.review as boolean|undefined,\n })\n }\n )\n .strict()\n .demandCommand(1, 'Specify a command or provider')\n .help()\n .fail((\n msg:string|null,\n err:unknown,\n y:{ showHelp:() => void }\n ) => {\n // A thrown or rejected error from a command handler arrives\n // as fail(null, err): one line, exit 2, same code as the\n // usage errors runExecute exits with itself. No help text,\n // no stack. A msg+err pair (parser or YError usage errors)\n // is a usage error and keeps the help text and exit 1.\n if (err && !msg) {\n console.error(formatErrorMessage(err))\n process.exit(2)\n }\n // A parse or validation error: keep today's output.\n y.showHelp()\n console.error(`\\n${msg}`)\n process.exit(1)\n })\n .parse()\n\nfunction isGitRepo ():boolean {\n try {\n getRepoRoot()\n return true\n } catch {\n return false\n }\n}\n\nfunction extractFeatureName (spec:string):string {\n const parts = spec.split(\n /[\\\\/]/\n )\n const scratchIndex = parts.indexOf('.scratch')\n if (scratchIndex >= 0 && scratchIndex < parts.length - 1) {\n return parts[scratchIndex + 1]\n }\n return parts[parts.length - 2] ??\n parts[parts.length - 1] ?? 'feature'\n}\n\ntype LoadedTickets = {\n allTickets:Ticket[]\n specBodies:Map<string, string>\n progressPaths:Map<string, string>\n issuesDirs:string[]\n firstFeatureName:string\n firstLogsDir:string\n // paths a selection needs that are not in the working tree\n missing:string[]\n // blockers that match no ticket, and likely feature-name typos\n warnings:BlockerWarning[]\n}\n\n// Scans every selected feature's tickets from the working tree.\n// Blockers are resolved by `loadSelection`, across features, and\n// the problems it finds come back as `warnings`. `log` is a no-op\n// for the silent re-scan after resuming an integration branch. A\n// selection whose issues dir or spec is absent is skipped and\n// reported in `missing`; the caller decides whether that is fatal.\nfunction loadTickets (\n selections:FeatureSelection[],\n log:(msg:string) => void\n):LoadedTickets {\n const allTickets:Ticket[] = []\n const specBodies = new Map<string, string>()\n const progressPaths = new Map<string, string>()\n const issuesDirs:string[] = []\n let firstFeatureName = ''\n let firstLogsDir = ''\n const missing:string[] = []\n\n const valid:FeatureSelection[] = []\n const specs = new Map<string, string>()\n for (const selection of selections) {\n const { dir, spec, name } = selection\n\n if (!existsSync(dir)) {\n missing.push(`Directory not found: ${dir}`)\n continue\n }\n if (!existsSync(spec)) {\n missing.push(`Spec file not found: ${spec}`)\n continue\n }\n\n specs.set(name, stripSpecSection(\n readFileSync(spec, 'utf8'),\n 'User Stories'\n ))\n valid.push(selection)\n }\n\n // process.cwd() is the base resolveIssuesDir uses; a nested\n // --spec name (a/b) only round-trips through the true scratch\n // dir, not dirname(dirname(dir)).\n const loaded = valid.length > 0 ?\n loadSelection(\n join(process.cwd(), '.scratch'),\n valid.map(s => s.name)\n ) :\n { tickets:[], warnings:[] }\n\n for (const { dir, spec, name } of valid) {\n const tickets = loaded.tickets.filter(t => t.feature === name)\n\n if (tickets.length === 0) {\n log(\n 'No ticket files found for ' +\n `${name}. Skipping.`\n )\n continue\n }\n\n log(\n `[${name}] Found ${tickets.length} tickets`\n )\n\n specBodies.set(name, specs.get(name)!)\n progressPaths.set(\n name, join(dirname(dir), 'progress.md')\n )\n issuesDirs.push(dir)\n allTickets.push(...tickets)\n\n if (!firstFeatureName) {\n firstFeatureName = extractFeatureName(spec)\n firstLogsDir = join(dirname(dir), 'logs')\n }\n }\n\n return {\n allTickets,\n specBodies,\n progressPaths,\n issuesDirs,\n firstFeatureName,\n firstLogsDir,\n missing,\n warnings:loaded.warnings,\n }\n}\n\n// The first scan of a run: anything missing is a usage error.\nfunction loadTicketsOrExit (\n selections:FeatureSelection[]\n):LoadedTickets {\n const loaded = loadTickets(selections, console.log)\n if (loaded.missing.length > 0) {\n for (const msg of loaded.missing) console.error(msg)\n process.exit(2)\n }\n return loaded\n}\n\n// Puts the launch branch back after a resume that stops early.\n// A failed checkout is reported by the caller's message.\nfunction checkoutLaunchBranch (plan:IntegrationPlan):void {\n try {\n execFileSync(\n 'git', ['checkout', '--quiet', plan.launchBranch],\n { cwd:getRepoRoot(), stdio:'ignore' }\n )\n } catch {\n // the caller reports the stop either way\n }\n}\n\n// A resumed integration branch can predate the tickets or spec of\n// this run. Puts the launch branch back and exits 2 with the fix.\nfunction failStaleResume (\n plan:IntegrationPlan,\n problems:string[]\n):never {\n checkoutLaunchBranch(plan)\n const n = plan.behind\n console.error(\n `Cannot resume ${plan.branch}: ` +\n `${problems.join('; ')}. It is ${n} ` +\n `commit${n === 1 ? '' : 's'} behind ${plan.launchBranch}. ` +\n `Merge ${plan.launchBranch} into it, or delete it with ` +\n `\\`git branch -D ${plan.branch}\\`. ` +\n `Back on ${plan.launchBranch}.`\n )\n process.exit(2)\n}\n\n// A resumed integration branch where every ready-for-agent\n// ticket is blocked: nothing to do here, so go back and say why.\nfunction stopNothingReady (\n plan:IntegrationPlan,\n loaded:LoadedTickets\n):never {\n checkoutLaunchBranch(plan)\n console.log(\n `Nothing to run on ${plan.branch}. ` +\n `Back on ${plan.launchBranch}.\\n` +\n renderNothingReady(loaded.allTickets, loaded.warnings)\n )\n process.exit(0)\n}\n\n// True when this run will resume an existing integration\n// branch. Its ticket statuses can differ from the launch\n// branch's, so the zero-ready check waits for the re-scan.\nfunction willResume (features:ReadonlyArray<string>):boolean {\n const root = getRepoRoot()\n const name = planIntegrationBranch(\n getCurrentBranch(root), getDefaultBranch(root), features\n )\n return name !== null && localBranchExists(root, name)\n}\n\n// One feature keeps its review log next to its progress file; a\n// multi-feature run reviews one combined diff, so its log sits in\n// .scratch/ itself.\nfunction reviewPathFor (issuesDirs:string[]):string {\n const featureDir = dirname(issuesDirs[0])\n return issuesDirs.length === 1 ?\n join(featureDir, 'review.md') :\n join(dirname(featureDir), 'review.md')\n}\n\nasync function runExecute (argv:{\n provider:string\n model?:string\n spec?:string\n dryRun?:boolean\n timeout?:number\n testCmd?:string\n installCmd?:string\n stopOnConflict?:boolean\n maxTurns?:number\n effort?:EffortLevel\n preferSubagent?:string\n retries?:number\n retryDelay?:number\n concurrency?:number\n review?:boolean\n}):Promise<void> {\n const selections = await resolveIssuesDir(\n argv.spec\n )\n\n let loaded = loadTicketsOrExit(selections)\n if (loaded.allTickets.length === 0) return\n\n // Stop before the dry run, provider lookup and any branch work\n // when every ready-for-agent ticket is blocked. A resumed\n // integration branch is checked after its re-scan instead.\n const resuming = () => !argv.dryRun && isGitRepo() &&\n willResume([...loaded.specBodies.keys()])\n if (nothingReady(loaded.allTickets) && !resuming()) {\n console.log(renderNothingReady(\n loaded.allTickets, loaded.warnings\n ))\n return\n }\n\n const providerPath = resolveExecutable(argv.provider)\n const providerIsPath = argv.provider.includes('/')\n // A path is never searched on PATH, so say what was checked\n const providerMissing = providerIsPath ?\n 'not found or not executable' :\n 'not found on PATH'\n if (providerPath === null && !argv.dryRun) {\n console.error(\n `Provider '${argv.provider}' ${providerMissing}`\n )\n process.exit(2)\n }\n // Worktrees spawn with their own cwd, so a relative path must\n // be resolved here, against the launch directory. A bare name\n // stays a PATH lookup at spawn time.\n const agentCmd = providerIsPath ?\n providerPath ?? argv.provider :\n argv.provider\n\n // claude is the only provider with subagents. Warn once here\n // and drop the value, so no agent gets the env var or the rule.\n let preferSubagent = argv.preferSubagent || undefined\n const providerName = basename(argv.provider)\n if (preferSubagent && providerName !== 'claude') {\n console.warn(\n '--prefer-subagent not supported by ' +\n `${providerName}, skipping`\n )\n preferSubagent = undefined\n }\n\n const isolated = isGitRepo()\n const featureNames = [...loaded.specBodies.keys()]\n let plan:IntegrationPlan|null = null\n if (isolated && !argv.dryRun) {\n try {\n plan = prepareIntegrationBranch(\n getRepoRoot(), featureNames\n )\n } catch (err) {\n console.error(formatErrorMessage(err))\n process.exit(2)\n }\n if (plan.created) {\n console.log(\n `Created branch ${plan.branch} ` +\n `from ${plan.launchBranch}`\n )\n } else if (plan.resumed) {\n console.log(\n `Resumed ${plan.branch}` +\n (plan.fastForwarded ?\n ` (fast-forwarded to ${plan.launchBranch})` :\n '') +\n (plan.behind > 0 ?\n ` (${plan.launchBranch} is ${plan.behind} ` +\n `commit${plan.behind === 1 ? '' : 's'} ahead)` :\n '')\n )\n // Ticket statuses live on the branch just checked out\n loaded = loadTickets(selections, () => {})\n if (loaded.missing.length > 0) {\n failStaleResume(plan, loaded.missing)\n }\n if (loaded.allTickets.length === 0) {\n failStaleResume(plan, ['no tickets'])\n }\n if (nothingReady(loaded.allTickets)) {\n stopNothingReady(plan, loaded)\n }\n }\n }\n\n const {\n allTickets, specBodies, progressPaths,\n firstFeatureName, firstLogsDir,\n } = loaded\n\n const timeout = argv.timeout ?? 900\n const testCmd = argv.testCmd ?? detectTestCmd(\n isolated ?\n getRepoRoot() :\n process.cwd()\n ) ?? ''\n if (argv.testCmd === undefined && testCmd === '') {\n console.log(\n 'No test command detected; running without a ' +\n 'test gate. Pass --test-cmd to add one.'\n )\n }\n // Only worktrees start without dependencies, so only an\n // isolated run installs. An explicit \"\" disables it.\n const installCmd = argv.installCmd ??\n (isolated ?\n detectInstallCmd(getRepoRoot()) ?? undefined :\n undefined)\n const conflictStrategy = argv.stopOnConflict ?\n 'stop' :\n 'respawn'\n const logsDir = firstLogsDir\n const fallbackSpec = specBodies.values().next().value!\n\n if (argv.dryRun) {\n console.log(\n `Provider: ${providerPath ?? providerMissing}`\n )\n if (isolated) {\n const repoName = getRepoName()\n dryRunIsolated({\n tickets:allTickets,\n specBody:fallbackSpec,\n repoName,\n conflictStrategy,\n progressPath:progressPaths.values()\n .next().value!,\n testCmd,\n installCmd,\n effort:argv.effort,\n retries:argv.retries,\n retryDelay:argv.retryDelay,\n concurrency:argv.concurrency,\n preferSubagent,\n })\n console.log(\n describeIntegrationBranch(\n getRepoRoot(), featureNames\n )\n )\n const reviewState = argv.review === false ? 'off' : 'on'\n console.log(`Review: ${reviewState}`)\n } else {\n dryRun(\n allTickets, fallbackSpec, testCmd, preferSubagent\n )\n }\n return\n }\n\n const display = createDisplay()\n\n function onSignal (exitCode:number):void {\n killRunningAgents()\n display.cleanup()\n process.exit(exitCode)\n }\n process.on('SIGINT', () => onSignal(130))\n process.on('SIGTERM', () => onSignal(143))\n\n let result:{ allDone:boolean; branch?:string }\n\n if (isolated) {\n result = await runWavesIsolated({\n tickets:allTickets,\n specBody:fallbackSpec,\n specBodies,\n agentCmd,\n model:argv.model ?? null,\n timeout,\n logsDir,\n featureName:firstFeatureName,\n conflictStrategy,\n display,\n testCmd,\n installCmd,\n maxTurns:argv.maxTurns,\n effort:argv.effort,\n retries:argv.retries,\n retryDelay:argv.retryDelay,\n concurrency:argv.concurrency,\n preferSubagent,\n progressPaths,\n warnings:loaded.warnings,\n review:argv.review === false ?\n undefined :\n {\n reviewPath:reviewPathFor(loaded.issuesDirs),\n forkedFrom:plan?.forkedFrom ?? undefined,\n },\n })\n } else {\n result = await runWaves(\n allTickets, fallbackSpec,\n agentCmd, argv.model ?? null,\n timeout,\n logsDir,\n testCmd,\n display,\n argv.maxTurns,\n argv.effort,\n argv.retries,\n argv.retryDelay,\n argv.concurrency,\n loaded.warnings,\n preferSubagent,\n )\n }\n\n if (!result.allDone) {\n process.exit(1)\n }\n}\n", "import {\n cpSync,\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n symlinkSync,\n writeFileSync,\n} from 'node:fs'\nimport { join } from 'node:path'\nimport { execSync } from 'node:child_process'\n\nexport const SKILL_DIRS = [\n 'grill', 'grilling', 'domain-modeling',\n 'to-spec', 'to-tickets', 'tdd',\n 'codebase-design',\n] as const\n\nexport const DOC_TEMPLATES = [\n 'triage-labels.md',\n 'domain.md',\n] as const\n\nconst START_MARKER = '<!-- nightralph:start -->'\nconst END_MARKER = '<!-- nightralph:end -->'\n\nexport function writeManagedSection (\n filePath:string,\n content:string,\n):void {\n const block = [\n START_MARKER,\n content,\n END_MARKER,\n ].join('\\n')\n\n if (!existsSync(filePath)) {\n writeFileSync(filePath, block + '\\n')\n return\n }\n\n const existing = readFileSync(filePath, 'utf8')\n const startIdx = existing.indexOf(START_MARKER)\n const endIdx = existing.indexOf(END_MARKER)\n\n if (startIdx !== -1 && endIdx !== -1) {\n const before = existing.slice(0, startIdx)\n const after = existing.slice(\n endIdx + END_MARKER.length\n )\n writeFileSync(filePath, before + block + after)\n } else {\n const sep = existing.endsWith('\\n') ? '\\n' : '\\n\\n'\n writeFileSync(filePath, existing + sep + block + '\\n')\n }\n}\n\nfunction ensureGitAttribute (\n filePath:string,\n line:string,\n):void {\n if (!existsSync(filePath)) {\n writeFileSync(filePath, line + '\\n')\n return\n }\n const existing = readFileSync(filePath, 'utf8')\n if (existing.split('\\n').includes(line)) return\n const sep = existing.endsWith('\\n') ? '' : '\\n'\n writeFileSync(filePath, existing + sep + line + '\\n')\n}\n\nexport function checkGhAuth ():boolean {\n try {\n execSync('gh auth status', { stdio:'ignore' })\n return true\n } catch {\n return false\n }\n}\n\nexport type TrackerKind = 'github'|'local'\n\nexport type SetupOpts = {\n bundledSkillsDir:string\n docsTemplatesDir:string\n projectDir:string\n tracker:TrackerKind\n}\n\nconst TRACKER_TEMPLATES:Record<TrackerKind, string> = {\n local:'issue-tracker.md',\n github:'issue-tracker-github.md',\n}\n\nexport function setup (opts:SetupOpts):void {\n const {\n bundledSkillsDir,\n docsTemplatesDir,\n projectDir,\n tracker,\n } = opts\n const agentsSkillsDir = join(\n projectDir, '.agents', 'skills'\n )\n\n const upstream = JSON.parse(\n readFileSync(\n join(bundledSkillsDir, 'upstream.json'),\n 'utf8'\n )\n ) as { repo:string; commit:string }\n\n console.log('Installing skills to .agents/skills/\\n')\n\n for (const skill of SKILL_DIRS) {\n const src = join(bundledSkillsDir, skill)\n const dest = join(agentsSkillsDir, skill)\n mkdirSync(dest, { recursive:true })\n cpSync(src, dest, { recursive:true })\n const files = readdirSync(src)\n console.log(\n ` ${skill}/ (${files.join(', ')})`\n )\n }\n\n const claudeSkillsDir = join(\n projectDir, '.claude', 'skills'\n )\n mkdirSync(claudeSkillsDir, { recursive:true })\n\n for (const skill of SKILL_DIRS) {\n const linkPath = join(claudeSkillsDir, skill)\n const target = join(\n '..', '..', '.agents', 'skills', skill\n )\n if (existsSync(linkPath)) continue\n symlinkSync(target, linkPath)\n }\n\n console.log(\n '\\nCreated symlinks in .claude/skills/'\n )\n\n const docsAgentsDir = join(\n projectDir, 'docs', 'agents'\n )\n mkdirSync(docsAgentsDir, { recursive:true })\n\n console.log('')\n for (const tmpl of DOC_TEMPLATES) {\n const dest = join(docsAgentsDir, tmpl)\n if (existsSync(dest)) {\n console.log(\n ` docs/agents/${tmpl} (already exists)`\n )\n continue\n }\n const src = join(docsTemplatesDir, tmpl)\n writeFileSync(dest, readFileSync(src, 'utf8'))\n console.log(` docs/agents/${tmpl} (created)`)\n }\n\n const trackerSrc = join(\n docsTemplatesDir, TRACKER_TEMPLATES[tracker]\n )\n const trackerDest = join(docsAgentsDir, 'issue-tracker.md')\n writeFileSync(trackerDest, readFileSync(trackerSrc, 'utf8'))\n console.log(\n ` docs/agents/issue-tracker.md (${tracker})`\n )\n\n const trackerLine = tracker === 'github' ?\n 'Issues are tracked via GitHub Issues using the `gh` ' +\n 'CLI.' :\n 'Issues are tracked as local markdown files under ' +\n '`.scratch/`.'\n\n const managedContent = [\n '## Agent skills',\n '',\n '### Issue tracker',\n '',\n `${trackerLine} See \\`docs/agents/issue-tracker.md\\`.`,\n '',\n '### Triage labels',\n '',\n 'Default label vocabulary. See ' +\n '`docs/agents/triage-labels.md`.',\n '',\n '### Domain docs',\n '',\n 'Single-context layout. See `docs/agents/domain.md`.',\n ].join('\\n')\n\n const agentsPath = join(projectDir, 'AGENTS.md')\n writeManagedSection(agentsPath, managedContent)\n console.log('\\n AGENTS.md (updated)')\n\n ensureGitAttribute(\n join(projectDir, '.gitattributes'),\n 'AGENTS.md merge=union',\n )\n console.log(' .gitattributes (AGENTS.md merge=union)')\n\n console.log(\n `\\nSource: ${upstream.repo} @ ${upstream.commit}`\n )\n}\n", "import { spawn, execFile } from 'node:child_process'\nimport {\n createWriteStream,\n mkdirSync,\n readFileSync,\n writeFileSync,\n unlinkSync,\n readdirSync,\n statSync,\n} from 'node:fs'\nimport { tmpdir } from 'node:os'\nimport { join, dirname, basename, relative } from 'node:path'\nimport { createInterface } from 'node:readline'\nimport { promisify } from 'node:util'\n\nconst execFileAsync = promisify(execFile)\nimport {\n getRepoRoot,\n getRepoName,\n getCurrentBranch,\n createWorktree,\n removeWorktree,\n buildBranchName,\n hasNewCommits,\n isDirty,\n commitDirty,\n headCommit,\n} from './worktree.js'\nimport {\n generateProgress,\n generateMultiFeatureProgress,\n createProgressTracker,\n readProgress,\n mergeProgress,\n writeProgress,\n commitProgress,\n checkTicket,\n type ProgressData,\n type ProgressTracker,\n} from './progress.js'\nimport {\n mergeBranch,\n mergeWave,\n updateWorktreeFromBase,\n type MergeConflictStrategy,\n} from './merge.js'\nimport {\n createDisplay,\n ticketLabel,\n type RunProgress,\n type Display,\n type TicketRef,\n} from './display.js'\nimport { runTestCmd } from './testcmd.js'\nimport {\n readDocsRule,\n installRule,\n subagentRule,\n testGateRule,\n LINT_RULE,\n integrityRule,\n CONFINEMENT_RULES,\n commitRule,\n notesRule,\n agentsMdRule,\n} from './rules.js'\nimport { runReviewPass, renderReviewSummary } from './review.js'\nimport {\n addRun,\n addStats,\n emptyRunStats,\n emptyStreamStats,\n isRecord,\n nextStreamStats,\n renderRunStats,\n type SubagentStats,\n} from './stats.js'\nimport {\n EFFORT_LADDERS,\n escalateEffort,\n retryDelayFor,\n runWithRetries,\n sleep,\n type EffortLevel,\n type ProviderName,\n} from './retry.js'\n\nexport {\n EFFORT_LADDERS,\n ALL_EFFORT_LEVELS,\n escalateEffort,\n retryDelayFor,\n type EffortLevel,\n type ProviderName,\n} from './retry.js'\nimport {\n LOG_TAIL_LINES,\n appendEntry,\n collectNotes,\n ensureNotesIgnored,\n learningsPathFor,\n readEntries,\n renderEntry,\n renderHistory,\n selectHistory,\n tailLines,\n type AgentRunRecord,\n type EntryInput,\n} from './learnings.js'\nimport {\n parseBlockerField,\n provisionalRefs,\n type BlockerRef,\n type BlockerWarning,\n} from './blockers.js'\n\nexport type Ticket = {\n num:number\n slug:string\n filename:string\n filepath:string\n body:string\n status:string\n blockers:BlockerRef[]\n feature:string\n}\n\nexport function formatErrorMessage (error:unknown):string {\n return error instanceof Error ?\n error.message :\n String(error)\n}\n\n// Removes a ticket's worktree, logging and swallowing any\n// failure instead of letting it interrupt the wave.\nasync function removeWorktreeQuietly (\n worktreePath:string,\n d:Display\n):Promise<void> {\n try {\n await removeWorktree(worktreePath, { force:true })\n } catch (err) {\n d.log(\n ' Failed to remove worktree ' +\n `${worktreePath}: ` +\n formatErrorMessage(err)\n )\n }\n}\n\nasync function commitTicketFiles (\n repoRoot:string,\n tickets:Ticket[],\n d:Display\n):Promise<void> {\n const paths = tickets.map(t => t.filepath)\n if (paths.length === 0) return\n try {\n await execFileAsync(\n 'git',\n ['add', '--force', ...paths],\n { cwd:repoRoot }\n )\n try {\n await execFileAsync(\n 'git',\n ['diff', '--cached', '--quiet',\n '--', ...paths],\n { cwd:repoRoot }\n )\n return\n } catch {\n // staged files differ from HEAD\n }\n await execFileAsync(\n 'git',\n ['commit', '-m',\n 'nightralph: update ticket checklists',\n '--', ...paths],\n { cwd:repoRoot }\n )\n } catch (err) {\n d.log(\n ' Failed to commit ticket updates: ' +\n formatErrorMessage(err)\n )\n }\n}\n\nexport const TICKET_RE = /^(\\d+)-(.+)\\.md$/\n\nexport function parseTicketFilename (\n filename:string\n):{ num:number; slug:string }|null {\n const m = filename.match(TICKET_RE)\n if (!m) return null\n return { num:Number(m[1]), slug:m[2] }\n}\n\nexport function parseStatus (body:string):string {\n const m = body.match(/\\*\\*Status:\\*\\*\\s*(.+)/i)\n return m ? m[1].trim().toLowerCase() : ''\n}\n\n/**\n * Reads every ticket file in `dir`. Blocker refs are provisional\n * (every ref `where:'run'`) until `loadSelection` resolves them\n * against the run; a word in `knownFeatures` before a number names\n * that number's feature.\n */\nexport function scanTickets (\n dir:string,\n feature:string = '',\n knownFeatures:ReadonlySet<string> = new Set()\n):Ticket[] {\n const files = readdirSync(dir)\n .filter(f => TICKET_RE.test(f))\n .sort((a, b) => a.localeCompare(\n b,\n undefined,\n { numeric:true, sensitivity:'base' }\n ))\n\n return files.map(filename => {\n const parsed = parseTicketFilename(filename)!\n const filepath = join(dir, filename)\n const body = readFileSync(filepath, 'utf8')\n return {\n num:parsed.num,\n slug:parsed.slug,\n filename,\n filepath,\n body,\n status:parseStatus(body),\n blockers:provisionalRefs(\n parseBlockerField(body, knownFeatures).refs,\n feature\n ),\n feature,\n }\n })\n}\n\nexport function ticketKey (feature:string, num:number):string {\n return `${feature}:${num}`\n}\n\n/**\n * Whether one blocker ref lets its dependent run. `run` refs are\n * decided by the live status of the ticket in this run; refs\n * outside the run were classified at load time.\n */\nexport function blockerSatisfied (\n ref:BlockerRef,\n doneKeys:ReadonlySet<string>\n):boolean {\n switch (ref.where) {\n case 'run':\n return doneKeys.has(ticketKey(ref.feature, ref.num))\n case 'done': return true\n case 'pending':\n case 'missing': return false\n }\n}\n\n/**\n * Display name of a blocker: `<feature>/<NN>`, plus why it is dead\n * when it is outside the run.\n */\nexport function blockerLabel (ref:BlockerRef):string {\n const nn = String(ref.num).padStart(2, '0')\n const base = ref.feature ? `${ref.feature}/${nn}` : nn\n if (ref.where === 'pending') {\n return `${base} (${ref.status ?? 'not done'}, not in run)`\n }\n if (ref.where === 'missing') return `${base} (not found)`\n return base\n}\n\nexport function findReadyTickets (\n tickets:ReadonlyArray<Ticket>\n):Ticket[] {\n const doneKeys = new Set(\n tickets\n .filter(t => t.status === 'done')\n .map(t => ticketKey(t.feature, t.num))\n )\n return tickets.filter(t => {\n if (t.status !== 'ready-for-agent') return false\n return t.blockers.every(r => blockerSatisfied(r, doneKeys))\n })\n}\n\n/**\n * Tickets that cannot run this session because a blocker they\n * depend on, directly or through a chain of in-run refs (across\n * features), is dead. Dead means a `pending` or `missing` ref, or\n * an in-run ticket that is in `failedKeys` or whose status is\n * neither done nor ready-for-agent, e.g. ready-for-human. A `done`\n * ref, or a done in-run ticket, ends the walk. An in-run ref with\n * no matching ticket (bare scans only) is not dead.\n * Returns ticketKey -> dead upstream refs. Only ready-for-agent\n * tickets that have not failed are keys.\n */\nexport function findBlockedTickets (\n tickets:ReadonlyArray<Ticket>,\n failedKeys:ReadonlySet<string>,\n):Map<string, BlockerRef[]> {\n const byKey = new Map(\n tickets.map(t => [ticketKey(t.feature, t.num), t])\n )\n\n function collectDead (\n ticket:Ticket,\n visited:Set<string>,\n found:Map<string, BlockerRef>,\n ):void {\n for (const ref of ticket.blockers) {\n const key = ticketKey(ref.feature, ref.num)\n if (visited.has(key)) continue\n visited.add(key)\n if (ref.where === 'done') continue\n if (ref.where === 'pending' || ref.where === 'missing') {\n found.set(key, ref)\n continue\n }\n const blocker = byKey.get(key)\n if (!blocker || blocker.status === 'done') continue\n if (\n failedKeys.has(key) ||\n blocker.status !== 'ready-for-agent'\n ) {\n found.set(key, ref)\n continue\n }\n collectDead(blocker, visited, found)\n }\n }\n\n const blocked = new Map<string, BlockerRef[]>()\n for (const t of tickets) {\n const key = ticketKey(t.feature, t.num)\n if (t.status !== 'ready-for-agent') continue\n if (failedKeys.has(key)) continue\n const found = new Map<string, BlockerRef>()\n collectDead(t, new Set([key]), found)\n if (found.size > 0) blocked.set(key, [...found.values()])\n }\n return blocked\n}\n\n// Matches an agent-reported completed item. Agents echo items\n// as markdown checklist lines (`- [x] item`) as often as bare\n// `[x] item` lines, so the bullet prefix is optional.\nexport const COMPLETED_RE = /^\\s*[-*+]?\\s*\\[x\\]\\s+(.+)$/i\nexport const TOOL_USE_RE = /^\\[[\\w.]+\\]/\n\n// Matches one checklist line in a ticket file: optional indent\n// and bullet, the `[ ]` / `[x]` box, and the item text.\nconst CHECKBOX_RE = /^(\\s*[-*+] )\\[( |x|X)\\]( .*)$/\n\n// The unchecked-box variant, used for the actual flip to [x].\nconst UNCHECKED_BOX_RE = /^(\\s*[-*+] )\\[( )\\]/\n\n// Normalizes checklist text for matching: agents echo an item as\n// one logical line while ticket files wrap items across lines,\n// so compare with whitespace runs collapsed, case-insensitively.\nfunction normalizeItemText (s:string):string {\n return s.replace(/\\s+/g, ' ').trim().toLowerCase()\n}\n\n// Drops an optional markdown bullet/checkbox prefix so items match\n// whether or not the caller already stripped the `[x]` marker.\nfunction stripCheckboxPrefix (s:string):string {\n return s.replace(/^\\s*[-*+]?\\s*\\[[ xX]\\]\\s+/, '')\n}\n\ntype ParsedItem = { start:number; text:string }\n\n// Parses the checklist items out of a ticket body. An item is its\n// checkbox line plus any immediately following indented lines\n// (wrapped text), so items written across multiple lines can be\n// matched by their full text. Code fences are skipped.\nfunction parseChecklistItems (\n lines:string[]\n):ParsedItem[] {\n const items:ParsedItem[] = []\n let inFence = false\n let i = 0\n while (i < lines.length) {\n if (/^\\s*```/.test(lines[i])) {\n inFence = !inFence\n i++\n continue\n }\n if (inFence) {\n i++\n continue\n }\n const m = lines[i].match(CHECKBOX_RE)\n if (!m) {\n i++\n continue\n }\n const start = i\n let text = m[3]\n i++\n while (\n i < lines.length &&\n /^\\s+\\S/.test(lines[i]) &&\n !CHECKBOX_RE.test(lines[i])\n ) {\n text += ' ' + lines[i].trim()\n i++\n }\n items.push({\n start,\n text:normalizeItemText(text),\n })\n }\n return items\n}\n\nexport function checkItems (\n ticket:Ticket,\n completedItems:string[]\n):void {\n if (completedItems.length === 0) return\n // Read from disk: a merge or respawn may have changed the\n // file since the ticket was scanned, and writing the stale\n // body would drop those edits.\n let body:string\n try {\n body = readFileSync(ticket.filepath, 'utf8')\n } catch {\n body = ticket.body\n }\n const wanted = new Set(\n completedItems.map(item =>\n normalizeItemText(stripCheckboxPrefix(item))\n )\n )\n const lines = body.split('\\n')\n let changed = false\n for (const item of parseChecklistItems(lines)) {\n if (!wanted.has(item.text)) continue\n const flipped = lines[item.start].replace(\n UNCHECKED_BOX_RE,\n '$1[x]'\n )\n if (flipped !== lines[item.start]) {\n lines[item.start] = flipped\n changed = true\n }\n }\n if (!changed) return\n body = lines.join('\\n')\n writeFileSync(ticket.filepath, body)\n ticket.body = body\n}\n\n// Checks off every remaining unchecked item in a ticket body,\n// ignoring fenced code blocks.\nfunction checkAllItems (body:string):string {\n const lines = body.split('\\n')\n let inFence = false\n for (let i = 0; i < lines.length; i++) {\n if (/^\\s*```/.test(lines[i])) {\n inFence = !inFence\n continue\n }\n if (inFence) continue\n lines[i] = lines[i].replace(\n UNCHECKED_BOX_RE,\n '$1[x]'\n )\n }\n return lines.join('\\n')\n}\n\nexport function markDone (ticket:Ticket):void {\n // Re-read from disk: the merge may have brought the agent's\n // own edits to the ticket file into the repo, and writing\n // the body scanned at startup would drop them.\n let body:string\n try {\n body = readFileSync(ticket.filepath, 'utf8')\n } catch {\n body = ticket.body\n }\n // A done ticket's items are complete by definition, so check\n // off anything the agent did not report instead of leaving\n // the file claiming done with unchecked items.\n body = checkAllItems(body)\n const updated = body.replace(\n /\\*\\*Status:\\*\\*\\s*.+/i,\n '**Status:** done'\n )\n writeFileSync(ticket.filepath, updated)\n ticket.status = 'done'\n ticket.body = updated\n}\n\n// Drops one markdown section from a spec. Used to keep the\n// per-ticket prompt short: the User Stories list is useful\n// to humans and to to-tickets but not to an implementing agent.\nexport function stripSpecSection (\n specBody:string,\n heading:string\n):string {\n const out:string[] = []\n let skipping = false\n let skipLevel = 0\n let inFence = false\n\n for (const line of specBody.split('\\n')) {\n // Toggle fence state on lines starting with ``` (after\n // optional whitespace)\n if (/^\\s*```/.test(line)) {\n inFence = !inFence\n }\n\n // Only check for headings outside of code fences\n if (!inFence) {\n const m = /^(#{1,6})\\s+(.*?)\\s*$/.exec(line)\n if (m) {\n const level = m[1].length\n if (skipping && level <= skipLevel) {\n skipping = false\n }\n if (!skipping && m[2] === heading) {\n skipping = true\n skipLevel = level\n continue\n }\n }\n }\n if (!skipping) out.push(line)\n }\n\n return out.join('\\n')\n}\n\n// The spec text for the review: the one spec, or every feature's\n// spec under its own heading for a multi-feature run.\nfunction reviewSpecBody (\n specBody:string,\n specBodies?:Map<string, string>\n):string {\n if (!specBodies || specBodies.size <= 1) return specBody\n return [...specBodies]\n .map(([name, body]) => `# Feature: ${name}\\n\\n${body}`)\n .join('\\n\\n')\n}\n\nexport function lookupSpec (\n specBodies:Map<string, string>|undefined,\n fallback:string,\n feature:string\n):string {\n if (!feature || !specBodies) return fallback\n return specBodies.get(feature) ?? fallback\n}\n\nfunction historyBlock (history?:string):string[] {\n if (!history) return []\n return [history, '']\n}\n\nexport function renderPrompt (\n specBody:string,\n ticket:Ticket,\n opts:{\n testCmd:string\n installCmd?:string\n history?:string\n preferSubagent?:string\n }\n):string {\n return [\n '---- SPEC CONTEXT ----',\n specBody,\n '',\n '---- TICKET ----',\n ticket.filename,\n ticket.body,\n '',\n ...historyBlock(opts.history),\n '---- AGENT INSTRUCTIONS ----',\n 'You are an autonomous coding agent. ' +\n 'Implement the ticket using /tdd.',\n '',\n 'Follow these rules:',\n readDocsRule('ticket'),\n '- Work ONLY on this ticket. Do not fix ' +\n 'unrelated problems you notice.',\n '- Do NOT research external APIs or services ' +\n 'via web search. Use the spec and ticket ' +\n 'body as your sole reference for API shapes.',\n ...installRule(opts.installCmd),\n ...subagentRule(opts.preferSubagent),\n '- Use /tdd for every checklist item. For ' +\n 'each item, write a failing test at the ' +\n 'seams named in the spec\\'s Testing ' +\n 'Decisions section, then write only ' +\n 'enough code to make it pass, then ' +\n 'refactor. For a checklist item that is ' +\n 'pure scaffolding, config, or docs (where ' +\n 'a test adds no value), skip test-first ' +\n 'and record that decision in your notes ' +\n 'file.',\n testGateRule(opts.testCmd, 'ticket'),\n LINT_RULE,\n integrityRule('checklist item'),\n ...CONFINEMENT_RULES,\n commitRule('checklist item'),\n notesRule('checklist item', 'ticket'),\n '- After completing each checklist item in the ' +\n 'ticket, print a line: [x] <item text> ' +\n '(matching the checklist text exactly).',\n agentsMdRule('ticket'),\n '',\n ].join('\\n')\n}\n\nexport function renderMergePrompt (\n specBody:string,\n ticket:Ticket,\n opts:{ installCmd?:string; preferSubagent?:string } = {}\n):string {\n return [\n '---- SPEC CONTEXT ----',\n specBody,\n '',\n '---- TICKET ----',\n ticket.filename,\n ticket.body,\n '',\n '---- AGENT INSTRUCTIONS ----',\n 'You are an autonomous coding agent resolving ' +\n 'a merge conflict.',\n '',\n 'Another agent already implemented this ticket ' +\n 'on a feature branch. The branch was then ' +\n 'merged with the base branch, but conflicts ' +\n 'arose. The working tree may contain conflict ' +\n 'markers that need resolution.',\n '',\n 'Your task:',\n '1. Find and resolve all conflict markers ' +\n '(<<<<<<< / ======= / >>>>>>>).',\n '2. When AGENTS.md or other docs conflict, ' +\n 'keep both sides\\' additions rather than ' +\n 'picking one.',\n '3. Make sure the code compiles and tests pass.',\n '4. Commit the resolved files.',\n '',\n 'Do NOT re-implement the ticket from scratch.',\n ...installRule(opts.installCmd),\n ...subagentRule(opts.preferSubagent),\n 'Do NOT read or modify files outside your ' +\n 'current directory (the worktree).',\n 'Do NOT run git push.',\n ].join('\\n')\n}\n\nfunction listTickets (tickets:ReadonlyArray<Ticket>):void {\n console.log('\\nTickets:')\n for (const t of tickets) {\n const blockerStr = t.blockers.length > 0 ?\n `blocked by [${t.blockers.map(blockerLabel).join(', ')}]` :\n 'no blockers'\n console.log(\n ` ${t.filename} ` +\n `(${t.status}) ${blockerStr}`\n )\n }\n}\n\nfunction * simulateWaves (\n tickets:ReadonlyArray<Ticket>\n):Generator<{ wave:number; ready:Array<Ticket> }> {\n const sim = new Map(\n tickets.map(t => [\n ticketKey(t.feature, t.num),\n t.status,\n ])\n )\n let wave = 1\n while (true) {\n const doneKeys = new Set(\n [...sim.entries()]\n .filter(([, s]) => s === 'done')\n .map(([k]) => k)\n )\n const ready = [...tickets].filter(t => {\n const key = ticketKey(t.feature, t.num)\n if (sim.get(key) !== 'ready-for-agent') {\n return false\n }\n return t.blockers.every(r => blockerSatisfied(r, doneKeys))\n })\n if (ready.length === 0) break\n yield { wave, ready }\n for (const t of ready) {\n sim.set(\n ticketKey(t.feature, t.num),\n 'done'\n )\n }\n wave++\n }\n}\n\nfunction detectDeadlocks (\n tickets:ReadonlyArray<Ticket>\n):Array<Ticket> {\n const doneKeys = new Set<string>()\n const readyKeys = new Set<string>()\n\n for (const t of tickets) {\n const key = ticketKey(t.feature, t.num)\n if (t.status === 'ready-for-agent') {\n readyKeys.add(key)\n } else if (t.status === 'done') {\n doneKeys.add(key)\n }\n }\n\n let changed = true\n while (changed) {\n changed = false\n for (const key of readyKeys) {\n const ticket = tickets.find(t =>\n ticketKey(t.feature, t.num) === key\n )!\n if (ticket.blockers.every(r =>\n blockerSatisfied(r, doneKeys)\n )) {\n doneKeys.add(key)\n readyKeys.delete(key)\n changed = true\n }\n }\n }\n\n return [...readyKeys].map(key =>\n tickets.find(t =>\n ticketKey(t.feature, t.num) === key\n )!\n )\n}\n\nconst PROVIDER_ARGS:Record<string, string[]> = {\n claude:[\n '--print', '--verbose',\n '--output-format', 'stream-json',\n '--dangerously-skip-permissions',\n ],\n // codex removed --full-auto; this is the counterpart\n // of claude's --dangerously-skip-permissions, and the\n // workspace-write sandbox would block commits because\n // a worktree's .git link points outside the tree\n codex:['exec', '--dangerously-bypass-approvals-and-sandbox'],\n pi:[\n '-p', '--verbose',\n '--approve', '--no-session',\n '--mode', 'json',\n ],\n}\n\nexport function getProviderArgs (cmd:string):string[] {\n const name = basename(cmd)\n return PROVIDER_ARGS[name] ?? []\n}\n\nexport function formatStreamLine (\n line:string\n):string|null {\n let value:unknown\n try {\n value = JSON.parse(line)\n } catch {\n return line\n }\n return formatStreamObject(value)\n}\n\n// Renders one parsed claude stream-json message. Values that are\n// not objects (a bare `null` or number line) and fields of the\n// wrong type are ignored rather than thrown on, since one bad line\n// must not crash the run.\nfunction formatStreamObject (value:unknown):string|null {\n if (!isRecord(value)) return null\n const obj = value\n\n if (obj.type === 'assistant') {\n // Subagent output is not the main agent's checklist\n // progress, so it stays out of the ticket log.\n if (obj.parent_tool_use_id != null) return null\n const msg = isRecord(obj.message) ?\n obj.message :\n undefined\n const content = Array.isArray(msg?.content) ?\n msg.content :\n undefined\n if (!content) return null\n for (const block of content) {\n if (!isRecord(block)) continue\n if (block.type !== 'text') continue\n if (typeof block.text === 'string') return block.text\n }\n return null\n }\n\n if (obj.type === 'result') {\n const sub = typeof obj.subtype === 'string' ?\n obj.subtype :\n 'done'\n const cost = typeof obj.total_cost_usd === 'number' ?\n obj.total_cost_usd :\n undefined\n const costStr = cost !== undefined ?\n ` ($${cost.toFixed(2)})` :\n ''\n return `${sub}${costStr}`\n }\n\n if (obj.type === 'system') {\n const sub = typeof obj.subtype === 'string' ?\n obj.subtype :\n undefined\n if (sub === 'api_retry') {\n const error = typeof obj.error === 'string' ?\n obj.error :\n 'unknown'\n return `retry: ${error}`\n }\n }\n\n return null\n}\n\nexport type PiStreamFormatter = {\n process:(line:string) => string[]\n flush:() => string[]\n}\n\nexport function createPiStreamFormatter (\n):PiStreamFormatter {\n const calls = new Map<\n number, { name:string; buf:string }\n >()\n let textBuf = ''\n\n function drainLines ():string[] {\n const parts = textBuf.split('\\n')\n if (parts.length === 1) return []\n textBuf = parts[parts.length - 1]\n return parts.slice(0, -1)\n }\n\n function flushBuf ():string[] {\n if (textBuf.length === 0) return []\n const out = textBuf\n textBuf = ''\n return [out]\n }\n\n function process (line:string):string[] {\n let obj:Record<string, unknown>\n try {\n obj = JSON.parse(line) as\n Record<string, unknown>\n } catch {\n return [line]\n }\n\n const evt = obj.assistantMessageEvent as\n Record<string, unknown>|undefined\n if (!evt) return []\n\n const type = evt.type as string|undefined\n const ci = evt.contentIndex as\n number|undefined ?? -1\n\n if (type === 'text_delta') {\n const delta =\n (evt.delta as string|undefined) ?? ''\n textBuf += delta\n return drainLines()\n }\n\n if (type === 'toolcall_start') {\n const flushed = flushBuf()\n calls.set(ci, {\n name:(evt.toolName as\n string|undefined) ?? '?',\n buf:'',\n })\n return flushed\n }\n\n if (\n type === 'toolcall_delta' &&\n calls.has(ci)\n ) {\n calls.get(ci)!.buf +=\n (evt.delta as string|undefined) ?? ''\n return []\n }\n\n if (\n type === 'toolcall_end' &&\n calls.has(ci)\n ) {\n const call = calls.get(ci)!\n calls.delete(ci)\n let label = ''\n try {\n const args = JSON.parse(call.buf) as\n Record<string, unknown>\n label = String(\n args.command ??\n args.file_path ??\n args.query ?? ''\n ).split('\\n')[0].slice(0, 72)\n } catch {\n // unparseable tool args\n }\n return [`[${call.name}] ${label}`]\n }\n\n return []\n }\n\n return { process, flush:flushBuf }\n}\n\nfunction writePromptFile (prompt:string):string {\n const name = `nightralph-${Date.now()}-` +\n `${Math.random().toString(36).slice(2)}.md`\n const filePath = join(tmpdir(), name)\n writeFileSync(filePath, prompt)\n return filePath\n}\n\nfunction cleanupPromptFile (filePath:string):void {\n try {\n unlinkSync(filePath)\n } catch {\n // already removed\n }\n}\n\nexport type AgentResult = {\n exitCode:number\n completedItems:string[]\n // true when the orchestrator killed the agent at\n // the timeout; exitCode is non-zero in that case\n timedOut:boolean\n // claude only: how many subagents the agent spawned, and the\n // run cost reported by its result message when there is one\n subagents?:number\n costUsd?:number\n}\n\n// How long to wait after the process exits before giving up on a\n// graceful pipe close and forcing the streams shut. A grandchild\n// (dev server, watcher) that inherited the agent's stdout can keep\n// the pipe open after the agent itself has been killed, which would\n// otherwise leave spawnAgent's promise pending forever.\nconst CLOSE_GRACE_MS = 2000\n\n// Agents are spawned with detached:true so they become their own\n// process group leader; this lets us kill the whole tree (agent +\n// any children it spawned, like dev servers) with one signal to\n// -pid instead of leaving orphans behind. Exported for reuse by\n// signal handling (Ctrl-C / SIGTERM).\nexport function killProcessGroup (pid:number|undefined):void {\n if (pid === undefined) return\n try {\n process.kill(-pid, 'SIGKILL')\n } catch {\n // The group kill failed (e.g. the group was already\n // reaped, or the pid is not a group leader). Fall back\n // to killing the process directly so a still-running\n // pid never escapes the kill.\n try {\n process.kill(pid, 'SIGKILL')\n } catch {\n // Process is already gone.\n }\n }\n}\n\n// Tracks every agent process spawnAgent currently has running, so\n// a Ctrl-C or SIGTERM to the orchestrator itself can kill them all\n// instead of leaving them running after the orchestrator exits.\nconst runningAgents = new Set<number>()\n\nexport function killRunningAgents ():number {\n let killed = 0\n for (const pid of runningAgents) {\n killProcessGroup(pid)\n killed++\n }\n return killed\n}\n\nexport function spawnAgent (opts:{\n prompt:string\n agentCmd:string\n model:string|null\n timeout:number\n logPath:string\n cwd?:string\n label?:string\n maxTurns?:number\n effort?:EffortLevel\n onLine?:(line:string) => void\n // claude only: sets CLAUDE_CODE_SUBAGENT_MODEL for the agent\n preferSubagent?:string\n // claude only: called each time the subagent stats change\n onStats?:(stats:SubagentStats) => void\n}):Promise<AgentResult> {\n const args:string[] = [\n ...getProviderArgs(opts.agentCmd),\n ]\n if (opts.model) {\n args.push('--model', opts.model)\n }\n const providerName = basename(opts.agentCmd)\n const isClaude = providerName === 'claude'\n const isPi = providerName === 'pi'\n\n if (opts.maxTurns) {\n if (isClaude) {\n args.push(\n '--max-turns',\n String(opts.maxTurns)\n )\n } else if (opts.onLine) {\n opts.onLine(\n 'Warning: --max-turns not ' +\n `supported by ${providerName}, ` +\n 'skipping'\n )\n }\n }\n if (opts.effort && providerName in EFFORT_LADDERS) {\n const ladder = EFFORT_LADDERS[\n providerName as ProviderName\n ]\n if (\n !(ladder as readonly string[])\n .includes(opts.effort)\n ) {\n if (opts.onLine) {\n opts.onLine(\n 'Warning: effort ' +\n `'${opts.effort}' not ` +\n 'supported by ' +\n `${providerName}, skipping`\n )\n }\n } else if (isPi) {\n args.push('--thinking', opts.effort)\n } else if (isClaude) {\n args.push('--effort', opts.effort)\n } else if (providerName === 'codex') {\n args.push(\n '-c',\n `model_reasoning_effort=${opts.effort}`\n )\n }\n }\n const prefix = opts.label ?\n ` [${opts.label}] ` :\n ' '\n\n let promptFile:string|null = null\n if (isPi) {\n promptFile = writePromptFile(opts.prompt)\n args.push(`@${promptFile}`)\n }\n\n const logStream = createWriteStream(\n opts.logPath,\n { flags:'w' }\n )\n // The subagent model is a default: CLAUDE_CODE_SUBAGENT_MODEL_FORCE\n // is never set, so a model the user exported still wins when the\n // option is absent.\n const env = isClaude && opts.preferSubagent ?\n {\n ...process.env,\n CLAUDE_CODE_SUBAGENT_MODEL:opts.preferSubagent,\n } :\n undefined\n const proc = spawn(opts.agentCmd, args, {\n stdio:['pipe', 'pipe', 'pipe'],\n cwd:opts.cwd,\n detached:true,\n ...(env ? { env } : {}),\n })\n\n if (proc.pid !== undefined) runningAgents.add(proc.pid)\n\n // stdout and stderr share one log, so neither pipe may end\n // it: the first to reach EOF would end the log while the\n // other still has data, which drops that output or crashes\n // the run with ERR_STREAM_WRITE_AFTER_END. finish() ends it.\n proc.stdout.pipe(logStream, { end:false })\n\n const piFormatter = isPi ?\n createPiStreamFormatter() :\n null\n\n const completedItems:string[] = []\n const seenItems = new Set<string>()\n\n function collectCompleted (text:string):void {\n // Reported items arrive as one multi-line text block\n // (claude), as drained single lines (pi), or as raw\n // lines (other providers); matching per line covers all\n // three, including summaries with several [x] lines.\n for (const line of text.split('\\n')) {\n const match = line.match(COMPLETED_RE)\n if (!match) continue\n const item = match[1].trim()\n if (!item || seenItems.has(item)) continue\n seenItems.add(item)\n completedItems.push(item)\n }\n }\n\n let streamStats = emptyStreamStats()\n\n // Formats one claude stream-json line and tracks subagent stats.\n // The stats are read from the raw object, so subagent text is\n // formatted away but still counted.\n function formatClaudeLine (line:string):string|null {\n let obj:unknown\n try {\n obj = JSON.parse(line)\n } catch {\n return line\n }\n const next = nextStreamStats(streamStats, obj)\n if (next !== streamStats) {\n streamStats = next\n opts.onStats?.(next.stats)\n }\n return formatStreamObject(obj)\n }\n\n const rl = createInterface({ input:proc.stdout })\n rl.on('line', line => {\n if (isClaude) {\n const formatted = formatClaudeLine(line)\n if (formatted !== null) {\n collectCompleted(formatted)\n const output = `${prefix}${formatted}`\n if (opts.onLine) {\n opts.onLine(output)\n } else {\n console.log(output)\n }\n }\n } else if (piFormatter) {\n const lines = piFormatter.process(line)\n for (const formatted of lines) {\n collectCompleted(formatted)\n const output = `${prefix}${formatted}`\n if (opts.onLine) {\n opts.onLine(output)\n } else {\n console.log(output)\n }\n }\n } else {\n collectCompleted(line)\n const output = `${prefix}${line}`\n if (opts.onLine) {\n opts.onLine(output)\n } else {\n console.log(output)\n }\n }\n })\n\n proc.stderr.pipe(logStream, { end:false })\n const rlErr = createInterface({ input:proc.stderr })\n rlErr.on('line', line => {\n if (isClaude && !TOOL_USE_RE.test(line)) return\n const output = `${prefix}${line}`\n if (opts.onLine) {\n opts.onLine(output)\n } else {\n console.error(output)\n }\n })\n\n let timedOut = false\n const timeout = setTimeout(() => {\n if (proc.killed) return\n timedOut = true\n const msg = 'agent timed out after ' +\n `${opts.timeout}s; killing it`\n // The status display repaints the screen, so a\n // bare console.warn would be painted over. Route\n // the reason through onLine and into the ticket\n // log so it is visible in both places.\n logStream.write(`nightralph: ${msg}\\n`)\n if (opts.onLine) {\n opts.onLine(`${prefix}${msg}`)\n } else {\n console.warn(`${prefix}${msg}`)\n }\n killProcessGroup(proc.pid)\n }, opts.timeout * 1000)\n\n // An agent that exits before draining stdin (bad flags,\n // auth failure) closes its end of the pipe; writing to it\n // then raises EPIPE on proc.stdin. Without a listener that\n // is an uncaught 'error' event that kills the orchestrator.\n proc.stdin.on('error', err => {\n logStream.write(\n 'nightralph: stdin write failed: ' +\n `${formatErrorMessage(err)}\\n`\n )\n })\n\n if (!promptFile) {\n proc.stdin.write(opts.prompt)\n }\n proc.stdin.end()\n\n return new Promise<AgentResult>(resolve => {\n let settled = false\n let graceTimer:ReturnType<typeof setTimeout>|undefined\n\n function finish (exitCode:number):void {\n if (settled) return\n settled = true\n clearTimeout(timeout)\n if (graceTimer) clearTimeout(graceTimer)\n if (proc.pid !== undefined) {\n runningAgents.delete(proc.pid)\n }\n if (piFormatter) {\n for (const line of piFormatter.flush()) {\n collectCompleted(line)\n const output = `${prefix}${line}`\n if (opts.onLine) {\n opts.onLine(output)\n } else {\n console.log(output)\n }\n }\n }\n rl.close()\n rlErr.close()\n logStream.end()\n if (promptFile) cleanupPromptFile(promptFile)\n resolve({\n exitCode,\n completedItems,\n timedOut,\n ...(isClaude ? streamStats.stats : {}),\n })\n }\n\n // The process itself has exited, but 'close' waits for its\n // stdio streams to close too -- a grandchild that inherited\n // stdout/stderr can hold those pipes open indefinitely. Give\n // it a grace period, then destroy the streams ourselves so\n // the run does not hang forever on someone else's fd.\n proc.on('exit', code => {\n graceTimer = setTimeout(() => {\n killProcessGroup(proc.pid)\n proc.stdout.destroy()\n proc.stderr.destroy()\n finish(code ?? 1)\n }, CLOSE_GRACE_MS)\n })\n\n proc.on('close', code => {\n finish(code ?? 1)\n })\n proc.on('error', err => {\n if (settled) return\n settled = true\n if (graceTimer) clearTimeout(graceTimer)\n clearTimeout(timeout)\n if (proc.pid !== undefined) {\n runningAgents.delete(proc.pid)\n }\n rl.close()\n rlErr.close()\n const msg = 'agent process error: ' +\n formatErrorMessage(err)\n logStream.write(`nightralph: ${msg}\\n`)\n if (promptFile) cleanupPromptFile(promptFile)\n if (opts.onLine) {\n opts.onLine(`${prefix}${msg}`)\n } else {\n console.error(`${prefix}${msg}`)\n }\n // Resolve only once the log is flushed, so a caller\n // that reads the log right away sees the message.\n logStream.end(() => {\n resolve({\n exitCode:1,\n completedItems,\n timedOut,\n })\n })\n })\n })\n}\n\nexport function dryRun (\n tickets:Array<Ticket>,\n specBody:string,\n testCmd:string,\n preferSubagent?:string\n):void {\n listTickets(tickets)\n\n console.log('\\nSimulated wave order:')\n for (const { wave, ready } of simulateWaves(tickets)) {\n console.log(\n ` Wave ${wave}: ` +\n ready.map(t => t.filename).join(', ')\n )\n }\n\n const stuck = detectDeadlocks(tickets)\n if (stuck.length > 0) {\n console.log(\n '\\nDeadlocked tickets: ' +\n stuck.map(t => t.filename).join(', ')\n )\n }\n\n console.log(`\\nTest command: ${testCmd || '(none)'}`)\n console.log(`Prefer subagent: ${preferSubagent || '(none)'}`)\n\n const firstReady = findReadyTickets(tickets)\n if (firstReady.length > 0) {\n console.log(\n '\\nPrompt for first ready ticket ' +\n `(${firstReady[0].filename}):\\n`\n )\n console.log(\n renderPrompt(specBody, firstReady[0],\n { testCmd, preferSubagent })\n )\n }\n}\n\nexport function dryRunIsolated (opts:{\n tickets:Array<Ticket>\n specBody:string\n repoName:string\n conflictStrategy:MergeConflictStrategy\n progressPath:string\n testCmd:string\n installCmd?:string\n effort?:EffortLevel\n retries?:number\n retryDelay?:number\n concurrency?:number\n // claude only: model for subagents; unset = off\n preferSubagent?:string\n}):void {\n listTickets(opts.tickets)\n\n console.log('\\nSimulated wave order:')\n for (const { wave, ready } of simulateWaves(\n opts.tickets\n )) {\n console.log(\n ` Wave ${wave}: ` +\n ready.map(t => t.filename).join(', ')\n )\n for (const t of ready) {\n const num = String(t.num).padStart(2, '0')\n const branchName = buildBranchName(\n opts.repoName, t\n )\n const prefix = t.feature ?\n `${t.feature}.` : ''\n const worktreePath =\n `../${opts.repoName}.${prefix}${num}-${t.slug}`\n console.log(` worktree: ${worktreePath}`)\n console.log(` branch: ${branchName}`)\n }\n }\n\n const stuck = detectDeadlocks(opts.tickets)\n if (stuck.length > 0) {\n console.log(\n '\\nDeadlocked tickets: ' +\n stuck.map(t => t.filename).join(', ')\n )\n }\n\n const firstReady = findReadyTickets(opts.tickets)\n if (firstReady.length > 0) {\n console.log(\n '\\nPrompt for first ready ticket ' +\n `(${firstReady[0].filename}):\\n`\n )\n console.log(\n renderPrompt(\n opts.specBody, firstReady[0],\n {\n testCmd:opts.testCmd,\n installCmd:opts.installCmd,\n preferSubagent:opts.preferSubagent,\n }\n )\n )\n }\n\n const strategyDesc =\n opts.conflictStrategy === 'respawn' ?\n 'respawn (re-run agent on conflict)' :\n 'stop (stop merging on conflict)'\n console.log(\n `\\nTest command: ${opts.testCmd || '(none)'}`\n )\n console.log(\n `Install: ${opts.installCmd || '(none)'}`\n )\n console.log(\n `Effort: ${opts.effort ?? '(provider default)'}`\n )\n console.log(\n `Prefer subagent: ${opts.preferSubagent || '(none)'}`\n )\n console.log(\n `Retries: ${opts.retries ?? DEFAULT_RETRIES}`\n )\n console.log(\n 'Retry delay: ' +\n `${opts.retryDelay ?? 0}s`\n )\n console.log(\n 'Concurrency: ' +\n `${opts.concurrency ?? DEFAULT_CONCURRENCY}`\n )\n console.log(\n `\\nMerge strategy: ${strategyDesc}`\n )\n console.log(`Progress file: ${opts.progressPath}`)\n}\n\n// Installs dependencies in a ticket's worktree before an\n// agent runs there. Writes the output to a per-ticket log\n// either way, and returns true only when the install exits 0.\nasync function runInstall (opts:{\n installCmd:string\n ticket:Ticket\n worktreePath:string\n timeout:number\n logsDir:string\n attempt?:number\n log:(msg:string) => void\n registry?:Set<number>\n}):Promise<boolean> {\n const result = await runTestCmd({\n cmd:opts.installCmd,\n cwd:opts.worktreePath,\n timeout:opts.timeout,\n registry:opts.registry,\n })\n const installLogPath = attemptLogPath(\n opts.logsDir, opts.ticket, opts.attempt ?? 1,\n '.install.log'\n )\n writeFileSync(installLogPath, result.output)\n\n if (result.exitCode !== 0) {\n opts.log(\n ` ${opts.ticket.filename}: install failed ` +\n `(exit ${result.exitCode}); ` +\n `see ${installLogPath}`\n )\n return false\n }\n return true\n}\n\n// Runs the project's test command in a ticket's worktree,\n// writes the output to a per-ticket log, and returns true\n// only when the suite is green. A testCmd of '' is no gate:\n// nothing runs, no log is written, and it returns true.\nasync function runTestGate (opts:{\n testCmd:string\n ticket:Ticket\n worktreePath:string\n timeout:number\n logsDir:string\n attempt?:number\n log:(msg:string) => void\n registry?:Set<number>\n}):Promise<boolean> {\n if (opts.testCmd === '') {\n opts.log(` ${opts.ticket.filename}: no test gate`)\n return true\n }\n const result = await runTestCmd({\n cmd:opts.testCmd,\n cwd:opts.worktreePath,\n timeout:opts.timeout,\n registry:opts.registry,\n })\n const testLogPath = attemptLogPath(\n opts.logsDir, opts.ticket, opts.attempt ?? 1,\n '.test.log'\n )\n writeFileSync(testLogPath, result.output)\n\n if (result.exitCode !== 0) {\n opts.log(\n ` ${opts.ticket.filename}: tests failed ` +\n `(exit ${result.exitCode}); ` +\n `see ${testLogPath}`\n )\n return false\n }\n\n opts.log(` ${opts.ticket.filename}: tests passed`)\n return true\n}\n\n// Re-runs the agent in a ticket's existing worktree\n// after a merge conflict, then retries the merge once.\n// Called at most once per ticket per wave.\nasync function respawnAndRetryMerge (opts:{\n repoRoot:string\n baseBranch:string\n branch:string\n ticket:Ticket\n worktreePath:string\n specBody:string\n agentCmd:string\n model:string|null\n timeout:number\n logsDir:string\n testCmd:string\n installCmd?:string\n maxTurns?:number\n // claude only: model for subagents; unset = off\n preferSubagent?:string\n onLine?:(msg:string) => void\n // called with every agent result, for the run's stats tally\n onAgentRun?:(result:AgentResult) => void\n}):Promise<boolean> {\n const log = (msg:string):void => {\n if (opts.onLine) {\n opts.onLine(msg)\n } else {\n console.log(msg)\n }\n }\n\n await updateWorktreeFromBase(\n opts.worktreePath, opts.baseBranch\n )\n\n const msg1 = ` ${opts.ticket.filename}: respawning agent ` +\n 'to resolve merge conflict'\n if (opts.onLine) {\n opts.onLine(msg1)\n } else {\n console.log(msg1)\n }\n\n // The base branch may have changed the dependencies.\n if (opts.installCmd) {\n const installed = await runInstall({\n installCmd:opts.installCmd,\n ticket:opts.ticket,\n worktreePath:opts.worktreePath,\n timeout:opts.timeout,\n logsDir:opts.logsDir,\n log,\n registry:runningAgents,\n })\n if (!installed) return false\n }\n\n const prompt = renderMergePrompt(\n opts.specBody, opts.ticket,\n {\n installCmd:opts.installCmd,\n preferSubagent:opts.preferSubagent,\n }\n )\n const logPath = join(\n opts.logsDir,\n opts.ticket.filename.replace(/\\.md$/, '.respawn.log')\n )\n const label = opts.ticket.filename.replace(\n /\\.md$/, ''\n )\n const result = await spawnAgent({\n prompt,\n agentCmd:opts.agentCmd,\n model:opts.model,\n timeout:opts.timeout,\n logPath,\n cwd:opts.worktreePath,\n label,\n maxTurns:opts.maxTurns,\n preferSubagent:opts.preferSubagent,\n onLine:opts.onLine,\n })\n opts.onAgentRun?.(result)\n\n if (result.exitCode !== 0) {\n const msg2 = ` ${opts.ticket.filename}: respawned agent ` +\n `exited ${result.exitCode}`\n if (opts.onLine) {\n opts.onLine(msg2)\n } else {\n console.log(msg2)\n }\n return false\n }\n\n const passed = await runTestGate({\n testCmd:opts.testCmd,\n ticket:opts.ticket,\n worktreePath:opts.worktreePath,\n timeout:opts.timeout,\n logsDir:opts.logsDir,\n log,\n registry:runningAgents,\n })\n if (!passed) {\n log(\n ` ${opts.ticket.filename}: tests failed ` +\n 'after conflict respawn; not merging'\n )\n return false\n }\n\n const mergeResult = await mergeBranch(\n opts.repoRoot, opts.branch\n )\n if (!mergeResult.success) {\n const msg3 = ` ${opts.ticket.filename}: merge still ` +\n 'conflicted after respawn'\n if (opts.onLine) {\n opts.onLine(msg3)\n } else {\n console.log(msg3)\n }\n if (mergeResult.stderr) {\n const stderrMsg =\n ` git: ${mergeResult.stderr.trim()}`\n if (opts.onLine) {\n opts.onLine(stderrMsg)\n } else {\n console.log(stderrMsg)\n }\n }\n }\n return mergeResult.success\n}\n\nexport const DEFAULT_RETRIES = 3\n\n// Seconds to wait before the first retry; each later retry\n// doubles the wait so a provider outage is waited out instead\n// of burning every attempt back to back.\nexport const DEFAULT_RETRY_DELAY = 30\n\n// Max agents running at the same time within a wave.\nexport const DEFAULT_CONCURRENCY = 5\n\n// Runs `fn` over `items`, at most `limit` at a time, and\n// resolves with the results in item order. Each call is\n// settled individually so one rejection does not stop\n// the others.\nexport async function runPool<T, R> (\n items:T[],\n limit:number,\n fn:(item:T) => Promise<R>,\n):Promise<PromiseSettledResult<R>[]> {\n const size = Math.max(1, Math.floor(limit))\n const results:PromiseSettledResult<R>[] = new Array(\n items.length\n )\n let next = 0\n async function worker ():Promise<void> {\n while (next < items.length) {\n const i = next++\n try {\n results[i] = {\n status:'fulfilled',\n value:await fn(items[i]),\n }\n } catch (reason) {\n results[i] = { status:'rejected', reason }\n }\n }\n }\n const workers = Array.from(\n { length:Math.min(size, items.length) },\n () => worker()\n )\n await Promise.all(workers)\n return results\n}\n\n// Log file for one attempt: the first attempt keeps the\n// plain name so existing tooling still finds it, later\n// attempts get their own file instead of overwriting it.\nfunction attemptLogPath (\n logsDir:string,\n ticket:Ticket,\n attempt:number,\n ext:string\n):string {\n const stem = ticket.filename.replace(/\\.md$/, '')\n const suffix = attempt > 1 ? `.attempt${attempt}` : ''\n return join(logsDir, `${stem}${suffix}${ext}`)\n}\n\ntype TicketOutcome =\n | { kind:'worktree-error'; error:unknown }\n | {\n kind:'error'\n error:unknown\n worktreePath?:string\n branchName?:string\n }\n | {\n kind:'no-commits'\n worktreePath:string\n branchName:string\n agentRun:AgentRunRecord\n }\n | {\n // No agent ran, so there is no agent record\n kind:'failed'\n reason:'install'\n branchName:string\n exitCode:number\n completedItems:string[]\n }\n | {\n kind:'failed'\n reason:'exit'|'tests'\n branchName:string\n // A placeholder 1 for 'tests'; the agent's real exit\n // code is agentRun.exitCode\n exitCode:number\n completedItems:string[]\n agentRun:AgentRunRecord\n }\n | {\n kind:'ready'\n worktreePath:string\n branchName:string\n completedItems:string[]\n agentRun:AgentRunRecord\n }\n\ntype TicketAttemptOpts = {\n ticket:Ticket\n repoRoot:string\n repoName:string\n baseBranch:string\n specBody:string\n specBodies?:Map<string, string>\n agentCmd:string\n model:string|null\n timeout:number\n logsDir:string\n testCmd:string\n installCmd?:string\n maxTurns?:number\n effort?:EffortLevel\n // claude only: model for subagents; unset = off\n preferSubagent?:string\n learningsPath:string\n d:Display\n // called with every agent result, for the run's stats tally\n onAgentRun?:(result:AgentResult) => void\n}\n\n/**\n * The ticket's own earlier attempts and its direct blockers' last\n * successful runs, rendered for the prompt. A blocker in another\n * feature is read from that feature's learnings.md, under the same\n * .scratch dir as this ticket's feature. Throws when a log cannot\n * be read.\n */\nexport function historyFor (\n learningsPath:string,\n ticket:Ticket\n):string {\n // <scratch>/<feature>/issues/<file>.md; a nested feature name\n // (a/b) is several dirs deep, so climb one level per segment.\n const featureDir = dirname(dirname(ticket.filepath))\n const scratchDir = ticket.feature ?\n join(featureDir, ...ticket.feature.split('/').map(() => '..')) :\n dirname(featureDir)\n const others = new Set(\n ticket.blockers\n .map(r => r.feature)\n .filter(f => f !== ticket.feature)\n )\n const entries = [\n ...readEntries(learningsPath),\n ...[...others].flatMap(f => readEntries(\n join(scratchDir, f, 'learnings.md')\n )),\n ]\n return renderHistory(selectHistory(entries, {\n key:ticketKey(ticket.feature, ticket.num),\n blockerKeys:ticket.blockers.map(r => {\n return ticketKey(r.feature, r.num)\n }),\n }))\n}\n\n// Learnings are advisory, so an unreadable log means no history,\n// not a failure.\nfunction buildHistory (\n learningsPath:string,\n ticket:Ticket,\n d:Display\n):string {\n try {\n return historyFor(learningsPath, ticket)\n } catch (err) {\n d.log(\n ` ${ticket.filename}: could not read ` +\n `learnings: ${formatErrorMessage(err)}`\n )\n return ''\n }\n}\n\n// One attempt at a ticket: a fresh worktree, one agent run,\n// and the checks that decide whether the branch can merge.\n// A failed attempt removes its worktree before returning.\nasync function runTicketAttempt (\n opts:TicketAttemptOpts&{\n attempt:number\n // live stats from this attempt's agent, as they change\n onStats?:(stats:SubagentStats) => void\n }\n):Promise<TicketOutcome> {\n const { ticket, d } = opts\n\n let worktree:{ worktreePath:string; branchName:string }\n try {\n worktree = await createWorktree({\n repoRoot:opts.repoRoot,\n repoName:opts.repoName,\n baseBranch:opts.baseBranch,\n ticket,\n })\n } catch (error) {\n return { kind:'worktree-error', error }\n }\n\n d.setTicketStatus(\n ticket.num, 'in-progress', ticket.feature\n )\n if (opts.installCmd) {\n const installed = await runInstall({\n installCmd:opts.installCmd,\n ticket,\n worktreePath:worktree.worktreePath,\n timeout:opts.timeout,\n logsDir:opts.logsDir,\n attempt:opts.attempt,\n log:(msg) => d.log(msg),\n registry:runningAgents,\n })\n if (!installed) {\n await removeWorktreeQuietly(\n worktree.worktreePath, d\n )\n return {\n kind:'failed',\n reason:'install',\n branchName:worktree.branchName,\n exitCode:1,\n completedItems:[],\n }\n }\n }\n\n // Keeps the agent's notes out of any `git add -A`.\n try {\n ensureNotesIgnored(worktree.worktreePath)\n } catch (err) {\n d.log(\n ` ${ticket.filename}: could not set up the notes ` +\n `directory: ${formatErrorMessage(err)}`\n )\n }\n\n const ticketSpec = lookupSpec(\n opts.specBodies, opts.specBody, ticket.feature\n )\n const agentResult = await spawnAgent({\n prompt:renderPrompt(\n ticketSpec, ticket,\n {\n testCmd:opts.testCmd,\n installCmd:opts.installCmd,\n // Rebuilt every attempt, so a retry sees the\n // entry its previous attempt just wrote\n history:buildHistory(\n opts.learningsPath, ticket, d\n ),\n preferSubagent:opts.preferSubagent,\n }\n ),\n agentCmd:opts.agentCmd,\n model:opts.model,\n timeout:opts.timeout,\n logPath:attemptLogPath(\n opts.logsDir, ticket, opts.attempt, '.log'\n ),\n cwd:worktree.worktreePath,\n label:ticket.filename.replace(/\\.md$/, ''),\n maxTurns:opts.maxTurns,\n effort:opts.effort,\n preferSubagent:opts.preferSubagent,\n onStats:opts.onStats,\n onLine:(line) => d.log(line),\n })\n opts.onAgentRun?.(agentResult)\n\n // Collect before anything commits or removes the worktree,\n // so the notes never reach the timeout auto-commit.\n let notes:string|null = null\n try {\n notes = collectNotes(worktree.worktreePath)\n } catch (err) {\n d.log(\n ` ${ticket.filename}: could not collect ` +\n `notes: ${formatErrorMessage(err)}`\n )\n }\n const agentRun:AgentRunRecord = {\n exitCode:agentResult.exitCode,\n completedItems:agentResult.completedItems,\n timedOut:agentResult.timedOut,\n notes,\n ...(agentResult.subagents === undefined ?\n {} :\n { subagents:agentResult.subagents }),\n ...(agentResult.costUsd === undefined ?\n {} :\n { costUsd:agentResult.costUsd }),\n }\n\n // A timeout kill is not the agent reporting failure.\n // Keep whatever it committed and let the test gate and\n // merge decide, instead of discarding the worktree.\n if (agentResult.timedOut) {\n d.log(\n ` ${ticket.filename}: timed out; ` +\n 'keeping the work it committed'\n )\n } else if (agentResult.exitCode !== 0) {\n d.log(\n ` ${ticket.filename}: ` +\n `agent exited ${agentResult.exitCode}`\n )\n await removeWorktreeQuietly(worktree.worktreePath, d)\n return {\n kind:'failed',\n reason:'exit',\n branchName:worktree.branchName,\n exitCode:agentResult.exitCode,\n completedItems:agentResult.completedItems,\n agentRun,\n }\n }\n\n if (isDirty(worktree.worktreePath)) {\n const committed = await commitDirty(\n worktree.worktreePath,\n 'nightralph: auto-commit ' +\n `${ticket.filename} remaining changes`\n )\n if (committed) {\n d.log(\n ` ${ticket.filename}: ` +\n 'auto-committed remaining changes'\n )\n }\n }\n\n if (!hasNewCommits(\n opts.repoRoot, opts.baseBranch, worktree.branchName\n )) {\n await removeWorktreeQuietly(worktree.worktreePath, d)\n return {\n kind:'no-commits',\n worktreePath:worktree.worktreePath,\n branchName:worktree.branchName,\n agentRun,\n }\n }\n\n const passed = await runTestGate({\n testCmd:opts.testCmd,\n ticket,\n worktreePath:worktree.worktreePath,\n timeout:opts.timeout,\n logsDir:opts.logsDir,\n attempt:opts.attempt,\n log:(msg) => d.log(msg),\n registry:runningAgents,\n })\n if (!passed) {\n await removeWorktreeQuietly(\n worktree.worktreePath, d\n )\n return {\n kind:'failed',\n reason:'tests',\n branchName:worktree.branchName,\n exitCode:1,\n completedItems:agentResult.completedItems,\n agentRun,\n }\n }\n\n return {\n kind:'ready',\n worktreePath:worktree.worktreePath,\n branchName:worktree.branchName,\n completedItems:agentResult.completedItems,\n agentRun,\n }\n}\n\n// The last lines of a log for a learnings entry; a missing or\n// unreadable log gives an empty tail.\nfunction readLogTail (path:string):string {\n try {\n return tailLines(readFileSync(path, 'utf8'), LOG_TAIL_LINES)\n } catch {\n return ''\n }\n}\n\n// Maps one attempt's outcome to a learnings entry, or null when\n// there is nothing to record. The exit code always comes from the\n// agent record, never the outcome's top-level `exitCode`, which is\n// a progress.md placeholder.\nfunction attemptEntry (opts:{\n logsDir:string\n ticket:Ticket\n attempt:number\n effort?:EffortLevel\n outcome:TicketOutcome\n}):EntryInput|null {\n const { logsDir, ticket, attempt, effort, outcome } = opts\n const base = {\n key:ticketKey(ticket.feature, ticket.num),\n label:ticketLabel(ticket),\n attempt,\n now:new Date(),\n }\n const logFor = (ext:string) => {\n const path = attemptLogPath(logsDir, ticket, attempt, ext)\n return { logName:basename(path), logTail:readLogTail(path) }\n }\n\n switch (outcome.kind) {\n case 'ready':\n return {\n ...base,\n outcome:'done',\n run:outcome.agentRun,\n effort,\n }\n case 'failed':\n switch (outcome.reason) {\n case 'exit':\n return {\n ...base,\n outcome:'exit',\n run:outcome.agentRun,\n effort,\n }\n case 'tests':\n return {\n ...base,\n outcome:'tests',\n run:outcome.agentRun,\n effort,\n ...logFor('.test.log'),\n }\n case 'install':\n return {\n ...base,\n outcome:'install',\n ...logFor('.install.log'),\n }\n default: {\n const _exhaustive:never = outcome\n return _exhaustive\n }\n }\n case 'no-commits':\n return {\n ...base,\n outcome:'no-commits',\n run:outcome.agentRun,\n effort,\n }\n case 'error':\n case 'worktree-error':\n return {\n ...base,\n outcome:'error',\n error:formatErrorMessage(outcome.error),\n }\n default: {\n const _exhaustive:never = outcome\n return _exhaustive\n }\n }\n}\n\n// Appends one attempt's entry to the learnings log. Learnings are\n// advisory: a failure is reported and never fails the ticket.\nfunction recordAttempt (opts:{\n learningsPath:string\n logsDir:string\n ticket:Ticket\n attempt:number\n effort?:EffortLevel\n outcome:TicketOutcome\n d:Display\n}):void {\n try {\n const entry = attemptEntry(opts)\n if (!entry) return\n appendEntry(opts.learningsPath, renderEntry(entry))\n } catch (err) {\n opts.d.log(\n ` ${opts.ticket.filename}: could not record ` +\n `learnings: ${formatErrorMessage(err)}`\n )\n }\n}\n\n// Runs a ticket until an attempt is ready to merge or the\n// retry cap is hit. Each retry starts from a fresh worktree\n// and a higher effort level.\nasync function runTicketAttempts (\n opts:TicketAttemptOpts&{ retries:number; retryDelay:number }\n):Promise<TicketOutcome> {\n const { ticket, d } = opts\n // The row shows every attempt's subagents and cost so far.\n let prior:SubagentStats = { subagents:0 }\n const showStats = (stats:SubagentStats):void => {\n d.setTicketStats(ticket.num, ticket.feature, stats)\n }\n return runWithRetries<TicketOutcome>({\n maxAttempts:opts.retries + 1,\n retryDelay:opts.retryDelay,\n agentCmd:opts.agentCmd,\n effort:opts.effort,\n label:ticket.filename,\n log:(msg) => d.log(msg),\n }, async (attempt, effort) => {\n const record = (o:TicketOutcome):void => {\n recordAttempt({\n learningsPath:opts.learningsPath,\n logsDir:opts.logsDir,\n ticket,\n attempt,\n effort,\n outcome:o,\n d,\n })\n }\n let outcome:TicketOutcome\n try {\n outcome = await runTicketAttempt({\n ...opts,\n attempt,\n effort,\n onStats:stats => showStats(addStats(prior, stats)),\n onAgentRun:result => {\n prior = addStats(prior, result)\n opts.onAgentRun?.(result)\n },\n })\n } catch (error) {\n d.log(\n ` ${ticket.filename}: attempt ${attempt} ` +\n `threw: ${formatErrorMessage(error)}`\n )\n const errorOutcome:TicketOutcome = { kind:'error', error }\n record(errorOutcome)\n return { result:errorOutcome, stop:true }\n }\n record(outcome)\n if (outcome.kind === 'ready') {\n // The agent is no longer running, but the branch is\n // only merged once the whole wave has finished.\n d.setTicketStatus(\n ticket.num, 'awaiting-merge',\n ticket.feature,\n )\n return { result:outcome, stop:true }\n }\n return {\n result:outcome,\n stop:outcome.kind === 'worktree-error',\n }\n })\n}\n\nfunction failureNote (reason:'exit'|'tests'|'install'):string {\n if (reason === 'tests') return 'tests failed'\n if (reason === 'install') return 'install failed'\n return 'failed'\n}\n\n// A path that git can stage as a file: a directory or other bad\n// path must not make `git add` fail and take a commit down with it.\nfunction isRegularFile (path:string):boolean {\n try {\n return statSync(path).isFile()\n } catch {\n return false\n }\n}\n\n// Wraps writeProgress + commitProgress so callers do not each\n// need to guard against a commit failure (e.g. a git lock held\n// by a concurrent process) crashing the run.\nasync function saveProgress (\n repoRoot:string,\n progressPath:string,\n progress:ProgressData,\n message:string,\n d:Display\n):Promise<void> {\n writeProgress(progressPath, progress)\n const learningsPath = learningsPathFor(progressPath)\n const paths = isRegularFile(learningsPath) ?\n [progressPath, learningsPath] :\n progressPath\n try {\n await commitProgress(repoRoot, paths, message)\n } catch (err) {\n d.log(\n ' Failed to commit progress: ' +\n formatErrorMessage(err)\n )\n }\n}\n\nexport const HUMAN_STATUS = 'ready-for-human'\n\nfunction indentFilenames (tickets:ReadonlyArray<Ticket>):string {\n return tickets.map(t => ` ${t.filename}`).join('\\n')\n}\n\n/**\n * The paragraphs that explain why open tickets did not run, each\n * preceded by a blank line: ready-for-human tickets and what they\n * block, then tickets waiting on blockers outside the run, blocker\n * refs that match no ticket, and likely feature-name typos. A\n * ticket counts as blocked by human or outside work when it waits\n * on it directly or through other in-run tickets.\n * Returns [] when there is nothing to explain.\n */\nfunction explainOpen (\n tickets:ReadonlyArray<Ticket>,\n failedKeys:ReadonlySet<string>,\n warnings:ReadonlyArray<BlockerWarning>,\n):string[] {\n const remaining = tickets.filter(\n t => t.status === 'ready-for-agent'\n )\n const open = remaining.filter(\n t => !failedKeys.has(ticketKey(t.feature, t.num))\n )\n // Dead refs upstream of each open ticket, through chains of\n // in-run tickets, so A waiting on B waiting on a human ticket\n // is listed too, not only B.\n const dead = findBlockedTickets(tickets, failedKeys)\n const deadRefs = (t:Ticket) => (\n dead.get(ticketKey(t.feature, t.num)) ?? []\n )\n const lines:string[] = []\n\n const human = tickets.filter(t => t.status === HUMAN_STATUS)\n if (human.length > 0) {\n const humanKeys = new Set(\n human.map(t => ticketKey(t.feature, t.num))\n )\n const blockedByHuman = open.filter(t => deadRefs(t).some(\n r => humanKeys.has(ticketKey(r.feature, r.num))\n ))\n const noun = human.length === 1 ?\n 'ticket is' :\n 'tickets are'\n lines.push(\n '',\n (remaining.length === 0 && failedKeys.size === 0 ?\n `All remaining ${noun} marked ${HUMAN_STATUS}. ` :\n `${human.length} ${noun} marked ${HUMAN_STATUS}. `) +\n 'nightralph only runs ready-for-agent tickets, ' +\n 'so an agent cannot finish these:',\n indentFilenames(human),\n )\n if (blockedByHuman.length > 0) {\n const n = blockedByHuman.length\n lines.push(\n `${n} ready-for-agent ticket` +\n `${n === 1 ? ' is' : 's are'} ` +\n 'blocked until they are done:',\n indentFilenames(blockedByHuman),\n )\n }\n lines.push(\n 'Do that work by hand, then set each ticket\\'s ' +\n '**Status:** to done' +\n (blockedByHuman.length > 0 ?\n ' and run nightralph again.' :\n '.')\n )\n }\n\n const blockers:string[] = []\n const outside = open.filter(\n t => deadRefs(t).some(r => r.where === 'pending')\n )\n if (outside.length > 0) {\n const n = outside.length\n blockers.push(\n `${n} ready-for-agent ticket` +\n `${n === 1 ? ' waits' : 's wait'} on tickets outside ` +\n 'this run. Select those features too, or finish them ' +\n 'first:',\n ...outside.map(t => (\n ` ${ticketLabel(toRef(t))} waits on ` +\n deadRefs(t)\n .filter(r => r.where === 'pending')\n .map(blockerLabel)\n .join(', ')\n )),\n )\n }\n const missing = open.flatMap(t => t.blockers\n .filter(r => r.where === 'missing')\n .map(r => ` ${ticketLabel(toRef(t))}: ${blockerLabel(r)}`))\n if (missing.length > 0) {\n const n = missing.length\n blockers.push(\n `${n} blocker reference${n === 1 ? '' : 's'} match no ` +\n 'ticket. Fix the **Blocked by:** line:',\n ...missing,\n )\n }\n const typos = warnings.filter(w => w.kind === 'typo')\n if (typos.length > 0) {\n const n = typos.length\n blockers.push(\n `${n} word${n === 1 ? '' : 's'} in a **Blocked by:** ` +\n `line look${n === 1 ? 's' : ''} like a feature name but ` +\n 'match no .scratch/<name>/issues directory:',\n ...typos.map(w => ` ${w.ticket}: ${w.text}`),\n )\n }\n if (blockers.length > 0) lines.push('', ...blockers)\n\n return lines\n}\n\n/**\n * The text logged when a run ends. The first line is the\n * count summary. Further paragraphs (`explainOpen`) name\n * open ready-for-human tickets and say that an agent cannot\n * finish them, list tickets waiting on blockers outside the\n * run and blocker refs that match no ticket, and repeat the\n * typo `warnings` from loading, so a run that exits with open\n * tickets never looks like it silently gave up.\n */\nexport function renderFinishSummary (\n tickets:ReadonlyArray<Ticket>,\n totalCompleted:number,\n failedKeys:ReadonlySet<string>,\n warnings:ReadonlyArray<BlockerWarning> = [],\n):string {\n const remaining = tickets.filter(\n t => t.status === 'ready-for-agent'\n )\n const human = tickets.filter(t => t.status === HUMAN_STATUS)\n\n const counts = `Finished: ${totalCompleted} completed` +\n (remaining.length > 0 ?\n `, ${remaining.length} remaining` :\n '') +\n (failedKeys.size > 0 ?\n `, ${failedKeys.size} failed` :\n '') +\n (human.length > 0 ?\n `, ${human.length} need a human` :\n '')\n\n const lines:string[] = [counts]\n\n const features = new Set(\n tickets.map(t => t.feature).filter(Boolean)\n )\n if (features.size > 1) {\n lines.push('')\n for (const feat of [...features].sort()) {\n const ft = tickets.filter(\n t => t.feature === feat\n )\n const done = ft.filter(\n t => t.status === 'done'\n ).length\n const failed = ft.filter(\n t => failedKeys.has(\n ticketKey(t.feature, t.num)\n )\n ).length\n const rem = ft.filter(\n t => t.status === 'ready-for-agent'\n ).length\n let detail = ` ${feat}: ${done} completed`\n if (rem > 0) detail += `, ${rem} remaining`\n if (failed > 0) detail += `, ${failed} failed`\n lines.push(detail)\n }\n }\n\n lines.push(...explainOpen(tickets, failedKeys, warnings))\n return lines.join('\\n')\n}\n\n/**\n * The zero-ready stop rule: nothing can start, yet a\n * ready-for-agent ticket is waiting on a blocker. A run with no\n * ready-for-agent ticket left (all done, or only human work) is\n * not a stop: it still gets its finish summary and review.\n */\nexport function nothingReady (\n tickets:ReadonlyArray<Ticket>\n):boolean {\n return findReadyTickets(tickets).length === 0 &&\n tickets.some(t => t.status === 'ready-for-agent')\n}\n\n/**\n * Why nothing can run: the same paragraphs as the finish summary\n * (human work, tickets outside the run, refs that match nothing,\n * typos), plus tickets waiting on an in-run ticket in another\n * status (e.g. needs-triage) and tickets that wait on each other\n * in a cycle.\n */\nexport function renderNothingReady (\n tickets:ReadonlyArray<Ticket>,\n warnings:ReadonlyArray<BlockerWarning>\n):string {\n const lines = [\n 'Nothing to run: every ready-for-agent ticket is ' +\n 'waiting on a blocker.',\n ...explainOpen(tickets, new Set(), warnings),\n ]\n const dead = findBlockedTickets(tickets, new Set())\n const byKey = new Map(\n tickets.map(t => [ticketKey(t.feature, t.num), t])\n )\n // Human blockers are explained by explainOpen; any other\n // in-run dead blocker is a status an agent will not pick up.\n const other:string[] = []\n for (const [key, refs] of dead) {\n const stuck = refs.flatMap(r => {\n const b = byKey.get(ticketKey(r.feature, r.num))\n return b && b.status !== HUMAN_STATUS ?\n [`${ticketLabel(toRef(b))} (${b.status})`] :\n []\n })\n const t = byKey.get(key)\n if (t && stuck.length > 0) {\n other.push(\n ` ${ticketLabel(toRef(t))} waits on ` +\n stuck.join(', ')\n )\n }\n }\n if (other.length > 0) {\n lines.push(\n '',\n 'These tickets wait on tickets that are not ' +\n 'ready-for-agent:',\n ...other,\n 'Set those tickets to ready-for-agent or done, or ' +\n 'fix the **Blocked by:** lines.'\n )\n }\n const cycle = detectDeadlocks(tickets).filter(t => (\n !dead.has(ticketKey(t.feature, t.num))\n ))\n if (cycle.length > 0) {\n lines.push(\n '',\n 'Deadlocked tickets (waiting on each other): ' +\n cycle.map(t => ticketLabel(toRef(t))).join(', ') +\n '. Fix their **Blocked by:** lines.'\n )\n }\n return lines.join('\\n')\n}\n\nfunction sessionTickets (\n tickets:ReadonlyArray<Ticket>,\n):Array<Ticket> {\n return [...tickets]\n .filter(t => t.status === 'ready-for-agent')\n .sort((a, b) => (\n a.feature.localeCompare(b.feature) || a.num - b.num\n ))\n}\n\nfunction toRef (t:Ticket):TicketRef {\n return { num:t.num, filename:t.filename, feature:t.feature }\n}\n\nfunction reportBlocked (\n d:Display,\n tickets:ReadonlyArray<Ticket>,\n failedKeys:ReadonlySet<string>,\n):void {\n const byKey = new Map(\n tickets.map(t => [ticketKey(t.feature, t.num), t])\n )\n for (const [key, dead] of findBlockedTickets(\n tickets, failedKeys\n )) {\n const ticket = byKey.get(key)\n if (!ticket) continue\n const labels = dead.map(ref => {\n const t = byKey.get(ticketKey(ref.feature, ref.num))\n return t ? ticketLabel(toRef(t)) : blockerLabel(ref)\n })\n d.setBlocked(ticket.num, ticket.feature, labels)\n }\n}\n\nfunction runProgress (tickets:ReadonlyArray<Ticket>):RunProgress {\n return {\n completed:tickets.filter(t => t.status === 'done').length,\n total:tickets.length,\n }\n}\n\nexport async function runWaves (\n tickets:Ticket[],\n specBody:string,\n agentCmd:string,\n model:string|null,\n timeout:number,\n logsDir:string,\n testCmd:string,\n display?:Display,\n maxTurns?:number,\n effort?:EffortLevel,\n retries?:number,\n retryDelay?:number,\n concurrency?:number,\n // blocker problems found while loading, for the finish summary\n warnings:ReadonlyArray<BlockerWarning> = [],\n // claude only: model for subagents; unset = off\n preferSubagent?:string,\n):Promise<{ allDone:boolean }> {\n mkdirSync(logsDir, { recursive:true })\n\n const d = display ?? createDisplay()\n const maxAttempts = (retries ?? DEFAULT_RETRIES) + 1\n const delayBase = retryDelay ?? 0\n const poolSize = concurrency ?? DEFAULT_CONCURRENCY\n const providerName = basename(agentCmd)\n const isKnown = providerName in EFFORT_LADDERS\n let totalWaves = 0\n for (const _ of simulateWaves(tickets)) totalWaves++\n\n let totalCompleted = 0\n let waveNum = 0\n const failedKeys = new Set<string>()\n const session = sessionTickets(tickets)\n // Every agent the run spawns, for the stats line at the end\n let runStats = emptyRunStats()\n\n while (true) {\n if (waveNum > 0) reportBlocked(d, tickets, failedKeys)\n\n const ready = findReadyTickets(tickets).filter(\n t => !failedKeys.has(\n ticketKey(t.feature, t.num)\n )\n )\n if (ready.length === 0) break\n\n waveNum++\n if (waveNum === 1) {\n d.startRun(session.map(toRef))\n reportBlocked(d, tickets, failedKeys)\n }\n d.startWave(\n waveNum,\n totalWaves,\n ready.map(t => ({\n num:t.num,\n filename:t.filename,\n feature:t.feature,\n })),\n runProgress(session),\n )\n\n const results = await runPool(\n ready, poolSize, async t => {\n const prompt = renderPrompt(specBody, t,\n { testCmd, preferSubagent })\n const label = t.filename.replace(\n /\\.md$/, ''\n )\n d.setTicketStatus(\n t.num, 'in-progress', t.feature\n )\n d.log(` Starting ${t.filename}`)\n // The row shows every attempt's subagents and\n // cost so far.\n let prior:SubagentStats = { subagents:0 }\n const onStats = (stats:SubagentStats):void => {\n d.setTicketStats(\n t.num, t.feature, addStats(prior, stats)\n )\n }\n const tally = (r:AgentResult):void => {\n prior = addStats(prior, r)\n runStats = addRun(runStats, r)\n }\n let level = effort\n let result = await spawnAgent({\n prompt,\n agentCmd,\n model,\n timeout,\n logPath:attemptLogPath(logsDir, t, 1, '.log'),\n label,\n maxTurns,\n effort:level,\n preferSubagent,\n onStats,\n onLine:(line) => d.log(line),\n })\n tally(result)\n // In-place runs have no worktree or test\n // gate, so a non-zero exit is the only\n // failure that can be retried here.\n for (\n let attempt = 2;\n result.exitCode !== 0 &&\n !result.timedOut &&\n attempt <= maxAttempts;\n attempt++\n ) {\n if (isKnown) {\n level = escalateEffort(\n providerName as ProviderName,\n level\n )\n }\n const delay = retryDelayFor(delayBase, attempt)\n d.log(\n ` ${t.filename}: agent exited ` +\n `${result.exitCode}; retrying ` +\n `(attempt ${attempt}/${maxAttempts}` +\n (isKnown && level ?\n `, effort ${level}` : '') +\n (delay > 0 ?\n `, waiting ${delay}s` : '') +\n ')'\n )\n if (delay > 0) await sleep(delay * 1000)\n result = await spawnAgent({\n prompt,\n agentCmd,\n model,\n timeout,\n logPath:attemptLogPath(\n logsDir, t, attempt, '.log'\n ),\n label,\n maxTurns,\n effort:level,\n preferSubagent,\n onStats,\n onLine:(line) => d.log(line),\n })\n tally(result)\n }\n return { ticket:t, result }\n }\n )\n\n let waveCompleted = 0\n for (const r of results) {\n if (r.status === 'rejected') continue\n const { ticket, result } = r.value\n if (result.exitCode !== 0) {\n failedKeys.add(\n ticketKey(ticket.feature, ticket.num)\n )\n d.setTicketStatus(\n ticket.num, 'failed', ticket.feature\n )\n d.log(\n ` ${ticket.filename}: ` +\n `agent exited ${result.exitCode}`\n )\n continue\n }\n\n checkItems(ticket, result.completedItems)\n markDone(ticket)\n waveCompleted++\n totalCompleted++\n d.setTicketStatus(\n ticket.num, 'done', ticket.feature\n )\n d.log(\n ` ${ticket.filename}: done`\n )\n }\n\n if (waveCompleted === 0) {\n const remaining = findReadyTickets(tickets)\n .filter(t => !failedKeys.has(\n ticketKey(t.feature, t.num)\n ))\n if (remaining.length === 0) {\n d.log(\n '\\nNo tickets completed this wave ' +\n 'and no ready tickets remain. ' +\n 'Stopping.'\n )\n break\n }\n d.log(\n '\\nNo tickets completed this wave. ' +\n `${remaining.length} ready ticket` +\n `${remaining.length === 1 ? '' : 's'} ` +\n 'remain; continuing.'\n )\n }\n }\n\n if (waveNum > 0) reportBlocked(d, tickets, failedKeys)\n\n const remaining = tickets.filter(\n t => t.status === 'ready-for-agent'\n )\n d.log('\\n' + renderFinishSummary(\n tickets, totalCompleted, failedKeys, warnings\n ))\n const statsLine = renderRunStats(runStats)\n if (statsLine) d.log(statsLine)\n d.cleanup()\n\n return { allDone:remaining.length === 0 }\n}\n\nexport async function runWavesIsolated (opts:{\n tickets:Array<Ticket>\n specBody:string\n specBodies?:Map<string, string>\n agentCmd:string\n model:string|null\n timeout:number\n logsDir:string\n featureName:string\n conflictStrategy:MergeConflictStrategy\n display?:Display\n testCmd:string\n // run in each fresh worktree before the agent; unset or\n // empty = no install\n installCmd?:string\n maxTurns?:number\n // starting effort level; unset = provider's default\n effort?:EffortLevel\n // extra attempts per ticket after a failure; default 3\n retries?:number\n // seconds to wait before the first retry; default 30\n retryDelay?:number\n // max agents running at once within a wave; default 5\n concurrency?:number\n // claude only: model for subagents; unset = off\n preferSubagent?:string\n // per-feature progress paths for multi-feature runs\n progressPaths?:Map<string, string>\n // blocker problems found while loading, for the finish summary\n warnings?:ReadonlyArray<BlockerWarning>\n // review the unreviewed work and run one fix pass at the end;\n // unset = no review\n review?:{\n reviewPath:string\n // the default branch, when this run is on an\n // integration branch\n forkedFrom?:string\n }\n}):Promise<{ allDone:boolean; branch:string }> {\n mkdirSync(opts.logsDir, { recursive:true })\n\n const d = opts.display ?? createDisplay()\n const retries = opts.retries ?? DEFAULT_RETRIES\n const retryDelay = opts.retryDelay ?? 0\n const poolSize = opts.concurrency ?? DEFAULT_CONCURRENCY\n let totalWaves = 0\n for (const _ of simulateWaves(opts.tickets)) totalWaves++\n\n const repoRoot = getRepoRoot()\n const repoName = getRepoName()\n const baseBranch = getCurrentBranch()\n\n if (isDirty(repoRoot)) {\n throw new Error(\n 'Working tree is dirty; commit or stash ' +\n 'changes before running'\n )\n }\n\n // The review falls back to this when no earlier review or\n // fork point applies.\n const launchCommit = headCommit(repoRoot)\n\n const features = new Set(\n opts.tickets.map(t => t.feature).filter(Boolean)\n )\n const multiFeature = features.size > 1 &&\n opts.progressPaths !== undefined\n\n const fallbackProgressPath = join(\n dirname(opts.logsDir), 'progress.md'\n )\n\n let tracker:ProgressTracker\n if (multiFeature) {\n const multiData = generateMultiFeatureProgress(\n opts.tickets\n )\n const dataMap = new Map<string, ProgressData>()\n for (const [feat, fresh] of multiData) {\n const path = opts.progressPaths!.get(feat) ??\n fallbackProgressPath\n const merged = mergeProgress(\n fresh, readProgress(path)\n )\n dataMap.set(feat, merged)\n await saveProgress(\n repoRoot, path, merged,\n `nightralph: start ${feat}`, d,\n )\n }\n tracker = createProgressTracker({\n progressPaths:opts.progressPaths!,\n dataMap,\n fallbackPath:fallbackProgressPath,\n fallbackData:generateProgress(\n opts.featureName, []\n ),\n })\n } else {\n const progressPath = fallbackProgressPath\n const progress:ProgressData = mergeProgress(\n generateProgress(\n opts.featureName, opts.tickets\n ),\n readProgress(progressPath)\n )\n await saveProgress(\n repoRoot, progressPath, progress,\n `nightralph: start ${opts.featureName}`, d,\n )\n tracker = createProgressTracker({\n progressPaths:new Map(),\n dataMap:new Map(),\n fallbackPath:progressPath,\n fallbackData:progress,\n })\n }\n\n let totalCompleted = 0\n let waveNum = 0\n const failedKeys = new Set<string>()\n const session = sessionTickets(opts.tickets)\n // Every agent the run spawns, for the stats line at the end\n let runStats = emptyRunStats()\n const onAgentRun = (result:AgentResult):void => {\n runStats = addRun(runStats, result)\n }\n\n while (true) {\n if (waveNum > 0) reportBlocked(d, opts.tickets, failedKeys)\n\n const ready = findReadyTickets(opts.tickets).filter(\n t => !failedKeys.has(\n ticketKey(t.feature, t.num)\n )\n )\n if (ready.length === 0) break\n\n waveNum++\n if (waveNum === 1) {\n d.startRun(session.map(toRef))\n reportBlocked(d, opts.tickets, failedKeys)\n }\n d.startWave(\n waveNum,\n totalWaves,\n ready.map(t => ({\n num:t.num,\n filename:t.filename,\n feature:t.feature,\n })),\n runProgress(session),\n )\n\n // Each ticket runs its own attempt loop, at most\n // `poolSize` at a time. Progress is recorded\n // afterwards, sequentially, so commits on the base\n // branch never race each other.\n const settled = await runPool(\n ready, poolSize, t => runTicketAttempts({\n ticket:t,\n repoRoot,\n repoName,\n baseBranch,\n specBody:opts.specBody,\n specBodies:opts.specBodies,\n agentCmd:opts.agentCmd,\n model:opts.model,\n timeout:opts.timeout,\n logsDir:opts.logsDir,\n testCmd:opts.testCmd,\n installCmd:opts.installCmd,\n maxTurns:opts.maxTurns,\n effort:opts.effort,\n preferSubagent:opts.preferSubagent,\n learningsPath:learningsPathFor(\n tracker.pathFor(t.feature)\n ),\n retries,\n retryDelay,\n d,\n onAgentRun,\n })\n )\n\n // Entries were appended while the pool ran, but not every\n // outcome below saves progress before merging. Commit them\n // now, so the base tree has no modified tracked files when\n // mergeWave touches it.\n const touched = new Set(ready.map(t => {\n return learningsPathFor(tracker.pathFor(t.feature))\n }))\n for (const path of touched) {\n if (!isRegularFile(path)) continue\n try {\n await commitProgress(\n repoRoot, path,\n 'nightralph: record attempt learnings'\n )\n } catch (err) {\n d.log(\n ' Failed to commit learnings: ' +\n formatErrorMessage(err)\n )\n }\n }\n\n // runTicketAttempts never rejects (a throw inside an\n // attempt becomes an 'error' outcome), so every\n // result here is fulfilled.\n const outcomes:TicketOutcome[] = settled.map(r =>\n r.status === 'fulfilled' ?\n r.value :\n { kind:'error', error:r.reason }\n )\n\n let waveCompleted = 0\n const successfulBranches:Array<{\n branch:string\n ticketNum:number\n worktreePath:string\n }> = []\n const ticketsByKey = new Map<string, Ticket>()\n const worktreePathsByKey = new Map<string, string>()\n const branchToKey = new Map<string, string>()\n\n for (let i = 0; i < outcomes.length; i++) {\n const outcome = outcomes[i]\n const ticket = ready[i]\n const key = ticketKey(ticket.feature, ticket.num)\n\n if (outcome.kind === 'worktree-error') {\n failedKeys.add(key)\n d.setTicketStatus(\n ticket.num, 'failed', ticket.feature\n )\n d.log(\n ` ${ticket.filename}: failed to create ` +\n `worktree: ${formatErrorMessage(outcome.error)}`\n )\n checkTicket(tracker.dataFor(ticket.feature), ticket.num, {\n branch:'',\n exitCode:-1,\n done:false,\n })\n await saveProgress(\n repoRoot,\n tracker.pathFor(ticket.feature),\n tracker.dataFor(ticket.feature),\n `nightralph: ${ticket.filename} ` +\n 'worktree error',\n d,\n )\n continue\n }\n\n if (outcome.kind === 'error') {\n failedKeys.add(key)\n d.setTicketStatus(\n ticket.num, 'failed', ticket.feature\n )\n d.log(\n ` ${ticket.filename}: attempt error: ` +\n formatErrorMessage(outcome.error)\n )\n checkTicket(tracker.dataFor(ticket.feature), ticket.num, {\n branch:outcome.branchName ?? '',\n exitCode:-1,\n done:false,\n })\n await saveProgress(\n repoRoot,\n tracker.pathFor(ticket.feature),\n tracker.dataFor(ticket.feature),\n `nightralph: ${ticket.filename} error`,\n d,\n )\n continue\n }\n\n if (outcome.kind === 'no-commits') {\n failedKeys.add(key)\n d.setTicketStatus(\n ticket.num, 'failed', ticket.feature\n )\n d.log(\n ` ${ticket.filename}: agent exited 0 ` +\n 'but made no changes; leaving ticket ' +\n 'ready-for-agent'\n )\n checkTicket(tracker.dataFor(ticket.feature), ticket.num, {\n branch:outcome.branchName,\n exitCode:0,\n done:false,\n })\n await saveProgress(\n repoRoot,\n tracker.pathFor(ticket.feature),\n tracker.dataFor(ticket.feature),\n `nightralph: ${ticket.filename} ` +\n 'no commits',\n d,\n )\n continue\n }\n\n if (outcome.kind === 'failed') {\n failedKeys.add(key)\n d.setTicketStatus(\n ticket.num, 'failed', ticket.feature\n )\n if (outcome.reason === 'exit') {\n checkItems(ticket, outcome.completedItems)\n }\n checkTicket(tracker.dataFor(ticket.feature), ticket.num, {\n branch:outcome.branchName,\n exitCode:outcome.exitCode,\n done:false,\n })\n await saveProgress(\n repoRoot,\n tracker.pathFor(ticket.feature),\n tracker.dataFor(ticket.feature),\n `nightralph: ${ticket.filename} ` +\n failureNote(outcome.reason),\n d,\n )\n continue\n }\n\n checkItems(ticket, outcome.completedItems)\n d.log(\n ` ${ticket.filename}: agent finished, ` +\n 'awaiting merge'\n )\n ticketsByKey.set(key, ticket)\n worktreePathsByKey.set(\n key, outcome.worktreePath\n )\n branchToKey.set(outcome.branchName, key)\n successfulBranches.push({\n branch:outcome.branchName,\n ticketNum:ticket.num,\n worktreePath:outcome.worktreePath,\n })\n }\n\n if (successfulBranches.length > 0) {\n await commitTicketFiles(\n repoRoot,\n successfulBranches\n .map(sb => {\n const k = branchToKey.get(sb.branch)!\n return ticketsByKey.get(k)!\n }),\n d,\n )\n\n const mergeResult = await mergeWave({\n repoRoot,\n baseBranch,\n branches:successfulBranches,\n strategy:opts.conflictStrategy,\n })\n\n const doneThisWave:Ticket[] = []\n for (const branchResult of mergeResult.merged) {\n const bk = branchToKey.get(\n branchResult.branch\n )\n const ticket = bk ?\n ticketsByKey.get(bk) :\n undefined\n if (!ticket) continue\n\n if (branchResult.merged) {\n markDone(ticket)\n doneThisWave.push(ticket)\n waveCompleted++\n totalCompleted++\n d.setTicketStatus(\n ticket.num, 'done', ticket.feature\n )\n d.log(\n ` ${ticket.filename}: done`\n )\n checkTicket(tracker.dataFor(ticket.feature), ticket.num, {\n branch:branchResult.branch,\n exitCode:0,\n })\n await saveProgress(\n repoRoot,\n tracker.pathFor(ticket.feature),\n tracker.dataFor(ticket.feature),\n `nightralph: ${ticket.filename} done`,\n d,\n )\n\n const worktreePath = bk ?\n worktreePathsByKey.get(bk) :\n undefined\n if (worktreePath) {\n await removeWorktreeQuietly(\n worktreePath, d\n )\n }\n } else {\n const wtKey = branchToKey.get(\n branchResult.branch\n )\n const worktreePath = wtKey ?\n worktreePathsByKey.get(wtKey) :\n undefined\n const recovered =\n opts.conflictStrategy === 'respawn' &&\n worktreePath ?\n await respawnAndRetryMerge({\n repoRoot,\n baseBranch,\n branch:branchResult.branch,\n ticket,\n worktreePath,\n specBody:lookupSpec(\n opts.specBodies,\n opts.specBody,\n ticket.feature,\n ),\n agentCmd:opts.agentCmd,\n model:opts.model,\n timeout:opts.timeout,\n logsDir:opts.logsDir,\n testCmd:opts.testCmd,\n installCmd:opts.installCmd,\n maxTurns:opts.maxTurns,\n preferSubagent:opts.preferSubagent,\n onLine:(msg) => d.log(msg),\n onAgentRun,\n }) :\n false\n\n if (recovered) {\n markDone(ticket)\n doneThisWave.push(ticket)\n waveCompleted++\n totalCompleted++\n d.setTicketStatus(\n ticket.num, 'done',\n ticket.feature,\n )\n d.log(\n ` ${ticket.filename}: done ` +\n '(resolved via respawn)'\n )\n checkTicket(tracker.dataFor(ticket.feature), ticket.num, {\n branch:branchResult.branch,\n exitCode:0,\n })\n await saveProgress(\n repoRoot,\n tracker.pathFor(ticket.feature),\n tracker.dataFor(ticket.feature),\n `nightralph: ${ticket.filename} ` +\n 'done (respawn)',\n d,\n )\n\n if (worktreePath) {\n try {\n await removeWorktree(\n worktreePath,\n { force:true }\n )\n } catch (err) {\n d.log(\n ' Failed to remove worktree ' +\n `${worktreePath}: ` +\n formatErrorMessage(err)\n )\n }\n }\n } else {\n failedKeys.add(\n ticketKey(ticket.feature, ticket.num)\n )\n d.setTicketStatus(\n ticket.num, 'failed', ticket.feature\n )\n d.log(\n ` ${ticket.filename}: merge failed, ` +\n 'staying ready-for-agent'\n )\n if (branchResult.stderr) {\n d.log(\n ' git: ' +\n branchResult.stderr.trim()\n )\n }\n checkTicket(tracker.dataFor(ticket.feature), ticket.num, {\n branch:branchResult.branch,\n exitCode:0,\n done:false,\n })\n // saveProgress below commits this entry\n try {\n appendEntry(\n learningsPathFor(\n tracker.pathFor(ticket.feature)\n ),\n renderEntry({\n outcome:'merge',\n key:ticketKey(\n ticket.feature, ticket.num\n ),\n label:ticketLabel(ticket),\n attempt:0,\n now:new Date(),\n stderr:branchResult.stderr ?? '',\n })\n )\n } catch (err) {\n d.log(\n ` ${ticket.filename}: could not ` +\n 'record learnings: ' +\n formatErrorMessage(err)\n )\n }\n await saveProgress(\n repoRoot,\n tracker.pathFor(ticket.feature),\n tracker.dataFor(ticket.feature),\n `nightralph: ${ticket.filename} ` +\n 'merge failed',\n d,\n )\n }\n }\n }\n\n // markDone edited the ticket files in the base checkout\n await commitTicketFiles(repoRoot, doneThisWave, d)\n\n if (mergeResult.stoppedAt) {\n d.log(\n '\\nMerge stopped at ' +\n `${mergeResult.stoppedAt.branch}`\n )\n\n for (const sb of successfulBranches) {\n const sbk = branchToKey.get(sb.branch)\n const ticket = sbk ?\n ticketsByKey.get(sbk) :\n undefined\n if (ticket && ticket.status === 'done') continue\n try {\n await removeWorktree(\n sb.worktreePath,\n { force:true }\n )\n } catch (err) {\n d.log(\n ' Failed to remove worktree ' +\n `${sb.worktreePath}: ` +\n formatErrorMessage(err)\n )\n }\n }\n\n break\n }\n }\n\n if (waveCompleted === 0) {\n const remaining = findReadyTickets(\n opts.tickets\n ).filter(t => !failedKeys.has(\n ticketKey(t.feature, t.num)\n ))\n if (remaining.length === 0) {\n d.log(\n '\\nNo tickets completed this wave ' +\n 'and no ready tickets remain. ' +\n 'Stopping.'\n )\n break\n }\n d.log(\n '\\nNo tickets completed this wave. ' +\n `${remaining.length} ready ticket` +\n `${remaining.length === 1 ? '' : 's'} ` +\n 'remain; continuing.'\n )\n }\n }\n\n if (waveNum > 0) reportBlocked(d, opts.tickets, failedKeys)\n\n // Advisory, like learnings: a broken review is reported and\n // never changes the run's result.\n let reviewLine:string|null = null\n if (opts.review) {\n try {\n const outcome = await runReviewPass({\n repoRoot,\n repoName,\n baseBranch,\n reviewPath:opts.review.reviewPath,\n forkedFrom:opts.review.forkedFrom,\n launchCommit,\n specBody:reviewSpecBody(\n opts.specBody, opts.specBodies\n ),\n agentCmd:opts.agentCmd,\n model:opts.model,\n timeout:opts.timeout,\n logsDir:opts.logsDir,\n testCmd:opts.testCmd,\n installCmd:opts.installCmd,\n maxTurns:opts.maxTurns,\n effort:opts.effort,\n preferSubagent:opts.preferSubagent,\n retries,\n retryDelay,\n log:(msg) => d.log(msg),\n }, {\n spawnAgent:async spawnOpts => {\n const result = await spawnAgent(spawnOpts)\n onAgentRun(result)\n return result\n },\n registry:runningAgents,\n })\n reviewLine = renderReviewSummary(\n outcome, relative(repoRoot, opts.review.reviewPath)\n )\n } catch (err) {\n d.log(`\\nReview failed: ${formatErrorMessage(err)}`)\n }\n }\n\n const remaining = opts.tickets.filter(\n t => t.status === 'ready-for-agent'\n )\n d.log('\\n' + renderFinishSummary(\n opts.tickets, totalCompleted, failedKeys, opts.warnings ?? []\n ))\n const statsLine = renderRunStats(runStats)\n if (statsLine) d.log(statsLine)\n if (reviewLine) d.log(reviewLine)\n d.log(`Work is on ${baseBranch}`)\n d.cleanup()\n\n return { allDone:remaining.length === 0, branch:baseBranch }\n}\n", "import { execFile, execFileSync } from 'node:child_process'\nimport { promisify } from 'node:util'\nimport { basename, dirname, join, resolve } from 'node:path'\nimport { existsSync } from 'node:fs'\nimport type { Ticket } from './orchestrator.js'\n\nconst execFileAsync = promisify(execFile)\n\nexport function getRepoRoot ():string {\n const stdout = execFileSync(\n 'git',\n ['rev-parse', '--show-toplevel'],\n { encoding:'utf8' }\n )\n return stdout.trim()\n}\n\nexport function getRepoName ():string {\n const commonDir = execFileSync(\n 'git',\n ['rev-parse', '--git-common-dir'],\n { encoding:'utf8' }\n ).trim()\n return basename(dirname(resolve(commonDir)))\n}\n\nexport function getCurrentBranch (cwd?:string):string {\n const stdout = execFileSync(\n 'git',\n ['rev-parse', '--abbrev-ref', 'HEAD'],\n { cwd, encoding:'utf8' }\n )\n return stdout.trim()\n}\n\nexport function localBranchExists (\n repoRoot:string,\n name:string\n):boolean {\n try {\n execFileSync(\n 'git',\n ['show-ref', '--verify', '--quiet', `refs/heads/${name}`],\n { cwd:repoRoot, stdio:'ignore' }\n )\n return true\n } catch {\n return false\n }\n}\n\n// The repo's default branch: what origin/HEAD points at, else a\n// local main or master, else null.\nexport function getDefaultBranch (repoRoot:string):string|null {\n try {\n const ref = execFileSync(\n 'git',\n [\n 'symbolic-ref', '--quiet', '--short',\n 'refs/remotes/origin/HEAD',\n ],\n {\n cwd:repoRoot,\n encoding:'utf8',\n stdio:['ignore', 'pipe', 'ignore'],\n }\n ).trim()\n if (ref) return ref.replace(/^origin\\//, '')\n } catch {\n // no origin/HEAD\n }\n for (const name of ['main', 'master']) {\n if (localBranchExists(repoRoot, name)) return name\n }\n return null\n}\n\n// Uses `--` rather than `/` for the same reason as\n// buildBranchName: refs/heads/X/Y cannot coexist with\n// refs/heads/X.\nexport function integrationBranchName (\n features:ReadonlyArray<string>\n):string {\n const distinct = [...new Set(features.filter(Boolean))]\n return distinct.length === 1 ?\n `nightralph--${distinct[0]}` :\n 'nightralph--all'\n}\n\n// The integration branch to use, or null to merge into the\n// current branch as before. Only a run launched from the default\n// branch gets one.\nexport function planIntegrationBranch (\n current:string,\n defaultBranch:string|null,\n features:ReadonlyArray<string>\n):string|null {\n if (!defaultBranch || current === 'HEAD') return null\n if (current !== defaultBranch) return null\n return integrationBranchName(features)\n}\n\nexport type IntegrationPlan = {\n // where this run's work lands\n branch:string\n created:boolean\n resumed:boolean\n // commits on the launch branch that `branch` lacks\n behind:number\n // true when a resumed branch that was already contained in the\n // launch branch was moved up to it\n fastForwarded:boolean\n launchBranch:string\n // the default branch when `branch` is an integration branch,\n // else null; the review falls back to its merge-base\n forkedFrom:string|null\n}\n\nfunction gitText (cwd:string, args:string[]):string {\n return execFileSync('git', args, { cwd, encoding:'utf8' }).trim()\n}\n\n// Enters the integration branch when the run was launched from\n// the default branch, creating it or resuming it. Callers must\n// scan tickets after this, since ticket statuses live on the\n// branch it checks out.\nexport function prepareIntegrationBranch (\n repoRoot:string,\n features:ReadonlyArray<string>\n):IntegrationPlan {\n const current = getCurrentBranch(repoRoot)\n const defaultBranch = getDefaultBranch(repoRoot)\n const name = planIntegrationBranch(\n current, defaultBranch, features\n )\n if (!name) {\n const onIntegration = defaultBranch !== null &&\n current === integrationBranchName(features)\n return {\n branch:current,\n created:false,\n resumed:false,\n behind:0,\n fastForwarded:false,\n launchBranch:current,\n forkedFrom:onIntegration ? defaultBranch : null,\n }\n }\n if (isDirty(repoRoot)) {\n throw new Error(\n 'Working tree is dirty; commit or stash ' +\n 'changes before running'\n )\n }\n if (localBranchExists(repoRoot, name)) {\n // Merged into the launch branch already: nothing of its own\n // to lose, so bring it up to date\n const contained = isAncestor(repoRoot, name, current)\n gitText(repoRoot, ['checkout', '--quiet', name])\n let behind = Number(gitText(\n repoRoot, ['rev-list', '--count', `${name}..${current}`]\n ))\n const fastForwarded = contained && behind > 0\n if (fastForwarded) {\n gitText(repoRoot, ['merge', '--ff-only', '--quiet', current])\n behind = 0\n }\n return {\n branch:name,\n created:false,\n resumed:true,\n behind,\n fastForwarded,\n launchBranch:current,\n forkedFrom:defaultBranch,\n }\n }\n gitText(repoRoot, ['checkout', '--quiet', '-b', name])\n return {\n branch:name,\n created:true,\n resumed:false,\n behind:0,\n fastForwarded:false,\n launchBranch:current,\n forkedFrom:defaultBranch,\n }\n}\n\n// What prepareIntegrationBranch would do, for --dry-run.\nexport function describeIntegrationBranch (\n repoRoot:string,\n features:ReadonlyArray<string>\n):string {\n const current = getCurrentBranch(repoRoot)\n const name = planIntegrationBranch(\n current, getDefaultBranch(repoRoot), features\n )\n if (!name) return `Branch: merges into ${current}`\n return localBranchExists(repoRoot, name) ?\n `Branch: would resume ${name}` :\n `Branch: would create ${name} from ${current}`\n}\n\nasync function branchExists (\n repoRoot:string,\n branchName:string\n):Promise<boolean> {\n try {\n await execFileAsync(\n 'git',\n ['show-ref', '--verify', '--quiet', `refs/heads/${branchName}`],\n { cwd:repoRoot }\n )\n return true\n } catch {\n return false\n }\n}\n\nexport function buildBranchName (\n repoName:string,\n ticket:Ticket\n):string {\n const num = String(ticket.num).padStart(2, '0')\n const prefix = ticket.feature ?\n `${ticket.feature}-` :\n ''\n return `${repoName}--${prefix}${num}-${ticket.slug}`\n}\n\nasync function removeWorktreeNow (\n worktreePath:string,\n opts?:{ force?:boolean }\n):Promise<void> {\n const args = [\n '-C', worktreePath,\n 'worktree', 'remove',\n ]\n if (opts?.force) args.push('--force')\n args.push(worktreePath)\n await execFileAsync('git', args)\n}\n\n// Creates a worktree on a fresh branch, first clearing any stale\n// worktree at the path and any leftover branch of the same name,\n// so re-running after a failed run is safe.\nasync function addWorktreeNow (opts:{\n repoRoot:string\n baseBranch:string\n branchName:string\n worktreePath:string\n}):Promise<{ worktreePath:string; branchName:string }> {\n const { repoRoot, baseBranch, branchName, worktreePath } = opts\n\n if (existsSync(worktreePath)) {\n try {\n await execFileAsync(\n 'git',\n ['worktree', 'remove', '--force', worktreePath],\n { cwd:repoRoot }\n )\n } catch {\n // directory may not be a registered worktree anymore;\n // prune stale entries below and let worktree add fail\n // loudly if the path is still unusable\n }\n }\n\n try {\n await execFileAsync(\n 'git',\n ['worktree', 'prune'],\n { cwd:repoRoot }\n )\n } catch {\n // best-effort cleanup of stale worktree metadata\n }\n\n if (await branchExists(repoRoot, branchName)) {\n await execFileAsync(\n 'git',\n ['branch', '-D', branchName],\n { cwd:repoRoot }\n )\n }\n\n await execFileAsync(\n 'git',\n [\n 'worktree',\n 'add',\n '-b',\n branchName,\n worktreePath,\n baseBranch,\n ],\n { cwd:repoRoot }\n )\n\n return { worktreePath, branchName }\n}\n\nlet worktreeQueue:Promise<unknown> = Promise.resolve()\n\n// Serializes every worktree and branch mutation module-wide, so\n// concurrent calls cannot race on shared git refs or on\n// .git/worktrees metadata.\nfunction enqueue<T> (fn:() => Promise<T>):Promise<T> {\n const result = worktreeQueue.then(fn)\n worktreeQueue = result.catch(() => {})\n return result\n}\n\nexport function createWorktree (\n opts:{\n repoRoot:string\n repoName:string\n baseBranch:string\n ticket:Ticket\n }\n):Promise<{ worktreePath:string; branchName:string }> {\n const { repoRoot, repoName, ticket } = opts\n const num = String(ticket.num).padStart(2, '0')\n const prefix = ticket.feature ?\n `${ticket.feature}-` :\n ''\n return enqueue(() => addWorktreeNow({\n repoRoot,\n baseBranch:opts.baseBranch,\n branchName:buildBranchName(repoName, ticket),\n worktreePath:join(\n repoRoot,\n '..',\n `${repoName}.${prefix}${num}-${ticket.slug}`\n ),\n }))\n}\n\n// A worktree that belongs to no ticket, e.g. the review pass:\n// `<repo>.<name>` on branch `<repo>--<name>`. Ticket branches\n// always carry a number, so the names cannot collide.\nexport function createNamedWorktree (\n opts:{\n repoRoot:string\n repoName:string\n baseBranch:string\n name:string\n }\n):Promise<{ worktreePath:string; branchName:string }> {\n const { repoRoot, repoName, name } = opts\n return enqueue(() => addWorktreeNow({\n repoRoot,\n baseBranch:opts.baseBranch,\n branchName:`${repoName}--${name}`,\n worktreePath:join(repoRoot, '..', `${repoName}.${name}`),\n }))\n}\n\nexport function removeWorktree (\n worktreePath:string,\n opts?:{ force?:boolean }\n):Promise<void> {\n return enqueue(() => removeWorktreeNow(worktreePath, opts))\n}\n\n// Deletes a local branch; a missing branch is not an error.\nexport function deleteBranch (\n repoRoot:string,\n name:string\n):Promise<void> {\n return enqueue(async () => {\n if (!(await branchExists(repoRoot, name))) return\n await execFileAsync(\n 'git', ['branch', '-D', name], { cwd:repoRoot }\n )\n })\n}\n\nexport function hasNewCommits (\n repoRoot:string,\n base:string,\n branch:string\n):boolean {\n const stdout = execFileSync(\n 'git',\n ['rev-list', '--count', `${base}..${branch}`],\n { cwd:repoRoot, encoding:'utf8' }\n )\n return Number(stdout.trim()) > 0\n}\n\nexport function headCommit (cwd:string):string {\n return gitText(cwd, ['rev-parse', 'HEAD'])\n}\n\nexport function mergeBase (\n cwd:string,\n a:string,\n b:string\n):string|null {\n try {\n return gitText(cwd, ['merge-base', a, b]) || null\n } catch {\n return null\n }\n}\n\n// False when `ancestor` is not an ancestor of `of`, or is not a\n// commit this repo knows.\nexport function isAncestor (\n cwd:string,\n ancestor:string,\n of:string\n):boolean {\n try {\n execFileSync(\n 'git',\n ['merge-base', '--is-ancestor', ancestor, of],\n { cwd, stdio:'ignore' }\n )\n return true\n } catch {\n return false\n }\n}\n\n// True when from..to changes any path outside `excludeDir`.\nexport function hasChangesOutside (\n cwd:string,\n from:string,\n to:string,\n excludeDir:string\n):boolean {\n try {\n execFileSync(\n 'git',\n [\n 'diff', '--quiet', `${from}..${to}`,\n '--', '.', `:(exclude)${excludeDir}`,\n ],\n { cwd, stdio:'ignore' }\n )\n return false\n } catch {\n return true\n }\n}\n\nexport function isDirty (cwd:string):boolean {\n const stdout = execFileSync(\n 'git',\n ['status', '--porcelain'],\n { cwd, encoding:'utf8' }\n )\n return stdout.trim().length > 0\n}\n\nexport async function commitDirty (\n cwd:string,\n message?:string\n):Promise<boolean> {\n if (!isDirty(cwd)) return false\n await execFileAsync(\n 'git',\n ['add', '-A'],\n { cwd }\n )\n try {\n await execFileAsync(\n 'git',\n [\n 'commit', '-m',\n message ??\n 'nightralph: auto-commit ' +\n 'remaining changes',\n ],\n { cwd }\n )\n return true\n } catch {\n return false\n }\n}\n\nexport async function listWorktrees (\n repoRoot:string\n):Promise<Array<string>> {\n const { stdout } = await execFileAsync(\n 'git',\n ['worktree', 'list', '--porcelain'],\n { cwd:repoRoot }\n )\n return stdout\n .trim()\n .split('\\n')\n .filter(line => line.startsWith('worktree '))\n .map(line => line.substring('worktree '.length))\n}\n", "import { execFile } from 'node:child_process'\nimport { readFileSync, writeFileSync } from 'node:fs'\nimport { promisify } from 'node:util'\nimport type { Ticket } from './orchestrator.js'\n\nconst TICKET_FILENAME_RE = /^(\\d+)-(.+)\\.md$/\n\nconst execFileAsync = promisify(execFile)\n\nexport type TicketProgress = {\n num:number\n slug:string\n filename:string\n done:boolean\n branch:string|null\n exitCode:number|null\n completedAt:string|null\n}\n\nexport type ProgressData = {\n feature:string\n startedAt:string\n tickets:Array<TicketProgress>\n}\n\nexport function generateProgress (\n feature:string,\n tickets:ReadonlyArray<Ticket>\n):ProgressData {\n return {\n feature,\n startedAt:new Date().toISOString(),\n tickets:tickets.map((ticket) => ({\n num:ticket.num,\n slug:ticket.slug,\n filename:ticket.filename,\n done:false,\n branch:null,\n exitCode:null,\n completedAt:null,\n })),\n }\n}\n\nexport function generateMultiFeatureProgress (\n tickets:ReadonlyArray<Ticket>\n):Map<string, ProgressData> {\n const byFeature = new Map<string, Ticket[]>()\n for (const t of tickets) {\n const key = t.feature || ''\n const arr = byFeature.get(key) ?? []\n arr.push(t)\n byFeature.set(key, arr)\n }\n const result = new Map<string, ProgressData>()\n for (const [feat, ft] of byFeature) {\n result.set(feat, generateProgress(feat, ft))\n }\n return result\n}\n\nexport type ProgressTracker = {\n dataFor:(feature:string) => ProgressData\n pathFor:(feature:string) => string\n}\n\nexport function createProgressTracker (opts:{\n progressPaths:Map<string, string>\n dataMap:Map<string, ProgressData>\n fallbackPath:string\n fallbackData:ProgressData\n}):ProgressTracker {\n return {\n dataFor (feature:string):ProgressData {\n return opts.dataMap.get(feature) ??\n opts.fallbackData\n },\n pathFor (feature:string):string {\n return opts.progressPaths.get(feature) ??\n opts.fallbackPath\n },\n }\n}\n\nexport function isSpecComplete (\n progressPath:string\n):boolean {\n const data = readProgress(progressPath)\n if (!data) return false\n if (data.tickets.length === 0) return false\n return data.tickets.every(t => t.done)\n}\n\nexport function readProgress (\n progressPath:string\n):ProgressData|null {\n let content:string\n try {\n content = readFileSync(progressPath, 'utf8')\n } catch {\n return null\n }\n\n const featureMatch = content.match(/^# Progress: (.*)$/m)\n const startedMatch = content.match(/^Started: (.*)$/m)\n\n const tickets:Array<TicketProgress> = []\n let current:TicketProgress|null = null\n\n for (const line of content.split('\\n')) {\n const ticketMatch = line.match(/^- \\[( |x)\\] (.+)$/)\n if (ticketMatch) {\n if (current) tickets.push(current)\n const filename = ticketMatch[2]\n const parsed = filename.match(TICKET_FILENAME_RE)\n current = {\n num:parsed ? Number(parsed[1]) : NaN,\n slug:parsed ? parsed[2] : '',\n filename,\n done:ticketMatch[1] === 'x',\n branch:null,\n exitCode:null,\n completedAt:null,\n }\n continue\n }\n if (!current) continue\n\n const branchMatch = line.match(/^ {2}branch: (.*)$/)\n if (branchMatch) {\n current.branch = branchMatch[1]\n continue\n }\n const exitMatch = line.match(/^ {2}exit: (-?\\d+)$/)\n if (exitMatch) {\n current.exitCode = Number(exitMatch[1])\n continue\n }\n const completedMatch = line.match(/^ {2}completed: (.*)$/)\n if (completedMatch) {\n current.completedAt = completedMatch[1]\n continue\n }\n }\n if (current) tickets.push(current)\n\n return {\n feature:featureMatch ? featureMatch[1] : '',\n startedAt:startedMatch ? startedMatch[1] : '',\n tickets,\n }\n}\n\nexport function mergeProgress (\n fresh:ProgressData,\n existing:ProgressData|null\n):ProgressData {\n if (!existing) return fresh\n\n const existingByFilename = new Map(\n existing.tickets.map((t) => [t.filename, t])\n )\n\n return {\n ...fresh,\n tickets:fresh.tickets.map((ticket) => {\n const prior = existingByFilename.get(ticket.filename)\n return (prior && prior.done) ? { ...prior } : ticket\n }),\n }\n}\n\nexport function renderProgress (data:ProgressData):string {\n const lines:Array<string> = [\n `# Progress: ${data.feature}`,\n '',\n `Started: ${data.startedAt}`,\n '',\n ]\n\n for (const ticket of data.tickets) {\n const checkbox = ticket.done ? '[x]' : '[ ]'\n lines.push(`- ${checkbox} ${ticket.filename}`)\n\n if (ticket.done || ticket.exitCode !== null) {\n if (ticket.branch) {\n lines.push(\n ` branch: ${ticket.branch}`\n )\n }\n if (ticket.exitCode !== null) {\n lines.push(\n ` exit: ${ticket.exitCode}`\n )\n }\n if (ticket.completedAt) {\n lines.push(\n ` completed: ${ticket.completedAt}`\n )\n }\n }\n }\n\n return lines.join('\\n') + '\\n'\n}\n\nexport function checkTicket (\n data:ProgressData,\n ticketNum:number,\n result:{ branch:string; exitCode:number; done?:boolean }\n):void {\n const ticket = data.tickets.find(\n (t) => t.num === ticketNum\n )\n if (!ticket) return\n\n ticket.done = result.done ?? true\n ticket.branch = result.branch\n ticket.exitCode = result.exitCode\n if (ticket.done) {\n ticket.completedAt = new Date().toISOString()\n }\n}\n\nexport function writeProgress (\n progressPath:string,\n data:ProgressData\n):void {\n writeFileSync(\n progressPath,\n renderProgress(data)\n )\n}\n\nexport async function commitProgress (\n repoRoot:string,\n paths:string|string[],\n message:string\n):Promise<boolean> {\n const list = typeof paths === 'string' ?\n [paths] :\n paths\n await execFileAsync(\n 'git',\n ['add', '--force', '--', ...list],\n { cwd:repoRoot }\n )\n\n try {\n await execFileAsync(\n 'git',\n ['diff', '--cached', '--quiet', '--', ...list],\n { cwd:repoRoot }\n )\n return false\n } catch {\n // non-zero exit means the staged file differs from HEAD\n }\n\n await execFileAsync(\n 'git',\n ['commit', '-m', message, '--', ...list],\n { cwd:repoRoot }\n )\n return true\n}\n", "import { execFile } from 'node:child_process'\nimport { promisify } from 'node:util'\n\nconst execFileAsync = promisify(execFile)\n\nexport type MergeConflictStrategy = 'respawn'|'stop'\n\nexport type MergeResult = {\n branch:string\n ticketNum:number\n merged:boolean\n conflicted:boolean\n stderr?:string\n}\n\nexport type WaveMergeResult = {\n merged:Array<MergeResult>\n stoppedAt:MergeResult|null\n}\n\nexport type GitOpResult = {\n success:boolean\n stderr?:string\n}\n\nexport async function mergeBranch (\n repoRoot:string,\n branch:string\n):Promise<GitOpResult> {\n if (!repoRoot || typeof repoRoot !== 'string') {\n throw new Error('repoRoot must be a non-empty string')\n }\n if (!branch || typeof branch !== 'string') {\n throw new Error('branch must be a non-empty string')\n }\n\n try {\n await execFileAsync(\n 'git',\n ['merge', branch, '--no-edit'],\n { cwd:repoRoot }\n )\n return { success:true }\n } catch (err) {\n const execErr = err as {\n stdout?:string; stderr?:string\n }\n const stderr =\n execErr.stderr || execErr.stdout\n try {\n await execFileAsync(\n 'git',\n ['merge', '--abort'],\n { cwd:repoRoot }\n )\n } catch {\n // no merge in progress to abort\n }\n return { success:false, stderr }\n }\n}\n\nexport async function rebaseBranch (\n repoRoot:string,\n branch:string,\n onto:string,\n worktreePath?:string\n):Promise<GitOpResult> {\n if (!repoRoot || typeof repoRoot !== 'string') {\n throw new Error('repoRoot must be a non-empty string')\n }\n if (!branch || typeof branch !== 'string') {\n throw new Error('branch must be a non-empty string')\n }\n if (!onto || typeof onto !== 'string') {\n throw new Error('onto must be a non-empty string')\n }\n\n // When the branch has its own worktree, it is already checked\n // out there -- checking it out in repoRoot too would fail with\n // \"already used by worktree\", so rebase in place instead.\n if (worktreePath) {\n try {\n await execFileAsync(\n 'git',\n ['rebase', onto],\n { cwd:worktreePath }\n )\n return { success:true }\n } catch (err) {\n const execErr = err as {\n stdout?:string; stderr?:string\n }\n const stderr =\n execErr.stderr || execErr.stdout\n try {\n await execFileAsync(\n 'git',\n ['rebase', '--abort'],\n { cwd:worktreePath }\n )\n } catch {\n // ignore abort errors\n }\n return { success:false, stderr }\n }\n }\n\n try {\n await execFileAsync(\n 'git',\n ['checkout', branch],\n { cwd:repoRoot }\n )\n\n await execFileAsync(\n 'git',\n ['rebase', onto],\n { cwd:repoRoot }\n )\n\n await execFileAsync(\n 'git',\n ['checkout', onto],\n { cwd:repoRoot }\n )\n\n return { success:true }\n } catch (err) {\n const stderr =\n (err as { stderr?:string }).stderr\n try {\n await execFileAsync(\n 'git',\n ['rebase', '--abort'],\n { cwd:repoRoot }\n )\n } catch {\n // ignore abort errors\n }\n try {\n await execFileAsync(\n 'git',\n ['checkout', onto],\n { cwd:repoRoot }\n )\n } catch {\n // ignore checkout errors\n }\n return { success:false, stderr }\n }\n}\n\n// Merges baseBranch into the worktree's branch so a\n// respawned agent sees the latest code. Conflicts are\n// left in place (not aborted) so the agent can resolve\n// and commit them.\nexport async function updateWorktreeFromBase (\n worktreePath:string,\n baseBranch:string\n):Promise<void> {\n try {\n await execFileAsync(\n 'git',\n ['merge', baseBranch, '--no-edit'],\n { cwd:worktreePath }\n )\n } catch {\n // conflict markers intentionally left for the\n // respawned agent to resolve\n }\n}\n\nexport async function mergeWave (\n opts:Readonly<{\n repoRoot:string\n baseBranch:string\n branches:ReadonlyArray<{\n branch:string\n ticketNum:number\n worktreePath?:string\n }>\n strategy:MergeConflictStrategy\n }>\n):Promise<WaveMergeResult> {\n const { repoRoot, baseBranch, branches, strategy } = opts\n\n if (!repoRoot || typeof repoRoot !== 'string') {\n throw new Error('repoRoot must be a non-empty string')\n }\n if (!baseBranch || typeof baseBranch !== 'string') {\n throw new Error('baseBranch must be a non-empty string')\n }\n\n const merged:Array<MergeResult> = []\n let stoppedAt:MergeResult|null = null\n\n for (let i = 0; i < branches.length; i++) {\n const { branch, ticketNum, worktreePath } = branches[i]\n const mergingResult:MergeResult = {\n branch,\n ticketNum,\n merged:false,\n conflicted:false,\n }\n\n if (i === 0) {\n const result = await mergeBranch(\n repoRoot,\n branch\n )\n mergingResult.merged = result.success\n mergingResult.conflicted = !result.success\n if (!result.success) {\n mergingResult.stderr = result.stderr\n }\n\n if (!result.success) {\n if (strategy === 'stop') {\n stoppedAt = mergingResult\n merged.push(mergingResult)\n break\n }\n merged.push(mergingResult)\n continue\n }\n } else {\n const rebaseResult = await rebaseBranch(\n repoRoot,\n branch,\n baseBranch,\n worktreePath\n )\n\n if (!rebaseResult.success) {\n mergingResult.conflicted = true\n mergingResult.stderr = rebaseResult.stderr\n\n if (strategy === 'stop') {\n stoppedAt = mergingResult\n merged.push(mergingResult)\n break\n } else {\n // strategy === 'respawn'\n merged.push(mergingResult)\n continue\n }\n }\n\n const mergeResult = await mergeBranch(\n repoRoot,\n branch\n )\n mergingResult.merged = mergeResult.success\n mergingResult.conflicted = !mergeResult.success\n if (!mergeResult.success) {\n mergingResult.stderr = mergeResult.stderr\n }\n\n if (!mergeResult.success) {\n if (strategy === 'stop') {\n stoppedAt = mergingResult\n merged.push(mergingResult)\n break\n }\n merged.push(mergingResult)\n continue\n }\n }\n\n merged.push(mergingResult)\n }\n\n return {\n merged,\n stoppedAt,\n }\n}\n", "// Subagent counts and cost read from claude's stream-json output,\n// and the run-wide total. Pure: imports nothing, so the\n// orchestrator, display and tests can all use it.\n\nexport type SubagentStats = {\n subagents:number\n // absent until a `result` message reports it\n costUsd?:number\n}\n\nexport type StreamStatsState = {\n readonly stats:SubagentStats\n // tool_use ids already counted, so a repeated id counts once\n readonly seenToolIds:ReadonlySet<string>\n}\n\nexport type RunStats = {\n // spawnAgent results tallied\n readonly agentRuns:number\n // of those, how many reported a cost\n readonly withCost:number\n readonly subagents:number\n readonly costUsd:number\n}\n\n// Starting a subagent is a tool_use named `Agent`; Claude Code\n// named it `Task` before 2.1.63.\nconst SUBAGENT_TOOLS:ReadonlySet<string> = new Set(['Agent', 'Task'])\n\nexport function isRecord (value:unknown):value is Record<string, unknown> {\n return typeof value === 'object' &&\n value !== null &&\n !Array.isArray(value)\n}\n\nexport function emptyStreamStats ():StreamStatsState {\n return { stats:{ subagents:0 }, seenToolIds:new Set() }\n}\n\n/**\n * Fold one parsed stream-json value into the state. Returns the\n * same `state` object when nothing changed, so callers can detect\n * a change by identity. Never throws.\n */\nexport function nextStreamStats (\n state:StreamStatsState,\n obj:unknown\n):StreamStatsState {\n if (!isRecord(obj)) return state\n if (obj.type === 'assistant') return countSubagents(state, obj)\n if (obj.type === 'result') return applyResult(state, obj)\n return state\n}\n\nfunction countSubagents (\n state:StreamStatsState,\n obj:Record<string, unknown>\n):StreamStatsState {\n // A message from inside a subagent carries the id of the\n // tool_use that started it; only the main loop is counted.\n if (obj.parent_tool_use_id != null) return state\n const message = obj.message\n if (!isRecord(message) || !Array.isArray(message.content)) {\n return state\n }\n const ids:string[] = []\n for (const block of message.content) {\n if (!isRecord(block) || block.type !== 'tool_use') continue\n if (\n typeof block.name !== 'string' ||\n !SUBAGENT_TOOLS.has(block.name)\n ) continue\n if (typeof block.id !== 'string') continue\n if (state.seenToolIds.has(block.id)) continue\n if (ids.includes(block.id)) continue\n ids.push(block.id)\n }\n if (ids.length === 0) return state\n return {\n stats:{\n ...state.stats,\n subagents:state.stats.subagents + ids.length,\n },\n seenToolIds:new Set([...state.seenToolIds, ...ids]),\n }\n}\n\n// `total_cost_usd` is cumulative and a process can emit several\n// `result` messages, so the latest one replaces earlier values.\nfunction applyResult (\n state:StreamStatsState,\n obj:Record<string, unknown>\n):StreamStatsState {\n const cost = obj.total_cost_usd\n const hasCost = typeof cost === 'number' && Number.isFinite(cost)\n const subagentStats = obj.subagent_stats\n const spawned = isRecord(subagentStats) ?\n subagentStats.spawned :\n undefined\n const hasSpawned = typeof spawned === 'number' &&\n Number.isInteger(spawned) &&\n spawned >= 0\n if (!hasCost && !hasSpawned) return state\n\n const subagents = hasSpawned ?\n spawned :\n state.stats.subagents\n const costUsd = hasCost ?\n cost :\n state.stats.costUsd\n // A repeated result with the same values is not a change\n if (\n subagents === state.stats.subagents &&\n costUsd === state.stats.costUsd\n ) return state\n return {\n stats:costUsd === undefined ?\n { subagents } :\n { subagents, costUsd },\n seenToolIds:state.seenToolIds,\n }\n}\n\n// The running total of a ticket's attempts. A cost is kept as\n// soon as either side reports one.\nexport function addStats (\n total:SubagentStats,\n run:{ subagents?:number; costUsd?:number }\n):SubagentStats {\n const subagents = total.subagents + (run.subagents ?? 0)\n if (total.costUsd === undefined && run.costUsd === undefined) {\n return { subagents }\n }\n return {\n subagents,\n costUsd:(total.costUsd ?? 0) + (run.costUsd ?? 0),\n }\n}\n\n/**\n * The display row suffix, e.g. `2 subagents, $0.42`, or `null`\n * when there is nothing to show.\n */\nexport function formatStats (stats?:SubagentStats):string|null {\n if (!stats) return null\n if (stats.subagents === 0 && stats.costUsd === undefined) {\n return null\n }\n const count = `${stats.subagents} ` +\n (stats.subagents === 1 ? 'subagent' : 'subagents')\n return stats.costUsd === undefined ?\n count :\n `${count}, $${stats.costUsd.toFixed(2)}`\n}\n\nexport function emptyRunStats ():RunStats {\n return { agentRuns:0, withCost:0, subagents:0, costUsd:0 }\n}\n\nexport function addRun (\n run:RunStats,\n result:{ subagents?:number; costUsd?:number }\n):RunStats {\n return {\n agentRuns:run.agentRuns + 1,\n withCost:run.withCost + (result.costUsd === undefined ? 0 : 1),\n subagents:run.subagents + (result.subagents ?? 0),\n costUsd:run.costUsd + (result.costUsd ?? 0),\n }\n}\n\n/**\n * The one-line total logged after the finish summary, or `null`\n * when no run reported a subagent or a cost (codex and pi never\n * do).\n */\nexport function renderRunStats (run:RunStats):string|null {\n if (run.agentRuns === 0) return null\n if (run.withCost === 0 && run.subagents === 0) return null\n const runs = `${run.agentRuns} agent ` +\n (run.agentRuns === 1 ? 'run' : 'runs')\n const partial = run.withCost < run.agentRuns ?\n ` (cost from ${run.withCost} of ${run.agentRuns} runs)` :\n ''\n return `Subagents: ${run.subagents} started across ${runs}, ` +\n `cost $${run.costUsd.toFixed(2)}${partial}`\n}\n", "import { formatStats, type SubagentStats } from './stats.js'\n\nexport type TicketStatus =\n | 'pending'\n | 'in-progress'\n | 'awaiting-merge'\n | 'done'\n | 'failed'\n | 'blocked'\n\nexport type DisplayTicket = {\n readonly num:number\n readonly filename:string\n readonly feature?:string\n status:TicketStatus\n blockedBy?:ReadonlyArray<string>\n stats?:SubagentStats\n}\n\nexport type TicketRef = {\n readonly num:number\n readonly filename:string\n readonly feature?:string\n}\n\nexport type WaveState = {\n readonly waveNum:number\n readonly totalWaves:number\n}\n\nexport type DisplayConfig = {\n readonly stream:NodeJS.WriteStream\n}\n\n/**\n * Progress across the whole run, not just the current wave.\n * `completed` counts this run's tickets done before the wave\n * started; `total` is the size of this run's ticket list. Only\n * PlainDisplay prints it; StatusDisplay counts from its own list.\n */\nexport type RunProgress = {\n readonly completed:number\n readonly total:number\n}\n\nexport type Display = {\n /**\n * Called once at the start of the run, fixes the ticket list\n * for the entire session.\n */\n startRun(tickets:ReadonlyArray<TicketRef>):void\n startWave(\n waveNum:number,\n totalWaves:number,\n tickets:ReadonlyArray<TicketRef>,\n progress?:RunProgress,\n ):void\n setTicketStatus(\n num:number,\n status:TicketStatus,\n feature?:string,\n ):void\n /**\n * Mark a ticket as blocked; `blockedBy` holds display labels\n * of the upstream tickets that failed or need a human.\n */\n setBlocked(\n num:number,\n feature:string|undefined,\n blockedBy:ReadonlyArray<string>,\n ):void\n /**\n * Subagent stats for a ticket's row: the running total of\n * its attempts so far.\n */\n setTicketStats(\n num:number,\n feature:string|undefined,\n stats:SubagentStats,\n ):void\n log(message:string):void\n cleanup():void\n}\n\nconst ESC = '\\x1b['\n\nexport const ansi = {\n cursorUp (n:number):string {\n return `${ESC}${n}A`\n },\n cursorTo (col:number):string {\n return `${ESC}${col}G`\n },\n eraseLine ():string {\n return `${ESC}2K`\n },\n eraseLines (n:number):string {\n let out = ''\n for (let i = 0; i < n; i++) {\n out += ansi.eraseLine()\n if (i < n - 1) out += ansi.cursorUp(1)\n }\n return out\n },\n cursorHide ():string {\n return `${ESC}?25l`\n },\n cursorShow ():string {\n return `${ESC}?25h`\n },\n} as const\n\nexport const color = {\n green (text:string):string {\n return `${ESC}32m${text}${ESC}0m`\n },\n yellow (text:string):string {\n return `${ESC}33m${text}${ESC}0m`\n },\n red (text:string):string {\n return `${ESC}31m${text}${ESC}0m`\n },\n cyan (text:string):string {\n return `${ESC}36m${text}${ESC}0m`\n },\n dim (text:string):string {\n return `${ESC}2m${text}${ESC}0m`\n },\n} as const\n\nexport function ticketLabel (\n ticket:{ num:number; filename:string; feature?:string },\n):string {\n if (ticket.feature) {\n const padded = String(ticket.num).padStart(2, '0')\n return `${ticket.feature}/${padded}`\n }\n return ticket.filename\n}\n\nconst FILLED_DOT = '\u25CF'\nconst EMPTY_DOT = '\u25CB'\nconst SEPARATOR_WIDTH = 50\nconst DEFAULT_COLUMNS = 80\nconst MIN_LOG_ROWS = 1\nconst MAX_MESSAGE_BUFFER = 200\n\n// eslint-disable-next-line no-control-regex\nconst ANSI_RE = /\\x1b\\[[0-9;?]*[A-Za-z]/g\n\nfunction rowText (ticket:DisplayTicket):string {\n const label = ticketLabel(ticket)\n const base = ticket.status === 'blocked' &&\n ticket.blockedBy?.length ?\n `${label} (blocked by ${ticket.blockedBy.join(', ')})` :\n label\n const suffix = formatStats(ticket.stats)\n return suffix === null ? base : `${base} - ${suffix}`\n}\n\n/**\n * Clamp a line to `width` visible columns so it can never wrap.\n * A wrapped line occupies more terminal rows than `render`\n * counts, which leaves stale rows behind on the next erase.\n */\nexport function fitLine (line:string, width:number):string {\n const visible = line.replace(ANSI_RE, '')\n if (visible.length <= width) return line\n return visible.slice(0, width)\n}\n\n/**\n * Split a line into rows of at most `width` visible columns,\n * the way a terminal would wrap it. Short lines keep their\n * ANSI styling; long lines are wrapped on visible text only,\n * so `render` can count every row it emits.\n */\nexport function wrapLine (line:string, width:number):Array<string> {\n const visible = line.replace(ANSI_RE, '')\n if (visible.length <= width) return [line]\n const rows:Array<string> = []\n for (let i = 0; i < visible.length; i += width) {\n rows.push(visible.slice(i, i + width))\n }\n return rows\n}\n\nexport function renderDot (status:TicketStatus):string {\n switch (status) {\n case 'pending':\n return color.dim(EMPTY_DOT)\n case 'in-progress':\n return color.yellow(FILLED_DOT)\n // The agent and its test gate are finished; the branch\n // waits for the rest of the wave before it is merged. It\n // stays cyan through the merge and any conflict respawn.\n case 'awaiting-merge':\n return color.cyan(FILLED_DOT)\n case 'done':\n return color.green(FILLED_DOT)\n case 'failed':\n return color.red(FILLED_DOT)\n case 'blocked':\n // Ticket cannot run this session because an upstream\n // ticket failed or needs a human.\n return color.dim(FILLED_DOT)\n }\n}\n\nexport class StatusDisplay implements Display {\n private wave:WaveState|null = null\n private tickets:Array<DisplayTicket> = []\n private hasRun:boolean = false\n private messages:Array<string> = []\n private renderedLines:number = 0\n private config:DisplayConfig\n private viewportStart:number = 0\n private resizeListener:(() => void)|null = null\n\n constructor (config?:Readonly<Partial<DisplayConfig>>) {\n this.config = {\n stream:config?.stream ?? process.stdout,\n }\n }\n\n private getAvailableRows ():number {\n const termHeight = this.config.stream.rows ?? 24\n const overhead = 2 + MIN_LOG_ROWS\n const available = termHeight - overhead\n return Math.max(1, available)\n }\n\n private findTicket (\n num:number,\n feature?:string,\n ):DisplayTicket|null {\n const found = feature ?\n this.tickets.find(\n t => t.num === num && t.feature === feature,\n ) :\n this.tickets.find(t => t.num === num)\n return found ?? null\n }\n\n startRun (tickets:ReadonlyArray<TicketRef>):void {\n this.tickets = tickets.map(t => ({\n ...t,\n status:'pending' as const,\n }))\n this.hasRun = true\n this.viewportStart = 0\n }\n\n startWave (\n waveNum:number,\n totalWaves:number,\n tickets:ReadonlyArray<TicketRef>,\n _progress?:RunProgress,\n ):void {\n if (!this.hasRun) {\n this.startRun(tickets)\n }\n\n this.wave = {\n waveNum,\n totalWaves,\n }\n this.messages = []\n this.viewportStart = 0\n this.config.stream.write(ansi.cursorHide())\n\n if (this.config.stream.isTTY) {\n if (this.resizeListener) {\n this.config.stream.removeListener(\n 'resize', this.resizeListener,\n )\n }\n this.resizeListener = () => this.render()\n this.config.stream.on(\n 'resize', this.resizeListener,\n )\n }\n\n this.render()\n }\n\n setTicketStatus (\n num:number,\n status:TicketStatus,\n feature?:string,\n ):void {\n const ticket = this.findTicket(num, feature)\n if (!ticket) return\n\n ticket.status = status\n\n if (status === 'in-progress') {\n const ticketIndex = this.tickets.indexOf(ticket)\n const availableRows = this.getAvailableRows()\n const totalTickets = this.tickets.length\n\n if (ticketIndex < this.viewportStart) {\n this.viewportStart = ticketIndex\n } else if (ticketIndex >= this.viewportStart + availableRows) {\n // offset by 3 to keep context visible below\n // the active ticket\n this.viewportStart = ticketIndex - availableRows + 3\n }\n this.viewportStart = Math.max(\n 0,\n Math.min(this.viewportStart, totalTickets - 1),\n )\n }\n\n this.render()\n }\n\n setBlocked (\n num:number,\n feature:string|undefined,\n blockedBy:ReadonlyArray<string>,\n ):void {\n const ticket = this.findTicket(num, feature)\n if (!ticket) return\n\n ticket.status = 'blocked'\n ticket.blockedBy = [...blockedBy]\n this.render()\n }\n\n setTicketStats (\n num:number,\n feature:string|undefined,\n stats:SubagentStats,\n ):void {\n const ticket = this.findTicket(num, feature)\n if (!ticket) return\n\n ticket.stats = { ...stats }\n this.render()\n }\n\n log (message:string):void {\n // Before the first wave there is no grid to repaint,\n // so a message would otherwise be dropped. Write it\n // straight to the stream instead. A later render\n // never erases these rows, since renderedLines is 0.\n if (!this.wave) {\n this.config.stream.write(message + '\\n')\n return\n }\n for (const line of message.split('\\n')) {\n this.messages.push(line)\n }\n while (this.messages.length > MAX_MESSAGE_BUFFER) {\n this.messages.shift()\n }\n this.render()\n }\n\n cleanup ():void {\n // Remove resize listener if it exists\n if (this.resizeListener && this.config.stream.isTTY) {\n this.config.stream.removeListener('resize', this.resizeListener)\n }\n this.config.stream.write(ansi.cursorShow())\n }\n\n private render ():void {\n if (!this.wave) return\n\n let output = ''\n\n if (this.renderedLines > 0) {\n output += ansi.eraseLines(this.renderedLines + 1)\n }\n\n const done = this.tickets.filter(\n t => t.status === 'done',\n ).length\n const total = this.tickets.length\n const pct = total === 0 ? 0 : Math.round((done / total) * 100)\n const width = Math.max(\n 1,\n (this.config.stream.columns ?? DEFAULT_COLUMNS) - 1,\n )\n\n const header = `Wave ${this.wave.waveNum}/` +\n `${this.wave.totalWaves} - ` +\n `${done}/${total} done - ${pct}%`\n output += fitLine(header, width) + '\\n'\n\n // Pagination logic\n const availableRows = this.getAvailableRows()\n let renderedTicketCount = 0\n\n if (this.tickets.length <= availableRows) {\n // All tickets fit, no pagination\n for (const ticket of this.tickets) {\n const dot = renderDot(ticket.status)\n const text = rowText(ticket)\n const name = fitLine(text, width - 2)\n output += `${dot} ${name}\\n`\n }\n renderedTicketCount = this.tickets.length\n } else {\n // Need pagination -- iterative clamp\n this.viewportStart = Math.max(\n 0,\n Math.min(\n this.viewportStart,\n this.tickets.length - 1,\n ),\n )\n\n let hasMoreAbove = this.viewportStart > 0\n let tentativeCount =\n availableRows - (hasMoreAbove ? 1 : 0)\n let hasMoreBelow =\n this.viewportStart + tentativeCount <\n this.tickets.length\n let ticketsToShow = Math.max(\n 0,\n tentativeCount - (hasMoreBelow ? 1 : 0),\n )\n\n const maxStart = Math.max(\n 0,\n this.tickets.length - Math.max(1, ticketsToShow),\n )\n if (this.viewportStart > maxStart) {\n this.viewportStart = maxStart\n hasMoreAbove = this.viewportStart > 0\n tentativeCount = availableRows - (hasMoreAbove ? 1 : 0)\n hasMoreBelow = (\n this.viewportStart +\n tentativeCount < this.tickets.length\n )\n ticketsToShow = Math.max(\n 0,\n tentativeCount - (hasMoreBelow ? 1 : 0)\n )\n }\n\n // Show \"more above\" indicator if needed\n if (hasMoreAbove) {\n const moreCount = this.viewportStart\n output += ` ... ${moreCount} more above\\n`\n }\n\n // Get visible tickets and render them\n const visibleTickets = this.tickets.slice(\n this.viewportStart,\n this.viewportStart + ticketsToShow,\n )\n\n for (const ticket of visibleTickets) {\n const dot = renderDot(ticket.status)\n const text = rowText(ticket)\n const name = fitLine(text, width - 2)\n output += `${dot} ${name}\\n`\n }\n\n // Show \"more below\" indicator if needed\n if (hasMoreBelow) {\n const moreCount = (\n this.tickets.length -\n (this.viewportStart + ticketsToShow)\n )\n output += ` ... ${moreCount} more below\\n`\n }\n\n renderedTicketCount = (hasMoreAbove ? 1 : 0) +\n visibleTickets.length +\n (hasMoreBelow ? 1 : 0)\n }\n\n output += '-'.repeat(Math.min(SEPARATOR_WIDTH, width)) + '\\n'\n\n const termHeight = this.config.stream.rows ?? 24\n const logRows = Math.max(\n 0,\n termHeight - 3 - renderedTicketCount,\n )\n const wrapped = this.messages.flatMap(\n msg => wrapLine(msg, width),\n )\n const visibleMessages = wrapped.slice(-logRows)\n for (const row of visibleMessages) {\n output += `${row}\\n`\n }\n const emptyRows = logRows - visibleMessages.length\n for (let i = 0; i < emptyRows; i++) {\n output += '\\n'\n }\n\n this.renderedLines = 2 + renderedTicketCount + logRows\n this.config.stream.write(output)\n }\n}\n\nexport class PlainDisplay implements Display {\n startRun (_tickets:ReadonlyArray<TicketRef>):void {\n // no-op: plain mode has no fixed list\n }\n\n startWave (\n waveNum:number,\n _totalWaves:number,\n tickets:ReadonlyArray<TicketRef>,\n progress?:RunProgress,\n ):void {\n const pct = progress && progress.total > 0 ?\n ` (${progress.completed}/${progress.total} done)` :\n ''\n console.log(\n `\\nWave ${waveNum}${pct}: ` +\n tickets.map(t => ticketLabel(t)).join(', ')\n )\n }\n\n setTicketStatus (\n _num:number,\n _status:TicketStatus,\n _feature?:string,\n ):void {\n // no-op: plain mode reports via log()\n }\n\n setBlocked (\n _num:number,\n _feature:string|undefined,\n _blockedBy:ReadonlyArray<string>,\n ):void {\n // no-op: plain mode has no fixed list\n }\n\n setTicketStats (\n _num:number,\n _feature:string|undefined,\n _stats:SubagentStats,\n ):void {\n // no-op: plain mode has no fixed list\n }\n\n log (message:string):void {\n console.log(message)\n }\n\n cleanup ():void {\n // no-op\n }\n}\n\nexport function createDisplay (stream?:NodeJS.WriteStream):Display {\n const s = stream ?? process.stdout\n if (s.isTTY) {\n return new StatusDisplay({ stream:s })\n }\n\n return new PlainDisplay()\n}\n", "import { spawn } from 'node:child_process'\nimport { existsSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\nexport type TestResult = {\n exitCode:number\n output:string\n}\n\n// Returns the command to run the project's tests, or null\n// when the project does not declare one.\nexport function detectTestCmd (projectDir:string):string|null {\n const pkgPath = join(projectDir, 'package.json')\n if (!existsSync(pkgPath)) return null\n try {\n const pkg = JSON.parse(\n readFileSync(pkgPath, 'utf8')\n ) as { scripts?:Record<string, string> }\n return pkg.scripts?.test ?\n 'npm test' :\n null\n } catch {\n return null\n }\n}\n\n// Returns the command that installs dependencies in a fresh\n// worktree, or null when the project has no package.json.\n// Follows the project's lockfile, so the worktree gets the\n// same dependency tree as the main checkout, and never\n// writes a lockfile a ticket branch would then commit.\nexport function detectInstallCmd (projectDir:string):string|null {\n const has = (name:string) => existsSync(join(projectDir, name))\n if (!has('package.json')) return null\n if (has('pnpm-lock.yaml')) {\n return 'pnpm install --prefer-offline --frozen-lockfile'\n }\n if (has('package-lock.json')) {\n return 'npm ci --prefer-offline --no-audit --no-fund'\n }\n return 'npm install --prefer-offline --no-audit ' +\n '--no-fund --no-package-lock'\n}\n\nexport function runTestCmd (opts:{\n cmd:string\n cwd:string\n timeout:number\n registry?:Set<number>\n}):Promise<TestResult> {\n return new Promise(resolve => {\n let settled = false\n const child = spawn('sh', ['-c', opts.cmd], {\n cwd:opts.cwd,\n stdio:['ignore', 'pipe', 'pipe'],\n detached:true,\n })\n\n if (child.pid !== undefined && opts.registry) {\n opts.registry.add(child.pid)\n }\n\n const chunks:string[] = []\n child.stdout.on('data', d => chunks.push(String(d)))\n child.stderr.on('data', d => chunks.push(String(d)))\n\n const timer = setTimeout(() => {\n if (child.pid) {\n try {\n process.kill(-child.pid, 'SIGKILL')\n } catch {\n child.kill('SIGKILL')\n }\n } else {\n child.kill('SIGKILL')\n }\n }, opts.timeout * 1000)\n\n child.on('error', err => {\n if (settled) return\n settled = true\n clearTimeout(timer)\n if (child.pid !== undefined && opts.registry) {\n opts.registry.delete(child.pid)\n }\n chunks.push(String(err))\n resolve({\n exitCode:1,\n output:chunks.join(''),\n })\n })\n\n child.on('close', code => {\n if (settled) return\n settled = true\n clearTimeout(timer)\n if (child.pid !== undefined && opts.registry) {\n opts.registry.delete(child.pid)\n }\n resolve({\n exitCode:code ?? 1,\n output:chunks.join(''),\n })\n })\n })\n}\n", "import {\n appendFileSync,\n existsSync,\n mkdirSync,\n readFileSync,\n rmSync,\n writeFileSync,\n} from 'node:fs'\nimport { basename, dirname, join } from 'node:path'\n\n// -- Constants and types --\n\nexport const MAX_OWN_ENTRIES = 4\nexport const MAX_ENTRY_CHARS = 4000\nexport const LOG_TAIL_LINES = 40\nexport const NOTES_PATH = '.nightralph/notes.md'\n\nconst SENTINEL_PREFIX = '<!-- nightralph:entry'\nexport const TRUNCATED_MARKER = '[truncated]'\n\nexport const LEARNING_OUTCOMES = [\n 'done',\n 'exit',\n 'tests',\n 'install',\n 'no-commits',\n 'error',\n 'merge',\n] as const\nexport type LearningOutcome = typeof LEARNING_OUTCOMES[number]\n\nexport type LearningEntry = {\n key:string\n attempt:number\n outcome:LearningOutcome\n timedOut:boolean\n // Everything after the sentinel line, trimmed, without\n // the trailing `---` separator\n body:string\n}\n\ntype EntryBase = {\n key:string // ticketKey(feature, num)\n label:string // ticketLabel(ticket), e.g. \"my-feature/04\"\n attempt:number // 0 for merge entries\n now:Date\n}\n\n// What one agent process did: its exit code, the items it reported,\n// whether it was killed at the timeout, and the notes it left.\nexport type AgentRunRecord = {\n exitCode:number\n completedItems:string[]\n timedOut:boolean\n notes:string|null\n // claude only; absent = not reported\n subagents?:number\n costUsd?:number\n}\n\ntype AgentFields = { run:AgentRunRecord; effort?:string }\n\ntype LogTail = { logName:string; logTail:string }\n\nexport type EntryInput = EntryBase&(\n | (AgentFields&{ outcome:'done'|'exit'|'no-commits' })\n | (AgentFields&LogTail&{ outcome:'tests' })\n | (LogTail&{ outcome:'install' })\n | { outcome:'error'; error:string }\n | { outcome:'merge'; stderr:string }\n)\n\nexport type HistorySelection = {\n own:LearningEntry[]\n blockers:LearningEntry[]\n}\n\n// -- Helpers --\n\nfunction encodeKey (key:string):string {\n return key\n .replace(/%/g, '%25')\n .replace(/\\s/g, c => encodeURIComponent(c))\n}\n\nfunction fence (content:string):string {\n const longest = Math.max(\n 0,\n ...[...content.matchAll(/`+/g)].map(m => m[0].length)\n )\n const ticks = '`'.repeat(Math.max(3, longest + 1))\n return `${ticks}\\n${content}\\n${ticks}`\n}\n\nfunction sanitize (text:string|null):string {\n if (!text) return ''\n return text.replace(\n new RegExp(SENTINEL_PREFIX, 'g'),\n '<!-- nightralph-entry'\n )\n}\n\nfunction renderAgentSummary (\n run:AgentRunRecord,\n effort?:string\n):string {\n const effortLine = effort ?\n `Effort: ${effort}.` :\n ''\n\n const exitLine = `Agent exit: ${run.exitCode}.`\n\n const subagentsLine = run.subagents === undefined ?\n '' :\n `Subagents: ${run.subagents}.`\n\n const costLine = run.costUsd === undefined ?\n '' :\n `Cost: $${run.costUsd.toFixed(2)}.`\n\n const itemsText = run.completedItems.length > 0 ?\n run.completedItems.map(item =>\n `\"${sanitize(item)}\"`\n ).join(', ') + '.' :\n 'none.'\n\n const itemsLine = `Checked items: ${itemsText}`\n\n return [\n effortLine,\n exitLine,\n subagentsLine,\n costLine,\n itemsLine,\n ].filter(Boolean).join(' ')\n}\n\nfunction renderNotesSection (notes:string|null):string {\n const notesSanitized = sanitize(notes)\n return notesSanitized.trim() ?\n `### Agent notes\\n${notesSanitized}` :\n 'The agent left no notes.'\n}\n\nexport function formatDate (date:Date):string {\n const year = date.getFullYear()\n const month = String(date.getMonth() + 1).padStart(2, '0')\n const day = String(date.getDate()).padStart(2, '0')\n const hours = String(date.getHours()).padStart(2, '0')\n const minutes = String(date.getMinutes()).padStart(2, '0')\n return `${year}-${month}-${day} ${hours}:${minutes}`\n}\n\nexport function isLearningOutcome (\n value:string\n):value is LearningOutcome {\n return LEARNING_OUTCOMES.some(o => o === value)\n}\n\nexport function renderEntry (input:EntryInput):string {\n const encodedKey = encodeKey(input.key)\n\n const hasRun = 'run' in input\n const timedOut = hasRun && input.run.timedOut\n\n const timedOutStr = timedOut ?\n ' timedout=true' :\n ''\n\n const sentinel =\n `<!-- nightralph:entry ticket=${encodedKey} ` +\n `attempt=${input.attempt} outcome=${input.outcome}` +\n `${timedOutStr} -->`\n\n const timestamp = formatDate(input.now)\n const attemptStr = input.outcome === 'merge' ?\n '' :\n ` attempt ${input.attempt}`\n\n let description:string\n\n switch (input.outcome) {\n case 'done':\n description = 'done'\n break\n case 'exit':\n description = `failed (exit ${input.run.exitCode})`\n break\n case 'tests':\n description = 'failed (tests)'\n break\n case 'install':\n description = 'failed (install)'\n break\n case 'no-commits':\n description = 'no commits'\n break\n case 'error':\n description = 'error'\n break\n case 'merge':\n description = 'merge failed'\n break\n default: {\n const _exhaustive:never = input\n description = _exhaustive\n }\n }\n\n const timedOutPrefix = timedOut ?\n 'timed out, then ' :\n ''\n\n const heading =\n `## ${timestamp} -- ${input.label}${attemptStr} -- ` +\n `${timedOutPrefix}${description}`\n\n let body:string\n\n switch (input.outcome) {\n case 'done':\n case 'exit':\n case 'no-commits': {\n const run = input.run\n const summary = renderAgentSummary(run, input.effort)\n const notesSection = renderNotesSection(run.notes)\n body = summary + '\\n\\n' + notesSection\n break\n }\n case 'tests': {\n const logTail = sanitize(input.logTail)\n const fenced = fence(logTail)\n const summary = renderAgentSummary(\n input.run,\n input.effort\n )\n const notesSection = renderNotesSection(input.run.notes)\n\n const lastNLines =\n `Last ${LOG_TAIL_LINES} lines of ` +\n `\\`${sanitize(input.logName)}\\`:`\n\n body =\n summary + '\\n\\n' +\n 'Test gate failed.\\n' +\n `${lastNLines}\\n` +\n `${fenced}\\n\\n` +\n notesSection\n break\n }\n case 'install': {\n const logTail = sanitize(input.logTail)\n const fenced = fence(logTail)\n\n const lastNLines =\n `Last ${LOG_TAIL_LINES} lines of ` +\n `\\`${sanitize(input.logName)}\\`:`\n\n body =\n 'Install failed.\\n' +\n `${lastNLines}\\n` +\n fenced\n break\n }\n case 'error': {\n const errorText = sanitize(input.error)\n const fenced = fence(errorText)\n body = fenced\n break\n }\n case 'merge': {\n const stderrText = sanitize(input.stderr)\n const fenced = fence(stderrText)\n body = `Merge failed.\\n${fenced}`\n break\n }\n default: {\n const unknown:never = input\n throw new Error(`Unknown outcome: ${JSON.stringify(unknown)}`)\n }\n }\n\n return `${sentinel}\\n${heading}\\n\\n${body}\\n\\n---\\n`\n}\n\nexport function parseEntries (text:string):LearningEntry[] {\n const lines = text.split('\\n').map(line => {\n // Strip trailing \\r for CRLF support\n return line.endsWith('\\r') ? line.slice(0, -1) : line\n })\n const entries:LearningEntry[] = []\n\n let currentSentinel:string|null = null\n let currentBody:string[] = []\n\n const sentinelRegex = /^<!-- nightralph:entry (.*) -->$/\n\n for (const line of lines) {\n const match = line.match(sentinelRegex)\n\n if (match) {\n // Process previous entry if exists\n if (currentSentinel !== null) {\n const entry = parseSentinel(currentSentinel, currentBody)\n if (entry) {\n entries.push(entry)\n }\n }\n\n currentSentinel = match[1]\n currentBody = []\n } else if (currentSentinel !== null) {\n currentBody.push(line)\n }\n }\n\n // Process last entry\n if (currentSentinel !== null) {\n const entry = parseSentinel(currentSentinel, currentBody)\n if (entry) {\n entries.push(entry)\n }\n }\n\n return entries\n}\n\nfunction parseSentinel (\n sentinel:string,\n bodyLines:string[]\n):LearningEntry|null {\n const parts = sentinel.split(/\\s+/).filter(Boolean)\n const attrs:Record<string, string> = {}\n\n for (const part of parts) {\n const idx = part.indexOf('=')\n if (idx > 0) {\n const key = part.slice(0, idx)\n const value = part.slice(idx + 1)\n if (value) {\n attrs[key] = value\n }\n }\n }\n\n // Validate ticket\n let key = attrs.ticket\n if (!key) return null\n\n try {\n key = decodeURIComponent(key)\n } catch (_e) {\n return null\n }\n\n if (!key.trim()) return null\n\n // Validate attempt\n const attemptStr = attrs.attempt\n if (!attemptStr) return null\n\n if (!/^\\d+$/.test(attemptStr)) return null\n const attempt = Number(attemptStr)\n\n // Validate outcome\n const outcome = attrs.outcome\n if (!outcome || !isLearningOutcome(outcome)) return null\n\n // Parse timedOut\n const timedOut = attrs.timedout === 'true'\n\n // Parse body\n let body = bodyLines.join('\\n').trim()\n\n // Remove trailing --- line (full line only)\n const lines = body.split('\\n')\n if (lines.length > 0 && lines[lines.length - 1] === '---') {\n body = lines.slice(0, -1).join('\\n').trim()\n }\n\n return {\n key,\n attempt,\n outcome,\n timedOut,\n body,\n }\n}\n\nexport function selectHistory (\n entries:LearningEntry[],\n opts:{ key:string; blockerKeys:string[] }\n):HistorySelection {\n const own = entries\n .filter(e => e.key === opts.key)\n .slice(-MAX_OWN_ENTRIES)\n\n const blockers = opts.blockerKeys.flatMap(k => {\n const done = entries.filter(e => {\n return e.key === k && e.outcome === 'done'\n })\n const last = done[done.length - 1]\n return last ? [last] : []\n })\n\n return { own, blockers }\n}\n\nexport function renderHistory (selection:HistorySelection):string {\n if (selection.own.length === 0 && selection.blockers.length === 0) {\n return ''\n }\n\n const framing =\n 'These are records of earlier runs. The ticket or spec may ' +\n 'have changed since then; where they disagree, follow the ' +\n 'ticket and spec. Do not repeat an approach these notes say ' +\n 'failed unless you can see why it failed.'\n\n const parts = [framing, '']\n\n if (selection.own.length > 0) {\n parts.push('---- PREVIOUS ATTEMPTS AT THIS TICKET ----')\n parts.push(selection.own.map(e => capEntry(e)).join('\\n\\n'))\n parts.push('')\n }\n\n if (selection.blockers.length > 0) {\n parts.push('---- WHAT THE BLOCKING TICKETS DID ----')\n parts.push(selection.blockers.map(e => capEntry(e)).join('\\n\\n'))\n }\n\n return parts.join('\\n')\n}\n\nfunction capEntry (entry:LearningEntry):string {\n if (entry.body.length <= MAX_ENTRY_CHARS) {\n return entry.body\n }\n\n return entry.body.slice(0, MAX_ENTRY_CHARS) + '\\n' + TRUNCATED_MARKER\n}\n\nexport function tailLines (text:string, n:number):string {\n let lines = text.split('\\n')\n\n // Remove empty string at end if text ended with newline\n if (lines.length > 0 && lines[lines.length - 1] === '') {\n lines = lines.slice(0, -1)\n }\n\n // Keep last n\n if (lines.length > n) {\n lines = lines.slice(-n)\n }\n\n return lines.join('\\n')\n}\n\nexport function learningsPathFor (progressPath:string):string {\n return join(dirname(progressPath), 'learnings.md')\n}\n\n// -- IO functions --\n\n// A missing log means no history yet. Any other read error (e.g.\n// the path is a directory) is thrown for the caller to report.\nexport function readEntries (path:string):LearningEntry[] {\n if (!existsSync(path)) return []\n return parseEntries(readFileSync(path, 'utf8'))\n}\n\n// Synchronous on purpose: tickets in a wave run concurrently in one\n// Node thread, so sync appends can never interleave.\nexport function appendEntry (path:string, text:string):void {\n mkdirSync(dirname(path), { recursive:true })\n appendFileSync(path, text)\n}\n\n// Reads one file from the worktree's notes directory (the notes\n// by default), then removes the whole directory (also when the\n// file is missing), so nothing in it can reach a commit. Blank\n// text counts as none.\nexport function collectNotes (\n worktreePath:string,\n file:string = basename(NOTES_PATH)\n):string|null {\n const dir = join(worktreePath, dirname(NOTES_PATH))\n const path = join(dir, file)\n const text = existsSync(path) ?\n readFileSync(path, 'utf8').trim() :\n ''\n rmSync(dir, { recursive:true, force:true })\n return text || null\n}\n\n// Makes the notes directory ignore itself, so an agent's\n// `git add -A` cannot stage its notes. Deliberately not\n// info/exclude: that file can be a symlink shared by every repo on\n// the machine (e.g. via init.templateDir).\nexport function ensureNotesIgnored (worktreePath:string):void {\n const dir = join(worktreePath, dirname(NOTES_PATH))\n mkdirSync(dir, { recursive:true })\n writeFileSync(join(dir, '.gitignore'), '*\\n')\n}\n", "import { NOTES_PATH } from './learnings.js'\n\n// Rule lines shared by the agent prompts. `unit` is what the agent\n// commits one at a time (\"checklist item\", \"finding\"); `subject` is\n// what the orchestrator accepts or rejects (\"ticket\", \"fix\").\n\nexport function readDocsRule (subject:string):string {\n return '- Read the files directly relevant to the ' +\n `${subject} before writing code. Also read any ` +\n 'AGENTS.md in or above the directories you ' +\n 'will touch, plus CONTEXT.md and the ' +\n 'relevant docs/adr/ entries if they exist. ' +\n 'If they do not exist, proceed silently.'\n}\n\n// The rule for agents in a worktree the orchestrator has\n// already installed dependencies into. Empty without one.\nexport function installRule (installCmd?:string):string[] {\n if (!installCmd) return []\n return [\n '- Dependencies are already installed with ' +\n `\\`${installCmd}\\`. Do NOT reinstall them ` +\n 'with any other command; to reinstall, run ' +\n 'that same command. To add a dependency, use ' +\n 'the package manager that command uses, so ' +\n 'its lockfile stays in sync.',\n ]\n}\n\n// The delegation rule for agents whose subagents default to a\n// cheaper model (CLAUDE_CODE_SUBAGENT_MODEL). Empty without one.\n// `readOnly` drops the edit/commit line, for the reviewer, which\n// never edits.\nexport function subagentRule (\n preferSubagent?:string,\n readOnly = false\n):string[] {\n if (!preferSubagent) return []\n return [\n '- Hand read-only work to subagents: exploring the ' +\n 'codebase, searching code, and experiments or test ' +\n 'runs whose output would flood your context. ' +\n `Subagents default to the ${preferSubagent} model.`,\n '- A subagent starts with no context. Brief each one ' +\n 'with the objective, what you already know, its ' +\n 'boundaries, and the reply you expect (file:line ' +\n 'references, or pass/fail with the relevant output).',\n ...(readOnly ? [] : [\n '- Subagents never edit files or run git commands ' +\n 'that write. You make every edit and every commit.',\n ]),\n '- Do not delegate a lookup that takes a single tool call.',\n ]\n}\n\nexport function testGateRule (testCmd:string, subject:string):string {\n if (testCmd === '') {\n return '- Before each commit, run the tests relevant ' +\n 'to what you changed. Do not commit with failing ' +\n 'tests. The orchestrator runs no test command ' +\n `for this ${subject}.`\n }\n return '- While iterating, run only the tests ' +\n 'relevant to what you changed. Run ' +\n `\\`${testCmd}\\` in full once, as the ` +\n 'final gate before your last commit. Do ' +\n 'not commit with failing tests. The ' +\n 'orchestrator runs the same command after ' +\n `you exit and rejects the ${subject} if it ` +\n 'fails.'\n}\n\nexport const LINT_RULE = '- If the project has a lint script, run it ' +\n 'and fix what it reports.'\n\nexport function integrityRule (unit:string):string {\n return '- INTEGRITY: never delete, skip, weaken, or ' +\n 'write tautological tests to force a green ' +\n `result. Only report a ${unit} done ` +\n 'when its real tests genuinely pass. If an ' +\n 'item cannot be completed honestly, leave ' +\n 'it unchecked and record what blocked you ' +\n 'in your notes file.'\n}\n\nexport const CONFINEMENT_RULES:string[] = [\n '- Do NOT read or modify files outside ' +\n 'your current directory (the worktree).',\n '- Do NOT run git push.',\n]\n\nexport function commitRule (unit:string):string {\n return `- Commit after each ${unit}, and make ` +\n 'sure everything is committed when finished, ' +\n 'except your notes file.'\n}\n\nexport function notesRule (unit:string, subject:string):string {\n return `- Keep notes for this attempt in \\`${NOTES_PATH}\\` ` +\n '(create the directory). Update it after each ' +\n `${unit} and as soon as you hit a ` +\n 'blocker, not only at the end. Record what you ' +\n 'implemented, files changed, how you read any ' +\n 'vague acceptance criteria, what blocked you, and ' +\n `anything the next attempt at this ${subject} should ` +\n 'know. Never commit, git add, or delete this ' +\n 'file; the orchestrator collects it.'\n}\n\nexport function agentsMdRule (subject:string):string {\n return '- Before your final commit, record reusable ' +\n 'learnings in the nearest AGENTS.md (in or ' +\n 'above the directories you modified; ' +\n 'prefer that over the repo root). Good ' +\n 'additions: module conventions, gotchas, ' +\n 'files that must change together, how to ' +\n 'test that area, environment requirements. ' +\n `Do NOT add ${subject}-specific details or ` +\n 'temporary debugging notes. Only write ' +\n 'when you have knowledge that would help ' +\n 'future work in that directory. Reusable ' +\n 'patterns go in AGENTS.md; anything ' +\n `specific to this ${subject} goes in your ` +\n 'notes file.'\n}\n", "import { existsSync, readFileSync, writeFileSync } from 'node:fs'\nimport { basename, dirname, join, relative } from 'node:path'\nimport {\n NOTES_PATH,\n formatDate,\n collectNotes,\n ensureNotesIgnored,\n appendEntry,\n} from './learnings.js'\nimport { runTestCmd } from './testcmd.js'\nimport { commitProgress } from './progress.js'\nimport { runWithRetries, type EffortLevel } from './retry.js'\nimport {\n createNamedWorktree,\n deleteBranch,\n removeWorktree,\n commitDirty,\n hasNewCommits,\n isDirty,\n hasChangesOutside,\n headCommit,\n isAncestor,\n mergeBase,\n} from './worktree.js'\nimport { mergeBranch } from './merge.js'\nimport type { AgentResult } from './orchestrator.js'\nimport {\n readDocsRule,\n installRule,\n subagentRule,\n testGateRule,\n LINT_RULE,\n integrityRule,\n CONFINEMENT_RULES,\n commitRule,\n notesRule,\n agentsMdRule,\n} from './rules.js'\n\nexport const FINDINGS_FILE = 'findings.md'\nexport const FINDINGS_PATH = `${dirname(NOTES_PATH)}/${FINDINGS_FILE}`\nexport const NO_FINDINGS = 'No findings.'\n// Bookkeeping lives here (tickets, progress, learnings, the\n// review log), so the review never looks at it.\nexport const REVIEW_EXCLUDE = '.scratch'\n\nexport const REVIEW_MARKER = '---- REVIEW INSTRUCTIONS ----'\nexport const FIX_MARKER = '---- REVIEW FINDINGS ----'\n\n// The bookkeeping directory for a review log: the nearest ancestor\n// of reviewPath named .scratch, relative to the repo root, so a run\n// launched from a subdirectory excludes the right path. Falls back\n// to REVIEW_EXCLUDE when reviewPath is not under a .scratch.\nexport function reviewExcludeFor (\n repoRoot:string,\n reviewPath:string\n):string {\n let dir = dirname(reviewPath)\n while (dirname(dir) !== dir) {\n if (basename(dir) === '.scratch') {\n const rel = relative(repoRoot, dir)\n if (rel && !rel.startsWith('..')) return rel\n break\n }\n dir = dirname(dir)\n }\n return REVIEW_EXCLUDE\n}\n\nexport function reviewDiffCommand (\n from:string,\n to:string,\n exclude:string = REVIEW_EXCLUDE\n):string {\n return `git diff ${from}..${to} -- . ':(exclude)${exclude}'`\n}\n\nexport function renderReviewPrompt (opts:{\n specBody:string\n from:string\n to:string\n exclude?:string\n preferSubagent?:string\n}):string {\n return [\n '---- SPEC CONTEXT ----',\n opts.specBody,\n '',\n REVIEW_MARKER,\n 'You are reviewing work that autonomous agents merged ' +\n 'into this branch, one ticket at a time. Review the ' +\n 'combined change as a whole.',\n '',\n 'The change to review:',\n '',\n ` ${reviewDiffCommand(opts.from, opts.to, opts.exclude)}`,\n '',\n 'Follow these rules:',\n '- Read any AGENTS.md in or above the directories the ' +\n 'change touches, plus CONTEXT.md and the relevant ' +\n 'docs/adr/ entries if they exist. Treat their ' +\n 'contracts and the spec above as the standard the ' +\n 'code must meet.',\n '- Look for correctness bugs, missing or weak tests, ' +\n 'and code that breaks a documented contract. Ignore ' +\n 'style preferences.',\n '- You may run the tests or the type checker to confirm ' +\n 'a suspicion.',\n ...subagentRule(opts.preferSubagent, true),\n '- Do NOT edit, stage, or commit code. Anything you ' +\n 'change here is discarded.',\n ...CONFINEMENT_RULES,\n '',\n `Write your findings to \\`${FINDINGS_PATH}\\` (create the ` +\n 'directory), most severe first, in exactly this form:',\n '',\n '- [ ] <one-line summary of the finding>',\n ' <file:line, and a concrete input or state that goes ' +\n 'wrong>',\n '',\n 'If you find nothing worth fixing, write the single line: ' +\n NO_FINDINGS,\n 'Never git add or commit that file; the orchestrator ' +\n 'collects it.',\n '',\n ].join('\\n')\n}\n\nexport type FixFailure =\n 'install'|'exit'|'no-commits'|'tests'|'merge'\n\nexport const FIX_FAILURE_TEXT:Record<FixFailure, string> = {\n install:'dependency install failed',\n exit:'the agent exited with an error',\n 'no-commits':'the agent made no commits',\n tests:'the test command failed after the agent finished',\n merge:'the fix branch did not merge cleanly',\n}\n\nfunction findingLines (findings:ReadonlyArray<Finding>):string[] {\n return findings.flatMap(f => [\n `- [ ] ${f.summary}`,\n ...(f.detail ?\n f.detail.split('\\n').map(l => ` ${l}`) :\n []),\n ])\n}\n\nfunction previousBlock (\n previous?:{ reason:FixFailure; notes:string|null }\n):string[] {\n if (!previous) return []\n return [\n '---- PREVIOUS FIX ATTEMPT ----',\n `It failed: ${FIX_FAILURE_TEXT[previous.reason]}.`,\n previous.notes ?? 'It left no notes.',\n '',\n ]\n}\n\nexport function renderFixPrompt (opts:{\n specBody:string\n findings:ReadonlyArray<Finding>\n testCmd:string\n installCmd?:string\n preferSubagent?:string\n previous?:{ reason:FixFailure; notes:string|null }\n}):string {\n return [\n '---- SPEC CONTEXT ----',\n opts.specBody,\n '',\n FIX_MARKER,\n ...findingLines(opts.findings),\n '',\n ...previousBlock(opts.previous),\n '---- AGENT INSTRUCTIONS ----',\n 'You are an autonomous coding agent. Fix the review ' +\n 'findings above using /tdd.',\n '',\n 'Follow these rules:',\n readDocsRule('findings'),\n '- Fix ONLY the listed findings. Do not fix unrelated ' +\n 'problems you notice.',\n ...installRule(opts.installCmd),\n ...subagentRule(opts.preferSubagent),\n '- Use /tdd for every finding: write a failing test that ' +\n 'shows the problem, then write only enough code to ' +\n 'make it pass, then refactor.',\n testGateRule(opts.testCmd, 'fix'),\n LINT_RULE,\n integrityRule('finding'),\n ...CONFINEMENT_RULES,\n commitRule('finding'),\n notesRule('finding', 'fix'),\n '- After fixing each finding, print a line: ' +\n '[x] <finding summary> (matching the summary ' +\n 'text exactly).',\n '- If a finding is wrong or cannot be fixed honestly, ' +\n 'leave it unchecked and explain why in your notes ' +\n 'file.',\n agentsMdRule('fix'),\n '',\n ].join('\\n')\n}\n\nconst SENTINEL_PREFIX = '<!-- nightralph:review'\nconst SENTINEL_RE = /^<!-- nightralph:review (.*) -->$/\nconst SHA_RE = /^[0-9a-f]{4,64}$/\nconst FIX_HEADING = '### Fix'\nconst FINDING_RE = /^ ?[-*+]\\s+\\[([ xX])\\]\\s+(.+)$/\n\nexport const REVIEW_STATUSES = [\n 'clean', 'fixed', 'unresolved', 'review-failed',\n] as const\n\nexport type ReviewStatus = typeof REVIEW_STATUSES[number]\n\nexport type Finding = {\n summary:string\n detail:string\n checked:boolean\n}\n\nexport type FixRecord = {\n attempts:number\n maxAttempts:number\n effort?:string\n exitCode:number|null\n result:string\n notes:string|null\n}\n\nexport type ReviewEntryInput = {\n from:string\n to:string\n status:ReviewStatus\n now:Date\n findings:Finding[]\n fix?:FixRecord\n}\n\nexport type ReviewEntry = {\n from:string\n to:string\n status:ReviewStatus\n findings:Finding[]\n body:string\n}\n\nexport type ReviewOutcome = {\n status:ReviewStatus|'skipped'\n findings:number\n fixed:number\n}\n\nfunction isReviewStatus (value:string):value is ReviewStatus {\n return (REVIEW_STATUSES as readonly string[]).includes(value)\n}\n\nfunction collapse (s:string):string {\n return s.replace(/\\s+/g, ' ').trim()\n}\n\nfunction normalize (s:string):string {\n return collapse(s).toLowerCase()\n}\n\nfunction sanitize (text:string):string {\n return text.replace(\n new RegExp(SENTINEL_PREFIX, 'g'),\n '<!-- nightralph-review'\n )\n}\n\nfunction splitLines (text:string):string[] {\n return text.split('\\n').map(line => {\n return line.endsWith('\\r') ? line.slice(0, -1) : line\n })\n}\n\n// The reviewer's checklist: `- [ ] summary` lines, each followed\n// by its detail lines. [] for an explicit \"No findings.\", null\n// when the text is neither, which fails the review attempt.\nexport function parseFindings (text:string):Finding[]|null {\n const findings:Finding[] = []\n const details:string[][] = []\n for (const line of splitLines(text)) {\n const m = line.match(FINDING_RE)\n if (m) {\n findings.push({\n summary:collapse(m[2]),\n detail:'',\n checked:m[1] !== ' ',\n })\n details.push([])\n } else if (findings.length > 0 && line.trim()) {\n details[details.length - 1].push(line.trim())\n }\n }\n if (findings.length > 0) {\n return findings.map((f, i) => {\n return { ...f, detail:details[i].join('\\n') }\n })\n }\n const clean = splitLines(text).some(line => {\n return normalize(line) === NO_FINDINGS.toLowerCase()\n })\n return clean ? [] : null\n}\n\n// Checks off the findings the fixer echoed as `[x] <summary>`,\n// compared loosely like ticket checklist items.\nexport function markFixed (\n findings:ReadonlyArray<Finding>,\n completedItems:ReadonlyArray<string>\n):Finding[] {\n const done = new Set(completedItems.map(normalize))\n return findings.map(f => {\n return { ...f, checked:done.has(normalize(f.summary)) }\n })\n}\n\nfunction headline (input:ReviewEntryInput):string {\n const n = input.findings.length\n const fixed = input.findings.filter(f => f.checked).length\n switch (input.status) {\n case 'clean': return 'no findings'\n case 'fixed': return `${fixed} of ${n} fixed`\n case 'unresolved':\n return `${n} finding${n === 1 ? '' : 's'}, fix failed`\n case 'review-failed': return 'review failed'\n default: {\n const _exhaustive:never = input.status\n return _exhaustive\n }\n }\n}\n\nfunction renderFindings (input:ReviewEntryInput):string[] {\n if (input.status === 'review-failed') {\n return ['The reviewer left no usable findings file.']\n }\n if (input.findings.length === 0) return [NO_FINDINGS]\n return input.findings.flatMap(f => {\n const box = f.checked ? '[x]' : '[ ]'\n const detail = f.detail ?\n f.detail.split('\\n').map(l => ` ${sanitize(l)}`) :\n []\n return [`- ${box} ${sanitize(collapse(f.summary))}`, ...detail]\n })\n}\n\nfunction renderFix (fix?:FixRecord):string[] {\n if (!fix) return []\n return [\n '',\n FIX_HEADING,\n `- attempts: ${fix.attempts} of ${fix.maxAttempts}`,\n ...(fix.effort ? [`- effort: ${fix.effort}`] : []),\n `- agent exit code: ${fix.exitCode ?? 'none'}`,\n `- result: ${sanitize(fix.result)}`,\n '',\n fix.notes ? sanitize(fix.notes) : 'The fixer left no notes.',\n ]\n}\n\nexport function renderReviewEntry (input:ReviewEntryInput):string {\n return [\n `${SENTINEL_PREFIX} from=${input.from} to=${input.to} ` +\n `status=${input.status} -->`,\n `## ${formatDate(input.now)} -- review ` +\n `${input.from.slice(0, 7)}..${input.to.slice(0, 7)} ` +\n `-- ${headline(input)}`,\n ...renderFindings(input),\n ...renderFix(input.fix),\n '---',\n '',\n ].join('\\n')\n}\n\nfunction parseEntry (\n sentinel:string,\n bodyLines:string[]\n):ReviewEntry|null {\n const attrs:Record<string, string> = {}\n for (const part of sentinel.split(/\\s+/).filter(Boolean)) {\n const idx = part.indexOf('=')\n if (idx > 0) attrs[part.slice(0, idx)] = part.slice(idx + 1)\n }\n const { from, to, status } = attrs\n if (!from || !SHA_RE.test(from)) return null\n if (!to || !SHA_RE.test(to)) return null\n if (!status || !isReviewStatus(status)) return null\n\n const lines = [...bodyLines]\n while (lines.length > 0 && !lines[lines.length - 1].trim()) {\n lines.pop()\n }\n if (lines[lines.length - 1] === '---') lines.pop()\n const fixAt = lines.indexOf(FIX_HEADING)\n const findingLines = fixAt === -1 ? lines : lines.slice(0, fixAt)\n return {\n from,\n to,\n status,\n findings:parseFindings(findingLines.join('\\n')) ?? [],\n body:lines.join('\\n').trim(),\n }\n}\n\n// Malformed entries are dropped, not thrown; text before the\n// first sentinel is ignored.\nexport function parseReviewEntries (text:string):ReviewEntry[] {\n const entries:ReviewEntry[] = []\n let sentinel:string|null = null\n let body:string[] = []\n const flush = ():void => {\n if (sentinel === null) return\n const entry = parseEntry(sentinel, body)\n if (entry) entries.push(entry)\n }\n for (const line of splitLines(text)) {\n const m = line.match(SENTINEL_RE)\n if (m) {\n flush()\n sentinel = m[1]\n body = []\n } else if (sentinel !== null) {\n body.push(line)\n }\n }\n flush()\n return entries\n}\n\n// Where the review range starts: the last reviewed commit while\n// it is still on this branch, else the fork point from the\n// default branch, else the commit the run started from.\nexport function selectReviewBase (\n entries:ReadonlyArray<ReviewEntry>,\n opts:{\n isAncestor:(sha:string) => boolean\n forkPoint:string|null\n launchCommit:string\n }\n):string {\n const last = [...entries].reverse().find(e => {\n return e.status !== 'review-failed'\n })\n if (last && opts.isAncestor(last.to)) return last.to\n return opts.forkPoint ?? opts.launchCommit\n}\n\n// One line for the finish summary; null when no review ran.\nexport function renderReviewSummary (\n outcome:ReviewOutcome,\n reviewPath:string\n):string|null {\n const see = ` -- see ${reviewPath}`\n const plural = outcome.findings === 1 ? '' : 's'\n switch (outcome.status) {\n case 'skipped': return null\n case 'clean': return `Review: no findings${see}`\n case 'fixed':\n return `Review: ${outcome.findings} finding${plural}, ` +\n `${outcome.fixed} fixed${see}`\n case 'unresolved':\n return `Review: ${outcome.findings} finding${plural}, ` +\n `fix failed${see}`\n case 'review-failed':\n return `Review: the reviewer failed${see}`\n default: {\n const _exhaustive:never = outcome.status\n return _exhaustive\n }\n }\n}\n\nexport type SpawnAgentFn = (opts:{\n prompt:string\n agentCmd:string\n model:string|null\n timeout:number\n logPath:string\n cwd?:string\n label?:string\n maxTurns?:number\n effort?:EffortLevel\n // claude only: model for subagents; unset = off\n preferSubagent?:string\n onLine?:(line:string) => void\n}) => Promise<AgentResult>\n\nexport type ReviewDeps = {\n spawnAgent:SpawnAgentFn\n // running child pids, so SIGINT also kills installs and tests\n registry?:Set<number>\n}\n\nexport type ReviewPassOpts = {\n repoRoot:string\n repoName:string\n // the branch the run merged into; the fix merges here too\n baseBranch:string\n reviewPath:string\n // the default branch, when baseBranch is an integration branch\n forkedFrom?:string\n launchCommit:string\n specBody:string\n agentCmd:string\n model:string|null\n timeout:number\n logsDir:string\n testCmd:string\n installCmd?:string\n maxTurns?:number\n effort?:EffortLevel\n // claude only: model for subagents; unset = off\n preferSubagent?:string\n retries:number\n retryDelay:number\n log:(msg:string) => void\n now?:() => Date\n}\n\n// Same naming as ticket logs: the first attempt keeps the plain\n// name, later attempts get their own file.\nfunction logPath (\n logsDir:string,\n stem:string,\n attempt:number,\n ext:string\n):string {\n const suffix = attempt > 1 ? `.attempt${attempt}` : ''\n return join(logsDir, `${stem}${suffix}${ext}`)\n}\n\n// Runs a shell step (install or tests) in a worktree, writing its\n// output to `path`; true only on exit 0.\nasync function runStep (\n opts:ReviewPassOpts,\n deps:ReviewDeps,\n cmd:string,\n cwd:string,\n path:string\n):Promise<boolean> {\n const result = await runTestCmd({\n cmd,\n cwd,\n timeout:opts.timeout,\n registry:deps.registry,\n })\n writeFileSync(path, result.output)\n return result.exitCode === 0\n}\n\nasync function discardWorktree (\n opts:ReviewPassOpts,\n wt:{ worktreePath:string; branchName:string }\n):Promise<void> {\n try {\n await removeWorktree(wt.worktreePath, { force:true })\n await deleteBranch(opts.repoRoot, wt.branchName)\n } catch (err) {\n opts.log(\n ` Failed to remove ${wt.worktreePath}: ` +\n (err instanceof Error ? err.message : String(err))\n )\n }\n}\n\n// Asks an agent to review from..to and returns its findings:\n// [] when clean, null when no attempt produced a usable findings\n// file. The worktree and anything the reviewer changed in it are\n// always discarded.\nexport async function runReviewer (\n opts:ReviewPassOpts,\n deps:ReviewDeps,\n range:{ from:string; to:string }\n):Promise<Finding[]|null> {\n return runWithRetries({\n maxAttempts:opts.retries + 1,\n retryDelay:opts.retryDelay,\n agentCmd:opts.agentCmd,\n effort:opts.effort,\n label:'review',\n log:opts.log,\n }, async (attempt, effort) => {\n const wt = await createNamedWorktree({\n repoRoot:opts.repoRoot,\n repoName:opts.repoName,\n baseBranch:opts.baseBranch,\n name:'review',\n })\n try {\n if (opts.installCmd && !(await runStep(\n opts, deps, opts.installCmd, wt.worktreePath,\n logPath(opts.logsDir, 'review', attempt, '.install.log')\n ))) {\n opts.log(' review: install failed')\n return { result:null, stop:false }\n }\n ensureNotesIgnored(wt.worktreePath)\n await deps.spawnAgent({\n prompt:renderReviewPrompt({\n specBody:opts.specBody,\n ...range,\n exclude:reviewExcludeFor(\n opts.repoRoot, opts.reviewPath\n ),\n preferSubagent:opts.preferSubagent,\n }),\n agentCmd:opts.agentCmd,\n model:opts.model,\n timeout:opts.timeout,\n logPath:logPath(opts.logsDir, 'review', attempt, '.log'),\n cwd:wt.worktreePath,\n label:'review',\n maxTurns:opts.maxTurns,\n effort,\n preferSubagent:opts.preferSubagent,\n onLine:opts.log,\n })\n const text = collectNotes(wt.worktreePath, FINDINGS_FILE)\n const findings = text === null ? null : parseFindings(text)\n if (findings === null) {\n opts.log(' review: no usable findings file')\n }\n return { result:findings, stop:findings !== null }\n } finally {\n await discardWorktree(opts, wt)\n }\n })\n}\n\nexport type FixResult = {\n merged:boolean\n // checked per the fixer's [x] lines when merged; all\n // unchecked otherwise\n findings:Finding[]\n attempts:number\n effort?:EffortLevel\n exitCode:number|null\n result:string\n notes:string|null\n}\n\n// Asks an agent to fix the findings in a fresh worktree off the\n// branch tip. Its work merges only after a green test gate;\n// every failure is retried like a ticket.\nexport async function runFixer (\n opts:ReviewPassOpts,\n deps:ReviewDeps,\n findings:ReadonlyArray<Finding>\n):Promise<FixResult> {\n const unchecked = findings.map(f => ({ ...f, checked:false }))\n let previous:{ reason:FixFailure; notes:string|null }|undefined\n\n return runWithRetries<FixResult>({\n maxAttempts:opts.retries + 1,\n retryDelay:opts.retryDelay,\n agentCmd:opts.agentCmd,\n effort:opts.effort,\n label:'review fix',\n log:opts.log,\n }, async (attempt, effort) => {\n const fail = (\n reason:FixFailure,\n exitCode:number|null,\n notes:string|null\n ) => {\n previous = { reason, notes }\n opts.log(` review fix: ${FIX_FAILURE_TEXT[reason]}`)\n return {\n result:{\n merged:false,\n findings:unchecked,\n attempts:attempt,\n effort,\n exitCode,\n result:FIX_FAILURE_TEXT[reason],\n notes,\n },\n stop:false,\n }\n }\n\n const wt = await createNamedWorktree({\n repoRoot:opts.repoRoot,\n repoName:opts.repoName,\n baseBranch:opts.baseBranch,\n name:'review-fix',\n })\n try {\n if (opts.installCmd && !(await runStep(\n opts, deps, opts.installCmd, wt.worktreePath,\n logPath(\n opts.logsDir, 'review-fix', attempt,\n '.install.log'\n )\n ))) {\n return fail('install', null, null)\n }\n ensureNotesIgnored(wt.worktreePath)\n const agent = await deps.spawnAgent({\n prompt:renderFixPrompt({\n specBody:opts.specBody,\n findings,\n testCmd:opts.testCmd,\n installCmd:opts.installCmd,\n previous,\n preferSubagent:opts.preferSubagent,\n }),\n agentCmd:opts.agentCmd,\n model:opts.model,\n timeout:opts.timeout,\n logPath:logPath(\n opts.logsDir, 'review-fix', attempt, '.log'\n ),\n cwd:wt.worktreePath,\n label:'review-fix',\n maxTurns:opts.maxTurns,\n effort,\n preferSubagent:opts.preferSubagent,\n onLine:opts.log,\n })\n // Before any auto-commit, so notes never get committed\n const notes = collectNotes(wt.worktreePath)\n\n if (!agent.timedOut && agent.exitCode !== 0) {\n return fail('exit', agent.exitCode, notes)\n }\n if (isDirty(wt.worktreePath)) {\n await commitDirty(\n wt.worktreePath,\n 'nightralph: auto-commit review fix ' +\n 'remaining changes'\n )\n }\n if (!hasNewCommits(\n opts.repoRoot, opts.baseBranch, wt.branchName\n )) {\n return fail('no-commits', agent.exitCode, notes)\n }\n if (opts.testCmd === '') {\n opts.log(' review fix: no test gate')\n } else if (!(await runStep(\n opts, deps, opts.testCmd, wt.worktreePath,\n logPath(\n opts.logsDir, 'review-fix', attempt, '.test.log'\n )\n ))) {\n return fail('tests', agent.exitCode, notes)\n }\n const merged = await mergeBranch(\n opts.repoRoot, wt.branchName\n )\n if (!merged.success) {\n return fail(\n 'merge',\n agent.exitCode,\n [notes, merged.stderr].filter(Boolean)\n .join('\\n\\n') || null\n )\n }\n opts.log(' review fix: merged')\n return {\n result:{\n merged:true,\n findings:markFixed(findings, agent.completedItems),\n attempts:attempt,\n effort,\n exitCode:agent.exitCode,\n result:'merged',\n notes,\n },\n stop:true,\n }\n } finally {\n await discardWorktree(opts, wt)\n }\n })\n}\n\nexport function readReviewEntries (path:string):ReviewEntry[] {\n if (!existsSync(path)) return []\n return parseReviewEntries(readFileSync(path, 'utf8'))\n}\n\n// Reviews everything since the last reviewed commit, runs one fix\n// pass when there are findings, and appends and commits one entry\n// to the review log. Skips entirely when the range only touches\n// bookkeeping under REVIEW_EXCLUDE.\nexport async function runReviewPass (\n opts:ReviewPassOpts,\n deps:ReviewDeps\n):Promise<ReviewOutcome> {\n const now = opts.now ?? (() => new Date())\n const to = headCommit(opts.repoRoot)\n const forkPoint = opts.forkedFrom ?\n mergeBase(opts.repoRoot, opts.forkedFrom, to) :\n null\n const from = selectReviewBase(readReviewEntries(opts.reviewPath), {\n isAncestor:sha => isAncestor(opts.repoRoot, sha, to),\n forkPoint,\n launchCommit:opts.launchCommit,\n })\n const exclude = reviewExcludeFor(opts.repoRoot, opts.reviewPath)\n if (!hasChangesOutside(opts.repoRoot, from, to, exclude)) {\n opts.log('\\nReview: nothing new to review')\n return { status:'skipped', findings:0, fixed:0 }\n }\n\n opts.log(`\\nReviewing ${from.slice(0, 7)}..${to.slice(0, 7)}`)\n const findings = await runReviewer(opts, deps, { from, to })\n\n let entry:ReviewEntryInput\n if (findings === null) {\n entry = {\n from,\n to,\n status:'review-failed',\n now:now(),\n findings:[]\n }\n } else if (findings.length === 0) {\n entry = { from, to, status:'clean', now:now(), findings:[] }\n } else {\n opts.log(\n `Review: ${findings.length} finding` +\n `${findings.length === 1 ? '' : 's'}`\n )\n const fix = await runFixer(opts, deps, findings)\n entry = {\n from,\n // A merged fix counts as reviewed\n to:fix.merged ? headCommit(opts.repoRoot) : to,\n status:fix.merged ? 'fixed' : 'unresolved',\n now:now(),\n findings:fix.findings,\n fix:{\n attempts:fix.attempts,\n maxAttempts:opts.retries + 1,\n effort:fix.effort,\n exitCode:fix.exitCode,\n result:fix.result,\n notes:fix.notes,\n },\n }\n }\n\n appendEntry(opts.reviewPath, renderReviewEntry(entry))\n await commitProgress(\n opts.repoRoot, opts.reviewPath, 'nightralph: record review'\n )\n return {\n status:entry.status,\n findings:entry.findings.length,\n fixed:entry.findings.filter(f => f.checked).length,\n }\n}\n", "import { basename } from 'node:path'\n\n// Per-provider effort ladders.\nexport const EFFORT_LADDERS = {\n pi:['off', 'minimal', 'low', 'medium',\n 'high', 'xhigh', 'max'],\n claude:['low', 'medium', 'high',\n 'xhigh', 'max'],\n codex:['low', 'medium', 'high'],\n} as const\n\nexport type ProviderName =\n keyof typeof EFFORT_LADDERS\n\nexport type EffortLevel =\n typeof EFFORT_LADDERS[ProviderName][number]\n\nexport const ALL_EFFORT_LEVELS:EffortLevel[] = [\n 'off', 'minimal', 'low', 'medium',\n 'high', 'xhigh', 'max',\n]\n\n// Step up the effort ladder for a given provider.\n// Without a starting level, the first retry jumps to high.\n// Otherwise, step one rung up and stop at the provider's max.\nexport function escalateEffort (\n provider:ProviderName,\n level?:EffortLevel\n):EffortLevel {\n if (!level) return 'high'\n const ladder = EFFORT_LADDERS[provider]\n const i = (ladder as readonly string[])\n .indexOf(level)\n if (i === -1) return level\n return ladder[\n Math.min(i + 1, ladder.length - 1)\n ] as EffortLevel\n}\n\nexport function retryDelayFor (base:number, attempt:number):number {\n return base * 2 ** (attempt - 2)\n}\n\nexport function sleep (ms:number):Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms))\n}\n\nexport type AttemptStep<T> = { result:T; stop:boolean }\n\nexport type RetryOpts = {\n maxAttempts:number\n // seconds before the first retry; doubles each further retry\n retryDelay:number\n agentCmd:string\n // starting effort level; unset = provider's default\n effort?:EffortLevel\n // names the work in log lines, e.g. a ticket filename\n label:string\n log:(msg:string) => void\n // test seam; defaults to sleep\n wait?:(ms:number) => Promise<void>\n}\n\n// Runs `run` until a step says stop or the attempt cap is hit,\n// escalating effort for known providers and backing off\n// exponentially between attempts. Returns the last step's result.\nexport async function runWithRetries<T> (\n opts:RetryOpts,\n run:(\n attempt:number,\n effort:EffortLevel|undefined\n ) => Promise<AttemptStep<T>>\n):Promise<T> {\n const maxAttempts = Math.max(1, opts.maxAttempts)\n const providerName = basename(opts.agentCmd)\n const isKnown = providerName in EFFORT_LADDERS\n const wait = opts.wait ?? sleep\n let effort = opts.effort\n\n for (let attempt = 1; ; attempt++) {\n if (attempt === 1) {\n opts.log(` Starting ${opts.label}`)\n } else {\n if (isKnown) {\n effort = escalateEffort(\n providerName as ProviderName,\n effort\n )\n }\n const delay = retryDelayFor(opts.retryDelay, attempt)\n opts.log(\n ` ${opts.label}: retrying ` +\n `(attempt ${attempt}/${maxAttempts}` +\n (isKnown && effort ?\n `, effort ${effort}` : '') +\n (delay > 0 ?\n `, waiting ${delay}s` : '') +\n ')'\n )\n if (delay > 0) await wait(delay * 1000)\n }\n const step = await run(attempt, effort)\n if (step.stop || attempt >= maxAttempts) return step.result\n }\n}\n", "// Blocker references in a ticket's **Blocked by:** field. Pure:\n// no file or process access and no imports, so orchestrator.ts\n// and resolve.ts can both depend on it.\n\nexport type RawRef = {\n feature?:string; // absent -> the ticket's own feature\n num:number;\n}\n\nexport type BlockerParse = {\n refs:RawRef[];\n typos:string[]; // feature-shaped words that name no feature\n}\n\nconst FIELD_RE = /\\*\\*Blocked by:\\*\\*/i\nconst NEXT_FIELD_RE = /^\\s*(?:[-*]\\s+)?\\*\\*[^*\\n]+:\\*\\*/\nconst HEADING_RE = /^\\s*#{1,6}\\s/\nconst CHECKLIST_RE = /^\\s*[-*+]\\s+\\[[ xX]\\]/\nconst TOKEN_RE = /[A-Za-z0-9_-]+/g\n\nfunction endsField (line:string):boolean {\n return line.trim() === '' ||\n NEXT_FIELD_RE.test(line) ||\n HEADING_RE.test(line) ||\n CHECKLIST_RE.test(line)\n}\n\n/**\n * The text of the **Blocked by:** field: the rest of its line\n * plus continuation lines, up to a blank line, the next\n * `**Field:**` line, a heading or a checklist item. `null` when\n * the body has no such field.\n */\nfunction fieldText (body:string):string|null {\n const lines = body.split(/\\r?\\n/)\n const start = lines.findIndex(l => FIELD_RE.test(l))\n if (start === -1) return null\n const first = lines[start]\n const m = FIELD_RE.exec(first)!\n const parts = [first.slice(m.index + m[0].length)]\n for (const line of lines.slice(start + 1)) {\n if (endsField(line)) break\n parts.push(line)\n }\n return parts.join('\\n')\n}\n\n/**\n * Blanks out backtick spans and `(...)` spans (nested, across\n * lines). Only paired delimiters count; an unpaired `(` or\n * backtick stays as text. Each blanked character becomes a space,\n * so the words on either side never merge.\n */\nfunction stripNotes (text:string):string {\n const chars = [...text]\n const drop = new Array<boolean>(chars.length).fill(false)\n const ticks:number[] = []\n chars.forEach((ch, i) => {\n if (ch === '`') ticks.push(i)\n })\n for (let i = 0; i + 1 < ticks.length; i += 2) {\n for (let j = ticks[i]; j <= ticks[i + 1]; j++) {\n drop[j] = true\n }\n }\n const open:number[] = []\n chars.forEach((ch, i) => {\n if (drop[i]) return\n if (ch === '(') {\n open.push(i)\n } else if (ch === ')' && open.length > 0) {\n const from = open.pop()!\n for (let j = from; j <= i; j++) drop[j] = true\n }\n })\n return chars.map((ch, i) => (drop[i] ? ' ' : ch)).join('')\n}\n\n/**\n * A word shaped like a feature dir name: lowercase letters and\n * digits joined by hyphens, or a nested path of such segments\n * joined by `/`, with at least one letter. Doc IDs such as\n * `FDR-018` are not.\n */\nfunction looksLikeFeature (word:string):boolean {\n const segments = word.split('/')\n return (segments.length > 1 || word.includes('-')) &&\n /[a-z]/.test(word) &&\n segments.every(s => /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(s))\n}\n\n/**\n * The word that ends right before `start`, separated from it by\n * whitespace only. A word may contain `/`, so a nested feature such\n * as `rollout/billing` is one word. `null` when the gap is empty or\n * holds anything but whitespace.\n */\nfunction wordBefore (text:string, start:number):string|null {\n let i = start\n while (i > 0 && /\\s/.test(text[i - 1])) i--\n if (i === start) return null\n const end = i\n while (i > 0 && /[A-Za-z0-9_/-]/.test(text[i - 1])) i--\n return i === end ? null : text.slice(i, end)\n}\n\n/**\n * Reads the **Blocked by:** field of a ticket body. A number\n * belongs to the feature named by the word directly before it\n * when that word is in `knownFeatures` (the names of\n * `.scratch/<name>/issues` dirs, `<name>` possibly nested, as in\n * `rollout/billing`); otherwise to the ticket's own feature.\n * Feature-shaped words that name no feature are returned as\n * `typos`.\n */\nexport function parseBlockerField (\n body:string,\n knownFeatures:ReadonlySet<string>\n):BlockerParse {\n const text = fieldText(body)\n if (text === null) return { refs:[], typos:[] }\n const clean = stripNotes(text)\n if (/^\\s*none\\b/i.test(clean)) return { refs:[], typos:[] }\n\n const refs:RawRef[] = []\n const typos:string[] = []\n const seen = new Set<string>()\n const add = (num:number, feature?:string) => {\n const id = `${feature ?? ''}:${num}`\n if (seen.has(id)) return\n seen.add(id)\n refs.push(feature === undefined ? { num } : { feature, num })\n }\n for (const m of clean.matchAll(TOKEN_RE)) {\n const word = m[0]\n if (/^\\d+(?:-\\d+)*$/.test(word)) {\n const before = wordBefore(clean, m.index ?? 0)\n let feature:string|undefined\n if (before !== null && knownFeatures.has(before)) {\n feature = before\n } else if (\n before !== null &&\n looksLikeFeature(before) &&\n !typos.includes(before)\n ) {\n typos.push(before)\n }\n // both ends of a range belong to the same feature\n for (const n of word.split('-').map(Number)) add(n, feature)\n }\n }\n return { refs, typos }\n}\n\nexport type BlockerWhere = 'run'|'done'|'pending'|'missing'\n\nexport type BlockerRef = {\n feature:string;\n num:number;\n // 'run' -> a ticket in this run; its live status decides\n // 'done' -> outside the run, done when loaded\n // 'pending' -> outside the run, not done (dead this session)\n // 'missing' -> no ticket matches (dead, reported)\n where:BlockerWhere;\n status?:string; // the outside ticket's status, for messages\n}\n\n// Same text as ticketKey in orchestrator.ts, which this module\n// must not import.\nfunction refId (feature:string, num:number):string {\n return `${feature}:${num}`\n}\n\n/**\n * Classifies raw refs. `selected` maps each feature in the run to\n * its ticket numbers; `lookup` returns the status of a ticket in a\n * feature outside the run, or undefined when there is none.\n * De-duplicates by (feature, num) after the own feature is filled\n * in.\n */\nexport function resolveBlockers (\n raw:ReadonlyArray<RawRef>,\n ownFeature:string,\n selected:ReadonlyMap<string, ReadonlySet<number>>,\n lookup:(feature:string, num:number) => string|undefined\n):BlockerRef[] {\n const out:BlockerRef[] = []\n const seen = new Set<string>()\n for (const r of raw) {\n const feature = r.feature ?? ownFeature\n const id = refId(feature, r.num)\n if (seen.has(id)) continue\n seen.add(id)\n const nums = selected.get(feature)\n if (nums) {\n out.push({\n feature,\n num:r.num,\n where:nums.has(r.num) ? 'run' : 'missing',\n })\n continue\n }\n const status = lookup(feature, r.num)\n if (status === undefined) {\n out.push({ feature, num:r.num, where:'missing' })\n } else {\n out.push({\n feature,\n num:r.num,\n where:status === 'done' ? 'done' : 'pending',\n status,\n })\n }\n }\n return out\n}\n\n/**\n * Refs for a bare scan, before the run is known: every ref is\n * `run`, so one that matches no ticket in the list is never\n * satisfied.\n */\nexport function provisionalRefs (\n raw:ReadonlyArray<RawRef>,\n ownFeature:string\n):BlockerRef[] {\n const out:BlockerRef[] = []\n const seen = new Set<string>()\n for (const r of raw) {\n const feature = r.feature ?? ownFeature\n const id = refId(feature, r.num)\n if (seen.has(id)) continue\n seen.add(id)\n out.push({ feature, num:r.num, where:'run' })\n }\n return out\n}\n\nexport type BlockerWarning = {\n ticket:string; // ticketLabel of the ticket with the problem\n kind:'missing'|'typo';\n text:string; // the ref label or the unknown word\n}\n", "import { accessSync, constants, statSync } from 'node:fs'\nimport { delimiter, join, resolve } from 'node:path'\n\nexport type ResolveExecutableOpts = {\n // PATH to search for a bare name; default process.env.PATH\n path?:string\n // directory a relative path is resolved against; default\n // process.cwd()\n cwd?:string\n}\n\nfunction isExecutableFile (file:string):boolean {\n try {\n if (!statSync(file).isFile()) return false\n accessSync(file, constants.X_OK)\n return true\n } catch {\n return false\n }\n}\n\n// Where a command would run from, or null when it would not run.\n// A name with a slash is a path, resolved against cwd. A bare name\n// is looked up in each PATH entry in order. Never throws.\nexport function resolveExecutable (\n cmd:string,\n opts:ResolveExecutableOpts = {}\n):string|null {\n if (cmd === '') return null\n const cwd = opts.cwd ?? process.cwd()\n if (cmd.includes('/')) {\n const full = resolve(cwd, cmd)\n return isExecutableFile(full) ? full : null\n }\n const path = opts.path ?? process.env.PATH ?? ''\n for (const dir of path.split(delimiter)) {\n if (dir === '') continue\n const candidate = join(dir, cmd)\n if (isExecutableFile(candidate)) return candidate\n }\n return null\n}\n", "import { existsSync, readdirSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { checkbox, Separator } from '@inquirer/prompts'\nimport { isSpecComplete } from './progress.js'\nimport {\n scanTickets,\n findReadyTickets,\n blockerLabel,\n type Ticket,\n} from './orchestrator.js'\nimport { ticketLabel } from './display.js'\nimport {\n parseBlockerField,\n resolveBlockers,\n type BlockerWarning,\n} from './blockers.js'\n\nexport type { BlockerWarning }\n\nexport type FeatureSelection = {\n dir:string;\n spec:string;\n name:string;\n}\n\nexport function getScriptDir (metaUrl:string):string {\n return dirname(fileURLToPath(metaUrl))\n}\n\nexport function findFeatureDirs (cwd:string):{\n name:string;\n dir:string;\n spec:string\n}[] {\n const scratchDir = join(cwd, '.scratch')\n if (!existsSync(scratchDir)) return []\n const entries = readdirSync(\n scratchDir, { withFileTypes:true }\n )\n const results:{ name:string; dir:string; spec:string }[] = []\n for (const entry of entries) {\n if (!entry.isDirectory()) continue\n const issuesDir = join(\n scratchDir, entry.name, 'issues'\n )\n const specFile = join(\n scratchDir, entry.name, 'spec.md'\n )\n if (!existsSync(issuesDir)) continue\n const progressFile = join(\n scratchDir, entry.name, 'progress.md'\n )\n if (isSpecComplete(progressFile)) continue\n results.push({\n name:entry.name,\n dir:issuesDir,\n spec:specFile,\n })\n }\n results.sort((a, b) => a.name.localeCompare(b.name))\n return results\n}\n\nexport type LoadedSelection = {\n tickets:Ticket[];\n warnings:BlockerWarning[];\n}\n\n// Names of the features under scratchDir: dirs with an issues\n// subdir, complete or not, at any depth. A nested feature's name\n// is its path, e.g. `rollout/billing`, the same name `--spec`\n// takes.\nfunction knownFeatureNames (scratchDir:string):Set<string> {\n const names = new Set<string>()\n const walk = (rel:string) => {\n const dir = rel === '' ? scratchDir : join(scratchDir, rel)\n for (const e of readdirSync(dir, { withFileTypes:true })) {\n if (!e.isDirectory() || e.name === 'issues') continue\n const name = rel === '' ? e.name : `${rel}/${e.name}`\n if (existsSync(join(scratchDir, name, 'issues'))) {\n names.add(name)\n }\n walk(name)\n }\n }\n if (existsSync(scratchDir)) walk('')\n return names\n}\n\n/**\n * Tickets of the named features with every blocker resolved, and\n * the problems found on the way. An unselected feature is scanned\n * only when a ref points into it, once.\n */\nexport function loadSelection (\n scratchDir:string,\n names:ReadonlyArray<string>\n):LoadedSelection {\n const known = knownFeatureNames(scratchDir)\n const issuesDir = (name:string) => join(scratchDir, name, 'issues')\n\n const tickets:Ticket[] = []\n const selected = new Map<string, Set<number>>()\n for (const name of new Set(names)) {\n const dir = issuesDir(name)\n const found = existsSync(dir) ?\n scanTickets(dir, name, known) :\n []\n selected.set(name, new Set(found.map(t => t.num)))\n tickets.push(...found)\n }\n\n const outside = new Map<string, Map<number, string>>()\n const lookup = (feature:string, num:number) => {\n if (!known.has(feature)) return undefined\n let statuses = outside.get(feature)\n if (!statuses) {\n statuses = new Map(\n scanTickets(issuesDir(feature), feature)\n .map(t => [t.num, t.status])\n )\n outside.set(feature, statuses)\n }\n return statuses.get(num)\n }\n\n const warnings:BlockerWarning[] = []\n for (const t of tickets) {\n const parsed = parseBlockerField(t.body, known)\n t.blockers = resolveBlockers(\n parsed.refs, t.feature, selected, lookup\n )\n const ticket = ticketLabel(t)\n for (const word of parsed.typos) {\n warnings.push({ ticket, kind:'typo', text:word })\n }\n for (const ref of t.blockers) {\n if (ref.where !== 'missing') continue\n warnings.push({\n ticket, kind:'missing', text:blockerLabel(ref),\n })\n }\n }\n return { tickets, warnings }\n}\n\nexport type FeatureCounts = {\n ready:number;\n total:number;\n badBlockers:number; // refs that match no ticket\n}\n\n/**\n * Counts for one feature as if it ran alone: the same\n * loadSelection a `--spec <name>` run uses.\n */\nexport function featureCounts (\n scratchDir:string,\n name:string\n):FeatureCounts {\n const { tickets, warnings } = loadSelection(scratchDir, [name])\n return {\n ready:findReadyTickets(tickets).length,\n total:tickets.length,\n badBlockers:warnings.filter(w => w.kind === 'missing').length,\n }\n}\n\nexport function featureChoiceLabel (\n scratchDir:string,\n name:string\n):string {\n const c = featureCounts(scratchDir, name)\n const bad = c.badBlockers === 0 ?\n '' :\n `, ${c.badBlockers} bad blocker` +\n (c.badBlockers === 1 ? '' : 's')\n return `${name} (${c.ready}/${c.total} ready${bad})`\n}\n\nconst ALL_VALUE = '__all__'\n\nexport async function resolveIssuesDir (\n specName:string|undefined,\n cwd:string = process.cwd(),\n):Promise<FeatureSelection[]> {\n if (specName) {\n const featureDir = join(cwd, '.scratch', specName)\n return [{\n dir:join(featureDir, 'issues'),\n spec:join(featureDir, 'spec.md'),\n name:specName,\n }]\n }\n\n const features = findFeatureDirs(cwd)\n\n if (features.length === 0) {\n console.error(\n 'No .scratch/<feature>/issues/ directories ' +\n 'found.\\nProvide --spec <feature-name>.'\n )\n process.exit(2)\n }\n\n if (features.length === 1) {\n const f = features[0]\n console.log(`Using feature: ${f.name}`)\n return [{ dir:f.dir, spec:f.spec, name:f.name }]\n }\n\n const scratchDir = join(cwd, '.scratch')\n const featureChoices = features.map(f => ({\n name:featureChoiceLabel(scratchDir, f.name),\n value:f.name,\n }))\n\n while (true) {\n const selected = await checkbox({\n message:'Which features?',\n choices:[\n { name:'All', value:ALL_VALUE },\n new Separator(),\n ...featureChoices,\n ],\n })\n\n if (selected.length === 0) {\n console.log('Select at least one feature')\n continue\n }\n\n const names = selected.includes(ALL_VALUE) ?\n features.map(f => f.name) :\n selected\n\n return names.map(name => {\n const f = features.find(\n ff => ff.name === name\n )!\n return { dir:f.dir, spec:f.spec, name:f.name }\n })\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["execFileSync", "existsSync", "readFileSync", "basename", "dirname", "join", "spawn", "execFile", "mkdirSync", "readFileSync", "writeFileSync", "readdirSync", "join", "dirname", "basename", "relative", "promisify", "join", "existsSync", "existsSync", "join", "execFile", "readFileSync", "writeFileSync", "promisify", "execFileAsync", "promisify", "execFile", "readFileSync", "checkbox", "writeFileSync", "execFile", "promisify", "execFileAsync", "promisify", "execFile", "existsSync", "readFileSync", "join", "join", "existsSync", "readFileSync", "resolve", "existsSync", "mkdirSync", "readFileSync", "writeFileSync", "basename", "dirname", "join", "key", "join", "dirname", "existsSync", "readFileSync", "mkdirSync", "basename", "writeFileSync", "existsSync", "readFileSync", "writeFileSync", "basename", "dirname", "join", "basename", "resolve", "basename", "dirname", "basename", "SENTINEL_PREFIX", "sanitize", "findingLines", "join", "writeFileSync", "existsSync", "readFileSync", "execFileAsync", "promisify", "execFile", "readdirSync", "join", "readFileSync", "writeFileSync", "basename", "process", "join", "writeFileSync", "basename", "spawn", "resolve", "logPath", "dirname", "readFileSync", "mkdirSync", "remaining", "relative", "statSync", "join", "resolve", "statSync", "resolve", "join", "existsSync", "readdirSync", "dirname", "join", "dirname", "join", "existsSync", "readdirSync", "join", "existsSync", "readFileSync", "dirname", "execFileSync", "basename"]
|
|
7
7
|
}
|