CodeNomad/dev-docs/UI_SHELL.md
Pascal André 7a1fc90310
docs(agents): keep AGENTS.md to universal rules and agent docs to the current state (#1082)
AGENTS.md loaded about 33,000 tokens into every agent session, subagent and reviewer, mostly per-feature contracts, and the agent documentation around it had accumulated duplicates, dated logs and history of removed designs. This PR makes AGENTS.md a short set of rules that apply everywhere plus an index of area documents, and leaves AGENTS.md, dev-docs and the repository skills describing only the current state.

Three commits, reviewable separately:

1. **Move (lossless).** Every per-area rule moved verbatim from AGENTS.md into its area document (existing ones, or six new ones: UI_CONVENTIONS, UI_SHELL, COMPOSER, TRANSCRIPT, SETTINGS, PROJECTS). A script split the old file into 208 units, required one destination for each and checked all 199 content units verbatim at their destination. AGENTS.md went from 134,000 to 16,000 characters.
2. **Trim.** A per-area ponytail review removed rules stated two or three times (keeping the more precise copy), dated validation logs, per-version qualification sections below the current minimum, abandoned designs and self-references; seven documents whose surviving rules live elsewhere were deleted. It also fixed statements the code contradicts (locale registration, the Mission play/recovery condition, plugin package updates, cleanup progress UI, timeline index persistence, automation restart/targets, stale pins and minimums).
3. **Current state only.** The new AGENTS.md rule: no history (removed features and their names, former behavior, provenance, dated logs) and no denials; correct a contradicted statement at its source. DEVELOPER_MODE.md is merged into BROWSER_AUTOMATION.md and every Developer Mode mention is gone (including the README and the browser help page in ten locales). Names that only made sense against older designs are renamed with every reference updated, MISSIONS_ENVIRONMENT_ADMISSION is folded into SESSION_ENVIRONMENT, and INDEX lists every document. The server npm README now states the real OpenCode minimum (2.1.2).

AGENTS.md is now about 14,000 characters (roughly 3,500 tokens); AGENTS.md, dev-docs and the vendor README went from about 11,200 lines to under 4,700.

Validation: every relative Markdown link and every cited dev-docs path resolves; no reference to a renamed or deleted document remains; `npm run test:help` passes for all ten locales.

Review: three independent GPT-6.1 Sol (high) reviews by area found binding rules lost in the trim and current-state passes; 25 were restored as present-tense facts or prohibitions and four contradicting statements corrected, each checked against code. A Fable 5.1 gatekeeper review of the whole PR passed; its follow-up routes session recovery from the index, points to dev-docs/INDEX.md and documents the family identity read.
2026-10-21 16:59:43 +02:00

6.2 KiB

Application shell

Panel toggles, floating drawers, project/right-panel tabs, the session sidebar and native application menus.

Agent conventions

  • Session rows keep actions inline until their measured title, badges, and controls no longer fit. Keep responsive action styles in styles/components/session-row-actions.css; hidden inline controls remain measurable but inert, and an open overflow menu stays mounted until dismissal.
  • A subsession that starts working is revealed only below the session active in that instance (revealWorkingSubsession); other families stay collapsed. A collapsed parent's own expander chevron carries its descendants' most urgent visible state (input steady, working/compacting pulsing, idle steady green) with counted states in its label (session-child-activity.ts); idle follows the existing badge visibility, unseen-subagent preference and seen/fade lifecycle, and never outranks input or work. Never add a separate badge, and an expanded parent's chevron stays plain. Automatic reveals are transient: excluded from restorable expansion state until the user toggles or explicitly reveals the row, and a manual collapse dismisses the branch for subsessions running at that moment. Styles live in styles/components/session-child-activity.css.
  • Session hierarchy geometry lives in styles/components/session-tree.css; connector axes follow the parent expander at every depth, including selection mode, RTL and touch layouts.
  • Session search/filter mode uses flat per-session results with an optional subsession switch; filters, sorting, worktree badges and selection use each result's own identity. Normal browsing retains the session hierarchy.
  • Project and right-panel tabs share components/tab-scroll.tsx and styles/components/tab-scroll.css. Keep their native scrollbar above upright content without mirrored transforms, negative border overlaps or permanent compositing hints. Validate shared scrollbar styling and adjoining edges at fractional zoom in the browser and isolated Electron renderer fixtures (tests/browser/tab-chrome.test.ts).
  • Built-in right-panel tabs are constructed directly in right-panel/core-runtime.tsx (never add a first-party plugin loader for them); external sandboxed panels keep their independent consent/loading path.
  • Embedded floating session drawers use instance/shell/HostedDrawer.tsx so their SUID modal roots are direct children of the existing geometry host. A Solid Portal wrapper must not become an ARIA-hidden ancestor of visible controls. Preserve SUID's modal stacking, sibling isolation, focus policy, Escape/backdrop handling and scroll restoration; validate with tests/browser/drawer-accessibility.test.ts rather than overriding ARIA or disabling modal enforcement.
  • Floating-panel outside-pointer dismissal must leave ARIA menus, listboxes and dialogs to their own selection/dismissal handlers: their portals are outside the drawer DOM, and closing the drawer on pointerdown destroys a menu before touch pointerup selects its action. Keep this guard shared in the shell, not in individual menu actions; validate the real session Delete confirmation with tests/browser/session-delete.test.ts.
  • Each side panel has exactly one open/close control: instance/shell/ShellPanelToggle.tsx (PanelLeft/PanelRight, .icon-toggle with aria-expanded/aria-controls), absolutely placed at the shell's outer header corners (--space-xs from the window edge) in .session-shell-frame, outside the drawer host so modal sibling isolation never hides it, and above floating drawers. The frame is an isolated stacking context: toggles stay above in-frame drawers but below body-portaled dialogs, scrims and utility windows. Both toggles precede the shell content in tab order and use the fixed View-menu labels (window.menu.leftPanel/rightPanel) with aria-expanded, never an Open/Close label flip. They are strictly fixed: no horizontal or vertical movement between docked, floating and closed states in any layout; the sidebar header, right-panel tab bar (both edges when floating) and the conversation header (data-{left,right}-toggle-reserve) reserve their footprint instead. Every header's action row (session list header row, right-panel .tab-strip-shortcuts, conversation side groups and status indicators, with or without the title row) and the toggles centre on one shared line, --panel-header-action-center in styles/tokens.css; never measure per-state offsets. The session list header holds a single action row; never add a keyboard-shortcut footer below the session list. Opening one floating drawer closes the other; the outside-pointer handler ignores the toggles. Styles live in styles/panels/shell-panel-toggles.css; validate with tests/browser/shell-navigation.test.ts.
  • The session sidebar header ends with Back/Forward (ArrowLeft/ArrowRight, mirrored in RTL; history wording "Back"/"Forward" with conversation tooltips, distinct from the palette's Previous/Next Session list cycling) over a browser-like in-memory history per project tab and window (stores/session-navigation-history.ts, instance/shell/useSessionNavigationHistory.ts, at most 50 entries). It records every displayed conversation whatever selected it; Info and the no-session draft are not entries (Back first returns to the cursor entry). Navigating moves the cursor and selects through the ordinary handleSessionSelect path without pushing; a new selection truncates the forward stack; unavailable/deleted sessions are skipped and determine the disabled states. Do not add keyboard shortcuts or persistence to this history.
  • Native Electron/Tauri application menus follow the UI locale: renderers translate NATIVE_MENU_LABEL_KEYS (lib/native/menu-labels.ts) and send them with the View menu state. Hosts keep English until a renderer reports labels, keep the last locale for windows without one, and escape & outside macOS. Electron takes its defaults from lib/native/menu-labels-en.ts; Tauri's menu_labels.rs defaults are checked against the English messages by menu-labels.test.ts. Tauri retitles retained items in place; Electron rebuilds its menu on a label change. About CodeNomad runs the open-about command (Settings → Info), falling back to a native panel only when no application window can receive it.