Commit Graph
3134 Commits
Author SHA1 Message Date
Mohamed Boudra 033b2cdfc2 fix(app): keep command suggestions visible as the composer grows (#7910)
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.
2026-10-26 14:24:38 +07:00
Mohamed Boudra 74a7e5803b Choose voice providers and local speech models from a Voice settings page (#7295)
* feat(voice): add a Voice settings page with provider choice and a local model catalog

Each host gets a Voice page under host settings. Dictation and voice mode
each pick a provider (Local or OpenAI) and a model. Provider settings sit in
one group of collapsible rows: local speech-to-text and text-to-speech list
every catalog model with its size, languages and description before download,
and OpenAI takes a write-only API key and an optional base URL.

The local catalog grows from Parakeet/Kokoro to Whisper, SenseVoice, Dolphin,
GigaAM, Parakeet Japanese, multilingual Kokoro, Kitten and Piper voices. Each
entry declares its sherpa engine family, so the recognizer and TTS build the
matching model config and the downloader verifies the files that family needs.
Kitten v0.8 is left out: it crashes the pinned sherpa-onnx 1.12.28.

Voice mode is now opt-in. The default lived only in code (true), never in
config.json, so hosts that never toggled it find it off after upgrading.

OpenAI speech-to-text resolved one model for both features, with voice mode's
choice taking precedence, so dictation silently used voice mode's model. The
resolved config now carries a model per feature; STT_MODEL still overrides both.

Rows revealed under a collapsible settings row are a nested density level set
by the container: tighter padding, smaller text, and xs controls, with
controls taking their size from the row instead of each caller.

* test(app): pre-bundle the JSX dev runtime for browser tests

Compiling test JSX with the automatic runtime imports react/jsx-dev-runtime. Vite discovered it mid-run on a cold cache and reloaded the page, which failed the first browser test file to import it.

* refactor(voice): keep speech provider settings at each use site

Store credentials and endpoint options beside the speech feature that consumes them so saved page values cannot be shadowed by a separate provider block. Normalize existing config on load and mirror the inline shape on config reads and patches.

This is the config, resolver and wire phase; the provider sheet follows separately.

* fix(voice): preserve saved keys when resaving provider settings

Forms send the selected provider on each save but cannot read back its API key. Merge patches for the existing provider so these saves retain credentials; replace the site only when the provider changes.

* feat(voice): configure each speech use site from a provider sheet

The Voice page now lists Speech-to-text, Listening and Speaking as one-line
summaries. Tapping one opens a sheet with the provider choice and only that
provider's settings: the local catalog (size, languages and description
before download, download state per model) or the OpenAI key, base URL,
model and language or voice.

The sheet's form model sends only the fields the user changed, so re-saving
never clears a saved key. Fields an env var decides are read-only with a
"Set by" hint; the API key and base URL stay editable because a saved value
wins over the env fallback. Save failures show a toast and keep the sheet
open with the input.

E2E daemons pin speech providers through env vars to avoid model downloads,
so the browser spec covers the locked-provider path, the key fallback and
the failed save; provider switching is covered by the form model tests.

* refactor(voice): press settings and catalog rows through PressHighlight

Settings rows that lead somewhere and local model rows now use the standard
row press primitive, so native shows the finger-down flash the rest of the
app's rows have. Web hover and press styling are unchanged.

* fix(voice): preserve STT language for local providers

Language belongs to every STT use site. Preserve legacy local language settings through config loading and saving, resolve them without provider gating, and expose them in the provider form.
2026-10-26 14:19:02 +07:00
Mohamed Boudraandbjspi 88bd1cf05a feat(app): long-press Send to queue or send now on touch screens (#7897)
Touch users had no way to reach what Cmd/Ctrl+Enter does: queue when
Default send is Steer or Interrupt, send now when it is Queue. Holding the
Send button now runs that same action on every platform, with a haptic on
native and an accessibility hint naming it. Tapping is unchanged.

Both paths go through runAlternateSendAction, which now falls back to the
default send when no turn is running, so holding Send while idle still
sends and the keyboard path no longer carries its own gate.

Co-authored-by: bjspi <43368639+bjspi@users.noreply.github.com>
2026-10-26 14:04:30 +07:00
5e53bb78c2 fix(app): keep your place in the Settings sidebar (#7899)
Keep sidebar scroll position for the Settings visit across app and host section navigation. Reject stale scroll callbacks from replaced sidebars and reset the offset when leaving Settings.

Preserve the existing sibling routes and host-selection behavior. Consolidate the restoration work and broader regression coverage from the predecessor pull requests.

Closes #1532.

Co-authored-by: bingqilinweimaotai <111987281+bingqilinweimaotai@users.noreply.github.com>
Co-authored-by: shampoo <wn990916@gmail.com>
2026-10-26 13:53:01 +07:00
Mohamed Boudra 78a3083fea perf(app): avoid stream updates in hidden chats (#7901)
Retained chats already preserve their last visible transcript. Keep their stream-tail selection stable while inactive so incoming chunks do not schedule React work; reveal reads the current model tail.
2026-10-26 13:49:56 +07:00
97ed96bdf6 release: prepare 0.13.1 sidebar startup hotfix from stable (#7902)
* fix(app): keep the sidebar alive when a workspace entry has not hydrated (#7896)

ProjectBlock asserted that every placement in a project has an entry in
workspaceEntriesByKey. A retained sidebar that is inactive (compact layout
with the sidebar closed) or still waiting for sessions keeps an empty map,
and Show background stops the project list from being pruned to hydrated
entries. From the eighth workspace on, selectSidebarGroupVisibility asked
for the status of a missing entry and the app crashed on start.

Count a missing entry as Done. It renders no row, so it should not claim a
slot past the limit.

Closes #7869

Co-authored-by: brucey0x <11062155+brucey0x@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 6bc4b73c42)

* docs(release): add 0.13.1 hotfix notes

* chore(release): cut 0.13.1

---------

Co-authored-by: Budi <11062155+budivoogt@users.noreply.github.com>
Co-authored-by: brucey0x <11062155+brucey0x@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 13:40:19 +07:00
Mohamed BoudraandKino Roy 27d6b3b7ce feat(desktop): remember project editors and support Xcode (#7898)
Keep editor choices local to each project and shared across its worktrees. Reuse the Xcode target contribution while preserving explicit editor selection.

Co-authored-by: Kino Roy <kinoroy@me.com>
2026-10-26 13:36:00 +07:00
Mohamed Boudra 8e5f536766 Release idle agent runtimes with work guards and live host controls (#7782)
* feat(server): release idle agent runtimes with provider safety checks

Require provider permission before releasing resumable runtimes so foreground idleness does not discard tracked background work. Preserve the saved conversation and serialize prompt admission with runtime closure; allow hosts to disable collection.

* docs: translate idle runtime cleanup configuration and provider contract

* feat(server): collect runtimes after one idle hour with optional provider vetoes

Keep callers resident while local or remote finish notification intent remains outstanding. Daemon-owned work determines baseline eligibility; provider checks add optional vetoes. Own the idle clock and sweep lifecycle in one cleanup module while the manager retains guarded closure.

* feat(agents): control idle runtime release live from host settings

Let hosts retain runtimes without restarting the daemon. Disabling invalidates pending collection decisions while preserving idle clocks for re-enabling. ACP-owned terminals and pending adapter work veto collection until they finish.

* fix(settings): clarify idle agent release with an info tooltip
2026-10-26 12:38:15 +07:00
6bc4b73c42 fix(app): keep the sidebar alive when a workspace entry has not hydrated (#7896)
ProjectBlock asserted that every placement in a project has an entry in
workspaceEntriesByKey. A retained sidebar that is inactive (compact layout
with the sidebar closed) or still waiting for sessions keeps an empty map,
and Show background stops the project list from being pruned to hydrated
entries. From the eighth workspace on, selectSidebarGroupVisibility asked
for the status of a missing entry and the app crashed on start.

Count a missing entry as Done. It renders no row, so it should not claim a
slot past the limit.

Closes #7869

Co-authored-by: brucey0x <11062155+brucey0x@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 12:36:51 +07:00
Mohamed Boudra 631ed0408d fix(app): preserve host selection across settings navigation (#7893)
Own the selected host for the Settings visit so screen replacements and Back do not reset an explicit picker choice. Apply named-host entry intents once while preserving workspace defaults for new visits.
2026-10-26 11:30:54 +07:00
Mohamed Boudra 6521739947 fix(markdown): preserve inline code formatting and heading sizes (#7889)
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.
2026-10-26 11:22:07 +07:00
Mohamed Boudra 6f07b0de48 feat(app): recall sent messages with Up and Down in an empty composer (#7710)
Fixing a prompt after interrupting it, or retrying one after a provider
error, meant scrolling up and copying it out of the chat. Up in an empty
agent composer now fills the last message sent to that agent; Up walks
older, Down walks newer and past the newest back to empty.

History is read from the loaded timeline on key press, not kept in a
separate store, so it follows rewinds, reloads and other devices and costs
nothing while a turn streams. Recall only starts from an empty composer, so
it never discards a half-written draft. While a recalled message is
unedited the autocomplete stays hidden, otherwise a recalled `/command`
would open the picker and Enter would pick an option instead of sending.
2026-10-26 11:18:47 +07:00
Alessio Re 16fe07560f fix(app): make question cards link-aware and selectable without accidental answers
Render question bodies and option text with the shared Markdown renderer. Opening links or selecting question and description text leaves answers unchanged. Labels remain answer controls, and double-clicking a label advances only once.

Add browser regression coverage and stabilize Markdown WASM loading in the test harness.

Closes #3164.

Co-authored-by: Alessio Re <NoSync@users.noreply.github.com>
2026-10-26 10:51:44 +07:00
Mohamed Boudra 2a890208ce feat(app): show a subagent's parent and a way back to it (#7784)
A subagent pane now names its parent and takes you back to it. With a composer, a pill leads the rail above it; without one, a parent box takes the composer's place. Both open the parent through navigateToAgent.
2026-10-26 10:51:19 +07:00
4bbacfed46 feat(app): fold finished agent turns behind a summary line (#7785)
Long agent turns bury the answer under intermediate messages, thoughts and
tool calls. A new Chat display preference (Full / Collapse tool calls /
Collapse turns) replaces the tool call detail level. Collapse turns folds
everything a finished turn did before its final message into one summary
line under the prompt; opening it shows those rows inline behind the same
indent rail that expanded tool call groups now use.

Expanded turns stay real timeline rows so virtualization, chat find and
scroll-to-message keep working; find and outline jumps open the turn that
holds their target. Opening or closing a turn stops following output so the
summary stays under the pointer.

Collapse turns is the default for new installs only. Existing settings were
materialized on first launch, so stored blobs without the new field map from
the legacy tool call detail level and otherwise stay on Full.

Co-authored-by: Ready <127541578+akaready@users.noreply.github.com>
Co-authored-by: Waishnav <86405648+Waishnav@users.noreply.github.com>
Co-authored-by: Shreyan Dey <90114886+Dey11@users.noreply.github.com>
Co-authored-by: Sebastian Parfitt <7753735+Sebeb@users.noreply.github.com>
2026-10-26 10:50:16 +07:00
Mohamed Boudra 8c9499dac6 fix(app): dismiss file link tooltips when leaving their panel (#7842)
Retained chats suspend while their tooltip portals remain mounted. Remove the surface before suspension and clear open state and pending hover timers so returning to the chat does not revive it.
2026-10-26 10:48:07 +07:00
paseo-bot[bot]androyenheart 5dc350034e Keep large Import Session lists responsive on Web (#7872)
* Virtualize long Import Session Web lists while preserving native and short-list scrolling

* fix(app): measure import list headers through the existing layout event

Keep the virtualized import list usable in the existing component harness without introducing an observer mock. Import React for the unit JSX transform.

Co-authored-by: royenheart <royenheart@outlook.com>

---------

Co-authored-by: royenheart <royenheart@outlook.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-25 15:05:12 +00:00
4845e1da58 fix(app): link bare URLs with ports, colons and user info as one link (#7859)
MD4C's permissive URL autolink read the host, never a ":port", and
accepted ":" as a link boundary. "http://127.0.0.1:8059/?token=abc"
linked only "http://127.0.0.1". A colon in the path ended the link the
same way.

Port the upstream md4c fix into the dependency patch:
- 3da1937: accept single-component hosts and a numeric port after an
  explicit scheme
- f895c2b: scan the URL tail continuously and trim terminal
  punctuation and excess closing parentheses
- 1645761: refuse an empty hostname
- f9e5eb2: stop the tail rescan from going quadratic on long lines

Also refuse the autolink when a colon after the host continues the URL
("user:pass@host"). Upstream does not parse user info, and the
single-component host rule would link only "http://user". The
text-link pattern links these URLs whole.

Rebuild the web parser with emsdk 4.0.10, which reproduces the
existing glue. That version has no GROWABLE_ARRAYBUFFERS setting, and
the existing artifact was built without it.

The fallback text-link pattern handles URLs MD4C rejects, like
user@host and IPv6 hosts. It now stops at quotes and unbalanced
parentheses and leaves trailing sentence punctuation outside the link.

Closes #7440

Co-authored-by: Mariotaku <git@mariotaku.me>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 10:01:31 +00:00
Okan YILDIRIM b8bb335c56 fix(app): close comboboxes when their retained panel becomes inactive (#7783)
Close open comboboxes through their existing handler and remove their
presentation before a retained chat can freeze its closing update.

The compact regression came from unmounting the sheet while its visibility
tracker survived in Combobox. Its non-closed phase blocked the next present().
Keep the tracker inside the sheet component so they unmount together, and
preserve the desktop closed-state guard in Combobox.

Cover draft and existing-chat model selectors and the compact tab switcher
through Settings, Back, and reopening. The desktop regressions also verify
Escape dismissal.
2026-10-24 07:25:30 +00:00
Mohamed Boudra d34d17a907 chore(release): cut 0.13.0 2026-10-24 08:02:33 +02:00
a54cc6dd11 chore(acp): refresh pinned provider packages (#7781)
* chore(acp): refresh pinned provider packages

Co-authored-by: Kim <androidj@qq.com>
Co-authored-by: Louis Deconinck <louis.dck@gmail.com>

* test(app): capture the visible composer across retained tabs

The settings regression sampler selected the first mounted composer even when it belonged to an inactive retained tab. Mount both tabs before capturing so the test consistently covers that case, and sample the visible composer.

---------

Co-authored-by: Kim <androidj@qq.com>
Co-authored-by: Louis Deconinck <louis.dck@gmail.com>
2026-10-24 12:36:10 +07:00
f3d74b8575 fix(plugins): restore deprecated useRevealedText compatibility (#7780)
The 0.13 UI entry rename dropped the reveal hook from the 0.12 runtime.
Keep it on the legacy entry until that entry is removed, with deprecated
SDK typing and migration guidance.

Closes #7577
Closes #7722

Co-authored-by: luke <luopeihuan@gmail.com>
Co-authored-by: RoundRedDot <roundreddot@gmail.com>
Co-authored-by: Matt Cowger <1929548+mcowger@users.noreply.github.com>
2026-10-24 11:44:08 +07:00
Mohamed Boudra 686588c44b feat(app): restore manual workspace sorting (#7771)
Keep manual workspace order separate from automatic sorting so surviving pre-beta arrangements and subsequent drags remain available across mode changes. Created stays the default; data already discarded by the beta cannot be reconstructed.
2026-10-24 09:06:05 +07:00
paseo-bot[bot] 48623801a1 fix(app): keep tablet sidebar controls above system navigation (#7768)
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>
2026-10-24 03:01:19 +02:00
Stephen ZhouandClaude Opus 5.5 632a7f8859 fix(app): keep live workspace rows when a late creation snapshot arrives (#7758)
A workspace.create.response carries the descriptor captured at provision
time but is sent after the initial agent starts. A pin or title change made
in between reaches the app first as a live update; the late response then
replaced that row with the older snapshot, so a new pin vanished from the
sidebar until the next directory update.

Creation and progress snapshots now only seed rows the replica has not
received; existing rows stay owned by directory updates. Archive rollback
still restores a row that was removed.

Closes #5447

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 01:05:57 +02:00
paseo-bot[bot] fed19f3d29 fix(app): identify Android DNS connection failures (#7701)
Recognize explicit name-resolution failures before TLS keywords in hostnames, while preserving certificate-not-found handling and raw details.

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-23 14:57:19 +02:00
Mohamed Boudra 30d8cb0447 chore(release): cut 0.13.0-beta.2 2026-10-23 14:28:15 +02:00
Mohamed Boudra 59b01b33f1 fix(app): build iOS releases with the foldable-capable SDK (#7705)
EAS auto selects Xcode 26.6 for Expo 57, leaving releases in phone compatibility mode despite scene support. Pin Xcode 27.1 for the native resizing opt-in.
2026-10-23 19:00:15 +07:00
Mohamed Boudra 582beeb10b fix(app): preserve compact sidebar context under sheets (#7693)
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.
2026-10-23 15:57:12 +07:00
Mohamed Boudra 6405edd8dc feat(app): show consistent agent and workspace status in search (#7690)
Share tab agent presentation and effective workspace status with Command Center. Preserve unchanged result identities so live directory updates only rerender the changed row, with bounded retention and browser regression coverage.
2026-10-23 14:35:27 +07:00
Mohamed Boudra 4b9b2fe130 fix(app): preserve manual Command Center scrolling during live updates (#7688)
Treat selection and permission to reveal it separately. Result publication and layout updates must not pull a manually scrolled viewport back to the active row; user navigation requests a one-shot reveal.
2026-10-23 14:04:43 +07:00
Mohamed Boudra 4fe006df86 feat(plugins): unify panel props and persist tab state (#7685)
* feat(plugins): unify panel props and persist tab state

* refactor(plugins): make agent panel registration canonical

* docs(plugins): update Chinese panel API reference and migration
2026-10-23 13:26:19 +07:00
Mohamed Boudraandsam 99a1d9a7a2 fix(app): keep the iPhone skill picker above the composer and keyboard (#7679)
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>
2026-10-23 11:41:00 +07:00
Mohamed Boudra 55a7590952 Sort sidebar workspaces and keep active overflow visible (#7635)
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.
2026-10-22 19:59:28 +07:00
Mohamed Boudra 793b16c0df fix(relay): protect sessions against replayed commands (#7610)
Protect relay sessions against replayed commands with authenticated Noise NK negotiation, ordered records, and identity-bound security pins. Preserve legacy admission during migration and add daemon enforcement policy.

All 21 CI checks passed. General engineering review is complete; specialist cryptographic review of the handwritten Noise implementation and static-key reuse remains required before release or deployment.

Closes #359
2026-10-22 19:50:06 +07:00
Mohamed Boudra 6376f2bf40 Remove the WebView terminal renderer: xterm on web, native grid on mobile (#7639)
* refactor(terminal): remove the WebView terminal renderer

Native uses the native grid renderer only; web keeps xterm. The legacy
renderer setting, its diagnostics toggle, the esbuild WebView bundle and
its CI drift check are gone.

* test(terminal): target the visible terminal surface in the file paste spec

A second page opening a terminal in the same workspace adds a retained,
hidden surface to the first page, so the unscoped locator matched two
textareas and failed strict mode.

* test(server): wait for the shortstat warm instead of polling 500ms

The background warm shells out to git; on Windows CI that regularly
outlasts the 20x25ms poll and fails the test. Use the completion callback
the warm already exposes and keep the non-blocking check.
2026-10-22 19:47:28 +07:00
Gerard BalaoroandMohamed Boudra 9d908d678b feat(terminal): support image paste into agent TUIs, local and remote (#3795)
* feat(terminal): support image paste into agent TUIs, local and remote (#3725)

Codex and OpenCode receive image pastes by binding Ctrl+V (\x16) and
reading the OS clipboard of the machine they run on; no image bytes
travel through the pty. Paseo's terminal swallowed that keystroke and
only ever pasted text, so image paste silently did nothing.

- web/Electron runtime: forward \x16 when the clipboard holds no text,
  keep the existing text-paste path otherwise (bash quoted-insert stays
  intact)
- new terminal.clipboard.write_image RPC ships client clipboard bytes to
  the daemon, which writes them onto its host clipboard (osascript /
  wl-copy / xclip / Set-Clipboard) so remote clients work like local
  ones; gated by server_info.features.terminalClipboardImage with a
  bare-\x16 fallback for older daemons
- clipboard tools are waited on via their exit event, not stream close:
  wl-copy and xclip fork a selection owner that inherits our pipes, so
  waiting for stream closure hung every Linux write until timeout
- headless hosts without a clipboard get a temp-file fallback: the
  daemon materializes the image under os.tmpdir() and returns its path;
  the client injects it as bracket-pasted text
- all four renderers covered (web DOM, Electron, native grid, WebView
  bridge); mobile Paste button enables for image clipboards and toasts
  failures in all 10 locales

* fix(terminal): bind image paste to private retained files

* fix(terminal): recover interrupted image metadata safely

* fix(terminal): retire image files with background lifecycle maintenance

* fix(terminal): check live paste modes and refresh native bridge

* fix(terminal): order image paste input and isolate failures

* fix(terminal): normalize paste and release failed creation reservations

* fix(terminal): validate missing Windows launch paths before spawn

* fix(terminal): keep input live during cancellable image uploads

* test(terminal): follow streamed input-mode updates

* feat(terminal): upload dropped images through the paste flow

* feat(terminal): paste and drop images through file uploads

Terminal image paste and drop now reuse the existing upload path
(client.uploadFile -> file.upload.request -> FileUploadStore) and paste
the quoted host path through the pane's input, bracketed when the app
asked for it. This replaces the PR's daemon-side image store, RPCs,
paste permits and file lifecycle, so the daemon, protocol and client
diffs for this feature are empty.

- terminal/image-paste owns a per-pane serial queue: gesture order,
  keystrokes stay live, Ctrl+C and pane/connection teardown cancel
  pending pastes, and a cancelled path is never pasted.
- Clipboard text wins over an image; any image/* type is accepted up
  to the composer's 50MB upload limit.
- Host paths are quoted for the host OS by path shape.
- One failure toast; i18n keeps two keys.
- Browser e2e covers two panes pasting distinct PNGs, drop, ordering,
  Ctrl+C cancel and disconnect against a real daemon.

Co-authored-by: Gerard Balaoro <miogerard@yahoo.com>

* fix(terminal): translate the disconnected image upload error

* feat(terminal): report image uploads through toasts

Show a lasting "Uploading image…" toast while an image uploads, replace
it with "Image uploaded" or a failure toast that carries the reason, and
dismiss it when Ctrl+C cancels the upload. Toast show now returns a dismiss
scoped to that toast, so the pane can clear its own toast without
removing a newer one.

* build(terminal): regenerate the WebView HTML for the toast events

* fix(terminal): keep i18n out of the terminal WebView bundle

The image paste queue imported i18n for its size-limit message, which pulled
every translation into the WebView HTML. The queue now reports a typed
TerminalImageTooLargeError and the pane words it.

* refactor(terminal): route dropped files by host locality and share the drop overlay

A dropped file pastes its own path only when the host is the desktop app's
own daemon (useIsLocalDaemon); anywhere else the host cannot read the
client's disk, so the file uploads through client.uploadFile and the host
path is pasted. File type no longer plays a part: images and other files
take the same route, and clipboard images always upload because they have
no path.

The terminal pane now sits in the shared FileDropZone, so dragging files
over it shows the agent panels' "Drop files here" overlay. The emulator's
own drag listeners, blue tint and 180 ms timeout are gone.
FileDropSink.onFiles is optional so a sink can take raw files without
persisting raster images as attachments.

terminal/image-paste becomes terminal/file-paste; the queue, callbacks,
toasts and i18n keys say "file".

* test(terminal): keep the fake desktop bridge in an e2e support helper

The CI contract test forbids browser specs from installing paseoDesktop
directly; the local-host drop scenario now imports it from support.

---------

Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
2026-10-22 17:40:01 +07:00
4ef4a95a42 Keep Claude session listing from loading whole histories into memory (#7626)
* fix(claude): stream and cache session import descriptors

* fix(claude): bound and schedule import reads

Reject JSONL records over 4 MiB explicitly to preserve metadata.
Limit shared reads to four globally and one per listing for fairness.
Deduplicate reads by cacheKey with independent subscriber cancellation.
Set a 45-second provider deadline before the 60-second client timeout.
Clone returned descriptors to isolate overlapping callers.

Validation: 97 focused tests passed; independent review approved.

Detected-By: user

* fix(claude): parallelize resilient session scans

Use up to four workers per listing with a shared four-read limit
and bounded FIFO queuing. Preserve cache-key deduplication,
subscriber cancellation, and candidate order.

Log and skip oversized or unreadable transcripts so healthy
sessions remain visible. Propagate programming and abort errors.

Detected-By: user

* fix(claude): surface session import read failures

Skip expected candidate read failures and return healthy sessions.
Distinguish unreadable metadata from parsed transcripts, and raise
AggregateError when every candidate is unreadable.

Propagate systemic file errors and narrow discovery error suppression.

Detected-By: user

* fix(claude): keep large sessions importable while streaming history

Preserve import metadata for transcripts containing image records above 4 MiB. Stream complete records instead of rejecting otherwise listable sessions, and cover overlapping requests across aliased provider roots under a constrained heap.

Co-authored-by: Josh Lane <joshlane@easypost.com>

* test(app): wait for active agent controls and submitted turns

Observe the mode control before testing Command Center keyboard selection. Observe a running turn before waiting for its completion, so the rewind test cannot mistake the previous idle state and end marker for the new turn.

---------

Co-authored-by: Josh Lane <joshlane@easypost.com>
Co-authored-by: Josh Lane <lane.joshlane@gmail.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-22 12:07:39 +02:00
Mohamed Boudra c3c6a936a4 List plugin header buttons in the workspace menu on phones and narrow windows (#7630)
* fix(app): list plugin header buttons in the compact workspace menu

The compact header rewrite left plugin header buttons with no home, so
phones and narrow windows had no way to reach them. They are now rows of
the compact workspace menu, with menus and popovers as pages of its sheet,
the way workspace scripts moved there.

The header overflow and the workspace menu share one row/page builder.
Each row and page resolves its own plugin installation's runtime: the old
overflow routed every row through the first entry's host client.

Closes #7601

* test(app): wait for agent control rows before keying the Command Center

Two Command Center agent-control tests typed a query and pressed Enter or
ArrowDown immediately. The agent's mode and model rows register after the
panel opens, so on a slow runner the keys landed while only file search
had matched and the mode never changed. The CI trace for the failure shows
no Mode or Model rows at the moment of the key press. The tests now wait
until both groups are listed, which keeps what they check: the best match
wins, and a stale arrow-key selection is dropped.
2026-10-22 16:32:10 +07:00
Mohamed BoudraandKassam Khoja 12e7a448f0 fix(app): open notification agents once in their current workspace (#7612)
* fix(app): open notification agents once in their current workspace

Keep tap ownership across Activity and React remounts, clear native responses, and resolve agent workspaces through existing navigation after startup settles.

Co-authored-by: Kassam Khoja <kassam@shopwrk.com>

* fix(app): hydrate agent targets with the compact sidebar closed

Hold directory demand for the agent route while resolving its workspace; the compact sidebar does not supply demand before it opens.

* fix(app): keep deferred workspace opens in the layout model

Key pending tab opens by workspace so redirects and retained screens cannot lose or consume another workspace's target. Legacy open URLs seed this state at their route boundary.

* docs(app): document notification tap ownership and native replay

* fix(ci): route feature-owned Electron sources to desktop checks

* refactor(app): separate notification API from React integration

* fix(app): consume pending opens before painting the restored tab

A legacy open link showed the previously focused terminal for a frame before switching to the requested terminal. Seed and consume the pending open in layout effects so a ready target switches before paint.

* fix(e2e): focus the visible retained terminal surface

---------

Co-authored-by: Kassam Khoja <kassam@shopwrk.com>
2026-10-22 14:41:38 +07:00
Mohamed Boudra 4574142314 fix(server): use only the configured models for manual metadata generation (#7611)
Manual metadata generation is a non-empty agents.metadataGeneration.providers
list, but the resolver always appended the built-in defaults and the current
agent selection after it. When a manual model failed, the prompt was retried
on providers the user never chose. Manual now resolves to exactly the
configured list; Automatic is unchanged.

Commit message and PR text generation swallowed failures without logging, so
a broken manual model was invisible. The git metadata generator now logs the
final failure with each attempt's provider, model and error, and the
structured generation loop receives the session logger for per-attempt
warnings, matching the branch name path.
2026-10-22 14:36:22 +07:00
paseo-bot[bot]and3ae3ae 4673ab1903 fix(app): fall back to relay when the direct connection drops (#7616)
The probe cycle reused the selected client's last heartbeat RTT even
after that client disconnected. A dead direct connection kept reporting
as available, so the app never switched to a reachable relay until it
was restarted. Mark the selected connection unavailable while its client
is not connected and let the existing failover pick another connection.

Co-authored-by: 3ae3ae <ogyshjsm@naver.com>
2026-10-22 09:08:33 +02:00
Mohamed Boudra 76b32544c6 Give Markdown and HTML file tabs back their Preview and Source views (#7614)
* fix(app): give Markdown and HTML file tabs back their Preview and Source views

The built-in Markdown and HTML panels own one toolbar again: file size,
line count, save status, vim mode, cursor, and a Preview | Source control
over a body that shows the rendered preview or the editor from the same
loaded content and editor model. Plain text files keep the toolbar on top.

The host no longer renders a panel switcher. Source is the built-in panel
for text files no other built-in claims, so it is never offered beside
Markdown or HTML in the picker, the Open with menu, or Settings > Files.
A line target opens the file's built-in panel in its Source view.

* refactor(app): name the shared text file panel TextFilePanel

Markdown and HTML own a Source view; they are not Source panels. The
composite in file-panels/source/panel.tsx is now TextFilePanel, and
SourcePanel is TextFilePanel without a Preview. Names only.
2026-10-22 13:04:59 +07:00
Mohamed Boudra bdae614e95 fix(app): restore chats after reopening unread workspaces (#7608)
Parked pane focus was persisted without its in-memory restoration record, so cold starts exposed hidden Explorer tabs and never requested the agent timeline. Restore an ordinary pane at the layout boundary, including for existing saved layouts.
2026-10-22 11:45:31 +07:00
Mohamed Boudra 3fa625701e chore(release): cut 0.13.0-beta.1 2026-10-22 03:53:53 +02:00
Mohamed Boudra e522e6ea8e fix(app): make the compact Explorer tab rail usable on phones (#7589)
Popovers on Android landed one status bar below their trigger. React Native
0.86 stopped subtracting the status bar from window coordinates under
edge-to-edge, so measureInWindow, touch pageY and a full-screen Modal already
share screen-top coordinates; the old StatusBar.currentHeight compensation in
the menu engine, tooltip, context menu and sidebar long-press now
double-shifted every anchor.

Compact tabs keep their natural width and the rail scrolls as soon as they
overflow, instead of squeezing labels first and then scrolling anyway. They
drop the inline close because the long-press sheet already closes a tab and a
narrow X beside the label is easy to hit. Any scrolling rail keeps natural
widths rather than collapsing every chip to the minimum, and the rail resets
its offset when scrolling ends so tabs scrolled out of view come back.

The Explorer rail paints the sidebar surface, so its chips climb the sidebar
hover and selected tokens. Light themes paint the sidebar with surface2, which
made the surface2 active chip invisible there.

The compact Explorer closes with the same X as the compact agent list, and the
compact + menu omits Diff because compact Changes already shows diffs inline.
2026-10-21 21:44:53 +07:00
1e0a9d5af0 fix(plugins): allow notification timeline transformers (#7582)
Co-authored-by: 陈睿 <chenrui.92@dcarlife.com>
Co-authored-by: Gavin Chen <chenrui920614@gmail.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-21 14:57:22 +02:00
Mohamed Boudra 995ad2f878 feat(plugin): render Markdown content with host UI (#7579)
* feat(plugin): expose Markdown content component

* docs(plugin): translate Markdown component reference
2026-10-21 19:14:17 +07:00
Mohamed Boudra 1d383519dd feat(app): always show the host picker with Add host on New workspace (#7580)
The Host field used to render only with two or more hosts, and Add host
only appeared on compact layouts. Single-host users had no sign that
Paseo can drive other machines from this screen. The field now always
renders and its menu always ends with Add host.
2026-10-21 18:56:12 +07:00
Mohamed Boudra 23c4df4818 Fix agents showing running after daemon restart (#7573)
* fix(server): close stale agent status after daemon restart

Repair persisted active statuses before serving clients. Let Claude process-tree cleanup run immediately after SDK close rather than waiting on an already closed control channel.

* test(app): expect closed agent status after daemon restart
2026-10-21 18:28:31 +07:00