issue-flow 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/README.md +25 -0
  2. package/dist/analyze-3SN7ZAZU.js +12 -0
  3. package/dist/{chunk-G36DIQ4J.js → chunk-2JZCWJEQ.js} +8 -8
  4. package/dist/chunk-2JZCWJEQ.js.map +1 -0
  5. package/dist/chunk-4OQ2ARLP.js +275 -0
  6. package/dist/chunk-4OQ2ARLP.js.map +1 -0
  7. package/dist/{chunk-D4WBCVB4.js → chunk-4PZXIOXD.js} +8 -8
  8. package/dist/chunk-4PZXIOXD.js.map +1 -0
  9. package/dist/{chunk-JEUHCE3V.js → chunk-CSSXTPWE.js} +2 -2
  10. package/dist/{chunk-7FRXZ2XA.js → chunk-CYWHYPTU.js} +7 -7
  11. package/dist/chunk-CYWHYPTU.js.map +1 -0
  12. package/dist/{chunk-7APADNBV.js → chunk-MEB3B2FI.js} +8 -7
  13. package/dist/chunk-MEB3B2FI.js.map +1 -0
  14. package/dist/{chunk-ZOX7M2C2.js → chunk-MWUIIUAS.js} +8 -8
  15. package/dist/chunk-MWUIIUAS.js.map +1 -0
  16. package/dist/{chunk-V356G3JS.js → chunk-WM6AYRHQ.js} +44 -45
  17. package/dist/chunk-WM6AYRHQ.js.map +1 -0
  18. package/dist/chunk-YAFHVFV5.js +199 -0
  19. package/dist/chunk-YAFHVFV5.js.map +1 -0
  20. package/dist/cli.js +60 -24
  21. package/dist/cli.js.map +1 -1
  22. package/dist/{execute-UF3IY2MG.js → execute-6AAKNSLM.js} +3 -3
  23. package/dist/{generate-WMYJEPI4.js → generate-HP4CPMJG.js} +7 -7
  24. package/dist/generate-HP4CPMJG.js.map +1 -0
  25. package/dist/init-SXFGOCML.js +9 -0
  26. package/dist/plan-HWZRG5GP.js +12 -0
  27. package/dist/pr-TTOFYUCV.js +12 -0
  28. package/dist/prd-ET2QN7GB.js +12 -0
  29. package/dist/review-3QDZCOMT.js +12 -0
  30. package/dist/run-6CR5FDYH.js +451 -0
  31. package/dist/run-6CR5FDYH.js.map +1 -0
  32. package/package.json +3 -2
  33. package/dist/analyze-YYQQP64A.js +0 -12
  34. package/dist/chunk-7APADNBV.js.map +0 -1
  35. package/dist/chunk-7FRXZ2XA.js.map +0 -1
  36. package/dist/chunk-D4WBCVB4.js.map +0 -1
  37. package/dist/chunk-G36DIQ4J.js.map +0 -1
  38. package/dist/chunk-L7RIGFP6.js +0 -92
  39. package/dist/chunk-L7RIGFP6.js.map +0 -1
  40. package/dist/chunk-PINC2LST.js +0 -82
  41. package/dist/chunk-PINC2LST.js.map +0 -1
  42. package/dist/chunk-V356G3JS.js.map +0 -1
  43. package/dist/chunk-ZOX7M2C2.js.map +0 -1
  44. package/dist/generate-WMYJEPI4.js.map +0 -1
  45. package/dist/init-QES2HLP5.js +0 -9
  46. package/dist/plan-BKSUDN34.js +0 -12
  47. package/dist/pr-E2ASXBWE.js +0 -12
  48. package/dist/prd-WYW35SGL.js +0 -12
  49. package/dist/review-YI2WPNC4.js +0 -12
  50. package/dist/run-J62FIB5O.js +0 -288
  51. package/dist/run-J62FIB5O.js.map +0 -1
  52. /package/dist/{analyze-YYQQP64A.js.map → analyze-3SN7ZAZU.js.map} +0 -0
  53. /package/dist/{chunk-JEUHCE3V.js.map → chunk-CSSXTPWE.js.map} +0 -0
  54. /package/dist/{execute-UF3IY2MG.js.map → execute-6AAKNSLM.js.map} +0 -0
  55. /package/dist/{init-QES2HLP5.js.map → init-SXFGOCML.js.map} +0 -0
  56. /package/dist/{plan-BKSUDN34.js.map → plan-HWZRG5GP.js.map} +0 -0
  57. /package/dist/{pr-E2ASXBWE.js.map → pr-TTOFYUCV.js.map} +0 -0
  58. /package/dist/{prd-WYW35SGL.js.map → prd-ET2QN7GB.js.map} +0 -0
  59. /package/dist/{review-YI2WPNC4.js.map → review-3QDZCOMT.js.map} +0 -0
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["import { Command, InvalidArgumentError } from 'commander';\nimport { printError } from './ui/logger.js';\n\n/**\n * Parse a numeric string, throwing InvalidArgumentError if not a valid number.\n */\nfunction parseInteger(value: string): number {\n const parsed = parseInt(value, 10);\n if (Number.isNaN(parsed) || parsed < 0) {\n throw new InvalidArgumentError('Must be a non-negative integer.');\n }\n return parsed;\n}\n\nconst program = new Command();\n\nprogram\n .name('issue-flow')\n .description(\n 'Unified CLI for orchestrating the full issue-flow pipeline via Claude Code Headless.',\n )\n .version('0.3.0');\n\n// ── init ────────────────────────────────────────────────────────────────────\nprogram\n .command('init')\n .description('Verify that all prerequisites (claude, gh, git) are met')\n .action(async () => {\n const { runInit } = await import('./commands/init.js');\n const code = await runInit();\n process.exit(code);\n });\n\n// ── generate ────────────────────────────────────────────────────────────────\nprogram\n .command('generate')\n .description('Create a GitHub issue via Claude Code Headless')\n .requiredOption('--prompt <text>', 'Issue description text')\n .action(async (options: { prompt: string }) => {\n const { runGenerate } = await import('./commands/generate.js');\n const code = await runGenerate(options.prompt);\n process.exit(code);\n });\n\n// ── run ─────────────────────────────────────────────────────────────────────\nprogram\n .command('run')\n .description('Execute the full pipeline: analyze → prd → plan → execute → review → pr')\n .argument('<issue>', 'Issue number')\n .option('--mode <mode>', 'Execution mode: auto | manual', 'auto')\n .option('--from <phase>', 'Resume from a specific phase')\n .action(async (issue: string, options: { mode: string; from?: string }) => {\n const { runPipeline } = await import('./commands/run.js');\n const code = await runPipeline(issue, options.mode, options.from);\n process.exit(code);\n });\n\n// ── analyze ─────────────────────────────────────────────────────────────────\nprogram\n .command('analyze')\n .description('Analyze a GitHub issue via Claude Code Headless')\n .argument('<issue>', 'Issue number')\n .action(async (issue: string) => {\n const { runAnalyze } = await import('./commands/analyze.js');\n const code = await runAnalyze(issue);\n process.exit(code);\n });\n\n// ── prd ─────────────────────────────────────────────────────────────────────\nprogram\n .command('prd')\n .description('Generate a PRD from an analyzed issue via Claude Code Headless')\n .argument('<issue>', 'Issue number')\n .action(async (issue: string) => {\n const { runPrd } = await import('./commands/prd.js');\n const code = await runPrd(issue);\n process.exit(code);\n });\n\n// ── plan ────────────────────────────────────────────────────────────────────\nprogram\n .command('plan')\n .description('Convert a PRD to a tasks.json task plan via Claude Code Headless')\n .argument('<issue>', 'Issue number')\n .action(async (issue: string) => {\n const { runPlan } = await import('./commands/plan.js');\n const code = await runPlan(issue);\n process.exit(code);\n });\n\n// ── execute ─────────────────────────────────────────────────────────────────\nprogram\n .command('execute')\n .description('Run the iterative story execution loop (issue-flow engine)')\n .option('--issue <number>', 'Issue number — reads artifacts from issues/N/')\n .option('--max-iterations <number>', 'Stop after N iterations', parseInteger)\n .option(\n '--retry-limit <number>',\n 'Retry transient Claude failures up to N consecutive times',\n parseInteger,\n )\n .option('--retry-forever', 'Retry transient Claude failures indefinitely')\n .argument('[max-iterations]', 'Backward-compatible alias for --max-iterations N', parseInteger)\n .action(\n async (\n positionalMaxIter: number | undefined,\n options: {\n issue?: string;\n maxIterations?: number;\n retryLimit?: number;\n retryForever?: boolean;\n },\n ) => {\n try {\n const { runExecute } = await import('./commands/execute.js');\n const code = await runExecute(positionalMaxIter, options);\n process.exit(code);\n } catch (error) {\n printError(error instanceof Error ? error.message : String(error));\n process.exit(1);\n }\n },\n );\n\n// ── review ──────────────────────────────────────────────────────────────────\nprogram\n .command('review')\n .description('Validate an issue resolution via Claude Code Headless')\n .argument('<issue>', 'Issue number')\n .action(async (issue: string) => {\n const { runReview } = await import('./commands/review.js');\n const code = await runReview(issue);\n process.exit(code);\n });\n\n// ── pr ──────────────────────────────────────────────────────────────────────\nprogram\n .command('pr')\n .description('Create a pull request via Claude Code Headless')\n .argument('<issue>', 'Issue number')\n .action(async (issue: string) => {\n const { runPr } = await import('./commands/pr.js');\n const code = await runPr(issue);\n process.exit(code);\n });\n\nprogram.parse();\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["import { Command, InvalidArgumentError } from 'commander';\nimport { setGlobalTimeout, setVerbose } from './core/verbose.js';\nimport { printError } from './ui/logger.js';\n\n/**\n * Parse a numeric string, throwing InvalidArgumentError if not a valid number.\n */\nfunction parseInteger(value: string): number {\n const parsed = parseInt(value, 10);\n if (Number.isNaN(parsed) || parsed < 0) {\n throw new InvalidArgumentError('Must be a non-negative integer.');\n }\n return parsed;\n}\n\n/**\n * Add shared options (--verbose) to a subcommand.\n */\nfunction withGlobalOptions(cmd: Command): Command {\n return cmd\n .option('-v, --verbose', 'Show Claude progress output in real time')\n .option(\n '-t, --timeout <seconds>',\n 'Override headless timeout in seconds (0 = no limit)',\n parseInteger,\n );\n}\n\nconst program = new Command();\n\nprogram\n .name('issue-flow')\n .description(\n 'Unified CLI for orchestrating the full issue-flow pipeline via Claude Code Headless.',\n )\n .version('0.3.0');\n\nprogram.hook('preAction', (_thisCommand, actionCommand) => {\n const opts = actionCommand.opts();\n if (opts.verbose) {\n setVerbose(true);\n }\n if (opts.timeout !== undefined) {\n setGlobalTimeout(opts.timeout * 1000);\n }\n});\n\n// ── init ────────────────────────────────────────────────────────────────────\nwithGlobalOptions(\n program.command('init').description('Verify that all prerequisites (claude, gh, git) are met'),\n).action(async () => {\n const { runInit } = await import('./commands/init.js');\n const code = await runInit();\n process.exit(code);\n});\n\n// ── generate ────────────────────────────────────────────────────────────────\nwithGlobalOptions(\n program\n .command('generate')\n .description('Create a GitHub issue via Claude Code Headless')\n .requiredOption('--prompt <text>', 'Issue description text'),\n).action(async (options: { prompt: string }) => {\n const { runGenerate } = await import('./commands/generate.js');\n const code = await runGenerate(options.prompt);\n process.exit(code);\n});\n\n// ── run ─────────────────────────────────────────────────────────────────────\nwithGlobalOptions(\n program\n .command('run')\n .description('Execute the full pipeline: analyze → prd → plan → execute → review → pr')\n .argument('<issue>', 'Issue number')\n .option('--mode <mode>', 'Execution mode: auto | manual', 'auto')\n .option('--from <phase>', 'Resume from a specific phase'),\n).action(async (issue: string, options: { mode: string; from?: string }) => {\n const { runPipeline } = await import('./commands/run.js');\n const code = await runPipeline(issue, options.mode, options.from);\n process.exit(code);\n});\n\n// ── analyze ─────────────────────────────────────────────────────────────────\nwithGlobalOptions(\n program\n .command('analyze')\n .description('Analyze a GitHub issue via Claude Code Headless')\n .argument('<issue>', 'Issue number'),\n).action(async (issue: string) => {\n const { runAnalyze } = await import('./commands/analyze.js');\n const code = await runAnalyze(issue);\n process.exit(code);\n});\n\n// ── prd ─────────────────────────────────────────────────────────────────────\nwithGlobalOptions(\n program\n .command('prd')\n .description('Generate a PRD from an analyzed issue via Claude Code Headless')\n .argument('<issue>', 'Issue number'),\n).action(async (issue: string) => {\n const { runPrd } = await import('./commands/prd.js');\n const code = await runPrd(issue);\n process.exit(code);\n});\n\n// ── plan ────────────────────────────────────────────────────────────────────\nwithGlobalOptions(\n program\n .command('plan')\n .description('Convert a PRD to a tasks.json task plan via Claude Code Headless')\n .argument('<issue>', 'Issue number'),\n).action(async (issue: string) => {\n const { runPlan } = await import('./commands/plan.js');\n const code = await runPlan(issue);\n process.exit(code);\n});\n\n// ── execute ─────────────────────────────────────────────────────────────────\nwithGlobalOptions(\n program\n .command('execute')\n .description('Run the iterative story execution loop (issue-flow engine)')\n .option('--issue <number>', 'Issue number — reads artifacts from issues/N/')\n .option('--max-iterations <number>', 'Stop after N iterations', parseInteger)\n .option(\n '--retry-limit <number>',\n 'Retry transient Claude failures up to N consecutive times',\n parseInteger,\n )\n .option('--retry-forever', 'Retry transient Claude failures indefinitely')\n .argument('[max-iterations]', 'Backward-compatible alias for --max-iterations N', parseInteger),\n).action(\n async (\n positionalMaxIter: number | undefined,\n options: {\n issue?: string;\n maxIterations?: number;\n retryLimit?: number;\n retryForever?: boolean;\n },\n ) => {\n try {\n const { runExecute } = await import('./commands/execute.js');\n const code = await runExecute(positionalMaxIter, options);\n process.exit(code);\n } catch (error) {\n printError(error instanceof Error ? error.message : String(error));\n process.exit(1);\n }\n },\n);\n\n// ── review ──────────────────────────────────────────────────────────────────\nwithGlobalOptions(\n program\n .command('review')\n .description('Validate an issue resolution via Claude Code Headless')\n .argument('<issue>', 'Issue number'),\n).action(async (issue: string) => {\n const { runReview } = await import('./commands/review.js');\n const code = await runReview(issue);\n process.exit(code);\n});\n\n// ── pr ──────────────────────────────────────────────────────────────────────\nwithGlobalOptions(\n program\n .command('pr')\n .description('Create a pull request via Claude Code Headless')\n .argument('<issue>', 'Issue number'),\n).action(async (issue: string) => {\n const { runPr } = await import('./commands/pr.js');\n const code = await runPr(issue);\n process.exit(code);\n});\n\nprogram.parse();\n"],"mappings":"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","names":[]}
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runExecute
4
- } from "./chunk-V356G3JS.js";
4
+ } from "./chunk-WM6AYRHQ.js";
5
5
  import "./chunk-64FU2L2T.js";
