* fix(app): preserve mobile sidebar scroll position when reopening
Keep hidden native overlays laid out so Android touch cancellation cannot spring retained scroll offsets through a zero scroll range. Hide and gate touch input on the UI thread to preserve panel motion during JS stalls.
* docs(app): quote sidebar replay workspace examples
* test(website): read plugin HTML without waiting for remote images
* test(website): exercise built worker in browser checks
The ordered plugin spec reproduces a no-response navigation timeout against a cold development server. Build and preview the published worker for E2E checks; preserve the original content and metadata assertions.
* fix(server): keep workspaces available after setup config errors
* refactor(server): drop the archive dependency from worktree setup
Setup no longer archives a workspace when it fails, so the setup
workflows no longer take archiveWorkspaceRecord.
Co-authored-by: Bae Seongmin <83870598+3ae3ae@users.noreply.github.com>
* test(server): stop passing the removed archive dependency to the worktree workflow
* test(server): check paseo.json survives without comparing line endings
Git checks the fixture out with CRLF on Windows, so comparing its exact
contents failed there.
---------
Co-authored-by: 3ae3ae <ogyshjsm@naver.com>
Co-authored-by: Bae Seongmin <83870598+3ae3ae@users.noreply.github.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
* fix(app): enlarge compact sidebar footer tap targets
The compact drawer reused 28px desktop buttons, making footer actions hard to tap. Use 44px targets with larger glyphs in compact layouts while preserving desktop geometry.
* test(app): wait for compact footer tap stability
* 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.
* fix(app): smooth chat history pagination and reserve image space
Select the range at the pending reading offset before a prepend mounts rows. Reuse committed geometry for scroll input so a layout correction cannot hide the user's movement. Reserve image dimensions before loading and measure transient mounts in the browser regression.
* fix(app): scope cached image dimensions to their source
Raw file-path aliases let one workspace supply dimensions for another. Keep file metadata tied to its daemon and workspace, and close the delayed-image test server even when setup fails.
* fix(app): retain local image context in row height estimates
Pass the rendering server and workspace through height estimation so scoped image metadata remains usable before an older row mounts.
* refactor(app): name row height estimate inputs
* fix(app): render linked pictures in PR markdown
Consume image-only headings, anchors, and picture wrappers together so splitting at the fallback image does not leave raw opening tags or discard its link.
* fix(app): preserve picture block boundaries in markdown
* fix(app): parse nested image wrappers without recursion
* test(app): account for delayed wheel input in scroll assertions
CI recorded a 480px wheel scroll delivered after its event alongside 41px of image growth below the new reader. Use the same input budget to locate the reader and account for intervening growth, while continuing to reject added viewport displacement.
* test(app): locate the scroll reader from frame movement
Use the existing platform input for editing, Find, and clipboard behavior. Exercise Mac and Linux modifier chords through the app and a real PTY, and keep pending modifier chips authoritative.
Promote the inline multi-property parameter types added by this PR to
named interfaces, per docs/coding-standards.md.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Greptile review: the browser tests patched navigator.userAgent/platform
globals to exercise mac-only key handling. Make the platform an
explicit mount option (defaulting to navigator detection) so tests
inject it directly and the runtime stops sniffing navigator per
keydown.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
xterm ignores meta+arrows, and 6.x dropped the macOS conversion of
option+arrow to ESC b/f, so cmd+arrow did nothing and option+arrow
leaked ESC[1;3C-style sequences the shell rendered as a stray "C"/"D"
plus a bell. Map the chords the way Terminal.app and iTerm2 (Natural
Text Editing) do: cmd+left/right -> ^A/^E, option+left/right ->
ESC b/f, cmd+backspace -> ^U.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(app): keep chat reading position stable while scrolling
Prepend restoration froze the reading offset while wheel input and delayed image measurements changed layout. Give the viewport one reading anchor, preserve concurrent user movement, and apply virtual row measurements before paint. Suspend automatic pagination while explicit message navigation settles.
* fix(app): type the reading anchor scroll intent explicitly
* fix(app): retain the reading anchor through virtualization startup
Keep the reader pinned while the first virtual range mounts. Strengthen the scroll regression detector to compare shared rows when the original anchor unmounts, and consume fixture replies only when they are emitted.
* test(app): distinguish delayed wheel input from idle scroll drift
CI frames can arrive long after their wheel events. Start idle assertions after the input driver finishes, and account for an image entered by wheel input expanding below the new reading line. Replayed all six CI captures without false positives while retaining the original 76 baseline jumps.
* test(app): bound image growth allowance to displaced reading rows
Require the entered image top to follow wheel input before attributing movement of a later row to its growth. Calibrate the detector against simultaneous viewport jumps and jumps of the growing row itself.
* test(app): clamp scroll expectations at the history boundary
* feat(app): unify Explorer tabs and refine interface styling
Give Explorer the workspace tab controls while keeping launcher choices separate from drag-and-drop support.
Upgrade Lucide and set a shared icon stroke width for consistent styling. Reduce the desktop composer bottom inset to align the action row with its corners.
* fix(app): show active Explorer tabs in foreground
The shared row coupled foreground styling to keyboard shortcut ownership. Separate those concerns so Explorer can highlight its active tab while Cmd+T remains with the workspace pane.
* fix(app): refine Explorer close controls and launch options
* test(app): respect singleton Files in Explorer plugin workflow
* test(server): trim unused setup from no-track checkout regression
* test(app): count visible main tab rows after pane moves
* 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
Chromium bounding boxes differ by millionths of a pixel for equal-width footer buttons. Allow less than 0.01px in width and grouped-gap comparisons while preserving alignment and Help/Settings separation checks.
* 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
* 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.
* fix(skills): install one Codex-discoverable orchestration copy
* fix(skills): keep installed skills when agent skill roots are symlinked together
Retiring the old Codex copy deleted the skills just installed when
~/.codex/skills resolved to ~/.agents/skills or ~/.claude/skills (or the
reverse), and status reported drift forever. The Codex skill directory is
now treated as a leftover only when it is a separate directory from the
shared and Claude copies.
Co-authored-by: 3ae3ae <ogyshjsm@naver.com>
* test(e2e): expect agent skills in the shared and Claude roots only
The skills settings spec still expected every skill in ~/.codex/skills.
It now checks the two install roots and that ~/.codex/skills holds no
Paseo skill, which fails against the previous installer.
---------
Co-authored-by: 3ae3ae <ogyshjsm@naver.com>
Co-authored-by: Bae Seongmin <83870598+3ae3ae@users.noreply.github.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
* 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.
The relay exports map sent the import and default conditions to src/*.ts,
which the published package does not include, so any bundler resolving
@getpaseo/client failed with 'Could not resolve "@getpaseo/relay/e2ee"'.
Every condition now resolves to dist, like @getpaseo/protocol and
@getpaseo/client. The client build now builds relay first, and the Metro
workaround for compiling relay source is removed.
Fixes#4730
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
The composer picked the thinking level from what was chosen at launch and
fell back to the model's catalog default when nothing was chosen. A Pi agent
started without a thinking level runs on Pi's own configured default, so the
composer showed Medium while the agent ran on High. The composer now prefers
the level the running agent reports when it is one of the model's options,
the same way it already prefers the running model.
Fixes#5800
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
The composer fell back to the catalog's default model whenever the agent's
model was missing from the loaded model list, so a Codex subagent started
on a model the catalog did not list yet was labeled as the default model,
with that model's thinking options.
Fixes#5791
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
* fix(app): show default usage windows when no windows are pinned
* fix(app): show only percentages in sidebar usage summaries
* fix(client): restore usage source logos for released hosts
* fix(app): restore the labeled footer line below sidebar items
* fix(app): use History's host filter to pick the usage and plugin host
The Usage screen, the compact usage sheet and plugin screens used a separate
HostSwitcher trigger. They now use HostFilter without "All hosts", as the
label manager does, and hide it with one host, as History does.
* fix(app): save the usage host pick and show it in the sidebar summary
Picking a host on the Usage screen or usage sheet was view state: it reset when
the view closed, and the sidebar summary never read it. The pick is now a
device-local usage preference. The summary and the screen show the picked host
while it is connected, else the active workspace's host, else the first host.
The usage fixture answers by request, since the summary and the screen each
load reports and only a card's Refresh forces one.
* test(app): expect plugin footer rows above the footer bottom line
Add project moved to the bottom line with the icons, so footer rows sit above
it, spanning Add project to Settings.
* test(app): expect the saved usage host in stored settings
* test(app): let usage settings specs share reports with the sidebar summary
The sidebar summary loads reports on app start, so the settings specs answer
by request instead of by order and read percents from the settings card.
* 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
* fix(app): stack adaptive sheets across native presentations
Root-owned dialogs could not present over a sibling native dialog on iOS. Use the existing app-wide sheet stack for both native presentation forms, and release the underlying keyboard when a new sheet opens.
* test(app): verify pairing sheet autofocus
* docs(app): clarify stacked sheet journey prerequisites
* Add confirmation for new hosts
Opening a pairing link (an `#offer=` URL, a scanned QR code, or a pasted
link) now asks the user to confirm before the host is added or connected.
The prompt shows the host id, its key fingerprint, and the relay. Cancel
leaves no new host and no connection.
The host runtime owns the check: `upsertConnectionFromOfferUrl` and
`probeAndUpsertConnectionFromOfferUrl` ask a registered confirmer before
doing anything. `HostTrustPromptModal`, mounted at the app root, registers
the confirmer and renders the prompt with the shared confirm sheet. Without
a registered confirmer, pairing links are declined.
Adds a test that an offer link with the confirmation declined adds no host
and attempts no connection.
* Only ask for new hosts or changed connections
A pairing link now connects without the confirmation when it matches a
saved host exactly (same server id, key and relay). It still asks for a new
host, and for a saved host whose key or relay differs from what is saved,
with the "This link changes how you connect to this host" text.
After the user approves a link that then needs a password, the password
retry no longer asks again. The approval is an `OfferApproval` owned by one
pairing flow (one QR scan, or one open pair-link or add-host modal) and
only covers the exact offer that was approved.
Adds tests for a matching saved host, a changed key or relay, and the
password retry.
* Move host confirmation into the host runtime
The host runtime now owns the pending host confirmation and the decision to
ask. The sheet reads the pending confirmation and sends the answer; nothing
registers into a module variable.
A pairing flow is a LinkPairing the runtime hands out, so the password retry
for a confirmed link doesn't ask again without views creating or resetting
approval objects. Cancel is a result instead of an error. Pairing waits for
saved hosts to load before deciding whether to ask.
* Stop QR scanning after an attempt ends
The scan screen now keeps its workflow in a small model. When the user
cancels the host confirmation, closes the password prompt, or the attempt
fails, scanning stops until they tap Scan QR code again. Before, the code
still in front of the camera started a new attempt on the next frame.
A host confirmation answer is now tied to the request it answers, so a tap
on one sheet never answers a newer one. Relay hosts can no longer be added
through HostMutations without the confirmation, the add-host modal drops
the reset its per-open mount made redundant, and the fingerprint comment
says what the shortened form shows.
The selectable UIKit text view was a sibling of the Fabric content container, so existing chat rows kept an old width after Explorer changed the available pane. Make the container own the text view and preserve layout notifications on bounds changes. Includes a native geometry regression.
Wide native tooltips followed the desktop hover policy, and native tab chips disabled their long-press menu. Enable the existing touch actions while keeping tab navigation on completed press so horizontal scrolling does not select a tab. Keep URL-opening links from leaving a tooltip over the app on return.
Co-authored-by: Jichen <zhangjichen@oppentech.com>
Wide native panes previously followed the compact-layout gate, hiding terminal keys and skipping software-keyboard clearance. Keep bar eligibility tied to native touch while sizing rows from the available pane width.
Co-authored-by: Leandro Ardissone <lardissone@gmail.com>
* 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
Create a fresh branch from the recorded base when available, or the repository default, so archived agents remain accessible. Cover the server recovery choices and the browser restore-to-agent flow.
* feat(app): let users set the chat and Markdown content width
Wide and ultrawide screens were stuck with an 820px reading column. The
width is now an Appearance setting that flows through the Unistyles theme,
like the font sizes, so every content surface picks it up.
The stored value stays null until the user picks a width, so a future
change to the default reaches everyone who never customized it. Reset
writes null back.
The native composer dock keeps plain React Native styles and takes the width
inline because those styles land on Reanimated views, where theme-driven
Unistyles crash on theme changes.
* fix(app): pass the content width into the web stream viewport
The viewport read app settings itself, which required a QueryClient in every
render of the stream strategy. The agent stream view already reads settings,
so it hands the width over with the rest of the render input.
On the wide settings layout, a plugin settings screen showed only its title
and the plugin's content, so getting back to the Plugins page meant finding
Plugins in the sidebar again. The compact layout already had a Back header
and project settings already had a desktop "Back to projects" link. Plugin
settings screens now render a "Back to plugins" link on desktop the same
way, including when the screen is offline or unavailable.
Closes#5518
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
A new agent's draft pane rendered the chat outline with its local tab or
draft id, so the web app asked the daemon for that id's prompt index before
the agent existed and the daemon logged Agent not found. The outline now
waits until the viewed timeline has an epoch, which only a daemon-served
agent timeline has.
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
The ring's quarter-turn lived in a Unistyles style on the react-native-svg
root. On web, Unistyles only turns styles into classes for the React Native
components its Babel plugin rewrites, so the Svg received an empty style and
the arc started at three o'clock. The rotation now lives on the progress
circle as an SVG transform, which renders the same on web and native.
Closes#5596
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
A draft composer passed no command config when it was missing a project
or a provider, which is what a running agent's composer passes. The `/`
menu then listed commands by the draft key, got "Agent not found", and
showed /clear and /exit. Drafts now always report a command target
(ready, needs-project, needs-provider), and an incomplete draft asks for
the missing choice instead of querying.
Closes#5516
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
Co-authored-by: Ivan Malison <IvanMalison@gmail.com>
Resolve retained variants against the destination model before applying a model change. Publish the effective thinking choice and refresh the provider resume handle immediately so a reload cannot restore the old selection.
While a reply streams, presentation reparses only the growing last Markdown
block: the cached block text plus the new chunk. splitMarkdownBlocks drops a
trailing whitespace-only line, and only trailing "\n"s were added back, so a
reply that paused on "]\n " cached the block as "]". The next chunk " B -->"
then continued the previous line, joining two lines of a code block. Codex
streams a line break and the next line's indent as separate deltas, so its
Mermaid diagrams hit this and failed to render. History reparses the whole
text, which is why a reload showed the reply correctly.
Keep every trailing blank line the split drops on the last block.
Closes#5456
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
* Keep relative timestamps current in agent, schedule, and import-session rows
Agent list rows, schedule rows, and import-session rows formatted their
"5m ago" labels once at render, so an idle row kept its first label until
something else re-rendered it. They now use useTimeAgo, which rides the
same shared ticker the sidebar and desktop tabs already use.
Closes#4625
* Say "just now" for the whole first minute so fresh labels stay honest
The shared ticker wakes once a minute, so a seconds label could only go
stale. The prose and compact formatters now share one age description,
and the schedule spec anchors its clock to the schedule's creation time.
* Run every cleanup in the schedule relative-time spec and name its steps
* Keep relative labels current with focused subscriptions
* Update usage card after relative-time hook rename
* Anchor import-session age spec to fixture time
---------
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
* fix(app): show Windows file links relative to workspace
Tooltip formatting only handled matching POSIX separators, so Windows paths could remain absolute. Reuse the workspace file-path resolver for normalized relative paths.
* fix(app): preserve workspace-root link tooltips
Workspace file resolution deliberately rejects the root as an openable file, so tooltip formatting preserves its display-only dot form separately.
* fix(app): share workspace path rules for file link tooltips
* Show a host's new version after its daemon restarts
The app wrote a host's server info into the session store only when a
client was first mounted, and a reconnect reuses the same client, so
after a daemon upgrade or restart the host page and version checks kept
the old version until the app restarted.
The host runtime now projects the client's current server info into the
session store on every connection change, keeping the last known value
while disconnected. The React mount effect that duplicated this write is
removed.
Closes#5236
Co-authored-by: Leonid <127580858+bashrusakh@users.noreply.github.com>
* Keep a caller-owned test daemon home across startup retries
A failed start removed the home even with cleanup disabled, so a retry on a
taken port came back with a new serverId. The host restart spec now drives a
restartable host daemon helper that owns its port, home, and teardown.
* Remove only the test daemon dirs a failed start created
A failed attempt now removes the temp home and static dirs it created and
leaves caller-supplied ones, so cleanup: false no longer leaks per retry.
* Use function declarations in the test daemon helpers
* test(app): cover host versions across daemon disconnect and reconnect
The host settings badge retains its last known version during a transport failure; the help menu should show the replacement version after reconnect without changing another host.
---------
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
Co-authored-by: Leonid <127580858+bashrusakh@users.noreply.github.com>
Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>