Repository navigation
fix: pre-release — Explorer paths, never delete a session on a failed relaunch, worktree remove safety - #182
Merged
Merged
Conversation
"Open in Explorer" ran explorer.exe with the folder as raw command-line text, and Explorer silently opened Documents instead for two kinds of path — measured by asking the Shell which folder each new Explorer window showed: - forward slashes (C:/repos/wt-feat): the form git prints, and so the form a session opened through "New session in sibling worktree" — and now the Worktrees menu — stored as its WorkingFolder; - a comma in the name: Explorer splits its arguments on commas, and quoting the path does not help (also measured). Services/FolderOpener opens the folder itself through the shell (ShellExecute "open" on the full Windows path), which opened the right folder for every case tried: plain, spaces, comma, &, %, forward slashes, trailing separator, 8.3. It refuses anything that is not an existing directory first — ShellExecute on a FILE runs it, and a session's folder comes from state.json and imports — and runs off the UI thread (the check is \wsl$ I/O for WSL). Used by the toolbar 📁, the sidebar menu and note search results. LaunchSessionInSiblingWorktreeAsync now stores the Windows form of the git path, so new worktree sessions don't carry forward slashes at all. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NsYm9iLc2aRnRDfV2uZRQX
…; worktree remove safety From two read-only reviews of everything since v0.9.0. Each finding was reproduced before fixing. Relaunch (restore, wake) — data loss since before v0.9.0: - Both called LaunchSessionAsync with the default removeOnFailure: true, so a session whose launch was refused or whose PTY failed to start (WSL distro uninstalled, claude briefly off PATH) was DELETED, and the next save made it permanent. Wake's catch never ran: the PTY-failure path returns, not throws. Both now pass removeOnFailure: false and end in FallBackToDormantIfNotLive, which also covers every WebView2 failure on restore (#175 only covered the two batched ones). Verified before/after with a real state.json via CSM_STATE_PATH: old build — session gone from sidebar and file; fixed — kept, asleep. Worktree remove (#180): - Refused when another worktree lives inside the target. git's clean check skips ignored folders: with B in A's .gitignored .worktrees/ holding uncommitted work, `git worktree remove A` exited 0 and deleted B (reproduced with git 2.54). Checked against a list re-read at click time. - Sleeping sessions are deleted only after git removed the folder — they never go through Recently closed, so a refusal used to lose them for good. - WSL: \wsl.localhost folded into \wsl$ (otherwise no match at all), and below the distro paths compare case-sensitively (/home/u/WT is not .../wt). Not fixed here (follow-up issue): window bounds restore under per-monitor DPI on mixed-DPI setups, the busy-slot key before RepoRoot resolves, and ParseStatusV2 showing every unmerged entry as "UU". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NsYm9iLc2aRnRDfV2uZRQX
4 tasks done
mortenaslo
added a commit
that referenced
this pull request
Nov 6, 2026
…check (#183) Second-round review (fresh eyes on the #182 fixes) and a release-facing review: - Worktree remove's nested check failed OPEN: ListWorktreesAsync returns empty on any git error, which read as "nothing nested". It now refuses unless the freshly read list contains the target. - It only saw worktrees registered with the same repo. An independent clone or another repo's worktree in an ignored folder was still deleted silently. GitWorktrees.NestedRepositories scans the folder for any .git of its own (no junction following, never into .git, capped — over the cap it refuses). - Stale comment: restart is no longer the only removeOnFailure: false caller. Docs: README feature list gains the git chip/menu, Worktrees menu, Open in VS Code / Explorer / PowerShell, drag-and-drop ordering and the full bulk-action list; worktrees re-rated "one click, not automatic" in README and comparison. CI: after Publish, fail if the SHIPPED exe lacks the PerMonitorV2 manifest — the unit test only pins it into the build output (verified by hand that the single-file publish keeps it). Tests: independent clone + submodule found, plain worktree and a junction to a repo not, cap returns null. 765/765. End-to-end remove re-run in the app. Claude-Session: https://claude.ai/code/session_01NsYm9iLc2aRnRDfV2uZRQX Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes from the v0.10.0 pre-release pass. Each one was reproduced before it was fixed.
Why
1. Explorer
The folder was passed to
explorer.exeas its raw command line. I measured the result by asking the Shell which folder each new Explorer window showed:FolderOpener)&,%, trailing\, 8.3C:/forward/slashesa,b(quoting doesn't help)Services/FolderOpeneropens the folder itself through the shell (ShellExecute "open" on the full Windows path). It refuses anything that isn't an existing directory first: ShellExecute on a file runs it, and folder paths come fromstate.jsonand imports. It runs off the UI thread. New sibling-worktree sessions now store the Windows path form in the first place.2. Restore and Wake
Both called
LaunchSessionAsyncwith the defaultremoveOnFailure: true. A refused launch (for example a WSL distro that's gone) or a PTY that failed to start therefore removed the session, and the next save made that permanent. Wake's own catch never ran, because the PTY-failure path returns rather than throws.Both now pass
removeOnFailure: falseand end inFallBackToDormantIfNotLive. That also covers every WebView2 failure on restore; #175 only covered the two batched ones.Before/after, run against a real
state.jsonviaCSM_STATE_PATH:IsDormant=true3. Worktree remove
.gitignored.worktrees/, with uncommitted work. A reports clean, andgit worktree remove Aexits 0 and deletes B. The menu now refuses whileGitWorktrees.NestedInsidefinds any, checked against a list re-read at click time.\\wsl.localhost\is folded into\\wsl$\. Before, such a session matched no worktree at all./home/u/WTis not/home/u/wt.Implementation notes
Test plan
FolderOpenerTests: forward slashes, comma,&,%, spaces, drive root; a file, a missing path, a relative path, a URL andcalc.exeare all refused.GitWorktreeTests: WSL case rules and both share spellings;NestedInside; and the real-git reproduction of the nested layout (A reported clean, B detected).🤖 Generated with Claude Code
https://claude.ai/code/session_01NsYm9iLc2aRnRDfV2uZRQX