@mhd-ghaith-abtah/flow 0.7.2-beta.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.
Files changed (53) hide show
  1. package/CHANGELOG.md +87 -0
  2. package/LICENSE +21 -0
  3. package/README.md +162 -0
  4. package/adapters/e2e/_interface.md +42 -0
  5. package/adapters/e2e/none.md +15 -0
  6. package/adapters/e2e/playwright-mcp.md +86 -0
  7. package/adapters/issue-tracker/_interface.md +46 -0
  8. package/adapters/issue-tracker/github-issues.md +103 -0
  9. package/adapters/issue-tracker/linear.md +65 -0
  10. package/adapters/issue-tracker/none.md +26 -0
  11. package/adapters/pr/_interface.md +29 -0
  12. package/adapters/pr/github.md +61 -0
  13. package/adapters/pr/none.md +32 -0
  14. package/adapters/verify/_interface.md +26 -0
  15. package/adapters/verify/custom.md +27 -0
  16. package/adapters/verify/make.md +30 -0
  17. package/adapters/verify/pnpm.md +27 -0
  18. package/bin/flow.js +129 -0
  19. package/catalog.yaml +364 -0
  20. package/docs/adapters.md +99 -0
  21. package/docs/migrate-from-bmad.md +95 -0
  22. package/docs/profiles.md +81 -0
  23. package/docs/quickstart.md +82 -0
  24. package/lib/catalog.js +164 -0
  25. package/lib/commands/add.js +147 -0
  26. package/lib/commands/doctor.js +392 -0
  27. package/lib/commands/init.js +86 -0
  28. package/lib/commands/install.js +181 -0
  29. package/lib/commands/plan.js +108 -0
  30. package/lib/commands/remove.js +87 -0
  31. package/lib/commands/uninstall.js +157 -0
  32. package/lib/repo-root.js +53 -0
  33. package/package.json +62 -0
  34. package/schemas/catalog.schema.json +155 -0
  35. package/schemas/flow-config.schema.json +85 -0
  36. package/schemas/install-state.schema.json +79 -0
  37. package/skills/flow-doctor/SKILL.md +15 -0
  38. package/skills/flow-doctor/workflow.md +157 -0
  39. package/skills/flow-init/SKILL.md +10 -0
  40. package/skills/flow-init/workflow.md +420 -0
  41. package/skills/flow-sprint/SKILL.md +10 -0
  42. package/skills/flow-sprint/workflow.md +394 -0
  43. package/skills/flow-story/SKILL.md +12 -0
  44. package/skills/flow-story/workflow.md +531 -0
  45. package/templates/claude-md-section.md.tmpl +55 -0
  46. package/templates/flow-readme.md.tmpl +34 -0
  47. package/templates/flow.config.yaml.tmpl +94 -0
  48. package/templates/pr.md.tmpl +40 -0
  49. package/templates/retro.md.tmpl +58 -0
  50. package/templates/sprint.yaml.tmpl +18 -0
  51. package/templates/story.md.tmpl +35 -0
  52. package/tools/fix-caveman-shrink.sh +68 -0
  53. package/tools/lint-changelog.js +98 -0
