nightralph 0.0.6 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -25,7 +25,7 @@ so they can't drift as long as you install the skills with this package.
25
25
  * [Install Dependency Skills](#install-dependency-skills)
26
26
  - [Workflow](#workflow)
27
27
  * [Create Issues](#create-issues)
28
- * [Execute Tasks with `nightralph`](#execute-tasks-with-nightralph)
28
+ * [Examples](#examples)
29
29
  - [How It Works](#how-it-works)
30
30
  * [Select a ticket](#select-a-ticket)
31
31
  * [Worktrees](#worktrees)
@@ -104,7 +104,7 @@ The `nightralph` CLI does the `tdd` part of the workflow.
104
104
  >
105
105
 
106
106
 
107
- ### Execute Tasks with `nightralph`
107
+ ### Examples
108
108
 
109
109
  After you have the tickets, use the `nightralph` loop to execute.
110
110
  The `to-tickets` skill produces markdown files at
@@ -114,6 +114,9 @@ The `to-tickets` skill produces markdown files at
114
114
  # Auto-discover .scratch features and run with claude
115
115
  npx nightralph claude -m claude-opus-4-6
116
116
 
117
+ # Run with pi and an OpenRouter model
118
+ npx nightralph pi -m openrouter/z-ai/glm-5.3-flash
119
+
117
120
  # Dry run to inspect the dependency graph and prompt
118
121
  npx nightralph codex --dry-run
119
122
 
@@ -131,7 +134,7 @@ Flags:
131
134
 
132
135
  | Flag | Required | Default | Description |
133
136
  |------|----------|---------|-------------|
134
- | `<provider>` | yes | -- | Agent CLI to spawn (e.g. `claude`, `codex`) |
137
+ | `<provider>` | yes | -- | Agent harness to spawn (e.g. `claude`, `codex`, `pi`) |
135
138
  | `-m`, `--model` | no | -- | Model flag passed to the agent |
136
139
  | `--spec <name>` | no | auto | Feature name (resolves `.scratch/<name>/`) |
137
140
  | `--dry-run` | no | -- | Show wave order and prompt without running |
@@ -161,6 +164,8 @@ Notes:
161
164
  actually be implemented without a permission prompt:
162
165
  * `claude`: `--print --dangerously-skip-permissions`
163
166
  * `codex`: `exec --full-auto`
167
+ * `pi`: `-p --approve --no-session`
168
+ (prompt delivered via temp file, not stdin)
164
169
 
165
170
 
166
171
  ## How It Works
package/dist/index.js CHANGED
@@ -69,7 +69,7 @@ yargs(hideBin(process.argv)).scriptName("nightralph").usage("$0 <command>").comm
69
69
  "Execute tickets with the given provider",
70
70
  (y) => y.positional("provider", {
71
71
  type: "string",
72
- describe: "Agent CLI to spawn (e.g. claude, codex)",
72
+ describe: "Agent CLI to spawn (e.g. claude, codex, pi)",
73
73
  demandOption: true
74
74
  }).option("m", {
75
75
  alias: "model",
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.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 {\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 'setup',\n 'Install bundled skills and doc templates',\n y => y.option('claude', {\n type:'boolean',\n describe:'Also create .claude/skills/ symlinks',\n default:false,\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 (e.g. claude, codex)',\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 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 })\n } else {\n result = await runWaves(\n tickets, specBody,\n argv.provider, argv.model ?? null,\n timeout,\n logsDir,\n )\n }\n\n if (!result.allDone) {\n process.exit(1)\n }\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 {\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 'setup',\n 'Install bundled skills and doc templates',\n y => y.option('claude', {\n type:'boolean',\n describe:'Also create .claude/skills/ symlinks',\n default:false,\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 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 })\n } else {\n result = await runWaves(\n tickets, specBody,\n argv.provider, argv.model ?? null,\n timeout,\n logsDir,\n )\n }\n\n if (!result.allDone) {\n process.exit(1)\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/dist/meta.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "inputs": {
3
3
  "src/index.ts": {
4
- "bytes": 6982,
4
+ "bytes": 7011,
5
5
  "imports": [],
6
6
  "format": "esm"
7
7
  },
8
8
  "src/orchestrator.ts": {
9
- "bytes": 27341,
9
+ "bytes": 30365,
10
10
  "imports": [],
11
11
  "format": "esm"
12
12
  },
@@ -41,7 +41,7 @@
41
41
  "imports": [],
42
42
  "exports": [],
43
43
  "inputs": {},
44
- "bytes": 10910
44
+ "bytes": 10940
45
45
  },
46
46
  "dist/index.js": {
47
47
  "imports": [
@@ -98,16 +98,16 @@
98
98
  "entryPoint": "src/index.ts",
99
99
  "inputs": {
100
100
  "src/index.ts": {
101
- "bytesInOutput": 5223
101
+ "bytesInOutput": 5227
102
102
  }
103
103
  },
104
- "bytes": 5456
104
+ "bytes": 5460
105
105
  },
106
106
  "dist/orchestrator.js.map": {
107
107
  "imports": [],
108
108
  "exports": [],
109
109
  "inputs": {},
110
- "bytes": 42564
110
+ "bytes": 47352
111
111
  },
112
112
  "dist/orchestrator.js": {
113
113
  "imports": [
@@ -121,6 +121,11 @@
121
121
  "kind": "import-statement",
122
122
  "external": true
123
123
  },
124
+ {
125
+ "path": "node:os",
126
+ "kind": "import-statement",
127
+ "external": true
128
+ },
124
129
  {
125
130
  "path": "node:path",
126
131
  "kind": "import-statement",
@@ -149,6 +154,7 @@
149
154
  ],
150
155
  "exports": [
151
156
  "TICKET_RE",
157
+ "createPiStreamFormatter",
152
158
  "dryRun",
153
159
  "dryRunIsolated",
154
160
  "findReadyTickets",
@@ -168,10 +174,10 @@
168
174
  "entryPoint": "src/orchestrator.ts",
169
175
  "inputs": {
170
176
  "src/orchestrator.ts": {
171
- "bytesInOutput": 21007
177
+ "bytesInOutput": 23243
172
178
  }
173
179
  },
174
- "bytes": 21454
180
+ "bytes": 23717
175
181
  },
176
182
  "dist/setup.js.map": {
177
183
  "imports": [],
@@ -6,8 +6,10 @@ import {
6
6
  mkdirSync,
7
7
  readFileSync,
8
8
  writeFileSync,
9
+ unlinkSync,
9
10
  readdirSync
10
11
  } from "node:fs";
12
+ import { tmpdir } from "node:os";
11
13
  import { join, dirname, basename } from "node:path";
12
14
  import { createInterface } from "node:readline";
13
15
  import {
@@ -201,7 +203,15 @@ const PROVIDER_ARGS = {
201
203
  "stream-json",
202
204
  "--dangerously-skip-permissions"
203
205
  ],
204
- codex: ["exec", "--full-auto"]
206
+ codex: ["exec", "--full-auto"],
207
+ pi: [
208
+ "-p",
209
+ "--verbose",
210
+ "--approve",
211
+ "--no-session",
212
+ "--mode",
213
+ "json"
214
+ ]
205
215
  };
206
216
  function getProviderArgs(cmd) {
207
217
  const name = basename(cmd);
@@ -242,6 +252,64 @@ function formatStreamLine(line) {
242
252
  return null;
243
253
  }
244
254
  __name(formatStreamLine, "formatStreamLine");
255
+ function createPiStreamFormatter() {
256
+ const calls = /* @__PURE__ */ new Map();
257
+ return (line) => {
258
+ let obj;
259
+ try {
260
+ obj = JSON.parse(line);
261
+ } catch {
262
+ return line;
263
+ }
264
+ const evt = obj.assistantMessageEvent;
265
+ if (!evt) return null;
266
+ const type = evt.type;
267
+ const ci = evt.contentIndex ?? -1;
268
+ if (type === "text_delta") {
269
+ return evt.delta ?? null;
270
+ }
271
+ if (type === "toolcall_start") {
272
+ calls.set(ci, {
273
+ name: evt.toolName ?? "?",
274
+ buf: ""
275
+ });
276
+ return null;
277
+ }
278
+ if (type === "toolcall_delta" && calls.has(ci)) {
279
+ calls.get(ci).buf += evt.delta ?? "";
280
+ return null;
281
+ }
282
+ if (type === "toolcall_end" && calls.has(ci)) {
283
+ const call = calls.get(ci);
284
+ calls.delete(ci);
285
+ let label = "";
286
+ try {
287
+ const args = JSON.parse(call.buf);
288
+ label = String(
289
+ args.command ?? args.file_path ?? args.query ?? ""
290
+ ).split("\n")[0].slice(0, 72);
291
+ } catch {
292
+ }
293
+ return `[${call.name}] ${label}`;
294
+ }
295
+ return null;
296
+ };
297
+ }
298
+ __name(createPiStreamFormatter, "createPiStreamFormatter");
299
+ function writePromptFile(prompt) {
300
+ const name = `nightralph-${Date.now()}-${Math.random().toString(36).slice(2)}.md`;
301
+ const filePath = join(tmpdir(), name);
302
+ writeFileSync(filePath, prompt);
303
+ return filePath;
304
+ }
305
+ __name(writePromptFile, "writePromptFile");
306
+ function cleanupPromptFile(filePath) {
307
+ try {
308
+ unlinkSync(filePath);
309
+ } catch {
310
+ }
311
+ }
312
+ __name(cleanupPromptFile, "cleanupPromptFile");
245
313
  function spawnAgent(opts) {
246
314
  const args = [
247
315
  ...getProviderArgs(opts.agentCmd)
@@ -249,8 +317,15 @@ function spawnAgent(opts) {
249
317
  if (opts.model) {
250
318
  args.push("--model", opts.model);
251
319
  }
252
- const isClaude = basename(opts.agentCmd) === "claude";
320
+ const providerName = basename(opts.agentCmd);
321
+ const isClaude = providerName === "claude";
322
+ const isPi = providerName === "pi";
253
323
  const prefix = opts.label ? ` [${opts.label}] ` : " ";
324
+ let promptFile = null;
325
+ if (isPi) {
326
+ promptFile = writePromptFile(opts.prompt);
327
+ args.push(`@${promptFile}`);
328
+ }
254
329
  const logStream = createWriteStream(
255
330
  opts.logPath,
256
331
  { flags: "w" }
@@ -260,6 +335,7 @@ function spawnAgent(opts) {
260
335
  cwd: opts.cwd
261
336
  });
262
337
  proc.stdout.pipe(logStream);
338
+ const piFormatter = isPi ? createPiStreamFormatter() : null;
263
339
  const rl = createInterface({ input: proc.stdout });
264
340
  rl.on("line", (line) => {
265
341
  if (isClaude) {
@@ -267,6 +343,11 @@ function spawnAgent(opts) {
267
343
  if (formatted !== null) {
268
344
  console.log(`${prefix}${formatted}`);
269
345
  }
346
+ } else if (piFormatter) {
347
+ const formatted = piFormatter(line);
348
+ if (formatted !== null) {
349
+ console.log(`${prefix}${formatted}`);
350
+ }
270
351
  } else {
271
352
  console.log(`${prefix}${line}`);
272
353
  }
@@ -284,7 +365,9 @@ function spawnAgent(opts) {
284
365
  proc.kill("SIGKILL");
285
366
  }
286
367
  }, opts.timeout * 1e3);
287
- proc.stdin.write(opts.prompt);
368
+ if (!promptFile) {
369
+ proc.stdin.write(opts.prompt);
370
+ }
288
371
  proc.stdin.end();
289
372
  return new Promise((resolve) => {
290
373
  proc.on("close", (code) => {
@@ -292,6 +375,7 @@ function spawnAgent(opts) {
292
375
  rl.close();
293
376
  rlErr.close();
294
377
  logStream.end();
378
+ if (promptFile) cleanupPromptFile(promptFile);
295
379
  resolve(code ?? 1);
296
380
  });
297
381
  proc.on("error", (err) => {
@@ -299,6 +383,7 @@ function spawnAgent(opts) {
299
383
  rl.close();
300
384
  rlErr.close();
301
385
  logStream.end();
386
+ if (promptFile) cleanupPromptFile(promptFile);
302
387
  console.error(
303
388
  "Agent process error:",
304
389
  formatErrorMessage(err)
@@ -761,6 +846,7 @@ Finished: ${totalCompleted} completed` + (remaining.length > 0 ? `, ${remaining.
761
846
  __name(runWavesIsolated, "runWavesIsolated");
762
847
  export {
763
848
  TICKET_RE,
849
+ createPiStreamFormatter,
764
850
  dryRun,
765
851
  dryRunIsolated,
766
852
  findReadyTickets,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/orchestrator.ts"],
4
- "sourcesContent": ["import { spawn } from 'node:child_process'\nimport {\n createWriteStream,\n mkdirSync,\n readFileSync,\n writeFileSync,\n readdirSync,\n} from 'node:fs'\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'\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 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 '',\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}\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 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}):Promise<number> {\n const args:string[] = [\n ...getProviderArgs(opts.agentCmd),\n ]\n if (opts.model) {\n args.push('--model', opts.model)\n }\n\n const isClaude = basename(opts.agentCmd) === 'claude'\n const prefix = opts.label ?\n ` [${opts.label}] ` :\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 rl = createInterface({ input:proc.stdout })\n rl.on('line', line => {\n if (isClaude) {\n const formatted = formatStreamLine(line)\n if (formatted !== null) {\n console.log(`${prefix}${formatted}`)\n }\n } else {\n console.log(`${prefix}${line}`)\n }\n })\n\n proc.stderr.pipe(logStream)\n const rlErr = createInterface({ input:proc.stderr })\n rlErr.on('line', line => {\n console.error(`${prefix}${line}`)\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 proc.stdin.write(opts.prompt)\n proc.stdin.end()\n\n return new Promise<number>(resolve => {\n proc.on('close', code => {\n clearTimeout(timeout)\n rl.close()\n rlErr.close()\n logStream.end()\n resolve(code ?? 1)\n })\n proc.on('error', err => {\n clearTimeout(timeout)\n rl.close()\n rlErr.close()\n logStream.end()\n console.error(\n 'Agent process error:',\n formatErrorMessage(err)\n )\n resolve(1)\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}):Promise<boolean> {\n await updateWorktreeFromBase(\n opts.worktreePath, opts.baseBranch\n )\n\n console.log(\n ` ${opts.ticket.filename}: respawning agent ` +\n 'to resolve merge conflict'\n )\n const prompt = renderPrompt(opts.specBody, opts.ticket)\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 exitCode = 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 })\n\n if (exitCode !== 0) {\n console.log(\n ` ${opts.ticket.filename}: respawned agent ` +\n `exited ${exitCode}`\n )\n return false\n }\n\n const merged = await mergeBranch(\n opts.repoRoot, opts.branch\n )\n if (!merged) {\n console.log(\n ` ${opts.ticket.filename}: merge still ` +\n 'conflicted after respawn'\n )\n }\n return merged\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):Promise<{ allDone:boolean }> {\n mkdirSync(logsDir, { recursive:true })\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 console.log(\n `\\nWave ${waveNum}: ` +\n ready.map(t => t.filename).join(', ')\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 console.log(` Starting ${t.filename}`)\n const code = await spawnAgent({\n prompt,\n agentCmd,\n model,\n timeout,\n logPath,\n label,\n })\n return { ticket:t, exitCode:code }\n })\n )\n\n let waveCompleted = 0\n for (const r of results) {\n if (r.status === 'rejected') continue\n const { ticket, exitCode } = r.value\n if (exitCode !== 0) {\n console.log(\n ` ${ticket.filename}: ` +\n `agent exited ${exitCode}`\n )\n continue\n }\n\n markDone(ticket)\n waveCompleted++\n totalCompleted++\n console.log(\n ` ${ticket.filename}: done`\n )\n }\n\n if (waveCompleted === 0) {\n console.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 console.log(\n `\\nFinished: ${totalCompleted} completed` +\n (remaining.length > 0 ?\n `, ${remaining.length} remaining` :\n '')\n )\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}):Promise<{ allDone:boolean }> {\n mkdirSync(opts.logsDir, { recursive:true })\n\n const repoRoot = getRepoRoot()\n const repoName = getRepoName()\n const baseBranch = getCurrentBranch()\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 console.log(\n `\\nWave ${waveNum}: ` +\n ready.map(t => t.filename).join(', ')\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 console.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 console.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 })\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 exitCode = r.value\n const ticket = activeTickets[i]\n const worktree = worktrees[i]\n\n if (exitCode !== 0) {\n console.log(\n ` ${ticket.filename}: ` +\n `agent exited ${exitCode}`\n )\n checkTicket(progress, ticket.num, {\n branch:worktree.branchName,\n 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 console.error(\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 console.log(\n ` ${ticket.filename}: ` +\n 'auto-committed remaining changes'\n )\n }\n }\n\n if (!hasNewCommits(\n repoRoot, baseBranch, worktree.branchName\n )) {\n console.log(\n ` ${ticket.filename}: agent exited 0 ` +\n 'but made no changes; leaving ticket ' +\n 'ready-for-agent'\n )\n continue\n }\n\n console.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 console.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 console.error(\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 }) :\n false\n\n if (recovered) {\n markDone(ticket)\n waveCompleted++\n totalCompleted++\n console.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 console.error(\n ' Failed to remove worktree ' +\n `${worktreePath}: ` +\n formatErrorMessage(err)\n )\n }\n }\n } else {\n console.log(\n ` ${ticket.filename}: merge failed, ` +\n 'staying ready-for-agent'\n )\n }\n }\n }\n\n if (mergeResult.stoppedAt) {\n console.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 console.error(\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 console.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 console.log(\n `\\nFinished: ${totalCompleted} completed` +\n (remaining.length > 0 ?\n `, ${remaining.length} remaining` :\n '')\n )\n\n return { allDone:remaining.length === 0 }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["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'\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 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 '',\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 function createPiStreamFormatter ():((line:string) => string|null) {\n const calls = new Map<number, { name:string; buf:string }>()\n\n return (line:string):string|null => {\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 null\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 return (evt.delta as string|undefined) ??\n null\n }\n\n if (type === 'toolcall_start') {\n calls.set(ci, {\n name:(evt.toolName as\n string|undefined) ?? '?',\n buf:'',\n })\n return null\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 null\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 null\n }\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 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}):Promise<number> {\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 rl = createInterface({ input:proc.stdout })\n rl.on('line', line => {\n if (isClaude) {\n const formatted = formatStreamLine(line)\n if (formatted !== null) {\n console.log(`${prefix}${formatted}`)\n }\n } else if (piFormatter) {\n const formatted = piFormatter(line)\n if (formatted !== null) {\n console.log(`${prefix}${formatted}`)\n }\n } else {\n console.log(`${prefix}${line}`)\n }\n })\n\n proc.stderr.pipe(logStream)\n const rlErr = createInterface({ input:proc.stderr })\n rlErr.on('line', line => {\n console.error(`${prefix}${line}`)\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<number>(resolve => {\n proc.on('close', code => {\n clearTimeout(timeout)\n rl.close()\n rlErr.close()\n logStream.end()\n if (promptFile) cleanupPromptFile(promptFile)\n resolve(code ?? 1)\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(1)\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}):Promise<boolean> {\n await updateWorktreeFromBase(\n opts.worktreePath, opts.baseBranch\n )\n\n console.log(\n ` ${opts.ticket.filename}: respawning agent ` +\n 'to resolve merge conflict'\n )\n const prompt = renderPrompt(opts.specBody, opts.ticket)\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 exitCode = 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 })\n\n if (exitCode !== 0) {\n console.log(\n ` ${opts.ticket.filename}: respawned agent ` +\n `exited ${exitCode}`\n )\n return false\n }\n\n const merged = await mergeBranch(\n opts.repoRoot, opts.branch\n )\n if (!merged) {\n console.log(\n ` ${opts.ticket.filename}: merge still ` +\n 'conflicted after respawn'\n )\n }\n return merged\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):Promise<{ allDone:boolean }> {\n mkdirSync(logsDir, { recursive:true })\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 console.log(\n `\\nWave ${waveNum}: ` +\n ready.map(t => t.filename).join(', ')\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 console.log(` Starting ${t.filename}`)\n const code = await spawnAgent({\n prompt,\n agentCmd,\n model,\n timeout,\n logPath,\n label,\n })\n return { ticket:t, exitCode:code }\n })\n )\n\n let waveCompleted = 0\n for (const r of results) {\n if (r.status === 'rejected') continue\n const { ticket, exitCode } = r.value\n if (exitCode !== 0) {\n console.log(\n ` ${ticket.filename}: ` +\n `agent exited ${exitCode}`\n )\n continue\n }\n\n markDone(ticket)\n waveCompleted++\n totalCompleted++\n console.log(\n ` ${ticket.filename}: done`\n )\n }\n\n if (waveCompleted === 0) {\n console.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 console.log(\n `\\nFinished: ${totalCompleted} completed` +\n (remaining.length > 0 ?\n `, ${remaining.length} remaining` :\n '')\n )\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}):Promise<{ allDone:boolean }> {\n mkdirSync(opts.logsDir, { recursive:true })\n\n const repoRoot = getRepoRoot()\n const repoName = getRepoName()\n const baseBranch = getCurrentBranch()\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 console.log(\n `\\nWave ${waveNum}: ` +\n ready.map(t => t.filename).join(', ')\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 console.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 console.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 })\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 exitCode = r.value\n const ticket = activeTickets[i]\n const worktree = worktrees[i]\n\n if (exitCode !== 0) {\n console.log(\n ` ${ticket.filename}: ` +\n `agent exited ${exitCode}`\n )\n checkTicket(progress, ticket.num, {\n branch:worktree.branchName,\n 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 console.error(\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 console.log(\n ` ${ticket.filename}: ` +\n 'auto-committed remaining changes'\n )\n }\n }\n\n if (!hasNewCommits(\n repoRoot, baseBranch, worktree.branchName\n )) {\n console.log(\n ` ${ticket.filename}: agent exited 0 ` +\n 'but made no changes; leaving ticket ' +\n 'ready-for-agent'\n )\n continue\n }\n\n console.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 console.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 console.error(\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 }) :\n false\n\n if (recovered) {\n markDone(ticket)\n waveCompleted++\n totalCompleted++\n console.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 console.error(\n ' Failed to remove worktree ' +\n `${worktreePath}: ` +\n formatErrorMessage(err)\n )\n }\n }\n } else {\n console.log(\n ` ${ticket.filename}: merge failed, ` +\n 'staying ready-for-agent'\n )\n }\n }\n }\n\n if (mergeResult.stoppedAt) {\n console.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 console.error(\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 console.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 console.log(\n `\\nFinished: ${totalCompleted} completed` +\n (remaining.length > 0 ?\n `, ${remaining.length} remaining` :\n '')\n )\n\n return { allDone:remaining.length === 0 }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -22,6 +22,7 @@ export declare function markDone(ticket: Ticket): void;
22
22
  export declare function renderPrompt(specBody: string, ticket: Ticket): string;
23
23
  export declare function getProviderArgs(cmd: string): string[];
24
24
  export declare function formatStreamLine(line: string): string | null;
25
+ export declare function createPiStreamFormatter(): ((line: string) => string | null);
25
26
  export declare function spawnAgent(opts: {
26
27
  prompt: string;
27
28
  agentCmd: string;
@@ -1 +1 @@
1
- {"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../src/orchestrator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../src/orchestrator.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.6",
3
+ "version": "0.0.8",
4
4
  "type": "module",
5
5
  "description": "Orchestrator that runs a single-agent session per issue.",
6
6
  "bin": {