nightralph 0.0.0

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.
Files changed (101) hide show
  1. package/.claude/settings.local.json +5 -0
  2. package/AGENTS.md +60 -0
  3. package/CLAUDE.md +1 -0
  4. package/PROMPT.md +95 -0
  5. package/README.md +138 -0
  6. package/WIP.md +5 -0
  7. package/dist/docs-templates/domain.md +36 -0
  8. package/dist/docs-templates/issue-tracker-github.md +228 -0
  9. package/dist/docs-templates/issue-tracker.md +30 -0
  10. package/dist/docs-templates/triage-labels.md +15 -0
  11. package/dist/index.js +154 -0
  12. package/dist/index.js.map +7 -0
  13. package/dist/meta.json +207 -0
  14. package/dist/orchestrator.js +273 -0
  15. package/dist/orchestrator.js.map +7 -0
  16. package/dist/resolve.js +71 -0
  17. package/dist/resolve.js.map +7 -0
  18. package/dist/setup.js +151 -0
  19. package/dist/setup.js.map +7 -0
  20. package/dist/skills/domain-modeling/ADR-FORMAT.md +47 -0
  21. package/dist/skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
  22. package/dist/skills/domain-modeling/SKILL.md +74 -0
  23. package/dist/skills/domain-modeling/agents/openai.yaml +3 -0
  24. package/dist/skills/grill/SKILL.md +7 -0
  25. package/dist/skills/grill/agents/openai.yaml +5 -0
  26. package/dist/skills/grilling/SKILL.md +28 -0
  27. package/dist/skills/grilling/agents/openai.yaml +3 -0
  28. package/dist/skills/tdd/SKILL.md +38 -0
  29. package/dist/skills/tdd/agents/openai.yaml +3 -0
  30. package/dist/skills/tdd/mocking.md +59 -0
  31. package/dist/skills/tdd/tests.md +77 -0
  32. package/dist/skills/to-spec/SKILL.md +75 -0
  33. package/dist/skills/to-spec/agents/openai.yaml +5 -0
  34. package/dist/skills/to-tickets/SKILL.md +105 -0
  35. package/dist/skills/to-tickets/agents/openai.yaml +5 -0
  36. package/dist/skills/upstream.json +5 -0
  37. package/dist/src/index.d.ts +4 -0
  38. package/dist/src/index.d.ts.map +1 -0
  39. package/dist/src/orchestrator.d.ts +31 -0
  40. package/dist/src/orchestrator.d.ts.map +1 -0
  41. package/dist/src/resolve.d.ts +10 -0
  42. package/dist/src/resolve.d.ts.map +1 -0
  43. package/dist/src/setup.d.ts +13 -0
  44. package/dist/src/setup.d.ts.map +1 -0
  45. package/dist/test/integration.test.js +848 -0
  46. package/dist/test/integration.test.js.map +7 -0
  47. package/dist/test/orchestrator.test.js +749 -0
  48. package/dist/test/orchestrator.test.js.map +7 -0
  49. package/dist/test/setup.test.js +574 -0
  50. package/dist/test/setup.test.js.map +7 -0
  51. package/docs/README.md +12 -0
  52. package/docs/agents/domain.md +36 -0
  53. package/docs/agents/issue-tracker.md +30 -0
  54. package/docs/agents/triage-labels.md +15 -0
  55. package/docs/implementation-plans/2026-08-27-issue-tracker-choice/phase-2-future-work.md +144 -0
  56. package/docs/implementation-plans/2026-08-27-issue-tracker-choice/phase_01.md +292 -0
  57. package/docs/implementation-plans/2026-08-27-issue-tracker-choice/phase_02.md +212 -0
  58. package/docs/implementation-plans/2026-08-27-issue-tracker-choice/test-requirements.md +203 -0
  59. package/docs/skills.md +58 -0
  60. package/docs/test-plans/2026-08-27-issue-tracker-choice.md +95 -0
  61. package/eslint.config.js +142 -0
  62. package/lib.es5.d.ts +19 -0
  63. package/package.json +36 -0
  64. package/progress.log +190 -0
  65. package/ralph_claude.sh +263 -0
  66. package/scripts/clone-skills.sh +52 -0
  67. package/specs/prd.json +172 -0
  68. package/src/docs-templates/domain.md +36 -0
  69. package/src/docs-templates/issue-tracker-github.md +228 -0
  70. package/src/docs-templates/issue-tracker.md +30 -0
  71. package/src/docs-templates/triage-labels.md +15 -0
  72. package/src/index.ts +184 -0
  73. package/src/orchestrator.ts +324 -0
  74. package/src/resolve.ts +73 -0
  75. package/src/setup.ts +157 -0
  76. package/src/skills/domain-modeling/ADR-FORMAT.md +47 -0
  77. package/src/skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
  78. package/src/skills/domain-modeling/SKILL.md +74 -0
  79. package/src/skills/domain-modeling/agents/openai.yaml +3 -0
  80. package/src/skills/grill/SKILL.md +7 -0
  81. package/src/skills/grill/agents/openai.yaml +5 -0
  82. package/src/skills/grilling/SKILL.md +28 -0
  83. package/src/skills/grilling/agents/openai.yaml +3 -0
  84. package/src/skills/tdd/SKILL.md +38 -0
  85. package/src/skills/tdd/agents/openai.yaml +3 -0
  86. package/src/skills/tdd/mocking.md +59 -0
  87. package/src/skills/tdd/tests.md +77 -0
  88. package/src/skills/to-spec/SKILL.md +75 -0
  89. package/src/skills/to-spec/agents/openai.yaml +5 -0
  90. package/src/skills/to-tickets/SKILL.md +105 -0
  91. package/src/skills/to-tickets/agents/openai.yaml +5 -0
  92. package/src/skills/upstream.json +5 -0
  93. package/tasks/prd-integration-test-coverage.md +243 -0
  94. package/test/integration.test.ts +636 -0
  95. package/test/mock-agent-echo-args.js +4 -0
  96. package/test/mock-agent-fail.js +3 -0
  97. package/test/mock-agent-pass.js +3 -0
  98. package/test/orchestrator.test.ts +609 -0
  99. package/test/setup.test.ts +417 -0
  100. package/tsconfig.build.json +7 -0
  101. package/tsconfig.json +31 -0
