mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-23 01:32:40 +00:00
main
194
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
55a7590952 |
Sort sidebar workspaces and keep active overflow visible (#7635)
Order ordinary sidebar workspaces by Created or Last prompt, preserve project and pin ordering, and keep later active or unacknowledged work visible beyond the first seven rows. Preserve reveal state through live updates and verify sorting, visibility, compatibility, and rendering behavior. |
||
|
|
9d908d678b |
feat(terminal): support image paste into agent TUIs, local and remote (#3795)
* feat(terminal): support image paste into agent TUIs, local and remote (#3725) Codex and OpenCode receive image pastes by binding Ctrl+V (\x16) and reading the OS clipboard of the machine they run on; no image bytes travel through the pty. Paseo's terminal swallowed that keystroke and only ever pasted text, so image paste silently did nothing. - web/Electron runtime: forward \x16 when the clipboard holds no text, keep the existing text-paste path otherwise (bash quoted-insert stays intact) - new terminal.clipboard.write_image RPC ships client clipboard bytes to the daemon, which writes them onto its host clipboard (osascript / wl-copy / xclip / Set-Clipboard) so remote clients work like local ones; gated by server_info.features.terminalClipboardImage with a bare-\x16 fallback for older daemons - clipboard tools are waited on via their exit event, not stream close: wl-copy and xclip fork a selection owner that inherits our pipes, so waiting for stream closure hung every Linux write until timeout - headless hosts without a clipboard get a temp-file fallback: the daemon materializes the image under os.tmpdir() and returns its path; the client injects it as bracket-pasted text - all four renderers covered (web DOM, Electron, native grid, WebView bridge); mobile Paste button enables for image clipboards and toasts failures in all 10 locales * fix(terminal): bind image paste to private retained files * fix(terminal): recover interrupted image metadata safely * fix(terminal): retire image files with background lifecycle maintenance * fix(terminal): check live paste modes and refresh native bridge * fix(terminal): order image paste input and isolate failures * fix(terminal): normalize paste and release failed creation reservations * fix(terminal): validate missing Windows launch paths before spawn * fix(terminal): keep input live during cancellable image uploads * test(terminal): follow streamed input-mode updates * feat(terminal): upload dropped images through the paste flow * feat(terminal): paste and drop images through file uploads Terminal image paste and drop now reuse the existing upload path (client.uploadFile -> file.upload.request -> FileUploadStore) and paste the quoted host path through the pane's input, bracketed when the app asked for it. This replaces the PR's daemon-side image store, RPCs, paste permits and file lifecycle, so the daemon, protocol and client diffs for this feature are empty. - terminal/image-paste owns a per-pane serial queue: gesture order, keystrokes stay live, Ctrl+C and pane/connection teardown cancel pending pastes, and a cancelled path is never pasted. - Clipboard text wins over an image; any image/* type is accepted up to the composer's 50MB upload limit. - Host paths are quoted for the host OS by path shape. - One failure toast; i18n keeps two keys. - Browser e2e covers two panes pasting distinct PNGs, drop, ordering, Ctrl+C cancel and disconnect against a real daemon. Co-authored-by: Gerard Balaoro <miogerard@yahoo.com> * fix(terminal): translate the disconnected image upload error * feat(terminal): report image uploads through toasts Show a lasting "Uploading image…" toast while an image uploads, replace it with "Image uploaded" or a failure toast that carries the reason, and dismiss it when Ctrl+C cancels the upload. Toast show now returns a dismiss scoped to that toast, so the pane can clear its own toast without removing a newer one. * build(terminal): regenerate the WebView HTML for the toast events * fix(terminal): keep i18n out of the terminal WebView bundle The image paste queue imported i18n for its size-limit message, which pulled every translation into the WebView HTML. The queue now reports a typed TerminalImageTooLargeError and the pane words it. * refactor(terminal): route dropped files by host locality and share the drop overlay A dropped file pastes its own path only when the host is the desktop app's own daemon (useIsLocalDaemon); anywhere else the host cannot read the client's disk, so the file uploads through client.uploadFile and the host path is pasted. File type no longer plays a part: images and other files take the same route, and clipboard images always upload because they have no path. The terminal pane now sits in the shared FileDropZone, so dragging files over it shows the agent panels' "Drop files here" overlay. The emulator's own drag listeners, blue tint and 180 ms timeout are gone. FileDropSink.onFiles is optional so a sink can take raw files without persisting raster images as attachments. terminal/image-paste becomes terminal/file-paste; the queue, callbacks, toasts and i18n keys say "file". * test(terminal): keep the fake desktop bridge in an e2e support helper The CI contract test forbids browser specs from installing paseoDesktop directly; the local-host drop scenario now imports it from support. --------- Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com> |
||
|
|
4ef4a95a42 |
Keep Claude session listing from loading whole histories into memory (#7626)
* fix(claude): stream and cache session import descriptors * fix(claude): bound and schedule import reads Reject JSONL records over 4 MiB explicitly to preserve metadata. Limit shared reads to four globally and one per listing for fairness. Deduplicate reads by cacheKey with independent subscriber cancellation. Set a 45-second provider deadline before the 60-second client timeout. Clone returned descriptors to isolate overlapping callers. Validation: 97 focused tests passed; independent review approved. Detected-By: user * fix(claude): parallelize resilient session scans Use up to four workers per listing with a shared four-read limit and bounded FIFO queuing. Preserve cache-key deduplication, subscriber cancellation, and candidate order. Log and skip oversized or unreadable transcripts so healthy sessions remain visible. Propagate programming and abort errors. Detected-By: user * fix(claude): surface session import read failures Skip expected candidate read failures and return healthy sessions. Distinguish unreadable metadata from parsed transcripts, and raise AggregateError when every candidate is unreadable. Propagate systemic file errors and narrow discovery error suppression. Detected-By: user * fix(claude): keep large sessions importable while streaming history Preserve import metadata for transcripts containing image records above 4 MiB. Stream complete records instead of rejecting otherwise listable sessions, and cover overlapping requests across aliased provider roots under a constrained heap. Co-authored-by: Josh Lane <joshlane@easypost.com> * test(app): wait for active agent controls and submitted turns Observe the mode control before testing Command Center keyboard selection. Observe a running turn before waiting for its completion, so the rewind test cannot mistake the previous idle state and end marker for the new turn. --------- Co-authored-by: Josh Lane <joshlane@easypost.com> Co-authored-by: Josh Lane <lane.joshlane@gmail.com> Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com> |
||
|
|
c3c6a936a4 |
List plugin header buttons in the workspace menu on phones and narrow windows (#7630)
* fix(app): list plugin header buttons in the compact workspace menu The compact header rewrite left plugin header buttons with no home, so phones and narrow windows had no way to reach them. They are now rows of the compact workspace menu, with menus and popovers as pages of its sheet, the way workspace scripts moved there. The header overflow and the workspace menu share one row/page builder. Each row and page resolves its own plugin installation's runtime: the old overflow routed every row through the first entry's host client. Closes #7601 * test(app): wait for agent control rows before keying the Command Center Two Command Center agent-control tests typed a query and pressed Enter or ArrowDown immediately. The agent's mode and model rows register after the panel opens, so on a slow runner the keys landed while only file search had matched and the mode never changed. The CI trace for the failure shows no Mode or Model rows at the moment of the key press. The tests now wait until both groups are listed, which keeps what they check: the best match wins, and a stale arrow-key selection is dropped. |
||
|
|
12e7a448f0 |
fix(app): open notification agents once in their current workspace (#7612)
* fix(app): open notification agents once in their current workspace Keep tap ownership across Activity and React remounts, clear native responses, and resolve agent workspaces through existing navigation after startup settles. Co-authored-by: Kassam Khoja <kassam@shopwrk.com> * fix(app): hydrate agent targets with the compact sidebar closed Hold directory demand for the agent route while resolving its workspace; the compact sidebar does not supply demand before it opens. * fix(app): keep deferred workspace opens in the layout model Key pending tab opens by workspace so redirects and retained screens cannot lose or consume another workspace's target. Legacy open URLs seed this state at their route boundary. * docs(app): document notification tap ownership and native replay * fix(ci): route feature-owned Electron sources to desktop checks * refactor(app): separate notification API from React integration * fix(app): consume pending opens before painting the restored tab A legacy open link showed the previously focused terminal for a frame before switching to the requested terminal. Seed and consume the pending open in layout effects so a ready target switches before paint. * fix(e2e): focus the visible retained terminal surface --------- Co-authored-by: Kassam Khoja <kassam@shopwrk.com> |
||
|
|
76b32544c6 |
Give Markdown and HTML file tabs back their Preview and Source views (#7614)
* fix(app): give Markdown and HTML file tabs back their Preview and Source views The built-in Markdown and HTML panels own one toolbar again: file size, line count, save status, vim mode, cursor, and a Preview | Source control over a body that shows the rendered preview or the editor from the same loaded content and editor model. Plain text files keep the toolbar on top. The host no longer renders a panel switcher. Source is the built-in panel for text files no other built-in claims, so it is never offered beside Markdown or HTML in the picker, the Open with menu, or Settings > Files. A line target opens the file's built-in panel in its Source view. * refactor(app): name the shared text file panel TextFilePanel Markdown and HTML own a Source view; they are not Source panels. The composite in file-panels/source/panel.tsx is now TextFilePanel, and SourcePanel is TextFilePanel without a Preview. Names only. |
||
|
|
91dca5702b |
Connect saved hosts and delegate agents across daemons (#7370)
* feat(hosts): connect to saved hosts through a daemon * fix(hosts): validate safe targets and verify encrypted relay routes * test(hosts): include relay coverage in existing CI contracts * fix(cli): preserve validated addresses in daemon command hints * fix(hosts): share daemon links across isolated routed sessions Multiplex logical sessions over the monitored daemon connection and wrap original binary bytes in routing headers. Admit channels under their authenticated parent and current grants; preserve scoped delivery and physical send completion. * fix(hosts): bound encrypted overload and initial acquisition Check encrypted wire capacity before the async channel converts a resource limit into a physical connection error. Bound initial routed acquisition with the existing client timeout, then enable reconnect after admission. * fix(hosts): keep compact row actions clear of host labels Give compact connected-host rows separate text and action widths so long names and producer labels cannot compete with primary controls. * refactor(hosts): remove management settings UI from phase one Keep connected-host management in the CLI and shared SDK while preserving app saved connections and plugin access. * test(hosts): control physical write backpressure across platforms Hold real TCP writes until assertions finish instead of assuming a paused receiver exhausts every platform receive buffer. Preserve physical send settlement, byte identity, capacity and sibling checks. * refactor(hosts): use the ordinary client contract over channel transports Keep queuing, permission codes and reconnection independent of transport selection. Track submitted request outcomes generically while retaining connection error codes and structured causes. * test(e2e): keep transient developer toasts from stalling checks Concurrent locator handlers can wait for a dismiss button another handler removed. Dismiss existing toast DOM at document lifetime, including its open shadow root, without intercepting app actions. * Create, prompt, and monitor agents across connected hosts (#7507) * feat(hosts): delegate agents across connected hosts Resolve MCP host operations through in-process commands for self and the existing routed client transport for other destinations. Keep ordinary parent labels, app sessions and idle finish notifications. * test(app): normalize subagent fixtures through snapshots * docs(protocol): clarify same-host parent labels * fix(hosts): resolve subagents through destination sessions A child address identifies its destination regardless of the connection used. Reuse the existing host candidate selection for discovered routes and direct connections, and keep navigation and row actions independent of the parent transport. * fix(hosts): keep routed destinations distinct during discovery A routed candidate names only the origin daemon. Match it within the named destination profile so two destinations discovered through the same origin retain separate identities and connections, including existing saved routes. * feat(hosts): prompt and query agents on selected hosts Extend the existing MCP host operation boundary with prompt, status, activity and list operations. Local calls retain their handlers and notification owner; selected destinations use ordinary client RPCs and the existing idle finish wait. * test(e2e): preserve toast coverage with CSS hiding * docs(hosts): translate connected host references |
||
|
|
fbd90cb88d |
Keep setup execution and output owned by the workspace (#7473)
* perf(workspaces): stop duplicating setup output in progress snapshots Keep the required combined log field empty for setup clients, which display per-command output. Preserve concatenation only for legacy agent bootstrap timeline cards whose released renderers still read it directly. * refactor(workspaces): own setup exclusively at the workspace boundary Preserve keyed modern agent worktree creation while retiring legacy placement that selected an agent-owned setup lifecycle. Keep output in per-command workspace snapshots and retain empty strings required by existing wire schemas. * fix(server): avoid duplicate cwd in worktree provisioning request * test(e2e): keep developer toasts out of concurrent app assertions Concurrent layout measurements could invoke the same Playwright locator handler before its first dismissal finished, leaving checks waiting for a removed button. Hide only the Expo toast host through test styling while retaining console error capture. |
||
|
|
30464cf234 |
Translate plugin content and labels in each app language (#7478)
* feat(website): serve paseo.sh in Simplified Chinese
Every page of the website now has a Simplified Chinese version under
/zh-CN: the interface, docs, blog posts, comparison pages, legal pages,
all changelog releases and the homepage mockup. English URLs are unchanged.
The URL alone decides the language. There is no browser-language redirect
and no stored preference, because either would have to redirect the
unprefixed English URLs that people share and search engines index.
Internal links carry the page's language instead, and hreflang alternates
point Chinese search results at /zh-CN.
Translated headings pin the English anchor with {#id}, so section links
work in both languages. content-translations.test.ts fails when a page
has no translation or a translation's headings drift from the English.
Changelog releases and plugin listings without a translation render
whole in English under a notice, so a release never waits on one.
Plugin manifests and the registry gain optional translations and
OVERVIEW.zh-CN.md fields; older clients and registries ignore them.
* feat(website): replace the native language select with an EN/ZH menu
The header showed an OS-native select whose popup did not match the site.
The trigger now shows the language abbreviated (EN, ZH) and opens a menu in
the app's dropdown style that names each language in itself, with its name
in the page language underneath. Rows are real links to the same page in
that language; arrows, Escape, outside presses and taps behave as a menu
button, and the menu keeps itself on screen when a narrow header pushes the
trigger toward an edge.
Also drops the stray space after the full-width comma in the Chinese
homepage subtitle.
* docs(website): translate main's new docs and 0.12.0 release notes
Main added Keep run workspaces to the schedules docs, rewrote plugin icons
around inline SVG, and promoted 0.12.0 with new entries. Bring the Chinese
pages and changelog in line so no section falls back to English.
* fix(server): leave plugin listing translations to the registry
The daemon rejected manifests whose translations the registry would refuse,
so a plugin main installs could fail to load here. Paseo never reads
translations; the registry validates them at publish. Docs now say which
checks are automated at publish and which are human review.
* docs(plugins): describe the registry's final overview translation discovery
* style(server): format manifest test
* feat(plugins): translate plugin UI in each app language
Keep translation resources and subscriptions inside each installation. Resolve host labels against the presentation locale so live language changes preserve mounted drafts and RPC state. Existing descriptor types retain string defaults for source compatibility.
* test(plugins): dismiss developer chrome in second translation client
* test(app): measure sidebar rows one at a time
After a reload the developer error toast appears while expectVerticalOrder
measures every row at once. Each concurrent boundingBox runs the toast
locator handler, and only one of them resumes, so the poll timed out on
every attempt since #7424. Measuring sequentially keeps one action in flight.
* test(app): return sidebar row measuring to main
#7480 hides the developer toast instead of running a locator handler, so
measuring the rows concurrently no longer races it. Reverts
|
||
|
|
9bce7dbd25 |
refactor(plugin): unify the client UI entrypoint (#7474)
* fix(files): report document MIME types for binary files File reads now carry the document's MIME type for binary files, so a file panel can hand the bytes to a viewer that needs the real type (application/pdf). * feat(plugins): file panels Plugins contribute file panels with addFilePanel. A file tab hosts the panels that claim the file: the built-in Markdown, HTML and image panels, plugin panels, and Source, Paseo's editor, which claims every text file and is always the last candidate. The panel is the tab body; the bar shows the document's status and a switcher between the file's panels (side by side up to three, two on a phone, a menu beyond that). Paseo asks which panel opens a file only when a plugin panel is among several candidates, once per open, and remembers the answer per extension or exact filename when told to. Open with in the tab menu and the switcher change the tab's panel; Always use remembers it. Opening a file at a line switches the tab to Source. Panels read and write the host's document, so dirty state, autosave and conflicts stay Paseo's. DocumentFrame shows bytes documents such as PDFs in the browser's viewer. Replaces the file tab's Preview/Source mode toggle. * feat(file-panels): choose and forget file panels in Settings > Files Settings > Files lists each extension or filename where a plugin panel competes with another candidate, or that has a remembered panel. Each row chooses the panel that opens it, or Ask every time; Ask again forgets the choice. Source appears as a candidate for text files. Panels no connected host offers can be forgotten but not chosen. * docs(plugins): file panel examples and author reference Adds the pdf-panel and markdown-panel examples, the File panels section of the plugin reference, and an e2e spec that installs both examples, opens a PDF in the browser viewer, and edits Markdown through Paseo's document across the switcher, Source, autosave and conflicts. * feat(file-panels): panels read and write through a file handle The file tab stats the file and mounts its panel without reading it. Every panel, built-in or plugin, gets a PluginFile handle: readText, readBytes, url, version-checked writeText/writeBytes (PluginFileConflictError unless force), and watch. useFileText, useFileBytes and useFileUrl read through it, and Loading joins @getpaseo/plugin/client/ui. Panels own their loading state. The host document pipeline, the explorer preview cache and the preview lifecycle are deleted. The daemon classifies a file version from a bounded sniff and writes base64 content as bytes behind fileByteWrites. A deleted file keeps its panel mounted; a read confirms the deletion first, so a remove-and-rewrite is not reported as one. Native Source decodes with builtins and highlights in idle-time slices, the lines around the opening line first, so a large file no longer blocks the JS thread. * fix(file-panels): Settings offers Source where the picker does, and review follow-ups - Settings > Files offers Source on every key except those a built-in panel of another kind (Image) claims, so a plugin that alone claims a text extension shows the same choices as the picker. - Delete the unused isSourceFilePanel. - The Markdown example warns with the file name when its unmount write fails, rather than dropping the edit silently. - Document that PluginFile stat fields are read at render time and that watch or the read hooks are how a panel learns they changed. * refactor(plugin): consolidate the client UI entrypoint |
||
|
|
e464fd3bd3 |
feat(plugins): file panels (#7411)
* fix(files): report document MIME types for binary files
File reads now carry the document's MIME type for binary files, so a file panel can
hand the bytes to a viewer that needs the real type (application/pdf).
* feat(plugins): file panels
Plugins contribute file panels with addFilePanel. A file tab hosts the panels that claim the
file: the built-in Markdown, HTML and image panels, plugin panels, and Source, Paseo's editor,
which claims every text file and is always the last candidate. The panel is the tab body;
the bar shows the document's status and a switcher between the file's panels (side by side
up to three, two on a phone, a menu beyond that).
Paseo asks which panel opens a file only when a plugin panel is among several candidates,
once per open, and remembers the answer per extension or exact filename when told to. Open
with in the tab menu and the switcher change the tab's panel; Always use remembers it.
Opening a file at a line switches the tab to Source.
Panels read and write the host's document, so dirty state, autosave and conflicts stay
Paseo's. DocumentFrame shows bytes documents such as PDFs in the browser's viewer.
Replaces the file tab's Preview/Source mode toggle.
* feat(file-panels): choose and forget file panels in Settings > Files
Settings > Files lists each extension or filename where a plugin panel competes with
another candidate, or that has a remembered panel. Each row chooses the panel that opens
it, or Ask every time; Ask again forgets the choice. Source appears as a candidate for
text files. Panels no connected host offers can be forgotten but not chosen.
* docs(plugins): file panel examples and author reference
Adds the pdf-panel and markdown-panel examples, the File panels section of the plugin
reference, and an e2e spec that installs both examples, opens a PDF in the browser
viewer, and edits Markdown through Paseo's document across the switcher, Source,
autosave and conflicts.
* feat(file-panels): panels read and write through a file handle
The file tab stats the file and mounts its panel without reading it. Every
panel, built-in or plugin, gets a PluginFile handle: readText, readBytes, url,
version-checked writeText/writeBytes (PluginFileConflictError unless force),
and watch. useFileText, useFileBytes and useFileUrl read through it, and
Loading joins @getpaseo/plugin/client/ui. Panels own their loading state.
The host document pipeline, the explorer preview cache and the preview
lifecycle are deleted. The daemon classifies a file version from a bounded
sniff and writes base64 content as bytes behind fileByteWrites.
A deleted file keeps its panel mounted; a read confirms the deletion first,
so a remove-and-rewrite is not reported as one. Native Source decodes with
builtins and highlights in idle-time slices, the lines around the opening
line first, so a large file no longer blocks the JS thread.
* fix(file-panels): Settings offers Source where the picker does, and review follow-ups
- Settings > Files offers Source on every key except those a built-in panel of
another kind (Image) claims, so a plugin that alone claims a text extension
shows the same choices as the picker.
- Delete the unused isSourceFilePanel.
- The Markdown example warns with the file name when its unmount write fails,
rather than dropping the edit silently.
- Document that PluginFile stat fields are read at render time and that watch
or the read hooks are how a panel learns they changed.
* fix(plugins): file events are objects, deletion is a typed error, DocumentFrame owns its fallback
- watch listeners receive { type: "changed" } | { type: "deleted" }, so later
versions can add fields without breaking them.
- PluginFileDeletedError joins PluginFileConflictError. The read hooks report a
deleted file with it, and a write over a deleted file rejects with it; Source
shows that as the deleted notice. PluginFileConflictError now means only
"changed on disk".
- DocumentFrame on Android shows Paseo's "<TYPE> files can't be shown on this
device" message for documents its WebView cannot display, so the PDF example
is useFileUrl + Loading + DocumentFrame with no platform branch.
* test(file-panels): Settings offers Source for a remembered panel no host has
* test(e2e): hide the developer error toast instead of clicking it away
The locator handler that dismissed #error-toast could match a toast that closed before its
click, then wait on it until the test timed out (agent-timeline-resume.spec.ts:45 failed every
attempt on this branch). Hiding the toast with CSS keeps it off app actions with no race.
* test(e2e): desktop browser-tabs hides developer toasts on its attached page
|
||
|
|
461ea2ee9e |
test(e2e): hide the developer error toast instead of clicking it away (#7480)
* test(e2e): hide the developer error toast instead of clicking it away The locator handler that dismissed #error-toast could match a toast that closed before its click; dispatchEvent then waited for the gone button until the test timed out. Hiding the toast with CSS keeps it off app actions with no race. * test(e2e): desktop browser-tabs hides developer toasts on its attached page |
||
|
|
adf27de7d0 |
Keep Explorer consistent across phone, tablet and desktop layouts (#7424)
* Upgrade to Expo 57 and unify Explorer across layouts * feat(app): retain Explorer across layout and appearance changes Keep one workspace Explorer host and destination-aware navigation so folding, theme updates and compact sheets preserve the current panel. Scope pull request discovery and timeline demand to active surfaces. * fix(app): keep Explorer resize handles stretched through the dock The shared frame moved the divider into an absolute column, leaving its horizontal handle without height. Restore the row so pointer drags reach it, preserving the existing resize and performance contract. * fix(app): keep Explorer drag widths out of the shared stylesheet Carry the existing inline sizing policy into the shared frame so pointer previews do not accumulate CSS rules. * fix(test): align isolated test runtimes with Expo 57 Hoisted React consumers need the matching DOM renderer at the repository root. Automated Metro processes must not install native DevTools into disposable homes, and development toast overlays must not cover compact actions. Keep Explorer journeys on the shared host and synchronize setup fixtures on daemon output rather than a one-second file-marker window. A delayed real child start reproduces the readiness failure on every platform. * fix(test): await retained shell layout after composer resize The gesture host now stays mounted across breakpoints, so its presence no longer identifies compact layout. Report the current layout on the retained host and synchronize composer journeys with that state. * fix(app): preserve browser interactions in retained workspace hosts Initially disabled gesture hosts still registered pointer and wheel listeners, while hover cards used window positions inside a workspace-local sheet portal. Respect initial gesture enablement and position cards relative to their measured floating host. Keep developer-toast dismissal independent of pointer input and replacement toast visibility so modal, hover, and focus checks retain their input state. * fix(test): share developer toast handling with Electron browser runs The standalone Electron browser runner bypassed the browser fixture, allowing developer errors to cover Settings. Use the same non-pointer dismissal in both runners while retaining their console logs. |
||
|
|
1c8c68f93e |
Keep workspace setup logs scoped to the visible setup panel (#7407)
* fix(workspaces): observe setup output only in the visible setup panel Setup logs were requested for the whole session, including unrelated workspaces. Use directory status for discovery and source-owned workspace observations for details, preserving legacy delivery only for clients without the negotiated capability. * fix(workspaces): publish external setup progress once per daemon MCP and scheduled setup enter through the broadcast API. Publish them to the shared setup owner before session fanout so each observation gets one update and snapshots survive periods without connected clients. Keep the setup action available on older hosts to explain the required host update. * fix(app): replace setup details with each observation snapshot A host restart can return an empty setup snapshot. Apply that authoritative snapshot so an open panel does not retain output from the previous daemon. Assert setup membership requests as well as delivery in the browser lifecycle regression. * test(workspaces): cover setup status catch-up after directory release * test(workspaces): synchronize setup output and release fixture resources |
||
|
|
b8bcd204a9 |
Dismiss touch composer focus when switching tabs (#7352)
* fix(app): dismiss touch composer focus when switching tabs A retained tab can hide and return before Chromium paints, preserving the focused textarea without another focus call. Blur web touch editors when their pane becomes inactive so returning leaves the conversation ready to read. Exercise the same mounted editor through a second edit and keyboard navigation cycle. * test(app): reproduce touch tab focus race before paint --------- Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com> |
||
|
|
9ed4f1069b |
fix(app): create project workspaces on the active host (#7308)
Grouped sidebar projects chose the first eligible host even while a workspace on another host was active. Prefer that active host when online and eligible, keeping the existing fallback for other placements. Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com> Co-authored-by: Michael Whitman <michael.whitman@getsteward.ai> |
||
|
|
a65478d0bf |
Rank Command Center results by match then recency, with highlights, timestamps, and project icons (#7277)
* feat(app): rank, highlight, and timestamp Command Center results
Workspace and agent rows now show when they were last active, rank by
match quality and then recency, mark the query terms in every result
kind, and lead workspaces with their project icon.
Ties used to be broken by where the match landed in the string, so
"Deliver sidebar usage" beat "expose usage data" on sentence position
and recency almost never decided anything. Built-in rows now compare
only which fields matched and the matcher tier, then the most recent
row wins. The empty query follows the same rule, so it lists the most
recent workspaces and agents instead of alphabetical workspaces and
status-first agents.
Row and section heights live in list-metrics: a layout picks one row
inset and every height derives from it plus shared line boxes, which
the styles also read. The layout is chosen once at the top, so rows
never branch on it, and two-line rows are now vertically centered.
Desktop is denser (32/46); compact keeps 44pt touch rows (44/58).
findHighlightRanges takes the matcher's options so the marks match
what the list matched: the Command Center is not typo-tolerant, the
history list is.
* fix(app): keep the project icon out of Command Center row names
The fallback project icon draws the project's initial as text, which
became the first word of the row's accessible name ("C Command Center
..."), so screen readers announced it. The icon is decorative.
The scroll spec now reads the newest seeded workspace: the empty query
lists the most recent workspaces, so the first one seeded is no longer
among them.
|
||
|
|
cf62b00911 |
Keep last successful usage visible when refresh fails (#7246)
* fix(usage): retain last successful data when polls fail Keep the latest poll outcome separate from its successful snapshot so errors remain visible without discarding known usage or advancing its freshness. Preserve attempt timestamps for response ordering and isolate retained values by scoped login set. * fix(usage): preserve history through discovery failures A failed account-store read does not confirm that an account was removed. Retain its existing host mapping until successful discovery replaces it, without carrying mappings across agent launch environments. |
||
|
|
a4eb0adcf6 | test(app): consolidate overlapping Playwright journeys (#7245) | ||
|
|
eb1a8a2ec7 |
fix(markdown): one renderer on react-native-enriched-markdown for iOS, Android and web (#6973)
* fix(app): group native assistant prose into selectable runs * fix(app): render selectable native prose with enriched markdown * docs: explain native prose selection boundaries and tradeoffs * fix(app): preserve markdown semantics and render limits in prose runs * docs: record native prose compatibility fixes and heading limits * fix(app): allow additive task lists and admonitions in native prose * fix(app): preserve inline image formatting and reference scope * fix(app): preserve markdown source and file actions in native prose Prepare original source blocks with source-position edits from the assistant parser. Keep reference scope and live/history projection consistent, and retain link text when dispatching workspace file actions. * fix(app): preserve native prose entities and links while bounding preparation cost * fix(app): preserve provisional syntax at cached reveal boundaries * fix(app): bound prose append work and preserve markdown edge cases * fix(app): preserve home paths and normalized prose links * fix(app): preserve parser-owned links and streaming tilde tails * fix(app): keep growing markdown on the streaming block renderer * fix(app): preserve bracketed IPv6 links in native prose * fix(app): skip prose classification for blocks over the render cap * fix(app): share selectable native prose across Markdown surfaces * fix(app): preserve Markdown containers before grouping prose * revert(app): remove shared prose-run renderer changes Reverts ab4737bb2 and ac47e1063 before replacing the Markdown engine across all platforms. * feat(markdown): use enriched renderer across all platforms * test: verify library image controls and isolate website config * fix(markdown): preserve file links and image revisions * fix(markdown): restore diagrams and preserve link origin * fix(markdown): retain diagram identity and reference scope * fix(markdown): avoid empty web history measurements * fix(markdown): preserve authored empty link titles * test(markdown): exercise find across whole-message history * fix(markdown): preserve encoded image paths after rebase Keep the shared renderer image normalization and file-read regression coverage that originally lived in the main integration merge. * fix(markdown): derive table and task list colours from the theme * fix(markdown): restore selection highlight on web * fix(markdown): restore file link hover tooltips on web * fix(markdown): normalize inline HTML before rendering * fix(markdown): create renderer types when applying package patch The published nightly omits both MarkdownRenderers type files. Represent them as new files so patch-package succeeds on a fresh npm install, matching the already patched development package. * fix(markdown): keep the renderer tree stable while images resolve * fix(markdown): size inline images to the line and collapse failed loads * fix(markdown): normalize only parsed HTML nodes * fix(markdown): keep the first image reference definition * fix(markdown): preserve complete assistant messages on native * fix(markdown): classify web links explicitly and complete renderer types * fix(markdown): preserve spacing between HTML elements * fix(markdown): normalize HTML following code elements * fix(markdown): preserve literal image fallback labels * fix(markdown): retry transient image decode failures * docs(markdown): record native selection and image limitations * fix(markdown): preserve first definitions across Mermaid segments * fix(markdown): reserve pending images and harden web rendering * test(markdown): cover state retention during image arrival * fix(markdown): preserve reader position while responses grow Keep the same message component boundary when a live row becomes retained history, preserving Mermaid runtimes and selection nodes. Observe paced child text commits at the web viewport so sticky-bottom follows before the next frame. * test(markdown): require growth while holding a streaming paragraph * test(markdown): isolate image arrival from reload positioning Mounted row totals change as history virtualizes, so observe the new response and tool directly. Hold the real PNG response after reload until the reading position settles, then verify its reserved height and viewport instead of attributing initial bottom-follow positioning to image decoding. * fix(markdown): preserve adjacency around inline HTML * fix(markdown): keep summary block boundaries outside bold text * perf(markdown): scan HTML block boundaries incrementally * test(markdown): gate delivery while establishing a held reader * test(markdown): name shared renderer setup and file actions * test(markdown): assert linear HTML boundary work without timing * test(markdown): check large HTML table output without observing built-ins * fix(markdown): restore accentBright link colour * fix(markdown): require letters and known extensions in bare path recognition * fix(markdown): match main's blockquote, bullet and h6 colours * fix(android): keep inverted chat still during text selection React Native decomposes Android list inversion into a 180-degree rotation with positive scaleY, so the existing visibility-scroll guard never recognized the inverted viewport. Inspect the composed matrix and reproduce the actual list transform through the native view manager in regression tests. * fix(markdown): linked inline code keeps inline code size * fix(markdown): reserve a placeholder box with an image glyph while images load * fix(markdown): bare prose paths need an extension, line suffix or depth Slash-separated English pairs were recognized as file links in prose. Require stronger path intent there while preserving the existing inline-code recognition rule. * fix(markdown): horizontal blocks own their drags on compact layouts * perf(markdown): keep native streaming updates in the unfinished tail Native markdown reparses each updated view in full. Keep parser-closed blocks in a memoized head during paced reveal, then reunite completed prose for cross-paragraph selection. Preserve trailing spacing and source indentation at the split. * perf(markdown): reuse Android measurements across view mounts * test(markdown): bare Fabel/model and daemon/client stay plain text when copied |
||
|
|
62ab2deb27 |
Run and watch workspace scripts from the phone header menu (#7122)
* feat(app): run and watch workspace scripts from the compact header menu The compact header redesign dropped the mobile scripts button, so phones had no way to run, stop, or restart workspace scripts. Scripts are now a page of the ⋯ sheet: the root row shows what is running, tinted by health, and the ⋯ carries a dot while a running service is unhealthy. Desktop keeps its popover; both surfaces share one set of script actions and one status model. Script status also froze on native whenever the sidebar was closed and no agent tab was viewed. DirectorySynchronizer releases its subscriptions, including script_status_update, when nothing demands the directory, and the workspace screen never demanded the workspace it shows. Web hid this because the favicon sync holds demand for the whole session. The focused workspace now holds directory demand, which also lets Restart's second half (start once the daemon reports the script stopped) complete. * perf(app): keep workspace script status live without syncing the directory The focused workspace held full directory demand so the scripts menu saw script_status_update on phones with the sidebar closed and no agent tab. That fetched the host's agent and workspace lists on every focus and streamed every agent and workspace update for the whole host. Script status now has its own event subscription, which a workspace screen can hold alone. It fetches the workspace's scripts once when the subscription lands, because the subscription only carries changes. Directory demand also holds it, so the sidebar and agent tabs see the same updates as before. |
||
|
|
5acfbb3777 |
Let Escape close plugin previews before stopping agents (#7110)
* fix(app): let Escape close an open popover before it interrupts the agent The agent.interrupt shortcut listens on the window in the capture phase, so it sees Escape before anything else. Registered overlays get first refusal through dispatchTopWebOverlayKeyDown, but plugins cannot register, and draw their floating panels with the Popover API instead. With such a panel open and the composer focused while an agent runs, Escape closed the panel and interrupted the agent in the same press. While a popover is open, Escape is left to it and no app shortcut runs. A second Escape, with nothing open, interrupts as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: RoundRedDot <roundreddot@gmail.com> * test(app): cover Escape with a popover open through the shortcut path The first test only checked hasOpenDomPopover and would still pass with the guard removed from useKeyboardShortcuts. The check is now keyBelongsToDomPopover, called by the hook, and a browser test drives it the way the app does: a window capture listener for shortcuts, a popover closed by its own document Escape listener, focus in a textarea. The first Escape closes the popover with no interrupt; the second interrupts. Both new tests fail with the guard removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: RoundRedDot <roundreddot@gmail.com> * test(app): exercise plugin Escape through the real composer Keep the contributor fix and replace the substitute shortcut-listener test with an installed-plugin browser regression. The first Escape must close the preview without cancelling the turn; the second must cancel it. Co-authored-by: luke <luopeihuan@gmail.com> Co-authored-by: RoundRedDot <roundreddot@gmail.com> * test(app): check dismissed model pickers leave the viewport --------- Co-authored-by: luke <luopeihuan@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: RoundRedDot <roundreddot@gmail.com> Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com> |
||
|
|
8388f16186 |
Keep Add Project keyboard selection visible (#7081)
* fix(app): scroll the Add Project results to the keyboard-selected row The results list had no scroll ref, so ArrowUp/ArrowDown moved the selection off-screen; the autocomplete reveal math is now shared through useRevealActiveItem. * test(app): verify the directory selected beyond the results viewport Check scrolling in both directions and across wrapping, then confirm Enter opens the selected directory. The previous regression used an aria-selected attribute that result buttons do not render. Co-authored-by: superheher <heh@vivaldi.net> * test(app): verify scroll reveal through browser behavior Keep pure offset checks and cover keyboard navigation, wrapping, and replacing search results in the real Add Project flow. * fix(app): measure retained Add Project rows when revealing selection * fix(app): measure scroll content through a native View reference --------- Co-authored-by: superheher <heh@vivaldi.net> Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com> |
||
|
|
d9b874f9d0 |
Scroll chat with Page Up and Page Down after clicking messages (#7033)
* fix(app): focus chat feed when clicking message content * test(app): wait for new chat output before checking scroll position Co-authored-by: Ivan Pantic <panta@talentkit.io> * test(app): capture the keyboard paging regression * test(app): verify paged chat text stays in place --------- Co-authored-by: Ivan Pantic <panta@talentkit.io> Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com> |
||
|
|
208e323035 |
Keep usage providers in place after refresh (#6947)
* fix(app): preserve usage provider order across refreshes * test(usage): keep refresh and scrolling journeys stable Usage reports can follow the long fixture card, so a fixed wheel distance can scroll past its final window. Target the named windows with wheel input while preserving the visibility checks. Assert refreshed provider order through visible names and keep viewport setup in journey helpers. Co-authored-by: Sleroq <hireme@sleroq.link> --------- Co-authored-by: Sleroq <hireme@sleroq.link> Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com> |
||
|
|
16bb179e67 |
feat(providers): add opt-in Hoplite and searchable provider grid (#6953)
Preserve the bundled Hoplite ACP adapter and provisioning transformer, activate it only after Add, and provide a searchable provider grid. Restore the contributor's original icon without the copyright mark. Co-authored-by: Odin Glynn-Martin <odin.glynn@icloud.com> |
||
|
|
e5124b039a |
Put sheets on one stack and show an agent's facts in its sheet (#6958)
* Put sheet tabs on the one sheet stack Sheets are one primitive with one stack. A sheet opened from any sheet stacks on top of it, and closing it uncovers the sheet underneath. The compact workspace's file and subagent sheets were an in-tree Gorhom BottomSheet with their own stacking, so a subagent chosen from the subagents list sheet replaced the list instead of covering it. - SheetHostScope: a subtree hosts the sheets presented inside it, so the sheet tabs draw inside the compact column and read the workspace providers while still joining the app-wide stack. Needs Gorhom's BottomSheetModalInternalProvider, which the patch exports. - IsolatedBottomSheetModal takes enableDismissOnClose; false keeps the content mounted through a close so the unsaved-changes guard can veto it. Its backdrop then closes the sheet rather than dismissing the top modal. The Gorhom patch also keeps a dismissing modal's status through its final onChange(-1), without which such a modal unmounting while presented never left the portal. - SheetTabs (was WorkspaceSheetHost) renders one IsolatedBottomSheetModal per store entry. The store never reorders sheets; a reveal of a covered sheet drops the unmodified sheets above it. - Subagent rows that open a sheet keep the list open (closeOnSelect false); rows that open a tab still close it. - A menu closes when its retained panel goes inactive, instead of hiding and reappearing with the panel on the next tab switch. Co-Authored-By: Claude <noreply@anthropic.com> * Show an agent's model and thinking in its sheet, and fit Open as tab in the header rail A Paseo agent shown in a sheet has no composer, so the facts the composer's model and thinking controls would show now sit in one line under the sheet header, the same row provider subagents already get from the daemon. The line resolves exactly as the controls do (resolveAgentModelSelection), from the session agent and the providers snapshot, and shows wherever the pane host is a sheet. Open as tab becomes the full-screen glyph beside Close, drawn by the shared SheetHeaderIconButton, so the title keeps its width. The tab switcher sheet is titled "Workspace tabs" so it reads as what it lists. Co-Authored-By: Claude <noreply@anthropic.com> * Show mode and context usage in the sheet facts line The line under a sheet's header now carries everything the composer's controls and context meter show: model, thinking, mode, and used/max context tokens with the share, each resolved as its control resolves it. Co-Authored-By: Claude <noreply@anthropic.com> * Re-render subagent rows when the workspace's tabs change A row decides at render time whether choosing it opens a sheet or reveals a tab, and keeps the list open only for a sheet. The hook behind it only subscribed to the layout mode, so a row rendered while its agent was a full tab kept closing the list after that tab was gone: on iOS, promoting a managed child, closing its tab, and reopening it from the list dropped the list under the sheet. Subscribe to the workspace's layout too. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
6db47b3c37 |
fix(app): keep the keyboard closed after mobile sidebar dismissal (#6945)
Separate composer keyboard eligibility from pane focus restoration. A sidebar dismisses the keyboard without hiding the pane, so its close must not restore editing focus. |
||
|
|
73221ce5bd |
fix(app): render local Markdown images with encoded paths (#6877)
Decode assistant Markdown image destinations before resolving a filesystem read. Keep plain filesystem paths and direct image URIs unchanged so Markdown Preview and literal percent filenames are decoded only once. Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com> |
||
|
|
6ad124758c |
Stack workspace sheets and tighten sidebar density (#6885)
* Stack workspace sheets and tighten sidebar density - Workspace sheets stack: opening a target from a sheet covers it, Back and drag close only the top sheet, and the header is the sheet's drag handle. - The workspace sheet reuses the shared sheet handle, background and header. - Fix the shared sheet handle indicator rendering black. - Sidebar text returns to semantic sizes; Pinned and Workspaces share one section header. * Pause covered workspace sheets and mock the shared sheet handle in tests * Export BottomSheetHandle from the browser test Gorhom stub * Let a stacked sheet's backdrop catch taps on iOS * Bring a revealed sheet to the top instead of duplicating it as a tab |
||
|
|
f3ddf99fe3 |
fix(app): restore fullscreen composer keyboard motion and clearing (#6902)
* fix(app): keep fullscreen composer in the keyboard dock * fix(app): preserve composer caret and scope keyboard actions |
||
|
|
56448842f0 |
Download files over the connected host (#6595)
* Let readFile callers disable the request timeout readFile resolves only when FileEnd arrives, so the default 60 s request timeout bounds the whole transfer. A large file over a slow relay fails before it finishes even though every chunk is arriving. Thread an optional timeout through requestFileExplorer; 0 disables the timer, as the workspace.create request already does, and a dead connection still rejects on disconnect. The relay e2e case reads a 1 MiB file through a real daemon and a local relay with timeout 0 and compares SHA-256 digests with the source. * Reject a binary file transfer whose byte count differs from FileBegin.size concatByteChunks allocated FileBegin.size bytes and copied the chunks in: a short transfer resolved as a zero-padded file, and a long one threw a RangeError inside the transport callback and left the request pending. Count the received bytes at FileEnd and reject the read when they differ from the announced size. * Download files over the session socket when no direct connection is active The download store only knew the HTTP token route and picked the first directTcp connection in the host profile, whatever connection the host runtime was using. A relay-only host has none, so every download ended in "Download host is unavailable." (#543). SSH, socket and pipe hosts failed the same way, and a stale directTcp entry won over a working relay (#3753). Choose the transport from the active connection: directTcp keeps the HTTP token download unchanged; anything else reads the file over the session socket with the binary frames previews already use, then hands the bytes to the browser's download manager on web and Electron or writes them to the cache directory and offers the share sheet on native. Files over 64 MiB are refused before any byte moves, using the existing fileTooLarge string, and a daemon response without content fails instead of saving an empty file. * fix(app): enforce the session download size limit during the read The token size is sampled before the file is read. Pass the download byte budget through the actual read so a changed file cannot bypass the in-memory limit. Co-authored-by: Michael Vandesompel <mv@droggol.be> Co-authored-by: YASICJUNWOO <joonoo3@naver.com> Co-authored-by: JrDw0 <JrDw0@users.noreply.github.com> * test: verify TCP downloads and own relay fixture cleanup --------- Co-authored-by: Michael Vandesompel <mv@droggol.be> Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com> Co-authored-by: YASICJUNWOO <joonoo3@naver.com> Co-authored-by: JrDw0 <JrDw0@users.noreply.github.com> |
||
|
|
ada7ba43f0 |
Keep long custom models removable in provider settings (#6507)
* fix(app): keep long custom models removable Custom model labels and IDs could consume the row width and push Remove outside the sheet. Allow those text cells to shrink while preserving the button width and short-name alignment. * test(app): wait for legacy agent creation before checking prompts Agent-list membership includes initialization. Waiting for finish at that point can return on the initial idle transition before the initial prompt starts. Wait for the matching creation response before checking each completed turn, preserving the existing exact-once assertions. * test(app): wait for directory search keyboard focus The search page becomes visible before its deferred focus callback runs. Wait for the input to own keyboard focus so the journey types its query rather than dropping it during navigation. --------- Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com> |
||
|
|
019e5279e9 |
Show Claude option previews in the question card, readable on Android (#6171)
* Show Claude option previews in the question card * Wrap long lines in question option previews * Check option previews under the option that owns them * Show the whole option preview on native so every line is reachable On Android, a slow drag inside a preview capped at 240px did not scroll it, so lines past the cap could not be read. The preview's nested scroll sits inside the option's Pressable; the same drag scrolls it once the preview is outside the Pressable. Native now renders the preview at full height so the chat scroll reaches every line, and a tap on it still selects the option. Web keeps the 240px cap. The mock agent's rollout preview is now taller than the cap so the Android replay can check the last line. --------- Co-authored-by: Gabriel Giordano <hello@gabrielgiordano.com> Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com> |
||
|
|
e135e9c101 |
Open files and subagents in a closable sheet on phones (#6827)
* feat(app): open files and subagents in a closable sheet on compact On phones, opening a file, a provider subagent, or a Paseo subagent now shows it in a bottom sheet over the current tab instead of adding a tab, so the tab strip stays for terminals and root agents. Paseo subagents get "Open as tab" to move the same tab (same tabId and state) into a full tab with a composer; agents in a sheet hide the composer. The decision lives in the workspace layout store's openTab, driven by a per-kind `compactSheet` rule in the panel manifest, so every open path (chat links, Explorer, subagents track, notifications, plugins) follows it without call-site branching, and a new kind opts in with one manifest entry. The app shell publishes the layout mode (compact / single-pane / split-panes) once, so callers stop passing isCompact for placement. A sheet holding unsaved edits is never implicitly displaced; later opens go to tabs underneath, and closing it goes through the existing discard guard. The editor host is position: sticky because CodeMirror's scrollIntoView otherwise scrolls the bottom sheet's container and drags the sheet to full height. * test(app): fail the compact sheet snap check when the sheet is oversized --------- Co-authored-by: paseo-bot[bot] <paseo-bot[bot]@users.noreply.github.com> |
||
|
|
ec6393f31f |
Keep pairing QR codes fully visible on mobile (#6758)
* Keep pairing QR code within compact tile * Move pairing screenshot after viewport assertion * test(pairing): verify the complete QR code on Android The native regression failed with the fixed-size SVG because the code was clipped at both screen edges. Verify the complete square and visible margins through the Android app, and keep browser geometry assertions in the pairing helper. Co-authored-by: fdkevin <25277753+fdkevin0@users.noreply.github.com> --------- Co-authored-by: fdkevin <25277753+fdkevin0@users.noreply.github.com> Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com> |
||
|
|
99e4b53aa0 |
fix(app): restore outline jumps to prompts rendered by plugins (#6690)
* fix(app): jump the chat outline to prompts a timeline plugin draws A timeline transformer replaces a stream item with plugin rows whose ids are "<pluginId>/<itemId>". The chat outline, chat find and history reveal look a message up by the source item's id, so once a plugin drew the prompts the outline found no row: the rail showed the prompts and clicking one did nothing, for mounted, virtualized and unloaded prompts alike. Projected plugin rows now carry the id of the item they replaced, and getStreamItemMessageId answers with it. Row wrappers, the virtualized index lookup, the visible-message set and history reveal all read that function, so they now find the plugin row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(app): verify outline jumps to virtualized plugin prompts Replacing every prompt keeps all loaded rows mounted, so the original plugin regression never exercised a virtualized target. Retain newer native prompts and verify that a loaded unmounted plugin prompt lands without fetching. Co-authored-by: luopeihuan <luopeihuan@roundreddot.com> * test(app): retain outline navigation screenshots --------- Co-authored-by: luopeihuan <luopeihuan@roundreddot.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com> |
||
|
|
750cb82fbb |
Keep long mobile drafts readable with fullscreen editing (#6531)
* feat(app): add fullscreen editing to the compact composer * fix(app): preserve read-only terminal command previews Static command previews must render their published source; the live editor buffer is updated after render and has no mounted input to repaint read-only content. * fix(app): import React for composer editing scope rendering Workspace pane unit tests use the classic JSX transform, so the editing-scope provider needs React in scope when mounted. * fix(app): preserve fullscreen composer controls and editing Keep the fullscreen frame inside the visual viewport, gate hidden autocomplete keys, apply replacement commands to local line measurement, and return to inline before starting voice so its controls stay accessible. * test(app): cover draft replacement through the production composer Replace the measurement-hook fixture with profile switching and typing through the real composer. Keep measurement state inside its production surface; Android manual red/green evidence covers the native replacement flow. |
||
|
|
01f9bc8291 |
Modernize compact headers and sidebar affordances (#6431)
* feat(app): modernize compact headers and sidebar affordances Use a shared island header with quick tab creation and keep sheet footers inside their visible layout. Opt sidebar rows into touch sizing without changing global appearance settings. * test(app): match darker light-theme workspace selection * test(app): align plugin journeys with compact header |
||
|
|
b26b9234c0 |
Improve diff review with mobile comment sheets and direct feedback (#6455)
* feat(review): edit compact diff comments in a sheet * feat(review): send diff feedback to workspace agents Send saved reviews from the diff while retaining file navigation and unrelated composer drafts. Clear acknowledged versions only so comments edited or added during submission remain available. * fix(review): preserve drafts and coordinate feedback across surfaces Share pending submission ownership by draft while keeping recipient menus local. Retain editable text across presentation changes and acknowledgement, and reserve safe-area clearance for floating actions. * fix(review): center a small primary feedback button on desktop * fix(review): restore focus to feedback button after closing menu |
||
|
|
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> |
||
|
|
29db2b7980 |
Keep created agents after first-prompt failures and bound fork history (#6379)
* fix(agents): preserve creation when the first prompt fails A rejected initial prompt must leave a created agent with a turn error instead of returning the user to a draft whose creation key is already committed. Preserve receipt replay without repeating the prompt, and bound fork history to 100,000 characters before it becomes an attachment. * test(creation): isolate user agent counters from background naming Workspace naming uses internal provider sessions. Counting and rejecting those sessions made creation assertions depend on installed provider discovery timing. Keep discovery within the test adapters and scope observations to user-created agents. * test(creation): retry temporary directory cleanup on Windows Windows CI completed the rejection assertions but failed teardown with EBUSY. Match the daemon test harness bounded removal retries so transient directory locks do not fail creation tests. * fix(agents): record rejected prompts before their errors Startup rejection recorded only the system error, leaving the client to append its local prompt after it. Record the rejected submission at the terminal failure boundary so stream and fetched history agree on prompt-before-error ordering. * fix(agents): require acceptance for delivery notifications Retain rejected human submissions before their errors without projecting rejected inter-agent prompts as completed deliveries. Reproduces and fixes the notification regression exposed by merge CI. * test(agents): retain rejected submissions across retries The existing browser retry test assumed terminally rejected prompts disappeared. Assert the intended prompt-before-error history and a separate accepted retry while preserving draft, attachment, and ambiguous-steering checks. * test(creation): allow integration latency in raw RPC responses The peer inherited a one-second polling timeout despite exercising Git and provider startup. Reproduce the timeout with delayed startup and wait within an explicit integration budget while retaining all response and identity assertions. |
||
|
|
48059aeae3 |
Show the PR panel's state, activity verbs, and thread badges in the app language (#6225)
* fix(app): show PR panel state, activity verbs, and thread badges in the app language The PR panel's state label, the verb after each activity author, and the Resolved and Outdated thread badges were English literals, so they stayed English in every other language. The state and verb translations already existed and were unused; the badges get new keys in every locale. Closes #6214 * fix(app): translate every PR panel verb and state, and phrase them after the author The zh-CN state and review labels still held English ("Open", "Draft", "已 review"), and the Spanish and Portuguese verbs were adjectives that do not read after an author's name. The translation test now checks each verb and state on its own, so one English label fails it. Co-authored-by: Dillon <dillonzq@outlook.com> --------- Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com> Co-authored-by: Dillon <dillonzq@outlook.com> |
||
|
|
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 |
||
|
|
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 |
||
|
|
f02cc16bb4 |
fix(app): close hover cards when the pointer leaves a clicked row (#6167)
* fix(app): close hover cards when the pointer leaves a clicked trigger A hover card stayed open while any focus sat inside its trigger or content, so clicking a sidebar workspace row (which focuses the row's button) pinned the card after the pointer moved away, until Escape or a click elsewhere. Only keyboard-visible focus now keeps the card open, which preserves the keyboard entry path added with the shared hover card. * fix(app): keep a hover card open when keyboard focus arrives during its close delay Recheck keyboard focus when the close timer fires, and move the hover card e2e steps into sidebar helpers. --------- Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com> |
||
|
|
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 |
||
|
|
fa0f04058d |
Keep account usage accessible before the first turn and restore compact sheets
* fix(usage): keep details hoverable and restore compact sidebar sheets Share hover-card mechanics with workspace details so context usage can stay open while users press Refresh. Honor Retry-After for rate-limited usage requests, and let both sidebar entry points share the compact sheet. * fix(usage): restore settings cog with a fitted popover and compact sheet Keep shared Usage preferences in the title controls on every surface. Settings rows use the menu surface directly, avoiding the trailing margin and duplicate card border from the page layout. * fix(app): show account usage before the first agent turn Keep the context meter available for existing agents without context readings so account usage can be opened before a turn. Show an empty ring and an explicit no-data state until readings arrive. * fix(usage): preserve keyboard access and hover card positioning Context details must remain reachable by keyboard after replacing the tooltip. Keep focus within the card, restore side flipping, and dismiss detached cards when the viewport moves. Prune expired cooldowns even after credential rotation. * chore: remove QA screenshots from the source tree * fix(app): let hover cards claim Escape before agent shortcuts Register hover surfaces with the shared overlay keyboard owner without moving or trapping focus on pointer hover. Component-local Escape handling ran after the global interrupt shortcut and cancelled the underlying turn. * fix(app): reopen focused hover cards with button keys Keep focused triggers registered with overlay arbitration after dismissal so activation keys are handled before composer shortcuts. * fix(app): release overlay ownership when hover cards close Closed triggers handle activation locally, so a dismissed card does not block pane Find. Open cards retain shared Escape arbitration to protect running turns. * test(app): pin Linux keyboard identity for composer Find * test(app): synchronize context usage hover journeys Return focus to the composer before asserting pointer dismissal, wait for the card to reach the viewport, and park the pointer before reloading so it cannot consume the next scripted usage response early. |
||
|
|
febe9611bf |
fix(app): stop composer autofocus on touch screens (#5477)
A tablet or an unfolded foldable is wide enough for the desktop layout, so opening an agent autofocused the composer and raised the on-screen keyboard over the conversation. Autofocus on open now also requires a fine pointer, the same signal the app already uses for hover. A mouse-driven window still focuses the composer when an agent opens, and sending a message still keeps the composer focused. Co-authored-by: Phieu Dinh <phieu@fiu.one> |
||
|
|
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. |