nightralph 0.0.52 → 0.0.54
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 +145 -16
- package/dist/display.js +80 -62
- package/dist/display.js.map +2 -2
- package/dist/index.js +2099 -314
- package/dist/index.js.map +4 -4
- package/dist/learnings.js +356 -0
- package/dist/learnings.js.map +7 -0
- package/dist/meta.json +234 -14
- package/dist/orchestrator.js +528 -142
- 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/retry.js +83 -0
- package/dist/retry.js.map +7 -0
- package/dist/review.js +662 -0
- package/dist/review.js.map +7 -0
- package/dist/rules.js +54 -0
- package/dist/rules.js.map +7 -0
- package/dist/src/display.d.ts +35 -33
- package/dist/src/display.d.ts.map +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/learnings.d.ts +68 -0
- package/dist/src/learnings.d.ts.map +1 -0
- package/dist/src/orchestrator.d.ts +24 -11
- 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/retry.d.ts +26 -0
- package/dist/src/retry.d.ts.map +1 -0
- package/dist/src/review.d.ts +127 -0
- package/dist/src/review.d.ts.map +1 -0
- package/dist/src/rules.d.ts +10 -0
- package/dist/src/rules.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/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 +5 -4
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 type RunProgress,\n type Display,\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// 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 proc.stdout.pipe(logStream)\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)\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 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\n while (true) {\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 const readyKeys = new Set(\n ready.map(t => ticketKey(t.feature, t.num))\n )\n const remaining = tickets.filter(t =>\n t.status === 'ready-for-agent' &&\n !readyKeys.has(ticketKey(t.feature, t.num))\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(tickets),\n remaining.map(t => ({\n num:t.num,\n filename:t.filename,\n feature:t.feature,\n })),\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 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\n while (true) {\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 const readyKeys = new Set(\n ready.map(t => ticketKey(t.feature, t.num))\n )\n const remaining = opts.tickets.filter(t =>\n t.status === 'ready-for-agent' &&\n !readyKeys.has(ticketKey(t.feature, t.num))\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(opts.tickets),\n remaining.map(t => ({\n num:t.num,\n filename:t.filename,\n feature:t.feature,\n })),\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.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 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\nexport type DisplayTicket = {\n readonly num:number\n readonly filename:string\n readonly feature?:string\n status:TicketStatus\n}\n\nexport type WaveState = {\n readonly waveNum:number\n readonly totalWaves:number\n readonly tickets:Array<DisplayTicket>\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 tickets done before the wave started;\n * tickets that finish during the wave are added on top.\n */\nexport type RunProgress = {\n readonly completed:number\n readonly total:number\n}\n\nexport type Display = {\n startWave(\n waveNum:number,\n totalWaves:number,\n tickets:ReadonlyArray<{\n num:number\n filename:string\n feature?:string\n }>,\n progress?:RunProgress,\n remaining?:ReadonlyArray<{\n num:number\n filename:string\n feature?:string\n }>,\n ):void\n setTicketStatus(\n num:number,\n status:TicketStatus,\n feature?: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\nfunction 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\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.\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 }\n}\n\nexport class StatusDisplay implements Display {\n private wave:WaveState|null = null\n private progress:RunProgress|null = null\n private remaining:Array<DisplayTicket> = []\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 startWave (\n waveNum:number,\n totalWaves:number,\n tickets:Array<Readonly<{\n num:number\n filename:string\n feature?:string\n }>>,\n progress?:RunProgress,\n remaining?:ReadonlyArray<{\n num:number\n filename:string\n feature?:string\n }>,\n ):void {\n this.wave = {\n waveNum,\n totalWaves,\n tickets:tickets.map(t => ({\n ...t,\n status:'pending' as const,\n })),\n }\n this.remaining = (remaining ?? []).map(t => ({\n ...t,\n status:'pending' as const,\n }))\n this.progress = progress ?? null\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 if (!this.wave) return\n\n const ticket = feature ?\n this.wave.tickets.find(\n t => t.num === num && t.feature === feature,\n ) :\n this.wave.tickets.find(t => t.num === num)\n if (ticket) {\n ticket.status = status\n\n if (status === 'in-progress') {\n const ticketIndex = this.wave.tickets.indexOf(ticket)\n const availableRows = this.getAvailableRows()\n const totalTickets = this.wave.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\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 doneInWave = this.wave.tickets.filter(\n t => t.status === 'done',\n ).length\n const completed = doneInWave + (this.progress?.completed ?? 0)\n const total = this.progress?.total ?? this.wave.tickets.length\n const pct = total === 0 ? 0 : Math.round((completed / total) * 100)\n const width = Math.max(\n 1,\n (this.config.stream.columns ?? DEFAULT_COLUMNS) - 1,\n )\n\n output += `Wave ${this.wave.waveNum}/` +\n `${this.wave.totalWaves} - ` +\n `${pct}% complete\\n`\n\n // Pagination logic\n const availableRows = this.getAvailableRows()\n const tickets:ReadonlyArray<DisplayTicket> = [\n ...this.wave.tickets,\n ...this.remaining,\n ]\n let renderedTicketCount = 0\n\n if (tickets.length <= availableRows) {\n // All tickets fit, no pagination\n for (const ticket of tickets) {\n const dot = renderDot(ticket.status)\n const name = fitLine(\n ticketLabel(ticket), width - 2,\n )\n output += `${dot} ${name}\\n`\n }\n renderedTicketCount = tickets.length\n } else {\n // Need pagination -- iterative clamp\n this.viewportStart = Math.max(\n 0,\n Math.min(\n this.viewportStart,\n 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 tickets.length\n let ticketsToShow = Math.max(\n 0,\n tentativeCount - (hasMoreBelow ? 1 : 0),\n )\n\n const maxStart = Math.max(\n 0,\n 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 < 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 = 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 name = fitLine(\n ticketLabel(ticket), width - 2,\n )\n output += `${dot} ${name}\\n`\n }\n\n // Show \"more below\" indicator if needed\n if (hasMoreBelow) {\n const moreCount = (\n 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 startWave (\n waveNum:number,\n _totalWaves:number,\n tickets:ReadonlyArray<{\n num:number\n filename:string\n feature?:string\n }>,\n progress?:RunProgress,\n _remaining?:ReadonlyArray<{\n num:number\n filename:string\n feature?:string\n }>,\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 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/display.ts", "../src/testcmd.ts", "../src/learnings.ts", "../src/rules.ts", "../src/review.ts", "../src/retry.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 { 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 formatErrorMessage,\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 type FeatureSelection,\n} from './resolve.js'\nimport {\n getRepoRoot,\n getRepoName,\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('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 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}\n\n// Scans every selected feature's tickets from the working tree.\n// `log` is a no-op for the silent re-scan after resuming an\n// integration branch. A selection whose issues dir or spec is\n// absent is skipped and reported in `missing`; the caller decides\n// 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 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 const specBody = stripSpecSection(\n readFileSync(spec, 'utf8'),\n 'User Stories'\n )\n const tickets = scanTickets(dir, 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 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 log(\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 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 }\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// 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 try {\n execFileSync(\n 'git', ['checkout', '--quiet', plan.launchBranch],\n { cwd:getRepoRoot(), stdio:'ignore' }\n )\n } catch {\n // report the problem below either way\n }\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// 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 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 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 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 }\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 })\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(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; 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 progressPaths,\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 )\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 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 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'\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\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 }\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 '- 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 } = {}\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 '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\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 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):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\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 installCmd?: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 {\n testCmd:opts.testCmd,\n installCmd:opts.installCmd,\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 `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 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 // 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 { installCmd:opts.installCmd }\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\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 learningsPath:string\n d:Display\n}\n\n// The ticket's own earlier attempts and its direct blockers'\n// last successful runs, rendered for the prompt. Learnings are\n// advisory, so an unreadable log means no history, not a failure.\nfunction buildHistory (\n learningsPath:string,\n ticket:Ticket,\n d:Display\n):string {\n try {\n return renderHistory(selectHistory(\n readEntries(learningsPath),\n {\n key:ticketKey(ticket.feature, ticket.num),\n blockerKeys:ticket.blockers.map(b => {\n return ticketKey(ticket.feature, b)\n }),\n }\n ))\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&{ 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 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 }\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 // 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 }\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 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, attempt, effort,\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 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 // 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 // per-feature progress paths for multi-feature runs\n progressPaths?:Map<string, string>\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\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 learningsPath:learningsPathFor(\n tracker.pathFor(t.feature)\n ),\n retries,\n retryDelay,\n d,\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 onLine:(msg) => d.log(msg),\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 retries,\n retryDelay,\n log:(msg) => d.log(msg),\n }, { spawnAgent, registry:runningAgents })\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\n ))\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", "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\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}\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 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 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\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 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}):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 '- 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 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 '- 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 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 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 }),\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 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 }),\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 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", "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 { 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": ["execFileSync", "existsSync", "readFileSync", "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", "spawn", "resolve", "logPath", "mkdirSync", "remaining", "dirname", "relative", "statSync", "join", "resolve", "statSync", "resolve", "join", "existsSync", "readdirSync", "dirname", "join", "dirname", "join", "existsSync", "readdirSync", "join", "existsSync", "readFileSync", "dirname", "execFileSync"]
|
|
7
7
|
}
|