nightralph 0.0.45 → 0.0.47
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/dist/display.js +7 -0
- package/dist/display.js.map +2 -2
- package/dist/index.js +10 -1
- package/dist/index.js.map +2 -2
- package/dist/meta.json +6 -6
- package/dist/orchestrator.js +3 -1
- package/dist/orchestrator.js.map +2 -2
- package/dist/src/display.d.ts +2 -1
- package/dist/src/display.d.ts.map +1 -1
- package/dist/src/orchestrator.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/meta.json
CHANGED
|
@@ -105,7 +105,7 @@
|
|
|
105
105
|
"format": "esm"
|
|
106
106
|
},
|
|
107
107
|
"src/display.ts": {
|
|
108
|
-
"bytes":
|
|
108
|
+
"bytes": 13350,
|
|
109
109
|
"imports": [
|
|
110
110
|
{
|
|
111
111
|
"path": "<runtime>",
|
|
@@ -142,7 +142,7 @@
|
|
|
142
142
|
"format": "esm"
|
|
143
143
|
},
|
|
144
144
|
"src/orchestrator.ts": {
|
|
145
|
-
"bytes":
|
|
145
|
+
"bytes": 72625,
|
|
146
146
|
"imports": [
|
|
147
147
|
{
|
|
148
148
|
"path": "node:child_process",
|
|
@@ -310,7 +310,7 @@
|
|
|
310
310
|
"imports": [],
|
|
311
311
|
"exports": [],
|
|
312
312
|
"inputs": {},
|
|
313
|
-
"bytes":
|
|
313
|
+
"bytes": 189789
|
|
314
314
|
},
|
|
315
315
|
"dist/index.js": {
|
|
316
316
|
"imports": [
|
|
@@ -478,7 +478,7 @@
|
|
|
478
478
|
"bytesInOutput": 4816
|
|
479
479
|
},
|
|
480
480
|
"src/orchestrator.ts": {
|
|
481
|
-
"bytesInOutput":
|
|
481
|
+
"bytesInOutput": 50199
|
|
482
482
|
},
|
|
483
483
|
"src/worktree.ts": {
|
|
484
484
|
"bytesInOutput": 4088
|
|
@@ -490,7 +490,7 @@
|
|
|
490
490
|
"bytesInOutput": 4995
|
|
491
491
|
},
|
|
492
492
|
"src/display.ts": {
|
|
493
|
-
"bytesInOutput":
|
|
493
|
+
"bytesInOutput": 8617
|
|
494
494
|
},
|
|
495
495
|
"src/testcmd.ts": {
|
|
496
496
|
"bytesInOutput": 1914
|
|
@@ -499,7 +499,7 @@
|
|
|
499
499
|
"bytesInOutput": 1937
|
|
500
500
|
}
|
|
501
501
|
},
|
|
502
|
-
"bytes":
|
|
502
|
+
"bytes": 88509
|
|
503
503
|
}
|
|
504
504
|
}
|
|
505
505
|
}
|
package/dist/orchestrator.js
CHANGED
|
@@ -1220,9 +1220,11 @@ async function runTicketAttempts(opts) {
|
|
|
1220
1220
|
);
|
|
1221
1221
|
return { kind: "error", error };
|
|
1222
1222
|
}
|
|
1223
|
-
if (outcome.kind === "ready"
|
|
1223
|
+
if (outcome.kind === "ready") {
|
|
1224
|
+
d.setTicketStatus(ticket.num, "awaiting-merge");
|
|
1224
1225
|
return outcome;
|
|
1225
1226
|
}
|
|
1227
|
+
if (outcome.kind === "worktree-error") return outcome;
|
|
1226
1228
|
}
|
|
1227
1229
|
return outcome;
|
|
1228
1230
|
}
|
package/dist/orchestrator.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/orchestrator.ts"],
|
|
4
|
-
"sourcesContent": ["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 readProgress,\n mergeProgress,\n writeProgress,\n commitProgress,\n checkTicket,\n type ProgressData,\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}\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 (dir:string):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 }\n })\n}\n\nexport function findReadyTickets (\n tickets:ReadonlyArray<Ticket>\n):Ticket[] {\n const doneNums = new Set(\n tickets\n .filter(t => t.status === 'done')\n .map(t => t.num)\n )\n return tickets.filter(t => {\n if (t.status !== 'ready-for-agent') return false\n return t.blockers.every(b => doneNums.has(b))\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 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 => [t.num, t.status])\n )\n let wave = 1\n while (true) {\n const doneNums = new Set(\n [...sim.entries()]\n .filter(([, s]) => s === 'done')\n .map(([n]) => n)\n )\n const ready = [...tickets].filter(t => {\n if (sim.get(t.num) !== 'ready-for-agent') {\n return false\n }\n return t.blockers.every(\n b => doneNums.has(b)\n )\n })\n if (ready.length === 0) break\n yield { wave, ready }\n for (const t of ready) {\n sim.set(t.num, 'done')\n }\n wave++\n }\n}\n\nfunction detectDeadlocks (\n tickets:ReadonlyArray<Ticket>\n):Array<Ticket> {\n const doneNums = new Set<number>()\n const ready = new Set<number>()\n\n for (const t of tickets) {\n if (t.status === 'ready-for-agent') {\n ready.add(t.num)\n } else if (t.status === 'done') {\n doneNums.add(t.num)\n }\n }\n\n let changed = true\n while (changed) {\n changed = false\n for (const num of ready) {\n const ticket = tickets.find(t =>\n t.num === num\n )!\n if (ticket.blockers.every(\n b => doneNums.has(b)\n )) {\n doneNums.add(num)\n ready.delete(num)\n changed = true\n }\n }\n }\n\n return [...ready].map(num =>\n tickets.find(t => t.num === num)!\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 worktreePath =\n `../${opts.repoName}.${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 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(ticket.num, 'in-progress')\n const agentResult = await spawnAgent({\n prompt:renderPrompt(\n opts.specBody, 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 (\n outcome.kind === 'ready' ||\n outcome.kind === 'worktree-error'\n ) {\n return outcome\n }\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 failedNums:ReadonlySet<number>,\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 !failedNums.has(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 (failedNums.size > 0 ?\n `, ${failedNums.size} failed` :\n '') +\n (human.length > 0 ?\n `, ${human.length} need a human` :\n '')\n if (human.length === 0) return counts\n\n const noun = human.length === 1 ? 'ticket is' : 'tickets are'\n const lines = [\n counts,\n '',\n (remaining.length === 0 && failedNums.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 failedNums = new Set<number>()\n\n while (true) {\n const ready = findReadyTickets(tickets).filter(\n t => !failedNums.has(t.num)\n )\n if (ready.length === 0) break\n\n waveNum++\n const readyNums = new Set(ready.map(t => t.num))\n const remaining = tickets.filter(t =>\n t.status === 'ready-for-agent' &&\n !readyNums.has(t.num)\n )\n d.startWave(\n waveNum,\n totalWaves,\n ready.map(t => ({\n num:t.num,\n filename:t.filename,\n })),\n runProgress(tickets),\n remaining.map(t => ({\n num:t.num,\n filename:t.filename,\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(t.num, 'in-progress')\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 failedNums.add(ticket.num)\n d.setTicketStatus(ticket.num, 'failed')\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(ticket.num, 'done')\n d.log(\n ` ${ticket.filename}: done`\n )\n }\n\n if (waveCompleted === 0) {\n const remaining = findReadyTickets(tickets)\n .filter(t => !failedNums.has(t.num))\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, failedNums\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 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}):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 progressPath = join(\n dirname(opts.logsDir), 'progress.md'\n )\n const progress:ProgressData = mergeProgress(\n generateProgress(opts.featureName, opts.tickets),\n readProgress(progressPath)\n )\n await saveProgress(\n repoRoot,\n progressPath,\n progress,\n `nightralph: start ${opts.featureName}`,\n d,\n )\n\n let totalCompleted = 0\n let waveNum = 0\n const failedNums = new Set<number>()\n\n while (true) {\n const ready = findReadyTickets(opts.tickets).filter(\n t => !failedNums.has(t.num)\n )\n if (ready.length === 0) break\n\n waveNum++\n const readyNums = new Set(ready.map(t => t.num))\n const remaining = opts.tickets.filter(t =>\n t.status === 'ready-for-agent' &&\n !readyNums.has(t.num)\n )\n d.startWave(\n waveNum,\n totalWaves,\n ready.map(t => ({\n num:t.num,\n filename:t.filename,\n })),\n runProgress(opts.tickets),\n remaining.map(t => ({\n num:t.num,\n filename:t.filename,\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 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 ticketsByNum = new Map<number, Ticket>()\n const worktreePathsByNum = new Map<number, string>()\n\n for (let i = 0; i < outcomes.length; i++) {\n const outcome = outcomes[i]\n const ticket = ready[i]\n\n if (outcome.kind === 'worktree-error') {\n failedNums.add(ticket.num)\n d.setTicketStatus(ticket.num, 'failed')\n d.log(\n ` ${ticket.filename}: failed to create ` +\n `worktree: ${formatErrorMessage(outcome.error)}`\n )\n checkTicket(progress, ticket.num, {\n branch:'',\n exitCode:-1,\n done:false,\n })\n await saveProgress(\n repoRoot,\n progressPath,\n progress,\n `nightralph: ${ticket.filename} ` +\n 'worktree error',\n d,\n )\n continue\n }\n\n if (outcome.kind === 'error') {\n failedNums.add(ticket.num)\n d.setTicketStatus(ticket.num, 'failed')\n d.log(\n ` ${ticket.filename}: attempt error: ` +\n formatErrorMessage(outcome.error)\n )\n checkTicket(progress, ticket.num, {\n branch:outcome.branchName ?? '',\n exitCode:-1,\n done:false,\n })\n await saveProgress(\n repoRoot,\n progressPath,\n progress,\n `nightralph: ${ticket.filename} error`,\n d,\n )\n continue\n }\n\n if (outcome.kind === 'no-commits') {\n failedNums.add(ticket.num)\n d.setTicketStatus(ticket.num, 'failed')\n d.log(\n ` ${ticket.filename}: agent exited 0 ` +\n 'but made no changes; leaving ticket ' +\n 'ready-for-agent'\n )\n checkTicket(progress, ticket.num, {\n branch:outcome.branchName,\n exitCode:0,\n done:false,\n })\n await saveProgress(\n repoRoot,\n progressPath,\n progress,\n `nightralph: ${ticket.filename} ` +\n 'no commits',\n d,\n )\n continue\n }\n\n if (outcome.kind === 'failed') {\n failedNums.add(ticket.num)\n d.setTicketStatus(ticket.num, 'failed')\n if (outcome.reason === 'exit') {\n checkItems(ticket, outcome.completedItems)\n }\n // Acceptance criteria are not met when the\n // suite is red, so checklist items the agent\n // claimed are not checked off in that case.\n checkTicket(progress, ticket.num, {\n branch:outcome.branchName,\n exitCode:outcome.exitCode,\n done:false,\n })\n await saveProgress(\n repoRoot,\n progressPath,\n progress,\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 ticketsByNum.set(ticket.num, ticket)\n worktreePathsByNum.set(\n ticket.num, outcome.worktreePath\n )\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 ticketsByNum.get(sb.ticketNum)!\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 ticket = ticketsByNum.get(\n branchResult.ticketNum\n )\n if (!ticket) continue\n\n if (branchResult.merged) {\n markDone(ticket)\n waveCompleted++\n totalCompleted++\n d.setTicketStatus(ticket.num, 'done')\n d.log(\n ` ${ticket.filename}: done`\n )\n checkTicket(progress, ticket.num, {\n branch:branchResult.branch,\n exitCode:0,\n })\n await saveProgress(\n repoRoot,\n progressPath,\n progress,\n `nightralph: ${ticket.filename} done`,\n d,\n )\n\n const worktreePath = worktreePathsByNum.get(\n ticket.num\n )\n if (worktreePath) {\n await removeWorktreeQuietly(\n worktreePath, d\n )\n }\n } else {\n const worktreePath = worktreePathsByNum.get(\n ticket.num\n )\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:opts.specBody,\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(ticket.num, 'done')\n d.log(\n ` ${ticket.filename}: done ` +\n '(resolved via respawn)'\n )\n checkTicket(progress, ticket.num, {\n branch:branchResult.branch,\n exitCode:0,\n })\n await saveProgress(\n repoRoot,\n progressPath,\n progress,\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 // Without this the ticket stays\n // ready-for-agent and the wave loop\n // would re-run it forever; excluding it\n // from later waves of this run ends the\n // loop while the file keeps its status\n // for the next run.\n failedNums.add(ticket.num)\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(progress, ticket.num, {\n branch:branchResult.branch,\n exitCode:0,\n done:false,\n })\n await saveProgress(\n repoRoot,\n progressPath,\n progress,\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 ticket = ticketsByNum.get(sb.ticketNum)\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 => !failedNums.has(t.num))\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, failedNums\n ))\n d.cleanup()\n\n return { allDone:remaining.length === 0 }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["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 readProgress,\n mergeProgress,\n writeProgress,\n commitProgress,\n checkTicket,\n type ProgressData,\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}\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 (dir:string):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 }\n })\n}\n\nexport function findReadyTickets (\n tickets:ReadonlyArray<Ticket>\n):Ticket[] {\n const doneNums = new Set(\n tickets\n .filter(t => t.status === 'done')\n .map(t => t.num)\n )\n return tickets.filter(t => {\n if (t.status !== 'ready-for-agent') return false\n return t.blockers.every(b => doneNums.has(b))\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 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 => [t.num, t.status])\n )\n let wave = 1\n while (true) {\n const doneNums = new Set(\n [...sim.entries()]\n .filter(([, s]) => s === 'done')\n .map(([n]) => n)\n )\n const ready = [...tickets].filter(t => {\n if (sim.get(t.num) !== 'ready-for-agent') {\n return false\n }\n return t.blockers.every(\n b => doneNums.has(b)\n )\n })\n if (ready.length === 0) break\n yield { wave, ready }\n for (const t of ready) {\n sim.set(t.num, 'done')\n }\n wave++\n }\n}\n\nfunction detectDeadlocks (\n tickets:ReadonlyArray<Ticket>\n):Array<Ticket> {\n const doneNums = new Set<number>()\n const ready = new Set<number>()\n\n for (const t of tickets) {\n if (t.status === 'ready-for-agent') {\n ready.add(t.num)\n } else if (t.status === 'done') {\n doneNums.add(t.num)\n }\n }\n\n let changed = true\n while (changed) {\n changed = false\n for (const num of ready) {\n const ticket = tickets.find(t =>\n t.num === num\n )!\n if (ticket.blockers.every(\n b => doneNums.has(b)\n )) {\n doneNums.add(num)\n ready.delete(num)\n changed = true\n }\n }\n }\n\n return [...ready].map(num =>\n tickets.find(t => t.num === num)!\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 worktreePath =\n `../${opts.repoName}.${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 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(ticket.num, 'in-progress')\n const agentResult = await spawnAgent({\n prompt:renderPrompt(\n opts.specBody, 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(ticket.num, 'awaiting-merge')\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 failedNums:ReadonlySet<number>,\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 !failedNums.has(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 (failedNums.size > 0 ?\n `, ${failedNums.size} failed` :\n '') +\n (human.length > 0 ?\n `, ${human.length} need a human` :\n '')\n if (human.length === 0) return counts\n\n const noun = human.length === 1 ? 'ticket is' : 'tickets are'\n const lines = [\n counts,\n '',\n (remaining.length === 0 && failedNums.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 failedNums = new Set<number>()\n\n while (true) {\n const ready = findReadyTickets(tickets).filter(\n t => !failedNums.has(t.num)\n )\n if (ready.length === 0) break\n\n waveNum++\n const readyNums = new Set(ready.map(t => t.num))\n const remaining = tickets.filter(t =>\n t.status === 'ready-for-agent' &&\n !readyNums.has(t.num)\n )\n d.startWave(\n waveNum,\n totalWaves,\n ready.map(t => ({\n num:t.num,\n filename:t.filename,\n })),\n runProgress(tickets),\n remaining.map(t => ({\n num:t.num,\n filename:t.filename,\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(t.num, 'in-progress')\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 failedNums.add(ticket.num)\n d.setTicketStatus(ticket.num, 'failed')\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(ticket.num, 'done')\n d.log(\n ` ${ticket.filename}: done`\n )\n }\n\n if (waveCompleted === 0) {\n const remaining = findReadyTickets(tickets)\n .filter(t => !failedNums.has(t.num))\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, failedNums\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 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}):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 progressPath = join(\n dirname(opts.logsDir), 'progress.md'\n )\n const progress:ProgressData = mergeProgress(\n generateProgress(opts.featureName, opts.tickets),\n readProgress(progressPath)\n )\n await saveProgress(\n repoRoot,\n progressPath,\n progress,\n `nightralph: start ${opts.featureName}`,\n d,\n )\n\n let totalCompleted = 0\n let waveNum = 0\n const failedNums = new Set<number>()\n\n while (true) {\n const ready = findReadyTickets(opts.tickets).filter(\n t => !failedNums.has(t.num)\n )\n if (ready.length === 0) break\n\n waveNum++\n const readyNums = new Set(ready.map(t => t.num))\n const remaining = opts.tickets.filter(t =>\n t.status === 'ready-for-agent' &&\n !readyNums.has(t.num)\n )\n d.startWave(\n waveNum,\n totalWaves,\n ready.map(t => ({\n num:t.num,\n filename:t.filename,\n })),\n runProgress(opts.tickets),\n remaining.map(t => ({\n num:t.num,\n filename:t.filename,\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 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 ticketsByNum = new Map<number, Ticket>()\n const worktreePathsByNum = new Map<number, string>()\n\n for (let i = 0; i < outcomes.length; i++) {\n const outcome = outcomes[i]\n const ticket = ready[i]\n\n if (outcome.kind === 'worktree-error') {\n failedNums.add(ticket.num)\n d.setTicketStatus(ticket.num, 'failed')\n d.log(\n ` ${ticket.filename}: failed to create ` +\n `worktree: ${formatErrorMessage(outcome.error)}`\n )\n checkTicket(progress, ticket.num, {\n branch:'',\n exitCode:-1,\n done:false,\n })\n await saveProgress(\n repoRoot,\n progressPath,\n progress,\n `nightralph: ${ticket.filename} ` +\n 'worktree error',\n d,\n )\n continue\n }\n\n if (outcome.kind === 'error') {\n failedNums.add(ticket.num)\n d.setTicketStatus(ticket.num, 'failed')\n d.log(\n ` ${ticket.filename}: attempt error: ` +\n formatErrorMessage(outcome.error)\n )\n checkTicket(progress, ticket.num, {\n branch:outcome.branchName ?? '',\n exitCode:-1,\n done:false,\n })\n await saveProgress(\n repoRoot,\n progressPath,\n progress,\n `nightralph: ${ticket.filename} error`,\n d,\n )\n continue\n }\n\n if (outcome.kind === 'no-commits') {\n failedNums.add(ticket.num)\n d.setTicketStatus(ticket.num, 'failed')\n d.log(\n ` ${ticket.filename}: agent exited 0 ` +\n 'but made no changes; leaving ticket ' +\n 'ready-for-agent'\n )\n checkTicket(progress, ticket.num, {\n branch:outcome.branchName,\n exitCode:0,\n done:false,\n })\n await saveProgress(\n repoRoot,\n progressPath,\n progress,\n `nightralph: ${ticket.filename} ` +\n 'no commits',\n d,\n )\n continue\n }\n\n if (outcome.kind === 'failed') {\n failedNums.add(ticket.num)\n d.setTicketStatus(ticket.num, 'failed')\n if (outcome.reason === 'exit') {\n checkItems(ticket, outcome.completedItems)\n }\n // Acceptance criteria are not met when the\n // suite is red, so checklist items the agent\n // claimed are not checked off in that case.\n checkTicket(progress, ticket.num, {\n branch:outcome.branchName,\n exitCode:outcome.exitCode,\n done:false,\n })\n await saveProgress(\n repoRoot,\n progressPath,\n progress,\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 ticketsByNum.set(ticket.num, ticket)\n worktreePathsByNum.set(\n ticket.num, outcome.worktreePath\n )\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 ticketsByNum.get(sb.ticketNum)!\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 ticket = ticketsByNum.get(\n branchResult.ticketNum\n )\n if (!ticket) continue\n\n if (branchResult.merged) {\n markDone(ticket)\n waveCompleted++\n totalCompleted++\n d.setTicketStatus(ticket.num, 'done')\n d.log(\n ` ${ticket.filename}: done`\n )\n checkTicket(progress, ticket.num, {\n branch:branchResult.branch,\n exitCode:0,\n })\n await saveProgress(\n repoRoot,\n progressPath,\n progress,\n `nightralph: ${ticket.filename} done`,\n d,\n )\n\n const worktreePath = worktreePathsByNum.get(\n ticket.num\n )\n if (worktreePath) {\n await removeWorktreeQuietly(\n worktreePath, d\n )\n }\n } else {\n const worktreePath = worktreePathsByNum.get(\n ticket.num\n )\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:opts.specBody,\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(ticket.num, 'done')\n d.log(\n ` ${ticket.filename}: done ` +\n '(resolved via respawn)'\n )\n checkTicket(progress, ticket.num, {\n branch:branchResult.branch,\n exitCode:0,\n })\n await saveProgress(\n repoRoot,\n progressPath,\n progress,\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 // Without this the ticket stays\n // ready-for-agent and the wave loop\n // would re-run it forever; excluding it\n // from later waves of this run ends the\n // loop while the file keeps its status\n // for the next run.\n failedNums.add(ticket.num)\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(progress, ticket.num, {\n branch:branchResult.branch,\n exitCode:0,\n done:false,\n })\n await saveProgress(\n repoRoot,\n progressPath,\n progress,\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 ticket = ticketsByNum.get(sb.ticketNum)\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 => !failedNums.has(t.num))\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, failedNums\n ))\n d.cleanup()\n\n return { allDone:remaining.length === 0 }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["process", "remaining"]
|
|
7
7
|
}
|