nightralph 0.0.5 → 0.0.7
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 +10 -5
- package/dist/index.js +1 -1
- package/dist/index.js.map +2 -2
- package/dist/meta.json +19 -12
- package/dist/orchestrator.js +129 -33
- package/dist/orchestrator.js.map +2 -2
- package/dist/src/orchestrator.d.ts +1 -0
- package/dist/src/orchestrator.d.ts.map +1 -1
- package/dist/src/worktree.d.ts +1 -0
- package/dist/src/worktree.d.ts.map +1 -1
- package/dist/worktree.js +24 -0
- package/dist/worktree.js.map +2 -2
- package/package.json +1 -1
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
|
-
* [
|
|
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
|
-
###
|
|
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,16 +134,16 @@ Flags:
|
|
|
131
134
|
|
|
132
135
|
| Flag | Required | Default | Description |
|
|
133
136
|
|------|----------|---------|-------------|
|
|
134
|
-
| `<provider>` | yes | -- | Agent
|
|
137
|
+
| `<provider>` | yes | -- | Agent harness to spawn (e.g. `claude`, `codex`, `pi`) |
|
|
135
138
|
| `-m`, `--model` | no | -- | Model flag passed to the agent |
|
|
136
|
-
| `--spec
|
|
139
|
+
| `--spec <name>` | no | auto | Feature name (resolves `.scratch/<name>/`) |
|
|
137
140
|
| `--dry-run` | no | -- | Show wave order and prompt without running |
|
|
138
141
|
| `-X` | no | -- | Stop on merge conflict instead of re-spawning |
|
|
139
142
|
| `--timeout` | no | `300` | Kill agent after N seconds |
|
|
140
143
|
|
|
141
144
|
Notes:
|
|
142
145
|
|
|
143
|
-
* When `--spec
|
|
146
|
+
* When `--spec <name>` is omitted, the CLI looks for
|
|
144
147
|
`.scratch/<feature>/issues/` directories. If multiple features exist,
|
|
145
148
|
**it prompts you to pick one** with an interactive selector.
|
|
146
149
|
* Tickets are selected by `**Status:** ready-for-agent` in the file body.
|
|
@@ -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": ";;;AAEA,SAAS,YAAY,oBAAoB;AACzC,SAAS,SAAS,YAAY;AAC9B,OAAO,WAAW;AAClB,SAAS,eAAe;AACxB,SAAS,cAAc;AACvB,SAAS,OAAO,mBAAqC;AACrD;AAAA,EACI;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACG;AACP;AAAA,EACI;AAAA,EACA;AAAA,EACA;AAAA,OACG;AACP,SAAS,aAAa,mBAAmB;AAIzC,MAAM,YAAY,aAAa,YAAY,GAAG;AAE9C,MAAM,QAAQ,QAAQ,IAAI,CAAC,EACtB,WAAW,YAAY,EACvB,MAAM,cAAc,EACpB;AAAA,EACG;AAAA,EACA;AAAA,EACA,OAAK,EAAE,OAAO,UAAU;AAAA,IACpB,MAAK;AAAA,IACL,UAAS;AAAA,IACT,SAAQ;AAAA,EACZ,CAAC;AAAA,EACD,OAAM,SAAQ;AACV,UAAM,UAAU,MAAM,OAAoB;AAAA,MACtC,SAAQ;AAAA,MACR,SAAQ;AAAA,QACJ;AAAA,UACI,MAAK;AAAA,UACL,OAAM;AAAA,UACN,aAAY;AAAA,QAEhB;AAAA,QACA;AAAA,UACI,MAAK;AAAA,UACL,OAAM;AAAA,UACN,aAAY;AAAA,QAChB;AAAA,MACJ;AAAA,IACJ,CAAC;AAED,QAAI,YAAY,UAAU;AACtB,UAAI,CAAC,YAAY,GAAG;AAChB,gBAAQ;AAAA,UACJ;AAAA,QAIJ;AACA,gBAAQ,KAAK,CAAC;AAAA,MAClB;AAAA,IACJ;AAEA,UAAM;AAAA,MACF,kBAAiB,KAAK,WAAW,QAAQ;AAAA,MACzC,kBAAiB;AAAA,QACb;AAAA,QAAW;AAAA,MACf;AAAA,MACA,YAAW,QAAQ,IAAI;AAAA,MACvB,QAAO,KAAK;AAAA,MACZ;AAAA,IACJ,CAAC;AAAA,EACL;AACJ,EACC;AAAA,EACG;AAAA,EACA;AAAA,EACA,OAAK,EACA,WAAW,YAAY;AAAA,IACpB,MAAK;AAAA,IACL,UAAS;AAAA,
|
|
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": ";;;AAEA,SAAS,YAAY,oBAAoB;AACzC,SAAS,SAAS,YAAY;AAC9B,OAAO,WAAW;AAClB,SAAS,eAAe;AACxB,SAAS,cAAc;AACvB,SAAS,OAAO,mBAAqC;AACrD;AAAA,EACI;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACG;AACP;AAAA,EACI;AAAA,EACA;AAAA,EACA;AAAA,OACG;AACP,SAAS,aAAa,mBAAmB;AAIzC,MAAM,YAAY,aAAa,YAAY,GAAG;AAE9C,MAAM,QAAQ,QAAQ,IAAI,CAAC,EACtB,WAAW,YAAY,EACvB,MAAM,cAAc,EACpB;AAAA,EACG;AAAA,EACA;AAAA,EACA,OAAK,EAAE,OAAO,UAAU;AAAA,IACpB,MAAK;AAAA,IACL,UAAS;AAAA,IACT,SAAQ;AAAA,EACZ,CAAC;AAAA,EACD,OAAM,SAAQ;AACV,UAAM,UAAU,MAAM,OAAoB;AAAA,MACtC,SAAQ;AAAA,MACR,SAAQ;AAAA,QACJ;AAAA,UACI,MAAK;AAAA,UACL,OAAM;AAAA,UACN,aAAY;AAAA,QAEhB;AAAA,QACA;AAAA,UACI,MAAK;AAAA,UACL,OAAM;AAAA,UACN,aAAY;AAAA,QAChB;AAAA,MACJ;AAAA,IACJ,CAAC;AAED,QAAI,YAAY,UAAU;AACtB,UAAI,CAAC,YAAY,GAAG;AAChB,gBAAQ;AAAA,UACJ;AAAA,QAIJ;AACA,gBAAQ,KAAK,CAAC;AAAA,MAClB;AAAA,IACJ;AAEA,UAAM;AAAA,MACF,kBAAiB,KAAK,WAAW,QAAQ;AAAA,MACzC,kBAAiB;AAAA,QACb;AAAA,QAAW;AAAA,MACf;AAAA,MACA,YAAW,QAAQ,IAAI;AAAA,MACvB,QAAO,KAAK;AAAA,MACZ;AAAA,IACJ,CAAC;AAAA,EACL;AACJ,EACC;AAAA,EACG;AAAA,EACA;AAAA,EACA,OAAK,EACA,WAAW,YAAY;AAAA,IACpB,MAAK;AAAA,IACL,UAAS;AAAA,IAET,cAAa;AAAA,EACjB,CAAC,EACA,OAAO,KAAK;AAAA,IACT,OAAM;AAAA,IACN,MAAK;AAAA,IACL,UAAS;AAAA,EACb,CAAC,EACA,OAAO,QAAQ;AAAA,IACZ,MAAK;AAAA,IACL,UAAS;AAAA,EAEb,CAAC,EACA,OAAO,WAAW;AAAA,IACf,MAAK;AAAA,IACL,UAAS;AAAA,IACT,SAAQ;AAAA,EACZ,CAAC,EACA,OAAO,WAAW;AAAA,IACf,MAAK;AAAA,IACL,UAAS;AAAA,IACT,SAAQ;AAAA,EACZ,CAAC,EACA,OAAO,KAAK;AAAA,IACT,MAAK;AAAA,IACL,UAAS;AAAA,IAET,SAAQ;AAAA,EACZ,CAAC;AAAA,EACL,OAAM,SAAQ;AACV,UAAM,WAAW;AAAA,MACb,UAAS,KAAK;AAAA,MACd,OAAM,KAAK;AAAA,MACX,MAAK,KAAK;AAAA,MACV,QAAO,KAAK;AAAA,MACZ,SAAQ,KAAK;AAAA,MAEb,gBAAe,KAAK;AAAA,IAExB,CAAC;AAAA,EACL;AACJ,EACC,OAAO,EACP,cAAc,GAAG,+BAA+B,EAChD,KAAK,EACL,MAAM;AAEX,SAAS,YAAqB;AAC1B,MAAI;AACA,gBAAY;AACZ,WAAO;AAAA,EACX,QAAQ;AACJ,WAAO;AAAA,EACX;AACJ;AAPS;AAST,SAAS,mBAAoB,MAAoB;AAC7C,QAAM,QAAQ,KAAK;AAAA,IACf;AAAA,EACJ;AACA,QAAM,eAAe,MAAM,QAAQ,UAAU;AAC7C,MAAI,gBAAgB,KAAK,eAAe,MAAM,SAAS,GAAG;AACtD,WAAO,MAAM,eAAe,CAAC;AAAA,EACjC;AACA,SAAO,MAAM,MAAM,SAAS,CAAC,KACzB,MAAM,MAAM,SAAS,CAAC,KAAK;AACnC;AAVS;AAYT,eAAe,WAAY,MAOV;AACb,QAAM,EAAE,KAAK,KAAK,IAAI,MAAM;AAAA,IACxB,KAAK;AAAA,EACT;AAEA,MAAI,CAAC,WAAW,GAAG,GAAG;AAClB,YAAQ,MAAM,wBAAwB,GAAG,EAAE;AAC3C,YAAQ,KAAK,CAAC;AAAA,EAClB;AACA,MAAI,CAAC,WAAW,IAAI,GAAG;AACnB,YAAQ,MAAM,wBAAwB,IAAI,EAAE;AAC5C,YAAQ,KAAK,CAAC;AAAA,EAClB;AAEA,QAAM,WAAW,aAAa,MAAM,MAAM;AAC1C,QAAM,UAAU,YAAY,GAAG;AAE/B,MAAI,QAAQ,WAAW,GAAG;AACtB,YAAQ,IAAI,iCAAiC;AAC7C;AAAA,EACJ;AAEA,UAAQ,IAAI,SAAS,QAAQ,MAAM,UAAU;AAE7C,QAAM,YAAY,IAAI,IAAI,QAAQ,IAAI,OAAK,EAAE,GAAG,CAAC;AACjD,aAAW,KAAK,SAAS;AACrB,UAAM,UAAU,EAAE,SAAS;AAAA,MACvB,OAAK,CAAC,UAAU,IAAI,CAAC;AAAA,IACzB;AACA,QAAI,QAAQ,SAAS,GAAG;AACpB,cAAQ;AAAA,QACJ,GAAG,EAAE,QAAQ,eACT,QAAQ,KAAK,IAAI,CAAC;AAAA,MAE1B;AAAA,IACJ;AACA,MAAE,WAAW,EAAE,SAAS;AAAA,MACpB,OAAK,UAAU,IAAI,CAAC;AAAA,IACxB;AAAA,EACJ;AAEA,QAAM,UAAU,KAAK,QAAQ,GAAG,GAAG,MAAM;AACzC,QAAM,UAAU,KAAK,WAAW;AAChC,QAAM,cAAc,mBAAmB,IAAI;AAC3C,QAAM,mBAAmB,KAAK,iBAC1B,SACA;AACJ,QAAM,eAAe;AAAA,IACjB,QAAQ,GAAG;AAAA,IAAG;AAAA,EAClB;AAEA,MAAI,KAAK,QAAQ;AACb,QAAI,UAAU,GAAG;AACb,YAAM,WAAW,YAAY;AAC7B,qBAAe;AAAA,QACX;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACJ,CAAC;AAAA,IACL,OAAO;AACH,aAAO,SAAS,QAAQ;AAAA,IAC5B;AACA;AAAA,EACJ;AAEA,MAAI;AAEJ,MAAI,UAAU,GAAG;AACb,aAAS,MAAM,iBAAiB;AAAA,MAC5B;AAAA,MACA;AAAA,MACA,UAAS,KAAK;AAAA,MACd,OAAM,KAAK,SAAS;AAAA,MACpB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACJ,CAAC;AAAA,EACL,OAAO;AACH,aAAS,MAAM;AAAA,MACX;AAAA,MAAS;AAAA,MACT,KAAK;AAAA,MAAU,KAAK,SAAS;AAAA,MAC7B;AAAA,MACA;AAAA,IACJ;AAAA,EACJ;AAEA,MAAI,CAAC,OAAO,SAAS;AACjB,YAAQ,KAAK,CAAC;AAAA,EAClB;AACJ;AAnGe;",
|
|
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":
|
|
4
|
+
"bytes": 7011,
|
|
5
5
|
"imports": [],
|
|
6
6
|
"format": "esm"
|
|
7
7
|
},
|
|
8
8
|
"src/orchestrator.ts": {
|
|
9
|
-
"bytes":
|
|
9
|
+
"bytes": 30428,
|
|
10
10
|
"imports": [],
|
|
11
11
|
"format": "esm"
|
|
12
12
|
},
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"format": "esm"
|
|
22
22
|
},
|
|
23
23
|
"src/worktree.ts": {
|
|
24
|
-
"bytes":
|
|
24
|
+
"bytes": 4464,
|
|
25
25
|
"imports": [],
|
|
26
26
|
"format": "esm"
|
|
27
27
|
},
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"imports": [],
|
|
42
42
|
"exports": [],
|
|
43
43
|
"inputs": {},
|
|
44
|
-
"bytes":
|
|
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":
|
|
101
|
+
"bytesInOutput": 5227
|
|
102
102
|
}
|
|
103
103
|
},
|
|
104
|
-
"bytes":
|
|
104
|
+
"bytes": 5460
|
|
105
105
|
},
|
|
106
106
|
"dist/orchestrator.js.map": {
|
|
107
107
|
"imports": [],
|
|
108
108
|
"exports": [],
|
|
109
109
|
"inputs": {},
|
|
110
|
-
"bytes":
|
|
110
|
+
"bytes": 47439
|
|
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":
|
|
177
|
+
"bytesInOutput": 23279
|
|
172
178
|
}
|
|
173
179
|
},
|
|
174
|
-
"bytes":
|
|
180
|
+
"bytes": 23753
|
|
175
181
|
},
|
|
176
182
|
"dist/setup.js.map": {
|
|
177
183
|
"imports": [],
|
|
@@ -258,7 +264,7 @@
|
|
|
258
264
|
"imports": [],
|
|
259
265
|
"exports": [],
|
|
260
266
|
"inputs": {},
|
|
261
|
-
"bytes":
|
|
267
|
+
"bytes": 7323
|
|
262
268
|
},
|
|
263
269
|
"dist/worktree.js": {
|
|
264
270
|
"imports": [
|
|
@@ -284,6 +290,7 @@
|
|
|
284
290
|
}
|
|
285
291
|
],
|
|
286
292
|
"exports": [
|
|
293
|
+
"commitDirty",
|
|
287
294
|
"createWorktree",
|
|
288
295
|
"getCurrentBranch",
|
|
289
296
|
"getRepoName",
|
|
@@ -296,10 +303,10 @@
|
|
|
296
303
|
"entryPoint": "src/worktree.ts",
|
|
297
304
|
"inputs": {
|
|
298
305
|
"src/worktree.ts": {
|
|
299
|
-
"bytesInOutput":
|
|
306
|
+
"bytesInOutput": 3507
|
|
300
307
|
}
|
|
301
308
|
},
|
|
302
|
-
"bytes":
|
|
309
|
+
"bytes": 3830
|
|
303
310
|
},
|
|
304
311
|
"dist/progress.js.map": {
|
|
305
312
|
"imports": [],
|
package/dist/orchestrator.js
CHANGED
|
@@ -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 {
|
|
@@ -17,7 +19,8 @@ import {
|
|
|
17
19
|
createWorktree,
|
|
18
20
|
removeWorktree,
|
|
19
21
|
hasNewCommits,
|
|
20
|
-
isDirty
|
|
22
|
+
isDirty,
|
|
23
|
+
commitDirty
|
|
21
24
|
} from "./worktree.js";
|
|
22
25
|
import {
|
|
23
26
|
generateProgress,
|
|
@@ -200,7 +203,15 @@ const PROVIDER_ARGS = {
|
|
|
200
203
|
"stream-json",
|
|
201
204
|
"--dangerously-skip-permissions"
|
|
202
205
|
],
|
|
203
|
-
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
|
+
]
|
|
204
215
|
};
|
|
205
216
|
function getProviderArgs(cmd) {
|
|
206
217
|
const name = basename(cmd);
|
|
@@ -241,6 +252,66 @@ function formatStreamLine(line) {
|
|
|
241
252
|
return null;
|
|
242
253
|
}
|
|
243
254
|
__name(formatStreamLine, "formatStreamLine");
|
|
255
|
+
function createPiStreamFormatter() {
|
|
256
|
+
const calls = /* @__PURE__ */ new Map();
|
|
257
|
+
let toolNum = 0;
|
|
258
|
+
return (line) => {
|
|
259
|
+
let obj;
|
|
260
|
+
try {
|
|
261
|
+
obj = JSON.parse(line);
|
|
262
|
+
} catch {
|
|
263
|
+
return line;
|
|
264
|
+
}
|
|
265
|
+
const evt = obj.assistantMessageEvent;
|
|
266
|
+
if (!evt) return null;
|
|
267
|
+
const type = evt.type;
|
|
268
|
+
const ci = evt.contentIndex ?? -1;
|
|
269
|
+
if (type === "text_delta") {
|
|
270
|
+
return evt.delta ?? null;
|
|
271
|
+
}
|
|
272
|
+
if (type === "toolcall_start") {
|
|
273
|
+
toolNum++;
|
|
274
|
+
calls.set(ci, {
|
|
275
|
+
name: evt.toolName ?? "?",
|
|
276
|
+
buf: ""
|
|
277
|
+
});
|
|
278
|
+
return null;
|
|
279
|
+
}
|
|
280
|
+
if (type === "toolcall_delta" && calls.has(ci)) {
|
|
281
|
+
calls.get(ci).buf += evt.delta ?? "";
|
|
282
|
+
return null;
|
|
283
|
+
}
|
|
284
|
+
if (type === "toolcall_end" && calls.has(ci)) {
|
|
285
|
+
const call = calls.get(ci);
|
|
286
|
+
calls.delete(ci);
|
|
287
|
+
let label = "";
|
|
288
|
+
try {
|
|
289
|
+
const args = JSON.parse(call.buf);
|
|
290
|
+
label = String(
|
|
291
|
+
args.command ?? args.file_path ?? args.query ?? ""
|
|
292
|
+
).split("\n")[0].slice(0, 72);
|
|
293
|
+
} catch {
|
|
294
|
+
}
|
|
295
|
+
return `[${call.name}] ${label}`;
|
|
296
|
+
}
|
|
297
|
+
return null;
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
__name(createPiStreamFormatter, "createPiStreamFormatter");
|
|
301
|
+
function writePromptFile(prompt) {
|
|
302
|
+
const name = `nightralph-${Date.now()}-${Math.random().toString(36).slice(2)}.md`;
|
|
303
|
+
const filePath = join(tmpdir(), name);
|
|
304
|
+
writeFileSync(filePath, prompt);
|
|
305
|
+
return filePath;
|
|
306
|
+
}
|
|
307
|
+
__name(writePromptFile, "writePromptFile");
|
|
308
|
+
function cleanupPromptFile(filePath) {
|
|
309
|
+
try {
|
|
310
|
+
unlinkSync(filePath);
|
|
311
|
+
} catch {
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
__name(cleanupPromptFile, "cleanupPromptFile");
|
|
244
315
|
function spawnAgent(opts) {
|
|
245
316
|
const args = [
|
|
246
317
|
...getProviderArgs(opts.agentCmd)
|
|
@@ -248,8 +319,15 @@ function spawnAgent(opts) {
|
|
|
248
319
|
if (opts.model) {
|
|
249
320
|
args.push("--model", opts.model);
|
|
250
321
|
}
|
|
251
|
-
const
|
|
322
|
+
const providerName = basename(opts.agentCmd);
|
|
323
|
+
const isClaude = providerName === "claude";
|
|
324
|
+
const isPi = providerName === "pi";
|
|
252
325
|
const prefix = opts.label ? ` [${opts.label}] ` : " ";
|
|
326
|
+
let promptFile = null;
|
|
327
|
+
if (isPi) {
|
|
328
|
+
promptFile = writePromptFile(opts.prompt);
|
|
329
|
+
args.push(`@${promptFile}`);
|
|
330
|
+
}
|
|
253
331
|
const logStream = createWriteStream(
|
|
254
332
|
opts.logPath,
|
|
255
333
|
{ flags: "w" }
|
|
@@ -259,6 +337,7 @@ function spawnAgent(opts) {
|
|
|
259
337
|
cwd: opts.cwd
|
|
260
338
|
});
|
|
261
339
|
proc.stdout.pipe(logStream);
|
|
340
|
+
const piFormatter = isPi ? createPiStreamFormatter() : null;
|
|
262
341
|
const rl = createInterface({ input: proc.stdout });
|
|
263
342
|
rl.on("line", (line) => {
|
|
264
343
|
if (isClaude) {
|
|
@@ -266,6 +345,11 @@ function spawnAgent(opts) {
|
|
|
266
345
|
if (formatted !== null) {
|
|
267
346
|
console.log(`${prefix}${formatted}`);
|
|
268
347
|
}
|
|
348
|
+
} else if (piFormatter) {
|
|
349
|
+
const formatted = piFormatter(line);
|
|
350
|
+
if (formatted !== null) {
|
|
351
|
+
console.log(`${prefix}${formatted}`);
|
|
352
|
+
}
|
|
269
353
|
} else {
|
|
270
354
|
console.log(`${prefix}${line}`);
|
|
271
355
|
}
|
|
@@ -283,7 +367,9 @@ function spawnAgent(opts) {
|
|
|
283
367
|
proc.kill("SIGKILL");
|
|
284
368
|
}
|
|
285
369
|
}, opts.timeout * 1e3);
|
|
286
|
-
|
|
370
|
+
if (!promptFile) {
|
|
371
|
+
proc.stdin.write(opts.prompt);
|
|
372
|
+
}
|
|
287
373
|
proc.stdin.end();
|
|
288
374
|
return new Promise((resolve) => {
|
|
289
375
|
proc.on("close", (code) => {
|
|
@@ -291,6 +377,7 @@ function spawnAgent(opts) {
|
|
|
291
377
|
rl.close();
|
|
292
378
|
rlErr.close();
|
|
293
379
|
logStream.end();
|
|
380
|
+
if (promptFile) cleanupPromptFile(promptFile);
|
|
294
381
|
resolve(code ?? 1);
|
|
295
382
|
});
|
|
296
383
|
proc.on("error", (err) => {
|
|
@@ -298,6 +385,7 @@ function spawnAgent(opts) {
|
|
|
298
385
|
rl.close();
|
|
299
386
|
rlErr.close();
|
|
300
387
|
logStream.end();
|
|
388
|
+
if (promptFile) cleanupPromptFile(promptFile);
|
|
301
389
|
console.error(
|
|
302
390
|
"Agent process error:",
|
|
303
391
|
formatErrorMessage(err)
|
|
@@ -573,35 +661,7 @@ Wave ${waveNum}: ` + ready.map((t) => t.filename).join(", ")
|
|
|
573
661
|
const exitCode = r.value;
|
|
574
662
|
const ticket = activeTickets[i];
|
|
575
663
|
const worktree = worktrees[i];
|
|
576
|
-
if (exitCode
|
|
577
|
-
repoRoot,
|
|
578
|
-
baseBranch,
|
|
579
|
-
worktree.branchName
|
|
580
|
-
)) {
|
|
581
|
-
console.log(
|
|
582
|
-
` ${ticket.filename}: agent exited 0 but made no commits; leaving ticket ready-for-agent`
|
|
583
|
-
);
|
|
584
|
-
} else if (exitCode === 0 && isDirty(
|
|
585
|
-
worktree.worktreePath
|
|
586
|
-
)) {
|
|
587
|
-
console.log(
|
|
588
|
-
` ${ticket.filename}: agent left uncommitted changes in the worktree; leaving ticket ready-for-agent`
|
|
589
|
-
);
|
|
590
|
-
} else if (exitCode === 0) {
|
|
591
|
-
console.log(
|
|
592
|
-
` ${ticket.filename}: agent finished, awaiting merge`
|
|
593
|
-
);
|
|
594
|
-
ticketsByNum.set(ticket.num, ticket);
|
|
595
|
-
worktreePathsByNum.set(
|
|
596
|
-
ticket.num,
|
|
597
|
-
worktree.worktreePath
|
|
598
|
-
);
|
|
599
|
-
successfulBranches.push({
|
|
600
|
-
branch: worktree.branchName,
|
|
601
|
-
ticketNum: ticket.num,
|
|
602
|
-
worktreePath: worktree.worktreePath
|
|
603
|
-
});
|
|
604
|
-
} else {
|
|
664
|
+
if (exitCode !== 0) {
|
|
605
665
|
console.log(
|
|
606
666
|
` ${ticket.filename}: agent exited ${exitCode}`
|
|
607
667
|
);
|
|
@@ -623,7 +683,42 @@ Wave ${waveNum}: ` + ready.map((t) => t.filename).join(", ")
|
|
|
623
683
|
` Failed to remove worktree ${worktree.worktreePath}: ` + formatErrorMessage(err)
|
|
624
684
|
);
|
|
625
685
|
}
|
|
686
|
+
continue;
|
|
687
|
+
}
|
|
688
|
+
if (isDirty(worktree.worktreePath)) {
|
|
689
|
+
const committed = await commitDirty(
|
|
690
|
+
worktree.worktreePath,
|
|
691
|
+
`nightralph: auto-commit ${ticket.filename} remaining changes`
|
|
692
|
+
);
|
|
693
|
+
if (committed) {
|
|
694
|
+
console.log(
|
|
695
|
+
` ${ticket.filename}: auto-committed remaining changes`
|
|
696
|
+
);
|
|
697
|
+
}
|
|
626
698
|
}
|
|
699
|
+
if (!hasNewCommits(
|
|
700
|
+
repoRoot,
|
|
701
|
+
baseBranch,
|
|
702
|
+
worktree.branchName
|
|
703
|
+
)) {
|
|
704
|
+
console.log(
|
|
705
|
+
` ${ticket.filename}: agent exited 0 but made no changes; leaving ticket ready-for-agent`
|
|
706
|
+
);
|
|
707
|
+
continue;
|
|
708
|
+
}
|
|
709
|
+
console.log(
|
|
710
|
+
` ${ticket.filename}: agent finished, awaiting merge`
|
|
711
|
+
);
|
|
712
|
+
ticketsByNum.set(ticket.num, ticket);
|
|
713
|
+
worktreePathsByNum.set(
|
|
714
|
+
ticket.num,
|
|
715
|
+
worktree.worktreePath
|
|
716
|
+
);
|
|
717
|
+
successfulBranches.push({
|
|
718
|
+
branch: worktree.branchName,
|
|
719
|
+
ticketNum: ticket.num,
|
|
720
|
+
worktreePath: worktree.worktreePath
|
|
721
|
+
});
|
|
627
722
|
}
|
|
628
723
|
if (successfulBranches.length > 0) {
|
|
629
724
|
const mergeResult = await mergeWave({
|
|
@@ -753,6 +848,7 @@ Finished: ${totalCompleted} completed` + (remaining.length > 0 ? `, ${remaining.
|
|
|
753
848
|
__name(runWavesIsolated, "runWavesIsolated");
|
|
754
849
|
export {
|
|
755
850
|
TICKET_RE,
|
|
851
|
+
createPiStreamFormatter,
|
|
756
852
|
dryRun,
|
|
757
853
|
dryRunIsolated,
|
|
758
854
|
findReadyTickets,
|
package/dist/orchestrator.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/orchestrator.ts"],
|
|
4
|
-
"sourcesContent": ["import { spawn } 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} 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 && !hasNewCommits(\n repoRoot, baseBranch, worktree.branchName\n )) {\n console.log(\n ` ${ticket.filename}: agent exited 0 ` +\n 'but made no commits; leaving ticket ' +\n 'ready-for-agent'\n )\n } else if (exitCode === 0 && isDirty(\n worktree.worktreePath\n )) {\n console.log(\n ` ${ticket.filename}: agent left ` +\n 'uncommitted changes in the worktree; ' +\n 'leaving ticket ready-for-agent'\n )\n } else if (exitCode === 0) {\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 } else {\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 }\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": ";;AAAA,SAAS,aAAa;AACtB;AAAA,EACI;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACG;AACP,SAAS,MAAM,SAAS,gBAAgB;AACxC,SAAS,uBAAuB;AAChC;AAAA,EACI;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACG;AACP;AAAA,EACI;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEG;AACP;AAAA,EACI;AAAA,EACA;AAAA,EACA;AAAA,OAEG;AAYA,SAAS,mBAAoB,OAAsB;AACtD,SAAO,iBAAiB,QACpB,MAAM,UACN,OAAO,KAAK;AACpB;AAJgB;AAMT,MAAM,YAAY;AAElB,SAAS,oBACZ,UAC+B;AAC/B,QAAM,IAAI,SAAS,MAAM,SAAS;AAClC,MAAI,CAAC,EAAG,QAAO;AACf,SAAO,EAAE,KAAI,OAAO,EAAE,CAAC,CAAC,GAAG,MAAK,EAAE,CAAC,EAAE;AACzC;AANgB;AAQT,SAAS,YAAa,MAAoB;AAC7C,QAAM,IAAI,KAAK,MAAM,yBAAyB;AAC9C,SAAO,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,YAAY,IAAI;AAC3C;AAHgB;AAKT,SAAS,cAAe,MAAsB;AACjD,QAAM,IAAI,KAAK,MAAM,6BAA6B;AAClD,MAAI,CAAC,EAAG,QAAO,CAAC;AAChB,QAAM,OAAO,EAAE,CAAC;AAChB,MAAI,QAAQ,KAAK,IAAI,EAAG,QAAO,CAAC;AAChC,QAAM,OAAgB,CAAC;AACvB,QAAM,KAAK;AACX,MAAI;AACJ,SAAQ,QAAQ,GAAG,KAAK,IAAI,GAAI;AAC5B,SAAK,KAAK,OAAO,MAAM,CAAC,CAAC,CAAC;AAAA,EAC9B;AACA,SAAO;AACX;AAZgB;AAcT,SAAS,YAAa,KAAqB;AAC9C,QAAM,QAAQ,YAAY,GAAG,EACxB,OAAO,OAAK,UAAU,KAAK,CAAC,CAAC,EAC7B,KAAK,CAAC,GAAG,MAAM,EAAE;AAAA,IACd;AAAA,IACA;AAAA,IACA,EAAE,SAAQ,MAAM,aAAY,OAAO;AAAA,EACvC,CAAC;AAEL,SAAO,MAAM,IAAI,cAAY;AACzB,UAAM,SAAS,oBAAoB,QAAQ;AAC3C,UAAM,WAAW,KAAK,KAAK,QAAQ;AACnC,UAAM,OAAO,aAAa,UAAU,MAAM;AAC1C,WAAO;AAAA,MACH,KAAI,OAAO;AAAA,MACX,MAAK,OAAO;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAO,YAAY,IAAI;AAAA,MACvB,UAAS,cAAc,IAAI;AAAA,IAC/B;AAAA,EACJ,CAAC;AACL;AAvBgB;AAyBT,SAAS,iBACZ,SACO;AACP,QAAM,WAAW,IAAI;AAAA,IACjB,QACK,OAAO,OAAK,EAAE,WAAW,MAAM,EAC/B,IAAI,OAAK,EAAE,GAAG;AAAA,EACvB;AACA,SAAO,QAAQ,OAAO,OAAK;AACvB,QAAI,EAAE,WAAW,kBAAmB,QAAO;AAC3C,WAAO,EAAE,SAAS,MAAM,OAAK,SAAS,IAAI,CAAC,CAAC;AAAA,EAChD,CAAC;AACL;AAZgB;AAcT,SAAS,SAAU,QAAoB;AAC1C,QAAM,UAAU,OAAO,KAAK;AAAA,IACxB;AAAA,IACA;AAAA,EACJ;AACA,gBAAc,OAAO,UAAU,OAAO;AACtC,SAAO,SAAS;AAChB,SAAO,OAAO;AAClB;AARgB;AAUT,SAAS,aACZ,UACA,QACK;AACL,SAAO;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO;AAAA,IACP,OAAO;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IAEA;AAAA,IACA;AAAA,IACA;AAAA,IAGA;AAAA,IAGA;AAAA,IAGA;AAAA,IACA;AAAA,EACJ,EAAE,KAAK,IAAI;AACf;AA7BgB;AA+BhB,SAAS,YAAa,SAAoC;AACtD,UAAQ,IAAI,YAAY;AACxB,aAAW,KAAK,SAAS;AACrB,UAAM,aAAa,EAAE,SAAS,SAAS,IACnC,eAAe,EAAE,SAAS,KAAK,IAAI,CAAC,MACpC;AACJ,YAAQ;AAAA,MACJ,KAAK,EAAE,QAAQ,KACX,EAAE,MAAM,KAAK,UAAU;AAAA,IAC/B;AAAA,EACJ;AACJ;AAXS;AAaT,UAAW,cACP,SAC8C;AAC9C,QAAM,MAAM,IAAI;AAAA,IACZ,QAAQ,IAAI,OAAK,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC;AAAA,EACtC;AACA,MAAI,OAAO;AACX,SAAO,MAAM;AACT,UAAM,WAAW,IAAI;AAAA,MACjB,CAAC,GAAG,IAAI,QAAQ,CAAC,EACZ,OAAO,CAAC,CAAC,EAAE,CAAC,MAAM,MAAM,MAAM,EAC9B,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;AAAA,IACvB;AACA,UAAM,QAAQ,CAAC,GAAG,OAAO,EAAE,OAAO,OAAK;AACnC,UAAI,IAAI,IAAI,EAAE,GAAG,MAAM,mBAAmB;AACtC,eAAO;AAAA,MACX;AACA,aAAO,EAAE,SAAS;AAAA,QACd,OAAK,SAAS,IAAI,CAAC;AAAA,MACvB;AAAA,IACJ,CAAC;AACD,QAAI,MAAM,WAAW,EAAG;AACxB,UAAM,EAAE,MAAM,MAAM;AACpB,eAAW,KAAK,OAAO;AACnB,UAAI,IAAI,EAAE,KAAK,MAAM;AAAA,IACzB;AACA;AAAA,EACJ;AACJ;AA5BW;AA8BX,SAAS,gBACL,SACY;AACZ,QAAM,WAAW,oBAAI,IAAY;AACjC,QAAM,QAAQ,oBAAI,IAAY;AAE9B,aAAW,KAAK,SAAS;AACrB,QAAI,EAAE,WAAW,mBAAmB;AAChC,YAAM,IAAI,EAAE,GAAG;AAAA,IACnB,WAAW,EAAE,WAAW,QAAQ;AAC5B,eAAS,IAAI,EAAE,GAAG;AAAA,IACtB;AAAA,EACJ;AAEA,MAAI,UAAU;AACd,SAAO,SAAS;AACZ,cAAU;AACV,eAAW,OAAO,OAAO;AACrB,YAAM,SAAS,QAAQ;AAAA,QAAK,OACxB,EAAE,QAAQ;AAAA,MACd;AACA,UAAI,OAAO,SAAS;AAAA,QAChB,OAAK,SAAS,IAAI,CAAC;AAAA,MACvB,GAAG;AACC,iBAAS,IAAI,GAAG;AAChB,cAAM,OAAO,GAAG;AAChB,kBAAU;AAAA,MACd;AAAA,IACJ;AAAA,EACJ;AAEA,SAAO,CAAC,GAAG,KAAK,EAAE;AAAA,IAAI,SAClB,QAAQ,KAAK,OAAK,EAAE,QAAQ,GAAG;AAAA,EACnC;AACJ;AAlCS;AAoCT,MAAM,gBAAyC;AAAA,EAC3C,QAAO;AAAA,IACH;AAAA,IAAW;AAAA,IACX;AAAA,IAAmB;AAAA,IACnB;AAAA,EACJ;AAAA,EACA,OAAM,CAAC,QAAQ,aAAa;AAChC;AAEO,SAAS,gBAAiB,KAAqB;AAClD,QAAM,OAAO,SAAS,GAAG;AACzB,SAAO,cAAc,IAAI,KAAK,CAAC;AACnC;AAHgB;AAKT,SAAS,iBACZ,MACU;AACV,MAAI;AACJ,MAAI;AACA,UAAM,KAAK,MAAM,IAAI;AAAA,EACzB,QAAQ;AACJ,WAAO;AAAA,EACX;AAEA,MAAI,IAAI,SAAS,aAAa;AAC1B,UAAM,MAAM,IAAI;AAEhB,UAAM,UAAU,KAAK;AAErB,QAAI,CAAC,QAAS,QAAO;AACrB,eAAW,SAAS,SAAS;AACzB,UAAI,MAAM,SAAS,QAAQ;AACvB,eAAO,OAAO,MAAM,IAAI;AAAA,MAC5B;AAAA,IACJ;AACA,WAAO;AAAA,EACX;AAEA,MAAI,IAAI,SAAS,UAAU;AACvB,UAAM,MAAM,IAAI,WAA+B;AAC/C,UAAM,OAAO,IAAI;AACjB,UAAM,UAAU,QAAQ,OACpB,MAAM,KAAK,QAAQ,CAAC,CAAC,MACrB;AACJ,WAAO,GAAG,GAAG,GAAG,OAAO;AAAA,EAC3B;AAEA,MAAI,IAAI,SAAS,UAAU;AACvB,UAAM,MAAM,IAAI;AAChB,QAAI,QAAQ,aAAa;AACrB,YAAM,QAAQ,IAAI;AAClB,aAAO,UAAU,SAAS,SAAS;AAAA,IACvC;AAAA,EACJ;AAEA,SAAO;AACX;AA1CgB;AA4CT,SAAS,WAAY,MAQT;AACf,QAAM,OAAgB;AAAA,IAClB,GAAG,gBAAgB,KAAK,QAAQ;AAAA,EACpC;AACA,MAAI,KAAK,OAAO;AACZ,SAAK,KAAK,WAAW,KAAK,KAAK;AAAA,EACnC;AAEA,QAAM,WAAW,SAAS,KAAK,QAAQ,MAAM;AAC7C,QAAM,SAAS,KAAK,QAChB,MAAM,KAAK,KAAK,OAChB;AAEJ,QAAM,YAAY;AAAA,IACd,KAAK;AAAA,IACL,EAAE,OAAM,IAAI;AAAA,EAChB;AACA,QAAM,OAAO,MAAM,KAAK,UAAU,MAAM;AAAA,IACpC,OAAM,CAAC,QAAQ,QAAQ,MAAM;AAAA,IAC7B,KAAI,KAAK;AAAA,EACb,CAAC;AAED,OAAK,OAAO,KAAK,SAAS;AAE1B,QAAM,KAAK,gBAAgB,EAAE,OAAM,KAAK,OAAO,CAAC;AAChD,KAAG,GAAG,QAAQ,UAAQ;AAClB,QAAI,UAAU;AACV,YAAM,YAAY,iBAAiB,IAAI;AACvC,UAAI,cAAc,MAAM;AACpB,gBAAQ,IAAI,GAAG,MAAM,GAAG,SAAS,EAAE;AAAA,MACvC;AAAA,IACJ,OAAO;AACH,cAAQ,IAAI,GAAG,MAAM,GAAG,IAAI,EAAE;AAAA,IAClC;AAAA,EACJ,CAAC;AAED,OAAK,OAAO,KAAK,SAAS;AAC1B,QAAM,QAAQ,gBAAgB,EAAE,OAAM,KAAK,OAAO,CAAC;AACnD,QAAM,GAAG,QAAQ,UAAQ;AACrB,YAAQ,MAAM,GAAG,MAAM,GAAG,IAAI,EAAE;AAAA,EACpC,CAAC;AAED,QAAM,UAAU,WAAW,MAAM;AAC7B,QAAI,CAAC,KAAK,QAAQ;AACd,cAAQ;AAAA,QACJ,yBACG,KAAK,OAAO;AAAA,MACnB;AACA,WAAK,KAAK,SAAS;AAAA,IACvB;AAAA,EACJ,GAAG,KAAK,UAAU,GAAI;AAEtB,OAAK,MAAM,MAAM,KAAK,MAAM;AAC5B,OAAK,MAAM,IAAI;AAEf,SAAO,IAAI,QAAgB,aAAW;AAClC,SAAK,GAAG,SAAS,UAAQ;AACrB,mBAAa,OAAO;AACpB,SAAG,MAAM;AACT,YAAM,MAAM;AACZ,gBAAU,IAAI;AACd,cAAQ,QAAQ,CAAC;AAAA,IACrB,CAAC;AACD,SAAK,GAAG,SAAS,SAAO;AACpB,mBAAa,OAAO;AACpB,SAAG,MAAM;AACT,YAAM,MAAM;AACZ,gBAAU,IAAI;AACd,cAAQ;AAAA,QACJ;AAAA,QACA,mBAAmB,GAAG;AAAA,MAC1B;AACA,cAAQ,CAAC;AAAA,IACb,CAAC;AAAA,EACL,CAAC;AACL;AAnFgB;AAqFT,SAAS,OACZ,SACA,UACG;AACH,cAAY,OAAO;AAEnB,UAAQ,IAAI,yBAAyB;AACrC,aAAW,EAAE,MAAM,MAAM,KAAK,cAAc,OAAO,GAAG;AAClD,YAAQ;AAAA,MACJ,UAAU,IAAI,OACd,MAAM,IAAI,OAAK,EAAE,QAAQ,EAAE,KAAK,IAAI;AAAA,IACxC;AAAA,EACJ;AAEA,QAAM,QAAQ,gBAAgB,OAAO;AACrC,MAAI,MAAM,SAAS,GAAG;AAClB,YAAQ;AAAA,MACJ,2BACA,MAAM,IAAI,OAAK,EAAE,QAAQ,EAAE,KAAK,IAAI;AAAA,IACxC;AAAA,EACJ;AAEA,QAAM,aAAa,iBAAiB,OAAO;AAC3C,MAAI,WAAW,SAAS,GAAG;AACvB,YAAQ;AAAA,MACJ;AAAA,iCACI,WAAW,CAAC,EAAE,QAAQ;AAAA;AAAA,IAC9B;AACA,YAAQ;AAAA,MACJ,aAAa,UAAU,WAAW,CAAC,CAAC;AAAA,IACxC;AAAA,EACJ;AACJ;AAhCgB;AAkCT,SAAS,eAAgB,MAMxB;AACJ,cAAY,KAAK,OAAO;AAExB,UAAQ,IAAI,yBAAyB;AACrC,aAAW,EAAE,MAAM,MAAM,KAAK;AAAA,IAC1B,KAAK;AAAA,EACT,GAAG;AACC,YAAQ;AAAA,MACJ,UAAU,IAAI,OACd,MAAM,IAAI,OAAK,EAAE,QAAQ,EAAE,KAAK,IAAI;AAAA,IACxC;AACA,eAAW,KAAK,OAAO;AACnB,YAAM,MAAM,OAAO,EAAE,GAAG,EAAE,SAAS,GAAG,GAAG;AACzC,YAAM,aACF,GAAG,KAAK,QAAQ,IAAI,GAAG,IAAI,EAAE,IAAI;AACrC,YAAM,eACF,MAAM,KAAK,QAAQ,IAAI,GAAG,IAAI,EAAE,IAAI;AACxC,cAAQ,IAAI,iBAAiB,YAAY,EAAE;AAC3C,cAAQ,IAAI,iBAAiB,UAAU,EAAE;AAAA,IAC7C;AAAA,EACJ;AAEA,QAAM,QAAQ,gBAAgB,KAAK,OAAO;AAC1C,MAAI,MAAM,SAAS,GAAG;AAClB,YAAQ;AAAA,MACJ,2BACA,MAAM,IAAI,OAAK,EAAE,QAAQ,EAAE,KAAK,IAAI;AAAA,IACxC;AAAA,EACJ;AAEA,QAAM,aAAa,iBAAiB,KAAK,OAAO;AAChD,MAAI,WAAW,SAAS,GAAG;AACvB,YAAQ;AAAA,MACJ;AAAA,iCACI,WAAW,CAAC,EAAE,QAAQ;AAAA;AAAA,IAC9B;AACA,YAAQ;AAAA,MACJ,aAAa,KAAK,UAAU,WAAW,CAAC,CAAC;AAAA,IAC7C;AAAA,EACJ;AAEA,QAAM,eACF,KAAK,qBAAqB,YACtB,uCACA;AACR,UAAQ;AAAA,IACJ;AAAA,kBAAqB,YAAY;AAAA,EACrC;AACA,UAAQ,IAAI,kBAAkB,KAAK,YAAY,EAAE;AACrD;AAvDgB;AA4DhB,eAAe,qBAAsB,MAWjB;AAChB,QAAM;AAAA,IACF,KAAK;AAAA,IAAc,KAAK;AAAA,EAC5B;AAEA,UAAQ;AAAA,IACJ,KAAK,KAAK,OAAO,QAAQ;AAAA,EAE7B;AACA,QAAM,SAAS,aAAa,KAAK,UAAU,KAAK,MAAM;AACtD,QAAM,UAAU;AAAA,IACZ,KAAK;AAAA,IACL,KAAK,OAAO,SAAS,QAAQ,SAAS,cAAc;AAAA,EACxD;AACA,QAAM,QAAQ,KAAK,OAAO,SAAS;AAAA,IAC/B;AAAA,IAAS;AAAA,EACb;AACA,QAAM,WAAW,MAAM,WAAW;AAAA,IAC9B;AAAA,IACA,UAAS,KAAK;AAAA,IACd,OAAM,KAAK;AAAA,IACX,SAAQ,KAAK;AAAA,IACb;AAAA,IACA,KAAI,KAAK;AAAA,IACT;AAAA,EACJ,CAAC;AAED,MAAI,aAAa,GAAG;AAChB,YAAQ;AAAA,MACJ,KAAK,KAAK,OAAO,QAAQ,4BACf,QAAQ;AAAA,IACtB;AACA,WAAO;AAAA,EACX;AAEA,QAAM,SAAS,MAAM;AAAA,IACjB,KAAK;AAAA,IAAU,KAAK;AAAA,EACxB;AACA,MAAI,CAAC,QAAQ;AACT,YAAQ;AAAA,MACJ,KAAK,KAAK,OAAO,QAAQ;AAAA,IAE7B;AAAA,EACJ;AACA,SAAO;AACX;AAxDe;AA0Df,eAAsB,SAClB,SACA,UACA,UACA,OACA,SACA,SAC2B;AAC3B,YAAU,SAAS,EAAE,WAAU,KAAK,CAAC;AAErC,MAAI,iBAAiB;AACrB,MAAI,UAAU;AAEd,SAAO,MAAM;AACT,UAAM,QAAQ,iBAAiB,OAAO;AACtC,QAAI,MAAM,WAAW,EAAG;AAExB;AACA,YAAQ;AAAA,MACJ;AAAA,OAAU,OAAO,OACjB,MAAM,IAAI,OAAK,EAAE,QAAQ,EAAE,KAAK,IAAI;AAAA,IACxC;AAEA,UAAM,UAAU,MAAM,QAAQ;AAAA,MAC1B,MAAM,IAAI,OAAM,MAAK;AACjB,cAAM,SAAS,aAAa,UAAU,CAAC;AACvC,cAAM,UAAU;AAAA,UACZ;AAAA,UACA,EAAE,SAAS,QAAQ,SAAS,MAAM;AAAA,QACtC;AACA,cAAM,QAAQ,EAAE,SAAS;AAAA,UACrB;AAAA,UAAS;AAAA,QACb;AACA,gBAAQ,IAAI,cAAc,EAAE,QAAQ,EAAE;AACtC,cAAM,OAAO,MAAM,WAAW;AAAA,UAC1B;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACJ,CAAC;AACD,eAAO,EAAE,QAAO,GAAG,UAAS,KAAK;AAAA,MACrC,CAAC;AAAA,IACL;AAEA,QAAI,gBAAgB;AACpB,eAAW,KAAK,SAAS;AACrB,UAAI,EAAE,WAAW,WAAY;AAC7B,YAAM,EAAE,QAAQ,SAAS,IAAI,EAAE;AAC/B,UAAI,aAAa,GAAG;AAChB,gBAAQ;AAAA,UACJ,KAAK,OAAO,QAAQ,kBACJ,QAAQ;AAAA,QAC5B;AACA;AAAA,MACJ;AAEA,eAAS,MAAM;AACf;AACA;AACA,cAAQ;AAAA,QACJ,KAAK,OAAO,QAAQ;AAAA,MACxB;AAAA,IACJ;AAEA,QAAI,kBAAkB,GAAG;AACrB,cAAQ;AAAA,QACJ;AAAA,MAEJ;AACA;AAAA,IACJ;AAAA,EACJ;AAEA,QAAM,YAAY,QAAQ;AAAA,IACtB,OAAK,EAAE,WAAW;AAAA,EACtB;AACA,UAAQ;AAAA,IACJ;AAAA,YAAe,cAAc,gBAC5B,UAAU,SAAS,IAChB,KAAK,UAAU,MAAM,eACrB;AAAA,EACR;AAEA,SAAO,EAAE,SAAQ,UAAU,WAAW,EAAE;AAC5C;AAtFsB;AAwFtB,eAAsB,iBAAkB,MASR;AAC5B,YAAU,KAAK,SAAS,EAAE,WAAU,KAAK,CAAC;AAE1C,QAAM,WAAW,YAAY;AAC7B,QAAM,WAAW,YAAY;AAC7B,QAAM,aAAa,iBAAiB;AAEpC,QAAM,eAAe;AAAA,IACjB,QAAQ,KAAK,OAAO;AAAA,IAAG;AAAA,EAC3B;AACA,QAAM,WAAwB;AAAA,IAC1B,iBAAiB,KAAK,aAAa,KAAK,OAAO;AAAA,IAC/C,aAAa,YAAY;AAAA,EAC7B;AACA,gBAAc,cAAc,QAAQ;AACpC,QAAM;AAAA,IACF;AAAA,IACA;AAAA,IACA,qBAAqB,KAAK,WAAW;AAAA,EACzC;AAEA,MAAI,iBAAiB;AACrB,MAAI,UAAU;AAEd,SAAO,MAAM;AACT,UAAM,QAAQ,iBAAiB,KAAK,OAAO;AAC3C,QAAI,MAAM,WAAW,EAAG;AAExB;AACA,YAAQ;AAAA,MACJ;AAAA,OAAU,OAAO,OACjB,MAAM,IAAI,OAAK,EAAE,QAAQ,EAAE,KAAK,IAAI;AAAA,IACxC;AAEA,UAAM,kBAAkB,MAAM,QAAQ;AAAA,MAClC,MAAM,IAAI,OAAK,eAAe;AAAA,QAC1B;AAAA,QACA;AAAA,QACA;AAAA,QACA,QAAO;AAAA,MACX,CAAC,CAAC;AAAA,IACN;AAEA,UAAM,gBAA8B,CAAC;AACrC,UAAM,YAGD,CAAC;AAEN,aAAS,IAAI,GAAG,IAAI,gBAAgB,QAAQ,KAAK;AAC7C,YAAM,UAAU,gBAAgB,CAAC;AACjC,YAAM,SAAS,MAAM,CAAC;AACtB,UAAI,QAAQ,WAAW,YAAY;AAC/B,gBAAQ;AAAA,UACJ,KAAK,OAAO,QAAQ,gCACP,mBAAmB,QAAQ,MAAM,CAAC;AAAA,QACnD;AACA;AAAA,MACJ;AACA,oBAAc,KAAK,MAAM;AACzB,gBAAU,KAAK,QAAQ,KAAK;AAAA,IAChC;AAEA,UAAM,UAAU,MAAM,QAAQ;AAAA,MAC1B,cAAc,IAAI,CAAC,GAAG,MAAM;AACxB,cAAM,SAAS,aAAa,KAAK,UAAU,CAAC;AAC5C,cAAM,UAAU;AAAA,UACZ,KAAK;AAAA,UACL,EAAE,SAAS,QAAQ,SAAS,MAAM;AAAA,QACtC;AACA,cAAM,QAAQ,EAAE,SAAS;AAAA,UACrB;AAAA,UAAS;AAAA,QACb;AACA,gBAAQ,IAAI,cAAc,EAAE,QAAQ,EAAE;AACtC,eAAO,WAAW;AAAA,UACd;AAAA,UACA,UAAS,KAAK;AAAA,UACd,OAAM,KAAK;AAAA,UACX,SAAQ,KAAK;AAAA,UACb;AAAA,UACA,KAAI,UAAU,CAAC,EAAE;AAAA,UACjB;AAAA,QACJ,CAAC;AAAA,MACL,CAAC;AAAA,IACL;AAEA,QAAI,gBAAgB;AACpB,UAAM,qBAID,CAAC;AACN,UAAM,eAAe,oBAAI,IAAoB;AAC7C,UAAM,qBAAqB,oBAAI,IAAoB;AAEnD,aAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACrC,YAAM,IAAI,QAAQ,CAAC;AACnB,UAAI,EAAE,WAAW,WAAY;AAC7B,YAAM,WAAW,EAAE;AACnB,YAAM,SAAS,cAAc,CAAC;AAC9B,YAAM,WAAW,UAAU,CAAC;AAE5B,UAAI,aAAa,KAAK,CAAC;AAAA,QACnB;AAAA,QAAU;AAAA,QAAY,SAAS;AAAA,MACnC,GAAG;AACC,gBAAQ;AAAA,UACJ,KAAK,OAAO,QAAQ;AAAA,QAGxB;AAAA,MACJ,WAAW,aAAa,KAAK;AAAA,QACzB,SAAS;AAAA,MACb,GAAG;AACC,gBAAQ;AAAA,UACJ,KAAK,OAAO,QAAQ;AAAA,QAGxB;AAAA,MACJ,WAAW,aAAa,GAAG;AACvB,gBAAQ;AAAA,UACJ,KAAK,OAAO,QAAQ;AAAA,QAExB;AACA,qBAAa,IAAI,OAAO,KAAK,MAAM;AACnC,2BAAmB;AAAA,UACf,OAAO;AAAA,UAAK,SAAS;AAAA,QACzB;AACA,2BAAmB,KAAK;AAAA,UACpB,QAAO,SAAS;AAAA,UAChB,WAAU,OAAO;AAAA,UACjB,cAAa,SAAS;AAAA,QAC1B,CAAC;AAAA,MACL,OAAO;AACH,gBAAQ;AAAA,UACJ,KAAK,OAAO,QAAQ,kBACJ,QAAQ;AAAA,QAC5B;AACA,oBAAY,UAAU,OAAO,KAAK;AAAA,UAC9B,QAAO,SAAS;AAAA,UAChB;AAAA,UACA,MAAK;AAAA,QACT,CAAC;AACD,sBAAc,cAAc,QAAQ;AACpC,cAAM;AAAA,UACF;AAAA,UACA;AAAA,UACA,eAAe,OAAO,QAAQ;AAAA,QAClC;AAEA,YAAI;AACA,gBAAM,eAAe,SAAS,YAAY;AAAA,QAC9C,SAAS,KAAK;AACV,kBAAQ;AAAA,YACJ,+BACG,SAAS,YAAY,OACxB,mBAAmB,GAAG;AAAA,UAC1B;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ;AAEA,QAAI,mBAAmB,SAAS,GAAG;AAC/B,YAAM,cAAc,MAAM,UAAU;AAAA,QAChC;AAAA,QACA;AAAA,QACA,UAAS;AAAA,QACT,UAAS,KAAK;AAAA,MAClB,CAAC;AAED,iBAAW,gBAAgB,YAAY,QAAQ;AAC3C,cAAM,SAAS,aAAa;AAAA,UACxB,aAAa;AAAA,QACjB;AACA,YAAI,CAAC,OAAQ;AAEb,YAAI,aAAa,QAAQ;AACrB,mBAAS,MAAM;AACf;AACA;AACA,kBAAQ;AAAA,YACJ,KAAK,OAAO,QAAQ;AAAA,UACxB;AACA,sBAAY,UAAU,OAAO,KAAK;AAAA,YAC9B,QAAO,aAAa;AAAA,YACpB,UAAS;AAAA,UACb,CAAC;AACD,wBAAc,cAAc,QAAQ;AACpC,gBAAM;AAAA,YACF;AAAA,YACA;AAAA,YACA,eAAe,OAAO,QAAQ;AAAA,UAClC;AAEA,gBAAM,eAAe,mBAAmB;AAAA,YACpC,OAAO;AAAA,UACX;AACA,cAAI,cAAc;AACd,gBAAI;AACA,oBAAM,eAAe,YAAY;AAAA,YACrC,SAAS,KAAK;AACV,sBAAQ;AAAA,gBACJ,+BACG,YAAY,OACf,mBAAmB,GAAG;AAAA,cAC1B;AAAA,YACJ;AAAA,UACJ;AAAA,QACJ,OAAO;AACH,gBAAM,eAAe,mBAAmB;AAAA,YACpC,OAAO;AAAA,UACX;AACA,gBAAM,YACF,KAAK,qBAAqB,aAC1B,eACI,MAAM,qBAAqB;AAAA,YACvB;AAAA,YACA;AAAA,YACA,QAAO,aAAa;AAAA,YACpB;AAAA,YACA;AAAA,YACA,UAAS,KAAK;AAAA,YACd,UAAS,KAAK;AAAA,YACd,OAAM,KAAK;AAAA,YACX,SAAQ,KAAK;AAAA,YACb,SAAQ,KAAK;AAAA,UACjB,CAAC,IACD;AAER,cAAI,WAAW;AACX,qBAAS,MAAM;AACf;AACA;AACA,oBAAQ;AAAA,cACJ,KAAK,OAAO,QAAQ;AAAA,YAExB;AACA,wBAAY,UAAU,OAAO,KAAK;AAAA,cAC9B,QAAO,aAAa;AAAA,cACpB,UAAS;AAAA,YACb,CAAC;AACD,0BAAc,cAAc,QAAQ;AACpC,kBAAM;AAAA,cACF;AAAA,cACA;AAAA,cACA,eAAe,OAAO,QAAQ;AAAA,YAElC;AAEA,gBAAI,cAAc;AACd,kBAAI;AACA,sBAAM,eAAe,YAAY;AAAA,cACrC,SAAS,KAAK;AACV,wBAAQ;AAAA,kBACJ,+BACG,YAAY,OACf,mBAAmB,GAAG;AAAA,gBAC1B;AAAA,cACJ;AAAA,YACJ;AAAA,UACJ,OAAO;AACH,oBAAQ;AAAA,cACJ,KAAK,OAAO,QAAQ;AAAA,YAExB;AAAA,UACJ;AAAA,QACJ;AAAA,MACJ;AAEA,UAAI,YAAY,WAAW;AACvB,gBAAQ;AAAA,UACJ;AAAA,mBACG,YAAY,UAAU,MAAM;AAAA,QACnC;AAEA,mBAAW,MAAM,oBAAoB;AACjC,gBAAM,SAAS,aAAa,IAAI,GAAG,SAAS;AAC5C,cAAI,UAAU,OAAO,WAAW,OAAQ;AACxC,cAAI;AACA,kBAAM,eAAe,GAAG,YAAY;AAAA,UACxC,SAAS,KAAK;AACV,oBAAQ;AAAA,cACJ,+BACG,GAAG,YAAY,OAClB,mBAAmB,GAAG;AAAA,YAC1B;AAAA,UACJ;AAAA,QACJ;AAEA;AAAA,MACJ;AAAA,IACJ;AAEA,QAAI,kBAAkB,GAAG;AACrB,cAAQ;AAAA,QACJ;AAAA,MAEJ;AACA;AAAA,IACJ;AAAA,EACJ;AAEA,QAAM,YAAY,KAAK,QAAQ;AAAA,IAC3B,OAAK,EAAE,WAAW;AAAA,EACtB;AACA,UAAQ;AAAA,IACJ;AAAA,YAAe,cAAc,gBAC5B,UAAU,SAAS,IAChB,KAAK,UAAU,MAAM,eACrB;AAAA,EACR;AAEA,SAAO,EAAE,SAAQ,UAAU,WAAW,EAAE;AAC5C;AAjUsB;",
|
|
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 (\n):(line:string) => string|null {\n const calls = new Map<\n number,\n { name:string; buf:string }\n >()\n let toolNum = 0\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 toolNum++\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":"
|
|
1
|
+
{"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../src/orchestrator.ts"],"names":[],"mappings":"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"}
|
package/dist/src/worktree.d.ts
CHANGED
|
@@ -14,5 +14,6 @@ export declare function createWorktree(opts: {
|
|
|
14
14
|
export declare function removeWorktree(worktreePath: string): Promise<void>;
|
|
15
15
|
export declare function hasNewCommits(repoRoot: string, base: string, branch: string): boolean;
|
|
16
16
|
export declare function isDirty(cwd: string): boolean;
|
|
17
|
+
export declare function commitDirty(cwd: string, message?: string): Promise<boolean>;
|
|
17
18
|
export declare function listWorktrees(repoRoot: string): Promise<Array<string>>;
|
|
18
19
|
//# sourceMappingURL=worktree.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worktree.d.ts","sourceRoot":"","sources":["../../src/worktree.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAI/C,wBAAgB,WAAW,IAAI,MAAM,CAOpC;AAED,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAOzC;AAkBD,wBAAsB,cAAc,CAChC,IAAI,EAAC;IACD,QAAQ,EAAC,MAAM,CAAA;IACf,QAAQ,EAAC,MAAM,CAAA;IACf,UAAU,EAAC,MAAM,CAAA;IACjB,MAAM,EAAC,MAAM,CAAA;CAChB,GACH,OAAO,CAAC;IAAE,YAAY,EAAC,MAAM,CAAC;IAAC,UAAU,EAAC,MAAM,CAAA;CAAE,CAAC,CA2DpD;AAED,wBAAsB,cAAc,CAChC,YAAY,EAAC,MAAM,GACrB,OAAO,CAAC,IAAI,CAAC,CAOd;AAED,wBAAgB,aAAa,CACzB,QAAQ,EAAC,MAAM,EACf,IAAI,EAAC,MAAM,EACX,MAAM,EAAC,MAAM,GACf,OAAO,CAOR;AAED,wBAAgB,OAAO,CAAE,GAAG,EAAC,MAAM,GAAE,OAAO,CAO3C;AAED,wBAAsB,aAAa,CAC/B,QAAQ,EAAC,MAAM,GACjB,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAWvB"}
|
|
1
|
+
{"version":3,"file":"worktree.d.ts","sourceRoot":"","sources":["../../src/worktree.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAI/C,wBAAgB,WAAW,IAAI,MAAM,CAOpC;AAED,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAOzC;AAkBD,wBAAsB,cAAc,CAChC,IAAI,EAAC;IACD,QAAQ,EAAC,MAAM,CAAA;IACf,QAAQ,EAAC,MAAM,CAAA;IACf,UAAU,EAAC,MAAM,CAAA;IACjB,MAAM,EAAC,MAAM,CAAA;CAChB,GACH,OAAO,CAAC;IAAE,YAAY,EAAC,MAAM,CAAC;IAAC,UAAU,EAAC,MAAM,CAAA;CAAE,CAAC,CA2DpD;AAED,wBAAsB,cAAc,CAChC,YAAY,EAAC,MAAM,GACrB,OAAO,CAAC,IAAI,CAAC,CAOd;AAED,wBAAgB,aAAa,CACzB,QAAQ,EAAC,MAAM,EACf,IAAI,EAAC,MAAM,EACX,MAAM,EAAC,MAAM,GACf,OAAO,CAOR;AAED,wBAAgB,OAAO,CAAE,GAAG,EAAC,MAAM,GAAE,OAAO,CAO3C;AAED,wBAAsB,WAAW,CAC7B,GAAG,EAAC,MAAM,EACV,OAAO,CAAC,EAAC,MAAM,GACjB,OAAO,CAAC,OAAO,CAAC,CAsBjB;AAED,wBAAsB,aAAa,CAC/B,QAAQ,EAAC,MAAM,GACjB,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAWvB"}
|
package/dist/worktree.js
CHANGED
|
@@ -117,6 +117,29 @@ function isDirty(cwd) {
|
|
|
117
117
|
return stdout.trim().length > 0;
|
|
118
118
|
}
|
|
119
119
|
__name(isDirty, "isDirty");
|
|
120
|
+
async function commitDirty(cwd, message) {
|
|
121
|
+
if (!isDirty(cwd)) return false;
|
|
122
|
+
await execFileAsync(
|
|
123
|
+
"git",
|
|
124
|
+
["add", "-A"],
|
|
125
|
+
{ cwd }
|
|
126
|
+
);
|
|
127
|
+
try {
|
|
128
|
+
await execFileAsync(
|
|
129
|
+
"git",
|
|
130
|
+
[
|
|
131
|
+
"commit",
|
|
132
|
+
"-m",
|
|
133
|
+
message ?? "nightralph: auto-commit remaining changes"
|
|
134
|
+
],
|
|
135
|
+
{ cwd }
|
|
136
|
+
);
|
|
137
|
+
return true;
|
|
138
|
+
} catch {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
__name(commitDirty, "commitDirty");
|
|
120
143
|
async function listWorktrees(repoRoot) {
|
|
121
144
|
const { stdout } = await execFileAsync(
|
|
122
145
|
"git",
|
|
@@ -127,6 +150,7 @@ async function listWorktrees(repoRoot) {
|
|
|
127
150
|
}
|
|
128
151
|
__name(listWorktrees, "listWorktrees");
|
|
129
152
|
export {
|
|
153
|
+
commitDirty,
|
|
130
154
|
createWorktree,
|
|
131
155
|
getCurrentBranch,
|
|
132
156
|
getRepoName,
|
package/dist/worktree.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/worktree.ts"],
|
|
4
|
-
"sourcesContent": ["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 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"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["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"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|