183 Commits
Author SHA1 Message Date
Mohamed Boudraandpaseo-bot[bot] acb3a8f207 Add Vercel Sandbox to related projects (#6708)
Co-authored-by: paseo-bot[bot] <paseo-bot[bot]@users.noreply.github.com>
2026-10-12 18:08:34 +07:00
Mohamed Boudra 6ec6633425 feat(cli): expose account usage reports (#6474) 2026-10-09 23:51:32 +01:00
0009a7e717 feat(workspaces): add background visibility (#5039)
* feat(server): let clients create internal agents

The daemon's own branch-name and commit-message generators run as
internal agents: never persisted, listed, flagged, announced, or seen by
plugin lifecycle hooks. Nothing outside the daemon could ask for one,
because the wire config schema strips `internal` and the agent.create
transform re-pins it. A plugin that runs a one-turn helper per event
therefore left an archived session in History every time.

Add an optional `internal` flag to `create_agent_request` (inherited by
`agent.create.request`), copy it onto the config in the session's create
path, and skip provider session persistence for it like the generators
do. The client SDK forwards the flag on both creation paths and gates it
once on `server_info.features.internalAgents`.

Two daemon paths assumed every agent is public and had to follow:
`resolveAgentIdentifier` now accepts a live agent by exact id, since the
id set it matched against came from listings that exclude internal
agents and left `wait_for_finish` answering "Agent not found"; and
archiving an internal agent now closes it without writing the record
that `registry.applySnapshot` used to leave behind, so `autoArchive`
does not accumulate hidden files on disk.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* fix(server): keep internal agents whole through failure, archive, and wait

Review follow-ups for internal agents:

- A create that fails after the runtime is registered now closes the
  internal agent before rethrowing, so a hidden runtime cannot outlive
  the failed request. Public agents keep today's behaviour.
- Archiving an internal agent cascades to attached children like any
  parent. cascadeArchiveChildren takes the parent record instead of
  reading it back from storage, where an internal agent never is.
- The archived snapshot and last message of an internal agent stay
  readable by exact id for ten minutes, so create-then-waitForFinish
  returns the finished turn whether the wait lands before or after an
  auto-archive. Storage plays that role for public agents.
- The internal-agent e2e scenarios live in the existing
  create_agent_request lifecycle suite rather than a new file.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* fix(server): cascade to live internal children and keep a failed internal create's worktree until it closes

Internal children never reach storage, so the parent archive cascade scans
live agents for them as well. A failed internal create now clears the
created id only after the runtime is archived, so worktree cleanup cannot
delete the directory under a runtime that would not close. Stored agent
payloads carry lastError, so a retained failed helper reports its error
through wait_for_finish instead of the generic message.

* feat(cli,mcp): expose internal agents and document --no-wait

paseo run gains --internal and create_agent gains internal, both forwarded
to the create request. --no-wait becomes the documented spelling for
returning immediately, matching paseo send; --background and --detach stay
as hidden aliases under COMPAT tags.

* test: follow the --no-wait rename and stub getRetiredInternalAgent

* feat: list internal agents on request and add internal workspaces

Internal agents stay hidden by default, but a caller can now ask for
them: `fetch_agents_request` takes `filter.includeInternal`, snapshots
carry `internal: true`, and `paseo ls --internal` shows them in an
INTERNAL column. The app never passes the flag.

Workspaces get the same flag. `workspace.create.request` with
`internal: true` persists a hidden workspace: listings, update
subscriptions, sync reads, empty-project counting, open-by-path, MCP
`list_workspaces`, and plugin workspace hooks all skip it unless the
caller opts in with `filter.includeInternal`. Every agent created inside
an internal workspace is internal and unpersisted; AgentManager applies
that from the workspace id before the plugin hook so creators cannot
opt out. Archive and shutdown enumerate internal agents so nothing
inside an internal workspace outlives it.

Surfaces: `paseo workspace create --internal`, `paseo workspace ls
--internal`, `paseo run --internal --new-workspace`, MCP
`create_workspace({ internal })`, SDK `workspaces.create({ internal })`
and `list({ filter: { includeInternal } })`. Clients gate on
`features.internalWorkspaces`.

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

* feat(workspaces): add background visibility with inherited creation defaults

* fix(cli): resolve workspace callers on the selected daemon

* test(workspaces): keep caller integration coverage in server suite

* test(cli): exercise workspace callers through CLI integration harness

* test(mcp): remove obsolete execution flags from browser fixtures

---------

Co-authored-by: marvin-ambrozio <marvin@gustavo.eng.br>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
2026-10-09 09:31:50 +01:00
Mohamed Boudra 8c096b5e33 docs: remove Linux setup detour from getting started (#6415) 2026-10-08 22:16:16 +01:00
Mohamed Boudra 2d55870490 docs(website): present Paseo as an agentic development environment (#6336) 2026-10-07 21:33:34 +01:00
Mohamed Boudra 56f4fca9e4 docs(workspaces): guide parallel development and review (#6294) 2026-10-07 11:40:18 +01:00
paseo-bot[bot] 28f7528588 docs: fix the Tailscale Serve command and log rotation defaults (#6284)
The web UI guide gave the pre-1.52 `tailscale serve https / <target>`
form, which current Tailscale rejects with "invalid number of
arguments". The configuration page said logs keep 2 files in total,
while the daemon keeps 3 rotated files next to the active one.

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-07 09:51:17 +02:00
Mohamed Boudra 2d85fe4e04 feat(plugins): declare display metadata in plugin manifests (#6263)
* feat(plugins): declare display metadata in plugin manifests

* style(website): format plugin page description

* fix(plugins): preserve default names and clarify registry follow-up

* test: fix stale plugin card selectors and terminal marker race
2026-10-06 23:18:24 +01:00
Mohamed Boudra a292b402cf Resolve local plugin directories in the CLI's working directory (#6239)
* fix(cli): resolve local plugin directories from the caller's cwd

Relative plugin sources were sent unchanged, so a daemon started elsewhere inspected the wrong directory. Resolve directory sources and expand the caller's home before sending, preserving subdirectory suffixes and managed source identifiers.

* fix(cli): preserve absolute plugin paths across host platforms

A remote daemon may use another operating system. Recognize absolute POSIX and Windows directory sources before resolving relative paths on the CLI host.
2026-10-06 17:31:57 +01:00
Mohamed Boudra 7fd469ae19 Enable plugin registry installs by default (#6224)
* feat(plugins): enable registry installs by default

* fix(plugins): explain explicit Git source for missing registry IDs

* fix(plugins): tailor missing registry guidance to installation

* test(app): sample footer geometry in one browser frame

* fix(plugins): make registry source resolution deterministic

Directory existence must not change the meaning of a registry identifier shared by CLI, RPC, and UI installs. Classify explicit host paths in the source parser and explain recovery from registry transport and revision-selection failures.

* fix(plugins): recognize dot and Windows directory sources

* test(cli): wait for readable daemon ownership before cancellation

The cancellation test raced PID-file creation against its first write and parsed empty JSON in CI. Use the public daemon-instance reader to wait for and capture the supervisor PID before asserting cancellation cleanup.

* test(app): expect missing directory install guidance
2026-10-06 16:52:02 +01:00
Mohamed Boudra 06bde1e57a Scaffold author overviews for plugin listings (#6226)
* feat(plugins): scaffold author listing overviews

* docs(plugins): refine the author overview contract

* docs(plugins): require repository overviews for registry listings

* docs(plugins): keep listing guidance focused on authors
2026-10-06 15:58:26 +01:00
Mohamed Boudra 4ede81e841 Open Usage as a modal over the current screen (#6216)
* Open Usage as a modal over the current screen

The sidebar Usage icon and summary now open Usage in the adaptive modal
(a dialog on wide layouts, a bottom sheet on compact ones) instead of
navigating to the /usage screen, so closing it leaves you where you were.
The /usage route and UsageScreen are removed.

* Reset Usage modal cards when the host changes; keep scroll test body linear
2026-10-06 12:54:09 +01:00
Mohamed Boudra 3e2d77723e fix(usage): scope Muse and agent logins, show every failed host login (#6156)
* fix(muse): show usage only for the agent account

Usage discovery ignored session scope and exposed all remembered accounts to unrelated agents. Resolve session accounts from their own launch environment while preserving global discovery.

* test(muse): own the usage scope regression in the plugin suite

* fix(usage): scope agent reports to their own logins

Account grouping also merged fetch inputs and cache entries across agent and host queries, hiding the agent login failure behind another harness. Preserve scoped login sets, collect every host failure with source-owned harness labels, and keep refresh results within their requesting view.

* test(usage): expect harness labels in discovered accounts
2026-10-05 18:41:54 +01:00
Mohamed Boudra 9760292650 fix(providers): launch plugin CLIs on Windows and tolerate Muse startup (#6151)
* fix(providers): launch plugin CLIs on Windows and tolerate Muse startup

Plugin providers bypassed the core Windows launcher and the plugin host exposed an empty server SDK module. Share the launcher through the SDK and bind it in the host. Give Muse initialization its own deadline because native startup traverses session history before answering MSP.

* fix(providers): terminate Windows launcher process trees

A command-script launcher leaves the CLI behind cmd.exe. Expose forced process-tree termination in the server SDK, use it for Muse and SDK ACP teardown, and bound Muse closing so inherited streams cannot leave callers waiting forever.

* test(muse): keep platform setup outside the teardown assertion

* refactor(plugin): expose process capabilities without quoting helpers

* fix(providers): close process trees on uncorrelated protocol errors
2026-10-05 17:10:02 +01:00
paseo-bot[bot]androyenheart 7b43f21940 fix(app): let Remote SSH connections authenticate to a password-protected daemon (#6081)
Co-authored-by: royenheart <royenheart@outlook.com>
2026-10-05 06:02:33 +02:00
Mohamed Boudra c062280429 Ship the plugin directory redesign and keep registry installs behind a daemon flag (#6080)
* website: plugin page design mockups (four directions, throwaway routes)

* website: final plugin page mockup (A directory, B browse frame, list cards, D detail)

* website: browse pages use a four-column card grid in the final plugin mockup

* feat(plugins): keep registry installs behind a daemon flag, off by default

Off restores the pre-registry behavior: bare owner/repo is GitHub shorthand and the
daemon never resolves or contacts a registry on install, update preview, or update.
Enable with pluginRegistryEnabled: true or PASEO_PLUGIN_REGISTRY_ENABLED=1.

* feat(website): ship the plugin directory, browse pages, and single-column detail

Directory: count, build/submit links, What's new, the nine categories, and Most installed
with a This week / This month / All time switch. Browse pages at /plugins/all and
/plugins/category/<slug> with a category sidebar, tabs, and a four-column grid; old
/plugins?category= links redirect. Install counts gain daily KV buckets kept 60 days.

* fix(website): keep a README's leading GitHub alert on the plugin page

* feat(website): search plugins from the directory and browse pages

Typing replaces the URL with /plugins/all?q=<term> (or the current category
with ?q=), which renders matching plugins on the server. Matching covers
name, description, ID, and author. Old /plugins?q= links redirect.

* fix(website): keep the directory's ranking window when searching
2026-10-04 20:38:39 +01:00
Mohamed Boudra 5eb4c8afad feat(usage): show each agent's own plan usage in its context window details (#5975)
* feat(usage): stream reports for live agent accounts

Resolve account scope from the running harness environment without invoking lifecycle hooks. Keep the client aggregate result while delivering report updates as each fetch settles; the app presentation follows separately.

* fix(usage): retain account scope for open agent sessions

Capture the launch environment once per session, independently of lazy child-process startup or exit. Use a session UUID for registry identity. Update remaining global discovery fixtures to the scoped SDK contract.

* test(usage): update browser fixtures for scoped report streams

* feat(usage): let a usage card show window rows without pins

UsageCard takes a required pinnable prop. When false, a window row is a
plain bar: no Pressable, hover highlight, or pin glyph. The settings
Usage list passes true.

* feat(usage): show the agent's usage in the context window popover

Reports stream into the query cache as each update arrives, for the
host list and for a new per-agent query keyed by agent. The context
window popover fetches its agent's reports while open and renders one
unpinnable card per report as it lands, a loading sentence before the
first, the request error as a sentence, and nothing on hosts without
usage reports.

* feat(usage): hide the Refresh button on popover usage cards

UsageCard takes a required refreshable prop. The popover passes false
because its content takes no pointer events, so the button could not
be pressed; the card then shows its freshness inline. The settings
Usage list keeps the button.

* feat(usage): make the sidebar Usage summary opt-in

The sidebar Usage item starts hidden on every layout, not only on
compact ones, so resolveSidebarNavItems drops its compact input. While
the summary is off, the Usage list renders window rows without pins;
saved pins stay in preferences and return when it is turned on. Specs
that read the summary now turn it on first.

* docs(glossary): describe the popover usage card and the opt-in sidebar summary

* fix(usage): show a popover request error without retrying

A daemon error for an agent's usage, such as an unknown agent, does not
heal on retry, and reopening the popover fetches again. Retrying held
the loading sentence for about seven seconds before the error.

* test(usage): cover agent usage in the context window popover

The usage fixture records agentId, streams reports held behind
promises, and can switch host support between reloads. The meter spec
walks loading, streaming, a report problem, a request error and a host
without usage reports, on desktop and compact in both themes.

* fix(usage): keep the plain context window tooltip on hosts without usage

The popover widened to fit usage cards on every host. Hosts that cannot
report usage now keep the tooltip's default padding and width, as
before, and mount no usage section.

* fix(usage): let a report's Refresh replace it in the agent's list too

Refresh wrote the refreshed report only into the host's list, so a card
rendered from an agent's list kept the old report. Both lists now sit
under one host key and Refresh replaces the report in each that holds it.

* feat(usage): open the context window details in a sheet on compact screens

Wide screens keep the tooltip. On compact screens pressing the meter opens
a content-sized bottom sheet titled Context window. Both render one
ContextWindowDetails body; only the sheet's usage cards have Refresh,
since the tooltip cannot be pressed. Pins stay off in both.

* test(usage): cover the compact context window sheet

On the compact viewport the meter opens the sheet; its cards have Refresh,
a Refresh replaces the card, and Close dismisses the sheet. The glossary
names the sheet.

* feat(ui): give tooltips and the context window sheet accessible roles

Tooltip content is role=tooltip, and the context window sheet is a dialog
named Context window, so assistive tech and tests find them by role. The
agent usage message drops its test ID; it is found by its text.

* test(usage): reshape the context window and Usage switch specs as journeys

The context window spec runs one tooltip journey and one sheet journey per
theme, with no layout branches. Its fixture script, meter actions and
report builders move to a context-window helper, and it finds the meter,
tooltip, sheet and Refresh buttons by role. The theme comes from the
system colour scheme. The Usage switch test uses named helpers for the
Usage icon and the Summary in sidebar switch.

* fix(usage): say an agent's usage request failed instead of showing older reports

A failed request keeps whatever reports the query held: those from an
earlier open, or those that streamed in before the failure. The context
window details showed them as if they were the agent's current usage.
The request error now wins over held reports.

* test(usage): let a fixture clean up the context window spec's agent

The tooltip and sheet tests no longer wrap their steps in try/finally;
a spec-local fixture seeds the agent and removes it after the test.

* fix(usage): keep a refreshed report when the list it is in finishes

Pressing Refresh on one card while another source was still streaming
put the pre-refresh report back: the finished list replaced the query's
data with the copies the request had fetched when it started. A report
now keeps whichever copy was fetched later, both when a streamed copy
arrives and when the finished list replaces the streamed one.

* fix(usage): show only the login a resumed agent runs under now

An agent resumed under another login keeps its ID, so its usage query
kept the previous login's reports: reopening the context window showed
them while the new login's reports loaded, then both side by side until
the request finished. The agent's usage is now dropped as soon as its
tooltip or sheet closes, so each open loads the login the agent runs
under at that moment.

* fix(usage): stop a closed agent usage request from writing reports

Closing the context window details cancels the agent's usage request and
drops reports still on their way, so reopening after a resume under
another login sends a new request instead of joining the old one.
2026-10-03 23:12:57 +01:00
Mohamed Boudra 42806cdbf9 Let plugins play audio on every client (#5976)
* feat(plugins): play audio files on every client

* fix(audio): preserve voice output and isolate waiting cues

* fix(plugins): normalize audio MIME parameters

* refactor(audio): share PCM conversion and keep plugin playback file-only
2026-10-03 16:56:59 +01:00
Mohamed Boudra b5e9747e2a Add the reviewed plugin registry and the unlinked plugin directory pages (#5986)
* feat(plugins): install reviewed artifacts from open registries

* fix(website): build protocol before deployment checks

* fix(website): make plugin pages discoverable to search engines

Resolve missing registry entries in route loaders to return HTTP 404. Serve a registry-backed sitemap so newly listed plugins and authors are discoverable without rebuilding the website.

* feat(website): keep plugin directory unlinked for coordinated launch

Preserve direct routes and SEO while retaining the partner directory link. Cover nested Git artifacts through registry installation and pinned website commands.

* fix(website): link plugin cards by registry owner and stub the clipboard in e2e

Plugin and author URLs come from the owner segment of the plugin ID, not the author's GitHub login, so a listed plugin always resolves. The Playwright spec records clipboard writes instead of granting a permission WebKit does not have.
2026-10-03 16:30:13 +01:00
paseo-bot[bot]andilteoood 5375f43a05 feat(plugins): expose agent closed lifecycle event (#5971)
* feat(plugins): expose agent closed lifecycle event

Emit the event when a live agent reaches its closed state so plugins can release agent-scoped resources. Keep archive and close notifications distinct.

Co-authored-by: ilteoood <6383527+ilteoood@users.noreply.github.com>

* fix(plugins): finish close hooks during daemon shutdown

Wait briefly for pending lifecycle events before stopping plugins so agent close hooks can release their resources during shutdown.

Co-authored-by: ilteoood <6383527+ilteoood@users.noreply.github.com>

---------

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
Co-authored-by: ilteoood <6383527+ilteoood@users.noreply.github.com>
2026-10-03 11:36:19 +01:00
Mohamed Boudra 73d25317a4 fix(usage): derive window names and unify pin selection (#5903)
* fix(usage): derive window names and unify pin selection

Quota slots do not identify a period. Derive numeric windows and IDs from reported duration and quota scope; keep unknown lengths neutral. Resolve source defaults and explicit pins through one model, with a persisted empty selection distinct from defaults.

* fix(plugins): declare the duration helper host requirement

* fix(usage): verify persisted selections at the storage boundary
2026-10-02 11:18:13 +01:00
Mohamed Boudra 05e94ab52e Keep usage logins visible and explain unavailable quota (#5876)
* fix(usage): keep existing logins visible and explain unavailable quota

Credential discovery must preserve accounts whose login exists even when it has expired. Keep vendor failures on the discovered account and isolate discovery failures without inventing provider cards.

* test(usage): align credential route tests with account discovery
2026-10-02 00:30:11 +01:00
Mohamed Boudra 70df09daeb Restore desktop usage and subscription discovery across harnesses (#5844)
* fix(app): hide the sidebar Usage item while it has no summary

Without a summary window with data, the item fell back to a plain "Usage"
row that duplicated the footer's Usage icon. It now renders nothing, and the
footer rows leave it out so an otherwise empty rows block and its separator
disappear with it.

* fix(desktop): restore built-in usage in packaged apps

The external plugin compiler cannot traverse app.asar, and dependency packaging drops declarations needed by import validation. Ship complete built-in resources beside the archive and verify registration in the packaged desktop smoke check.

* fix(usage): restore login discovery across harnesses

Discover subscription accounts independently of agent sessions and retain each account’s logins in preference order so an unusable credential can fall back to another login for the same account.
2026-10-01 14:51:11 +01:00
Mohamed Boudra 7b0cace991 Restore Antigravity with Full access and session warnings (#5795)
* Revert "Remove the unreleased Antigravity provider plugin (#5781)"

This reverts commit 9d9d9af993.

* fix(providers): commit plugin notices emitted during session opening

* feat(providers): restore Antigravity with full access and session warnings

* fix(providers): warn once when opening Antigravity sessions

Driver respawn retains the live transcript and unchanged permission posture. Emit the warning only when opening a session, including resume after a daemon restart.
2026-09-30 23:18:05 +01:00
Mohamed Boudra 695ecb2812 fix(muse): make package installs and project rules work by default (#5775)
* fix(muse): make launch defaults usable and configure each agent

Disable sandboxing and trust workspaces by default so package installs and project rules work. Replace the host settings UI with validated per-agent providerOptions, preserving posture across session resume.

* docs(muse): describe shared provider options configuration
2026-09-30 20:09:10 +01:00
Mohamed Boudra 9d9d9af993 Remove the unreleased Antigravity provider plugin (#5781)
* refactor(providers): remove the unreleased Antigravity plugin

Remove the provider at the owner’s request because headless command approvals are unsupported. Preserve Muse, shared plugin infrastructure, and earlier editor and terminal integrations.

* test(plugins): keep builtin startup coverage generic
2026-09-30 19:39:09 +01:00
Mohamed Boudra 29c198f955 fix(providers): apply configured options to every agent provider (#5780)
* fix(providers): apply configured options at session startup

Treat provider options as one opaque record, with provider-owned validation and per-agent overrides over configured defaults. Keep agent overrides separate from defaults so configuration changes apply on the next launch or resume.

* test(providers): verify provider-owned validation through Hub

* fix(providers): preserve the complete wrapped session interface
2026-09-30 19:37:14 +01:00
Mohamed Boudraandmillerben95 8332f4d1ff feat(muse): add Muse Code as a built-in provider plugin (#5719)
* test(muse): record real host protocol fixtures

* feat(muse): add built-in MSP provider

Co-authored-by: millerben95 <millerben95@users.noreply.github.com>

* fix(muse): expose provider settings in the app

The daemon registered host settings without a client contribution, leaving sandbox, network, and workspace trust unreachable. Share the definition with a settings screen and expose it through Command Center even when installed plugins are disabled.

* docs(muse): publish setup and provider support

* test: correct runtime fixtures and restart readiness

* fix(muse): hide reminder housekeeping from the timeline

* fix(muse): use the official Muse Code mark

Source: https://muse.ai/images/favicon/app-squiggle.svg

Preserve the official silhouette path verbatim. Remove its gradient definition and use currentColor, scaling the original 100-unit coordinates into the 24-unit viewBox. Black silhouette renders match pixel-for-pixel.

* fix(muse): adapt to current plugin APIs

Use the screen API introduced with sidebar plugin items. Usage reports now come from source account discovery; remove the retired agent usage-reference request and headline marker, and exercise discovery through the existing provider fixtures.

---------

Co-authored-by: millerben95 <millerben95@users.noreply.github.com>
2026-09-30 14:56:41 +01:00
Mohamed Boudra 7b7685678d feat(antigravity): add Antigravity provider plugin (#5714)
* test(antigravity): record agy stream-json fixtures

* feat(antigravity): add Antigravity provider plugin

* fix(antigravity): address Phase 1 review findings

* test(antigravity): record parity discovery blockers

* feat(antigravity): support image prompts and daemon e2e

* docs(antigravity): document provider setup and limitations

* test(antigravity): respect Windows interrupt semantics

* docs(plugins): avoid duplicate provider override guidance

* fix(antigravity): report fresh denials and correct mode metadata

Native denial results accumulate within a driver process. Track reported occurrences until respawn so later text-only turns do not repeat notices, while new denials of the same action remain visible.

* fix(antigravity): use the official Antigravity mark
2026-09-30 14:09:07 +01:00
Mohamed BoudraandClaude 3a9304607c feat: sidebar header and footer plugin items, Usage in the sidebar footer (#5685)
* refactor(usage): remove agent-to-usage wiring

* feat(plugins): screens, sidebar header and footer items

Plugins register screens with addScreen and contribute component-based
sidebar items with addSidebarHeaderItem and addSidebarFooterItem. Items get
currentScreen, openScreen and openPopover, and render the SidebarRow and
SidebarButton kit. The footer shares the header's ordering model through the
new sidebarFooterItems preference, and Settings > Sidebar gains a Footer card.
addSurface, openSurface and addSidebarItem stay as aliases with their
settings keys and routes.

* refactor(plugins): share resolvePluginPlatform and keep header remembered-host key

Consolidate the five resolvePlatform copies into plugins/platform.ts.
Header sidebar items keep the <pluginId>/sidebar/<id> remembered-host key
so existing users keep their remembered host; footer items use
<pluginId>/sidebar-footer/<id>.

* feat(usage): global usage summary, pins and used/remaining display

- Device-local usage preferences (displayAs, pinned windows) in app settings.
- Sidebar footer usage summary: pinned windows in pin order, one per account;
  opens the expanded view as a popover on desktop and a sheet on compact.
- Pin checkboxes on window rows and a used/remaining toggle shared by the
  summary, popover, Usage screen and Settings usage section.
- Usage screen shows one host with a selector when several are connected.
- Extract HostSwitcher and the sidebar popover host for reuse.

* fix(usage): render each usage report as its own card

* feat(usage): row pinning, one title row for usage controls, even sidebar footer

- Window rows are the pin toggle (checkbox role, checked state); pinned rows
  get a surface2 highlight, unpinned rows an interactionHighlight hover.
- Usage screen, Settings section, popover and sheet put the title left and
  the host selector, used/remaining toggle and Refresh right (UsageControls).
  PageLayout gains an actions slot; the menu sheet header a trailing slot.
- Sidebar footer rows share 28px height, spacing[1] gaps and one leading rail.

* fix(usage): keep row hover lighter than the pinned highlight

Hovering an unpinned window row shows the pinned surface2 at half opacity on
a separate layer, so it never reads stronger than a pinned row. Pinned rows
do not react to hover.

* fix(app): defer sidebar styles and preserve layout exports in timeline test

* fix(usage): open the Usage screen on desktop, drop the Usage footer icon, match git panel refresh

- Desktop presses on the usage summary open the Usage screen; only compact opens the sheet.
- The Usage footer icon is gone; with nothing pinned the summary renders a plain "Usage" row
  in the footer row style. A stored `usage` footer preference is ignored.
- Refresh controls use the Changes panel's icon-only ToolbarButton with RotateCw.

* fix(sidebar): keep the footer icon row fixed; footer items are rows only

The footer's icon row (Hosts, Import session, Help and support, Settings) is back to main's
fixed implementation: not in Settings, not reorderable, and plugins can't add to it.

- Footer items are full-width rows between Add project and the icon row: the usage summary
  and plugin `addSidebarFooterItem` rows. The Footer card in Settings lists only those rows.
- Stored `sidebarFooterItems` keys for hosts, import, help and usage are ignored.
- `SidebarButton` is removed from the plugin UI kit; a footer item renders `SidebarRow`.

* refactor(usage): call the sidebar footer item Usage

One concept, one word: the footer item is the Usage item, with key `usage`.

- Settings > Sidebar > Footer lists it as "Usage"; its preference key is `usage`.
- `usage/summary-item.tsx` becomes `usage/sidebar-item.tsx` (`UsageSidebarItem`); both states
  use testID `sidebar-usage`.
- `usage/summary.ts` becomes `usage/pinned.ts` (`resolvePinnedUsage`, `PinnedUsageWindow`):
  it resolves the pinned windows the item shows.

* feat(plugins): screen params, several rows per sidebar item, SidebarSeparator

openScreen takes { screenId, params }; params live in the screen route's
query so reload, history and links keep them. currentScreen carries the
params. A sidebar item may render a fragment or array of rows; a row press
anchors the popover to that row. SidebarSeparator joins the plugin UI kit.

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

* fix(plugins): any screen param key; trailing presses anchor the row's popover

Screen params go in the query under a param. prefix, so keys like serverId
no longer collide with the route segments Expo Router merges into search
params. A press anywhere inside a SidebarRow, trailing content included,
makes that row the popover anchor.

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

* feat(plugins): plugins title their screens

addScreen takes { id, title, Component }. title is a string or a function
of the screen's params; the screen header shows it and follows param
changes. A title function that throws or returns empty falls back to the
screen id. Legacy addSidebarItem screens keep their item's title and icon,
and the addSurface alias titles its screen with the id.

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

* fix(usage): require discovery and remove unreleased agent resolver

* fix(plugins): restore legacy sidebar rows, share the item runtime, header hint presses its row

- Legacy addSidebarItem rows are their own group kind again: main's row, registered icon in
  Settings, /sidebar/<id> route, host remembered per row.
- New-API items follow the host last used on any of the plugin's screens.
- /sidebar/<id> falls back to a same-id screen so pre-migration links resolve.
- params moves to PluginScreenProps; settings screens no longer receive it.
- Sidebar items, buttons and popovers share one runtime per installation, so no empty first frame.
- A header row's hint slot presses the row; labels wrap as on main.
- Skill and docs corrected.

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

* fix(usage): one host resolver, sheet reuses the screen's controls, name the host

- The Usage row and screen default to the same host.
- The compact sheet carries the screen's controls, host selector included.
- The host selector shows with one host, and unavailable messages name the host.
- The row, sheet title and pinned label use the sidebar.footer.usage translation.
- Window rows read their percent and reset after the pin label.
- Drop the unread per-report cache writes and headline fixture fields.

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

* fix(plugins): popovers, header buttons and composer pills own their runtime again

Only sidebar item rows use the installation's shared runtime. Popover content
disposes its runtime on unmount, so observations close with the popover.

* fix(plugins): a sidebar item releases its subscriptions when it unmounts

Each mounted sidebar item gets its own API scope over the host's client, created
during render so its first frame has content. The scope closes a microtask after
unmount (StrictMode's remount keeps it), when the item moves to another host, or
when the installation stops. Replaces the installation-wide shared runtime.

* refactor(plugins): one Paseo client per plugin; authors own their subscriptions

usePaseo() in every plugin surface, and client.paseo in setup, is the
installation's client, created with the installation in the registry. Authors
release their subscriptions in their own cleanup; plugin teardown disposes the
client and ends the rest. Nothing is created or disposed per mounted surface:
the per-surface runtimes, their boundaries, and the per-run Command Center and
slash command APIs are gone.

* refactor(plugins): one Paseo client per plugin; authors own their subscriptions

usePaseo() in every plugin surface, and client.paseo in setup, is the
installation's client, created with the installation in the registry. Authors
release their subscriptions in their own cleanup; plugin teardown disposes the
client and ends the rest. Nothing is created or disposed per mounted surface:
the per-surface runtimes, their boundaries, and the per-run Command Center and
slash command APIs are gone.

* fix(usage): show usage from released hosts

Normalize released-host usage responses at the client boundary so existing usage and pins remain available across app and daemon versions. Include account labels in legacy responses for older apps.

* fix(usage): keep the usage capability check out of the public SDK

* test(server): retry transient locks during runtime test cleanup

* test(usage): model hosts without either usage capability

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-09-30 12:52:13 +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 c54f20e53e feat(website): show Hub's Free and Pro plans, and drop trial wording (#5138)
Hosted Hub replaces its automatic trial with a real Free plan, so the
pricing section becomes three columns: Self-hosted, Free, and Pro. Both
hosted columns render entirely from `GET /api/billing/plans` — name,
price, the `included` figures, and the catalog's feature prose — because
those figures are derived from the entitlement template the instance
enforces, so nothing on this page can drift from the limit a customer
actually gets.

The parser requires both slugs and the new `included` object and throws
on anything else. The page already degrades to "temporarily unavailable"
when the loader throws, so a strict boundary costs a fallback we have
rather than a wrong number we would ship. This is also why the change
must not merge before the Hub side deploys: against today's API the
section renders that fallback.

Public docs follow the two Hub changes: Free replaces the trial and
points at /hub for the figures Stripe metadata now owns; sign-in lands on
Home with its four-step checklist; `hub.execute` gets the grant command
it needs; and trigger authoring documents that the agent is validated
against the target daemon at save, which needs that daemon connected and
accepts Claude, Codex, and OpenCode only.
2026-09-28 15:51:12 +01:00
Mohamed Boudra 047f40e623 Install npm plugins and review source updates (#4975)
* feat(plugins): unify source installation and simplify plugin settings

* feat(plugins): install npm sources and review CLI updates

Treat install selectors as one-time choices. Keep source identity separate from the installed revision, and resolve ordinary updates from the current upstream default. npm only acquires directories; plugin loading remains independent of npm.

* fix(plugins): preserve CLI diagnostics and exercise reviewed updates

Move new source capability coverage to real browser journeys. Update the requirements regression to exercise preview and apply, and preserve the existing duplicate-selector diagnostic across positional option scopes.

* test(plugins): remove unused pending helper

* test(plugins): pack registry fixtures with the Windows command runner

* test(plugins): assert failed client contribution setup

* docs(plugins): consolidate guides and document npm publishing

* docs(plugins): introduce publishing choices before npm instructions

* test(plugins): own browser journey cleanup in a fixture

* feat(plugins): prepare scaffolded packages for publishing
2026-09-17 10:22:20 +02:00
Mohamed Boudra c7db3c5a8c Let plugins open external links and workspace browsers (#4972)
* feat(plugins): open external links and workspace browsers

* fix(plugins): refuse invalid links and unavailable browser workspaces

* docs(plugins): clarify external links and browser navigation
2026-09-16 23:25:17 +02:00
Mohamed Boudra 6ce6f4c961 Let plugins discover hosts and use host-targeted SDK clients (#4971)
* feat(plugins): expose hosts and host-targeted SDK clients

* test(plugins): verify exact cross-host observation cleanup

* fix(plugins): reacquire explicitly disposed host clients

* docs(plugins): clarify host client usage and lifecycle

* docs(plugins): use theme colors in host discovery example
2026-09-16 22:45:18 +02:00
paseo-bot[bot] 72e3d6957a Let plugins navigate across hosts (#4942)
* feat(plugin): support cross-host navigation

Keep route construction inside Paseo while letting plugin surfaces target a host other than the currently selected one. Calls without a server ID retain selected-host behavior.

* test(plugin): cover cross-host navigation

Exercise workspace and agent navigation against a second live daemon so the SDK contract is verified through the caller-visible route instead of mocked helper forwarding.

* test(plugin): clarify cross-host navigation journey

Keep the scenario at the caller-visible intent level while shared helpers own route waits and visibility mechanics.

---------

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-09-16 20:27:15 +02:00
0aca3b605a fix(plugins): transform whole timeline items before grouping and Markdown splitting (#4675)
Send every original tool call and each whole accumulated assistant message through plugin transformers before display grouping or Markdown splitting. Preserve streaming callbacks, original payloads, native Markdown block identities, and chat outline reading position. Reject legacy fragment caches and retain failing-first plugin-interface and browser regressions.

Fixes #4673. Fixes #4789. Consolidates #4820.

Co-authored-by: Matt Cowger <matt@cowger.us>
Co-authored-by: Jegor Kitskerkin <jegor.kitskerkin@gmail.com>
Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
2026-09-14 23:03:38 +02:00
Matt CowgerandMohamed Boudra 0c5f472da1 fix(plugins): expose server settings access (#4674)
* fix(plugins): expose server settings access

* fix(plugins): isolate settings subscriber state

* test(plugins): read persisted settings before clients connect

* test(app): reconnect seed client after old daemon restart

* test(server): drain file creation events before deletion assertions

* test(creation): expose errors when completion fails

---------

Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
2026-09-14 23:03:20 +02:00
Mohamed Boudra 03a54a171d Keep older daemons usable and let clients choose timeline recovery (#4737)
* fix(subscriptions): preserve older-host workflows and explicit timeline recovery

Keep established app and SDK workflows available on older daemons without emulating independent directory filters. Restore live timeline membership without choosing the consumer's history recovery policy. Preserve daemon filesystem paths separately from legacy workspace IDs.

* fix(client): keep legacy workspace replies scoped to the requested page
2026-09-12 08:50:16 +02:00
Mohamed Boudra 772ff8d6f3 fix(desktop): preserve Linux sandboxing wherever the host allows it (#4447)
* fix(desktop): preserve Linux sandboxing wherever the host allows it

Chromium checks its Linux sandbox before main.js, while package installation probes run as root and miss AppArmor restrictions on desktop users. Choose the launch flags before exec and always install the SUID alternative for native packages. Test published artifacts as an ordinary user with namespaces both denied and allowed; never repair permissions in the smoke harness.

* fix(desktop): retain the Linux release build baseline

* fix(ci): allow canceled desktop smoke uploads to stop

* test(desktop): verify the installed RPM sandbox under AppArmor

* fix(ci): resolve packaged desktop dependencies before installation

* chore(desktop): keep QA evidence out of the repository
2026-09-11 09:05:26 +02:00
Mohamed Boudra 0110302b6f fix(daemon): keep lifecycle operations on the selected instance (#4575)
* fix(daemon): keep lifecycle operations on the selected instance

Restart reconstructed launch inputs and address fallback could redirect a home-selected shutdown to another daemon. Let supervisors publish bound endpoints, retain their worker restart contract, and share captured local lifecycle ownership between CLI and Desktop.

* test(daemon): verify bounded desktop readiness and cancellable artifacts

* test(cli): verify reload target hints and durable offline pairing

* test(daemon): align lifecycle fixtures with ownership and targeting

* fix(daemon): preserve reachability when status details time out

Provider discovery can outlast a status request after authentication succeeds. Keep local connection facts separate from unavailable details, while explicit remote queries retain their error outcome.

Migrate CLI and packaged Desktop fixtures to persistent managed configuration and explicit targets. Isolate generic Git observation from forge discovery and reuse disposable CLI homes on Windows.

* test(daemon): observe restart through the worker status RPC

The bounded CLI status observation may omit worker details while an authenticated connection remains healthy. Exercise the app-style restart through its full RPC and retain the replacement observation, with a real slow provider probe covering the distinction.
2026-09-11 08:33:22 +02:00
Mohamed Boudra 6f2195904b fix(subscriptions): isolate observers and silence unrequested feeds (#4596)
Give each observation a server-issued ID owned by its physical connection. Preserve snapshot-only reads and combined list-and-subscribe, source-bound replies, lifecycle cleanup and legacy wire compatibility.
2026-09-11 08:07:35 +02:00
Mohamed Boudra 7bcf167862 Document scoped credentials during Hub continuation (#4607)
* docs(hub): explain scoped credentials during agent continuation

* docs(hub): align credential lifetime across trigger guides

* docs(hub): centralize continuation credential lifecycle

* docs(hub): keep continuation guidance focused on agent reuse

* docs(hub): state when shared tokens are revoked
2026-09-10 10:08:54 +02:00
Mohamed Boudra ae1cf642bb docs(hub): remove navigation implementation FAQ (#4645)
* docs(hub): explain pending dashboard navigation

* docs(hub): remove navigation implementation FAQ
2026-09-10 09:05:43 +02:00
Mohamed Boudra 2ee0191ea1 docs(hub): explain pending dashboard navigation (#4608) 2026-09-10 09:00:33 +02:00
Mohamed Boudra 92504cd525 docs(hub): document configurable startup timeout (#4601)
* docs(hub): document configurable startup timeout

* docs: keep startup timeout guidance in one place
2026-09-09 23:37:54 +02:00
Mohamed Boudra 433e67b18b feat(website): link the community plugin directory
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.
2026-09-09 16:06:08 +02:00
Mohamed Boudra 0b3d82a469 feat(plugin): add shared header buttons and composer controls (#4577)
* feat(plugin): add shared header buttons and composer controls

* fix(plugin): isolate button registration imports and settle captures

* test(plugin): express button journeys through domain helpers
2026-09-09 15:39:12 +02:00
Mohamed Boudra c172076bff Initialize Hub with organization triggers (#4517)
* 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
2026-09-09 09:15:28 +02:00
Mohamed Boudra da8c1b5c94 Make orchestration setup, profiles, and agent communication discoverable (#4486)
* docs(orchestration): lead with capabilities and practical delegation

* docs(orchestration): correct model requirements and agent list scope
2026-09-08 13:40:21 +02:00