Commit Graph
11 Commits
Author SHA1 Message Date
Callum WongandMohamed Boudra db303be3c2 fix(nix): ship resolved daemon dependencies and working terminals (#5523)
* fix(nix): ship @getpaseo/server's main export in the desktop closure

The desktop's runtime-paths.js locates the server package root with
require.resolve("@getpaseo/server"), which resolves through the exports
map to dist/server/server/exports.js. The desktop never loads that file,
so nft doesn't trace it, and the Linux Nix desktop build fails to start
the daemon with MODULE_NOT_FOUND.

* fix(nix): retain the server resolution anchor for CLI and desktop

Run the existing Nix daemon smoke through the built CLI so package-root resolution is exercised before readiness and HTTP checks.

Co-authored-by: Callum Wong <mail@callumwong.com>

* fix(nix): ship complete terminal runtimes

Resolve runtime dependency edges at their importing modules so package links and exports survive closure tracing regardless of npm hoisting. Use the native loader's selected files and verify terminal commands and hook CLI execution through the built package.

Co-authored-by: Callum Wong <mail@callumwong.com>

* test(desktop): make packaged CLI path expectations portable

---------

Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
2026-10-05 19:25:48 +01:00
paseo-bot[bot] ed87679c67 fix(nix): ship the OpenCode v2 bridge plugin in the daemon closure (#5988)
The Nix package copies only what scripts/trace-daemon.mjs lists. The list
named the v1 bridge bundle but not opencode/v2/bridge-plugin.bundle.mjs,
so creating an OpenCode v2 agent from the Nix package failed with
"Bundled OpenCode bridge plugin artifact is missing".

List every bridge bundle under opencode/, and add a dist test that
installs the traced closure the way nix/package.nix does and loads the
bridge plugin for each OpenCode version from it.

Closes #5926

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-03 23:16:11 +01:00
Mohamed Boudra 792715e762 feat(usage): usage sources as built-in plugins, following the session's account (#5465)
* feat(server): run internal plugins in-process through the plugin runtime

* fix(server): harden internal plugin startup and boundary checks

* feat(usage): add plugin usage sources and Codex discovery

* fix(usage): share SDK helpers and bound source cache

* feat(usage): migrate usage fetchers to plugin sources

Serve the legacy usage RPC from discovered source reports so older apps retain the same host usage list while new clients use the source registry. Keep credential reads and normalization inside each source.

* refactor(usage): shape sources as fetch functions

Keep the plugin usage API limited to stable report and presentation helpers. Source-local parsers and timeout handling preserve credential and response parity while the cases move alongside each source.

* feat(usage): resolve reports from active session accounts

Resolve source inputs at fetch time so model and credential changes select the account each session spends. Keep the legacy discovered-account RPC for existing clients. Sync OpenCode model events outside foreground turns so usage follows model switches.

* fix usage source discovery and session report parity

* test adapter usage references through daemon RPC

* name usage reference contract across server

* refactor(usage): own usage RPCs and validate session auth

* feat(omp): resolve session usage from active OAuth credential

* fix(omp): match usage source input and valid credential fallback

* test(omp): use upstream credential database schema

* test(omp): verify live session usage references

* fix(usage): declare YAML parser and consolidate credential validation

* feat(app): show usage sources in the composer and a Usage screen

Replace the provider-matched usage in the context ring tooltip with a
composer pill driven by agent.get_usage_report, add a sidebar Usage
screen over usage.list_reports grouped by host, and move the host
settings Usage page to usage.list_reports. Hosts without
features.usageSources show an update message. Source icons come from
the report's catalog SVG. The app no longer calls provider.usage.list.

* fix(usage): declare the Paseo requirement on internal usage-source plugins

A manifest without requirements.paseo targets Paseo before 0.8, so the daemon
refused to start eight of the nine usage sources.

* fix(app): keep host connection statuses live under the React Compiler

The hook read a store version only as a memo trigger (void version); the
compiler dropped it, so pages that mounted before a host came online kept
showing it as connecting.

* fix(app): place the context ring slot before the usage pill

The ring reserves its slot before it has data. With the pill first, the empty
slot sat between the pill and the mic; now it falls in the flexible space.

* refactor(app): extract the settings page layout into PageLayout

Desktop puts the title in the page above a centered column; compact moves it
into a back header. Settings renders the same pixels through it.

* feat(app): lay out the Usage screen like a settings page

The title moves from the header bar into the page on desktop; compact gets the
settings back header, which returns home when the screen was opened by URL.

* refactor(app): drop the unused actions slot from PageLayout

* test(plugin): classify the usage source SDK entry

* fix(usage): preserve platform test contracts

* fix(settings): preserve page title test contract

* feat(usage): identify and cache reports by account ID

Keep report identity stable across input routes and token rotation, and make selective refresh operate on known account reports.

* feat(app): read usage reports through report IDs

Share report data between agent pills and host views while preserving the existing popover interaction for the next UI phase.

* fix(usage): keep account identity aligned with credentials

Read labels from local token claims and use one credential lookup for usage fetches and account identification. Bound cached profile identities across token rotation.

* fix(usage): isolate failure IDs and prune expired reports

Failure reports live outside the account-key namespace, and cache writes discard entries past the five-minute TTL.

* refactor(app): share the compact time-ago prose formatter

Move the tab tooltip's "3m" -> "3m ago" wording into utils/time so the
usage card can reuse it.

* feat(usage): show when each report was fetched

The usage card reads fetchedAt as "Updated 3m ago": a tooltip on the
card header where hover exists (web, desktop), printed in the card
footer on native and compact. Shared by the pill popover and the Usage
screen.

* feat(usage): open the pill popover from cache and refresh on demand

Opening the popover no longer forces a vendor fetch; it shows the cached
report. A Refresh control force-refreshes only this report
(usage.list_reports with its single ID and forceRefresh), shows
Refreshing... while it runs, keeps the previous report visible, and says
"Unable to refresh usage" if the request fails.

* feat(app): let ToolbarButton show a tooltip other than its label

An icon action can now say a status in its tooltip ("Updated 3m ago")
while keeping its label for accessibility.

* feat(usage): refresh a report from its card header

Refresh is an icon button at the right edge of every usage card header,
in the pill popover and on the Usage screen. It force-refreshes only that
report, writes the result to the report's cache and its host list, shows
a spinner and disables itself while pending, and prints "Unable to
refresh usage" in the card on failure. Its tooltip carries the
freshness; without hover the freshness stays in the card footer. The
status indicator sits just left of the button, and the popover's
separate refresh row is gone.

* fix(server): include internal plugin assets in built output

* feat(server): built-in plugins in /plugins (#5544)

* feat(server): load compiled built-in Codex plugin

* test(server): guard built-in plugin loading and installs

* test(server): verify built-in plugins from dist in CI

* refactor(server): migrate remaining usage sources to built-in plugins

* test(server): guard all packaged usage source registrations

* docs: describe usage validation across plugin hosts

* test(ci): include built-in plugins in routing contract

* test(server): import moved Codex usage source

* fix(server): retain ACP updates received with session creation
2026-09-28 16:36:34 +01: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
Mohamed Boudra 4108960709 Manage orchestration skills per host (#3451)
* feat(skills): manage orchestration skills per host

Agent skills execute on the daemon host, so their bundle, selection, and filesystem convergence must share that owner. Preserve the existing install semantics while letting every capable client manage the selected host and migrating the legacy desktop preference once.

* fix(client): keep skill management internal

Keep host skill management on the low-level daemon client used by the app. Do not expose daemon settings or the desktop-only compatibility migration through the shared Paseo API handed to plugins.

* fix(e2e): declare skills fixture dependencies

Use Playwright's required destructuring form for the test-scoped daemon sandbox fixture so CI can collect the real-host skills suite.

* test(skills): use native managed paths

Assert fixed skill targets relative to the daemon user's real home with platform-native path joining so the ownership contract holds on Windows and POSIX hosts.
2026-08-18 09:51:46 +02:00
Mohamed Boudra 48e65b407f Replace Parcel Watcher with Custom Watcher (#3107)
* fix(server): replace wedging file observation

Native watcher teardown could block the daemon main thread during workspace archive. Own recursive observation behind an awaited lifecycle boundary, retain an isolated comparison harness, and gate correctness, resources, and sustained CPU across platforms.

* test(server): accept root watcher evidence

Native recursive watchers may coalesce ignored descendant changes into a root event. Assert that ignored paths stay excluded while a nonignored sentinel proves delivery remains live.

* test(server): preserve watcher comparison evidence

Record Parcel delivery misses without weakening the production observer gate, and allow the Windows stress test to use its declared polling window.

* fix(server): reconcile native watcher omissions

Back macOS and Windows recursive watching with a bounded namespace inventory so coalesced create and delete events converge without unbounded rescans.

* test(server): compare worktree filesystem identity

Windows can return the same worktree through 8.3 and long path spellings. Preserve cardinality and branch checks while comparing the real path.

* perf(server): bound native inventory audits

Reduce full native inventory cadence while preserving a six-second convergence bound, and gate setup readiness and event-loop p99 against platform-appropriate budgets.

* build: refresh Nix npm dependency hash

* perf(server): scope native file reconciliation

* perf(server): defer native safety audits until quiet

* fix(server): move native safety deadline during audits

* perf(server): audit native inventories after settled churn

* fix(server): reconcile native root evidence promptly

* perf(server): deduplicate native audit scheduling

* perf(server): coalesce native event clusters

* perf(server): suppress fresh native change scans

* test(server): separate burst recovery from sustained churn

* test(server): stabilize observer performance gates

* perf(server): skip fresh native change scans

* fix(server): preserve nested native change audits

* perf(server): coalesce native repair scans

* fix(server): reconcile native directory moves promptly

* test(server): bound observer burst repair cost

* refactor(server): own file observer lifecycle

* build: refresh Nix npm dependency hash

* ci: fold observer coverage into server suite

* fix(server): await file observer shutdown
2026-08-10 13:43:48 +02:00
Mohamed Boudra 0a106dd35f Keep Git status and diffs current across platforms (#2775)
* fix(server): make Git observation cross-platform

Platform-specific watchers and forced full refreshes amplified Git processes and could miss nested changes. Share checkout and repository observation internally, scope final-state refreshes, and bound degraded polling so streamed summaries and diffs stay correct under bursts.

* fix(server): refresh Git worktree state on metadata changes

* fix(server): keep Git watcher runtime inputs current

* fix(server): normalize watcher runtime boundaries

* fix(server): reconcile Git observer topology

* test(server): report Git watcher event batches

* fix(server): close Git observation gaps

* chore(ci): remove temporary Git observation jobs
2026-08-02 12:20:20 +02:00
Ivan Malison b960594d44 fix(nix): shrink desktop runtime output (#2550)
Package only the traced desktop and daemon runtime graph, preserve required runtime entrypoints, and exclude the npm Electron distribution supplied by nixpkgs.
2026-08-01 01:37:18 +02:00
yhori 0c68b26a8b fix(nix): package local speech worker (#1587)
* fix(nix): package local speech worker

* fix(nix): reuse sherpa package helper

* fix(nix): patch sherpa-onnx prebuilt binaries for NixOS libstdc++

The prebuilt sherpa-onnx-linux-x64 .so files link against libstdc++.so.6
which is not on the NixOS library path. Add autoPatchelfHook to fix ELF
RPATHs and stdenv.cc.cc.lib to provide the C++ runtime, resolving the
"Failed to load model because protobuf parsing failed" SIGABRT at
speech worker startup.
2026-07-20 09:21:10 +00:00
Mohamed Boudra 53c14d9855 Extract client SDK package (#1052)
* Extract client SDK package

* Polish SDK client identity defaults

* Build client before dependent CI jobs

* Restore daemon client server export

* Extract protocol and client SDK packages

* Fix provider override schema validation

* Fix app test daemon client imports

* Simplify workspace build targets

* Fix CLI test server build bootstrap

* Run SDK package tests in CI

* Fix rebase package split drift

* Restore lockfile registry metadata

* Update SDK config test for prompt default

* Move terminal stream router test to client package

* Fix rebase drift for protocol imports

* Fix SDK agent capability fixture

* Restore legacy server client exports

* Fix server export compatibility test

* Advertise custom mode icon client capability

* Remove server daemon-client exports

* Format rebased mode control import

* Fix rebase drift for protocol imports

Files added by upstream PRs (#893, #1147, #1154) referenced the pre-split
shared/ paths that this branch moves into @getpaseo/protocol. Redirect
those imports to the protocol package so typecheck stays green after the
rebase.
2026-05-28 01:58:18 +08:00
Matan Bendix ShenhavandClaude Opus 4.7 e309d82b41 nix: shrink daemon install with @vercel/nft tracing (#966)
* nix: share npmDeps FOD between paseo and paseo-desktop

The daemon and desktop derivations share package-lock.json, so their
npmDeps FODs contain byte-identical content. But Nix names the FOD
store path with the consuming pname prefix, so paseo-<v>-npm-deps and
paseo-desktop-<v>-npm-deps resolve to different store paths despite
identical bytes. Building both runs prefetch-npm-deps twice in
parallel; on a clean store this downloads the entire registry
(~1-2 GB of tarballs) twice over the wire.

Wire paseo through as a callPackage arg of the desktop drv and
inherit (paseo) npmDeps. One FOD, one fetch, one store path.

Override path becomes paseo.override { npmDepsHash = "..."; } — the
desktop drv picks up the overridden npmDeps transitively. Downstream
flakes that previously did paseo-desktop.override { npmDepsHash }
need to either drop the desktop-side override (recommended) or pass
the overridden daemon through as paseo-desktop.override { paseo }.

* nix: trace daemon runtime closure with @vercel/nft

The daemon Nix installPhase used to `cp -a node_modules $out/lib/paseo/`,
shipping every package in the hoisted root — Expo, React Native, Metro,
Electron, ML stacks, ~1700 third-party deps the daemon never `require()`s
at runtime. Result: ~2.6 GB store path for a daemon whose actual runtime
closure is a tiny fraction of that.

Replace it with static module-graph tracing via @vercel/nft (the same
library Vercel and Next.js use for serverless bundling). The new
installPhase runs `node scripts/trace-daemon.mjs`, which:

1. Calls nodeFileTrace on three entry points — cli/dist/index.js,
   server/dist/scripts/supervisor-entrypoint.js, and the forked
   server/dist/server/terminal/terminal-worker-process.js. The worker
   needs to be a separate entry because nft does not follow fork()
   process boundaries.
2. Unions the trace result with an explicit list of non-JS runtime
   inputs nft does not detect: shell-integration assets read via
   readFileSync, the Silero VAD ONNX model loaded by the sherpa
   provider, .env.example, the CLI shebang script, and node-pty's
   compiled prebuilt binary for the host platform.
3. Ignores cross-platform native variants we explicitly do not ship
   (sherpa-onnx-*, @mariozechner/clipboard-*) and node-fetch's
   optional `encoding` peer.

installPhase consumes the file list, copies each entry into
$out/lib/paseo/ preserving its repo-relative path, and wraps two bin
entries (paseo, paseo-server) via makeWrapper.

Verified end-to-end:
- daemon $out drops from ~2.6 GB to ~131 MB (≈95% reduction)
- paseo --version, paseo --help work from the new $out
- paseo-server boots, HTTP server reaches "Server listening" within
  ~40 ms, no missing-module errors in the bootstrap log
- speech features degrade gracefully when sherpa-onnx-* / model files
  are absent (the documented behaviour for the Nix build, unchanged)

@vercel/nft added to root devDependencies (1.5.0); used only at
build time by the Nix derivation.

* fix(nix): gitignore result

* fix(nix): refresh npm deps hash post-rebase

The conflict resolution during rebase kept the trace-daemon hash, but
the merged package-lock.json combines upstream's lockfile updates with
the @vercel/nft addition, so the hash needed to be recomputed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 20:08:06 +08:00