moflo 4.12.12 → 4.13.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/.claude/guidance/shipped/moflo-cli-reference.md +45 -1
- package/.claude/guidance/shipped/moflo-cross-install-memory-sharing.md +1 -0
- package/.claude/helpers/gate.cjs +33 -4
- package/.claude/skills/fl/phases.md +51 -17
- package/README.md +95 -1
- package/bin/gate.cjs +33 -4
- package/dist/src/cli/commands/index.js +5 -0
- package/dist/src/cli/commands/worktree.js +408 -0
- package/dist/src/cli/config/moflo-config.js +57 -0
- package/dist/src/cli/init/embedded-helpers.js +1 -1
- package/dist/src/cli/services/worktree-provision.js +400 -0
- package/dist/src/cli/version.js +1 -1
- package/package.json +2 -2
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
## CLI Commands (
|
|
7
|
+
## CLI Commands (27 Commands, 140+ Subcommands)
|
|
8
8
|
|
|
9
9
|
### Core Commands
|
|
10
10
|
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
| `epic` | 3 | Epic orchestrator — run/status/reset with single-branch or auto-merge strategy |
|
|
41
41
|
| `doctor` | 1 | System diagnostics with health checks |
|
|
42
42
|
| `completions` | 4 | Shell completions (bash, zsh, fish, powershell) |
|
|
43
|
+
| `worktree` | 3 | Provisioned git worktrees (add, list, remove) — alias `wt` |
|
|
43
44
|
|
|
44
45
|
### Quick Examples (MCP Preferred)
|
|
45
46
|
|
|
@@ -59,6 +60,49 @@ npx flo daemon start
|
|
|
59
60
|
|
|
60
61
|
---
|
|
61
62
|
|
|
63
|
+
## Provisioned Worktrees (`flo worktree`)
|
|
64
|
+
|
|
65
|
+
A bare `git worktree add` produces a valid checkout and an unrunnable workspace — no
|
|
66
|
+
`node_modules`, none of the gitignored `.env` files, and dev servers that collide with the
|
|
67
|
+
primary checkout on fixed ports. `flo worktree add` creates the worktree **and** provisions it.
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
flo worktree add feature/123-thing # create + provision (this is what /flo -wt runs)
|
|
71
|
+
flo worktree add feature/123 --json # {"path":…,"branch":…,"index":0,"provisioned":true}
|
|
72
|
+
flo worktree list # every worktree + its provisioning state
|
|
73
|
+
flo worktree remove feature/123-thing # refuses a dirty tree unless --force
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Provisioning is driven by an optional `worktree:` block in `moflo.yaml`. **With no block, `add`
|
|
77
|
+
creates the worktree and provisions nothing** — identical to a plain `git worktree add`.
|
|
78
|
+
|
|
79
|
+
```yaml
|
|
80
|
+
worktree:
|
|
81
|
+
dir: ../myrepo-worktrees # default: <repo-parent>/<repo>-worktrees
|
|
82
|
+
copy: [".env", ".env.*"] # gitignored files copied from the primary checkout
|
|
83
|
+
link: ["node_modules"] # symlinked (junctioned on Windows) from the primary checkout
|
|
84
|
+
setup: "npm ci" # run in the new worktree, with MOFLO_WORKTREE_INDEX in its env
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
| Key | Use it when | Watch out for |
|
|
88
|
+
|-----|-------------|---------------|
|
|
89
|
+
| `copy` | A fresh checkout is missing gitignored config a build needs | It relocates **secrets** outside the repo and outside its `.gitignore`. Sources must live inside the primary checkout; `../secrets` is rejected. |
|
|
90
|
+
| `link` | `node_modules` is large and the project does not use npm workspaces | A symlinked root `node_modules` is fragile under npm/yarn workspaces — prefer `setup: npm ci` there. An existing destination is never clobbered. |
|
|
91
|
+
| `setup` | Install/build steps must run per workspace | A non-zero exit marks the provision failed but leaves the worktree in place. |
|
|
92
|
+
|
|
93
|
+
**Port collisions.** moflo cannot rewrite a project's hardcoded ports. It gives each worktree a
|
|
94
|
+
small stable integer — unique among live worktrees, reused when one is removed — as
|
|
95
|
+
`MOFLO_WORKTREE_INDEX` in the `setup` command's environment. Offset your own ports from it:
|
|
96
|
+
|
|
97
|
+
```yaml
|
|
98
|
+
worktree:
|
|
99
|
+
setup: "npm ci && node -e \"require('fs').writeFileSync('.env.local','PORT='+(3500+Number(process.env.MOFLO_WORKTREE_INDEX)*20))\""
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Memory needs no setup: durable learnings already converge across a repo's worktrees
|
|
103
|
+
automatically. See `moflo-cross-install-memory-sharing.md` for the snapshot recipe that also
|
|
104
|
+
skips the structural cold-start.
|
|
105
|
+
|
|
62
106
|
## Available Agents
|
|
63
107
|
|
|
64
108
|
The shipped agent roster — each is invoked via the `Agent` tool with `subagent_type: <name>`. The canonical handle is the `name:` frontmatter inside `.claude/agents/**/*.md` (filename may differ from agent name). Aspirational agents that never shipped were retired — `retired-files.json` enforces auto-prune on consumer upgrade.
|
|
@@ -138,3 +138,4 @@ A foreign-writer warning from the Writers Audit check (`flo doctor -c writers`)
|
|
|
138
138
|
- `.claude/guidance/moflo-memory-strategy.md` — Namespaces, RAG indexing, and the durable-vs-derived split this doc builds on
|
|
139
139
|
- `.claude/guidance/moflo-memory-protocol.md` — Search-and-traverse protocol for the shared `learnings` once it is populated
|
|
140
140
|
- `.claude/guidance/moflo-core-guidance.md` — CLI, daemon, and `moflo.yaml` reference (the `memory` config block)
|
|
141
|
+
- `.claude/guidance/moflo-cli-reference.md` — `flo worktree`, which provisions a new worktree's gitignored files, `node_modules`, and per-workspace port index (memory sharing needs no setup; the rest of the workspace does)
|
package/.claude/helpers/gate.cjs
CHANGED
|
@@ -920,10 +920,39 @@ function applyPromptStateReset(state, promptText, opts) {
|
|
|
920
920
|
state.sddMode = detectSddMode(promptText);
|
|
921
921
|
state.activeSddSlug = null;
|
|
922
922
|
}
|
|
923
|
-
// Match npm/yarn/pnpm/bun test, npx vitest|jest|..., bare runners
|
|
924
|
-
// and language-native test commands. The bare-runner arm
|
|
925
|
-
// `npm install jest`, `grep -r vitest src/`, and similar
|
|
926
|
-
|
|
923
|
+
// Match npm/yarn/pnpm/bun/turbo/nx/lerna test, npx vitest|jest|..., bare runners
|
|
924
|
+
// at command-start only, and language-native test commands. The bare-runner arm
|
|
925
|
+
// is anchored so that `npm install jest`, `grep -r vitest src/`, and similar
|
|
926
|
+
// don't false-positive.
|
|
927
|
+
//
|
|
928
|
+
// #1484 — the package-manager arm allows a BOUNDED run of selector tokens
|
|
929
|
+
// between the tool and the script name. Every monorepo invocation puts the
|
|
930
|
+
// workspace selection there (`npm run --prefix packages/api test`,
|
|
931
|
+
// `pnpm --filter @acme/api test`, `yarn workspace @acme/api test`), and the old
|
|
932
|
+
// `<pm> [run] test` shape had no slot for it — so a green suite earned no
|
|
933
|
+
// credit and check-before-pr hard-blocked `gh pr create` with no way out.
|
|
934
|
+
//
|
|
935
|
+
// This arm credits the gate, so every way it can over-match is a way the gate
|
|
936
|
+
// fails OPEN. Four properties bound it, and each is pinned by a test:
|
|
937
|
+
// * separators are HORIZONTAL-only (`[ \t]`, not `\s`). Claude Code runs
|
|
938
|
+
// multi-line Bash blocks as one string, so a `\s` separator would let
|
|
939
|
+
// `npm run build\ntest -f dist/x` bridge a newline into the unrelated Unix
|
|
940
|
+
// `test` builtin and credit a suite that never ran.
|
|
941
|
+
// * the token class excludes shell separators (; & | < > ( ) $ `) so a match
|
|
942
|
+
// can never span `npm run build && rm -rf test`, and excludes `#` so a
|
|
943
|
+
// trailing comment (`npm run build # fix test later`) can't supply the
|
|
944
|
+
// keyword.
|
|
945
|
+
// * the class is NEGATED rather than a positive path class. `[-\w=/.:@]`
|
|
946
|
+
// would pass on POSIX and silently keep missing Windows' `--prefix
|
|
947
|
+
// C:\repo\pkg` form (Rule #1).
|
|
948
|
+
// * the `t` alias keeps its own NARROW arm below — reachable only directly
|
|
949
|
+
// after the package manager, never after selector tokens, so a stray bare
|
|
950
|
+
// `t` argument (`npm run build --env t`) can't credit the gate.
|
|
951
|
+
// The script name keeps its `(?:[:\s]|$)` terminator, so `test-utils`, `test/`
|
|
952
|
+
// and `dist-tags.test` still don't match. The repetition is bounded at 8 and its
|
|
953
|
+
// character classes are disjoint from the separator, so there is no backtracking
|
|
954
|
+
// blowup (27k-char pathological input: 0 ms).
|
|
955
|
+
var TEST_RUNNER_RE = /(?:^|[^a-z])(?:npm|yarn|pnpm|bun|turbo|nx|lerna)[ \t]+(?:[^\s;&|<>()$`#]+[ \t]+){0,8}test(?:[:\s]|$)|(?:^|[^a-z])(?:npm|yarn|pnpm|bun)[ \t]+(?:run[ \t]+)?t(?:[:\s]|$)|\b(?:npx|pnpx)\s+(?:vitest|jest|mocha|ava|tap|jasmine|pytest)\b|(?:^|;|&&|\|\|)\s*(?:vitest|jest|pytest|mocha|jasmine|tap|ava)\s|\b(?:cargo|go|deno|dotnet|mvn)\s+test\b|\bgradle\w*\s+test\b/i;
|
|
927
956
|
// #1322 — failure markers in a test runner's own OUTPUT.
|
|
928
957
|
//
|
|
929
958
|
// This is deliberately not an exit-code check: Claude Code's PostToolUse payload
|
|
@@ -106,30 +106,64 @@ implementation, tests, simplify, commit, and PR from inside it. The current chec
|
|
|
106
106
|
untouched. Durable learnings still converge automatically — a worktree shares the repo's
|
|
107
107
|
`<git-common-dir>/moflo/durable.db` (see `/memory-worktree`).
|
|
108
108
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
109
|
+
Use `flo worktree add`. It computes the path, creates the branch off the repo's default
|
|
110
|
+
branch, and **provisions** the tree per the optional `worktree:` block in `moflo.yaml` — copying
|
|
111
|
+
gitignored `.env` material, linking `node_modules`, running a `setup` command. A fresh worktree is
|
|
112
|
+
otherwise a valid checkout and an unrunnable workspace. Do not hand-roll the path or shell
|
|
113
|
+
`git worktree add` directly: the path computation and the copy/link/setup steps are
|
|
114
|
+
platform-sensitive (Rule #1) and live in tested code.
|
|
112
115
|
|
|
113
116
|
```bash
|
|
114
|
-
|
|
115
|
-
|
|
117
|
+
cd "<repo-root>" && flo worktree add "<type>/<issue-number>-<short-desc>" --json
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Bind the repo root to the call. `flo worktree` resolves the repo from its working directory, and in
|
|
121
|
+
Claude Code that resets between calls — run it from the wrong place and it silently targets a
|
|
122
|
+
different repository (`Not a registered worktree of this repo` on the good day, the wrong repo's
|
|
123
|
+
worktree on the bad one).
|
|
116
124
|
|
|
117
|
-
|
|
118
|
-
# Slug the branch's "/" to "-" so the dir is flat and valid on Windows/macOS/Linux.
|
|
119
|
-
node -e "const p=require('path'),cp=require('child_process');const root=cp.execSync('git rev-parse --show-toplevel').toString().trim();const branch=process.argv[1];const slug=branch.replace(/[\\\\/]/g,'-');const dir=p.join(p.dirname(root),p.basename(root)+'-worktrees',slug);console.log(dir)" "<type>/<issue-number>-<short-desc>"
|
|
125
|
+
It prints one JSON object — read `path` from it:
|
|
120
126
|
|
|
121
|
-
|
|
122
|
-
|
|
127
|
+
```json
|
|
128
|
+
{"path":"/abs/path/to/repo-worktrees/type-123-slug","branch":"type/123-slug","index":0,"provisioned":true}
|
|
123
129
|
```
|
|
124
130
|
|
|
125
|
-
Then
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
131
|
+
Then run **every** remaining phase (implement → tests → simplify → commit → PR) against that
|
|
132
|
+
`path`, and report it to the user.
|
|
133
|
+
|
|
134
|
+
**A bare `cd` does not stick.** In Claude Code the Bash working directory resets to the project root
|
|
135
|
+
after each call, so `cd <path>` in one call and `npm test` in the next runs the test in the WRONG
|
|
136
|
+
tree — the primary checkout — and everything looks fine until the PR contains no changes. Bind the
|
|
137
|
+
directory to each command instead:
|
|
138
|
+
|
|
139
|
+
- shell commands — put the `cd` in the *same* call: `cd "<path>" && npm test`
|
|
140
|
+
- git — prefer `git -C "<path>" status` over cd'ing at all
|
|
141
|
+
- file edits — use the absolute path under `<path>`; never a repo-relative one
|
|
142
|
+
|
|
143
|
+
**Fallback — `flo worktree` not available.** The command ships in the same package as this skill,
|
|
144
|
+
so normally they move together. They can still drift apart: a `flo` binary on PATH older than the
|
|
145
|
+
synced `.claude/skills/`, or a moflo source checkout whose change has not been published and
|
|
146
|
+
reinstalled yet. If the command errors with `Unknown command: worktree`, do NOT stop — create the
|
|
147
|
+
worktree the plain way and continue the run, noting to the user that provisioning was skipped:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
git fetch origin
|
|
151
|
+
node -e "const p=require('path'),cp=require('child_process');const root=cp.execSync('git rev-parse --show-toplevel').toString().trim();const branch=process.argv[1];const dir=p.join(p.dirname(root),p.basename(root)+'-worktrees',branch.replace(/[\\/]/g,'-'));console.log(dir)" "<type>/<issue-number>-<short-desc>"
|
|
152
|
+
git worktree add -b "<type>/<issue-number>-<short-desc>" "<computed-path>" origin/main
|
|
153
|
+
```
|
|
129
154
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
155
|
+
The tree is then a valid checkout with no `node_modules` and no gitignored `.env` files — fine for a
|
|
156
|
+
typecheck-only ticket, and not for one that runs the app.
|
|
157
|
+
|
|
158
|
+
Notes:
|
|
159
|
+
- `--from <ref>` overrides the base ref (default: the repo's default branch via `origin/HEAD`).
|
|
160
|
+
- `provisioned: false` means a copy/link/setup step failed — the worktree is still a usable
|
|
161
|
+
checkout. Surface the failing step to the user rather than silently continuing to run tests that
|
|
162
|
+
will fail for want of a dependency.
|
|
163
|
+
- If the branch's worktree already exists (a prior run), `add` reuses it rather than deleting it.
|
|
164
|
+
- Leave the worktree in place after the PR — the user may want to inspect it. Clean up with
|
|
165
|
+
`flo worktree remove "<branch>"` (it refuses a tree with uncommitted changes unless `--force`).
|
|
166
|
+
`flo worktree list` shows every worktree and its provisioning state.
|
|
133
167
|
|
|
134
168
|
### 3.3 Implement
|
|
135
169
|
Follow the plan from the ticket.
|
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="https://raw.githubusercontent.com/eric-cielo/moflo/main/docs/
|
|
2
|
+
<img src="https://raw.githubusercontent.com/eric-cielo/moflo/main/docs/Moflo_wide.png?v=7" alt="MoFlo" />
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
# MoFlo
|
|
@@ -349,6 +349,89 @@ Inside Claude Code, the `/flo` (or `/fl`) slash command drives GitHub issue exec
|
|
|
349
349
|
|
|
350
350
|
Flags compose: e.g. `/flo -sd -m <issue>` runs the SDD cycle and auto-merges. Each modifier has a `--no-*` form (`--no-sdd`, `--no-verify`, `--no-merge`) to override a `moflo.yaml` default for a single run — including `--no-verify`, since verify-before-done is on by default. For full options and details, type `/flo` with no arguments — Claude Code will display the complete skill documentation. Also available as `/fl`.
|
|
351
351
|
|
|
352
|
+
### Provisioned worktrees (`-w` / `flo worktree`)
|
|
353
|
+
|
|
354
|
+
Running two tickets at once means two worktrees, and a bare `git worktree add` gives you a valid
|
|
355
|
+
checkout that you cannot actually run: no `node_modules`, none of your gitignored `.env` files, and
|
|
356
|
+
dev servers that fight the primary checkout over the same ports. `/flo -w` drives `flo worktree add`,
|
|
357
|
+
which creates the worktree **and** provisions it.
|
|
358
|
+
|
|
359
|
+
Provisioning is opt-in per project. **With no `worktree:` block in `moflo.yaml`, `flo worktree add`
|
|
360
|
+
creates the worktree and provisions nothing** — exactly what a plain `git worktree add` would do.
|
|
361
|
+
|
|
362
|
+
```yaml
|
|
363
|
+
worktree:
|
|
364
|
+
dir: ../myrepo-worktrees # default: <repo-parent>/<repo>-worktrees
|
|
365
|
+
copy: [".env", ".env.*"] # gitignored files copied from the primary checkout
|
|
366
|
+
link: ["node_modules"] # symlinked (junctioned on Windows) from the primary checkout
|
|
367
|
+
setup: "npm ci" # run inside the new worktree after copy/link
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
| Key | Reach for it when | Watch out for |
|
|
371
|
+
|-----|-------------------|---------------|
|
|
372
|
+
| `copy` | A fresh checkout is missing gitignored config your build needs | It relocates **secrets** outside the repo, and outside its `.gitignore`. Sources must live inside the primary checkout — `../secrets` is refused. |
|
|
373
|
+
| `link` | `node_modules` is large and you are not using npm workspaces | A symlinked root `node_modules` is fragile under npm/yarn workspaces — prefer `setup: npm ci` there. An existing path is never clobbered. |
|
|
374
|
+
| `setup` | Install or build steps must run per workspace | A non-zero exit marks the provision failed but leaves the worktree in place. |
|
|
375
|
+
|
|
376
|
+
**Ports.** MoFlo cannot rewrite your hardcoded ports — it has no way to know which files hold them.
|
|
377
|
+
Instead each worktree gets a small integer, unique among live worktrees and reused when one is
|
|
378
|
+
removed, exported to the `setup` command as `MOFLO_WORKTREE_INDEX`. Offset your own ports from it:
|
|
379
|
+
|
|
380
|
+
```yaml
|
|
381
|
+
worktree:
|
|
382
|
+
setup: "npm ci && node -e \"require('fs').writeFileSync('.env.local','PORT='+(3000+Number(process.env.MOFLO_WORKTREE_INDEX)*20))\""
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
`flo worktree remove` refuses a tree with uncommitted changes unless you pass `--force`, and names
|
|
386
|
+
any gitignored files it discarded that provisioning did not create. MoFlo's own
|
|
387
|
+
`.moflo/worktree.json` never counts as "uncommitted work" — otherwise every worktree it created
|
|
388
|
+
would demand `--force` — but un-pushed specs under `.moflo/specs/` do.
|
|
389
|
+
|
|
390
|
+
Memory needs no setup at all: durable learnings already converge across a repo's worktrees
|
|
391
|
+
automatically — see [Sharing learnings across installations](#sharing-learnings-across-installations).
|
|
392
|
+
|
|
393
|
+
#### Running it inside a Claude session
|
|
394
|
+
|
|
395
|
+
`flo worktree` is a plain CLI command with no MCP wrapper, so it works the same whether you type it
|
|
396
|
+
in a terminal or Claude runs it through Bash. `/flo -w` takes the second path — that is all the flag
|
|
397
|
+
does.
|
|
398
|
+
|
|
399
|
+
One thing to know if you drive it yourself from a session, and the reason `/flo -w` handles it for
|
|
400
|
+
you: **Claude Code resets the Bash working directory to the project root after every call.** Two
|
|
401
|
+
consequences, both silent when you get them wrong:
|
|
402
|
+
|
|
403
|
+
```bash
|
|
404
|
+
# ✗ the cd is gone by the next call — this resolves the WRONG repo
|
|
405
|
+
cd path/to/repo
|
|
406
|
+
flo worktree add feature/42-thing --json
|
|
407
|
+
|
|
408
|
+
# ✓ bind the directory to the call
|
|
409
|
+
cd path/to/repo && flo worktree add feature/42-thing --json
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
```bash
|
|
413
|
+
# ✗ runs the tests in the PRIMARY checkout; the run goes green and the PR is empty
|
|
414
|
+
cd "$WORKTREE"
|
|
415
|
+
npm test
|
|
416
|
+
|
|
417
|
+
# ✓ bind it, or skip cd entirely where the tool supports it
|
|
418
|
+
cd "$WORKTREE" && npm test
|
|
419
|
+
git -C "$WORKTREE" status
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
`flo worktree` resolves the repository from its working directory, so a call made from the wrong
|
|
423
|
+
place targets a different repository — usually reported as `Not a registered worktree of this repo`,
|
|
424
|
+
occasionally as work landing somewhere you did not intend. When editing files in the worktree, use
|
|
425
|
+
absolute paths under the path `add` printed rather than repo-relative ones.
|
|
426
|
+
|
|
427
|
+
Read the worktree location from `--json` rather than reconstructing it; the sibling-directory
|
|
428
|
+
convention lives in one tested function, and a second copy of that rule will drift from it.
|
|
429
|
+
|
|
430
|
+
If you are on a `flo` older than the skills synced into `.claude/` — which happens in a MoFlo source
|
|
431
|
+
checkout before a change is published, or when a global `flo` lags the project's devDependency —
|
|
432
|
+
the command reports `Unknown command: worktree`. `/flo -w` falls back to a plain `git worktree add`
|
|
433
|
+
and tells you provisioning was skipped, rather than failing the run.
|
|
434
|
+
|
|
352
435
|
### Spec-Driven Development (SDD)
|
|
353
436
|
|
|
354
437
|
`/flo` can run the full **spec → plan → (review) → implement → verify** cycle — the 2026 agentic-coding pattern — with two independent modifiers. Turning SDD on is opt-in, but once a run is armed for it (via `-sd` or `sdd.default`) **both halves are enforced**: the front half by an implement gate, the back half by verify-before-done.
|
|
@@ -637,6 +720,17 @@ flo gate prompt-reminder # Context bracket tracking
|
|
|
637
720
|
flo gate session-reset # Reset gate state
|
|
638
721
|
```
|
|
639
722
|
|
|
723
|
+
### Worktrees
|
|
724
|
+
|
|
725
|
+
```bash
|
|
726
|
+
flo worktree add feature/123-thing # Create a worktree and provision it (alias: flo wt)
|
|
727
|
+
flo worktree add feature/123 --json # {"path":…,"branch":…,"index":0,"provisioned":true}
|
|
728
|
+
flo worktree add feature/123 --from v2.1.0 # Branch off a specific ref
|
|
729
|
+
flo worktree add feature/123 --no-provision # Create it, skip copy/link/setup
|
|
730
|
+
flo worktree list # Every worktree and its provisioning state
|
|
731
|
+
flo worktree remove feature/123-thing # Refuses a dirty tree unless --force
|
|
732
|
+
```
|
|
733
|
+
|
|
640
734
|
### Diagnostics
|
|
641
735
|
|
|
642
736
|
```bash
|
package/bin/gate.cjs
CHANGED
|
@@ -920,10 +920,39 @@ function applyPromptStateReset(state, promptText, opts) {
|
|
|
920
920
|
state.sddMode = detectSddMode(promptText);
|
|
921
921
|
state.activeSddSlug = null;
|
|
922
922
|
}
|
|
923
|
-
// Match npm/yarn/pnpm/bun test, npx vitest|jest|..., bare runners
|
|
924
|
-
// and language-native test commands. The bare-runner arm
|
|
925
|
-
// `npm install jest`, `grep -r vitest src/`, and similar
|
|
926
|
-
|
|
923
|
+
// Match npm/yarn/pnpm/bun/turbo/nx/lerna test, npx vitest|jest|..., bare runners
|
|
924
|
+
// at command-start only, and language-native test commands. The bare-runner arm
|
|
925
|
+
// is anchored so that `npm install jest`, `grep -r vitest src/`, and similar
|
|
926
|
+
// don't false-positive.
|
|
927
|
+
//
|
|
928
|
+
// #1484 — the package-manager arm allows a BOUNDED run of selector tokens
|
|
929
|
+
// between the tool and the script name. Every monorepo invocation puts the
|
|
930
|
+
// workspace selection there (`npm run --prefix packages/api test`,
|
|
931
|
+
// `pnpm --filter @acme/api test`, `yarn workspace @acme/api test`), and the old
|
|
932
|
+
// `<pm> [run] test` shape had no slot for it — so a green suite earned no
|
|
933
|
+
// credit and check-before-pr hard-blocked `gh pr create` with no way out.
|
|
934
|
+
//
|
|
935
|
+
// This arm credits the gate, so every way it can over-match is a way the gate
|
|
936
|
+
// fails OPEN. Four properties bound it, and each is pinned by a test:
|
|
937
|
+
// * separators are HORIZONTAL-only (`[ \t]`, not `\s`). Claude Code runs
|
|
938
|
+
// multi-line Bash blocks as one string, so a `\s` separator would let
|
|
939
|
+
// `npm run build\ntest -f dist/x` bridge a newline into the unrelated Unix
|
|
940
|
+
// `test` builtin and credit a suite that never ran.
|
|
941
|
+
// * the token class excludes shell separators (; & | < > ( ) $ `) so a match
|
|
942
|
+
// can never span `npm run build && rm -rf test`, and excludes `#` so a
|
|
943
|
+
// trailing comment (`npm run build # fix test later`) can't supply the
|
|
944
|
+
// keyword.
|
|
945
|
+
// * the class is NEGATED rather than a positive path class. `[-\w=/.:@]`
|
|
946
|
+
// would pass on POSIX and silently keep missing Windows' `--prefix
|
|
947
|
+
// C:\repo\pkg` form (Rule #1).
|
|
948
|
+
// * the `t` alias keeps its own NARROW arm below — reachable only directly
|
|
949
|
+
// after the package manager, never after selector tokens, so a stray bare
|
|
950
|
+
// `t` argument (`npm run build --env t`) can't credit the gate.
|
|
951
|
+
// The script name keeps its `(?:[:\s]|$)` terminator, so `test-utils`, `test/`
|
|
952
|
+
// and `dist-tags.test` still don't match. The repetition is bounded at 8 and its
|
|
953
|
+
// character classes are disjoint from the separator, so there is no backtracking
|
|
954
|
+
// blowup (27k-char pathological input: 0 ms).
|
|
955
|
+
var TEST_RUNNER_RE = /(?:^|[^a-z])(?:npm|yarn|pnpm|bun|turbo|nx|lerna)[ \t]+(?:[^\s;&|<>()$`#]+[ \t]+){0,8}test(?:[:\s]|$)|(?:^|[^a-z])(?:npm|yarn|pnpm|bun)[ \t]+(?:run[ \t]+)?t(?:[:\s]|$)|\b(?:npx|pnpx)\s+(?:vitest|jest|mocha|ava|tap|jasmine|pytest)\b|(?:^|;|&&|\|\|)\s*(?:vitest|jest|pytest|mocha|jasmine|tap|ava)\s|\b(?:cargo|go|deno|dotnet|mvn)\s+test\b|\bgradle\w*\s+test\b/i;
|
|
927
956
|
// #1322 — failure markers in a test runner's own OUTPUT.
|
|
928
957
|
//
|
|
929
958
|
// This is deliberately not an exit-code check: Claude Code's PostToolUse payload
|
|
@@ -68,6 +68,11 @@ const commandLoaders = {
|
|
|
68
68
|
epic: () => import('./epic.js'),
|
|
69
69
|
// Spec-Driven Development artifacts (Epic #1269)
|
|
70
70
|
sdd: () => import('./sdd.js'),
|
|
71
|
+
worktree: () => import('./worktree.js'),
|
|
72
|
+
// Alias key, not just `aliases: ['wt']` on the command: lazy commands resolve
|
|
73
|
+
// through `commandLoaders` by name, and an alias declared only on the command
|
|
74
|
+
// object is unreachable until something has already loaded it.
|
|
75
|
+
wt: () => import('./worktree.js'),
|
|
71
76
|
// GitHub Repository Setup
|
|
72
77
|
github: () => import('./github.js'),
|
|
73
78
|
// /flo run ledger + per-run token rollup (#1333).
|