6
6
  import "./chunk-OZVHOVDT.js";
7
- import "./chunk-L7RIGFP6.js";
7
+ import "./chunk-YAFHVFV5.js";
8
8
  export {
9
9
  runExecute
10
10
  };
11
- //# sourceMappingURL=execute-UF3IY2MG.js.map
11
+ //# sourceMappingURL=execute-6AAKNSLM.js.map
@@ -1,16 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runHeadless
4
- } from "./chunk-PINC2LST.js";
4
+ } from "./chunk-4OQ2ARLP.js";
5
5
  import {
6
6
  applyPlaceholders,
7
7
  loadPrompt
8
8
  } from "./chunk-OZVHOVDT.js";
9
9
  import {
10
+ getGlobalTimeout,
10
11
  printError,
11
- printInfo,
12
12
  printSuccess
13
- } from "./chunk-L7RIGFP6.js";
13
+ } from "./chunk-YAFHVFV5.js";
14
14
 
15
15
  // src/commands/generate.ts
16
16
  function parseIssueUrl(output) {
@@ -18,7 +18,6 @@ function parseIssueUrl(output) {
18
18
  return match?.[1] ?? null;
19
19
  }
20
20
  async function runGenerate(promptText) {
21
- printInfo("Creating GitHub issue...");
22
21
  const template = await loadPrompt("generate");
23
22
  const prompt = applyPlaceholders(template, {
24
23
  __USER_PROMPT__: promptText
@@ -26,9 +25,10 @@ async function runGenerate(promptText) {
26
25
  const result = await runHeadless({
27
26
  prompt,
28
27
  maxTurns: 15,
29
- timeout: 12e4,
28
+ timeout: getGlobalTimeout() ?? 3e5,
30
29
  outputFormat: "text",
31
- allowedTools: ["Bash", "Read", "Glob", "Grep"]
30
+ allowedTools: ["Bash", "Read", "Glob", "Grep"],
31
+ statusMessage: "Creating GitHub issue..."
32
32
  });
33
33
  if (!result.success) {
34
34
  printError(`Issue creation failed: ${result.error}`);
@@ -45,4 +45,4 @@ async function runGenerate(promptText) {
45
45
  export {
46
46
  runGenerate
47
47
  };
48
- //# sourceMappingURL=generate-WMYJEPI4.js.map
48
+ //# sourceMappingURL=generate-HP4CPMJG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/generate.ts"],"sourcesContent":["import { runHeadless } from '../core/headless.js';\nimport { applyPlaceholders, loadPrompt } from '../core/prompt-resolver.js';\nimport { getGlobalTimeout } from '../core/verbose.js';\nimport { printError, printSuccess } from '../ui/logger.js';\n\n/**\n * Extract an issue URL from headless output.\n */\nfunction parseIssueUrl(output: string): string | null {\n const match = output.match(/(https:\\/\\/github\\.com\\/[^\\s]+\\/issues\\/\\d+)/);\n return match?.[1] ?? null;\n}\n\nexport async function runGenerate(promptText: string): Promise<number> {\n const template = await loadPrompt('generate');\n const prompt = applyPlaceholders(template, {\n __USER_PROMPT__: promptText,\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 GitHub issue...',\n });\n\n if (!result.success) {\n printError(`Issue creation failed: ${result.error}`);\n return 1;\n }\n\n const issueUrl = parseIssueUrl(result.result);\n\n if (issueUrl) {\n printSuccess(`Issue created: ${issueUrl}`);\n } else {\n printSuccess('Issue creation completed');\n }\n return 0;\n}\n"],"mappings":";;;;;;;;;;;;;;;AAQA,SAAS,cAAc,QAA+B;AACpD,QAAM,QAAQ,OAAO,MAAM,8CAA8C;AACzE,SAAO,QAAQ,CAAC,KAAK;AACvB;AAEA,eAAsB,YAAY,YAAqC;AACrE,QAAM,WAAW,MAAM,WAAW,UAAU;AAC5C,QAAM,SAAS,kBAAkB,UAAU;AAAA,IACzC,iBAAiB;AAAA,EACnB,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;AAAA,EACjB,CAAC;AAED,MAAI,CAAC,OAAO,SAAS;AACnB,eAAW,0BAA0B,OAAO,KAAK,EAAE;AACnD,WAAO;AAAA,EACT;AAEA,QAAM,WAAW,cAAc,OAAO,MAAM;AAE5C,MAAI,UAAU;AACZ,iBAAa,kBAAkB,QAAQ,EAAE;AAAA,EAC3C,OAAO;AACL,iBAAa,0BAA0B;AAAA,EACzC;AACA,SAAO;AACT;","names":[]}
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ runInit
4
+ } from "./chunk-CSSXTPWE.js";
5
+ import "./chunk-YAFHVFV5.js";
6
+ export {
7
+ runInit
8
+ };
9
+ //# sourceMappingURL=init-SXFGOCML.js.map
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ runPlan
4
+ } from "./chunk-MWUIIUAS.js";
5
+ import "./chunk-4OQ2ARLP.js";
6
+ import "./chunk-64FU2L2T.js";
7
+ import "./chunk-OZVHOVDT.js";
8
+ import "./chunk-YAFHVFV5.js";
9
+ export {
10
+ runPlan
11
+ };
12
+ //# sourceMappingURL=plan-HWZRG5GP.js.map
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ runPr
4
+ } from "./chunk-CYWHYPTU.js";
5
+ import "./chunk-4OQ2ARLP.js";
6
+ import "./chunk-64FU2L2T.js";
7
+ import "./chunk-OZVHOVDT.js";
8
+ import "./chunk-YAFHVFV5.js";
9
+ export {
10
+ runPr
11
+ };
12
+ //# sourceMappingURL=pr-TTOFYUCV.js.map
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ runPrd
4
+ } from "./chunk-2JZCWJEQ.js";
5
+ import "./chunk-4OQ2ARLP.js";
6
+ import "./chunk-64FU2L2T.js";
7
+ import "./chunk-OZVHOVDT.js";
8
+ import "./chunk-YAFHVFV5.js";
9
+ export {
10
+ runPrd
11
+ };
12
+ //# sourceMappingURL=prd-ET2QN7GB.js.map
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ runReview
4
+ } from "./chunk-4PZXIOXD.js";
5
+ import "./chunk-4OQ2ARLP.js";
6
+ import "./chunk-64FU2L2T.js";
7
+ import "./chunk-OZVHOVDT.js";
8
+ import "./chunk-YAFHVFV5.js";
9
+ export {
10
+ runReview
11
+ };
12
+ //# sourceMappingURL=review-3QDZCOMT.js.map
@@ -0,0 +1,451 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ runReview
4
+ } from "./chunk-4PZXIOXD.js";
5
+ import {
6
+ runInit
7
+ } from "./chunk-CSSXTPWE.js";
8
+ import {
9
+ runAnalyze
10
+ } from "./chunk-MEB3B2FI.js";
11
+ import {
12
+ runExecute
13
+ } from "./chunk-WM6AYRHQ.js";
14
+ import {
15
+ runPlan
16
+ } from "./chunk-MWUIIUAS.js";
17
+ import {
18
+ runPr
19
+ } from "./chunk-CYWHYPTU.js";
20
+ import {
21
+ runPrd
22
+ } from "./chunk-2JZCWJEQ.js";
23
+ import "./chunk-4OQ2ARLP.js";
24
+ import {
25
+ isoNow,
26
+ loadTaskPlan,
27
+ saveTaskPlan
28
+ } from "./chunk-64FU2L2T.js";
29
+ import "./chunk-OZVHOVDT.js";
30
+ import {
31
+ formatDuration,
32
+ isVerbose,
33
+ printError,
34
+ printInfo,
35
+ printSuccess,
36
+ printWarning,
37
+ setOutputCallback,
38
+ setStoryUpdateCallback
39
+ } from "./chunk-YAFHVFV5.js";
40
+
41
+ // src/commands/run.ts
42
+ import { join } from "path";
43
+ import { execa } from "execa";
44
+
45
+ // src/core/pipeline.ts
46
+ var PIPELINE_PHASES = [
47
+ "init",
48
+ "analyze",
49
+ "prd",
50
+ "plan",
51
+ "execute",
52
+ "review",
53
+ "pr"
54
+ ];
55
+ var PHASE_TO_FIELD = {
56
+ init: null,
57
+ analyze: "analyzeCompleted",
58
+ prd: "prdCompleted",
59
+ plan: "jsonCompleted",
60
+ execute: "executionCompleted",
61
+ review: "reviewCompleted",
62
+ pr: "prCreated"
63
+ };
64
+ var PipelineManager = class {
65
+ tasksJsonPath;
66
+ plan;
67
+ constructor(plan, tasksJsonPath) {
68
+ this.plan = plan;
69
+ this.tasksJsonPath = tasksJsonPath;
70
+ }
71
+ /**
72
+ * Reload state from disk.
73
+ */
74
+ async reload() {
75
+ this.plan = await loadTaskPlan(this.tasksJsonPath);
76
+ }
77
+ /**
78
+ * Check if a phase is complete.
79
+ */
80
+ isPhaseComplete(phase) {
81
+ const field = PHASE_TO_FIELD[phase];
82
+ if (field === null) return true;
83
+ return this.plan.pipeline?.[field] ?? false;
84
+ }
85
+ /**
86
+ * Get the first incomplete phase in the pipeline.
87
+ * Returns null if all phases are complete.
88
+ */
89
+ getNextPhase() {
90
+ for (const phase of PIPELINE_PHASES) {
91
+ if (!this.isPhaseComplete(phase)) {
92
+ return phase;
93
+ }
94
+ }
95
+ return null;
96
+ }
97
+ /**
98
+ * Get the current phase (alias for getNextPhase).
99
+ */
100
+ getCurrentPhase() {
101
+ return this.getNextPhase();
102
+ }
103
+ /**
104
+ * Check whether we can resume from a specific phase.
105
+ * All prerequisite phases must be complete.
106
+ */
107
+ canResume(fromPhase) {
108
+ const idx = PIPELINE_PHASES.indexOf(fromPhase);
109
+ if (idx < 0) return false;
110
+ for (let i = 0; i < idx; i++) {
111
+ if (!this.isPhaseComplete(PIPELINE_PHASES[i])) {
112
+ return false;
113
+ }
114
+ }
115
+ return true;
116
+ }
117
+ /**
118
+ * Mark a phase as complete and persist to disk.
119
+ */
120
+ async markPhaseComplete(phase) {
121
+ const field = PHASE_TO_FIELD[phase];
122
+ if (field === null) return;
123
+ this.plan = {
124
+ ...this.plan,
125
+ pipeline: {
126
+ ...this.plan.pipeline ?? {
127
+ analyzeCompleted: false,
128
+ prdCompleted: false,
129
+ jsonCompleted: false,
130
+ executionCompleted: false,
131
+ reviewCompleted: false,
132
+ prCreated: false
133
+ },
134
+ [field]: true
135
+ }
136
+ };
137
+ await saveTaskPlan(this.tasksJsonPath, this.plan);
138
+ }
139
+ };
140
+
141
+ // src/ui/pipeline-renderer.ts
142
+ import { Listr, PRESET_TIMER, PRESET_TIMESTAMP } from "listr2";
143
+ var PHASE_LABELS = {
144
+ analyze: "Analyze",
145
+ prd: "PRD",
146
+ plan: "Plan",
147
+ execute: "Execute",
148
+ review: "Review",
149
+ pr: "PR"
150
+ };
151
+ function selectRenderer(verbose) {
152
+ const isTTY = !!process.stdout.isTTY;
153
+ const isCI = !!process.env.CI;
154
+ if (!isTTY || isCI) {
155
+ return "simple";
156
+ }
157
+ return verbose ? "verbose" : "default";
158
+ }
159
+ function buildExecutePhaseTask(runner, tasksPath, verbose) {
160
+ return async (_ctx, task) => {
161
+ let stories;
162
+ try {
163
+ const plan = await loadTaskPlan(tasksPath);
164
+ stories = [...plan.userStories].sort((a, b) => a.priority - b.priority);
165
+ } catch {
166
+ setOutputCallback((line) => {
167
+ task.output = line;
168
+ });
169
+ try {
170
+ await runner();
171
+ } finally {
172
+ setOutputCallback(void 0);
173
+ }
174
+ return;
175
+ }
176
+ const totalStories = stories.length;
177
+ const initialPassed = stories.filter((s) => s.passes).length;
178
+ task.title = `Execute (${initialPassed}/${totalStories} stories passing)`;
179
+ const resolvers = /* @__PURE__ */ new Map();
180
+ setStoryUpdateCallback((updatedStories) => {
181
+ const passed = updatedStories.filter((s) => s.passes).length;
182
+ task.title = `Execute (${passed}/${totalStories} stories passing)`;
183
+ for (const s of updatedStories) {
184
+ if (s.passes && resolvers.has(s.id)) {
185
+ resolvers.get(s.id).resolve();
186
+ resolvers.delete(s.id);
187
+ }
188
+ }
189
+ });
190
+ const subtaskDefs = stories.map((story) => ({
191
+ title: `${story.id}: ${story.title}`,
192
+ skip: story.passes ? "already passing" : false,
193
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
194
+ task: async () => {
195
+ await new Promise((resolve, reject) => {
196
+ resolvers.set(story.id, { resolve, reject });
197
+ });
198
+ },
199
+ rendererOptions: {
200
+ timer: PRESET_TIMER
201
+ }
202
+ }));
203
+ const engineSubtask = {
204
+ title: "Running engine",
205
+ task: async (_c, engineTask) => {
206
+ setOutputCallback((line) => {
207
+ engineTask.output = line;
208
+ });
209
+ try {
210
+ await runner();
211
+ } finally {
212
+ setOutputCallback(void 0);
213
+ setStoryUpdateCallback(void 0);
214
+ for (const [, { resolve }] of resolvers) {
215
+ resolve();
216
+ }
217
+ resolvers.clear();
218
+ }
219
+ },
220
+ rendererOptions: {
221
+ timer: PRESET_TIMER,
222
+ outputBar: verbose ? Infinity : false,
223
+ persistentOutput: false,
224
+ bottomBar: verbose ? Infinity : 5
225
+ }
226
+ };
227
+ return task.newListr([engineSubtask, ...subtaskDefs], {
228
+ concurrent: true,
229
+ exitOnError: false,
230
+ rendererOptions: {
231
+ timer: PRESET_TIMER,
232
+ collapseSkips: false
233
+ }
234
+ });
235
+ };
236
+ }
237
+ async function runPipelineWithRenderer(options) {
238
+ const { phases, startIndex, verbose, runners, tasksPath } = options;
239
+ const overallStart = Date.now();
240
+ let currentPhase;
241
+ const renderer = selectRenderer(verbose);
242
+ const isSimple = renderer === "simple";
243
+ const tasks = new Listr(
244
+ phases.map((phase, index) => {
245
+ const label = PHASE_LABELS[phase] ?? phase.charAt(0).toUpperCase() + phase.slice(1);
246
+ const isExecutePhase = phase === "execute" && tasksPath;
247
+ return {
248
+ title: label,
249
+ skip: index < startIndex ? "skipped" : false,
250
+ task: isExecutePhase ? async (_ctx, task) => {
251
+ currentPhase = phase;
252
+ const runner = runners[phase];
253
+ if (!runner) {
254
+ throw new Error(`No runner defined for phase: ${phase}`);
255
+ }
256
+ return buildExecutePhaseTask(runner, tasksPath, verbose)(_ctx, task);
257
+ } : async (_ctx, task) => {
258
+ currentPhase = phase;
259
+ const runner = runners[phase];
260
+ if (!runner) {
261
+ throw new Error(`No runner defined for phase: ${phase}`);
262
+ }
263
+ setOutputCallback((line) => {
264
+ task.output = line;
265
+ });
266
+ try {
267
+ await runner();
268
+ } finally {
269
+ setOutputCallback(void 0);
270
+ }
271
+ },
272
+ rendererOptions: {
273
+ timer: PRESET_TIMER,
274
+ outputBar: verbose ? Infinity : false,
275
+ persistentOutput: false
276
+ }
277
+ };
278
+ }),
279
+ {
280
+ renderer,
281
+ rendererOptions: {
282
+ timer: PRESET_TIMER,
283
+ collapseSkips: false,
284
+ ...isSimple ? { timestamp: PRESET_TIMESTAMP } : {}
285
+ },
286
+ exitOnError: true
287
+ }
288
+ );
289
+ let failedPhase;
290
+ try {
291
+ await tasks.run();
292
+ } catch {
293
+ failedPhase = currentPhase ?? phases[startIndex];
294
+ } finally {
295
+ setOutputCallback(void 0);
296
+ setStoryUpdateCallback(void 0);
297
+ }
298
+ const overallElapsedSeconds = Math.floor((Date.now() - overallStart) / 1e3);
299
+ return {
300
+ success: !failedPhase,
301
+ failedPhase,
302
+ overallElapsedSeconds
303
+ };
304
+ }
305
+
306
+ // src/commands/run.ts
307
+ async function runPipeline(issue, mode, from) {
308
+ const issueNumber = issue.replace(/^#/, "");
309
+ const issueDir = join("issues", issueNumber);
310
+ const tasksPath = join(issueDir, "tasks.json");
311
+ printInfo(`Starting pipeline for issue #${issueNumber} (mode: ${mode})`);
312
+ printInfo("Running prerequisite checks...");
313
+ const initCode = await runInit();
314
+ if (initCode !== 0) {
315
+ printError("Prerequisites not met. Fix the issues above and try again.");
316
+ return 1;
317
+ }
318
+ let startPhase = "analyze";
319
+ if (from) {
320
+ if (!PIPELINE_PHASES.includes(from)) {
321
+ printError(`Invalid phase: ${from}. Valid phases: ${PIPELINE_PHASES.join(", ")}`);
322
+ return 1;
323
+ }
324
+ startPhase = from;
325
+ } else {
326
+ try {
327
+ const plan = await loadTaskPlan(tasksPath);
328
+ const mgr = new PipelineManager(plan, tasksPath);
329
+ const nextPhase = mgr.getNextPhase();
330
+ if (nextPhase && nextPhase !== "init") {
331
+ startPhase = nextPhase;
332
+ printInfo(`Resuming from phase: ${startPhase}`);
333
+ }
334
+ } catch {
335
+ }
336
+ }
337
+ if (from) {
338
+ try {
339
+ const plan = await loadTaskPlan(tasksPath);
340
+ const mgr = new PipelineManager(plan, tasksPath);
341
+ if (!mgr.canResume(startPhase)) {
342
+ printError(`Cannot resume from ${startPhase}: prerequisite phases not complete`);
343
+ return 1;
344
+ }
345
+ } catch {
346
+ if (startPhase !== "analyze") {
347
+ printError(`Cannot resume from ${startPhase}: no pipeline state found`);
348
+ return 1;
349
+ }
350
+ }
351
+ }
352
+ const phaseOrder = ["analyze", "prd", "plan", "execute", "review", "pr"];
353
+ const startIdx = phaseOrder.indexOf(startPhase);
354
+ const makeRunner = (fn, phase) => async () => {
355
+ const code = await fn();
356
+ if (code !== 0) {
357
+ throw new Error(`Phase ${phase} failed with exit code ${code}`);
358
+ }
359
+ };
360
+ const runners = {
361
+ analyze: makeRunner(() => runAnalyze(issueNumber), "analyze"),
362
+ prd: makeRunner(() => runPrd(issueNumber), "prd"),
363
+ plan: makeRunner(() => runPlan(issueNumber), "plan"),
364
+ execute: makeRunner(() => runExecute(void 0, { issue: issueNumber }), "execute"),
365
+ review: async () => {
366
+ let maxCycles = 3;
367
+ try {
368
+ const plan = await loadTaskPlan(tasksPath);
369
+ maxCycles = plan.maxCorrectionCycles;
370
+ } catch {
371
+ }
372
+ let code = await runReview(issueNumber);
373
+ let cycle = 0;
374
+ while (code !== 0 && cycle < maxCycles) {
375
+ cycle++;
376
+ printWarning(`Review failed. Starting correction cycle ${cycle}/${maxCycles}...`);
377
+ try {
378
+ const plan = await loadTaskPlan(tasksPath);
379
+ plan.correctionCycle = cycle;
380
+ await saveTaskPlan(tasksPath, plan);
381
+ } catch {
382
+ }
383
+ const execCode = await runExecute(void 0, { issue: issueNumber });
384
+ if (execCode !== 0) {
385
+ throw new Error("Correction execution failed");
386
+ }
387
+ code = await runReview(issueNumber);
388
+ }
389
+ if (code !== 0) {
390
+ throw new Error(`Review failed after ${maxCycles} correction cycles`);
391
+ }
392
+ },
393
+ pr: makeRunner(() => runPr(issueNumber), "pr")
394
+ };
395
+ const result = await runPipelineWithRenderer({
396
+ phases: phaseOrder,
397
+ startIndex: startIdx,
398
+ verbose: isVerbose(),
399
+ runners,
400
+ tasksPath
401
+ });
402
+ if (!result.success) {
403
+ printError(`Phase ${result.failedPhase} failed`);
404
+ return 1;
405
+ }
406
+ printInfo("Closing issue...");
407
+ try {
408
+ await execa("gh", ["issue", "close", issueNumber], { reject: false });
409
+ } catch {
410
+ printWarning("Failed to close issue automatically");
411
+ }
412
+ let prUrl = "unknown";
413
+ try {
414
+ const proc = await execa("gh", ["pr", "list", "--head", "", "--json", "url", "--limit", "1"], {
415
+ reject: false
416
+ });
417
+ const parsed = JSON.parse(proc.stdout?.toString() ?? "[]");
418
+ if (parsed[0]?.url) {
419
+ prUrl = parsed[0].url;
420
+ }
421
+ } catch {
422
+ }
423
+ let branchName = "unknown";
424
+ try {
425
+ const proc = await execa("git", ["branch", "--show-current"], { reject: false });
426
+ branchName = proc.stdout?.toString().trim() ?? "unknown";
427
+ } catch {
428
+ }
429
+ let storyCount = 0;
430
+ try {
431
+ const plan = await loadTaskPlan(tasksPath);
432
+ storyCount = plan.userStories.length;
433
+ plan.issueStatus = "completed";
434
+ plan.completedAt = isoNow();
435
+ plan.lastAttemptAt = isoNow();
436
+ await saveTaskPlan(tasksPath, plan);
437
+ } catch {
438
+ }
439
+ const totalDuration = formatDuration(result.overallElapsedSeconds);
440
+ console.log("");
441
+ printSuccess(`Pipeline complete for issue #${issueNumber}!`);
442
+ console.log(` Branch: ${branchName}`);
443
+ console.log(` Stories: ${storyCount}`);
444
+ console.log(` Duration: ${totalDuration}`);
445
+ console.log(` PR: ${prUrl}`);
446
+ return 0;
447
+ }
448
+ export {
449
+ runPipeline
450
+ };
451
+ //# sourceMappingURL=run-6CR5FDYH.js.map