Repository navigation
dsh-swiftUI v0.2.0 — a bounded ladder, and our own orphans reclaimed
The native macOS shell for dsh. This release is about the two ways a real dsh
crash used to end on an error screen when it should have recovered.
Auto-restart that can finish
- A failed respawn now consumes a budget unit and continues the back-off
ladder instead of ending it at the firstEADDRINUSE. - The budget resets only after 60s of healthy uptime, not when the URL line
arrives — a dsh that announces its endpoint and immediately dies is a crash
loop, and is now treated as one. - A crash between the URL line and
start()returning no longer races the
ladder (anexitGenerationseparates them), and a start that dies early fails
fast instead of sitting out the spawn timeout. - Before respawning, the shell waits (bounded, 10s) for the dead child's port to
come free.
Leftover dsh processes are reclaimed, not retried into
The remaining failure was a genuine orphan: a dsh web from an earlier app run
with ppid == 1, holding the port, which no amount of waiting or retrying could
dislodge. The shell now closes leftovers it can prove are its own before
spawning — the same rule Windows applies at startup
(orphan::reclaim_orphan). All three facts are required:
- it listens on this app's configured port;
- its parent is
1(nothing supervises it); - its command line runs this app's configured
dshBinaryPath.
A dsh web you started in a terminal keeps that terminal as its parent, so it
is never touched. Anything that fails a fact is refused with the evidence, not
killed. Reclaims are logged and shown in the console, and the manual "Close
leftover and Retry" remains as the fallback.
Failures that explain themselves
The error screen now carries dsh's own last words, the exec detail, and the
current port holder, so a failure says EADDRINUSE with the PID rather than
"exited with status 1".
Preferences
"Open Preferences…" on the failure page and in the menu is a real SettingsLink
again; the flag it used to set raised a window that no longer existed.
Verification
swift test— 190 tests, 1 skipped, 0 failures. New coverage: three-attempt
exhaustion, budget restoration after 60s, bounded port wait, reclaim-only-
orphans, and an end-to-end test where a realppid == 1stub orphan on the
port is reclaimed and the shell starts.scripts/build-app.sh— release build with both JS bridges injected; smoke
test launches, quits, confirms the child is reaped and the port released.
Requirements
A working dsh install and the dsh front-end dist built (pnpm run build in the
dsh repo). Build from source with macos/scripts/build-app.sh; the app is
ad-hoc signed, so a copy from another machine needs the one-time xattr step
described in macos/README.md.