@mhd-ghaith-abtah/flow 0.8.0-beta.0 → 0.8.0-beta.1

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 CHANGED
@@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.8.0-beta.1] — 2026-05-23
10
+
11
+ ### Added
12
+ - **`flow install-skills` command** — closes the bootstrap gap between npm install and Claude Code slash command discovery. After `npm install -g @mhd-ghaith-abtah/flow@beta`, run `flow install-skills` to symlink the four `skills/flow-*` directories into `~/.claude/skills/` (or `<project>/.claude/skills/` with `--scope project` for the team-commit pattern; `--scope both` for both). Idempotent (skips already-correctly-linked targets); refuses to clobber real directories at the target without `--force`; replaces wrong-source symlinks silently. 9 new tests covering home/project/both scopes, refusal-without-force, force-replace, dry-run, idempotent re-run, and wrong-source-symlink replacement. README + docs/usage.md updated with the corrected bootstrap order (`npm install -g` → `flow install-skills` → `/flow-init`).
13
+
9
14
  ## [0.8.0-beta.0] — 2026-05-23
10
15
 
11
16
  ### Added
package/README.md CHANGED
@@ -23,25 +23,26 @@ Existing per-story workflows are token-heavy. BMad's create-story re-reads epics
23
23
  > **Status (v0.7.2-beta.0, published 2026-05-19):** Flow is live on npm as a **beta channel**. Stable `latest` will be promoted from beta after a soak period. Expect minor breaking changes between beta releases until then.
24
24
 
25
25
  ```bash
26
- # Inside Claude Code (recommended for first install interactive)
27
- /flow-init
28
-
29
- # Headless install via npm — beta channel (no Claude Code required)
26
+ # 1. Install the Node CLI + bootstrap the Claude Code surface
30
27
  npm install -g @mhd-ghaith-abtah/flow@beta
28
+ flow install-skills # one-time; symlinks 4 skills into ~/.claude/skills/
29
+
30
+ # 2. Then EITHER (interactive):
31
+ /flow-init # inside Claude Code
32
+
33
+ # OR (headless, no Claude Code needed):
31
34
  flow init --profile standard --yes # chains detect → upstreams → MCPs → scaffold
35
+
36
+ # Useful at any point:
32
37
  flow plan --profile standard # preview without executing
33
38
  flow doctor # health check
34
39
 
35
- # One-shot via npx — no install
36
- npx -y @mhd-ghaith-abtah/flow@beta init --profile mini --yes
37
-
38
- # Or from a clone (development / contributing)
40
+ # Dev clone (contributors):
39
41
  git clone https://github.com/mhd-ghaith-abtah/flow.git
40
- cd flow && npm install && tools/dev-link.sh
41
- flow plan --profile standard
42
+ cd flow && npm install && tools/dev-link.sh # dev-mode equivalent of install-skills + PATH link
42
43
  ```
43
44
 
44
- Two paths, same end state. `/flow-init` is interactive Claude Code drives the Q&A, error recovery, and multi-step ceremony. `flow init --yes` is headless pre-populates every answer from the profile defaults so it runs end-to-end without prompts (override individual knobs via `--ecc-scope`, `--bmad-subset`, `--ecc-subset`). Both invoke the same upstream installers and scaffold the same files.
45
+ The `flow install-skills` step is what makes `/flow-init` resolve in Claude Code npm puts the package in your global node_modules, but Claude Code only scans `~/.claude/skills/`. After install-skills, both paths (interactive slash or headless CLI) reach the same orchestrator and write the same files. Override individual knobs via `--ecc-scope`, `--bmad-subset`, `--ecc-subset`. Full guide: [docs/usage.md](docs/usage.md).
45
46
 
46
47
  The installer detects your project shape, then:
47
48
  - Installs Flow's four skills (`flow-init`, `flow-sprint`, `flow-story`, `flow-doctor`)
@@ -55,6 +56,8 @@ The installer detects your project shape, then:
55
56
 
56
57
  ## Quickstart
57
58
 
59
+ > **Want every option in one place?** See the long-form [Usage Guide](docs/usage.md) — installation paths, daily workflow, sprint commands, profiles, ECC scope, maintenance, uninstall, full CLI reference, common scenarios (recipe book), and troubleshooting. The block below is the 30-second version.
60
+
58
61
  ```bash
59
62
  $ /flow-init # one time per project
60
63
  $ /flow-sprint add "First story" --epic E1 --tags ui # add a story
package/bin/flow.js CHANGED
@@ -24,6 +24,7 @@ ${chalk.bold('Usage:')}
24
24
  ${chalk.bold('Commands:')}
25
25
  init Interactive first-time setup (same as /flow-init in Claude Code)
26
26
  install Non-interactive install with flags
27
+ install-skills Symlink Flow skills into ~/.claude/skills/ (bootstrap)
27
28
  plan Dry-run: show the resolved install plan
28
29
  status What's installed where
29
30
  doctor [--mcp <id>] Health check
@@ -68,7 +69,7 @@ Version ${PKG.version} · ${chalk.dim(PKG.homepage)}
68
69
  `;
69
70
 
70
71
  const COMMANDS = [
71
- 'init', 'install', 'plan', 'status', 'doctor', 'add', 'remove', 'uninstall',
72
+ 'init', 'install', 'install-skills', 'plan', 'status', 'doctor', 'add', 'remove', 'uninstall',
72
73
  'list-profiles', 'list-components', 'list-mcps', 'mcp', 'sprint', 'help', 'version', '--version'
73
74
  ];
74
75
 
