Skip to content

refactor(worktrees): replace the sidebar surface with a session toggle - #1798

Merged
bobleer merged 2 commits into
GCWing:mainfrom
bobleer:refactor/worktrees-session-toggle
Jul 27, 2026
Merged

refactor(worktrees): replace the sidebar surface with a session toggle#1798
bobleer merged 2 commits into
GCWing:mainfrom
bobleer:refactor/worktrees-session-toggle

Conversation

@bobleer

@bobleer bobleer commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Summary

Managed worktrees were exposed as a WORKTREES group in the workspace list, plus a launcher dialog, a Worktree Manager modal, and four workspace menu entries. That places an execution detail at the same level as projects and assistants, which is not where the concept belongs — neither Claude Code nor Codex surfaces worktrees there.

Worktree isolation becomes a property of a session: a checkbox chip next to the branch in the chat input strip, shown for Git workspaces.

  • On — creates a managed worktree from the current HEAD and rebinds the session to it.
  • Off — returns the session to the project checkout, then removes the worktree if it is clean, or keeps it and reports the path when it still holds local work.

The toggle is locked once a session has a transcript, since that history describes work done in one specific directory.

Removed: ProjectWorktrees, WorktreeManagerModal, WorktreeLauncherModal, worktreeUIEvents, the nav top-action button, the four workspace menu entries, and worktreeWorkspaceService (which already had no production callers).

Added: worktree_bind_session command backed by WorktreeService::bind_session, which performs the worktree create/release and the session rebind as one step. Session storage stays keyed on project_workspace_path, so a session keeps its transcript identity across the move, and a failed rebind rolls the new worktree back.

Fixes #

Type and Areas

Type: Refactor / UI-UX

Areas: web UI, Rust core (assembly/core worktree + session manager), desktop/Tauri commands, stable contracts, locales, E2E

Motivation / Impact

The worktree list competed for attention with the project list while describing something users rarely browse. The thing they actually want is per-session: run this agent somewhere that will not collide with my other agents. Putting the control next to the branch — where the session's execution location is already displayed — expresses exactly that, and removes an entire sidebar surface plus two modals.

Worktree sessions now appear directly in their project's session list rather than in a separate group. The localSessionsOnly filter that hid them from the project row was only there to avoid duplicating the WORKTREES group, so it is gone.

User-facing: the launcher and manager are no longer available. Existing managed worktrees are unaffected — they remain in the registry, sessions bound to them keep working, and the deferred Worktree agent tool still lists, creates, branches, and removes them.

Verification

cargo check --workspace --all-targets
cargo clippy -p bitfun-core -p bitfun-core-types -p bitfun-runtime-ports --all-targets
cargo test -p bitfun-core --lib worktree     # 15 passed
pnpm --dir src/web-ui run type-check
pnpm --dir src/web-ui run lint
pnpm --dir src/web-ui run test:run           # 334 files, 2204 tests passed
pnpm run i18n:contract:test                  # 37 passed
pnpm run i18n:audit                          # 0 warnings
pnpm run check:repo-hygiene

Not run: the E2E suite. tests/e2e/specs/l1-worktree.spec.ts and l1-worktree-restart.spec.ts were rewritten to drive the new toggle (chat-input-worktree-toggle) instead of the launcher dialog, and type-check clean, but they were not executed against a built desktop binary.

Pre-existing and unrelated: bitfun-relay-server's library_compat test fails to compile on upstream/main (missing field page_browser_auth). Confirmed against a clean tree.

Reviewer Notes

Three latent problems surfaced while wiring this up and are fixed in the same commit:

  1. Workspace label degraded to a generated id. A managed worktree's directory basename is a raw UUID, and the strip labelled sessions by that basename. It now keeps the owning project's name — the toggle already communicates that the session is isolated.
  2. Branch went stale after a rebind. useGitState only auto-refreshes on mount; moving the execution root under a live strip left the previous directory's branch on screen. The strip now refetches when the path changes (regression test added).
  3. Dead setting. defaultTarget had exactly one consumer, the launcher. Dropped from WorktreeSettings and from the WorktreeDefaultTarget contract. Root path, branch prefix, and copy-local-changes are kept — the toggle still uses all three.

Ordering detail worth a look: disable_session_worktree rebinds the session before attempting removal, because validate_removal counts sessions still pointing at the worktree and would otherwise reject its own caller with worktree_busy.

Checklist

  • This PR is focused and does not include secrets, temporary prompts, generated scratch files, or unrelated artifacts.
  • Relevant verification is recorded above, or skipped checks are explained.
  • User-facing strings, docs, and locales are updated where applicable.

bobleer added 2 commits July 27, 2026 01:00
Managed worktrees were exposed as a WORKTREES group in the workspace list,
plus a launcher dialog, a manager modal, and four workspace menu entries.
That put an execution detail at the same level as projects and assistants,
which is not where the concept belongs.

Worktree isolation is now a property of a session: a checkbox chip next to
the branch in the chat input strip, shown for Git workspaces. Turning it on
creates a managed worktree and rebinds the session; turning it off returns
the session to the project checkout and removes the worktree when it is
clean, keeping it (with the path reported) when it still holds local work.

The toggle is locked once a session has a transcript, since the history
describes work done in one specific directory.

Worktree sessions now appear directly in the project's session list instead
of a separate group, so the removed `localSessionsOnly` filter no longer
hides them.

Also fixed while here:
- the strip labelled worktree sessions with the worktree directory basename,
  which is a generated id; it now keeps the owning project's name
- useGitState only auto-refreshes on mount, so the branch went stale when the
  execution root moved; the strip now refetches on a path change
- dropped the `defaultTarget` setting, whose only consumer was the launcher
…ession

Every command in generate_handler! must appear in
REMOTE_WORKSPACE_COMMAND_POLICIES. RemoteUnsupported matches the other
worktree commands and what the binding already does: load_binding_context
rejects remote sessions and remote project paths up front.
@bobleer
bobleer merged commit e528e85 into GCWing:main Jul 27, 2026
6 checks passed
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.

1 participant