issue-flow 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/README.md +25 -0
  2. package/dist/analyze-YSKLI2YL.js +13 -0
  3. package/dist/{chunk-ZOX7M2C2.js → chunk-2DR5PWPR.js} +10 -8
  4. package/dist/chunk-2DR5PWPR.js.map +1 -0
  5. package/dist/chunk-3M7FPMO7.js +269 -0
  6. package/dist/chunk-3M7FPMO7.js.map +1 -0
  7. package/dist/{chunk-JEUHCE3V.js → chunk-7A6NLYQE.js} +2 -2
  8. package/dist/{chunk-G36DIQ4J.js → chunk-FPX32B2W.js} +10 -8
  9. package/dist/chunk-FPX32B2W.js.map +1 -0
  10. package/dist/{chunk-D4WBCVB4.js → chunk-K22WFAWY.js} +10 -8
  11. package/dist/chunk-K22WFAWY.js.map +1 -0
  12. package/dist/chunk-KMZHFUOY.js +25 -0
  13. package/dist/chunk-KMZHFUOY.js.map +1 -0
  14. package/dist/{chunk-V356G3JS.js → chunk-KTJI7WMC.js} +140 -10
  15. package/dist/chunk-KTJI7WMC.js.map +1 -0
  16. package/dist/{chunk-7APADNBV.js → chunk-R7HJYTQU.js} +10 -7
  17. package/dist/chunk-R7HJYTQU.js.map +1 -0
  18. package/dist/{chunk-L7RIGFP6.js → chunk-SB52G2M2.js} +64 -4
  19. package/dist/chunk-SB52G2M2.js.map +1 -0
  20. package/dist/{chunk-7FRXZ2XA.js → chunk-ZR5KSQWZ.js} +9 -7
  21. package/dist/chunk-ZR5KSQWZ.js.map +1 -0
  22. package/dist/cli.js +62 -24
  23. package/dist/cli.js.map +1 -1
  24. package/dist/{execute-UF3IY2MG.js → execute-H3COM62D.js} +3 -3
  25. package/dist/{generate-WMYJEPI4.js → generate-KRVWNLQU.js} +9 -7
  26. package/dist/generate-KRVWNLQU.js.map +1 -0
  27. package/dist/init-AA453TQF.js +9 -0
  28. package/dist/plan-GGF7FMOV.js +13 -0
  29. package/dist/pr-OF25YHPZ.js +13 -0
  30. package/dist/prd-MEYPY6XI.js +13 -0
  31. package/dist/review-7DQIPFTD.js +13 -0
  32. package/dist/{run-J62FIB5O.js → run-JZAL7XB2.js} +29 -15
  33. package/dist/run-JZAL7XB2.js.map +1 -0
  34. package/package.json +2 -2
  35. package/dist/analyze-YYQQP64A.js +0 -12
  36. package/dist/chunk-7APADNBV.js.map +0 -1
  37. package/dist/chunk-7FRXZ2XA.js.map +0 -1
  38. package/dist/chunk-D4WBCVB4.js.map +0 -1
  39. package/dist/chunk-G36DIQ4J.js.map +0 -1
  40. package/dist/chunk-L7RIGFP6.js.map +0 -1
  41. package/dist/chunk-PINC2LST.js +0 -82
  42. package/dist/chunk-PINC2LST.js.map +0 -1
  43. package/dist/chunk-V356G3JS.js.map +0 -1
  44. package/dist/chunk-ZOX7M2C2.js.map +0 -1
  45. package/dist/generate-WMYJEPI4.js.map +0 -1
  46. package/dist/init-QES2HLP5.js +0 -9
  47. package/dist/plan-BKSUDN34.js +0 -12
  48. package/dist/pr-E2ASXBWE.js +0 -12
  49. package/dist/prd-WYW35SGL.js +0 -12
  50. package/dist/review-YI2WPNC4.js +0 -12
  51. package/dist/run-J62FIB5O.js.map +0 -1
  52. /package/dist/{analyze-YYQQP64A.js.map → analyze-YSKLI2YL.js.map} +0 -0
  53. /package/dist/{chunk-JEUHCE3V.js.map → chunk-7A6NLYQE.js.map} +0 -0
  54. /package/dist/{execute-UF3IY2MG.js.map → execute-H3COM62D.js.map} +0 -0
  55. /package/dist/{init-QES2HLP5.js.map → init-AA453TQF.js.map} +0 -0
  56. /package/dist/{plan-BKSUDN34.js.map → plan-GGF7FMOV.js.map} +0 -0
  57. /package/dist/{pr-E2ASXBWE.js.map → pr-OF25YHPZ.js.map} +0 -0
  58. /package/dist/{prd-WYW35SGL.js.map → prd-MEYPY6XI.js.map} +0 -0
  59. /package/dist/{review-YI2WPNC4.js.map → review-7DQIPFTD.js.map} +0 -0
