issue-flow 0.3.0 → 0.4.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 +25 -0
- package/dist/analyze-3SN7ZAZU.js +12 -0
- package/dist/{chunk-G36DIQ4J.js → chunk-2JZCWJEQ.js} +8 -8
- package/dist/chunk-2JZCWJEQ.js.map +1 -0
- package/dist/chunk-4OQ2ARLP.js +275 -0
- package/dist/chunk-4OQ2ARLP.js.map +1 -0
- package/dist/{chunk-D4WBCVB4.js → chunk-4PZXIOXD.js} +8 -8
- package/dist/chunk-4PZXIOXD.js.map +1 -0
- package/dist/{chunk-JEUHCE3V.js → chunk-CSSXTPWE.js} +2 -2
- package/dist/{chunk-7FRXZ2XA.js → chunk-CYWHYPTU.js} +7 -7
- package/dist/chunk-CYWHYPTU.js.map +1 -0
- package/dist/{chunk-7APADNBV.js → chunk-MEB3B2FI.js} +8 -7
- package/dist/chunk-MEB3B2FI.js.map +1 -0
- package/dist/{chunk-ZOX7M2C2.js → chunk-MWUIIUAS.js} +8 -8
- package/dist/chunk-MWUIIUAS.js.map +1 -0
- package/dist/{chunk-V356G3JS.js → chunk-WM6AYRHQ.js} +44 -45
- package/dist/chunk-WM6AYRHQ.js.map +1 -0
- package/dist/chunk-YAFHVFV5.js +199 -0
- package/dist/chunk-YAFHVFV5.js.map +1 -0
- package/dist/cli.js +60 -24
- package/dist/cli.js.map +1 -1
- package/dist/{execute-UF3IY2MG.js → execute-6AAKNSLM.js} +3 -3
- package/dist/{generate-WMYJEPI4.js → generate-HP4CPMJG.js} +7 -7
- package/dist/generate-HP4CPMJG.js.map +1 -0
- package/dist/init-SXFGOCML.js +9 -0
- package/dist/plan-HWZRG5GP.js +12 -0
- package/dist/pr-TTOFYUCV.js +12 -0
- package/dist/prd-ET2QN7GB.js +12 -0
- package/dist/review-3QDZCOMT.js +12 -0
- package/dist/run-6CR5FDYH.js +451 -0
- package/dist/run-6CR5FDYH.js.map +1 -0
- package/package.json +3 -2
- package/dist/analyze-YYQQP64A.js +0 -12
- package/dist/chunk-7APADNBV.js.map +0 -1
- package/dist/chunk-7FRXZ2XA.js.map +0 -1
- package/dist/chunk-D4WBCVB4.js.map +0 -1
- package/dist/chunk-G36DIQ4J.js.map +0 -1
- package/dist/chunk-L7RIGFP6.js +0 -92
- package/dist/chunk-L7RIGFP6.js.map +0 -1
- package/dist/chunk-PINC2LST.js +0 -82
- package/dist/chunk-PINC2LST.js.map +0 -1
- package/dist/chunk-V356G3JS.js.map +0 -1
- package/dist/chunk-ZOX7M2C2.js.map +0 -1
- package/dist/generate-WMYJEPI4.js.map +0 -1
- package/dist/init-QES2HLP5.js +0 -9
- package/dist/plan-BKSUDN34.js +0 -12
- package/dist/pr-E2ASXBWE.js +0 -12
- package/dist/prd-WYW35SGL.js +0 -12
- package/dist/review-YI2WPNC4.js +0 -12
- package/dist/run-J62FIB5O.js +0 -288
- package/dist/run-J62FIB5O.js.map +0 -1
- /package/dist/{analyze-YYQQP64A.js.map → analyze-3SN7ZAZU.js.map} +0 -0
- /package/dist/{chunk-JEUHCE3V.js.map → chunk-CSSXTPWE.js.map} +0 -0
- /package/dist/{execute-UF3IY2MG.js.map → execute-6AAKNSLM.js.map} +0 -0
- /package/dist/{init-QES2HLP5.js.map → init-SXFGOCML.js.map} +0 -0
- /package/dist/{plan-BKSUDN34.js.map → plan-HWZRG5GP.js.map} +0 -0
- /package/dist/{pr-E2ASXBWE.js.map → pr-TTOFYUCV.js.map} +0 -0
- /package/dist/{prd-WYW35SGL.js.map → prd-ET2QN7GB.js.map} +0 -0
- /package/dist/{review-YI2WPNC4.js.map → review-3QDZCOMT.js.map} +0 -0
package/dist/run-J62FIB5O.js
DELETED
|
@@ -1,288 +0,0 @@
|
|
|
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
|
package/dist/run-J62FIB5O.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
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":[]}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|