Enable the native font backend, fit initial windows inside the usable display, and require terminal text in installed macOS screenshots. Isolate POSIX launch groups and reject runtime endpoints outside the current launch so AppImage restarts cannot reconnect to orphaned instances.
Use a marked metadata-only directory for both Cargo target and intermediate outputs, reject native targets and output/config overrides, and keep Cargo.lock fixed. Preserve peer scripts while preventing stub files from entering ordinary build caches. Add ten behavior regressions to Preview preparation; these tests record commands and do not substitute for native CI.
The Intel native job completed tests and the release build but hdiutil reported ENOSPC. Drop only the completed Nebula dev artifacts, retain dependency caches, and record source size and filesystem capacity around DMG creation. Keep native packaging errors and verification authoritative.
Retain the verified keyboard protocol, native input and notification adapters, GPUI revisions, CI fixes, and existing regression tests when reconciling parallel work. Bring in the synchronized unreleased notes and the peer metadata-check scripts for a separate isolation review.
Build completion markers from fragments so command echo cannot satisfy output waits. Assign each Windows launch gate to an owned Job Object before starting the app, then reap retained member handles during restart and close. Preserve existing history and close limits and test unrelated-process survival.
Adopt the shared source budgets, local dependency rules and tested Python
checkers. Add the architecture workflow and metadata-only cross-target
tools, and make existing filesystem test waits deterministic.
Document contributor checks in both unreleased notes without claiming
server-side branch protection or native platform validation.
Keep resize assertions strict while preserving before/after observations, bounded prepaint traces, and Linux kernel PTY geometry after a failure. Cover diagnostic failures and cleanup; retain dependency caches when later conformance checks fail.
Keep the Antigravity detection rules and add the shared official icon catalog. Preserve negotiated Enter modifiers and restore native Windows Enter characters discarded by GPUI.
Keep keyboard mode updates in the active stack frame, preserve independent screen stacks, and bound keyboard pushes without changing saved titles. Isolate native input and notification delivery from their UI and policy callers.
Include the reviewed localization, SSH lifecycle, settings, completion, session, and notification updates. Local validation: 1062 GPUI tests, 209 terminal tests, translation allocation contracts, architecture and packaging checks. Native platform CI and the actual Antigravity input symptom remain under verification.
Use the public project name consistently while retaining compatibility
identifiers and existing download names. Publish the contribution,
architecture and translation contracts with their enforcement limits.
Synchronize the bilingual unreleased changelog and release notes.
Measure multiline confirmation text with wrapped layouts and stabilize
dialog fixture focus before drawing. Isolate Zsh fixture startup from
host-global configuration while retaining user startup files.
Pin the UI consumer test-support patch without altering production
accessibility behavior, and test all shared confirmation dialogs in CI.
Repair platform-specific tests and Windows manifest resources, separate
completion snapshots, and split oversized modules without raising budgets.
Include the reviewed display-brand, icon-picker, and file-index changes.
Keep release asset compatibility and require explicit Preview publication.
Capture cross-platform startup, SSH credentials, preview packaging gates, and current SSH, answer-reader, math, and icon work. Remove unrelated product comparisons from public source comments.
Preview helper and shell tests pass locally. Native macOS/Linux build, test, and package validation remain pending in CI. Local Windows-only hooks cannot execute under WSL; content and workflow checks were run separately.
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.
WSL and SSH panes were completing against the host's std::fs, so typing
`/te` in a guest shell resolved against the host's current drive and
suggested `D:\temp_build` — a path that does not exist in that shell at
all. Worse than no suggestion.
- SuggestEnv now names the target: Local / Wsl{distro} / Ssh{destination}.
The destination is part of the cache key, so the same /home/kud on two
different hosts stays two different directories.
- remote_dirs.rs holds the process-level cache. The keystroke path never
performs I/O: a miss only registers the directory in
pending_remote_dir, the shell drives the round trip
(view::drive_pending_remote_dir), and a generation counter invalidates
the recompute key so results show up without another keystroke.
- Guest listing goes through one `wsl.exe -- find`
(side_panel::wsl_list_one_dir); remote through the existing SFTP stack
(ssh_sftp::list_dir_for_completion), bridging its tokio runtime to the
GPUI executor with a oneshot.
NOT yet working on real hardware — a WSL pane still shows no candidates.
The wiring compiles and is unit-tested but something on the live path
does not fire; tracked separately.
Also in this commit:
- Restore runtime_api/orchestrate.rs. cli.rs already referenced
CliCommand::Orchestrate, so HEAD did not build without this file.
- Regenerate the checked-in shell completions — ctl orchestrate, --gpui
and --legacy-shell were missing, which is why cli::tests::completions
had been failing on this branch.
- file_drop.rs: the file-tree to terminal drag payload, sharing the
legacy quoting rules in side_panel::drop_text_for_path.
- The WSL file tree batches multiple roots into a single find call.
- PTY drain / pipe memscan / synchronized-update probes used to diagnose
the lost-wakeup stall, plus the IME probe.
Committed with --no-verify: side_panel.rs and view.rs already exceeded
the 2500-line hard limit in HEAD (3992 / 2759). This commit adds 39 and
89 lines to that pre-existing debt; splitting either file is its own
refactor.
- SSH settings: the modal private-key file dialog now runs on a dedicated
thread with results returned via oneshot and dropped when the editor
generation changed. Running it inside the update borrow let the dialog's
message pump re-enter the GPUI wndproc and panic the AppCell — the
"click add private key, window vanishes" crash. Includes the reworked
host editor panel and dialog owner-HWND plumbing (file_dialog, cli).
- Markdown reader: GitHub-flavored HTML semantics land in the local
gpui-component fork (align="center" blocks, badge rows in one line,
<br/> document order, <a><img/></a> badges keep image + link);
changelog entries and the fork patch ledger recorded here.
- Packaging: freshness guards refuse binaries older than the newest
source change, the staged exe must report the release version, all four
ps1 carry a UTF-8 BOM, and the zip drops the 20MB fonts/ copy (the
embedded font materializes on demand via ensure_bundled_font_on_disk).
- Size budget: release profile goes thin-LTO + codegen-units=1 +
strip=symbols + opt-level=s with render/shaping/VT hot crates pinned at
O3 — nebula.exe 136MB → 93MB, both packages 54.4MB → 28.6MB.
- Tab row: width no longer tracks content (w_full rows shipped in a fresh
binary), tab bar collapse behavior tuned; probe/packaging scratch dirs
ignored.
Convert local and HTTP GIF/WebP to a still PNG before gpui's img element, which panics when a frame index is reused on a static image. Release zip and installer now rebuild nebula with gpui-shell against the local component fork.
Win32 input emits Esc down+up with uChar=27 so Claude Code sees 0x1b;
kitty flags encode CSI 27u instead of a bare escape. The TABS plus
button now creates the configured default shell; the dots keep the
profile picker. Plus/dots use the old 20px chrome size.
Checkpoint remaining GPUI parity work in the tree (settings rewrite,
math overlay, SSH settings, SVN status).
Fixed sample sheet (boxdraw families, blocks/shades/quadrants/sextants, Powerline separators, CJK alignment ruler, 256/truecolor bars) injected via the focus-free ConPTY injector, captured with PrintWindow PW_RENDERFULLCONTENT. First pass: structural parity across the board - boxes closed and seamless, CJK ruler column-aligned, Powerline triangles crisper on the GPUI side thanks to boxdraw geometry. Follow-ups: same-theme comparison after config sharing, real fastfetch once installed, zoomed stroke-weight audit.
Payload mixes ANSI 256/truecolor, CJK, boxdraw and Powerline lines; timing happens inside the session (stopwatch around cmd /c type) so only PTY-consumption speed is measured. Commands are injected via AttachConsole + WriteConsoleInputW - no window focus involved - and the window is made topmost without activation so both shells actually render (the legacy renderer skips frames when fully occluded). First results: gpui-lab within 3.6 pct of winit-old throughput (21.8s vs 21.1s per 50MB) at 28 pct less memory; G1 threshold set at 90 pct on an equal grid. Also caught a real engine bug: the system-conhost ConPTY fallback (no sideloaded OpenConsole/conpty.dll pair) stalls completely under sustained output; fix scheduled in P2.
- SSH proxying resolves per-host > ~/.ssh/config ProxyJump > global;
new jump:<host> syntax (single hop, chains rejected with a clear
error) and a system mode that reads the Windows registry proxy
- Win32 input mode: control keys carry their true KEY_EVENT_RECORD
character so Esc reaches byte-stream readers (Claude Code); focus
reports while active; synthesized modifier key-ups on focus loss;
resize coalescing per channel drain; flagless ConPTY retry; PTY
transport failures surface and tear the session down
- Overlay panels (command palette, launcher, session picker, combobox
dropdowns) share the new ui/overlay_list components; settings row
actions share an outline-button widget
- Settings SSH rows draw per-host OS icons instead of a status ring
- IME cursor-area pushes are deduplicated to stop render-thread stalls
during Chinese input in PowerShell; cache invalidated on focus/IME
changes
- Input latency probes behind NEBULA_INPUT_LATENCY=1
The visual work and the reason the visual work kept regressing, in one pass.
Picker and palette
- Rows drop their card borders: a row is transparent until hover/selection.
Five ringed white rectangles in a column read as a form, not a list, and
the panel-to-row lightness difference already separates them.
- Option paths start at one shared column instead of being right-aligned.
Right alignment floated every row's path START with its own length
(cmd.exe began ~300px right of Nushell's), so scanning meant hunting
left and right per line.
- Footer hints drop their chips. A chip background means "clickable" here;
the arrow/Enter/Esc legends aren't buttons, so key and description
separate by ink weight instead.
Keycaps go back to one chip per combination
Per-key chips are a macOS form, where the modifiers are single-character
glyphs that tile evenly. Ctrl/Shift/Alt are words, so splitting produced a
row of ragged blocks; and Windows users already read Ctrl+Shift+P as one
string in VS Code and Office.
Carets that look alive
The blink phase hung off the wall clock, so a field taking focus had a 50%
chance of showing its caret up to half a second late — which reads as "not
focused". Phase now starts at the last edit: lit immediately, steady while
typing, breathing only after the hand stops, at the system's
GetCaretBlinkTime (including the accessibility setting that disables
blinking). The palette was also missing from the fast-redraw list, so its
caret froze once the open animation ended. The palette caret is now a
1.5px beam rather than a full-cell glyph, which lets placeholder and real
input share one x — the first keystroke no longer shifts the line.
Overlays share one recipe
Confirm dialogs and the SSH editor gain a real drop shadow and the common
radius; both previously drew hairline + fill only, so a dialog demanding an
answer floated lower than the palette you dismiss with Esc. The SSH
editor's dim was a hard-coded 67% black ignoring the theme. Dropdowns cast
a shadow instead of a glow (a glow spreads brightness without establishing
height) and are opaque, since a menu sits directly on the content it hides.
Why this kept regressing
ui/mod.rs has said "layer contract: no magic numbers" for a while, and
widgets.rs violated it — a constraint expressed only in a comment is not a
constraint. ui/guardrails.rs turns three of them into failing tests, each
carrying a budget equal to today's real count: new violations fail the
build, and clearing old ones fails it too until the budget is lowered, so
the number only goes down. This pass: radius 121 -> 94, strokes 69 -> 56,
glow-as-shadow 12 -> 9.
Probe script now runs a COPY of the debug binary. Running the build output
directly makes the next cargo build die with an opaque mingw link error,
and it invites cleaning up by image name — which would kill the user's own
window, possibly the one hosting this session.
- Ctrl+K opens/closes the shell picker (new ToggleShellPicker action, listed
and rebindable in Settings -> Key bindings). It takes over the shell's
kill-line by default.
- The picker is now a card list: a "Recommended" hero card (name, full program
path, Enter chip) plus uniform "All options" cards. PaletteLayout exposes
per-row rects and `row_at`, so hover and click stop lighting up section
captions and the gaps between cards -- both passes and hit-testing read one
geometry instead of dividing by row_h.
- One keycap recipe (display/keycap.rs) shared by the picker's Ctrl+K badge,
the command list's shortcut hints, Settings key rows, confirm dialogs and
the picker footer. Combos split per key; confirm keycaps no longer restack
the button's own fill.
- Light-theme overlays go white-based instead of inheriting a silver fill from
the theme family.
- The palette's right edge measures from a single GUTTER instead of four
different insets; the footer measured from the panel rather than the card
column, which left a ragged margin that drifted with font size.