@@ -16,6 +16,7 @@ import {
16
16
  loadPrompt
17
17
  } from "./chunk-OZVHOVDT.js";
18
18
  import {
19
+ formatDuration,
19
20
  getIcons,
20
21
  getTermWidth,
21
22
  printError,
@@ -23,7 +24,7 @@ import {
23
24
  printRetry,
24
25
  printSuccess,
25
26
  printWarning
26
- } from "./chunk-L7RIGFP6.js";
27
+ } from "./chunk-SB52G2M2.js";
27
28
 
28
29
  // src/config.ts
29
30
  import { platform } from "os";
@@ -186,6 +187,142 @@ function printIterationHeader(iteration, maxIter, stories) {
186
187
  console.log("");
187
188
  console.log(` ${printProgressBar(passed, total)}`);
188
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
+ `);
283
+ }
284
+ formatPhase(phase, icons, colored) {
285
+ let icon;
286
+ let colorFn;
287
+ let durationStr = "";
288
+ switch (phase.status) {
289
+ case "completed":
290
+ icon = icons.success;
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}`);
322
+ }
323
+ return colorFn(` ${icon} ${label}`);
324
+ }
325
+ };
189
326
 
190
327
  // src/ui/summary.ts
191
328
  import chalk2 from "chalk";
@@ -262,14 +399,6 @@ function printStartupHeader(config, plan) {
262
399
  `Retries: ${retryLabel}`
263
400
  ]);