package/dist/index.js ADDED
@@ -0,0 +1,154 @@
1
+ #!/usr/bin/env node
2
+ var __defProp = Object.defineProperty;
3
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
4
+ import { existsSync, readFileSync } from "node:fs";
5
+ import { dirname, join } from "node:path";
6
+ import yargs from "yargs";
7
+ import { hideBin } from "yargs/helpers";
8
+ import { select } from "@inquirer/prompts";
9
+ import { setup, checkGhAuth } from "./setup.js";
10
+ import {
11
+ scanTickets,
12
+ dryRun,
13
+ runWaves
14
+ } from "./orchestrator.js";
15
+ import {
16
+ findFeatureDirs,
17
+ resolveIssuesDir
18
+ } from "./resolve.js";
19
+ const scriptDir = dirname(process.argv[1]);
20
+ yargs(hideBin(process.argv)).scriptName("nightralph").usage("$0 <command>").command(
21
+ "setup",
22
+ "Install bundled skills and doc templates",
23
+ (y) => y.option("claude", {
24
+ type: "boolean",
25
+ describe: "Also create .claude/skills/ symlinks",
26
+ default: false
27
+ }),
28
+ async (argv) => {
29
+ const tracker = await select({
30
+ message: "Issue tracker format",
31
+ choices: [
32
+ {
33
+ name: "Local Markdown",
34
+ value: "local",
35
+ description: "Issues as .md files in .scratch/"
36
+ },
37
+ {
38
+ name: "GitHub Issues",
39
+ value: "github",
40
+ description: "Issues via gh CLI"
41
+ }
42
+ ]
43
+ });
44
+ if (tracker === "github") {
45
+ if (!checkGhAuth()) {
46
+ console.error(
47
+ "GitHub Issues requires the gh CLI, authenticated.\nInstall: https://cli.github.com\nThen run: gh auth login"
48
+ );
49
+ process.exit(2);
50
+ }
51
+ }
52
+ setup({
53
+ bundledSkillsDir: join(scriptDir, "skills"),
54
+ docsTemplatesDir: join(
55
+ scriptDir,
56
+ "docs-templates"
57
+ ),
58
+ projectDir: process.cwd(),
59
+ claude: argv.claude,
60
+ tracker
61
+ });
62
+ }
63
+ ).command(
64
+ "$0 <provider>",
65
+ "Execute tickets with the given provider",
66
+ (y) => y.positional("provider", {
67
+ type: "string",
68
+ describe: "Agent CLI to spawn (e.g. claude, codex)",
69
+ demandOption: true
70
+ }).option("m", {
71
+ alias: "model",
72
+ type: "string",
73
+ describe: "Model passed to the agent"
74
+ }).option("dir", {
75
+ type: "string",
76
+ describe: "Path to the issues directory"
77
+ }).option("spec", {
78
+ type: "string",
79
+ describe: "Path to the spec file"
80
+ }).option("dry-run", {
81
+ type: "boolean",
82
+ describe: "Show wave order without running",
83
+ default: false
84
+ }).option("timeout-secs", {
85
+ type: "number",
86
+ describe: "Kill agent after N seconds",
87
+ default: 300
88
+ }),
89
+ async (argv) => {
90
+ await runExecute({
91
+ provider: argv.provider,
92
+ model: argv.model,
93
+ dir: argv.dir,
94
+ spec: argv.spec,
95
+ dryRun: argv.dryRun,
96
+ timeoutSecs: argv.timeoutSecs
97
+ });
98
+ }
99
+ ).strict().demandCommand(1, "Specify a command or provider").help().parse();
100
+ async function runExecute(argv) {
101
+ const { dir, spec } = await resolveIssuesDir(
102
+ argv.dir,
103
+ argv.spec
104
+ );
105
+ if (!existsSync(dir)) {
106
+ console.error(`Directory not found: ${dir}`);
107
+ process.exit(2);
108
+ }
109
+ if (!existsSync(spec)) {
110
+ console.error(`Spec file not found: ${spec}`);
111
+ process.exit(2);
112
+ }
113
+ const specBody = readFileSync(spec, "utf8");
114
+ const tickets = scanTickets(dir);
115
+ if (tickets.length === 0) {
116
+ console.log("No ticket files found. Exiting.");
117
+ return;
118
+ }
119
+ console.log(`Found ${tickets.length} tickets`);
120
+ const knownNums = new Set(tickets.map((t) => t.num));
121
+ for (const t of tickets) {
122
+ const unknown = t.blockers.filter(
123
+ (b) => !knownNums.has(b)
124
+ );
125
+ if (unknown.length > 0) {
126
+ console.warn(
127
+ `${t.filename}: blockers [${unknown.join(", ")}] not found in directory`
128
+ );
129
+ }
130
+ t.blockers = t.blockers.filter(
131
+ (b) => knownNums.has(b)
132
+ );
133
+ }
134
+ if (argv.dryRun) {
135
+ dryRun(tickets, specBody);
136
+ return;
137
+ }
138
+ const logsDir = join(dirname(dir), "logs");
139
+ const timeoutSecs = argv.timeoutSecs ?? 300;
140
+ await runWaves(
141
+ tickets,
142
+ specBody,
143
+ argv.provider,
144
+ argv.model ?? null,
145
+ timeoutSecs,
146
+ logsDir
147
+ );
148
+ }
149
+ __name(runExecute, "runExecute");
150
+ export {
151
+ findFeatureDirs,
152
+ resolveIssuesDir
153
+ };
154
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 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 runWaves,\n} from './orchestrator.js'\nimport {\n findFeatureDirs,\n resolveIssuesDir,\n} from './resolve.js'\n\nexport { findFeatureDirs, resolveIssuesDir }\n\nconst scriptDir = dirname(process.argv[1])\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('dir', {\n type:'string',\n describe:'Path to the issues directory',\n })\n .option('spec', {\n type:'string',\n describe:'Path to the spec file',\n })\n .option('dry-run', {\n type:'boolean',\n describe:'Show wave order without running',\n default:false,\n })\n .option('timeout-secs', {\n type:'number',\n describe:'Kill agent after N seconds',\n default:300,\n }),\n async argv => {\n await runExecute({\n provider:argv.provider as string,\n model:argv.model as string|undefined,\n dir:argv.dir as string|undefined,\n spec:argv.spec as string|undefined,\n dryRun:argv.dryRun as boolean|undefined,\n timeoutSecs:argv.timeoutSecs as\n number|undefined,\n })\n }\n )\n .strict()\n .demandCommand(1, 'Specify a command or provider')\n .help()\n .parse()\n\nasync function runExecute (argv:{\n provider:string\n model?:string\n dir?:string\n spec?:string\n dryRun?:boolean\n timeoutSecs?:number\n}):Promise<void> {\n const { dir, spec } = await resolveIssuesDir(\n argv.dir, 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 if (argv.dryRun) {\n dryRun(tickets, specBody)\n return\n }\n\n const logsDir = join(dirname(dir), 'logs')\n const timeoutSecs = argv.timeoutSecs ?? 300\n await runWaves(\n tickets, specBody,\n argv.provider, argv.model ?? null, timeoutSecs,\n logsDir,\n )\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
package/dist/meta.json ADDED
@@ -0,0 +1,207 @@
1
+ {
2
+ "inputs": {
3
+ "src/index.ts": {
4
+ "bytes": 5325,
5
+ "imports": [],
6
+ "format": "esm"
7
+ },
8
+ "src/orchestrator.ts": {
9
+ "bytes": 8174,
10
+ "imports": [],
11
+ "format": "esm"
12
+ },
13
+ "src/setup.ts": {
14
+ "bytes": 4024,
15
+ "imports": [],
16
+ "format": "esm"
17
+ },
18
+ "src/resolve.ts": {
19
+ "bytes": 1978,
20
+ "imports": [],
21
+ "format": "esm"
22
+ }
23
+ },
24
+ "outputs": {
25
+ "dist/index.js.map": {
26
+ "imports": [],
27
+ "exports": [],
28
+ "inputs": {},
29
+ "bytes": 8282
30
+ },
31
+ "dist/index.js": {
32
+ "imports": [
33
+ {
34
+ "path": "node:fs",
35
+ "kind": "import-statement",
36
+ "external": true
37
+ },
38
+ {
39
+ "path": "node:path",
40
+ "kind": "import-statement",
41
+ "external": true
42
+ },
43
+ {
44
+ "path": "yargs",
45
+ "kind": "import-statement",
46
+ "external": true
47
+ },
48
+ {
49
+ "path": "yargs/helpers",
50
+ "kind": "import-statement",
51
+ "external": true
52
+ },
53
+ {
54
+ "path": "@inquirer/prompts",
55
+ "kind": "import-statement",
56
+ "external": true
57
+ },
58
+ {
59
+ "path": "./setup.js",
60
+ "kind": "import-statement",
61
+ "external": true
62
+ },
63
+ {
64
+ "path": "./orchestrator.js",
65
+ "kind": "import-statement",
66
+ "external": true
67
+ },
68
+ {
69
+ "path": "./resolve.js",
70
+ "kind": "import-statement",
71
+ "external": true
72
+ }
73
+ ],
74
+ "exports": [
75
+ "findFeatureDirs",
76
+ "resolveIssuesDir"
77
+ ],
78
+ "entryPoint": "src/index.ts",
79
+ "inputs": {
80
+ "src/index.ts": {
81
+ "bytesInOutput": 3847
82
+ }
83
+ },
84
+ "bytes": 4080
85
+ },
86
+ "dist/orchestrator.js.map": {
87
+ "imports": [],
88
+ "exports": [],
89
+ "inputs": {},
90
+ "bytes": 13697
91
+ },
92
+ "dist/orchestrator.js": {
93
+ "imports": [
94
+ {
95
+ "path": "node:child_process",
96
+ "kind": "import-statement",
97
+ "external": true
98
+ },
99
+ {
100
+ "path": "node:fs",
101
+ "kind": "import-statement",
102
+ "external": true
103
+ },
104
+ {
105
+ "path": "node:path",
106
+ "kind": "import-statement",
107
+ "external": true
108
+ }
109
+ ],
110
+ "exports": [
111
+ "TICKET_RE",
112
+ "dryRun",
113
+ "findReadyTickets",
114
+ "formatErrorMessage",
115
+ "markDone",
116
+ "parseBlockers",
117
+ "parseStatus",
118
+ "parseTicketFilename",
119
+ "renderPrompt",
120
+ "runWaves",
121
+ "scanTickets",
122
+ "spawnAgent"
123
+ ],
124
+ "entryPoint": "src/orchestrator.ts",
125
+ "inputs": {
126
+ "src/orchestrator.ts": {
127
+ "bytesInOutput": 6754
128
+ }
129
+ },
130
+ "bytes": 7124
131
+ },
132
+ "dist/setup.js.map": {
133
+ "imports": [],
134
+ "exports": [],
135
+ "inputs": {},
136
+ "bytes": 6493
137
+ },
138
+ "dist/setup.js": {
139
+ "imports": [
140
+ {
141
+ "path": "node:fs",
142
+ "kind": "import-statement",
143
+ "external": true
144
+ },
145
+ {
146
+ "path": "node:path",
147
+ "kind": "import-statement",
148
+ "external": true
149
+ },
150
+ {
151
+ "path": "node:child_process",
152
+ "kind": "import-statement",
153
+ "external": true
154
+ }
155
+ ],
156
+ "exports": [
157
+ "DOC_TEMPLATES",
158
+ "SKILL_DIRS",
159
+ "checkGhAuth",
160
+ "setup"
161
+ ],
162
+ "entryPoint": "src/setup.ts",
163
+ "inputs": {
164
+ "src/setup.ts": {
165
+ "bytesInOutput": 3417
166
+ }
167
+ },
168
+ "bytes": 3646
169
+ },
170
+ "dist/resolve.js.map": {
171
+ "imports": [],
172
+ "exports": [],
173
+ "inputs": {},
174
+ "bytes": 3349
175
+ },
176
+ "dist/resolve.js": {
177
+ "imports": [
178
+ {
179
+ "path": "node:fs",
180
+ "kind": "import-statement",
181
+ "external": true
182
+ },
183
+ {
184
+ "path": "node:path",
185
+ "kind": "import-statement",
186
+ "external": true
187
+ },
188
+ {
189
+ "path": "@inquirer/prompts",
190
+ "kind": "import-statement",
191
+ "external": true
192
+ }
193
+ ],
194
+ "exports": [
195
+ "findFeatureDirs",
196
+ "resolveIssuesDir"
197
+ ],
198
+ "entryPoint": "src/resolve.ts",
199
+ "inputs": {
200
+ "src/resolve.ts": {
201
+ "bytesInOutput": 1677
202
+ }
203
+ },
204
+ "bytes": 1892
205
+ }
206
+ }
207
+ }
@@ -0,0 +1,273 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+ import { spawn } from "node:child_process";
4
+ import {
5
+ createWriteStream,
6
+ mkdirSync,
7
+ readFileSync,
8
+ writeFileSync,
9
+ readdirSync
10
+ } from "node:fs";
11
+ import { join } from "node:path";
12
+ function formatErrorMessage(error) {
13
+ return error instanceof Error ? error.message : String(error);
14
+ }
15
+ __name(formatErrorMessage, "formatErrorMessage");
16
+ const TICKET_RE = /^(\d+)-(.+)\.md$/;
17
+ function parseTicketFilename(filename) {
18
+ const m = filename.match(TICKET_RE);
19
+ if (!m) return null;
20
+ return { num: Number(m[1]), slug: m[2] };
21
+ }
22
+ __name(parseTicketFilename, "parseTicketFilename");
23
+ function parseStatus(body) {
24
+ const m = body.match(/\*\*Status:\*\*\s*(.+)/i);
25
+ return m ? m[1].trim().toLowerCase() : "";
26
+ }
27
+ __name(parseStatus, "parseStatus");
28
+ function parseBlockers(body) {
29
+ const m = body.match(/\*\*Blocked by:\*\*\s*(.+)/i);
30
+ if (!m) return [];
31
+ const text = m[1];
32
+ if (/none/i.test(text)) return [];
33
+ const nums = [];
34
+ const re = /(\d+)/g;
35
+ let match;
36
+ while (match = re.exec(text)) {
37
+ nums.push(Number(match[1]));
38
+ }
39
+ return nums;
40
+ }
41
+ __name(parseBlockers, "parseBlockers");
42
+ function scanTickets(dir) {
43
+ const files = readdirSync(dir).filter((f) => TICKET_RE.test(f)).sort((a, b) => a.localeCompare(
44
+ b,
45
+ void 0,
46
+ { numeric: true, sensitivity: "base" }
47
+ ));
48
+ return files.map((filename) => {
49
+ const parsed = parseTicketFilename(filename);
50
+ const filepath = join(dir, filename);
51
+ const body = readFileSync(filepath, "utf8");
52
+ return {
53
+ num: parsed.num,
54
+ slug: parsed.slug,
55
+ filename,
56
+ filepath,
57
+ body,
58
+ status: parseStatus(body),
59
+ blockers: parseBlockers(body)
60
+ };
61
+ });
62
+ }
63
+ __name(scanTickets, "scanTickets");
64
+ function findReadyTickets(tickets) {
65
+ const doneNums = new Set(
66
+ tickets.filter((t) => t.status !== "ready-for-agent").map((t) => t.num)
67
+ );
68
+ return tickets.filter((t) => {
69
+ if (t.status !== "ready-for-agent") return false;
70
+ return t.blockers.every((b) => doneNums.has(b));
71
+ });
72
+ }
73
+ __name(findReadyTickets, "findReadyTickets");
74
+ function markDone(ticket) {
75
+ const updated = ticket.body.replace(
76
+ /\*\*Status:\*\*\s*.+/i,
77
+ "**Status:** done"
78
+ );
79
+ writeFileSync(ticket.filepath, updated);
80
+ ticket.status = "done";
81
+ ticket.body = updated;
82
+ }
83
+ __name(markDone, "markDone");
84
+ function renderPrompt(specBody, ticket) {
85
+ return [
86
+ "---- SPEC CONTEXT ----",
87
+ specBody,
88
+ "",
89
+ "---- TICKET ----",
90
+ ticket.filename,
91
+ ticket.body,
92
+ "",
93
+ "---- AGENT INSTRUCTIONS ----",
94
+ "You are an autonomous coding agent. Implement the ticket.",
95
+ ""
96
+ ].join("\n");
97
+ }
98
+ __name(renderPrompt, "renderPrompt");
99
+ function spawnAgent(opts) {
100
+ const args = [];
101
+ if (opts.model) {
102
+ args.push("--model", opts.model);
103
+ }
104
+ const logStream = createWriteStream(
105
+ opts.logPath,
106
+ { flags: "w" }
107
+ );
108
+ const proc = spawn(opts.agentCmd, args, {
109
+ stdio: ["pipe", "pipe", "pipe"]
110
+ });
111
+ proc.stdout.pipe(logStream);
112
+ proc.stderr.pipe(logStream);
113
+ const timeout = setTimeout(() => {
114
+ if (!proc.killed) {
115
+ console.warn(
116
+ `Agent did not exit in ${opts.timeoutSecs}s; killing.`
117
+ );
118
+ proc.kill("SIGKILL");
119
+ }
120
+ }, opts.timeoutSecs * 1e3);
121
+ proc.stdin.write(opts.prompt);
122
+ proc.stdin.end();
123
+ return new Promise((resolve) => {
124
+ proc.on("close", (code) => {
125
+ clearTimeout(timeout);
126
+ logStream.end();
127
+ resolve(code ?? 1);
128
+ });
129
+ proc.on("error", (err) => {
130
+ clearTimeout(timeout);
131
+ logStream.end();
132
+ console.error(
133
+ "Agent process error:",
134
+ formatErrorMessage(err)
135
+ );
136
+ resolve(1);
137
+ });
138
+ });
139
+ }
140
+ __name(spawnAgent, "spawnAgent");
141
+ function dryRun(tickets, specBody) {
142
+ console.log("\nTickets:");
143
+ for (const t of tickets) {
144
+ const blockerStr = t.blockers.length > 0 ? `blocked by [${t.blockers.join(", ")}]` : "no blockers";
145
+ console.log(
146
+ ` ${t.filename} (${t.status}) ${blockerStr}`
147
+ );
148
+ }
149
+ console.log("\nSimulated wave order:");
150
+ const sim = new Map(
151
+ tickets.map((t) => [t.num, t.status])
152
+ );
153
+ let wave = 1;
154
+ while (true) {
155
+ const doneNums = new Set(
156
+ [...sim.entries()].filter(([, s]) => s !== "ready-for-agent").map(([n]) => n)
157
+ );
158
+ const ready = tickets.filter((t) => {
159
+ if (sim.get(t.num) !== "ready-for-agent") {
160
+ return false;
161
+ }
162
+ return t.blockers.every(
163
+ (b) => doneNums.has(b)
164
+ );
165
+ });
166
+ if (ready.length === 0) break;
167
+ console.log(
168
+ ` Wave ${wave}: ` + ready.map((t) => t.filename).join(", ")
169
+ );
170
+ for (const t of ready) {
171
+ sim.set(t.num, "done");
172
+ }
173
+ wave++;
174
+ }
175
+ const stuck = tickets.filter(
176
+ (t) => sim.get(t.num) === "ready-for-agent"
177
+ );
178
+ if (stuck.length > 0) {
179
+ console.log(
180
+ "\nDeadlocked tickets: " + stuck.map((t) => t.filename).join(", ")
181
+ );
182
+ }
183
+ const firstReady = findReadyTickets(tickets);
184
+ if (firstReady.length > 0) {
185
+ console.log(
186
+ `
187
+ Prompt for first ready ticket (${firstReady[0].filename}):
188
+ `
189
+ );
190
+ console.log(
191
+ renderPrompt(specBody, firstReady[0])
192
+ );
193
+ }
194
+ }
195
+ __name(dryRun, "dryRun");
196
+ async function runWaves(tickets, specBody, agentCmd, model, timeoutSecs, logsDir) {
197
+ mkdirSync(logsDir, { recursive: true });
198
+ let totalCompleted = 0;
199
+ let waveNum = 0;
200
+ while (true) {
201
+ const ready = findReadyTickets(tickets);
202
+ if (ready.length === 0) break;
203
+ waveNum++;
204
+ console.log(
205
+ `
206
+ Wave ${waveNum}: ` + ready.map((t) => t.filename).join(", ")
207
+ );
208
+ const results = await Promise.allSettled(
209
+ ready.map(async (t) => {
210
+ const prompt = renderPrompt(specBody, t);
211
+ const logPath = join(
212
+ logsDir,
213
+ t.filename.replace(/\.md$/, ".log")
214
+ );
215
+ console.log(` Starting ${t.filename}`);
216
+ const code = await spawnAgent({
217
+ prompt,
218
+ agentCmd,
219
+ model,
220
+ timeoutSecs,
221
+ logPath
222
+ });
223
+ return { ticket: t, exitCode: code };
224
+ })
225
+ );
226
+ let waveCompleted = 0;
227
+ for (const r of results) {
228
+ if (r.status === "rejected") continue;
229
+ const { ticket, exitCode } = r.value;
230
+ if (exitCode === 0) {
231
+ markDone(ticket);
232
+ waveCompleted++;
233
+ totalCompleted++;
234
+ console.log(
235
+ ` ${ticket.filename}: done`
236
+ );
237
+ } else {
238
+ console.log(
239
+ ` ${ticket.filename}: agent exited ${exitCode}`
240
+ );
241
+ }
242
+ }
243
+ if (waveCompleted === 0) {
244
+ console.log(
245
+ "\nNo tickets completed this wave. Stopping."
246
+ );
247
+ break;
248
+ }
249
+ }
250
+ const remaining = tickets.filter(
251
+ (t) => t.status === "ready-for-agent"
252
+ );
253
+ console.log(
254
+ `
255
+ Finished: ${totalCompleted} completed` + (remaining.length > 0 ? `, ${remaining.length} remaining` : "")
256
+ );
257
+ }
258
+ __name(runWaves, "runWaves");
259
+ export {
260
+ TICKET_RE,
261
+ dryRun,
262
+ findReadyTickets,
263
+ formatErrorMessage,
264
+ markDone,
265
+ parseBlockers,
266
+ parseStatus,
267
+ parseTicketFilename,
268
+ renderPrompt,
269
+ runWaves,
270
+ scanTickets,
271
+ spawnAgent
272
+ };
273
+ //# sourceMappingURL=orchestrator.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 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 } from 'node:path'\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 !== 'ready-for-agent')\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 ].join('\\n')\n}\n\nexport function spawnAgent (opts:{\n prompt:string\n agentCmd:string\n model:string|null\n timeoutSecs:number\n logPath:string\n}):Promise<number> {\n const args:string[] = []\n if (opts.model) {\n args.push('--model', opts.model)\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 })\n\n proc.stdout.pipe(logStream)\n proc.stderr.pipe(logStream)\n\n const timeout = setTimeout(() => {\n if (!proc.killed) {\n console.warn(\n 'Agent did not exit in ' +\n `${opts.timeoutSecs}s; killing.`\n )\n proc.kill('SIGKILL')\n }\n }, opts.timeoutSecs * 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 logStream.end()\n resolve(code ?? 1)\n })\n proc.on('error', err => {\n clearTimeout(timeout)\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:Ticket[],\n specBody:string\n):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 console.log('\\nSimulated wave order:')\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 !== 'ready-for-agent')\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 console.log(\n ` Wave ${wave}: ` +\n ready.map(t => t.filename).join(', ')\n )\n for (const t of ready) {\n sim.set(t.num, 'done')\n }\n wave++\n }\n\n const stuck = tickets.filter(\n t => sim.get(t.num) === 'ready-for-agent'\n )\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 async function runWaves (\n tickets:Ticket[],\n specBody:string,\n agentCmd:string,\n model:string|null,\n timeoutSecs:number,\n logsDir:string,\n):Promise<void> {\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 console.log(` Starting ${t.filename}`)\n const code = await spawnAgent({\n prompt,\n agentCmd,\n model,\n timeoutSecs,\n logPath,\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 markDone(ticket)\n waveCompleted++\n totalCompleted++\n console.log(\n ` ${ticket.filename}: done`\n )\n } else {\n console.log(\n ` ${ticket.filename}: ` +\n `agent exited ${exitCode}`\n )\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"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }