nightralph 0.0.18 → 0.0.19

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 CHANGED
@@ -44,6 +44,8 @@ const FILLED_DOT = "\u25CF";
44
44
  const EMPTY_DOT = "\u25CB";
45
45
  const SEPARATOR_WIDTH = 50;
46
46
  const DEFAULT_COLUMNS = 80;
47
+ const MIN_LOG_ROWS = 1;
48
+ const MAX_MESSAGE_BUFFER = 200;
47
49
  const ANSI_RE = /\x1b\[[0-9;?]*[A-Za-z]/g;
48
50
  function fitLine(line, width) {
49
51
  const visible = line.replace(ANSI_RE, "");
@@ -79,13 +81,12 @@ class StatusDisplay {
79
81
  signalHandler = null;
80
82
  constructor(config) {
81
83
  this.config = {
82
- messageLines: config?.messageLines ?? 10,
83
84
  stream: config?.stream ?? process.stdout
84
85
  };
85
86
  }
86
87
  getAvailableRows() {
87
88
  const termHeight = this.config.stream.rows ?? 24;
88
- const overhead = 2 + this.config.messageLines;
89
+ const overhead = 2 + MIN_LOG_ROWS;
89
90
  const available = termHeight - overhead;
90
91
  return Math.max(1, available);
91
92
  }
@@ -152,7 +153,7 @@ class StatusDisplay {
152
153
  }
153
154
  log(message) {
154
155
  this.messages.push(message);
155
- if (this.messages.length > this.config.messageLines) {
156
+ if (this.messages.length > MAX_MESSAGE_BUFFER) {
156
157
  this.messages.shift();
157
158
  }
158
159
  this.render();
@@ -251,18 +252,21 @@ class StatusDisplay {
251
252
  renderedTicketCount = (hasMoreAbove ? 1 : 0) + visibleTickets.length + (hasMoreBelow ? 1 : 0);
252
253
  }
253
254
  output += "-".repeat(Math.min(SEPARATOR_WIDTH, width)) + "\n";
254
- const msgLines = Math.max(
255
+ const termHeight = this.config.stream.rows ?? 24;
256
+ const logRows = Math.max(
255
257
  0,
256
- this.config.messageLines - this.messages.length
258
+ termHeight - 2 - renderedTicketCount
257
259
  );
258
- for (const msg of this.messages) {
260
+ const visibleMessages = this.messages.slice(-logRows);
261
+ for (const msg of visibleMessages) {
259
262
  output += `${fitLine(msg, width)}
260
263
  `;
261
264
  }
262
- for (let i = 0; i < msgLines; i++) {
265
+ const emptyRows = logRows - visibleMessages.length;
266
+ for (let i = 0; i < emptyRows; i++) {
263
267
  output += "\n";
264
268
  }
265
- this.renderedLines = 2 + renderedTicketCount + this.config.messageLines;
269
+ this.renderedLines = 2 + renderedTicketCount + logRows;
266
270
  this.config.stream.write(output);
267
271
  }
268
272
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/display.ts"],
4
- "sourcesContent": ["export type TicketStatus =\n | 'pending'\n | 'in-progress'\n | 'done'\n | 'failed'\n\nexport type DisplayTicket = {\n readonly num:number\n readonly filename:string\n status:TicketStatus\n}\n\nexport type WaveState = {\n readonly waveNum:number\n readonly totalWaves:number\n readonly tickets:Array<DisplayTicket>\n}\n\nexport type DisplayConfig = {\n readonly messageLines:number\n readonly stream:NodeJS.WriteStream\n}\n\n/**\n * Progress across the whole run, not just the current wave.\n * `completed` counts tickets done before the wave started;\n * tickets that finish during the wave are added on top.\n */\nexport type RunProgress = {\n readonly completed:number\n readonly total:number\n}\n\nexport type Display = {\n startWave(\n waveNum:number,\n totalWaves:number,\n tickets:ReadonlyArray<{\n num:number\n filename:string\n }>,\n progress?:RunProgress,\n remaining?:ReadonlyArray<{\n num:number\n filename:string\n }>,\n ):void\n setTicketStatus(num:number, status:TicketStatus):void\n log(message:string):void\n cleanup():void\n}\n\nconst ESC = '\\x1b['\n\nexport const ansi = {\n cursorUp (n:number):string {\n return `${ESC}${n}A`\n },\n cursorTo (col:number):string {\n return `${ESC}${col}G`\n },\n eraseLine ():string {\n return `${ESC}2K`\n },\n eraseLines (n:number):string {\n let out = ''\n for (let i = 0; i < n; i++) {\n out += ansi.eraseLine()\n if (i < n - 1) out += ansi.cursorUp(1)\n }\n return out\n },\n cursorHide ():string {\n return `${ESC}?25l`\n },\n cursorShow ():string {\n return `${ESC}?25h`\n },\n} as const\n\nexport const color = {\n green (text:string):string {\n return `${ESC}32m${text}${ESC}0m`\n },\n yellow (text:string):string {\n return `${ESC}33m${text}${ESC}0m`\n },\n red (text:string):string {\n return `${ESC}31m${text}${ESC}0m`\n },\n dim (text:string):string {\n return `${ESC}2m${text}${ESC}0m`\n },\n} as const\n\nconst FILLED_DOT = '\u25CF'\nconst EMPTY_DOT = '\u25CB'\nconst SEPARATOR_WIDTH = 50\nconst DEFAULT_COLUMNS = 80\n\n// eslint-disable-next-line no-control-regex\nconst ANSI_RE = /\\x1b\\[[0-9;?]*[A-Za-z]/g\n\n/**\n * Clamp a line to `width` visible columns so it can never wrap.\n * A wrapped line occupies more terminal rows than `render`\n * counts, which leaves stale rows behind on the next erase.\n */\nexport function fitLine (line:string, width:number):string {\n const visible = line.replace(ANSI_RE, '')\n if (visible.length <= width) return line\n return visible.slice(0, width)\n}\n\nexport function renderDot (status:TicketStatus):string {\n switch (status) {\n case 'pending':\n return color.dim(EMPTY_DOT)\n case 'in-progress':\n return color.yellow(FILLED_DOT)\n case 'done':\n return color.green(FILLED_DOT)\n case 'failed':\n return color.red(FILLED_DOT)\n }\n}\n\nexport class StatusDisplay implements Display {\n private wave:WaveState|null = null\n private progress:RunProgress|null = null\n private remaining:Array<DisplayTicket> = []\n private messages:Array<string> = []\n private renderedLines:number = 0\n private config:DisplayConfig\n private viewportStart:number = 0\n private resizeListener:(() => void)|null = null\n private signalHandler:(() => void)|null = null\n\n constructor (config?:Readonly<Partial<DisplayConfig>>) {\n this.config = {\n messageLines:config?.messageLines ?? 10,\n stream:config?.stream ?? process.stdout,\n }\n }\n\n private getAvailableRows ():number {\n const termHeight = this.config.stream.rows ?? 24\n const overhead = 2 + this.config.messageLines\n const available = termHeight - overhead\n return Math.max(1, available)\n }\n\n startWave (\n waveNum:number,\n totalWaves:number,\n tickets:Array<Readonly<{ num:number; filename:string }>>,\n progress?:RunProgress,\n remaining?:ReadonlyArray<{\n num:number\n filename:string\n }>,\n ):void {\n this.wave = {\n waveNum,\n totalWaves,\n tickets:tickets.map(t => ({\n ...t,\n status:'pending' as const,\n })),\n }\n this.remaining = (remaining ?? []).map(t => ({\n ...t,\n status:'pending' as const,\n }))\n this.progress = progress ?? null\n this.messages = []\n this.viewportStart = 0\n this.config.stream.write(ansi.cursorHide())\n\n if (this.config.stream.isTTY) {\n if (this.resizeListener) {\n this.config.stream.removeListener(\n 'resize', this.resizeListener,\n )\n }\n this.resizeListener = () => this.render()\n this.config.stream.on(\n 'resize', this.resizeListener,\n )\n }\n\n // Register signal handler to restore cursor on interruption\n if (this.signalHandler) {\n process.removeListener('SIGINT', this.signalHandler)\n process.removeListener('SIGTERM', this.signalHandler)\n }\n this.signalHandler = () => this.cleanup()\n process.on('SIGINT', this.signalHandler)\n process.on('SIGTERM', this.signalHandler)\n\n this.render()\n }\n\n setTicketStatus (num:number, status:TicketStatus):void {\n if (!this.wave) return\n\n const ticket = this.wave.tickets.find(t => t.num === num)\n if (ticket) {\n ticket.status = status\n\n if (status === 'in-progress') {\n const ticketIndex = this.wave.tickets.indexOf(ticket)\n const availableRows = this.getAvailableRows()\n const totalTickets = this.wave.tickets.length\n\n if (ticketIndex < this.viewportStart) {\n this.viewportStart = ticketIndex\n } else if (ticketIndex >= this.viewportStart + availableRows) {\n // offset by 3 to keep context visible below\n // the active ticket\n this.viewportStart = ticketIndex - availableRows + 3\n }\n this.viewportStart = Math.max(\n 0,\n Math.min(this.viewportStart, totalTickets - 1),\n )\n }\n\n this.render()\n }\n }\n\n log (message:string):void {\n this.messages.push(message)\n if (this.messages.length > this.config.messageLines) {\n this.messages.shift()\n }\n this.render()\n }\n\n cleanup ():void {\n // Remove resize listener if it exists\n if (this.resizeListener && this.config.stream.isTTY) {\n this.config.stream.removeListener('resize', this.resizeListener)\n }\n // Remove signal handlers\n if (this.signalHandler) {\n process.removeListener('SIGINT', this.signalHandler)\n process.removeListener('SIGTERM', this.signalHandler)\n }\n this.config.stream.write(ansi.cursorShow())\n }\n\n private render ():void {\n if (!this.wave) return\n\n let output = ''\n\n if (this.renderedLines > 0) {\n output += ansi.eraseLines(this.renderedLines + 1)\n }\n\n const doneInWave = this.wave.tickets.filter(\n t => t.status === 'done',\n ).length\n const completed = doneInWave + (this.progress?.completed ?? 0)\n const total = this.progress?.total ?? this.wave.tickets.length\n const pct = total === 0 ? 0 : Math.round((completed / total) * 100)\n const width = Math.max(\n 1,\n (this.config.stream.columns ?? DEFAULT_COLUMNS) - 1,\n )\n\n output += `Wave ${this.wave.waveNum}/` +\n `${this.wave.totalWaves} - ` +\n `${pct}% complete\\n`\n\n // Pagination logic\n const availableRows = this.getAvailableRows()\n const tickets:ReadonlyArray<DisplayTicket> = [\n ...this.wave.tickets,\n ...this.remaining,\n ]\n let renderedTicketCount = 0\n\n if (tickets.length <= availableRows) {\n // All tickets fit, no pagination\n for (const ticket of tickets) {\n const dot = renderDot(ticket.status)\n const name = fitLine(ticket.filename, width - 2)\n output += `${dot} ${name}\\n`\n }\n renderedTicketCount = tickets.length\n } else {\n // Need pagination -- iterative clamp\n this.viewportStart = Math.max(\n 0,\n Math.min(\n this.viewportStart,\n tickets.length - 1,\n ),\n )\n\n let hasMoreAbove = this.viewportStart > 0\n let tentativeCount =\n availableRows - (hasMoreAbove ? 1 : 0)\n let hasMoreBelow =\n this.viewportStart + tentativeCount <\n tickets.length\n let ticketsToShow = Math.max(\n 0,\n tentativeCount - (hasMoreBelow ? 1 : 0),\n )\n\n const maxStart = Math.max(\n 0,\n tickets.length - Math.max(1, ticketsToShow),\n )\n if (this.viewportStart > maxStart) {\n this.viewportStart = maxStart\n hasMoreAbove = this.viewportStart > 0\n tentativeCount = availableRows - (hasMoreAbove ? 1 : 0)\n hasMoreBelow = (\n this.viewportStart +\n tentativeCount < tickets.length\n )\n ticketsToShow = Math.max(\n 0,\n tentativeCount - (hasMoreBelow ? 1 : 0)\n )\n }\n\n // Show \"more above\" indicator if needed\n if (hasMoreAbove) {\n const moreCount = this.viewportStart\n output += ` ... ${moreCount} more above\\n`\n }\n\n // Get visible tickets and render them\n const visibleTickets = tickets.slice(\n this.viewportStart,\n this.viewportStart + ticketsToShow,\n )\n\n for (const ticket of visibleTickets) {\n const dot = renderDot(ticket.status)\n const name = fitLine(ticket.filename, width - 2)\n output += `${dot} ${name}\\n`\n }\n\n // Show \"more below\" indicator if needed\n if (hasMoreBelow) {\n const moreCount = (\n tickets.length -\n (this.viewportStart + ticketsToShow)\n )\n output += ` ... ${moreCount} more below\\n`\n }\n\n renderedTicketCount = (hasMoreAbove ? 1 : 0) +\n visibleTickets.length +\n (hasMoreBelow ? 1 : 0)\n }\n\n output += '-'.repeat(Math.min(SEPARATOR_WIDTH, width)) + '\\n'\n\n const msgLines = Math.max(\n 0,\n this.config.messageLines - this.messages.length,\n )\n for (const msg of this.messages) {\n output += `${fitLine(msg, width)}\\n`\n }\n for (let i = 0; i < msgLines; i++) {\n output += '\\n'\n }\n\n this.renderedLines = 2 + renderedTicketCount + this.config.messageLines\n this.config.stream.write(output)\n }\n}\n\nexport class PlainDisplay implements Display {\n startWave (\n waveNum:number,\n _totalWaves:number,\n tickets:ReadonlyArray<{ num:number; filename:string }>,\n progress?:RunProgress,\n _remaining?:ReadonlyArray<{\n num:number\n filename:string\n }>,\n ):void {\n const pct = progress && progress.total > 0 ?\n ` (${progress.completed}/${progress.total} done)` :\n ''\n console.log(\n `\\nWave ${waveNum}${pct}: ` +\n tickets.map(t => t.filename).join(', ')\n )\n }\n\n setTicketStatus (_num:number, _status:TicketStatus):void {\n // no-op: plain mode reports via log()\n }\n\n log (message:string):void {\n console.log(message)\n }\n\n cleanup ():void {\n // no-op\n }\n}\n\nexport function createDisplay (stream?:NodeJS.WriteStream):Display {\n const s = stream ?? process.stdout\n if (s.isTTY) {\n return new StatusDisplay({ stream:s })\n }\n\n return new PlainDisplay()\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["export type TicketStatus =\n | 'pending'\n | 'in-progress'\n | 'done'\n | 'failed'\n\nexport type DisplayTicket = {\n readonly num:number\n readonly filename:string\n status:TicketStatus\n}\n\nexport type WaveState = {\n readonly waveNum:number\n readonly totalWaves:number\n readonly tickets:Array<DisplayTicket>\n}\n\nexport type DisplayConfig = {\n readonly stream:NodeJS.WriteStream\n}\n\n/**\n * Progress across the whole run, not just the current wave.\n * `completed` counts tickets done before the wave started;\n * tickets that finish during the wave are added on top.\n */\nexport type RunProgress = {\n readonly completed:number\n readonly total:number\n}\n\nexport type Display = {\n startWave(\n waveNum:number,\n totalWaves:number,\n tickets:ReadonlyArray<{\n num:number\n filename:string\n }>,\n progress?:RunProgress,\n remaining?:ReadonlyArray<{\n num:number\n filename:string\n }>,\n ):void\n setTicketStatus(num:number, status:TicketStatus):void\n log(message:string):void\n cleanup():void\n}\n\nconst ESC = '\\x1b['\n\nexport const ansi = {\n cursorUp (n:number):string {\n return `${ESC}${n}A`\n },\n cursorTo (col:number):string {\n return `${ESC}${col}G`\n },\n eraseLine ():string {\n return `${ESC}2K`\n },\n eraseLines (n:number):string {\n let out = ''\n for (let i = 0; i < n; i++) {\n out += ansi.eraseLine()\n if (i < n - 1) out += ansi.cursorUp(1)\n }\n return out\n },\n cursorHide ():string {\n return `${ESC}?25l`\n },\n cursorShow ():string {\n return `${ESC}?25h`\n },\n} as const\n\nexport const color = {\n green (text:string):string {\n return `${ESC}32m${text}${ESC}0m`\n },\n yellow (text:string):string {\n return `${ESC}33m${text}${ESC}0m`\n },\n red (text:string):string {\n return `${ESC}31m${text}${ESC}0m`\n },\n dim (text:string):string {\n return `${ESC}2m${text}${ESC}0m`\n },\n} as const\n\nconst FILLED_DOT = '\u25CF'\nconst EMPTY_DOT = '\u25CB'\nconst SEPARATOR_WIDTH = 50\nconst DEFAULT_COLUMNS = 80\nconst MIN_LOG_ROWS = 1\nconst MAX_MESSAGE_BUFFER = 200\n\n// eslint-disable-next-line no-control-regex\nconst ANSI_RE = /\\x1b\\[[0-9;?]*[A-Za-z]/g\n\n/**\n * Clamp a line to `width` visible columns so it can never wrap.\n * A wrapped line occupies more terminal rows than `render`\n * counts, which leaves stale rows behind on the next erase.\n */\nexport function fitLine (line:string, width:number):string {\n const visible = line.replace(ANSI_RE, '')\n if (visible.length <= width) return line\n return visible.slice(0, width)\n}\n\nexport function renderDot (status:TicketStatus):string {\n switch (status) {\n case 'pending':\n return color.dim(EMPTY_DOT)\n case 'in-progress':\n return color.yellow(FILLED_DOT)\n case 'done':\n return color.green(FILLED_DOT)\n case 'failed':\n return color.red(FILLED_DOT)\n }\n}\n\nexport class StatusDisplay implements Display {\n private wave:WaveState|null = null\n private progress:RunProgress|null = null\n private remaining:Array<DisplayTicket> = []\n private messages:Array<string> = []\n private renderedLines:number = 0\n private config:DisplayConfig\n private viewportStart:number = 0\n private resizeListener:(() => void)|null = null\n private signalHandler:(() => void)|null = null\n\n constructor (config?:Readonly<Partial<DisplayConfig>>) {\n this.config = {\n stream:config?.stream ?? process.stdout,\n }\n }\n\n private getAvailableRows ():number {\n const termHeight = this.config.stream.rows ?? 24\n const overhead = 2 + MIN_LOG_ROWS\n const available = termHeight - overhead\n return Math.max(1, available)\n }\n\n startWave (\n waveNum:number,\n totalWaves:number,\n tickets:Array<Readonly<{ num:number; filename:string }>>,\n progress?:RunProgress,\n remaining?:ReadonlyArray<{\n num:number\n filename:string\n }>,\n ):void {\n this.wave = {\n waveNum,\n totalWaves,\n tickets:tickets.map(t => ({\n ...t,\n status:'pending' as const,\n })),\n }\n this.remaining = (remaining ?? []).map(t => ({\n ...t,\n status:'pending' as const,\n }))\n this.progress = progress ?? null\n this.messages = []\n this.viewportStart = 0\n this.config.stream.write(ansi.cursorHide())\n\n if (this.config.stream.isTTY) {\n if (this.resizeListener) {\n this.config.stream.removeListener(\n 'resize', this.resizeListener,\n )\n }\n this.resizeListener = () => this.render()\n this.config.stream.on(\n 'resize', this.resizeListener,\n )\n }\n\n // Register signal handler to restore cursor on interruption\n if (this.signalHandler) {\n process.removeListener('SIGINT', this.signalHandler)\n process.removeListener('SIGTERM', this.signalHandler)\n }\n this.signalHandler = () => this.cleanup()\n process.on('SIGINT', this.signalHandler)\n process.on('SIGTERM', this.signalHandler)\n\n this.render()\n }\n\n setTicketStatus (num:number, status:TicketStatus):void {\n if (!this.wave) return\n\n const ticket = this.wave.tickets.find(t => t.num === num)\n if (ticket) {\n ticket.status = status\n\n if (status === 'in-progress') {\n const ticketIndex = this.wave.tickets.indexOf(ticket)\n const availableRows = this.getAvailableRows()\n const totalTickets = this.wave.tickets.length\n\n if (ticketIndex < this.viewportStart) {\n this.viewportStart = ticketIndex\n } else if (ticketIndex >= this.viewportStart + availableRows) {\n // offset by 3 to keep context visible below\n // the active ticket\n this.viewportStart = ticketIndex - availableRows + 3\n }\n this.viewportStart = Math.max(\n 0,\n Math.min(this.viewportStart, totalTickets - 1),\n )\n }\n\n this.render()\n }\n }\n\n log (message:string):void {\n this.messages.push(message)\n if (this.messages.length > MAX_MESSAGE_BUFFER) {\n this.messages.shift()\n }\n this.render()\n }\n\n cleanup ():void {\n // Remove resize listener if it exists\n if (this.resizeListener && this.config.stream.isTTY) {\n this.config.stream.removeListener('resize', this.resizeListener)\n }\n // Remove signal handlers\n if (this.signalHandler) {\n process.removeListener('SIGINT', this.signalHandler)\n process.removeListener('SIGTERM', this.signalHandler)\n }\n this.config.stream.write(ansi.cursorShow())\n }\n\n private render ():void {\n if (!this.wave) return\n\n let output = ''\n\n if (this.renderedLines > 0) {\n output += ansi.eraseLines(this.renderedLines + 1)\n }\n\n const doneInWave = this.wave.tickets.filter(\n t => t.status === 'done',\n ).length\n const completed = doneInWave + (this.progress?.completed ?? 0)\n const total = this.progress?.total ?? this.wave.tickets.length\n const pct = total === 0 ? 0 : Math.round((completed / total) * 100)\n const width = Math.max(\n 1,\n (this.config.stream.columns ?? DEFAULT_COLUMNS) - 1,\n )\n\n output += `Wave ${this.wave.waveNum}/` +\n `${this.wave.totalWaves} - ` +\n `${pct}% complete\\n`\n\n // Pagination logic\n const availableRows = this.getAvailableRows()\n const tickets:ReadonlyArray<DisplayTicket> = [\n ...this.wave.tickets,\n ...this.remaining,\n ]\n let renderedTicketCount = 0\n\n if (tickets.length <= availableRows) {\n // All tickets fit, no pagination\n for (const ticket of tickets) {\n const dot = renderDot(ticket.status)\n const name = fitLine(ticket.filename, width - 2)\n output += `${dot} ${name}\\n`\n }\n renderedTicketCount = tickets.length\n } else {\n // Need pagination -- iterative clamp\n this.viewportStart = Math.max(\n 0,\n Math.min(\n this.viewportStart,\n tickets.length - 1,\n ),\n )\n\n let hasMoreAbove = this.viewportStart > 0\n let tentativeCount =\n availableRows - (hasMoreAbove ? 1 : 0)\n let hasMoreBelow =\n this.viewportStart + tentativeCount <\n tickets.length\n let ticketsToShow = Math.max(\n 0,\n tentativeCount - (hasMoreBelow ? 1 : 0),\n )\n\n const maxStart = Math.max(\n 0,\n tickets.length - Math.max(1, ticketsToShow),\n )\n if (this.viewportStart > maxStart) {\n this.viewportStart = maxStart\n hasMoreAbove = this.viewportStart > 0\n tentativeCount = availableRows - (hasMoreAbove ? 1 : 0)\n hasMoreBelow = (\n this.viewportStart +\n tentativeCount < tickets.length\n )\n ticketsToShow = Math.max(\n 0,\n tentativeCount - (hasMoreBelow ? 1 : 0)\n )\n }\n\n // Show \"more above\" indicator if needed\n if (hasMoreAbove) {\n const moreCount = this.viewportStart\n output += ` ... ${moreCount} more above\\n`\n }\n\n // Get visible tickets and render them\n const visibleTickets = tickets.slice(\n this.viewportStart,\n this.viewportStart + ticketsToShow,\n )\n\n for (const ticket of visibleTickets) {\n const dot = renderDot(ticket.status)\n const name = fitLine(ticket.filename, width - 2)\n output += `${dot} ${name}\\n`\n }\n\n // Show \"more below\" indicator if needed\n if (hasMoreBelow) {\n const moreCount = (\n tickets.length -\n (this.viewportStart + ticketsToShow)\n )\n output += ` ... ${moreCount} more below\\n`\n }\n\n renderedTicketCount = (hasMoreAbove ? 1 : 0) +\n visibleTickets.length +\n (hasMoreBelow ? 1 : 0)\n }\n\n output += '-'.repeat(Math.min(SEPARATOR_WIDTH, width)) + '\\n'\n\n const termHeight = this.config.stream.rows ?? 24\n const logRows = Math.max(\n 0,\n termHeight - 2 - renderedTicketCount,\n )\n const visibleMessages = this.messages.slice(-logRows)\n for (const msg of visibleMessages) {\n output += `${fitLine(msg, width)}\\n`\n }\n const emptyRows = logRows - visibleMessages.length\n for (let i = 0; i < emptyRows; i++) {\n output += '\\n'\n }\n\n this.renderedLines = 2 + renderedTicketCount + logRows\n this.config.stream.write(output)\n }\n}\n\nexport class PlainDisplay implements Display {\n startWave (\n waveNum:number,\n _totalWaves:number,\n tickets:ReadonlyArray<{ num:number; filename:string }>,\n progress?:RunProgress,\n _remaining?:ReadonlyArray<{\n num:number\n filename:string\n }>,\n ):void {\n const pct = progress && progress.total > 0 ?\n ` (${progress.completed}/${progress.total} done)` :\n ''\n console.log(\n `\\nWave ${waveNum}${pct}: ` +\n tickets.map(t => t.filename).join(', ')\n )\n }\n\n setTicketStatus (_num:number, _status:TicketStatus):void {\n // no-op: plain mode reports via log()\n }\n\n log (message:string):void {\n console.log(message)\n }\n\n cleanup ():void {\n // no-op\n }\n}\n\nexport function createDisplay (stream?:NodeJS.WriteStream):Display {\n const s = stream ?? process.stdout\n if (s.isTTY) {\n return new StatusDisplay({ stream:s })\n }\n\n return new PlainDisplay()\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/dist/index.js CHANGED
@@ -734,6 +734,8 @@ var FILLED_DOT = "\u25CF";
734
734
  var EMPTY_DOT = "\u25CB";
735
735
  var SEPARATOR_WIDTH = 50;
736
736
  var DEFAULT_COLUMNS = 80;
737
+ var MIN_LOG_ROWS = 1;
738
+ var MAX_MESSAGE_BUFFER = 200;
737
739
  var ANSI_RE = /\x1b\[[0-9;?]*[A-Za-z]/g;
738
740
  function fitLine(line, width) {
739
741
  const visible = line.replace(ANSI_RE, "");
@@ -769,13 +771,12 @@ var StatusDisplay = class {
769
771
  signalHandler = null;
770
772
  constructor(config) {
771
773
  this.config = {
772
- messageLines: config?.messageLines ?? 10,
773
774
  stream: config?.stream ?? process.stdout
774
775
  };
775
776
  }
776
777
  getAvailableRows() {
777
778
  const termHeight = this.config.stream.rows ?? 24;
778
- const overhead = 2 + this.config.messageLines;
779
+ const overhead = 2 + MIN_LOG_ROWS;
779
780
  const available = termHeight - overhead;
780
781
  return Math.max(1, available);
781
782
  }
@@ -842,7 +843,7 @@ var StatusDisplay = class {
842
843
  }
843
844
  log(message) {
844
845
  this.messages.push(message);
845
- if (this.messages.length > this.config.messageLines) {
846
+ if (this.messages.length > MAX_MESSAGE_BUFFER) {
846
847
  this.messages.shift();
847
848
  }
848
849
  this.render();
@@ -941,18 +942,21 @@ var StatusDisplay = class {
941
942
  renderedTicketCount = (hasMoreAbove ? 1 : 0) + visibleTickets.length + (hasMoreBelow ? 1 : 0);
942
943
  }
943
944
  output += "-".repeat(Math.min(SEPARATOR_WIDTH, width)) + "\n";
944
- const msgLines = Math.max(
945
+ const termHeight = this.config.stream.rows ?? 24;
946
+ const logRows = Math.max(
945
947
  0,
946
- this.config.messageLines - this.messages.length
948
+ termHeight - 2 - renderedTicketCount
947
949
  );
948
- for (const msg of this.messages) {
950
+ const visibleMessages = this.messages.slice(-logRows);
951
+ for (const msg of visibleMessages) {
949
952
  output += `${fitLine(msg, width)}
950
953
  `;
951
954
  }
952
- for (let i = 0; i < msgLines; i++) {
955
+ const emptyRows = logRows - visibleMessages.length;
956
+ for (let i = 0; i < emptyRows; i++) {
953
957
  output += "\n";
954
958
  }
955
- this.renderedLines = 2 + renderedTicketCount + this.config.messageLines;
959
+ this.renderedLines = 2 + renderedTicketCount + logRows;
956
960
  this.config.stream.write(output);
957
961
  }
958
962
  };
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts", "../src/setup.ts", "../src/orchestrator.ts", "../src/worktree.ts", "../src/progress.ts", "../src/merge.ts", "../src/display.ts", "../src/resolve.ts"],
4
- "sourcesContent": ["#!/usr/bin/env node\n\nimport { existsSync, readFileSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport yargs from 'yargs'\nimport { hideBin } from 'yargs/helpers'\nimport { select } from '@inquirer/prompts'\nimport { setup, checkGhAuth, type TrackerKind } from './setup.js'\nimport {\n scanTickets,\n dryRun,\n dryRunIsolated,\n runWaves,\n runWavesIsolated,\n} from './orchestrator.js'\nimport { createDisplay } from './display.js'\nimport {\n findFeatureDirs,\n resolveIssuesDir,\n getScriptDir,\n} from './resolve.js'\nimport { getRepoRoot, getRepoName } from './worktree.js'\n\nexport { findFeatureDirs, resolveIssuesDir }\n\nconst scriptDir = getScriptDir(import.meta.url)\n\nyargs(hideBin(process.argv))\n .scriptName('nightralph')\n .usage('$0 <command>')\n .command(\n 'init',\n 'Install bundled skills and doc templates',\n y => y.option('claude', {\n type:'boolean',\n describe:'Also create .claude/skills/ symlinks',\n default:true,\n }),\n async argv => {\n const tracker = await select<TrackerKind>({\n message:'Issue tracker format',\n choices:[\n {\n name:'Local Markdown',\n value:'local' as const,\n description:'Issues as .md files in ' +\n '.scratch/',\n },\n {\n name:'GitHub Issues',\n value:'github' as const,\n description:'Issues via gh CLI',\n },\n ],\n })\n\n if (tracker === 'github') {\n if (!checkGhAuth()) {\n console.error(\n 'GitHub Issues requires the gh CLI, ' +\n 'authenticated.\\n' +\n 'Install: https://cli.github.com\\n' +\n 'Then run: gh auth login'\n )\n process.exit(2)\n }\n }\n\n setup({\n bundledSkillsDir:join(scriptDir, 'skills'),\n docsTemplatesDir:join(\n scriptDir, 'docs-templates'\n ),\n projectDir:process.cwd(),\n claude:argv.claude,\n tracker,\n })\n }\n )\n .command(\n '$0 <provider>',\n 'Execute tickets with the given provider',\n y => y\n .positional('provider', {\n type:'string',\n describe:'Agent CLI to spawn ' +\n '(e.g. claude, codex, pi)',\n demandOption:true,\n })\n .option('m', {\n alias:'model',\n type:'string',\n describe:'Model passed to the agent',\n })\n .option('spec', {\n type:'string',\n describe:'Feature name ' +\n '(resolves .scratch/<name>/)',\n })\n .option('dry-run', {\n type:'boolean',\n describe:'Show wave order without running',\n default:false,\n })\n .option('timeout', {\n type:'number',\n describe:'Kill agent after N seconds',\n default:900,\n })\n .option('X', {\n type:'boolean',\n describe:'Stop on merge conflict instead of ' +\n 're-spawning',\n default:false,\n }),\n async argv => {\n await runExecute({\n provider:argv.provider as string,\n model:argv.model as string|undefined,\n spec:argv.spec as string|undefined,\n dryRun:argv.dryRun as boolean|undefined,\n timeout:argv.timeout as\n number|undefined,\n stopOnConflict:argv.X as\n boolean|undefined,\n })\n }\n )\n .strict()\n .demandCommand(1, 'Specify a command or provider')\n .help()\n .parse()\n\nfunction isGitRepo ():boolean {\n try {\n getRepoRoot()\n return true\n } catch {\n return false\n }\n}\n\nfunction extractFeatureName (spec:string):string {\n const parts = spec.split(\n /[\\\\/]/\n )\n const scratchIndex = parts.indexOf('.scratch')\n if (scratchIndex >= 0 && scratchIndex < parts.length - 1) {\n return parts[scratchIndex + 1]\n }\n return parts[parts.length - 2] ??\n parts[parts.length - 1] ?? 'feature'\n}\n\nasync function runExecute (argv:{\n provider:string\n model?:string\n spec?:string\n dryRun?:boolean\n timeout?:number\n stopOnConflict?:boolean\n}):Promise<void> {\n const { dir, spec } = await resolveIssuesDir(\n argv.spec\n )\n\n if (!existsSync(dir)) {\n console.error(`Directory not found: ${dir}`)\n process.exit(2)\n }\n if (!existsSync(spec)) {\n console.error(`Spec file not found: ${spec}`)\n process.exit(2)\n }\n\n const specBody = readFileSync(spec, 'utf8')\n const tickets = scanTickets(dir)\n\n if (tickets.length === 0) {\n console.log('No ticket files found. Exiting.')\n return\n }\n\n console.log(`Found ${tickets.length} tickets`)\n\n const knownNums = new Set(tickets.map(t => t.num))\n for (const t of tickets) {\n const unknown = t.blockers.filter(\n b => !knownNums.has(b)\n )\n if (unknown.length > 0) {\n console.warn(\n `${t.filename}: blockers ` +\n `[${unknown.join(', ')}] ` +\n 'not found in directory'\n )\n }\n t.blockers = t.blockers.filter(\n b => knownNums.has(b)\n )\n }\n\n const logsDir = join(dirname(dir), 'logs')\n const timeout = argv.timeout ?? 300\n const featureName = extractFeatureName(spec)\n const conflictStrategy = argv.stopOnConflict ?\n 'stop' :\n 'respawn'\n const progressPath = join(\n dirname(dir), 'progress.md'\n )\n\n if (argv.dryRun) {\n if (isGitRepo()) {\n const repoName = getRepoName()\n dryRunIsolated({\n tickets,\n specBody,\n repoName,\n conflictStrategy,\n progressPath,\n })\n } else {\n dryRun(tickets, specBody)\n }\n return\n }\n\n const display = createDisplay()\n let result:{ allDone:boolean }\n\n if (isGitRepo()) {\n result = await runWavesIsolated({\n tickets,\n specBody,\n agentCmd:argv.provider,\n model:argv.model ?? null,\n timeout,\n logsDir,\n featureName,\n conflictStrategy,\n display,\n })\n } else {\n result = await runWaves(\n tickets, specBody,\n argv.provider, argv.model ?? null,\n timeout,\n logsDir,\n display,\n )\n }\n\n if (!result.allDone) {\n process.exit(1)\n }\n}\n", "import {\n cpSync,\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n symlinkSync,\n writeFileSync,\n} from 'node:fs'\nimport { join } from 'node:path'\nimport { execSync } from 'node:child_process'\n\nexport const SKILL_DIRS = [\n 'grill', 'grilling', 'domain-modeling',\n 'to-spec', 'to-tickets', 'tdd',\n] as const\n\nexport const DOC_TEMPLATES = [\n 'triage-labels.md',\n 'domain.md',\n] as const\n\nconst START_MARKER = '<!-- nightralph:start -->'\nconst END_MARKER = '<!-- nightralph:end -->'\n\nexport function writeManagedSection (\n filePath:string,\n content:string,\n):void {\n const block = [\n START_MARKER,\n content,\n END_MARKER,\n ].join('\\n')\n\n if (!existsSync(filePath)) {\n writeFileSync(filePath, block + '\\n')\n return\n }\n\n const existing = readFileSync(filePath, 'utf8')\n const startIdx = existing.indexOf(START_MARKER)\n const endIdx = existing.indexOf(END_MARKER)\n\n if (startIdx !== -1 && endIdx !== -1) {\n const before = existing.slice(0, startIdx)\n const after = existing.slice(\n endIdx + END_MARKER.length\n )\n writeFileSync(filePath, before + block + after)\n } else {\n const sep = existing.endsWith('\\n') ? '\\n' : '\\n\\n'\n writeFileSync(filePath, existing + sep + block + '\\n')\n }\n}\n\nexport function checkGhAuth ():boolean {\n try {\n execSync('gh auth status', { stdio:'ignore' })\n return true\n } catch {\n return false\n }\n}\n\nexport type TrackerKind = 'github'|'local'\n\nexport type SetupOpts = {\n bundledSkillsDir:string\n docsTemplatesDir:string\n projectDir:string\n claude?:boolean\n tracker:TrackerKind\n}\n\nconst TRACKER_TEMPLATES:Record<TrackerKind, string> = {\n local:'issue-tracker.md',\n github:'issue-tracker-github.md',\n}\n\nexport function setup (opts:SetupOpts):void {\n const {\n bundledSkillsDir,\n docsTemplatesDir,\n projectDir,\n claude,\n tracker,\n } = opts\n const agentsSkillsDir = join(\n projectDir, '.agents', 'skills'\n )\n\n const upstream = JSON.parse(\n readFileSync(\n join(bundledSkillsDir, 'upstream.json'),\n 'utf8'\n )\n ) as { repo:string; commit:string }\n\n console.log('Installing skills to .agents/skills/\\n')\n\n for (const skill of SKILL_DIRS) {\n const src = join(bundledSkillsDir, skill)\n const dest = join(agentsSkillsDir, skill)\n mkdirSync(dest, { recursive:true })\n cpSync(src, dest, { recursive:true })\n const files = readdirSync(src)\n console.log(\n ` ${skill}/ (${files.join(', ')})`\n )\n }\n\n if (claude) {\n const claudeSkillsDir = join(\n projectDir, '.claude', 'skills'\n )\n mkdirSync(claudeSkillsDir, { recursive:true })\n\n for (const skill of SKILL_DIRS) {\n const linkPath = join(claudeSkillsDir, skill)\n const target = join(\n '..', '..', '.agents', 'skills', skill\n )\n if (existsSync(linkPath)) continue\n symlinkSync(target, linkPath)\n }\n\n console.log(\n '\\nCreated symlinks in .claude/skills/'\n )\n }\n\n const docsAgentsDir = join(\n projectDir, 'docs', 'agents'\n )\n mkdirSync(docsAgentsDir, { recursive:true })\n\n console.log('')\n for (const tmpl of DOC_TEMPLATES) {\n const dest = join(docsAgentsDir, tmpl)\n if (existsSync(dest)) {\n console.log(\n ` docs/agents/${tmpl} (already exists)`\n )\n continue\n }\n const src = join(docsTemplatesDir, tmpl)\n writeFileSync(dest, readFileSync(src, 'utf8'))\n console.log(` docs/agents/${tmpl} (created)`)\n }\n\n const trackerSrc = join(\n docsTemplatesDir, TRACKER_TEMPLATES[tracker]\n )\n const trackerDest = join(docsAgentsDir, 'issue-tracker.md')\n writeFileSync(trackerDest, readFileSync(trackerSrc, 'utf8'))\n console.log(\n ` docs/agents/issue-tracker.md (${tracker})`\n )\n\n const trackerLine = tracker === 'github' ?\n 'Issues are tracked via GitHub Issues using the `gh` ' +\n 'CLI.' :\n 'Issues are tracked as local markdown files under ' +\n '`.scratch/`.'\n\n const managedContent = [\n '## Agent skills',\n '',\n '### Issue tracker',\n '',\n `${trackerLine} See \\`docs/agents/issue-tracker.md\\`.`,\n '',\n '### Triage labels',\n '',\n 'Default label vocabulary. See ' +\n '`docs/agents/triage-labels.md`.',\n '',\n '### Domain docs',\n '',\n 'Single-context layout. See `docs/agents/domain.md`.',\n ].join('\\n')\n\n const agentsPath = join(projectDir, 'AGENTS.md')\n writeManagedSection(agentsPath, managedContent)\n console.log('\\n AGENTS.md (updated)')\n\n console.log(\n `\\nSource: ${upstream.repo} @ ${upstream.commit}`\n )\n}\n", "import { spawn } 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 {\n getRepoRoot,\n getRepoName,\n getCurrentBranch,\n createWorktree,\n removeWorktree,\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'\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\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\nexport const COMPLETED_RE = /^\\[x\\]\\s+(.+)$/i\nexport const TOOL_USE_RE = /^\\[[\\w.]+\\]/\n\nexport function checkItems (\n ticket:Ticket,\n completedItems:string[]\n):void {\n if (completedItems.length === 0) return\n let body = ticket.body\n for (const item of completedItems) {\n const escaped = item.replace(\n /[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'\n )\n body = body.replace(\n new RegExp(\n `- \\\\[ \\\\] ${escaped}`,\n 'i'\n ),\n `- [x] ${item}`\n )\n }\n writeFileSync(ticket.filepath, body)\n ticket.body = body\n}\n\nexport function markDone (ticket:Ticket):void {\n const updated = ticket.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\nexport function renderPrompt (\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. ' +\n 'Implement the ticket.',\n '',\n 'Time is limited. Follow these rules:',\n '- Spend at most 2 minutes reading existing ' +\n 'code. Read only the files directly relevant ' +\n 'to the ticket.',\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 '- Start writing code as soon as you understand ' +\n 'the immediate context. You can read more ' +\n 'files as needed while implementing.',\n '- Commit your work 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 '',\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. Make sure the code compiles and tests pass.',\n '3. Commit the resolved files.',\n '',\n 'Do NOT re-implement the ticket from scratch.',\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:['exec', '--full-auto'],\n pi:[\n '-p', '--verbose',\n '--approve', '--no-session',\n '--mode', 'json',\n ],\n}\n\nexport function getProviderArgs (cmd:string):string[] {\n const name = basename(cmd)\n return PROVIDER_ARGS[name] ?? []\n}\n\nexport function formatStreamLine (\n line:string\n):string|null {\n let obj:Record<string, unknown>\n try {\n obj = JSON.parse(line) as Record<string, unknown>\n } catch {\n return line\n }\n\n if (obj.type === 'assistant') {\n const msg = obj.message as\n Record<string, unknown>|undefined\n const content = msg?.content as\n Array<Record<string, unknown>>|undefined\n if (!content) return null\n for (const block of content) {\n if (block.type === 'text') {\n return String(block.text)\n }\n }\n return null\n }\n\n if (obj.type === 'result') {\n const sub = obj.subtype as string|undefined ?? 'done'\n const cost = obj.total_cost_usd as number|undefined\n const costStr = cost != null ?\n ` ($${cost.toFixed(2)})` :\n ''\n return `${sub}${costStr}`\n }\n\n if (obj.type === 'system') {\n const sub = obj.subtype as string|undefined\n if (sub === 'api_retry') {\n const error = obj.error as string|undefined\n return `retry: ${error ?? 'unknown'}`\n }\n }\n\n return null\n}\n\nexport type PiStreamFormatter = {\n process:(line:string) => string[]\n flush:() => string[]\n}\n\nexport function createPiStreamFormatter (\n):PiStreamFormatter {\n const calls = new Map<\n number, { name:string; buf:string }\n >()\n let textBuf = ''\n\n function drainLines ():string[] {\n const parts = textBuf.split('\\n')\n if (parts.length === 1) return []\n textBuf = parts[parts.length - 1]\n return parts.slice(0, -1)\n }\n\n function flushBuf ():string[] {\n if (textBuf.length === 0) return []\n const out = textBuf\n textBuf = ''\n return [out]\n }\n\n function process (line:string):string[] {\n let obj:Record<string, unknown>\n try {\n obj = JSON.parse(line) as\n Record<string, unknown>\n } catch {\n return [line]\n }\n\n const evt = obj.assistantMessageEvent as\n Record<string, unknown>|undefined\n if (!evt) return []\n\n const type = evt.type as string|undefined\n const ci = evt.contentIndex as\n number|undefined ?? -1\n\n if (type === 'text_delta') {\n const delta =\n (evt.delta as string|undefined) ?? ''\n textBuf += delta\n return drainLines()\n }\n\n if (type === 'toolcall_start') {\n const flushed = flushBuf()\n calls.set(ci, {\n name:(evt.toolName as\n string|undefined) ?? '?',\n buf:'',\n })\n return flushed\n }\n\n if (\n type === 'toolcall_delta' &&\n calls.has(ci)\n ) {\n calls.get(ci)!.buf +=\n (evt.delta as string|undefined) ?? ''\n return []\n }\n\n if (\n type === 'toolcall_end' &&\n calls.has(ci)\n ) {\n const call = calls.get(ci)!\n calls.delete(ci)\n let label = ''\n try {\n const args = JSON.parse(call.buf) as\n Record<string, unknown>\n label = String(\n args.command ??\n args.file_path ??\n args.query ?? ''\n ).split('\\n')[0].slice(0, 72)\n } catch {\n // unparseable tool args\n }\n return [`[${call.name}] ${label}`]\n }\n\n return []\n }\n\n return { process, flush:flushBuf }\n}\n\nfunction writePromptFile (prompt:string):string {\n const name = `nightralph-${Date.now()}-` +\n `${Math.random().toString(36).slice(2)}.md`\n const filePath = join(tmpdir(), name)\n writeFileSync(filePath, prompt)\n return filePath\n}\n\nfunction cleanupPromptFile (filePath:string):void {\n try {\n unlinkSync(filePath)\n } catch {\n // already removed\n }\n}\n\nexport type AgentResult = {\n exitCode:number\n completedItems:string[]\n}\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 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\n const providerName = basename(opts.agentCmd)\n const isClaude = providerName === 'claude'\n const isPi = providerName === 'pi'\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 })\n\n proc.stdout.pipe(logStream)\n\n const piFormatter = isPi ?\n createPiStreamFormatter() :\n null\n\n const completedItems:string[] = []\n\n function collectCompleted (text:string):void {\n const match = text.match(COMPLETED_RE)\n if (match) completedItems.push(match[1])\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 const timeout = setTimeout(() => {\n if (!proc.killed) {\n console.warn(\n 'Agent did not exit in ' +\n `${opts.timeout}s; killing.`\n )\n proc.kill('SIGKILL')\n }\n }, opts.timeout * 1000)\n\n if (!promptFile) {\n proc.stdin.write(opts.prompt)\n }\n proc.stdin.end()\n\n return new Promise<AgentResult>(resolve => {\n proc.on('close', code => {\n clearTimeout(timeout)\n if (piFormatter) {\n for (const line of piFormatter.flush()) {\n collectCompleted(line)\n const output = `${prefix}${line}`\n if (opts.onLine) {\n opts.onLine(output)\n } else {\n console.log(output)\n }\n }\n }\n rl.close()\n rlErr.close()\n logStream.end()\n if (promptFile) cleanupPromptFile(promptFile)\n resolve({\n exitCode:code ?? 1,\n completedItems,\n })\n })\n proc.on('error', err => {\n clearTimeout(timeout)\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({ exitCode:1, completedItems })\n })\n })\n}\n\nexport function dryRun (\n tickets:Array<Ticket>,\n specBody: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 )\n }\n}\n\nexport function dryRunIsolated (opts:{\n tickets:Array<Ticket>\n specBody:string\n repoName:string\n conflictStrategy:MergeConflictStrategy\n progressPath:string\n}):void {\n listTickets(opts.tickets)\n\n console.log('\\nSimulated wave order:')\n for (const { wave, ready } of simulateWaves(\n opts.tickets\n )) {\n console.log(\n ` Wave ${wave}: ` +\n ready.map(t => t.filename).join(', ')\n )\n for (const t of ready) {\n const num = String(t.num).padStart(2, '0')\n const branchName =\n `${opts.repoName}/${num}-${t.slug}`\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(opts.specBody, firstReady[0])\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 `\\nMerge strategy: ${strategyDesc}`\n )\n console.log(`Progress file: ${opts.progressPath}`)\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 onLine?:(msg:string) => void\n}):Promise<boolean> {\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 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 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\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 display?:Display,\n):Promise<{ allDone:boolean }> {\n mkdirSync(logsDir, { recursive:true })\n\n const d = display ?? createDisplay()\n let totalWaves = 0\n for (const _ of simulateWaves(tickets)) totalWaves++\n\n let totalCompleted = 0\n let waveNum = 0\n\n while (true) {\n const ready = findReadyTickets(tickets)\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 Promise.allSettled(\n ready.map(async t => {\n const prompt = renderPrompt(specBody, t)\n const logPath = join(\n logsDir,\n t.filename.replace(/\\.md$/, '.log')\n )\n const label = t.filename.replace(\n /\\.md$/, ''\n )\n d.setTicketStatus(t.num, 'in-progress')\n d.log(` Starting ${t.filename}`)\n const result = await spawnAgent({\n prompt,\n agentCmd,\n model,\n timeout,\n logPath,\n label,\n onLine:(line) => d.log(line),\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 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 d.log(\n '\\nNo tickets completed this wave. ' +\n 'Stopping.'\n )\n break\n }\n }\n\n const remaining = tickets.filter(\n t => t.status === 'ready-for-agent'\n )\n d.log(\n `\\nFinished: ${totalCompleted} completed` +\n (remaining.length > 0 ?\n `, ${remaining.length} remaining` :\n '')\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}):Promise<{ allDone:boolean }> {\n mkdirSync(opts.logsDir, { recursive:true })\n\n const d = opts.display ?? createDisplay()\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 writeProgress(progressPath, progress)\n await commitProgress(\n repoRoot,\n progressPath,\n `nightralph: start ${opts.featureName}`\n )\n\n let totalCompleted = 0\n let waveNum = 0\n\n while (true) {\n const ready = findReadyTickets(opts.tickets)\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 const worktreeSettled = await Promise.allSettled(\n ready.map(t => createWorktree({\n repoRoot,\n repoName,\n baseBranch,\n ticket:t,\n }))\n )\n\n const activeTickets:Array<Ticket> = []\n const worktrees:Array<{\n worktreePath:string\n branchName:string\n }> = []\n\n for (let i = 0; i < worktreeSettled.length; i++) {\n const settled = worktreeSettled[i]\n const ticket = ready[i]\n if (settled.status === 'rejected') {\n d.setTicketStatus(ticket.num, 'failed')\n d.log(\n ` ${ticket.filename}: failed to create ` +\n `worktree: ${formatErrorMessage(settled.reason)}`\n )\n continue\n }\n activeTickets.push(ticket)\n worktrees.push(settled.value)\n }\n\n const results = await Promise.allSettled(\n activeTickets.map((t, i) => {\n const prompt = renderPrompt(opts.specBody, t)\n const logPath = join(\n opts.logsDir,\n t.filename.replace(/\\.md$/, '.log')\n )\n const label = t.filename.replace(\n /\\.md$/, ''\n )\n d.setTicketStatus(t.num, 'in-progress')\n d.log(` Starting ${t.filename}`)\n return spawnAgent({\n prompt,\n agentCmd:opts.agentCmd,\n model:opts.model,\n timeout:opts.timeout,\n logPath,\n cwd:worktrees[i].worktreePath,\n label,\n onLine:(line) => d.log(line),\n })\n })\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 < results.length; i++) {\n const r = results[i]\n if (r.status === 'rejected') continue\n const agentResult = r.value\n const ticket = activeTickets[i]\n const worktree = worktrees[i]\n\n if (agentResult.exitCode !== 0) {\n d.setTicketStatus(ticket.num, 'failed')\n d.log(\n ` ${ticket.filename}: ` +\n `agent exited ${agentResult.exitCode}`\n )\n checkItems(ticket, agentResult.completedItems)\n checkTicket(progress, ticket.num, {\n branch:worktree.branchName,\n exitCode:agentResult.exitCode,\n done:false,\n })\n writeProgress(progressPath, progress)\n await commitProgress(\n repoRoot,\n progressPath,\n `nightralph: ${ticket.filename} failed`\n )\n\n try {\n await removeWorktree(worktree.worktreePath)\n } catch (err) {\n d.log(\n ' Failed to remove worktree ' +\n `${worktree.worktreePath}: ` +\n formatErrorMessage(err)\n )\n }\n continue\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 repoRoot, baseBranch, worktree.branchName\n )) {\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 continue\n }\n\n checkItems(ticket, agentResult.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, worktree.worktreePath\n )\n successfulBranches.push({\n branch:worktree.branchName,\n ticketNum:ticket.num,\n worktreePath:worktree.worktreePath,\n })\n }\n\n if (successfulBranches.length > 0) {\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 writeProgress(progressPath, progress)\n await commitProgress(\n repoRoot,\n progressPath,\n `nightralph: ${ticket.filename} done`\n )\n\n const worktreePath = worktreePathsByNum.get(\n ticket.num\n )\n if (worktreePath) {\n try {\n await removeWorktree(worktreePath)\n } catch (err) {\n d.log(\n ' Failed to remove worktree ' +\n `${worktreePath}: ` +\n formatErrorMessage(err)\n )\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 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 writeProgress(progressPath, progress)\n await commitProgress(\n repoRoot,\n progressPath,\n `nightralph: ${ticket.filename} ` +\n 'done (respawn)'\n )\n\n if (worktreePath) {\n try {\n await removeWorktree(worktreePath)\n } catch (err) {\n d.log(\n ' Failed to remove worktree ' +\n `${worktreePath}: ` +\n formatErrorMessage(err)\n )\n }\n }\n } else {\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 writeProgress(progressPath, progress)\n await commitProgress(\n repoRoot,\n progressPath,\n `nightralph: ${ticket.filename} ` +\n 'merge failed'\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(sb.worktreePath)\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 d.log(\n '\\nNo tickets completed this wave. ' +\n 'Stopping.'\n )\n break\n }\n }\n\n const remaining = opts.tickets.filter(\n t => t.status === 'ready-for-agent'\n )\n d.log(\n `\\nFinished: ${totalCompleted} completed` +\n (remaining.length > 0 ?\n `, ${remaining.length} remaining` :\n '')\n )\n d.cleanup()\n\n return { allDone:remaining.length === 0 }\n}\n", "import { execFile, execFileSync } from 'node:child_process'\nimport { promisify } from 'node:util'\nimport { basename, join } from 'node:path'\nimport { existsSync } from 'node:fs'\nimport type { Ticket } from './orchestrator.js'\n\nconst execFileAsync = promisify(execFile)\n\nexport function getRepoRoot ():string {\n const stdout = execFileSync(\n 'git',\n ['rev-parse', '--show-toplevel'],\n { encoding:'utf8' }\n )\n return stdout.trim()\n}\n\nexport function getRepoName ():string {\n return basename(getRepoRoot())\n}\n\nexport function getCurrentBranch ():string {\n const stdout = execFileSync(\n 'git',\n ['rev-parse', '--abbrev-ref', 'HEAD'],\n { encoding:'utf8' }\n )\n return stdout.trim()\n}\n\nasync function branchExists (\n repoRoot:string,\n branchName:string\n):Promise<boolean> {\n try {\n await execFileAsync(\n 'git',\n ['show-ref', '--verify', '--quiet', `refs/heads/${branchName}`],\n { cwd:repoRoot }\n )\n return true\n } catch {\n return false\n }\n}\n\nexport async function createWorktree (\n opts:{\n repoRoot:string\n repoName:string\n baseBranch:string\n ticket:Ticket\n }\n):Promise<{ worktreePath:string; branchName:string }> {\n const { repoRoot, repoName, baseBranch, ticket } = opts\n const branchName = `${repoName}/${String(\n ticket.num\n ).padStart(2, '0')}-${ticket.slug}`\n const worktreePath = join(\n repoRoot,\n '..',\n `${repoName}.${String(\n ticket.num\n ).padStart(2, '0')}-${ticket.slug}`\n )\n\n if (existsSync(worktreePath)) {\n try {\n await execFileAsync(\n 'git',\n ['worktree', 'remove', '--force', worktreePath],\n { cwd:repoRoot }\n )\n } catch {\n // directory may not be a registered worktree anymore;\n // prune stale entries below and let worktree add fail\n // loudly if the path is still unusable\n }\n }\n\n try {\n await execFileAsync(\n 'git',\n ['worktree', 'prune'],\n { cwd:repoRoot }\n )\n } catch {\n // best-effort cleanup of stale worktree metadata\n }\n\n if (await branchExists(repoRoot, branchName)) {\n await execFileAsync(\n 'git',\n ['branch', '-D', branchName],\n { cwd:repoRoot }\n )\n }\n\n await execFileAsync(\n 'git',\n [\n 'worktree',\n 'add',\n '-b',\n branchName,\n worktreePath,\n baseBranch,\n ],\n { cwd:repoRoot }\n )\n\n return { worktreePath, branchName }\n}\n\nexport async function removeWorktree (\n worktreePath:string\n):Promise<void> {\n // Use git -C to run the command from the worktree directory context\n // so git can resolve the repository\n await execFileAsync(\n 'git',\n ['-C', worktreePath, 'worktree', 'remove', worktreePath]\n )\n}\n\nexport function hasNewCommits (\n repoRoot:string,\n base:string,\n branch:string\n):boolean {\n const stdout = execFileSync(\n 'git',\n ['rev-list', '--count', `${base}..${branch}`],\n { cwd:repoRoot, encoding:'utf8' }\n )\n return Number(stdout.trim()) > 0\n}\n\nexport function isDirty (cwd:string):boolean {\n const stdout = execFileSync(\n 'git',\n ['status', '--porcelain'],\n { cwd, encoding:'utf8' }\n )\n return stdout.trim().length > 0\n}\n\nexport async function commitDirty (\n cwd:string,\n message?:string\n):Promise<boolean> {\n if (!isDirty(cwd)) return false\n await execFileAsync(\n 'git',\n ['add', '-A'],\n { cwd }\n )\n try {\n await execFileAsync(\n 'git',\n [\n 'commit', '-m',\n message ??\n 'nightralph: auto-commit ' +\n 'remaining changes',\n ],\n { cwd }\n )\n return true\n } catch {\n return false\n }\n}\n\nexport async function listWorktrees (\n repoRoot:string\n):Promise<Array<string>> {\n const { stdout } = await execFileAsync(\n 'git',\n ['worktree', 'list', '--porcelain'],\n { cwd:repoRoot }\n )\n return stdout\n .trim()\n .split('\\n')\n .filter(line => line.startsWith('worktree '))\n .map(line => line.substring('worktree '.length))\n}\n", "import { execFile } from 'node:child_process'\nimport { readFileSync, writeFileSync } from 'node:fs'\nimport { promisify } from 'node:util'\nimport type { Ticket } from './orchestrator.js'\n\nconst TICKET_FILENAME_RE = /^(\\d+)-(.+)\\.md$/\n\nconst execFileAsync = promisify(execFile)\n\nexport type TicketProgress = {\n num:number\n slug:string\n filename:string\n done:boolean\n branch:string|null\n exitCode:number|null\n completedAt:string|null\n}\n\nexport type ProgressData = {\n feature:string\n startedAt:string\n tickets:Array<TicketProgress>\n}\n\nexport function generateProgress (\n feature:string,\n tickets:ReadonlyArray<Ticket>\n):ProgressData {\n return {\n feature,\n startedAt:new Date().toISOString(),\n tickets:tickets.map((ticket) => ({\n num:ticket.num,\n slug:ticket.slug,\n filename:ticket.filename,\n done:false,\n branch:null,\n exitCode:null,\n completedAt:null,\n })),\n }\n}\n\nexport function readProgress (\n progressPath:string\n):ProgressData|null {\n let content:string\n try {\n content = readFileSync(progressPath, 'utf8')\n } catch {\n return null\n }\n\n const featureMatch = content.match(/^# Progress: (.*)$/m)\n const startedMatch = content.match(/^Started: (.*)$/m)\n\n const tickets:Array<TicketProgress> = []\n let current:TicketProgress|null = null\n\n for (const line of content.split('\\n')) {\n const ticketMatch = line.match(/^- \\[( |x)\\] (.+)$/)\n if (ticketMatch) {\n if (current) tickets.push(current)\n const filename = ticketMatch[2]\n const parsed = filename.match(TICKET_FILENAME_RE)\n current = {\n num:parsed ? Number(parsed[1]) : NaN,\n slug:parsed ? parsed[2] : '',\n filename,\n done:ticketMatch[1] === 'x',\n branch:null,\n exitCode:null,\n completedAt:null,\n }\n continue\n }\n if (!current) continue\n\n const branchMatch = line.match(/^ {2}branch: (.*)$/)\n if (branchMatch) {\n current.branch = branchMatch[1]\n continue\n }\n const exitMatch = line.match(/^ {2}exit: (-?\\d+)$/)\n if (exitMatch) {\n current.exitCode = Number(exitMatch[1])\n continue\n }\n const completedMatch = line.match(/^ {2}completed: (.*)$/)\n if (completedMatch) {\n current.completedAt = completedMatch[1]\n continue\n }\n }\n if (current) tickets.push(current)\n\n return {\n feature:featureMatch ? featureMatch[1] : '',\n startedAt:startedMatch ? startedMatch[1] : '',\n tickets,\n }\n}\n\nexport function mergeProgress (\n fresh:ProgressData,\n existing:ProgressData|null\n):ProgressData {\n if (!existing) return fresh\n\n const existingByFilename = new Map(\n existing.tickets.map((t) => [t.filename, t])\n )\n\n return {\n ...fresh,\n tickets:fresh.tickets.map((ticket) => {\n const prior = existingByFilename.get(ticket.filename)\n return (prior && prior.done) ? { ...prior } : ticket\n }),\n }\n}\n\nexport function renderProgress (data:ProgressData):string {\n const lines:Array<string> = [\n `# Progress: ${data.feature}`,\n '',\n `Started: ${data.startedAt}`,\n '',\n ]\n\n for (const ticket of data.tickets) {\n const checkbox = ticket.done ? '[x]' : '[ ]'\n lines.push(`- ${checkbox} ${ticket.filename}`)\n\n if (ticket.done || ticket.exitCode !== null) {\n if (ticket.branch) {\n lines.push(\n ` branch: ${ticket.branch}`\n )\n }\n if (ticket.exitCode !== null) {\n lines.push(\n ` exit: ${ticket.exitCode}`\n )\n }\n if (ticket.completedAt) {\n lines.push(\n ` completed: ${ticket.completedAt}`\n )\n }\n }\n }\n\n return lines.join('\\n') + '\\n'\n}\n\nexport function checkTicket (\n data:ProgressData,\n ticketNum:number,\n result:{ branch:string; exitCode:number; done?:boolean }\n):void {\n const ticket = data.tickets.find(\n (t) => t.num === ticketNum\n )\n if (!ticket) return\n\n ticket.done = result.done ?? true\n ticket.branch = result.branch\n ticket.exitCode = result.exitCode\n if (ticket.done) {\n ticket.completedAt = new Date().toISOString()\n }\n}\n\nexport function writeProgress (\n progressPath:string,\n data:ProgressData\n):void {\n writeFileSync(\n progressPath,\n renderProgress(data)\n )\n}\n\nexport async function commitProgress (\n repoRoot:string,\n progressPath:string,\n message:string\n):Promise<void> {\n await execFileAsync(\n 'git',\n ['add', '--force', progressPath],\n { cwd:repoRoot }\n )\n\n await execFileAsync(\n 'git',\n ['commit', '-m', message, '--', progressPath],\n { cwd:repoRoot }\n )\n}\n", "import { execFile } from 'node:child_process'\nimport { promisify } from 'node:util'\n\nconst execFileAsync = promisify(execFile)\n\nexport type MergeConflictStrategy = 'respawn'|'stop'\n\nexport type MergeResult = {\n branch:string\n ticketNum:number\n merged:boolean\n conflicted:boolean\n stderr?:string\n}\n\nexport type WaveMergeResult = {\n merged:Array<MergeResult>\n stoppedAt:MergeResult|null\n}\n\nexport type GitOpResult = {\n success:boolean\n stderr?:string\n}\n\nexport async function mergeBranch (\n repoRoot:string,\n branch:string\n):Promise<GitOpResult> {\n if (!repoRoot || typeof repoRoot !== 'string') {\n throw new Error('repoRoot must be a non-empty string')\n }\n if (!branch || typeof branch !== 'string') {\n throw new Error('branch must be a non-empty string')\n }\n\n try {\n await execFileAsync(\n 'git',\n ['merge', branch, '--no-edit'],\n { cwd:repoRoot }\n )\n return { success:true }\n } catch (err) {\n const execErr = err as {\n stdout?:string; stderr?:string\n }\n const stderr =\n execErr.stderr || execErr.stdout\n try {\n await execFileAsync(\n 'git',\n ['merge', '--abort'],\n { cwd:repoRoot }\n )\n } catch {\n // no merge in progress to abort\n }\n return { success:false, stderr }\n }\n}\n\nexport async function rebaseBranch (\n repoRoot:string,\n branch:string,\n onto:string,\n worktreePath?:string\n):Promise<GitOpResult> {\n if (!repoRoot || typeof repoRoot !== 'string') {\n throw new Error('repoRoot must be a non-empty string')\n }\n if (!branch || typeof branch !== 'string') {\n throw new Error('branch must be a non-empty string')\n }\n if (!onto || typeof onto !== 'string') {\n throw new Error('onto must be a non-empty string')\n }\n\n // When the branch has its own worktree, it is already checked\n // out there -- checking it out in repoRoot too would fail with\n // \"already used by worktree\", so rebase in place instead.\n if (worktreePath) {\n try {\n await execFileAsync(\n 'git',\n ['rebase', onto],\n { cwd:worktreePath }\n )\n return { success:true }\n } catch (err) {\n const execErr = err as {\n stdout?:string; stderr?:string\n }\n const stderr =\n execErr.stderr || execErr.stdout\n try {\n await execFileAsync(\n 'git',\n ['rebase', '--abort'],\n { cwd:worktreePath }\n )\n } catch {\n // ignore abort errors\n }\n return { success:false, stderr }\n }\n }\n\n try {\n await execFileAsync(\n 'git',\n ['checkout', branch],\n { cwd:repoRoot }\n )\n\n await execFileAsync(\n 'git',\n ['rebase', onto],\n { cwd:repoRoot }\n )\n\n await execFileAsync(\n 'git',\n ['checkout', onto],\n { cwd:repoRoot }\n )\n\n return { success:true }\n } catch (err) {\n const stderr =\n (err as { stderr?:string }).stderr\n try {\n await execFileAsync(\n 'git',\n ['rebase', '--abort'],\n { cwd:repoRoot }\n )\n } catch {\n // ignore abort errors\n }\n try {\n await execFileAsync(\n 'git',\n ['checkout', onto],\n { cwd:repoRoot }\n )\n } catch {\n // ignore checkout errors\n }\n return { success:false, stderr }\n }\n}\n\n// Merges baseBranch into the worktree's branch so a\n// respawned agent sees the latest code. Conflicts are\n// left in place (not aborted) so the agent can resolve\n// and commit them.\nexport async function updateWorktreeFromBase (\n worktreePath:string,\n baseBranch:string\n):Promise<void> {\n try {\n await execFileAsync(\n 'git',\n ['merge', baseBranch, '--no-edit'],\n { cwd:worktreePath }\n )\n } catch {\n // conflict markers intentionally left for the\n // respawned agent to resolve\n }\n}\n\nexport async function mergeWave (\n opts:Readonly<{\n repoRoot:string\n baseBranch:string\n branches:ReadonlyArray<{\n branch:string\n ticketNum:number\n worktreePath?:string\n }>\n strategy:MergeConflictStrategy\n }>\n):Promise<WaveMergeResult> {\n const { repoRoot, baseBranch, branches, strategy } = opts\n\n if (!repoRoot || typeof repoRoot !== 'string') {\n throw new Error('repoRoot must be a non-empty string')\n }\n if (!baseBranch || typeof baseBranch !== 'string') {\n throw new Error('baseBranch must be a non-empty string')\n }\n\n const merged:Array<MergeResult> = []\n let stoppedAt:MergeResult|null = null\n\n for (let i = 0; i < branches.length; i++) {\n const { branch, ticketNum, worktreePath } = branches[i]\n const mergingResult:MergeResult = {\n branch,\n ticketNum,\n merged:false,\n conflicted:false,\n }\n\n if (i === 0) {\n const result = await mergeBranch(\n repoRoot,\n branch\n )\n mergingResult.merged = result.success\n mergingResult.conflicted = !result.success\n if (!result.success) {\n mergingResult.stderr = result.stderr\n }\n\n if (!result.success) {\n if (strategy === 'stop') {\n stoppedAt = mergingResult\n merged.push(mergingResult)\n break\n }\n merged.push(mergingResult)\n continue\n }\n } else {\n const rebaseResult = await rebaseBranch(\n repoRoot,\n branch,\n baseBranch,\n worktreePath\n )\n\n if (!rebaseResult.success) {\n mergingResult.conflicted = true\n mergingResult.stderr = rebaseResult.stderr\n\n if (strategy === 'stop') {\n stoppedAt = mergingResult\n merged.push(mergingResult)\n break\n } else {\n // strategy === 'respawn'\n merged.push(mergingResult)\n continue\n }\n }\n\n const mergeResult = await mergeBranch(\n repoRoot,\n branch\n )\n mergingResult.merged = mergeResult.success\n mergingResult.conflicted = !mergeResult.success\n if (!mergeResult.success) {\n mergingResult.stderr = mergeResult.stderr\n }\n\n if (!mergeResult.success) {\n if (strategy === 'stop') {\n stoppedAt = mergingResult\n merged.push(mergingResult)\n break\n }\n merged.push(mergingResult)\n continue\n }\n }\n\n merged.push(mergingResult)\n }\n\n return {\n merged,\n stoppedAt,\n }\n}\n", "export type TicketStatus =\n | 'pending'\n | 'in-progress'\n | 'done'\n | 'failed'\n\nexport type DisplayTicket = {\n readonly num:number\n readonly filename:string\n status:TicketStatus\n}\n\nexport type WaveState = {\n readonly waveNum:number\n readonly totalWaves:number\n readonly tickets:Array<DisplayTicket>\n}\n\nexport type DisplayConfig = {\n readonly messageLines:number\n readonly stream:NodeJS.WriteStream\n}\n\n/**\n * Progress across the whole run, not just the current wave.\n * `completed` counts tickets done before the wave started;\n * tickets that finish during the wave are added on top.\n */\nexport type RunProgress = {\n readonly completed:number\n readonly total:number\n}\n\nexport type Display = {\n startWave(\n waveNum:number,\n totalWaves:number,\n tickets:ReadonlyArray<{\n num:number\n filename:string\n }>,\n progress?:RunProgress,\n remaining?:ReadonlyArray<{\n num:number\n filename:string\n }>,\n ):void\n setTicketStatus(num:number, status:TicketStatus):void\n log(message:string):void\n cleanup():void\n}\n\nconst ESC = '\\x1b['\n\nexport const ansi = {\n cursorUp (n:number):string {\n return `${ESC}${n}A`\n },\n cursorTo (col:number):string {\n return `${ESC}${col}G`\n },\n eraseLine ():string {\n return `${ESC}2K`\n },\n eraseLines (n:number):string {\n let out = ''\n for (let i = 0; i < n; i++) {\n out += ansi.eraseLine()\n if (i < n - 1) out += ansi.cursorUp(1)\n }\n return out\n },\n cursorHide ():string {\n return `${ESC}?25l`\n },\n cursorShow ():string {\n return `${ESC}?25h`\n },\n} as const\n\nexport const color = {\n green (text:string):string {\n return `${ESC}32m${text}${ESC}0m`\n },\n yellow (text:string):string {\n return `${ESC}33m${text}${ESC}0m`\n },\n red (text:string):string {\n return `${ESC}31m${text}${ESC}0m`\n },\n dim (text:string):string {\n return `${ESC}2m${text}${ESC}0m`\n },\n} as const\n\nconst FILLED_DOT = '\u25CF'\nconst EMPTY_DOT = '\u25CB'\nconst SEPARATOR_WIDTH = 50\nconst DEFAULT_COLUMNS = 80\n\n// eslint-disable-next-line no-control-regex\nconst ANSI_RE = /\\x1b\\[[0-9;?]*[A-Za-z]/g\n\n/**\n * Clamp a line to `width` visible columns so it can never wrap.\n * A wrapped line occupies more terminal rows than `render`\n * counts, which leaves stale rows behind on the next erase.\n */\nexport function fitLine (line:string, width:number):string {\n const visible = line.replace(ANSI_RE, '')\n if (visible.length <= width) return line\n return visible.slice(0, width)\n}\n\nexport function renderDot (status:TicketStatus):string {\n switch (status) {\n case 'pending':\n return color.dim(EMPTY_DOT)\n case 'in-progress':\n return color.yellow(FILLED_DOT)\n case 'done':\n return color.green(FILLED_DOT)\n case 'failed':\n return color.red(FILLED_DOT)\n }\n}\n\nexport class StatusDisplay implements Display {\n private wave:WaveState|null = null\n private progress:RunProgress|null = null\n private remaining:Array<DisplayTicket> = []\n private messages:Array<string> = []\n private renderedLines:number = 0\n private config:DisplayConfig\n private viewportStart:number = 0\n private resizeListener:(() => void)|null = null\n private signalHandler:(() => void)|null = null\n\n constructor (config?:Readonly<Partial<DisplayConfig>>) {\n this.config = {\n messageLines:config?.messageLines ?? 10,\n stream:config?.stream ?? process.stdout,\n }\n }\n\n private getAvailableRows ():number {\n const termHeight = this.config.stream.rows ?? 24\n const overhead = 2 + this.config.messageLines\n const available = termHeight - overhead\n return Math.max(1, available)\n }\n\n startWave (\n waveNum:number,\n totalWaves:number,\n tickets:Array<Readonly<{ num:number; filename:string }>>,\n progress?:RunProgress,\n remaining?:ReadonlyArray<{\n num:number\n filename:string\n }>,\n ):void {\n this.wave = {\n waveNum,\n totalWaves,\n tickets:tickets.map(t => ({\n ...t,\n status:'pending' as const,\n })),\n }\n this.remaining = (remaining ?? []).map(t => ({\n ...t,\n status:'pending' as const,\n }))\n this.progress = progress ?? null\n this.messages = []\n this.viewportStart = 0\n this.config.stream.write(ansi.cursorHide())\n\n if (this.config.stream.isTTY) {\n if (this.resizeListener) {\n this.config.stream.removeListener(\n 'resize', this.resizeListener,\n )\n }\n this.resizeListener = () => this.render()\n this.config.stream.on(\n 'resize', this.resizeListener,\n )\n }\n\n // Register signal handler to restore cursor on interruption\n if (this.signalHandler) {\n process.removeListener('SIGINT', this.signalHandler)\n process.removeListener('SIGTERM', this.signalHandler)\n }\n this.signalHandler = () => this.cleanup()\n process.on('SIGINT', this.signalHandler)\n process.on('SIGTERM', this.signalHandler)\n\n this.render()\n }\n\n setTicketStatus (num:number, status:TicketStatus):void {\n if (!this.wave) return\n\n const ticket = this.wave.tickets.find(t => t.num === num)\n if (ticket) {\n ticket.status = status\n\n if (status === 'in-progress') {\n const ticketIndex = this.wave.tickets.indexOf(ticket)\n const availableRows = this.getAvailableRows()\n const totalTickets = this.wave.tickets.length\n\n if (ticketIndex < this.viewportStart) {\n this.viewportStart = ticketIndex\n } else if (ticketIndex >= this.viewportStart + availableRows) {\n // offset by 3 to keep context visible below\n // the active ticket\n this.viewportStart = ticketIndex - availableRows + 3\n }\n this.viewportStart = Math.max(\n 0,\n Math.min(this.viewportStart, totalTickets - 1),\n )\n }\n\n this.render()\n }\n }\n\n log (message:string):void {\n this.messages.push(message)\n if (this.messages.length > this.config.messageLines) {\n this.messages.shift()\n }\n this.render()\n }\n\n cleanup ():void {\n // Remove resize listener if it exists\n if (this.resizeListener && this.config.stream.isTTY) {\n this.config.stream.removeListener('resize', this.resizeListener)\n }\n // Remove signal handlers\n if (this.signalHandler) {\n process.removeListener('SIGINT', this.signalHandler)\n process.removeListener('SIGTERM', this.signalHandler)\n }\n this.config.stream.write(ansi.cursorShow())\n }\n\n private render ():void {\n if (!this.wave) return\n\n let output = ''\n\n if (this.renderedLines > 0) {\n output += ansi.eraseLines(this.renderedLines + 1)\n }\n\n const doneInWave = this.wave.tickets.filter(\n t => t.status === 'done',\n ).length\n const completed = doneInWave + (this.progress?.completed ?? 0)\n const total = this.progress?.total ?? this.wave.tickets.length\n const pct = total === 0 ? 0 : Math.round((completed / total) * 100)\n const width = Math.max(\n 1,\n (this.config.stream.columns ?? DEFAULT_COLUMNS) - 1,\n )\n\n output += `Wave ${this.wave.waveNum}/` +\n `${this.wave.totalWaves} - ` +\n `${pct}% complete\\n`\n\n // Pagination logic\n const availableRows = this.getAvailableRows()\n const tickets:ReadonlyArray<DisplayTicket> = [\n ...this.wave.tickets,\n ...this.remaining,\n ]\n let renderedTicketCount = 0\n\n if (tickets.length <= availableRows) {\n // All tickets fit, no pagination\n for (const ticket of tickets) {\n const dot = renderDot(ticket.status)\n const name = fitLine(ticket.filename, width - 2)\n output += `${dot} ${name}\\n`\n }\n renderedTicketCount = tickets.length\n } else {\n // Need pagination -- iterative clamp\n this.viewportStart = Math.max(\n 0,\n Math.min(\n this.viewportStart,\n tickets.length - 1,\n ),\n )\n\n let hasMoreAbove = this.viewportStart > 0\n let tentativeCount =\n availableRows - (hasMoreAbove ? 1 : 0)\n let hasMoreBelow =\n this.viewportStart + tentativeCount <\n tickets.length\n let ticketsToShow = Math.max(\n 0,\n tentativeCount - (hasMoreBelow ? 1 : 0),\n )\n\n const maxStart = Math.max(\n 0,\n tickets.length - Math.max(1, ticketsToShow),\n )\n if (this.viewportStart > maxStart) {\n this.viewportStart = maxStart\n hasMoreAbove = this.viewportStart > 0\n tentativeCount = availableRows - (hasMoreAbove ? 1 : 0)\n hasMoreBelow = (\n this.viewportStart +\n tentativeCount < tickets.length\n )\n ticketsToShow = Math.max(\n 0,\n tentativeCount - (hasMoreBelow ? 1 : 0)\n )\n }\n\n // Show \"more above\" indicator if needed\n if (hasMoreAbove) {\n const moreCount = this.viewportStart\n output += ` ... ${moreCount} more above\\n`\n }\n\n // Get visible tickets and render them\n const visibleTickets = tickets.slice(\n this.viewportStart,\n this.viewportStart + ticketsToShow,\n )\n\n for (const ticket of visibleTickets) {\n const dot = renderDot(ticket.status)\n const name = fitLine(ticket.filename, width - 2)\n output += `${dot} ${name}\\n`\n }\n\n // Show \"more below\" indicator if needed\n if (hasMoreBelow) {\n const moreCount = (\n tickets.length -\n (this.viewportStart + ticketsToShow)\n )\n output += ` ... ${moreCount} more below\\n`\n }\n\n renderedTicketCount = (hasMoreAbove ? 1 : 0) +\n visibleTickets.length +\n (hasMoreBelow ? 1 : 0)\n }\n\n output += '-'.repeat(Math.min(SEPARATOR_WIDTH, width)) + '\\n'\n\n const msgLines = Math.max(\n 0,\n this.config.messageLines - this.messages.length,\n )\n for (const msg of this.messages) {\n output += `${fitLine(msg, width)}\\n`\n }\n for (let i = 0; i < msgLines; i++) {\n output += '\\n'\n }\n\n this.renderedLines = 2 + renderedTicketCount + this.config.messageLines\n this.config.stream.write(output)\n }\n}\n\nexport class PlainDisplay implements Display {\n startWave (\n waveNum:number,\n _totalWaves:number,\n tickets:ReadonlyArray<{ num:number; filename:string }>,\n progress?:RunProgress,\n _remaining?:ReadonlyArray<{\n num:number\n filename:string\n }>,\n ):void {\n const pct = progress && progress.total > 0 ?\n ` (${progress.completed}/${progress.total} done)` :\n ''\n console.log(\n `\\nWave ${waveNum}${pct}: ` +\n tickets.map(t => t.filename).join(', ')\n )\n }\n\n setTicketStatus (_num:number, _status:TicketStatus):void {\n // no-op: plain mode reports via log()\n }\n\n log (message:string):void {\n console.log(message)\n }\n\n cleanup ():void {\n // no-op\n }\n}\n\nexport function createDisplay (stream?:NodeJS.WriteStream):Display {\n const s = stream ?? process.stdout\n if (s.isTTY) {\n return new StatusDisplay({ stream:s })\n }\n\n return new PlainDisplay()\n}\n", "import { existsSync, readdirSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { select } from '@inquirer/prompts'\n\nexport function getScriptDir (metaUrl:string):string {\n return dirname(fileURLToPath(metaUrl))\n}\n\nexport function findFeatureDirs (cwd:string):{\n name:string;\n dir:string;\n spec:string\n}[] {\n const scratchDir = join(cwd, '.scratch')\n if (!existsSync(scratchDir)) return []\n const entries = readdirSync(\n scratchDir, { withFileTypes:true }\n )\n const results:{ name:string; dir:string; spec:string }[] = []\n for (const entry of entries) {\n if (!entry.isDirectory()) continue\n const issuesDir = join(\n scratchDir, entry.name, 'issues'\n )\n const specFile = join(\n scratchDir, entry.name, 'spec.md'\n )\n if (existsSync(issuesDir)) {\n results.push({\n name:entry.name,\n dir:issuesDir,\n spec:specFile,\n })\n }\n }\n return results\n}\n\nexport async function resolveIssuesDir (\n specName:string|undefined,\n cwd:string = process.cwd(),\n):Promise<{ dir:string; spec:string }> {\n if (specName) {\n const featureDir = join(cwd, '.scratch', specName)\n return {\n dir:join(featureDir, 'issues'),\n spec:join(featureDir, 'spec.md'),\n }\n }\n\n const features = findFeatureDirs(cwd)\n\n if (features.length === 0) {\n console.error(\n 'No .scratch/<feature>/issues/ directories ' +\n 'found.\\nProvide --spec <feature-name>.'\n )\n process.exit(2)\n }\n\n let chosen:typeof features[0]\n if (features.length === 1) {\n chosen = features[0]\n console.log(`Using feature: ${chosen.name}`)\n } else {\n const name = await select({\n message:'Which feature?',\n choices:features.map(f => ({\n name:f.name,\n value:f.name,\n })),\n })\n chosen = features.find(f => f.name === name)!\n }\n\n return { dir:chosen.dir, spec:chosen.spec }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["#!/usr/bin/env node\n\nimport { existsSync, readFileSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport yargs from 'yargs'\nimport { hideBin } from 'yargs/helpers'\nimport { select } from '@inquirer/prompts'\nimport { setup, checkGhAuth, type TrackerKind } from './setup.js'\nimport {\n scanTickets,\n dryRun,\n dryRunIsolated,\n runWaves,\n runWavesIsolated,\n} from './orchestrator.js'\nimport { createDisplay } from './display.js'\nimport {\n findFeatureDirs,\n resolveIssuesDir,\n getScriptDir,\n} from './resolve.js'\nimport { getRepoRoot, getRepoName } from './worktree.js'\n\nexport { findFeatureDirs, resolveIssuesDir }\n\nconst scriptDir = getScriptDir(import.meta.url)\n\nyargs(hideBin(process.argv))\n .scriptName('nightralph')\n .usage('$0 <command>')\n .command(\n 'init',\n 'Install bundled skills and doc templates',\n y => y.option('claude', {\n type:'boolean',\n describe:'Also create .claude/skills/ symlinks',\n default:true,\n }),\n async argv => {\n const tracker = await select<TrackerKind>({\n message:'Issue tracker format',\n choices:[\n {\n name:'Local Markdown',\n value:'local' as const,\n description:'Issues as .md files in ' +\n '.scratch/',\n },\n {\n name:'GitHub Issues',\n value:'github' as const,\n description:'Issues via gh CLI',\n },\n ],\n })\n\n if (tracker === 'github') {\n if (!checkGhAuth()) {\n console.error(\n 'GitHub Issues requires the gh CLI, ' +\n 'authenticated.\\n' +\n 'Install: https://cli.github.com\\n' +\n 'Then run: gh auth login'\n )\n process.exit(2)\n }\n }\n\n setup({\n bundledSkillsDir:join(scriptDir, 'skills'),\n docsTemplatesDir:join(\n scriptDir, 'docs-templates'\n ),\n projectDir:process.cwd(),\n claude:argv.claude,\n tracker,\n })\n }\n )\n .command(\n '$0 <provider>',\n 'Execute tickets with the given provider',\n y => y\n .positional('provider', {\n type:'string',\n describe:'Agent CLI to spawn ' +\n '(e.g. claude, codex, pi)',\n demandOption:true,\n })\n .option('m', {\n alias:'model',\n type:'string',\n describe:'Model passed to the agent',\n })\n .option('spec', {\n type:'string',\n describe:'Feature name ' +\n '(resolves .scratch/<name>/)',\n })\n .option('dry-run', {\n type:'boolean',\n describe:'Show wave order without running',\n default:false,\n })\n .option('timeout', {\n type:'number',\n describe:'Kill agent after N seconds',\n default:900,\n })\n .option('X', {\n type:'boolean',\n describe:'Stop on merge conflict instead of ' +\n 're-spawning',\n default:false,\n }),\n async argv => {\n await runExecute({\n provider:argv.provider as string,\n model:argv.model as string|undefined,\n spec:argv.spec as string|undefined,\n dryRun:argv.dryRun as boolean|undefined,\n timeout:argv.timeout as\n number|undefined,\n stopOnConflict:argv.X as\n boolean|undefined,\n })\n }\n )\n .strict()\n .demandCommand(1, 'Specify a command or provider')\n .help()\n .parse()\n\nfunction isGitRepo ():boolean {\n try {\n getRepoRoot()\n return true\n } catch {\n return false\n }\n}\n\nfunction extractFeatureName (spec:string):string {\n const parts = spec.split(\n /[\\\\/]/\n )\n const scratchIndex = parts.indexOf('.scratch')\n if (scratchIndex >= 0 && scratchIndex < parts.length - 1) {\n return parts[scratchIndex + 1]\n }\n return parts[parts.length - 2] ??\n parts[parts.length - 1] ?? 'feature'\n}\n\nasync function runExecute (argv:{\n provider:string\n model?:string\n spec?:string\n dryRun?:boolean\n timeout?:number\n stopOnConflict?:boolean\n}):Promise<void> {\n const { dir, spec } = await resolveIssuesDir(\n argv.spec\n )\n\n if (!existsSync(dir)) {\n console.error(`Directory not found: ${dir}`)\n process.exit(2)\n }\n if (!existsSync(spec)) {\n console.error(`Spec file not found: ${spec}`)\n process.exit(2)\n }\n\n const specBody = readFileSync(spec, 'utf8')\n const tickets = scanTickets(dir)\n\n if (tickets.length === 0) {\n console.log('No ticket files found. Exiting.')\n return\n }\n\n console.log(`Found ${tickets.length} tickets`)\n\n const knownNums = new Set(tickets.map(t => t.num))\n for (const t of tickets) {\n const unknown = t.blockers.filter(\n b => !knownNums.has(b)\n )\n if (unknown.length > 0) {\n console.warn(\n `${t.filename}: blockers ` +\n `[${unknown.join(', ')}] ` +\n 'not found in directory'\n )\n }\n t.blockers = t.blockers.filter(\n b => knownNums.has(b)\n )\n }\n\n const logsDir = join(dirname(dir), 'logs')\n const timeout = argv.timeout ?? 300\n const featureName = extractFeatureName(spec)\n const conflictStrategy = argv.stopOnConflict ?\n 'stop' :\n 'respawn'\n const progressPath = join(\n dirname(dir), 'progress.md'\n )\n\n if (argv.dryRun) {\n if (isGitRepo()) {\n const repoName = getRepoName()\n dryRunIsolated({\n tickets,\n specBody,\n repoName,\n conflictStrategy,\n progressPath,\n })\n } else {\n dryRun(tickets, specBody)\n }\n return\n }\n\n const display = createDisplay()\n let result:{ allDone:boolean }\n\n if (isGitRepo()) {\n result = await runWavesIsolated({\n tickets,\n specBody,\n agentCmd:argv.provider,\n model:argv.model ?? null,\n timeout,\n logsDir,\n featureName,\n conflictStrategy,\n display,\n })\n } else {\n result = await runWaves(\n tickets, specBody,\n argv.provider, argv.model ?? null,\n timeout,\n logsDir,\n display,\n )\n }\n\n if (!result.allDone) {\n process.exit(1)\n }\n}\n", "import {\n cpSync,\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n symlinkSync,\n writeFileSync,\n} from 'node:fs'\nimport { join } from 'node:path'\nimport { execSync } from 'node:child_process'\n\nexport const SKILL_DIRS = [\n 'grill', 'grilling', 'domain-modeling',\n 'to-spec', 'to-tickets', 'tdd',\n] as const\n\nexport const DOC_TEMPLATES = [\n 'triage-labels.md',\n 'domain.md',\n] as const\n\nconst START_MARKER = '<!-- nightralph:start -->'\nconst END_MARKER = '<!-- nightralph:end -->'\n\nexport function writeManagedSection (\n filePath:string,\n content:string,\n):void {\n const block = [\n START_MARKER,\n content,\n END_MARKER,\n ].join('\\n')\n\n if (!existsSync(filePath)) {\n writeFileSync(filePath, block + '\\n')\n return\n }\n\n const existing = readFileSync(filePath, 'utf8')\n const startIdx = existing.indexOf(START_MARKER)\n const endIdx = existing.indexOf(END_MARKER)\n\n if (startIdx !== -1 && endIdx !== -1) {\n const before = existing.slice(0, startIdx)\n const after = existing.slice(\n endIdx + END_MARKER.length\n )\n writeFileSync(filePath, before + block + after)\n } else {\n const sep = existing.endsWith('\\n') ? '\\n' : '\\n\\n'\n writeFileSync(filePath, existing + sep + block + '\\n')\n }\n}\n\nexport function checkGhAuth ():boolean {\n try {\n execSync('gh auth status', { stdio:'ignore' })\n return true\n } catch {\n return false\n }\n}\n\nexport type TrackerKind = 'github'|'local'\n\nexport type SetupOpts = {\n bundledSkillsDir:string\n docsTemplatesDir:string\n projectDir:string\n claude?:boolean\n tracker:TrackerKind\n}\n\nconst TRACKER_TEMPLATES:Record<TrackerKind, string> = {\n local:'issue-tracker.md',\n github:'issue-tracker-github.md',\n}\n\nexport function setup (opts:SetupOpts):void {\n const {\n bundledSkillsDir,\n docsTemplatesDir,\n projectDir,\n claude,\n tracker,\n } = opts\n const agentsSkillsDir = join(\n projectDir, '.agents', 'skills'\n )\n\n const upstream = JSON.parse(\n readFileSync(\n join(bundledSkillsDir, 'upstream.json'),\n 'utf8'\n )\n ) as { repo:string; commit:string }\n\n console.log('Installing skills to .agents/skills/\\n')\n\n for (const skill of SKILL_DIRS) {\n const src = join(bundledSkillsDir, skill)\n const dest = join(agentsSkillsDir, skill)\n mkdirSync(dest, { recursive:true })\n cpSync(src, dest, { recursive:true })\n const files = readdirSync(src)\n console.log(\n ` ${skill}/ (${files.join(', ')})`\n )\n }\n\n if (claude) {\n const claudeSkillsDir = join(\n projectDir, '.claude', 'skills'\n )\n mkdirSync(claudeSkillsDir, { recursive:true })\n\n for (const skill of SKILL_DIRS) {\n const linkPath = join(claudeSkillsDir, skill)\n const target = join(\n '..', '..', '.agents', 'skills', skill\n )\n if (existsSync(linkPath)) continue\n symlinkSync(target, linkPath)\n }\n\n console.log(\n '\\nCreated symlinks in .claude/skills/'\n )\n }\n\n const docsAgentsDir = join(\n projectDir, 'docs', 'agents'\n )\n mkdirSync(docsAgentsDir, { recursive:true })\n\n console.log('')\n for (const tmpl of DOC_TEMPLATES) {\n const dest = join(docsAgentsDir, tmpl)\n if (existsSync(dest)) {\n console.log(\n ` docs/agents/${tmpl} (already exists)`\n )\n continue\n }\n const src = join(docsTemplatesDir, tmpl)\n writeFileSync(dest, readFileSync(src, 'utf8'))\n console.log(` docs/agents/${tmpl} (created)`)\n }\n\n const trackerSrc = join(\n docsTemplatesDir, TRACKER_TEMPLATES[tracker]\n )\n const trackerDest = join(docsAgentsDir, 'issue-tracker.md')\n writeFileSync(trackerDest, readFileSync(trackerSrc, 'utf8'))\n console.log(\n ` docs/agents/issue-tracker.md (${tracker})`\n )\n\n const trackerLine = tracker === 'github' ?\n 'Issues are tracked via GitHub Issues using the `gh` ' +\n 'CLI.' :\n 'Issues are tracked as local markdown files under ' +\n '`.scratch/`.'\n\n const managedContent = [\n '## Agent skills',\n '',\n '### Issue tracker',\n '',\n `${trackerLine} See \\`docs/agents/issue-tracker.md\\`.`,\n '',\n '### Triage labels',\n '',\n 'Default label vocabulary. See ' +\n '`docs/agents/triage-labels.md`.',\n '',\n '### Domain docs',\n '',\n 'Single-context layout. See `docs/agents/domain.md`.',\n ].join('\\n')\n\n const agentsPath = join(projectDir, 'AGENTS.md')\n writeManagedSection(agentsPath, managedContent)\n console.log('\\n AGENTS.md (updated)')\n\n console.log(\n `\\nSource: ${upstream.repo} @ ${upstream.commit}`\n )\n}\n", "import { spawn } 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 {\n getRepoRoot,\n getRepoName,\n getCurrentBranch,\n createWorktree,\n removeWorktree,\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'\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\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\nexport const COMPLETED_RE = /^\\[x\\]\\s+(.+)$/i\nexport const TOOL_USE_RE = /^\\[[\\w.]+\\]/\n\nexport function checkItems (\n ticket:Ticket,\n completedItems:string[]\n):void {\n if (completedItems.length === 0) return\n let body = ticket.body\n for (const item of completedItems) {\n const escaped = item.replace(\n /[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'\n )\n body = body.replace(\n new RegExp(\n `- \\\\[ \\\\] ${escaped}`,\n 'i'\n ),\n `- [x] ${item}`\n )\n }\n writeFileSync(ticket.filepath, body)\n ticket.body = body\n}\n\nexport function markDone (ticket:Ticket):void {\n const updated = ticket.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\nexport function renderPrompt (\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. ' +\n 'Implement the ticket.',\n '',\n 'Time is limited. Follow these rules:',\n '- Spend at most 2 minutes reading existing ' +\n 'code. Read only the files directly relevant ' +\n 'to the ticket.',\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 '- Start writing code as soon as you understand ' +\n 'the immediate context. You can read more ' +\n 'files as needed while implementing.',\n '- Commit your work 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 '',\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. Make sure the code compiles and tests pass.',\n '3. Commit the resolved files.',\n '',\n 'Do NOT re-implement the ticket from scratch.',\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:['exec', '--full-auto'],\n pi:[\n '-p', '--verbose',\n '--approve', '--no-session',\n '--mode', 'json',\n ],\n}\n\nexport function getProviderArgs (cmd:string):string[] {\n const name = basename(cmd)\n return PROVIDER_ARGS[name] ?? []\n}\n\nexport function formatStreamLine (\n line:string\n):string|null {\n let obj:Record<string, unknown>\n try {\n obj = JSON.parse(line) as Record<string, unknown>\n } catch {\n return line\n }\n\n if (obj.type === 'assistant') {\n const msg = obj.message as\n Record<string, unknown>|undefined\n const content = msg?.content as\n Array<Record<string, unknown>>|undefined\n if (!content) return null\n for (const block of content) {\n if (block.type === 'text') {\n return String(block.text)\n }\n }\n return null\n }\n\n if (obj.type === 'result') {\n const sub = obj.subtype as string|undefined ?? 'done'\n const cost = obj.total_cost_usd as number|undefined\n const costStr = cost != null ?\n ` ($${cost.toFixed(2)})` :\n ''\n return `${sub}${costStr}`\n }\n\n if (obj.type === 'system') {\n const sub = obj.subtype as string|undefined\n if (sub === 'api_retry') {\n const error = obj.error as string|undefined\n return `retry: ${error ?? 'unknown'}`\n }\n }\n\n return null\n}\n\nexport type PiStreamFormatter = {\n process:(line:string) => string[]\n flush:() => string[]\n}\n\nexport function createPiStreamFormatter (\n):PiStreamFormatter {\n const calls = new Map<\n number, { name:string; buf:string }\n >()\n let textBuf = ''\n\n function drainLines ():string[] {\n const parts = textBuf.split('\\n')\n if (parts.length === 1) return []\n textBuf = parts[parts.length - 1]\n return parts.slice(0, -1)\n }\n\n function flushBuf ():string[] {\n if (textBuf.length === 0) return []\n const out = textBuf\n textBuf = ''\n return [out]\n }\n\n function process (line:string):string[] {\n let obj:Record<string, unknown>\n try {\n obj = JSON.parse(line) as\n Record<string, unknown>\n } catch {\n return [line]\n }\n\n const evt = obj.assistantMessageEvent as\n Record<string, unknown>|undefined\n if (!evt) return []\n\n const type = evt.type as string|undefined\n const ci = evt.contentIndex as\n number|undefined ?? -1\n\n if (type === 'text_delta') {\n const delta =\n (evt.delta as string|undefined) ?? ''\n textBuf += delta\n return drainLines()\n }\n\n if (type === 'toolcall_start') {\n const flushed = flushBuf()\n calls.set(ci, {\n name:(evt.toolName as\n string|undefined) ?? '?',\n buf:'',\n })\n return flushed\n }\n\n if (\n type === 'toolcall_delta' &&\n calls.has(ci)\n ) {\n calls.get(ci)!.buf +=\n (evt.delta as string|undefined) ?? ''\n return []\n }\n\n if (\n type === 'toolcall_end' &&\n calls.has(ci)\n ) {\n const call = calls.get(ci)!\n calls.delete(ci)\n let label = ''\n try {\n const args = JSON.parse(call.buf) as\n Record<string, unknown>\n label = String(\n args.command ??\n args.file_path ??\n args.query ?? ''\n ).split('\\n')[0].slice(0, 72)\n } catch {\n // unparseable tool args\n }\n return [`[${call.name}] ${label}`]\n }\n\n return []\n }\n\n return { process, flush:flushBuf }\n}\n\nfunction writePromptFile (prompt:string):string {\n const name = `nightralph-${Date.now()}-` +\n `${Math.random().toString(36).slice(2)}.md`\n const filePath = join(tmpdir(), name)\n writeFileSync(filePath, prompt)\n return filePath\n}\n\nfunction cleanupPromptFile (filePath:string):void {\n try {\n unlinkSync(filePath)\n } catch {\n // already removed\n }\n}\n\nexport type AgentResult = {\n exitCode:number\n completedItems:string[]\n}\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 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\n const providerName = basename(opts.agentCmd)\n const isClaude = providerName === 'claude'\n const isPi = providerName === 'pi'\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 })\n\n proc.stdout.pipe(logStream)\n\n const piFormatter = isPi ?\n createPiStreamFormatter() :\n null\n\n const completedItems:string[] = []\n\n function collectCompleted (text:string):void {\n const match = text.match(COMPLETED_RE)\n if (match) completedItems.push(match[1])\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 const timeout = setTimeout(() => {\n if (!proc.killed) {\n console.warn(\n 'Agent did not exit in ' +\n `${opts.timeout}s; killing.`\n )\n proc.kill('SIGKILL')\n }\n }, opts.timeout * 1000)\n\n if (!promptFile) {\n proc.stdin.write(opts.prompt)\n }\n proc.stdin.end()\n\n return new Promise<AgentResult>(resolve => {\n proc.on('close', code => {\n clearTimeout(timeout)\n if (piFormatter) {\n for (const line of piFormatter.flush()) {\n collectCompleted(line)\n const output = `${prefix}${line}`\n if (opts.onLine) {\n opts.onLine(output)\n } else {\n console.log(output)\n }\n }\n }\n rl.close()\n rlErr.close()\n logStream.end()\n if (promptFile) cleanupPromptFile(promptFile)\n resolve({\n exitCode:code ?? 1,\n completedItems,\n })\n })\n proc.on('error', err => {\n clearTimeout(timeout)\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({ exitCode:1, completedItems })\n })\n })\n}\n\nexport function dryRun (\n tickets:Array<Ticket>,\n specBody: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 )\n }\n}\n\nexport function dryRunIsolated (opts:{\n tickets:Array<Ticket>\n specBody:string\n repoName:string\n conflictStrategy:MergeConflictStrategy\n progressPath:string\n}):void {\n listTickets(opts.tickets)\n\n console.log('\\nSimulated wave order:')\n for (const { wave, ready } of simulateWaves(\n opts.tickets\n )) {\n console.log(\n ` Wave ${wave}: ` +\n ready.map(t => t.filename).join(', ')\n )\n for (const t of ready) {\n const num = String(t.num).padStart(2, '0')\n const branchName =\n `${opts.repoName}/${num}-${t.slug}`\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(opts.specBody, firstReady[0])\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 `\\nMerge strategy: ${strategyDesc}`\n )\n console.log(`Progress file: ${opts.progressPath}`)\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 onLine?:(msg:string) => void\n}):Promise<boolean> {\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 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 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\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 display?:Display,\n):Promise<{ allDone:boolean }> {\n mkdirSync(logsDir, { recursive:true })\n\n const d = display ?? createDisplay()\n let totalWaves = 0\n for (const _ of simulateWaves(tickets)) totalWaves++\n\n let totalCompleted = 0\n let waveNum = 0\n\n while (true) {\n const ready = findReadyTickets(tickets)\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 Promise.allSettled(\n ready.map(async t => {\n const prompt = renderPrompt(specBody, t)\n const logPath = join(\n logsDir,\n t.filename.replace(/\\.md$/, '.log')\n )\n const label = t.filename.replace(\n /\\.md$/, ''\n )\n d.setTicketStatus(t.num, 'in-progress')\n d.log(` Starting ${t.filename}`)\n const result = await spawnAgent({\n prompt,\n agentCmd,\n model,\n timeout,\n logPath,\n label,\n onLine:(line) => d.log(line),\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 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 d.log(\n '\\nNo tickets completed this wave. ' +\n 'Stopping.'\n )\n break\n }\n }\n\n const remaining = tickets.filter(\n t => t.status === 'ready-for-agent'\n )\n d.log(\n `\\nFinished: ${totalCompleted} completed` +\n (remaining.length > 0 ?\n `, ${remaining.length} remaining` :\n '')\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}):Promise<{ allDone:boolean }> {\n mkdirSync(opts.logsDir, { recursive:true })\n\n const d = opts.display ?? createDisplay()\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 writeProgress(progressPath, progress)\n await commitProgress(\n repoRoot,\n progressPath,\n `nightralph: start ${opts.featureName}`\n )\n\n let totalCompleted = 0\n let waveNum = 0\n\n while (true) {\n const ready = findReadyTickets(opts.tickets)\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 const worktreeSettled = await Promise.allSettled(\n ready.map(t => createWorktree({\n repoRoot,\n repoName,\n baseBranch,\n ticket:t,\n }))\n )\n\n const activeTickets:Array<Ticket> = []\n const worktrees:Array<{\n worktreePath:string\n branchName:string\n }> = []\n\n for (let i = 0; i < worktreeSettled.length; i++) {\n const settled = worktreeSettled[i]\n const ticket = ready[i]\n if (settled.status === 'rejected') {\n d.setTicketStatus(ticket.num, 'failed')\n d.log(\n ` ${ticket.filename}: failed to create ` +\n `worktree: ${formatErrorMessage(settled.reason)}`\n )\n continue\n }\n activeTickets.push(ticket)\n worktrees.push(settled.value)\n }\n\n const results = await Promise.allSettled(\n activeTickets.map((t, i) => {\n const prompt = renderPrompt(opts.specBody, t)\n const logPath = join(\n opts.logsDir,\n t.filename.replace(/\\.md$/, '.log')\n )\n const label = t.filename.replace(\n /\\.md$/, ''\n )\n d.setTicketStatus(t.num, 'in-progress')\n d.log(` Starting ${t.filename}`)\n return spawnAgent({\n prompt,\n agentCmd:opts.agentCmd,\n model:opts.model,\n timeout:opts.timeout,\n logPath,\n cwd:worktrees[i].worktreePath,\n label,\n onLine:(line) => d.log(line),\n })\n })\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 < results.length; i++) {\n const r = results[i]\n if (r.status === 'rejected') continue\n const agentResult = r.value\n const ticket = activeTickets[i]\n const worktree = worktrees[i]\n\n if (agentResult.exitCode !== 0) {\n d.setTicketStatus(ticket.num, 'failed')\n d.log(\n ` ${ticket.filename}: ` +\n `agent exited ${agentResult.exitCode}`\n )\n checkItems(ticket, agentResult.completedItems)\n checkTicket(progress, ticket.num, {\n branch:worktree.branchName,\n exitCode:agentResult.exitCode,\n done:false,\n })\n writeProgress(progressPath, progress)\n await commitProgress(\n repoRoot,\n progressPath,\n `nightralph: ${ticket.filename} failed`\n )\n\n try {\n await removeWorktree(worktree.worktreePath)\n } catch (err) {\n d.log(\n ' Failed to remove worktree ' +\n `${worktree.worktreePath}: ` +\n formatErrorMessage(err)\n )\n }\n continue\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 repoRoot, baseBranch, worktree.branchName\n )) {\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 continue\n }\n\n checkItems(ticket, agentResult.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, worktree.worktreePath\n )\n successfulBranches.push({\n branch:worktree.branchName,\n ticketNum:ticket.num,\n worktreePath:worktree.worktreePath,\n })\n }\n\n if (successfulBranches.length > 0) {\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 writeProgress(progressPath, progress)\n await commitProgress(\n repoRoot,\n progressPath,\n `nightralph: ${ticket.filename} done`\n )\n\n const worktreePath = worktreePathsByNum.get(\n ticket.num\n )\n if (worktreePath) {\n try {\n await removeWorktree(worktreePath)\n } catch (err) {\n d.log(\n ' Failed to remove worktree ' +\n `${worktreePath}: ` +\n formatErrorMessage(err)\n )\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 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 writeProgress(progressPath, progress)\n await commitProgress(\n repoRoot,\n progressPath,\n `nightralph: ${ticket.filename} ` +\n 'done (respawn)'\n )\n\n if (worktreePath) {\n try {\n await removeWorktree(worktreePath)\n } catch (err) {\n d.log(\n ' Failed to remove worktree ' +\n `${worktreePath}: ` +\n formatErrorMessage(err)\n )\n }\n }\n } else {\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 writeProgress(progressPath, progress)\n await commitProgress(\n repoRoot,\n progressPath,\n `nightralph: ${ticket.filename} ` +\n 'merge failed'\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(sb.worktreePath)\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 d.log(\n '\\nNo tickets completed this wave. ' +\n 'Stopping.'\n )\n break\n }\n }\n\n const remaining = opts.tickets.filter(\n t => t.status === 'ready-for-agent'\n )\n d.log(\n `\\nFinished: ${totalCompleted} completed` +\n (remaining.length > 0 ?\n `, ${remaining.length} remaining` :\n '')\n )\n d.cleanup()\n\n return { allDone:remaining.length === 0 }\n}\n", "import { execFile, execFileSync } from 'node:child_process'\nimport { promisify } from 'node:util'\nimport { basename, join } from 'node:path'\nimport { existsSync } from 'node:fs'\nimport type { Ticket } from './orchestrator.js'\n\nconst execFileAsync = promisify(execFile)\n\nexport function getRepoRoot ():string {\n const stdout = execFileSync(\n 'git',\n ['rev-parse', '--show-toplevel'],\n { encoding:'utf8' }\n )\n return stdout.trim()\n}\n\nexport function getRepoName ():string {\n return basename(getRepoRoot())\n}\n\nexport function getCurrentBranch ():string {\n const stdout = execFileSync(\n 'git',\n ['rev-parse', '--abbrev-ref', 'HEAD'],\n { encoding:'utf8' }\n )\n return stdout.trim()\n}\n\nasync function branchExists (\n repoRoot:string,\n branchName:string\n):Promise<boolean> {\n try {\n await execFileAsync(\n 'git',\n ['show-ref', '--verify', '--quiet', `refs/heads/${branchName}`],\n { cwd:repoRoot }\n )\n return true\n } catch {\n return false\n }\n}\n\nexport async function createWorktree (\n opts:{\n repoRoot:string\n repoName:string\n baseBranch:string\n ticket:Ticket\n }\n):Promise<{ worktreePath:string; branchName:string }> {\n const { repoRoot, repoName, baseBranch, ticket } = opts\n const branchName = `${repoName}/${String(\n ticket.num\n ).padStart(2, '0')}-${ticket.slug}`\n const worktreePath = join(\n repoRoot,\n '..',\n `${repoName}.${String(\n ticket.num\n ).padStart(2, '0')}-${ticket.slug}`\n )\n\n if (existsSync(worktreePath)) {\n try {\n await execFileAsync(\n 'git',\n ['worktree', 'remove', '--force', worktreePath],\n { cwd:repoRoot }\n )\n } catch {\n // directory may not be a registered worktree anymore;\n // prune stale entries below and let worktree add fail\n // loudly if the path is still unusable\n }\n }\n\n try {\n await execFileAsync(\n 'git',\n ['worktree', 'prune'],\n { cwd:repoRoot }\n )\n } catch {\n // best-effort cleanup of stale worktree metadata\n }\n\n if (await branchExists(repoRoot, branchName)) {\n await execFileAsync(\n 'git',\n ['branch', '-D', branchName],\n { cwd:repoRoot }\n )\n }\n\n await execFileAsync(\n 'git',\n [\n 'worktree',\n 'add',\n '-b',\n branchName,\n worktreePath,\n baseBranch,\n ],\n { cwd:repoRoot }\n )\n\n return { worktreePath, branchName }\n}\n\nexport async function removeWorktree (\n worktreePath:string\n):Promise<void> {\n // Use git -C to run the command from the worktree directory context\n // so git can resolve the repository\n await execFileAsync(\n 'git',\n ['-C', worktreePath, 'worktree', 'remove', worktreePath]\n )\n}\n\nexport function hasNewCommits (\n repoRoot:string,\n base:string,\n branch:string\n):boolean {\n const stdout = execFileSync(\n 'git',\n ['rev-list', '--count', `${base}..${branch}`],\n { cwd:repoRoot, encoding:'utf8' }\n )\n return Number(stdout.trim()) > 0\n}\n\nexport function isDirty (cwd:string):boolean {\n const stdout = execFileSync(\n 'git',\n ['status', '--porcelain'],\n { cwd, encoding:'utf8' }\n )\n return stdout.trim().length > 0\n}\n\nexport async function commitDirty (\n cwd:string,\n message?:string\n):Promise<boolean> {\n if (!isDirty(cwd)) return false\n await execFileAsync(\n 'git',\n ['add', '-A'],\n { cwd }\n )\n try {\n await execFileAsync(\n 'git',\n [\n 'commit', '-m',\n message ??\n 'nightralph: auto-commit ' +\n 'remaining changes',\n ],\n { cwd }\n )\n return true\n } catch {\n return false\n }\n}\n\nexport async function listWorktrees (\n repoRoot:string\n):Promise<Array<string>> {\n const { stdout } = await execFileAsync(\n 'git',\n ['worktree', 'list', '--porcelain'],\n { cwd:repoRoot }\n )\n return stdout\n .trim()\n .split('\\n')\n .filter(line => line.startsWith('worktree '))\n .map(line => line.substring('worktree '.length))\n}\n", "import { execFile } from 'node:child_process'\nimport { readFileSync, writeFileSync } from 'node:fs'\nimport { promisify } from 'node:util'\nimport type { Ticket } from './orchestrator.js'\n\nconst TICKET_FILENAME_RE = /^(\\d+)-(.+)\\.md$/\n\nconst execFileAsync = promisify(execFile)\n\nexport type TicketProgress = {\n num:number\n slug:string\n filename:string\n done:boolean\n branch:string|null\n exitCode:number|null\n completedAt:string|null\n}\n\nexport type ProgressData = {\n feature:string\n startedAt:string\n tickets:Array<TicketProgress>\n}\n\nexport function generateProgress (\n feature:string,\n tickets:ReadonlyArray<Ticket>\n):ProgressData {\n return {\n feature,\n startedAt:new Date().toISOString(),\n tickets:tickets.map((ticket) => ({\n num:ticket.num,\n slug:ticket.slug,\n filename:ticket.filename,\n done:false,\n branch:null,\n exitCode:null,\n completedAt:null,\n })),\n }\n}\n\nexport function readProgress (\n progressPath:string\n):ProgressData|null {\n let content:string\n try {\n content = readFileSync(progressPath, 'utf8')\n } catch {\n return null\n }\n\n const featureMatch = content.match(/^# Progress: (.*)$/m)\n const startedMatch = content.match(/^Started: (.*)$/m)\n\n const tickets:Array<TicketProgress> = []\n let current:TicketProgress|null = null\n\n for (const line of content.split('\\n')) {\n const ticketMatch = line.match(/^- \\[( |x)\\] (.+)$/)\n if (ticketMatch) {\n if (current) tickets.push(current)\n const filename = ticketMatch[2]\n const parsed = filename.match(TICKET_FILENAME_RE)\n current = {\n num:parsed ? Number(parsed[1]) : NaN,\n slug:parsed ? parsed[2] : '',\n filename,\n done:ticketMatch[1] === 'x',\n branch:null,\n exitCode:null,\n completedAt:null,\n }\n continue\n }\n if (!current) continue\n\n const branchMatch = line.match(/^ {2}branch: (.*)$/)\n if (branchMatch) {\n current.branch = branchMatch[1]\n continue\n }\n const exitMatch = line.match(/^ {2}exit: (-?\\d+)$/)\n if (exitMatch) {\n current.exitCode = Number(exitMatch[1])\n continue\n }\n const completedMatch = line.match(/^ {2}completed: (.*)$/)\n if (completedMatch) {\n current.completedAt = completedMatch[1]\n continue\n }\n }\n if (current) tickets.push(current)\n\n return {\n feature:featureMatch ? featureMatch[1] : '',\n startedAt:startedMatch ? startedMatch[1] : '',\n tickets,\n }\n}\n\nexport function mergeProgress (\n fresh:ProgressData,\n existing:ProgressData|null\n):ProgressData {\n if (!existing) return fresh\n\n const existingByFilename = new Map(\n existing.tickets.map((t) => [t.filename, t])\n )\n\n return {\n ...fresh,\n tickets:fresh.tickets.map((ticket) => {\n const prior = existingByFilename.get(ticket.filename)\n return (prior && prior.done) ? { ...prior } : ticket\n }),\n }\n}\n\nexport function renderProgress (data:ProgressData):string {\n const lines:Array<string> = [\n `# Progress: ${data.feature}`,\n '',\n `Started: ${data.startedAt}`,\n '',\n ]\n\n for (const ticket of data.tickets) {\n const checkbox = ticket.done ? '[x]' : '[ ]'\n lines.push(`- ${checkbox} ${ticket.filename}`)\n\n if (ticket.done || ticket.exitCode !== null) {\n if (ticket.branch) {\n lines.push(\n ` branch: ${ticket.branch}`\n )\n }\n if (ticket.exitCode !== null) {\n lines.push(\n ` exit: ${ticket.exitCode}`\n )\n }\n if (ticket.completedAt) {\n lines.push(\n ` completed: ${ticket.completedAt}`\n )\n }\n }\n }\n\n return lines.join('\\n') + '\\n'\n}\n\nexport function checkTicket (\n data:ProgressData,\n ticketNum:number,\n result:{ branch:string; exitCode:number; done?:boolean }\n):void {\n const ticket = data.tickets.find(\n (t) => t.num === ticketNum\n )\n if (!ticket) return\n\n ticket.done = result.done ?? true\n ticket.branch = result.branch\n ticket.exitCode = result.exitCode\n if (ticket.done) {\n ticket.completedAt = new Date().toISOString()\n }\n}\n\nexport function writeProgress (\n progressPath:string,\n data:ProgressData\n):void {\n writeFileSync(\n progressPath,\n renderProgress(data)\n )\n}\n\nexport async function commitProgress (\n repoRoot:string,\n progressPath:string,\n message:string\n):Promise<void> {\n await execFileAsync(\n 'git',\n ['add', '--force', progressPath],\n { cwd:repoRoot }\n )\n\n await execFileAsync(\n 'git',\n ['commit', '-m', message, '--', progressPath],\n { cwd:repoRoot }\n )\n}\n", "import { execFile } from 'node:child_process'\nimport { promisify } from 'node:util'\n\nconst execFileAsync = promisify(execFile)\n\nexport type MergeConflictStrategy = 'respawn'|'stop'\n\nexport type MergeResult = {\n branch:string\n ticketNum:number\n merged:boolean\n conflicted:boolean\n stderr?:string\n}\n\nexport type WaveMergeResult = {\n merged:Array<MergeResult>\n stoppedAt:MergeResult|null\n}\n\nexport type GitOpResult = {\n success:boolean\n stderr?:string\n}\n\nexport async function mergeBranch (\n repoRoot:string,\n branch:string\n):Promise<GitOpResult> {\n if (!repoRoot || typeof repoRoot !== 'string') {\n throw new Error('repoRoot must be a non-empty string')\n }\n if (!branch || typeof branch !== 'string') {\n throw new Error('branch must be a non-empty string')\n }\n\n try {\n await execFileAsync(\n 'git',\n ['merge', branch, '--no-edit'],\n { cwd:repoRoot }\n )\n return { success:true }\n } catch (err) {\n const execErr = err as {\n stdout?:string; stderr?:string\n }\n const stderr =\n execErr.stderr || execErr.stdout\n try {\n await execFileAsync(\n 'git',\n ['merge', '--abort'],\n { cwd:repoRoot }\n )\n } catch {\n // no merge in progress to abort\n }\n return { success:false, stderr }\n }\n}\n\nexport async function rebaseBranch (\n repoRoot:string,\n branch:string,\n onto:string,\n worktreePath?:string\n):Promise<GitOpResult> {\n if (!repoRoot || typeof repoRoot !== 'string') {\n throw new Error('repoRoot must be a non-empty string')\n }\n if (!branch || typeof branch !== 'string') {\n throw new Error('branch must be a non-empty string')\n }\n if (!onto || typeof onto !== 'string') {\n throw new Error('onto must be a non-empty string')\n }\n\n // When the branch has its own worktree, it is already checked\n // out there -- checking it out in repoRoot too would fail with\n // \"already used by worktree\", so rebase in place instead.\n if (worktreePath) {\n try {\n await execFileAsync(\n 'git',\n ['rebase', onto],\n { cwd:worktreePath }\n )\n return { success:true }\n } catch (err) {\n const execErr = err as {\n stdout?:string; stderr?:string\n }\n const stderr =\n execErr.stderr || execErr.stdout\n try {\n await execFileAsync(\n 'git',\n ['rebase', '--abort'],\n { cwd:worktreePath }\n )\n } catch {\n // ignore abort errors\n }\n return { success:false, stderr }\n }\n }\n\n try {\n await execFileAsync(\n 'git',\n ['checkout', branch],\n { cwd:repoRoot }\n )\n\n await execFileAsync(\n 'git',\n ['rebase', onto],\n { cwd:repoRoot }\n )\n\n await execFileAsync(\n 'git',\n ['checkout', onto],\n { cwd:repoRoot }\n )\n\n return { success:true }\n } catch (err) {\n const stderr =\n (err as { stderr?:string }).stderr\n try {\n await execFileAsync(\n 'git',\n ['rebase', '--abort'],\n { cwd:repoRoot }\n )\n } catch {\n // ignore abort errors\n }\n try {\n await execFileAsync(\n 'git',\n ['checkout', onto],\n { cwd:repoRoot }\n )\n } catch {\n // ignore checkout errors\n }\n return { success:false, stderr }\n }\n}\n\n// Merges baseBranch into the worktree's branch so a\n// respawned agent sees the latest code. Conflicts are\n// left in place (not aborted) so the agent can resolve\n// and commit them.\nexport async function updateWorktreeFromBase (\n worktreePath:string,\n baseBranch:string\n):Promise<void> {\n try {\n await execFileAsync(\n 'git',\n ['merge', baseBranch, '--no-edit'],\n { cwd:worktreePath }\n )\n } catch {\n // conflict markers intentionally left for the\n // respawned agent to resolve\n }\n}\n\nexport async function mergeWave (\n opts:Readonly<{\n repoRoot:string\n baseBranch:string\n branches:ReadonlyArray<{\n branch:string\n ticketNum:number\n worktreePath?:string\n }>\n strategy:MergeConflictStrategy\n }>\n):Promise<WaveMergeResult> {\n const { repoRoot, baseBranch, branches, strategy } = opts\n\n if (!repoRoot || typeof repoRoot !== 'string') {\n throw new Error('repoRoot must be a non-empty string')\n }\n if (!baseBranch || typeof baseBranch !== 'string') {\n throw new Error('baseBranch must be a non-empty string')\n }\n\n const merged:Array<MergeResult> = []\n let stoppedAt:MergeResult|null = null\n\n for (let i = 0; i < branches.length; i++) {\n const { branch, ticketNum, worktreePath } = branches[i]\n const mergingResult:MergeResult = {\n branch,\n ticketNum,\n merged:false,\n conflicted:false,\n }\n\n if (i === 0) {\n const result = await mergeBranch(\n repoRoot,\n branch\n )\n mergingResult.merged = result.success\n mergingResult.conflicted = !result.success\n if (!result.success) {\n mergingResult.stderr = result.stderr\n }\n\n if (!result.success) {\n if (strategy === 'stop') {\n stoppedAt = mergingResult\n merged.push(mergingResult)\n break\n }\n merged.push(mergingResult)\n continue\n }\n } else {\n const rebaseResult = await rebaseBranch(\n repoRoot,\n branch,\n baseBranch,\n worktreePath\n )\n\n if (!rebaseResult.success) {\n mergingResult.conflicted = true\n mergingResult.stderr = rebaseResult.stderr\n\n if (strategy === 'stop') {\n stoppedAt = mergingResult\n merged.push(mergingResult)\n break\n } else {\n // strategy === 'respawn'\n merged.push(mergingResult)\n continue\n }\n }\n\n const mergeResult = await mergeBranch(\n repoRoot,\n branch\n )\n mergingResult.merged = mergeResult.success\n mergingResult.conflicted = !mergeResult.success\n if (!mergeResult.success) {\n mergingResult.stderr = mergeResult.stderr\n }\n\n if (!mergeResult.success) {\n if (strategy === 'stop') {\n stoppedAt = mergingResult\n merged.push(mergingResult)\n break\n }\n merged.push(mergingResult)\n continue\n }\n }\n\n merged.push(mergingResult)\n }\n\n return {\n merged,\n stoppedAt,\n }\n}\n", "export type TicketStatus =\n | 'pending'\n | 'in-progress'\n | 'done'\n | 'failed'\n\nexport type DisplayTicket = {\n readonly num:number\n readonly filename:string\n status:TicketStatus\n}\n\nexport type WaveState = {\n readonly waveNum:number\n readonly totalWaves:number\n readonly tickets:Array<DisplayTicket>\n}\n\nexport type DisplayConfig = {\n readonly stream:NodeJS.WriteStream\n}\n\n/**\n * Progress across the whole run, not just the current wave.\n * `completed` counts tickets done before the wave started;\n * tickets that finish during the wave are added on top.\n */\nexport type RunProgress = {\n readonly completed:number\n readonly total:number\n}\n\nexport type Display = {\n startWave(\n waveNum:number,\n totalWaves:number,\n tickets:ReadonlyArray<{\n num:number\n filename:string\n }>,\n progress?:RunProgress,\n remaining?:ReadonlyArray<{\n num:number\n filename:string\n }>,\n ):void\n setTicketStatus(num:number, status:TicketStatus):void\n log(message:string):void\n cleanup():void\n}\n\nconst ESC = '\\x1b['\n\nexport const ansi = {\n cursorUp (n:number):string {\n return `${ESC}${n}A`\n },\n cursorTo (col:number):string {\n return `${ESC}${col}G`\n },\n eraseLine ():string {\n return `${ESC}2K`\n },\n eraseLines (n:number):string {\n let out = ''\n for (let i = 0; i < n; i++) {\n out += ansi.eraseLine()\n if (i < n - 1) out += ansi.cursorUp(1)\n }\n return out\n },\n cursorHide ():string {\n return `${ESC}?25l`\n },\n cursorShow ():string {\n return `${ESC}?25h`\n },\n} as const\n\nexport const color = {\n green (text:string):string {\n return `${ESC}32m${text}${ESC}0m`\n },\n yellow (text:string):string {\n return `${ESC}33m${text}${ESC}0m`\n },\n red (text:string):string {\n return `${ESC}31m${text}${ESC}0m`\n },\n dim (text:string):string {\n return `${ESC}2m${text}${ESC}0m`\n },\n} as const\n\nconst FILLED_DOT = '\u25CF'\nconst EMPTY_DOT = '\u25CB'\nconst SEPARATOR_WIDTH = 50\nconst DEFAULT_COLUMNS = 80\nconst MIN_LOG_ROWS = 1\nconst MAX_MESSAGE_BUFFER = 200\n\n// eslint-disable-next-line no-control-regex\nconst ANSI_RE = /\\x1b\\[[0-9;?]*[A-Za-z]/g\n\n/**\n * Clamp a line to `width` visible columns so it can never wrap.\n * A wrapped line occupies more terminal rows than `render`\n * counts, which leaves stale rows behind on the next erase.\n */\nexport function fitLine (line:string, width:number):string {\n const visible = line.replace(ANSI_RE, '')\n if (visible.length <= width) return line\n return visible.slice(0, width)\n}\n\nexport function renderDot (status:TicketStatus):string {\n switch (status) {\n case 'pending':\n return color.dim(EMPTY_DOT)\n case 'in-progress':\n return color.yellow(FILLED_DOT)\n case 'done':\n return color.green(FILLED_DOT)\n case 'failed':\n return color.red(FILLED_DOT)\n }\n}\n\nexport class StatusDisplay implements Display {\n private wave:WaveState|null = null\n private progress:RunProgress|null = null\n private remaining:Array<DisplayTicket> = []\n private messages:Array<string> = []\n private renderedLines:number = 0\n private config:DisplayConfig\n private viewportStart:number = 0\n private resizeListener:(() => void)|null = null\n private signalHandler:(() => void)|null = null\n\n constructor (config?:Readonly<Partial<DisplayConfig>>) {\n this.config = {\n stream:config?.stream ?? process.stdout,\n }\n }\n\n private getAvailableRows ():number {\n const termHeight = this.config.stream.rows ?? 24\n const overhead = 2 + MIN_LOG_ROWS\n const available = termHeight - overhead\n return Math.max(1, available)\n }\n\n startWave (\n waveNum:number,\n totalWaves:number,\n tickets:Array<Readonly<{ num:number; filename:string }>>,\n progress?:RunProgress,\n remaining?:ReadonlyArray<{\n num:number\n filename:string\n }>,\n ):void {\n this.wave = {\n waveNum,\n totalWaves,\n tickets:tickets.map(t => ({\n ...t,\n status:'pending' as const,\n })),\n }\n this.remaining = (remaining ?? []).map(t => ({\n ...t,\n status:'pending' as const,\n }))\n this.progress = progress ?? null\n this.messages = []\n this.viewportStart = 0\n this.config.stream.write(ansi.cursorHide())\n\n if (this.config.stream.isTTY) {\n if (this.resizeListener) {\n this.config.stream.removeListener(\n 'resize', this.resizeListener,\n )\n }\n this.resizeListener = () => this.render()\n this.config.stream.on(\n 'resize', this.resizeListener,\n )\n }\n\n // Register signal handler to restore cursor on interruption\n if (this.signalHandler) {\n process.removeListener('SIGINT', this.signalHandler)\n process.removeListener('SIGTERM', this.signalHandler)\n }\n this.signalHandler = () => this.cleanup()\n process.on('SIGINT', this.signalHandler)\n process.on('SIGTERM', this.signalHandler)\n\n this.render()\n }\n\n setTicketStatus (num:number, status:TicketStatus):void {\n if (!this.wave) return\n\n const ticket = this.wave.tickets.find(t => t.num === num)\n if (ticket) {\n ticket.status = status\n\n if (status === 'in-progress') {\n const ticketIndex = this.wave.tickets.indexOf(ticket)\n const availableRows = this.getAvailableRows()\n const totalTickets = this.wave.tickets.length\n\n if (ticketIndex < this.viewportStart) {\n this.viewportStart = ticketIndex\n } else if (ticketIndex >= this.viewportStart + availableRows) {\n // offset by 3 to keep context visible below\n // the active ticket\n this.viewportStart = ticketIndex - availableRows + 3\n }\n this.viewportStart = Math.max(\n 0,\n Math.min(this.viewportStart, totalTickets - 1),\n )\n }\n\n this.render()\n }\n }\n\n log (message:string):void {\n this.messages.push(message)\n if (this.messages.length > MAX_MESSAGE_BUFFER) {\n this.messages.shift()\n }\n this.render()\n }\n\n cleanup ():void {\n // Remove resize listener if it exists\n if (this.resizeListener && this.config.stream.isTTY) {\n this.config.stream.removeListener('resize', this.resizeListener)\n }\n // Remove signal handlers\n if (this.signalHandler) {\n process.removeListener('SIGINT', this.signalHandler)\n process.removeListener('SIGTERM', this.signalHandler)\n }\n this.config.stream.write(ansi.cursorShow())\n }\n\n private render ():void {\n if (!this.wave) return\n\n let output = ''\n\n if (this.renderedLines > 0) {\n output += ansi.eraseLines(this.renderedLines + 1)\n }\n\n const doneInWave = this.wave.tickets.filter(\n t => t.status === 'done',\n ).length\n const completed = doneInWave + (this.progress?.completed ?? 0)\n const total = this.progress?.total ?? this.wave.tickets.length\n const pct = total === 0 ? 0 : Math.round((completed / total) * 100)\n const width = Math.max(\n 1,\n (this.config.stream.columns ?? DEFAULT_COLUMNS) - 1,\n )\n\n output += `Wave ${this.wave.waveNum}/` +\n `${this.wave.totalWaves} - ` +\n `${pct}% complete\\n`\n\n // Pagination logic\n const availableRows = this.getAvailableRows()\n const tickets:ReadonlyArray<DisplayTicket> = [\n ...this.wave.tickets,\n ...this.remaining,\n ]\n let renderedTicketCount = 0\n\n if (tickets.length <= availableRows) {\n // All tickets fit, no pagination\n for (const ticket of tickets) {\n const dot = renderDot(ticket.status)\n const name = fitLine(ticket.filename, width - 2)\n output += `${dot} ${name}\\n`\n }\n renderedTicketCount = tickets.length\n } else {\n // Need pagination -- iterative clamp\n this.viewportStart = Math.max(\n 0,\n Math.min(\n this.viewportStart,\n tickets.length - 1,\n ),\n )\n\n let hasMoreAbove = this.viewportStart > 0\n let tentativeCount =\n availableRows - (hasMoreAbove ? 1 : 0)\n let hasMoreBelow =\n this.viewportStart + tentativeCount <\n tickets.length\n let ticketsToShow = Math.max(\n 0,\n tentativeCount - (hasMoreBelow ? 1 : 0),\n )\n\n const maxStart = Math.max(\n 0,\n tickets.length - Math.max(1, ticketsToShow),\n )\n if (this.viewportStart > maxStart) {\n this.viewportStart = maxStart\n hasMoreAbove = this.viewportStart > 0\n tentativeCount = availableRows - (hasMoreAbove ? 1 : 0)\n hasMoreBelow = (\n this.viewportStart +\n tentativeCount < tickets.length\n )\n ticketsToShow = Math.max(\n 0,\n tentativeCount - (hasMoreBelow ? 1 : 0)\n )\n }\n\n // Show \"more above\" indicator if needed\n if (hasMoreAbove) {\n const moreCount = this.viewportStart\n output += ` ... ${moreCount} more above\\n`\n }\n\n // Get visible tickets and render them\n const visibleTickets = tickets.slice(\n this.viewportStart,\n this.viewportStart + ticketsToShow,\n )\n\n for (const ticket of visibleTickets) {\n const dot = renderDot(ticket.status)\n const name = fitLine(ticket.filename, width - 2)\n output += `${dot} ${name}\\n`\n }\n\n // Show \"more below\" indicator if needed\n if (hasMoreBelow) {\n const moreCount = (\n tickets.length -\n (this.viewportStart + ticketsToShow)\n )\n output += ` ... ${moreCount} more below\\n`\n }\n\n renderedTicketCount = (hasMoreAbove ? 1 : 0) +\n visibleTickets.length +\n (hasMoreBelow ? 1 : 0)\n }\n\n output += '-'.repeat(Math.min(SEPARATOR_WIDTH, width)) + '\\n'\n\n const termHeight = this.config.stream.rows ?? 24\n const logRows = Math.max(\n 0,\n termHeight - 2 - renderedTicketCount,\n )\n const visibleMessages = this.messages.slice(-logRows)\n for (const msg of visibleMessages) {\n output += `${fitLine(msg, width)}\\n`\n }\n const emptyRows = logRows - visibleMessages.length\n for (let i = 0; i < emptyRows; i++) {\n output += '\\n'\n }\n\n this.renderedLines = 2 + renderedTicketCount + logRows\n this.config.stream.write(output)\n }\n}\n\nexport class PlainDisplay implements Display {\n startWave (\n waveNum:number,\n _totalWaves:number,\n tickets:ReadonlyArray<{ num:number; filename:string }>,\n progress?:RunProgress,\n _remaining?:ReadonlyArray<{\n num:number\n filename:string\n }>,\n ):void {\n const pct = progress && progress.total > 0 ?\n ` (${progress.completed}/${progress.total} done)` :\n ''\n console.log(\n `\\nWave ${waveNum}${pct}: ` +\n tickets.map(t => t.filename).join(', ')\n )\n }\n\n setTicketStatus (_num:number, _status:TicketStatus):void {\n // no-op: plain mode reports via log()\n }\n\n log (message:string):void {\n console.log(message)\n }\n\n cleanup ():void {\n // no-op\n }\n}\n\nexport function createDisplay (stream?:NodeJS.WriteStream):Display {\n const s = stream ?? process.stdout\n if (s.isTTY) {\n return new StatusDisplay({ stream:s })\n }\n\n return new PlainDisplay()\n}\n", "import { existsSync, readdirSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { select } from '@inquirer/prompts'\n\nexport function getScriptDir (metaUrl:string):string {\n return dirname(fileURLToPath(metaUrl))\n}\n\nexport function findFeatureDirs (cwd:string):{\n name:string;\n dir:string;\n spec:string\n}[] {\n const scratchDir = join(cwd, '.scratch')\n if (!existsSync(scratchDir)) return []\n const entries = readdirSync(\n scratchDir, { withFileTypes:true }\n )\n const results:{ name:string; dir:string; spec:string }[] = []\n for (const entry of entries) {\n if (!entry.isDirectory()) continue\n const issuesDir = join(\n scratchDir, entry.name, 'issues'\n )\n const specFile = join(\n scratchDir, entry.name, 'spec.md'\n )\n if (existsSync(issuesDir)) {\n results.push({\n name:entry.name,\n dir:issuesDir,\n spec:specFile,\n })\n }\n }\n return results\n}\n\nexport async function resolveIssuesDir (\n specName:string|undefined,\n cwd:string = process.cwd(),\n):Promise<{ dir:string; spec:string }> {\n if (specName) {\n const featureDir = join(cwd, '.scratch', specName)\n return {\n dir:join(featureDir, 'issues'),\n spec:join(featureDir, 'spec.md'),\n }\n }\n\n const features = findFeatureDirs(cwd)\n\n if (features.length === 0) {\n console.error(\n 'No .scratch/<feature>/issues/ directories ' +\n 'found.\\nProvide --spec <feature-name>.'\n )\n process.exit(2)\n }\n\n let chosen:typeof features[0]\n if (features.length === 1) {\n chosen = features[0]\n console.log(`Using feature: ${chosen.name}`)\n } else {\n const name = await select({\n message:'Which feature?',\n choices:features.map(f => ({\n name:f.name,\n value:f.name,\n })),\n })\n chosen = features.find(f => f.name === name)!\n }\n\n return { dir:chosen.dir, spec:chosen.spec }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["existsSync", "readFileSync", "dirname", "join", "select", "mkdirSync", "readFileSync", "writeFileSync", "readdirSync", "join", "basename", "join", "existsSync", "join", "existsSync", "execFile", "readFileSync", "writeFileSync", "promisify", "execFileAsync", "promisify", "execFile", "readFileSync", "writeFileSync", "execFile", "promisify", "execFileAsync", "promisify", "execFile", "readdirSync", "join", "readFileSync", "writeFileSync", "basename", "process", "mkdirSync", "remaining", "existsSync", "readdirSync", "dirname", "join", "dirname", "join", "existsSync", "readdirSync", "select", "join", "existsSync", "readFileSync", "dirname"]
7
7
  }
package/dist/meta.json CHANGED
@@ -105,7 +105,7 @@
105
105
  "format": "esm"
106
106
  },
107
107
  "src/display.ts": {
108
- "bytes": 12548,
108
+ "bytes": 12650,
109
109
  "imports": [
110
110
  {
111
111
  "path": "<runtime>",
@@ -269,7 +269,7 @@
269
269
  "imports": [],
270
270
  "exports": [],
271
271
  "inputs": {},
272
- "bytes": 128120
272
+ "bytes": 128292
273
273
  },
274
274
  "dist/index.js": {
275
275
  "imports": [
@@ -429,13 +429,13 @@
429
429
  "bytesInOutput": 4995
430
430
  },
431
431
  "src/display.ts": {
432
- "bytesInOutput": 8226
432
+ "bytesInOutput": 8355
433
433
  },
434
434
  "src/resolve.ts": {
435
435
  "bytesInOutput": 1937
436
436
  }
437
437
  },
438
- "bytes": 61684
438
+ "bytes": 61813
439
439
  }
440
440
  }
441
441
  }
@@ -10,7 +10,6 @@ export type WaveState = {
10
10
  readonly tickets: Array<DisplayTicket>;
11
11
  };
12
12
  export type DisplayConfig = {
13
- readonly messageLines: number;
14
13
  readonly stream: NodeJS.WriteStream;
15
14
  };
16
15
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"display.d.ts","sourceRoot":"","sources":["../../src/display.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAClB,SAAS,GACT,aAAa,GACb,MAAM,GACN,QAAQ,CAAA;AAEd,MAAM,MAAM,aAAa,GAAG;IACxB,QAAQ,CAAC,GAAG,EAAC,MAAM,CAAA;IACnB,QAAQ,CAAC,QAAQ,EAAC,MAAM,CAAA;IACxB,MAAM,EAAC,YAAY,CAAA;CACtB,CAAA;AAED,MAAM,MAAM,SAAS,GAAG;IACpB,QAAQ,CAAC,OAAO,EAAC,MAAM,CAAA;IACvB,QAAQ,CAAC,UAAU,EAAC,MAAM,CAAA;IAC1B,QAAQ,CAAC,OAAO,EAAC,KAAK,CAAC,aAAa,CAAC,CAAA;CACxC,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IACxB,QAAQ,CAAC,YAAY,EAAC,MAAM,CAAA;IAC5B,QAAQ,CAAC,MAAM,EAAC,MAAM,CAAC,WAAW,CAAA;CACrC,CAAA;AAED;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG;IACtB,QAAQ,CAAC,SAAS,EAAC,MAAM,CAAA;IACzB,QAAQ,CAAC,KAAK,EAAC,MAAM,CAAA;CACxB,CAAA;AAED,MAAM,MAAM,OAAO,GAAG;IAClB,SAAS,CACL,OAAO,EAAC,MAAM,EACd,UAAU,EAAC,MAAM,EACjB,OAAO,EAAC,aAAa,CAAC;QAClB,GAAG,EAAC,MAAM,CAAA;QACV,QAAQ,EAAC,MAAM,CAAA;KAClB,CAAC,EACF,QAAQ,CAAC,EAAC,WAAW,EACrB,SAAS,CAAC,EAAC,aAAa,CAAC;QACrB,GAAG,EAAC,MAAM,CAAA;QACV,QAAQ,EAAC,MAAM,CAAA;KAClB,CAAC,GACJ,IAAI,CAAA;IACN,eAAe,CAAC,GAAG,EAAC,MAAM,EAAE,MAAM,EAAC,YAAY,GAAE,IAAI,CAAA;IACrD,GAAG,CAAC,OAAO,EAAC,MAAM,GAAE,IAAI,CAAA;IACxB,OAAO,IAAG,IAAI,CAAA;CACjB,CAAA;AAID,eAAO,MAAM,IAAI;2BACD,MAAM,KAAE,MAAM;6BAGZ,MAAM,KAAE,MAAM;8BAGf,MAAM;6BAGL,MAAM,KAAE,MAAM;+BAQd,MAAM;+BAGN,MAAM;CAGd,CAAA;AAEV,eAAO,MAAM,KAAK;2BACF,MAAM,KAAE,MAAM;4BAGb,MAAM,KAAE,MAAM;yBAGjB,MAAM,KAAE,MAAM;yBAGd,MAAM,KAAE,MAAM;CAGlB,CAAA;AAUV;;;;GAIG;AACH,wBAAgB,OAAO,CAAE,IAAI,EAAC,MAAM,EAAE,KAAK,EAAC,MAAM,GAAE,MAAM,CAIzD;AAED,wBAAgB,SAAS,CAAE,MAAM,EAAC,YAAY,GAAE,MAAM,CAWrD;AAED,qBAAa,aAAc,YAAW,OAAO;IACzC,OAAO,CAAC,IAAI,CAAsB;IAClC,OAAO,CAAC,QAAQ,CAAwB;IACxC,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,QAAQ,CAAmB;IACnC,OAAO,CAAC,aAAa,CAAW;IAChC,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,aAAa,CAAW;IAChC,OAAO,CAAC,cAAc,CAAyB;IAC/C,OAAO,CAAC,aAAa,CAAyB;gBAEjC,MAAM,CAAC,EAAC,QAAQ,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;IAOrD,OAAO,CAAC,gBAAgB;IAOxB,SAAS,CACL,OAAO,EAAC,MAAM,EACd,UAAU,EAAC,MAAM,EACjB,OAAO,EAAC,KAAK,CAAC,QAAQ,CAAC;QAAE,GAAG,EAAC,MAAM,CAAC;QAAC,QAAQ,EAAC,MAAM,CAAA;KAAE,CAAC,CAAC,EACxD,QAAQ,CAAC,EAAC,WAAW,EACrB,SAAS,CAAC,EAAC,aAAa,CAAC;QACrB,GAAG,EAAC,MAAM,CAAA;QACV,QAAQ,EAAC,MAAM,CAAA;KAClB,CAAC,GACJ,IAAI;IA0CN,eAAe,CAAE,GAAG,EAAC,MAAM,EAAE,MAAM,EAAC,YAAY,GAAE,IAAI;IA6BtD,GAAG,CAAE,OAAO,EAAC,MAAM,GAAE,IAAI;IAQzB,OAAO,IAAI,IAAI;IAaf,OAAO,CAAC,MAAM;CA+HjB;AAED,qBAAa,YAAa,YAAW,OAAO;IACxC,SAAS,CACL,OAAO,EAAC,MAAM,EACd,WAAW,EAAC,MAAM,EAClB,OAAO,EAAC,aAAa,CAAC;QAAE,GAAG,EAAC,MAAM,CAAC;QAAC,QAAQ,EAAC,MAAM,CAAA;KAAE,CAAC,EACtD,QAAQ,CAAC,EAAC,WAAW,EACrB,UAAU,CAAC,EAAC,aAAa,CAAC;QACtB,GAAG,EAAC,MAAM,CAAA;QACV,QAAQ,EAAC,MAAM,CAAA;KAClB,CAAC,GACJ,IAAI;IAUN,eAAe,CAAE,IAAI,EAAC,MAAM,EAAE,OAAO,EAAC,YAAY,GAAE,IAAI;IAIxD,GAAG,CAAE,OAAO,EAAC,MAAM,GAAE,IAAI;IAIzB,OAAO,IAAI,IAAI;CAGlB;AAED,wBAAgB,aAAa,CAAE,MAAM,CAAC,EAAC,MAAM,CAAC,WAAW,GAAE,OAAO,CAOjE"}
1
+ {"version":3,"file":"display.d.ts","sourceRoot":"","sources":["../../src/display.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nightralph",
3
- "version": "0.0.18",
3
+ "version": "0.0.19",
4
4
  "type": "module",
5
5
  "description": "Orchestrator that runs a single-agent session per issue.",
6
6
  "bin": {