issue-flow 0.11.1 → 0.13.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.
- package/README.md +79 -274
- package/dist/agent-BXRIEKVM.js +238 -0
- package/dist/agent-BXRIEKVM.js.map +1 -0
- package/dist/{analyze-XV3K25K3.js → analyze-WS47UYGN.js} +32 -15
- package/dist/analyze-WS47UYGN.js.map +1 -0
- package/dist/{apply-WUJHDD7A.js → apply-OS62UWRN.js} +15 -5
- package/dist/{apply-WUJHDD7A.js.map → apply-OS62UWRN.js.map} +1 -1
- package/dist/bench-SA3BOME5.js +906 -0
- package/dist/bench-SA3BOME5.js.map +1 -0
- package/dist/chunk-37N2RJW2.js +120 -0
- package/dist/chunk-37N2RJW2.js.map +1 -0
- package/dist/chunk-3XLCNVMD.js +180 -0
- package/dist/chunk-3XLCNVMD.js.map +1 -0
- package/dist/chunk-5TB6KLC2.js +72 -0
- package/dist/chunk-5TB6KLC2.js.map +1 -0
- package/dist/{chunk-OBLVLIUS.js → chunk-664Y3NDX.js} +25 -13
- package/dist/chunk-664Y3NDX.js.map +1 -0
- package/dist/chunk-6FDFRNXZ.js +357 -0
- package/dist/chunk-6FDFRNXZ.js.map +1 -0
- package/dist/chunk-7KD66LIM.js +658 -0
- package/dist/chunk-7KD66LIM.js.map +1 -0
- package/dist/chunk-7Z4Y3VKM.js +26 -0
- package/dist/chunk-7Z4Y3VKM.js.map +1 -0
- package/dist/chunk-ARFVHC2F.js +1111 -0
- package/dist/chunk-ARFVHC2F.js.map +1 -0
- package/dist/{chunk-RKTEV6EG.js → chunk-BHJCGWQX.js} +141 -12
- package/dist/chunk-BHJCGWQX.js.map +1 -0
- package/dist/chunk-BQDQTIM7.js +74 -0
- package/dist/chunk-BQDQTIM7.js.map +1 -0
- package/dist/chunk-CNBYCMSU.js +2709 -0
- package/dist/chunk-CNBYCMSU.js.map +1 -0
- package/dist/chunk-CRGIQFUQ.js +83 -0
- package/dist/chunk-CRGIQFUQ.js.map +1 -0
- package/dist/chunk-DIG5XKQQ.js +298 -0
- package/dist/chunk-DIG5XKQQ.js.map +1 -0
- package/dist/chunk-FZDR7CGH.js +71 -0
- package/dist/chunk-FZDR7CGH.js.map +1 -0
- package/dist/chunk-HEF2RMKN.js +413 -0
- package/dist/chunk-HEF2RMKN.js.map +1 -0
- package/dist/{chunk-IVHZEYAX.js → chunk-HJGGNLWI.js} +25 -19
- package/dist/chunk-HJGGNLWI.js.map +1 -0
- package/dist/chunk-HQAHNIAR.js +283 -0
- package/dist/chunk-HQAHNIAR.js.map +1 -0
- package/dist/{chunk-GANSDJV7.js → chunk-IHIEXUTC.js} +46 -24
- package/dist/chunk-IHIEXUTC.js.map +1 -0
- package/dist/chunk-IV5SS4JN.js +84 -0
- package/dist/chunk-IV5SS4JN.js.map +1 -0
- package/dist/{chunk-HC2MT7BX.js → chunk-IYV6KNVF.js} +158 -592
- package/dist/chunk-IYV6KNVF.js.map +1 -0
- package/dist/{chunk-LVKQ2AKT.js → chunk-J62QSVP6.js} +10 -8
- package/dist/chunk-J62QSVP6.js.map +1 -0
- package/dist/chunk-KMMASOA6.js +134 -0
- package/dist/chunk-KMMASOA6.js.map +1 -0
- package/dist/chunk-KQHB7ZT3.js +559 -0
- package/dist/chunk-KQHB7ZT3.js.map +1 -0
- package/dist/chunk-L6HSKTQE.js +77 -0
- package/dist/chunk-L6HSKTQE.js.map +1 -0
- package/dist/{chunk-6N7LZZ5U.js → chunk-LZ6GFQAG.js} +474 -160
- package/dist/chunk-LZ6GFQAG.js.map +1 -0
- package/dist/{chunk-HQYXVIH6.js → chunk-MIVHK5YI.js} +5 -5
- package/dist/chunk-NEZZ6KDR.js +1217 -0
- package/dist/chunk-NEZZ6KDR.js.map +1 -0
- package/dist/{run-DBF2VWUN.js → chunk-OPNGPUKJ.js} +747 -594
- package/dist/chunk-OPNGPUKJ.js.map +1 -0
- package/dist/chunk-P3LRUNC6.js +16 -0
- package/dist/chunk-P3LRUNC6.js.map +1 -0
- package/dist/{chunk-BXCPXRBR.js → chunk-PIVGJM6K.js} +129 -32
- package/dist/chunk-PIVGJM6K.js.map +1 -0
- package/dist/{chunk-AAY6KM7N.js → chunk-PV4OX5TC.js} +167 -196
- package/dist/chunk-PV4OX5TC.js.map +1 -0
- package/dist/chunk-QCXPNSEL.js +141 -0
- package/dist/chunk-QCXPNSEL.js.map +1 -0
- package/dist/{chunk-34WNTK3K.js → chunk-QXDNBYQF.js} +53 -13
- package/dist/chunk-QXDNBYQF.js.map +1 -0
- package/dist/chunk-SNTTOQAD.js +30 -0
- package/dist/chunk-SNTTOQAD.js.map +1 -0
- package/dist/{chunk-EY6WMHV2.js → chunk-TM67EHSV.js} +67 -23
- package/dist/chunk-TM67EHSV.js.map +1 -0
- package/dist/chunk-TVN2JVOF.js +77 -0
- package/dist/chunk-TVN2JVOF.js.map +1 -0
- package/dist/chunk-TX5WIVYP.js +129 -0
- package/dist/chunk-TX5WIVYP.js.map +1 -0
- package/dist/{chunk-KQ4JQN7T.js → chunk-UJ7XWK7J.js} +83 -21
- package/dist/chunk-UJ7XWK7J.js.map +1 -0
- package/dist/{chunk-47VIN33V.js → chunk-UOCPC2Y2.js} +596 -17
- package/dist/chunk-UOCPC2Y2.js.map +1 -0
- package/dist/chunk-XEYH6ZZI.js +289 -0
- package/dist/chunk-XEYH6ZZI.js.map +1 -0
- package/dist/cli.js +390 -40
- package/dist/cli.js.map +1 -1
- package/dist/config-MEM2IWWN.js +76 -0
- package/dist/contract-JH2WBIO6.js +8 -0
- package/dist/conventions-WV4NDXGH.js +143 -0
- package/dist/conventions-WV4NDXGH.js.map +1 -0
- package/dist/execute-NITIHHCK.js +31 -0
- package/dist/{generate-TBVTLMOP.js → generate-MVQI7A45.js} +39 -19
- package/dist/{generate-TBVTLMOP.js.map → generate-MVQI7A45.js.map} +1 -1
- package/dist/git-YRVRUN3C.js +31 -0
- package/dist/init-OKWEC3EV.js +21 -0
- package/dist/operations-LU6JA3BX.js +374 -0
- package/dist/operations-LU6JA3BX.js.map +1 -0
- package/dist/permissions-7NMDFU27.js +18 -0
- package/dist/plan-LEJJF3DE.js +31 -0
- package/dist/{policy-XQW5NUIE.js → policy-JSYEK5B2.js} +17 -4
- package/dist/policy-JSYEK5B2.js.map +1 -0
- package/dist/pr-HPVUZ7S3.js +36 -0
- package/dist/pr-review-R2QZBT3F.js +29 -0
- package/dist/pr-review-R2QZBT3F.js.map +1 -0
- package/dist/prd-5O6GYCC6.js +30 -0
- package/dist/prd-5O6GYCC6.js.map +1 -0
- package/dist/ps-TNE44R5V.js +90 -0
- package/dist/ps-TNE44R5V.js.map +1 -0
- package/dist/recorder-XGF55WXI.js +31 -0
- package/dist/recorder-XGF55WXI.js.map +1 -0
- package/dist/registry-LGPE53QD.js +15 -0
- package/dist/registry-LGPE53QD.js.map +1 -0
- package/dist/resume-QMEPMSZW.js +238 -0
- package/dist/resume-QMEPMSZW.js.map +1 -0
- package/dist/review-YKWD6SNN.js +32 -0
- package/dist/review-YKWD6SNN.js.map +1 -0
- package/dist/routing-2ZUMZPJB.js +91 -0
- package/dist/routing-2ZUMZPJB.js.map +1 -0
- package/dist/run-YU4TR62R.js +50 -0
- package/dist/run-YU4TR62R.js.map +1 -0
- package/dist/state-manager-X3PT3FGT.js +36 -0
- package/dist/state-manager-X3PT3FGT.js.map +1 -0
- package/dist/usage-VCFLDA5Y.js +174 -0
- package/dist/usage-VCFLDA5Y.js.map +1 -0
- package/dist/{web-ANQQTTRD.js → web-XVHLX62B.js} +43 -27
- package/dist/web-XVHLX62B.js.map +1 -0
- package/package.json +6 -2
- package/prompts/execute.md +7 -8
- package/prompts/plan.md +4 -5
- package/prompts/pr.md +13 -6
- package/web/AGENTS.md +3 -3
- package/web/public/app.css +38 -0
- package/web/public/app.js +132 -10
- package/web/public/index.html +24 -0
- package/dist/analyze-XV3K25K3.js.map +0 -1
- package/dist/chunk-34WNTK3K.js.map +0 -1
- package/dist/chunk-3BOHTH4V.js +0 -58
- package/dist/chunk-3BOHTH4V.js.map +0 -1
- package/dist/chunk-47VIN33V.js.map +0 -1
- package/dist/chunk-6N7LZZ5U.js.map +0 -1
- package/dist/chunk-AAY6KM7N.js.map +0 -1
- package/dist/chunk-BXCPXRBR.js.map +0 -1
- package/dist/chunk-EWDJENFW.js +0 -303
- package/dist/chunk-EWDJENFW.js.map +0 -1
- package/dist/chunk-EY6WMHV2.js.map +0 -1
- package/dist/chunk-GANSDJV7.js.map +0 -1
- package/dist/chunk-HC2MT7BX.js.map +0 -1
- package/dist/chunk-HDV3YDTG.js +0 -52
- package/dist/chunk-HDV3YDTG.js.map +0 -1
- package/dist/chunk-IVHZEYAX.js.map +0 -1
- package/dist/chunk-KQ4JQN7T.js.map +0 -1
- package/dist/chunk-LVKQ2AKT.js.map +0 -1
- package/dist/chunk-OBLVLIUS.js.map +0 -1
- package/dist/chunk-RKTEV6EG.js.map +0 -1
- package/dist/chunk-VQ5VN7DF.js +0 -1018
- package/dist/chunk-VQ5VN7DF.js.map +0 -1
- package/dist/config-4THHOXNN.js +0 -41
- package/dist/execute-5OEKLM5X.js +0 -15
- package/dist/init-PRMOTQ7N.js +0 -9
- package/dist/plan-Y2BYZD24.js +0 -17
- package/dist/policy-XQW5NUIE.js.map +0 -1
- package/dist/pr-H6GLOSXF.js +0 -21
- package/dist/pr-review-CK5FR6WX.js +0 -17
- package/dist/prd-4PWLCGH5.js +0 -17
- package/dist/review-QGVAHEZF.js +0 -15
- package/dist/run-DBF2VWUN.js.map +0 -1
- package/dist/web-ANQQTTRD.js.map +0 -1
- /package/dist/{chunk-HQYXVIH6.js.map → chunk-MIVHK5YI.js.map} +0 -0
- /package/dist/{config-4THHOXNN.js.map → config-MEM2IWWN.js.map} +0 -0
- /package/dist/{execute-5OEKLM5X.js.map → contract-JH2WBIO6.js.map} +0 -0
- /package/dist/{init-PRMOTQ7N.js.map → execute-NITIHHCK.js.map} +0 -0
- /package/dist/{plan-Y2BYZD24.js.map → git-YRVRUN3C.js.map} +0 -0
- /package/dist/{pr-H6GLOSXF.js.map → init-OKWEC3EV.js.map} +0 -0
- /package/dist/{pr-review-CK5FR6WX.js.map → permissions-7NMDFU27.js.map} +0 -0
- /package/dist/{prd-4PWLCGH5.js.map → plan-LEJJF3DE.js.map} +0 -0
- /package/dist/{review-QGVAHEZF.js.map → pr-HPVUZ7S3.js.map} +0 -0
package/README.md
CHANGED
|
@@ -1,310 +1,115 @@
|
|
|
1
1
|
# issue-flow
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Turn an issue into a reviewed Pull Request, without sitting in front of it.**
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
-
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
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
|
-
|
|
90
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
223
|
-
|
|
224
|
-
|
|
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
|
-
|
|
87
|
+
## Configuration
|
|
240
88
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
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
|
-
#
|
|
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
|
-
|
|
301
|
-
|
|
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
|
|
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
|
-
##
|
|
113
|
+
## License
|
|
309
114
|
|
|
310
|
-
|
|
115
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
GLOBAL_CONFIG_FILENAME,
|
|
4
|
+
PROJECT_CONFIG_FILENAME,
|
|
5
|
+
describeRunAgents,
|
|
6
|
+
loadAgentConfig,
|
|
7
|
+
probeAgent
|
|
8
|
+
} from "./chunk-CNBYCMSU.js";
|
|
9
|
+
import "./chunk-HQAHNIAR.js";
|
|
10
|
+
import {
|
|
11
|
+
printError,
|
|
12
|
+
printSuccess
|
|
13
|
+
} from "./chunk-IYV6KNVF.js";
|
|
14
|
+
import "./chunk-6FDFRNXZ.js";
|
|
15
|
+
import "./chunk-P3LRUNC6.js";
|
|
16
|
+
import "./chunk-DIG5XKQQ.js";
|
|
17
|
+
import {
|
|
18
|
+
AGENT_PHASES,
|
|
19
|
+
AGENT_SCHEMA_VERSION,
|
|
20
|
+
isAgentPhase,
|
|
21
|
+
isAgentProviderId
|
|
22
|
+
} from "./chunk-NEZZ6KDR.js";
|
|
23
|
+
import {
|
|
24
|
+
getGlobalRoot
|
|
25
|
+
} from "./chunk-TX5WIVYP.js";
|
|
26
|
+
import {
|
|
27
|
+
getProjectRoot
|
|
28
|
+
} from "./chunk-KQHB7ZT3.js";
|
|
29
|
+
import {
|
|
30
|
+
writeFileAtomic
|
|
31
|
+
} from "./chunk-7Z4Y3VKM.js";
|
|
32
|
+
import "./chunk-XEYH6ZZI.js";
|
|
33
|
+
|
|
34
|
+
// src/commands/agent.ts
|
|
35
|
+
import { mkdir, readFile } from "fs/promises";
|
|
36
|
+
import { dirname, join } from "path";
|
|
37
|
+
var AGENT_COMMAND_SCHEMA_VERSION = AGENT_SCHEMA_VERSION;
|
|
38
|
+
function originLabel(origin) {
|
|
39
|
+
switch (origin) {
|
|
40
|
+
case "default":
|
|
41
|
+
return "default";
|
|
42
|
+
case "global":
|
|
43
|
+
return "~/.issue-flow/config.json";
|
|
44
|
+
case "project":
|
|
45
|
+
return ".issue-flow.json";
|
|
46
|
+
case "env":
|
|
47
|
+
return "ISSUE_FLOW_*";
|
|
48
|
+
case "cli":
|
|
49
|
+
return "CLI";
|
|
50
|
+
default:
|
|
51
|
+
return origin;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function formatPhaseLine(phase, provider, model, origin, inherited) {
|
|
55
|
+
const modelBit = model ? ` \xB7 ${model}` : "";
|
|
56
|
+
const source = inherited ? "herdado do padr\xE3o" : originLabel(origin);
|
|
57
|
+
return `${` ${phase.padEnd(12)} ${provider}${modelBit}`.padEnd(40)}(${source})`;
|
|
58
|
+
}
|
|
59
|
+
async function runAgent(options = {}) {
|
|
60
|
+
const config = await loadAgentConfig();
|
|
61
|
+
const summary = await describeRunAgents();
|
|
62
|
+
const [claude, codex, cursor, antigravity] = await Promise.all([
|
|
63
|
+
probeAgent("claude"),
|
|
64
|
+
probeAgent("codex"),
|
|
65
|
+
probeAgent("cursor"),
|
|
66
|
+
probeAgent("antigravity")
|
|
67
|
+
]);
|
|
68
|
+
if (options.json === true) {
|
|
69
|
+
const phases = {};
|
|
70
|
+
for (const phase of AGENT_PHASES) {
|
|
71
|
+
const resolved = summary.byPhase[phase];
|
|
72
|
+
const inherited = config.phases[phase] === void 0;
|
|
73
|
+
phases[phase] = {
|
|
74
|
+
provider: resolved.provider,
|
|
75
|
+
model: resolved.model,
|
|
76
|
+
inherited
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
console.log(
|
|
80
|
+
JSON.stringify(
|
|
81
|
+
{
|
|
82
|
+
schemaVersion: AGENT_COMMAND_SCHEMA_VERSION,
|
|
83
|
+
default: {
|
|
84
|
+
provider: summary.defaultProvider,
|
|
85
|
+
model: summary.defaultModel
|
|
86
|
+
},
|
|
87
|
+
phases,
|
|
88
|
+
availability: [
|
|
89
|
+
{
|
|
90
|
+
id: "claude",
|
|
91
|
+
installed: claude.installed,
|
|
92
|
+
version: claude.version,
|
|
93
|
+
authenticated: claude.authenticated
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
id: "codex",
|
|
97
|
+
installed: codex.installed,
|
|
98
|
+
version: codex.version,
|
|
99
|
+
authenticated: codex.authenticated
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
id: "cursor",
|
|
103
|
+
installed: cursor.installed,
|
|
104
|
+
version: cursor.version,
|
|
105
|
+
authenticated: cursor.authenticated
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
id: "antigravity",
|
|
109
|
+
installed: antigravity.installed,
|
|
110
|
+
version: antigravity.version,
|
|
111
|
+
authenticated: antigravity.authenticated,
|
|
112
|
+
authProbe: "none"
|
|
113
|
+
}
|
|
114
|
+
]
|
|
115
|
+
},
|
|
116
|
+
null,
|
|
117
|
+
2
|
|
118
|
+
)
|
|
119
|
+
);
|
|
120
|
+
return 0;
|
|
121
|
+
}
|
|
122
|
+
const modelLabel = summary.defaultModel ?? "(default do provider)";
|
|
123
|
+
console.log(`Agente padr\xE3o ${summary.defaultProvider.padEnd(22)} (${originLabel("default")})`);
|
|
124
|
+
console.log(`Modelo ${modelLabel}`);
|
|
125
|
+
console.log("");
|
|
126
|
+
console.log("Por fase");
|
|
127
|
+
for (const phase of AGENT_PHASES) {
|
|
128
|
+
const resolved = summary.byPhase[phase];
|
|
129
|
+
const inherited = config.phases[phase] === void 0;
|
|
130
|
+
console.log(
|
|
131
|
+
formatPhaseLine(
|
|
132
|
+
phase,
|
|
133
|
+
resolved.provider,
|
|
134
|
+
resolved.model,
|
|
135
|
+
inherited ? "default" : "project",
|
|
136
|
+
inherited
|
|
137
|
+
)
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
console.log("");
|
|
141
|
+
console.log("Disponibilidade");
|
|
142
|
+
console.log(` claude ${(claude.version ?? "\u2014").padEnd(16)} ${claude.detail}`);
|
|
143
|
+
console.log(` codex ${(codex.version ?? "\u2014").padEnd(16)} ${codex.detail}`);
|
|
144
|
+
console.log(` cursor ${(cursor.version ?? "\u2014").padEnd(16)} ${cursor.detail}`);
|
|
145
|
+
console.log(
|
|
146
|
+
` antigravity ${(antigravity.version ?? "\u2014").padEnd(16)} ${antigravity.detail} (no auth probe)`
|
|
147
|
+
);
|
|
148
|
+
if (antigravity.installed) {
|
|
149
|
+
console.log(
|
|
150
|
+
" Warning: every Antigravity invocation passes --dangerously-skip-permissions. --mode plan is the write containment."
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
return 0;
|
|
154
|
+
}
|
|
155
|
+
async function runAgentUse(providerRaw, options = {}) {
|
|
156
|
+
if (!isAgentProviderId(providerRaw)) {
|
|
157
|
+
printError(
|
|
158
|
+
`Unknown agent provider '${providerRaw}'. Valid providers: claude, codex, cursor, antigravity.`
|
|
159
|
+
);
|
|
160
|
+
return 1;
|
|
161
|
+
}
|
|
162
|
+
const provider = providerRaw;
|
|
163
|
+
let phase;
|
|
164
|
+
if (options.phase !== void 0) {
|
|
165
|
+
if (!isAgentPhase(options.phase)) {
|
|
166
|
+
printError(
|
|
167
|
+
`Unknown agent phase '${options.phase}'. Valid phases: ${AGENT_PHASES.join(", ")}.`
|
|
168
|
+
);
|
|
169
|
+
return 1;
|
|
170
|
+
}
|
|
171
|
+
phase = options.phase;
|
|
172
|
+
}
|
|
173
|
+
const target = options.project === true ? "project" : "global";
|
|
174
|
+
try {
|
|
175
|
+
const path = await writeAgentPreference({
|
|
176
|
+
target,
|
|
177
|
+
provider,
|
|
178
|
+
model: options.model,
|
|
179
|
+
phase
|
|
180
|
+
});
|
|
181
|
+
printSuccess(`Wrote agent preference to ${path}`);
|
|
182
|
+
return 0;
|
|
183
|
+
} catch (err) {
|
|
184
|
+
printError(err instanceof Error ? err.message : String(err));
|
|
185
|
+
return 1;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
async function writeAgentPreference(input) {
|
|
189
|
+
const path = input.target === "global" ? join(getGlobalRoot(), GLOBAL_CONFIG_FILENAME) : join(input.projectRoot ?? await getProjectRoot(), PROJECT_CONFIG_FILENAME);
|
|
190
|
+
let existing = {};
|
|
191
|
+
try {
|
|
192
|
+
const raw = await readFile(path, "utf-8");
|
|
193
|
+
const parsed = JSON.parse(raw);
|
|
194
|
+
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
195
|
+
existing = parsed;
|
|
196
|
+
}
|
|
197
|
+
} catch (err) {
|
|
198
|
+
if (err.code !== "ENOENT") {
|
|
199
|
+
throw new Error(`Could not read ${path}: ${err.message}`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
const currentAgent = existing.agent !== null && typeof existing.agent === "object" && !Array.isArray(existing.agent) ? { ...existing.agent } : {};
|
|
203
|
+
if (input.phase) {
|
|
204
|
+
const phases = currentAgent.phases !== null && typeof currentAgent.phases === "object" && !Array.isArray(currentAgent.phases) ? { ...currentAgent.phases } : {};
|
|
205
|
+
phases[input.phase] = {
|
|
206
|
+
provider: input.provider,
|
|
207
|
+
...input.model ? { model: input.model } : {}
|
|
208
|
+
};
|
|
209
|
+
currentAgent.phases = phases;
|
|
210
|
+
} else {
|
|
211
|
+
currentAgent.provider = input.provider;
|
|
212
|
+
if (input.model) currentAgent.model = input.model;
|
|
213
|
+
else delete currentAgent.model;
|
|
214
|
+
}
|
|
215
|
+
existing.agent = currentAgent;
|
|
216
|
+
await mkdir(dirname(path), { recursive: true });
|
|
217
|
+
await writeFileAtomic(path, `${JSON.stringify(existing, null, 2)}
|
|
218
|
+
`);
|
|
219
|
+
if (input.provider === "cursor") {
|
|
220
|
+
const { ensureCursorStorageGrant } = await import("./permissions-7NMDFU27.js");
|
|
221
|
+
await ensureCursorStorageGrant({
|
|
222
|
+
mode: input.target === "project" ? "project" : "global",
|
|
223
|
+
...input.projectRoot === void 0 ? {} : { projectRoot: input.projectRoot }
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
return path;
|
|
227
|
+
}
|
|
228
|
+
async function persistFirstAgentChoice(provider) {
|
|
229
|
+
return writeAgentPreference({ target: "global", provider });
|
|
230
|
+
}
|
|
231
|
+
export {
|
|
232
|
+
AGENT_COMMAND_SCHEMA_VERSION,
|
|
233
|
+
persistFirstAgentChoice,
|
|
234
|
+
runAgent,
|
|
235
|
+
runAgentUse,
|
|
236
|
+
writeAgentPreference
|
|
237
|
+
};
|
|
238
|
+
//# sourceMappingURL=agent-BXRIEKVM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/agent.ts"],"sourcesContent":["import { mkdir, readFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { probeAgent } from '../agents/availability.js';\nimport { describeRunAgents } from '../agents/resolve.js';\nimport {\n AGENT_PHASES,\n AGENT_SCHEMA_VERSION,\n type AgentPhase,\n type AgentProviderId,\n isAgentPhase,\n isAgentProviderId,\n} from '../agents/types.js';\nimport { GLOBAL_CONFIG_FILENAME, loadAgentConfig, PROJECT_CONFIG_FILENAME } from '../config.js';\nimport { getGlobalRoot } from '../storage/paths.js';\nimport { printError, printSuccess } from '../ui/logger.js';\nimport { writeFileAtomic } from '../utils/fs.js';\nimport { getProjectRoot } from '../utils/git.js';\n\nexport const AGENT_COMMAND_SCHEMA_VERSION = AGENT_SCHEMA_VERSION;\n\nexport interface AgentCommandOptions {\n json?: boolean;\n}\n\nexport interface AgentUseOptions {\n model?: string;\n global?: boolean;\n project?: boolean;\n phase?: string;\n}\n\nfunction originLabel(origin: string): string {\n switch (origin) {\n case 'default':\n return 'default';\n case 'global':\n return '~/.issue-flow/config.json';\n case 'project':\n return '.issue-flow.json';\n case 'env':\n return 'ISSUE_FLOW_*';\n case 'cli':\n return 'CLI';\n default:\n return origin;\n }\n}\n\nfunction formatPhaseLine(\n phase: AgentPhase,\n provider: string,\n model: string | null,\n origin: string,\n inherited: boolean,\n): string {\n const modelBit = model ? ` · ${model}` : '';\n const source = inherited ? 'herdado do padrão' : originLabel(origin);\n return `${` ${phase.padEnd(12)} ${provider}${modelBit}`.padEnd(40)}(${source})`;\n}\n\nexport async function runAgent(options: AgentCommandOptions = {}): Promise<number> {\n const config = await loadAgentConfig();\n const summary = await describeRunAgents();\n const [claude, codex, cursor, antigravity] = await Promise.all([\n probeAgent('claude'),\n probeAgent('codex'),\n probeAgent('cursor'),\n probeAgent('antigravity'),\n ]);\n\n if (options.json === true) {\n const phases: Record<string, unknown> = {};\n for (const phase of AGENT_PHASES) {\n const resolved = summary.byPhase[phase];\n const inherited = config.phases[phase] === undefined;\n phases[phase] = {\n provider: resolved.provider,\n model: resolved.model,\n inherited,\n };\n }\n console.log(\n JSON.stringify(\n {\n schemaVersion: AGENT_COMMAND_SCHEMA_VERSION,\n default: {\n provider: summary.defaultProvider,\n model: summary.defaultModel,\n },\n phases,\n availability: [\n {\n id: 'claude',\n installed: claude.installed,\n version: claude.version,\n authenticated: claude.authenticated,\n },\n {\n id: 'codex',\n installed: codex.installed,\n version: codex.version,\n authenticated: codex.authenticated,\n },\n {\n id: 'cursor',\n installed: cursor.installed,\n version: cursor.version,\n authenticated: cursor.authenticated,\n },\n {\n id: 'antigravity',\n installed: antigravity.installed,\n version: antigravity.version,\n authenticated: antigravity.authenticated,\n authProbe: 'none',\n },\n ],\n },\n null,\n 2,\n ),\n );\n return 0;\n }\n\n const modelLabel = summary.defaultModel ?? '(default do provider)';\n console.log(`Agente padrão ${summary.defaultProvider.padEnd(22)} (${originLabel('default')})`);\n console.log(`Modelo ${modelLabel}`);\n console.log('');\n console.log('Por fase');\n for (const phase of AGENT_PHASES) {\n const resolved = summary.byPhase[phase];\n const inherited = config.phases[phase] === undefined;\n console.log(\n formatPhaseLine(\n phase,\n resolved.provider,\n resolved.model,\n inherited ? 'default' : 'project',\n inherited,\n ),\n );\n }\n console.log('');\n console.log('Disponibilidade');\n console.log(` claude ${(claude.version ?? '—').padEnd(16)} ${claude.detail}`);\n console.log(` codex ${(codex.version ?? '—').padEnd(16)} ${codex.detail}`);\n console.log(` cursor ${(cursor.version ?? '—').padEnd(16)} ${cursor.detail}`);\n console.log(\n ` antigravity ${(antigravity.version ?? '—').padEnd(16)} ${antigravity.detail} (no auth probe)`,\n );\n if (antigravity.installed) {\n console.log(\n ' Warning: every Antigravity invocation passes --dangerously-skip-permissions. --mode plan is the write containment.',\n );\n }\n return 0;\n}\n\nexport async function runAgentUse(\n providerRaw: string,\n options: AgentUseOptions = {},\n): Promise<number> {\n if (!isAgentProviderId(providerRaw)) {\n printError(\n `Unknown agent provider '${providerRaw}'. Valid providers: claude, codex, cursor, antigravity.`,\n );\n return 1;\n }\n const provider = providerRaw as AgentProviderId;\n\n let phase: AgentPhase | undefined;\n if (options.phase !== undefined) {\n if (!isAgentPhase(options.phase)) {\n printError(\n `Unknown agent phase '${options.phase}'. Valid phases: ${AGENT_PHASES.join(', ')}.`,\n );\n return 1;\n }\n phase = options.phase;\n }\n\n const target: 'global' | 'project' = options.project === true ? 'project' : 'global';\n try {\n const path = await writeAgentPreference({\n target,\n provider,\n model: options.model,\n phase,\n });\n printSuccess(`Wrote agent preference to ${path}`);\n return 0;\n } catch (err) {\n printError(err instanceof Error ? err.message : String(err));\n return 1;\n }\n}\n\nexport async function writeAgentPreference(input: {\n target: 'global' | 'project';\n provider: AgentProviderId;\n model?: string;\n phase?: AgentPhase;\n projectRoot?: string;\n}): Promise<string> {\n const path =\n input.target === 'global'\n ? join(getGlobalRoot(), GLOBAL_CONFIG_FILENAME)\n : join(input.projectRoot ?? (await getProjectRoot()), PROJECT_CONFIG_FILENAME);\n\n let existing: Record<string, unknown> = {};\n try {\n const raw = await readFile(path, 'utf-8');\n const parsed: unknown = JSON.parse(raw);\n if (parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)) {\n existing = parsed as Record<string, unknown>;\n }\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n throw new Error(`Could not read ${path}: ${(err as Error).message}`);\n }\n }\n\n const currentAgent =\n existing.agent !== null && typeof existing.agent === 'object' && !Array.isArray(existing.agent)\n ? { ...(existing.agent as Record<string, unknown>) }\n : {};\n\n if (input.phase) {\n const phases =\n currentAgent.phases !== null &&\n typeof currentAgent.phases === 'object' &&\n !Array.isArray(currentAgent.phases)\n ? { ...(currentAgent.phases as Record<string, unknown>) }\n : {};\n phases[input.phase] = {\n provider: input.provider,\n ...(input.model ? { model: input.model } : {}),\n };\n currentAgent.phases = phases;\n } else {\n currentAgent.provider = input.provider;\n if (input.model) currentAgent.model = input.model;\n else delete currentAgent.model;\n }\n\n existing.agent = currentAgent;\n await mkdir(dirname(path), { recursive: true });\n await writeFileAtomic(path, `${JSON.stringify(existing, null, 2)}\\n`);\n if (input.provider === 'cursor') {\n const { ensureCursorStorageGrant } = await import('../agents/permissions.js');\n await ensureCursorStorageGrant({\n mode: input.target === 'project' ? 'project' : 'global',\n ...(input.projectRoot === undefined ? {} : { projectRoot: input.projectRoot }),\n });\n }\n return path;\n}\n\n/** Used by init to persist a first-run choice without touching other keys. */\nexport async function persistFirstAgentChoice(provider: AgentProviderId): Promise<string> {\n return writeAgentPreference({ target: 'global', provider });\n}\n"],"mappings":"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","names":[]}
|