Commit Graph
2715 Commits
Author SHA1 Message Date
paseo-bot[bot] 34f9e18bf6 fix(app): keep split dividers under gesture input
Measure the gesture from its initial press so activation does not discard the movement before its threshold. Cover coarse-pointer mouse and touch input alongside app-created workspaces, Explorer changes and reload.
2026-10-28 16:36:29 +00:00
paseo-bot[bot] 5f8b9db679 fix(app): keep split dividers under the mouse before Explorer is first opened
The main row only left the Explorer pane out once the Explorer had been
shown, because the split container read the registered pane id directly.
Before that, the hidden Explorer stayed in the row with its share of the
sizes, and every divider drag moved about 1.28 times the mouse distance.
Resolve the pane the same way the workspace screen does, so the default
Explorer pane is left out from the start.

Closes #5998
2026-10-28 15:45:46 +00:00
Sebastian ArenaandMohamed Boudra 41582eb5fd Terminals survive daemon restarts, crashes and updates (#7644)
* 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>
2026-10-28 18:04:29 +07:00
Mohamed Boudra eee70e7fef Show a lone tool call as itself and group from the second call (#8109)
* fix(app): show a lone tool call as itself and group from the second call

A run of one tool call or thought renders as the call. When a second call
arrives the row becomes a group that keeps the first call's id, so the row
key stays put. Tool call and group open state move into a per-agent store:
opening a lone call also opens its future group without notifying the
timeline, so a click re-renders only that tool call.

* test(app): cover lone tool calls turning into groups

Desktop journeys check that an opened lone call keeps its details open inside
the new group, that clicking it renders no timeline component, and that the
group header lands where the call was. Compact covers the call sheet and a
closed group.
2026-10-28 16:34:58 +07:00
8e7e8cce21 fix(app): retain plugin state across host disconnects (#8105)
Keep client plugin installations and local UI state alive through transient host disconnects. Reconcile changed bundles and removals on reconnect and refresh settings changed while offline. Connection switching still replaces the client and reinstalls plugins.

Preserves the implementation from #6731, adds a failing-before/passing-after real browser regression, and corrects the English and Chinese lifecycle documentation. Verified with focused tests, browser reconnect journeys, Android debug offline interaction, root checks and green current-head CI.

Co-authored-by: luke <luopeihuan@gmail.com>
Co-authored-by: RoundRedDot <roundreddot@gmail.com>
2026-10-28 15:55:32 +07:00
Mohamed Boudra d6d5a266ad Open a subagent in place of the subagents list on mobile (#8093)
* fix(app): seat the subagent sheet's parent callout like the composer

The sheet tab body padded the bottom safe-area inset, and the composer dock
padded it again, so the parent callout in a subagent sheet floated a full
navigation-bar height above where the composer sits in a tab.

The sheet body (SheetBottomInset) now owns the inset: it pads it once and
tells its content none is left, so the dock stays host-agnostic. Overlay
sheets (adaptive modal sheet, menu sheet, combobox sheet) read the inset on
the far side of their portal, so ones opened from sheet content still clear
the screen edge.

The callout takes the composer's rail and shows the parent's provider icon
through StatusIcon: no icon box, with the running ring, attention dot or
needs-input alert on the icon.

* fix(app): give the attachment lightbox its own safe area

An RN Modal passes its call site's context straight through, so a lightbox
opened from a sheet tab read the bottom inset the sheet body had already
spent (0) and drew over the navigation bar. The modal is its own window:
it now gets its own SafeAreaProvider, which measures that window, and the
image area reads its insets below it.

floating-panels.md records the rule for overlays: read insets where the
overlay draws.

* feat(app): open a subagent in place of the subagents list on compact

On phones, choosing a subagent from the subagents list now replaces the list
inside the same sheet instead of stacking a second sheet over it. Back returns
to the list, Close closes both, Android Back steps subagent -> list -> closed,
and Open parent lands on the pane the list was opened from (for a nested
subagent, its parent's sheet).

- Menu engine: fill pages (`fill: true`) take the full sheet height, Back pops
  a page via `goBack`, and a page whose definition disappears falls back to
  the list.
- One sheet pane (`screens/workspace/sheet-pane`) renders the header, body,
  bottom inset and focus for both containers: the workspace's detached sheet
  tabs and the in-list menu page. Only the container differs.
- The header drags the sheet through `SheetDragArea`; compact menu sheets use
  the shared `SheetBackground`/`SheetHandle` chrome.
- `selectSheetTab` describes the sheet a reveal would show without opening it.

* fix(app): put the parent callout on one row

The Open parent button already says what the callout is, so the Parent label
goes. The parent's title shrinks to one line before the button does, so Open
parent never wraps or leaves the row.

* refactor(app): register panels once in the workspace screen

Every reader of the panel registry called ensurePanelsRegistered, which
imports every panel module. The panels render those readers (the agent panel's
subagent track and parent callout, the new-tab panel's launcher, the diff
panel's review surface), so each reader closed an import cycle through
register-panels.

The workspace screen, the only route that renders a registry reader, now
registers the panels before anything under it renders, and the readers import
only the leaf panel-registry. The pane content test registers a probe panel for
real instead of mocking the registry.

* test(app): transform the markdown WASM factory when Vite versions its URL

Importing the sheet pane barrel in retained-chat-content.browser.test.tsx made
Vite request md4c.js with a ?v= query, which the CommonJS-to-ESM transform did
not match, so the test file failed to import.
2026-10-28 13:55:41 +07:00
Mohamed Boudra bede2b90ed fix(app): truncate agent sender attribution to one line (#8092)
Constrain the sender label to the message width so long agent names do not wrap above received messages. Keep the line limit opt-in on Button and cover compact chat widths with a real-browser regression.
2026-10-28 13:50:16 +07:00
Mohamed Boudra befc3d5663 fix(app): restore expansion of long native user messages (#8089)
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.
2026-10-28 13:46:43 +07:00
paseo-bot[bot]andElsa ce412d04c3 Keep docked navigation sizes consistent in narrow windows (#8052)
* fix(app): unify layout and density breakpoints

Align md styles with the existing 600pt compact/wide boundary so
600-719pt tablet windows no longer mix wide layout with compact metrics.
Keep the 500pt composer threshold local to its measured content width.

Let Settings navigation shrink before its detail pane falls below the
existing 400pt target, while retaining the preferred 720pt split budget.

Validated workspace typecheck, lint, formatting, real Chromium resize
checks, Duo portrait and landscape, and existing sidebar geometry tests.

* test(app): cover consistent docked navigation and readable Settings

Compare narrow and wide navigation density and Settings detail space
through the real browser journey, including compact Settings after resize.
The regression fails with main's split layout and density boundaries.

Co-authored-by: Elsa <zeyugao@outlook.com>

---------

Co-authored-by: Elsa <zeyugao@outlook.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-28 06:07:57 +00:00
paseo-bot[bot]andMatteo Pietro Dazzi de50243885 Keep model-discovery errors away from picker edges (#8039)
* fix(app): pad the model picker empty state on all sides

The empty state carried vertical padding only, so the provider refresh
error it renders wrapped from edge to edge and read as attached to the
model picker's left border on web and mobile.

One padding value keeps the message off the border on every platform.

* test(app): keep model discovery errors inside picker edges

Exercise a real catalog deadline through the existing Pi RPC fixture at desktop and compact browser widths. Both gutter assertions fail without the shared padding fix.

Co-authored-by: Matteo Pietro Dazzi <matteopietro.dazzi@gmail.com>

---------

Co-authored-by: Matteo Pietro Dazzi <matteopietro.dazzi@gmail.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-27 15:59:03 +00:00
Mohamed BoudraandClaude 25721c7847 fix(app): keep grouped reasoning closed when Expand thinking is off (#8042)
Thoughts are grouped with tool calls only while Expand thinking is off,
yet opening a group rendered each thought with `defaultExpanded`, so the
reasoning text popped open against the setting. Grouped thoughts now open
like any other call: a closed Thinking row the reader clicks.

The folded history also treated the latest retained turn as live whenever
the agent was active without a known turn id, which unfolded the previous
turn until the new turn's rows arrived. Without head rows, the latest turn
stays live only while the active run is that turn.

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-27 22:34:13 +07:00
78f580f9e8 perf(plugins): reuse verified bundles and fix repeated timeline preparation (#8040)
Reuse verified host-scoped plugin bundles across client launches and reconstruct complete catalogs when unchanged code is omitted. Keep store ownership on the connected client, including adopted bootstrap clients, and persist in the background with bounded writes.

Remove catalog catch-up deferral and fix repeated timeline preparation that promoted cached completed history into a live head. This preserves completed plugin-rendered chat when catalog installation precedes timeline catch-up.

Carries forward #6732 on an upstream branch, with the original hash/cache contribution and integration attribution preserved.

Co-authored-by: luke <luopeihuan@gmail.com>
Co-authored-by: RoundRedDot <roundreddot@gmail.com>
2026-10-27 22:00:23 +07:00
Mohamed Boudra 1b8dbc38ab fix(app): preserve chat reading position across older pages (#8026)
* fix(app): preserve reading position when older turns fold

Item-based history pages can complete and collapse the row at the reading position. Transfer its anchor to the folded turn host so reaching history start does not drain older pages. Also omit reasoning from action summaries and align sender attribution with its message bubble.

* fix(app): preserve the reader when older pages extend tool groups

Resolve grouped calls and folded turns through one presentation-owned row lookup. Keep retained group indexing off the streaming path and verify item-page group replacement against its failing baseline.

* fix(app): preserve message previews when opening turns

Keep the wrapper child structure stable so React does not remount the message fragment when the indent rail appears. Remounting reset preview measurements and briefly removed the fade and Show more control.

* fix(app): separate show less from expanded message text
2026-10-27 19:25:13 +07:00
paseo-bot[bot]andJacek Tomaszewski a8032a1502 fix(app): open outside folder links without breaking Files (#7726)
Outside folder links were routed to the workspace-scoped Files explorer,
which kept an access error until Retry. Route explicit outside folders
to the local file manager or show an outside-workspace message, while
preserving existing file and inside-folder behavior.

Refs #7513

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
Co-authored-by: Jacek Tomaszewski <jacek@fullstack.house>
2026-10-27 10:57:58 +00:00
Dong Hyeon An b9f624f72e fix(app): update xterm to prevent shared-atlas glyph corruption (#8013)
Use upstream atlas invalidation fixes and cover ordinary output and shared-atlas clearing with real-WebGL pixel regressions.\n\nRelated to #6506; does not close the broader rendering issue.
2026-10-27 09:22:15 +00:00
Mohamed Boudra 50623965b4 Make line wrapping responsive in large diffs (#8006)
* perf(app): make diff line wrapping responsive on large changes

Wrapping eagerly shaped every expanded line before the viewport could paint. Estimate off-screen heights and measure rows as they enter the window, preserving the scroll anchor as geometry becomes exact. Add shared layout and browser benchmarks to track toggle latency and shaping cost.

* fix(app): preserve wrapped diff anchors across bounded relayouts

Resizing can move the viewed row outside the old materialization window. Keep its estimated wrap geometry available to anchor resolution, and measure the anchored row in the same layout pass so inaccurate estimates cannot discard the exact fragment or pixel offset.
2026-10-27 16:09:53 +07:00
Mohamed Boudraandluke ef58ace424 Fix history compatibility and turn presentation regressions (#8010)
* fix(client): preserve history loading on older hosts

Whole-turn paging is optional, but requiring its capability blocked existing history reads before any request was sent. Negotiate the paging enhancement at the client boundary while preserving item-based requests for older daemons.

* fix(app): preserve row ownership during late turn updates

Late lifecycle events retagged the newest row even when they updated an earlier call, causing the next update to append a duplicate tool ID. Assign turn membership only to rows written by the event before finalizing unrelated reasoning.

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

* fix(app): preserve reasoning continuity and turn expansion controls

* fix(app): hide reasoning inside collapsed turns

---------

Co-authored-by: luke <luopeihuan@gmail.com>
2026-10-27 15:49:42 +07:00
Mohamed Boudra b12eefb28f Keep conversation turns distinct and history stable (#7990)
* fix(app): keep autonomous turns distinct and readable

Hidden system prompts merged autonomous work into the previous response and reopened completed turns. Preserve canonical turn boundaries and expose their triggers, while making received messages attributable and expanded turn details readable in one step.

* fix(timeline): mount history at actual run boundaries

* fix(timeline): load and retain complete available turns

* fix(app): summarize actions and preserve conversation events

* test(timeline): verify whole-turn paging stays responsive

* fix(app): group reasoning according to thinking preference

* test(app): align history journeys with whole-turn loading
2026-10-27 13:57:17 +07:00
Luke LaBonte 7f6a805e0e feat(app): choose the composer send shortcut (#5503)
Add a client-local Send shortcut selector with Enter and Command/Ctrl+Enter choices. Preserve Enter as the default and route the selected shortcut through the existing send behavior. Cover selection, persistence, editing, and running-agent send behavior with browser tests.

Co-authored-by: Luke LaBonte <contact@lukelabonte.com>
2026-10-27 10:05:16 +07:00
odoo-mvds 65ce4b590a fix(app): remove restored agent tabs from foreign workspaces (#7956)
A persisted explicit pin outlives archive recovery because its agent never joins the unrelated workspace directory. Drop positively foreign pins after hydration and let existing reconciliation remove only the misplaced view. Preserve unknown ownership and legitimate historical opens.

Adapts the repair proposed by kaicot in getpaseo/paseo#6901 to current main, with persisted-store and real-browser regression evidence. Refs getpaseo/paseo#6900.
2026-10-26 17:54:25 +00:00
Mohamed Boudra 287ca54749 fix(app): enlarge sidebar kebab tap targets on compact layouts (#7928)
On phones the project and workspace row kebabs were 24px and 18px boxes
with a 14px glyph, too small to hit reliably. Compact layouts now use a
32px box and the density-sized glyph (18px); desktop sizes are unchanged.
Negative margins keep the dots on the existing right rail and the rows at
their 44px compact height.
2026-10-26 18:12:56 +07:00
Mohamed Boudra 428ef707ad fix(app): demand the host directory from the workspace route (#7918)
A workspace restored at launch with no open chat had nothing demanding its host's directory on a phone, so the deck waited on hydration that never started. The workspace route now keeps its host's directory demanded while mounted, through the same hook the agent route uses.
2026-10-26 15:46:10 +07:00
Mohamed Boudra e277656cbd fix(app): clean up native animation and layout lifecycles (#7914)
Worklets 0.10.4 and Reanimated 4.5.5 while keeping the stale-view guard from #7907; backport the Enriched Markdown settled-row measurement fix (upstream #924); release each bottom sheet's Dimensions subscription on unmount.
2026-10-26 15:46:04 +07:00
Mohamed Boudra e958540b0a fix(app): remove SVG prop and nested button warnings on web (#7915)
* fix(app): prevent web SVG prop and nested button warnings

Consume Unistyles mapping props at the wrapper boundary and use web accessibility attributes for decorative rings. Register composer track rows as menu items so nested actions stay valid and keyboard selection remains available.

* test(app): select archive actions by their menu role
2026-10-26 15:06:02 +07:00
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
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
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 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