264
401
  }
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
402
  function printSummaryBox(status, iterations, totalRetries, elapsedSeconds, plan, extraInfo) {
274
403
  const icons = getIcons();
275
404
  const storiesTotal = plan.userStories.length;
@@ -606,6 +735,7 @@ async function runExecute(positionalMaxIter, options) {
606
735
  }
607
736
 
608
737
  export {
738
+ PipelineTracker,
609
739
  runExecute
610
740
  };
611
- //# sourceMappingURL=chunk-V356G3JS.js.map
741
+ //# sourceMappingURL=chunk-KTJI7WMC.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';\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 * 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 console.log(`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 console.log(`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 console.log('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 console.log('');\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 // 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 console.log('');\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 type { UserStory } from '../types.js';\nimport { formatDuration, getIcons } from './logger.js';\n\n/**\n * Check if color output is enabled.\n */\nfunction useColor(): boolean {\n if (process.env.NO_COLOR === '1') return false;\n if (!process.stdout.isTTY) return false;\n return true;\n}\n\n/**\n * Check if unicode output is enabled.\n */\nfunction useUnicode(): boolean {\n if (process.env.NO_COLOR === '1') return false;\n if (!process.stdout.isTTY) return false;\n return true;\n}\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 */\nexport function printIterationHeader(\n iteration: number,\n maxIter: number | undefined,\n stories: UserStory[],\n): void {\n const icons = getIcons();\n const colored = useColor();\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 console.log('');\n if (colored) {\n console.log(chalk.blue(`\\u2501\\u2501\\u2501 ${icons.start} ${iterLabel} \\u2501\\u2501\\u2501`));\n } else {\n console.log(`--- ${icons.start} ${iterLabel} ---`);\n }\n console.log('');\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 console.log(colorFn(` ${icon} ${story.id}: ${story.title}`));\n }\n\n console.log('');\n console.log(` ${printProgressBar(passed, total)}`);\n}\n\n/* ── Pipeline progress tracker ────────────────────────────────────────── */\n\nexport interface PhaseInfo {\n name: string;\n label: string;\n status: 'pending' | 'running' | 'completed' | 'skipped' | 'failed';\n durationSeconds: number | null;\n}\n\nconst PHASE_LABELS: Record<string, string> = {\n analyze: 'Analyze',\n prd: 'PRD',\n plan: 'Plan',\n execute: 'Execute',\n review: 'Review',\n pr: 'PR',\n};\n\n/**\n * Tracks and renders pipeline phase progress with live elapsed time.\n */\nexport class PipelineTracker {\n private phases: PhaseInfo[];\n private overallStartTime: number;\n private currentPhaseStart: number | null = null;\n private intervalId: ReturnType<typeof setInterval> | null = null;\n private lastLineCount = 0;\n private isTTY: boolean;\n\n constructor(phaseNames: string[], startIndex: number) {\n this.overallStartTime = Date.now();\n this.isTTY = !!process.stderr.isTTY;\n\n this.phases = phaseNames.map((name, i) => ({\n name,\n label: PHASE_LABELS[name] ?? name.charAt(0).toUpperCase() + name.slice(1),\n status: i < startIndex ? 'skipped' : 'pending',\n durationSeconds: null,\n }));\n }\n\n startPhase(name: string): void {\n const phase = this.phases.find((p) => p.name === name);\n if (phase) {\n phase.status = 'running';\n this.currentPhaseStart = Date.now();\n }\n this.render();\n }\n\n completePhase(name: string): void {\n const phase = this.phases.find((p) => p.name === name);\n if (phase) {\n phase.status = 'completed';\n phase.durationSeconds = this.currentPhaseStart\n ? Math.floor((Date.now() - this.currentPhaseStart) / 1000)\n : 0;\n this.currentPhaseStart = null;\n }\n this.render();\n }\n\n failPhase(name: string): void {\n const phase = this.phases.find((p) => p.name === name);\n if (phase) {\n phase.status = 'failed';\n phase.durationSeconds = this.currentPhaseStart\n ? Math.floor((Date.now() - this.currentPhaseStart) / 1000)\n : 0;\n this.currentPhaseStart = null;\n }\n this.stopLiveUpdate();\n this.render();\n }\n\n getOverallElapsed(): number {\n return Math.floor((Date.now() - this.overallStartTime) / 1000);\n }\n\n startLiveUpdate(): void {\n if (!this.isTTY) return;\n this.intervalId = setInterval(() => {\n this.render();\n }, 1_000);\n if (this.intervalId && typeof this.intervalId === 'object' && 'unref' in this.intervalId) {\n this.intervalId.unref();\n }\n }\n\n stopLiveUpdate(): void {\n if (this.intervalId) {\n clearInterval(this.intervalId);\n this.intervalId = null;\n }\n }\n\n private render(): void {\n const icons = getIcons();\n const colored = useColor();\n const unicode = useUnicode();\n\n const overallElapsed = formatDuration(this.getOverallElapsed());\n const separator = unicode ? '\\u2500'.repeat(48) : '-'.repeat(48);\n\n const lines: string[] = [];\n\n // Header\n const title = 'Pipeline Progress';\n const timeLabel = `Total: ${overallElapsed}`;\n const headerPad = Math.max(0, 48 - title.length - timeLabel.length);\n const headerLine = ` ${title}${' '.repeat(headerPad)}${timeLabel}`;\n lines.push(colored ? chalk.blue(headerLine) : headerLine);\n lines.push(colored ? chalk.dim(` ${separator}`) : ` ${separator}`);\n\n // Phase lines\n for (const phase of this.phases) {\n lines.push(this.formatPhase(phase, icons, colored));\n }\n\n lines.push(''); // trailing blank line\n\n // Clear previous output if TTY\n if (this.isTTY && this.lastLineCount > 0) {\n process.stderr.write(`\\x1B[${this.lastLineCount}A\\x1B[0J`);\n }\n\n this.lastLineCount = lines.length;\n process.stderr.write(`${lines.join('\\n')}\\n`);\n }\n\n private formatPhase(\n phase: PhaseInfo,\n icons: ReturnType<typeof getIcons>,\n colored: boolean,\n ): string {\n let icon: string;\n let colorFn: (s: string) => string;\n let durationStr = '';\n\n switch (phase.status) {\n case 'completed':\n icon = icons.success;\n colorFn = colored ? chalk.green : (s: string) => s;\n durationStr = phase.durationSeconds != null ? formatDuration(phase.durationSeconds) : '';\n break;\n case 'running': {\n icon = icons.pending;\n colorFn = colored ? chalk.yellow : (s: string) => s;\n const runningElapsed = this.currentPhaseStart\n ? Math.floor((Date.now() - this.currentPhaseStart) / 1000)\n : 0;\n durationStr = formatDuration(runningElapsed);\n break;\n }\n case 'failed':\n icon = icons.fail;\n colorFn = colored ? chalk.red : (s: string) => s;\n durationStr = phase.durationSeconds != null ? formatDuration(phase.durationSeconds) : '';\n break;\n case 'skipped':\n icon = icons.success;\n colorFn = colored ? chalk.dim : (s: string) => s;\n durationStr = 'skipped';\n break;\n default:\n icon = icons.notReached;\n colorFn = colored ? chalk.gray : (s: string) => s;\n break;\n }\n\n const label = phase.label;\n if (durationStr) {\n const dotChar = colored ? chalk.dim('.') : '.';\n const maxDots = Math.max(1, 40 - label.length - durationStr.length);\n const dots = dotChar.repeat(maxDots);\n return colorFn(` ${icon} ${label} ${dots} ${durationStr}`);\n }\n return colorFn(` ${icon} ${label}`);\n }\n}\n","import chalk from 'chalk';\nimport type { EngineConfig, TaskPlan } from '../types.js';\nimport { formatDuration, getIcons, getTermWidth } from './logger.js';\n\n/**\n * Check if color/unicode output is enabled.\n */\nfunction 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\nfunction 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 * 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","useColor","useUnicode","chalk","execa","join","elapsed"]}
@@ -1,7 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runHeadless
4
- } from "./chunk-PINC2LST.js";
4
+ } from "./chunk-3M7FPMO7.js";
5
+ import {
6
+ getGlobalTimeout
7
+ } from "./chunk-KMZHFUOY.js";
5
8
  import {
6
9
  loadTaskPlan,
7
10
  saveTaskPlan
@@ -14,7 +17,7 @@ import {
14
17
  printError,
15
18
  printInfo,
16
19
  printSuccess
17
- } from "./chunk-L7RIGFP6.js";
20
+ } from "./chunk-SB52G2M2.js";
18
21
 
