issue-flow 0.2.2__tar.gz → 0.2.3__tar.gz
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.
- issue_flow-0.2.3/PKG-INFO +216 -0
- issue_flow-0.2.3/README.md +192 -0
- {issue_flow-0.2.2 → issue_flow-0.2.3}/pyproject.toml +1 -1
- {issue_flow-0.2.2 → issue_flow-0.2.3}/src/issue_flow/cli.py +20 -2
- {issue_flow-0.2.2 → issue_flow-0.2.3}/src/issue_flow/config.py +14 -3
- issue_flow-0.2.3/src/issue_flow/dependencies.py +162 -0
- {issue_flow-0.2.2 → issue_flow-0.2.3}/src/issue_flow/init.py +43 -3
- issue_flow-0.2.3/src/issue_flow/templates/commands/iflow.md.j2 +77 -0
- issue_flow-0.2.3/src/issue_flow/templates/commands/issue-cleanup.md.j2 +60 -0
- issue_flow-0.2.3/src/issue_flow/templates/commands/issue-close.md.j2 +64 -0
- {issue_flow-0.2.2 → issue_flow-0.2.3}/src/issue_flow/templates/commands/issue-init.md.j2 +6 -0
- issue_flow-0.2.3/src/issue_flow/templates/commands/issue-pause.md.j2 +57 -0
- issue_flow-0.2.3/src/issue_flow/templates/commands/issue-plan.md.j2 +82 -0
- issue_flow-0.2.3/src/issue_flow/templates/commands/issue-start.md.j2 +50 -0
- issue_flow-0.2.3/src/issue_flow/templates/commands/issue-yolo.md.j2 +75 -0
- issue_flow-0.2.3/src/issue_flow/templates/docs/cursor-issue-workflow.md.j2 +239 -0
- issue_flow-0.2.3/src/issue_flow/templates/rules/issueflow-rules.mdc.j2 +125 -0
- issue_flow-0.2.3/src/issue_flow/templates/skills/issueflow_history_update/SKILL.md.j2 +84 -0
- issue_flow-0.2.3/src/issue_flow/templates/skills/issueflow_iflow/SKILL.md.j2 +55 -0
- issue_flow-0.2.3/src/issue_flow/templates/skills/issueflow_issue_cleanup/SKILL.md.j2 +44 -0
- issue_flow-0.2.3/src/issue_flow/templates/skills/issueflow_issue_close/SKILL.md.j2 +62 -0
- {issue_flow-0.2.2 → issue_flow-0.2.3}/src/issue_flow/templates/skills/issueflow_issue_init/SKILL.md.j2 +5 -2
- issue_flow-0.2.3/src/issue_flow/templates/skills/issueflow_issue_pause/SKILL.md.j2 +44 -0
- issue_flow-0.2.3/src/issue_flow/templates/skills/issueflow_issue_plan/SKILL.md.j2 +49 -0
- issue_flow-0.2.3/src/issue_flow/templates/skills/issueflow_issue_start/SKILL.md.j2 +50 -0
- issue_flow-0.2.3/src/issue_flow/templates/skills/issueflow_issue_yolo/SKILL.md.j2 +49 -0
- {issue_flow-0.2.2 → issue_flow-0.2.3}/src/issue_flow/templating.py +38 -9
- issue_flow-0.2.2/PKG-INFO +0 -157
- issue_flow-0.2.2/README.md +0 -133
- issue_flow-0.2.2/src/issue_flow/templates/commands/issue-close.md.j2 +0 -50
- issue_flow-0.2.2/src/issue_flow/templates/commands/issue-start.md.j2 +0 -16
- issue_flow-0.2.2/src/issue_flow/templates/docs/cursor-issue-workflow.md.j2 +0 -120
- issue_flow-0.2.2/src/issue_flow/templates/rules/issueflow-rules.mdc.j2 +0 -86
- issue_flow-0.2.2/src/issue_flow/templates/skills/issueflow_issue_close/SKILL.md.j2 +0 -49
- issue_flow-0.2.2/src/issue_flow/templates/skills/issueflow_issue_start/SKILL.md.j2 +0 -39
- {issue_flow-0.2.2 → issue_flow-0.2.3}/LICENSE +0 -0
- {issue_flow-0.2.2 → issue_flow-0.2.3}/src/issue_flow/__init__.py +0 -0
- {issue_flow-0.2.2 → issue_flow-0.2.3}/src/issue_flow/py.typed +0 -0
- {issue_flow-0.2.2 → issue_flow-0.2.3}/src/issue_flow/templates/__init__.py +0 -0
- {issue_flow-0.2.2 → issue_flow-0.2.3}/src/issue_flow/templates/commands/__init__.py +0 -0
- {issue_flow-0.2.2 → issue_flow-0.2.3}/src/issue_flow/templates/docs/__init__.py +0 -0
- {issue_flow-0.2.2 → issue_flow-0.2.3}/src/issue_flow/templates/rules/__init__.py +0 -0
- {issue_flow-0.2.2 → issue_flow-0.2.3}/src/issue_flow/templates/skills/issueflow_version_bump/SKILL.md.j2 +0 -0
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: issue-flow
|
|
3
|
+
Version: 0.2.3
|
|
4
|
+
Summary: Agents should behave. Let them follow the issue flow.
|
|
5
|
+
Keywords: cursor,ai,agents,issue-tracking,workflow
|
|
6
|
+
Author: jepegit
|
|
7
|
+
Author-email: jepegit <jepe@ife.no>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Requires-Dist: jinja2>=3.1.6
|
|
16
|
+
Requires-Dist: python-dotenv>=1.2.2
|
|
17
|
+
Requires-Dist: rich>=14.3.3
|
|
18
|
+
Requires-Dist: typer>=0.24.1
|
|
19
|
+
Requires-Python: >=3.13
|
|
20
|
+
Project-URL: Homepage, https://github.com/jepegit/issue-flow
|
|
21
|
+
Project-URL: Repository, https://github.com/jepegit/issue-flow
|
|
22
|
+
Project-URL: Issues, https://github.com/jepegit/issue-flow/issues
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# issue-flow
|
|
26
|
+
|
|
27
|
+
Agents should behave. Let them follow the issue flow.
|
|
28
|
+
|
|
29
|
+
**issue-flow** scaffolds a lightweight issue-tracking workflow into your project so that Cursor AI agents can pick up GitHub issues, plan work, and land PRs in a consistent way.
|
|
30
|
+
|
|
31
|
+
## What it does
|
|
32
|
+
|
|
33
|
+
Running `issue-flow init` in your project root creates:
|
|
34
|
+
|
|
35
|
+
```text
|
|
36
|
+
your-project/
|
|
37
|
+
.issueflows/
|
|
38
|
+
00-tools/ # Helper scripts for agents
|
|
39
|
+
01-current-issues/ # Active issue markdown files
|
|
40
|
+
02-partly-solved-issues/ # Parked / in-progress issues
|
|
41
|
+
03-solved-issues/ # Completed issues archive
|
|
42
|
+
.cursor/
|
|
43
|
+
commands/
|
|
44
|
+
iflow.md # /iflow — smart dispatcher (quick start)
|
|
45
|
+
issue-init.md # /issue-init — fetch a GitHub issue locally
|
|
46
|
+
issue-plan.md # /issue-plan — write issue<N>_plan.md and confirm
|
|
47
|
+
issue-start.md # /issue-start — implement the plan
|
|
48
|
+
issue-pause.md # /issue-pause — park work in 02-partly-solved-issues/
|
|
49
|
+
issue-close.md # /issue-close — test, commit, push, PR
|
|
50
|
+
issue-cleanup.md # /issue-cleanup — post-merge branch hygiene
|
|
51
|
+
issue-yolo.md # /issue-yolo — all-in-one for small, low-risk issues
|
|
52
|
+
skills/ # Optional Agent Skills (explicit / @ invoke)
|
|
53
|
+
issueflow-iflow/SKILL.md
|
|
54
|
+
issueflow-issue-init/SKILL.md
|
|
55
|
+
issueflow-issue-plan/SKILL.md
|
|
56
|
+
issueflow-issue-start/SKILL.md
|
|
57
|
+
issueflow-issue-pause/SKILL.md
|
|
58
|
+
issueflow-issue-close/SKILL.md
|
|
59
|
+
issueflow-issue-cleanup/SKILL.md
|
|
60
|
+
issueflow-issue-yolo/SKILL.md
|
|
61
|
+
issueflow-version-bump/SKILL.md
|
|
62
|
+
issueflow-history-update/SKILL.md
|
|
63
|
+
rules/
|
|
64
|
+
issueflow-rules.mdc # Always-on Cursor rule for the workflow
|
|
65
|
+
docs/
|
|
66
|
+
cursor-issue-workflow.md # Human-readable overview of the workflow
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The Cursor slash commands give agents a repeatable flow. The linear path is:
|
|
70
|
+
|
|
71
|
+
1. `/issue-init 42` — pulls GitHub issue #42 into `.issueflows/01-current-issues/` and archives older issues.
|
|
72
|
+
2. `/issue-plan` — drafts `issue<N>_plan.md` (Goal / Constraints / Approach / Files to touch / Test strategy / Open questions) and stops for your confirmation.
|
|
73
|
+
3. `/issue-start` — reads the confirmed plan and implements it. If no plan file exists, it offers to run `/issue-plan` first, proceed without a plan, or abort.
|
|
74
|
+
4. `/issue-close` — runs tests, optionally bumps version with `uv version --bump`, appends a `HISTORY.md` entry (or promotes `[Unreleased]` to a new release section on a bump), updates status files, commits, pushes, and opens a PR.
|
|
75
|
+
5. `/issue-cleanup` — after the PR merges, switches to the default branch, fast-forwards, prunes, and deletes the merged local branch.
|
|
76
|
+
|
|
77
|
+
Plus a few off-path commands:
|
|
78
|
+
|
|
79
|
+
- `/iflow` — **quick start**: inspects the current issue's state and dispatches to the right linear step automatically. A branch-derived number (`42-fix-login` → `N=42`) is authoritative, so `/iflow` works from a fresh branch too.
|
|
80
|
+
- `/issue-pause` — park the current issue in `02-partly-solved-issues/` with a **Remaining work** note; optional WIP commit + switch back to the default branch.
|
|
81
|
+
- `/issue-yolo` — all-in-one chain (`init → plan → start → close`) for small, low-risk issues, with up-front safeguards (refuses on the default branch, refuses with dirty unrelated changes, requires passing tests, single consolidated confirm).
|
|
82
|
+
|
|
83
|
+
The matching **Agent Skills** (under `.cursor/skills/`) carry the same workflows for on-demand use with `/issueflow-iflow`, `/issueflow-issue-init`, `/issueflow-issue-plan`, `/issueflow-issue-start`, `/issueflow-issue-pause`, `/issueflow-issue-close`, `/issueflow-issue-cleanup`, `/issueflow-issue-yolo`, `@issueflow-version-bump` when you need only the bump steps, or `@issueflow-history-update` when you need only the changelog update (see [Cursor Agent Skills](https://cursor.com/docs/context/skills)).
|
|
84
|
+
|
|
85
|
+
## Prerequisites
|
|
86
|
+
|
|
87
|
+
issue-flow itself is a small Python CLI, but the **scaffolded slash commands
|
|
88
|
+
it writes into your project shell out to a few external tools**. If they are
|
|
89
|
+
missing, the slash commands will fail at runtime — so `issue-flow init` now
|
|
90
|
+
checks for them up front and prints install hints before it does anything.
|
|
91
|
+
|
|
92
|
+
Required:
|
|
93
|
+
|
|
94
|
+
- **[Git](https://git-scm.com/downloads)** — used by every slash command for
|
|
95
|
+
branch, fetch, status, commit, and push operations. Almost certainly already
|
|
96
|
+
installed if you're here, but the check covers it for completeness.
|
|
97
|
+
- **[GitHub CLI (`gh`)](https://cli.github.com/)** — used by `/issue-init` to
|
|
98
|
+
fetch issues, by `/issue-close` to open PRs, and by `/issue-cleanup` to check
|
|
99
|
+
PR merge status. After installing, run `gh auth login` once to authenticate.
|
|
100
|
+
|
|
101
|
+
Recommended:
|
|
102
|
+
|
|
103
|
+
- **[uv](https://docs.astral.sh/uv/)** — how issue-flow itself is meant to be
|
|
104
|
+
installed, and how this repo manages its own Python environment.
|
|
105
|
+
|
|
106
|
+
Quick install pointers for `gh`:
|
|
107
|
+
|
|
108
|
+
| Platform | Command |
|
|
109
|
+
|---|---|
|
|
110
|
+
| macOS (Homebrew) | `brew install gh` |
|
|
111
|
+
| Windows (winget) | `winget install --id GitHub.cli -e` |
|
|
112
|
+
| Linux (Debian/Ubuntu) | `sudo apt install gh` (or see [cli.github.com](https://cli.github.com/) for the official repo) |
|
|
113
|
+
|
|
114
|
+
If a dependency is missing, `issue-flow init` prints the installation hints
|
|
115
|
+
and asks whether to continue anyway. You can bypass the prompt in automation
|
|
116
|
+
with `issue-flow init --skip-dep-check` (the same flag is available on
|
|
117
|
+
`issue-flow update`), and the prompt is also auto-skipped when stdin is not
|
|
118
|
+
a TTY (e.g. CI pipelines).
|
|
119
|
+
|
|
120
|
+
## Installation
|
|
121
|
+
|
|
122
|
+
Requires Python 3.13+ and [uv](https://docs.astral.sh/uv/).
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
uv tool install issue-flow
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Or add it as a dev dependency to your project:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
uv add --dev issue-flow
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Quick start
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
cd your-project
|
|
138
|
+
issue-flow init
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
That's it. Open the project in Cursor and start with `/iflow` (or step through `/issue-init`, `/issue-plan`, `/issue-start`, `/issue-close`, `/issue-cleanup` explicitly).
|
|
142
|
+
|
|
143
|
+
## Usage
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
issue-flow init [PROJECT_DIR] [--force] [--skip-dep-check]
|
|
147
|
+
issue-flow update [PROJECT_DIR] [--skip-dep-check]
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### `issue-flow init`
|
|
151
|
+
|
|
152
|
+
| Argument / Option | Description |
|
|
153
|
+
|---|---|
|
|
154
|
+
| `PROJECT_DIR` | Project root directory. Defaults to `.` (current directory). |
|
|
155
|
+
| `--force`, `-f` | Overwrite generated Cursor commands, rules, and workflow doc instead of skipping them. |
|
|
156
|
+
| `--skip-dep-check` | Skip the external-CLI dependency check (`git`, `gh`) and the confirmation prompt that follows if anything is missing. Useful in automation. |
|
|
157
|
+
|
|
158
|
+
Running `init` again without `--force` is safe: generated scaffold files that already exist are skipped, and **issue markdown under `.issueflows/` is never touched** by `init` or `update`. When the CLI detects an existing scaffold, it reminds you about `update` and `--force`.
|
|
159
|
+
|
|
160
|
+
### `issue-flow update`
|
|
161
|
+
|
|
162
|
+
| Argument / Option | Description |
|
|
163
|
+
|---|---|
|
|
164
|
+
| `PROJECT_DIR` | Project root directory. Defaults to `.` (current directory). |
|
|
165
|
+
| `--skip-dep-check` | Skip the external-CLI dependency check (`git`, `gh`) and the confirmation prompt that follows if anything is missing. |
|
|
166
|
+
|
|
167
|
+
Use `update` after upgrading the **issue-flow** package to refresh the packaged slash commands, Cursor rule, and `docs/cursor-issue-workflow.md` from the version you have installed. This **overwrites** those generated files (unlike a plain second `init`). It still does not modify arbitrary files under `.issueflows/` (for example your `issue*_original.md` / `issue*_status.md` files), and it creates any **new** `.issueflows/` subdirectories required by the current package.
|
|
168
|
+
|
|
169
|
+
### When to use which
|
|
170
|
+
|
|
171
|
+
| Goal | Command |
|
|
172
|
+
|---|---|
|
|
173
|
+
| First-time setup, or add missing files only | `issue-flow init` |
|
|
174
|
+
| Pull newer templates after `uv tool upgrade issue-flow` (or similar) | `issue-flow update` |
|
|
175
|
+
| Replace generated scaffolds without upgrading logic | `issue-flow init --force` |
|
|
176
|
+
|
|
177
|
+
## Configuration
|
|
178
|
+
|
|
179
|
+
issue-flow reads a `.env` file from the project root (via python-dotenv). The following environment variables are supported:
|
|
180
|
+
|
|
181
|
+
| Variable | Default | Description |
|
|
182
|
+
|---|---|---|
|
|
183
|
+
| `ISSUEFLOW_DIR` | `.issueflows` | Name of the issue-tracking directory. |
|
|
184
|
+
| `ISSUEFLOW_AGENT_DIR` | `.cursor` | Name of the agent/IDE config directory (currently `.cursor`). |
|
|
185
|
+
| `ISSUEFLOW_DOCS_DIR` | `docs` | Where to write the workflow documentation file. |
|
|
186
|
+
| `ISSUEFLOW_HISTORY_FILE` | `HISTORY.md` | Changelog file that `/issue-close` updates (set to e.g. `CHANGELOG.md` for different conventions). |
|
|
187
|
+
|
|
188
|
+
## Development
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
git clone https://github.com/jepegit/issue-flow.git
|
|
192
|
+
cd issue-flow
|
|
193
|
+
uv sync
|
|
194
|
+
|
|
195
|
+
# Run tests
|
|
196
|
+
uv run pytest
|
|
197
|
+
|
|
198
|
+
# Lint
|
|
199
|
+
uv run ruff check src/ tests/
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Changelog
|
|
203
|
+
|
|
204
|
+
See [HISTORY.md](HISTORY.md) for release notes.
|
|
205
|
+
|
|
206
|
+
## Future plans
|
|
207
|
+
|
|
208
|
+
- **Multi-tool support** — generate config for other AI coding tools (Claude Code, Windsurf, etc.) in addition to Cursor.
|
|
209
|
+
- **`issue-flow status`** — show a dashboard of current, partly-solved, and solved issues.
|
|
210
|
+
- **Custom templates** — let users supply their own Jinja2 templates to tailor slash commands and rules to their team's conventions.
|
|
211
|
+
- **Git hook integration** — optionally move issue files on commit based on status markers.
|
|
212
|
+
- **GitHub Actions workflow** — ship a reusable action that syncs issue state between `.issueflows/` and GitHub issue labels/milestones.
|
|
213
|
+
|
|
214
|
+
## License
|
|
215
|
+
|
|
216
|
+
This project is released under the MIT License. See the full text in the repository: [LICENSE](https://github.com/jepegit/issue-flow/blob/main/LICENSE).
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# issue-flow
|
|
2
|
+
|
|
3
|
+
Agents should behave. Let them follow the issue flow.
|
|
4
|
+
|
|
5
|
+
**issue-flow** scaffolds a lightweight issue-tracking workflow into your project so that Cursor AI agents can pick up GitHub issues, plan work, and land PRs in a consistent way.
|
|
6
|
+
|
|
7
|
+
## What it does
|
|
8
|
+
|
|
9
|
+
Running `issue-flow init` in your project root creates:
|
|
10
|
+
|
|
11
|
+
```text
|
|
12
|
+
your-project/
|
|
13
|
+
.issueflows/
|
|
14
|
+
00-tools/ # Helper scripts for agents
|
|
15
|
+
01-current-issues/ # Active issue markdown files
|
|
16
|
+
02-partly-solved-issues/ # Parked / in-progress issues
|
|
17
|
+
03-solved-issues/ # Completed issues archive
|
|
18
|
+
.cursor/
|
|
19
|
+
commands/
|
|
20
|
+
iflow.md # /iflow — smart dispatcher (quick start)
|
|
21
|
+
issue-init.md # /issue-init — fetch a GitHub issue locally
|
|
22
|
+
issue-plan.md # /issue-plan — write issue<N>_plan.md and confirm
|
|
23
|
+
issue-start.md # /issue-start — implement the plan
|
|
24
|
+
issue-pause.md # /issue-pause — park work in 02-partly-solved-issues/
|
|
25
|
+
issue-close.md # /issue-close — test, commit, push, PR
|
|
26
|
+
issue-cleanup.md # /issue-cleanup — post-merge branch hygiene
|
|
27
|
+
issue-yolo.md # /issue-yolo — all-in-one for small, low-risk issues
|
|
28
|
+
skills/ # Optional Agent Skills (explicit / @ invoke)
|
|
29
|
+
issueflow-iflow/SKILL.md
|
|
30
|
+
issueflow-issue-init/SKILL.md
|
|
31
|
+
issueflow-issue-plan/SKILL.md
|
|
32
|
+
issueflow-issue-start/SKILL.md
|
|
33
|
+
issueflow-issue-pause/SKILL.md
|
|
34
|
+
issueflow-issue-close/SKILL.md
|
|
35
|
+
issueflow-issue-cleanup/SKILL.md
|
|
36
|
+
issueflow-issue-yolo/SKILL.md
|
|
37
|
+
issueflow-version-bump/SKILL.md
|
|
38
|
+
issueflow-history-update/SKILL.md
|
|
39
|
+
rules/
|
|
40
|
+
issueflow-rules.mdc # Always-on Cursor rule for the workflow
|
|
41
|
+
docs/
|
|
42
|
+
cursor-issue-workflow.md # Human-readable overview of the workflow
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
The Cursor slash commands give agents a repeatable flow. The linear path is:
|
|
46
|
+
|
|
47
|
+
1. `/issue-init 42` — pulls GitHub issue #42 into `.issueflows/01-current-issues/` and archives older issues.
|
|
48
|
+
2. `/issue-plan` — drafts `issue<N>_plan.md` (Goal / Constraints / Approach / Files to touch / Test strategy / Open questions) and stops for your confirmation.
|
|
49
|
+
3. `/issue-start` — reads the confirmed plan and implements it. If no plan file exists, it offers to run `/issue-plan` first, proceed without a plan, or abort.
|
|
50
|
+
4. `/issue-close` — runs tests, optionally bumps version with `uv version --bump`, appends a `HISTORY.md` entry (or promotes `[Unreleased]` to a new release section on a bump), updates status files, commits, pushes, and opens a PR.
|
|
51
|
+
5. `/issue-cleanup` — after the PR merges, switches to the default branch, fast-forwards, prunes, and deletes the merged local branch.
|
|
52
|
+
|
|
53
|
+
Plus a few off-path commands:
|
|
54
|
+
|
|
55
|
+
- `/iflow` — **quick start**: inspects the current issue's state and dispatches to the right linear step automatically. A branch-derived number (`42-fix-login` → `N=42`) is authoritative, so `/iflow` works from a fresh branch too.
|
|
56
|
+
- `/issue-pause` — park the current issue in `02-partly-solved-issues/` with a **Remaining work** note; optional WIP commit + switch back to the default branch.
|
|
57
|
+
- `/issue-yolo` — all-in-one chain (`init → plan → start → close`) for small, low-risk issues, with up-front safeguards (refuses on the default branch, refuses with dirty unrelated changes, requires passing tests, single consolidated confirm).
|
|
58
|
+
|
|
59
|
+
The matching **Agent Skills** (under `.cursor/skills/`) carry the same workflows for on-demand use with `/issueflow-iflow`, `/issueflow-issue-init`, `/issueflow-issue-plan`, `/issueflow-issue-start`, `/issueflow-issue-pause`, `/issueflow-issue-close`, `/issueflow-issue-cleanup`, `/issueflow-issue-yolo`, `@issueflow-version-bump` when you need only the bump steps, or `@issueflow-history-update` when you need only the changelog update (see [Cursor Agent Skills](https://cursor.com/docs/context/skills)).
|
|
60
|
+
|
|
61
|
+
## Prerequisites
|
|
62
|
+
|
|
63
|
+
issue-flow itself is a small Python CLI, but the **scaffolded slash commands
|
|
64
|
+
it writes into your project shell out to a few external tools**. If they are
|
|
65
|
+
missing, the slash commands will fail at runtime — so `issue-flow init` now
|
|
66
|
+
checks for them up front and prints install hints before it does anything.
|
|
67
|
+
|
|
68
|
+
Required:
|
|
69
|
+
|
|
70
|
+
- **[Git](https://git-scm.com/downloads)** — used by every slash command for
|
|
71
|
+
branch, fetch, status, commit, and push operations. Almost certainly already
|
|
72
|
+
installed if you're here, but the check covers it for completeness.
|
|
73
|
+
- **[GitHub CLI (`gh`)](https://cli.github.com/)** — used by `/issue-init` to
|
|
74
|
+
fetch issues, by `/issue-close` to open PRs, and by `/issue-cleanup` to check
|
|
75
|
+
PR merge status. After installing, run `gh auth login` once to authenticate.
|
|
76
|
+
|
|
77
|
+
Recommended:
|
|
78
|
+
|
|
79
|
+
- **[uv](https://docs.astral.sh/uv/)** — how issue-flow itself is meant to be
|
|
80
|
+
installed, and how this repo manages its own Python environment.
|
|
81
|
+
|
|
82
|
+
Quick install pointers for `gh`:
|
|
83
|
+
|
|
84
|
+
| Platform | Command |
|
|
85
|
+
|---|---|
|
|
86
|
+
| macOS (Homebrew) | `brew install gh` |
|
|
87
|
+
| Windows (winget) | `winget install --id GitHub.cli -e` |
|
|
88
|
+
| Linux (Debian/Ubuntu) | `sudo apt install gh` (or see [cli.github.com](https://cli.github.com/) for the official repo) |
|
|
89
|
+
|
|
90
|
+
If a dependency is missing, `issue-flow init` prints the installation hints
|
|
91
|
+
and asks whether to continue anyway. You can bypass the prompt in automation
|
|
92
|
+
with `issue-flow init --skip-dep-check` (the same flag is available on
|
|
93
|
+
`issue-flow update`), and the prompt is also auto-skipped when stdin is not
|
|
94
|
+
a TTY (e.g. CI pipelines).
|
|
95
|
+
|
|
96
|
+
## Installation
|
|
97
|
+
|
|
98
|
+
Requires Python 3.13+ and [uv](https://docs.astral.sh/uv/).
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
uv tool install issue-flow
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Or add it as a dev dependency to your project:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
uv add --dev issue-flow
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Quick start
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
cd your-project
|
|
114
|
+
issue-flow init
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
That's it. Open the project in Cursor and start with `/iflow` (or step through `/issue-init`, `/issue-plan`, `/issue-start`, `/issue-close`, `/issue-cleanup` explicitly).
|
|
118
|
+
|
|
119
|
+
## Usage
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
issue-flow init [PROJECT_DIR] [--force] [--skip-dep-check]
|
|
123
|
+
issue-flow update [PROJECT_DIR] [--skip-dep-check]
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### `issue-flow init`
|
|
127
|
+
|
|
128
|
+
| Argument / Option | Description |
|
|
129
|
+
|---|---|
|
|
130
|
+
| `PROJECT_DIR` | Project root directory. Defaults to `.` (current directory). |
|
|
131
|
+
| `--force`, `-f` | Overwrite generated Cursor commands, rules, and workflow doc instead of skipping them. |
|
|
132
|
+
| `--skip-dep-check` | Skip the external-CLI dependency check (`git`, `gh`) and the confirmation prompt that follows if anything is missing. Useful in automation. |
|
|
133
|
+
|
|
134
|
+
Running `init` again without `--force` is safe: generated scaffold files that already exist are skipped, and **issue markdown under `.issueflows/` is never touched** by `init` or `update`. When the CLI detects an existing scaffold, it reminds you about `update` and `--force`.
|
|
135
|
+
|
|
136
|
+
### `issue-flow update`
|
|
137
|
+
|
|
138
|
+
| Argument / Option | Description |
|
|
139
|
+
|---|---|
|
|
140
|
+
| `PROJECT_DIR` | Project root directory. Defaults to `.` (current directory). |
|
|
141
|
+
| `--skip-dep-check` | Skip the external-CLI dependency check (`git`, `gh`) and the confirmation prompt that follows if anything is missing. |
|
|
142
|
+
|
|
143
|
+
Use `update` after upgrading the **issue-flow** package to refresh the packaged slash commands, Cursor rule, and `docs/cursor-issue-workflow.md` from the version you have installed. This **overwrites** those generated files (unlike a plain second `init`). It still does not modify arbitrary files under `.issueflows/` (for example your `issue*_original.md` / `issue*_status.md` files), and it creates any **new** `.issueflows/` subdirectories required by the current package.
|
|
144
|
+
|
|
145
|
+
### When to use which
|
|
146
|
+
|
|
147
|
+
| Goal | Command |
|
|
148
|
+
|---|---|
|
|
149
|
+
| First-time setup, or add missing files only | `issue-flow init` |
|
|
150
|
+
| Pull newer templates after `uv tool upgrade issue-flow` (or similar) | `issue-flow update` |
|
|
151
|
+
| Replace generated scaffolds without upgrading logic | `issue-flow init --force` |
|
|
152
|
+
|
|
153
|
+
## Configuration
|
|
154
|
+
|
|
155
|
+
issue-flow reads a `.env` file from the project root (via python-dotenv). The following environment variables are supported:
|
|
156
|
+
|
|
157
|
+
| Variable | Default | Description |
|
|
158
|
+
|---|---|---|
|
|
159
|
+
| `ISSUEFLOW_DIR` | `.issueflows` | Name of the issue-tracking directory. |
|
|
160
|
+
| `ISSUEFLOW_AGENT_DIR` | `.cursor` | Name of the agent/IDE config directory (currently `.cursor`). |
|
|
161
|
+
| `ISSUEFLOW_DOCS_DIR` | `docs` | Where to write the workflow documentation file. |
|
|
162
|
+
| `ISSUEFLOW_HISTORY_FILE` | `HISTORY.md` | Changelog file that `/issue-close` updates (set to e.g. `CHANGELOG.md` for different conventions). |
|
|
163
|
+
|
|
164
|
+
## Development
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
git clone https://github.com/jepegit/issue-flow.git
|
|
168
|
+
cd issue-flow
|
|
169
|
+
uv sync
|
|
170
|
+
|
|
171
|
+
# Run tests
|
|
172
|
+
uv run pytest
|
|
173
|
+
|
|
174
|
+
# Lint
|
|
175
|
+
uv run ruff check src/ tests/
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Changelog
|
|
179
|
+
|
|
180
|
+
See [HISTORY.md](HISTORY.md) for release notes.
|
|
181
|
+
|
|
182
|
+
## Future plans
|
|
183
|
+
|
|
184
|
+
- **Multi-tool support** — generate config for other AI coding tools (Claude Code, Windsurf, etc.) in addition to Cursor.
|
|
185
|
+
- **`issue-flow status`** — show a dashboard of current, partly-solved, and solved issues.
|
|
186
|
+
- **Custom templates** — let users supply their own Jinja2 templates to tailor slash commands and rules to their team's conventions.
|
|
187
|
+
- **Git hook integration** — optionally move issue files on commit based on status markers.
|
|
188
|
+
- **GitHub Actions workflow** — ship a reusable action that syncs issue state between `.issueflows/` and GitHub issue labels/milestones.
|
|
189
|
+
|
|
190
|
+
## License
|
|
191
|
+
|
|
192
|
+
This project is released under the MIT License. See the full text in the repository: [LICENSE](https://github.com/jepegit/issue-flow/blob/main/LICENSE).
|
|
@@ -32,11 +32,21 @@ def init(
|
|
|
32
32
|
"-f",
|
|
33
33
|
help="Overwrite existing files without asking.",
|
|
34
34
|
),
|
|
35
|
+
skip_dep_check: bool = typer.Option(
|
|
36
|
+
False,
|
|
37
|
+
"--skip-dep-check",
|
|
38
|
+
help=(
|
|
39
|
+
"Skip the external-CLI dependency check (git, gh) and the "
|
|
40
|
+
"confirmation prompt that follows if anything is missing."
|
|
41
|
+
),
|
|
42
|
+
),
|
|
35
43
|
) -> None:
|
|
36
44
|
"""Scaffold issue-flow directories and Cursor config files in a project."""
|
|
37
45
|
from issue_flow.init import run_init
|
|
38
46
|
|
|
39
|
-
run_init(
|
|
47
|
+
run_init(
|
|
48
|
+
project_root=project_dir, force=force, skip_dep_check=skip_dep_check
|
|
49
|
+
)
|
|
40
50
|
|
|
41
51
|
|
|
42
52
|
@app.command()
|
|
@@ -48,11 +58,19 @@ def update(
|
|
|
48
58
|
file_okay=False,
|
|
49
59
|
resolve_path=True,
|
|
50
60
|
),
|
|
61
|
+
skip_dep_check: bool = typer.Option(
|
|
62
|
+
False,
|
|
63
|
+
"--skip-dep-check",
|
|
64
|
+
help=(
|
|
65
|
+
"Skip the external-CLI dependency check (git, gh) and the "
|
|
66
|
+
"confirmation prompt that follows if anything is missing."
|
|
67
|
+
),
|
|
68
|
+
),
|
|
51
69
|
) -> None:
|
|
52
70
|
"""Refresh packaged Cursor commands, rules, and workflow doc from this package."""
|
|
53
71
|
from issue_flow.init import run_update
|
|
54
72
|
|
|
55
|
-
run_update(project_root=project_dir)
|
|
73
|
+
run_update(project_root=project_dir, skip_dep_check=skip_dep_check)
|
|
56
74
|
|
|
57
75
|
|
|
58
76
|
def main() -> None:
|
|
@@ -25,18 +25,26 @@ class Settings:
|
|
|
25
25
|
issueflows_dir: str = field(
|
|
26
26
|
default_factory=lambda: os.getenv("ISSUEFLOW_DIR", ".issueflows")
|
|
27
27
|
)
|
|
28
|
-
|
|
29
|
-
default_factory=lambda: os.getenv("
|
|
28
|
+
agent_dir: str = field(
|
|
29
|
+
default_factory=lambda: os.getenv("ISSUEFLOW_AGENT_DIR", ".cursor")
|
|
30
30
|
)
|
|
31
31
|
docs_dir: str = field(
|
|
32
32
|
default_factory=lambda: os.getenv("ISSUEFLOW_DOCS_DIR", "docs")
|
|
33
33
|
)
|
|
34
|
+
history_file: str = field(
|
|
35
|
+
default_factory=lambda: os.getenv("ISSUEFLOW_HISTORY_FILE", "HISTORY.md")
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
# Give a deprecation warning if the user is using the old ISSUEFLOW_CURSOR_DIR environment variable
|
|
39
|
+
if os.getenv("ISSUEFLOW_CURSOR_DIR"):
|
|
40
|
+
print("WARNING: The ISSUEFLOW_CURSOR_DIR environment variable is deprecated (replaced by ISSUEFLOW_AGENT_DIR).")
|
|
34
41
|
|
|
35
42
|
# Subdirectory names inside .issueflows/
|
|
36
43
|
tools_folder: str = "00-tools"
|
|
37
44
|
current_issues_folder: str = "01-current-issues"
|
|
38
45
|
partly_solved_folder: str = "02-partly-solved-issues"
|
|
39
46
|
solved_folder: str = "03-solved-issues"
|
|
47
|
+
designs_folder: str = "04-designs-and-guides"
|
|
40
48
|
|
|
41
49
|
@property
|
|
42
50
|
def issueflows_subdirs(self) -> list[str]:
|
|
@@ -45,6 +53,7 @@ class Settings:
|
|
|
45
53
|
self.current_issues_folder,
|
|
46
54
|
self.partly_solved_folder,
|
|
47
55
|
self.solved_folder,
|
|
56
|
+
self.designs_folder,
|
|
48
57
|
]
|
|
49
58
|
|
|
50
59
|
def template_context(self, project_root: Path) -> dict[str, str]:
|
|
@@ -52,12 +61,14 @@ class Settings:
|
|
|
52
61
|
project_name = _detect_project_name(project_root)
|
|
53
62
|
return {
|
|
54
63
|
"issueflows_dir": self.issueflows_dir,
|
|
55
|
-
"
|
|
64
|
+
"agent_dir": self.agent_dir,
|
|
56
65
|
"docs_dir": self.docs_dir,
|
|
66
|
+
"history_file": self.history_file,
|
|
57
67
|
"tools_folder": self.tools_folder,
|
|
58
68
|
"current_issues_folder": self.current_issues_folder,
|
|
59
69
|
"partly_solved_folder": self.partly_solved_folder,
|
|
60
70
|
"solved_folder": self.solved_folder,
|
|
71
|
+
"designs_folder": self.designs_folder,
|
|
61
72
|
"project_name": project_name,
|
|
62
73
|
}
|
|
63
74
|
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"""External CLI dependency detection for issue-flow.
|
|
2
|
+
|
|
3
|
+
The scaffolded workflow shells out to ``git`` and ``gh`` (GitHub CLI) via
|
|
4
|
+
slash commands. We detect missing tools at ``issue-flow init`` /
|
|
5
|
+
``issue-flow update`` time so users get a clear install hint rather than a
|
|
6
|
+
confusing failure later from inside a Cursor command.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import shutil
|
|
12
|
+
import sys
|
|
13
|
+
from dataclasses import dataclass
|
|
14
|
+
|
|
15
|
+
from rich.console import Console
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass(frozen=True)
|
|
19
|
+
class Dependency:
|
|
20
|
+
"""A single external CLI tool issue-flow's workflow depends on."""
|
|
21
|
+
|
|
22
|
+
name: str
|
|
23
|
+
command: str
|
|
24
|
+
purpose: str
|
|
25
|
+
docs_url: str
|
|
26
|
+
# Platform hint → short install snippet. Keys are free-form labels
|
|
27
|
+
# shown verbatim (e.g. "macOS (Homebrew)", "Windows (winget)", "Linux
|
|
28
|
+
# (Debian/Ubuntu)"). Values are one-line commands.
|
|
29
|
+
install_hints: tuple[tuple[str, str], ...]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# The scaffolded slash commands (see
|
|
33
|
+
# ``src/issue_flow/templates/commands/*.md.j2``) invoke these tools. ``uv``
|
|
34
|
+
# is intentionally *not* listed here: it is an install-time prerequisite
|
|
35
|
+
# for issue-flow itself, not something the scaffold calls at runtime, so
|
|
36
|
+
# it belongs in the README only.
|
|
37
|
+
REQUIRED_DEPENDENCIES: tuple[Dependency, ...] = (
|
|
38
|
+
Dependency(
|
|
39
|
+
name="Git",
|
|
40
|
+
command="git",
|
|
41
|
+
purpose=(
|
|
42
|
+
"Used by every slash command for branch, fetch, status, "
|
|
43
|
+
"commit, and push operations."
|
|
44
|
+
),
|
|
45
|
+
docs_url="https://git-scm.com/downloads",
|
|
46
|
+
install_hints=(
|
|
47
|
+
("macOS (Homebrew)", "brew install git"),
|
|
48
|
+
("Windows (winget)", "winget install --id Git.Git -e"),
|
|
49
|
+
("Linux (Debian/Ubuntu)", "sudo apt install git"),
|
|
50
|
+
),
|
|
51
|
+
),
|
|
52
|
+
Dependency(
|
|
53
|
+
name="GitHub CLI",
|
|
54
|
+
command="gh",
|
|
55
|
+
purpose=(
|
|
56
|
+
"Used by /issue-init to fetch issues, /issue-close to open "
|
|
57
|
+
"PRs, and /issue-cleanup to check PR merge status. Remember "
|
|
58
|
+
"to run `gh auth login` once after installing."
|
|
59
|
+
),
|
|
60
|
+
docs_url="https://cli.github.com/",
|
|
61
|
+
install_hints=(
|
|
62
|
+
("macOS (Homebrew)", "brew install gh"),
|
|
63
|
+
("Windows (winget)", "winget install --id GitHub.cli -e"),
|
|
64
|
+
(
|
|
65
|
+
"Linux (Debian/Ubuntu)",
|
|
66
|
+
"sudo apt install gh # or see https://cli.github.com/ for the official repo",
|
|
67
|
+
),
|
|
68
|
+
),
|
|
69
|
+
),
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def check_dependencies(
|
|
74
|
+
dependencies: tuple[Dependency, ...] = REQUIRED_DEPENDENCIES,
|
|
75
|
+
) -> list[Dependency]:
|
|
76
|
+
"""Return the subset of ``dependencies`` whose ``command`` is not on ``PATH``.
|
|
77
|
+
|
|
78
|
+
Uses :func:`shutil.which` only — no subprocess invocations — so it is
|
|
79
|
+
safe to call on any platform without risk of hanging or prompting.
|
|
80
|
+
"""
|
|
81
|
+
return [dep for dep in dependencies if shutil.which(dep.command) is None]
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def format_missing_report(
|
|
85
|
+
missing: list[Dependency],
|
|
86
|
+
console: Console,
|
|
87
|
+
) -> None:
|
|
88
|
+
"""Print a human-readable report listing missing dependencies.
|
|
89
|
+
|
|
90
|
+
The output is intentionally compact and uses only ``rich`` markup so
|
|
91
|
+
it blends with the rest of the ``init`` output.
|
|
92
|
+
"""
|
|
93
|
+
if not missing:
|
|
94
|
+
return
|
|
95
|
+
|
|
96
|
+
count = len(missing)
|
|
97
|
+
noun = "dependency" if count == 1 else "dependencies"
|
|
98
|
+
console.print(
|
|
99
|
+
f"[bold yellow]Missing {count} external {noun}:[/bold yellow]"
|
|
100
|
+
)
|
|
101
|
+
for dep in missing:
|
|
102
|
+
console.print(
|
|
103
|
+
f"\n [bold]{dep.name}[/bold] "
|
|
104
|
+
f"([cyan]{dep.command}[/cyan] not found on PATH)"
|
|
105
|
+
)
|
|
106
|
+
console.print(f" [dim]{dep.purpose}[/dim]")
|
|
107
|
+
console.print(f" Docs: [blue]{dep.docs_url}[/blue]")
|
|
108
|
+
console.print(" Install:")
|
|
109
|
+
for label, snippet in dep.install_hints:
|
|
110
|
+
console.print(f" - {label}: [green]{snippet}[/green]")
|
|
111
|
+
console.print()
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def prompt_or_skip(
|
|
115
|
+
missing: list[Dependency],
|
|
116
|
+
console: Console,
|
|
117
|
+
*,
|
|
118
|
+
skip: bool,
|
|
119
|
+
stdin_is_tty: bool | None = None,
|
|
120
|
+
) -> bool:
|
|
121
|
+
"""Decide whether to proceed despite missing deps.
|
|
122
|
+
|
|
123
|
+
Returns ``True`` to continue, ``False`` if the user declined.
|
|
124
|
+
|
|
125
|
+
- If ``missing`` is empty, returns ``True``.
|
|
126
|
+
- If ``skip`` is ``True``, prints a one-line note and returns ``True``
|
|
127
|
+
without prompting.
|
|
128
|
+
- If stdin is not a TTY (e.g. CI, piped input), prints a one-line
|
|
129
|
+
note and returns ``True`` without prompting so automation doesn't
|
|
130
|
+
hang.
|
|
131
|
+
- Otherwise asks the user with :func:`typer.confirm`.
|
|
132
|
+
"""
|
|
133
|
+
if not missing:
|
|
134
|
+
return True
|
|
135
|
+
|
|
136
|
+
format_missing_report(missing, console)
|
|
137
|
+
|
|
138
|
+
if skip:
|
|
139
|
+
console.print(
|
|
140
|
+
"[dim]Dependency check bypassed via --skip-dep-check; "
|
|
141
|
+
"continuing anyway.[/dim]\n"
|
|
142
|
+
)
|
|
143
|
+
return True
|
|
144
|
+
|
|
145
|
+
if stdin_is_tty is None:
|
|
146
|
+
stdin_is_tty = sys.stdin.isatty()
|
|
147
|
+
|
|
148
|
+
if not stdin_is_tty:
|
|
149
|
+
console.print(
|
|
150
|
+
"[dim]Non-interactive session (stdin is not a TTY); "
|
|
151
|
+
"continuing without prompting. "
|
|
152
|
+
"Install the tools above before running the slash commands.[/dim]\n"
|
|
153
|
+
)
|
|
154
|
+
return True
|
|
155
|
+
|
|
156
|
+
# Imported lazily to keep this module importable in environments
|
|
157
|
+
# that only need check_dependencies (e.g. tests or custom scripts).
|
|
158
|
+
import typer
|
|
159
|
+
|
|
160
|
+
return typer.confirm(
|
|
161
|
+
"Continue with issue-flow setup anyway?", default=False
|
|
162
|
+
)
|