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.
Files changed (55) hide show
  1. {feature_flow_cli-0.1.1/feature_flow_cli.egg-info → feature_flow_cli-0.1.2}/PKG-INFO +3 -1
  2. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/README.md +2 -0
  3. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/adapters/codex/feature-flow/SKILL.md +1 -1
  4. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow/__init__.py +1 -1
  5. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow/conductor.py +4 -2
  6. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow/git.py +28 -2
  7. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow/install.py +32 -0
  8. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2/feature_flow_cli.egg-info}/PKG-INFO +3 -1
  9. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/guides/build.md +1 -1
  10. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/skills/feature-flow/SKILL.md +1 -1
  11. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/LICENSE +0 -0
  12. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/MANIFEST.in +0 -0
  13. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/adapters/codex/feature-flow/agents/openai.yaml +0 -0
  14. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/agents/feature-planner.md +0 -0
  15. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/agents/plan-reviewer.md +0 -0
  16. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/agents/ticket-builder.md +0 -0
  17. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/agents/ticket-reviewer.md +0 -0
  18. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow/__main__.py +0 -0
  19. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow/checks.py +0 -0
  20. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow/cli.py +0 -0
  21. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow/command.py +0 -0
  22. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow/floorguard.py +0 -0
  23. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow/gate.py +0 -0
  24. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow/prompts.py +0 -0
  25. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow/state.py +0 -0
  26. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow/status.py +0 -0
  27. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow/tickets.py +0 -0
  28. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow/view.py +0 -0
  29. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow_cli.egg-info/SOURCES.txt +0 -0
  30. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow_cli.egg-info/dependency_links.txt +0 -0
  31. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow_cli.egg-info/entry_points.txt +0 -0
  32. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/feature_flow_cli.egg-info/top_level.txt +0 -0
  33. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/guides/brief.md +0 -0
  34. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/guides/plan-review.md +0 -0
  35. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/guides/plan.md +0 -0
  36. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/guides/review.md +0 -0
  37. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/guides/show.md +0 -0
  38. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/guides/templates/commands.md +0 -0
  39. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/guides/templates/learnings.md +0 -0
  40. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/guides/templates/map.md +0 -0
  41. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/guides/templates/spec.md +0 -0
  42. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/guides/templates/ticket.md +0 -0
  43. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/guides/templates/ui-mockup.md +0 -0
  44. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/install.py +0 -0
  45. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/install.sh +0 -0
  46. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/pyproject.toml +0 -0
  47. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/scripts/floor-guard.py +0 -0
  48. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/scripts/flow-status.py +0 -0
  49. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/scripts/flow-view.html +0 -0
  50. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/scripts/flow-view.py +0 -0
  51. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/scripts/flow.py +0 -0
  52. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/scripts/gate.py +0 -0
  53. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/setup.cfg +0 -0
  54. {feature_flow_cli-0.1.1 → feature_flow_cli-0.1.2}/skills/architect-review/SKILL.md +0 -0
  55. {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.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
 
@@ -1,3 +1,3 @@
1
1
  """Feature Flow: a ticket-graph workflow for coding agents."""
2
2
 
3
- __version__ = "0.1.1"
3
+ __version__ = "0.1.2"
@@ -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
- if not git.is_clean():
165
- raise Stop("working tree is not clean, commit or stash first")
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
- """No change at all, untracked files included, as `git status --porcelain` sees it."""
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.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