issue-flow 0.12.0 → 0.14.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 (197) hide show
  1. package/README.md +79 -274
  2. package/dist/agent-OX3KPHE4.js +30 -0
  3. package/dist/{analyze-OEET7KGE.js → analyze-WIND2SEB.js} +31 -16
  4. package/dist/analyze-WIND2SEB.js.map +1 -0
  5. package/dist/{apply-ZIA3C52S.js → apply-JNOI2LR4.js} +18 -7
  6. package/dist/{apply-ZIA3C52S.js.map → apply-JNOI2LR4.js.map} +1 -1
  7. package/dist/bench-B4VZON7E.js +910 -0
  8. package/dist/bench-B4VZON7E.js.map +1 -0
  9. package/dist/{chunk-FADTCQGM.js → chunk-2IQ6M4ZE.js} +94 -32
  10. package/dist/chunk-2IQ6M4ZE.js.map +1 -0
  11. package/dist/chunk-3BWZO4YI.js +141 -0
  12. package/dist/chunk-3BWZO4YI.js.map +1 -0
  13. package/dist/chunk-3WFZETIM.js +163 -0
  14. package/dist/chunk-3WFZETIM.js.map +1 -0
  15. package/dist/chunk-67YIU2VB.js +362 -0
  16. package/dist/chunk-67YIU2VB.js.map +1 -0
  17. package/dist/{chunk-QCPGHBSZ.js → chunk-6BENHR2I.js} +63 -21
  18. package/dist/chunk-6BENHR2I.js.map +1 -0
  19. package/dist/{chunk-BYZDPR7N.js → chunk-6QYMSNVA.js} +194 -235
  20. package/dist/chunk-6QYMSNVA.js.map +1 -0
  21. package/dist/{chunk-Y5ZDJ4PJ.js → chunk-76MMPJ53.js} +20 -10
  22. package/dist/chunk-76MMPJ53.js.map +1 -0
  23. package/dist/chunk-7Z4Y3VKM.js +26 -0
  24. package/dist/chunk-7Z4Y3VKM.js.map +1 -0
  25. package/dist/{chunk-3QHK4YQA.js → chunk-B72RQZBV.js} +346 -119
  26. package/dist/chunk-B72RQZBV.js.map +1 -0
  27. package/dist/chunk-BEZ5BA5U.js +625 -0
  28. package/dist/chunk-BEZ5BA5U.js.map +1 -0
  29. package/dist/chunk-BRCNQXYQ.js +74 -0
  30. package/dist/chunk-BRCNQXYQ.js.map +1 -0
  31. package/dist/chunk-CGKLE6WR.js +1203 -0
  32. package/dist/chunk-CGKLE6WR.js.map +1 -0
  33. package/dist/chunk-CRGIQFUQ.js +83 -0
  34. package/dist/chunk-CRGIQFUQ.js.map +1 -0
  35. package/dist/{chunk-NS6R37II.js → chunk-F6TOYSYY.js} +141 -12
  36. package/dist/chunk-F6TOYSYY.js.map +1 -0
  37. package/dist/chunk-G5EK2XRN.js +25 -0
  38. package/dist/chunk-G5EK2XRN.js.map +1 -0
  39. package/dist/chunk-HAKDLR6N.js +134 -0
  40. package/dist/chunk-HAKDLR6N.js.map +1 -0
  41. package/dist/chunk-J3SOTUVI.js +298 -0
  42. package/dist/chunk-J3SOTUVI.js.map +1 -0
  43. package/dist/chunk-JN6D3MY6.js +30 -0
  44. package/dist/chunk-JN6D3MY6.js.map +1 -0
  45. package/dist/{chunk-LAFNLLQP.js → chunk-KMRFRXIT.js} +5 -5
  46. package/dist/chunk-KT7JKOXB.js +72 -0
  47. package/dist/chunk-KT7JKOXB.js.map +1 -0
  48. package/dist/chunk-L6HSKTQE.js +77 -0
  49. package/dist/chunk-L6HSKTQE.js.map +1 -0
  50. package/dist/chunk-LBGHI4S2.js +1264 -0
  51. package/dist/chunk-LBGHI4S2.js.map +1 -0
  52. package/dist/chunk-LEW4QM74.js +180 -0
  53. package/dist/chunk-LEW4QM74.js.map +1 -0
  54. package/dist/{chunk-FJP3UQGD.js → chunk-LFEQIZLB.js} +115 -20
  55. package/dist/chunk-LFEQIZLB.js.map +1 -0
  56. package/dist/chunk-OOVG2KBY.js +77 -0
  57. package/dist/chunk-OOVG2KBY.js.map +1 -0
  58. package/dist/{chunk-56KS3TFQ.js → chunk-OR43364P.js} +115 -160
  59. package/dist/chunk-OR43364P.js.map +1 -0
  60. package/dist/chunk-P3LRUNC6.js +16 -0
  61. package/dist/chunk-P3LRUNC6.js.map +1 -0
  62. package/dist/{chunk-TSOLWK7Y.js → chunk-PBTA3QQX.js} +8 -7
  63. package/dist/{chunk-TSOLWK7Y.js.map → chunk-PBTA3QQX.js.map} +1 -1
  64. package/dist/{chunk-MJULIKQU.js → chunk-PHW2YV6N.js} +23 -47
  65. package/dist/chunk-PHW2YV6N.js.map +1 -0
  66. package/dist/{chunk-73ATPIYX.js → chunk-PZTWU277.js} +36 -71
  67. package/dist/chunk-PZTWU277.js.map +1 -0
  68. package/dist/{chunk-M5UCXTIT.js → chunk-QD4VOILZ.js} +22 -18
  69. package/dist/chunk-QD4VOILZ.js.map +1 -0
  70. package/dist/chunk-QJ5UZAH5.js +2718 -0
  71. package/dist/chunk-QJ5UZAH5.js.map +1 -0
  72. package/dist/chunk-QK7WUO7A.js +283 -0
  73. package/dist/chunk-QK7WUO7A.js.map +1 -0
  74. package/dist/{chunk-A4SLHOW7.js → chunk-QZVKRDJY.js} +27 -19
  75. package/dist/chunk-QZVKRDJY.js.map +1 -0
  76. package/dist/chunk-REO3PXXO.js +71 -0
  77. package/dist/chunk-REO3PXXO.js.map +1 -0
  78. package/dist/{chunk-EZATO3DW.js → chunk-RVO7L4FX.js} +594 -17
  79. package/dist/chunk-RVO7L4FX.js.map +1 -0
  80. package/dist/{chunk-XQUSIEKA.js → chunk-SZMHCEYV.js} +63 -14
  81. package/dist/chunk-SZMHCEYV.js.map +1 -0
  82. package/dist/chunk-TYRNTSPJ.js +243 -0
  83. package/dist/chunk-TYRNTSPJ.js.map +1 -0
  84. package/dist/chunk-UJ3L2MS7.js +238 -0
  85. package/dist/chunk-UJ3L2MS7.js.map +1 -0
  86. package/dist/chunk-V7MO5EDS.js +120 -0
  87. package/dist/chunk-V7MO5EDS.js.map +1 -0
  88. package/dist/chunk-WB2X37MO.js +415 -0
  89. package/dist/chunk-WB2X37MO.js.map +1 -0
  90. package/dist/{chunk-NTMMF5UD.js → chunk-X44FKNKP.js} +525 -252
  91. package/dist/chunk-X44FKNKP.js.map +1 -0
  92. package/dist/chunk-XEYH6ZZI.js +289 -0
  93. package/dist/chunk-XEYH6ZZI.js.map +1 -0
  94. package/dist/cli.js +267 -44
  95. package/dist/cli.js.map +1 -1
  96. package/dist/{config-PRJGWW7J.js → config-HMFMCY2M.js} +31 -5
  97. package/dist/contract-JH2WBIO6.js +8 -0
  98. package/dist/conventions-NJF2OPVQ.js +146 -0
  99. package/dist/conventions-NJF2OPVQ.js.map +1 -0
  100. package/dist/diagnostics-THH42ZMP.js +23 -0
  101. package/dist/execute-KFNNZZHI.js +35 -0
  102. package/dist/{generate-EGB4KV2B.js → generate-FW5C6NP7.js} +37 -20
  103. package/dist/{generate-EGB4KV2B.js.map → generate-FW5C6NP7.js.map} +1 -1
  104. package/dist/git-W72QQ6GT.js +33 -0
  105. package/dist/init-HTN4V67Q.js +24 -0
  106. package/dist/{operations-BYT626KQ.js → operations-BCFOBH42.js} +27 -15
  107. package/dist/{operations-BYT626KQ.js.map → operations-BCFOBH42.js.map} +1 -1
  108. package/dist/permissions-4AKNQZHK.js +18 -0
  109. package/dist/plan-SIZLGA4V.js +34 -0
  110. package/dist/{policy-6S4GFC76.js → policy-DT6Q6ZVM.js} +20 -6
  111. package/dist/policy-DT6Q6ZVM.js.map +1 -0
  112. package/dist/pr-OMWCGUOW.js +39 -0
  113. package/dist/pr-review-N24CZPKR.js +32 -0
  114. package/dist/pr-review-N24CZPKR.js.map +1 -0
  115. package/dist/prd-5OFTZAHJ.js +33 -0
  116. package/dist/prd-5OFTZAHJ.js.map +1 -0
  117. package/dist/ps-RFORTCUD.js +93 -0
  118. package/dist/ps-RFORTCUD.js.map +1 -0
  119. package/dist/recorder-KCCPMKQG.js +32 -0
  120. package/dist/recorder-KCCPMKQG.js.map +1 -0
  121. package/dist/registry-GLPXOMFG.js +15 -0
  122. package/dist/registry-GLPXOMFG.js.map +1 -0
  123. package/dist/{resume-PPCNQVVV.js → resume-M5RLKP4I.js} +55 -34
  124. package/dist/{resume-PPCNQVVV.js.map → resume-M5RLKP4I.js.map} +1 -1
  125. package/dist/review-YM4JAABY.js +35 -0
  126. package/dist/review-YM4JAABY.js.map +1 -0
  127. package/dist/routing-NNT5WKGX.js +94 -0
  128. package/dist/routing-NNT5WKGX.js.map +1 -0
  129. package/dist/run-PZUKHPQK.js +54 -0
  130. package/dist/run-PZUKHPQK.js.map +1 -0
  131. package/dist/session-publisher-T7EI3CIP.js +11 -0
  132. package/dist/session-publisher-T7EI3CIP.js.map +1 -0
  133. package/dist/{state-manager-2EDVDBAR.js → state-manager-GQH32C44.js} +4 -2
  134. package/dist/state-manager-GQH32C44.js.map +1 -0
  135. package/dist/usage-V2CHE5PY.js +177 -0
  136. package/dist/usage-V2CHE5PY.js.map +1 -0
  137. package/dist/{web-EF5WIIGG.js → web-EA3KGNFN.js} +45 -30
  138. package/dist/web-EA3KGNFN.js.map +1 -0
  139. package/package.json +6 -2
  140. package/prompts/execute.md +7 -8
  141. package/prompts/plan.md +4 -5
  142. package/prompts/pr.md +2 -2
  143. package/web/AGENTS.md +152 -13
  144. package/web/public/app.css +380 -109
  145. package/web/public/app.js +525 -25
  146. package/web/public/index.html +68 -1
  147. package/dist/analyze-OEET7KGE.js.map +0 -1
  148. package/dist/chunk-3QHK4YQA.js.map +0 -1
  149. package/dist/chunk-42PJFMAR.js +0 -605
  150. package/dist/chunk-42PJFMAR.js.map +0 -1
  151. package/dist/chunk-4JSOYE4G.js +0 -368
  152. package/dist/chunk-4JSOYE4G.js.map +0 -1
  153. package/dist/chunk-56KS3TFQ.js.map +0 -1
  154. package/dist/chunk-73ATPIYX.js.map +0 -1
  155. package/dist/chunk-A4SLHOW7.js.map +0 -1
  156. package/dist/chunk-BAUPQXPE.js +0 -173
  157. package/dist/chunk-BAUPQXPE.js.map +0 -1
  158. package/dist/chunk-BYZDPR7N.js.map +0 -1
  159. package/dist/chunk-CD5ULRVC.js +0 -615
  160. package/dist/chunk-CD5ULRVC.js.map +0 -1
  161. package/dist/chunk-DIDUVL6O.js +0 -1365
  162. package/dist/chunk-DIDUVL6O.js.map +0 -1
  163. package/dist/chunk-EZATO3DW.js.map +0 -1
  164. package/dist/chunk-FADTCQGM.js.map +0 -1
  165. package/dist/chunk-FJP3UQGD.js.map +0 -1
  166. package/dist/chunk-LWRSMTTZ.js +0 -18
  167. package/dist/chunk-LWRSMTTZ.js.map +0 -1
  168. package/dist/chunk-M5UCXTIT.js.map +0 -1
  169. package/dist/chunk-M66SJHQQ.js +0 -206
  170. package/dist/chunk-M66SJHQQ.js.map +0 -1
  171. package/dist/chunk-MJULIKQU.js.map +0 -1
  172. package/dist/chunk-NS6R37II.js.map +0 -1
  173. package/dist/chunk-NTMMF5UD.js.map +0 -1
  174. package/dist/chunk-QCPGHBSZ.js.map +0 -1
  175. package/dist/chunk-XQUSIEKA.js.map +0 -1
  176. package/dist/chunk-Y5ZDJ4PJ.js.map +0 -1
  177. package/dist/execute-XBNVL753.js +0 -18
  178. package/dist/init-AJHCXJBP.js +0 -10
  179. package/dist/plan-QOZ3RIO6.js +0 -21
  180. package/dist/policy-6S4GFC76.js.map +0 -1
  181. package/dist/pr-EBBHD2ZX.js +0 -26
  182. package/dist/pr-review-VVMW5PO4.js +0 -20
  183. package/dist/prd-JQSZF7PR.js +0 -21
  184. package/dist/review-3F6MARWH.js +0 -19
  185. package/dist/run-RXE5GDQO.js +0 -36
  186. package/dist/web-EF5WIIGG.js.map +0 -1
  187. /package/dist/{config-PRJGWW7J.js.map → agent-OX3KPHE4.js.map} +0 -0
  188. /package/dist/{chunk-LAFNLLQP.js.map → chunk-KMRFRXIT.js.map} +0 -0
  189. /package/dist/{execute-XBNVL753.js.map → config-HMFMCY2M.js.map} +0 -0
  190. /package/dist/{init-AJHCXJBP.js.map → contract-JH2WBIO6.js.map} +0 -0
  191. /package/dist/{plan-QOZ3RIO6.js.map → diagnostics-THH42ZMP.js.map} +0 -0
  192. /package/dist/{pr-EBBHD2ZX.js.map → execute-KFNNZZHI.js.map} +0 -0
  193. /package/dist/{pr-review-VVMW5PO4.js.map → git-W72QQ6GT.js.map} +0 -0
  194. /package/dist/{prd-JQSZF7PR.js.map → init-HTN4V67Q.js.map} +0 -0
  195. /package/dist/{review-3F6MARWH.js.map → permissions-4AKNQZHK.js.map} +0 -0
  196. /package/dist/{run-RXE5GDQO.js.map → plan-SIZLGA4V.js.map} +0 -0
  197. /package/dist/{state-manager-2EDVDBAR.js.map → pr-OMWCGUOW.js.map} +0 -0
