Remove canceled durable agent records before evaluating receipt retry safety, and roll back a recreated checkout when restore expires. Verify cancellation at the registration boundary and drive journal deadlines with an injected clock.
Keep cancellation, serialized operations, and durable receipts in AgentRequests so Hub can release expired startup waiters without allowing a late launch or cleanup replay to overtake the next continuation.
Add a paseo.cafe link to the Plugins card on the landing page and a
section at the top of the related projects doc. The card link is accented
so it reads without hover; the card now takes a list of links instead of
one hardcoded link.
* perf(app): reduce avoidable work when opening large diffs
Large snapshots were recursively reconstructed for reference stability, while native scroll worklets captured complete file models. Preserve identity at the data producers and prepare text for the visible window without rebuilding unchanged files.
* test(app): await commit diff query completion without polling
* chore(app): remove profiling artifacts from the source tree
What's new opens an adaptive sheet — bottom sheet on compact, centred card on
desktop — that fetches CHANGELOG.md from the repository and renders it with the
app's own chrome. The desktop update callout, the sidebar help menu, and a new
row in Settings → About all open it; the sheet header links out to
paseo.sh/changelog.
The parser commits to two facts only: `##` starts a release and `###` starts a
section. Section titles are read from the document rather than matched against a
list, and everything under a section passes through verbatim to the Markdown
renderer, so a future callout, block quote, code fence or image needs no parser
change. Fences are tracked because a fenced sample is the one thing that can
fool a line scan.
The document is fetched rather than bundled because the app has to describe a
release that shipped after it was built, which is the update callout's whole
purpose. It goes straight to the repository rather than through a host: the
notes describe the app, and routing them through a daemon would make them
depend on which host happens to be connected. Nothing is fetched or parsed
until the sheet opens.
The latest release renders as soon as there is one and the rest of the first
page follows in a transition, so React slices that work around the opening
animation instead of committing hundreds of list items at once.
Restored tabs render before the terminal list arrives. Mark their titles as loading until metadata is available so they do not briefly display the generic terminal name.
* fix(app): preserve plugin provider icons in model buttons
Pass the selected host to the composer glyph so it resolves the same plugin SVG as the model picker. Require the nullable glyph host prop to catch omitted identity at compile time.
* test(app): isolate plugin icon regression setup
Restore unread attention on finished workspaces and preserve the reminder when leaving the current workspace. Cover desktop and compact read flows, and retain change-only file paths for deletion observation.
Co-authored-by: Edi Hasaj <34984294+edihasaj@users.noreply.github.com>
* fix(cli): initialize current Hub triggers
Hub init still authored and deployed project bundles after hosted configuration moved to organization triggers. Generate the self-contained trigger contract and keep project bundle deployment behind the existing --project path.
* fix(cli): harden Hub trigger setup
* docs(hub): align public setup guides with organization triggers
Move supported protocol capabilities into client defaults and make session traffic subscription-driven. Preserve timeline readiness and reconnect recovery across SDK, CLI, and plugin consumers.
ACP SDK extension dispatch can finish after a later response, letting vendor config notifications escape commit or rollback depending on pipe chunking. Consume synchronous vendor transforms at the stream boundary before forwarding later responses, and reproduce coalesced single and burst notifications through a real subprocess.
The ESM main-module guard compared import.meta.url with "file://" + process.argv[1],
which never matches on Windows (file://D:\a\... vs file:///D:/a/...). On the Windows
desktop release job, scripts/github-release.mjs therefore printed nothing and
gh release upload received an empty release lookup ("release not found"), leaving
v0.8.0-beta.1 without a Windows build. Compare resolved paths instead, shared by
every release script that runs as a CLI.
* fix(app): keep terminal keyboard focus stable
Clearing the terminal buffer remounted the shared native input, triggering an IME hide/show cycle. Keep text replacement in place and make the composer explicitly reset its editor to preserve multiline layout clearing.
* test(app): verify terminal keyboard continuity on Android
Replace the new JSDOM regression with a real Android harness. It detects focused native input replacement and IME hide/show requests through terminal toolbar controls, and fails with the previous remount behavior.
Accept plugin requirements against the runtime version or its stable core while preserving the legacy version boundary. Validate all example manifests, correct the ACP example metadata, and prepare plugin author documentation for the beta.
* fix(plugins): keep React out of the server plugin host
* fix(plugins): align SDK guidance and tests with runtime boundaries
* fix(plugin): loosen the react peer to ~19.1.0
The plugin SDK pins its react peer to exactly 19.1.0, and that pin is
what a downstream `npm i -g @getpaseo/cli` resolves against. So every
user ends up with react 19.1.0 in their global node_modules, where
corporate dependency scanners flag it: the CVE-2025-55182 advisory range
covers 19.1.0 even though the vulnerability itself lives in
react-server-dom-webpack/-parcel/-turbopack, none of which the CLI
installs. The user is then left hand-patching node_modules or
uninstalling Paseo.
Widening the peer to ~19.1.0 lets a downstream install pick the latest
19.1.x patch (19.1.9 today) while this repo stays on 19.1.0, which the
root override still pins.
Keeping the repo itself on 19.1.0 is deliberate. react-native 0.81.5
embeds a 19.1.0 Paper renderer that hard-throws "Incompatible React
versions" on any exact mismatch, and it is reachable from Fabric builds
too: RendererImplementation.js requires the Paper shim unconditionally
in findNodeHandle, unstable_batchedUpdates, sendAccessibilityEvent and
three other entry points, and react-native-gesture-handler re-exports
findNodeHandle. Bumping the app's react is therefore not safe until
react-native moves.
The published CLI tree contains no react-native, so downstream installs
are not subject to that constraint.
Supersedes the earlier 19.1.5/19.1.9 version-bump approach on this
branch, which would have broken the mobile app.
* Enforce example import ownership including client types
* Update Nix dependency hash for plugin peer metadata
* Group plugin APIs under client and server entry trees
* Resolve plugin type dependencies through declarations
* Validate declarations for implicit plugin type imports
* Preserve optional imports and validate declaration references
* Refresh Nix hash for plugin declaration resolver
* Canonicalize plugin paths consistently on Windows
* Normalize plugin ownership paths across resolver boundaries
---------
Co-authored-by: liujin0506 <liujin0506@qq.com>
Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
* fix(app): keep reconnect enabled while backgrounded
Visibility should flush cached state and accelerate foreground recovery without disabling normal reconnect backoff. Preserve healthy sockets and retry whenever the OS permits execution.
* test(app): clarify the background reconnect journey
* test(app): name reconnect screenshot helper inputs
* test(app): wait for stable content before delayed-history scroll
* chore(app): keep reconnect QA evidence in the PR body
* fix(app): show workspace plugin panels in Explorer menu
Let the host-filtered launch catalog identify toggleable views and their targets. Explorer uses the same identity comparison for every view while plugin panels remain workspace-scoped.
* test(app): express Explorer panel regression as user steps
* fix(plugin): loosen the react peer to ~19.1.0
The plugin SDK pins its react peer to exactly 19.1.0, and that pin is
what a downstream `npm i -g @getpaseo/cli` resolves against. So every
user ends up with react 19.1.0 in their global node_modules, where
corporate dependency scanners flag it: the CVE-2025-55182 advisory range
covers 19.1.0 even though the vulnerability itself lives in
react-server-dom-webpack/-parcel/-turbopack, none of which the CLI
installs. The user is then left hand-patching node_modules or
uninstalling Paseo.
Widening the peer to ~19.1.0 lets a downstream install pick the latest
19.1.x patch (19.1.9 today) while this repo stays on 19.1.0, which the
root override still pins.
Keeping the repo itself on 19.1.0 is deliberate. react-native 0.81.5
embeds a 19.1.0 Paper renderer that hard-throws "Incompatible React
versions" on any exact mismatch, and it is reachable from Fabric builds
too: RendererImplementation.js requires the Paper shim unconditionally
in findNodeHandle, unstable_batchedUpdates, sendAccessibilityEvent and
three other entry points, and react-native-gesture-handler re-exports
findNodeHandle. Bumping the app's react is therefore not safe until
react-native moves.
The published CLI tree contains no react-native, so downstream installs
are not subject to that constraint.
Supersedes the earlier 19.1.5/19.1.9 version-bump approach on this
branch, which would have broken the mobile app.
* Update Nix dependency hash for plugin peer metadata
---------
Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
* fix(protocol): keep 0.7.2 clients working with 0.8 hosts
Gate plugin timeline rows and blocked workspace setup statuses per client capability so app-store version lag does not make existing agents unloadable. Preserve canonical pagination and document the intended Hub provider-mode authority.
* test(protocol): clarify compatibility test preconditions
* fix(server): support OpenCode 2 in terminal activity plugin
OpenCode 2 rejects V1 hook-object plugins, so the installed
paseo-terminal-activity.js failed to load on every OpenCode 2
session. Ship one definition object that serves both generations:
OpenCode 2 loads id + setup() and ignores the 1.x server entrypoint,
OpenCode 1 loads the same object through server().
* fix(server): preserve terminal activity across plugin generations
* test(server): drain persistence before reload test cleanup
---------
Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
* Revert "Restore cached conversations before reconnecting (#4421)"
This reverts commit 1c51b52d07.
* fix(app): restore provider loading on native
* fix(app): preserve native navigators across appearance changes
Reapply the isolated appearance boundaries and native menu transform origin from #4421 so appearance hydration preserves native navigator and gesture host lifetimes.
* fix(app): retain cached baselines during live updates
Read the timeline concurrently with agent preparation and reconcile display-only cache rows beneath the live head using the existing reducer. Merge cached directory entries beneath live state while preserving the existing checkpoint race guard.
Supplying a list controls scroll-container ownership, not whether content can move the sheet. Preserve the shared expand-scroll-dismiss interaction for model selectors and plugin lists, with native gesture regressions and updated plugin guidance.
* 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
* 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.
* Settle autonomous Pi turns triggered by extensions
Treat Pi's agent lifecycle as authoritative for extension-triggered turns that do not have a Paseo provider turn ID. Keep locally handled extension commands immediate, but defer autonomous completion until agent_settled.
* Fail autonomous Pi turns on process exit
* Fix cancellation of autonomous Pi turns
* Synchronize Pi cancellation regressions with queue clearing
* Release Pi interruption state at its terminal boundary
---------
Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
* 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.
* 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
The startup override replaced the bundle icon with a flat PNG even in packaged builds. Limit the override to development so macOS retains the bundle icon appearance.
* 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.
* 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.
* 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
* 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
* 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.
* fix(server): filter empty ACP import sessions
ACP metadata probes can leave persisted sessions that later appear in import results. Replay available session history to exclude truly empty entries while retaining sessions whose history is unavailable, and close probe sessions before process teardown.
* fix(server): bound ACP session history loading
Keep import enrichment inside the provider listing deadline when session histories are inaccessible. Catalog abort cleanup now also waits briefly for an in-flight session creation so the resulting probe session can be closed.
* test(server): avoid wall-clock ACP assertion
Verify the history budget through the number of attempted protocol loads instead of elapsed process time, so scheduler delays cannot make the regression flaky.
* fix(server): allow slower ACP history loads
Give native session history more time to replay while retaining a shared enrichment budget below the provider listing deadline.
* fix(server): give ACP history replay enough time
Use the provider RPC timeout scale for native history loading, with a larger shared budget and provider-list deadline. Keep timeout coverage fast and deterministic with a controlled clock.
* fix(server): isolate generous ACP import deadlines
Keep the long listing deadline for the picker’s single-provider requests while preserving the short aggregate deadline for callers that fan out across providers. Restore deterministic coverage of unresolved history loads through fake timers and an injected clock boundary.
* fix(server): preserve ACP aggregate listings
* 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
A provider configuration edit invalidated every cached catalog and could turn healthy providers into false availability errors under the resulting probe burst. Preserve unchanged registry entries, clients, loads, and snapshots, and keep the submitted draft snapshot stable while creation is pending.
* 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