Commit Graph

2194 Commits

Author SHA1 Message Date
Mohamed Boudra
adc9b3b43c Preserve loader behavior while reducing hidden work (#1996)
* fix(app): preserve loader behavior in retained panels

Keep the running footer mounted across panel switches. Inactive loaders stop their animation work, then realign to the original wall-clock phase before they become visible.

* perf(app): remove inactive loader wrapper worklet

* perf(app): pause hidden turn elapsed timers

* perf(app): reduce loader animation work

Keep one wall-clock-aligned clock for visible loaders and detach retained
hidden loaders without unmounting them. Preserve the 950 ms sequence and
reduced-motion behavior.
2026-07-11 13:25:24 +02:00
Mohamed Boudra
6c764f211a fix(app): stop updates after chat teardown (#1997)
Plain chat views started the history virtualizer even without virtualized rows. Its delayed scroll callback could outlive the mounted view and make the app test job fail during environment teardown.
2026-07-11 09:12:28 +00:00
Mohamed Boudra
28a27b02d3 Prevent Android chats from freezing or going blank (#1989)
* fix(app): stabilize streamed chat rendering

Use deterministic Markdown AST keys and preserve unique row identities when an assistant message resumes after a tool. Keep native gesture and plan-card children correctly keyed to avoid unsupported Fabric reconciliation paths.

* fix(app): stabilize retained native panels

Keep retained workspace roots in a stable native order and make active
panels present in the selection commit. Hidden panels now stop expensive
subscriptions and animations without losing mounted state.

* fix(app): harden retained panel activity
2026-07-11 15:39:14 +08:00
Mohamed Boudra
4c72bf0209 chore(release): cut 0.1.105 2026-07-10 12:58:31 +02:00
Mohamed Boudra
8c639fd796 fix(app): stabilize project picker E2E selectors
Project picker tests had depended on a placeholder changed for fuzzy search. Use a dedicated input test ID so product copy no longer breaks the selectors.
2026-07-10 12:39:40 +02:00
Mohamed Boudra
e6a316456d chore: refresh ACP provider catalog 2026-07-10 12:24:35 +02:00
Mohamed Boudra
3c2339f841 fix(app): clarify fuzzy project search 2026-07-10 12:01:50 +02:00
Mohamed Boudra
61a9117a6b Restore fuzzy project folder search and desktop browsing (#1968)
* fix(projects): restore folder search and browsing

* fix(projects): preserve fuzzy search edge cases

* test(projects): move picker cleanup into fixture

* fix(projects): preserve absolute path descendants

* test(server): compare canonical search paths

* fix(projects): anchor root path suggestions

* fix(projects): anchor Windows root suggestions

* fix(projects): anchor directory search paths

* test(server): canonicalize directory search root

* fix(app): anchor rooted basename suggestions

* refactor(search): unify directory suggestions

Use one parameterized daemon search engine for project paths and workspace entries. Keep local recommendations as a small client overlay and remove unnecessary response metadata.

* fix(search): preserve filesystem root semantics

Accept absolute queries through configured root aliases while keeping traversal and output canonical. Keep blank suffix browsing matcher-independent and avoid metadata-keyed listing caches where Windows cannot invalidate them reliably.
2026-07-10 17:52:55 +08:00
Mohamed Boudra
1f0285c06b fix(app): restore mobile left sidebar swipe (#1976)
Keep the shared sidebar model outside the root gesture detector so Gesture Handler attaches to the native surface on Android/Fabric.
2026-07-10 11:34:47 +02:00
Mohamed Boudra
cac71ee8f5 Hide keyboard shortcut badges in workspace menu on native (#1964)
* Hide keyboard shortcut badges in workspace menu on native

The archive item's shortcut badge (e.g. Ctrl+Shift+⌫) rendered in the
workspace kebab/context menu on mobile, where there's no physical
keyboard to invoke it. Gate the trailing badge behind !isNative in both
kebab menu variants.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(app): hide native shortcuts in every workspace menu

Workspace menus were duplicated across project and status views, so the status path missed the native gate. Centralize the menu so every sidebar view shares the same shortcut policy.

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 00:42:36 +02:00
Mohamed Boudra
a743a22496 Keep large sidebars responsive (#1966)
* perf(app): keep large sidebars responsive

Sidebar rows rescanned every agent for each session update, multiplying work with both workspace and agent count. Build workspace activity once and share the derived sidebar model so updates scale with the underlying collections.

* test(app): use valid agent fixture for workspace restore

* refactor(app): keep sidebar model surface focused
2026-07-10 06:12:56 +08:00
Mohamed Boudra
6af1379357 Stop mobile sidebars getting stuck out of sync (#1953)
* fix(app): keep mobile sidebars synced with store

Gesture-owned skip flags could swallow the next store sync after a no-op or overlapping gesture, leaving React state and Reanimated shared values split. Always reconcile both mobile sidebars from the panel store after gesture animations.

* test(app): keep sidebar sync coverage pure

* fix(app): keep sidebar close transitions idempotent

* fix(app): keep mobile sidebars stable through interruptions

Independent React and worklet state let stale gesture or animation callbacks
overwrite newer panel commands. Use one revisioned target and one transient
motion runtime so outdated callbacks cannot restore an earlier panel.
2026-07-09 23:08:56 +02:00
Matt Cowger
d96d599466 Show reasoning output automatically when enabled (#1943)
* feat(app): add auto-expand reasoning setting

* chore: add cross-env mise tool

* fix(app): stabilize web export and settings detail placement

* Revert "chore: add cross-env mise tool"

This reverts commit f56a367e0c.

* perf(app): narrow settings reads in agent stream

---------

Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
2026-07-08 21:39:03 +00:00
Mohamed Boudra
29a3261dd6 Restore compact Changes diff controls (#1945)
* feat(app): restore compact Changes diff controls

Keep the folder tree behind a view toggle while preserving the flat file list as the default.

Move secondary diff options into the overflow menu so the Changes toolbar stays compact.

* fix(app): mirror whitespace diff option copy

* fix(app): polish diff controls review follow-up
2026-07-08 21:20:51 +00:00
Slava Goltser
c7406a415d fix(app): handle CancelledError from cancelled provider usage queries (#1885)
Move canFetch guard before first await so disabled refresh bails out synchronously instead of entering async path. Add .catch() swallow for fire-and-forget call to prevent unhandled promise rejections when react-query cancels pending queries during rapid tooltip open/close cycles.
2026-07-09 05:00:57 +08:00
Christoph Leiter
3259a69466 feat(app): folder tree in the Changes view (#1918)
Group changed files in the Changes view into a collapsible directory
tree instead of a flat list, on every form factor — consistent with the
Files explorer, which already renders a directory tree on mobile.
Folders are collapsible and expanded by default, single-child directory
chains are compressed into one row (packages/app/src), and folder rows
show aggregate +/- stats.

Client-only, built entirely from the existing ParsedDiffFile paths:

- diff-tree.ts: pure build/compress/flatten of the directory hierarchy,
  keyed by full uncompressed dir path so collapse state survives
  compression changes as the diff mutates.
- diff-flat-items.ts: pure buildDiffFlatItems + sumHeightsBefore. The
  function retains a flat mode (showTree=false) as a tested seam for a
  possible future flat/tree toggle; sticky header indices are
  file-headers-only, derived from the post-collapse list.
- panel-store: diffCollapsedFoldersByWorkspace slice (collapsed-set, so
  folders default to expanded), persisted via version 12. The set is
  reconciled against the current diff so folders that leave and reappear
  default to expanded and the stored set stays bounded.

Presentation primitives (chevron, indent guides, indent constant) are
extracted into components/tree-primitives and shared with the Files
explorer, which drops its private copies (and a banned useUnistyles
call site). The two trees now render identical rows; only the
tree-building stays separate (server listings vs. diff paths).

The toolbar's expand-all stays file-diffs-only (renamed
allFileDiffsExpanded); a separate control collapses/expands all folders.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 03:55:30 +08:00
Mohamed Boudra
cab0e4b3f8 Show a recovery screen for app render errors (#1924)
* fix(app): show recovery screen for render failures

Render a retryable fallback with useful error details when the routed app tree throws during render instead of leaving the app blank.

* test(app): cover root error details without mounting

Move caught-value formatting into a pure module, cover AggregateError fields without duplicate output, and remove the component-mounted test.

* fix(app): keep empty error details caught

* fix(app): preserve nullable aggregate errors

* fix(app): guard malformed error details

* fix(app): handle recursive error causes

* fix(app): guard error detail formatting failures

* fix(app): localize root error fallback

* fix(app): keep root error fallback on existing i18n
2026-07-09 00:06:29 +08:00
Mohamed Boudra
251d88a37a Stop Android audio interruptions crashing voice mode (#1941)
* fix(android): handle denied voice audio focus

Android can deny voice-mode audio focus while another system audio owner, such as an incoming call, is active. Treat that as an interruption so resume does not crash the app and JS stops voice mode coherently.

* fix(voice): keep interruption state consistent

Make native interruption handling payload-aware so iOS resume events do not stop the shared JS runtime, avoid ending voice mode for duck-only Android focus changes, and roll host voice mode back if capture fails after startup enabled it.

* fix(voice): avoid duplicate interruption handling

Keep exactly one Android audio-focus request active at a time and leave JS capture state untouched for non-terminal interruption events.

* fix(android): abandon blocked audio focus requests

When Android denies or blocks voice audio focus, abandon the pending focus request so delayed focus gain cannot arrive after voice mode has already stopped.

* fix(voice): handle interrupted dictation capture

Stop Android resume from replaying after recording restart fails, and propagate native blocked interruptions into dictation so users do not remain in a stale recording state.
2026-07-08 19:45:02 +08:00
Mohamed Boudra
f3fdeab131 chore(release): cut 0.1.104 2026-07-08 12:47:07 +02:00
Mohamed Boudra
ed67e6e0f1 fix(app): preserve renamed host labels (#1940)
Daemon-advertised hostnames still name new/default hosts, but connection refreshes and re-pairing no longer overwrite labels that users already changed.
2026-07-08 10:20:06 +00:00
Mohamed Boudra
4fb70668f2 Manage the built-in daemon from one place in settings (#1938)
* feat(settings): consolidate daemon management into the host page

The app-level Daemon section and the localhost host page rendered the
same daemon card in two places. The host page is now the single home:
the Host sidebar group leads with Overview, and a desktop-only "Enable
built-in daemon" option in the host switcher recovers a removed
localhost connection. Old settings/daemon deep links redirect
(COMPAT-tagged).

* fix(settings): hide daemon recovery option when the server id probe fails

Review feedback: !query.isLoading treated an errored IPC probe as
resolved, so the recovery affordance could show without knowing the
local server id. Replace the resolved-boolean hook with a single
discriminated state hook (loading | error | resolved) — errors hide the
affordance and fall back to the settings root in the redirect. Also
collapses the two query subscriptions per caller into one.

* fix(settings): keep daemon recovery reachable when no hosts remain

Review feedback: removing localhost as the only host takes the settings
sidebar down its no-host branch, which never mounts the host picker —
so the "Enable built-in daemon" option was unreachable in the most
common recovery case. The sidebar now owns the single hook call, passes
it to the picker, and renders the same action as a sidebar row next to
"Add host" when no hosts exist.

* test(e2e): update settings host header to Overview

Test drift: the host section's sidebar/header label was intentionally
renamed to "Overview"; the spec still asserted the old "Host" title.
Also assert the retired app-level Daemon row stays absent.
2026-07-08 10:20:30 +02:00
Mohamed Boudra
a85139c3f3 chore(release): cut 0.1.104-beta.5 2026-07-07 23:01:34 +02:00
Mohamed Boudra
8d0b3e69e8 chore(providers): update ACP catalog pins 2026-07-07 22:57:49 +02:00
Mohamed Boudra
d9b65e269f Scheduled runs each get their own workspace in the sidebar (#1934)
* feat(schedules): per-run workspaces, isolation and archive controls

Scheduled agents never appeared in the sidebar: each schedule reused one
stamped workspace and archived the run's agent on completion. Now every run
mints its own workspace — the entity the sidebar shows — with per-schedule
controls for isolation (local or worktree) and whether to archive that
workspace when the run finishes.

The schedule form is rebuilt on a non-React form model (open/commands/close)
to end the flicker, edit-into-create contamination, and multi-host hydration
bugs that came from effect-choreographed shared state. That lands the reusable
foundations it needed: a form kit over a single control-geometry owner, a
data-access taxonomy (replica/snapshot/fetch) with real load-state semantics,
and lint/boundary guardrails so new screens inherit the paved road.

Also fixes desktop combobox popovers truncating options when the trigger is
narrower than the content. New schedule protocol fields are optional on both
create and update, so old and new clients/daemons stay compatible.

* test(app): complete mock themes for control-geometry tokens

switch and terminal-profile-edit-modal now style through
createControlGeometry, which reads theme.borderWidth[1], theme.opacity[50],
and theme.colors.borderAccent. The hand-rolled mock themes in these two
suites lacked those tokens, so the eager StyleSheet.create mock threw at
import (collection error), not on any assertion. Add the missing tokens.

* fix(schedules): address review findings on run cleanup, edit isolation, load error, sheet dismiss, and preference hydration

- Server: archive the run's workspace even when agent creation fails, so a
  misconfigured provider no longer orphans a sidebar workspace/worktree.
- Edit form: keep a stored worktree isolation while worktree eligibility is
  still resolving, instead of silently downgrading a saved schedule to local.
- Schedules screen: show the load error/retry UI when every host fails, rather
  than spinning forever behind the loading branch.
- Form sheet: fire the parent onClose on native gesture/backdrop dismiss so the
  sheet closes instead of re-opening.
- Form model: apply late-loading saved preferences to untouched create-mode
  fields (never to edited schedules or user-modified fields).

* fix(schedules): review batch — reconnect resubscribe, worktree prune, Android dismiss, cadence and provider edit safety

- Push-router: re-send terminal and checkout-diff subscriptions after a
  reconnect; the old per-hook effect resubscribed on isConnected and the
  extracted router did not, so daemon restarts silently stopped terminals_changed
  pushes (root cause of the terminal-activity e2e failures).
- Server: pass the run's source repo root when archiving worktree runs so the
  worktree is unregistered (git worktree remove/prune), not just deleted; also
  archive the workspace when agent creation fails even with archive-off (an
  agentless workspace has nothing to inspect).
- Sheet: RN Modal onDismiss is iOS-only — notify dismiss once-per-close on the
  Android native path too; replace the JSDOM component test with a real
  Playwright dismiss spec and inline the trivial dismiss decision.
- Form model: editing an interval schedule no longer rewrites its cadence to
  cron unless the cadence UI is touched (90-minute intervals have no cron
  equivalent); switching projects clears stale provider/model state and gates
  submit until the new host's snapshot resolves.

* chore(lint): drop custom lint wrapper and boundary script, plain oxlint

The import bans stay in .oxlintrc.json (oxlint-native no-restricted-imports).
The receiver-sensitive checks the custom script enforced are not worth a
parallel lint pipeline; if they come back it will be as oxlint rules.

* fix(schedules): crash-safe run cleanup, capability-gated run options, resilient mutations

- Persist the run's workspace/agent ids on the running-run record so a daemon
  crash mid-run can be recovered: restart archives the interrupted run's
  workspace under the same policy as normal cleanup (agentless always archives,
  otherwise archiveOnFinish is respected).
- Hide Archive on finish (and omit archiveOnFinish/isolation from payloads) on
  hosts without workspaceMultiplicity — an old daemon ignores the fields, so
  offering the switch there would lie.
- Optimistic pause/resume/delete no longer throw when the schedules cache holds
  a still-connecting entry alongside loaded data.
- Mode field is gated on provider mode options, not a selected model, so
  model-less providers can pick their advertised modes.
2026-07-07 22:13:42 +02:00
Mohamed Boudra
d3e1fe48f6 Scheduled and loop agents get workspaces; schedules UI speaks the user's timezone (#1909)
* fix(app): schedules UI speaks the user's timezone

* refactor(server): require explicit agent placement and bind create-agent command

* fix(server): scheduled agents get a workspace and show in the sidebar

* fix(server): loop agents get a workspace and show in the sidebar

* fix(server): preserve scheduled and loop run semantics through the create command

* fix(server): serialize all schedule record writes through the per-schedule queue

* fix(server): tighten create-agent dependency contracts

* fix(server): handle schedule restamps and loop cancellations

* fix(server): preserve scheduled and loop create semantics

* refactor(server): schedule store owns atomic mutations

* fix(server): keep schedule stamp reuse deterministic

* fix(server): handle loop workspace stamp rejection

* refactor(server): schedule store owns typed identity upsert

* fix(server): keep schedule workspace stamps server-owned

* fix(server): preserve scheduled run semantics

* refactor: required nullable workspaceId replaces placement union; pure cadence policy

* fix(server): tighten scheduled and loop agent edges

* fix(server): fail canceled scheduled runs

* fix(server): close schedule and loop cwd edges

* fix(server): refresh schedule workspace stamps

* fix(server): preserve schedule timezone on replace

* fix(server): close loop stop and cadence reset edges
2026-07-07 17:13:28 +08:00
Mohamed Boudra
503a5a9e1e Fix desktop-managed daemon restart from settings (#1915)
* fix(settings): restart managed desktop daemon fully

* fix(settings): respect paused desktop daemon management

* test(settings): cover restart routing through public helper

* fix(settings): wait for daemon restart disconnect

* fix(settings): handle restart review edge cases
2026-07-06 17:50:49 +02:00
Mohamed Boudra
f21c997b17 Include desktop app logs in diagnostics (#1914)
* fix(diagnostics): include desktop app logs

Settings diagnostics now collect the Electron main-process log separately from daemon.log so desktop startup and environment-probe failures are included in app reports.

* refactor(desktop): share log tail reader

* fix(diagnostics): surface desktop app log read errors

* refactor(diagnostics): tighten desktop report API
2026-07-06 17:50:45 +02:00
Xisheng Parker Zhao
61df450366 fix(server): surface TRAE CLI slash commands and skills over ACP (#1896)
traecli publishes its slash commands and skills asynchronously via the standard
ACP available_commands_update notification ~400ms after session/new resolves.
Because the catalog entry runs through the plain GenericACPAgentClient
(waitForInitialCommands defaults to false), listCommands() resolves before that
first batch arrives and the Paseo UI shows an empty slash menu — intermittently,
depending on whether the menu is opened inside the ~400ms race window.

Add a thin TraeACPAgentClient that sets waitForInitialCommands: true (10s
timeout) and wire it into the extends:"acp" derived-provider branch, mirroring
CursorACPAgentClient exactly. Cursor has the identical async-commands behavior;
this reuses that adopted pattern rather than introducing anything provider-
specific. Unlike Kiro (#1792), traecli uses the standard available_commands_update
update type, so no extensionCommandsParser is needed.
2026-07-06 20:30:22 +08:00
Mohamed Boudra
391cf75ece chore(release): cut 0.1.104-beta.4 2026-07-06 09:58:20 +02:00
Mohamed Boudra
b3eb77981a chore(release): cut 0.1.104-beta.3 2026-07-04 10:22:14 +02:00
Mohamed Boudra
3e28b9b59e chore(providers): update ACP catalog pins 2026-07-04 10:20:07 +02:00
Mohamed Boudra
9c220c2451 Browser tools: full accessibility snapshot, trusted input, dialogs, evaluate, and tab controls (#1881)
* feat(browser): replace flat snapshot with ARIA tree and page-side refs

* feat(browser): trusted CDP input with actionability waits

* feat(browser): auto-handle javascript dialogs

* feat(browser): add browser_evaluate

* feat(browser): add scroll, resize, and close_tab tools

* fix(browser): review fixes for snapshot/input/dialog seams

* fix(browser): address review findings on dialog capture, truncation, and keypress targets

* fix(harness): drop resize check that cannot run under parked compositor surfaces

* fix(browser): second review round — snapshot fidelity, key input, dialog scoping
2026-07-04 01:38:07 +02:00
Mohamed Boudra
b28f291493 Generalize browser automation hosting beyond the desktop app (#1878)
* feat(browser): generalize browser automation hosts

Rename the browser automation client capability to a host-neutral payload, advertise supported commands, and route tab-scoped commands by browserId affinity so future browser hosts can register without another protocol shape change.

* fix(browser): harden browser host registration

Reject unusable browser host capabilities, clean up pending requests when a host registration is replaced, and defer list_tabs affinity updates until every host in the aggregation succeeds.

* fix(browser): preserve host tab affinity across reconnects

Keep stranded tab ownership tied to the disconnected host so the same host can reclaim open tabs after reconnect, and tolerate future command names in browser_host capability payloads while retaining only known commands.
2026-07-04 01:46:04 +08:00
Mohamed Boudra
8d3a43e05d Stop new browser tabs from an agent stealing your focus (#1875)
* fix(browser): stop new MCP browser tabs stealing focus

browser_new_tab used openTabFocused, switching the workspace UI to
the new tab and interrupting whatever the user was looking at.
Automation commands don't need visual focus to work: webviews stay
resident and paintable regardless, so open the tab in the background
via openTabInBackground instead.

* fix(browser): stop background MCP tabs hijacking Reload

openBrowserTabForRequest still called setWorkspaceActiveBrowser for
tabs opened in the background, so the desktop Reload/Force Reload
menu (which targets getMostRecentWorkspaceActivePaseoBrowserWebContents)
could reload an agent's hidden tab instead of whatever the user was
looking at. Automation commands never needed this: every tab-scoped
MCP tool takes an explicit browserId, and the existing
useSyncWorkspaceActiveBrowser hook already keeps "active browser" in
sync with real UI focus. Drop the redundant call.
2026-07-03 13:19:24 +02:00
Mohamed Boudra
75b11ac93e chore(release): cut 0.1.104-beta.2 2026-07-03 11:58:21 +02:00
Mohamed Boudra
860fe92fdd fix(browser): normalize resident webview reuse
Resident nodes restored from the parking host could carry stale offscreen styles after hot reload, so reapply the permanent parking path before returning them.
2026-07-03 11:42:39 +02:00
Mohamed Boudra
ab62a023fd fix(browser): park webviews permanently paintable
Delete the renderer capture prep handshake and keep screenshots on the serialized invalidate/retry path. The capture harness now defaults to the production P1 attach-off parking check.
2026-07-03 11:34:48 +02:00
Mohamed Boudra
a13fa4e614 chore(release): cut 0.1.104-beta.1 2026-07-03 08:27:07 +02:00
Mohamed Boudra
570e652496 chore: update ACP provider catalog version pins 2026-07-03 08:17:17 +02:00
Mohamed Boudra
1bf50349a5 Prefer resident webview for screenshot prep 2026-07-03 07:50:34 +02:00
Mohamed Boudra
cda1ba43cc Fix fresh browser screenshot prep race 2026-07-03 07:18:45 +02:00
Mohamed Boudra
f22865df62 Fix multi-webview browser capture prep 2026-07-03 07:00:06 +02:00
Mohamed Boudra
33ffeb4d42 Harden browser capture prep cleanup 2026-07-03 03:53:53 +02:00
Mohamed Boudra
9430a897e8 Fix browser screenshot capture for parked webviews 2026-07-03 00:27:35 +02:00
Mohamed Boudra
b2714ccd89 feat(browser): rework element annotation and picker toolbar
Element annotation is now free-text: dropped the Fix/Change/Question/
Approve intent pills and the intent field, so the user just says what
they want. The card uses the shared Button and is titled "Annotate
element".

Toolbar: the element picker and DevTools are no longer dev-gated and
work in prod; DevTools uses a wrench icon, and the old clipboard "grab"
is now a Camera "Screenshot element" tool. Each toolbar button
highlights only its own mode, and the copy toast reflects whether a
screenshot image was actually captured.
2026-07-02 23:20:57 +02:00
Mohamed Boudra
441b935b73 test(browser-tools): restore automation coverage 2026-07-02 20:38:48 +02:00
Mohamed Boudra
71ce96b60f refactor(browser-tools): require explicit tab targets
Remove hidden active-browser targeting so automation requests carry workspace in the envelope and browserId in tab command args.
2026-07-02 19:53:40 +02:00
Mohamed Boudra
172de4fbc2 Focus browser automation new tabs 2026-07-02 18:46:57 +02:00
Mohamed Boudra
3eed8c31a2 Fix browser tool workspace context 2026-07-02 18:39:10 +02:00
Mohamed Boudra
58fce6622b Merge branch 'main' of github.com:getpaseo/paseo 2026-07-02 18:22:13 +02:00