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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/plan.ts"],"sourcesContent":["import { mkdir, readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { runHeadless } from '../core/headless.js';\nimport { applyPlaceholders, loadPrompt } from '../core/prompt-resolver.js';\nimport { loadTaskPlan, saveTaskPlan } from '../core/state-manager.js';\nimport { getGlobalTimeout } from '../core/verbose.js';\nimport { taskPlanSchema } from '../schemas.js';\nimport { printError, printSuccess } from '../ui/logger.js';\n\nexport async function runPlan(issue: string): Promise<number> {\n const issueNumber = issue.replace(/^#/, '');\n const issueDir = join('issues', issueNumber);\n\n // Read the PRD\n const prdPath = join(issueDir, 'prd.md');\n let prdContent: string;\n try {\n prdContent = await readFile(prdPath, 'utf-8');\n } catch {\n printError(`PRD not found at ${prdPath}. Run 'issue-flow prd ${issueNumber}' first.`);\n return 1;\n }\n\n const tasksPath = join(issueDir, 'tasks.json');\n\n const template = await loadPrompt('plan');\n const prompt = applyPlaceholders(template, {\n __ISSUE_NUMBER__: issueNumber,\n __PRD_CONTENT__: prdContent,\n __TASKS_PATH__: tasksPath,\n });\n\n await mkdir(issueDir, { recursive: true });\n\n const result = await runHeadless({\n prompt,\n maxTurns: 25,\n timeout: getGlobalTimeout() ?? 300_000,\n outputFormat: 'text',\n allowedTools: ['Bash', 'Read', 'Glob', 'Grep', 'Write'],\n statusMessage: `Converting PRD to task plan for issue #${issueNumber}...`,\n });\n\n if (!result.success) {\n printError(`Task plan generation failed: ${result.error}`);\n return 1;\n }\n\n // Validate the created file\n let rawContent: string;\n try {\n rawContent = await readFile(tasksPath, 'utf-8');\n } catch {\n printError(`tasks.json was not created at ${tasksPath}`);\n return 1;\n }\n\n // Validate JSON structure\n let parsed: unknown;\n try {\n parsed = JSON.parse(rawContent);\n } catch {\n printError('tasks.json contains invalid JSON');\n return 1;\n }\n\n // Validate with zod schema\n const validation = taskPlanSchema.safeParse(parsed);\n if (!validation.success) {\n const issues = validation.error.issues\n .map((i) => ` - ${i.path.join('.')}: ${i.message}`)\n .join('\\n');\n printError(`tasks.json does not match expected schema:\\n${issues}`);\n return 1;\n }\n\n // Ensure pipeline state reflects completion of this phase\n const plan = await loadTaskPlan(tasksPath);\n plan.pipeline.jsonCompleted = true;\n await saveTaskPlan(tasksPath, plan);\n\n printSuccess(`Task plan saved to ${tasksPath} (${plan.userStories.length} stories)`);\n return 0;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA,SAAS,OAAO,gBAAgB;AAChC,SAAS,YAAY;AAQrB,eAAsB,QAAQ,OAAgC;AAC5D,QAAM,cAAc,MAAM,QAAQ,MAAM,EAAE;AAC1C,QAAM,WAAW,KAAK,UAAU,WAAW;AAG3C,QAAM,UAAU,KAAK,UAAU,QAAQ;AACvC,MAAI;AACJ,MAAI;AACF,iBAAa,MAAM,SAAS,SAAS,OAAO;AAAA,EAC9C,QAAQ;AACN,eAAW,oBAAoB,OAAO,yBAAyB,WAAW,UAAU;AACpF,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,KAAK,UAAU,YAAY;AAE7C,QAAM,WAAW,MAAM,WAAW,MAAM;AACxC,QAAM,SAAS,kBAAkB,UAAU;AAAA,IACzC,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,IACjB,gBAAgB;AAAA,EAClB,CAAC;AAED,QAAM,MAAM,UAAU,EAAE,WAAW,KAAK,CAAC;AAEzC,QAAM,SAAS,MAAM,YAAY;AAAA,IAC/B;AAAA,IACA,UAAU;AAAA,IACV,SAAS,iBAAiB,KAAK;AAAA,IAC/B,cAAc;AAAA,IACd,cAAc,CAAC,QAAQ,QAAQ,QAAQ,QAAQ,OAAO;AAAA,IACtD,eAAe,0CAA0C,WAAW;AAAA,EACtE,CAAC;AAED,MAAI,CAAC,OAAO,SAAS;AACnB,eAAW,gCAAgC,OAAO,KAAK,EAAE;AACzD,WAAO;AAAA,EACT;AAGA,MAAI;AACJ,MAAI;AACF,iBAAa,MAAM,SAAS,WAAW,OAAO;AAAA,EAChD,QAAQ;AACN,eAAW,iCAAiC,SAAS,EAAE;AACvD,WAAO;AAAA,EACT;AAGA,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,UAAU;AAAA,EAChC,QAAQ;AACN,eAAW,kCAAkC;AAC7C,WAAO;AAAA,EACT;AAGA,QAAM,aAAa,eAAe,UAAU,MAAM;AAClD,MAAI,CAAC,WAAW,SAAS;AACvB,UAAM,SAAS,WAAW,MAAM,OAC7B,IAAI,CAAC,MAAM,OAAO,EAAE,KAAK,KAAK,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,EAClD,KAAK,IAAI;AACZ,eAAW;AAAA,EAA+C,MAAM,EAAE;AAClE,WAAO;AAAA,EACT;AAGA,QAAM,OAAO,MAAM,aAAa,SAAS;AACzC,OAAK,SAAS,gBAAgB;AAC9B,QAAM,aAAa,WAAW,IAAI;AAElC,eAAa,sBAAsB,SAAS,KAAK,KAAK,YAAY,MAAM,WAAW;AACnF,SAAO;AACT;","names":[]}
|
|
@@ -16,14 +16,19 @@ import {
|
|
|
16
16
|
loadPrompt
|
|
17
17
|
} from "./chunk-OZVHOVDT.js";
|
|
18
18
|
import {
|
|
19
|
+
formatDuration,
|
|
19
20
|
getIcons,
|
|
21
|
+
getOutputCallback,
|
|
22
|
+
getStoryUpdateCallback,
|
|
20
23
|
getTermWidth,
|
|
21
24
|
printError,
|
|
22
25
|
printInfo,
|
|
23
26
|
printRetry,
|
|
24
27
|
printSuccess,
|
|
25
|
-
printWarning
|
|
26
|
-
|
|
28
|
+
printWarning,
|
|
29
|
+
useColor,
|
|
30
|
+
useUnicode
|
|
31
|
+
} from "./chunk-YAFHVFV5.js";
|
|
27
32
|
|
|
28
33
|
// src/config.ts
|
|
29
34
|
import { platform } from "os";
|
|
@@ -125,16 +130,6 @@ import { join as join2 } from "path";
|
|
|
125
130
|
|
|
126
131
|
// src/ui/progress.ts
|
|
127
132
|
import chalk from "chalk";
|
|
128
|
-
function useColor() {
|
|
129
|
-
if (process.env.NO_COLOR === "1") return false;
|
|
130
|
-
if (!process.stdout.isTTY) return false;
|
|
131
|
-
return true;
|
|
132
|
-
}
|
|
133
|
-
function useUnicode() {
|
|
134
|
-
if (process.env.NO_COLOR === "1") return false;
|
|
135
|
-
if (!process.stdout.isTTY) return false;
|
|
136
|
-
return true;
|
|
137
|
-
}
|
|
138
133
|
function printProgressBar(passed, total) {
|
|
139
134
|
const barWidth = 20;
|
|
140
135
|
let pct = 0;
|
|
@@ -156,16 +151,16 @@ function printProgressBar(passed, total) {
|
|
|
156
151
|
function printIterationHeader(iteration, maxIter, stories) {
|
|
157
152
|
const icons = getIcons();
|
|
158
153
|
const colored = useColor();
|
|
154
|
+
const cb = getOutputCallback();
|
|
159
155
|
const iterLabel = maxIter ? `Iteration ${iteration} of ${maxIter}` : `Iteration ${iteration}`;
|
|
160
156
|
const total = stories.length;
|
|
161
157
|
const passed = stories.filter((s) => s.passes).length;
|
|
162
|
-
|
|
158
|
+
const lines = [];
|
|
163
159
|
if (colored) {
|
|
164
|
-
|
|
160
|
+
lines.push(chalk.blue(`\u2501\u2501\u2501 ${icons.start} ${iterLabel} \u2501\u2501\u2501`));
|
|
165
161
|
} else {
|
|
166
|
-
|
|
162
|
+
lines.push(`--- ${icons.start} ${iterLabel} ---`);
|
|
167
163
|
}
|
|
168
|
-
console.log("");
|
|
169
164
|
let foundFirstPending = false;
|
|
170
165
|
for (const story of stories) {
|
|
171
166
|
let icon;
|
|
@@ -181,24 +176,22 @@ function printIterationHeader(iteration, maxIter, stories) {
|
|
|
181
176
|
icon = icons.notReached;
|
|
182
177
|
colorFn = colored ? chalk.gray : (s) => s;
|
|
183
178
|
}
|
|
184
|
-
|
|
179
|
+
lines.push(colorFn(` ${icon} ${story.id}: ${story.title}`));
|
|
180
|
+
}
|
|
181
|
+
lines.push(` ${printProgressBar(passed, total)}`);
|
|
182
|
+
if (cb) {
|
|
183
|
+
cb(lines.join("\n"));
|
|
184
|
+
} else {
|
|
185
|
+
console.log("");
|
|
186
|
+
for (const line of lines) {
|
|
187
|
+
console.log(line);
|
|
188
|
+
}
|
|
189
|
+
console.log("");
|
|
185
190
|
}
|
|
186
|
-
console.log("");
|
|
187
|
-
console.log(` ${printProgressBar(passed, total)}`);
|
|
188
191
|
}
|
|
189
192
|
|
|
190
193
|
// src/ui/summary.ts
|
|
191
194
|
import chalk2 from "chalk";
|
|
192
|
-
function useColor2() {
|
|
193
|
-
if (process.env.NO_COLOR != null && process.env.NO_COLOR !== "") return false;
|
|
194
|
-
if (!process.stdout.isTTY) return false;
|
|
195
|
-
return true;
|
|
196
|
-
}
|
|
197
|
-
function useUnicode2() {
|
|
198
|
-
if (process.env.NO_COLOR != null && process.env.NO_COLOR !== "") return false;
|
|
199
|
-
if (!process.stdout.isTTY) return false;
|
|
200
|
-
return true;
|
|
201
|
-
}
|
|
202
195
|
function fitLine(text, width) {
|
|
203
196
|
if (text.length > width) {
|
|
204
197
|
return text.substring(0, width);
|
|
@@ -206,8 +199,8 @@ function fitLine(text, width) {
|
|
|
206
199
|
return text.padEnd(width);
|
|
207
200
|
}
|
|
208
201
|
function printBox(lines) {
|
|
209
|
-
const colored =
|
|
210
|
-
const unicode =
|
|
202
|
+
const colored = useColor();
|
|
203
|
+
const unicode = useUnicode();
|
|
211
204
|
const termWidth = getTermWidth();
|
|
212
205
|
let maxContentWidth = 0;
|
|
213
206
|
for (const line of lines) {
|
|
@@ -262,14 +255,6 @@ function printStartupHeader(config, plan) {
|
|
|
262
255
|
`Retries: ${retryLabel}`
|
|
263
256
|
]);
|
|
264
257
|
}
|
|
265
|
-
function formatDuration(totalSeconds) {
|
|
266
|
-
const mins = Math.floor(totalSeconds / 60);
|
|
267
|
-
const secs = totalSeconds % 60;
|
|
268
|
-
if (mins > 0) {
|
|
269
|
-
return `${mins}m ${secs}s`;
|
|
270
|
-
}
|
|
271
|
-
return `${secs}s`;
|
|
272
|
-
}
|
|
273
258
|
function printSummaryBox(status, iterations, totalRetries, elapsedSeconds, plan, extraInfo) {
|
|
274
259
|
const icons = getIcons();
|
|
275
260
|
const storiesTotal = plan.userStories.length;
|
|
@@ -377,6 +362,16 @@ ${stderr}` : "");
|
|
|
377
362
|
function sleep(seconds) {
|
|
378
363
|
return new Promise((resolve) => setTimeout(resolve, seconds * 1e3));
|
|
379
364
|
}
|
|
365
|
+
function emitLog(message) {
|
|
366
|
+
const cb = getOutputCallback();
|
|
367
|
+
if (cb) {
|
|
368
|
+
if (message) {
|
|
369
|
+
cb(message);
|
|
370
|
+
}
|
|
371
|
+
} else {
|
|
372
|
+
console.log(message);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
380
375
|
async function ensureProgressFile(progressFile) {
|
|
381
376
|
if (!existsSync(progressFile)) {
|
|
382
377
|
const content = `# Issue Flow Progress Log
|
|
@@ -432,7 +427,7 @@ async function runEngine(config, paths) {
|
|
|
432
427
|
if (!existsSync(paths.prdFile)) {
|
|
433
428
|
printError(`PRD file not found at ${paths.prdFile}`);
|
|
434
429
|
if (config.issueNumber) {
|
|
435
|
-
|
|
430
|
+
emitLog(`Have you run the resolve-issue skill for issue #${config.issueNumber} first?`);
|
|
436
431
|
}
|
|
437
432
|
return 1;
|
|
438
433
|
}
|
|
@@ -440,7 +435,7 @@ async function runEngine(config, paths) {
|
|
|
440
435
|
plan = initializeState(plan);
|
|
441
436
|
await saveTaskPlan(paths.prdFile, plan);
|
|
442
437
|
if (plan.issueStatus === "completed" && allStoriesPass(plan)) {
|
|
443
|
-
|
|
438
|
+
emitLog(`Issue already marked complete in ${paths.prdFile}`);
|
|
444
439
|
return 0;
|
|
445
440
|
}
|
|
446
441
|
if (plan.issueStatus === "completed" && !allStoriesPass(plan)) {
|
|
@@ -456,7 +451,7 @@ async function runEngine(config, paths) {
|
|
|
456
451
|
await saveTaskPlan(paths.prdFile, plan);
|
|
457
452
|
}
|
|
458
453
|
if (allStoriesPass(plan)) {
|
|
459
|
-
|
|
454
|
+
emitLog("All user stories already pass. Marking issue as completed.");
|
|
460
455
|
plan = markIssueCompleted(plan);
|
|
461
456
|
await saveTaskPlan(paths.prdFile, plan);
|
|
462
457
|
return 0;
|
|
@@ -511,7 +506,7 @@ async function runEngine(config, paths) {
|
|
|
511
506
|
config.backoffBaseSeconds,
|
|
512
507
|
config.backoffMaxSeconds
|
|
513
508
|
);
|
|
514
|
-
|
|
509
|
+
emitLog("");
|
|
515
510
|
printRetry(
|
|
516
511
|
`Transient Claude failure on iteration ${i} (attempt ${retryCount}). Retrying in ${delaySeconds}s.`
|
|
517
512
|
);
|
|
@@ -537,6 +532,10 @@ async function runEngine(config, paths) {
|
|
|
537
532
|
plan = await loadTaskPlan(paths.prdFile);
|
|
538
533
|
plan = clearLastError(plan, iterationStartedAt);
|
|
539
534
|
await saveTaskPlan(paths.prdFile, plan);
|
|
535
|
+
const storyUpdateCb = getStoryUpdateCallback();
|
|
536
|
+
if (storyUpdateCb) {
|
|
537
|
+
storyUpdateCb(plan.userStories);
|
|
538
|
+
}
|
|
540
539
|
if (result.output.includes("<promise>COMPLETE</promise>")) {
|
|
541
540
|
plan = await loadTaskPlan(paths.prdFile);
|
|
542
541
|
if (allStoriesPass(plan)) {
|
|
@@ -552,7 +551,7 @@ async function runEngine(config, paths) {
|
|
|
552
551
|
"Claude returned <promise>COMPLETE</promise> before every story had passes=true."
|
|
553
552
|
);
|
|
554
553
|
await saveTaskPlan(paths.prdFile, plan);
|
|
555
|
-
|
|
554
|
+
emitLog("");
|
|
556
555
|
printWarning(
|
|
557
556
|
"Claude returned a completion signal, but tasks.json still has pending stories. Ignoring completion and continuing."
|
|
558
557
|
);
|
|
@@ -608,4 +607,4 @@ async function runExecute(positionalMaxIter, options) {
|
|
|
608
607
|
export {
|
|
609
608
|
runExecute
|
|
610
609
|
};
|
|
611
|
-
//# sourceMappingURL=chunk-
|
|
610
|
+
//# sourceMappingURL=chunk-WM6AYRHQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/config.ts","../src/utils/shell.ts","../src/utils/git.ts","../src/core/engine.ts","../src/ui/progress.ts","../src/ui/summary.ts","../src/utils/retry.ts","../src/core/executor.ts","../src/commands/execute.ts"],"sourcesContent":["import { platform } from 'node:os';\nimport { join } from 'node:path';\nimport type { EngineConfig, ResolvedPaths } from './types.js';\nimport { getProjectRoot } from './utils/git.js';\nimport { run } from './utils/shell.js';\n\n/**\n * Default configuration values — matching the Bash script exactly.\n */\nexport const DEFAULTS = {\n retryLimit: 10,\n retryForever: false,\n backoffBaseSeconds: 30,\n backoffMaxSeconds: 900,\n} as const;\n\n/**\n * Create a EngineConfig with defaults merged with provided options.\n */\nexport function createConfig(options: Partial<EngineConfig>): EngineConfig {\n return {\n issueNumber: options.issueNumber,\n maxIterations: options.maxIterations,\n retryLimit: options.retryLimit ?? DEFAULTS.retryLimit,\n retryForever: options.retryForever ?? DEFAULTS.retryForever,\n backoffBaseSeconds: options.backoffBaseSeconds ?? DEFAULTS.backoffBaseSeconds,\n backoffMaxSeconds: options.backoffMaxSeconds ?? DEFAULTS.backoffMaxSeconds,\n };\n}\n\n/**\n * Resolve file paths based on issue number and project root.\n *\n * With --issue N:\n * prdFile = {projectRoot}/issues/{N}/tasks.json\n * progressFile = {projectRoot}/issues/{N}/progress.txt\n *\n * Standalone:\n * prdFile = {projectRoot}/prd.json\n * progressFile = {projectRoot}/progress.txt\n */\nexport async function resolvePaths(\n config: EngineConfig,\n scriptDir?: string,\n): Promise<ResolvedPaths> {\n const projectRoot = await getProjectRoot();\n\n if (config.issueNumber) {\n const issueDir = join(projectRoot, 'issues', config.issueNumber);\n return {\n prdFile: join(issueDir, 'tasks.json'),\n progressFile: join(issueDir, 'progress.txt'),\n archiveDir: join(issueDir, 'archive'),\n lastBranchFile: join(issueDir, '.last-branch'),\n projectRoot,\n };\n }\n\n // Standalone mode — use scriptDir if available, otherwise projectRoot\n const base = scriptDir ?? projectRoot;\n return {\n prdFile: join(base, 'prd.json'),\n progressFile: join(base, 'progress.txt'),\n archiveDir: join(base, 'archive'),\n lastBranchFile: join(base, '.last-branch'),\n projectRoot,\n };\n}\n\n/**\n * Return a platform-appropriate install hint for a given package.\n */\nexport function getInstallHint(pkg: string): string {\n const os = platform();\n\n if (os === 'darwin') {\n return `brew install ${pkg}`;\n }\n if (os === 'linux') {\n return `apt install ${pkg} (or your distro's package manager)`;\n }\n if (os === 'win32') {\n return `winget install ${pkg} (or choco install ${pkg})`;\n }\n\n return `install ${pkg} using your system package manager`;\n}\n\n/**\n * Validate that required external dependencies are available.\n * Returns an array of error messages (empty if all deps are found).\n */\nexport async function validateDependencies(): Promise<string[]> {\n const errors: string[] = [];\n\n // Check git\n const gitResult = await run('git', ['--version']);\n if (gitResult.exitCode !== 0) {\n errors.push(` - git (install with: ${getInstallHint('git')})`);\n }\n\n // Check claude\n const claudeResult = await run('claude', ['--version']);\n if (claudeResult.exitCode !== 0) {\n errors.push(' - claude (install with: npm install -g @anthropic-ai/claude-code)');\n }\n\n // Note: jq is NOT required — the TypeScript CLI handles JSON natively\n\n return errors;\n}\n","import { type Options as ExecaOptions, execa } from 'execa';\n\nexport interface ExecResult {\n stdout: string;\n stderr: string;\n exitCode: number;\n}\n\n/**\n * Execute a command with arguments and capture its output.\n * Uses execa which calls execFile internally (no shell injection risk).\n * Does not throw on non-zero exit codes.\n */\nexport async function run(\n command: string,\n args: string[] = [],\n options?: ExecaOptions,\n): Promise<ExecResult> {\n const result = await execa(command, args, {\n reject: false,\n ...options,\n });\n\n return {\n stdout: result.stdout?.toString() ?? '',\n stderr: result.stderr?.toString() ?? '',\n exitCode: result.exitCode ?? 1,\n };\n}\n","import { run } from './shell.js';\n\n/**\n * Get the root directory of the current git repository.\n * Throws if not inside a git repository.\n */\nexport async function getProjectRoot(): Promise<string> {\n const result = await run('git', ['rev-parse', '--show-toplevel']);\n\n if (result.exitCode !== 0) {\n throw new Error(\n 'Not inside a git repository. Please run issue-flow from within a git project.',\n );\n }\n\n return result.stdout.trim();\n}\n\n/**\n * Get the current git branch name.\n * Returns an empty string if in detached HEAD state.\n */\nexport async function getCurrentBranch(): Promise<string> {\n const result = await run('git', ['branch', '--show-current']);\n\n if (result.exitCode !== 0) {\n throw new Error(\n 'Failed to detect git branch. Ensure git is installed and you are inside a repository.',\n );\n }\n\n return result.stdout.trim();\n}\n","import { existsSync } from 'node:fs';\nimport { cp, mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { EngineConfig, ResolvedPaths, TaskPlan } from '../types.js';\nimport { printError, printInfo, printRetry, printSuccess, printWarning } from '../ui/logger.js';\nimport { printIterationHeader } from '../ui/progress.js';\nimport { printStartupHeader, printSummaryBox } from '../ui/summary.js';\nimport { isTransientFailure, retryDelaySeconds } from '../utils/retry.js';\nimport { executeClaude } from './executor.js';\nimport { applyPlaceholders, loadPrompt } from './prompt-resolver.js';\nimport {\n allStoriesPass,\n clearLastError,\n initializeState,\n isoNow,\n loadTaskPlan,\n markIssueCompleted,\n markIssueInProgress,\n saveTaskPlan,\n setLastError,\n trimErrorMessage,\n} from './state-manager.js';\nimport { getOutputCallback, getStoryUpdateCallback } from './verbose.js';\n\n/**\n * Sleep for a given number of seconds.\n */\nfunction sleep(seconds: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, seconds * 1000));\n}\n\n/**\n * Emit a message through the output callback if available, otherwise console.log.\n * Used for bare console.log calls in engine functions so they route through listr2.\n */\nfunction emitLog(message: string): void {\n const cb = getOutputCallback();\n if (cb) {\n // Skip empty lines in listr2 context — they don't render meaningfully\n if (message) {\n cb(message);\n }\n } else {\n console.log(message);\n }\n}\n\n/**\n * Initialize the progress file if it doesn't exist.\n */\nasync function ensureProgressFile(progressFile: string): Promise<void> {\n if (!existsSync(progressFile)) {\n const content = `# Issue Flow Progress Log\\nStarted: ${new Date().toString()}\\n---\\n`;\n await writeFile(progressFile, content, 'utf-8');\n }\n}\n\n/**\n * Archive previous run artifacts if the branch has changed.\n */\nasync function archiveIfBranchChanged(plan: TaskPlan, paths: ResolvedPaths): Promise<void> {\n const { lastBranchFile, archiveDir, prdFile, progressFile } = paths;\n\n if (!existsSync(lastBranchFile)) {\n return;\n }\n\n const currentBranch = plan.branchName ?? '';\n let lastBranch = '';\n\n try {\n lastBranch = (await readFile(lastBranchFile, 'utf-8')).trim();\n } catch {\n return;\n }\n\n if (currentBranch && lastBranch && currentBranch !== lastBranch) {\n const dateStr = new Date().toISOString().split('T')[0];\n const folderName = lastBranch.replace(/^issue\\//, '').replace(/[<>:\"|?*\\\\]/g, '_');\n const archiveFolder = join(archiveDir, `${dateStr}-${folderName}`);\n\n printInfo(`Archiving previous run: ${lastBranch}`);\n await mkdir(archiveFolder, { recursive: true });\n\n if (existsSync(prdFile)) {\n await cp(prdFile, join(archiveFolder, 'tasks.json'));\n }\n if (existsSync(progressFile)) {\n await cp(progressFile, join(archiveFolder, 'progress.txt'));\n }\n\n printInfo(` Archived to: ${archiveFolder}`);\n\n // Reset progress file for new run\n await writeFile(\n progressFile,\n `# Issue Flow Progress Log\\nStarted: ${new Date().toString()}\\n---\\n`,\n 'utf-8',\n );\n }\n}\n\n/**\n * Write the current branch to the last-branch tracking file.\n */\nasync function trackBranch(plan: TaskPlan, lastBranchFile: string): Promise<void> {\n const branch = plan.branchName ?? '';\n if (branch) {\n await writeFile(lastBranchFile, `${branch}\\n`, 'utf-8');\n }\n}\n\n/**\n * Run the issue-flow engine loop.\n *\n * This replicates the full execution flow:\n * 1. Load and initialize task plan state\n * 2. Check for early exit (already complete)\n * 3. Archive previous run if branch changed\n * 4. Resolve prompt\n * 5. Main loop: iterate, execute Claude, handle results\n * 6. Print summary\n */\nexport async function runEngine(config: EngineConfig, paths: ResolvedPaths): Promise<number> {\n // Load task plan\n if (!existsSync(paths.prdFile)) {\n printError(`PRD file not found at ${paths.prdFile}`);\n if (config.issueNumber) {\n emitLog(`Have you run the resolve-issue skill for issue #${config.issueNumber} first?`);\n }\n return 1;\n }\n\n let plan = await loadTaskPlan(paths.prdFile);\n plan = initializeState(plan);\n await saveTaskPlan(paths.prdFile, plan);\n\n // Check if already completed\n if (plan.issueStatus === 'completed' && allStoriesPass(plan)) {\n emitLog(`Issue already marked complete in ${paths.prdFile}`);\n return 0;\n }\n\n // Warn if marked complete but stories still pending\n if (plan.issueStatus === 'completed' && !allStoriesPass(plan)) {\n printWarning(\n 'Issue marked completed but some stories are still pending. Resetting to in_progress.',\n );\n plan = markIssueInProgress(plan);\n plan = setLastError(\n plan,\n 'invalid_completion_state',\n 'tasks.json claimed the issue was completed before every story had passes=true.',\n );\n await saveTaskPlan(paths.prdFile, plan);\n }\n\n // Check if all stories already pass\n if (allStoriesPass(plan)) {\n emitLog('All user stories already pass. Marking issue as completed.');\n plan = markIssueCompleted(plan);\n await saveTaskPlan(paths.prdFile, plan);\n return 0;\n }\n\n // Archive previous run if branch changed\n await archiveIfBranchChanged(plan, paths);\n\n // Track current branch\n await trackBranch(plan, paths.lastBranchFile);\n\n // Initialize progress file\n await ensureProgressFile(paths.progressFile);\n\n // Load prompt template\n const promptTemplate = await loadPrompt('execute');\n\n // Print startup header\n printStartupHeader(config, plan);\n\n const startTime = Date.now();\n let i = 0;\n let retryCount = 0;\n let totalRetryCount = 0;\n\n // Main loop\n while (true) {\n // Check iteration limit\n if (config.maxIterations !== undefined && i >= config.maxIterations) {\n break;\n }\n\n i++;\n\n // Re-read plan to get latest state\n plan = await loadTaskPlan(paths.prdFile);\n\n printIterationHeader(i, config.maxIterations, plan.userStories);\n\n // Apply placeholders to prompt\n const prompt = applyPlaceholders(promptTemplate, {\n __PRD_FILE__: paths.prdFile,\n __PROGRESS_FILE__: paths.progressFile,\n });\n\n const iterationStartedAt = isoNow();\n plan = markIssueInProgress(plan, iterationStartedAt);\n await saveTaskPlan(paths.prdFile, plan);\n\n // Execute Claude\n const result = await executeClaude(prompt);\n\n if (result.exitCode !== 0) {\n const errorMessage = trimErrorMessage(result.output);\n\n if (isTransientFailure(result.exitCode, result.output)) {\n retryCount++;\n totalRetryCount++;\n plan = await loadTaskPlan(paths.prdFile);\n plan = setLastError(plan, 'transient_claude_failure', errorMessage);\n await saveTaskPlan(paths.prdFile, plan);\n\n if (!config.retryForever && retryCount > config.retryLimit) {\n const elapsed = Math.floor((Date.now() - startTime) / 1000);\n plan = await loadTaskPlan(paths.prdFile);\n printSummaryBox(\n 'failed',\n i,\n totalRetryCount,\n elapsed,\n plan,\n `Exceeded retry limit (${config.retryLimit}) on transient errors`,\n );\n return result.exitCode;\n }\n\n const delaySeconds = retryDelaySeconds(\n retryCount,\n config.backoffBaseSeconds,\n config.backoffMaxSeconds,\n );\n\n emitLog('');\n printRetry(\n `Transient Claude failure on iteration ${i} (attempt ${retryCount}). Retrying in ${delaySeconds}s.`,\n );\n\n // Stay within current iteration budget\n i--;\n await sleep(delaySeconds);\n continue;\n }\n\n // Fatal failure\n plan = await loadTaskPlan(paths.prdFile);\n plan = setLastError(plan, 'fatal_claude_failure', errorMessage);\n await saveTaskPlan(paths.prdFile, plan);\n\n const elapsed = Math.floor((Date.now() - startTime) / 1000);\n printSummaryBox(\n 'failed',\n i,\n totalRetryCount,\n elapsed,\n plan,\n `Claude CLI failed with exit code ${result.exitCode}`,\n );\n return result.exitCode;\n }\n\n // Success — reset retry counter\n retryCount = 0;\n plan = await loadTaskPlan(paths.prdFile);\n plan = clearLastError(plan, iterationStartedAt);\n await saveTaskPlan(paths.prdFile, plan);\n\n // Notify story progress listeners (e.g., listr2 subtasks)\n const storyUpdateCb = getStoryUpdateCallback();\n if (storyUpdateCb) {\n storyUpdateCb(plan.userStories);\n }\n\n // Check for completion signal\n if (result.output.includes('<promise>COMPLETE</promise>')) {\n plan = await loadTaskPlan(paths.prdFile);\n if (allStoriesPass(plan)) {\n plan = markIssueCompleted(plan);\n await saveTaskPlan(paths.prdFile, plan);\n\n const elapsed = Math.floor((Date.now() - startTime) / 1000);\n printSummaryBox('success', i, totalRetryCount, elapsed, plan);\n return 0;\n }\n\n plan = setLastError(\n plan,\n 'invalid_completion_signal',\n 'Claude returned <promise>COMPLETE</promise> before every story had passes=true.',\n );\n await saveTaskPlan(paths.prdFile, plan);\n\n emitLog('');\n printWarning(\n 'Claude returned a completion signal, but tasks.json still has pending stories. Ignoring completion and continuing.',\n );\n }\n\n printSuccess(`Iteration ${i} complete. Continuing...`);\n await sleep(2);\n }\n\n // Reached max iterations\n const elapsed = Math.floor((Date.now() - startTime) / 1000);\n plan = await loadTaskPlan(paths.prdFile);\n printSummaryBox(\n 'incomplete',\n config.maxIterations ?? i,\n totalRetryCount,\n elapsed,\n plan,\n 'Reached max iterations without completing all tasks.',\n );\n return 1;\n}\n","import chalk from 'chalk';\nimport { getOutputCallback } from '../core/verbose.js';\nimport type { UserStory } from '../types.js';\nimport { getIcons, useColor, useUnicode } from './logger.js';\n\n/**\n * Print a visual progress bar showing passed/total stories.\n */\nexport function printProgressBar(passed: number, total: number): string {\n const barWidth = 20;\n let pct = 0;\n let filled = 0;\n\n if (total > 0) {\n pct = Math.floor((passed * 100) / total);\n filled = Math.floor((passed * barWidth) / total);\n }\n\n const empty = barWidth - filled;\n const fillChar = useUnicode() ? '\\u2588' : '#';\n const emptyChar = useUnicode() ? '\\u2591' : '-';\n\n const bar = fillChar.repeat(filled) + emptyChar.repeat(empty);\n const text = `${passed}/${total} (${pct}%)`;\n\n if (useColor()) {\n return `${chalk.green(bar)} ${text}`;\n }\n return `${bar} ${text}`;\n}\n\n/**\n * Print the iteration header showing story statuses and progress bar.\n *\n * When a global output callback is set (e.g., inside a listr2 task),\n * output is routed through it instead of console.log.\n */\nexport function printIterationHeader(\n iteration: number,\n maxIter: number | undefined,\n stories: UserStory[],\n): void {\n const icons = getIcons();\n const colored = useColor();\n const cb = getOutputCallback();\n\n const iterLabel = maxIter ? `Iteration ${iteration} of ${maxIter}` : `Iteration ${iteration}`;\n\n const total = stories.length;\n const passed = stories.filter((s) => s.passes).length;\n\n const lines: string[] = [];\n\n if (colored) {\n lines.push(chalk.blue(`\\u2501\\u2501\\u2501 ${icons.start} ${iterLabel} \\u2501\\u2501\\u2501`));\n } else {\n lines.push(`--- ${icons.start} ${iterLabel} ---`);\n }\n\n // Display each story status\n let foundFirstPending = false;\n for (const story of stories) {\n let icon: string;\n let colorFn: (s: string) => string;\n\n if (story.passes) {\n icon = icons.success;\n colorFn = colored ? chalk.green : (s: string) => s;\n } else if (!foundFirstPending) {\n // First non-passing story = current in-progress\n icon = icons.pending;\n colorFn = colored ? chalk.yellow : (s: string) => s;\n foundFirstPending = true;\n } else {\n // Not yet reached\n icon = icons.notReached;\n colorFn = colored ? chalk.gray : (s: string) => s;\n }\n\n lines.push(colorFn(` ${icon} ${story.id}: ${story.title}`));\n }\n\n lines.push(` ${printProgressBar(passed, total)}`);\n\n if (cb) {\n // Send as single output to listr2 task context\n cb(lines.join('\\n'));\n } else {\n console.log('');\n for (const line of lines) {\n console.log(line);\n }\n console.log('');\n }\n}\n","import chalk from 'chalk';\nimport type { EngineConfig, TaskPlan } from '../types.js';\nimport { formatDuration, getIcons, getTermWidth, useColor, useUnicode } from './logger.js';\n\n/**\n * Truncate or pad a string to fit within a given width.\n */\nfunction fitLine(text: string, width: number): string {\n if (text.length > width) {\n return text.substring(0, width);\n }\n return text.padEnd(width);\n}\n\n/**\n * Print a box with border characters around content lines.\n * Lines equal to \"---\" render as separator rows.\n */\nexport function printBox(lines: string[]): void {\n const colored = useColor();\n const unicode = useUnicode();\n const termWidth = getTermWidth();\n\n // Find max content width\n let maxContentWidth = 0;\n for (const line of lines) {\n if (line !== '---' && line.length > maxContentWidth) {\n maxContentWidth = line.length;\n }\n }\n\n // Cap to terminal width (border + padding = 4 chars)\n const available = termWidth - 4;\n if (maxContentWidth > available) {\n maxContentWidth = available;\n }\n if (maxContentWidth < 20) {\n maxContentWidth = 20;\n }\n\n // Box drawing characters\n const tl = unicode ? '\\u256D' : '+';\n const tr = unicode ? '\\u256E' : '+';\n const bl = unicode ? '\\u2570' : '+';\n const br = unicode ? '\\u256F' : '+';\n const h = unicode ? '\\u2500' : '-';\n const v = unicode ? '\\u2502' : '|';\n const sepL = unicode ? '\\u251C' : '+';\n const sepR = unicode ? '\\u2524' : '+';\n\n const hrule = h.repeat(maxContentWidth + 2);\n\n const blue = colored ? chalk.blue : (s: string) => s;\n const _reset = (s: string) => s;\n\n // Top border\n console.log(blue(`${tl}${hrule}${tr}`));\n\n // Content lines\n for (const line of lines) {\n if (line === '---') {\n console.log(blue(`${sepL}${hrule}${sepR}`));\n } else {\n const fitted = fitLine(line, maxContentWidth);\n console.log(`${blue(v)} ${fitted} ${blue(v)}`);\n }\n }\n\n // Bottom border\n console.log(blue(`${bl}${hrule}${br}`));\n}\n\n/**\n * Print the startup header box showing engine configuration.\n */\nexport function printStartupHeader(config: EngineConfig, plan: TaskPlan): void {\n const icons = getIcons();\n\n const storiesTotal = plan.userStories.length;\n const storiesPassing = plan.userStories.filter((s) => s.passes).length;\n const branchName = plan.branchName ?? 'N/A';\n\n const issueLabel = config.issueNumber ? `Issue #${config.issueNumber}` : 'Standalone mode';\n\n const maxIterLabel =\n config.maxIterations !== undefined ? String(config.maxIterations) : 'unlimited';\n\n const retryLabel = config.retryForever\n ? 'unlimited retries'\n : `${config.retryLimit} consecutive retries`;\n\n printBox([\n `${icons.start} Issue Flow`,\n '---',\n `Issue: ${issueLabel}`,\n `Branch: ${branchName}`,\n `Stories: ${storiesPassing}/${storiesTotal} passing`,\n `Iterations: ${maxIterLabel}`,\n `Retries: ${retryLabel}`,\n ]);\n}\n\n// Re-export formatDuration from logger to maintain backwards compatibility\nexport { formatDuration } from './logger.js';\n\n/**\n * Print the final summary box.\n */\nexport function printSummaryBox(\n status: 'success' | 'incomplete' | 'failed',\n iterations: number,\n totalRetries: number,\n elapsedSeconds: number,\n plan: TaskPlan,\n extraInfo?: string,\n): void {\n const icons = getIcons();\n\n const storiesTotal = plan.userStories.length;\n const storiesPassing = plan.userStories.filter((s) => s.passes).length;\n const duration = formatDuration(elapsedSeconds);\n\n let statusIcon: string;\n let statusLabel: string;\n\n switch (status) {\n case 'success':\n statusIcon = icons.success;\n statusLabel = 'Completed';\n break;\n case 'incomplete':\n statusIcon = icons.warn;\n statusLabel = 'Incomplete';\n break;\n case 'failed':\n statusIcon = icons.fail;\n statusLabel = 'Failed';\n break;\n }\n\n const boxLines = [\n `${icons.end} Issue Flow Summary`,\n '---',\n `Status: ${statusIcon} ${statusLabel}`,\n `Stories: ${storiesPassing}/${storiesTotal} passing`,\n `Iterations: ${iterations}`,\n `Duration: ${duration}`,\n `Retries: ${totalRetries}`,\n ];\n\n if (extraInfo) {\n boxLines.push('---');\n boxLines.push(extraInfo);\n }\n\n console.log('');\n printBox(boxLines);\n}\n","/**\n * Transient failure patterns — matching the Bash script's detection heuristics.\n * These are checked case-insensitively against the combined output.\n */\nconst TRANSIENT_PATTERNS = [\n 'timed out',\n 'timeout',\n 'connection reset',\n 'connection refused',\n 'connection aborted',\n 'network error',\n 'network unavailable',\n 'temporary failure',\n 'temporarily unavailable',\n 'service unavailable',\n 'overloaded',\n 'rate limit',\n 'too many requests',\n 'bad gateway',\n 'gateway timeout',\n 'internal server error',\n 'http 429',\n 'http 500',\n 'http 502',\n 'http 503',\n 'http 504',\n 'econnreset',\n 'econnrefused',\n 'enotfound',\n 'etimedout',\n 'socket hang up',\n];\n\n/**\n * Determine if a Claude CLI failure is transient (retryable).\n *\n * A failure is considered transient if:\n * - Exit code is 75 (EX_TEMPFAIL)\n * - Output contains known transient error patterns\n */\nexport function isTransientFailure(exitCode: number, output: string): boolean {\n // Exit code 75 = EX_TEMPFAIL\n if (exitCode === 75) {\n return true;\n }\n\n const lowered = output.toLowerCase();\n return TRANSIENT_PATTERNS.some((pattern) => lowered.includes(pattern));\n}\n\n/**\n * Calculate retry delay using exponential backoff.\n *\n * delay = baseSeconds * 2^(attempt-1), capped at maxSeconds\n *\n * @param attempt - The retry attempt number (1-based)\n * @param baseSeconds - Base delay in seconds (default: 30)\n * @param maxSeconds - Maximum delay in seconds (default: 900)\n */\nexport function retryDelaySeconds(\n attempt: number,\n baseSeconds: number = 30,\n maxSeconds: number = 900,\n): number {\n const delay = baseSeconds * 2 ** (attempt - 1);\n return Math.min(delay, maxSeconds);\n}\n","import { execa } from 'execa';\nimport type { ClaudeResult } from '../types.js';\n\n/**\n * Execute Claude CLI with a prompt piped to stdin.\n *\n * Runs: echo $PROMPT | claude --dangerously-skip-permissions --print\n *\n * Captures combined stdout+stderr output. Does not throw on non-zero exit codes.\n * Output is also forwarded to the process stderr (matching Bash behavior).\n */\nexport async function executeClaude(prompt: string): Promise<ClaudeResult> {\n const result = await execa('claude', ['--dangerously-skip-permissions', '--print'], {\n input: prompt,\n reject: false,\n timeout: 0, // No timeout — let the engine handle iteration limits\n stripFinalNewline: false,\n });\n\n // Combine stdout and stderr to match Bash's 2>&1 behavior\n const stdout = result.stdout?.toString() ?? '';\n const stderr = result.stderr?.toString() ?? '';\n const output = stdout + (stderr ? `\\n${stderr}` : '');\n\n // Forward output to process stderr (matching Bash: printf '%s\\n' \"$OUTPUT\" >&2)\n if (output.trim()) {\n process.stderr.write(`${output}\\n`);\n }\n\n return {\n exitCode: result.exitCode ?? 1,\n output,\n };\n}\n","import { createConfig, resolvePaths, validateDependencies } from '../config.js';\nimport { runEngine } from '../core/engine.js';\nimport { allStoriesPass, loadTaskPlan, saveTaskPlan } from '../core/state-manager.js';\nimport { printError } from '../ui/logger.js';\n\nexport interface ExecuteOptions {\n issue?: string;\n maxIterations?: number;\n retryLimit?: number;\n retryForever?: boolean;\n}\n\nexport async function runExecute(\n positionalMaxIter: number | undefined,\n options: ExecuteOptions,\n): Promise<number> {\n const errors = await validateDependencies();\n if (errors.length > 0) {\n printError('The following required tools are not installed:');\n for (const err of errors) {\n console.log(err);\n }\n return 1;\n }\n\n const maxIterations = options.maxIterations ?? positionalMaxIter;\n\n const config = createConfig({\n issueNumber: options.issue,\n maxIterations,\n retryLimit: options.retryLimit,\n retryForever: options.retryForever,\n });\n\n const paths = await resolvePaths(config);\n const exitCode = await runEngine(config, paths);\n\n // Update pipeline state if all stories pass\n if (exitCode === 0 && config.issueNumber) {\n try {\n const plan = await loadTaskPlan(paths.prdFile);\n if (allStoriesPass(plan)) {\n plan.pipeline.executionCompleted = true;\n await saveTaskPlan(paths.prdFile, plan);\n }\n } catch {\n // Non-critical — engine already handled state\n }\n }\n\n return exitCode;\n}\n"],"mappings":"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","names":["join","chalk","chalk","execa","join","elapsed"]}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/core/verbose.ts
|
|
4
|
+
var _verbose = false;
|
|
5
|
+
function setVerbose(enabled) {
|
|
6
|
+
_verbose = enabled;
|
|
7
|
+
}
|
|
8
|
+
function isVerbose() {
|
|
9
|
+
return _verbose;
|
|
10
|
+
}
|
|
11
|
+
var _onOutput;
|
|
12
|
+
function setOutputCallback(callback) {
|
|
13
|
+
_onOutput = callback;
|
|
14
|
+
}
|
|
15
|
+
function getOutputCallback() {
|
|
16
|
+
return _onOutput;
|
|
17
|
+
}
|
|
18
|
+
var _onStoryUpdate;
|
|
19
|
+
function setStoryUpdateCallback(callback) {
|
|
20
|
+
_onStoryUpdate = callback;
|
|
21
|
+
}
|
|
22
|
+
function getStoryUpdateCallback() {
|
|
23
|
+
return _onStoryUpdate;
|
|
24
|
+
}
|
|
25
|
+
var _globalTimeout;
|
|
26
|
+
function setGlobalTimeout(ms) {
|
|
27
|
+
_globalTimeout = ms;
|
|
28
|
+
}
|
|
29
|
+
function getGlobalTimeout() {
|
|
30
|
+
return _globalTimeout;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// src/ui/logger.ts
|
|
34
|
+
import chalk from "chalk";
|
|
35
|
+
import ora from "ora";
|
|
36
|
+
function useUnicode() {
|
|
37
|
+
if (process.env.NO_COLOR != null && process.env.NO_COLOR !== "") return false;
|
|
38
|
+
if (!process.stdout.isTTY) return false;
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
function useColor() {
|
|
42
|
+
if (process.env.NO_COLOR != null && process.env.NO_COLOR !== "") return false;
|
|
43
|
+
if (!process.stdout.isTTY) return false;
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
function getIcons() {
|
|
47
|
+
if (useUnicode()) {
|
|
48
|
+
return {
|
|
49
|
+
success: "\u2713",
|
|
50
|
+
fail: "\u2717",
|
|
51
|
+
pending: "\u23F3",
|
|
52
|
+
retry: "\u21BB",
|
|
53
|
+
warn: "\u26A0",
|
|
54
|
+
start: "\u25B6",
|
|
55
|
+
end: "\u25A0",
|
|
56
|
+
notReached: "\u25CB",
|
|
57
|
+
tool: "\u25B8",
|
|
58
|
+
connector: "\u2502"
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
success: "[OK]",
|
|
63
|
+
fail: "[FAIL]",
|
|
64
|
+
pending: "[...]",
|
|
65
|
+
retry: "[RETRY]",
|
|
66
|
+
warn: "[WARN]",
|
|
67
|
+
start: "[START]",
|
|
68
|
+
end: "[END]",
|
|
69
|
+
notReached: "[ ]",
|
|
70
|
+
tool: ">",
|
|
71
|
+
connector: "|"
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function getTermWidth() {
|
|
75
|
+
return process.stdout.columns ?? 80;
|
|
76
|
+
}
|
|
77
|
+
function emit(line) {
|
|
78
|
+
const cb = getOutputCallback();
|
|
79
|
+
if (cb) {
|
|
80
|
+
cb(line);
|
|
81
|
+
} else {
|
|
82
|
+
console.log(line);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function printSuccess(message) {
|
|
86
|
+
const icons = getIcons();
|
|
87
|
+
if (useColor()) {
|
|
88
|
+
emit(chalk.green(`${icons.success} ${message}`));
|
|
89
|
+
} else {
|
|
90
|
+
emit(`${icons.success} ${message}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function printError(message) {
|
|
94
|
+
const icons = getIcons();
|
|
95
|
+
if (useColor()) {
|
|
96
|
+
emit(chalk.red(`${icons.fail} ${message}`));
|
|
97
|
+
} else {
|
|
98
|
+
emit(`${icons.fail} ${message}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function printWarning(message) {
|
|
102
|
+
const icons = getIcons();
|
|
103
|
+
if (useColor()) {
|
|
104
|
+
emit(chalk.yellow(`${icons.warn} ${message}`));
|
|
105
|
+
} else {
|
|
106
|
+
emit(`${icons.warn} ${message}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function printRetry(message) {
|
|
110
|
+
const icons = getIcons();
|
|
111
|
+
if (useColor()) {
|
|
112
|
+
emit(chalk.yellow(`${icons.retry} ${message}`));
|
|
113
|
+
} else {
|
|
114
|
+
emit(`${icons.retry} ${message}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function printInfo(message) {
|
|
118
|
+
const icons = getIcons();
|
|
119
|
+
if (useColor()) {
|
|
120
|
+
emit(chalk.blue(`${icons.start} ${message}`));
|
|
121
|
+
} else {
|
|
122
|
+
emit(`${icons.start} ${message}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function createSpinner(message) {
|
|
126
|
+
return ora({
|
|
127
|
+
text: message,
|
|
128
|
+
color: "blue",
|
|
129
|
+
spinner: "dots"
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
function formatDuration(totalSeconds) {
|
|
133
|
+
const hours = Math.floor(totalSeconds / 3600);
|
|
134
|
+
const mins = Math.floor(totalSeconds % 3600 / 60);
|
|
135
|
+
const secs = totalSeconds % 60;
|
|
136
|
+
if (hours > 0) {
|
|
137
|
+
return `${hours}h ${mins}m ${secs}s`;
|
|
138
|
+
}
|
|
139
|
+
if (mins > 0) {
|
|
140
|
+
return `${mins}m ${secs}s`;
|
|
141
|
+
}
|
|
142
|
+
return `${secs}s`;
|
|
143
|
+
}
|
|
144
|
+
var ElapsedTimer = class {
|
|
145
|
+
constructor(onTick) {
|
|
146
|
+
this.onTick = onTick;
|
|
147
|
+
this.startTime = Date.now();
|
|
148
|
+
}
|
|
149
|
+
startTime;
|
|
150
|
+
intervalId = null;
|
|
151
|
+
cleanup = () => this.stop();
|
|
152
|
+
start() {
|
|
153
|
+
this.startTime = Date.now();
|
|
154
|
+
this.intervalId = setInterval(() => {
|
|
155
|
+
const seconds = Math.floor((Date.now() - this.startTime) / 1e3);
|
|
156
|
+
this.onTick(formatDuration(seconds));
|
|
157
|
+
}, 1e3);
|
|
158
|
+
if (this.intervalId && typeof this.intervalId === "object" && "unref" in this.intervalId) {
|
|
159
|
+
this.intervalId.unref();
|
|
160
|
+
}
|
|
161
|
+
process.on("exit", this.cleanup);
|
|
162
|
+
return this;
|
|
163
|
+
}
|
|
164
|
+
getElapsedSeconds() {
|
|
165
|
+
return Math.floor((Date.now() - this.startTime) / 1e3);
|
|
166
|
+
}
|
|
167
|
+
stop() {
|
|
168
|
+
if (this.intervalId) {
|
|
169
|
+
clearInterval(this.intervalId);
|
|
170
|
+
this.intervalId = null;
|
|
171
|
+
}
|
|
172
|
+
process.removeListener("exit", this.cleanup);
|
|
173
|
+
return this.getElapsedSeconds();
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
export {
|
|
178
|
+
setVerbose,
|
|
179
|
+
isVerbose,
|
|
180
|
+
setOutputCallback,
|
|
181
|
+
getOutputCallback,
|
|
182
|
+
setStoryUpdateCallback,
|
|
183
|
+
getStoryUpdateCallback,
|
|
184
|
+
setGlobalTimeout,
|
|
185
|
+
getGlobalTimeout,
|
|
186
|
+
useUnicode,
|
|
187
|
+
useColor,
|
|
188
|
+
getIcons,
|
|
189
|
+
getTermWidth,
|
|
190
|
+
printSuccess,
|
|
191
|
+
printError,
|
|
192
|
+
printWarning,
|
|
193
|
+
printRetry,
|
|
194
|
+
printInfo,
|
|
195
|
+
createSpinner,
|
|
196
|
+
formatDuration,
|
|
197
|
+
ElapsedTimer
|
|
198
|
+
};
|
|
199
|
+
//# sourceMappingURL=chunk-YAFHVFV5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/verbose.ts","../src/ui/logger.ts"],"sourcesContent":["let _verbose = false;\n\nexport function setVerbose(enabled: boolean): void {\n _verbose = enabled;\n}\n\nexport function isVerbose(): boolean {\n return _verbose;\n}\n\nlet _onOutput: ((line: string) => void) | undefined;\n\n/**\n * Set a global output callback for routing verbose output (e.g., through listr2 task.output).\n * Pass undefined to clear and fall back to direct stderr writes.\n */\nexport function setOutputCallback(callback: ((line: string) => void) | undefined): void {\n _onOutput = callback;\n}\n\nexport function getOutputCallback(): ((line: string) => void) | undefined {\n return _onOutput;\n}\n\nlet _onStoryUpdate: ((stories: import('../types.js').UserStory[]) => void) | undefined;\n\n/**\n * Set a global callback for story progress updates during engine execution.\n * Called after each iteration with the latest user stories state.\n * Pass undefined to clear.\n */\nexport function setStoryUpdateCallback(\n callback: ((stories: import('../types.js').UserStory[]) => void) | undefined,\n): void {\n _onStoryUpdate = callback;\n}\n\nexport function getStoryUpdateCallback():\n | ((stories: import('../types.js').UserStory[]) => void)\n | undefined {\n return _onStoryUpdate;\n}\n\nlet _globalTimeout: number | undefined;\n\nexport function setGlobalTimeout(ms: number): void {\n _globalTimeout = ms;\n}\n\nexport function getGlobalTimeout(): number | undefined {\n return _globalTimeout;\n}\n","import chalk from 'chalk';\nimport ora, { type Ora } from 'ora';\nimport { getOutputCallback } from '../core/verbose.js';\n\n/**\n * Detect if unicode output is supported.\n */\nexport function useUnicode(): boolean {\n if (process.env.NO_COLOR != null && process.env.NO_COLOR !== '') return false;\n if (!process.stdout.isTTY) return false;\n return true;\n}\n\n/**\n * Detect if color output is supported.\n */\nexport function useColor(): boolean {\n if (process.env.NO_COLOR != null && process.env.NO_COLOR !== '') return false;\n if (!process.stdout.isTTY) return false;\n return true;\n}\n\nexport interface Icons {\n success: string;\n fail: string;\n pending: string;\n retry: string;\n warn: string;\n start: string;\n end: string;\n notReached: string;\n tool: string;\n connector: string;\n}\n\nexport function getIcons(): Icons {\n if (useUnicode()) {\n return {\n success: '\\u2713',\n fail: '\\u2717',\n pending: '\\u23F3',\n retry: '\\u21BB',\n warn: '\\u26A0',\n start: '\\u25B6',\n end: '\\u25A0',\n notReached: '\\u25CB',\n tool: '\\u25B8',\n connector: '\\u2502',\n };\n }\n return {\n success: '[OK]',\n fail: '[FAIL]',\n pending: '[...]',\n retry: '[RETRY]',\n warn: '[WARN]',\n start: '[START]',\n end: '[END]',\n notReached: '[ ]',\n tool: '>',\n connector: '|',\n };\n}\n\n/**\n * Get the terminal width.\n */\nexport function getTermWidth(): number {\n return process.stdout.columns ?? 80;\n}\n\n/**\n * Emit a line of output. Routes through the global output callback when\n * running inside a listr2 task context, otherwise falls back to console.log.\n */\nfunction emit(line: string): void {\n const cb = getOutputCallback();\n if (cb) {\n cb(line);\n } else {\n console.log(line);\n }\n}\n\nexport function printSuccess(message: string): void {\n const icons = getIcons();\n if (useColor()) {\n emit(chalk.green(`${icons.success} ${message}`));\n } else {\n emit(`${icons.success} ${message}`);\n }\n}\n\nexport function printError(message: string): void {\n const icons = getIcons();\n if (useColor()) {\n emit(chalk.red(`${icons.fail} ${message}`));\n } else {\n emit(`${icons.fail} ${message}`);\n }\n}\n\nexport function printWarning(message: string): void {\n const icons = getIcons();\n if (useColor()) {\n emit(chalk.yellow(`${icons.warn} ${message}`));\n } else {\n emit(`${icons.warn} ${message}`);\n }\n}\n\nexport function printRetry(message: string): void {\n const icons = getIcons();\n if (useColor()) {\n emit(chalk.yellow(`${icons.retry} ${message}`));\n } else {\n emit(`${icons.retry} ${message}`);\n }\n}\n\nexport function printInfo(message: string): void {\n const icons = getIcons();\n if (useColor()) {\n emit(chalk.blue(`${icons.start} ${message}`));\n } else {\n emit(`${icons.start} ${message}`);\n }\n}\n\n/**\n * Create an ora spinner with consistent styling.\n */\nexport function createSpinner(message: string): Ora {\n return ora({\n text: message,\n color: 'blue',\n spinner: 'dots',\n });\n}\n\n/**\n * Format a duration in seconds to a human-readable string.\n */\nexport function formatDuration(totalSeconds: number): string {\n const hours = Math.floor(totalSeconds / 3600);\n const mins = Math.floor((totalSeconds % 3600) / 60);\n const secs = totalSeconds % 60;\n\n if (hours > 0) {\n return `${hours}h ${mins}m ${secs}s`;\n }\n if (mins > 0) {\n return `${mins}m ${secs}s`;\n }\n return `${secs}s`;\n}\n\n/**\n * Timer that calls a callback every second with the formatted elapsed time.\n */\nexport class ElapsedTimer {\n private startTime: number;\n private intervalId: ReturnType<typeof setInterval> | null = null;\n private cleanup = () => this.stop();\n\n constructor(private onTick: (elapsed: string) => void) {\n this.startTime = Date.now();\n }\n\n start(): this {\n this.startTime = Date.now();\n this.intervalId = setInterval(() => {\n const seconds = Math.floor((Date.now() - this.startTime) / 1000);\n this.onTick(formatDuration(seconds));\n }, 1_000);\n // Prevent the timer from keeping the process alive\n if (this.intervalId && typeof this.intervalId === 'object' && 'unref' in this.intervalId) {\n this.intervalId.unref();\n }\n process.on('exit', this.cleanup);\n return this;\n }\n\n getElapsedSeconds(): number {\n return Math.floor((Date.now() - this.startTime) / 1000);\n }\n\n stop(): number {\n if (this.intervalId) {\n clearInterval(this.intervalId);\n this.intervalId = null;\n }\n process.removeListener('exit', this.cleanup);\n return this.getElapsedSeconds();\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
printError
|
|
4
|
-
|
|
3
|
+
printError,
|
|
4
|
+
setGlobalTimeout,
|
|
5
|
+
setVerbose
|
|
6
|
+
} from "./chunk-YAFHVFV5.js";
|
|
5
7
|
|
|
6
8
|
// src/cli.ts
|
|
7
9
|
import { Command, InvalidArgumentError } from "commander";
|
|
@@ -12,48 +14,78 @@ function parseInteger(value) {
|
|
|
12
14
|
}
|
|
13
15
|
return parsed;
|
|
14
16
|
}
|
|
17
|
+
function withGlobalOptions(cmd) {
|
|
18
|
+
return cmd.option("-v, --verbose", "Show Claude progress output in real time").option(
|
|
19
|
+
"-t, --timeout <seconds>",
|
|
20
|
+
"Override headless timeout in seconds (0 = no limit)",
|
|
21
|
+
parseInteger
|
|
22
|
+
);
|
|
23
|
+
}
|
|
15
24
|
var program = new Command();
|
|
16
25
|
program.name("issue-flow").description(
|
|
17
26
|
"Unified CLI for orchestrating the full issue-flow pipeline via Claude Code Headless."
|
|
18
27
|
).version("0.3.0");
|
|
19
|
-
program.
|
|
20
|
-
const
|
|
28
|
+
program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
29
|
+
const opts = actionCommand.opts();
|
|
30
|
+
if (opts.verbose) {
|
|
31
|
+
setVerbose(true);
|
|
32
|
+
}
|
|
33
|
+
if (opts.timeout !== void 0) {
|
|
34
|
+
setGlobalTimeout(opts.timeout * 1e3);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
withGlobalOptions(
|
|
38
|
+
program.command("init").description("Verify that all prerequisites (claude, gh, git) are met")
|
|
39
|
+
).action(async () => {
|
|
40
|
+
const { runInit } = await import("./init-SXFGOCML.js");
|
|
21
41
|
const code = await runInit();
|
|
22
42
|
process.exit(code);
|
|
23
43
|
});
|
|
24
|
-
|
|
25
|
-
|
|
44
|
+
withGlobalOptions(
|
|
45
|
+
program.command("generate").description("Create a GitHub issue via Claude Code Headless").requiredOption("--prompt <text>", "Issue description text")
|
|
46
|
+
).action(async (options) => {
|
|
47
|
+
const { runGenerate } = await import("./generate-HP4CPMJG.js");
|
|
26
48
|
const code = await runGenerate(options.prompt);
|
|
27
49
|
process.exit(code);
|
|
28
50
|
});
|
|
29
|
-
|
|
30
|
-
|
|
51
|
+
withGlobalOptions(
|
|
52
|
+
program.command("run").description("Execute the full pipeline: analyze \u2192 prd \u2192 plan \u2192 execute \u2192 review \u2192 pr").argument("<issue>", "Issue number").option("--mode <mode>", "Execution mode: auto | manual", "auto").option("--from <phase>", "Resume from a specific phase")
|
|
53
|
+
).action(async (issue, options) => {
|
|
54
|
+
const { runPipeline } = await import("./run-6CR5FDYH.js");
|
|
31
55
|
const code = await runPipeline(issue, options.mode, options.from);
|
|
32
56
|
process.exit(code);
|
|
33
57
|
});
|
|
34
|
-
|
|
35
|
-
|
|
58
|
+
withGlobalOptions(
|
|
59
|
+
program.command("analyze").description("Analyze a GitHub issue via Claude Code Headless").argument("<issue>", "Issue number")
|
|
60
|
+
).action(async (issue) => {
|
|
61
|
+
const { runAnalyze } = await import("./analyze-3SN7ZAZU.js");
|
|
36
62
|
const code = await runAnalyze(issue);
|
|
37
63
|
process.exit(code);
|
|
38
64
|
});
|
|
39
|
-
|
|
40
|
-
|
|
65
|
+
withGlobalOptions(
|
|
66
|
+
program.command("prd").description("Generate a PRD from an analyzed issue via Claude Code Headless").argument("<issue>", "Issue number")
|
|
67
|
+
).action(async (issue) => {
|
|
68
|
+
const { runPrd } = await import("./prd-ET2QN7GB.js");
|
|
41
69
|
const code = await runPrd(issue);
|
|
42
70
|
process.exit(code);
|
|
43
71
|
});
|
|
44
|
-
|
|
45
|
-
|
|
72
|
+
withGlobalOptions(
|
|
73
|
+
program.command("plan").description("Convert a PRD to a tasks.json task plan via Claude Code Headless").argument("<issue>", "Issue number")
|
|
74
|
+
).action(async (issue) => {
|
|
75
|
+
const { runPlan } = await import("./plan-HWZRG5GP.js");
|
|
46
76
|
const code = await runPlan(issue);
|
|
47
77
|
process.exit(code);
|
|
48
78
|
});
|
|
49
|
-
|
|
50
|
-
"--
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
79
|
+
withGlobalOptions(
|
|
80
|
+
program.command("execute").description("Run the iterative story execution loop (issue-flow engine)").option("--issue <number>", "Issue number \u2014 reads artifacts from issues/N/").option("--max-iterations <number>", "Stop after N iterations", parseInteger).option(
|
|
81
|
+
"--retry-limit <number>",
|
|
82
|
+
"Retry transient Claude failures up to N consecutive times",
|
|
83
|
+
parseInteger
|
|
84
|
+
).option("--retry-forever", "Retry transient Claude failures indefinitely").argument("[max-iterations]", "Backward-compatible alias for --max-iterations N", parseInteger)
|
|
85
|
+
).action(
|
|
54
86
|
async (positionalMaxIter, options) => {
|
|
55
87
|
try {
|
|
56
|
-
const { runExecute } = await import("./execute-
|
|
88
|
+
const { runExecute } = await import("./execute-6AAKNSLM.js");
|
|
57
89
|
const code = await runExecute(positionalMaxIter, options);
|
|
58
90
|
process.exit(code);
|
|
59
91
|
} catch (error) {
|
|
@@ -62,13 +94,17 @@ program.command("execute").description("Run the iterative story execution loop (
|
|
|
62
94
|
}
|
|
63
95
|
}
|
|
64
96
|
);
|
|
65
|
-
|
|
66
|
-
|
|
97
|
+
withGlobalOptions(
|
|
98
|
+
program.command("review").description("Validate an issue resolution via Claude Code Headless").argument("<issue>", "Issue number")
|
|
99
|
+
).action(async (issue) => {
|
|
100
|
+
const { runReview } = await import("./review-3QDZCOMT.js");
|
|
67
101
|
const code = await runReview(issue);
|
|
68
102
|
process.exit(code);
|
|
69
103
|
});
|
|
70
|
-
|
|
71
|
-
|
|
104
|
+
withGlobalOptions(
|
|
105
|
+
program.command("pr").description("Create a pull request via Claude Code Headless").argument("<issue>", "Issue number")
|
|
106
|
+
).action(async (issue) => {
|
|
107
|
+
const { runPr } = await import("./pr-TTOFYUCV.js");
|
|
72
108
|
const code = await runPr(issue);
|
|
73
109
|
process.exit(code);
|
|
74
110
|
});
|