docs/internal/orchestrator-dock-gaps.md
Status: Tracking doc for the global dock (branch
claude/elegant-fermat-vKK5G). The dock ships as a non-modal, full-height left column: toggle via "Orchestrator: Toggle Dock"; ↑↓ live-switch the active window (30ms debounce) with a directional whole-window wipe; Enter/Esc/editor-click blur to the editor with the dock pinned; mouse click selects+activates a row; wheel over the dock is consumed.
chrome_area, so they sit beside the dock instead of
being overpainted by it. The workspace-trust dialog still uses size
— it's a startup gate that can't be concurrent with the dock.render_top_global_popup (global popups) and the
per-buffer LSP hover/completion popups now clamp to chrome_area, so
they can't overrun the dock column. (The popup fixes mirror the
verified overlay fixes; the LSP/global popups couldn't be triggered
interactively here — no LSP server in the sandbox — but the change is
the same chrome_area clamp and renders without regression.)last_frame_width/height store full size, not chrome_area, so
macro-replay / recompute_layout lays the chrome at the wrong width
while the dock is up.Editor. dock_width). Cross-session persistence (config) is still TODO.hide-trivial filter as the
modal.OPEN_MODE binds Space to
orchestrator_toggle_select unconditionally — it has to, to keep
Space out of the filter text-input. toggleSelectCurrent now branches
on the focused widget key (mirrored from the existing focus
widget_event) and dispatches to the focused control's toggle
(scope-toggle → toggleScope, worktree-show →
toggleShowWorktrees, hide-trivial → toggleHideTrivial) or falls
through to the list when focus is on sessions. Buttons / filter
input no-op (Space has no toggle semantic on them).dock.focused = true on the un-dive click but didn't notify the
plugin (set_panel_focus_and_notify no-ops when the inner focus_key
is unchanged, which is the common case — the dive only touched
overall focus, not the inner widget). The plugin's dockBlurred
mirror stayed true, so scheduleDockSwitch short-circuited at the
+30 ms check and the click — and every subsequent arrow — was
swallowed. The host now fires a focus widget_event when the click
un-blurs the dock, symmetric with blur_floating_panel (which has
always fired blur on the inverse transition).set_active_window should land focus on the last editor pane.terminal_exit / idle) before adding the glyph.list widget is flat; grouping needs interleaved header rows +
selection-index remapping).PanelSlot::Dock +
PanelSlot::Floating, see app/mod.rs); the dock mounts into the Dock
slot (mountFloatingWidget(..., asDock=true)) and a centered modal
(the New-Session form) into the Floating slot, so + New / Alt+N
leaves the dock visible beside the form. Input/mouse/wheel route to the
focused slot, with the centered modal taking precedence over the dock.
The dock has its own KeyContext::Dock. See
Design: dock + modal coexistence.buildPreviewEntries) is not
surfaced in the dock to keep the list-fill height maths exact.We only want principled, final solutions here — no slot-juggling or reopen-after-close workarounds. All correct options start from the same ontology: the dock is persistent, non-modal, owns a fixed layout region → it is chrome, not an overlay. Today's bug exists only because it was built as a modal-ish floating panel sharing one host slot with the orchestrator's centered form/picker. (Settings, the keybinding editor, popups, and menus live in separate state and already coexist with the dock — the conflict is isolated to the orchestrator's own panels.)
The two-tier chrome must keep working exactly as it does now:
compute_dock_split →
dock_area + chrome_area), independent of active_window.Editor, shows all
sessions, persists across switches) — not per-window like the file
explorer. It renders into dock_area.chrome_area; switching sessions only swaps
what's in chrome_area.chrome_area. Because dock_area and
chrome_area are disjoint, the dock stays static while the window
slides; the animation's "before" snapshot is bounded to the animated
rect, so the dock is never captured/moved.Any solution below must preserve all of the above — they change only how the dock is hosted/focused and how a centered modal coexists, never the carve or the animation scoping.
Make the dock an editor-level chrome region with its own
KeyContext::Dock (modeled on KeyContext::FileExplorer, but
editor-global, not per-window), hosting a declarative widget spec.
Centered modals stay as the single overlay layer above chrome.
KeyContext precedence
(Settings > Menu > Prompt > Popup > … > Dock/FileExplorer/Normal). No
new focus subsystem, no per-call-site focused flags; dock blur/dive
is just a context transition back to the editor split.chrome_area-scoped animation;
only dock hosting + focus change. A centered modal then renders over
chrome_area while the dock keeps rendering in dock_area.last_frame_width macro-replay bug (dock width is computed once,
authoritatively, as part of the layout).Replace the ad-hoc overlay/focus zoo (floating_widget_panel,
settings_state, keybinding_editor, the global/buffer popup stacks,
menu_state, the prompt) with one ordered layer stack. Each layer
declares a region (full-screen-centred, left-dock column,
cursor-anchored, …), a focus policy (modal / non-modal / passive), and
paint order; a single focused_layer pointer is the keyboard target,
and input + mouse dispatch walk layers top-down by region.
render.rs / input.rs /
mouse_input.rs. Dock + modal + popup coexistence is intrinsic, and it
also fixes the existing per-slot inconsistencies (each current overlay
reinvents dim / focus / mouse).LeftDock-region layer, modals modal layers, popups passive
anchored layers. The window-switch wipe is still scoped to the window's
region (the dock layer's region is disjoint), so persistent dock +
independent animated window is intrinsic to the model.KeyContext precedence, or it's less
principled than P1.P1 is the correct minimal-principled answer (dock = chrome, reuse
KeyContext, delete the floating-panel dock code, coexistence by
construction, today's carve+animation preserved). P2 is the eventual
destination only if a future need demands arbitrary layered panels and we
choose to consolidate the overlay zoo; if so, P1's dock-as-chrome should
be a layer within it. A hybrid (P1 for the dock now + a later
OverlayManager unifying just the modal/popup zoo) is a reasonable
staged path to P2.
Non-modal dock placement + layout carve; focus/blur key + mouse routing; list fills height with pinned hint; live-switch + whole-window directional wipe; worktree toggle, scope, filter, inline Stop/Archive/Delete + in-place Delete confirm; wheel consumption.