issue-flow 0.3.1 → 0.4.2
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/dist/analyze-3SN7ZAZU.js +12 -0
- package/dist/{chunk-FPX32B2W.js → chunk-2JZCWJEQ.js} +4 -6
- package/dist/{chunk-FPX32B2W.js.map → chunk-2JZCWJEQ.js.map} +1 -1
- package/dist/{chunk-3M7FPMO7.js → chunk-4OQ2ARLP.js} +28 -22
- package/dist/chunk-4OQ2ARLP.js.map +1 -0
- package/dist/{chunk-K22WFAWY.js → chunk-4PZXIOXD.js} +4 -6
- package/dist/{chunk-K22WFAWY.js.map → chunk-4PZXIOXD.js.map} +1 -1
- package/dist/{chunk-7A6NLYQE.js → chunk-CSSXTPWE.js} +2 -2
- package/dist/{chunk-ZR5KSQWZ.js → chunk-CYWHYPTU.js} +4 -6
- package/dist/{chunk-ZR5KSQWZ.js.map → chunk-CYWHYPTU.js.map} +1 -1
- package/dist/{chunk-KTJI7WMC.js → chunk-HYP64MZI.js} +48 -176
- package/dist/chunk-HYP64MZI.js.map +1 -0
- package/dist/{chunk-R7HJYTQU.js → chunk-MEB3B2FI.js} +4 -6
- package/dist/{chunk-R7HJYTQU.js.map → chunk-MEB3B2FI.js.map} +1 -1
- package/dist/{chunk-2DR5PWPR.js → chunk-MWUIIUAS.js} +4 -6
- package/dist/{chunk-2DR5PWPR.js.map → chunk-MWUIIUAS.js.map} +1 -1
- package/dist/{chunk-SB52G2M2.js → chunk-YAFHVFV5.js} +58 -11
- package/dist/chunk-YAFHVFV5.js.map +1 -0
- package/dist/cli.js +15 -14
- package/dist/cli.js.map +1 -1
- package/dist/{execute-H3COM62D.js → execute-GIA4IKS5.js} +3 -3
- package/dist/{generate-KRVWNLQU.js → generate-HP4CPMJG.js} +4 -6
- package/dist/{generate-KRVWNLQU.js.map → generate-HP4CPMJG.js.map} +1 -1
- 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-PKHPULYL.js +451 -0
- package/dist/run-PKHPULYL.js.map +1 -0
- package/package.json +2 -1
- package/dist/analyze-YSKLI2YL.js +0 -13
- package/dist/chunk-3M7FPMO7.js.map +0 -1
- package/dist/chunk-KMZHFUOY.js +0 -25
- package/dist/chunk-KMZHFUOY.js.map +0 -1
- package/dist/chunk-KTJI7WMC.js.map +0 -1
- package/dist/chunk-SB52G2M2.js.map +0 -1
- package/dist/init-AA453TQF.js +0 -9
- package/dist/plan-GGF7FMOV.js +0 -13
- package/dist/pr-OF25YHPZ.js +0 -13
- package/dist/prd-MEYPY6XI.js +0 -13
- package/dist/review-7DQIPFTD.js +0 -13
- package/dist/run-JZAL7XB2.js +0 -302
- package/dist/run-JZAL7XB2.js.map +0 -1
- /package/dist/{analyze-YSKLI2YL.js.map → analyze-3SN7ZAZU.js.map} +0 -0
- /package/dist/{chunk-7A6NLYQE.js.map → chunk-CSSXTPWE.js.map} +0 -0
- /package/dist/{execute-H3COM62D.js.map → execute-GIA4IKS5.js.map} +0 -0
- /package/dist/{init-AA453TQF.js.map → init-SXFGOCML.js.map} +0 -0
- /package/dist/{plan-GGF7FMOV.js.map → plan-HWZRG5GP.js.map} +0 -0
- /package/dist/{pr-OF25YHPZ.js.map → pr-TTOFYUCV.js.map} +0 -0
- /package/dist/{prd-MEYPY6XI.js.map → prd-ET2QN7GB.js.map} +0 -0
- /package/dist/{review-7DQIPFTD.js.map → review-3QDZCOMT.js.map} +0 -0
|
@@ -18,13 +18,17 @@ import {
|
|
|
18
18
|
import {
|
|
19
19
|
formatDuration,
|
|
20
20
|
getIcons,
|
|
21
|
+
getOutputCallback,
|
|
22
|
+
getStoryUpdateCallback,
|
|
21
23
|
getTermWidth,
|
|
22
24
|
printError,
|
|
23
25
|
printInfo,
|
|
24
26
|
printRetry,
|
|
25
27
|
printSuccess,
|
|
26
|
-
printWarning
|
|
27
|
-
|
|
28
|
+
printWarning,
|
|
29
|
+
useColor,
|
|
30
|
+
useUnicode
|
|
31
|
+
} from "./chunk-YAFHVFV5.js";
|
|
28
32
|
|
|
29
33
|
// src/config.ts
|
|
30
34
|
import { platform } from "os";
|
|
@@ -126,16 +130,6 @@ import { join as join2 } from "path";
|
|
|
126
130
|
|
|
127
131
|
// src/ui/progress.ts
|
|
128
132
|
import chalk from "chalk";
|
|
129
|
-
function useColor() {
|
|
130
|
-
if (process.env.NO_COLOR === "1") return false;
|
|
131
|
-
if (!process.stdout.isTTY) return false;
|
|
132
|
-
return true;
|
|
133
|
-
}
|
|
134
|
-
function useUnicode() {
|
|
135
|
-
if (process.env.NO_COLOR === "1") return false;
|
|
136
|
-
if (!process.stdout.isTTY) return false;
|
|
137
|
-
return true;
|
|
138
|
-
}
|
|
139
133
|
function printProgressBar(passed, total) {
|
|
140
134
|
const barWidth = 20;
|
|
141
135
|
let pct = 0;
|
|
@@ -157,16 +151,16 @@ function printProgressBar(passed, total) {
|
|
|
157
151
|
function printIterationHeader(iteration, maxIter, stories) {
|
|
158
152
|
const icons = getIcons();
|
|
159
153
|
const colored = useColor();
|
|
154
|
+
const cb = getOutputCallback();
|
|
160
155
|
const iterLabel = maxIter ? `Iteration ${iteration} of ${maxIter}` : `Iteration ${iteration}`;
|
|
161
156
|
const total = stories.length;
|
|
162
157
|
const passed = stories.filter((s) => s.passes).length;
|
|
163
|
-
|
|
158
|
+
const lines = [];
|
|
164
159
|
if (colored) {
|
|
165
|
-
|
|
160
|
+
lines.push(chalk.blue(`\u2501\u2501\u2501 ${icons.start} ${iterLabel} \u2501\u2501\u2501`));
|
|
166
161
|
} else {
|
|
167
|
-
|
|
162
|
+
lines.push(`--- ${icons.start} ${iterLabel} ---`);
|
|
168
163
|
}
|
|
169
|
-
console.log("");
|
|
170
164
|
let foundFirstPending = false;
|
|
171
165
|
for (const story of stories) {
|
|
172
166
|
let icon;
|
|
@@ -182,160 +176,22 @@ function printIterationHeader(iteration, maxIter, stories) {
|
|
|
182
176
|
icon = icons.notReached;
|
|
183
177
|
colorFn = colored ? chalk.gray : (s) => s;
|
|
184
178
|
}
|
|
185
|
-
|
|
186
|
-
}
|
|
187
|
-
console.log("");
|
|
188
|
-
console.log(` ${printProgressBar(passed, total)}`);
|
|
189
|
-
}
|
|
190
|
-
var PHASE_LABELS = {
|
|
191
|
-
analyze: "Analyze",
|
|
192
|
-
prd: "PRD",
|
|
193
|
-
plan: "Plan",
|
|
194
|
-
execute: "Execute",
|
|
195
|
-
review: "Review",
|
|
196
|
-
pr: "PR"
|
|
197
|
-
};
|
|
198
|
-
var PipelineTracker = class {
|
|
199
|
-
phases;
|
|
200
|
-
overallStartTime;
|
|
201
|
-
currentPhaseStart = null;
|
|
202
|
-
intervalId = null;
|
|
203
|
-
lastLineCount = 0;
|
|
204
|
-
isTTY;
|
|
205
|
-
constructor(phaseNames, startIndex) {
|
|
206
|
-
this.overallStartTime = Date.now();
|
|
207
|
-
this.isTTY = !!process.stderr.isTTY;
|
|
208
|
-
this.phases = phaseNames.map((name, i) => ({
|
|
209
|
-
name,
|
|
210
|
-
label: PHASE_LABELS[name] ?? name.charAt(0).toUpperCase() + name.slice(1),
|
|
211
|
-
status: i < startIndex ? "skipped" : "pending",
|
|
212
|
-
durationSeconds: null
|
|
213
|
-
}));
|
|
214
|
-
}
|
|
215
|
-
startPhase(name) {
|
|
216
|
-
const phase = this.phases.find((p) => p.name === name);
|
|
217
|
-
if (phase) {
|
|
218
|
-
phase.status = "running";
|
|
219
|
-
this.currentPhaseStart = Date.now();
|
|
220
|
-
}
|
|
221
|
-
this.render();
|
|
222
|
-
}
|
|
223
|
-
completePhase(name) {
|
|
224
|
-
const phase = this.phases.find((p) => p.name === name);
|
|
225
|
-
if (phase) {
|
|
226
|
-
phase.status = "completed";
|
|
227
|
-
phase.durationSeconds = this.currentPhaseStart ? Math.floor((Date.now() - this.currentPhaseStart) / 1e3) : 0;
|
|
228
|
-
this.currentPhaseStart = null;
|
|
229
|
-
}
|
|
230
|
-
this.render();
|
|
231
|
-
}
|
|
232
|
-
failPhase(name) {
|
|
233
|
-
const phase = this.phases.find((p) => p.name === name);
|
|
234
|
-
if (phase) {
|
|
235
|
-
phase.status = "failed";
|
|
236
|
-
phase.durationSeconds = this.currentPhaseStart ? Math.floor((Date.now() - this.currentPhaseStart) / 1e3) : 0;
|
|
237
|
-
this.currentPhaseStart = null;
|
|
238
|
-
}
|
|
239
|
-
this.stopLiveUpdate();
|
|
240
|
-
this.render();
|
|
241
|
-
}
|
|
242
|
-
getOverallElapsed() {
|
|
243
|
-
return Math.floor((Date.now() - this.overallStartTime) / 1e3);
|
|
244
|
-
}
|
|
245
|
-
startLiveUpdate() {
|
|
246
|
-
if (!this.isTTY) return;
|
|
247
|
-
this.intervalId = setInterval(() => {
|
|
248
|
-
this.render();
|
|
249
|
-
}, 1e3);
|
|
250
|
-
if (this.intervalId && typeof this.intervalId === "object" && "unref" in this.intervalId) {
|
|
251
|
-
this.intervalId.unref();
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
stopLiveUpdate() {
|
|
255
|
-
if (this.intervalId) {
|
|
256
|
-
clearInterval(this.intervalId);
|
|
257
|
-
this.intervalId = null;
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
render() {
|
|
261
|
-
const icons = getIcons();
|
|
262
|
-
const colored = useColor();
|
|
263
|
-
const unicode = useUnicode();
|
|
264
|
-
const overallElapsed = formatDuration(this.getOverallElapsed());
|
|
265
|
-
const separator = unicode ? "\u2500".repeat(48) : "-".repeat(48);
|
|
266
|
-
const lines = [];
|
|
267
|
-
const title = "Pipeline Progress";
|
|
268
|
-
const timeLabel = `Total: ${overallElapsed}`;
|
|
269
|
-
const headerPad = Math.max(0, 48 - title.length - timeLabel.length);
|
|
270
|
-
const headerLine = ` ${title}${" ".repeat(headerPad)}${timeLabel}`;
|
|
271
|
-
lines.push(colored ? chalk.blue(headerLine) : headerLine);
|
|
272
|
-
lines.push(colored ? chalk.dim(` ${separator}`) : ` ${separator}`);
|
|
273
|
-
for (const phase of this.phases) {
|
|
274
|
-
lines.push(this.formatPhase(phase, icons, colored));
|
|
275
|
-
}
|
|
276
|
-
lines.push("");
|
|
277
|
-
if (this.isTTY && this.lastLineCount > 0) {
|
|
278
|
-
process.stderr.write(`\x1B[${this.lastLineCount}A\x1B[0J`);
|
|
279
|
-
}
|
|
280
|
-
this.lastLineCount = lines.length;
|
|
281
|
-
process.stderr.write(`${lines.join("\n")}
|
|
282
|
-
`);
|
|
179
|
+
lines.push(colorFn(` ${icon} ${story.id}: ${story.title}`));
|
|
283
180
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
colorFn = colored ? chalk.green : (s) => s;
|
|
292
|
-
durationStr = phase.durationSeconds != null ? formatDuration(phase.durationSeconds) : "";
|
|
293
|
-
break;
|
|
294
|
-
case "running": {
|
|
295
|
-
icon = icons.pending;
|
|
296
|
-
colorFn = colored ? chalk.yellow : (s) => s;
|
|
297
|
-
const runningElapsed = this.currentPhaseStart ? Math.floor((Date.now() - this.currentPhaseStart) / 1e3) : 0;
|
|
298
|
-
durationStr = formatDuration(runningElapsed);
|
|
299
|
-
break;
|
|
300
|
-
}
|
|
301
|
-
case "failed":
|
|
302
|
-
icon = icons.fail;
|
|
303
|
-
colorFn = colored ? chalk.red : (s) => s;
|
|
304
|
-
durationStr = phase.durationSeconds != null ? formatDuration(phase.durationSeconds) : "";
|
|
305
|
-
break;
|
|
306
|
-
case "skipped":
|
|
307
|
-
icon = icons.success;
|
|
308
|
-
colorFn = colored ? chalk.dim : (s) => s;
|
|
309
|
-
durationStr = "skipped";
|
|
310
|
-
break;
|
|
311
|
-
default:
|
|
312
|
-
icon = icons.notReached;
|
|
313
|
-
colorFn = colored ? chalk.gray : (s) => s;
|
|
314
|
-
break;
|
|
315
|
-
}
|
|
316
|
-
const label = phase.label;
|
|
317
|
-
if (durationStr) {
|
|
318
|
-
const dotChar = colored ? chalk.dim(".") : ".";
|
|
319
|
-
const maxDots = Math.max(1, 40 - label.length - durationStr.length);
|
|
320
|
-
const dots = dotChar.repeat(maxDots);
|
|
321
|
-
return colorFn(` ${icon} ${label} ${dots} ${durationStr}`);
|
|
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);
|
|
322
188
|
}
|
|
323
|
-
|
|
189
|
+
console.log("");
|
|
324
190
|
}
|
|
325
|
-
}
|
|
191
|
+
}
|
|
326
192
|
|
|
327
193
|
// src/ui/summary.ts
|
|
328
194
|
import chalk2 from "chalk";
|
|
329
|
-
function useColor2() {
|
|
330
|
-
if (process.env.NO_COLOR != null && process.env.NO_COLOR !== "") return false;
|
|
331
|
-
if (!process.stdout.isTTY) return false;
|
|
332
|
-
return true;
|
|
333
|
-
}
|
|
334
|
-
function useUnicode2() {
|
|
335
|
-
if (process.env.NO_COLOR != null && process.env.NO_COLOR !== "") return false;
|
|
336
|
-
if (!process.stdout.isTTY) return false;
|
|
337
|
-
return true;
|
|
338
|
-
}
|
|
339
195
|
function fitLine(text, width) {
|
|
340
196
|
if (text.length > width) {
|
|
341
197
|
return text.substring(0, width);
|
|
@@ -343,8 +199,8 @@ function fitLine(text, width) {
|
|
|
343
199
|
return text.padEnd(width);
|
|
344
200
|
}
|
|
345
201
|
function printBox(lines) {
|
|
346
|
-
const colored =
|
|
347
|
-
const unicode =
|
|
202
|
+
const colored = useColor();
|
|
203
|
+
const unicode = useUnicode();
|
|
348
204
|
const termWidth = getTermWidth();
|
|
349
205
|
let maxContentWidth = 0;
|
|
350
206
|
for (const line of lines) {
|
|
@@ -492,9 +348,12 @@ async function executeClaude(prompt) {
|
|
|
492
348
|
const stderr = result.stderr?.toString() ?? "";
|
|
493
349
|
const output = stdout + (stderr ? `
|
|
494
350
|
${stderr}` : "");
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
351
|
+
const onOutput = getOutputCallback();
|
|
352
|
+
if (onOutput) {
|
|
353
|
+
const trimmed = output.trim();
|
|
354
|
+
if (trimmed) {
|
|
355
|
+
onOutput(trimmed);
|
|
356
|
+
}
|
|
498
357
|
}
|
|
499
358
|
return {
|
|
500
359
|
exitCode: result.exitCode ?? 1,
|
|
@@ -506,6 +365,16 @@ ${stderr}` : "");
|
|
|
506
365
|
function sleep(seconds) {
|
|
507
366
|
return new Promise((resolve) => setTimeout(resolve, seconds * 1e3));
|
|
508
367
|
}
|
|
368
|
+
function emitLog(message) {
|
|
369
|
+
const cb = getOutputCallback();
|
|
370
|
+
if (cb) {
|
|
371
|
+
if (message) {
|
|
372
|
+
cb(message);
|
|
373
|
+
}
|
|
374
|
+
} else {
|
|
375
|
+
console.log(message);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
509
378
|
async function ensureProgressFile(progressFile) {
|
|
510
379
|
if (!existsSync(progressFile)) {
|
|
511
380
|
const content = `# Issue Flow Progress Log
|
|
@@ -561,7 +430,7 @@ async function runEngine(config, paths) {
|
|
|
561
430
|
if (!existsSync(paths.prdFile)) {
|
|
562
431
|
printError(`PRD file not found at ${paths.prdFile}`);
|
|
563
432
|
if (config.issueNumber) {
|
|
564
|
-
|
|
433
|
+
emitLog(`Have you run the resolve-issue skill for issue #${config.issueNumber} first?`);
|
|
565
434
|
}
|
|
566
435
|
return 1;
|
|
567
436
|
}
|
|
@@ -569,7 +438,7 @@ async function runEngine(config, paths) {
|
|
|
569
438
|
plan = initializeState(plan);
|
|
570
439
|
await saveTaskPlan(paths.prdFile, plan);
|
|
571
440
|
if (plan.issueStatus === "completed" && allStoriesPass(plan)) {
|
|
572
|
-
|
|
441
|
+
emitLog(`Issue already marked complete in ${paths.prdFile}`);
|
|
573
442
|
return 0;
|
|
574
443
|
}
|
|
575
444
|
if (plan.issueStatus === "completed" && !allStoriesPass(plan)) {
|
|
@@ -585,7 +454,7 @@ async function runEngine(config, paths) {
|
|
|
585
454
|
await saveTaskPlan(paths.prdFile, plan);
|
|
586
455
|
}
|
|
587
456
|
if (allStoriesPass(plan)) {
|
|
588
|
-
|
|
457
|
+
emitLog("All user stories already pass. Marking issue as completed.");
|
|
589
458
|
plan = markIssueCompleted(plan);
|
|
590
459
|
await saveTaskPlan(paths.prdFile, plan);
|
|
591
460
|
return 0;
|
|
@@ -640,7 +509,7 @@ async function runEngine(config, paths) {
|
|
|
640
509
|
config.backoffBaseSeconds,
|
|
641
510
|
config.backoffMaxSeconds
|
|
642
511
|
);
|
|
643
|
-
|
|
512
|
+
emitLog("");
|
|
644
513
|
printRetry(
|
|
645
514
|
`Transient Claude failure on iteration ${i} (attempt ${retryCount}). Retrying in ${delaySeconds}s.`
|
|
646
515
|
);
|
|
@@ -666,6 +535,10 @@ async function runEngine(config, paths) {
|
|
|
666
535
|
plan = await loadTaskPlan(paths.prdFile);
|
|
667
536
|
plan = clearLastError(plan, iterationStartedAt);
|
|
668
537
|
await saveTaskPlan(paths.prdFile, plan);
|
|
538
|
+
const storyUpdateCb = getStoryUpdateCallback();
|
|
539
|
+
if (storyUpdateCb) {
|
|
540
|
+
storyUpdateCb(plan.userStories);
|
|
541
|
+
}
|
|
669
542
|
if (result.output.includes("<promise>COMPLETE</promise>")) {
|
|
670
543
|
plan = await loadTaskPlan(paths.prdFile);
|
|
671
544
|
if (allStoriesPass(plan)) {
|
|
@@ -681,7 +554,7 @@ async function runEngine(config, paths) {
|
|
|
681
554
|
"Claude returned <promise>COMPLETE</promise> before every story had passes=true."
|
|
682
555
|
);
|
|
683
556
|
await saveTaskPlan(paths.prdFile, plan);
|
|
684
|
-
|
|
557
|
+
emitLog("");
|
|
685
558
|
printWarning(
|
|
686
559
|
"Claude returned a completion signal, but tasks.json still has pending stories. Ignoring completion and continuing."
|
|
687
560
|
);
|
|
@@ -735,7 +608,6 @@ async function runExecute(positionalMaxIter, options) {
|
|
|
735
608
|
}
|
|
736
609
|
|
|
737
610
|
export {
|
|
738
|
-
PipelineTracker,
|
|
739
611
|
runExecute
|
|
740
612
|
};
|
|
741
|
-
//# sourceMappingURL=chunk-
|
|
613
|
+
//# sourceMappingURL=chunk-HYP64MZI.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';\nimport { getOutputCallback } from './verbose.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 returned via ClaudeResult and routed through the output callback infrastructure.\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 through the global callback (listr2 renderer) when active\n const onOutput = getOutputCallback();\n if (onOutput) {\n const trimmed = output.trim();\n if (trimmed) {\n onOutput(trimmed);\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","execa","join","elapsed"]}
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
runHeadless
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import {
|
|
6
|
-
getGlobalTimeout
|
|
7
|
-
} from "./chunk-KMZHFUOY.js";
|
|
4
|
+
} from "./chunk-4OQ2ARLP.js";
|
|
8
5
|
import {
|
|
9
6
|
loadTaskPlan,
|
|
10
7
|
saveTaskPlan
|
|
@@ -14,10 +11,11 @@ import {
|
|
|
14
11
|
loadPrompt
|
|
15
12
|
} from "./chunk-OZVHOVDT.js";
|
|
16
13
|
import {
|
|
14
|
+
getGlobalTimeout,
|
|
17
15
|
printError,
|
|
18
16
|
printInfo,
|
|
19
17
|
printSuccess
|
|
20
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-YAFHVFV5.js";
|
|
21
19
|
|
|
22
20
|
// src/commands/analyze.ts
|
|
23
21
|
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
@@ -68,4 +66,4 @@ async function runAnalyze(issue) {
|
|
|
68
66
|
export {
|
|
69
67
|
runAnalyze
|
|
70
68
|
};
|
|
71
|
-
//# sourceMappingURL=chunk-
|
|
69
|
+
//# sourceMappingURL=chunk-MEB3B2FI.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/analyze.ts"],"sourcesContent":["import { mkdir, readFile, writeFile } 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 { printError, printInfo, printSuccess } from '../ui/logger.js';\n\nexport async function runAnalyze(issue: string): Promise<number> {\n const issueNumber = issue.replace(/^#/, '');\n const issueDir = join('issues', issueNumber);\n const analysisPath = join(issueDir, 'analysis.md');\n\n await mkdir(issueDir, { recursive: true });\n\n const template = await loadPrompt('analyze');\n const prompt = applyPlaceholders(template, {\n __ISSUE_NUMBER__: issueNumber,\n __ANALYSIS_PATH__: analysisPath,\n });\n\n const result = await runHeadless({\n prompt,\n maxTurns: 30,\n timeout: getGlobalTimeout() ?? 300_000,\n outputFormat: 'text',\n allowedTools: ['Bash', 'Read', 'Glob', 'Grep', 'Write'],\n statusMessage: `Analyzing issue #${issueNumber}...`,\n });\n\n if (!result.success) {\n printError(`Analysis failed: ${result.error}`);\n return 1;\n }\n\n // Verify the file was created\n try {\n const content = await readFile(analysisPath, 'utf-8');\n if (content.length < 10) {\n printError('Analysis file was created but appears empty');\n return 1;\n }\n } catch {\n // File wasn't created by headless — save the result as analysis\n printInfo('Headless did not create analysis file; saving output directly');\n await writeFile(analysisPath, result.result, 'utf-8');\n }\n\n // Update pipeline state\n const tasksPath = join(issueDir, 'tasks.json');\n try {\n const plan = await loadTaskPlan(tasksPath);\n plan.pipeline.analyzeCompleted = true;\n await saveTaskPlan(tasksPath, plan);\n } catch {\n // tasks.json may not exist yet — that's OK for standalone analyze\n }\n\n printSuccess(`Analysis saved to ${analysisPath}`);\n return 0;\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/commands/analyze.ts"],"sourcesContent":["import { mkdir, readFile, writeFile } 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 { printError, printInfo, printSuccess } from '../ui/logger.js';\n\nexport async function runAnalyze(issue: string): Promise<number> {\n const issueNumber = issue.replace(/^#/, '');\n const issueDir = join('issues', issueNumber);\n const analysisPath = join(issueDir, 'analysis.md');\n\n await mkdir(issueDir, { recursive: true });\n\n const template = await loadPrompt('analyze');\n const prompt = applyPlaceholders(template, {\n __ISSUE_NUMBER__: issueNumber,\n __ANALYSIS_PATH__: analysisPath,\n });\n\n const result = await runHeadless({\n prompt,\n maxTurns: 30,\n timeout: getGlobalTimeout() ?? 300_000,\n outputFormat: 'text',\n allowedTools: ['Bash', 'Read', 'Glob', 'Grep', 'Write'],\n statusMessage: `Analyzing issue #${issueNumber}...`,\n });\n\n if (!result.success) {\n printError(`Analysis failed: ${result.error}`);\n return 1;\n }\n\n // Verify the file was created\n try {\n const content = await readFile(analysisPath, 'utf-8');\n if (content.length < 10) {\n printError('Analysis file was created but appears empty');\n return 1;\n }\n } catch {\n // File wasn't created by headless — save the result as analysis\n printInfo('Headless did not create analysis file; saving output directly');\n await writeFile(analysisPath, result.result, 'utf-8');\n }\n\n // Update pipeline state\n const tasksPath = join(issueDir, 'tasks.json');\n try {\n const plan = await loadTaskPlan(tasksPath);\n plan.pipeline.analyzeCompleted = true;\n await saveTaskPlan(tasksPath, plan);\n } catch {\n // tasks.json may not exist yet — that's OK for standalone analyze\n }\n\n printSuccess(`Analysis saved to ${analysisPath}`);\n return 0;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA,SAAS,OAAO,UAAU,iBAAiB;AAC3C,SAAS,YAAY;AAOrB,eAAsB,WAAW,OAAgC;AAC/D,QAAM,cAAc,MAAM,QAAQ,MAAM,EAAE;AAC1C,QAAM,WAAW,KAAK,UAAU,WAAW;AAC3C,QAAM,eAAe,KAAK,UAAU,aAAa;AAEjD,QAAM,MAAM,UAAU,EAAE,WAAW,KAAK,CAAC;AAEzC,QAAM,WAAW,MAAM,WAAW,SAAS;AAC3C,QAAM,SAAS,kBAAkB,UAAU;AAAA,IACzC,kBAAkB;AAAA,IAClB,mBAAmB;AAAA,EACrB,CAAC;AAED,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,oBAAoB,WAAW;AAAA,EAChD,CAAC;AAED,MAAI,CAAC,OAAO,SAAS;AACnB,eAAW,oBAAoB,OAAO,KAAK,EAAE;AAC7C,WAAO;AAAA,EACT;AAGA,MAAI;AACF,UAAM,UAAU,MAAM,SAAS,cAAc,OAAO;AACpD,QAAI,QAAQ,SAAS,IAAI;AACvB,iBAAW,6CAA6C;AACxD,aAAO;AAAA,IACT;AAAA,EACF,QAAQ;AAEN,cAAU,+DAA+D;AACzE,UAAM,UAAU,cAAc,OAAO,QAAQ,OAAO;AAAA,EACtD;AAGA,QAAM,YAAY,KAAK,UAAU,YAAY;AAC7C,MAAI;AACF,UAAM,OAAO,MAAM,aAAa,SAAS;AACzC,SAAK,SAAS,mBAAmB;AACjC,UAAM,aAAa,WAAW,IAAI;AAAA,EACpC,QAAQ;AAAA,EAER;AAEA,eAAa,qBAAqB,YAAY,EAAE;AAChD,SAAO;AACT;","names":[]}
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
runHeadless
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import {
|
|
6
|
-
getGlobalTimeout
|
|
7
|
-
} from "./chunk-KMZHFUOY.js";
|
|
4
|
+
} from "./chunk-4OQ2ARLP.js";
|
|
8
5
|
import {
|
|
9
6
|
loadTaskPlan,
|
|
10
7
|
saveTaskPlan,
|
|
@@ -15,9 +12,10 @@ import {
|
|
|
15
12
|
loadPrompt
|
|
16
13
|
} from "./chunk-OZVHOVDT.js";
|
|
17
14
|
import {
|
|
15
|
+
getGlobalTimeout,
|
|
18
16
|
printError,
|
|
19
17
|
printSuccess
|
|
20
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-YAFHVFV5.js";
|
|
21
19
|
|
|
22
20
|
// src/commands/plan.ts
|
|
23
21
|
import { mkdir, readFile } from "fs/promises";
|
|
@@ -84,4 +82,4 @@ ${issues}`);
|
|
|
84
82
|
export {
|
|
85
83
|
runPlan
|
|
86
84
|
};
|
|
87
|
-
//# sourceMappingURL=chunk-
|
|
85
|
+
//# sourceMappingURL=chunk-MWUIIUAS.js.map
|
|
@@ -1 +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":"
|
|
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":[]}
|
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
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
|
+
|
|
3
33
|
// src/ui/logger.ts
|
|
4
34
|
import chalk from "chalk";
|
|
5
35
|
import ora from "ora";
|
|
@@ -44,44 +74,52 @@ function getIcons() {
|
|
|
44
74
|
function getTermWidth() {
|
|
45
75
|
return process.stdout.columns ?? 80;
|
|
46
76
|
}
|
|
77
|
+
function emit(line) {
|
|
78
|
+
const cb = getOutputCallback();
|
|
79
|
+
if (cb) {
|
|
80
|
+
cb(line);
|
|
81
|
+
} else {
|
|
82
|
+
console.log(line);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
47
85
|
function printSuccess(message) {
|
|
48
86
|
const icons = getIcons();
|
|
49
87
|
if (useColor()) {
|
|
50
|
-
|
|
88
|
+
emit(chalk.green(`${icons.success} ${message}`));
|
|
51
89
|
} else {
|
|
52
|
-
|
|
90
|
+
emit(`${icons.success} ${message}`);
|
|
53
91
|
}
|
|
54
92
|
}
|
|
55
93
|
function printError(message) {
|
|
56
94
|
const icons = getIcons();
|
|
57
95
|
if (useColor()) {
|
|
58
|
-
|
|
96
|
+
emit(chalk.red(`${icons.fail} ${message}`));
|
|
59
97
|
} else {
|
|
60
|
-
|
|
98
|
+
emit(`${icons.fail} ${message}`);
|
|
61
99
|
}
|
|
62
100
|
}
|
|
63
101
|
function printWarning(message) {
|
|
64
102
|
const icons = getIcons();
|
|
65
103
|
if (useColor()) {
|
|
66
|
-
|
|
104
|
+
emit(chalk.yellow(`${icons.warn} ${message}`));
|
|
67
105
|
} else {
|
|
68
|
-
|
|
106
|
+
emit(`${icons.warn} ${message}`);
|
|
69
107
|
}
|
|
70
108
|
}
|
|
71
109
|
function printRetry(message) {
|
|
72
110
|
const icons = getIcons();
|
|
73
111
|
if (useColor()) {
|
|
74
|
-
|
|
112
|
+
emit(chalk.yellow(`${icons.retry} ${message}`));
|
|
75
113
|
} else {
|
|
76
|
-
|
|
114
|
+
emit(`${icons.retry} ${message}`);
|
|
77
115
|
}
|
|
78
116
|
}
|
|
79
117
|
function printInfo(message) {
|
|
80
118
|
const icons = getIcons();
|
|
81
119
|
if (useColor()) {
|
|
82
|
-
|
|
120
|
+
emit(chalk.blue(`${icons.start} ${message}`));
|
|
83
121
|
} else {
|
|
84
|
-
|
|
122
|
+
emit(`${icons.start} ${message}`);
|
|
85
123
|
}
|
|
86
124
|
}
|
|
87
125
|
function createSpinner(message) {
|
|
@@ -137,6 +175,15 @@ var ElapsedTimer = class {
|
|
|
137
175
|
};
|
|
138
176
|
|
|
139
177
|
export {
|
|
178
|
+
setVerbose,
|
|
179
|
+
isVerbose,
|
|
180
|
+
setOutputCallback,
|
|
181
|
+
getOutputCallback,
|
|
182
|
+
setStoryUpdateCallback,
|
|
183
|
+
getStoryUpdateCallback,
|
|
184
|
+
setGlobalTimeout,
|
|
185
|
+
getGlobalTimeout,
|
|
186
|
+
useUnicode,
|
|
140
187
|
useColor,
|
|
141
188
|
getIcons,
|
|
142
189
|
getTermWidth,
|
|
@@ -149,4 +196,4 @@ export {
|
|
|
149
196
|
formatDuration,
|
|
150
197
|
ElapsedTimer
|
|
151
198
|
};
|
|
152
|
-
//# sourceMappingURL=chunk-
|
|
199
|
+
//# sourceMappingURL=chunk-YAFHVFV5.js.map
|