issue-flow 0.3.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.
- package/README.md +226 -0
- package/dist/analyze-YYQQP64A.js +12 -0
- package/dist/analyze-YYQQP64A.js.map +1 -0
- package/dist/chunk-64FU2L2T.js +180 -0
- package/dist/chunk-64FU2L2T.js.map +1 -0
- package/dist/chunk-7APADNBV.js +68 -0
- package/dist/chunk-7APADNBV.js.map +1 -0
- package/dist/chunk-7FRXZ2XA.js +78 -0
- package/dist/chunk-7FRXZ2XA.js.map +1 -0
- package/dist/chunk-D4WBCVB4.js +85 -0
- package/dist/chunk-D4WBCVB4.js.map +1 -0
- package/dist/chunk-G36DIQ4J.js +80 -0
- package/dist/chunk-G36DIQ4J.js.map +1 -0
- package/dist/chunk-JEUHCE3V.js +123 -0
- package/dist/chunk-JEUHCE3V.js.map +1 -0
- package/dist/chunk-L7RIGFP6.js +92 -0
- package/dist/chunk-L7RIGFP6.js.map +1 -0
- package/dist/chunk-OZVHOVDT.js +43 -0
- package/dist/chunk-OZVHOVDT.js.map +1 -0
- package/dist/chunk-PINC2LST.js +82 -0
- package/dist/chunk-PINC2LST.js.map +1 -0
- package/dist/chunk-V356G3JS.js +611 -0
- package/dist/chunk-V356G3JS.js.map +1 -0
- package/dist/chunk-ZOX7M2C2.js +85 -0
- package/dist/chunk-ZOX7M2C2.js.map +1 -0
- package/dist/cli.js +76 -0
- package/dist/cli.js.map +1 -0
- package/dist/execute-UF3IY2MG.js +11 -0
- package/dist/execute-UF3IY2MG.js.map +1 -0
- package/dist/generate-WMYJEPI4.js +48 -0
- package/dist/generate-WMYJEPI4.js.map +1 -0
- package/dist/init-QES2HLP5.js +9 -0
- package/dist/init-QES2HLP5.js.map +1 -0
- package/dist/plan-BKSUDN34.js +12 -0
- package/dist/plan-BKSUDN34.js.map +1 -0
- package/dist/pr-E2ASXBWE.js +12 -0
- package/dist/pr-E2ASXBWE.js.map +1 -0
- package/dist/prd-WYW35SGL.js +12 -0
- package/dist/prd-WYW35SGL.js.map +1 -0
- package/dist/review-YI2WPNC4.js +12 -0
- package/dist/review-YI2WPNC4.js.map +1 -0
- package/dist/run-J62FIB5O.js +288 -0
- package/dist/run-J62FIB5O.js.map +1 -0
- package/package.json +58 -0
- package/prompts/analyze.md +28 -0
- package/prompts/execute.md +124 -0
- package/prompts/generate.md +19 -0
- package/prompts/plan.md +49 -0
- package/prompts/pr.md +19 -0
- package/prompts/prd.md +30 -0
- package/prompts/review.md +27 -0
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
runReview
|
|
4
|
+
} from "./chunk-D4WBCVB4.js";
|
|
5
|
+
import {
|
|
6
|
+
runInit
|
|
7
|
+
} from "./chunk-JEUHCE3V.js";
|
|
8
|
+
import {
|
|
9
|
+
runAnalyze
|
|
10
|
+
} from "./chunk-7APADNBV.js";
|
|
11
|
+
import {
|
|
12
|
+
runExecute
|
|
13
|
+
} from "./chunk-V356G3JS.js";
|
|
14
|
+
import {
|
|
15
|
+
runPlan
|
|
16
|
+
} from "./chunk-ZOX7M2C2.js";
|
|
17
|
+
import {
|
|
18
|
+
runPr
|
|
19
|
+
} from "./chunk-7FRXZ2XA.js";
|
|
20
|
+
import {
|
|
21
|
+
runPrd
|
|
22
|
+
} from "./chunk-G36DIQ4J.js";
|
|
23
|
+
import "./chunk-PINC2LST.js";
|
|
24
|
+
import {
|
|
25
|
+
isoNow,
|
|
26
|
+
loadTaskPlan,
|
|
27
|
+
saveTaskPlan
|
|
28
|
+
} from "./chunk-64FU2L2T.js";
|
|
29
|
+
import "./chunk-OZVHOVDT.js";
|
|
30
|
+
import {
|
|
31
|
+
printError,
|
|
32
|
+
printInfo,
|
|
33
|
+
printSuccess,
|
|
34
|
+
printWarning
|
|
35
|
+
} from "./chunk-L7RIGFP6.js";
|
|
36
|
+
|
|
37
|
+
// src/commands/run.ts
|
|
38
|
+
import { join } from "path";
|
|
39
|
+
import { execa } from "execa";
|
|
40
|
+
|
|
41
|
+
// src/core/pipeline.ts
|
|
42
|
+
var PIPELINE_PHASES = [
|
|
43
|
+
"init",
|
|
44
|
+
"analyze",
|
|
45
|
+
"prd",
|
|
46
|
+
"plan",
|
|
47
|
+
"execute",
|
|
48
|
+
"review",
|
|
49
|
+
"pr"
|
|
50
|
+
];
|
|
51
|
+
var PHASE_TO_FIELD = {
|
|
52
|
+
init: null,
|
|
53
|
+
analyze: "analyzeCompleted",
|
|
54
|
+
prd: "prdCompleted",
|
|
55
|
+
plan: "jsonCompleted",
|
|
56
|
+
execute: "executionCompleted",
|
|
57
|
+
review: "reviewCompleted",
|
|
58
|
+
pr: "prCreated"
|
|
59
|
+
};
|
|
60
|
+
var PipelineManager = class {
|
|
61
|
+
tasksJsonPath;
|
|
62
|
+
plan;
|
|
63
|
+
constructor(plan, tasksJsonPath) {
|
|
64
|
+
this.plan = plan;
|
|
65
|
+
this.tasksJsonPath = tasksJsonPath;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Reload state from disk.
|
|
69
|
+
*/
|
|
70
|
+
async reload() {
|
|
71
|
+
this.plan = await loadTaskPlan(this.tasksJsonPath);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Check if a phase is complete.
|
|
75
|
+
*/
|
|
76
|
+
isPhaseComplete(phase) {
|
|
77
|
+
const field = PHASE_TO_FIELD[phase];
|
|
78
|
+
if (field === null) return true;
|
|
79
|
+
return this.plan.pipeline?.[field] ?? false;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Get the first incomplete phase in the pipeline.
|
|
83
|
+
* Returns null if all phases are complete.
|
|
84
|
+
*/
|
|
85
|
+
getNextPhase() {
|
|
86
|
+
for (const phase of PIPELINE_PHASES) {
|
|
87
|
+
if (!this.isPhaseComplete(phase)) {
|
|
88
|
+
return phase;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Get the current phase (alias for getNextPhase).
|
|
95
|
+
*/
|
|
96
|
+
getCurrentPhase() {
|
|
97
|
+
return this.getNextPhase();
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Check whether we can resume from a specific phase.
|
|
101
|
+
* All prerequisite phases must be complete.
|
|
102
|
+
*/
|
|
103
|
+
canResume(fromPhase) {
|
|
104
|
+
const idx = PIPELINE_PHASES.indexOf(fromPhase);
|
|
105
|
+
if (idx < 0) return false;
|
|
106
|
+
for (let i = 0; i < idx; i++) {
|
|
107
|
+
if (!this.isPhaseComplete(PIPELINE_PHASES[i])) {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Mark a phase as complete and persist to disk.
|
|
115
|
+
*/
|
|
116
|
+
async markPhaseComplete(phase) {
|
|
117
|
+
const field = PHASE_TO_FIELD[phase];
|
|
118
|
+
if (field === null) return;
|
|
119
|
+
this.plan = {
|
|
120
|
+
...this.plan,
|
|
121
|
+
pipeline: {
|
|
122
|
+
...this.plan.pipeline ?? {
|
|
123
|
+
analyzeCompleted: false,
|
|
124
|
+
prdCompleted: false,
|
|
125
|
+
jsonCompleted: false,
|
|
126
|
+
executionCompleted: false,
|
|
127
|
+
reviewCompleted: false,
|
|
128
|
+
prCreated: false
|
|
129
|
+
},
|
|
130
|
+
[field]: true
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
await saveTaskPlan(this.tasksJsonPath, this.plan);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
// src/commands/run.ts
|
|
138
|
+
async function runPipeline(issue, mode, from) {
|
|
139
|
+
const issueNumber = issue.replace(/^#/, "");
|
|
140
|
+
const issueDir = join("issues", issueNumber);
|
|
141
|
+
const tasksPath = join(issueDir, "tasks.json");
|
|
142
|
+
printInfo(`Starting pipeline for issue #${issueNumber} (mode: ${mode})`);
|
|
143
|
+
printInfo("Running prerequisite checks...");
|
|
144
|
+
const initCode = await runInit();
|
|
145
|
+
if (initCode !== 0) {
|
|
146
|
+
printError("Prerequisites not met. Fix the issues above and try again.");
|
|
147
|
+
return 1;
|
|
148
|
+
}
|
|
149
|
+
let startPhase = "analyze";
|
|
150
|
+
if (from) {
|
|
151
|
+
if (!PIPELINE_PHASES.includes(from)) {
|
|
152
|
+
printError(`Invalid phase: ${from}. Valid phases: ${PIPELINE_PHASES.join(", ")}`);
|
|
153
|
+
return 1;
|
|
154
|
+
}
|
|
155
|
+
startPhase = from;
|
|
156
|
+
} else {
|
|
157
|
+
try {
|
|
158
|
+
const plan = await loadTaskPlan(tasksPath);
|
|
159
|
+
const mgr = new PipelineManager(plan, tasksPath);
|
|
160
|
+
const nextPhase = mgr.getNextPhase();
|
|
161
|
+
if (nextPhase && nextPhase !== "init") {
|
|
162
|
+
startPhase = nextPhase;
|
|
163
|
+
printInfo(`Resuming from phase: ${startPhase}`);
|
|
164
|
+
}
|
|
165
|
+
} catch {
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if (from) {
|
|
169
|
+
try {
|
|
170
|
+
const plan = await loadTaskPlan(tasksPath);
|
|
171
|
+
const mgr = new PipelineManager(plan, tasksPath);
|
|
172
|
+
if (!mgr.canResume(startPhase)) {
|
|
173
|
+
printError(`Cannot resume from ${startPhase}: prerequisite phases not complete`);
|
|
174
|
+
return 1;
|
|
175
|
+
}
|
|
176
|
+
} catch {
|
|
177
|
+
if (startPhase !== "analyze") {
|
|
178
|
+
printError(`Cannot resume from ${startPhase}: no pipeline state found`);
|
|
179
|
+
return 1;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
const phaseOrder = ["analyze", "prd", "plan", "execute", "review", "pr"];
|
|
184
|
+
const startIdx = phaseOrder.indexOf(startPhase);
|
|
185
|
+
for (let i = startIdx; i < phaseOrder.length; i++) {
|
|
186
|
+
const phase = phaseOrder[i];
|
|
187
|
+
printInfo(`
|
|
188
|
+
--- Phase: ${phase} ---`);
|
|
189
|
+
let code;
|
|
190
|
+
switch (phase) {
|
|
191
|
+
case "analyze":
|
|
192
|
+
code = await runAnalyze(issueNumber);
|
|
193
|
+
break;
|
|
194
|
+
case "prd":
|
|
195
|
+
code = await runPrd(issueNumber);
|
|
196
|
+
break;
|
|
197
|
+
case "plan":
|
|
198
|
+
code = await runPlan(issueNumber);
|
|
199
|
+
break;
|
|
200
|
+
case "execute":
|
|
201
|
+
code = await runExecute(void 0, { issue: issueNumber });
|
|
202
|
+
break;
|
|
203
|
+
case "review": {
|
|
204
|
+
let maxCycles = 3;
|
|
205
|
+
try {
|
|
206
|
+
const plan = await loadTaskPlan(tasksPath);
|
|
207
|
+
maxCycles = plan.maxCorrectionCycles;
|
|
208
|
+
} catch {
|
|
209
|
+
}
|
|
210
|
+
code = await runReview(issueNumber);
|
|
211
|
+
let cycle = 0;
|
|
212
|
+
while (code !== 0 && cycle < maxCycles) {
|
|
213
|
+
cycle++;
|
|
214
|
+
printWarning(`Review failed. Starting correction cycle ${cycle}/${maxCycles}...`);
|
|
215
|
+
try {
|
|
216
|
+
const plan = await loadTaskPlan(tasksPath);
|
|
217
|
+
plan.correctionCycle = cycle;
|
|
218
|
+
await saveTaskPlan(tasksPath, plan);
|
|
219
|
+
} catch {
|
|
220
|
+
}
|
|
221
|
+
const execCode = await runExecute(void 0, { issue: issueNumber });
|
|
222
|
+
if (execCode !== 0) {
|
|
223
|
+
printError("Correction execution failed");
|
|
224
|
+
return 1;
|
|
225
|
+
}
|
|
226
|
+
code = await runReview(issueNumber);
|
|
227
|
+
}
|
|
228
|
+
if (code !== 0) {
|
|
229
|
+
printError(`Review failed after ${maxCycles} correction cycles`);
|
|
230
|
+
return 1;
|
|
231
|
+
}
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
case "pr":
|
|
235
|
+
code = await runPr(issueNumber);
|
|
236
|
+
break;
|
|
237
|
+
default:
|
|
238
|
+
code = 1;
|
|
239
|
+
}
|
|
240
|
+
if (code !== 0) {
|
|
241
|
+
printError(`Phase ${phase} failed with exit code ${code}`);
|
|
242
|
+
return 1;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
printInfo("Closing issue...");
|
|
246
|
+
try {
|
|
247
|
+
await execa("gh", ["issue", "close", issueNumber], { reject: false });
|
|
248
|
+
} catch {
|
|
249
|
+
printWarning("Failed to close issue automatically");
|
|
250
|
+
}
|
|
251
|
+
let prUrl = "unknown";
|
|
252
|
+
try {
|
|
253
|
+
const proc = await execa("gh", ["pr", "list", "--head", "", "--json", "url", "--limit", "1"], {
|
|
254
|
+
reject: false
|
|
255
|
+
});
|
|
256
|
+
const parsed = JSON.parse(proc.stdout?.toString() ?? "[]");
|
|
257
|
+
if (parsed[0]?.url) {
|
|
258
|
+
prUrl = parsed[0].url;
|
|
259
|
+
}
|
|
260
|
+
} catch {
|
|
261
|
+
}
|
|
262
|
+
let branchName = "unknown";
|
|
263
|
+
try {
|
|
264
|
+
const proc = await execa("git", ["branch", "--show-current"], { reject: false });
|
|
265
|
+
branchName = proc.stdout?.toString().trim() ?? "unknown";
|
|
266
|
+
} catch {
|
|
267
|
+
}
|
|
268
|
+
let storyCount = 0;
|
|
269
|
+
try {
|
|
270
|
+
const plan = await loadTaskPlan(tasksPath);
|
|
271
|
+
storyCount = plan.userStories.length;
|
|
272
|
+
plan.issueStatus = "completed";
|
|
273
|
+
plan.completedAt = isoNow();
|
|
274
|
+
plan.lastAttemptAt = isoNow();
|
|
275
|
+
await saveTaskPlan(tasksPath, plan);
|
|
276
|
+
} catch {
|
|
277
|
+
}
|
|
278
|
+
console.log("");
|
|
279
|
+
printSuccess(`Pipeline complete for issue #${issueNumber}!`);
|
|
280
|
+
console.log(` Branch: ${branchName}`);
|
|
281
|
+
console.log(` Stories: ${storyCount}`);
|
|
282
|
+
console.log(` PR: ${prUrl}`);
|
|
283
|
+
return 0;
|
|
284
|
+
}
|
|
285
|
+
export {
|
|
286
|
+
runPipeline
|
|
287
|
+
};
|
|
288
|
+
//# sourceMappingURL=run-J62FIB5O.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/run.ts","../src/core/pipeline.ts"],"sourcesContent":["import { join } from 'node:path';\nimport { execa } from 'execa';\nimport { PIPELINE_PHASES, PipelineManager, type PipelinePhase } from '../core/pipeline.js';\nimport { isoNow, loadTaskPlan, saveTaskPlan } from '../core/state-manager.js';\nimport { printError, printInfo, printSuccess, printWarning } from '../ui/logger.js';\nimport { runAnalyze } from './analyze.js';\nimport { runExecute } from './execute.js';\nimport { runInit } from './init.js';\nimport { runPlan } from './plan.js';\nimport { runPr } from './pr.js';\nimport { runPrd } from './prd.js';\nimport { runReview } from './review.js';\n\nexport async function runPipeline(issue: string, mode: string, from?: string): Promise<number> {\n const issueNumber = issue.replace(/^#/, '');\n const issueDir = join('issues', issueNumber);\n const tasksPath = join(issueDir, 'tasks.json');\n\n printInfo(`Starting pipeline for issue #${issueNumber} (mode: ${mode})`);\n\n // Phase 1: Init check\n printInfo('Running prerequisite checks...');\n const initCode = await runInit();\n if (initCode !== 0) {\n printError('Prerequisites not met. Fix the issues above and try again.');\n return 1;\n }\n\n // Determine starting phase\n let startPhase: PipelinePhase = 'analyze';\n if (from) {\n if (!PIPELINE_PHASES.includes(from as PipelinePhase)) {\n printError(`Invalid phase: ${from}. Valid phases: ${PIPELINE_PHASES.join(', ')}`);\n return 1;\n }\n startPhase = from as PipelinePhase;\n } else {\n // Try to auto-resume from pipeline state\n try {\n const plan = await loadTaskPlan(tasksPath);\n const mgr = new PipelineManager(plan, tasksPath);\n const nextPhase = mgr.getNextPhase();\n if (nextPhase && nextPhase !== 'init') {\n startPhase = nextPhase;\n printInfo(`Resuming from phase: ${startPhase}`);\n }\n } catch {\n // No tasks.json yet — start from beginning\n }\n }\n\n // Validate resume prerequisites if starting from a later phase\n if (from) {\n try {\n const plan = await loadTaskPlan(tasksPath);\n const mgr = new PipelineManager(plan, tasksPath);\n if (!mgr.canResume(startPhase)) {\n printError(`Cannot resume from ${startPhase}: prerequisite phases not complete`);\n return 1;\n }\n } catch {\n if (startPhase !== 'analyze') {\n printError(`Cannot resume from ${startPhase}: no pipeline state found`);\n return 1;\n }\n }\n }\n\n const phaseOrder: PipelinePhase[] = ['analyze', 'prd', 'plan', 'execute', 'review', 'pr'];\n const startIdx = phaseOrder.indexOf(startPhase);\n\n for (let i = startIdx; i < phaseOrder.length; i++) {\n const phase = phaseOrder[i];\n printInfo(`\\n--- Phase: ${phase} ---`);\n\n let code: number;\n switch (phase) {\n case 'analyze':\n code = await runAnalyze(issueNumber);\n break;\n case 'prd':\n code = await runPrd(issueNumber);\n break;\n case 'plan':\n code = await runPlan(issueNumber);\n break;\n case 'execute':\n code = await runExecute(undefined, { issue: issueNumber });\n break;\n case 'review': {\n // Read maxCorrectionCycles\n let maxCycles = 3;\n try {\n const plan = await loadTaskPlan(tasksPath);\n maxCycles = plan.maxCorrectionCycles;\n } catch {\n /* use default */\n }\n\n code = await runReview(issueNumber);\n\n // Auto-correction loop on failure\n let cycle = 0;\n while (code !== 0 && cycle < maxCycles) {\n cycle++;\n printWarning(`Review failed. Starting correction cycle ${cycle}/${maxCycles}...`);\n\n // Update correction cycle in tasks.json\n try {\n const plan = await loadTaskPlan(tasksPath);\n plan.correctionCycle = cycle;\n await saveTaskPlan(tasksPath, plan);\n } catch {\n /* non-critical */\n }\n\n // Re-execute\n const execCode = await runExecute(undefined, { issue: issueNumber });\n if (execCode !== 0) {\n printError('Correction execution failed');\n return 1;\n }\n\n // Re-review\n code = await runReview(issueNumber);\n }\n\n if (code !== 0) {\n printError(`Review failed after ${maxCycles} correction cycles`);\n return 1;\n }\n break;\n }\n case 'pr':\n code = await runPr(issueNumber);\n break;\n default:\n code = 1;\n }\n\n if (code !== 0) {\n printError(`Phase ${phase} failed with exit code ${code}`);\n return 1;\n }\n }\n\n // Close the issue\n printInfo('Closing issue...');\n try {\n await execa('gh', ['issue', 'close', issueNumber], { reject: false });\n } catch {\n printWarning('Failed to close issue automatically');\n }\n\n // Get PR URL for summary\n let prUrl = 'unknown';\n try {\n const proc = await execa('gh', ['pr', 'list', '--head', '', '--json', 'url', '--limit', '1'], {\n reject: false,\n });\n const parsed = JSON.parse(proc.stdout?.toString() ?? '[]');\n if (parsed[0]?.url) {\n prUrl = parsed[0].url;\n }\n } catch {\n /* non-critical */\n }\n\n // Get branch and story count\n let branchName = 'unknown';\n try {\n const proc = await execa('git', ['branch', '--show-current'], { reject: false });\n branchName = proc.stdout?.toString().trim() ?? 'unknown';\n } catch {\n /* non-critical */\n }\n\n let storyCount = 0;\n try {\n const plan = await loadTaskPlan(tasksPath);\n storyCount = plan.userStories.length;\n\n // Mark as completed\n plan.issueStatus = 'completed';\n plan.completedAt = isoNow();\n plan.lastAttemptAt = isoNow();\n await saveTaskPlan(tasksPath, plan);\n } catch {\n /* non-critical */\n }\n\n console.log('');\n printSuccess(`Pipeline complete for issue #${issueNumber}!`);\n console.log(` Branch: ${branchName}`);\n console.log(` Stories: ${storyCount}`);\n console.log(` PR: ${prUrl}`);\n\n return 0;\n}\n","import type { PipelineState, TaskPlan } from '../types.js';\nimport { loadTaskPlan, saveTaskPlan } from './state-manager.js';\n\n/**\n * Ordered pipeline phases. Each phase must complete before the next can start.\n */\nexport const PIPELINE_PHASES = [\n 'init',\n 'analyze',\n 'prd',\n 'plan',\n 'execute',\n 'review',\n 'pr',\n] as const;\n\nexport type PipelinePhase = (typeof PIPELINE_PHASES)[number];\n\n/**\n * Map pipeline phases to their corresponding PipelineState field.\n * 'init' has no persisted state — it's a runtime-only check.\n */\nconst PHASE_TO_FIELD: Record<PipelinePhase, keyof PipelineState | null> = {\n init: null,\n analyze: 'analyzeCompleted',\n prd: 'prdCompleted',\n plan: 'jsonCompleted',\n execute: 'executionCompleted',\n review: 'reviewCompleted',\n pr: 'prCreated',\n};\n\nexport class PipelineManager {\n private tasksJsonPath: string;\n private plan: TaskPlan;\n\n constructor(plan: TaskPlan, tasksJsonPath: string) {\n this.plan = plan;\n this.tasksJsonPath = tasksJsonPath;\n }\n\n /**\n * Reload state from disk.\n */\n async reload(): Promise<void> {\n this.plan = await loadTaskPlan(this.tasksJsonPath);\n }\n\n /**\n * Check if a phase is complete.\n */\n isPhaseComplete(phase: PipelinePhase): boolean {\n const field = PHASE_TO_FIELD[phase];\n if (field === null) return true; // init is always \"complete\" after running\n return this.plan.pipeline?.[field] ?? false;\n }\n\n /**\n * Get the first incomplete phase in the pipeline.\n * Returns null if all phases are complete.\n */\n getNextPhase(): PipelinePhase | null {\n for (const phase of PIPELINE_PHASES) {\n if (!this.isPhaseComplete(phase)) {\n return phase;\n }\n }\n return null;\n }\n\n /**\n * Get the current phase (alias for getNextPhase).\n */\n getCurrentPhase(): PipelinePhase | null {\n return this.getNextPhase();\n }\n\n /**\n * Check whether we can resume from a specific phase.\n * All prerequisite phases must be complete.\n */\n canResume(fromPhase: PipelinePhase): boolean {\n const idx = PIPELINE_PHASES.indexOf(fromPhase);\n if (idx < 0) return false;\n\n // All phases before fromPhase must be complete\n for (let i = 0; i < idx; i++) {\n if (!this.isPhaseComplete(PIPELINE_PHASES[i])) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * Mark a phase as complete and persist to disk.\n */\n async markPhaseComplete(phase: PipelinePhase): Promise<void> {\n const field = PHASE_TO_FIELD[phase];\n if (field === null) return; // init has no persisted state\n\n this.plan = {\n ...this.plan,\n pipeline: {\n ...(this.plan.pipeline ?? {\n analyzeCompleted: false,\n prdCompleted: false,\n jsonCompleted: false,\n executionCompleted: false,\n reviewCompleted: false,\n prCreated: false,\n }),\n [field]: true,\n },\n };\n\n await saveTaskPlan(this.tasksJsonPath, this.plan);\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "issue-flow",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Unified CLI for orchestrating the full issue-flow pipeline via Claude Code Headless",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"issue-flow": "./dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsup",
|
|
11
|
+
"dev": "tsup --watch",
|
|
12
|
+
"typecheck": "tsc --noEmit",
|
|
13
|
+
"test": "vitest run",
|
|
14
|
+
"test:watch": "vitest",
|
|
15
|
+
"lint": "biome check src/",
|
|
16
|
+
"lint:fix": "biome check --write src/",
|
|
17
|
+
"format": "biome format --write src/",
|
|
18
|
+
"check": "biome check --write src/ && tsc --noEmit"
|
|
19
|
+
},
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=18.0.0"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist",
|
|
25
|
+
"prompts"
|
|
26
|
+
],
|
|
27
|
+
"keywords": [
|
|
28
|
+
"ai",
|
|
29
|
+
"agent",
|
|
30
|
+
"claude",
|
|
31
|
+
"automation",
|
|
32
|
+
"cli",
|
|
33
|
+
"pipeline",
|
|
34
|
+
"headless",
|
|
35
|
+
"issue-flow",
|
|
36
|
+
"github"
|
|
37
|
+
],
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "https://github.com/fabioassuncao/issue-flow.git",
|
|
42
|
+
"directory": "packages/issue-flow"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"chalk": "^5.4.1",
|
|
46
|
+
"commander": "^13.1.0",
|
|
47
|
+
"execa": "^9.5.2",
|
|
48
|
+
"ora": "^8.2.0",
|
|
49
|
+
"zod": "^4.3.6"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@biomejs/biome": "^2.4.10",
|
|
53
|
+
"@types/node": "^22.14.0",
|
|
54
|
+
"tsup": "^8.4.0",
|
|
55
|
+
"typescript": "^5.8.3",
|
|
56
|
+
"vitest": "^3.1.1"
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
You are analyzing GitHub issue #__ISSUE_NUMBER__ for this repository.
|
|
2
|
+
|
|
3
|
+
Steps:
|
|
4
|
+
1. Fetch the issue data using: gh issue view __ISSUE_NUMBER__ --json title,body,labels,comments
|
|
5
|
+
2. Analyze the codebase to understand the affected areas, tech stack, and architecture
|
|
6
|
+
3. Identify the scope, complexity, and key files/modules involved
|
|
7
|
+
4. Produce a structured analysis
|
|
8
|
+
|
|
9
|
+
Save your analysis to __ANALYSIS_PATH__ with this structure:
|
|
10
|
+
|
|
11
|
+
# Issue Analysis: #__ISSUE_NUMBER__
|
|
12
|
+
|
|
13
|
+
## Summary
|
|
14
|
+
[Brief description of the issue]
|
|
15
|
+
|
|
16
|
+
## Affected Areas
|
|
17
|
+
[List files, modules, or systems affected]
|
|
18
|
+
|
|
19
|
+
## Technical Context
|
|
20
|
+
[Relevant architecture, patterns, dependencies]
|
|
21
|
+
|
|
22
|
+
## Complexity Assessment
|
|
23
|
+
[Low/Medium/High with justification]
|
|
24
|
+
|
|
25
|
+
## Implementation Notes
|
|
26
|
+
[Key considerations, risks, dependencies]
|
|
27
|
+
|
|
28
|
+
IMPORTANT: You MUST write the analysis to the file path above. Do not just output it.
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# Issue Flow Agent Instructions
|
|
2
|
+
|
|
3
|
+
You are an autonomous coding agent working on a software project.
|
|
4
|
+
|
|
5
|
+
## Your Task
|
|
6
|
+
|
|
7
|
+
1. Read the PRD at `__PRD_FILE__`
|
|
8
|
+
2. Read the progress log at `__PROGRESS_FILE__` (check Codebase Patterns section first)
|
|
9
|
+
3. Check you're on the correct branch from PRD `branchName`. If not, check it out or create from main.
|
|
10
|
+
4. Treat the issue as unresolved unless **every** `userStories[].passes` value is `true`
|
|
11
|
+
5. Pick the **highest priority** user story where `passes: false`
|
|
12
|
+
6. Implement that single user story
|
|
13
|
+
7. Run quality checks (e.g., typecheck, lint, test - use whatever your project requires)
|
|
14
|
+
8. Update CLAUDE.md files if you discover reusable patterns (see below)
|
|
15
|
+
9. If checks pass, commit ALL changes with message: `feat: [Story ID] - [Story Title]`
|
|
16
|
+
10. Update the PRD to set `passes: true` for the completed story
|
|
17
|
+
11. Append your progress to `__PROGRESS_FILE__`
|
|
18
|
+
|
|
19
|
+
## Progress Report Format
|
|
20
|
+
|
|
21
|
+
APPEND to `__PROGRESS_FILE__` (never replace, always append):
|
|
22
|
+
```
|
|
23
|
+
## [Date/Time] - [Story ID]
|
|
24
|
+
- What was implemented
|
|
25
|
+
- Files changed
|
|
26
|
+
- **Learnings for future iterations:**
|
|
27
|
+
- Patterns discovered (e.g., "this codebase uses X for Y")
|
|
28
|
+
- Gotchas encountered (e.g., "don't forget to update Z when changing W")
|
|
29
|
+
- Useful context (e.g., "the evaluation panel is in component X")
|
|
30
|
+
---
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The learnings section is critical - it helps future iterations avoid repeating mistakes and understand the codebase better.
|
|
34
|
+
|
|
35
|
+
## Consolidate Patterns
|
|
36
|
+
|
|
37
|
+
If you discover a **reusable pattern** that future iterations should know, add it to the `## Codebase Patterns` section at the TOP of `__PROGRESS_FILE__` (create it if it doesn't exist). This section should consolidate the most important learnings:
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
## Codebase Patterns
|
|
41
|
+
- Example: Use `sql<number>` template for aggregations
|
|
42
|
+
- Example: Always use `IF NOT EXISTS` for migrations
|
|
43
|
+
- Example: Export types from actions.ts for UI components
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Only add patterns that are **general and reusable**, not story-specific details.
|
|
47
|
+
|
|
48
|
+
## Update CLAUDE.md Files
|
|
49
|
+
|
|
50
|
+
Before committing, check if any edited files have learnings worth preserving in nearby CLAUDE.md files:
|
|
51
|
+
|
|
52
|
+
1. **Identify directories with edited files** - Look at which directories you modified
|
|
53
|
+
2. **Check for existing CLAUDE.md** - Look for CLAUDE.md in those directories or parent directories
|
|
54
|
+
3. **Add valuable learnings** - If you discovered something future developers/agents should know:
|
|
55
|
+
- API patterns or conventions specific to that module
|
|
56
|
+
- Gotchas or non-obvious requirements
|
|
57
|
+
- Dependencies between files
|
|
58
|
+
- Testing approaches for that area
|
|
59
|
+
- Configuration or environment requirements
|
|
60
|
+
|
|
61
|
+
**Examples of good CLAUDE.md additions:**
|
|
62
|
+
- "When modifying X, also update Y to keep them in sync"
|
|
63
|
+
- "This module uses pattern Z for all API calls"
|
|
64
|
+
- "Tests require the dev server running on PORT 3000"
|
|
65
|
+
- "Field names must match the template exactly"
|
|
66
|
+
|
|
67
|
+
**Do NOT add:**
|
|
68
|
+
- Story-specific implementation details
|
|
69
|
+
- Temporary debugging notes
|
|
70
|
+
- Information already in progress.txt
|
|
71
|
+
|
|
72
|
+
Only update CLAUDE.md if you have **genuinely reusable knowledge** that would help future work in that directory.
|
|
73
|
+
|
|
74
|
+
## Quality Requirements
|
|
75
|
+
|
|
76
|
+
- ALL commits must pass your project's quality checks (typecheck, lint, test)
|
|
77
|
+
- Do NOT commit broken code
|
|
78
|
+
- Keep changes focused and minimal
|
|
79
|
+
- Follow existing code patterns
|
|
80
|
+
|
|
81
|
+
## Browser Testing (If Available)
|
|
82
|
+
|
|
83
|
+
For any story that changes UI, verify it works in the browser if you have browser testing tools configured (e.g., via MCP):
|
|
84
|
+
|
|
85
|
+
1. Navigate to the relevant page
|
|
86
|
+
2. Verify the UI changes work as expected
|
|
87
|
+
3. Take a screenshot if helpful for the progress log
|
|
88
|
+
|
|
89
|
+
If no browser tools are available, note in your progress report that manual browser verification is needed.
|
|
90
|
+
|
|
91
|
+
## Pipeline State Tracking
|
|
92
|
+
|
|
93
|
+
The task plan may contain a `pipeline` object that tracks orchestrator phase completion. Update these fields as appropriate:
|
|
94
|
+
|
|
95
|
+
- After completing a story: set `pipeline.executionCompleted` to `false` (still in progress)
|
|
96
|
+
- After ALL stories complete: set `pipeline.executionCompleted` to `true`
|
|
97
|
+
|
|
98
|
+
The task plan may also contain `correctionCycle` and `maxCorrectionCycles` fields. These track how many review-fix cycles have occurred. The execution loop does not manage the correction loop — that is handled by the orchestrator or manually.
|
|
99
|
+
|
|
100
|
+
If these fields don't exist in the task plan (older format), ignore them — they are optional.
|
|
101
|
+
|
|
102
|
+
## Stop Condition
|
|
103
|
+
|
|
104
|
+
After completing a user story, check if ALL stories have `passes: true`.
|
|
105
|
+
|
|
106
|
+
If ALL stories are complete and passing, first update the task plan metadata:
|
|
107
|
+
- Set `issueStatus` to `completed`
|
|
108
|
+
- Set `completedAt` to the current ISO timestamp
|
|
109
|
+
- Set `lastAttemptAt` to the current ISO timestamp
|
|
110
|
+
- Clear `lastError`
|
|
111
|
+
- If `pipeline` object exists, set `pipeline.executionCompleted` to `true`
|
|
112
|
+
|
|
113
|
+
Then reply with:
|
|
114
|
+
<promise>COMPLETE</promise>
|
|
115
|
+
|
|
116
|
+
If there are still stories with `passes: false`, end your response normally (another iteration will pick up the next story).
|
|
117
|
+
If you need to stop for user guidance or another non-transient blocker, record it in top-level `lastError` and do not clear it.
|
|
118
|
+
|
|
119
|
+
## Important
|
|
120
|
+
|
|
121
|
+
- Work on ONE story per iteration
|
|
122
|
+
- Commit frequently
|
|
123
|
+
- Keep CI green
|
|
124
|
+
- Read the Codebase Patterns section in `__PROGRESS_FILE__` before starting
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
You are creating a GitHub issue for this repository.
|
|
2
|
+
|
|
3
|
+
The user provided this description:
|
|
4
|
+
__USER_PROMPT__
|
|
5
|
+
|
|
6
|
+
Steps:
|
|
7
|
+
1. Analyze the project's tech stack, architecture, and codebase
|
|
8
|
+
2. Check for duplicate issues: gh issue list --state open --search "<keywords>"
|
|
9
|
+
3. Create a well-structured GitHub issue using gh issue create
|
|
10
|
+
|
|
11
|
+
The issue should:
|
|
12
|
+
- Have a clear, descriptive title
|
|
13
|
+
- Include context about why the change is needed
|
|
14
|
+
- Include acceptance criteria
|
|
15
|
+
- Add appropriate labels (create them if they don't exist)
|
|
16
|
+
|
|
17
|
+
Use: gh issue create --title "..." --body "..."
|
|
18
|
+
|
|
19
|
+
IMPORTANT: Output the issue URL after creation so it can be parsed.
|
package/prompts/plan.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
You are converting a PRD into a structured JSON task plan for issue #__ISSUE_NUMBER__.
|
|
2
|
+
|
|
3
|
+
Here is the PRD:
|
|
4
|
+
|
|
5
|
+
__PRD_CONTENT__
|
|
6
|
+
|
|
7
|
+
Create a tasks.json file at __TASKS_PATH__ with this exact structure:
|
|
8
|
+
|
|
9
|
+
{
|
|
10
|
+
"project": "<repo-name>",
|
|
11
|
+
"issueNumber": __ISSUE_NUMBER__,
|
|
12
|
+
"issueUrl": "<github-issue-url>",
|
|
13
|
+
"branchName": "issue/__ISSUE_NUMBER__-<slug>",
|
|
14
|
+
"description": "<brief description>",
|
|
15
|
+
"issueStatus": "pending",
|
|
16
|
+
"completedAt": null,
|
|
17
|
+
"lastAttemptAt": null,
|
|
18
|
+
"lastError": null,
|
|
19
|
+
"correctionCycle": 0,
|
|
20
|
+
"maxCorrectionCycles": 3,
|
|
21
|
+
"pipeline": {
|
|
22
|
+
"analyzeCompleted": true,
|
|
23
|
+
"prdCompleted": true,
|
|
24
|
+
"jsonCompleted": true,
|
|
25
|
+
"executionCompleted": false,
|
|
26
|
+
"reviewCompleted": false,
|
|
27
|
+
"prCreated": false
|
|
28
|
+
},
|
|
29
|
+
"userStories": [
|
|
30
|
+
{
|
|
31
|
+
"id": "US-001",
|
|
32
|
+
"title": "...",
|
|
33
|
+
"description": "As a ..., I want ... so that ...",
|
|
34
|
+
"acceptanceCriteria": ["..."],
|
|
35
|
+
"priority": 1,
|
|
36
|
+
"passes": false,
|
|
37
|
+
"notes": ""
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
Rules:
|
|
43
|
+
- Each user story from the PRD becomes one entry in userStories
|
|
44
|
+
- Priority should order stories by dependency (build foundations first)
|
|
45
|
+
- acceptanceCriteria must include "Typecheck passes" for code changes
|
|
46
|
+
- Get the repo name and issue URL from: gh issue view __ISSUE_NUMBER__ --json url
|
|
47
|
+
- The branchName should use a short kebab-case slug derived from the issue title
|
|
48
|
+
|
|
49
|
+
IMPORTANT: You MUST write the tasks.json to the file path above. Do not just output it.
|
package/prompts/pr.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
You are creating a pull request for issue #__ISSUE_NUMBER__ on branch __BRANCH_NAME__.
|
|
2
|
+
|
|
3
|
+
Steps:
|
|
4
|
+
1. Fetch the issue data: gh issue view __ISSUE_NUMBER__ --json title,body
|
|
5
|
+
2. Read the task plan from __TASKS_PATH__ if it exists
|
|
6
|
+
3. Review the git log for this branch: git log main..HEAD --oneline
|
|
7
|
+
4. Review the diff: git diff main...HEAD --stat
|
|
8
|
+
5. Create a well-structured PR using gh pr create
|
|
9
|
+
|
|
10
|
+
The PR should:
|
|
11
|
+
- Have a clear, concise title (under 70 characters)
|
|
12
|
+
- Reference the issue: "Closes #__ISSUE_NUMBER__"
|
|
13
|
+
- Include a summary of changes
|
|
14
|
+
- Include a test plan
|
|
15
|
+
|
|
16
|
+
Use this command format:
|
|
17
|
+
gh pr create --title "..." --body "..." --base main
|
|
18
|
+
|
|
19
|
+
IMPORTANT: Output the PR URL after creation so it can be parsed.
|
package/prompts/prd.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
You are generating a Product Requirements Document (PRD) for GitHub issue #__ISSUE_NUMBER__ in this repository.__ANALYSIS_CONTEXT__
|
|
2
|
+
|
|
3
|
+
Steps:
|
|
4
|
+
1. If no analysis was provided above, fetch the issue data using: gh issue view __ISSUE_NUMBER__ --json title,body,labels,comments
|
|
5
|
+
2. Analyze the codebase to understand the context
|
|
6
|
+
3. Generate a structured PRD
|
|
7
|
+
|
|
8
|
+
Save the PRD to __PRD_PATH__ with this structure:
|
|
9
|
+
|
|
10
|
+
# PRD: [Issue Title]
|
|
11
|
+
|
|
12
|
+
## Context
|
|
13
|
+
[Why this change is needed]
|
|
14
|
+
|
|
15
|
+
## Goals
|
|
16
|
+
[What success looks like]
|
|
17
|
+
|
|
18
|
+
## User Stories
|
|
19
|
+
[US-001, US-002, etc. with acceptance criteria]
|
|
20
|
+
|
|
21
|
+
## Technical Approach
|
|
22
|
+
[High-level implementation strategy]
|
|
23
|
+
|
|
24
|
+
## Out of Scope
|
|
25
|
+
[What is explicitly NOT included]
|
|
26
|
+
|
|
27
|
+
## Dependencies
|
|
28
|
+
[External dependencies or prerequisites]
|
|
29
|
+
|
|
30
|
+
IMPORTANT: You MUST write the PRD to the file path above. Do not just output it.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
You are reviewing whether GitHub issue #__ISSUE_NUMBER__ has been fully resolved.
|
|
2
|
+
|
|
3
|
+
IMPORTANT: You are running in --orchestrator mode. Do NOT close the issue directly. Only report results.
|
|
4
|
+
|
|
5
|
+
Steps:
|
|
6
|
+
1. Fetch the issue data using: gh issue view __ISSUE_NUMBER__ --json title,body,labels
|
|
7
|
+
2. Read the task plan from __TASKS_PATH__ to understand what was supposed to be implemented
|
|
8
|
+
3. Analyze the codebase to verify all acceptance criteria are met
|
|
9
|
+
4. Run the project's test suite and typecheck
|
|
10
|
+
5. Check for regressions
|
|
11
|
+
|
|
12
|
+
At the end, output your result in this exact format:
|
|
13
|
+
|
|
14
|
+
<review-result>
|
|
15
|
+
STATUS: PASS
|
|
16
|
+
</review-result>
|
|
17
|
+
|
|
18
|
+
Or if there are issues:
|
|
19
|
+
|
|
20
|
+
<review-result>
|
|
21
|
+
STATUS: FAIL
|
|
22
|
+
FINDINGS:
|
|
23
|
+
- Finding 1
|
|
24
|
+
- Finding 2
|
|
25
|
+
</review-result>
|
|
26
|
+
|
|
27
|
+
IMPORTANT: You MUST include the <review-result> block in your output.
|