* feat(keyboard): support hardware keyboards on iPad
Register app shortcuts as iOS UIKeyCommands so a paired hardware keyboard
drives the same bindings as web and desktop. Overlays (menus, comboboxes,
modals, command center) get first refusal on bare keys, and a focused
terminal keeps the keys it needs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(keyboard): record iOS hardware key observation spike
With a UITextView focused on iPad Pro M4/iOS 18.6, window and controller observers received Cmd+B, Cmd+P and Escape. Escape also invoked UIKeyCommand when registered, so the stream must be the sole emitter. Use observation for shortcuts and commands only for text-control ownership. Simulator intercepted Cmd+K as HID184; input capture blocked synthetic typing entirely. Keep capture off and verify the toggle via a rebind during simulator QA.
* refactor(keyboard): give overlays one key registration API
Overlay ownership now follows one layer-ordered registry on every runtime. Web retains focus trapping and restoration through its adapter; native registers the same key handler without a DOM scope. Picker navigation and dismissal no longer require a parallel native stack.
Co-authored-by: jeroenfrenken <16974549+jeroenfrenken@users.noreply.github.com>
* feat(keyboard): route native hardware keys through the shared resolver
Observe each physical press once, including native modal windows, and derive focus from declared composer and terminal surfaces. Native bindings and rebinds now use the same resolver and overlay precedence as browser and Electron input.
Co-authored-by: jeroenfrenken <16974549+jeroenfrenken@users.noreply.github.com>
* feat(keyboard): show shortcuts when hardware keyboards are present
Keep routing independent of compact layout and detect hardware capability for hints and settings. Rebind capture uses the shared overlay interface on native too. Keep the filtered sidebar model available for keyboard navigation while its panel is hidden.
Co-authored-by: Les Stroud <public@lesstroud.com>
Co-authored-by: jeroenfrenken <16974549+jeroenfrenken@users.noreply.github.com>
* test(keyboard): allow shortcut hints in compact menu assertions
Compact menus now display hardware keyboard hints. Assert action labels, order and uniqueness without treating a trailing shortcut badge as part of the action label.
* fix(keyboard): retain an overlay's opening layer in state
Capture the registry's current top when an overlay opens and retain that layer through rerenders. React Compiler removed the previous useMemo cache after the registry getter moved across modules, allowing a parent modal to rise above its child and start an infinite focus loop.
Compile this hook in Vitest as Expo does. The new hook regression failed first with layer 220 instead of 20, then passed with explicit opening state. Focused unit and browser tests pass, and the previously failing onboarding E2E completes through the real Expo compiler. Typecheck, lint and format pass.
* refactor(keyboard): let overlays own native hardware input
Remove the TextInput key handlers that duplicate declared overlay arrows and Escape in Add Project and Command Center. Remove Add Project's hidden responder now that native window sources observe keys without it. Keep soft-keyboard submit editing behavior.
* fix(keyboard): close Add Project outside its state updater
Root Escape previously called the parent close action from a React state updater, producing a cross-component render warning when navigation was still queued. Compute the previous page in the event handler and close outside the updater.
The existing Escape/Back E2E now batches navigation and dismissal through the DOM key source. It failed first with the AddProjectFlowHost render warning, then passed after the correction. Typecheck, lint and format pass; native Escape checks pass on Android and iPad.
* fix(keyboard): preserve Android dead-key composition
* fix(keyboard): recognize focused native text inputs
* test(keyboard): replace JSDOM coverage with browser tests
* refactor(menu): spell out arrow navigation branches
* fix(composer): claim fullscreen Escape on native
* refactor(composer): one fullscreen Escape module for every platform
The shared registration lived in fullscreen-exit.shared.ts with two one-line
re-exports (fullscreen-exit.ts and fullscreen-exit.native.ts). Metro needs no
native override now that the Android back button is its own adapter, so the
implementation moves into fullscreen-exit.ts and the browser test imports the
module every platform resolves.
---------
Co-authored-by: Ubuntu <jeroenfrenken@icloud.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: jeroenfrenken <16974549+jeroenfrenken@users.noreply.github.com>
* fix(app): add hosts without leaving the current screen
A retained Settings route replayed its addHost query after appearance remounts. Own the connection flow outside screen lifetimes and let each consumer choose its completion navigation.
* fix(app): release the project dialog before adding a host
* fix(app): size the QR scanner viewport on wide layouts
* test(app): align creation and desktop setup with in-place host flow
Keep compact sidebars open while users inspect Search, Import session, Add project, or file sheets. Reveal the resolved destination when navigation commits, and place compact workspace sheets above both sidebars while preserving shared editing and cache state.
* fix(app): scroll the Add Project results to the keyboard-selected row
The results list had no scroll ref, so ArrowUp/ArrowDown moved the selection off-screen; the autocomplete reveal math is now shared through useRevealActiveItem.
* test(app): verify the directory selected beyond the results viewport
Check scrolling in both directions and across wrapping, then confirm Enter opens the selected directory. The previous regression used an aria-selected attribute that result buttons do not render.
Co-authored-by: superheher <heh@vivaldi.net>
* test(app): verify scroll reveal through browser behavior
Keep pure offset checks and cover keyboard navigation, wrapping, and replacing search results in the real Add Project flow.
* fix(app): measure retained Add Project rows when revealing selection
* fix(app): measure scroll content through a native View reference
---------
Co-authored-by: superheher <heh@vivaldi.net>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
* fix(app): keep long custom models removable
Custom model labels and IDs could consume the row width and push Remove outside the sheet. Allow those text cells to shrink while preserving the button width and short-name alignment.
* test(app): wait for legacy agent creation before checking prompts
Agent-list membership includes initialization. Waiting for finish at that point can return on the initial idle transition before the initial prompt starts. Wait for the matching creation response before checking each completed turn, preserving the existing exact-once assertions.
* test(app): wait for directory search keyboard focus
The search page becomes visible before its deferred focus callback runs. Wait for the input to own keyboard focus so the journey types its query rather than dropping it during navigation.
---------
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
* fix(app): remove search from project method selection
The fixed method list should not accept text because it can be mistaken for the directory path step that follows.
* fix(app): preserve native project picker keys
Keep hardware-keyboard delivery owned by the Add Project flow even when method selection has no visible text field.
* test(app): update add project overlay expectation
* fix(ci): skip unrelated required checks cleanly
Matrix jobs had to start no-op runners to preserve interpolated required-check names. Static named jobs let GitHub report genuine skipped conclusions while keeping those names stable.
* fix(ci): gate changes to install patching script
* fix(ci): route cross-package test contracts narrowly
* fix(ci): keep routed contracts merge-blocking
* fix(server): exclude nested test utilities from builds
* fix(ci): cover app-owned native and browser domains
* refactor(ci): align tests with runtime domains
Own browser specs, desktop specs, and Electron-only app code by stable directories so PR routing does not depend on filename conventions. Keep desktop integration coverage inside the required desktop check.
* fix(ci): keep routing and desktop suites isolated
The routing regression must run before dependency installation, and desktop Vitest must not collect Playwright-owned specs.
* fix(ci): isolate desktop e2e runtime
* perf(test): isolate Playwright workers
* perf(test): parallelize Playwright within specs
* fix(test): keep Playwright file scheduling
* fix(test): share dynamic Metro fixture
* fix(test): preserve own-host restart fixtures
* fix(ci): preserve routed contracts after rebase
* Stabilize Playwright wheel-scroll assertions