@@ -0,0 +1,26 @@
1
+ # No issue tracker adapter
2
+
3
+ All issue-tracker operations are no-ops. sprint.yaml is the source of truth.
4
+
5
+ Story ids use the internal scheme `E<epic>-<NNN>` (e.g. `E1-001`).
6
+
7
+ ## create_issue(title, body, labels)
8
+
9
+ Returns `{ skipped: true, issue_id: null, url: null }`. Flow uses the internal story id.
10
+
11
+ ## transition_to_doing(issue_id)
12
+ Returns `ok`.
13
+
14
+ ## transition_to_review(issue_id, pr_url)
15
+ Returns `ok`.
16
+
17
+ ## transition_to_done(issue_id)
18
+ Returns `ok`.
19
+
20
+ ## verify_merged(issue_id)
21
+
22
+ Returns `true` (no external check). User is responsible for confirming PR is merged before `/flow-sprint done`.
23
+
24
+ ## get_state(issue_id)
25
+
26
+ Returns the `status` field from sprint.yaml for the matching story.
@@ -0,0 +1,29 @@
1
+ # PR Platform Adapter Interface
2
+
3
+ Every pr adapter MUST implement these operations.
4
+
5
+ ## Required operations
6
+
7
+ ### `open_pr(title, body, base, head) → { pr_id, pr_number, url }`
8
+
9
+ Called by `/flow-story` at the commit-pr phase. Open a PR from `head` (current branch) to `base` (default `main`).
10
+
11
+ ### `get_pr_state(pr_id) → { state, mergedAt, reviewDecision }`
12
+
13
+ - `state` ∈ `{open, closed, merged}`
14
+ - `mergedAt` ISO timestamp or null
15
+ - `reviewDecision` ∈ `{approved, changes_requested, review_required, null}`
16
+
17
+ ### `merge_pr(pr_id, method) → ok | { error }`
18
+
19
+ Method ∈ `{squash, merge, rebase}`. flow-sprint done uses `squash` by default.
20
+
21
+ ## Optional operations
22
+
23
+ ### `branch_name(story_id, slug) → string`
24
+
25
+ Convention for branch naming. Default: `flow/<story_id>-<slug>`. Adapters can override (e.g., Linear-style `PLA-42-feature-name`).
26
+
27
+ ### `pr_template(story) → string`
28
+
29
+ Return the body template for a new PR. Default reads `templates/pr.md.tmpl`. Adapters can substitute platform-specific tokens.
@@ -0,0 +1,61 @@
1
+ # GitHub PR adapter
2
+
3
+ Uses `gh` CLI. Same auth as the github-issues adapter.
4
+
5
+ **Dependencies:** `gh` authenticated; remote `origin` is a GitHub repo.
6
+
7
+ ---
8
+
9
+ ## open_pr(title, body, base, head)
10
+
11
+ 1. Push branch if not pushed: `git push -u origin {{head}}`.
12
+ 2. Run:
13
+ ```bash
14
+ gh pr create \
15
+ --title "{{title}}" \
16
+ --body "$(cat <<'EOF'
17
+ {{body}}
18
+ EOF
19
+ )" \
20
+ --base "{{base}}" \
21
+ --head "{{head}}"
22
+ ```
23
+ 3. Parse stdout — last non-empty line is the PR URL.
24
+ 4. Extract `pr_number` from URL.
25
+ 5. Return `{ pr_id: pr_number, pr_number, url }`.
26
+
27
+ ## get_pr_state(pr_id)
28
+
29
+ ```bash
30
+ gh pr view {{pr_id}} --json state,mergedAt,reviewDecision
31
+ ```
32
+
33
+ Map:
34
+ - `state` from GitHub: `OPEN` → `open`, `CLOSED` (no merge) → `closed`, `MERGED` → `merged`
35
+ - `reviewDecision`: `APPROVED` / `CHANGES_REQUESTED` / `REVIEW_REQUIRED` lowercased
36
+
37
+ ## merge_pr(pr_id, method)
38
+
39
+ ```bash
40
+ gh pr merge {{pr_id}} \
41
+ --{{method}} # --squash | --merge | --rebase
42
+ --delete-branch \
43
+ --auto # waits for required checks if needed
44
+ ```
45
+
46
+ If `--auto` is rejected (no required checks configured), retry without `--auto`.
47
+
48
+ ## branch_name(story_id, slug)
49
+
50
+ `flow/{{story_id}}-{{slug}}` (e.g. `flow/E1-001-tokens-base-layout`).
51
+
52
+ If the active issue-tracker is `linear`, override to `{{issue_id}}-{{story_id}}-{{slug}}` so Linear's auto-link recognition works (`PLA-42-...`).
53
+
54
+ ## pr_template(story)
55
+
56
+ Reads `{repo_root}/templates/pr.md.tmpl`. Substitutes:
57
+ - `{{story.title}}`
58
+ - `{{story.id}}`
59
+ - `{{issue_ref}}` — `Fixes #N` (github-issues) or `Closes PLA-42` (linear) or empty
60
+ - `{{summary}}` — first sentence of story's `Why`
61
+ - `{{test_plan}}` — rendered from story's ACs (each AC becomes a `- [ ]` line)
@@ -0,0 +1,32 @@
1
+ # No PR platform adapter
2
+
3
+ All PR operations are no-ops. Commits go straight to `main` (or whatever the default branch is). Flow uses local branches per story but `flow-sprint done` merges via `git merge --ff-only` instead of opening a PR.
4
+
5
+ Use when:
6
+ - Solo project with no review needed
7
+ - Internal scripts / experiments
8
+ - Pre-publish prototypes
9
+
10
+ ## open_pr(title, body, base, head)
11
+
12
+ 1. Switch to base: `git checkout {{base}}`.
13
+ 2. Merge feature branch fast-forward: `git merge --ff-only {{head}}`.
14
+ 3. Push: `git push origin {{base}}`.
15
+ 4. Delete local branch: `git branch -d {{head}}`.
16
+ 5. Return `{ pr_id: "local-merge", pr_number: null, url: null }`.
17
+
18
+ ## get_pr_state(pr_id)
19
+
20
+ Returns `{ state: "merged", mergedAt: <ISO timestamp of local merge>, reviewDecision: null }`.
21
+
22
+ ## merge_pr(pr_id, method)
23
+
24
+ No-op — merge happened at `open_pr` time. Returns `ok`.
25
+
26
+ ## branch_name(story_id, slug)
27
+
28
+ `flow/{{story_id}}-{{slug}}`. Same as github.
29
+
30
+ ## pr_template(story)
31
+
32
+ Returns empty string (no body needed).
@@ -0,0 +1,26 @@
1
+ # Verify Adapter Interface
2
+
3
+ Runs the project's build + test gate. Returns a single pass/fail signal plus the raw output for triage.
4
+
5
+ ## Required operations
6
+
7
+ ### `verify_cmd → string`
8
+
9
+ Return the shell command Flow should execute as the verification gate. Examples:
10
+ - make adapter: `make verify`
11
+ - pnpm adapter: `pnpm verify` (or whatever script name was configured)
12
+ - custom adapter: user-defined command from config
13
+
14
+ ### `run() → { passed, duration_ms, exit_code, stdout, stderr }`
15
+
16
+ Execute `verify_cmd`. Capture exit code + output. Stream to terminal so user sees progress.
17
+
18
+ ## Optional operations
19
+
20
+ ### `on_failure(exit_code, stderr) → string`
21
+
22
+ Return a one-line suggestion for the user (e.g., "Run `/build-fix` to triage the type error").
23
+
24
+ ### `precheck() → ok | { error }`
25
+
26
+ Sanity check before running verify (e.g., for make adapter: confirm Makefile exists and has a `verify` target).
@@ -0,0 +1,27 @@
1
+ # Custom verify adapter
2
+
3
+ User-defined shell command. Use for non-JS stacks or when verify is a one-off compound command.
4
+
5
+ **Config:** `integrations.verify.command` — required, free-form shell string. Examples:
6
+ - Go: `go vet ./... && go test ./... && go build ./...`
7
+ - Rust: `cargo check && cargo clippy --all-targets && cargo test`
8
+ - Python: `ruff check . && pytest && mypy .`
9
+ - Mixed monorepo: `make -C web verify && pytest api/`
10
+
11
+ ---
12
+
13
+ ## verify_cmd
14
+
15
+ `{{config.integrations.verify.command}}`
16
+
17
+ ## precheck
18
+
19
+ `test -n "{{config.integrations.verify.command}}"` → if empty, halt: "Set `integrations.verify.command` in `flow.config.yaml`."
20
+
21
+ ## run
22
+
23
+ Execute via Bash. Stream output. Return `{ passed, duration_ms, exit_code, stdout, stderr }`.
24
+
25
+ ## on_failure(exit_code, stderr)
26
+
27
+ Generic: "Verify command failed. Run directly to see full output: `{{verify_cmd}}`."
@@ -0,0 +1,30 @@
1
+ # Make verify adapter
2
+
3
+ Runs `make verify` (or another target). Standard for repos that wrap their build/test/lint in a Makefile.
4
+
5
+ **Config:** none required. Optional override: `integrations.verify.target` (default `verify`).
6
+
7
+ **Dependencies:** `make` CLI in `$PATH`; `Makefile` at repo root with the configured target.
8
+
9
+ ---
10
+
11
+ ## verify_cmd
12
+
13
+ `make {{config.integrations.verify.target || "verify"}}`
14
+
15
+ ## precheck
16
+
17
+ 1. `test -f Makefile` → if false, halt: "No Makefile at repo root. Either create one with a `{{target}}:` target or switch to `flow adapter swap verify pnpm` / `custom`."
18
+ 2. `grep -q '^{{target}}:' Makefile` → if false, halt: "Makefile is present but has no `{{target}}:` target."
19
+
20
+ ## run
21
+
22
+ 1. Execute `make {{target}}` via Bash, capturing exit code + streaming output.
23
+ 2. Record `duration_ms` from start to finish.
24
+ 3. Return `{ passed: exit_code == 0, duration_ms, exit_code, stdout, stderr }`.
25
+
26
+ ## on_failure(exit_code, stderr)
27
+
28
+ - If stderr contains `error TS` or `Type error`, suggest: "TypeScript errors — try `/build-fix` or run `make typecheck` directly."
29
+ - If stderr contains `eslint`, suggest: "Lint errors — run `make lint --fix` or `pnpm lint --fix`."
30
+ - Otherwise generic: "Verify failed — run `make {{target}}` directly to see full output."
@@ -0,0 +1,27 @@
1
+ # pnpm verify adapter
2
+
3
+ Runs a pnpm script (default `verify`). Use when the project doesn't have a Makefile but exposes a verification chain via package.json scripts.
4
+
5
+ **Config:** `integrations.verify.script` (default `verify`).
6
+
7
+ **Dependencies:** `pnpm` in `$PATH`; `package.json > scripts > {{script}}` defined.
8
+
9
+ ---
10
+
11
+ ## verify_cmd
12
+
13
+ `pnpm {{config.integrations.verify.script || "verify"}}`
14
+
15
+ ## precheck
16
+
17
+ 1. `test -f package.json` → if false, halt.
18
+ 2. `jq -e '.scripts["{{script}}"]' package.json` → if missing, halt: "No `{{script}}` script in package.json. Add one (typical: `\"verify\": \"pnpm typecheck && pnpm lint && pnpm test\"`) or switch verify adapter."
19
+
20
+ ## run
21
+
22
+ Execute `pnpm {{script}}` via Bash, stream output, return `{ passed, duration_ms, exit_code, stdout, stderr }`.
23
+
24
+ ## on_failure(exit_code, stderr)
25
+
26
+ Same suggestion logic as make.md adapter. Plus:
27
+ - If stderr contains `pnpm: command not found`, halt: "Install pnpm: https://pnpm.io/installation."
package/bin/flow.js ADDED
@@ -0,0 +1,129 @@
1
+ #!/usr/bin/env node
2
+ // Flow CLI entry — dispatches to lib/commands/<cmd>.js
3
+ //
4
+ // Detects whether we're running inside a Claude Code session (CLAUDECODE=1 env)
5
+ // or from a terminal. The slash-command path uses the same lib/ functions; this
6
+ // binary is the headless / scriptable / CI path.
7
+
8
+ import { fileURLToPath } from 'node:url';
9
+ import { dirname, resolve } from 'node:path';
10
+ import { readFileSync, existsSync } from 'node:fs';
11
+ import yargsParser from 'yargs-parser';
12
+ import chalk from 'chalk';
13
+
14
+ const __dirname = dirname(fileURLToPath(import.meta.url));
15
+ const REPO_ROOT = resolve(__dirname, '..');
16
+
17
+ const PKG = JSON.parse(readFileSync(resolve(REPO_ROOT, 'package.json'), 'utf-8'));
18
+
19
+ const USAGE = `${chalk.bold('flow')} — ${PKG.description}
20
+
21
+ ${chalk.bold('Usage:')}
22
+ flow <command> [options]
23
+
24
+ ${chalk.bold('Commands:')}
25
+ init Interactive first-time setup (same as /flow-init in Claude Code)
26
+ install Non-interactive install with flags
27
+ plan Dry-run: show the resolved install plan
28
+ status What's installed where
29
+ doctor [--mcp <id>] Health check
30
+ add <component-id> Add a single component
31
+ remove <component-id> Remove a single component
32
+ uninstall Remove Flow from this project (or --scope home for global)
33
+ list-profiles List available profiles
34
+ list-components [--family X] List available components
35
+ list-mcps List MCP servers Flow tracks
36
+ mcp <add|remove|reauth> ... Manage MCP servers
37
+ adapter <swap|list> ... Manage active adapters
38
+ help [command] Show help
39
+
40
+ ${chalk.bold('Common flags:')}
41
+ --profile <name> mini | standard | team | minimal | full
42
+ --bmad-subset <name> none | planning-only | planning-plus-research | creative-thinking | test-architecture | full | passthrough
43
+ --ecc-subset <name> none | flow-essentials | flow-essentials-plus-tdd | security-heavy | research-heavy | use-ecc-default | passthrough
44
+ --with <component> Add a component on top of the profile
45
+ --without <component> Remove a component from the profile
46
+ --scope home|project|both Install scope (default: both)
47
+ --dry-run Print the plan, don't execute
48
+ --json Machine-readable output
49
+ --yes Skip prompts (for CI)
50
+ --catalog-source <url|path> Use an alternate catalog (advanced)
51
+
52
+ ${chalk.bold('Examples:')}
53
+ flow init # interactive
54
+ flow install --profile standard --yes # scripted
55
+ flow install --profile mini --with adapter:e2e-playwright-mcp --yes
56
+ flow plan --profile team --json
57
+ flow status
58
+ flow doctor
59
+ flow uninstall --scope project
60
+
61
+ ${chalk.bold('Inside Claude Code (slash commands — hyphenated):')}
62
+ /flow-init first-time setup (interactive)
63
+ /flow-sprint <subcommand> [args] add | next | status | done | retro | ...
64
+ /flow-story [story-id] advance the active story
65
+
66
+ Version ${PKG.version} · ${chalk.dim(PKG.homepage)}
67
+ `;
68
+
69
+ const COMMANDS = [
70
+ 'init', 'install', 'plan', 'status', 'doctor', 'add', 'remove', 'uninstall',
71
+ 'list-profiles', 'list-components', 'list-mcps', 'mcp', 'adapter', 'help', 'version', '--version'
72
+ ];
73
+
74
+ async function main() {
75
+ const argv = process.argv.slice(2);
76
+
77
+ if (argv.length === 0 || argv[0] === 'help' || argv[0] === '--help' || argv[0] === '-h') {
78
+ console.log(USAGE);
79
+ return 0;
80
+ }
81
+
82
+ if (argv[0] === 'version' || argv[0] === '--version' || argv[0] === '-v') {
83
+ console.log(PKG.version);
84
+ return 0;
85
+ }
86
+
87
+ const cmd = argv[0];
88
+ if (!COMMANDS.includes(cmd)) {
89
+ console.error(chalk.red(`Unknown command: ${cmd}`));
90
+ console.error(`Run ${chalk.bold('flow help')} for usage.`);
91
+ return 1;
92
+ }
93
+
94
+ // Parse remaining args. Note: no global `scope` default — each command sets
95
+ // its own (install: both; uninstall: project, for safety).
96
+ const args = yargsParser(argv.slice(1), {
97
+ string: ['profile', 'bmad-subset', 'ecc-subset', 'with', 'without', 'scope', 'catalog-source', 'mcp', 'family', 'repair-upstream'],
98
+ boolean: ['dry-run', 'json', 'yes', 'execute', 'remove-stories', 'remove-backups', 'archive-unused', 'migrate-bmad', 'verbose'],
99
+ array: ['with', 'without'],
100
+ alias: { y: 'yes' }
101
+ });
102
+
103
+ // Dispatch — each command module exports a default async function(args, ctx)
104
+ const modulePath = resolve(__dirname, '..', 'lib', 'commands', `${cmd}.js`);
105
+ if (!existsSync(modulePath)) {
106
+ console.error(chalk.yellow(`⚠ Command ${chalk.bold(cmd)} not implemented yet (v0.0.1 scaffold).`));
107
+ console.error(` File ${chalk.dim(modulePath)} is missing.`);
108
+ console.error(` Track progress: https://github.com/mhd-ghaith-abtah/flow/issues`);
109
+ return 2;
110
+ }
111
+
112
+ try {
113
+ const mod = await import(modulePath);
114
+ const ctx = {
115
+ repoRoot: REPO_ROOT,
116
+ pkg: PKG,
117
+ cwd: process.cwd(),
118
+ home: process.env.HOME,
119
+ insideClaudeCode: Boolean(process.env.CLAUDECODE || process.env.CLAUDE_CODE),
120
+ };
121
+ return await mod.default(args, ctx);
122
+ } catch (err) {
123
+ console.error(chalk.red(`✗ ${cmd} failed: ${err.message}`));
124
+ if (process.env.FLOW_DEBUG) console.error(err.stack);
125
+ return 1;
126
+ }
127
+ }
128
+
129
+ main().then(code => process.exit(code ?? 0));