614 Commits
Author SHA1 Message Date
Mohamed Boudra 9c8d775895 Let plugins customize agent creation and observe lifecycle events (#4435)
* feat(plugins): expose agent and workspace lifecycle hooks

* test(plugins): verify lifecycle examples with version requirements

* fix(plugins): publish archive hooks for closed agents

* test(plugins): remove diagnostic catch from lifecycle test

* refactor(plugins): define hook handlers in lifecycle module
2026-09-07 19:17:42 +02:00
Mohamed Boudra a5d2b7d863 Declare and enforce plugin Paseo version requirements (#4430)
* feat(plugins): enforce declared Paseo version requirements

Treat manifests without a Paseo requirement as pre-0.8 plugins so the first breaking plugin release offers an explicit migration path. Check the daemon and app independently before plugin execution, and preserve installed Git revisions when updates are incompatible.

* fix(nix): refresh dependency hash for plugin requirements

* refactor(plugins): validate test manifest inputs and name compatibility input
2026-09-07 17:20:19 +02:00
Mohamed Boudra 1c51b52d07 Restore cached conversations before reconnecting (#4421)
* fix(app): restore cached conversations before reconnecting

Give each host one timeline write authority so cache restores, live events and fetched pages publish consistent rows and coverage. Persist a moving 40-entry restart page independently of loaded scrollback, and keep native navigation mounted while startup settings hydrate.

* fix(app): recover cache writes after initialization failures

Keep accepted writes pending and retry initialization without another UI update. Publish the storage index only after loading succeeds, while queued host identity changes still settle in order.

* test(app): wait for sidebar and workspace transitions

Viewport intersection and leaving the creation route can precede completed UI transitions. Wait for the layering hit test and selected agent tab before asserting or navigating again.

* fix(app): restore provider loading on native clients

The native AbortSignal lacks throwIfAborted, so successful provider responses failed before reaching every model selector. Preserve both cancellation boundaries using the supported aborted property and the existing query cancellation error.
2026-09-07 15:52:21 +02:00
Mohamed Boudra dd7671be20 Remember model selections across workspace creation (#4401)
* fix(providers): remember model selections across workspace creation

Keep saved model intent independent of catalogue readiness and use the caller-owned host and directory from the first render. Share discovery through provider-owned keys while preserving execution context.

Give each target one committed snapshot, publish actual transitions atomically, and share catalogue content across client directory associations. Regression coverage exercises successful repeated creation and provider lifecycle boundaries.

* fix(providers): preserve shared cache bodies during eviction

Admit directory references with their bodies, retain reference recency during eviction and recovery, and remove the unused persisted index. Refresh known workspace catalogues concurrently.

Make repeated-creation picker states explicit and seed mode tests from the installed provider catalogue, preserving assertions across Codex versions.

* fix(providers): bound discovery independently per provider

Settings refresh repairs all remembered targets, which otherwise starts an unbounded number of discoveries. Admit work after catalogue-key deduplication and keep each provider’s budget independent so a stalled provider cannot block another. Preserve active accounting across configuration changes and settle obsolete queued requests during replacement and shutdown.
2026-09-06 20:29:41 +02:00
Mohamed Boudra 38c22139bb Let plugins control modal layout, scrolling and clipboard actions (#4392)
* feat(plugins): support modal body layout, scrolling and clipboard actions

* fix(app): keep native scroll dependencies out of web imports

* fix(nix): sync dependency hash for plugin native types

* test(plugins): express modal QA as user journeys
2026-09-06 13:48:29 +02:00
Mohamed Boudra ae80ec4252 Let plugins contribute settings screens (#4357)
* feat(plugins): contribute settings screens and shared controls

* fix(plugins): localize settings and verify shared UI consumers

* test(composer): unmount draft test roots after each case

* test(app): keep launch terminals alive until cleanup

The fixed ten-second profile lifetime could expire before a busy CI browser attached or finished revisiting the composer. Keep the real process waiting for input until project teardown terminates it.

* test(server): await the initial snapshot before a buffered ref event

Watcher setup can read checkout facts before the initial refresh publishes a snapshot. Wait for publication before injecting the event so the test consistently exercises a second refresh.
2026-09-06 10:22:26 +02:00
Mohamed Boudra ab7d66dfed Let Hub continue agents through the standard daemon API (#4354)
* feat(hub): continue agents through standard daemon operations

Authorize ordinary agent and workspace recovery operations with hub.execute. Keep conversation routing in Hub and persist generic creation and message receipts so retries cannot silently duplicate work.

* fix(hub): expose custom providers to continuing clients

Allow Hub to advertise provider support independently of the app version. Document the companion continuation policy and migration. Preserve newly observed files in the native watcher inventory so coalesced deletions remain visible to reconciliation, addressing the Windows CI failure.

* fix(hub): allow retries after confirmed local failures

Prepare message loading before recording dispatch intent. Remove failed creation receipts only when creation cleanup completed and no live or stored agent exists. Keep ambiguous provider deliveries fail-closed. Exercise native file observation with real filesystem dependencies.
2026-09-06 10:19:40 +02:00
Mohamed Boudra efd6023b90 Restore live sessions immediately after app resume (#4160)
* perf(app): restore live sessions immediately after resume

Foregrounding now reconnects every host without waiting for scheduled backoff, while cached turns, timelines, agents, and workspaces remain internally consistent until authoritative catch-up arrives. Replica persistence is keyed and incremental so ordinary updates avoid whole-directory serialization.

* fix(app): preserve turn ownership through session updates

Stream turn closure now wakes queued-message delivery, while same-turn snapshots retain local cancellation state. Offline liveness remains visible until an authoritative close arrives.

* fix(app): preserve pending chat cache writes and trim resume refactor

Directory baseline replacement must preserve independently accepted timeline changes until the deferred flush. Keep the reconnect and persistence fixes while removing the session-data facade and broad read-hook migration.

* fix(app): initialize reconnect policy from current app state

Initialize visibility before host bootstrap so a background mount cannot leave reconnect enabled. Seed sidebar fixtures through the workspace owner so cache hydration preserves their rows.

* test(app): verify submission settlement across reconnect

Keep submission acknowledgement separate from turn liveness: disconnect preserves the running turn until authoritative catch-up. Wait for confirmed running chrome before exercising queued cancellation so the alternate-send shortcut cannot race turn startup.

* docs: remove cache implementation recap
2026-09-06 10:18:41 +02:00
Mohamed Boudra c8a417c4fb Address terminals by workspace ID in the SDK and CLI (#4358)
* feat(terminals): expose workspace ownership through the SDK and CLI

Directory-based terminal creation selected the oldest workspace sharing that path. Expose explicit workspace ownership in the shared public API and CLI, retain ownership and process directories in listings, and acknowledge terminal deletion after teardown.

* fix(file-observer): preserve nested shallow reconciliation scopes

A parent directory scan does not visit its descendants. Collapsing change scopes discarded nested scans and left coalesced native deletions unseen until a full audit.

* test(terminals): extract output waits from end-to-end scenarios
2026-09-06 10:17:58 +02:00
Mohamed Boudra 78b285059f Fix agent reloads blocked by an active session writer (#4353)
* fix(server): keep agent reloads from overlapping session writers

Idle runtimes can still own their persisted session writer. Release the original runtime before resuming and retain failed cleanup for retry; a timeout must not authorize another writer.

* fix(server): honor closes queued during agent reload

Serialize public close with reload so a completed close cannot be undone by replacement registration. Keep archive cleanup inside its existing lifecycle operation.
2026-09-05 14:55:19 +02:00
Mohamed Boudra f4b209be4d Preserve nested subagent ownership (#4321)
* fix(subagents): preserve recursive provider ownership

Provider events retained enough lineage to identify nested work, but the canonical descriptor discarded the direct owner. Preserve that relationship at ingestion so child timelines and hierarchy remain attached to the process that emitted them, including after history replay.

* test(e2e): clarify nested ownership journey

* test(e2e): separate nested ownership actions

* fix(subagents): retain nested ownership across replay

Wait and interaction events can reference descendants without spawning them. Preserve the original spawning owner and route persisted background notifications through that same relationship after history reload.

* test(subagents): hide provider turn plumbing

* fix(subagents): scope nested tracks to their host

Plugin-provided icons are host-specific. Carry the panel host through nested child tracks so the rebased ownership UI resolves the same provider presentation as its parent.

* fix(workspaces): preserve launched terminal focus
2026-09-04 23:49:26 +02:00
Mohamed Boudra 9e90b86afa Restore reliable macOS desktop updates (#4322)
* fix(desktop): restore macOS app updates

Electron 41's Squirrel helper can leave the update handoff dormant on current macOS, so Paseo quits cleanly but relaunches the old bundle. Electron 44 wakes ShipIt through its XPC service.

Include updater lifecycle events and ShipIt state in app diagnostics so future handoff failures identify the current version, target version, cache paths, and installer output.

* fix(desktop): harden updater diagnostics

Keep each ShipIt file's evidence available when another read fails, carry the service-selected version into updater lifecycle logs, and make clean workspace installs resolve the Electron runtime used by desktop tests.

* refactor(desktop): name updater install options

* refactor(desktop): name updater log payloads

* refactor(desktop): name clipboard payload

* fix(desktop): surface updater lookup failures

* test(desktop): await guest focus transition

* fix(desktop): guard macOS update compatibility

* test(release): validate desktop manifests before publish

* test(desktop): await populated daemon pid file
2026-09-04 22:17:39 +02:00
Mohamed Boudra 35d2457d83 Let plugins provide coding agents (#4314)
Allow trusted local plugins to register complete coding-agent providers through the existing agent lifecycle. Includes direct and ACP implementations, SVG provider icons, custom timeline items, runnable examples, and public authoring documentation.

Closes #3547
Closes #3556
2026-09-04 19:56:57 +02:00
Mohamed Boudra bb676ef086 Smooth mobile keyboard transitions (#4275)
* perf(app): smooth mobile keyboard transitions

Animating dock padding forced Fabric and Yoga to relayout the chat tree on every keyboard frame, producing visible stepping and React list churn. Keep the surface full-height and move it as one translated unit, with scroll range and portal measurements updated only after keyboard motion settles.\n\niOS keeps its native keyboard animation driver behind the same component boundary because its Reanimated signal reports the endpoint at animation start.

* fix(app): isolate native keyboard implementation
2026-09-03 20:27:19 +02:00
Mohamed Boudra 53c9607479 Control Paseo tools per provider (#4277)
Add backend-only exact-provider controls for the Paseo tool catalog across native and MCP-backed agents, including persisted configuration, session snapshots, public documentation, and regression coverage.\n\nCo-authored-by: Matt Cowger <matt@cowger.us>
2026-09-03 20:10:47 +02:00
Mohamed Boudra 25defbafb4 Make plugin upgrade failures actionable (#4265)
* fix(plugins): clarify upgrade diagnostics

Keep plugin inspection network-free and consolidate runtime, source, and installed revision details under plugin ls. Legacy entry failures now explain the required v0.8 migration in user-facing language.

* test(cli): align hidden plugin status command
2026-09-03 13:22:21 +02:00
Mohamed Boudra 20ecdee72d docs(plugins): version breaking API guides (#4245)
Keep stable v0.7 guidance available while the client-entry layout is previewed for v0.8. Existing reference and migration URLs redirect to the release that owns their content.
2026-09-02 23:45:23 +02:00
Mohamed Boudra a835136854 Let CLI host selection work globally (#4238)
* feat(cli): accept host as a global option

Keep the command-local position for compatibility while letting users place one daemon target before the command and reuse it while changing verbs. Local daemon lifecycle commands continue to operate locally.

* fix(cli): preserve project host resolution boundary

Project creation already handled PASEO_HOST directly. Avoid routing that established behavior through a newly exported client helper so its isolated command tests keep their existing dependency boundary.

* test(cli): allow scaffold typecheck under CI load

* test(cli): provide remote cwd in schedule e2e

* docs(cli): teach only global host syntax
2026-09-02 22:53:55 +02:00
Mohamed Boudra 7178583612 Stop Settings navigation from retaining closed views (#4228)
* fix(desktop): stop retaining closed Settings views

Settings rotations left detached detail panes reachable from the web style registry's strong element sets. Backport the upstream weak cleanup design and cover the real Electron bundle with a forced-GC regression.\n\nKeep the established sibling-route topology; compact Back relies on route-name identity.

* test(app): synchronize Mermaid completion layout assertion

The streaming acceptance test can observe the intentional completion remount between visibility and layout sampling. Consult the existing completion promise around that measurement so the transition is not reported as diagram loss.

* test(app): isolate worktree restart from provider startup
2026-09-02 21:27:30 +02:00
Mohamed Boudra f75dff2322 Require explicit setup for fork pull requests (#4215)
* feat(workspaces): gate fork repository automation

Cross-repository change requests can execute contributor-controlled package hooks even when the setup command comes from the base repository. Persist the checkout provenance and require one explicit workspace-level setup action before repository automation runs.

* fix(workspaces): clarify blocked script errors

* fix(app): keep long toasts readable

* test(server): expect fork repository provenance

* test(server): make setup marker portable

* test(app): retry transient sidebar layout
2026-09-02 20:50:22 +02:00
Mohamed Boudra 53d824a320 feat(plugins): split client and server plugin entries (#4206)
* feat(plugins): phase 1 split runtime entries after green gate

The compiler now builds explicit client and server entries, so runtime boundaries are source-owned instead of registration-name filtering. Compiler and runtime tests prove the entry split, directory and suffix boundaries, client Node import errors, migration failure, and client-only operation without a subprocess.

* feat(plugins): phase 2 run client entries after green gate

Explicit client and server contexts replace the mixed plugin context. The app runner owns every client registration and its idempotent removal, including late contributions and composer pills; focused contribution tests prove the removal contract, and all five migrated examples reached running on the isolated worktree daemon.

* feat(cli): phase 3 scaffold runtime split after green gate

The generated project demonstrates the required shared RPC contract, server handler, client surface, and sidebar wiring. The scaffold test and an isolated init, typecheck, install, and running check prove the phase acceptance path.

* docs(plugins): phase 4 publish migration after green gate

Gate: current docs and the paseo-plugin skill describe only explicit client/server entries. The standalone migration guide maps every former registration, and migration-doc.test.ts proves every client add* method remains represented.

* fixup! feat(plugins): phase 1 split runtime entries after green gate

Gate: compiler 13, runtime 24, typecheck, lint, and format passed. The dependency fixture proved node_modules/client was incorrectly treated as a plugin boundary.

* fixup! feat(plugins): phase 2 run client entries after green gate

Gate: client runtime and registry tests, typecheck, lint, format

* fixup! docs(plugins): phase 4 publish migration after green gate

Gate: migration docs test, paragraph audit, typecheck, lint, format

* fixup! feat(plugins): phase 1 split runtime entries after green gate

Gate: compiler organization tests, typecheck, lint, targeted format

* fixup! feat(plugins): phase 2 run client entries after green gate

Gate: shared SDK tests, runtime tests, typecheck, lint, targeted format

* fixup! feat(cli): phase 3 scaffold runtime split after green gate

* fixup! docs(plugins): phase 4 publish migration after green gate

* fixup! feat(plugins): phase 1 split runtime entries after green gate

* docs(plugins): rewrite public plugin docs for runtime entries and mobile guardrails

* fixup! feat(cli): phase 3 scaffold runtime split after green gate

The scaffold now keeps DOM globals out of the program and declares only window.open inside client/web.ts. The scaffold test invokes tsc in a fresh process, proves the generated project passes, and proves a stray document access fails.

* fixup! docs(plugins): phase 4 publish migration after green gate

The internal guide and plugin skill now forbid both the DOM lib and triple-slash DOM references. They direct web adapters to declare only the globals used by client/web.ts.

* fixup! feat(plugins): phase 1 split runtime entries after green gate

Removing the obsolete Babel parser changes the locked npm dependency graph. The macOS Nix desktop gate reported the new fixed-output hash, which this commit records.

* fixup! feat(plugins): phase 1 split runtime entries after green gate

Reject relative imports that escape the plugin root while continuing to skip resolved node_modules internals. The compiler regression test proves the escaped import is rejected and the dependency-internal fixture remains accepted.

* fixup! feat(plugins): phase 1 split runtime entries after green gate

Classify absolute imports and reject plugin-authored paths that escape into node_modules. Dependency internals remain exempt based on their importer path. Red-first compiler regressions cover both bypasses, and the existing dependency fixture remains green.

* fixup! feat(plugins): phase 1 split runtime entries after green gate

Classify canonical esbuild resolution results so dependency-relative and symlink imports cannot escape client/server boundaries. The two compiler regressions failed before the fix and pass afterward.

* test(ci): synchronize flaky state transitions

Wait for repository watcher registration before emitting buffered ref events, let sidebar order polling retry unlaid-out rows, and wait for the inactive browser parking state before screenshot capture. These changes directly address the three observed CI failures; the affected server, Playwright, and desktop browser tests pass locally.

* test(ci): synchronize Mermaid completion layout assertion

The Playwright streaming acceptance test exposed a completion remount between visibility and layout sampling. Check the existing completion promise around the measurement so that transition is not reported as diagram loss.

* fixup! feat(plugins): phase 1 split runtime entries after green gate

Resolve bare package imports before boundary classification so symlinked dependency entries cannot expose server modules to the client bundle. The focused regression proves the bypass and the compiler file passes 20/20.

* fixup! feat(plugins): phase 1 split runtime entries after green gate

Allow canonical paths only within a matching linked package root while preserving runtime and containment checks for imports that leave it. The linked-dependency regression fails before the fix and compiler tests pass 21/21 afterward.

* fixup! feat(plugins): phase 1 split runtime entries after green gate

Reject matching package manifests that contain the plugin or live inside it, so linked-dependency roots cannot exempt plugin or workspace files. The ancestor-manifest regression fails before the fix and compiler tests pass 22/22 afterward.

* fixup! feat(plugins): phase 1 split runtime entries after green gate

Validate plugin-local lexical boundaries before canonical linked-root exemptions and require remembered-root imports to originate inside that root. The linked-root bypass regression fails before the fix and compiler tests pass 23/23 afterward.
2026-09-02 19:11:45 +02:00
Mohamed Boudra e34aea206e feat(plugins): add live timeline rows and client slash commands
Plugins can transform live timeline source items at render time, append durable plugin rows from daemon handlers, and register client-only slash commands in the composer.

Related to #3940 and #3952.
2026-09-02 13:12:09 +02:00
Mohamed Boudra 49784fac15 Keep Changes and working diff comparisons in sync (#4199)
* fix(app): keep Changes comparison and diff in sync

Own the working comparison at the workspace checkout so the Changes tree and adjacent working diff share it. Immutable commit diffs remain scoped to their commit SHA.

* docs(app): align working diff ownership notes
2026-09-02 12:38:16 +02:00
Mohamed Boudra de8535c38b Customize top-level sidebar items (#4203)
* feat(app): customize top-level sidebar items

Let users reorder and hide built-in and plugin sidebar rows from Appearance settings while keeping the preference device-local. Add Search as a first-class row and standardize section explanations as header info tooltips.

* fix(app): preserve consecutive sidebar preference edits

Derive each sidebar change from the latest cached settings and retain unavailable plugin slots while editing the visible list. Keep E2E interaction selectors tied to accessible control names.

* test(app): isolate provider settings unit boundary

Keep the legacy provider-section test focused on provider behavior now that its shared section shell can render the settings info control.
2026-09-02 11:42:39 +02:00
Mohamed Boudra d67a6f5f6c fix(release): keep releases draft until manifests are ready (#4201)
Create tag-triggered GitHub releases as drafts and publish them only after the desktop updater manifests are complete, stamped, and uploaded. Preserve beta prerelease semantics and safe retry behavior.\n\nCloses #4183
2026-09-02 11:29:41 +02:00
Mohamed Boudra 8dd4da6ee0 Keep mobile streaming and panel motion stable under JS stalls (#4190)
* fix(app): activate mobile panels after motion settles

Gesture previews were publishing React presentation state and activating retained content before the native motion finished. Keep transient motion on the UI thread and publish the active panel only from the accepted animation completion.

* perf(app): re-render only changed history rows

Every coalesced stream tick re-rendered all mounted history rows because the inverted FlatList recreates each cell with a new index and ref. Keep layout item identity for unchanged rows and memoize the row on it, and resolve tool-call groups through a stable event so the render callbacks stop churning.

* perf(app): count replica row bytes once

Budget accounting measured every stored row of a touched host on each persist through the Buffer polyfill. Cache the UTF-8 length per immutable row and count without materialising bytes.

* fix(app): settle mobile panels on position

Activity now follows the UI-thread position reaching the canonical anchor instead of an animation completion callback. A successful gesture keeps its finishing motion and the matching command adopts it; settlement and command acceptance may arrive in either order.

* fix(app): keep settled panel props across JS stalls

Turn off Reanimated's FORCE_REACT_RENDER_FOR_SETTLED_ANIMATIONS. Its settled-props collector drops entries older than two seconds before React receives them, so a JS stall across a settle left the overlay display and backdrop opacity reverted on the next commit while the store held the new panel.

* fix(app): reconcile hidden keyboard end on iOS

Only a hidden end event resets the keyboard shift. A late visible end no longer resurrects a keyboard that already dismissed.

* fix(app): focus the replacement input through autoFocus after clearing

Clearing swaps the native input for a fresh instance. Focusing the doomed instance asked Android for the keyboard and then tore the focused view down, which cancelled the show; a JS focus command sent alongside the remount reached a view that was not attached yet and the IME ignored it. Focus and blur requested while the replacement is pending now decide the replacement's autoFocus, which native applies once the view is attached.

* fix(app): revise history rows in every viewport

The history row memo boundary bails out until its item identity changes, but only the native viewport cloned rows flagged by historyRowRevision. On web and desktop a history host whose tool-call group kept updating from the live head rendered stale. Move the revision into useRevisedHistoryRows and run both viewports' history through it. Regression test renders the web strategy with a memoized row and asserts only the revised host re-renders.
2026-09-02 00:52:44 +02:00
JunsandMohamed Boudra 95575ad05a fix(omp): honor configured timeout while waiting for ready (#4143)
* fix(omp): honor configured timeout while waiting for ready

* fix(omp): increase ready timeout to 20 seconds

* docs: keep OMP timeout policy in one place

---------

Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
2026-09-01 17:19:56 +02:00
Mohamed Boudra 07125d2c02 Let Git plugins prepare themselves during installation (#4158)
* feat(plugins): support prepared Git installations

Let Git plugins declare explicit preparation commands without making package installation the default. Keep installation transactional, make plugin trust explicit, and use one canonical source reference for monorepos.

* fix(plugins): parse Windows source references
2026-09-01 16:12:23 +02:00
Matt Cowgerandpaseo-bot[bot] ecec33265e feat(pi): add active-turn steering via native steer RPC (#3752)
* feat(pi): add active-turn steering via native steer RPC

* fix(pi): clear queued steering before interrupt

---------

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-08-31 21:10:27 +02:00
Mohamed Boudra 4a3e6dea63 Increase mobile content text to 16px (#4111)
Keep mobile interface chrome at 15px while defaulting readable content to 16px. Migrate existing mobile 15px content preferences once while preserving later explicit choices.
2026-08-31 11:58:42 +02:00
Mohamed Boudra adf80a9fe0 Keep Hub daemon access explicit (#4088)
* feat(hub): make daemon authority explicit

Connecting a daemon establishes presence without granting execution. Hub authority now uses semantic session permissions, with workflow execution granted explicitly and inspectable through the normal session protocol.

Attention frames remain part of the existing agent and terminal subscriptions, keeping session output solicited.

* test(server): match sentence-case tool labels
2026-08-30 22:46:24 +02:00
Mohamed Boudra b1050d9bed feat(cli): simplify Hub login and export triggers (#4050) 2026-08-30 14:11:19 +02:00
Mohamed Boudra 5e561f8a23 fix(android): release communication route after dictation (#4069)
Stopping capture abandoned audio focus but left Android's communication mode and selected device owned by Paseo, which could keep Bluetooth audio on its narrow-band call route without an active microphone. Release and reacquire the complete route with the audio session, and prevent idle device callbacks from restoring it.
2026-08-30 11:42:29 +02:00
Mohamed Boudra 63587a9c03 feat(server): establish semantic session permissions (#3981)
Keep trusted-client and Hub behavior stable while replacing RPC-name grants with a semantic authorization boundary. This establishes the operation inventory needed for future principal, pairing, and resource-scoped access work.
2026-08-29 22:40:20 +02:00
Mohamed Boudra 650f3ca7f6 Reuse OpenCode helpers across ordinary agent sessions (#4009)
* fix(opencode): reuse servers across agent sessions

Paseo's always-present per-agent environment forced every OpenCode session onto a dedicated helper, multiplying cold starts and memory use. Route ordinary sessions through one shared helper while a daemon-owned session bridge preserves exact environment and caller-scoped tools; keep custom process environment and MCP configuration isolated.

* fix(build): bundle the agent bridge from existing dependencies

The helper package duplicated Zod and changed the fixed-output desktop dependency graph even though its tool wrapper was identity-only. Use the server's existing Zod runtime directly so packaged daemons can materialize the bridge without extra traced dependencies.

* refactor(server): isolate provider runtime composition

Keep provider-specific lifecycle and tool-catalog wiring behind an agent-owned runtime boundary so the generic daemon bootstrap remains provider-agnostic. The runtime now owns bridge startup, snapshot injection, and idempotent cleanup.

* fix(desktop): prebundle the agent bridge plugin

Packaged daemons run from an application archive where esbuild cannot spawn its binary. Produce the self-contained plugin during the server build and make compiled runtimes read that artifact; source-mode tests retain a gated compiler fallback.
2026-08-29 22:08:03 +02:00
Omer Cohenandpaseo-bot[bot] 1d4c3a2722 feat(plugin): add host navigation capabilities for plugin surfaces (#3901)
* feat(plugin): add optional agent navigation capability

* feat(plugin): extend host navigation capability

* fix(plugin): preserve navigation tests after sdk rebase

* fix(plugin): scope host navigation contracts

---------

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-08-29 21:33:09 +02:00
Mohamed Boudra 6c813d1a91 fix(app): keep chat synchronized with keyboard (#4044)
* fix(app): keep chat synchronized with keyboard

Dock the complete chat surface with worklet-driven layout padding so visual and native touch geometry move together. Reset cleared multiline native inputs and keep autocomplete portals anchored to the docked composer.

* fix(android): tolerate detached composer inputs

Return the nullable base input connection during IME restart instead of force-unwrapping it after the composer has blurred or unmounted.
2026-08-29 21:27:41 +02:00
Mohamed Boudra 463415ae84 fix(providers): tolerate slow Pi and OMP RPC startup (#4008)
MCP and extension initialization can keep provider control-plane requests pending beyond 30 seconds even when the response will arrive. Use a configurable 60-second provider default and include the active RPC phase in timeout errors.
2026-08-29 00:00:41 +02:00
667664847d Connect to remote daemons over SSH (#3989)
Add transport-only SSH connectivity for the CLI and Electron desktop through the user's OpenSSH configuration. Remote installation and daemon lifecycle remain explicit, separate operations.

Preserve actionable SSH failure details when the proxy socket closes before the SSH child exits.

Closes #3949

Co-authored-by: James Strain <jstrain@nvidia.com>
Co-authored-by: Reid Levesque <reidlevesque@users.noreply.github.com>
2026-08-28 16:32:12 +02:00
Mohamed Boudra deb846eed6 Let plugins use Paseo modals, icons, and toasts (#3967)
* feat(plugins): add React Native UI primitives

Give client plugins host-owned adaptive UI without exposing app internals. Preserve plugin runtime contexts when modal content moves through the compact portal host.

* docs(plugins): clarify host UI reference

* refactor(plugins): harden host UI boundary

Replace mocked pass-through coverage with a real browser plugin journey, keep host runtime ownership inside the evaluator, preserve toast context across compact portals, and expose modal content as a compound component.

* fix(plugins): defer native UI presentation runtime

Loading the plugin evaluator initialized the modal and toast presentation stacks even when no plugin requested host UI. Keep the capability stable while delaying platform-heavy presentation code until Modal.Content renders.

* refactor(plugins): move modal metadata to root

Keep Modal.Content body-only while the top-level Modal owns the host-rendered title and leading icon. This leaves presentation metadata stable as the compound API gains future regions.
2026-08-28 11:43:30 +02:00
Desmond ChaiandMohamed Boudra a1ed5a8bad Stop PR status polling from rate-limiting your entire GitHub account (#3825)
* Batch GitHub PR status polls into aliased GraphQL requests

The PR status poller ran one `gh pr view` (GraphQL-backed) plus a
per-PR facts query for every workspace on its own timer, so cost
scaled linearly with workspace count and exhausted the 5,000 pts/hour
GraphQL quota machine-wide past ~50 workspaces (#3587, #2470).

Replace the per-target timers with a global scheduler that snaps poll
targets to a shared 5s grid and flushes all due targets together:

- One aliased discovery query per batch of up to 25 targets (grouped
  by GH host) resolves PR identity, state, mergeability, and the merge
  facts that previously required a second GraphQL call per PR.
- A second aliased query fetches statusCheckRollup contexts only for
  the PRs that matched. Checks for merged/closed PRs are frozen and
  cached by repo#number@headOid, so idle workspaces settle to the
  discovery query alone.
- A failed batch backs off every target in it with one request spent;
  healthy aliases are recovered from the body gh still prints on
  stdout when a single alias errors (ForgeCommandError now carries
  stdout for this).
- Targets whose origin slug/host is still resolving, and fork repos
  whose PR lives in the parent, fall back to the legacy per-target
  path for that cycle. Unowned lookups filter out other forks' PRs
  that share a branch name.

Fixes #3587. Addresses the API budget in #2470.

* fix(server): reserve the shared GitHub polling budget

---------

Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
2026-08-28 11:29:34 +02:00
Mohamed Boudra fe803f6e70 Let plugins contribute contextual composer pills (#3956)
* feat(plugin): allow composer pill contributions

Keep pill presentation host-owned while plugin components render contextual content. Pill callbacks reuse the selected host's API, RPC, surface, and registered-panel navigation capabilities without exposing router or workspace layout internals.

* fix(plugin): place composer pills in track bar

* fix(plugin): make composer pills client-owned
2026-08-28 16:02:00 +08:00
Mohamed Boudra a8734a9724 Update project licensing (#3944) 2026-08-27 14:25:31 +02:00
Mohamed Boudra cda441d3b2 fix(app): prevent composer height flash after settings (#3943)
Retained workspace panels collapse to zero width while Settings is visible. Treat that geometry as an absent surface so hidden measurements cannot overwrite the last valid composer height before reveal.
2026-08-27 13:58:05 +02:00
Omer Cohen 8e0af11b66 feat(plugin): add host-rendered Icon component (#3903) 2026-08-27 10:50:20 +00:00
Mohamed Boudra 7ae5133ed2 feat(plugins): let plugins transform and render timeline items (#3940)
* feat(plugins): add timeline item contributions

Keep canonical daemon history unchanged while plugins project and render custom timeline items in clients. Live matches refresh authoritative projected history before replacement so lifecycle deltas stay collapsed.

* fix(nix): update npm dependency hash

The plugin SDK lockfile change invalidated the fixed-output npm dependency derivation. Use the hash calculated by the macOS Nix build for the current lockfile.
2026-08-27 11:40:17 +02:00
PMandpaseo-bot[bot] b0ce40804d fix(acp): enable terminal client capability by default (#3910)
* fix(acp): enable terminal client capability by default (#3812)

* test(acp): remove non-asserting Kimi coverage

---------

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-08-27 08:10:25 +00:00
Omer Cohen 657152c47a feat(client): expose project list in public SDK (#3899) 2026-08-27 07:54:20 +00:00
Mohamed Boudra ecfb77b014 feat(plugins): install and update Git sources (#3920)
Make every trusted Git repository directly distributable without introducing a registry or package manager. Managed checkouts retain their resolved commit, track branches explicitly, and stage validation before activation so failed updates restore the running version.
2026-08-27 15:24:01 +08:00
Mohamed Boudra 0ad69d3eb0 fix(app): paint conversations immediately after restart (#3907)
* fix(app): paint cached conversations before reconnect

Cold startup restored every saved host before publishing any session, so a valid cached chat was blocked behind unrelated directory validation and network-only readiness. Directory and timeline owners now resolve demand through typed storage and authoritative reconciliation while consumers remain source-agnostic.

* fix(app): stabilize demand-driven cache restore

Create host projections before network availability, route cached workspace and timeline preparation through their owners, and coalesce directory reconciliation per online connection. Update browser cache fixtures for per-agent timeline rows.

* fix(app): resume cached timeline through owner

* fix(app): surface timeline owner load errors
2026-08-26 22:55:48 +02:00