Cerbur/clutch-dsh--packages-clutch-dsh-worktree ↗★ 25
@cerbur/clutch-dsh-worktree
Adds a Worktree view to DSH Web UI that groups Sessions by Git worktree while keeping DSH as the source of truth. 适合在多个Git分支或工作区中切换、需要按项目整理会话的开发者。
Install
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:Cerbur/clutch-dsh#46397fb4c63ccc1a5ad66dc1e51c07890dcefb64&path:packages/clutch-dsh-worktreeREADME
Read the full README ↗Usage
Open Worktree mode
- Start DSH Web and select Worktree from the DSH Sidebar footer.
- Search or expand a Workspace in the Worktree tree.
- Select Local/Main or a Worktree to browse its Sessions. The view is additive; DSH's native Workspace and Session navigation remains available. Each group initially shows five rows; use Expand more and Collapse for additional rows.
- Use Collapse All in the header to collapse other unrelated Workspaces and Worktrees; the Workspace and Worktree containing the current Session remain expanded.
Create a Worktree
- Open the options menu for Local/Main or an active Worktree and choose Create Worktree.
- Choose the local base branch. You can also provide a new branch name.
- Confirm the dialog. The plugin creates the Git Worktree, records its acquisition facts, and continues through the normal Session and binding flow when you open a Session from that Worktree.
Git must have a usable repository, local branch, and initial commit. If setup is incomplete, DSH shows the relevant readiness message and copyable setup guidance.
Import an existing Worktree
- Select a Workspace, open its
+action, and switch to Import. - Choose a candidate from the branch-and-path list.
- Select Import Worktree. The plugin registers the existing directory without moving, copying, or changing its files, then uses the same Session flow as a created Worktree.
The first version lists only ready, branch-attached, non-root Git Worktrees that are not already managed by the plugin. Detached, bare, prunable, missing, and invalid entries are omitted. Imported Worktrees can still use Git & Changes after you choose a local baseline branch.
Create and open Sessions
- Use + on Local/Main for a normal DSH Session whose runtime directory is the Workspace root.
- Use + on a Worktree for a Session whose runtime directory is that Worktree.
- When possible, the plugin reuses an unarchived blank Session with the exact target directory.
- Use native DSH fork actions from a Session list, Worktree Session menu, or conversation. A child of a Worktree-bound Session is bound to the same Worktree and opens in that view.
If DSH creates a Session but binding fails, the Session is kept. The Worktree view exposes retry or open recovery actions; the plugin does not delete or rewrite the DSH Session.
Open the Worktree Dashboard
Open Dashboard from a Local/Main or Worktree row menu, its hover action, or the Dashboard icon beside the native Session-header actions. The Dashboard is a peer page to the native Session content: it occupies the center area beside the Sidebar while leaving an already-open right sidebar visible for a session-bound target. When the target Worktree has Sessions, opening its Dashboard waits for an initial pending Session list to become ready, then keeps the current Session if it belongs to that Worktree; otherwise it switches to the retained head Session so both views stay aligned. A ready empty Session list opens a page-level Dashboard without changing the current Session, collapses any currently open native right sidebar because there is no target Session, and does not create a Session automatically. The Dashboard header keeps the native right-sidebar button available whenever a current Session can host it and the sidebar is collapsed; once opened, the button is hidden following native behavior.
Use Back to session, Escape, a Sidebar Session, or Worktree mode exit to close it. For a Worktree with no Sessions, the top-right action becomes New Session and starts one in that Worktree. The connected MVP surface can show Overview and Sessions, create a Session or Worktree, archive a Worktree, edit instructions, copy a path, open the recorded directory in VS Code, and inspect Git & Changes. Derived Worktrees, Settings, and other marked quick actions remain placeholders. VS Code must be installed on the browser's machine and able to access the recorded path; the link does not verify launch success.
Use Git & Changes
Open the Git & Changes tab from a managed Worktree Dashboard. For a managed Worktree with a
persisted baseBranch that differs from the current branch, or with a captured acquisition commit that
supplies the implicit baseline, the Overview performs one compact, on-demand Git status read through the
existing /api Connection. It shows ahead/behind commit counts plus separate
committed (baseline-to-HEAD) and uncommitted (live working-tree) line totals; this is an ephemeral
projection, not a watcher or a Worktree-record field. Main,
unavailable, or baseline-unselected views honestly remain Not connected. Opening Overview does not
load the branch list; the first Git tab activation loads local branches and, once a baseline is resolved,
commit history. To replace that baseline, click the pencil icon beside the Base fact to open the branch
picker: its search field sits permanently above a bounded branch list that shows roughly seven rows and
scrolls internally, so the dialog keeps one size while you filter. Choose any local branch except the
current Worktree branch and save.
The save replaces the persisted baseBranch in the plugin sidecar; the saved value becomes the default for
the Git selector. Once the Git tab is open, changing its selector remains a transient view choice and reloads
history, changed files, and diffs without another Worktree-record write. If no usable saved baseline exists
(absent or equal to the current Worktree branch), the Git tab and the Overview read against the Worktree's
immutable captured acquisition commit and show that resolved commit as the Base fact; only a Worktree with
neither a usable saved baseline nor a captured commit stays baseline-unselected and prompts you to choose
one. When the selected branch has diverged, Git resolves the two heads' common ancestor. The
Git & Changes view reports Worktree commits after that ancestor as +N ahead and base-branch commits after it
as -N behind; history and file reads remain available. If the two heads have no common ancestor, the
committed summary falls back to the full tree diff between the base branch tip and Worktree HEAD, while
history uses the Worktree commits not reachable from that base tip.
With a valid baseline loaded, the Git & Changes tab initially selects Baseline summary rather than the
first commit; changing the baseline branch also returns to that summary. Choose a commit or Uncommitted
changes when you need a narrower target.
The selected local branch is resolved again for each read. The browser can choose only a plain local branch
name, not a raw commit SHA or arbitrary Git ref: a full ref path, tag, or remote-tracking ref is rejected
outright, while a selected branch that no longer exists shows the honest unavailable state instead of a
generic Git failure. baseCommit is immutable acquisition metadata, is never user-selectable directly, and
is the implicit baseline whenever no saved branch baseline is usable; creation recovery never overwrites
it. When the Worktree has staged, unstaged, or untracked
files, the list prepends an Uncommitted changes entry; selecting it compares the live working tree with
HEAD and uses the same changed-file and diff views.
The Baseline summary is a separate target that shows the net committed tree diff from the resolved
common ancestor to the request's captured HEAD (or the two branch tips when no common ancestor exists);
it excludes working-tree changes by default. Turn on Include working tree to replace that target with
one net diff from the same comparison boundary to the current working tree, including committed, staged,
unstaged, untracked, deleted, and renamed changes. This is a
fresh on-demand projection rather than a concatenation of two diffs. Clicking a commit shows that
commit's own diff. Turn on Multi-select commits in the commits header to pick several committed rows
and view the exact union of their first-parent deltas; the switch is off by default, and turning it off
collapses the selection back to the focused commit. The changed-file list
records the contributing commits, and each selected commit is rendered as its own diff segment; this is
not an implicit range and does not include unselected commits. The changed-files column header shows the
aggregate green +N and red -N totals for the current target, including the Baseline summary, selected
commits, or Uncommitted changes; binary-only totals show Unknown. The working-tree entry remains mutually
exclusive with committed multi-selection. The Open in Sidebar action in the summary diff toolbar
reveals the current file in the native right sidebar using the current Session, only when that Session
belongs to the Dashboard Worktree. An empty Worktree
or an unrelated current Session cannot open a file through this action.
The history is capped at 200 commits and marks longer histories as truncated. A changed-file list larger
than the Git adapter's output bound reports an explicit truncated state instead of a generic error.
Commit details use
first-parent comparisons; root commits compare against the empty tree; rename and copy rows retain
both paths; binary or oversized diffs show an explicit display-safe state. Changed-file rows show text
line counts as green +N additions and red -N deletions; binary files omit those counts. File names use
green for additions, red for deletions, and blue for other changes, and each row's title and accessible
label spells the status out. Folder icons indicate whether each folder is
expanded or collapsed. The Uncommitted changes entry is an on-demand snapshot, is not persisted, and is not a
Git watcher; refresh it to see later edits.
Git & Changes uses a viewport-bounded, fixed-size surface. Wide layouts show two columns: commits and changed files stack in the narrower left column around a draggable divider, while the diff keeps the full height on the right. Narrow layouts keep two rows: commits and changed files side by side on the first row, with the summary diff underneath. Both dividers stay draggable in either layout — the vertical one trades width between the columns, or between commits and changed files inside the first row, and the horizontal one trades height between the commits and changed-file panes, or between the first row and the diff. Drag a divider, or focus it and press the arrow keys, to move it, and double-click it to restore the default split. Long commit and changed-file lists scroll inside their panes instead of expanding the Dashboard. The changed-file pane also scrolls horizontally when paths are wider than the pane, keeping file and folder names untruncated. Changed files are grouped by folders; folders start expanded and can be opened or collapsed independently. Diff content also scrolls inside its bounded pane, while the read-only selection and refresh behavior remains unchanged.
The view is read-only and does not provide commit or staging controls. The plugin validates committed
entries against the selected branch-to-HEAD projection and re-reads working-tree paths against a fresh
status projection, so these endpoints are not generic Git object or file readers. Refresh keeps ready
content visible while replacement data loads, and late responses for an older commit or file selection
are ignored.
Add Worktree instructions
In the Dashboard, use Edit on the instructions card to save or clear shared guidance, up to 32,000 UTF-16 code units. For an active binding, the next model request receives the text as a separate `` context entry through DSH's pre-step hook.
Instructions stay in the plugin's own data. They are not written to the project directory or an
AGENTS.md file. Clearing, detaching, archiving, cleaning, or forgetting a Worktree stops future
injection; unchanged instruction text is not repeatedly added while its message remains visible.
Archive or remove a Worktree
- Archive Worktree is non-destructive. It keeps the directory, bindings, instructions, and runtime Worktree context. An archived Worktree can be unarchived while its Git registration is intact.
- Clean Up Disk is a separate action. It requires a second confirmation and runs the normal
non-forced
git worktree remove. The plugin does not check whether Sessions or subagents are still using the directory; stop those tasks before confirming. Successful cleanup detaches the bindings while keeping the recorded history until it is forgotten. - Remove from Management deletes only the plugin's Worktree and binding records. It preserves the disk files and native DSH Sessions, and does not require a Session activity check.