Skip to content

feat: add main-session worktree mode for /specflow (#186)#187

Merged
skr19930617 merged 1 commit into
mainfrom
worktree
Apr 25, 2026
Merged

feat: add main-session worktree mode for /specflow (#186)#187
skr19930617 merged 1 commit into
mainfrom
worktree

Conversation

@skr19930617

Copy link
Copy Markdown
Owner

Summary

/specflow no longer hijacks the user's branch. When a change starts, prepare-change creates a dedicated git worktree at .specflow/worktrees/<CHANGE_ID>/main/ (named after the change-id) from the user repo's current HEAD. The <CHANGE_ID> branch lives only inside that worktree; the user's repo stays on whatever branch they were on, with all staged/unstaged/untracked changes preserved.

  • New capability main-session-worktree with full lifecycle (create / reuse / fail-fast / cleanup).
  • LocalRunState gains base_commit, base_branch, cleanup_pending (drift-guard updated).
  • Subagent worktrees re-parented under .specflow/worktrees/<CHANGE_ID>/<RUN_ID>/<BUNDLE_ID>/; WorktreeRuntime.{mainWorkspacePath,changeId} are mandatory and patches now land in the main-session worktree, never the user repo.
  • /specflow.approve pushes from the worktree; PR base resolves from base_commit (single remote match) → base_branch upstream → base_branch itself → repo default branch.
  • /specflow.reject runs inside the worktree and triggers terminal cleanup.
  • Terminal cleanup gate: removes .specflow/worktrees/<CHANGE_ID>/ only on success_full ∧ tree_clean; otherwise records cleanup_pending = true and surfaces dirty paths for retry.
  • Legacy guard refuses to resume worktree_path == repo_path non-synthetic records on prepare-change; watcher fail-fasts on the same condition.
  • 992 tests pass, including new conflict / cleanup-defer / legacy / E2E invariant coverage.

Accepted-risk follow-ups

  • readRunState backfills missing run-state fields with defaults (defense-in-depth fail-fast lives at the mutating entry points and the watcher, not the read helper).
  • Downstream phase CLIs (specflow-review-*, specflow-challenge-proposal, specflow-generate-task-graph) and most slash-command templates other than approve / reject still operate from caller's git root. src/lib/worktree-resolver.ts is the foundation for the audit; threading it through every CLI is a follow-up.

Test plan

  • npm test — 992 tests pass.
  • Smoke-test on a fresh repo: /specflow from a feature branch, confirm user branch unchanged, worktree created, PR base = feature branch.
  • Verify git worktree list is clean after /specflow.approve succeeds.
  • Drain in-flight legacy /specflow runs (if any) before merging.

Issue

Closes #186

`/specflow` no longer hijacks the user's branch. When a change starts,
prepare-change creates a dedicated git worktree at
`.specflow/worktrees/<CHANGE_ID>/main/` (named after the change-id) from
the user repo's current HEAD. The `<CHANGE_ID>` branch lives only inside
that worktree; the user's repo stays on whatever branch they were on, with
all staged/unstaged/untracked changes preserved.

Highlights:

- New capability `main-session-worktree` (path layout, base commit / branch
  capture, conflict fail-fast, reuse policy, push/PR semantics, cleanup
  gating, no legacy mode coexistence).
- LocalRunState gains `base_commit`, `base_branch`, `cleanup_pending`
  fields with drift-guard test coverage.
- Subagent worktrees re-parented under
  `.specflow/worktrees/<CHANGE_ID>/<RUN_ID>/<BUNDLE_ID>/`. Subagent base
  HEAD and patch-apply target are now the main-session worktree —
  `mainWorkspacePath` and `changeId` are mandatory in `WorktreeRuntime`.
- `/specflow.approve` push and PR creation execute inside the worktree;
  PR base resolves from `base_commit` (single matching remote) →
  `base_branch` upstream → `base_branch` itself → repo default branch.
- `/specflow.reject` operates inside the worktree and triggers terminal
  cleanup of `.specflow/worktrees/<CHANGE_ID>/`.
- Terminal cleanup gate (`src/lib/terminal-worktree-cleanup.ts`) — removes
  the per-change worktree subtree only when the terminal action succeeded
  AND every worktree is clean; otherwise records `cleanup_pending = true`
  for retry on next terminal-phase invocation.
- Legacy run-state guard refuses to resume `worktree_path == repo_path`
  records on prepare-change (synthetic runs exempt). Watcher fail-fasts on
  the same condition.
- 992 tests pass, including new coverage for conflict paths, terminal
  cleanup defer/retry, legacy guard with synthetic exemption, and end-to-
  end invariants (C-1 through C-7).

Accepted-risk (scope-limited follow-ups, see approval-summary.md):

- R1-F04: `readRunState` backfills missing fields with defaults; the
  fail-fast policy is applied at mutating entry points (prepare-change)
  and the watcher, not at the read helper itself.
- R2-F06 / R3-F08 / R3-F09: downstream phase CLIs (`specflow-review-*`,
  `specflow-challenge-proposal`, `specflow-generate-task-graph`) and the
  remaining slash-command templates still operate from caller's git root.
  The `worktree-resolver` foundation is in place; threading it through
  every CLI is a follow-up audit.

Issue: #186
@skr19930617 skr19930617 merged commit 405945d into main Apr 25, 2026
4 checks passed
@skr19930617 skr19930617 deleted the worktree branch April 25, 2026 13:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ブランチを切らずにworktreeで作業する

1 participant