Commit Graph
5975 Commits
Author SHA1 Message Date
Mohamed Boudra 7be772f997 Merge origin/main into fix-mobile-text-selection-multi-paragraph
Both sides fixed Android inverted-chat selection scrolling (89d42e441 here,
#7131 on main); main's version of paseo-scroll wins.
2026-10-16 13:17:35 +02:00
Mohamed Boudra e20c025033 test(markdown): bare Fabel/model and daemon/client stay plain text when copied
a502cfd0d stopped linking bare two-segment prose paths; the clipboard
expectation still carried the links from the earlier loose pattern and
failed on CI (playwright shard 1/4 on 60b4e2d05). main expects the plain
text, so restore that.
2026-10-16 13:16:47 +02:00
Mohamed Boudra 8d9a7123ba feat(app): polish compact header, composer, and settings menu (#7129)
Header islands lose their filled background and shadow; the round tap
highlight stays. The floating header's fade now carries the icon contrast
the island fill used to give, so it stays solid through the header and
runs a longer tail into the content. The fade lives inside the overlay
because Android clips children that overhang their parent, and keeps
three gradient stops because Android rendered a four-stop version far
more transparent than specified.

Single-line header titles read one step larger. The compact composer
gets a soft drop shadow. The compact settings root groups App and Host
into islands of tiles, driven by breakpoint style values so desktop
keeps its plain list.
2026-10-16 18:05:11 +07:00
Mohamed Boudra 9747307d9f perf(markdown): reuse Android measurements across view mounts 2026-10-16 12:56:03 +02:00
Mohamed Boudra 6017706cc1 fix(app): avoid restoring composer focus on touch navigation (#7130)
Limit implicit pane and remount focus replay to the existing fine-pointer policy. Fullscreen keeps one editor mounted, so touch navigation does not need the restoration introduced for the former portal handoff.
2026-10-16 17:27:06 +07:00
Mohamed Boudra 62ab2deb27 Run and watch workspace scripts from the phone header menu (#7122)
* 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.
2026-10-16 17:26:44 +07:00
48b310c8a2 Keep Android chat still when selecting text (#7131)
Android's scroll guard now reads the view's transform matrix, so React Native's inverted chat list (scale: -1, decomposed into a 180-degree rotation with positive scaleY) no longer scrolls on text focus or selection.

Closes #7125

Co-authored-by: luke <luopeihuan@gmail.com>
Co-authored-by: RoundRedDot <roundreddot@gmail.com>
2026-10-16 12:21:58 +02:00
Mohamed Boudra 53d614b8f7 perf(markdown): keep native streaming updates in the unfinished tail
Native markdown reparses each updated view in full. Keep parser-closed blocks in a memoized head during paced reveal, then reunite completed prose for cross-paragraph selection. Preserve trailing spacing and source indentation at the split.
2026-10-16 11:16:02 +02:00
Mohamed Boudra 60b4e2d05b fix(markdown): horizontal blocks own their drags on compact layouts 2026-10-16 09:16:59 +02:00
5acfbb3777 Let Escape close plugin previews before stopping agents (#7110)
* fix(app): let Escape close an open popover before it interrupts the agent

The agent.interrupt shortcut listens on the window in the capture phase, so
it sees Escape before anything else. Registered overlays get first refusal
through dispatchTopWebOverlayKeyDown, but plugins cannot register, and draw
their floating panels with the Popover API instead. With such a panel open
and the composer focused while an agent runs, Escape closed the panel and
interrupted the agent in the same press.

While a popover is open, Escape is left to it and no app shortcut runs. A
second Escape, with nothing open, interrupts as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: RoundRedDot <roundreddot@gmail.com>

* test(app): cover Escape with a popover open through the shortcut path

The first test only checked hasOpenDomPopover and would still pass with the
guard removed from useKeyboardShortcuts. The check is now keyBelongsToDomPopover,
called by the hook, and a browser test drives it the way the app does: a
window capture listener for shortcuts, a popover closed by its own document
Escape listener, focus in a textarea. The first Escape closes the popover
with no interrupt; the second interrupts. Both new tests fail with the guard
removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: RoundRedDot <roundreddot@gmail.com>

* test(app): exercise plugin Escape through the real composer

Keep the contributor fix and replace the substitute shortcut-listener test with an installed-plugin browser regression. The first Escape must close the preview without cancelling the turn; the second must cancel it.

Co-authored-by: luke <luopeihuan@gmail.com>
Co-authored-by: RoundRedDot <roundreddot@gmail.com>

* test(app): check dismissed model pickers leave the viewport

---------

Co-authored-by: luke <luopeihuan@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: RoundRedDot <roundreddot@gmail.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-16 09:14:10 +02:00
Mohamed Boudra a502cfd0d0 fix(markdown): bare prose paths need an extension, line suffix or depth
Slash-separated English pairs were recognized as file links in prose. Require stronger path intent there while preserving the existing inline-code recognition rule.
2026-10-16 09:08:29 +02:00
Mohamed Boudra d9178eac75 fix(markdown): reserve a placeholder box with an image glyph while images load 2026-10-16 08:55:33 +02:00
Mohamed Boudra 313d284c3f fix(markdown): linked inline code keeps inline code size 2026-10-16 08:39:19 +02:00
4117dce2d3 Fix local WAV transcription startup (#7103)
* fix(speech): complete local transcription providers

* test(speech): document lazy worker assumption

Co-authored-by: LauraGPT <18321252+LauraGPT@users.noreply.github.com>

---------

Co-authored-by: LauraGPT <lauragpt@users.noreply.github.com>
Co-authored-by: LauraGPT <18321252+LauraGPT@users.noreply.github.com>
2026-10-16 08:19:21 +02:00
Mohamed Boudra 89d42e4419 fix(android): keep inverted chat still during text selection
React Native decomposes Android list inversion into a 180-degree rotation with positive scaleY, so the existing visibility-scroll guard never recognized the inverted viewport. Inspect the composed matrix and reproduce the actual list transform through the native view manager in regression tests.
2026-10-16 07:29:01 +02:00
Mohamed Boudra 4962a9a591 fix(markdown): match main's blockquote, bullet and h6 colours 2026-10-16 07:23:35 +02:00
Mohamed Boudra 3929643da9 fix(markdown): require letters and known extensions in bare path recognition 2026-10-16 07:21:40 +02:00
Mohamed Boudra c0c187ed29 fix(markdown): restore accentBright link colour 2026-10-16 07:18:32 +02:00
paseo-bot[bot]andsuperheher 8388f16186 Keep Add Project keyboard selection visible (#7081)
* 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>
2026-10-16 07:04:35 +02:00
paseo-bot[bot]anddbunk903 5c2a1552df fix(app): preserve number groups when rebinding navigation shortcuts (#7065)
Recording a digit for tab or workspace navigation replaced the existing
1–9 wildcard with one literal key. Preserve the group when capturing a
replacement and display its range after saving and reloading.

Adapted the number-group fix from getpaseo/paseo#5237, with independent
failing-first renderer reproduction and tab/workspace matcher coverage.

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
Co-authored-by: dbunk903 <74584941+dbunk903@users.noreply.github.com>
2026-10-16 04:14:28 +02:00
e0de0fdf6f Read cached chats while other agents stream (#7074)
* perf(app): overlay pending replica rows on read instead of forcing persists

readRows flushed every pending change to storage, read, and retried
whenever the host revision moved. Every stream reducer flush (48 ms) and
every agent delta advanced that revision, so opening another agent or
workspace on a host with a streaming agent re-serialized the whole
pending batch per iteration and could spin until the stream paused.

Reads now run on the write queue, so no drained batch is mid-apply while
a read runs, and rows still pending in memory are overlaid for the
requested keys. A read never forces a persist and never waits for the
host to go quiet.

Persist retries after a storage failure back off exponentially (1 s to
60 s) and log the failure instead of re-serializing every second.

Before: one readAgent during a 200-commit stream cost 201 store reads and
200 forced persists; a permanently failing store was written 30 times in
30 s. After: 1 read, 0 persists; 5 writes in 30 s.

Fixes #4813
Refs #4814

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* fix(app): log replica persist retry failures

---------

Co-authored-by: Ivan Malison <IvanMalison@gmail.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
Co-authored-by: paseo-bot[bot] <paseo-bot[bot]@users.noreply.github.com>
2026-10-16 03:15:23 +02:00
8d424e039e Reduce rendering cost in long chats (#7052)
* perf(app): stop re-walking the timeline on every streamed delta

Every coalesced delta rebuilds the stream render model with the same
tail. The model re-sliced the tail at the history-window start on every
call, so the rendered tail was a fresh array per delta and every WeakMap
keyed on it (ordering, history split, turn timing, the layout history
cache, row revision) missed each time. Cache the slice by tail identity
and window start.

Turn timing then still walked the whole rendered tail per delta and
allocated a new assistant-timing Map, which the layout memo depends on.
Split the walk: the tail is walked once per tail identity and the head is
walked from the carried open turn per delta. The Map keeps its identity
while the head adds no completed turn.

Adds identity-contract tests and a vitest bench for the per-delta
pipeline. 200 deltas over a 2,000-item timeline, mean per run:
default mounted window 5.68ms -> 2.82ms, history fully revealed
16.95ms -> 1.81ms.

Fixes #4816

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* perf(app): keep the stream view's per-delta work bounded by the head

The chat outline concatenated tail and head, reduced over the result in
the render body, and rebuilt jumpToPrompt on every delta even when the
outline was disabled, which is every native viewport. Memoize the tail's
contribution, scan only the head per delta, do nothing while disabled,
make jumpToPrompt a stable event so the rail's memo holds, and republish
the active prompt only when the index or reading position changes.

The view built a Set of every mounted id plus the live head per delta for
the outline's pending-jump check; key it on mounted history only and
treat live head rows as always mounted. Split plugin projection so a head
change does not re-project the tail, memoize the history-window boundary
lookup, and read the turn presentation's submission flag with some()
instead of allocating a filtered array.

Refs #4816

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* test(app): confirm full history before measuring streaming

---------

Co-authored-by: Ivan Malison <IvanMalison@gmail.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-16 01:15:40 +02:00
paseo-bot[bot]andIvan Pantic d9b874f9d0 Scroll chat with Page Up and Page Down after clicking messages (#7033)
* fix(app): focus chat feed when clicking message content

* test(app): wait for new chat output before checking scroll position

Co-authored-by: Ivan Pantic <panta@talentkit.io>

* test(app): capture the keyboard paging regression

* test(app): verify paged chat text stays in place

---------

Co-authored-by: Ivan Pantic <panta@talentkit.io>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-16 00:14:23 +02:00
f56c013928 Open configured terminals after worktree setup (#6999)
* fix(server): open worktree.terminals when a workspace is created on its own

runWorktreeSetupInBackground only opened the paseo.json worktree.terminals
when its caller passed runAutoTerminals, and only the fork-PR "allow setup"
handler did. workspace.create, the request the New Workspace screen sends,
ran worktree.setup and then skipped the terminals.

Both callers want the terminals, so the flag goes away: terminals follow a
successful setup on a newly created worktree. Reused worktrees stay excluded
by shouldBootstrap, and the agent setup continuation never reaches this
function, so nothing opens twice.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* test(server): run automatic terminal regressions in CI

Include workspace creation in the existing integration command, and append to the terminal marker so repeated command execution fails the regression.

* test(server): make workspace fixtures portable on Windows

Run the setup fixture through a command accepted by PowerShell, await its readiness, and fix the fixture Git line-ending policy. Allow Windows directory locks to settle during cleanup.

* test(server): expose setup failures and await fixture cleanup

Check the public setup status before terminal startup so failures distinguish setup errors from terminal creation. Use asynchronous directory removal so Windows cleanup retries leave the event loop available.

* test(server): start the Windows setup service asynchronously

The Windows regression starts its service but setup stays running, so terminal bootstrap is never reached. Launch the fixture service explicitly with Start-Process and retain the readiness and setup-completion assertions.

---------

Co-authored-by: David Yang <9925+davidyang@users.noreply.github.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-15 23:11:13 +02:00
Mohamed Boudra 57b8a69a42 test(markdown): check large HTML table output without observing built-ins 2026-10-15 21:21:50 +02:00
paseo-bot[bot]andSleroq 208e323035 Keep usage providers in place after refresh (#6947)
* fix(app): preserve usage provider order across refreshes

* test(usage): keep refresh and scrolling journeys stable

Usage reports can follow the long fixture card, so a fixed wheel distance
can scroll past its final window. Target the named windows with wheel
input while preserving the visibility checks. Assert refreshed provider
order through visible names and keep viewport setup in journey helpers.

Co-authored-by: Sleroq <hireme@sleroq.link>

---------

Co-authored-by: Sleroq <hireme@sleroq.link>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-15 21:16:52 +02:00
Mohamed Boudra ec7446add4 docs(readme): enlarge sponsor logos 2026-10-15 21:11:51 +02:00
Mohamed Boudra 9cb7984f0b test(markdown): assert linear HTML boundary work without timing 2026-10-15 20:52:11 +02:00
Mohamed Boudra ce4e7fc0f8 test(markdown): name shared renderer setup and file actions 2026-10-15 20:33:35 +02:00
Mohamed Boudra ca01fa4133 test(markdown): gate delivery while establishing a held reader 2026-10-15 20:32:07 +02:00
Mohamed Boudra 97dc696c9e perf(markdown): scan HTML block boundaries incrementally 2026-10-15 20:29:00 +02:00
Mohamed Boudra 35592a26f8 fix(markdown): keep summary block boundaries outside bold text 2026-10-15 20:26:35 +02:00
Mohamed Boudra b30302b630 docs(changelog): 0.11.4 2026-10-15 20:26:28 +02:00
Mohamed Boudra 904fc10d89 fix(markdown): preserve adjacency around inline HTML 2026-10-15 20:24:56 +02:00
Mohamed Boudra 7aa3fac069 fix(providers): scope project-dependent model discovery to workspaces
Global discovery has no linked project. Initialize the bridge to check availability, but only open discovery sessions when a workspace is supplied.
2026-10-16 01:19:00 +07:00
Mohamed Boudra 1456d461a9 test(markdown): isolate image arrival from reload positioning
Mounted row totals change as history virtualizes, so observe the new response and tool directly. Hold the real PNG response after reload until the reading position settles, then verify its reserved height and viewport instead of attributing initial bottom-follow positioning to image decoding.
2026-10-15 19:14:43 +02:00
Mohamed Boudra fd1e7a34ce docs(changelog): welcome Hoplite as first sponsor in 0.11.3 2026-10-15 19:06:24 +02:00
Mohamed Boudra ce0f21e2ff docs(changelog): 0.11.3
Cherry-picked from ed53a7193 on release/0.11.3-hoplite (tag v0.11.3).
2026-10-15 18:58:16 +02:00
Mohamed Boudra 1f12ee95a1 test(markdown): require growth while holding a streaming paragraph 2026-10-15 18:35:05 +02:00
paseo-bot[bot] d172d060a5 server: keep streamed OpenCode v2 chunks from holding their whole message (#6262)
Each streamed text or reasoning chunk was cut from the accumulated
message with slice, which can share the source string's storage. The
timeline store keeps every chunk, so a 128 KB reasoning part retained
about 128 MB: every chunk held the full message as it stood when the
chunk arrived. Long OpenCode v2 reasoning streams exhausted the daemon
worker's heap.

The timeline now emits an independent copy of each suffix, so retained
memory follows the length of the text.

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-15 18:28:07 +02:00
Mohamed Boudra 4dfd7c18a0 fix(markdown): preserve reader position while responses grow
Keep the same message component boundary when a live row becomes retained history, preserving Mermaid runtimes and selection nodes. Observe paced child text commits at the web viewport so sticky-bottom follows before the next frame.
2026-10-15 18:15:14 +02:00
Mohamed Boudra 2d86b94b2f Refine provider catalog buttons and show Add errors as toasts (#7030)
* fix(app): refine provider catalog actions and error feedback

Use compact row tiles and the shared error toast so failed Add actions remain visible while browsing the catalog. Point Hoplite installation instructions at the CLI install section.

* test(app): supply toast context in provider settings tests

Import the toast API independently of its renderer so the provider section only depends on the context it consumes.
2026-10-15 22:45:12 +07:00
Mohamed Boudra 5e413ad36c test(markdown): cover state retention during image arrival 2026-10-15 17:41:35 +02:00
Mohamed Boudra 9e240d5d61 fix(markdown): reserve pending images and harden web rendering 2026-10-15 17:17:49 +02:00
Mohamed Boudra 30b7b269e9 fix(markdown): preserve first definitions across Mermaid segments 2026-10-15 17:03:08 +02:00
Mohamed Boudra a97f02e16f docs(markdown): record native selection and image limitations 2026-10-15 16:55:48 +02:00
Mohamed Boudra ad4d910aef fix(markdown): retry transient image decode failures 2026-10-15 16:55:15 +02:00
Mohamed Boudra b88b018d5f fix(markdown): preserve literal image fallback labels 2026-10-15 16:54:07 +02:00
Mohamed Boudra f90e160ac6 fix(markdown): normalize HTML following code elements 2026-10-15 16:53:16 +02:00
Mohamed Boudra 65f16f6322 fix(markdown): preserve spacing between HTML elements 2026-10-15 16:52:02 +02:00