Forward the current and legacy hook executable variables through WSLENV with /p path translation. Document the boundary contract and cover the primary hook variable in the existing environment test.
Include cloud settings, panel sizing, command groups, Agent integration settings and runtime input fixes from main. Bind native Codex recovery to the live pane process and preserve verified IDs; add CMD recovery choices and an explicit exit path when identity discovery fails.
Right-clicking a folder has always opened the configured default shell —
usually PowerShell — with no way to ask for a WSL distribution instead.
- `--shell <id>` takes the same ids the `shell` setting uses (`pwsh`, `cmd`,
`wsl:Ubuntu`, or an imported profile's settings id) and applies to the
first tab this process creates. It carries an id rather than a path so
every launch re-resolves the executable.
- The id travels both startup paths: the cold start (`run_shell` →
`WorkspaceStartup::NewTerminal`), and the resident hand-off, which is the
common case on Windows. `tab.new`/`window.create` gained an optional
`shell` field, so clicking the menu while Pebrel is already running adds a
tab to the existing window instead of starting a second process.
- An explicit request never silently degrades. An unresolvable id fails
(`invalid_shell`, or a startup error before any window opens), and a
`wsl:<distro>` id that the registry no longer lists still launches
`wsl.exe -d <distro>`, leaving the complaint to the distribution itself.
The `shell` setting keeps its documented fallback to the platform default.
- The winit shell rejects a shell request instead of ignoring it, so the
caller falls back to a cold GPUI start and still gets the requested shell.
The resolution lives in a new `workspace::shell_launch` module: `main.rs` has
to validate `--shell` before it opens a window, and none of it needs
`NebulaWorkspace` state — `workspace.rs` is also at its line budget, which
this keeps from growing (`architecture/file-budgets.txt`).
The installer registers one context-menu entry per registered WSL
distribution (`PebrelWsl<n>`, skipping `docker-desktop*`) and the uninstaller
reclaims them by key prefix plus the command line it wrote. `--shell` is
passed before `--working-directory`: a drive-root `%V` ends in `\"`, which
would swallow the rest of the line if the directory came first. Both the
string and the order are pinned by installer assertions.
Docs (runtime API schema + control API) and shell completions are updated.
Replace references to specific terminal products in comments and the runtime
API document with neutral descriptions of the shared convention. The technical
facts stay; only the product names go.
Snapshot commit of the in-progress runtime-control and terminal-fidelity
work on this branch. Every item below is code-complete and covered by
targeted checks; none of it has had human UX acceptance yet.
Runtime control surface
- Resource-style CLI (`nebula <resource> <verb>`) replacing the flat verb
list, with shell completions regenerated for zsh/bash/fish.
- `pane.exec` end to end: protocol params, both UI routes, and a process
executor that reaps the whole descendant tree through a Windows Job
Object so a timed-out or early-exiting child cannot leave the stdout
reader waiting on an EOF that never comes.
- `shortcuts` module exposing the keybinding surface to the API.
- Agent environment contract (`agent_env`): TERM_PROGRAM and friends, so
third-party tooling identifies Nebula without special-casing.
- Provider command matrix filled in for OpenCode, Cursor, Kimi, Pi and
omp (cold start / resume / fork), each from verified CLI syntax.
Workspace
- Quick Jump over tabs, panes, frecency directories, SSH hosts and AI
sessions; Recipes and Files scopes stay hidden until their backends
exist end to end.
- Send-selection-to-chat with explicit pane routing.
- Taskbar integration.
- Configurable terminal-card geometry (radius, gutter, shadow, divider)
carried by the theme, with a single radius constant shared by both
shells instead of one literal per shell.
Terminal
- PTY lost-wakeup fix completed. The 1.2.0 repost keyed on "the pipe
still holds bytes", but `drain_inner` takes the read waker *before*
copying, so that check was a TOCTOU: a read that got data already
means no waker is registered. The repost now keys only on "this read
got data", which self-converges, plus a regression test.
- `conpty_realign` now corrects both directions. Only the collapse case
(conhost above our cursor) was handled; a rewrap that leaves conhost
*below* us left every absolute CUP from PSReadLine landing on the
wrong row after a split.
- DECSET 2031 colour-scheme change notifications, with the light/dark
predicate sharing one source with the OSC 11 answer.
- `TerminalColorResolver` reachable from the GPUI shell (`pub(crate)`),
and its line endings restored to LF after an editor round-trip had
rewritten all 329 lines as CRLF.
Repro tooling
- `pty_stall_repro.ps1` reproduces the lost wakeup by separating the
64 KB burst from the tail, which is the half the earlier drain probe
was missing.
- `tui_redraw_dup_probe.ps1` checks in-place UI-block redraws for
duplicated and dropped lines via monotonic line numbering.
Ignore rules: the `.run-*`, `.isolated-*`, `.chk*.js`, `*-probe.png`,
`NebulaTerminal-*/` and `*-preview-package/` families were reaching
`git status` as untracked. They are per-round debug evidence and local
build output.
Verification
- `cargo check -p nebula --features gpui-shell` passes.
- `cargo test -p nebula --features gpui-shell`: 1001 passed, 1 failed.
- `git diff --check` passes.
- The single failure, `math_overlay::tests::alt_screen_renders_agent_math`,
reproduces identically on e41b3c8 in a clean worktree. It predates this
work and is not addressed here: the test swaps to the alternate screen,
which resets its region, then expects the primary screen's formula to
still be planned.
A rustfmt run was cut short by a full D: drive and left
gpui_shell/terminal/view.rs at 0 bytes. Restored from the editor
history snapshot taken at 18:32 - the selection auto-scroll work and
the suggest_env wiring are both back in.
Emergency baseline snapshot, committed with --no-verify: the tree does
not compile yet (missing SuggestEnv import, one stale
update_selection_scroll call site) and the pre-commit size budgets are
pre-existing failures on this branch.