* feat(macos): native-feel dashboard hosting: instant reopen, preload, frame autosave, ⌘N/⌘K, route memory
The hosted Control UI dashboard now skips SPA reloads when reopening an
unchanged endpoint (auth-equality gated), preloads after launch when a
credentialed local/direct config exists, autosaves its window frame, maps
⌘N/⌘K menu items onto the shipped native web events, filters browser-tell
context-menu items, restores the last committed route via web-side
localStorage memory, and themes the pre-paint background.
* refactor(ui): satisfy TS LOC ratchet: move optional lazy-element helpers out of app-host
app-host.ts is over the 500-line ratchet ceiling and may not grow; move the
self-contained optional custom-element block into lazy-custom-element.ts (its
natural owner) and fold the route-restore decision into native-route-memory's
considerRouteRestore so the shell only replaces-or-persists.
* fix(macos): recover stuck dashboard command queue via deliverability gate
Replace the failure-page-only fast-path check with canDeliverNativeCommands
(live document or in-flight load); a terminally cancelled reload now falls
through to the reload path instead of queueing ⌘N/⌘K forever.
* fix(ui): let in-flight navigation win over native route restore
The one-shot startup restore now checks the rendered/pending match against
the committed bootstrap route; an explicit navigation already in flight
(replayed native new-session, fast click) is no longer clobbered.
* docs(ui): note idempotent collapse of pending native new-session replays
* fix(macos): drop queued dashboard commands on terminal load failure
Queued ⌘N/⌘K are moment-bound; surviving a failure page meant a later
recovery reload replayed stale commands (double palette toggle nets closed,
surprise navigation). Both failure entry points now clear the queue.
* fix(ui): persist native route memory only for settled router states
Mid-navigation emissions still carry the stale committed bootstrap route; an
interrupted restore could overwrite the remembered destination with it.
* fix(macos): coalesce dashboard opens for queued native commands
One in-flight open drains a manager-level queue in press order; a Task per
key press could race window creation (duplicate windows) and reorder ⌘N/⌘K
delivery on the non-immediate remote path.
* fix(macos): correct dashboard placement after frame-autosave restore
setFrameAutosaveName re-applies the stored frame; run ensureOnScreen after
both autosave-name assignments so a frame saved on a disconnected monitor
cannot restore the window off-screen.
* fix(macos): clear dashboard failure state when history restores a real document
Swipe-back/⌘[ off the failure page commits an http(s) document without
passing through load(); the flag previously stayed set and forced a reload
on the next native command.
* fix(macos): keep in-flight dashboard loads instead of restarting them
An open/update during the launch preload previously cancelled and restarted
the same-URL load; in-flight non-failure documents now count as usable in
the reload decision.
* fix(macos,ui): ⌘K legacy fallback + transient search param filtering
Command palette dispatch now sends a cancelable toggle event and falls back
to the shipped open-search event when no handler acknowledges it, so ⌘K
keeps working against older gateway-served bundles. Route memory strips
one-shot action params (?draft=) before persisting; navigation state like
?session= still restores.
* chore(i18n): register dashboard menu strings + drop unused route-memory export
native:i18n:sync inventory + per-locale artifacts for New Session / Command
Palette…; StoredNativeRoute is module-internal after the considerRouteRestore
refactor (deadcode exports gate).
* chore(i18n): rebaseline raw-copy for relocated lazy-element labels
The lazy-custom-element extraction moved three internal load-failure labels
out of app-host.ts; refresh the keyless raw-copy baseline to match (main's
new ui:i18n:verify gate).
* fix(terminal): harden node PTY relay and terminal session lifecycle
Pin node relay invokes to the authorized node connection (ROUTE_CHANGED
guard), stop node-side input writes to settled/dead PTYs, finalize
sessions on resize failure like write failure, keep surrogate pairs
intact across scrollback and relay prelude truncation, bound the relay
pre-registration output buffer, and buffer Control UI keystrokes typed
while terminal.open/attach is in flight so slow node-relay opens no
longer drop input. Correct the terminal.data seq doc to its real
contract and pin seq monotonicity, seq-gap bounds, input coercion, and
runner event routing with new tests.
* refactor(terminal): extract startup input buffer and fix CI findings
Move Control UI startup input buffering into terminal-startup-input.ts
(LOC budget), drop a stale session-manager comment, remove a map
spread, and fix test typings for event frames and typed mock access.
Catalog session rows (sidebar context menu + click), the built-in viewer
header, and a new "Open Codex/Claude sessions in" preference can launch the
native CLI (codex resume / claude --resume) in the operator terminal on the
machine that owns the session.
- Gateway-local sessions spawn through the existing terminal launch policy
(sandbox/enabled gates preserved) with the resume command in the session cwd.
- Paired-node sessions run through a new seq-ordered node PTY relay: a
duplex node-host command streams PTY output via node.invoke.progress and
receives keystrokes/resize via a new node.invoke.input event, behind the
unchanged terminal.* client protocol (TerminalSessionManager gains a backend
abstraction; node relay reuses the streaming-invoke controller).
- Owner boundary: each plugin owns its resume command and builds argv from a
validated thread id; the gateway routes node opens through the node command
allowlist and plugin invoke policy (no advertisement-only trust), and nodes
re-verify session eligibility before spawning.
- UI setting catalogOpenTarget + canOpenTerminal capability gate every entry
point; capability requires the owning host to actually have the CLI.
Node PATH is normalized before command-availability probes, Windows .cmd/.bat
shims spawn via ComSpec, and catalog terminal opens reattach persisted tabs
before opening the new tab.
* improve(ui): drop page subtitles from settings and hub headers
The one-line page subtitles restated the nav label the user just
clicked ('Channels and settings.') while sections and rows already
carry contextual descriptions; every header now reads title-only,
matching the settings design language reference. Subtitle strings stay
in app-navigation for settings-search matching and the sidebar search
blocks. Removes the now-unused .page-sub rule.
* fix(ui): give Skills and Skill Workshop route-specific page titles
* chore(ui): drop unused configPageSubtitle helper
* feat(control-ui): show compaction savings and run time
* fix(control-ui): satisfy locale and export checks
* fix(control-ui): refresh locale metadata
* refactor(ui): add Web Awesome foundation
* refactor(ui): migrate shared menus and chat controls
* refactor(ui): migrate page controls to Web Awesome
* refactor(ui): migrate workboard controls to Web Awesome
* fix(ui): harden Web Awesome interactions
* test(ui): type Web Awesome dropdown state
* fix(ui): preserve menu focus and selection
* fix(ui): restore agent picker focus
* fix(ui): track keyboard menu dismissal
* fix(ui): ignore stale session menu closes
* fix(ui): complete Web Awesome keyboard migration
* fix(ui): repair Web Awesome lockfile graph
* docs(ui): keep release note in PR body
* fix(ui): satisfy Web Awesome migration gates
* perf(ui): keep Web Awesome theme in startup stylesheet
* fix(ui): replace reopened Web Awesome session menus
* fix(ui): keep replacement session menus open
Inputs (41px), buttons (30-38px), and segmented switches (33px) sat at
mixed heights inside the same settings rows and toolbars. All controls
in settings clusters now share --settings-control-height (32px), and
the eight remaining native selects (cron filter popover, model-provider
default/fallback pickers, usage session sort) adopt .settings-select.
Row control clusters wrap only at mobile widths where they have a
definite width (Chromium collapses wrappable shrink-to-fit flex
containers to their widest item).
* feat(web): show session branch row for local changed files
The pre-PR branch row above the composer only appeared once the branch
was pushed and ahead of the default branch. Sessions with local work
(committed, uncommitted, or untracked changes) showed nothing.
The gateway now emits the branch payload whenever the working tree has
changed files vs the default-branch merge base; createUrl is withheld
until GitHub's pull/new page has something to compare, and the UI only
renders the Create PR link when it is present.
* refactor(gateway): keep control-ui-session-prs under LOC ratchet
* docs(gateway): note explicit-base diff counts conflict paths