Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ keyboard alone, and the mouse stays first-class.
repo naming, branch/session labels, dirty count, ahead/behind, last commit,
and one-click Review pinned where the branch diverged from main. Worktree
tabs of one repo group together instead of looking like separate repos.
Rows badge merged / unpushed work against the detected base; **Merge &
clean up** lands a worktree's branch (squash / merge / fast-forward, exact
commands previewed) and retires the worktree + branch in one motion, and
every removal first archives a full snapshot — uncommitted and untracked
files included — restorable later as a new worktree.
- **Everyday Git** — staging with per-change-block stage / discard / unstage
inline in the diff, fetch / pull / push with streaming progress, branches,
tags, stashes, remotes, cherry-pick, revert, merge, and a fully
Expand Down
33 changes: 33 additions & 0 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -1428,6 +1428,39 @@ end-to-end WebView2 CDP pass on the running app (tracked file drag → git
`R`, untracked drag stays untracked, dialog rename of a modified file → `RM`
with the edit preserved, ghost text + cleanup asserted).

**Worktree lifecycle: merge & clean up, health badges, archive snapshots
(2026-07-07):** The worktree overview grew the missing second half of the
agent-worktree loop — retiring a worktree safely once its work lands. Engine
(`worktree.rs`): `worktree_health` (detected base, ahead-of-base,
can-fast-forward, upstream/unpushed, and merged-detection via a containment
scan across all local branches — the detect-base heuristic alone names a
sibling when several worktrees sit at one fork point, exactly the
parallel-agent shape, and would hide "merged"), `integrate_worktree_branch`
(squash / merge-commit / ff into the detected base, run in whichever worktree
holds the base with a clean-workdir guard and conflict auto-abort, or as a pure
ref fast-forward when the base isn't checked out), and archive snapshots:
`archive_worktree_state` captures HEAD+staged+unstaged+untracked into
`refs/strand/archive/<slug>/<secs>` via a throwaway `GIT_INDEX_FILE` (real
index untouched), with list / restore / delete counterparts — restore puts
the original identity back (recorded directory when free; branch recreated
or re-attached when it's unheld and still at the archived commit; fallback
dir/detached otherwise), archived changes returning as uncommitted state on
the original commit; `prunable`'s reason is now parsed alongside `locked`'s. Six new
IPC commands, and the existing worktree add/remove/prune commands now route
through `run_blocking` (they wait on subprocesses — `add` even runs a full
checkout). UI: every `removeWorktree` archives first (best-effort), so force
remove is always recoverable; overview rows badge **merged** /
**unpushed** / **unmerged** with lock/prune reasons as tooltips; the hero
gains a merged metric, **Clean up (N)** (confirm-listed removal of
clean+merged worktrees incl. branch deletion), and **Prune stale**;
`WorktreeMergeDialog` previews the exact git commands Crystal-style before
merging, has an editable base picker (detected base preselected, per-base
ff-possibility via `repoMergeBase`), and optionally removes worktree + branch
in the same motion; a collapsible "Archived snapshots" strip offers
Restore / Delete. Verified:
`cargo test -p strand-core` (102, +4 worktree), workspace `clippy` clean,
`tsc`, `vitest` (200).

---

## 1.1+ — Post-1.0
Expand Down
42 changes: 42 additions & 0 deletions TASKS.md
Original file line number Diff line number Diff line change
Expand Up @@ -853,6 +853,48 @@ Legend: ☐ not started · ◐ in progress · ☑ done · ✗ blocked
on the Review view in session mode, so committed + uncommitted work since the
fork point shows in one diff via the existing `diff_since`. The main worktree,
or a failed merge-base (toast), falls back to Local Changes as before.)
- ☑ Worktree health + dirty-aware cleanup (W2 — `Repo::worktree_health` in
`worktree.rs`: detected base, ahead-of-base, can-fast-forward,
upstream/unpushed, and **merged via a containment scan across all local
branches** (`merged_into`) — detect_base_branch alone misses a branch merged
into main when sibling worktrees sit at the fork, the canonical
parallel-agent shape; `repo_worktree_health` IPC; overview rows
fetch it lazily and badge **merged** / **unpushed** / **unmerged**, with
`lock_reason` + new `prune_reason` surfaced as badge tooltips; hero gains a
merged metric, a **Clean up (N)** action that lists clean+merged worktrees in
a confirm dialog and removes them + deletes their branches, and a **Prune
stale** button.)
- ☑ Merge & clean up (W1 — `Repo::integrate_worktree_branch` in `worktree.rs`:
squash / merge-commit / ff of a worktree branch into its detected base,
running in whichever worktree holds the base (clean-workdir guard, conflict
auto-abort) or as a pure ref fast-forward when the base isn't checked out;
`repo_worktree_integrate` IPC; `views/WorktreeMergeDialog.tsx` previews the
exact git commands, warns about uncommitted files, offers an editable base
picker (detected base preselected; per-base ff-possibility recomputed via
`repoMergeBase`) since the detection heuristic can name a sibling, and
optionally removes the worktree + deletes the branch after merging.
+3 engine tests.)
- ☑ Archive-before-remove snapshots (W3 — `Repo::archive_worktree_state` in
`worktree.rs` snapshots HEAD+staged+unstaged+untracked into
`refs/strand/archive/<slug>/<secs>` via a throwaway `GIT_INDEX_FILE`, without
touching the real index; `worktree_archives` / `restore_worktree_archive`
(puts the original identity back: recorded directory when free, branch
recreated-or-reattached when unambiguous — commit subject carries the exact
branch, body a `Path:` line — else fallback dir/detached; archived changes
return as uncommitted state on the original commit) /
`delete_worktree_archive`; four
`repo_worktree_archive*` IPC commands; the store's `removeWorktree` archives
best-effort before every removal, and the overview grows a collapsible
"Archived snapshots" strip with Restore / Delete. +1 engine test.)
- ☐ Surface "Merge & clean up" beyond the overview (sidebar worktree context
menu + worktree review header) and add palette entries for Clean up / Prune.
- ☐ Auto-prune old worktree archive snapshots (keep last N per slug or
age-based) instead of manual-delete only.
- ☐ `detect_base_branch` tie-break revisit: with several sibling branches at
one fork point it picks a sibling (smallest `base_ahead`) over the real
parent. Harmless for review baselines (same merge-base) but it seeds the
merge dialog's base picker; consider preferring the branch another worktree
has checked out, or main-ish names, on exact rank ties.

### File view (4-tab)
- ☑ Tab strip + header (opened via `selectFile` from the Files tab / palette;
Expand Down
Loading
Loading