* fix(client): reject a message over the daemon's size limit instead of reconnecting in a loop
The daemon closes the WebSocket with 1009 when a message exceeds its 100 MiB
limit. A workspace or agent creation that loses its connection mid-request
stays pending and, after reconnecting, finds no record of itself on the
daemon (the oversized frame was never read), so it resubmits the same frame
and the connection drops again every couple of seconds until the app reloads.
The client now checks each outbound frame against the same limit, which
protocol exports and the daemon sets explicitly, and fails that request with
a size error while the connection stays up.
Refs #5501
* test(client): cover the UTF-8 byte count at the message size limit
* fix(client): reject oversized relay messages without disconnecting
Check the encrypted wire size synchronously before submission, so a frame below the direct limit cannot close the relay and leave workspace creation resubmitting forever. Keep the relay limit shared with the existing checkout diff budget.
---------
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
* fix(app): restore terminal surface after tab hide so CJK cells redraw
Retained panels use display:none. Coming back remasured without treating
that as a surface restore, so Hangul kept 2-cell slots while glyphs painted
at ~1 cell (extra gap). Reload WebGL if the context was lost and force a
refresh when the host grows from zero.
Closes#3434
* fix(server): keep wide-char continuation cells out of terminal snapshots
Wide chars (CJK) occupy two xterm cells, and the second cell reports no
chars. The snapshot capture collapsed that empty continuation to " ", so
every restored Hangul syllable took three columns instead of two. The
injected space was real: selecting and copying the restored row carried
it into the clipboard.
Capture the continuation as "" and have renderTerminalSnapshotToAnsi
skip it. No schema change; snapshots from older daemons still replay
verbatim.
* fix(app): restore retained terminals on presentation
Co-authored-by: seob717 <dev.seob717@gmail.com>
* fix(terminal): limit restoration changes to confirmed CJK corruption
Keep the independently reproduced snapshot fix. Surface recovery behavior remains unverified and belongs with the broader viewport report. Dispose the replay terminal after the regression test.
---------
Co-authored-by: Jason <mildreins@gmail.com>
Co-authored-by: seob717 <dev.seob717@gmail.com>
Co-authored-by: liujin0506 <liujin0506@qq.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
* 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>
* feat(agents): show agent messages and completion notifications with sender identity
* fix(agents): preserve human envelope examples and attachment context
* fix(agents): separate message provenance from timeline presentation
* website: match left and right edge padding on ranked plugin rows
The rank sat right-aligned in a fixed 16px column and the row had 8px of
padding, so a single digit started ~15.6px from the row edge while the
install count ended 8px from it. The rank now sits at the row's padding,
which is 16px on both sides, and the list's negative margin matches so
the rank still lines up with the section heading. Tabular figures keep
the tile column aligned without the fixed width.
* website: give plugins section headings room above their content
Section headings sat 16px above their cards while sections sat 56px
apart, so a heading read as closer to the section above it. A shared
PluginSection now owns the header-to-content gap (32px), used by the
index sections and by the browse results under the sort tabs.
* website: center the Build your own plugin card
The heading, description, and buttons were left-aligned in a full-width
card, leaving most of it empty. Center them and keep the description at
its readable measure.
* website: order What's new by first-listing date
newestFirst and addedAgo read submittedAt. The registry publishes the
first-listing date as publishedAt, so What's new now sorts and dates by
it. The fixture's publishedAt values become first-listing dates.
* website: plugin media with video tiles and a click-to-view viewer
The registry's published screenshots field becomes media and may hold
mp4 and webm videos. Cards and link previews use the first image, the
thumbnail route serves only image entries, and the detail gallery shows
videos as tiles alongside images. Any tile opens one viewer. An image
fits the viewport but never exceeds its natural size. A video plays with
controls and scales to the largest size that fits, small sources included.
The daemon resolver now validates only the ID and artifact it installs.
* server: drop the unreleased pluginRegistryEnabled config key
The key only existed in unreleased betas and nothing reads it. The
config schema is strict, so a config that still sets it now fails
validation and names the key.
* website: Featured section on the plugins index
The registry index gains a required featured list of plugin IDs. The
index shows those plugins above What's new, in the registry's order,
skipping IDs that are not listed, and hides the section when none are.
The index sections now share one container for their spacing.
* fix(plugins): restrict overview content to safe Markdown and HTTPS destinations
Registry overviews are author-controlled content read away from their repositories. Apply a shared presentation policy instead of the documentation renderer so relative links, non-HTTPS URLs, raw HTML, and author styles never become active overview content.
* fix(plugins): choose the first allowed screenshot for previews
* 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
* 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
* 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.
* 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.
* 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
* feat(app): streamline sidebar usage and stacked sheets
* fix(app): restore compact sidebar navigation clicks
The close button container emitted box-none through Unistyles as invalid CSS and intercepted New workspace clicks. Let React Native apply click-through behavior at the view boundary. Keep the import journey on its existing New workspace screen and assert only the visible transcript.
* fix(app): cap menu sheets at eighty percent height
Keep long sidebar usage reports recognizably sheet-sized while allowing the content to scroll. Short menu sheets retain dynamic sizing.
* 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
* 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>
* feat(codex): discover Fast and Ultrafast speeds from the catalog
Replace the model allowlist with advertised service tiers so new models and speeds need no Paseo catalog update. Normal explicitly overrides the thread tier. Desktop icon-only triggers are provider metadata; mobile selectors remain labeled.
* chore: remove QA screenshots from the change
* Show the Cursor icon for terminal profiles that run cursor-agent
The Cursor CLI binary is cursor-agent, so a profile created in settings
with that command matched no known icon and fell back to the generic
terminal icon. Map cursor-agent to the cursor icon while keeping
command matching exact.
Closes#4702
* Verify Cursor terminal profile icons in real browser
---------
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
* 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
* feat(auth): authenticate daemon clients through hello
Give local CLI and desktop clients a per-run credential while remote clients send the host password inside the protocol. Keep relay passwordless admission for this mobile release so existing saved hosts keep working until the follow-up enforcement release.
Move password recovery for saved hosts into host settings and keep pairing credentials in the add flow. Include isolated web QA evidence for both flows.
* fix(auth): preserve Hub bootstrap and local credential expectations
Hub-owned sockets already carry admission; keep their hello handling synchronous through session bootstrap while resolving credentials asynchronously for ordinary sockets. Keep the resolver out of lightweight configuration imports.
Update CLI expectations for same-home credentials, let a rejected connection yield to another usable connection, and clear pairing secrets when add-flow targets change.
* fix(pairing): retain passwords across edits to the same target
Track the last valid pairing host while a URI is edited. This preserves an entered password for whitespace and partial edits but clears it when a different host becomes the target.
* test(auth): align local credential checks across platforms
Expect the CLI to authenticate through the credential in its selected home, and verify POSIX file modes only where Node exposes them.
* feat(app): move host password into a settings row with a modal
The host page rendered an always-visible password form above Name on every
host. Replace it with a Password row under a Security section below
Appearance; tapping it opens a modal with Save and, when a password is saved,
Clear. The connection-error callout keeps its guidance and gains a Set
password button that opens the same modal. Drop the unused
pairing.hostPassword body/reopen/saveError strings.
* chore: remove committed QA screenshots
QA evidence stays out of the repository; the PR body describes it in words.
* feat(app): keep the host password out of the host page
The saved password is connection data, entered only when a host is added. A
Password setting on the host page reads as the daemon's own password, so the
row, modal, and callout button are gone. A rejected host shows the daemon's
reason with guidance to remove the host and add it again with the password.
useHostMutations no longer exposes setHostPassword; relay imports still set it
inside the runtime.
* feat(app): show host connection errors in an error alert
HostConnectionError renders the existing Alert with the connection error as
its title. Auth rejections add the re-add guidance as the description; other
errors show the title only. The Overview and Connections pages share it.
* style(app): soften alert borders to half-opacity accent
* feat(app): size alerts on the button scale
Alert takes a size prop (xs/sm/md/lg, default md) whose geometry lives next to
the button's in control-geometry: one font size for title and description, the
button icon size centered on the first text line, button padding and radius,
and a one-line alert as tall as the button of the same size. Consumers pick
sm among settings rows, cards, panels, and modals, and md when the alert is
the whole page or sheet state.
* style(app): roomier, rounder alerts with a tight title block
Alert sm padding returns to the original 12/16 and every size is at least
borderRadius.xl. Title and description sit a small gap apart with no line
height override. The icon slot carries a zero-width text strut in the alert's
font so the icon centers on the first line for titled, title-only, and
description-only alerts.
* refactor(app): align the alert icon with a centered lead row
Drop the zero-width strut. The icon and the alert's first text (title, else
description) share one row centered on each other; the description and actions
sit below, indented by the icon slot width plus gap so they start at the lead
text's left edge.
* refactor(app): drop the unused Alert icon override
* fix(app): count chat Find matches across the whole chat
Chat Find searched the whole chat but its counter read "1 of N in
message", where N was the occurrences inside the selected message. The
per-message split is an implementation detail of how the client verifies
and highlights a hit; a reader counting matches is counting the scope
they searched. The counter now reads "3 of 7" for the position across
every message that holds a hit, and Next/Previous walk that sequence,
crossing message boundaries and wrapping at the ends. Per-message
occurrence stays inside the model as navigation state.
The total needs a per-message count for messages that are not on screen,
so the daemon now reports one. It counts with the same matcher the
browser uses on rendered text — query words joined by any whitespace,
case-insensitive, never across a Markdown block boundary — which also
stops it from reporting locations the client would reject. The client
replaces the estimate with the rendered count as each message is
revealed, so the total is exact for everything that has been on screen.
`count` is optional on the wire and tagged COMPAT(timelineSearchCount):
a host that omits it is worth one match per located message until a
reveal corrects it.
* fix(server): stop chat search reporting matches the browser cannot show
Falling back to the whole Markdown source when the per-block scan found
nothing reported a match whenever the query words straddled a block
boundary — "one target" across "target one\n\ntarget two" — and on
syntax the reader never sees. The client always rejected those
locations, so before the whole-chat counter the cost was a wasted round
trip. Now that the total sums the host's per-message counts, a rejected
location inflates the number the reader sees until navigation reaches
that message and drops it. The block scan alone is the whole rule.
The model's Location derives from the wire type again, with count
narrowed to required: the search boundary fills in the COMPAT default,
so the interior never re-checks it.
Desktop and CLI helpers imported daemon bootstrap through the server root, while supervisor configuration retained the full wire schema tree. Expose existing capabilities through narrow package entrypoints and share configuration schemas without loading message definitions. Guard the dependency trees without tree-shaking so unused exports cannot hide the runtime cost.
* 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
* fix(history): preserve chronology and clarify search matches
Keep workspace names primary and highlight each searched field so results explain why they matched. Filter before cursor pagination and retain date buckets.
Constrain shared subsequence matching to each whitespace-delimited word while preserving fuzzy abbreviations in Command Center and other consumers.
* test(history): reuse response helper in pagination regression
* test(history): express browser journey through named helpers
* fix(app): start menu entering animation only once the surface is placed
Reanimated's web entering path snapshots the element rect at animationend and
writes top/left back when it cleans up the keyframe 750ms later. When the
150ms animation ends before anchor and content measurement resolve, that
snapshot is the off-screen measuring position and the open menu jumps back to
-9999. Remount the surface when its position resolves so the animation starts
from the final position.
* feat(app): add pane Find to file source
* fix(app): float the pane Find widget and tighten its chrome
Find pushed the first lines of the file down, ran 480px wide with 32px
ghost buttons, and let the replacement input start left of the query
input. Float the CodeMirror top panel out of flow so the widget overlays
the top right of the pane, move the disclosure toggle into a gutter that
spans both rows so the two fields share a leading rail, put the match
count inside the query field, and drop the icon controls to the shared
pane-toolbar chrome the file bar above already uses.
* fix(app): keep the active match visible and drop the Find button
The floating widget covered the active match whenever the match sat under
it and the document was too short to scroll clear. CodeMirror's own panel
scroll margin cannot reveal a first line, so the file integration now owns
placement: the widget renders as an overlay beside the editor, the model
measures it against the active match, and flips it to the opposite corner
only when the current corner collides. Hysteresis keeps navigation from
bouncing the widget between corners.
Also removes the standalone Find button shown while Find is closed, per
user direction. Cmd/Ctrl+F is the entry point.
* fix(app): stop the Find placeholder from hiding Go to line
Hiding `.cm-panels` suppressed every CodeMirror panel in the file editor,
including the Go to line dialog that Mod-Alt-g opens through the same
search keymap. Hide only the inert Find placeholder panel instead, by its
own class, and leave the shared panel container alone.
* feat(app): find text throughout chat history
Discover candidate transcript locations on the daemon, then reuse prompt navigation to load history and verify rendered occurrences on the client. Keep search state inside its own modules without changing timeline or task presentation contracts.
* fix(app): show actionable chat search failures
Keep transport error details in the search model while showing localized retry guidance. Use named client request options for timeline search.
* fix(providers): keep duplicate catalogs from breaking agent drafts
Normalize model identities before publication and when materializing older
catalogs, preserving the first definition and configured overrides. Keep
explicit default variants separate from the base model selection.
* fix(providers): preserve saved variant identities across resumes
Persist the selection encoding so legacy names remain literal. Refresh provider persistence when a selection changes, before another prompt is sent.
* test(app): let fixtures own catalog journey cleanup
* fix(providers): preserve the existing default variant contract
Keep one Default catalog choice and let the provider resolve an omitted variant. Remove the encoding and persistence machinery; other variant IDs retain their literal meaning.
* test(creation): expose failed completion after conflicting requests
Creation returns a failed snapshot instead of rejecting. Assert the result before its side effects so platform failures report the underlying error.
* test(app): wait for the seed client after daemon restart
The browser and seed client reconnect independently. Wait for the seed connection before issuing post-restart RPCs instead of assuming browser readiness covers both clients.
* test(app): isolate visible prompts and checkout diff fixtures
Inactive tabs retain message DOM, so prompt assertions must inspect visible rows. Ignore the local fixture remote before observation rather than deleting it after the daemon has started tracking the checkout.
* fix(file-observer): preserve final deletions when batching events
A duplicate creation notification followed by deletion was collapsed into an update, hiding final absence from consumers that distinguish deletes. Keep final deletes while retaining update semantics for atomic replacement.
* fix(desktop): wait for Metro HTTP readiness before launching Electron
Expo briefly listens while probing port availability. A successful TCP connection can therefore launch Electron before Metro starts and leave it exiting on connection refusal. Require the configured renderer origin to report the running packager status.
* test(ci): consolidate fixture and readiness corrections
Await the connection and UI states each journey owns, isolate Git fixture contents before observation, and hold real Markdown frames at asserted checkpoints. Keep creation completion diagnostics explicit without claiming the original Windows failure is fixed.
* fix(agents): prevent OOM from cumulative tool history
Repeated progress updates retained complete historical copies of growing tool output. Retain projected items on ingestion and serve them for every history fetch, preserving source sequence coverage for catch-up. Keep intermediate payloads only in streaming; confine compatibility degradation to child transcripts and overwritten fork checkpoints.
* test(client): expect projected subagent capability in hello
* fix(app): report unexpected child history failures
Keep connection failures recoverable while forwarding unexpected fetch and reconciliation errors to diagnostics. Name observer arguments to keep server and agent identities explicit.
* test(agents): assert projected history after rewind
* docs(protocol): tag projected child compatibility gates
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.
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>
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.
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(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