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
package/dist/cli.js CHANGED
@@ -1,7 +1,11 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ setGlobalTimeout,
4
+ setVerbose
5
+ } from "./chunk-KMZHFUOY.js";
2
6
  import {
3
7
  printError
4
- } from "./chunk-L7RIGFP6.js";
8
+ } from "./chunk-SB52G2M2.js";
5
9
 
6
10
  // src/cli.ts
7
11
  import { Command, InvalidArgumentError } from "commander";
@@ -12,48 +16,78 @@ function parseInteger(value) {
12
16
  }
13
17
  return parsed;
14
18
  }
19
+ function withGlobalOptions(cmd) {
20
+ return cmd.option("-v, --verbose", "Show Claude progress output in real time").option(
21
+ "-t, --timeout <seconds>",
22
+ "Override headless timeout in seconds (0 = no limit)",
23
+ parseInteger
24
+ );
25
+ }
15
26
  var program = new Command();
16
27
  program.name("issue-flow").description(
17
28
  "Unified CLI for orchestrating the full issue-flow pipeline via Claude Code Headless."
18
- ).version("0.3.0");
19
- program.command("init").description("Verify that all prerequisites (claude, gh, git) are met").action(async () => {
20
- const { runInit } = await import("./init-QES2HLP5.js");
29
+ ).version("0.3.1");
30
+ program.hook("preAction", (_thisCommand, actionCommand) => {
31
+ const opts = actionCommand.opts();
32
+ if (opts.verbose) {
33
+ setVerbose(true);
34
+ }
35
+ if (opts.timeout !== void 0) {
36
+ setGlobalTimeout(opts.timeout * 1e3);
37
+ }
38
+ });
39
+ withGlobalOptions(
40
+ program.command("init").description("Verify that all prerequisites (claude, gh, git) are met")
41
+ ).action(async () => {
42
+ const { runInit } = await import("./init-AA453TQF.js");
21
43
  const code = await runInit();
22
44
  process.exit(code);
23
45
  });
24
- program.command("generate").description("Create a GitHub issue via Claude Code Headless").requiredOption("--prompt <text>", "Issue description text").action(async (options) => {
25
- const { runGenerate } = await import("./generate-WMYJEPI4.js");
46
+ withGlobalOptions(
47
+ program.command("generate").description("Create a GitHub issue via Claude Code Headless").requiredOption("--prompt <text>", "Issue description text")
48
+ ).action(async (options) => {
49
+ const { runGenerate } = await import("./generate-KRVWNLQU.js");
26
50
  const code = await runGenerate(options.prompt);
27
51
  process.exit(code);
28
52
  });
29
- program.command("run").description("Execute the full pipeline: analyze \u2192 prd \u2192 plan \u2192 execute \u2192 review \u2192 pr").argument("<issue>", "Issue number").option("--mode <mode>", "Execution mode: auto | manual", "auto").option("--from <phase>", "Resume from a specific phase").action(async (issue, options) => {
30
- const { runPipeline } = await import("./run-J62FIB5O.js");
53
+ withGlobalOptions(
54
+ program.command("run").description("Execute the full pipeline: analyze \u2192 prd \u2192 plan \u2192 execute \u2192 review \u2192 pr").argument("<issue>", "Issue number").option("--mode <mode>", "Execution mode: auto | manual", "auto").option("--from <phase>", "Resume from a specific phase")
55
+ ).action(async (issue, options) => {
56
+ const { runPipeline } = await import("./run-JZAL7XB2.js");
31
57
  const code = await runPipeline(issue, options.mode, options.from);
32
58
  process.exit(code);
33
59
  });
34
- program.command("analyze").description("Analyze a GitHub issue via Claude Code Headless").argument("<issue>", "Issue number").action(async (issue) => {
35
- const { runAnalyze } = await import("./analyze-YYQQP64A.js");
60
+ withGlobalOptions(
61
+ program.command("analyze").description("Analyze a GitHub issue via Claude Code Headless").argument("<issue>", "Issue number")
62
+ ).action(async (issue) => {
63
+ const { runAnalyze } = await import("./analyze-YSKLI2YL.js");
36
64
  const code = await runAnalyze(issue);
37
65
  process.exit(code);
38
66
  });
39
- program.command("prd").description("Generate a PRD from an analyzed issue via Claude Code Headless").argument("<issue>", "Issue number").action(async (issue) => {
40
- const { runPrd } = await import("./prd-WYW35SGL.js");
67
+ withGlobalOptions(
68
+ program.command("prd").description("Generate a PRD from an analyzed issue via Claude Code Headless").argument("<issue>", "Issue number")
69
+ ).action(async (issue) => {
70
+ const { runPrd } = await import("./prd-MEYPY6XI.js");
41
71
  const code = await runPrd(issue);
42
72
  process.exit(code);
43
73
  });
44
- program.command("plan").description("Convert a PRD to a tasks.json task plan via Claude Code Headless").argument("<issue>", "Issue number").action(async (issue) => {
45
- const { runPlan } = await import("./plan-BKSUDN34.js");
74
+ withGlobalOptions(
75
+ program.command("plan").description("Convert a PRD to a tasks.json task plan via Claude Code Headless").argument("<issue>", "Issue number")
76
+ ).action(async (issue) => {
77
+ const { runPlan } = await import("./plan-GGF7FMOV.js");
46
78
  const code = await runPlan(issue);
47
79
  process.exit(code);
48
80
  });
49
- program.command("execute").description("Run the iterative story execution loop (issue-flow engine)").option("--issue <number>", "Issue number \u2014 reads artifacts from issues/N/").option("--max-iterations <number>", "Stop after N iterations", parseInteger).option(
50
- "--retry-limit <number>",
51
- "Retry transient Claude failures up to N consecutive times",
52
- parseInteger
53
- ).option("--retry-forever", "Retry transient Claude failures indefinitely").argument("[max-iterations]", "Backward-compatible alias for --max-iterations N", parseInteger).action(
81
+ withGlobalOptions(
82
+ program.command("execute").description("Run the iterative story execution loop (issue-flow engine)").option("--issue <number>", "Issue number \u2014 reads artifacts from issues/N/").option("--max-iterations <number>", "Stop after N iterations", parseInteger).option(
83
+ "--retry-limit <number>",
84
+ "Retry transient Claude failures up to N consecutive times",
85
+ parseInteger
86
+ ).option("--retry-forever", "Retry transient Claude failures indefinitely").argument("[max-iterations]", "Backward-compatible alias for --max-iterations N", parseInteger)
87
+ ).action(
54
88
  async (positionalMaxIter, options) => {
55
89
  try {
56
- const { runExecute } = await import("./execute-UF3IY2MG.js");
90
+ const { runExecute } = await import("./execute-H3COM62D.js");
57
91
  const code = await runExecute(positionalMaxIter, options);
58
92
  process.exit(code);
59
93
  } catch (error) {
@@ -62,13 +96,17 @@ program.command("execute").description("Run the iterative story execution loop (
62
96
  }
63
97
  }
64
98
  );
65
- program.command("review").description("Validate an issue resolution via Claude Code Headless").argument("<issue>", "Issue number").action(async (issue) => {
66
- const { runReview } = await import("./review-YI2WPNC4.js");
99
+ withGlobalOptions(
100
+ program.command("review").description("Validate an issue resolution via Claude Code Headless").argument("<issue>", "Issue number")
101
+ ).action(async (issue) => {
102
+ const { runReview } = await import("./review-7DQIPFTD.js");
67
103
  const code = await runReview(issue);
68
104
  process.exit(code);
69
105
  });
70
- program.command("pr").description("Create a pull request via Claude Code Headless").argument("<issue>", "Issue number").action(async (issue) => {
71
- const { runPr } = await import("./pr-E2ASXBWE.js");
106
+ withGlobalOptions(
107
+ program.command("pr").description("Create a pull request via Claude Code Headless").argument("<issue>", "Issue number")
108
+ ).action(async (issue) => {
109
+ const { runPr } = await import("./pr-OF25YHPZ.js");
72
110
  const code = await runPr(issue);
73
111
  process.exit(code);
74
112
  });
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":";;;;;;AAAA,SAAS,SAAS,4BAA4B;AAM9C,SAAS,aAAa,OAAuB;AAC3C,QAAM,SAAS,SAAS,OAAO,EAAE;AACjC,MAAI,OAAO,MAAM,MAAM,KAAK,SAAS,GAAG;AACtC,UAAM,IAAI,qBAAqB,iCAAiC;AAAA,EAClE;AACA,SAAO;AACT;AAEA,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,YAAY,EACjB;AAAA,EACC;AACF,EACC,QAAQ,OAAO;AAGlB,QACG,QAAQ,MAAM,EACd,YAAY,yDAAyD,EACrE,OAAO,YAAY;AAClB,QAAM,EAAE,QAAQ,IAAI,MAAM,OAAO,oBAAoB;AACrD,QAAM,OAAO,MAAM,QAAQ;AAC3B,UAAQ,KAAK,IAAI;AACnB,CAAC;AAGH,QACG,QAAQ,UAAU,EAClB,YAAY,gDAAgD,EAC5D,eAAe,mBAAmB,wBAAwB,EAC1D,OAAO,OAAO,YAAgC;AAC7C,QAAM,EAAE,YAAY,IAAI,MAAM,OAAO,wBAAwB;AAC7D,QAAM,OAAO,MAAM,YAAY,QAAQ,MAAM;AAC7C,UAAQ,KAAK,IAAI;AACnB,CAAC;AAGH,QACG,QAAQ,KAAK,EACb,YAAY,kGAAyE,EACrF,SAAS,WAAW,cAAc,EAClC,OAAO,iBAAiB,iCAAiC,MAAM,EAC/D,OAAO,kBAAkB,8BAA8B,EACvD,OAAO,OAAO,OAAe,YAA6C;AACzE,QAAM,EAAE,YAAY,IAAI,MAAM,OAAO,mBAAmB;AACxD,QAAM,OAAO,MAAM,YAAY,OAAO,QAAQ,MAAM,QAAQ,IAAI;AAChE,UAAQ,KAAK,IAAI;AACnB,CAAC;AAGH,QACG,QAAQ,SAAS,EACjB,YAAY,iDAAiD,EAC7D,SAAS,WAAW,cAAc,EAClC,OAAO,OAAO,UAAkB;AAC/B,QAAM,EAAE,WAAW,IAAI,MAAM,OAAO,uBAAuB;AAC3D,QAAM,OAAO,MAAM,WAAW,KAAK;AACnC,UAAQ,KAAK,IAAI;AACnB,CAAC;AAGH,QACG,QAAQ,KAAK,EACb,YAAY,gEAAgE,EAC5E,SAAS,WAAW,cAAc,EAClC,OAAO,OAAO,UAAkB;AAC/B,QAAM,EAAE,OAAO,IAAI,MAAM,OAAO,mBAAmB;AACnD,QAAM,OAAO,MAAM,OAAO,KAAK;AAC/B,UAAQ,KAAK,IAAI;AACnB,CAAC;AAGH,QACG,QAAQ,MAAM,EACd,YAAY,kEAAkE,EAC9E,SAAS,WAAW,cAAc,EAClC,OAAO,OAAO,UAAkB;AAC/B,QAAM,EAAE,QAAQ,IAAI,MAAM,OAAO,oBAAoB;AACrD,QAAM,OAAO,MAAM,QAAQ,KAAK;AAChC,UAAQ,KAAK,IAAI;AACnB,CAAC;AAGH,QACG,QAAQ,SAAS,EACjB,YAAY,4DAA4D,EACxE,OAAO,oBAAoB,oDAA+C,EAC1E,OAAO,6BAA6B,2BAA2B,YAAY,EAC3E;AAAA,EACC;AAAA,EACA;AAAA,EACA;AACF,EACC,OAAO,mBAAmB,8CAA8C,EACxE,SAAS,oBAAoB,oDAAoD,YAAY,EAC7F;AAAA,EACC,OACE,mBACA,YAMG;AACH,QAAI;AACF,YAAM,EAAE,WAAW,IAAI,MAAM,OAAO,uBAAuB;AAC3D,YAAM,OAAO,MAAM,WAAW,mBAAmB,OAAO;AACxD,cAAQ,KAAK,IAAI;AAAA,IACnB,SAAS,OAAO;AACd,iBAAW,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AACjE,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AACF;AAGF,QACG,QAAQ,QAAQ,EAChB,YAAY,uDAAuD,EACnE,SAAS,WAAW,cAAc,EAClC,OAAO,OAAO,UAAkB;AAC/B,QAAM,EAAE,UAAU,IAAI,MAAM,OAAO,sBAAsB;AACzD,QAAM,OAAO,MAAM,UAAU,KAAK;AAClC,UAAQ,KAAK,IAAI;AACnB,CAAC;AAGH,QACG,QAAQ,IAAI,EACZ,YAAY,gDAAgD,EAC5D,SAAS,WAAW,cAAc,EAClC,OAAO,OAAO,UAAkB;AAC/B,QAAM,EAAE,MAAM,IAAI,MAAM,OAAO,kBAAkB;AACjD,QAAM,OAAO,MAAM,MAAM,KAAK;AAC9B,UAAQ,KAAK,IAAI;AACnB,CAAC;AAEH,QAAQ,MAAM;","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.1');\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-KTJI7WMC.js";
5
5
  import "./chunk-64FU2L2T.js";
6
6
  import "./chunk-OZVHOVDT.js";
7
- import "./chunk-L7RIGFP6.js";
7
+ import "./chunk-SB52G2M2.js";
8
8
  export {
9
9
  runExecute
10
10
  };
11
- //# sourceMappingURL=execute-UF3IY2MG.js.map
11
+ //# sourceMappingURL=execute-H3COM62D.js.map
@@ -1,16 +1,18 @@
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
  applyPlaceholders,
7
10
  loadPrompt
8
11
  } from "./chunk-OZVHOVDT.js";
9
12
  import {
10
13
  printError,
11
- printInfo,
12
14
  printSuccess
13
- } from "./chunk-L7RIGFP6.js";
15
+ } from "./chunk-SB52G2M2.js";
14
16
 
15
17
  // src/commands/generate.ts
16
18
  function parseIssueUrl(output) {
@@ -18,7 +20,6 @@ function parseIssueUrl(output) {
18
20
  return match?.[1] ?? null;
19
21
  }
20
22
  async function runGenerate(promptText) {
21
- printInfo("Creating GitHub issue...");
22
23
  const template = await loadPrompt("generate");
23
24
  const prompt = applyPlaceholders(template, {
24
25
  __USER_PROMPT__: promptText
@@ -26,9 +27,10 @@ async function runGenerate(promptText) {
26
27
  const result = await runHeadless({
27
28
  prompt,
28
29
  maxTurns: 15,
29
- timeout: 12e4,
30
+ timeout: getGlobalTimeout() ?? 3e5,
30
31
  outputFormat: "text",
31
- allowedTools: ["Bash", "Read", "Glob", "Grep"]
32
+ allowedTools: ["Bash", "Read", "Glob", "Grep"],
33
+ statusMessage: "Creating GitHub issue..."
32
34
  });
33
35
  if (!result.success) {
34
36
  printError(`Issue creation failed: ${result.error}`);
@@ -45,4 +47,4 @@ async function runGenerate(promptText) {
45
47
  export {
46
48
  runGenerate
47
49
  };
48
- //# sourceMappingURL=generate-WMYJEPI4.js.map
50
+ //# sourceMappingURL=generate-KRVWNLQU.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-7A6NLYQE.js";
5
+ import "./chunk-SB52G2M2.js";
6
+ export {
7
+ runInit
8
+ };
9
+ //# sourceMappingURL=init-AA453TQF.js.map
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ runPlan
4
+ } from "./chunk-2DR5PWPR.js";
5
+ import "./chunk-3M7FPMO7.js";
6
+ import "./chunk-KMZHFUOY.js";
7
+ import "./chunk-64FU2L2T.js";
8
+ import "./chunk-OZVHOVDT.js";
9
+ import "./chunk-SB52G2M2.js";
10
+ export {
11
+ runPlan
12
+ };
13
+ //# sourceMappingURL=plan-GGF7FMOV.js.map
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ runPr
4
+ } from "./chunk-ZR5KSQWZ.js";
5
+ import "./chunk-3M7FPMO7.js";
6
+ import "./chunk-KMZHFUOY.js";
7
+ import "./chunk-64FU2L2T.js";
8
+ import "./chunk-OZVHOVDT.js";
9
+ import "./chunk-SB52G2M2.js";
10
+ export {
11
+ runPr
12
+ };
13
+ //# sourceMappingURL=pr-OF25YHPZ.js.map
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ runPrd
4
+ } from "./chunk-FPX32B2W.js";
5
+ import "./chunk-3M7FPMO7.js";
6
+ import "./chunk-KMZHFUOY.js";
7
+ import "./chunk-64FU2L2T.js";
8
+ import "./chunk-OZVHOVDT.js";
9
+ import "./chunk-SB52G2M2.js";
10
+ export {
11
+ runPrd
12
+ };
13
+ //# sourceMappingURL=prd-MEYPY6XI.js.map
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ runReview
4
+ } from "./chunk-K22WFAWY.js";
5
+ import "./chunk-3M7FPMO7.js";
6
+ import "./chunk-KMZHFUOY.js";
7
+ import "./chunk-64FU2L2T.js";
8
+ import "./chunk-OZVHOVDT.js";
9
+ import "./chunk-SB52G2M2.js";
10
+ export {
11
+ runReview
12
+ };
13
+ //# sourceMappingURL=review-7DQIPFTD.js.map
@@ -1,26 +1,28 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runReview
4
- } from "./chunk-D4WBCVB4.js";
4
+ } from "./chunk-K22WFAWY.js";
5
5
  import {
6
6
  runInit
7
- } from "./chunk-JEUHCE3V.js";
7
+ } from "./chunk-7A6NLYQE.js";
8
8
  import {
9
9
  runAnalyze
10
- } from "./chunk-7APADNBV.js";
10
+ } from "./chunk-R7HJYTQU.js";
11
11
  import {
12
+ PipelineTracker,
12
13
  runExecute
13
- } from "./chunk-V356G3JS.js";
14
+ } from "./chunk-KTJI7WMC.js";
14
15
  import {
15
16
  runPlan
16
- } from "./chunk-ZOX7M2C2.js";
17
+ } from "./chunk-2DR5PWPR.js";
17
18
  import {
18
19
  runPr
19
- } from "./chunk-7FRXZ2XA.js";
20
+ } from "./chunk-ZR5KSQWZ.js";
20
21
  import {
21
22
  runPrd
22
- } from "./chunk-G36DIQ4J.js";
23
- import "./chunk-PINC2LST.js";
23
+ } from "./chunk-FPX32B2W.js";
24
+ import "./chunk-3M7FPMO7.js";
25
+ import "./chunk-KMZHFUOY.js";
24
26
  import {
25
27
  isoNow,
26
28
  loadTaskPlan,
@@ -28,11 +30,12 @@ import {
28
30
  } from "./chunk-64FU2L2T.js";
29
31
  import "./chunk-OZVHOVDT.js";
30
32
  import {
33
+ formatDuration,
31
34
  printError,
32
35
  printInfo,
33
36
  printSuccess,
34
37
  printWarning
35
- } from "./chunk-L7RIGFP6.js";
38
+ } from "./chunk-SB52G2M2.js";
36
39
 
37
40
  // src/commands/run.ts
38
41
  import { join } from "path";
@@ -182,10 +185,14 @@ async function runPipeline(issue, mode, from) {
182
185
  }
183
186
  const phaseOrder = ["analyze", "prd", "plan", "execute", "review", "pr"];
184
187
  const startIdx = phaseOrder.indexOf(startPhase);
188
+ const tracker = new PipelineTracker(
189
+ phaseOrder.map((p) => p),
190
+ startIdx
191
+ );
192
+ tracker.startLiveUpdate();
185
193
  for (let i = startIdx; i < phaseOrder.length; i++) {
186
194
  const phase = phaseOrder[i];
187
- printInfo(`
188
- --- Phase: ${phase} ---`);
195
+ tracker.startPhase(phase);
189
196
  let code;
190
197
  switch (phase) {
191
198
  case "analyze":
@@ -220,12 +227,14 @@ async function runPipeline(issue, mode, from) {
220
227
  }
221
228
  const execCode = await runExecute(void 0, { issue: issueNumber });
222
229
  if (execCode !== 0) {
230
+ tracker.failPhase(phase);
223
231
  printError("Correction execution failed");
224
232
  return 1;
225
233
  }
226
234
  code = await runReview(issueNumber);
227
235
  }
228
236
  if (code !== 0) {
237
+ tracker.failPhase(phase);
229
238
  printError(`Review failed after ${maxCycles} correction cycles`);
230
239
  return 1;
231
240
  }
@@ -238,10 +247,13 @@ async function runPipeline(issue, mode, from) {
238
247
  code = 1;
239
248
  }
240
249
  if (code !== 0) {
250
+ tracker.failPhase(phase);
241
251
  printError(`Phase ${phase} failed with exit code ${code}`);
242
252
  return 1;
243
253
  }
254
+ tracker.completePhase(phase);
244
255
  }
256
+ tracker.stopLiveUpdate();
245
257
  printInfo("Closing issue...");
246
258
  try {
247
259
  await execa("gh", ["issue", "close", issueNumber], { reject: false });
@@ -275,14 +287,16 @@ async function runPipeline(issue, mode, from) {
275
287
  await saveTaskPlan(tasksPath, plan);
276
288
  } catch {
277
289
  }
290
+ const totalDuration = formatDuration(tracker.getOverallElapsed());
278
291
  console.log("");
279
292
  printSuccess(`Pipeline complete for issue #${issueNumber}!`);
280
- console.log(` Branch: ${branchName}`);
281
- console.log(` Stories: ${storyCount}`);
282
- console.log(` PR: ${prUrl}`);
293
+ console.log(` Branch: ${branchName}`);
294
+ console.log(` Stories: ${storyCount}`);
295
+ console.log(` Duration: ${totalDuration}`);
296
+ console.log(` PR: ${prUrl}`);
283
297
  return 0;
284
298
  }
285
299
  export {
286
300
  runPipeline
287
301
  };
288
- //# sourceMappingURL=run-J62FIB5O.js.map
302
+ //# sourceMappingURL=run-JZAL7XB2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/run.ts","../src/core/pipeline.ts"],"sourcesContent":["import { join } from 'node:path';\nimport { execa } from 'execa';\nimport { PIPELINE_PHASES, PipelineManager, type PipelinePhase } from '../core/pipeline.js';\nimport { isoNow, loadTaskPlan, saveTaskPlan } from '../core/state-manager.js';\nimport { formatDuration, printError, printInfo, printSuccess, printWarning } from '../ui/logger.js';\nimport { PipelineTracker } from '../ui/progress.js';\nimport { runAnalyze } from './analyze.js';\nimport { runExecute } from './execute.js';\nimport { runInit } from './init.js';\nimport { runPlan } from './plan.js';\nimport { runPr } from './pr.js';\nimport { runPrd } from './prd.js';\nimport { runReview } from './review.js';\n\nexport async function runPipeline(issue: string, mode: string, from?: string): Promise<number> {\n const issueNumber = issue.replace(/^#/, '');\n const issueDir = join('issues', issueNumber);\n const tasksPath = join(issueDir, 'tasks.json');\n\n printInfo(`Starting pipeline for issue #${issueNumber} (mode: ${mode})`);\n\n // Phase 1: Init check\n printInfo('Running prerequisite checks...');\n const initCode = await runInit();\n if (initCode !== 0) {\n printError('Prerequisites not met. Fix the issues above and try again.');\n return 1;\n }\n\n // Determine starting phase\n let startPhase: PipelinePhase = 'analyze';\n if (from) {\n if (!PIPELINE_PHASES.includes(from as PipelinePhase)) {\n printError(`Invalid phase: ${from}. Valid phases: ${PIPELINE_PHASES.join(', ')}`);\n return 1;\n }\n startPhase = from as PipelinePhase;\n } else {\n // Try to auto-resume from pipeline state\n try {\n const plan = await loadTaskPlan(tasksPath);\n const mgr = new PipelineManager(plan, tasksPath);\n const nextPhase = mgr.getNextPhase();\n if (nextPhase && nextPhase !== 'init') {\n startPhase = nextPhase;\n printInfo(`Resuming from phase: ${startPhase}`);\n }\n } catch {\n // No tasks.json yet — start from beginning\n }\n }\n\n // Validate resume prerequisites if starting from a later phase\n if (from) {\n try {\n const plan = await loadTaskPlan(tasksPath);\n const mgr = new PipelineManager(plan, tasksPath);\n if (!mgr.canResume(startPhase)) {\n printError(`Cannot resume from ${startPhase}: prerequisite phases not complete`);\n return 1;\n }\n } catch {\n if (startPhase !== 'analyze') {\n printError(`Cannot resume from ${startPhase}: no pipeline state found`);\n return 1;\n }\n }\n }\n\n const phaseOrder: PipelinePhase[] = ['analyze', 'prd', 'plan', 'execute', 'review', 'pr'];\n const startIdx = phaseOrder.indexOf(startPhase);\n\n // Pipeline progress tracker\n const tracker = new PipelineTracker(\n phaseOrder.map((p) => p),\n startIdx,\n );\n tracker.startLiveUpdate();\n\n for (let i = startIdx; i < phaseOrder.length; i++) {\n const phase = phaseOrder[i];\n tracker.startPhase(phase);\n\n let code: number;\n switch (phase) {\n case 'analyze':\n code = await runAnalyze(issueNumber);\n break;\n case 'prd':\n code = await runPrd(issueNumber);\n break;\n case 'plan':\n code = await runPlan(issueNumber);\n break;\n case 'execute':\n code = await runExecute(undefined, { issue: issueNumber });\n break;\n case 'review': {\n // Read maxCorrectionCycles\n let maxCycles = 3;\n try {\n const plan = await loadTaskPlan(tasksPath);\n maxCycles = plan.maxCorrectionCycles;\n } catch {\n /* use default */\n }\n\n code = await runReview(issueNumber);\n\n // Auto-correction loop on failure\n let cycle = 0;\n while (code !== 0 && cycle < maxCycles) {\n cycle++;\n printWarning(`Review failed. Starting correction cycle ${cycle}/${maxCycles}...`);\n\n // Update correction cycle in tasks.json\n try {\n const plan = await loadTaskPlan(tasksPath);\n plan.correctionCycle = cycle;\n await saveTaskPlan(tasksPath, plan);\n } catch {\n /* non-critical */\n }\n\n // Re-execute\n const execCode = await runExecute(undefined, { issue: issueNumber });\n if (execCode !== 0) {\n tracker.failPhase(phase);\n printError('Correction execution failed');\n return 1;\n }\n\n // Re-review\n code = await runReview(issueNumber);\n }\n\n if (code !== 0) {\n tracker.failPhase(phase);\n printError(`Review failed after ${maxCycles} correction cycles`);\n return 1;\n }\n break;\n }\n case 'pr':\n code = await runPr(issueNumber);\n break;\n default:\n code = 1;\n }\n\n if (code !== 0) {\n tracker.failPhase(phase);\n printError(`Phase ${phase} failed with exit code ${code}`);\n return 1;\n }\n\n tracker.completePhase(phase);\n }\n\n tracker.stopLiveUpdate();\n\n // Close the issue\n printInfo('Closing issue...');\n try {\n await execa('gh', ['issue', 'close', issueNumber], { reject: false });\n } catch {\n printWarning('Failed to close issue automatically');\n }\n\n // Get PR URL for summary\n let prUrl = 'unknown';\n try {\n const proc = await execa('gh', ['pr', 'list', '--head', '', '--json', 'url', '--limit', '1'], {\n reject: false,\n });\n const parsed = JSON.parse(proc.stdout?.toString() ?? '[]');\n if (parsed[0]?.url) {\n prUrl = parsed[0].url;\n }\n } catch {\n /* non-critical */\n }\n\n // Get branch and story count\n let branchName = 'unknown';\n try {\n const proc = await execa('git', ['branch', '--show-current'], { reject: false });\n branchName = proc.stdout?.toString().trim() ?? 'unknown';\n } catch {\n /* non-critical */\n }\n\n let storyCount = 0;\n try {\n const plan = await loadTaskPlan(tasksPath);\n storyCount = plan.userStories.length;\n\n // Mark as completed\n plan.issueStatus = 'completed';\n plan.completedAt = isoNow();\n plan.lastAttemptAt = isoNow();\n await saveTaskPlan(tasksPath, plan);\n } catch {\n /* non-critical */\n }\n\n const totalDuration = formatDuration(tracker.getOverallElapsed());\n\n console.log('');\n printSuccess(`Pipeline complete for issue #${issueNumber}!`);\n console.log(` Branch: ${branchName}`);\n console.log(` Stories: ${storyCount}`);\n console.log(` Duration: ${totalDuration}`);\n console.log(` PR: ${prUrl}`);\n\n return 0;\n}\n","import type { PipelineState, TaskPlan } from '../types.js';\nimport { loadTaskPlan, saveTaskPlan } from './state-manager.js';\n\n/**\n * Ordered pipeline phases. Each phase must complete before the next can start.\n */\nexport const PIPELINE_PHASES = [\n 'init',\n 'analyze',\n 'prd',\n 'plan',\n 'execute',\n 'review',\n 'pr',\n] as const;\n\nexport type PipelinePhase = (typeof PIPELINE_PHASES)[number];\n\n/**\n * Map pipeline phases to their corresponding PipelineState field.\n * 'init' has no persisted state — it's a runtime-only check.\n */\nconst PHASE_TO_FIELD: Record<PipelinePhase, keyof PipelineState | null> = {\n init: null,\n analyze: 'analyzeCompleted',\n prd: 'prdCompleted',\n plan: 'jsonCompleted',\n execute: 'executionCompleted',\n review: 'reviewCompleted',\n pr: 'prCreated',\n};\n\nexport class PipelineManager {\n private tasksJsonPath: string;\n private plan: TaskPlan;\n\n constructor(plan: TaskPlan, tasksJsonPath: string) {\n this.plan = plan;\n this.tasksJsonPath = tasksJsonPath;\n }\n\n /**\n * Reload state from disk.\n */\n async reload(): Promise<void> {\n this.plan = await loadTaskPlan(this.tasksJsonPath);\n }\n\n /**\n * Check if a phase is complete.\n */\n isPhaseComplete(phase: PipelinePhase): boolean {\n const field = PHASE_TO_FIELD[phase];\n if (field === null) return true; // init is always \"complete\" after running\n return this.plan.pipeline?.[field] ?? false;\n }\n\n /**\n * Get the first incomplete phase in the pipeline.\n * Returns null if all phases are complete.\n */\n getNextPhase(): PipelinePhase | null {\n for (const phase of PIPELINE_PHASES) {\n if (!this.isPhaseComplete(phase)) {\n return phase;\n }\n }\n return null;\n }\n\n /**\n * Get the current phase (alias for getNextPhase).\n */\n getCurrentPhase(): PipelinePhase | null {\n return this.getNextPhase();\n }\n\n /**\n * Check whether we can resume from a specific phase.\n * All prerequisite phases must be complete.\n */\n canResume(fromPhase: PipelinePhase): boolean {\n const idx = PIPELINE_PHASES.indexOf(fromPhase);\n if (idx < 0) return false;\n\n // All phases before fromPhase must be complete\n for (let i = 0; i < idx; i++) {\n if (!this.isPhaseComplete(PIPELINE_PHASES[i])) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * Mark a phase as complete and persist to disk.\n */\n async markPhaseComplete(phase: PipelinePhase): Promise<void> {\n const field = PHASE_TO_FIELD[phase];\n if (field === null) return; // init has no persisted state\n\n this.plan = {\n ...this.plan,\n pipeline: {\n ...(this.plan.pipeline ?? {\n analyzeCompleted: false,\n prdCompleted: false,\n jsonCompleted: false,\n executionCompleted: false,\n reviewCompleted: false,\n prCreated: false,\n }),\n [field]: true,\n },\n };\n\n await saveTaskPlan(this.tasksJsonPath, this.plan);\n }\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "issue-flow",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Unified CLI for orchestrating the full issue-flow pipeline via Claude Code Headless",
5
5
  "type": "module",
6
6
  "bin": {
@@ -18,7 +18,7 @@
18
18
  "check": "biome check --write src/ && tsc --noEmit"
19
19
  },
20
20
  "engines": {
21
- "node": ">=18.0.0"
21
+ "node": ">=22.0.0"
22
22
  },
23
23
  "files": [
24
24
  "dist",
@@ -1,12 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- runAnalyze
4
- } from "./chunk-7APADNBV.js";
5
- import "./chunk-PINC2LST.js";
6
- import "./chunk-64FU2L2T.js";
7
- import "./chunk-OZVHOVDT.js";
8
- import "./chunk-L7RIGFP6.js";
9
- export {
10
- runAnalyze
11
- };
12
- //# sourceMappingURL=analyze-YYQQP64A.js.map
@@ -1 +0,0 @@
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 { 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 printInfo(`Analyzing issue #${issueNumber}...`);\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: 15,\n timeout: 120_000,\n outputFormat: 'text',\n allowedTools: ['Bash', 'Read', 'Glob', 'Grep', 'Write'],\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;AAMrB,eAAsB,WAAW,OAAgC;AAC/D,QAAM,cAAc,MAAM,QAAQ,MAAM,EAAE;AAC1C,QAAM,WAAW,KAAK,UAAU,WAAW;AAC3C,QAAM,eAAe,KAAK,UAAU,aAAa;AAEjD,YAAU,oBAAoB,WAAW,KAAK;AAE9C,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;AAAA,IACT,cAAc;AAAA,IACd,cAAc,CAAC,QAAQ,QAAQ,QAAQ,QAAQ,OAAO;AAAA,EACxD,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 +0,0 @@
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 { printError, printInfo, 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 printInfo(`Creating PR for issue #${issueNumber}...`);\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: 120_000,\n outputFormat: 'text',\n allowedTools: ['Bash', 'Read', 'Glob', 'Grep'],\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;AAStB,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;AAE7C,YAAU,0BAA0B,WAAW,KAAK;AAGpD,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;AAAA,IACT,cAAc;AAAA,IACd,cAAc,CAAC,QAAQ,QAAQ,QAAQ,MAAM;AAAA,EAC/C,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":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/review.ts"],"sourcesContent":["import { 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 { printError, printInfo, printSuccess } from '../ui/logger.js';\n\nexport interface ReviewResult {\n status: 'PASS' | 'FAIL';\n findings?: string;\n}\n\n/**\n * Parse the <review-result> block from headless output.\n */\nfunction parseReviewResult(output: string): ReviewResult {\n const match = output.match(/<review-result>([\\s\\S]*?)<\\/review-result>/);\n if (!match) {\n // Try to detect PASS/FAIL from the raw output\n if (/STATUS:\\s*PASS/i.test(output)) {\n return { status: 'PASS' };\n }\n if (/STATUS:\\s*FAIL/i.test(output)) {\n const findingsMatch = output.match(/FINDINGS:([\\s\\S]*?)(?:$|<\\/)/);\n return { status: 'FAIL', findings: findingsMatch?.[1]?.trim() ?? 'Unknown findings' };\n }\n // Default to PASS if no explicit status found and no errors\n return { status: 'PASS' };\n }\n\n const block = match[1];\n if (/STATUS:\\s*PASS/i.test(block)) {\n return { status: 'PASS' };\n }\n\n const findingsMatch = block.match(/FINDINGS:([\\s\\S]*)/);\n return {\n status: 'FAIL',\n findings: findingsMatch?.[1]?.trim() ?? 'Unknown findings',\n };\n}\n\nexport async function runReview(issue: string): Promise<number> {\n const issueNumber = issue.replace(/^#/, '');\n const issueDir = join('issues', issueNumber);\n const tasksPath = join(issueDir, 'tasks.json');\n\n printInfo(`Reviewing issue #${issueNumber} resolution...`);\n\n const template = await loadPrompt('review');\n const prompt = applyPlaceholders(template, {\n __ISSUE_NUMBER__: issueNumber,\n __TASKS_PATH__: tasksPath,\n });\n\n const result = await runHeadless({\n prompt,\n maxTurns: 20,\n timeout: 180_000,\n outputFormat: 'text',\n allowedTools: ['Bash', 'Read', 'Glob', 'Grep'],\n });\n\n if (!result.success) {\n printError(`Review failed: ${result.error}`);\n return 1;\n }\n\n const review = parseReviewResult(result.result);\n\n if (review.status === 'PASS') {\n // Update pipeline state\n try {\n const plan = await loadTaskPlan(tasksPath);\n plan.pipeline.reviewCompleted = true;\n await saveTaskPlan(tasksPath, plan);\n } catch {\n // tasks.json may not exist\n }\n\n printSuccess('Review PASSED — implementation meets acceptance criteria');\n return 0;\n }\n\n printError('Review FAILED — issues found:');\n if (review.findings) {\n console.log(review.findings);\n }\n return 1;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA,SAAS,YAAY;AAcrB,SAAS,kBAAkB,QAA8B;AACvD,QAAM,QAAQ,OAAO,MAAM,4CAA4C;AACvE,MAAI,CAAC,OAAO;AAEV,QAAI,kBAAkB,KAAK,MAAM,GAAG;AAClC,aAAO,EAAE,QAAQ,OAAO;AAAA,IAC1B;AACA,QAAI,kBAAkB,KAAK,MAAM,GAAG;AAClC,YAAMA,iBAAgB,OAAO,MAAM,8BAA8B;AACjE,aAAO,EAAE,QAAQ,QAAQ,UAAUA,iBAAgB,CAAC,GAAG,KAAK,KAAK,mBAAmB;AAAA,IACtF;AAEA,WAAO,EAAE,QAAQ,OAAO;AAAA,EAC1B;AAEA,QAAM,QAAQ,MAAM,CAAC;AACrB,MAAI,kBAAkB,KAAK,KAAK,GAAG;AACjC,WAAO,EAAE,QAAQ,OAAO;AAAA,EAC1B;AAEA,QAAM,gBAAgB,MAAM,MAAM,oBAAoB;AACtD,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,UAAU,gBAAgB,CAAC,GAAG,KAAK,KAAK;AAAA,EAC1C;AACF;AAEA,eAAsB,UAAU,OAAgC;AAC9D,QAAM,cAAc,MAAM,QAAQ,MAAM,EAAE;AAC1C,QAAM,WAAW,KAAK,UAAU,WAAW;AAC3C,QAAM,YAAY,KAAK,UAAU,YAAY;AAE7C,YAAU,oBAAoB,WAAW,gBAAgB;AAEzD,QAAM,WAAW,MAAM,WAAW,QAAQ;AAC1C,QAAM,SAAS,kBAAkB,UAAU;AAAA,IACzC,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,EAClB,CAAC;AAED,QAAM,SAAS,MAAM,YAAY;AAAA,IAC/B;AAAA,IACA,UAAU;AAAA,IACV,SAAS;AAAA,IACT,cAAc;AAAA,IACd,cAAc,CAAC,QAAQ,QAAQ,QAAQ,MAAM;AAAA,EAC/C,CAAC;AAED,MAAI,CAAC,OAAO,SAAS;AACnB,eAAW,kBAAkB,OAAO,KAAK,EAAE;AAC3C,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,kBAAkB,OAAO,MAAM;AAE9C,MAAI,OAAO,WAAW,QAAQ;AAE5B,QAAI;AACF,YAAM,OAAO,MAAM,aAAa,SAAS;AACzC,WAAK,SAAS,kBAAkB;AAChC,YAAM,aAAa,WAAW,IAAI;AAAA,IACpC,QAAQ;AAAA,IAER;AAEA,iBAAa,+DAA0D;AACvE,WAAO;AAAA,EACT;AAEA,aAAW,oCAA+B;AAC1C,MAAI,OAAO,UAAU;AACnB,YAAQ,IAAI,OAAO,QAAQ;AAAA,EAC7B;AACA,SAAO;AACT;","names":["findingsMatch"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/prd.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 { printError, printInfo, printSuccess } from '../ui/logger.js';\n\nexport async function runPrd(issue: string): Promise<number> {\n const issueNumber = issue.replace(/^#/, '');\n const issueDir = join('issues', issueNumber);\n const prdPath = join(issueDir, 'prd.md');\n\n printInfo(`Generating PRD for issue #${issueNumber}...`);\n\n await mkdir(issueDir, { recursive: true });\n\n // Read analysis if it exists\n let analysisContext = '';\n const analysisPath = join(issueDir, 'analysis.md');\n try {\n const content = await readFile(analysisPath, 'utf-8');\n analysisContext = `\\n\\nHere is the existing analysis for this issue:\\n\\n${content}`;\n } catch {\n // No analysis available — that's OK\n }\n\n const template = await loadPrompt('prd');\n const prompt = applyPlaceholders(template, {\n __ISSUE_NUMBER__: issueNumber,\n __ANALYSIS_CONTEXT__: analysisContext,\n __PRD_PATH__: prdPath,\n });\n\n const result = await runHeadless({\n prompt,\n maxTurns: 15,\n timeout: 120_000,\n outputFormat: 'text',\n allowedTools: ['Bash', 'Read', 'Glob', 'Grep', 'Write'],\n });\n\n if (!result.success) {\n printError(`PRD generation failed: ${result.error}`);\n return 1;\n }\n\n // Verify the file was created\n try {\n const content = await readFile(prdPath, 'utf-8');\n if (content.length < 10) {\n printError('PRD file was created but appears empty');\n return 1;\n }\n } catch {\n printError(`PRD file was not created at ${prdPath}`);\n return 1;\n }\n\n // Update pipeline state\n const tasksPath = join(issueDir, 'tasks.json');\n try {\n const plan = await loadTaskPlan(tasksPath);\n plan.pipeline.prdCompleted = true;\n await saveTaskPlan(tasksPath, plan);\n } catch {\n // tasks.json may not exist yet\n }\n\n printSuccess(`PRD saved to ${prdPath}`);\n return 0;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA,SAAS,OAAO,gBAAgB;AAChC,SAAS,YAAY;AAMrB,eAAsB,OAAO,OAAgC;AAC3D,QAAM,cAAc,MAAM,QAAQ,MAAM,EAAE;AAC1C,QAAM,WAAW,KAAK,UAAU,WAAW;AAC3C,QAAM,UAAU,KAAK,UAAU,QAAQ;AAEvC,YAAU,6BAA6B,WAAW,KAAK;AAEvD,QAAM,MAAM,UAAU,EAAE,WAAW,KAAK,CAAC;AAGzC,MAAI,kBAAkB;AACtB,QAAM,eAAe,KAAK,UAAU,aAAa;AACjD,MAAI;AACF,UAAM,UAAU,MAAM,SAAS,cAAc,OAAO;AACpD,sBAAkB;AAAA;AAAA;AAAA;AAAA,EAAwD,OAAO;AAAA,EACnF,QAAQ;AAAA,EAER;AAEA,QAAM,WAAW,MAAM,WAAW,KAAK;AACvC,QAAM,SAAS,kBAAkB,UAAU;AAAA,IACzC,kBAAkB;AAAA,IAClB,sBAAsB;AAAA,IACtB,cAAc;AAAA,EAChB,CAAC;AAED,QAAM,SAAS,MAAM,YAAY;AAAA,IAC/B;AAAA,IACA,UAAU;AAAA,IACV,SAAS;AAAA,IACT,cAAc;AAAA,IACd,cAAc,CAAC,QAAQ,QAAQ,QAAQ,QAAQ,OAAO;AAAA,EACxD,CAAC;AAED,MAAI,CAAC,OAAO,SAAS;AACnB,eAAW,0BAA0B,OAAO,KAAK,EAAE;AACnD,WAAO;AAAA,EACT;AAGA,MAAI;AACF,UAAM,UAAU,MAAM,SAAS,SAAS,OAAO;AAC/C,QAAI,QAAQ,SAAS,IAAI;AACvB,iBAAW,wCAAwC;AACnD,aAAO;AAAA,IACT;AAAA,EACF,QAAQ;AACN,eAAW,+BAA+B,OAAO,EAAE;AACnD,WAAO;AAAA,EACT;AAGA,QAAM,YAAY,KAAK,UAAU,YAAY;AAC7C,MAAI;AACF,UAAM,OAAO,MAAM,aAAa,SAAS;AACzC,SAAK,SAAS,eAAe;AAC7B,UAAM,aAAa,WAAW,IAAI;AAAA,EACpC,QAAQ;AAAA,EAER;AAEA,eAAa,gBAAgB,OAAO,EAAE;AACtC,SAAO;AACT;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/ui/logger.ts"],"sourcesContent":["import chalk from 'chalk';\n\n/**\n * Detect if unicode output is supported.\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 * Detect if color output is supported.\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\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}\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 };\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 };\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"],"mappings":";;;AAAA,OAAO,WAAW;AAKlB,SAAS,aAAsB;AAC7B,MAAI,QAAQ,IAAI,YAAY,QAAQ,QAAQ,IAAI,aAAa,GAAI,QAAO;AACxE,MAAI,CAAC,QAAQ,OAAO,MAAO,QAAO;AAClC,SAAO;AACT;AAKA,SAAS,WAAoB;AAC3B,MAAI,QAAQ,IAAI,YAAY,QAAQ,QAAQ,IAAI,aAAa,GAAI,QAAO;AACxE,MAAI,CAAC,QAAQ,OAAO,MAAO,QAAO;AAClC,SAAO;AACT;AAaO,SAAS,WAAkB;AAChC,MAAI,WAAW,GAAG;AAChB,WAAO;AAAA,MACL,SAAS;AAAA,MACT,MAAM;AAAA,MACN,SAAS;AAAA,MACT,OAAO;AAAA,MACP,MAAM;AAAA,MACN,OAAO;AAAA,MACP,KAAK;AAAA,MACL,YAAY;AAAA,IACd;AAAA,EACF;AACA,SAAO;AAAA,IACL,SAAS;AAAA,IACT,MAAM;AAAA,IACN,SAAS;AAAA,IACT,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,KAAK;AAAA,IACL,YAAY;AAAA,EACd;AACF;AAKO,SAAS,eAAuB;AACrC,SAAO,QAAQ,OAAO,WAAW;AACnC;AAEO,SAAS,aAAa,SAAuB;AAClD,QAAM,QAAQ,SAAS;AACvB,MAAI,SAAS,GAAG;AACd,YAAQ,IAAI,MAAM,MAAM,GAAG,MAAM,OAAO,IAAI,OAAO,EAAE,CAAC;AAAA,EACxD,OAAO;AACL,YAAQ,IAAI,GAAG,MAAM,OAAO,IAAI,OAAO,EAAE;AAAA,EAC3C;AACF;AAEO,SAAS,WAAW,SAAuB;AAChD,QAAM,QAAQ,SAAS;AACvB,MAAI,SAAS,GAAG;AACd,YAAQ,IAAI,MAAM,IAAI,GAAG,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;AAAA,EACnD,OAAO;AACL,YAAQ,IAAI,GAAG,MAAM,IAAI,IAAI,OAAO,EAAE;AAAA,EACxC;AACF;AAEO,SAAS,aAAa,SAAuB;AAClD,QAAM,QAAQ,SAAS;AACvB,MAAI,SAAS,GAAG;AACd,YAAQ,IAAI,MAAM,OAAO,GAAG,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;AAAA,EACtD,OAAO;AACL,YAAQ,IAAI,GAAG,MAAM,IAAI,IAAI,OAAO,EAAE;AAAA,EACxC;AACF;AAEO,SAAS,WAAW,SAAuB;AAChD,QAAM,QAAQ,SAAS;AACvB,MAAI,SAAS,GAAG;AACd,YAAQ,IAAI,MAAM,OAAO,GAAG,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;AAAA,EACvD,OAAO;AACL,YAAQ,IAAI,GAAG,MAAM,KAAK,IAAI,OAAO,EAAE;AAAA,EACzC;AACF;AAEO,SAAS,UAAU,SAAuB;AAC/C,QAAM,QAAQ,SAAS;AACvB,MAAI,SAAS,GAAG;AACd,YAAQ,IAAI,MAAM,KAAK,GAAG,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;AAAA,EACrD,OAAO;AACL,YAAQ,IAAI,GAAG,MAAM,KAAK,IAAI,OAAO,EAAE;AAAA,EACzC;AACF;","names":[]}