19
22
  // src/commands/analyze.ts
20
23
  import { mkdir, readFile, writeFile } from "fs/promises";
@@ -23,7 +26,6 @@ async function runAnalyze(issue) {
23
26
  const issueNumber = issue.replace(/^#/, "");
24
27
  const issueDir = join("issues", issueNumber);
25
28
  const analysisPath = join(issueDir, "analysis.md");
26
- printInfo(`Analyzing issue #${issueNumber}...`);
27
29
  await mkdir(issueDir, { recursive: true });
28
30
  const template = await loadPrompt("analyze");
29
31
  const prompt = applyPlaceholders(template, {
@@ -32,10 +34,11 @@ async function runAnalyze(issue) {
32
34
  });
33
35
  const result = await runHeadless({
34
36
  prompt,
35
- maxTurns: 15,
36
- timeout: 12e4,
37
+ maxTurns: 30,
38
+ timeout: getGlobalTimeout() ?? 3e5,
37
39
  outputFormat: "text",
38
- allowedTools: ["Bash", "Read", "Glob", "Grep", "Write"]
40
+ allowedTools: ["Bash", "Read", "Glob", "Grep", "Write"],
41
+ statusMessage: `Analyzing issue #${issueNumber}...`
39
42
  });
40
43
  if (!result.success) {
41
44
  printError(`Analysis failed: ${result.error}`);
@@ -65,4 +68,4 @@ async function runAnalyze(issue) {
65
68
  export {
66
69
  runAnalyze
67
70
  };
68
- //# sourceMappingURL=chunk-7APADNBV.js.map
71
+ //# sourceMappingURL=chunk-R7HJYTQU.js.map
@@ -0,0 +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":";;;;;;;;;;;;;;;;;;;;;;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":[]}
@@ -2,6 +2,7 @@
2
2
 
3
3
  // src/ui/logger.ts
4
4
  import chalk from "chalk";
5
+ import ora from "ora";
5
6
  function useUnicode() {
6
7
  if (process.env.NO_COLOR != null && process.env.NO_COLOR !== "") return false;
7
8
  if (!process.stdout.isTTY) return false;
@@ -22,7 +23,9 @@ function getIcons() {
22
23
  warn: "\u26A0",
23
24
  start: "\u25B6",
24
25
  end: "\u25A0",
25
- notReached: "\u25CB"
26
+ notReached: "\u25CB",
27
+ tool: "\u25B8",
28
+ connector: "\u2502"
26
29
  };
27
30
  }
28
31
  return {
@@ -33,7 +36,9 @@ function getIcons() {
33
36
  warn: "[WARN]",
34
37
  start: "[START]",
35
38
  end: "[END]",
36
- notReached: "[ ]"
39
+ notReached: "[ ]",
40
+ tool: ">",
41
+ connector: "|"
37
42
  };
38
43
  }
39
44
  function getTermWidth() {
@@ -79,14 +84,69 @@ function printInfo(message) {
79
84
  console.log(`${icons.start} ${message}`);
80
85
  }
81
86
  }
87
+ function createSpinner(message) {
88
+ return ora({
89
+ text: message,
90
+ color: "blue",
91
+ spinner: "dots"
92
+ });
93
+ }
94
+ function formatDuration(totalSeconds) {
95
+ const hours = Math.floor(totalSeconds / 3600);
96
+ const mins = Math.floor(totalSeconds % 3600 / 60);
97
+ const secs = totalSeconds % 60;
98
+ if (hours > 0) {
99
+ return `${hours}h ${mins}m ${secs}s`;
100
+ }
101
+ if (mins > 0) {
102
+ return `${mins}m ${secs}s`;
103
+ }
104
+ return `${secs}s`;
105
+ }
106
+ var ElapsedTimer = class {
107
+ constructor(onTick) {
108
+ this.onTick = onTick;
109
+ this.startTime = Date.now();
110
+ }
111
+ startTime;
112
+ intervalId = null;
113
+ cleanup = () => this.stop();
114
+ start() {
115
+ this.startTime = Date.now();
116
+ this.intervalId = setInterval(() => {
117
+ const seconds = Math.floor((Date.now() - this.startTime) / 1e3);
118
+ this.onTick(formatDuration(seconds));
119
+ }, 1e3);
120
+ if (this.intervalId && typeof this.intervalId === "object" && "unref" in this.intervalId) {
121
+ this.intervalId.unref();
122
+ }
123
+ process.on("exit", this.cleanup);
124
+ return this;
125
+ }
126
+ getElapsedSeconds() {
127
+ return Math.floor((Date.now() - this.startTime) / 1e3);
128
+ }
129
+ stop() {
130
+ if (this.intervalId) {
131
+ clearInterval(this.intervalId);
132
+ this.intervalId = null;
133
+ }
134
+ process.removeListener("exit", this.cleanup);
135
+ return this.getElapsedSeconds();
136
+ }
137
+ };
82
138
 
83
139
  export {
140
+ useColor,
84
141
  getIcons,
85
142
  getTermWidth,
86
143
  printSuccess,
87
144
  printError,
88
145
  printWarning,
89
146
  printRetry,
90
- printInfo
147
+ printInfo,
148
+ createSpinner,
149
+ formatDuration,
150
+ ElapsedTimer
91
151
  };
92
- //# sourceMappingURL=chunk-L7RIGFP6.js.map
152
+ //# sourceMappingURL=chunk-SB52G2M2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ui/logger.ts"],"sourcesContent":["import chalk from 'chalk';\nimport ora, { type Ora } from 'ora';\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\nexport function printSuccess(message: string): void {\n const icons = getIcons();\n if (useColor()) {\n console.log(chalk.green(`${icons.success} ${message}`));\n } else {\n console.log(`${icons.success} ${message}`);\n }\n}\n\nexport function printError(message: string): void {\n const icons = getIcons();\n if (useColor()) {\n console.log(chalk.red(`${icons.fail} ${message}`));\n } else {\n console.log(`${icons.fail} ${message}`);\n }\n}\n\nexport function printWarning(message: string): void {\n const icons = getIcons();\n if (useColor()) {\n console.log(chalk.yellow(`${icons.warn} ${message}`));\n } else {\n console.log(`${icons.warn} ${message}`);\n }\n}\n\nexport function printRetry(message: string): void {\n const icons = getIcons();\n if (useColor()) {\n console.log(chalk.yellow(`${icons.retry} ${message}`));\n } else {\n console.log(`${icons.retry} ${message}`);\n }\n}\n\nexport function printInfo(message: string): void {\n const icons = getIcons();\n if (useColor()) {\n console.log(chalk.blue(`${icons.start} ${message}`));\n } else {\n console.log(`${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":[]}
@@ -1,7 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runHeadless
4
- } from "./chunk-PINC2LST.js";
4
+ } from "./chunk-3M7FPMO7.js";
5
+ import {
6
+ getGlobalTimeout
7
+ } from "./chunk-KMZHFUOY.js";
5
8
  import {
6
9
  loadTaskPlan,
7
10
  saveTaskPlan
@@ -12,9 +15,8 @@ import {
12
15
  } from "./chunk-OZVHOVDT.js";
13
16
  import {
14
17
  printError,
15
- printInfo,
16
18
  printSuccess
17
- } from "./chunk-L7RIGFP6.js";
19
+ } from "./chunk-SB52G2M2.js";
18
20
 
19
21
  // src/commands/pr.ts
20
22
  import { join } from "path";
@@ -27,7 +29,6 @@ async function runPr(issue) {
27
29
  const issueNumber = issue.replace(/^#/, "");
28
30
  const issueDir = join("issues", issueNumber);
29
31
  const tasksPath = join(issueDir, "tasks.json");
30
- printInfo(`Creating PR for issue #${issueNumber}...`);
31
32
  let branchName;
32
33
  try {
33
34
  const proc = await execa("git", ["branch", "--show-current"], { reject: false });
@@ -49,9 +50,10 @@ async function runPr(issue) {
49
50
  const result = await runHeadless({
50
51
  prompt,
51
52
  maxTurns: 15,
52
- timeout: 12e4,
53
+ timeout: getGlobalTimeout() ?? 3e5,
53
54
  outputFormat: "text",
54
- allowedTools: ["Bash", "Read", "Glob", "Grep"]
55
+ allowedTools: ["Bash", "Read", "Glob", "Grep"],
56
+ statusMessage: `Creating PR for issue #${issueNumber}...`
55
57
  });
56
58
  if (!result.success) {
57
59
  printError(`PR creation failed: ${result.error}`);
@@ -75,4 +77,4 @@ async function runPr(issue) {
75
77
  export {
76
78
  runPr
77
79
  };
78
- //# sourceMappingURL=chunk-7FRXZ2XA.js.map
80
+ //# sourceMappingURL=chunk-ZR5KSQWZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/pr.ts"],"sourcesContent":["import { join } from 'node:path';\nimport { execa } from 'execa';\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, printSuccess } from '../ui/logger.js';\n\n/**\n * Extract a PR URL from headless output.\n */\nfunction parsePrUrl(output: string): string | null {\n const match = output.match(/(https:\\/\\/github\\.com\\/[^\\s]+\\/pull\\/\\d+)/);\n return match?.[1] ?? null;\n}\n\nexport async function runPr(issue: string): Promise<number> {\n const issueNumber = issue.replace(/^#/, '');\n const issueDir = join('issues', issueNumber);\n const tasksPath = join(issueDir, 'tasks.json');\n\n // Get current branch\n let branchName: string;\n try {\n const proc = await execa('git', ['branch', '--show-current'], { reject: false });\n branchName = proc.stdout?.toString().trim() ?? '';\n if (!branchName) {\n printError('Could not determine current branch');\n return 1;\n }\n } catch {\n printError('Failed to get current branch');\n return 1;\n }\n\n const template = await loadPrompt('pr');\n const prompt = applyPlaceholders(template, {\n __ISSUE_NUMBER__: issueNumber,\n __BRANCH_NAME__: branchName,\n __TASKS_PATH__: tasksPath,\n });\n\n const result = await runHeadless({\n prompt,\n maxTurns: 15,\n timeout: getGlobalTimeout() ?? 300_000,\n outputFormat: 'text',\n allowedTools: ['Bash', 'Read', 'Glob', 'Grep'],\n statusMessage: `Creating PR for issue #${issueNumber}...`,\n });\n\n if (!result.success) {\n printError(`PR creation failed: ${result.error}`);\n return 1;\n }\n\n const prUrl = parsePrUrl(result.result);\n\n // Update pipeline state\n try {\n const plan = await loadTaskPlan(tasksPath);\n plan.pipeline.prCreated = true;\n await saveTaskPlan(tasksPath, plan);\n } catch {\n // tasks.json may not exist\n }\n\n if (prUrl) {\n printSuccess(`PR created: ${prUrl}`);\n } else {\n printSuccess('PR creation completed');\n }\n return 0;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,YAAY;AACrB,SAAS,aAAa;AAUtB,SAAS,WAAW,QAA+B;AACjD,QAAM,QAAQ,OAAO,MAAM,4CAA4C;AACvE,SAAO,QAAQ,CAAC,KAAK;AACvB;AAEA,eAAsB,MAAM,OAAgC;AAC1D,QAAM,cAAc,MAAM,QAAQ,MAAM,EAAE;AAC1C,QAAM,WAAW,KAAK,UAAU,WAAW;AAC3C,QAAM,YAAY,KAAK,UAAU,YAAY;AAG7C,MAAI;AACJ,MAAI;AACF,UAAM,OAAO,MAAM,MAAM,OAAO,CAAC,UAAU,gBAAgB,GAAG,EAAE,QAAQ,MAAM,CAAC;AAC/E,iBAAa,KAAK,QAAQ,SAAS,EAAE,KAAK,KAAK;AAC/C,QAAI,CAAC,YAAY;AACf,iBAAW,oCAAoC;AAC/C,aAAO;AAAA,IACT;AAAA,EACF,QAAQ;AACN,eAAW,8BAA8B;AACzC,WAAO;AAAA,EACT;AAEA,QAAM,WAAW,MAAM,WAAW,IAAI;AACtC,QAAM,SAAS,kBAAkB,UAAU;AAAA,IACzC,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,IACjB,gBAAgB;AAAA,EAClB,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,MAAM;AAAA,IAC7C,eAAe,0BAA0B,WAAW;AAAA,EACtD,CAAC;AAED,MAAI,CAAC,OAAO,SAAS;AACnB,eAAW,uBAAuB,OAAO,KAAK,EAAE;AAChD,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,WAAW,OAAO,MAAM;AAGtC,MAAI;AACF,UAAM,OAAO,MAAM,aAAa,SAAS;AACzC,SAAK,SAAS,YAAY;AAC1B,UAAM,aAAa,WAAW,IAAI;AAAA,EACpC,QAAQ;AAAA,EAER;AAEA,MAAI,OAAO;AACT,iBAAa,eAAe,KAAK,EAAE;AAAA,EACrC,OAAO;AACL,iBAAa,uBAAuB;AAAA,EACtC;AACA,SAAO;AACT;","names":[]}