package/docs/usage.md ADDED
@@ -0,0 +1,940 @@
1
+ # Using Flow — the complete guide
2
+
3
+ How to install, configure, run, maintain, and uninstall Flow in every supported scenario.
4
+
5
+ This is the long-form reference. For the 10-minute first-install path, see [quickstart.md](quickstart.md). For per-profile details, see [profiles.md](profiles.md). For adapter mechanics, see [adapters.md](adapters.md). For BMad → Flow migration, see [migrate-from-bmad.md](migrate-from-bmad.md).
6
+
7
+ > **Heads up on availability.** Some flags described here (`flow init --yes`, `--update`, `--repair`, `--remove-project-ecc`, MCP secrets collection) require **v0.8.0-beta.0 or later**. Earlier versions on the `latest` dist-tag have the slash-command path only. Install the beta with `npm install -g @mhd-ghaith-abtah/flow@beta` until `latest` catches up.
8
+
9
+ ---
10
+
11
+ ## Table of contents
12
+
13
+ - [1. Installation paths](#1-installation-paths)
14
+ - [2. First-time install](#2-first-time-install)
15
+ - [3. Daily story workflow](#3-daily-story-workflow)
16
+ - [4. Sprint state management](#4-sprint-state-management)
17
+ - [5. Profiles and customization](#5-profiles-and-customization)
18
+ - [6. ECC install scope](#6-ecc-install-scope)
19
+ - [7. Health checks and maintenance](#7-health-checks-and-maintenance)
20
+ - [8. Updating an existing install](#8-updating-an-existing-install)
21
+ - [9. Repairing a broken install](#9-repairing-a-broken-install)
22
+ - [10. Uninstalling](#10-uninstalling)
23
+ - [11. Inside Claude Code — slash command reference](#11-inside-claude-code--slash-command-reference)
24
+ - [12. Complete CLI flag reference](#12-complete-cli-flag-reference)
25
+ - [13. Common scenarios (recipe book)](#13-common-scenarios-recipe-book)
26
+ - [14. Environment variables](#14-environment-variables)
27
+ - [15. Files Flow writes](#15-files-flow-writes)
28
+ - [16. Troubleshooting](#16-troubleshooting)
29
+
30
+ ---
31
+
32
+ ## 1. Installation paths
33
+
34
+ Flow ships in two surfaces: a Claude Code skill bundle (interactive) and a Node CLI (`flow`, headless). Both invoke the same underlying installers and write the same files.
35
+
36
+ **Bootstrap order matters.** Claude Code discovers slash commands by scanning `~/.claude/skills/<name>/`. The npm package puts skill files in the install location (typically `~/.npm-global/lib/node_modules/...`), NOT in `~/.claude/skills/`. So `/flow-init` does NOT work after a bare `npm install -g`. You need to run `flow install-skills` once to symlink the four skills into Claude Code's discovery path.
37
+
38
+ ### a. From npm (recommended)
39
+
40
+ ```bash
41
+ # 1. Install the Node CLI
42
+ npm install -g @mhd-ghaith-abtah/flow@beta
43
+ flow --version
44
+
45
+ # 2. Bootstrap Claude Code surface (links 4 skills into ~/.claude/skills/)
46
+ flow install-skills
47
+
48
+ # 3. Now both paths work — pick one per project:
49
+ flow init --profile mini --yes # headless
50
+ # OR, inside Claude Code:
51
+ /flow-init # interactive
52
+ ```
53
+
54
+ `flow install-skills` is idempotent — re-run safely after every upgrade to refresh the symlinks. It refuses to clobber existing real directories at the target without `--force`.
55
+
56
+ ### b. install-skills scope flag
57
+
58
+ By default `flow install-skills` writes to `~/.claude/skills/` (home scope). Override:
59
+
60
+ ```bash
61
+ flow install-skills # default: --scope home
62
+ flow install-skills --scope home # user-wide ~/.claude/skills/
63
+ flow install-skills --scope project # team-commit: <cwd>/.claude/skills/
64
+ flow install-skills --scope both # both
65
+ flow install-skills --dry-run # preview
66
+ flow install-skills --force # replace existing real dirs
67
+ ```
68
+
69
+ The `--scope project` mode is for teams that want every contributor to get Flow's slash commands the moment they `git clone` the repo — commit `<project>/.claude/skills/flow-*` so Claude Code picks them up automatically when the session is opened inside the project. The user still needs the npm package installed because the symlinks point at it.
70
+
71
+ ### c. `npx` — no install
72
+
73
+ ```bash
74
+ npx -y @mhd-ghaith-abtah/flow@beta install-skills # one-time bootstrap
75
+ npx -y @mhd-ghaith-abtah/flow@beta init --profile mini --yes
76
+ ```
77
+
78
+ `npx` works but the symlink targets the npx cache path, which can disappear when the cache rotates. For ongoing use, prefer `npm install -g`.
79
+
80
+ ### d. Development clone
81
+
82
+ ```bash
83
+ git clone https://github.com/mhd-ghaith-abtah/flow.git
84
+ cd flow && npm install && tools/dev-link.sh
85
+ ```
86
+
87
+ `tools/dev-link.sh` is the dev-mode equivalent of `flow install-skills --scope home` — symlinks the four `skills/flow-*` dirs into `~/.claude/skills/` AND puts `flow` on `$PATH` from your clone. Use when you're contributing so changes to skill workflows take effect immediately.
88
+
89
+ `tools/dev-link.sh` symlinks your clone into `$HOME/.claude/skills/flow-*` and onto `$PATH` as `flow`. Use when you're contributing.
90
+
91
+ ### e. Verifying the install
92
+
93
+ ```bash
94
+ flow --version # → 0.8.0-beta.0 (or newer)
95
+ flow doctor # health check
96
+ flow help # subcommand list
97
+ ```
98
+
99
+ ---
100
+
101
+ ## 2. First-time install
102
+
103
+ ### a. Interactive (inside Claude Code)
104
+
105
+ ```
106
+ /flow-init
107
+ ```
108
+
109
+ The skill walks through Q1–Q9:
110
+
111
+ | Q | Asks about |
112
+ |---|---|
113
+ | Q1 | **Profile** — minimal / mini / standard / team (recommended option auto-detected from project shape) |
114
+ | Q2 | **Issue tracker adapter** — linear / github-issues / none |
115
+ | Q3 | **PR adapter** — github / none |
116
+ | Q4 | **E2E adapter** — playwright-mcp / none |
117
+ | Q5 | **Verify adapter** — make / pnpm / custom |
118
+ | Q6 | **BMad subset** — none / planning-only / full / etc. |
119
+ | Q7 | **ECC subset** — none / flow-essentials / flow-essentials-plus-tdd / etc. |
120
+ | Q7c | **ECC install scope** — user / project (asked only when ECC subset ≠ none) |
121
+ | Q7b | **Caveman compression mode** — none / lite / full / ultra / wenyan |
122
+ | Q8 | **Migrate existing BMad state?** — only asked if BMad is detected |
123
+ | Q9 | **Secrets store** — env-file / shell / 1password (only env-file persists; the others print instructions) |
124
+
125
+ Each answer pre-populates from the chosen profile's default. Hit Enter to accept; type to override.
126
+
127
+ ### b. Headless (via the CLI)
128
+
129
+ ```bash
130
+ flow init --profile mini --yes
131
+ ```
132
+
133
+ Pre-fills every answer from the profile's defaults — no prompts. Useful for scripted setup, fresh-machine bootstrap, and CI.
134
+
135
+ Override individual knobs without leaving the profile:
136
+
137
+ ```bash
138
+ flow init --profile team --yes \
139
+ --ecc-scope user \
140
+ --bmad-subset planning-only \
141
+ --ecc-subset flow-essentials
142
+ ```
143
+
144
+ CLI flag → answer mapping:
145
+
146
+ | Flag | Maps to |
147
+ |---|---|
148
+ | `--profile <name>` | Q1 |
149
+ | `--bmad-subset <name>` | Q6 |
150
+ | `--ecc-subset <name>` | Q7 |
151
+ | `--ecc-scope user\|project` | Q7c |
152
+ | `--with adapter:<id>` | Adds to Q2–Q5 picks |
153
+ | `--without adapter:<id>` | Removes a profile-default adapter |
154
+
155
+ Q2–Q5 adapter picks aren't exposed as single flags yet — use the profile default or `--with`/`--without` to compose.
156
+
157
+ ### c. Preview only (no execution)
158
+
159
+ ```bash
160
+ flow init --profile standard --dry-run # plan only
161
+ flow init --profile standard --yes --dry-run # exercise full chain in dry-run mode
162
+ ```
163
+
164
+ The first form prints the resolved bundle from `catalog.yaml`. The second runs the entire orchestrator (detect → upstreams → MCPs → scaffold) without actually writing or shelling out — useful for verifying a fresh setup before committing to it.
165
+
166
+ ### d. What gets installed
167
+
168
+ Regardless of path, a fresh install produces:
169
+
170
+ ```
171
+ <project>/
172
+ ├── .claude/
173
+ │ ├── flow.config.yaml # team-shared config (COMMIT THIS)
174
+ │ └── flow/
175
+ │ └── install-state.json # what Flow did, when
176
+ └── docs/
177
+ └── flow/
178
+ ├── sprint.yaml # SOURCE OF TRUTH for stories (COMMIT THIS)
179
+ ├── deferred.md # one-line backlog items
180
+ ├── stories/ # active story markdown files
181
+ ├── archive/ # completed story files
182
+ ├── journeys/ # E2E journey definitions
183
+ └── retros/ # epic retros
184
+ ```
185
+
186
+ Plus, depending on profile:
187
+ - Skills under `~/.claude/skills/{flow-init,flow-sprint,flow-story,flow-doctor}/`
188
+ - ECC content under `~/.claude/rules/ecc/` + `~/.claude/skills/ecc/` (user scope) OR `<project>/.claude/rules/ecc/` + `skills/ecc/` (project scope — team profile default)
189
+ - BMad in `_bmad/` if BMad subset ≠ none
190
+ - Caveman in `~/.claude/plugins/cache/caveman/` if Caveman subset ≠ none
191
+ - MCPs registered with Claude Code via `claude mcp add`
192
+ - Secrets in `~/.claude/.env.flow` (chmod 600) if any `api_token` MCP was selected
193
+
194
+ ---
195
+
196
+ ## 3. Daily story workflow
197
+
198
+ The per-story phase chain is **Claude Code only** — it's LLM-driven and the CLI doesn't have an equivalent. Inside Claude Code:
199
+
200
+ ```
201
+ /flow-story # advance the active story to its next phase
202
+ /flow-story E1-001 # advance a specific story
203
+ /flow-story status # show the current story-id without advancing
204
+ ```
205
+
206
+ Phases chain automatically:
207
+
208
+ ```
209
+ plan → /prp-implement → /code-review → /update-docs → /prp-commit → /prp-pr
210
+ ```
211
+
212
+ The chain stops on hard halts: CRITICAL review findings, verify failures, e2e failures, PR open (waiting for merge).
213
+
214
+ To run a specific phase manually without going through `/flow-story`:
215
+
216
+ ```
217
+ /plan
218
+ /prp-implement
219
+ /code-review
220
+ /update-docs
221
+ /prp-commit
222
+ /prp-pr
223
+ ```
224
+
225
+ Most users never call these directly — `/flow-story` dispatches to the right one.
226
+
227
+ ---
228
+
229
+ ## 4. Sprint state management
230
+
231
+ Sprint state lives in `docs/flow/sprint.yaml`. Mutate via either surface:
232
+
233
+ ### a. Inside Claude Code (slash)
234
+
235
+ ```
236
+ /flow-sprint add "Story title" --epic E1
237
+ /flow-sprint next
238
+ /flow-sprint status
239
+ /flow-sprint done E1-001
240
+ /flow-sprint done E1-001 --note "PR auto-merged"
241
+ /flow-sprint deferred
242
+ /flow-sprint retro E1
243
+ /flow-sprint scope-review
244
+ /flow-sprint import-bmad
245
+ ```
246
+
247
+ ### b. Headless CLI (pure-YAML ops, no LLM)
248
+
249
+ ```bash
250
+ flow sprint status
251
+ flow sprint status --json
252
+
253
+ flow sprint next # pick first backlog story
254
+ flow sprint next --epic E2 # restrict to one epic
255
+
256
+ flow sprint add --id E1-003 --title "New thing" --epic E1
257
+ flow sprint add --id E1-004 --title "Tagged work" --epic E1 \
258
+ --tags cli,ux --why "Closes the X gap"
259
+
260
+ flow sprint done E1-002
261
+ flow sprint done E1-002 --note "PR auto-merged"
262
+ flow sprint done E1-002 --force # bypass review-only gate
263
+
264
+ flow sprint deferred
265
+ flow sprint deferred --json
266
+
267
+ flow sprint import-bmad # one-shot BMad migration
268
+ ```
269
+
270
+ ### c. What stays slash-only
271
+
272
+ LLM-driven subcommands (`retro`, `scope-review`) live in `skills/flow-sprint/workflow.md` and don't have a CLI equivalent. They synthesize across multiple inputs (story files, git history, deferred items) using the LLM. A CLI stub would inevitably drift from the skill behavior — see [ROADMAP.md](../ROADMAP.md) principle #6.
273
+
274
+ ### d. Sprint YAML round-trip preservation
275
+
276
+ Flow uses the `yaml` library's Document API rather than parse-then-stringify, so your hand-edited comments, blank lines, and key ordering in `sprint.yaml` survive every mutation. You can confidently put load-bearing notes in the file.
277
+
278
+ ---
279
+
280
+ ## 5. Profiles and customization
281
+
282
+ Profiles are pre-built bundles. Pick one based on your situation. Full reference: [profiles.md](profiles.md).
283
+
284
+ | Profile | Best for | Tokens/story | Default ECC scope |
285
+ |---|---|---:|---|
286
+ | `minimal` | Bare Flow, no upstreams | <10k | user |
287
+ | `mini` | Solo dev, one repo | ~20k | user |
288
+ | `standard` | Solo/small team, formal review | ~40k | user |
289
+ | `team` | Multi-LLM review, Linear-driven | ~60k | **project** |
290
+
291
+ ### a. Inspect a profile without installing
292
+
293
+ ```bash
294
+ flow plan --profile team
295
+ flow plan --profile team --json
296
+ ```
297
+
298
+ ### b. Override individual adapters
299
+
300
+ ```bash
301
+ # Add an adapter on top of a profile's defaults:
302
+ flow init --profile mini --with adapter:e2e-playwright-mcp --yes
303
+
304
+ # Remove a profile-default adapter:
305
+ flow init --profile standard --without adapter:issue-tracker-github-issues --yes
306
+ ```
307
+
308
+ ### c. Swap profile mid-life
309
+
310
+ ```bash
311
+ flow init --update --profile team # mini → team
312
+ flow init --update --profile team --dry-run # preview deltas first
313
+ ```
314
+
315
+ `--update` reads recorded answers from `install-state.json`, applies the new profile's defaults for any answer the user didn't pin via CLI, and re-runs the chain. See [Section 8](#8-updating-an-existing-install).
316
+
317
+ ### d. Add or remove single components
318
+
319
+ ```bash
320
+ flow add adapter:e2e-playwright-mcp # adds + installs
321
+ flow add adapter:issue-tracker-linear # swaps issue-tracker family
322
+ flow remove adapter:pr-github # removes
323
+ ```
324
+
325
+ `flow add` and `flow remove` are the canonical adapter-swap mechanism. `flow.config.yaml` hand-edit also works — both routes update install-state.
326
+
327
+ ---
328
+
329
+ ## 6. ECC install scope
330
+
331
+ ECC content can land at two locations:
332
+
333
+ - **user scope:** `~/.claude/rules/ecc` + `~/.claude/skills/ecc` (shared across all your projects)
334
+ - **project scope:** `<projectRoot>/.claude/rules/ecc` + `<projectRoot>/.claude/skills/ecc` (per-repo isolation)
335
+
336
+ The team profile defaults to **project** scope so each Flow-managed repo keeps its own ECC selection. All other stock profiles default to **user** scope.
337
+
338
+ ### a. Override at install time
339
+
340
+ ```bash
341
+ flow init --profile team --ecc-scope user --yes # team but user-scope
342
+ flow init --profile mini --ecc-scope project --yes # mini but project-scope
343
+ flow plan --profile mini --ecc-scope project # preview
344
+ ```
345
+
346
+ Typos like `--ecc-scope=projet` fail loud with a clear error — silent fallback to the profile default would be a confusing UX.
347
+
348
+ ### b. Distribution caveat
349
+
350
+ ECC's `claude-project` install target merged into ECC's `main` branch via [affaan-m/ECC#2006](https://github.com/affaan-m/ECC/pull/2006) on 2026-05-19, but the current `ecc-universal@latest` is `1.10.0` (from 2026-04-15), which predates the merge. Flow's `catalog.yaml` pins to a post-merge github commit (`npx -y -p "github:affaan-m/ECC#98bd5174" ecc-install`) until ECC publishes a 2.x release.
351
+
352
+ You don't have to do anything — Flow's installer handles this transparently. The catalog's `cmd_fallback` field will get swapped back to `npx ecc-universal install` the day ECC 2.x publishes.
353
+
354
+ ### c. Detect scope drift
355
+
356
+ ```bash
357
+ flow doctor # reports both scopes if present
358
+ ```
359
+
360
+ The doctor probe surfaces a `Collisions` section when ECC content exists at BOTH `~/.claude/rules/ecc` AND `<cwd>/.claude/rules/ecc`. Common cause: a user switched `--ecc-scope` between installs without uninstalling first. The probe reads `install-state.json` to identify the active scope and suggests `rm -rf <stale_dir>`.
361
+
362
+ ---
363
+
364
+ ## 7. Health checks and maintenance
365
+
366
+ ### a. `flow doctor` — health check
367
+
368
+ ```bash
369
+ flow doctor # human-readable
370
+ flow doctor --json # scriptable
371
+ flow doctor --verbose # extra detail
372
+ ```
373
+
374
+ Reports:
375
+ - Catalog: parse + schema validation
376
+ - Install state: home + project-scope `install-state.json` presence/validity
377
+ - Config: `flow.config.yaml` presence, required keys
378
+ - Adapters: files present at expected paths (symlink-vs-regular-file detection)
379
+ - CLIs: required CLIs in `$PATH` for the active adapters
380
+ - Upstreams: BMad/ECC/Caveman version pins vs recorded values
381
+ - Collisions: ECC dual-scope content (E7-004)
382
+
383
+ Exit codes:
384
+ - `0` — all OK or only informational
385
+ - `1` — at least one warning
386
+ - `2` — at least one failure
387
+
388
+ ### b. Repair upstream installer pins
389
+
390
+ ```bash
391
+ flow doctor --repair-upstream bmad
392
+ flow doctor --repair-upstream ecc
393
+ flow doctor --repair-upstream caveman
394
+ ```
395
+
396
+ Prints (does NOT auto-run) the exact reinstall commands for one upstream, parameterized by the pinned version recorded in `install-state.json`. For ECC, output is scope-aware — user-scope vs project-scope produces different commands.
397
+
398
+ ### c. Re-register MCPs that drifted
399
+
400
+ There's no dedicated `flow mcp` command; running `flow init --update` re-registers any MCPs missing from `claude mcp list`. The `mcp.js` dispatcher is idempotent — already-registered MCPs are skipped.
401
+
402
+ ---
403
+
404
+ ## 8. Updating an existing install
405
+
406
+ `flow init --update` re-runs the chain against an existing install with the same — or overridden — answers.
407
+
408
+ ### a. No-op check
409
+
410
+ ```bash
411
+ flow init --update
412
+ ```
413
+
414
+ Reads `install-state.json`, computes the delta against the resolved profile, and reports "No changes — install matches the requested state." Useful as a sanity check.
415
+
416
+ ### b. Swap profile
417
+
418
+ ```bash
419
+ flow init --update --profile team
420
+ flow init --update --profile team --dry-run # preview deltas first
421
+ ```
422
+
423
+ Output shows per-key deltas before applying:
424
+
425
+ ```
426
+ ━━━ flow init (update) ━━━
427
+ was: profile=mini → now: profile=team cwd=... dry-run=false
428
+
429
+ Changes:
430
+ Δ profile: mini → team
431
+ Δ issueTracker: github-issues → linear
432
+ Δ bmadSubset: none → full
433
+ Δ eccSubset: flow-essentials → flow-essentials-plus-tdd
434
+ Δ eccScope: user → project
435
+ ```
436
+
437
+ ### c. Bump individual knobs
438
+
439
+ ```bash
440
+ flow init --update --bmad-subset full
441
+ flow init --update --ecc-subset security
442
+ ```
443
+
444
+ ### d. Force-rewrite flow.config.yaml
445
+
446
+ ```bash
447
+ flow init --update --force
448
+ ```
449
+
450
+ Useful when the catalog template logic changed between Flow versions and you want your `flow.config.yaml` regenerated even though nothing in your answers changed.
451
+
452
+ ### e. What `--update` refuses
453
+
454
+ `--update` halts with an explicit uninstall+reinstall recipe when:
455
+
456
+ - **install_scope changes** (user → project or vice versa). Scope swaps need filesystem cleanup at the old location. The error message includes the exact `flow uninstall` command including `--remove-project-ecc` when applicable.
457
+
458
+ ```
459
+ ✗ flow init --update: install_scope change (user → project) is not supported mid-flight
460
+ Suggested:
461
+ flow uninstall --execute --yes
462
+ flow init --profile team --ecc-scope project --yes
463
+ ```
464
+
465
+ ### f. What `--update` does NOT do
466
+
467
+ - Doesn't *remove* MCPs you've unselected (destructive; explicit `claude mcp remove` needed)
468
+ - Doesn't *uninstall* upstreams whose subset changed to `none` (manual cleanup)
469
+ - Doesn't run `git pull` on `_bmad/` or `~/.claude/rules/ecc/` — version pinning stays whatever the upstream installer wrote
470
+
471
+ ---
472
+
473
+ ## 9. Repairing a broken install
474
+
475
+ Use `flow init --repair` when scaffold files have been deleted but the install otherwise looks intact:
476
+
477
+ ```bash
478
+ flow init --repair # restore missing docs/flow/sprint.yaml etc.
479
+ flow init --repair --dry-run # preview
480
+ ```
481
+
482
+ ### a. What `--repair` does
483
+
484
+ - Loads `profile` + `answers` from `install-state.json`
485
+ - Runs `scaffold()` with `force: false` so existing files are preserved
486
+ - Recreates ONLY the missing scaffold files (sprint.yaml, deferred.md, install-state.json, etc.)
487
+ - Skips upstream installers, MCP registration, BMad migration entirely
488
+
489
+ ### b. What `--repair` refuses
490
+
491
+ - No `install-state.json` present → exit 1 with hint to run `flow init --profile <name> --yes` for a fresh install
492
+ - Corrupt `install-state.json` → exit 2 with parse error
493
+
494
+ ### c. When to use `--repair` vs `--update`
495
+
496
+ | Symptom | Command |
497
+ |---|---|
498
+ | `docs/flow/sprint.yaml` deleted | `flow init --repair` |
499
+ | `flow.config.yaml` deleted | `flow init --repair` |
500
+ | Want to swap profile | `flow init --update --profile <new>` |
501
+ | Want to change ECC scope | `flow uninstall ... && flow init ...` |
502
+ | Want to rotate MCP api_token | `flow init --update` (re-prompts) |
503
+ | Recorded answers look right but `flow doctor` reports drift | `flow init --repair` first; if not enough, `--update` |
504
+
505
+ ---
506
+
507
+ ## 10. Uninstalling
508
+
509
+ ### a. Project-scope (default)
510
+
511
+ ```bash
512
+ flow uninstall # dry-run by default
513
+ flow uninstall --execute --yes # actually remove
514
+ ```
515
+
516
+ Removes:
517
+ - `<project>/.claude/flow/` (install-state, runtime state)
518
+ - `<project>/flow.config.yaml` + `flow.config.local.yaml`
519
+ - (with `--remove-stories`) `<project>/docs/flow/`
520
+ - (with `--remove-project-ecc`) `<project>/.claude/rules/ecc/` + `<project>/.claude/skills/ecc/`
521
+
522
+ Keeps:
523
+ - `<project>/docs/flow/` (your stories — your content) unless `--remove-stories`
524
+ - `<project>/.claude/rules/ecc/` and `skills/ecc/` unless `--remove-project-ecc`
525
+ - BMad, user-scope ECC, Caveman (owned by their respective installers)
526
+
527
+ ### b. Home-scope
528
+
529
+ ```bash
530
+ flow uninstall --scope home --execute --yes
531
+ ```
532
+
533
+ Removes:
534
+ - `~/.claude/skills/{flow-init,flow-sprint,flow-story,flow-doctor}/`
535
+ - `~/.claude/flow/`
536
+
537
+ ### c. Both scopes
538
+
539
+ ```bash
540
+ flow uninstall --scope both --execute --yes --remove-stories --remove-project-ecc
541
+ ```
542
+
543
+ ### d. Removing the upstream installers themselves
544
+
545
+ Flow does NOT remove BMad, ECC, or Caveman because they were installed by their own installers. `flow uninstall` prints the manual commands at the end:
546
+
547
+ ```
548
+ BMad: rm -rf _bmad/ docs/_bmad-output/ (or `npx bmad-method uninstall`)
549
+ ECC: ~/.claude/rules/uninstall.sh (or rm -rf ~/.claude/rules/)
550
+ Caveman: rm -rf ~/.claude/plugins/cache/caveman/ and `claude mcp remove caveman-shrink`
551
+ ```
552
+
553
+ ### e. Refused without `--yes`
554
+
555
+ `--execute` without `--yes` shows the plan + asks for explicit confirmation:
556
+
557
+ ```
558
+ ⚠ About to remove the above. Re-run with --execute --yes to confirm.
559
+ ```
560
+
561
+ This is intentional — `--execute` alone won't accidentally delete files.
562
+
563
+ ---
564
+
565
+ ## 11. Inside Claude Code — slash command reference
566
+
567
+ The slash commands have CLI equivalents for the LLM-free operations:
568
+
569
+ | Slash (Claude Code) | Headless CLI | LLM dependency |
570
+ |---|---|---|
571
+ | `/flow-init` | `flow init --yes` | None |
572
+ | `/flow-init --update` | `flow init --update` | None |
573
+ | `/flow-init --repair` | `flow init --repair` | None |
574
+ | `/flow-sprint add` | `flow sprint add` | None |
575
+ | `/flow-sprint next` | `flow sprint next` | None |
576
+ | `/flow-sprint status` | `flow sprint status` | None |
577
+ | `/flow-sprint done` | `flow sprint done` | None |
578
+ | `/flow-sprint deferred` | `flow sprint deferred` | None |
579
+ | `/flow-sprint import-bmad` | `flow sprint import-bmad` | None |
580
+ | `/flow-sprint retro` | — | **Yes** (synthesizes archive + git log + retros) |
581
+ | `/flow-sprint scope-review` | — | **Yes** (audits scope creep across the sprint) |
582
+ | `/flow-doctor` | `flow doctor` | Some (probes MCP responsiveness) |
583
+ | `/flow-story` | — | **Yes** (per-story phase chain) |
584
+
585
+ Inside Claude Code, default to slash. Outside Claude Code, the CLI covers everything except `/flow-story`, `retro`, and `scope-review`.
586
+
587
+ ---
588
+
589
+ ## 12. Complete CLI flag reference
590
+
591
+ ### Global flags (work on every command)
592
+
593
+ | Flag | Meaning |
594
+ |---|---|
595
+ | `--yes`, `-y` | Skip confirmation prompts (CI mode) |
596
+ | `--dry-run` | Print plan, don't execute |
597
+ | `--json` | Machine-readable output |
598
+ | `--force` | Overwrite existing files |
599
+ | `--verbose` | Show extra detail |
600
+ | `--scope home\|project\|both` | Install/uninstall scope |
601
+
602
+ ### `flow init` flags
603
+
604
+ | Flag | Meaning |
605
+ |---|---|
606
+ | `--profile <name>` | minimal / mini / standard / team |
607
+ | `--update` | Re-run chain against existing install |
608
+ | `--repair` | Recreate missing scaffold (no upstreams) |
609
+ | `--ecc-scope user\|project` | Override profile's ECC scope |
610
+ | `--bmad-subset <name>` | Override BMad subset |
611
+ | `--ecc-subset <name>` | Override ECC subset |
612
+ | `--with adapter:<id>` | Add an adapter to the profile bundle |
613
+ | `--without adapter:<id>` | Remove a profile-default adapter |
614
+ | `--continue-on-error` | Don't halt at first upstream failure |
615
+ | `--migrate-bmad` | Run BMad migration (if BMad detected) |
616
+
617
+ ### `flow sprint <subcommand>` flags
618
+
619
+ | Subcommand | Required / common flags |
620
+ |---|---|
621
+ | `status` | `--json` |
622
+ | `next` | `--epic <id>` (optional) |
623
+ | `add` | `--id <id> --title <t> --epic <E?>`, plus `--tags`, `--why`, `--issue`, `--status` |
624
+ | `done <id>` | `--note <s>`, `--force` |
625
+ | `deferred` | `--json` |
626
+ | `import-bmad` | `--project <name>` |
627
+
628
+ ### `flow uninstall` flags
629
+
630
+ | Flag | Meaning |
631
+ |---|---|
632
+ | `--scope project\|home\|both` | Default: project |
633
+ | `--execute` | Required to actually remove (otherwise dry-run) |
634
+ | `--yes` | Required with `--execute` |
635
+ | `--remove-stories` | Also remove `docs/flow/` (user content) |
636
+ | `--remove-project-ecc` | Also remove `<project>/.claude/{rules,skills}/ecc` |
637
+ | `--remove-backups` | Also remove `*.flow-backup-*` files |
638
+
639
+ ### `flow doctor` flags
640
+
641
+ | Flag | Meaning |
642
+ |---|---|
643
+ | `--repair-upstream <bmad\|ecc\|caveman>` | Print reinstall commands for one upstream |
644
+ | `--mcp <id>` | Probe a specific MCP only |
645
+
646
+ ### `flow plan` flags
647
+
648
+ | Flag | Meaning |
649
+ |---|---|
650
+ | `--profile <name>` | Profile to resolve |
651
+ | `--with`, `--without`, `--ecc-scope` | Same as `flow init` |
652
+ | `--json` | Machine-readable plan |
653
+
654
+ ---
655
+
656
+ ## 13. Common scenarios (recipe book)
657
+
658
+ ### a. Solo dev, single repo, light review
659
+
660
+ ```bash
661
+ flow init --profile mini --yes
662
+ ```
663
+
664
+ ### b. Solo dev with several side projects, want ECC isolation per repo
665
+
666
+ ```bash
667
+ flow init --profile mini --yes --ecc-scope project
668
+ ```
669
+
670
+ ### c. Small team using Linear + Playwright + cross-model code review
671
+
672
+ ```bash
673
+ flow init --profile team --yes
674
+ # team defaults to project-scope ECC + Linear adapter + Playwright MCP
675
+ ```
676
+
677
+ ### d. Just want Flow's state model, no upstreams
678
+
679
+ ```bash
680
+ flow init --profile minimal --yes
681
+ ```
682
+
683
+ ### e. Existing BMad project, want to migrate
684
+
685
+ ```bash
686
+ flow init --profile standard --yes --migrate-bmad
687
+ # Or, after a first install:
688
+ flow sprint import-bmad
689
+ ```
690
+
691
+ ### f. Try before you commit
692
+
693
+ ```bash
694
+ flow plan --profile team # preview profile
695
+ flow init --profile team --yes --dry-run # exercise full chain in dry-run
696
+ ```
697
+
698
+ ### g. Rotate an MCP API token
699
+
700
+ ```bash
701
+ flow init --update # re-prompts for any required env vars
702
+ ```
703
+
704
+ ### h. Profile bump
705
+
706
+ ```bash
707
+ flow init --update --profile team # mini → team
708
+ flow init --update --profile team --dry-run # preview first
709
+ ```
710
+
711
+ ### i. Wrong ECC scope at install time, want to swap
712
+
713
+ ```bash
714
+ flow uninstall --execute --yes --remove-project-ecc
715
+ flow init --profile team --ecc-scope user --yes
716
+ ```
717
+
718
+ ### j. Forgot what's installed
719
+
720
+ ```bash
721
+ flow doctor
722
+ flow doctor --json | jq .
723
+ cat .claude/flow/install-state.json | jq .
724
+ ```
725
+
726
+ ### k. Build a fresh project from scratch in CI
727
+
728
+ ```bash
729
+ # .github/workflows/setup-flow.yml
730
+ - run: npm install -g @mhd-ghaith-abtah/flow@beta
731
+ - run: flow init --profile mini --yes --dry-run # smoke first
732
+ - run: flow init --profile mini --yes # real install
733
+ - run: flow doctor # gate
734
+ ```
735
+
736
+ ### l. Replace Caveman fork once upstream merges
737
+
738
+ When [JuliusBrussee/caveman#407](https://github.com/JuliusBrussee/caveman/pull/407) merges, Flow's `catalog.yaml` will be updated to point at upstream Caveman instead of `mhd-ghaith-abtah/caveman#flow-pin-v0.1`. Users get the swap automatically on the next Flow release. No action required on your end.
739
+
740
+ ### m. Inspect Flow's install scripts before they run
741
+
742
+ ```bash
743
+ export FLOW_INSPECT_INSTALL_SCRIPTS=1
744
+ flow init --profile mini --yes
745
+ # Each upstream halts before exec and prints the command + a hint at
746
+ # how to review the source (e.g. `gh repo view ...` for the Caveman fork).
747
+ ```
748
+
749
+ ### n. Re-run the full install chain after a major version bump
750
+
751
+ ```bash
752
+ npm install -g @mhd-ghaith-abtah/flow@beta # get the new version
753
+ flow init --update --force # rewrite flow.config.yaml + re-run
754
+ ```
755
+
756
+ ### o. Open a fresh `/flow-story` cycle from the CLI
757
+
758
+ You can't — `/flow-story` is LLM-driven. But you can prep the state from the CLI:
759
+
760
+ ```bash
761
+ flow sprint add --id E1-001 --title "Bootstrap" --epic E1 --tags ci,setup
762
+ flow sprint next # flip to doing
763
+ # Then inside Claude Code:
764
+ /flow-story E1-001
765
+ ```
766
+
767
+ ### p. Headless story bookkeeping during a marathon session
768
+
769
+ If you're driving multiple stories from one Claude Code session, the slash command updates sprint.yaml automatically. If you're driving from a script (CI, shell loop), use the CLI:
770
+
771
+ ```bash
772
+ for id in E1-001 E1-002 E1-003; do
773
+ flow sprint done "$id" --note "scripted close"
774
+ done
775
+ flow sprint status
776
+ ```
777
+
778
+ ---
779
+
780
+ ## 14. Environment variables
781
+
782
+ | Variable | Meaning |
783
+ |---|---|
784
+ | `FLOW_REPO_ROOT` | Override catalog/templates location. Used internally when the slash command dispatches to the CLI. |
785
+ | `FLOW_INSPECT_INSTALL_SCRIPTS=1` | Don't auto-run upstream installers. Each dispatcher halts before exec, prints the command + a hint, and returns `inspect_only: true` in the state record. |
786
+ | `FLOW_DEBUG=1` | Show stack traces on CLI errors. |
787
+ | `HOME` | Standard. Used for user-scope paths (`~/.claude/...`) and the secrets file. |
788
+ | `CLAUDECODE` / `CLAUDE_CODE` | Auto-detected. Outside Claude Code, `flow init` falls through to the headless path. Inside, it nudges to the slash command. |
789
+
790
+ ---
791
+
792
+ ## 15. Files Flow writes
793
+
794
+ ### a. Project tree (committed)
795
+
796
+ ```
797
+ <project>/
798
+ ├── .claude/
799
+ │ ├── flow.config.yaml # team-shared, COMMIT THIS
800
+ │ ├── flow/
801
+ │ │ └── install-state.json # what Flow did, COMMIT IT (helps `--repair`, `--update`)
802
+ │ ├── rules/ecc/ # team profile only — owned by ECC, gitignore optional
803
+ │ └── skills/ecc/ # team profile only — owned by ECC, gitignore optional
804
+ └── docs/
805
+ └── flow/
806
+ ├── sprint.yaml # SOURCE OF TRUTH for stories, COMMIT THIS
807
+ ├── deferred.md # open one-liners, COMMIT THIS
808
+ ├── stories/ # active story files, COMMIT THIS
809
+ ├── archive/ # completed stories, COMMIT THIS
810
+ ├── journeys/ # E2E journey definitions, COMMIT THIS
811
+ └── retros/ # epic retros, COMMIT THIS
812
+ ```
813
+
814
+ ### b. Gitignored
815
+
816
+ ```
817
+ flow.config.local.yaml # per-developer overrides
818
+ ```
819
+
820
+ ### c. User-scope (never committed)
821
+
822
+ ```
823
+ ~/.claude/
824
+ ├── skills/{flow-init,flow-sprint,flow-story,flow-doctor}/
825
+ ├── flow/install-state.json # if you installed user-scope
826
+ ├── .env.flow # secrets, chmod 600
827
+ ├── rules/ecc/ # mini/standard profile only
828
+ └── skills/ecc/ # mini/standard profile only
829
+ ```
830
+
831
+ ### d. Backup files from BMad migration
832
+
833
+ ```
834
+ docs/_bmad-output/implementation-artifacts/sprint-status.yaml.flow-backup-<ts>
835
+ docs/_bmad-output/implementation-artifacts/deferred-work.md.flow-backup-<ts>
836
+ ```
837
+
838
+ These get created by `flow sprint import-bmad` (or `/flow-init --migrate-bmad`) before any write. Delete them after you're confident the migration is correct, or pass `--remove-backups` to `flow uninstall`.
839
+
840
+ ---
841
+
842
+ ## 16. Troubleshooting
843
+
844
+ ### a. `flow: command not found`
845
+
846
+ `npm install -g @mhd-ghaith-abtah/flow@beta` didn't put `flow` on `$PATH`. Check `npm config get prefix` — that directory's `bin/` needs to be on your shell `$PATH`. Or use `npx`:
847
+
848
+ ```bash
849
+ npx -y @mhd-ghaith-abtah/flow@beta --version
850
+ ```
851
+
852
+ ### b. `flow init --yes` exits with "ECC upstream failed"
853
+
854
+ The github-pinned ECC fallback can fail if:
855
+
856
+ 1. **No network during install.** `npx -y -p "github:..."` needs to clone. Retry with network access.
857
+ 2. **GitHub rate-limited.** Wait 5 min and retry.
858
+ 3. **The pinned commit was force-pushed away.** Open an issue — Flow needs to re-pin.
859
+
860
+ Workaround: pass `--continue-on-error` to skip past upstream failures and inspect the resulting state with `flow doctor`.
861
+
862
+ ### c. `flow doctor` shows "ECC scope collision"
863
+
864
+ Both `~/.claude/rules/ecc/` and `<project>/.claude/rules/ecc/` exist. Cause: you changed `--ecc-scope` between installs without uninstalling first. The doctor probe reads `install-state.json` to identify the active scope and prints the exact `rm -rf` command for the stale one.
865
+
866
+ ### d. Caveman MCP not active in this session
867
+
868
+ Caveman activates via `~/.claude/hooks/caveman-config.js` on `SessionStart`. If you have `~/.config/caveman/config.json` set to `{"defaultMode": "off"}` (the recommended allowlist mode), drop a `.caveman-enable` marker in the project root:
869
+
870
+ ```bash
871
+ touch .caveman-enable
872
+ ```
873
+
874
+ Flow's `/flow-init` drops this automatically. Restart your Claude Code session for the hook to re-fire.
875
+
876
+ ### e. `flow sprint done E1-002` says "expects 'review' or 'doing'"
877
+
878
+ Story is in a state Flow won't auto-flip to done. Either:
879
+
880
+ - Move it to `review` first (typical when the PR is open and waiting)
881
+ - Pass `--force` to skip the gate (typical for backfilled offline stories)
882
+
883
+ ```bash
884
+ flow sprint done E1-002 --force
885
+ ```
886
+
887
+ ### f. `flow init --repair` says "no install-state.json found"
888
+
889
+ Repair needs an authoritative install to read from. If you never ran `flow init`, run it first:
890
+
891
+ ```bash
892
+ flow init --profile mini --yes
893
+ ```
894
+
895
+ ### g. `flow init --update` says "install_scope change is not supported mid-flight"
896
+
897
+ Scope swaps need filesystem cleanup at the old location. Follow the printed recipe:
898
+
899
+ ```bash
900
+ flow uninstall --execute --yes --remove-project-ecc # cleanup
901
+ flow init --profile team --ecc-scope user --yes # reinstall with new scope
902
+ ```
903
+
904
+ ### h. `npm publish` fails with `EOTP` / `E401`
905
+
906
+ Authentication or 2FA issue. Run `npm login` to refresh auth, then retry the publish with `--otp=<code>`:
907
+
908
+ ```bash
909
+ npm publish --tag beta --access public --otp=123456
910
+ ```
911
+
912
+ ### i. CI fails with `actions/checkout@v4` auth error
913
+
914
+ Transient GitHub Actions infrastructure flake. Rerun the failed jobs:
915
+
916
+ ```bash
917
+ gh run rerun <run-id> --failed
918
+ ```
919
+
920
+ This has hit us 3+ times in 2026-05; consistently resolves on rerun.
921
+
922
+ ### j. Want to start over completely
923
+
924
+ ```bash
925
+ flow uninstall --scope both --execute --yes --remove-stories --remove-project-ecc
926
+ flow init --profile <name> --yes
927
+ ```
928
+
929
+ This blows away Flow + Flow's project content + project-scope ECC. Does NOT remove BMad, user-scope ECC, or Caveman — those need their own uninstall commands (printed at the end of `flow uninstall`).
930
+
931
+ ---
932
+
933
+ ## See also
934
+
935
+ - [Quickstart](quickstart.md) — 10-minute first-install path
936
+ - [Profiles](profiles.md) — per-profile details and ECC scope mechanics
937
+ - [Adapters](adapters.md) — adapter contract and how to add new ones
938
+ - [BMad migration](migrate-from-bmad.md) — specifics on the BMad → Flow state migration
939
+ - [ROADMAP](../ROADMAP.md) — the multi-epic arc + guiding principles
940
+ - [CHANGELOG](../CHANGELOG.md) — what shipped when
@@ -0,0 +1,190 @@
1
+ // lib/commands/install-skills.js — bootstrap Flow's slash commands.
2
+ //
3
+ // Symlinks the four flow-* skills (flow-init, flow-sprint, flow-story,
4
+ // flow-doctor) from the Flow package source into a Claude Code skill
5
+ // directory so /flow-init / /flow-sprint / etc. resolve.
6
+ //
7
+ // This closes the bootstrap gap: `npm install -g @mhd-ghaith-abtah/flow`
8
+ // puts `flow` on $PATH but does NOT make slash commands work in Claude
9
+ // Code — those need to live under ~/.claude/skills/ (home scope) or
10
+ // <project>/.claude/skills/ (project scope, team-commit pattern).
11
+ //
12
+ // Idempotent: re-running is safe. Symlinks pointing at the correct
13
+ // source are skipped. Real directories at the target path refuse
14
+ // overwrite without --force (defensive — could be hand-edited content).
15
+ //
16
+ // Why symlinks (not copies):
17
+ // - Updates to the package propagate automatically. Bug fix in the
18
+ // skill workflow? `npm install -g @latest` and the slash command
19
+ // immediately picks it up — no re-bootstrap.
20
+ // - Disk footprint: 4× <1 kB symlinks instead of 4× ~30 kB copies.
21
+ // The tradeoff: deleting the npm package breaks the slash commands.
22
+ // That's a correct failure mode — uninstalling Flow SHOULD break /flow-*.
23
+
24
+ import { existsSync, lstatSync, mkdirSync, readlinkSync, rmSync, symlinkSync, unlinkSync } from 'node:fs';
25
+ import { resolve, dirname, join } from 'node:path';
26
+ import { fileURLToPath } from 'node:url';
27
+ import chalk from 'chalk';
28
+ import { resolveRepoRoot } from '../repo-root.js';
29
+
30
+ const SKILLS = Object.freeze(['flow-init', 'flow-sprint', 'flow-story', 'flow-doctor']);
31
+
32
+ /**
33
+ * @param {Object} args - yargs-parser output
34
+ * @param {Object} ctx
35
+ */
36
+ export default async function installSkills(args, ctx) {
37
+ const repoRoot = ctx.repoRoot ?? resolveRepoRoot(import.meta.url);
38
+ const sourceSkillsDir = join(repoRoot, 'skills');
39
+ const scope = args.scope ?? 'home';
40
+ const force = Boolean(args.force);
41
+ const dryRun = Boolean(args['dry-run']);
42
+ const cwd = ctx.cwd || process.cwd();
43
+ const homeDir = ctx.home || process.env.HOME;
44
+
45
+ if (!existsSync(sourceSkillsDir)) {
46
+ console.error(chalk.red(`✗ source skills not found at ${sourceSkillsDir}`));
47
+ console.error(chalk.dim(' Repo root or package install path is wrong.'));
48
+ return 2;
49
+ }
50
+
51
+ if (!['home', 'project', 'both'].includes(scope)) {
52
+ console.error(chalk.red(`✗ Unknown scope: ${scope}. Use home | project | both.`));
53
+ return 1;
54
+ }
55
+
56
+ const targets = resolveTargets({ scope, homeDir, cwd });
57
+ if (targets.length === 0) {
58
+ console.error(chalk.red(`✗ no target directories resolved for scope=${scope}`));
59
+ if (scope !== 'project' && !homeDir) console.error(chalk.dim(' $HOME is not set; cannot resolve home scope.'));
60
+ return 1;
61
+ }
62
+
63
+ console.log(chalk.bold('━━━ flow install-skills ━━━'));
64
+ console.log(chalk.dim(` source: ${sourceSkillsDir}`));
65
+ console.log(chalk.dim(` scope: ${scope} ${force ? '(force)' : ''}${dryRun ? ' (dry-run)' : ''}`));
66
+ console.log();
67
+
68
+ let linked = 0;
69
+ let skipped = 0;
70
+ let failed = 0;
71
+ for (const targetDir of targets) {
72
+ console.log(chalk.bold(`Target: ${targetDir}`));
73
+ if (!dryRun) mkdirSync(targetDir, { recursive: true });
74
+ for (const skill of SKILLS) {
75
+ const src = join(sourceSkillsDir, skill);
76
+ const dst = join(targetDir, skill);
77
+ const result = linkOne({ src, dst, force, dryRun });
78
+ if (result.status === 'linked') {
79
+ console.log(` ${chalk.green('+')} ${skill} ${chalk.dim('→ ' + src)}`);
80
+ linked++;
81
+ } else if (result.status === 'already-linked') {
82
+ console.log(` ${chalk.dim('=')} ${skill} ${chalk.dim('(symlink already points to source)')}`);
83
+ skipped++;
84
+ } else if (result.status === 'refused') {
85
+ console.log(` ${chalk.yellow('!')} ${skill} ${chalk.dim('(real directory exists; pass --force to replace)')}`);
86
+ skipped++;
87
+ } else {
88
+ console.log(` ${chalk.red('✗')} ${skill} ${chalk.red(result.error)}`);
89
+ failed++;
90
+ }
91
+ }
92
+ console.log();
93
+ }
94
+
95
+ if (failed > 0) {
96
+ console.error(chalk.red(`✗ ${failed} skill(s) failed to link.`));
97
+ return 1;
98
+ }
99
+
100
+ console.log(chalk.bold(`Done: ${linked} linked, ${skipped} skipped${failed ? `, ${failed} failed` : ''}.`));
101
+ if (dryRun) {
102
+ console.log(chalk.yellow(' (--dry-run: nothing was actually linked)'));
103
+ } else if (linked > 0) {
104
+ console.log();
105
+ console.log(chalk.dim('Slash commands /flow-init, /flow-sprint, /flow-story, /flow-doctor are now'));
106
+ console.log(chalk.dim('available in any Claude Code session for the chosen scope.'));
107
+ }
108
+ return 0;
109
+ }
110
+
111
+ /**
112
+ * Resolve the absolute target dirs based on the scope flag.
113
+ *
114
+ * - home → ~/.claude/skills/ (default; user-wide)
115
+ * - project → <cwd>/.claude/skills/ (team-commit pattern; the skill
116
+ * dir gets committed to the repo so contributors don't each have
117
+ * to bootstrap)
118
+ * - both → both of the above
119
+ */
120
+ function resolveTargets({ scope, homeDir, cwd }) {
121
+ const out = [];
122
+ if (scope === 'home' || scope === 'both') {
123
+ if (homeDir) out.push(join(homeDir, '.claude', 'skills'));
124
+ }
125
+ if (scope === 'project' || scope === 'both') {
126
+ if (cwd) out.push(join(cwd, '.claude', 'skills'));
127
+ }
128
+ return out;
129
+ }
130
+
131
+ /**
132
+ * Attempt to symlink one skill. Possible outcomes:
133
+ * - linked — fresh symlink created (or dry-run no-op)
134
+ * - already-linked — symlink already points to the right source
135
+ * - refused — target exists and isn't ours; need --force
136
+ * - replaced — target was a wrong-source link or (under
137
+ * --force) a real dir; removed + re-linked
138
+ * - error — fs op failed; result.error has the message
139
+ *
140
+ * @returns {{status: 'linked'|'already-linked'|'refused'|'replaced'|'error', error?: string}}
141
+ */
142
+ function linkOne({ src, dst, force, dryRun }) {
143
+ if (existsSync(dst) || lstatSafe(dst)) {
144
+ const stat = lstatSafe(dst);
145
+ if (stat?.isSymbolicLink()) {
146
+ try {
147
+ const current = readlinkSync(dst);
148
+ if (resolve(dirname(dst), current) === src) {
149
+ return { status: 'already-linked' };
150
+ }
151
+ // Wrong-source symlink → safe to replace (it's already a link, not user content).
152
+ // Use unlinkSync rather than rmSync — rmSync on a symlink-to-dir follows
153
+ // the link on macOS and tries to delete the target dir, failing with
154
+ // "Path is a directory".
155
+ if (!dryRun) {
156
+ unlinkSync(dst);
157
+ symlinkSync(src, dst);
158
+ }
159
+ return { status: 'linked' };
160
+ } catch (err) {
161
+ return { status: 'error', error: err.message };
162
+ }
163
+ }
164
+ // Real directory or file at the target.
165
+ if (!force) {
166
+ return { status: 'refused' };
167
+ }
168
+ // --force: replace.
169
+ try {
170
+ if (!dryRun) {
171
+ rmSync(dst, { recursive: true, force: true });
172
+ symlinkSync(src, dst);
173
+ }
174
+ return { status: 'linked' };
175
+ } catch (err) {
176
+ return { status: 'error', error: err.message };
177
+ }
178
+ }
179
+ // Nothing at target → fresh link.
180
+ try {
181
+ if (!dryRun) symlinkSync(src, dst);
182
+ return { status: 'linked' };
183
+ } catch (err) {
184
+ return { status: 'error', error: err.message };
185
+ }
186
+ }
187
+
188
+ function lstatSafe(path) {
189
+ try { return lstatSync(path); } catch { return null; }
190
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mhd-ghaith-abtah/flow",
3
- "version": "0.8.0-beta.0",
3
+ "version": "0.8.0-beta.1",
4
4
  "description": "Token-light per-story workflow for Claude Code. Delegates to BMad + ECC.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -19,6 +19,7 @@
19
19
  "tools/fix-caveman-shrink.sh",
20
20
  "catalog.yaml",
21
21
  "docs/quickstart.md",
22
+ "docs/usage.md",
22
23
  "docs/adapters.md",
23
24
  "docs/profiles.md",
24
25
  "docs/migrate-from-bmad.md",