flow-cc 0.1.1 → 0.3.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/CHANGELOG.md +63 -0
- package/CONTRIBUTING.md +59 -0
- package/README.md +17 -7
- package/VERSION +1 -1
- package/bin/install.js +253 -62
- package/hooks/flow-check-update.js +80 -33
- package/hooks/flow-statusline.js +30 -3
- package/package.json +7 -2
- package/skills/flow-done.md +3 -1
- package/skills/flow-go.md +38 -6
- package/skills/flow-intro.md +14 -7
- package/skills/flow-milestone.md +67 -0
- package/skills/{flow-init.md → flow-setup.md} +13 -60
- package/skills/flow-spec.md +18 -2
- package/skills/flow-status.md +3 -3
- package/skills/flow-task.md +1 -1
- package/skills/flow-update.md +11 -2
- package/templates/STATE.md.template +1 -1
- package/templates/lessons.md.template +10 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.3.0] - 2026-02-11
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- `/flow:setup` command — replaces `/flow:init` for project scaffolding only. Adds overwrite protection (stops if project already initialized).
|
|
12
|
+
- `/flow:milestone` command — extracted from `/flow:init` for milestone transitions. Adds guard for pending phases before archiving.
|
|
13
|
+
- Codebase scan exclusions in `/flow:spec` — explicitly excludes `node_modules/`, `.git/`, `dist/`, `build/`, `.next/`, `__pycache__/`, `*.min.js`, `*.map`, `*.lock`. Uses targeted glob patterns instead of bare `**/*`.
|
|
14
|
+
- Minimum viable PRD check in `/flow:spec` — validates at least 3 user stories, 1 phase, and 1 verification command before finalizing.
|
|
15
|
+
- Agent timeout + progress indicators in `/flow:go` — prints wave spawn/completion status, checks stuck agents after 10 minutes.
|
|
16
|
+
- Max retry limit (3 attempts) for verification in `/flow:go` — stops after 3 failures with user options instead of looping forever.
|
|
17
|
+
- Wave failure handling in `/flow:go` — detects all-failed vs partial-failed waves, asks user how to proceed.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
- `/flow:init` split into `/flow:setup` (project scaffolding) and `/flow:milestone` (milestone transitions)
|
|
21
|
+
- Skill count: 9 skills (was 8 — setup replaces init, milestone is new)
|
|
22
|
+
- All cross-references updated: intro, done, status, go, task, README, install.js, DESIGN.md, templates
|
|
23
|
+
|
|
24
|
+
### Removed
|
|
25
|
+
- `/flow:init` command — replaced by `/flow:setup` and `/flow:milestone`
|
|
26
|
+
|
|
27
|
+
## [0.2.0] - 2026-02-11
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
- `CHANGELOG.md` in Keep a Changelog format
|
|
31
|
+
- `CONTRIBUTING.md` with skill file format docs and testing expectations
|
|
32
|
+
- Example lesson in `templates/lessons.md.template` showing PATTERN/CAUSE/FIX/RULE format
|
|
33
|
+
- Node.js version check (requires >= 18) with clear error message
|
|
34
|
+
- Write permission check before install starts
|
|
35
|
+
- Rollback on install failure — tracks created files and cleans up
|
|
36
|
+
- Post-install verification — checks key files exist after copy
|
|
37
|
+
- `--verify` flag for install health check without modifying anything
|
|
38
|
+
- `engines` field in package.json (`node >= 18`)
|
|
39
|
+
- Error logging for hooks — writes to `~/.claude/hooks/flow-error.log` (capped at 50KB)
|
|
40
|
+
- Context size limits in `/flow:spec` — caps codebase scan at 50 files, focused mode for 500+ file repos
|
|
41
|
+
|
|
42
|
+
### Fixed
|
|
43
|
+
- `.gitignore` now has proper Node.js entries (was just `nul`)
|
|
44
|
+
- `/flow:done` archive step now creates `.planning/archive/` if missing and skips gracefully when no `.planning/` exists
|
|
45
|
+
- `/flow:update` now shows changelog for the new version before confirming update
|
|
46
|
+
|
|
47
|
+
## [0.1.1] - 2025-05-01
|
|
48
|
+
|
|
49
|
+
### Changed
|
|
50
|
+
- Updated package.json metadata (description, keywords, repository links)
|
|
51
|
+
- Polished README with badges and install instructions
|
|
52
|
+
- Added MIT license file
|
|
53
|
+
|
|
54
|
+
## [0.1.0] - 2025-05-01
|
|
55
|
+
|
|
56
|
+
### Added
|
|
57
|
+
- Initial release of Flow plugin for Claude Code
|
|
58
|
+
- 8 skills: init, spec, go, done, status, task, intro, update
|
|
59
|
+
- 2 hooks: statusline display, background update checker
|
|
60
|
+
- 4 templates: CLAUDE.md, STATE.md, ROADMAP.md, lessons.md
|
|
61
|
+
- One-command installer via `npx flow-cc`
|
|
62
|
+
- Automatic statusLine configuration
|
|
63
|
+
- Uninstall support via `npx flow-cc --uninstall`
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Contributing to Flow
|
|
2
|
+
|
|
3
|
+
Thanks for your interest in contributing! Flow is a structured workflow system for Claude Code, and contributions are welcome.
|
|
4
|
+
|
|
5
|
+
## Reporting Bugs
|
|
6
|
+
|
|
7
|
+
Open an issue at [github.com/troyhoffman-oss/flow-plugin/issues](https://github.com/troyhoffman-oss/flow-plugin/issues) with:
|
|
8
|
+
|
|
9
|
+
- Steps to reproduce
|
|
10
|
+
- Expected vs. actual behavior
|
|
11
|
+
- Your OS and Node.js version
|
|
12
|
+
- Claude Code version (if relevant)
|
|
13
|
+
|
|
14
|
+
## Suggesting Features
|
|
15
|
+
|
|
16
|
+
Open an issue with the `enhancement` label. Describe:
|
|
17
|
+
|
|
18
|
+
- The problem you're trying to solve
|
|
19
|
+
- Your proposed solution
|
|
20
|
+
- Any alternatives you've considered
|
|
21
|
+
|
|
22
|
+
## Submitting Pull Requests
|
|
23
|
+
|
|
24
|
+
1. Fork the repo and create a branch from `master`
|
|
25
|
+
2. Make your changes
|
|
26
|
+
3. Test the installer: `node bin/install.js` from the repo root
|
|
27
|
+
4. Verify skills load in Claude Code (run `/flow:intro`)
|
|
28
|
+
5. Open a PR with a clear description of what changed and why
|
|
29
|
+
|
|
30
|
+
### Skill File Format
|
|
31
|
+
|
|
32
|
+
Skills live in `skills/` as Markdown files with YAML frontmatter:
|
|
33
|
+
|
|
34
|
+
```markdown
|
|
35
|
+
---
|
|
36
|
+
name: flow:example
|
|
37
|
+
description: One-line description
|
|
38
|
+
user_invocable: true
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
# /flow:example — Title
|
|
42
|
+
|
|
43
|
+
Instructions for Claude Code to follow when this skill is invoked.
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Testing Expectations
|
|
47
|
+
|
|
48
|
+
- Run `node bin/install.js` and verify all files land in `~/.claude/`
|
|
49
|
+
- Run `node bin/install.js --uninstall` and verify clean removal
|
|
50
|
+
- Run `node bin/install.js --verify` to check install health
|
|
51
|
+
- Test on both Windows and macOS/Linux if possible
|
|
52
|
+
|
|
53
|
+
## Architecture
|
|
54
|
+
|
|
55
|
+
See [DESIGN.md](DESIGN.md) for architecture decisions and system design.
|
|
56
|
+
|
|
57
|
+
## Code of Conduct
|
|
58
|
+
|
|
59
|
+
Be kind, constructive, and respectful. We're all here to build better tools.
|
package/README.md
CHANGED
|
@@ -35,7 +35,8 @@ Flow fixes this by giving Claude Code a **memory system and execution framework*
|
|
|
35
35
|
| Command | What it does |
|
|
36
36
|
|---|---|
|
|
37
37
|
| `/flow:intro` | Walkthrough of the system — **start here** |
|
|
38
|
-
| `/flow:
|
|
38
|
+
| `/flow:setup` | Set up a new project with `.planning/` scaffolding, CLAUDE.md, templates |
|
|
39
|
+
| `/flow:milestone` | Archive completed milestone and start a new one |
|
|
39
40
|
| `/flow:spec` | Spec interview that produces an executable PRD with phased execution plan |
|
|
40
41
|
| `/flow:go` | Execute the next phase from the PRD using wave-based agent teams |
|
|
41
42
|
| `/flow:task` | Bug fixes, cleanup, small features — no PRD needed |
|
|
@@ -46,16 +47,18 @@ Flow fixes this by giving Claude Code a **memory system and execution framework*
|
|
|
46
47
|
## How It Works
|
|
47
48
|
|
|
48
49
|
```
|
|
49
|
-
/flow:
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
/flow:setup → /flow:spec → /flow:go (repeat per phase) → /flow:done
|
|
51
|
+
↓
|
|
52
|
+
handoff prompt for next session
|
|
53
|
+
↓
|
|
54
|
+
/flow:milestone → next cycle
|
|
52
55
|
|
|
53
56
|
/flow:task ← standalone path for bug fixes and small features
|
|
54
57
|
```
|
|
55
58
|
|
|
56
59
|
**The lifecycle in practice:**
|
|
57
60
|
|
|
58
|
-
1. **`/flow:
|
|
61
|
+
1. **`/flow:setup`** — Creates `.planning/` directory, CLAUDE.md, STATE.md, ROADMAP.md, lessons.md
|
|
59
62
|
2. **`/flow:spec`** — Interviews you about the milestone. Produces a PRD with wave-based phases, acceptance criteria, and agent-team structure
|
|
60
63
|
3. **`/flow:go`** — Reads the PRD, spawns parallel agent teams per wave, builds, verifies, commits
|
|
61
64
|
4. **`/flow:done`** — Updates all planning docs, captures lessons, generates a one-line handoff prompt so the next session starts instantly
|
|
@@ -66,7 +69,8 @@ Flow fixes this by giving Claude Code a **memory system and execution framework*
|
|
|
66
69
|
```
|
|
67
70
|
~/.claude/
|
|
68
71
|
├── commands/flow/
|
|
69
|
-
│ ├── flow-
|
|
72
|
+
│ ├── flow-setup.md # 9 skill files
|
|
73
|
+
│ ├── flow-milestone.md
|
|
70
74
|
│ ├── flow-spec.md
|
|
71
75
|
│ ├── flow-go.md
|
|
72
76
|
│ ├── flow-task.md
|
|
@@ -88,7 +92,7 @@ Flow fixes this by giving Claude Code a **memory system and execution framework*
|
|
|
88
92
|
|
|
89
93
|
## Project Structure
|
|
90
94
|
|
|
91
|
-
Every Flow project gets this structure via `/flow:
|
|
95
|
+
Every Flow project gets this structure via `/flow:setup`:
|
|
92
96
|
|
|
93
97
|
```
|
|
94
98
|
your-project/
|
|
@@ -121,6 +125,12 @@ Flow uses the same `.planning/` directory structure as [GSD](https://github.com/
|
|
|
121
125
|
|
|
122
126
|
[Claude Code](https://docs.anthropic.com/en/docs/claude-code) CLI with skills support.
|
|
123
127
|
|
|
128
|
+
## Links
|
|
129
|
+
|
|
130
|
+
- [Changelog](CHANGELOG.md) — what changed in each version
|
|
131
|
+
- [Contributing](CONTRIBUTING.md) — how to report bugs, suggest features, submit PRs
|
|
132
|
+
- [Design](DESIGN.md) — architecture decisions and system design
|
|
133
|
+
|
|
124
134
|
## License
|
|
125
135
|
|
|
126
136
|
MIT
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.3.0
|
package/bin/install.js
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
// Flow plugin installer for Claude Code
|
|
3
|
-
// Usage: npx flow-cc [--uninstall]
|
|
3
|
+
// Usage: npx flow-cc [--uninstall] [--verify]
|
|
4
4
|
|
|
5
5
|
const fs = require('fs');
|
|
6
6
|
const path = require('path');
|
|
7
7
|
const os = require('os');
|
|
8
8
|
|
|
9
|
+
// ---------- Node.js version check ----------
|
|
10
|
+
const nodeMajor = parseInt(process.versions.node.split('.')[0], 10);
|
|
11
|
+
if (nodeMajor < 18) {
|
|
12
|
+
console.error('Flow requires Node.js 18 or later. You have ' + process.version);
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
|
|
9
16
|
const homeDir = os.homedir();
|
|
10
17
|
const claudeDir = path.join(homeDir, '.claude');
|
|
11
18
|
const commandsDir = path.join(claudeDir, 'commands', 'flow');
|
|
@@ -21,6 +28,93 @@ const templatesDir = path.join(pkgRoot, 'templates');
|
|
|
21
28
|
const versionFile = path.join(pkgRoot, 'VERSION');
|
|
22
29
|
|
|
23
30
|
const uninstall = process.argv.includes('--uninstall') || process.argv.includes('-u');
|
|
31
|
+
const verify = process.argv.includes('--verify') || process.argv.includes('-v');
|
|
32
|
+
|
|
33
|
+
// ---------- Verify ----------
|
|
34
|
+
if (verify) {
|
|
35
|
+
console.log('Flow install health check:\n');
|
|
36
|
+
|
|
37
|
+
let passed = 0;
|
|
38
|
+
const total = 5;
|
|
39
|
+
|
|
40
|
+
// 1. Skills installed
|
|
41
|
+
try {
|
|
42
|
+
const files = fs.existsSync(commandsDir)
|
|
43
|
+
? fs.readdirSync(commandsDir).filter(f => f.endsWith('.md'))
|
|
44
|
+
: [];
|
|
45
|
+
if (files.length > 0) {
|
|
46
|
+
console.log(` \u2713 Skills installed (${files.length} files)`);
|
|
47
|
+
passed++;
|
|
48
|
+
} else {
|
|
49
|
+
console.log(' \u2717 Skills not installed (0 .md files in commands/flow/)');
|
|
50
|
+
}
|
|
51
|
+
} catch (e) {
|
|
52
|
+
console.log(' \u2717 Skills not installed (cannot read commands/flow/)');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// 2. Hooks installed
|
|
56
|
+
try {
|
|
57
|
+
const hookFiles = ['flow-check-update.js', 'flow-statusline.js'];
|
|
58
|
+
const found = hookFiles.filter(h => fs.existsSync(path.join(hooksDir, h)));
|
|
59
|
+
if (found.length === 2) {
|
|
60
|
+
console.log(' \u2713 Hooks installed (2 files)');
|
|
61
|
+
passed++;
|
|
62
|
+
} else {
|
|
63
|
+
console.log(` \u2717 Hooks incomplete (${found.length}/2 files)`);
|
|
64
|
+
}
|
|
65
|
+
} catch (e) {
|
|
66
|
+
console.log(' \u2717 Hooks not installed');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// 3. VERSION file
|
|
70
|
+
try {
|
|
71
|
+
const vPath = path.join(commandsDir, 'VERSION');
|
|
72
|
+
if (fs.existsSync(vPath)) {
|
|
73
|
+
const ver = fs.readFileSync(vPath, 'utf8').trim();
|
|
74
|
+
console.log(` \u2713 VERSION file present (${ver})`);
|
|
75
|
+
passed++;
|
|
76
|
+
} else {
|
|
77
|
+
console.log(' \u2717 VERSION file missing');
|
|
78
|
+
}
|
|
79
|
+
} catch (e) {
|
|
80
|
+
console.log(' \u2717 VERSION file missing');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// 4. Templates installed
|
|
84
|
+
try {
|
|
85
|
+
const tDir = path.join(commandsDir, 'templates');
|
|
86
|
+
const files = fs.existsSync(tDir) ? fs.readdirSync(tDir) : [];
|
|
87
|
+
if (files.length > 0) {
|
|
88
|
+
console.log(` \u2713 Templates installed (${files.length} files)`);
|
|
89
|
+
passed++;
|
|
90
|
+
} else {
|
|
91
|
+
console.log(' \u2717 Templates not installed (0 files)');
|
|
92
|
+
}
|
|
93
|
+
} catch (e) {
|
|
94
|
+
console.log(' \u2717 Templates not installed');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// 5. StatusLine configured
|
|
98
|
+
try {
|
|
99
|
+
if (fs.existsSync(settingsPath)) {
|
|
100
|
+
const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
|
|
101
|
+
if (settings.statusLine && typeof settings.statusLine.command === 'string' &&
|
|
102
|
+
settings.statusLine.command.includes('flow-statusline')) {
|
|
103
|
+
console.log(' \u2713 StatusLine configured');
|
|
104
|
+
passed++;
|
|
105
|
+
} else {
|
|
106
|
+
console.log(' \u2717 StatusLine not configured');
|
|
107
|
+
}
|
|
108
|
+
} else {
|
|
109
|
+
console.log(' \u2717 StatusLine not configured (no settings.json)');
|
|
110
|
+
}
|
|
111
|
+
} catch (e) {
|
|
112
|
+
console.log(' \u2717 StatusLine not configured');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
console.log(`\nResult: ${passed}/${total} checks passed`);
|
|
116
|
+
process.exit(passed === total ? 0 : 1);
|
|
117
|
+
}
|
|
24
118
|
|
|
25
119
|
// ---------- Uninstall ----------
|
|
26
120
|
if (uninstall) {
|
|
@@ -60,7 +154,7 @@ if (uninstall) {
|
|
|
60
154
|
console.log(' Removed statusLine from ~/.claude/settings.json');
|
|
61
155
|
}
|
|
62
156
|
} catch (e) {
|
|
63
|
-
// settings.json parse error
|
|
157
|
+
// settings.json parse error -- leave it alone
|
|
64
158
|
}
|
|
65
159
|
}
|
|
66
160
|
|
|
@@ -71,79 +165,176 @@ if (uninstall) {
|
|
|
71
165
|
// ---------- Install ----------
|
|
72
166
|
console.log('Installing Flow plugin...\n');
|
|
73
167
|
|
|
74
|
-
//
|
|
75
|
-
|
|
76
|
-
|
|
168
|
+
// ---------- Write permission check ----------
|
|
169
|
+
const permTestDir = fs.existsSync(claudeDir) ? claudeDir : path.dirname(claudeDir);
|
|
170
|
+
const permTestFile = path.join(permTestDir, '.flow-perm-test-' + process.pid);
|
|
171
|
+
try {
|
|
172
|
+
fs.writeFileSync(permTestFile, 'test');
|
|
173
|
+
fs.unlinkSync(permTestFile);
|
|
174
|
+
} catch (e) {
|
|
175
|
+
console.error('Cannot write to ' + claudeDir + ' \u2014 check permissions.');
|
|
176
|
+
process.exit(1);
|
|
77
177
|
}
|
|
78
178
|
|
|
79
|
-
//
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
179
|
+
// ---------- Rollback tracking ----------
|
|
180
|
+
const created = []; // paths created during install (files and dirs we created fresh)
|
|
181
|
+
|
|
182
|
+
function trackFile(filePath) {
|
|
183
|
+
created.push({ type: 'file', path: filePath });
|
|
84
184
|
}
|
|
85
|
-
console.log(` Installed ${skillFiles.length} skills → ~/.claude/commands/flow/`);
|
|
86
185
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
if (fs.existsSync(src)) {
|
|
92
|
-
fs.copyFileSync(src, path.join(hooksDir, hook));
|
|
186
|
+
function trackDir(dirPath) {
|
|
187
|
+
// Only track if we actually created it (didn't exist before)
|
|
188
|
+
if (!fs.existsSync(dirPath)) {
|
|
189
|
+
created.push({ type: 'dir', path: dirPath });
|
|
93
190
|
}
|
|
94
191
|
}
|
|
95
|
-
console.log(' Installed hooks → ~/.claude/hooks/');
|
|
96
192
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
fs.
|
|
104
|
-
if (fs.existsSync(
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
193
|
+
function rollback() {
|
|
194
|
+
console.error('\nRolling back partial install...');
|
|
195
|
+
for (let i = created.length - 1; i >= 0; i--) {
|
|
196
|
+
const item = created[i];
|
|
197
|
+
try {
|
|
198
|
+
if (item.type === 'file' && fs.existsSync(item.path)) {
|
|
199
|
+
fs.unlinkSync(item.path);
|
|
200
|
+
} else if (item.type === 'dir' && fs.existsSync(item.path)) {
|
|
201
|
+
fs.rmSync(item.path, { recursive: true });
|
|
202
|
+
}
|
|
203
|
+
} catch (e) {
|
|
204
|
+
// Best-effort cleanup
|
|
205
|
+
}
|
|
108
206
|
}
|
|
109
|
-
console.
|
|
207
|
+
console.error('Rollback complete.');
|
|
110
208
|
}
|
|
111
209
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
} catch (e) {
|
|
118
|
-
// Corrupted settings — start fresh but warn
|
|
119
|
-
console.log(' Warning: could not parse existing settings.json, preserving as backup');
|
|
120
|
-
fs.copyFileSync(settingsPath, settingsPath + '.bak');
|
|
210
|
+
try {
|
|
211
|
+
// 1. Create directories
|
|
212
|
+
for (const dir of [commandsDir, hooksDir, cacheDir]) {
|
|
213
|
+
trackDir(dir);
|
|
214
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
121
215
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
//
|
|
134
|
-
const
|
|
135
|
-
|
|
216
|
+
|
|
217
|
+
// 2. Copy skills: skills/flow-*.md -> commands/flow/*.md (strip "flow-" prefix)
|
|
218
|
+
const skillFiles = fs.readdirSync(skillsDir).filter(f => f.startsWith('flow-') && f.endsWith('.md'));
|
|
219
|
+
for (const file of skillFiles) {
|
|
220
|
+
const dest = file.replace(/^flow-/, '');
|
|
221
|
+
const destPath = path.join(commandsDir, dest);
|
|
222
|
+
fs.copyFileSync(path.join(skillsDir, file), destPath);
|
|
223
|
+
trackFile(destPath);
|
|
224
|
+
}
|
|
225
|
+
console.log(` Installed ${skillFiles.length} skills \u2192 ~/.claude/commands/flow/`);
|
|
226
|
+
|
|
227
|
+
// 3. Copy hooks
|
|
228
|
+
const hookFiles = ['flow-check-update.js', 'flow-statusline.js'];
|
|
229
|
+
for (const hook of hookFiles) {
|
|
230
|
+
const src = path.join(srcHooksDir, hook);
|
|
231
|
+
if (fs.existsSync(src)) {
|
|
232
|
+
const destPath = path.join(hooksDir, hook);
|
|
233
|
+
fs.copyFileSync(src, destPath);
|
|
234
|
+
trackFile(destPath);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
console.log(' Installed hooks \u2192 ~/.claude/hooks/');
|
|
238
|
+
|
|
239
|
+
// 4. Copy VERSION
|
|
240
|
+
const versionDest = path.join(commandsDir, 'VERSION');
|
|
241
|
+
fs.copyFileSync(versionFile, versionDest);
|
|
242
|
+
trackFile(versionDest);
|
|
243
|
+
console.log(' Installed VERSION \u2192 ~/.claude/commands/flow/VERSION');
|
|
244
|
+
|
|
245
|
+
// 5. Copy templates
|
|
246
|
+
const destTemplatesDir = path.join(commandsDir, 'templates');
|
|
247
|
+
trackDir(destTemplatesDir);
|
|
248
|
+
fs.mkdirSync(destTemplatesDir, { recursive: true });
|
|
249
|
+
if (fs.existsSync(templatesDir)) {
|
|
250
|
+
const templateFiles = fs.readdirSync(templatesDir);
|
|
251
|
+
for (const file of templateFiles) {
|
|
252
|
+
const destPath = path.join(destTemplatesDir, file);
|
|
253
|
+
fs.copyFileSync(path.join(templatesDir, file), destPath);
|
|
254
|
+
trackFile(destPath);
|
|
255
|
+
}
|
|
256
|
+
console.log(` Installed ${templateFiles.length} templates \u2192 ~/.claude/commands/flow/templates/`);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// 6. Merge statusLine into settings.json
|
|
260
|
+
let settings = {};
|
|
261
|
+
if (fs.existsSync(settingsPath)) {
|
|
262
|
+
try {
|
|
263
|
+
settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
|
|
264
|
+
} catch (e) {
|
|
265
|
+
// Corrupted settings -- start fresh but warn
|
|
266
|
+
console.log(' Warning: could not parse existing settings.json, preserving as backup');
|
|
267
|
+
fs.copyFileSync(settingsPath, settingsPath + '.bak');
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
settings.statusLine = {
|
|
271
|
+
type: 'command',
|
|
272
|
+
command: `node "${path.join(hooksDir, 'flow-statusline.js')}"`
|
|
273
|
+
};
|
|
274
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
|
|
275
|
+
trackFile(settingsPath);
|
|
276
|
+
console.log(' Configured statusLine in ~/.claude/settings.json');
|
|
277
|
+
|
|
278
|
+
// 7. Write .source breadcrumb (for dev/setup.sh compat)
|
|
279
|
+
const sourcePath = path.join(commandsDir, '.source');
|
|
280
|
+
fs.writeFileSync(sourcePath, pkgRoot + '\n');
|
|
281
|
+
trackFile(sourcePath);
|
|
282
|
+
|
|
283
|
+
// ---------- Post-install verification ----------
|
|
284
|
+
let warnings = 0;
|
|
285
|
+
|
|
286
|
+
// Check: at least 1 file in commandsDir
|
|
287
|
+
const installedSkills = fs.readdirSync(commandsDir).filter(f => f.endsWith('.md'));
|
|
288
|
+
if (installedSkills.length === 0) {
|
|
289
|
+
console.log(' Warning: no skill files found in commands/flow/');
|
|
290
|
+
warnings++;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Check: both hook files
|
|
294
|
+
const installedHooks = hookFiles.filter(h => fs.existsSync(path.join(hooksDir, h)));
|
|
295
|
+
if (installedHooks.length < 2) {
|
|
296
|
+
console.log(` Warning: only ${installedHooks.length}/2 hook files installed`);
|
|
297
|
+
warnings++;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Check: VERSION file
|
|
301
|
+
if (!fs.existsSync(path.join(commandsDir, 'VERSION'))) {
|
|
302
|
+
console.log(' Warning: VERSION file not found after install');
|
|
303
|
+
warnings++;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Check: templates directory with at least 1 file
|
|
307
|
+
const tplDir = path.join(commandsDir, 'templates');
|
|
308
|
+
const tplFiles = fs.existsSync(tplDir) ? fs.readdirSync(tplDir) : [];
|
|
309
|
+
if (tplFiles.length === 0) {
|
|
310
|
+
console.log(' Warning: no template files found after install');
|
|
311
|
+
warnings++;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (warnings > 0) {
|
|
315
|
+
console.log(` (${warnings} verification warning${warnings > 1 ? 's' : ''} — install may be incomplete)`);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Done
|
|
319
|
+
const version = fs.readFileSync(versionFile, 'utf8').trim();
|
|
320
|
+
console.log(`
|
|
136
321
|
Flow v${version} installed successfully!
|
|
137
322
|
|
|
138
323
|
Commands available:
|
|
139
|
-
/flow:intro
|
|
140
|
-
/flow:
|
|
141
|
-
/flow:
|
|
142
|
-
/flow:
|
|
143
|
-
/flow:
|
|
144
|
-
/flow:
|
|
145
|
-
/flow:
|
|
146
|
-
/flow:
|
|
324
|
+
/flow:intro \u2014 Learn the Flow workflow
|
|
325
|
+
/flow:setup \u2014 Set up a new project
|
|
326
|
+
/flow:milestone \u2014 Start a new milestone
|
|
327
|
+
/flow:spec \u2014 Spec interview \u2192 executable PRD
|
|
328
|
+
/flow:go \u2014 Execute next phase with agent teams
|
|
329
|
+
/flow:done \u2014 Session-end documentation
|
|
330
|
+
/flow:status \u2014 Quick orientation
|
|
331
|
+
/flow:task \u2014 Lightweight task execution
|
|
332
|
+
/flow:update \u2014 Update Flow to latest version
|
|
147
333
|
|
|
148
334
|
Get started: run /flow:intro in any Claude Code session.
|
|
149
335
|
`);
|
|
336
|
+
} catch (err) {
|
|
337
|
+
rollback();
|
|
338
|
+
console.error('\nInstall failed: ' + err.message);
|
|
339
|
+
process.exit(1);
|
|
340
|
+
}
|
|
@@ -11,43 +11,90 @@ const homeDir = os.homedir();
|
|
|
11
11
|
const cacheDir = path.join(homeDir, '.claude', 'cache');
|
|
12
12
|
const cacheFile = path.join(cacheDir, 'flow-update-check.json');
|
|
13
13
|
const versionFile = path.join(homeDir, '.claude', 'commands', 'flow', 'VERSION');
|
|
14
|
+
const errorLog = path.join(homeDir, '.claude', 'hooks', 'flow-error.log');
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
function logError(context, err) {
|
|
17
|
+
try {
|
|
18
|
+
const line = `[${new Date().toISOString()}] flow-check-update: ${context}: ${err.message || err}\n`;
|
|
19
|
+
// Cap log at 50KB — truncate oldest entries
|
|
20
|
+
if (fs.existsSync(errorLog)) {
|
|
21
|
+
const stat = fs.statSync(errorLog);
|
|
22
|
+
if (stat.size > 50 * 1024) {
|
|
23
|
+
const content = fs.readFileSync(errorLog, 'utf8');
|
|
24
|
+
const lines = content.split('\n');
|
|
25
|
+
fs.writeFileSync(errorLog, lines.slice(Math.floor(lines.length / 2)).join('\n'));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
fs.appendFileSync(errorLog, line);
|
|
29
|
+
} catch (_) {
|
|
30
|
+
// Logging must never throw
|
|
31
|
+
}
|
|
18
32
|
}
|
|
19
33
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
34
|
+
try {
|
|
35
|
+
// Ensure cache directory exists
|
|
36
|
+
if (!fs.existsSync(cacheDir)) {
|
|
37
|
+
fs.mkdirSync(cacheDir, { recursive: true });
|
|
38
|
+
}
|
|
24
39
|
|
|
25
|
-
|
|
26
|
-
const
|
|
40
|
+
// Run check in background (spawn detached process, windowsHide prevents console flash)
|
|
41
|
+
const child = spawn(process.execPath, ['-e', `
|
|
42
|
+
const fs = require('fs');
|
|
43
|
+
const { execSync } = require('child_process');
|
|
27
44
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
45
|
+
const cacheFile = ${JSON.stringify(cacheFile)};
|
|
46
|
+
const versionFile = ${JSON.stringify(versionFile)};
|
|
47
|
+
const errorLog = ${JSON.stringify(errorLog)};
|
|
48
|
+
|
|
49
|
+
function logError(context, err) {
|
|
50
|
+
try {
|
|
51
|
+
const line = '[' + new Date().toISOString() + '] flow-check-update(child): ' + context + ': ' + (err.message || err) + '\\n';
|
|
52
|
+
if (fs.existsSync(errorLog)) {
|
|
53
|
+
const stat = fs.statSync(errorLog);
|
|
54
|
+
if (stat.size > 50 * 1024) {
|
|
55
|
+
const content = fs.readFileSync(errorLog, 'utf8');
|
|
56
|
+
const lines = content.split('\\n');
|
|
57
|
+
fs.writeFileSync(errorLog, lines.slice(Math.floor(lines.length / 2)).join('\\n'));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
fs.appendFileSync(errorLog, line);
|
|
61
|
+
} catch (_) {}
|
|
32
62
|
}
|
|
33
|
-
} catch (e) {}
|
|
34
63
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
64
|
+
try {
|
|
65
|
+
let installed = '0.0.0';
|
|
66
|
+
try {
|
|
67
|
+
if (fs.existsSync(versionFile)) {
|
|
68
|
+
installed = fs.readFileSync(versionFile, 'utf8').trim();
|
|
69
|
+
}
|
|
70
|
+
} catch (e) {
|
|
71
|
+
logError('read-version', e);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
let latest = null;
|
|
75
|
+
try {
|
|
76
|
+
latest = execSync('npm view flow-cc version', { encoding: 'utf8', timeout: 10000, windowsHide: true }).trim();
|
|
77
|
+
} catch (e) {
|
|
78
|
+
logError('npm-view', e);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const result = {
|
|
82
|
+
update_available: latest && installed !== latest,
|
|
83
|
+
installed,
|
|
84
|
+
latest: latest || 'unknown',
|
|
85
|
+
checked: Math.floor(Date.now() / 1000)
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
fs.writeFileSync(cacheFile, JSON.stringify(result));
|
|
89
|
+
} catch (e) {
|
|
90
|
+
logError('main', e);
|
|
91
|
+
}
|
|
92
|
+
`], {
|
|
93
|
+
stdio: 'ignore',
|
|
94
|
+
windowsHide: true
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
child.unref();
|
|
98
|
+
} catch (e) {
|
|
99
|
+
logError('spawn', e);
|
|
100
|
+
}
|
package/hooks/flow-statusline.js
CHANGED
|
@@ -7,6 +7,25 @@ const path = require('path');
|
|
|
7
7
|
const os = require('os');
|
|
8
8
|
|
|
9
9
|
const homeDir = os.homedir();
|
|
10
|
+
const errorLog = path.join(homeDir, '.claude', 'hooks', 'flow-error.log');
|
|
11
|
+
|
|
12
|
+
function logError(context, err) {
|
|
13
|
+
try {
|
|
14
|
+
const line = `[${new Date().toISOString()}] flow-statusline: ${context}: ${err.message || err}\n`;
|
|
15
|
+
// Cap log at 50KB — truncate oldest entries
|
|
16
|
+
if (fs.existsSync(errorLog)) {
|
|
17
|
+
const stat = fs.statSync(errorLog);
|
|
18
|
+
if (stat.size > 50 * 1024) {
|
|
19
|
+
const content = fs.readFileSync(errorLog, 'utf8');
|
|
20
|
+
const lines = content.split('\n');
|
|
21
|
+
fs.writeFileSync(errorLog, lines.slice(Math.floor(lines.length / 2)).join('\n'));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
fs.appendFileSync(errorLog, line);
|
|
25
|
+
} catch (_) {
|
|
26
|
+
// Logging must never throw
|
|
27
|
+
}
|
|
28
|
+
}
|
|
10
29
|
|
|
11
30
|
// Read JSON from stdin (Claude Code statusline protocol)
|
|
12
31
|
let input = '';
|
|
@@ -56,9 +75,13 @@ process.stdin.on('end', () => {
|
|
|
56
75
|
const todos = JSON.parse(fs.readFileSync(path.join(todosDir, files[0].name), 'utf8'));
|
|
57
76
|
const inProgress = todos.find(t => t.status === 'in_progress');
|
|
58
77
|
if (inProgress) task = inProgress.activeForm || '';
|
|
59
|
-
} catch (e) {
|
|
78
|
+
} catch (e) {
|
|
79
|
+
logError('parse-todos', e);
|
|
80
|
+
}
|
|
60
81
|
}
|
|
61
|
-
} catch (e) {
|
|
82
|
+
} catch (e) {
|
|
83
|
+
logError('read-todos', e);
|
|
84
|
+
}
|
|
62
85
|
}
|
|
63
86
|
|
|
64
87
|
// --- Flow update notification ---
|
|
@@ -78,6 +101,7 @@ process.stdin.on('end', () => {
|
|
|
78
101
|
shouldCheck = true;
|
|
79
102
|
}
|
|
80
103
|
} catch (e) {
|
|
104
|
+
logError('parse-cache', e);
|
|
81
105
|
shouldCheck = true;
|
|
82
106
|
}
|
|
83
107
|
} else {
|
|
@@ -96,7 +120,9 @@ process.stdin.on('end', () => {
|
|
|
96
120
|
});
|
|
97
121
|
child.unref();
|
|
98
122
|
}
|
|
99
|
-
} catch (e) {
|
|
123
|
+
} catch (e) {
|
|
124
|
+
logError('spawn-update-check', e);
|
|
125
|
+
}
|
|
100
126
|
}
|
|
101
127
|
|
|
102
128
|
// --- Output ---
|
|
@@ -107,6 +133,7 @@ process.stdin.on('end', () => {
|
|
|
107
133
|
process.stdout.write(`${flowUpdate}\x1b[2m${model}\x1b[0m \u2502 \x1b[2m${dirname}\x1b[0m${ctx}`);
|
|
108
134
|
}
|
|
109
135
|
} catch (e) {
|
|
136
|
+
logError('main', e);
|
|
110
137
|
// Silent fail — statusline must never crash
|
|
111
138
|
}
|
|
112
139
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flow-cc",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Structured workflow system for Claude Code — spec interviews, agent-team execution, session handoffs, compounding knowledge",
|
|
5
5
|
"author": "Troy Hoffman",
|
|
6
6
|
"license": "MIT",
|
|
@@ -25,11 +25,16 @@
|
|
|
25
25
|
"bin": {
|
|
26
26
|
"flow-cc": "bin/install.js"
|
|
27
27
|
},
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=18"
|
|
30
|
+
},
|
|
28
31
|
"files": [
|
|
29
32
|
"bin",
|
|
30
33
|
"skills",
|
|
31
34
|
"hooks",
|
|
32
35
|
"templates",
|
|
33
|
-
"VERSION"
|
|
36
|
+
"VERSION",
|
|
37
|
+
"CHANGELOG.md",
|
|
38
|
+
"CONTRIBUTING.md"
|
|
34
39
|
]
|
|
35
40
|
}
|
package/skills/flow-done.md
CHANGED
|
@@ -65,6 +65,8 @@ Structure:
|
|
|
65
65
|
- Mark completed phases with completion date
|
|
66
66
|
- Ensure pending phases have enough detail that the next session can start with a one-line prompt
|
|
67
67
|
- **Archive check:** If the current milestone is fully complete:
|
|
68
|
+
- If `.planning/` does not exist, skip archiving entirely — there's nothing to archive
|
|
69
|
+
- Create `.planning/archive/` if it doesn't already exist (use `mkdir -p` or equivalent)
|
|
68
70
|
- Move milestone phase details to `.planning/archive/milestones-vX.md`
|
|
69
71
|
- Keep only the summary row in the ROADMAP milestone table
|
|
70
72
|
- Move `PRD.md` to `.planning/archive/PRD-vX.md`
|
|
@@ -98,7 +100,7 @@ Determine the next action and generate a copyable handoff prompt:
|
|
|
98
100
|
```
|
|
99
101
|
- If milestone is complete:
|
|
100
102
|
```
|
|
101
|
-
Milestone [name] complete. Run /flow:
|
|
103
|
+
Milestone [name] complete. Run /flow:milestone to start the next milestone.
|
|
102
104
|
```
|
|
103
105
|
|
|
104
106
|
Print the handoff prompt in a fenced code block so the user can copy it.
|
package/skills/flow-go.md
CHANGED
|
@@ -32,7 +32,7 @@ Run these checks before executing. If any fail, stop and tell the user what to d
|
|
|
32
32
|
- Verification commands
|
|
33
33
|
- If missing: "PRD phase section is too vague. Add wave structure + file lists, or run `/flow:spec`."
|
|
34
34
|
3. **Branch check:** Verify you're on the correct feature branch (from PRD header). If not, warn the user.
|
|
35
|
-
4. **All phases done?** If no pending phases remain: "All phases complete! Run `/flow:done` to wrap up, or `/flow:
|
|
35
|
+
4. **All phases done?** If no pending phases remain: "All phases complete! Run `/flow:done` to wrap up, or `/flow:milestone` for the next milestone."
|
|
36
36
|
|
|
37
37
|
## Step 3 — Staleness Check
|
|
38
38
|
|
|
@@ -82,22 +82,54 @@ so agents have it in their context without needing to search.]
|
|
|
82
82
|
|
|
83
83
|
- Use TeamCreate or Task tool to spawn all agents in the wave simultaneously
|
|
84
84
|
- Each agent runs with `mode: "bypassPermissions"` for autonomous execution
|
|
85
|
-
-
|
|
85
|
+
- Print: **"Wave N: Spawned X agents — [agent-1-task], [agent-2-task], ..."**
|
|
86
|
+
- As each agent completes, print: **"Wave N: agent-name completed (X/Y)"**
|
|
87
|
+
- Set a reasonable timeout for each agent. If an agent hasn't completed after 10 minutes, check on it. If it's stuck, stop it and note the failure.
|
|
88
|
+
- Wait for all agents in the wave to complete (or timeout) before moving to the next wave
|
|
86
89
|
|
|
87
|
-
### 4c.
|
|
90
|
+
### 4c. Wave Failure Handling
|
|
88
91
|
|
|
89
|
-
After
|
|
92
|
+
After a wave completes, check results:
|
|
93
|
+
|
|
94
|
+
**If ALL agents in a wave failed:**
|
|
95
|
+
- Print: **"Wave N failed — all X agents errored."**
|
|
96
|
+
- Show error summaries from each agent
|
|
97
|
+
- Use AskUserQuestion: "Wave N failed completely. How to proceed?"
|
|
98
|
+
- "Retry this wave"
|
|
99
|
+
- "Skip to next wave"
|
|
100
|
+
- "Abort phase"
|
|
101
|
+
|
|
102
|
+
**If SOME agents failed but others succeeded:**
|
|
103
|
+
- Print: **"Wave N: X/Y agents succeeded, Z failed."**
|
|
104
|
+
- Show failed agent error summaries
|
|
105
|
+
- Use AskUserQuestion: "Some agents failed. How to proceed?"
|
|
106
|
+
- "Retry failed agents"
|
|
107
|
+
- "Continue without them"
|
|
108
|
+
- "Abort phase"
|
|
109
|
+
|
|
110
|
+
When a wave completes successfully (all agents or user chose to continue), print: **"Wave N complete. Proceeding to Wave N+1."**
|
|
111
|
+
|
|
112
|
+
### 4d. Between Waves
|
|
113
|
+
|
|
114
|
+
After each wave completes (and failure handling is resolved):
|
|
90
115
|
1. Run verification commands from CLAUDE.md (e.g., `npx tsc --noEmit`, `npx biome check`)
|
|
91
116
|
2. Check for integration issues between agents' output
|
|
92
117
|
3. Fix any issues before proceeding to the next wave
|
|
93
118
|
4. If verification fails and you can fix it quickly (< 2 minutes of work), fix it. Otherwise, stop and report.
|
|
94
119
|
|
|
95
|
-
###
|
|
120
|
+
### 4e. Final Verification
|
|
96
121
|
|
|
97
122
|
After ALL waves complete:
|
|
98
123
|
1. Run full verification suite
|
|
99
124
|
2. Check all acceptance criteria for this phase's user stories
|
|
100
|
-
3. If
|
|
125
|
+
3. If verification fails, attempt to fix (max **3 attempts**):
|
|
126
|
+
- After attempt 1 fails: Print **"Verification failed. Attempting fix (1/3)..."**
|
|
127
|
+
- After attempt 2 fails: Print **"Verification failed. Attempting fix (2/3)..."**
|
|
128
|
+
- After attempt 3 fails: Print **"Verification failed after 3 attempts. STOP."** Print the errors and use AskUserQuestion:
|
|
129
|
+
- "Skip verification and continue"
|
|
130
|
+
- "Fix manually and retry"
|
|
131
|
+
- "Abort this phase"
|
|
132
|
+
- Do NOT loop further beyond 3 attempts.
|
|
101
133
|
|
|
102
134
|
## Step 5 — Commit
|
|
103
135
|
|
package/skills/flow-intro.md
CHANGED
|
@@ -14,28 +14,35 @@ Print this:
|
|
|
14
14
|
|
|
15
15
|
## Flow — Your Workflow System
|
|
16
16
|
|
|
17
|
-
Flow is
|
|
17
|
+
Flow is 6 commands that turn your specs into shipped code through agent teams. Each command feeds the next.
|
|
18
18
|
|
|
19
19
|
### The Lifecycle
|
|
20
20
|
|
|
21
21
|
```
|
|
22
|
-
/flow:
|
|
22
|
+
/flow:setup → /flow:spec → /flow:go (repeat) → /flow:done
|
|
23
23
|
↓
|
|
24
24
|
handoff prompt for next session
|
|
25
|
+
↓
|
|
26
|
+
/flow:milestone → next cycle
|
|
25
27
|
|
|
26
28
|
/flow:task ← standalone path for bug fixes, cleanup, small features (no PRD needed)
|
|
27
29
|
```
|
|
28
30
|
|
|
29
31
|
### Command by Command
|
|
30
32
|
|
|
31
|
-
**`/flow:
|
|
32
|
-
-
|
|
33
|
+
**`/flow:setup`** — Run once per project
|
|
34
|
+
- Asks you 4-5 questions (what is it, tech stack, verify commands, first milestone)
|
|
33
35
|
- Creates the scaffolding: `CLAUDE.md`, `.planning/STATE.md`, `.planning/ROADMAP.md`, `tasks/lessons.md`
|
|
34
|
-
-
|
|
36
|
+
- If project already set up, tells you to use `/flow:milestone` or `/flow:spec` instead
|
|
37
|
+
|
|
38
|
+
**`/flow:milestone`** — Run when starting a new milestone
|
|
39
|
+
- Archives the completed milestone + PRD
|
|
40
|
+
- Sets up fresh planning docs for the next milestone
|
|
41
|
+
- Guards against archiving milestones with incomplete phases
|
|
35
42
|
|
|
36
43
|
**`/flow:task`** — Run anytime for small work
|
|
37
44
|
- Bug fixes, cleanup, one-off features — anything that doesn't need a full PRD
|
|
38
|
-
- Works standalone without `/flow:
|
|
45
|
+
- Works standalone without `/flow:setup` — lowest friction entry to Flow
|
|
39
46
|
- Executes, verifies, commits, and logs to STATE.md (if it exists)
|
|
40
47
|
- Scope guard recommends `/flow:spec` if the task grows beyond 5 files or 3 layers
|
|
41
48
|
|
|
@@ -80,7 +87,7 @@ Flow is 5 commands that turn your specs into shipped code through agent teams. E
|
|
|
80
87
|
### Starting a Brand New Project
|
|
81
88
|
|
|
82
89
|
```
|
|
83
|
-
1. /flow:
|
|
90
|
+
1. /flow:setup ← scaffolds everything
|
|
84
91
|
2. /flow:spec ← interview → PRD
|
|
85
92
|
3. /flow:go ← phase 1
|
|
86
93
|
4. /flow:done ← wrap up
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: flow:milestone
|
|
3
|
+
description: Archive completed milestone and start a new one
|
|
4
|
+
user_invocable: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# /flow:milestone — Start New Milestone
|
|
8
|
+
|
|
9
|
+
You are executing the `/flow:milestone` skill. This archives the current milestone and sets up a new one.
|
|
10
|
+
|
|
11
|
+
## Guard: Project Must Exist
|
|
12
|
+
|
|
13
|
+
Check if `.planning/STATE.md` exists:
|
|
14
|
+
- **If it does NOT exist** → Print: "No project found. Run `/flow:setup` first." and **STOP.**
|
|
15
|
+
- **If it exists** → Continue.
|
|
16
|
+
|
|
17
|
+
## Step 1: Read Context
|
|
18
|
+
|
|
19
|
+
Read `.planning/STATE.md` and `.planning/ROADMAP.md` to understand:
|
|
20
|
+
- What milestone just completed (or is completing)
|
|
21
|
+
- What version number to use next
|
|
22
|
+
- Current state of the project
|
|
23
|
+
|
|
24
|
+
## Step 2: Check for Pending Phases
|
|
25
|
+
|
|
26
|
+
Parse ROADMAP.md for the current milestone's phases:
|
|
27
|
+
- If any phases have status "Pending" or "In Progress" (not complete):
|
|
28
|
+
- Print: "Warning: The current milestone has incomplete phases:"
|
|
29
|
+
- List the pending/in-progress phases
|
|
30
|
+
- Use AskUserQuestion: "Archive this milestone anyway?" with options:
|
|
31
|
+
- "Yes — archive and move on"
|
|
32
|
+
- "No — finish current phases first"
|
|
33
|
+
- If the user says No → Print: "Run `/flow:go` to continue the current milestone." and **STOP.**
|
|
34
|
+
|
|
35
|
+
## Step 3: Ask Milestone Question
|
|
36
|
+
|
|
37
|
+
Use AskUserQuestion:
|
|
38
|
+
- "What's the goal of this new milestone?" (free text)
|
|
39
|
+
- "What should it be called?" (free text, or suggest a name based on context)
|
|
40
|
+
|
|
41
|
+
## Step 4: Archive Completed Milestone
|
|
42
|
+
|
|
43
|
+
1. Read current ROADMAP.md phase details for the completed milestone
|
|
44
|
+
2. Write them to `.planning/archive/milestones-vX.md` (where X is the completed version)
|
|
45
|
+
3. If `PRD.md` exists, move it to `.planning/archive/PRD-vX.md` (read it, write to archive, delete original)
|
|
46
|
+
4. In ROADMAP.md, replace the completed milestone's phase details with just the summary row (mark as "Complete")
|
|
47
|
+
|
|
48
|
+
## Step 5: Update Planning Docs
|
|
49
|
+
|
|
50
|
+
**ROADMAP.md:**
|
|
51
|
+
- Add new milestone row to the table
|
|
52
|
+
- Add new milestone section with goal and "Run `/flow:spec` to define phases"
|
|
53
|
+
|
|
54
|
+
**STATE.md:**
|
|
55
|
+
- Replace with fresh state for the new milestone
|
|
56
|
+
- Reset phase progress table
|
|
57
|
+
- Note the milestone transition in "What Was Built"
|
|
58
|
+
|
|
59
|
+
## Step 6: Print Completion Message
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
Milestone [name] (v[X]) initialized.
|
|
63
|
+
- Archived: previous milestone details + PRD
|
|
64
|
+
- Updated: ROADMAP.md, STATE.md
|
|
65
|
+
|
|
66
|
+
Run `/flow:spec` to build the PRD for this milestone.
|
|
67
|
+
```
|
|
@@ -1,24 +1,22 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: flow:
|
|
3
|
-
description:
|
|
2
|
+
name: flow:setup
|
|
3
|
+
description: Set up a new project with Flow planning scaffolding
|
|
4
4
|
user_invocable: true
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
# /flow:
|
|
7
|
+
# /flow:setup — Set Up New Project
|
|
8
8
|
|
|
9
|
-
You are executing the `/flow:
|
|
9
|
+
You are executing the `/flow:setup` skill. This sets up the planning scaffolding for a new project.
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Guard: Already Initialized
|
|
12
12
|
|
|
13
|
-
Check if `.planning/STATE.md` exists:
|
|
14
|
-
- **If it
|
|
15
|
-
- **If it
|
|
13
|
+
Check if `.planning/STATE.md` already exists:
|
|
14
|
+
- **If it exists** → Print: "This project is already set up. Run `/flow:milestone` to start a new milestone, or `/flow:spec` to spec the current one." and **STOP. Do not overwrite.**
|
|
15
|
+
- **If it does NOT exist** → Continue with setup below.
|
|
16
16
|
|
|
17
17
|
---
|
|
18
18
|
|
|
19
|
-
##
|
|
20
|
-
|
|
21
|
-
### Step 1: Ask Setup Questions
|
|
19
|
+
## Step 1: Ask Setup Questions
|
|
22
20
|
|
|
23
21
|
Use AskUserQuestion to gather project info. Ask these questions (you may combine into 2-3 AskUserQuestion calls):
|
|
24
22
|
|
|
@@ -47,7 +45,7 @@ Use AskUserQuestion to gather project info. Ask these questions (you may combine
|
|
|
47
45
|
- "Yes — scan and catalog existing code"
|
|
48
46
|
- "No — greenfield project"
|
|
49
47
|
|
|
50
|
-
|
|
48
|
+
## Step 2: Brownfield Scan (if requested)
|
|
51
49
|
|
|
52
50
|
If the user said yes to scanning:
|
|
53
51
|
1. Use Glob to find key directories: `src/`, `app/`, `lib/`, `components/`, `api/`, `pages/`, `utils/`, `types/`
|
|
@@ -55,7 +53,7 @@ If the user said yes to scanning:
|
|
|
55
53
|
3. Build a brief catalog of what exists (key components, patterns, data layer)
|
|
56
54
|
4. Include this in the CLAUDE.md Quick Context section
|
|
57
55
|
|
|
58
|
-
|
|
56
|
+
## Step 3: Create Project Files
|
|
59
57
|
|
|
60
58
|
Create these 5 files (create directories as needed):
|
|
61
59
|
|
|
@@ -76,7 +74,7 @@ Create these 5 files (create directories as needed):
|
|
|
76
74
|
| — | Run `/flow:spec` to define phases | — |
|
|
77
75
|
|
|
78
76
|
## What Was Built (This Session)
|
|
79
|
-
- Project initialized with `/flow:
|
|
77
|
+
- Project initialized with `/flow:setup`
|
|
80
78
|
- Created: CLAUDE.md, STATE.md, ROADMAP.md, tasks/lessons.md
|
|
81
79
|
|
|
82
80
|
## Key Decisions
|
|
@@ -159,7 +157,7 @@ Format: PATTERN → CAUSE → FIX → RULE
|
|
|
159
157
|
|
|
160
158
|
**`.planning/archive/`** — Create this empty directory (use `mkdir -p` via Bash).
|
|
161
159
|
|
|
162
|
-
|
|
160
|
+
## Step 4: Print Completion Message
|
|
163
161
|
|
|
164
162
|
```
|
|
165
163
|
Project initialized:
|
|
@@ -171,48 +169,3 @@ Project initialized:
|
|
|
171
169
|
|
|
172
170
|
Run `/flow:spec` to plan your first milestone.
|
|
173
171
|
```
|
|
174
|
-
|
|
175
|
-
---
|
|
176
|
-
|
|
177
|
-
## New Milestone Mode
|
|
178
|
-
|
|
179
|
-
### Step 1: Read Context
|
|
180
|
-
|
|
181
|
-
Read `.planning/STATE.md` and `.planning/ROADMAP.md` to understand:
|
|
182
|
-
- What milestone just completed (or is completing)
|
|
183
|
-
- What version number to use next
|
|
184
|
-
- Current state of the project
|
|
185
|
-
|
|
186
|
-
### Step 2: Ask Milestone Question
|
|
187
|
-
|
|
188
|
-
Use AskUserQuestion:
|
|
189
|
-
- "What's the goal of this new milestone?" (free text)
|
|
190
|
-
- "What should it be called?" (free text, or suggest a name based on context)
|
|
191
|
-
|
|
192
|
-
### Step 3: Archive Completed Milestone
|
|
193
|
-
|
|
194
|
-
1. Read current ROADMAP.md phase details for the completed milestone
|
|
195
|
-
2. Write them to `.planning/archive/milestones-vX.md` (where X is the completed version)
|
|
196
|
-
3. If `PRD.md` exists, move it to `.planning/archive/PRD-vX.md` (read it, write to archive, delete original)
|
|
197
|
-
4. In ROADMAP.md, replace the completed milestone's phase details with just the summary row (mark as "Complete")
|
|
198
|
-
|
|
199
|
-
### Step 4: Update Planning Docs
|
|
200
|
-
|
|
201
|
-
**ROADMAP.md:**
|
|
202
|
-
- Add new milestone row to the table
|
|
203
|
-
- Add new milestone section with goal and "Run `/flow:spec` to define phases"
|
|
204
|
-
|
|
205
|
-
**STATE.md:**
|
|
206
|
-
- Replace with fresh state for the new milestone
|
|
207
|
-
- Reset phase progress table
|
|
208
|
-
- Note the milestone transition in "What Was Built"
|
|
209
|
-
|
|
210
|
-
### Step 5: Print Completion Message
|
|
211
|
-
|
|
212
|
-
```
|
|
213
|
-
Milestone [name] (v[X]) initialized.
|
|
214
|
-
- Archived: previous milestone details + PRD
|
|
215
|
-
- Updated: ROADMAP.md, STATE.md
|
|
216
|
-
|
|
217
|
-
Run `/flow:spec` to build the PRD for this milestone.
|
|
218
|
-
```
|
package/skills/flow-spec.md
CHANGED
|
@@ -16,8 +16,10 @@ You are executing the `/flow:spec` skill. This is the KEYSTONE skill of the flow
|
|
|
16
16
|
2. Read `CLAUDE.md` — understand project rules and tech stack
|
|
17
17
|
3. Read `PRD.md` if it exists — check for existing spec to build on
|
|
18
18
|
4. **Codebase scan** (brownfield projects):
|
|
19
|
-
- Use Glob
|
|
20
|
-
- Use
|
|
19
|
+
- **Exclusions:** NEVER scan these directories/files: `node_modules/`, `.git/`, `dist/`, `build/`, `.next/`, `__pycache__/`, `*.min.js`, `*.map`, `*.lock`. Use Glob with patterns like `src/**/*`, `app/**/*`, `lib/**/*` — never use bare `**/*` which includes generated files.
|
|
20
|
+
- **Size check first:** Use Glob with `src/**/*`, `app/**/*`, `lib/**/*`, `components/**/*` (excluding the above) to estimate relevant file count. If > 500 files, switch to focused mode (see below).
|
|
21
|
+
- **Standard mode (≤ 500 files):** Use Glob to find components, pages/routes, API endpoints, types, utilities, config files, database models. Use Grep for export patterns, route definitions, key function signatures. **Cap at 50 files sampled** — prioritize entry points, config, and type definitions.
|
|
22
|
+
- **Focused mode (> 500 files):** Scan ONLY: package.json/config files, entry points (index.ts, main.ts, app.ts), route definitions, database schema/models, and type definition files. Skip component trees, test files, and generated code entirely.
|
|
21
23
|
- Build internal summary: "Here's what exists that we can reuse"
|
|
22
24
|
5. Print a brief context summary to the user: "Here's what I found in the codebase: [key components, patterns, data layer]. Starting the spec interview."
|
|
23
25
|
|
|
@@ -113,6 +115,20 @@ Cover these areas thoroughly. There are no "rounds" — move fluidly between are
|
|
|
113
115
|
|
|
114
116
|
## Phase 3 — PRD Generation
|
|
115
117
|
|
|
118
|
+
### Minimum Viable PRD Check
|
|
119
|
+
|
|
120
|
+
Before generating the final PRD, validate:
|
|
121
|
+
- At least **3 user stories** with acceptance criteria have been discussed
|
|
122
|
+
- At least **1 implementation phase** has been defined
|
|
123
|
+
- At least **1 verification command** has been specified
|
|
124
|
+
|
|
125
|
+
If any check fails, print what's missing and use AskUserQuestion:
|
|
126
|
+
- "The PRD is thin — [missing items]. Want to continue the interview to flesh it out, or finalize as-is?"
|
|
127
|
+
- "Continue interview" — return to Phase 2 and probe the missing areas
|
|
128
|
+
- "Finalize as-is" — proceed with what we have
|
|
129
|
+
|
|
130
|
+
### Write PRD
|
|
131
|
+
|
|
116
132
|
Write `PRD.md` to the project root with this EXACT structure:
|
|
117
133
|
|
|
118
134
|
```markdown
|
package/skills/flow-status.md
CHANGED
|
@@ -17,7 +17,7 @@ Read ALL of the following in parallel:
|
|
|
17
17
|
- Count lessons in `tasks/lessons.md` (if exists)
|
|
18
18
|
|
|
19
19
|
IF both STATE.md AND ROADMAP.md are missing:
|
|
20
|
-
- Print: "No flow project found. Run `/flow:
|
|
20
|
+
- Print: "No flow project found. Run `/flow:setup` to set up, or `/flow:task` for a quick standalone fix."
|
|
21
21
|
- STOP here.
|
|
22
22
|
|
|
23
23
|
IF only one file exists, continue with what's available.
|
|
@@ -47,7 +47,7 @@ Use this explicit decision tree:
|
|
|
47
47
|
|
|
48
48
|
**IF all phases are complete:**
|
|
49
49
|
→ Primary: `/flow:done` to finalize this milestone
|
|
50
|
-
→ Then: `/flow:
|
|
50
|
+
→ Then: `/flow:milestone` to start the next milestone
|
|
51
51
|
→ Alt: `/flow:task` for quick fixes or cleanup (no PRD needed)
|
|
52
52
|
|
|
53
53
|
**IF no phases exist in ROADMAP (milestone defined but not planned):**
|
|
@@ -65,7 +65,7 @@ Lessons: [N] rules
|
|
|
65
65
|
[routing recommendations from Step 3]
|
|
66
66
|
```
|
|
67
67
|
|
|
68
|
-
Adapt the block based on available information. If STATE.md is missing, omit "Last session". If ROADMAP.md is missing, omit phase counts and say "Run /flow:
|
|
68
|
+
Adapt the block based on available information. If STATE.md is missing, omit "Last session". If ROADMAP.md is missing, omit phase counts and say "Run /flow:setup to set up tracking."
|
|
69
69
|
|
|
70
70
|
## Step 5 — No File Writes
|
|
71
71
|
|
package/skills/flow-task.md
CHANGED
|
@@ -11,7 +11,7 @@ You are executing the `/flow:task` skill. This is for small, focused work — bu
|
|
|
11
11
|
RULES:
|
|
12
12
|
- NO AGENT TEAMS. NO PRD. Single execution context.
|
|
13
13
|
- Exception: ONE Task agent for an isolated subtask to prevent context bloat.
|
|
14
|
-
- This skill MUST work without `/flow:
|
|
14
|
+
- This skill MUST work without `/flow:setup`. Missing planning files are fine.
|
|
15
15
|
|
|
16
16
|
## Step 1 — Context Load
|
|
17
17
|
|
package/skills/flow-update.md
CHANGED
|
@@ -46,14 +46,23 @@ If installed version equals latest version, print this and stop:
|
|
|
46
46
|
Flow is up to date (v<version>)
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
-
## Step 4:
|
|
49
|
+
## Step 4: Show what's new
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
Fetch the CHANGELOG.md from the Flow repo to show the user what changed:
|
|
52
|
+
|
|
53
|
+
1. Run: `npx -y -p flow-cc@<latest> node -e "const fs=require('fs'),p=require('path');try{console.log(fs.readFileSync(p.join(require.resolve('flow-cc/package.json'),'..','CHANGELOG.md'),'utf8'))}catch(e){console.log('CHANGELOG not available')}"`
|
|
54
|
+
2. Parse the output and extract only the section for `v<latest>` (from the `## [<latest>]` heading to the next `## [` heading or end of file)
|
|
55
|
+
3. Print:
|
|
52
56
|
|
|
53
57
|
```
|
|
54
58
|
Update available: v<installed> → v<latest>
|
|
59
|
+
|
|
60
|
+
Here's what's new in v<latest>:
|
|
61
|
+
<extracted changelog section>
|
|
55
62
|
```
|
|
56
63
|
|
|
64
|
+
If the CHANGELOG fetch fails, just print the version line without the changelog section. Don't let a missing changelog block the update.
|
|
65
|
+
|
|
57
66
|
Wait for user confirmation before proceeding.
|
|
58
67
|
|
|
59
68
|
## Step 5: Run update
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
| — | Run `/flow:spec` to define phases | — |
|
|
14
14
|
|
|
15
15
|
## What Was Built (This Session)
|
|
16
|
-
- Project initialized with `/flow:
|
|
16
|
+
- Project initialized with `/flow:setup`
|
|
17
17
|
- Created: CLAUDE.md, STATE.md, ROADMAP.md, tasks/lessons.md
|
|
18
18
|
|
|
19
19
|
## Key Decisions
|
|
@@ -5,6 +5,16 @@ Format: PATTERN → CAUSE → FIX → RULE
|
|
|
5
5
|
## Execution Patterns
|
|
6
6
|
<!-- Lessons about workflow, delegation, verification -->
|
|
7
7
|
|
|
8
|
+
<!-- EXAMPLE (replace with real lessons as you work):
|
|
9
|
+
|
|
10
|
+
### Agent context overflow on large files
|
|
11
|
+
- **PATTERN:** Spawned agent tried to read a 2000-line file and ran out of context before finishing its task
|
|
12
|
+
- **CAUSE:** Agent prompt didn't specify which lines/functions to read — it read the whole file
|
|
13
|
+
- **FIX:** Added explicit line ranges and function names to the agent prompt
|
|
14
|
+
- **RULE:** Always tell agents exactly which functions/sections to read. Never say "read file.ts" — say "read file.ts lines 50-120 (the handleSubmit function)"
|
|
15
|
+
|
|
16
|
+
END EXAMPLE -->
|
|
17
|
+
|
|
8
18
|
## Domain Knowledge
|
|
9
19
|
<!-- Lessons about business logic, data models, user behavior -->
|
|
10
20
|
|