package/README.md CHANGED
@@ -1,310 +1,115 @@
1
1
  # issue-flow
2
2
 
3
- > This is the npm package README. For full project documentation, see the [root README](../../README.md).
3
+ **Turn an issue into a reviewed Pull Request, without sitting in front of it.**
4
4
 
5
- Unified CLI that orchestrates the full issue-to-PR pipeline via [Claude Code](https://docs.anthropic.com/en/docs/claude-code) Headless mode. Analyzes issues, generates PRDs, creates task plans, implements code iteratively, reviews results, and opens pull requests -- all programmatically, without interactive sessions.
6
-
7
- Built on the [Ralph pattern](https://ghuntley.com/ralph/) for autonomous AI agent loops.
8
-
9
- ## Pipeline Flow
10
-
11
- ```mermaid
12
- flowchart LR
13
- subgraph "issue-flow run 42"
14
- A["init"] --> B["analyze"]
15
- B --> C["prd"]
16
- C --> D["plan"]
17
- D --> E["execute"]
18
- E --> F["review"]
19
- F --> G{PASS?}
20
- G -- Yes --> H["pr"]
21
- G -- No --> I{"Retries\n< max?"}
22
- I -- Yes --> E
23
- I -- No --> J["Stop"]
24
- end
25
- ```
26
-
27
- ## Requirements
28
-
29
- - **Node.js** >= 18.0.0
30
- - **git** installed and available in PATH
31
- - **Claude Code** (`npm install -g @anthropic-ai/claude-code`)
32
- - **GitHub CLI** (`gh`) authenticated (`gh auth login`)
33
-
34
- Run `npx issue-flow init` to verify all prerequisites.
35
-
36
- ## Installation
5
+ A CLI that orchestrates the whole path analyse, plan, implement, verify,
6
+ review, deliver — by driving a coding agent in headless mode:
7
+ [Claude Code](https://docs.anthropic.com/en/docs/claude-code) (the default),
8
+ [Codex CLI](https://developers.openai.com/codex/noninteractive), Cursor CLI or
9
+ [Antigravity CLI](https://antigravity.google/docs/cli/getting-started/), one
10
+ agent per phase if you want.
37
11
 
38
12
  ```bash
39
- # Run directly via npx (no install needed)
40
- npx issue-flow run 42
41
-
42
- # Or install globally
43
- npm install -g issue-flow
44
- issue-flow run 42
13
+ npx issue-flow init # check prerequisites and repository conventions
14
+ npx issue-flow run 42 # prd → plan → execute → review → pr
15
+ npx issue-flow run 42 --web # …and watch it live at http://localhost:3737
45
16
  ```
46
17
 
47
- ## Global Options
48
-
49
- All commands support the following options:
50
-
51
- | Flag | Description |
52
- |------|-------------|
53
- | `-v, --verbose` | Show Claude progress output in real time |
54
- | `-t, --timeout <seconds>` | Override headless timeout in seconds (0 = no limit) |
18
+ > **Full documentation lives in the repository:**
19
+ > [README](https://github.com/fabioassuncao/issue-flow#readme) ·
20
+ > [Commands](https://github.com/fabioassuncao/issue-flow/blob/main/docs/commands.md) ·
21
+ > [Configuration](https://github.com/fabioassuncao/issue-flow/blob/main/docs/configuration.md) ·
22
+ > [Agents](https://github.com/fabioassuncao/issue-flow/blob/main/docs/agents.md) ·
23
+ > [Storage](https://github.com/fabioassuncao/issue-flow/blob/main/docs/storage.md) ·
24
+ > [Web monitoring](https://github.com/fabioassuncao/issue-flow/blob/main/docs/web-monitor.md) ·
25
+ > [Resilience](https://github.com/fabioassuncao/issue-flow/blob/main/docs/resilience.md)
55
26
 
56
- ```bash
57
- # Run with verbose output
58
- npx issue-flow analyze 42 --verbose
59
-
60
- # Override timeout to 10 minutes
61
- npx issue-flow analyze 42 --timeout 600
62
-
63
- # Disable timeout entirely
64
- npx issue-flow run 42 --timeout 0
65
-
66
- # Combine flags
67
- npx issue-flow analyze 42 -v -t 600
68
- ```
27
+ ## Requirements
69
28
 
70
- Every phase that invokes Claude once (`analyze`, `prd`, `plan`, `review`, `pr`, `pr-review`, `generate`) shares a default limit of **15 minutes** per invocation; `execute` has no limit, since its iteration budget is what bounds it. Use `--timeout` to raise it on a large issue, or `--timeout 0` to remove it. When an invocation is cut short the phase reports it as a timeout and retries with backoff, so the limit is the first thing to raise if a phase keeps dying at the same elapsed time.
29
+ - **Node.js** 22
30
+ - **Git**, available in `PATH`, inside a repository
31
+ - **A coding agent** — `npm install -g @anthropic-ai/claude-code` for the default
32
+ - **GitHub CLI** (`gh`), authenticated — only for GitHub issues; a run on local
33
+ issues does not need it
34
+
35
+ ## What it does
36
+
37
+ - The full pipeline `prd` → `plan` → `execute` → `review` → `pr`, plus an
38
+ optional whole-PR review. Every phase is also a standalone command.
39
+ - An iterative execute loop: each iteration is a fresh agent instance that picks
40
+ the highest-priority pending user story, implements it, runs quality checks and
41
+ commits.
42
+ - An objective acceptance contract (typecheck, lint, tests) before the LLM
43
+ judges. An empty contract finishes `unverified`, never green.
44
+ - Per-phase agent selection, resolved explicitly and never inferred from which
45
+ binary happens to be installed.
46
+ - Resilience for long unattended runs: a failure taxonomy, per-kind retry
47
+ budgets, provider failover with circuit breakers, an inactivity watchdog and an
48
+ append-only event journal.
49
+ - Multi-issue queues discovered from sub-issues and dependencies: one branch, one
50
+ Pull Request.
51
+ - A read-only live web monitor, one card per active run across every project.
52
+ - Issues from GitHub or from plain files — the local provider needs nothing
53
+ beyond git.
54
+ - Repository conventions (templates, labels, base branch, commit and branch
55
+ format) discovered rather than imposed.
71
56
 
72
57
  ## Commands
73
58
 
74
- ### `run` -- Full pipeline (end-to-end)
75
-
76
- ```bash
77
- # Run the complete pipeline for an issue
78
- npx issue-flow run 42
79
-
80
- # Resume from a specific phase
81
- npx issue-flow run 42 --from execute
82
-
83
- # Manual mode (artifacts only, no execution)
84
- npx issue-flow run 42 --mode manual
85
-
86
- # Watch the run live in the browser (see "Web Monitoring" below)
87
- npx issue-flow run 42 --web
59
+ | Command | What it does |
60
+ |---------|--------------|
61
+ | `run <issues...>` | The full pipeline, for one issue or a queue |
62
+ | `resume [issue]` | Continue an interrupted pipeline, explicitly |
63
+ | `generate` | Draft and create an issue on GitHub, locally, or both |
64
+ | `init` | Check prerequisites and report (or create) missing conventions |
65
+ | `analyze`, `prd`, `plan`, `execute`, `review`, `pr`, `pr-review` | The phases, standalone |
66
+ | `status`, `ps`, `runs`, `logs`, `usage`, `pause`, `cancel` | Operate a running pipeline |
67
+ | `agent`, `policy`, `conventions`, `routing` | Inspect what was resolved, and why |
68
+ | `web serve`, `web stop` | The monitoring server |
88
69
 
89
- # Continue User Story numbering from the last used in this project
90
- npx issue-flow run 42 --continue
70
+ Run `issue-flow <command> --help` for the flags, or read the
71
+ [command reference](https://github.com/fabioassuncao/issue-flow/blob/main/docs/commands.md).
91
72
 
92
- # Force User Story numbering to start at a specific number
93
- npx issue-flow run 42 --start-us 27
94
- ```
95
-
96
- Executes all phases in order: **init** → **analyze** → **prd** → **plan** → **execute** → **review** → **pr**. Automatically resumes from the last incomplete phase if pipeline state exists. On review failure, its findings are saved verbatim to `lastReviewFindings` in `tasks.json`, and a correction cycle (re-execute + re-review) runs up to `maxCorrectionCycles`. The re-execute step reads `lastReviewFindings` and treats the issue as unresolved even if every user story already has `passes: true`, until the findings are addressed and the field is cleared back to `null`.
97
-
98
- `--continue` and `--start-us <n>` control User Story (`US-NNN`) numbering continuity across `plan` runs of the same project — see [`plan`](#plan----convert-prd-to-task-plan) below.
99
-
100
- ### `init` -- Check prerequisites
101
-
102
- ```bash
103
- npx issue-flow init
104
- ```
105
-
106
- Verifies that `claude`, `gh` (authenticated), and `git` (inside a repo) are available. Reports pass/fail for each with install hints.
73
+ ## Where things are written
107
74
 
108
- ### `analyze` -- Analyze an issue
109
-
110
- ```bash
111
- npx issue-flow analyze 42
112
- ```
113
-
114
- Invokes Claude headlessly to fetch issue data, analyze the codebase, and produce a structured analysis saved to `~/.issue-flow/…/issues/42/analysis.md` (see [Pipeline State](#pipeline-state)).
115
-
116
- ### `prd` -- Generate a PRD
117
-
118
- ```bash
119
- npx issue-flow prd 42
120
- ```
121
-
122
- Generates a Product Requirements Document from the issue analysis. Reads `analysis.md` from the same directory as context if available. Saves to `~/.issue-flow/…/issues/42/prd.md`.
123
-
124
- ### `plan` -- Convert PRD to task plan
125
-
126
- ```bash
127
- npx issue-flow plan 42
128
-
129
- # Continue User Story numbering from the last used in this project
130
- npx issue-flow plan 42 --continue
131
-
132
- # Force numbering to start at a specific number, ignoring history
133
- npx issue-flow plan 42 --start-us 27
134
- ```
135
-
136
- Converts the PRD into a structured `~/.issue-flow/…/issues/42/tasks.json` with ordered user stories, acceptance criteria, and pipeline state. Validates the output with zod schemas.
137
-
138
- `US-NNN` numbering continues automatically across `plan` runs of the same project: the highest number already used in any of the project's `tasks.json` files is recovered and the next story continues from there, falling back to `US-001` when the project has no history yet. `--continue` names that automatic recovery explicitly; `--start-us <n>` forces a specific starting number instead, ignoring history — the two flags are mutually exclusive. The decision is always printed to the terminal and recorded in the project's `metadata.json` (`userStoryNumbering`) for audit. See the root [README](https://github.com/fabioassuncao/issue-flow#user-story-numbering-continuity) for the full cascade.
139
-
140
- ### `execute` -- Run the story execution loop
141
-
142
- ```bash
143
- npx issue-flow execute --issue 42
144
- npx issue-flow execute --issue 42 --max-iterations 15
145
- npx issue-flow execute --issue 42 --retry-forever
146
- ```
147
-
148
- Runs the iterative agent loop. Each iteration is a fresh Claude instance that picks the next pending story, implements it, runs quality checks, and commits.
149
-
150
- | Flag | Description |
151
- |------|-------------|
152
- | `--issue N` | Issue number -- reads artifacts from `~/.issue-flow/…/issues/N/` |
153
- | `--max-iterations N` | Stop after N iterations (default: unlimited) |
154
- | `--retry-limit N` | Retry transient Claude failures up to N consecutive times (default: 10) |
155
- | `--retry-forever` | Retry transient Claude failures indefinitely |
156
-
157
- ### `review` -- Validate the implementation
158
-
159
- ```bash
160
- npx issue-flow review 42
161
- ```
162
-
163
- Invokes Claude headlessly to verify acceptance criteria, run tests, and check for regressions. Outputs `PASS` or `FAIL` with findings.
164
-
165
- ### `pr` -- Create a pull request
166
-
167
- ```bash
168
- npx issue-flow pr 42
169
- ```
170
-
171
- Creates a well-structured PR referencing the issue, with summary and test plan.
172
-
173
- ### `generate` -- Create a new issue
174
-
175
- ```bash
176
- npx issue-flow generate --prompt "Add dark mode support to the settings page"
177
- ```
178
-
179
- Analyzes the project and creates a detailed GitHub issue via Claude headless.
180
-
181
- ## Web Monitoring
182
-
183
- `run` and `execute` support an optional (off by default) real-time monitoring mode: a local HTTP server (plain `node:http`, zero new dependencies) serves a self-contained, read-only web UI with live progress -- current phase and activity, user stories, commits, pull requests, logs, and time estimates.
184
-
185
- ```bash
186
- # Enable with defaults -- binds to 0.0.0.0:3737, reachable from your LAN/VPN
187
- npx issue-flow run 42 --web
188
-
189
- # Restrict to this machine only
190
- npx issue-flow run 42 --web --host 127.0.0.1
191
- ```
192
-
193
- Each setting resolves with the precedence **CLI flag > environment variable > `.issue-flow.json` > default**:
194
-
195
- | CLI flag | Environment variable | `.issue-flow.json` key | Default |
196
- |----------|----------------------|------------------------|---------|
197
- | `--web` / `--serve` | `ISSUE_FLOW_WEB` | `web.enabled` | `false` |
198
- | `--port <n>` | `ISSUE_FLOW_WEB_PORT` | `web.port` | `3737` |
199
- | `--host <h>` | `ISSUE_FLOW_WEB_HOST` | `web.host` | `0.0.0.0` |
200
- | `--refresh <s>` | `ISSUE_FLOW_WEB_REFRESH` | `web.refreshSeconds` | `5` |
201
- | `--web-log-limit <n>` | `ISSUE_FLOW_WEB_LOG_LIMIT` | `web.logLimit` | `200` |
202
- | `--web-no-logs` | -- | `web.includeLogs` | logs included |
203
-
204
- Monitoring never affects the pipeline: with `--web` off the behavior is byte-for-byte identical, a busy port just skips the server with a warning, and killing the server mid-run has no effect on the execution. While enabled, the snapshot served at `/api/status` is also persisted to `~/.issue-flow/…/issues/N/session.json` -- outside your working tree, so there is nothing to add to `.gitignore`.
205
-
206
- For the full documentation (endpoints, `session.json` format, Tailscale setup), see the [root README](../../README.md#web-monitoring).
207
-
208
- ## Pipeline State
209
-
210
- Each issue's state is tracked in a directory of its own under `~/.issue-flow`, keyed by a deterministic project id and the issue identifier:
75
+ Nothing is written inside your repository. Artifacts live in a machine-wide tree
76
+ keyed by a deterministic project id:
211
77
 
212
78
  ```
213
79
  ~/.issue-flow/projects/<project-id>/issues/42/
214
- analysis.md # Issue analysis
215
- prd.md # Product requirements
216
- tasks.json # Task plan with pipeline state and user stories
217
- progress.txt # Execution log
218
- session.json # Live session snapshot (web monitoring only)
219
- pr-review/ # PR review reports and index
80
+ prd.md tasks.json progress.txt session.json events.jsonl pr-review/
220
81
  ```
221
82
 
222
- Nothing is written to your repository. A `<projectRoot>/issues/` tree left by an earlier release is copied here automatically on first use and then treated as read-only -- see the [root README](../../README.md#global-storage) for the full layout, the project id derivation and the migration.
223
-
224
- The `pipeline` field tracks which phases have completed, enabling resume from any point:
225
-
226
- ```json
227
- {
228
- "pipeline": {
229
- "analyzeCompleted": true,
230
- "prdCompleted": true,
231
- "jsonCompleted": true,
232
- "executionCompleted": false,
233
- "reviewCompleted": false,
234
- "prCreated": false
235
- }
236
- }
237
- ```
83
+ `ISSUE_FLOW_HOME` relocates the whole tree. A legacy `<projectRoot>/issues/`
84
+ directory from an earlier release is copied in automatically on first use and
85
+ then left read-only.
238
86
 
239
- The top-level `lastReviewFindings` field (`string | null`) holds the verbatim findings of the most recent failed `review` phase. Non-null overrides the "issue already complete" check even when every user story has `passes: true`, so a correction cycle's re-execute step is guaranteed to run instead of exiting immediately — see `core/engine.ts`.
87
+ ## Configuration
240
88
 
241
- ## Architecture
242
-
243
- ```
244
- src/
245
- cli.ts # Entry point, subcommand registration (commander)
246
- config.ts # Configuration resolution and defaults
247
- types.ts # Shared TypeScript interfaces
248
- schemas.ts # Zod validation schemas
249
- commands/
250
- init.ts # Prerequisite verification
251
- generate.ts # Headless issue creation
252
- run.ts # Full pipeline orchestrator
253
- analyze.ts # Headless issue analysis
254
- prd.ts # Headless PRD generation
255
- plan.ts # Headless PRD-to-JSON conversion
256
- execute.ts # Iterative story execution (engine wrapper)
257
- review.ts # Headless implementation review
258
- pr.ts # Headless PR creation
259
- core/
260
- engine.ts # Main agent loop
261
- executor.ts # Claude CLI invocation via execa
262
- headless.ts # Typed wrapper for claude -p invocations
263
- pipeline.ts # Pipeline state machine
264
- state-manager.ts # Typed CRUD for tasks.json
265
- prompt-resolver.ts # Prompt resolution and templating
266
- session-state.ts # Session snapshot reducer and publishers
267
- session-publisher.ts # Global session publisher slot
268
- session-git.ts # Commit/PR enrichment for the snapshot
269
- web/
270
- server.ts # Web monitoring HTTP server (assets in web/public/)
271
- ui/
272
- logger.ts # Colored logging utilities
273
- progress.ts # Progress bar and iteration headers
274
- summary.ts # Box drawing and summary display
275
- utils/
276
- shell.ts # Shell command execution
277
- git.ts # Git operations
278
- retry.ts # Transient failure detection and backoff
279
- ```
89
+ Everything resolves through **CLI flag > environment variable >
90
+ `.issue-flow.json` > `~/.issue-flow/config.json` > default**. Nothing is
91
+ mandatory. See the
92
+ [configuration reference](https://github.com/fabioassuncao/issue-flow/blob/main/docs/configuration.md).
280
93
 
281
94
  ## Development
282
95
 
283
96
  ```bash
284
- # Install dependencies
285
97
  npm install
286
-
287
- # Build
288
- npm run build
289
-
290
- # Type check
98
+ npm run build # tsup → dist/
291
99
  npm run typecheck
292
-
293
- # Run tests
294
100
  npm test
295
-
296
- # Watch mode
297
- npm run dev
101
+ npm run smoke # end-to-end, against deterministic stand-ins for claude and gh
102
+ npm run check # biome + typecheck
298
103
  ```
299
104
 
300
- For the full development setup and local testing guide, see [CONTRIBUTING.md](CONTRIBUTING.md).
301
- The official release procedure (changelog, version bump, tag, `npm publish`, GitHub
302
- Release) is documented in [CONTRIBUTING.md → Release process](CONTRIBUTING.md#release-process).
105
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for the full setup and the release
106
+ process.
303
107
 
304
108
  ## Credits
305
109
 
306
- Based on [Geoffrey Huntley's Ralph pattern](https://ghuntley.com/ralph/) and the [snarktank/ralph](https://github.com/snarktank/ralph) repository.
110
+ Based on [Geoffrey Huntley's Ralph pattern](https://ghuntley.com/ralph/) and the
111
+ [snarktank/ralph](https://github.com/snarktank/ralph) repository.
307
112
 
308
- ## See Also
113
+ ## License
309
114
 
310
- - [Skills & Sub-Agent Architecture](../../docs/skills-and-agents.md) -- Using Issue Flow interactively via Claude Code skills and the `resolve-issue` sub-agent.
115
+ [MIT](LICENSE)
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ AGENT_COMMAND_SCHEMA_VERSION,
4
+ persistFirstAgentChoice,
5
+ runAgent,
6
+ runAgentUse,
7
+ writeAgentPreference
8
+ } from "./chunk-UJ3L2MS7.js";
9
+ import "./chunk-QJ5UZAH5.js";
10
+ import "./chunk-QK7WUO7A.js";
11
+ import "./chunk-TYRNTSPJ.js";
12
+ import "./chunk-6QYMSNVA.js";
13
+ import "./chunk-3WFZETIM.js";
14
+ import "./chunk-HAKDLR6N.js";
15
+ import "./chunk-BEZ5BA5U.js";
16
+ import "./chunk-67YIU2VB.js";
17
+ import "./chunk-P3LRUNC6.js";
18
+ import "./chunk-G5EK2XRN.js";
19
+ import "./chunk-J3SOTUVI.js";
20
+ import "./chunk-LBGHI4S2.js";
21
+ import "./chunk-7Z4Y3VKM.js";
22
+ import "./chunk-XEYH6ZZI.js";
23
+ export {
24
+ AGENT_COMMAND_SCHEMA_VERSION,
25
+ persistFirstAgentChoice,
26
+ runAgent,
27
+ runAgentUse,
28
+ writeAgentPreference
29
+ };
30
+ //# sourceMappingURL=agent-OX3KPHE4.js.map
@@ -2,36 +2,49 @@
2
2
  import {
3
3
  issuePlaceholders,
4
4
  resolveCommandIssue
5
- } from "./chunk-73ATPIYX.js";
6
- import {
7
- DEFAULT_HEADLESS_TIMEOUT_MS,
8
- runHeadless
9
- } from "./chunk-4JSOYE4G.js";
5
+ } from "./chunk-REO3PXXO.js";
6
+ import "./chunk-PZTWU277.js";
10
7
  import "./chunk-KMMASOA6.js";
11
8
  import {
12
9
  publishPhaseMetrics,
13
10
  resolvePolicyPlaceholders
14
- } from "./chunk-MJULIKQU.js";
11
+ } from "./chunk-PHW2YV6N.js";
15
12
  import {
16
13
  applyPlaceholders,
17
14
  loadPrompt
18
- } from "./chunk-LAFNLLQP.js";
19
- import "./chunk-M66SJHQQ.js";
20
- import "./chunk-EZATO3DW.js";
21
- import "./chunk-42PJFMAR.js";
15
+ } from "./chunk-KMRFRXIT.js";
16
+ import {
17
+ DEFAULT_HEADLESS_TIMEOUT_MS,
18
+ runHeadless
19
+ } from "./chunk-CGKLE6WR.js";
20
+ import "./chunk-LEW4QM74.js";
21
+ import "./chunk-3BWZO4YI.js";
22
+ import "./chunk-OOVG2KBY.js";
23
+ import "./chunk-RVO7L4FX.js";
24
+ import "./chunk-QJ5UZAH5.js";
22
25
  import {
23
26
  resolveIssuePaths
24
- } from "./chunk-DIDUVL6O.js";
27
+ } from "./chunk-QK7WUO7A.js";
25
28
  import {
26
29
  getGlobalTimeout,
27
30
  printError,
28
31
  printInfo,
29
32
  printSuccess
30
- } from "./chunk-BYZDPR7N.js";
33
+ } from "./chunk-TYRNTSPJ.js";
34
+ import "./chunk-6QYMSNVA.js";
35
+ import "./chunk-3WFZETIM.js";
36
+ import "./chunk-HAKDLR6N.js";
37
+ import "./chunk-BEZ5BA5U.js";
38
+ import "./chunk-67YIU2VB.js";
39
+ import "./chunk-P3LRUNC6.js";
40
+ import "./chunk-G5EK2XRN.js";
31
41
  import {
32
42
  loadTaskPlan,
33
43
  saveTaskPlan
34
- } from "./chunk-CD5ULRVC.js";
44
+ } from "./chunk-J3SOTUVI.js";
45
+ import "./chunk-LBGHI4S2.js";
46
+ import "./chunk-7Z4Y3VKM.js";
47
+ import "./chunk-XEYH6ZZI.js";
35
48
 
36
49
  // src/commands/analyze.ts
37
50
  import { mkdir, readFile, writeFile } from "fs/promises";
@@ -65,9 +78,11 @@ async function runAnalyze(issue, resolvedIssue) {
65
78
  outputFormat: "json",
66
79
  allowedTools: ["Bash", "Read", "Glob", "Grep", "Write"],
67
80
  addDirs: [paths.issueDir],
68
- statusMessage: `Analyzing issue #${issueNumber}...`
81
+ statusMessage: `Analyzing issue #${issueNumber}...`,
82
+ phase: "analyze",
83
+ permission: "read-only"
69
84
  });
70
- publishPhaseMetrics("analyze", result.cost, startedAtMs);
85
+ publishPhaseMetrics("analyze", result.cost, startedAtMs, result.agent?.provider);
71
86
  if (!result.success) {
72
87
  printError(`Analysis failed: ${result.error}`);
73
88
  return 1;
@@ -95,4 +110,4 @@ async function runAnalyze(issue, resolvedIssue) {
95
110
  export {
96
111
  runAnalyze
97
112
  };
98
- //# sourceMappingURL=analyze-OEET7KGE.js.map
113
+ //# sourceMappingURL=analyze-WIND2SEB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/analyze.ts"],"sourcesContent":["import { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { DEFAULT_HEADLESS_TIMEOUT_MS, runHeadless } from '../core/headless.js';\nimport { applyPlaceholders, loadPrompt } from '../core/prompt-resolver.js';\nimport { publishPhaseMetrics } from '../core/session-metrics.js';\nimport { loadTaskPlan, saveTaskPlan } from '../core/state-manager.js';\nimport { getGlobalTimeout } from '../core/verbose.js';\nimport { issuePlaceholders, resolveCommandIssue } from '../issues/context.js';\nimport type { ResolvedIssue } from '../issues/types.js';\nimport { resolvePolicyPlaceholders } from '../policy/placeholders.js';\nimport { resolveIssuePaths } from '../storage/resolve.js';\nimport { printError, printInfo, printSuccess } from '../ui/logger.js';\n\nexport async function runAnalyze(issue: string, resolvedIssue?: ResolvedIssue): Promise<number> {\n const issueNumber = issue.replace(/^#/, '');\n const paths = await resolveIssuePaths(issueNumber);\n const analysisPath = paths.analysisFile;\n\n const resolution = await resolveCommandIssue(issueNumber, resolvedIssue);\n if (!resolution.ok) {\n return resolution.code;\n }\n\n await mkdir(paths.issueDir, { recursive: true });\n\n const template = await loadPrompt('analyze');\n const prompt = applyPlaceholders(template, {\n // The repository's own conventions. Empty when it declares none, which is\n // what keeps the rendered prompt identical to the pre-policy one.\n ...(await resolvePolicyPlaceholders()),\n __ISSUE_NUMBER__: issueNumber,\n __ANALYSIS_PATH__: analysisPath,\n // Last: the Issue content is substituted in but never scanned again, so a\n // body that happens to contain a placeholder is left untouched.\n ...issuePlaceholders(resolution.resolved),\n });\n\n const startedAtMs = Date.now();\n const result = await runHeadless({\n prompt,\n maxTurns: 30,\n timeout: getGlobalTimeout() ?? DEFAULT_HEADLESS_TIMEOUT_MS,\n // json (not text) so the CLI reports usage: the envelope's `result` field\n // carries the same assistant text this phase already consumed.\n outputFormat: 'json',\n allowedTools: ['Bash', 'Read', 'Glob', 'Grep', 'Write'],\n addDirs: [paths.issueDir],\n statusMessage: `Analyzing issue #${issueNumber}...`,\n phase: 'analyze',\n permission: 'read-only',\n });\n // Before the success check: the tokens were spent either way.\n publishPhaseMetrics('analyze', result.cost, startedAtMs, result.agent?.provider);\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 = paths.tasksFile;\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;AAY3C,eAAsB,WAAW,OAAe,eAAgD;AAC9F,QAAM,cAAc,MAAM,QAAQ,MAAM,EAAE;AAC1C,QAAM,QAAQ,MAAM,kBAAkB,WAAW;AACjD,QAAM,eAAe,MAAM;AAE3B,QAAM,aAAa,MAAM,oBAAoB,aAAa,aAAa;AACvE,MAAI,CAAC,WAAW,IAAI;AAClB,WAAO,WAAW;AAAA,EACpB;AAEA,QAAM,MAAM,MAAM,UAAU,EAAE,WAAW,KAAK,CAAC;AAE/C,QAAM,WAAW,MAAM,WAAW,SAAS;AAC3C,QAAM,SAAS,kBAAkB,UAAU;AAAA;AAAA;AAAA,IAGzC,GAAI,MAAM,0BAA0B;AAAA,IACpC,kBAAkB;AAAA,IAClB,mBAAmB;AAAA;AAAA;AAAA,IAGnB,GAAG,kBAAkB,WAAW,QAAQ;AAAA,EAC1C,CAAC;AAED,QAAM,cAAc,KAAK,IAAI;AAC7B,QAAM,SAAS,MAAM,YAAY;AAAA,IAC/B;AAAA,IACA,UAAU;AAAA,IACV,SAAS,iBAAiB,KAAK;AAAA;AAAA;AAAA,IAG/B,cAAc;AAAA,IACd,cAAc,CAAC,QAAQ,QAAQ,QAAQ,QAAQ,OAAO;AAAA,IACtD,SAAS,CAAC,MAAM,QAAQ;AAAA,IACxB,eAAe,oBAAoB,WAAW;AAAA,IAC9C,OAAO;AAAA,IACP,YAAY;AAAA,EACd,CAAC;AAED,sBAAoB,WAAW,OAAO,MAAM,aAAa,OAAO,OAAO,QAAQ;AAE/E,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,MAAM;AACxB,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,14 +1,25 @@
1
1
  #!/usr/bin/env node
2
2
  import "./chunk-3D4A4B46.js";
3
3
  import {
4
+ DEFAULT_BRANCH_CONVENTION,
4
5
  loadRepositoryPolicy
5
- } from "./chunk-EZATO3DW.js";
6
- import "./chunk-42PJFMAR.js";
6
+ } from "./chunk-RVO7L4FX.js";
7
+ import "./chunk-QJ5UZAH5.js";
8
+ import "./chunk-QK7WUO7A.js";
9
+ import "./chunk-TYRNTSPJ.js";
10
+ import "./chunk-6QYMSNVA.js";
11
+ import "./chunk-3WFZETIM.js";
12
+ import "./chunk-HAKDLR6N.js";
7
13
  import {
8
14
  getProjectRoot
9
- } from "./chunk-DIDUVL6O.js";
10
- import "./chunk-BYZDPR7N.js";
11
- import "./chunk-CD5ULRVC.js";
15
+ } from "./chunk-BEZ5BA5U.js";
16
+ import "./chunk-67YIU2VB.js";
17
+ import "./chunk-P3LRUNC6.js";
18
+ import "./chunk-G5EK2XRN.js";
19
+ import "./chunk-J3SOTUVI.js";
20
+ import "./chunk-LBGHI4S2.js";
21
+ import "./chunk-7Z4Y3VKM.js";
22
+ import "./chunk-XEYH6ZZI.js";
12
23
 
13
24
  // src/scaffold/apply.ts
14
25
  import { access, mkdir, writeFile } from "fs/promises";
@@ -503,7 +514,7 @@ it: the label becomes a second truth that ages on its own.
503
514
 
504
515
  ## Branches and commits
505
516
 
506
- - Branch: \`issue/{N}-{slug}\`
517
+ - Branch: \`${DEFAULT_BRANCH_CONVENTION}\`
507
518
  - Commit: ${DEFAULT_COMMIT_CONVENTION}
508
519
 
509
520
  The commit type must match the nature of the change. A bug fix committed as
@@ -787,4 +798,4 @@ export {
787
798
  planRepositoryScaffold,
788
799
  resolveRepositoryState
789
800
  };
790
- //# sourceMappingURL=apply-ZIA3C52S.js.map
801
+ //# sourceMappingURL=apply-JNOI2LR4.js.map