feature-flow-cli 0.1.1__tar.gz → 0.1.2__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.
- {feature_flow_cli-0.1.1/feature_flow_cli.egg-info → feature_flow_cli-0.1.2}/PKG-INFO +3 -1
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/README.md +2 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/adapters/codex/feature-flow/SKILL.md +1 -1
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow/__init__.py +1 -1
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow/conductor.py +4 -2
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow/git.py +28 -2
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow/install.py +32 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2/feature_flow_cli.egg-info}/PKG-INFO +3 -1
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/guides/build.md +1 -1
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/skills/feature-flow/SKILL.md +1 -1
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/LICENSE +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/MANIFEST.in +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/adapters/codex/feature-flow/agents/openai.yaml +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/agents/feature-planner.md +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/agents/plan-reviewer.md +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/agents/ticket-builder.md +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/agents/ticket-reviewer.md +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow/__main__.py +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow/checks.py +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow/cli.py +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow/command.py +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow/floorguard.py +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow/gate.py +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow/prompts.py +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow/state.py +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow/status.py +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow/tickets.py +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow/view.py +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow_cli.egg-info/SOURCES.txt +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow_cli.egg-info/dependency_links.txt +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow_cli.egg-info/entry_points.txt +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow_cli.egg-info/top_level.txt +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/guides/brief.md +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/guides/plan-review.md +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/guides/plan.md +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/guides/review.md +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/guides/show.md +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/guides/templates/commands.md +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/guides/templates/learnings.md +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/guides/templates/map.md +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/guides/templates/spec.md +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/guides/templates/ticket.md +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/guides/templates/ui-mockup.md +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/install.py +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/install.sh +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/pyproject.toml +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/scripts/floor-guard.py +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/scripts/flow-status.py +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/scripts/flow-view.html +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/scripts/flow-view.py +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/scripts/flow.py +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/scripts/gate.py +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/setup.cfg +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/skills/architect-review/SKILL.md +0 -0
- {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/skills/automation-design/SKILL.md +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: feature-flow-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: A ticket-graph workflow for coding agents: installs the feature-flow skill into a repo
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Project-URL: Homepage, https://github.com/hamilton-sky/feature-flow
|
|
@@ -53,6 +53,8 @@ uvx feature-flow-cli install /path/to/your/repo --agent all # or: pipx run fea
|
|
|
53
53
|
|
|
54
54
|
The package puts a `feature-flow` command on your PATH with `install`, `status <feature>` and `view <feature>`. It installs the same files, byte for byte, as `install.py` from a clone.
|
|
55
55
|
|
|
56
|
+
The installer lists what it wrote in `.feature-flow/installed.txt`. Commit those files (`git add --pathspec-from-file=.feature-flow/installed.txt`); until you do, the flow does not count them as uncommitted changes.
|
|
57
|
+
|
|
56
58
|
Then, in your repo, in the agent:
|
|
57
59
|
|
|
58
60
|
| | Claude Code | Codex |
|
|
@@ -34,6 +34,8 @@ uvx feature-flow-cli install /path/to/your/repo --agent all # or: pipx run fea
|
|
|
34
34
|
|
|
35
35
|
The package puts a `feature-flow` command on your PATH with `install`, `status <feature>` and `view <feature>`. It installs the same files, byte for byte, as `install.py` from a clone.
|
|
36
36
|
|
|
37
|
+
The installer lists what it wrote in `.feature-flow/installed.txt`. Commit those files (`git add --pathspec-from-file=.feature-flow/installed.txt`); until you do, the flow does not count them as uncommitted changes.
|
|
38
|
+
|
|
37
39
|
Then, in your repo, in the agent:
|
|
38
40
|
|
|
39
41
|
| | Claude Code | Codex |
|
|
@@ -31,7 +31,7 @@ To add tickets to a plan that exists, edit it by hand following the ticket rules
|
|
|
31
31
|
|
|
32
32
|
With a plan present, check these before `start`, and stop at the first that fails:
|
|
33
33
|
|
|
34
|
-
- `git status --porcelain` is empty.
|
|
34
|
+
- `git status --porcelain` is empty, apart from untracked files listed in `.feature-flow/installed.txt`: those are feature-flow's own install, so never stop for them. Suggest committing them (`git add --pathspec-from-file=.feature-flow/installed.txt && git commit -m "chore: install feature-flow"`) and carry on.
|
|
35
35
|
- `python3 scripts/flow-status.py <feature> --check` prints `OK`.
|
|
36
36
|
- `.agents/flow-roles/ticket-builder.md` and `.agents/flow-roles/ticket-reviewer.md` exist. If not, say to run `uvx feature-flow-cli install . --agent codex` in this repo (or `python3 install.py <repo> --agent codex` from a feature-flow clone).
|
|
37
37
|
|
|
@@ -161,8 +161,10 @@ class Conductor:
|
|
|
161
161
|
check = checks.flow_status(self.scripts, self.feature, "--check")
|
|
162
162
|
if not check.ok:
|
|
163
163
|
raise Stop("ticket check failed, fix the tickets first")
|
|
164
|
-
|
|
165
|
-
|
|
164
|
+
dirty = git.changes()
|
|
165
|
+
if dirty:
|
|
166
|
+
raise Stop("working tree is not clean, commit or stash first: %s%s"
|
|
167
|
+
% (" ".join(dirty[:5]), " and %d more" % (len(dirty) - 5) if len(dirty) > 5 else ""))
|
|
166
168
|
nxt = checks.flow_status(self.scripts, self.feature, "--next")
|
|
167
169
|
if nxt.code == 10:
|
|
168
170
|
done = self.num("done")
|
|
@@ -30,9 +30,35 @@ def head():
|
|
|
30
30
|
return _git("rev-parse", "HEAD").stdout.strip()
|
|
31
31
|
|
|
32
32
|
|
|
33
|
+
def changes():
|
|
34
|
+
"""Every changed path, untracked files included, as `git status --porcelain` sees them, except
|
|
35
|
+
the untracked files feature-flow's installer wrote: an install not committed yet is not a change."""
|
|
36
|
+
installed = set()
|
|
37
|
+
top = toplevel()
|
|
38
|
+
if top is not None:
|
|
39
|
+
try:
|
|
40
|
+
installed = set((top / ".feature-flow" / "installed.txt").read_text(encoding="utf-8").splitlines())
|
|
41
|
+
except (OSError, UnicodeDecodeError):
|
|
42
|
+
pass
|
|
43
|
+
entries = _git("status", "--porcelain", "-z", "-uall").stdout.split("\0")
|
|
44
|
+
found = []
|
|
45
|
+
i = 0
|
|
46
|
+
while i < len(entries):
|
|
47
|
+
entry = entries[i]
|
|
48
|
+
i += 1
|
|
49
|
+
if len(entry) < 4:
|
|
50
|
+
continue
|
|
51
|
+
code, path = entry[:2], entry[3:]
|
|
52
|
+
if code[0] in "RC":
|
|
53
|
+
i += 1 # the rename's source path follows
|
|
54
|
+
if code == "??" and path in installed:
|
|
55
|
+
continue
|
|
56
|
+
found.append(path)
|
|
57
|
+
return found
|
|
58
|
+
|
|
59
|
+
|
|
33
60
|
def is_clean():
|
|
34
|
-
|
|
35
|
-
return _git("status", "--porcelain").stdout.strip() == ""
|
|
61
|
+
return not changes()
|
|
36
62
|
|
|
37
63
|
|
|
38
64
|
def tracked_clean():
|
|
@@ -39,6 +39,9 @@ BUNDLE = "_bundle"
|
|
|
39
39
|
|
|
40
40
|
# the skills this installs
|
|
41
41
|
SKILLS = ("feature-flow", "architect-review", "automation-design")
|
|
42
|
+
# the in-repo files an install wrote, one path per line, relative to the target. The conductor does not
|
|
43
|
+
# count them as a dirty tree while they are untracked, and `git add --pathspec-from-file` commits them.
|
|
44
|
+
INSTALLED = ".feature-flow/installed.txt"
|
|
42
45
|
|
|
43
46
|
# an old skill that runs the ticket script (the bash one or the Python one) or ends a review with a verdict
|
|
44
47
|
LEFTOVER = re.compile(rb"scripts/flow-status\.(?:sh|py)|REVIEW: PASS")
|
|
@@ -169,6 +172,7 @@ class Installer:
|
|
|
169
172
|
package = os.path.dirname(os.path.abspath(__file__))
|
|
170
173
|
self.package = package
|
|
171
174
|
self.added = self.updated = self.same = self.kept = 0
|
|
175
|
+
self.written = []
|
|
172
176
|
|
|
173
177
|
def place(self, file, dest, data=None):
|
|
174
178
|
"""One file: add it, replace it (--force), leave it alone (same) or keep the user's version.
|
|
@@ -177,14 +181,17 @@ class Installer:
|
|
|
177
181
|
if not os.path.exists(dest):
|
|
178
182
|
self.out(" add " + dest)
|
|
179
183
|
self.added += 1
|
|
184
|
+
self.written.append(dest)
|
|
180
185
|
if not self.dry:
|
|
181
186
|
os.makedirs(os.path.dirname(dest), exist_ok=True)
|
|
182
187
|
self._copy(file, dest, data)
|
|
183
188
|
elif new is not None and _read(dest) == new:
|
|
184
189
|
self.same += 1
|
|
190
|
+
self.written.append(dest)
|
|
185
191
|
elif self.force:
|
|
186
192
|
self.out(" update " + dest)
|
|
187
193
|
self.updated += 1
|
|
194
|
+
self.written.append(dest)
|
|
188
195
|
if not self.dry:
|
|
189
196
|
self._copy(file, dest, data)
|
|
190
197
|
else:
|
|
@@ -235,6 +242,23 @@ class Installer:
|
|
|
235
242
|
self.place(file, self.target + "/.agents/flow-roles/" + name,
|
|
236
243
|
role_body(data if data is not None else b""))
|
|
237
244
|
|
|
245
|
+
def write_installed(self):
|
|
246
|
+
"""Add this run's in-repo files to the list, keeping the earlier runs' files that still exist."""
|
|
247
|
+
path = self.target + "/" + INSTALLED
|
|
248
|
+
names = set()
|
|
249
|
+
try:
|
|
250
|
+
with open(path, encoding="utf-8") as old:
|
|
251
|
+
names.update(line.strip() for line in old)
|
|
252
|
+
except OSError:
|
|
253
|
+
pass
|
|
254
|
+
names = set(n for n in names if n and os.path.isfile(self.target + "/" + n))
|
|
255
|
+
prefix = self.target + "/"
|
|
256
|
+
names.update(dest[len(prefix):] for dest in self.written if dest.startswith(prefix))
|
|
257
|
+
names.add(INSTALLED)
|
|
258
|
+
os.makedirs(os.path.dirname(path), exist_ok=True)
|
|
259
|
+
with open(path, "w", encoding="utf-8", newline="\n") as new:
|
|
260
|
+
new.write("".join(n + "\n" for n in sorted(names)))
|
|
261
|
+
|
|
238
262
|
def report_leftovers(self, dirs):
|
|
239
263
|
"""A skill folder this installer does not own but that drives the flow (it runs the ticket
|
|
240
264
|
scripts or ends a review with a verdict) is left from an earlier version: named once, never deleted."""
|
|
@@ -270,6 +294,8 @@ class Installer:
|
|
|
270
294
|
self.copy_tree(here + "/guides", self.target + "/.feature-flow/guides")
|
|
271
295
|
self.copy_tree(here + "/agents", self.target + "/.feature-flow/agents")
|
|
272
296
|
self.copy_tree(self.package, self.target + "/.feature-flow/feature_flow", skip=BUNDLE)
|
|
297
|
+
if not self.dry:
|
|
298
|
+
self.write_installed()
|
|
273
299
|
|
|
274
300
|
self.out("")
|
|
275
301
|
verb = "would add" if self.dry else "added"
|
|
@@ -285,6 +311,12 @@ class Installer:
|
|
|
285
311
|
git = 127
|
|
286
312
|
if git != 0:
|
|
287
313
|
self.out("note: %s is not a git repository, and the flow needs one" % self.target)
|
|
314
|
+
elif self.added or self.updated:
|
|
315
|
+
git_c = ""
|
|
316
|
+
if os.path.realpath(self.target) != os.path.realpath(os.getcwd()):
|
|
317
|
+
git_c = '-C "%s" ' % self.target if " " in self.target else "-C %s " % self.target
|
|
318
|
+
self.out('next: commit the installed files: git %sadd --pathspec-from-file=%s'
|
|
319
|
+
' && git %scommit -m "chore: install feature-flow"' % (git_c, INSTALLED, git_c))
|
|
288
320
|
if not shutil.which("python3"):
|
|
289
321
|
self.out("note: install python3 (3.9 or later): scripts/flow.py needs it")
|
|
290
322
|
if agent in ("claude", "all"):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: feature-flow-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: A ticket-graph workflow for coding agents: installs the feature-flow skill into a repo
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Project-URL: Homepage, https://github.com/hamilton-sky/feature-flow
|
|
@@ -53,6 +53,8 @@ uvx feature-flow-cli install /path/to/your/repo --agent all # or: pipx run fea
|
|
|
53
53
|
|
|
54
54
|
The package puts a `feature-flow` command on your PATH with `install`, `status <feature>` and `view <feature>`. It installs the same files, byte for byte, as `install.py` from a clone.
|
|
55
55
|
|
|
56
|
+
The installer lists what it wrote in `.feature-flow/installed.txt`. Commit those files (`git add --pathspec-from-file=.feature-flow/installed.txt`); until you do, the flow does not count them as uncommitted changes.
|
|
57
|
+
|
|
56
58
|
Then, in your repo, in the agent:
|
|
57
59
|
|
|
58
60
|
| | Claude Code | Codex |
|
|
@@ -12,7 +12,7 @@ Follow the repo's documented ticket location if it has one. Otherwise they are i
|
|
|
12
12
|
|
|
13
13
|
## Step 2: Pre-flight
|
|
14
14
|
|
|
15
|
-
Run `git status --porcelain`.
|
|
15
|
+
Run `git status --porcelain`. Untracked files listed in `.feature-flow/installed.txt` are feature-flow's own install and do not count.
|
|
16
16
|
|
|
17
17
|
- Clean: continue.
|
|
18
18
|
- Dirty, manual: show the files and offer to commit, stash, or continue anyway.
|
|
@@ -31,7 +31,7 @@ To add tickets to a plan that exists, edit it by hand following the ticket rules
|
|
|
31
31
|
|
|
32
32
|
With a plan present, check these before `start`, and stop at the first that fails:
|
|
33
33
|
|
|
34
|
-
- `git status --porcelain` is empty.
|
|
34
|
+
- `git status --porcelain` is empty, apart from untracked files listed in `.feature-flow/installed.txt`: those are feature-flow's own install, so never stop for them. Suggest committing them (`git add --pathspec-from-file=.feature-flow/installed.txt && git commit -m "chore: install feature-flow"`) and carry on.
|
|
35
35
|
- `python3 scripts/flow-status.py <feature> --check` prints `OK`.
|
|
36
36
|
- `ticket-builder.md` and `ticket-reviewer.md` are in `.claude/agents/`, `~/.claude/agents/`, or `$CLAUDE_HOME/agents/` when `CLAUDE_HOME` is set. If not, say to run `uvx feature-flow-cli install .` in this repo (or `python3 install.py <repo>` from a feature-flow clone).
|
|
37
37
|
|
|
File without changes
|
|
File without changes
|
{feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/adapters/codex/feature-flow/agents/openai.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow_cli.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow_cli.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|