Shell Pilot 1.19.1

September 5, 2026 · Hotfix

This release fixes a crash that made v1.19.0 unusable for some people. If the sidebar file tree drew the same folder several times over, or the app started crashing on launch and would not come back, this is the fix. Install it and the app repairs itself on first launch.

What went wrong

The trigger was mundane: opening a session in a directory you reached with different capitalization than the folder actually has on disk. Typing cd desktop instead of cd Desktop was enough.

macOS volumes are case-insensitive but case-preserving, and the two halves of the file tree disagreed about spelling as a result. zsh reports the working directory exactly as you typed it, so the session's root became /Users/you/desktop. FileManager, listing that same folder, always hands back the on-disk spelling — /Users/you/Desktop/…. The tree loader worked out each child's position by testing the child's absolute path against the root's with a case-sensitive prefix comparison. That comparison could never match, so every child came back with an empty relative path.

A node's identity is its relative path. With every child sharing one empty identity, SwiftUI drew the first item in every slot — hence the same folder repeated down the sidebar. Clicking its disclosure triangle then wrote that empty path into the session's expanded set, and a row whose path is empty renders the children of the root — which is the list it is already inside, also empty-pathed, also expanded. That recursion had no bottom, and because v1.19.0 builds the tree eagerly it ran the instant the view was drawn. The app died with a stack overflow inside SwiftUI's view builder.

The part that turned a bug into a brick: the bad state was saved to disk. The next launch restored it, rebuilt the same infinite tree before the window appeared, and crashed again — every time.

The fixes

Five of them, one per layer, so that no single mistake can reproduce this.

On top of those, the tree view itself now refuses to render a node inside itself, skips any child that repeats its parent's identity, and stops at a hard depth cap of 32 levels. The same guards are mirrored on the remote (SSH) tree, which had the same shape of risk.

If you are stuck on 1.19.0

If the app crashes before its window appears, you cannot update from inside it. Two ways out:

Tests

300 tests pass, up from 292. The eight new ones build a real CaseRoot/{Alpha,beta.txt} on disk, list it through a lowercased caseroot root, and assert the children come back with unique, non-empty relative paths — plus coverage for canonical-case resolution, the ignored root toggle, and the sanitizing of saved expansion state. The exact sessions.json that crash-looped v1.19.0 has been confirmed to launch and run on this build with no crash.

Known limits