Shape rows in native Canvas and CoreText, then place clusters on xterm columns so fallback font advances cannot separate text from its cursor. Wait for measured dimensions before attachment and repaint overhanging ink with affected rows.
Use Android platform ICU to avoid bundling approximately 14 MB of data; retain and document the Android 10 conjunct limitation.
Backport the Unistyles 3.5.3 Activity configuration fix while keeping 3.2.4 and its existing fixes. Application resources could leave the responsive shell on the previous fold size after resume. Cover the real device-state sequence with a native UI regression.
The notice arrived with the terminal worker change (#7644) but is a separate
product change. Remove it with the native/compact callout filtering it needed,
restoring the sidebar callout slot to web-only. Restart and close terminals in
Settings stays.
* M1: terminals survive daemon restarts: stop reasons, detached terminal worker, kill cleanup
restart_server_request.killTerminals / shutdown_server_request.keepTerminals and server_info.features.terminalsSurviveRestart; CLI daemon restart --kill-terminals and daemon stop --keep-terminals (capability-gated). The terminal worker runs detached over an owner-only, secret-authenticated socket and is adopted on daemon start. One kill cleanup contract (the reaper) by birth time, used by the daemon, the supervisor and stopDaemonInstance. Settings offers Restart and close terminals.
* M1: fix review findings: reaper session/table retry, short-command creation order, remote kill-restart cleanup report, stop test port
* M1: fix review findings: reaper-owned cleanup record, session member identity by terminal id, unreadable cleanup records, Settings restart error rendered in the card
* M2: worker protocol versions and draining, worker runs from its own copy, desktop upgrades keep terminals, out-of-date daemon notice, docs/terminal-worker.md
- Daemon classifies live workers by protocol: adopts current, drains one version old, shuts
down older, leaves a newer one running and answers list/create with
terminal_worker_incompatible (daemon status prints it). Never more than two workers.
- esbuild worker bundle (build:lib); a built daemon copies bundle, shell integration and
node-pty into $PASEO_HOME/terminal-worker/<version>-<hash>/ and launches from it; copies no
record names are pruned.
- Desktop app_update/version_mismatch stop with keep terminals on macOS/Linux; Windows and a
daemon without the capability close them.
- Out-of-date daemon sidebar notice with Update button, worded by terminalsSurviveRestart.
- PASEO-13: unreadable worker records fail status and kill-restart retry.
- PASEO-14: a session member without a terminal id is unknown, not unrelated.
- Smoke test 46 with A/B installation fixtures and per-fixture CLI shims (PASEO-9 fold).
* M2: track in-flight worker requests without leaving an unhandled rejection
detach({ afterPendingRequests }) tracked each request with request.finally(), which rejects
with the request; a fire-and-forget send that timed out surfaced as an unhandled rejection
(worker-terminal-manager.test.ts). Track settlement only.
* M2: CI round 1 fixes: worker terminal manager in the MCP key test, status cleanup field, shared socket dir
- mcp-server.test.ts (new upstream test) built the worker manager with the old fork API;
it now starts a real detached worker in a throwaway home.
- daemon-session.test.ts expected status without terminalCleanupUnconfirmed (added in M1).
- paseo-daemon.test.ts: a home under the scratch temp dir is too long for a unix socket, so
the worker listens in the per-user paseo-<uid> directory, which outlives workers by design;
the test now requires it to be empty instead of absent.
* M2: run Windows PowerShell by its install path for process identity
server-tests (windows-latest): bootstrap-provider-availability.test.ts starts a daemon with a
PATH that holds only git, and the terminal worker failed to start: 'cannot read its own process
identity: spawn powershell.exe ENOENT'. Process inspection (managed-processes.ts inspect and the
terminal worker's process table) now runs %SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe.
* M2: lifecycle e2e plain stop uses the shutdown RPC on Windows
CI round 2, server-integration (windows-latest): 'stop and stop --force never signal processes
a stale or earlier-boot record names' called stopDaemonInstance without a shutdown channel,
which Windows refuses ('has no graceful shutdown channel'). Plain stops in the file now pass
one, as the CLI does.
* M2: native notice outlet, Windows desktop-update wording, worker cap counts unconfirmed cleanups, create recovers after a drain
* M2: phone sidebar mounts the callout slot (iOS notice verified), worker record reads retry transient errors
* M2: native notice preconditions use explicit working directories, one block per terminal
* M1: compact sidebar shows only native callouts on every platform; PTY round trips in the MCP key test get a 5 s window
* ci: pin Playwright browser jobs to ubuntu-24.04
The pinned Playwright (1.58) has no ubuntu-26.04 build, and forks whose
ubuntu-latest already resolves to 26.04 fail at browser install. Job names
are unchanged, so required-check contexts still match.
* ci: use ubuntu-latest for Playwright jobs, same as upstream
Reverts the ubuntu-24.04 pin; upstream main's Playwright shards pass on ubuntu-latest.
* fix(server): keep terminal worker record IO off the daemon event loop
* fix(server): restore terminal creation after worker failure
A disconnected terminal worker remained the current manager indefinitely, leaving dead sessions listed and every later create bound to a closed socket. Confirm process death before retiring the member and use the existing single launch path for replacement. Reconnect live workers and replay their screens while preserving terminal identity.
* test(server): verify orphan cleanup during worker recovery
Recovery reaps orphaned programs before a later daemon stop. The previous fixed-delay assertion raced that cleanup and failed when it completed promptly. Verify orphan removal, same-daemon replacement creation and cleanup on normal or forced stop instead.
* test(server): isolate Windows dependency fixture setup
Build the local package registry in setup so its npm packing processes do not consume the installation journey deadline. Install the platform package used by Windows runtime fixtures directly, avoiding an unused wrapper postinstall probe without a timeout.
* test(server): wait for pending watchers before disposal
Observation admission starts before asynchronous path setup reaches watcher subscription. Disposing at the admission counter races setup and never exercises late watcher cleanup. Wait for the subscriptions to be pending before disposing.
---------
Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
Android ships generated Markdown props without code.fontScale, so native measurement wraps inline code at a larger size than drawing. Regenerate both Android code structs and enforce generated-header parity for both platforms.
Native hidden overflow capped the measured content at the preview height, so long messages never offered Show more. Use the native scroll layout mode on the existing View to measure full content while preserving clipping, and store only whether it overflows.
Long command descriptions exhausted the available space above a tall draft, leaving no complete selectable row. Bound the preview and reserve list space. Let the popover own its composer anchor so layout changes refresh its position while suggestions remain open.
Scale inline code with the enclosing block using theme tokens, and preserve its size and font through bold and links. Use contextual package patches so clean installs reproduce the verified native source.
The wide sidebar reserved only the top safe area, leaving its footer under Android navigation UI. Apply the existing bottom inset to the same interior and add a native geometry regression check.
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
Keep iOS command and file suggestions above the composer and keyboard across chat, workspace drafts and New workspace. Share transform-free anchor measurement and keyboard translation through keyboard/shift.
Includes failing-first native placement and exact-insertion coverage, plus two CI test reliability fixes.
Co-authored-by: sam <76036008+masz77@users.noreply.github.com>
Order ordinary sidebar workspaces by Created or Last prompt, preserve project and pin ordering, and keep later active or unacknowledged work visible beyond the first seven rows. Preserve reveal state through live updates and verify sorting, visibility, compatibility, and rendering behavior.
* Upgrade to Expo 57 and unify Explorer across layouts
* feat(app): retain Explorer across layout and appearance changes
Keep one workspace Explorer host and destination-aware navigation so folding, theme updates and compact sheets preserve the current panel. Scope pull request discovery and timeline demand to active surfaces.
* fix(app): keep Explorer resize handles stretched through the dock
The shared frame moved the divider into an absolute column, leaving its horizontal handle without height. Restore the row so pointer drags reach it, preserving the existing resize and performance contract.
* fix(app): keep Explorer drag widths out of the shared stylesheet
Carry the existing inline sizing policy into the shared frame so pointer previews do not accumulate CSS rules.
* fix(test): align isolated test runtimes with Expo 57
Hoisted React consumers need the matching DOM renderer at the repository root. Automated Metro processes must not install native DevTools into disposable homes, and development toast overlays must not cover compact actions.
Keep Explorer journeys on the shared host and synchronize setup fixtures on daemon output rather than a one-second file-marker window. A delayed real child start reproduces the readiness failure on every platform.
* fix(test): await retained shell layout after composer resize
The gesture host now stays mounted across breakpoints, so its presence no longer identifies compact layout. Report the current layout on the retained host and synchronize composer journeys with that state.
* fix(app): preserve browser interactions in retained workspace hosts
Initially disabled gesture hosts still registered pointer and wheel listeners, while hover cards used window positions inside a workspace-local sheet portal. Respect initial gesture enablement and position cards relative to their measured floating host.
Keep developer-toast dismissal independent of pointer input and replacement toast visibility so modal, hover, and focus checks retain their input state.
* fix(test): share developer toast handling with Electron browser runs
The standalone Electron browser runner bypassed the browser fixture, allowing developer errors to cover Settings. Use the same non-pointer dismissal in both runners while retaining their console logs.
Retained panels keep their children mounted, so mount-only registration kept hidden rings subscribed to the shared UI clock. Detach inactive rings and retain a local phase so hidden animated styles also stop receiving updates while visible rings continue.
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
Co-authored-by: Pete Keen <pete@petekeen.net>
* fix(app): reveal Android settings inputs above the keyboard
PageLayout kept its full-height scroll viewport while the keyboard controller handled Android insets, leaving Code size covered. Use the existing keyboard-aware scroller for Android pages and cover the real focused field and keyboard geometry in the mobile regression harness.
* fix(app): keep settings field frames above the Android keyboard
Keyboard scrolling revealed only the native text input, leaving the enclosing field border and padding covered. Allow theme spacing around the input and assert the visible Plugins source frame against the real keyboard.
---------
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
* fix(terminal): select complete Korean words on long press
Wide-character continuation cells carry a blank character but occupy no extra glyph. Treat only actual cells as word separators so either half selects the complete word while real spaces still delimit it.
* fix(terminal): preserve selected words until a drag begins
An unmoved touch release contracted the word selected by the long-press timer. Only extend selection after crossing the existing drag threshold. The Android regression checks the copied whole word after the finger lifts.
---------
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
Keep keyboard translation attached to the native animation graph when fullscreen resizes the dock. Apply the enabled mode on the native animation frame so Fabric does not restore the previous transform during layout.
An iOS pan waiting for manual activation can deliver finger-up without finalizing, leaving the row active and the outer scroller locked. Fail a pending pan when its touch stream ends so the existing finalization path cancels the drag. Track activation immediately so an active drag keeps its normal completion path.
Based on the touch-release diagnosis in #5586. The native regression fails before the fix and passes on the Namespace iOS simulator.
Co-authored-by: Kassam Khoja <kassam@shopwrk.com>
* feat(app): run and watch workspace scripts from the compact header menu
The compact header redesign dropped the mobile scripts button, so phones had
no way to run, stop, or restart workspace scripts. Scripts are now a page of
the ⋯ sheet: the root row shows what is running, tinted by health, and the ⋯
carries a dot while a running service is unhealthy. Desktop keeps its popover;
both surfaces share one set of script actions and one status model.
Script status also froze on native whenever the sidebar was closed and no
agent tab was viewed. DirectorySynchronizer releases its subscriptions,
including script_status_update, when nothing demands the directory, and the
workspace screen never demanded the workspace it shows. Web hid this because
the favicon sync holds demand for the whole session. The focused workspace now
holds directory demand, which also lets Restart's second half (start once the
daemon reports the script stopped) complete.
* perf(app): keep workspace script status live without syncing the directory
The focused workspace held full directory demand so the scripts menu saw
script_status_update on phones with the sidebar closed and no agent tab.
That fetched the host's agent and workspace lists on every focus and
streamed every agent and workspace update for the whole host.
Script status now has its own event subscription, which a workspace
screen can hold alone. It fetches the workspace's scripts once when the
subscription lands, because the subscription only carries changes.
Directory demand also holds it, so the sidebar and agent tabs see the
same updates as before.
* Show Claude option previews in the question card
* Wrap long lines in question option previews
* Check option previews under the option that owns them
* Show the whole option preview on native so every line is reachable
On Android, a slow drag inside a preview capped at 240px did not scroll
it, so lines past the cap could not be read. The preview's nested
scroll sits inside the option's Pressable; the same drag scrolls it
once the preview is outside the Pressable. Native now renders the
preview at full height so the chat scroll reaches every line, and a tap
on it still selects the option. Web keeps the 240px cap.
The mock agent's rollout preview is now taller than the cap so the
Android replay can check the last line.
---------
Co-authored-by: Gabriel Giordano <hello@gabrielgiordano.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
* Keep pairing QR code within compact tile
* Move pairing screenshot after viewport assertion
* test(pairing): verify the complete QR code on Android
The native regression failed with the fixed-size SVG because the code was clipped at both screen edges. Verify the complete square and visible margins through the Android app, and keep browser geometry assertions in the pairing helper.
Co-authored-by: fdkevin <25277753+fdkevin0@users.noreply.github.com>
---------
Co-authored-by: fdkevin <25277753+fdkevin0@users.noreply.github.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
* fix(app): sync Android system bar icon style with app theme
With edge-to-edge enabled the app draws under the Android system bars,
but the bars keep their default light icon style regardless of theme,
so the status bar clock/battery/icons are invisible on light themes
(white on white). Call SystemBars.setStyle from the appearance provider
whenever the theme is applied: dark icons on light themes, light icons
on dark themes, auto following the system for adaptive themes and
plugin-contributed themes.
Refs #1272 (runtime only; the splash screen phase is not covered).
* fix(app): keep Android status icons readable as themes change
Keep system-bar contrast subscribed to the resolved app theme so automatic appearance changes update the icons as well as the app surface. Add a native regression covering explicit and automatic themes.
Co-authored-by: TeraYang <4110825+terayang@users.noreply.github.com>
* fix(app): map system-bar appearance through color scheme
Unistyles reserves style mappings for React Native style objects. Keep SystemBars style selection inside its appearance adapter and map the colorScheme prop instead.
---------
Co-authored-by: TeraYang <4110825+terayang@users.noreply.github.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
* feat(app): modernize compact headers and sidebar affordances
Use a shared island header with quick tab creation and keep sheet footers inside their visible layout. Opt sidebar rows into touch sizing without changing global appearance settings.
* test(app): match darker light-theme workspace selection
* test(app): align plugin journeys with compact header
* fix(app): preserve mobile sidebar scroll position when reopening
Keep hidden native overlays laid out so Android touch cancellation cannot spring retained scroll offsets through a zero scroll range. Hide and gate touch input on the UI thread to preserve panel motion during JS stalls.
* docs(app): quote sidebar replay workspace examples
* test(website): read plugin HTML without waiting for remote images
* test(website): exercise built worker in browser checks
The ordered plugin spec reproduces a no-response navigation timeout against a cold development server. Build and preview the published worker for E2E checks; preserve the original content and metadata assertions.
* fix(app): stack adaptive sheets across native presentations
Root-owned dialogs could not present over a sibling native dialog on iOS. Use the existing app-wide sheet stack for both native presentation forms, and release the underlying keyboard when a new sheet opens.
* test(app): verify pairing sheet autofocus
* docs(app): clarify stacked sheet journey prerequisites
The selectable UIKit text view was a sibling of the Fabric content container, so existing chat rows kept an old width after Explorer changed the available pane. Make the container own the text view and preserve layout notifications on bounds changes. Includes a native geometry regression.
Wide native tooltips followed the desktop hover policy, and native tab chips disabled their long-press menu. Enable the existing touch actions while keeping tab navigation on completed press so horizontal scrolling does not select a tab. Keep URL-opening links from leaving a tooltip over the app on return.
Co-authored-by: Jichen <zhangjichen@oppentech.com>
Wide native panes previously followed the compact-layout gate, hiding terminal keys and skipping software-keyboard clearance. Keep bar eligibility tied to native touch while sizing rows from the available pane width.
Co-authored-by: Leandro Ardissone <lardissone@gmail.com>
* fix(app): dock the New workspace composer like a chat on phones
Only the composer is bounded by the viewport; the setup fields sit above it in a
bottom-anchored stack that moves up as the draft grows. The keyboard reservation
is retained on every screen, so the composer keeps one height across keyboard
transitions. Removes the per-screen reserve policy.
* fix(app): share composer docking across mobile hosts
Extract chat's retained capacity and platform keyboard motion so chat,
workspace drafts, and New workspace share one sizing and dismissal boundary.
Keep the native drivers and settled portal reconciliation unchanged.
* fix(app): preserve overlays in centered composer docks
Honor the optional overlay child in both layouts so changing dock placement does not silently discard part of its content.
* test(app): resolve keyboard controller through its web entry
The shared keyboard entry point makes stream tests load the provider. Keep its real ESM dependencies inside the Vitest resolver so CommonJS does not bypass the React Native web alias and parse native Flow sources.
* fix(app): keep native chat scrolling responsive
Place keyboard dismissal behind scrollable content so an idle Android Fabric JS responder cannot intercept native drags. Keep decorative form padding transparent to iOS hit testing and exercise idle native scrolling after submission from every composer host.
* fix(app): stabilize native composer sizing after edits
* test(app): verify workspace composer space after keyboard dismissal
* test(app): start the hold-to-delete regression mid-draft
From the end of the draft the pre-fix input also returns to baseline. Placing the cursor
eight lines into the draft before the first hold-delete leaves the old build at the
capped height with the placeholder visible, and the fixed build at one line.
Restore provider/model selection in Android tablet modal windows by giving both native modal hosts their own gesture-handler root. Preserve phone sheet and web portal behavior.
Include native regression scripts, test dependency resolution, and verified CI test corrections. Generated media and logs are excluded. Refs #4475 and #4377; consolidates #4721 and #4771.
Co-authored-by: Mike P. Kuhl <mkuhl@softmachine.at>
Co-authored-by: Cameron Chin <cjcrjc@users.noreply.github.com>
* fix(app): keep growing composers below the header
Native keyboard translation left the dock at full height, so intrinsic composer growth could extend behind the header. Reserve the keyboard destination at motion boundaries and bound the composer to its stationary viewport while preserving native input scrolling and animation.
* docs: reuse existing test suites and automation
* fix(app): keep terminal keyboard focus stable
Clearing the terminal buffer remounted the shared native input, triggering an IME hide/show cycle. Keep text replacement in place and make the composer explicitly reset its editor to preserve multiline layout clearing.
* test(app): verify terminal keyboard continuity on Android
Replace the new JSDOM regression with a real Android harness. It detects focused native input replacement and IME hide/show requests through terminal toolbar controls, and fails with the previous remount behavior.
Supplying a list controls scroll-container ownership, not whether content can move the sheet. Preserve the shared expand-scroll-dismiss interaction for model selectors and plugin lists, with native gesture regressions and updated plugin guidance.
Allow the composer constraint chain to shrink inside KeyboardDock so overlong drafts scroll internally without hiding controls behind the IME. Extend the Android keyboard invariant to cover the maximum-height case.
* fix(app): keep chat synchronized with keyboard
Dock the complete chat surface with worklet-driven layout padding so visual and native touch geometry move together. Reset cleared multiline native inputs and keep autocomplete portals anchored to the docked composer.
* fix(android): tolerate detached composer inputs
Return the nullable base input connection during IME restart instead of force-unwrapping it after the composer has blurred or unmounted.
Use mobile action sheets and long-press file menus while preserving provider context across sheet portals. Keep sidebar and file-pane glyphs on shared visual rails, avoid scrollbar layout shifts, and hide keyboard affordances where shortcuts are unavailable.
* Improve mobile terminal typing and selection
* Address mobile terminal review feedback
* Remove dead native terminal input branch
* Replay bracketed paste in terminal preamble
* Stop per-key terminal resize claims
* Stabilize terminal resize browser test
* Use tracked terminal mode for native paste
* Restore terminal toolbar focus handling
* Adapt native terminal to active visibility state
* Stabilize native mobile terminal interactions
* Add native terminal fallback boundary
* test(app): expect explicit terminal resize reclaim
* fix(app): stabilize terminal buffer coordinates
* fix(app): restrict terminal resize ownership
* fix(terminal): gate restored input modes
* fix(app): recover stalled terminal WebViews
* chore(app): remove obsolete terminal harnesses
* fix(app): make terminal resize claims explicit
* test(app): stabilize native terminal device flows
* test(app): track absolute scrollback coordinates
* fix(app): isolate terminal WebView streams
* fix(terminal): arbitrate size ownership across clients
The daemon now distinguishes explicit ownership claims from passive geometry updates. This keeps the active client authoritative while allowing its split, viewport, and keyboard changes to resize the PTY without idle clients stealing it.
* test(server): make worker resize assertion portable
Query the worker's authoritative terminal snapshot instead of invoking a Unix-only shell command, so the resize regression exercises the same boundary on Windows and Unix.