Commit Graph

4381 Commits

Author SHA1 Message Date
Mohamed Boudra
0b820d729a ci(android): stop consuming EAS credits for APKs
Build production-signed APKs on GitHub while leaving AAB store builds on EAS. Manual dispatches default to artifact-only dry runs so arbitrary refs can be verified without publishing.
2026-07-16 17:42:56 +02:00
adradr
0d3b717cf3 Git commit history (#1534)
* feat(app): add fileView preference for changes panel

* feat(app): add buildDiffTree util for changed-files tree

* feat(app): add changed-files tree directory row

* feat(app): changed-files tree view mode in changes panel (#117)

* feat(protocol): add checkout.commits.list RPC + commitsList feature flag

* feat(server): list branch commits ahead of base with on-remote flags

* feat(server): handle checkout.commits.list RPC and advertise capability

* feat(client): checkout.commits.list method + useCommitsQuery hook

* feat(app): per-commit inline view with local-vs-remote markers (#117)

* feat(protocol,server): per-commit file diff RPC (checkout.commits.file_diff)

* feat(app): open per-commit file diff on click (#117)

* refactor: surface baseRef + commits loading/error, drop dead depth field

* fix(app): flip commit local/remote dot — local hollow, remote filled

* feat(app): list/tree view for expanded commit file list (#117)

* fix(app): syntax-highlight per-commit file diff to match Changes view

* feat(app): draggable resize between commits and diff sections

* refactor(app): dedupe wrap-text helpers into diff-highlighted-text

* fix(app): clean up commits resize drag on unmount + a11y label

* fix(app): collapse commits section by default

* fix(app): render per-commit file diff with the shared Changes line renderer

* perf(app): memoize shared diff line row; drop redundant DiffLineView wrapper

* refactor(app): extract shared DiffFileBody; render commit file diff through it

* fix(app): hide inline-comment affordance in per-commit diffs (no reviewActions)

* feat(app): move commits to a resizable bottom drawer in the Changes panel

* feat(review): commitSha scoping for per-commit review drafts + attachment

* feat(app): per-commit inline comments wired through to the composer (#117)

* refactor(app): own commit file-diff open state in CommitFileList (drop reset effect)

* refactor(app): colocate diff-render cluster under git/diff-file-body/

* feat(app): add diff tab target kind (working/commit diff tabs)

* feat(app): useDiffFiles hook unifying working + commit diff targets

* feat(app): diff tab panel rendering working/commit diffs

* feat(app): open a commit diff tab on commit click; drop per-commit drawer/file list

* feat(app): open/scroll working diff tab on changed-file click

* fix(app): keep commit diff tabs ephemeral; align working diff whitespace

* feat(app): collapsible file sections in the diff tab, collapsed by default

* feat(app): make the on-remote commit dot more subtle

Dims the filled green remote dot (row + legend) to ~0.55 opacity so the
local-only ring stays the state that draws the eye.

* Reshape commit diffs around the existing Changes view

* Fix diff tab migration complexity after rebase

* Address diff tab review findings

* Clean up diff tab review interfaces

* Collapse commit diffs into the existing view

* Load commits when expanded

---------

Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
2026-07-16 17:36:41 +02:00
Mohamed Boudra
5da6548aff Improve the archived workspace restore flow (#2002)
* fix(app): restore missing workspaces from History

Workspace and agent archival are separate lifecycles. Carry restore intent from History so closed agents can reopen archived workspaces without changing ordinary navigation.

* fix(app): wait for workspace hydration before restore

* fix(app): preserve History agent unarchive

* fix(app): reopen archived History agents outside active directory

History entries are not merged into the active session maps. Carry the row archive state through explicit restore intent so live workspaces still reopen without broadening ordinary navigation.

* fix(app): ignore stale History archive state for active agents

A cached History row can outlive a successful reopen. When the workspace exists, live session state now wins so an active agent is not interrupted by another refresh.

* fix(app): reopen every selected archived History agent

History entries without workspace IDs returned before restoration, and a second archived agent sharing an in-flight workspace restore was dropped. Preserve both agent-only and deferred reopen intent.

* fix(app): require explicit workspace recovery

* fix: preserve workspace recovery contracts

* fix: preserve workspace recovery compatibility

* fix: preserve recovered workspace session state

* fix: preserve terminal navigation timing

* fix(server): preserve successful workspace recovery

* fix: preserve workspace recovery intent
2026-07-16 17:22:37 +02:00
Mohamed Boudra
d42ab91971 Show agent history errors without a one-minute wait (#2124)
* fix(client): fail invalid RPC responses immediately

Correlated responses that failed schema validation were discarded before request matching, leaving callers blocked until the RPC timeout. Preserve only the raw correlation identity at the boundary so the matching request fails with a protocol error.

* test(client): preserve invalid response diagnostics

* fix(client): ignore invalid correlated progress events
2026-07-16 16:44:01 +02:00
Mohamed Boudra
e528a0db06 Remove custom providers from settings (#1951)
* feat(providers): remove custom providers from settings

Add a destructive removal flow so mistaken custom providers can be deleted from config.json instead of only disabled.

* test(app): cover provider removal with e2e

Move provider removal coverage out of mocked component tests and into the real Settings flow.

* fix(providers): keep removal live after config updates
2026-07-16 16:11:51 +02:00
Mohamed Boudra
6aba0370ae Make remote daemon update failures actionable (#2120)
* fix(settings): show daemon update failures

React Native web ignores Alert.alert, so failed remote updates reset to an enabled button without any user-visible explanation. Keep updater progress and failure as explicit rendered state, including the daemon's error, and cover the real browser-to-daemon failure path.

* test(settings): harden daemon update regression

* fix(settings): disable Desktop-managed daemon updates

Desktop-bundled daemons advertised npm self-update even though the install-origin checks always rejected it. Report Desktop ownership to clients, render actionable guidance, and refuse stale requests before touching npm.
2026-07-16 21:04:31 +08:00
Mohamed Boudra
f4509fe044 Open files in more installed editors (#2119)
* feat(desktop): open files in more installed editors

Detect bundled app commands as well as PATH launchers and preserve file positions through editor-specific launches.

* fix(desktop): preserve editor target compatibility

Keep existing file-manager preference ids, retain project context for file launches, and recognize Windows 64-bit IDE commands.
2026-07-16 14:39:55 +02:00
Jason@HND
3e8dce7d7c Hide browser shortcuts outside the desktop app (#2116)
* fix: hide browser pin on non-Electron web

Browser is desktop-only, but the pinned shortcut bar still rendered a
New browser pin on web where createBrowser is a silent no-op.

Skip browser pins in usePinnedLaunchers when not Electron, and drop
browser from default pinned targets so new users only get terminal.

* fix(app): preserve browser pin defaults on desktop

Keep platform availability in the pinned-target policy so regular web hides browser shortcuts without changing Electron defaults.

---------

Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
2026-07-16 12:36:20 +00:00
Mohamed Boudra
47532952f3 Catch broken desktop packages before release (#2114)
* test(desktop): exercise packaged app startup

The previous smoke exited before IPC, window creation, and preload execution, so a broken packaged preload could still pass. Launch the normal app and observe its renderer bridge and managed daemon through CDP instead.

* test(desktop): preserve Linux sandbox in smoke

Configure the unpacked artifact's chrome-sandbox helper with the permissions Electron requires, while keeping sandboxing enabled so preload failures remain observable. Bound startup probes and include process logs in daemon timeout failures.

* ci(desktop): keep packaged smoke on releases

Remove the temporary pull-request artifact build after it validated the Linux launch path. Keep the real packaged smoke in the native desktop release matrix.

* ci(desktop): gate packaged smoke by changes

Run the Linux real-artifact smoke in pull-request CI when packages/desktop changes, while leaving the regular desktop unit-test matrix unconditional.
2026-07-16 12:04:45 +02:00
paseo-ai[bot]
d7ca1b5a03 fix: update lockfile signatures and Nix hash [skip ci] 2026-07-16 07:55:15 +00:00
Mohamed Boudra
42e101c81e chore(release): cut 0.1.109 v0.1.109 2026-07-16 09:46:41 +02:00
Mohamed Boudra
75d784534f docs: add 0.1.109 changelog 2026-07-16 09:43:10 +02:00
Christoph Leiter
64c819efeb fix(desktop): stop sandboxed preload from requiring a local module (#2111)
* fix(desktop): stop sandboxed preload from requiring a local module

The preload imported PASEO_BROWSER_PROFILE_PARTITION from the local module
./features/browser-profile.js. The preload runs in Electron's sandbox and is
tsc-compiled (not bundled), so that import emits require("./features/
browser-profile.js") at the top of preload.js. A sandboxed preload cannot
require a local module, so the require throws before
contextBridge.exposeInMainWorld runs. window.paseoDesktop is then undefined,
the app no longer detects itself as the desktop host, and it never starts the
built-in daemon (users had to run `paseo start` by hand).

The import was added in 0.1.108; 0.1.107 is clean, which matches the reports
that downgrading fixes it. See #2103.

Inline the one value the preload needs (the partition string) so it no longer
loads any local module, and keep browser-profile.ts as the source of truth for
the main process. Add preload-sandbox.test.ts, which parses preload.ts with the
TypeScript compiler API and asserts the only runtime module load is "electron"
(covering value imports, side-effect imports, re-exports, require, dynamic
import, and import-equals; type-only imports are ignored), plus a drift check
that the inlined literal matches the canonical constant.

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

* test(desktop): clearer preload drift-check failure message

Assert the inlined PASEO_BROWSER_PROFILE_PARTITION is present before comparing its value, so a missing/renamed constant reports "not found" instead of a misleading value-drift mismatch (Greptile feedback on #2111).

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

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 09:39:51 +02:00
paseo-ai[bot]
8554b94cdb fix: update lockfile signatures and Nix hash [skip ci] 2026-07-15 22:24:07 +00:00
Mohamed Boudra
75ea0d4534 chore(release): cut 0.1.108 v0.1.108 2026-07-16 00:15:57 +02:00
Mohamed Boudra
d791a0aa91 docs: add 0.1.108 changelog 2026-07-16 00:13:46 +02:00
Mohamed Boudra
943d03ad99 fix(projects): separate registration from workspace setup
Adding or cloning a project now registers it and opens workspace setup
instead of creating a workspace implicitly. Keep Add Project independently
mounted from Search so closing one cannot control the other.
2026-07-15 23:13:55 +02:00
paseo-ai[bot]
38cfe109c9 fix: update lockfile signatures and Nix hash [skip ci] 2026-07-15 19:26:41 +00:00
Mohamed Boudra
5ef1b9dbb1 fix(website): include test dependency in deploy install 2026-07-15 21:19:40 +02:00
Mohamed Boudra
dfe3330ef8 Add a keyboard-driven project setup flow (#2097)
* feat(projects): add keyboard-driven project setup

* test(app): update add project loading assertion

* fix(projects): harden GitHub project setup
2026-07-15 21:16:10 +02:00
Mohamed Boudra
90e0a0e353 Find and open workspaces from the command center (#2096)
* feat(app): add workspaces to command center

* fix(app): scale down command center typography

* fix(app): avoid workspace theme subscription

* fix(app): theme command center bottom sheet

* fix(app): tighten command center workspace results
2026-07-15 20:40:24 +02:00
Mohamed Boudra
37bde90d9f refactor(app): unify assistant fork boundary resolution (#2091) 2026-07-16 00:54:04 +08:00
Christoph Leiter
6804882761 Document iOS/Android local dev setup and fix the mise Android toolchain (#2092)
* Pin android-sdk to 21.0 and unify Java on 21 for mise

The `.tool-versions` `android-sdk latest` pin had resolved to the
ancient `1.0` cmdline-tools bundle, whose sdkmanager (3.6.0) predates
the `emulator` package and fails with `Failed to find package
emulator`. Pin `android-sdk 21.0`, point the hardcoded install paths
in `.mise.toml` at it, and add `cmdline-tools/21.0/bin` to PATH so
sdkmanager and avdmanager resolve.

Also unify the Java version on 21: `.tool-versions` already pinned 21,
but `.mise.toml` overrode it to 17. A local `npm run android` Gradle
build succeeds on 21.

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

* Document iOS simulator and Android emulator local dev setup

Add local-dev docs for running the app against a worktree daemon:

- development.md: prerequisites for the ios-simulator preview service
  (Xcode, an iOS runtime, automatic CocoaPods install), the
  xcode-select/simctl troubleshooting fix, and a "Running the iOS app
  on a local simulator" section covering `npm run ios` and pointing
  the app at a worktree daemon via EXPO_PUBLIC_LOCAL_DAEMON.
- android.md: a "Prerequisites (local dev)" section (mise java 21 +
  android-sdk 21.0, sdkmanager components, AVD creation) and a
  "Running on an emulator against a worktree daemon" section covering
  REACT_NATIVE_PACKAGER_HOSTNAME and EXPO_PUBLIC_LOCAL_DAEMON=10.0.2.2
  for reaching the host daemon.

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

* Give full Intel x86_64 emulator setup commands in Android docs

Greptile flagged that the arm64-v8a -> x86_64 substitution for Intel
Macs was only a parenthetical. Provide a complete, copy-pasteable
x86_64 command block instead of asking readers to hand-edit the arm64
one.

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

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 00:44:17 +08:00
1254087415
13e92f8a30 fix(server): create autonomous turns for spontaneous ACP session updates (#2058)
* fix(server): create autonomous turns for spontaneous ACP session updates

When an ACP-based provider handles background-agent completion
notifications, the resulting spontaneous session/update messages have no
active foreground turn to attach to. Mirror the Claude provider's
autonomous-turn mechanism so these updates are recorded in Paseo's
timeline.

- Start an autonomous turn when a sessionUpdate arrives with no active
  foreground turn
- Tag timeline events with the autonomous turn id
- Complete the autonomous turn after a timeout, or before a new
  foreground turn starts

* Fix ACP autonomous event scoping

---------

Co-authored-by: zab <b13022010527@gmail.com>
Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
2026-07-15 18:42:10 +02:00
Mohamed Boudra
328361667f Keep browser sign-ins across tabs and restarts (#2089)
* feat(desktop): share persistent browser data across tabs

Keep browser sign-ins and site storage across tabs and app restarts, with a Settings action to clear the shared profile.

* fix(settings): prevent duplicate browser data clears

* fix(desktop): complete browser data cleanup

Clear legacy per-tab profiles after upgrades and localize the browser data settings in every supported language.

* fix(desktop): close browser profile cleanup races
2026-07-16 00:40:24 +08:00
Mohamed Boudra
9423b091b9 fix(app): keep tool call summaries neutral (#2090)
Individual tool outcomes remain visible in the expanded list. The aggregate header no longer treats a handled tool result as a failure of the overall work.
2026-07-15 18:34:30 +02:00
Mohamed Boudra
04e893417e Allow failed agent turns to be forked (#2063)
* fix(chat): allow failed turns to be forked

Failed turns can end in Paseo-generated timeline items without provider
message IDs. Anchor forks to canonical timeline positions while retaining
legacy boundaries for compatibility.

Place the fork summary before the new prompt and delimit it as structured
chat history.

* fix(chat): tighten fork boundary handling
2026-07-15 16:30:42 +02:00
Mohamed Boudra
f06792ae89 Recover desktop startup from stale daemon locks
Refs #1950
Refs #1904
Refs #769
2026-07-15 15:48:09 +02:00
Mohamed Boudra
7f011d16c5 Reduce composer overhead while typing (#2086)
* perf(app): reduce composer draft writes

Persist draft checkpoints every 200 ms during sustained typing while keeping the latest in-memory draft current. A trailing write stores the newest checkpoint when typing stops.

* test(app): cover draft persistence checkpoints

Keep the throttle policy deterministic at its storage boundary, including latest-value coalescing and pending-write cancellation when drafts are cleared.

* fix(app): flush pending drafts on background

Flush the latest throttled checkpoint when the app leaves the foreground and report asynchronous persistence failures. Extend the storage-boundary tests across consecutive intervals and explicit lifecycle flushing.
2026-07-15 15:40:11 +02:00
Mohamed Boudra
319d9017c2 Publish the latest Android version code (#2085)
* feat(website): publish latest Android version code

* fix(website): select latest Android APK release
2026-07-15 21:38:52 +08:00
Mohamed Boudra
4a5630bfce fix(app): stop composer height flicker
Native scrollbar appearance changed the textarea's usable width, feeding alternating measurements back into the composer height mirror. Reserve the gutter so wrapping and height remain stable.
2026-07-15 12:05:09 +02:00
Mohamed Boudra
5ddd5f3726 perf(app): keep desktop sidebar ready to reopen
Retain the hidden sidebar tree so common toggles preserve local UI state while existing activity gates pause expensive hidden work.
2026-07-15 12:05:08 +02:00
Mohamed Boudra
3673846433 fix(app): keep single tool calls in overview list 2026-07-15 12:05:08 +02:00
Mohamed Boudra
abfe955867 Show friendly native subagent names and hide finished work (#2073)
* feat(subagents): archive finished children and show native names

Keep native provider sessions intact while letting users clear completed children from the track. Persist dismissed provider child IDs so history replay does not restore them.

* fix(subagents): cover persistence and naming edge cases

* fix(subagents): preserve active descendants and native names

* fix(subagents): retain dismissed timelines and trim paths

* fix(subagents): retain history across hydration

* test(subagents): expect normalized native descriptions

* fix(subagents): separate hidden rows from retained history

* fix(subagents): preserve restored hidden tabs safely

* fix(subagents): integrate archive with run state

* test(codex): expect normalized child name

* fix(subagents): retain dismissed tabs on reload

* fix(subagents): hide finished native agents locally

Keep the header action presentation-only so it does not mutate agent lifecycle or expand the runtime protocol.

* fix(subagents): humanize native agent names

* fix(subagents): preserve names in Codex history

* fix(subagents): retain hidden rows across reloads
2026-07-15 11:58:31 +02:00
Mohamed Boudra
38e4d9ad5d feat(app): polish sidebar and tool call summaries 2026-07-15 11:24:05 +02:00
Mohamed Boudra
77f6069ec1 Keep desktop sidebar controls stable across panel changes (#2078)
* fix(app): stabilize desktop sidebar controls

Keep the left-window-controls toggle mounted across sidebar state changes so its position and tooltip state remain stable. Preserve browser placement and show an explicit Explorer close control only where native right-side controls do not provide one.

* fix(app): suppress inactive sidebar chrome
2026-07-15 15:30:57 +08:00
Mohamed Boudra
9c40cb7637 Render provider images from paths with spaces (#2074)
* fix(server): render image paths with spaces

Raw spaces in local Markdown image destinations made the renderer treat provider images as text. Emit encoded file URIs for spaced paths so the client parses and resolves them as images.

* fix(server): encode all absolute image paths

Provider image paths without spaces could still contain URI-significant characters such as fragment or query markers. Route every absolute local path through the encoded file URI boundary.

* fix(server): encode network image paths

Windows network-share paths bypassed the absolute local path handling. Normalize UNC and extended UNC paths before encoding them as file URIs.

* fix(app): preserve network image paths

Host-based file URIs were decoded as relative paths. Restore the UNC prefix so provider images on network shares resolve through the file RPC correctly.

* fix(server): preserve double-slash POSIX image paths

Classify only backslash-prefixed paths as Windows network paths so POSIX double-leading-slash paths retain their filesystem semantics.
2026-07-15 00:10:24 +02:00
Mohamed Boudra
d706c4339b Fix hidden Codex subagents and stuck parent sessions (#2068)
* fix(server): prevent hidden Codex subagents and stuck turns

Codex can announce native children only through its mirrored lifecycle stream, while rejected interrupts previously looked like successful local cancellation. Preserve those child announcements and keep manager state active until the provider acknowledges cancellation.

* fix(server): block actions after rejected cancellation

A provider can accept a turn before publishing the turn ID needed to interrupt it. Keep that interval non-cancelable, and prevent reload, replacement, or rewind from proceeding without an acknowledged cancellation.

* fix(server): surface rejected agent cancellations

Replacement prompts and Stop requests could appear accepted after the provider kept ownership of the active turn. Complete replacement cancellation before detaching the stream, and return cancellation failures through the client response.

* fix(server): handle turn completion during cancellation

* fix: finish cancellation lifecycle handling

* fix(server): close remaining cancellation races

* fix(server): settle autonomous cancellations

* fix: honor cancellation failures at call sites

* refactor(server): centralize agent run state

* fix(server): keep pending runs isolated from stale events

* fix: surface remaining cancellation failures

* fix(server): narrow cancellation error handling
2026-07-15 00:01:58 +02:00
Mohamed Boudra
50ed0d0ab1 Fix desktop layout and window controls at half-screen width (#1983)
* fix(app): preserve desktop layout in half-screen windows

Treat native window controls as physical corner obstructions instead of deriving clearance from compact layout state. Keep 751px windows in desktop mode while preserving usable content when persisted sidebars are wide.

* fix(app): retain sidebar width across window resizes

* fix(app): yield app sidebar to narrow settings

* test(app): wait for mobile sidebar motion to settle

* fix(app): yield navigation to narrow workspace explorer

* fix(app): mark sidebar sizing helpers as worklets

* fix(app): hide app navigation when space is constrained
2026-07-14 23:01:14 +02:00
Mohamed Boudra
1b8af2e58e Refine tool call summaries and scrolling (#2069)
* feat(app): refine tool call summaries and scrolling

Keep summary groups stable from the first tool call, preserve live activity feedback, and scroll expanded groups to the latest entry. Consolidate web scrollbar styling around the native browser mechanism.

* refactor(app): reuse tool call height constant

* fix(app): preserve tool call summary state

* fix(app): refresh web tool groups on expand

* fix(app): preserve grouped tool errors
2026-07-14 21:16:29 +02:00
Mohamed Boudra
d781b68711 Polish release notes and in-app help (#2070)
* feat(ui): improve changelog and help navigation

Make release notes easier to scan and reach from the app. Also keep the homepage marquee within the layout viewport so it cannot create horizontal scrolling.

* fix(website): reject duplicate release anchors
2026-07-14 21:06:25 +02:00
Ethan Greenfeld
cd6c608c9e Fix Pi slash commands hanging after local completion (#2066)
* fix(pi): complete locally handled prompts

Slash commands the Pi CLI handles without starting a model turn previously
left the Paseo turn hanging until interrupt. Parse the optional
agentInvoked correlation from prompt acknowledgements, surface
command_output/notify output as timeline content, and complete the turn
locally when no agent turn will start. Older Pi binaries without the
correlation are detected via a getState compatibility probe.

* review: guard command output without an active turn, simplify delegates

- Drop late-arriving command_output when no turn is active instead of
  emitting an orphaned timeline item with turnId undefined
- Remove redundant 'text' in event check (type is already narrowed)
- Inline recordNoTurnNotification delegate

* refactor(pi): consolidate local prompt state

---------

Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
2026-07-14 20:29:42 +02:00
Mohamed Boudra
1f5283f5a3 Surface cross-workspace subagents in their workspaces (#2061)
* fix(workspaces): show provider subagent activity

Provider subagent lifecycle lives outside managed agent snapshots, so workspace aggregation dropped it after the parent turn finished. Count running provider subagents against the delegation root and emit workspace updates when their status changes.

* fix(workspaces): surface cross-workspace subagents
2026-07-14 14:22:14 +02:00
OnCloud
c0b801b805 Fix shortcut capture ignoring - = ; ' keys (#2047)
* Fix shortcut capture ignoring - = ; ' keys

KEY_MAP was missing Minus/Equal/Semicolon/Quote, so
keyboardEventToComboString returned null for those physical keys and
the capture UI silently dropped them. Add the four entries with their
shifted variants.

Also suppress the Electron View > Zoom accelerators (Cmd+-/=/0) while
capturing, so those combos reach the renderer instead of zooming the
window. Driven by the existing capturingShortcut flag via a new
paseo:menu:set-capturing-shortcut IPC.

* fix: address review feedback from PR #2047

Trim the capturing useEffect so it only fires when capture is active
(removes the redundant on-mount false and the double-fire on true->false),
and reset the main-process capturingShortcut flag on renderer reload via
browser-window-created + did-finish-load so a Cmd+R mid-capture can't
leave the zoom accelerators disabled.

---------

Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
2026-07-14 13:30:32 +02:00
Matt Cowger
9ea58aae0c fix(server): stop OpenCode daemon crash on session close, fix #2014 (#2027)
* fix(server): patch OpenCode SDK unhandled rejection on stream abort

The SDK's SSE abort handler calls reader.cancel() without handling
its rejection. When Paseo aborts the event stream during normal
session close, that promise can reject and crash the daemon with an
unhandled rejection outside any Paseo-owned code path.

Patches both copies the SDK ships (dist/gen and dist/v2/gen, the
latter being what Paseo actually imports). Extends
postinstall-patches.mjs to support patch-package running from a
non-root cwd, since @opencode-ai/sdk lives in packages/server's own
node_modules rather than the hoisted root.

* fix(server): stop assuming OpenCode's default agent is "build"

OpenCode users can rename or delete any agent, including the built-in
"build"/"plan" defaults. Paseo was injecting a hardcoded "build"
agent in several places whenever no mode was explicitly requested:

- The protocol manifest declared defaultModeId: "build" for opencode,
  which AgentManager.normalizeConfig applied to every session
  (including internal metadata-generation sessions) before any
  provider-level logic ran.
- OpenCode's own normalizeOpenCodeModeId defaulted an empty/"default"
  modeId to "build" rather than omitting the agent field.
- Unattended child creates (e.g. subagents spawned by an unattended
  parent) forced modeId: "build" to express unattendedness, even
  though that's already carried by the auto_accept feature.

Now an unset mode stays unset end-to-end: the "agent" field is
omitted from OpenCode prompt/command calls entirely, letting OpenCode
fall back to its own configured default agent instead of Paseo
guessing one that may not exist.

* fix(server): validate agent create mode on the WebSocket session path

resolveAndValidateCreateAgentMode already rejects modes unknown to a
provider's discovered mode list, but it was only wired into the MCP
create path. App-created agents (create_agent_request) skipped it
entirely, so a client's remembered mode preference — which can go
stale when a user renames or deletes OpenCode agents — sailed through
to the provider and failed mid-turn with an opaque error instead of a
clear rejection at creation time.

resolveSessionCreateAgent now calls
providerSnapshotManager.resolveCreateConfig, matching the MCP path,
so an invalid mode now throws 'Invalid mode ... Available modes: ...'
immediately on create.

* chore: address review feedback on create-agent and postinstall script

- Document the cleanup-ordering constraint in resolveSessionCreateAgent:
  mode validation runs after buildSessionConfig (cwd isn't known until
  that completes), so a thrown validation error leaves any
  worktree/workspace buildSessionConfig created for the caller to clean
  up. session.ts already handles this for the worktree path; the
  directory-only workspace path has a pre-existing gap, not introduced
  by this validation.
- Log spawn errors from patch-package in postinstall-patches.mjs
  (e.g. ENOENT if it's missing from PATH) instead of failing silently.

* fix(server): don't fabricate OpenCode modes when discovery finds none

fetchModesFromClient and mergeOpenCodeModes fell back to
DEFAULT_MODES ([build, plan]) whenever OpenCode discovery returned
nothing — e.g. for a freshly-created worktree whose OpenCode server
hasn't loaded the project config yet. That fabricated list let
create-time mode validation accept a stale 'plan' preference that the
provider then rejects at prompt time (Agent not found: 'plan').

Return an empty list instead: OpenCode users can rename or delete any
agent, so any hardcoded fallback risks validating a mode that doesn't
exist. DEFAULT_MODES is retained only for description enrichment and
sort ordering.

* fix(app): reconcile stale selected mode against discovered modes on create

The mode picker displays modeOptions[0] when the stored modeId isn't
in the discovered list (e.g. a globally-remembered 'plan' that a
workspace's OpenCode config no longer defines), but the create request
still submitted the raw stored modeId. Result: UI showed 'Build' while
the request sent 'plan', which the daemon then rejected.

Reconcile the selected mode against the discovered mode ids when
building the create config (both the workspace draft composer and the
workspace-setup dialog), so the submitted mode matches what the picker
shows — falling back to the first available mode when the stored one is
absent. Mirrors the existing resolveEffectiveModel reconciliation for
models.

* test(server): fix opencode mode tests after fallback change + rebase

- Replace 'available modes include build and plan' (which relied on the
  removed [build, plan] discovery-failure fallback) with two tests:
  one asserting discovered agents map to modes, one asserting empty
  discovery yields no fabricated modes.
- Restore messageId fields in the four provider-subagent timeline
  assertions. These were accidentally dropped during rebase conflict
  resolution; the #2013 subagent code legitimately emits messageId, so
  the expectations must include it.

* test(app): fix e2e seed helper using invalid opencode mode

createIdleAgent seeded an OpenCode agent with modeId
'bypassPermissions' — a Claude mode OpenCode never had. This worked
before only because the session create path silently coerced unknown
modes to 'build'. Now that create-time mode validation rejects modes
the provider doesn't define, use 'build' + auto_accept (OpenCode's
unattended full-access equivalent), matching the rewind-flow helper.

Fixes the e2e failures across archive-tab, command-center-host,
settings-toggle-tab-regression, workspace-agent-tab-rename,
workspace-pane-remount, workspace-navigation-regression, and
worktree-restore specs, which all seed via this helper.
2026-07-14 19:00:53 +08:00
Mohamed Boudra
f35b16b316 docs(orchestration): explain cross-provider workflows (#2062) 2026-07-14 18:56:45 +08:00
Matt Cowger
81113d1582 feat(app): add tool call detail levels (#2031)
* feat(app): compact tool call sequences

* feat(app): summarize compact tool activity

* feat(app): add tool call detail levels

* fix(app): stabilize compact tool groups

* fix(app): address compact tool review feedback
2026-07-14 18:55:06 +08:00
Liam Diprose
3b078240a8 Serve the daemon web UI from Nix packages (#1978)
* fix(nix): include daemon-web-ui in nix package

* fix(nix): verify web UI without packaging website sources

* test(nix): cover bundled web UI inputs

---------

Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
2026-07-14 18:50:09 +08:00
Xisheng Parker Zhao
279e1aa91c Fix Codebuddy Code model discovery (#1979)
* fix(app): use global codebuddy binary for codebuddy-code ACP provider

The @tencent-ai/codebuddy-code npm package ships multiple bins
(codebuddy/cbc/cbc-prewarm), so `npx -y @tencent-ai/codebuddy-code`
fails with "could not determine executable to run" and exits
immediately. Paseo's ACP catalog probe treats npx as a long-running
process, so the initialize request never gets a response and the
probe times out after 60s, leaving the model list empty.

Switch to the user-installed codebuddy CLI (matching kiro-cli,
traecli, cursor, etc.) so the probe completes and models load.

* chore: trigger CI rerun (app-tests flaky: window-is-not-defined in strategy-web.test.tsx, unrelated to this change)

---------

Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
2026-07-14 10:15:36 +00:00
Mohamed Boudra
b4ab0d9db6 Find .opencode files in workspace search (#2049)
* fix(search): find .opencode workspace files

Workspace autocomplete skips hidden directories unless they are explicitly allowlisted. The missing .opencode entry made provider commands and workflows invisible to file search.

* refactor(search): centralize hidden directory policy
2026-07-13 22:50:34 +02:00