* fix(app): prevent and recover workspace layout crash loops
* fix(desktop): capture resized browser tabs without hanging
A resident guest can paint fresh pixels after resize while capturePage's
native surface-copy request remains pending. The same failed guest returns
a fresh frame through frame subscription, so waiting for resize or another
animation frame does not correct the failing copy request.
Capture one subscribed frame within the existing five-second budget and
release the subscription on completion or cancellation. Preserve temporary
frame production and its original throttling policy. Remove viewport copy
retries and E2E screenshot polling; assert the resized image dimensions.
Refs #4866. Three full real-Electron browser journeys passed under Xvfb,
including physical clicks and fresh screenshots while the window is hidden.
* test(app): choose Agent before exercising the runtime catalog
The newly merged catalog journey assumed an empty workspace opened an agent draft tab. This branch opens the New launcher, so create the agent draft tab explicitly before checking its composer and model choices.
* fix: settle closed browser captures and validate persisted layout fixtures
Destroying a guest during frame subscription left its screenshot pending until the capture deadline and blocked queued captures. Reject at destruction, remove the listener on every exit, and return browser_tab_closed. The regression proves immediate settlement and queue release.
Reuse the unchanged persisted layout schema from a UI-independent module so the recovery fixture validates storage before editing it.
* test(app): encapsulate Explorer layout setup and cleanup
Keep persisted layout schemas and corrupted-state construction inside the seedCorruptedWorkspaceLayout helper. Use the existing withWorkspace fixture for cleanup in all four Explorer journeys so test bodies follow a straight setup, action and assertion flow.
* test(app): target the selected workspace in layout recovery
The corruption helper selected the first persisted entry, so a multi-workspace journey could leave the intended workspace untouched. Resolve its exact persistence key from the requested workspace ID and fail setup when absent. The failing-first journey now preserves an earlier workspace with an agent draft tab while recovering the selected workspace.
* fix(desktop): wait for Metro HTTP readiness before launching Electron
Expo briefly listens while probing port availability. A successful TCP connection can therefore launch Electron before Metro starts and leave it exiting on connection refusal. Require the configured renderer origin to report the running packager status.
* test(ci): consolidate fixture and readiness corrections
Await the connection and UI states each journey owns, isolate Git fixture contents before observation, and hold real Markdown frames at asserted checkpoints. Keep creation completion diagnostics explicit without claiming the original Windows failure is fixed.
* test(desktop): describe Metro readiness through HTTP states
Keep protocol mechanics in the fixture and assert readiness only after a successful packager response. Cover non-success status and unrelated HTTP content without inline synchronization in the test body.
* fix(desktop): throttle hidden browsers between screenshots
Keep Chromium background throttling enabled outside serialized captures. Temporarily enable frame production and wait for fresh paint so hidden-window screenshots remain usable without continuously animating idle guests.
* fix(desktop): share screenshot deadline across paint and capture
* test(desktop): wait for browser fixture readiness before sampling
* test(desktop): exit Electron after screenshot verification
CI completed every screenshot assertion but remained alive after app.quit. Exit the standalone test explicitly and keep its deadline active until process shutdown.
* test(desktop): clean browser profile after Electron exits
Explicit Electron exit skips quit handlers, and removing the profile before shutdown lets Chromium recreate it. The launcher owns the temporary profile and removes it after the child exits.
* test(desktop): reuse browser E2E for hidden screenshot regression
Exercise the running app and browser MCP tools within the existing browser journey. Remove the separate Electron fixtures, npm script, and CI step.
* fix(desktop): restore macOS app updates
Electron 41's Squirrel helper can leave the update handoff dormant on current macOS, so Paseo quits cleanly but relaunches the old bundle. Electron 44 wakes ShipIt through its XPC service.
Include updater lifecycle events and ShipIt state in app diagnostics so future handoff failures identify the current version, target version, cache paths, and installer output.
* fix(desktop): harden updater diagnostics
Keep each ShipIt file's evidence available when another read fails, carry the service-selected version into updater lifecycle logs, and make clean workspace installs resolve the Electron runtime used by desktop tests.
* refactor(desktop): name updater install options
* refactor(desktop): name updater log payloads
* refactor(desktop): name clipboard payload
* fix(desktop): surface updater lookup failures
* test(desktop): await guest focus transition
* fix(desktop): guard macOS update compatibility
* test(release): validate desktop manifests before publish
* test(desktop): await populated daemon pid file
Allow trusted local plugins to register complete coding-agent providers through the existing agent lifecycle. Includes direct and ACP implementations, SVG provider icons, custom timeline items, runnable examples, and public authoring documentation.
Closes#3547Closes#3556
* fix(desktop): stop retaining closed Settings views
Settings rotations left detached detail panes reachable from the web style registry's strong element sets. Backport the upstream weak cleanup design and cover the real Electron bundle with a forced-GC regression.\n\nKeep the established sibling-route topology; compact Back relies on route-name identity.
* test(app): synchronize Mermaid completion layout assertion
The streaming acceptance test can observe the intentional completion remount between visibility and layout sampling. Consult the existing completion promise around that measurement so the transition is not reported as diagram loss.
* test(app): isolate worktree restart from provider startup
* feat(plugins): phase 1 split runtime entries after green gate
The compiler now builds explicit client and server entries, so runtime boundaries are source-owned instead of registration-name filtering. Compiler and runtime tests prove the entry split, directory and suffix boundaries, client Node import errors, migration failure, and client-only operation without a subprocess.
* feat(plugins): phase 2 run client entries after green gate
Explicit client and server contexts replace the mixed plugin context. The app runner owns every client registration and its idempotent removal, including late contributions and composer pills; focused contribution tests prove the removal contract, and all five migrated examples reached running on the isolated worktree daemon.
* feat(cli): phase 3 scaffold runtime split after green gate
The generated project demonstrates the required shared RPC contract, server handler, client surface, and sidebar wiring. The scaffold test and an isolated init, typecheck, install, and running check prove the phase acceptance path.
* docs(plugins): phase 4 publish migration after green gate
Gate: current docs and the paseo-plugin skill describe only explicit client/server entries. The standalone migration guide maps every former registration, and migration-doc.test.ts proves every client add* method remains represented.
* fixup! feat(plugins): phase 1 split runtime entries after green gate
Gate: compiler 13, runtime 24, typecheck, lint, and format passed. The dependency fixture proved node_modules/client was incorrectly treated as a plugin boundary.
* fixup! feat(plugins): phase 2 run client entries after green gate
Gate: client runtime and registry tests, typecheck, lint, format
* fixup! docs(plugins): phase 4 publish migration after green gate
Gate: migration docs test, paragraph audit, typecheck, lint, format
* fixup! feat(plugins): phase 1 split runtime entries after green gate
Gate: compiler organization tests, typecheck, lint, targeted format
* fixup! feat(plugins): phase 2 run client entries after green gate
Gate: shared SDK tests, runtime tests, typecheck, lint, targeted format
* fixup! feat(cli): phase 3 scaffold runtime split after green gate
* fixup! docs(plugins): phase 4 publish migration after green gate
* fixup! feat(plugins): phase 1 split runtime entries after green gate
* docs(plugins): rewrite public plugin docs for runtime entries and mobile guardrails
* fixup! feat(cli): phase 3 scaffold runtime split after green gate
The scaffold now keeps DOM globals out of the program and declares only window.open inside client/web.ts. The scaffold test invokes tsc in a fresh process, proves the generated project passes, and proves a stray document access fails.
* fixup! docs(plugins): phase 4 publish migration after green gate
The internal guide and plugin skill now forbid both the DOM lib and triple-slash DOM references. They direct web adapters to declare only the globals used by client/web.ts.
* fixup! feat(plugins): phase 1 split runtime entries after green gate
Removing the obsolete Babel parser changes the locked npm dependency graph. The macOS Nix desktop gate reported the new fixed-output hash, which this commit records.
* fixup! feat(plugins): phase 1 split runtime entries after green gate
Reject relative imports that escape the plugin root while continuing to skip resolved node_modules internals. The compiler regression test proves the escaped import is rejected and the dependency-internal fixture remains accepted.
* fixup! feat(plugins): phase 1 split runtime entries after green gate
Classify absolute imports and reject plugin-authored paths that escape into node_modules. Dependency internals remain exempt based on their importer path. Red-first compiler regressions cover both bypasses, and the existing dependency fixture remains green.
* fixup! feat(plugins): phase 1 split runtime entries after green gate
Classify canonical esbuild resolution results so dependency-relative and symlink imports cannot escape client/server boundaries. The two compiler regressions failed before the fix and pass afterward.
* test(ci): synchronize flaky state transitions
Wait for repository watcher registration before emitting buffered ref events, let sidebar order polling retry unlaid-out rows, and wait for the inactive browser parking state before screenshot capture. These changes directly address the three observed CI failures; the affected server, Playwright, and desktop browser tests pass locally.
* test(ci): synchronize Mermaid completion layout assertion
The Playwright streaming acceptance test exposed a completion remount between visibility and layout sampling. Check the existing completion promise around the measurement so that transition is not reported as diagram loss.
* fixup! feat(plugins): phase 1 split runtime entries after green gate
Resolve bare package imports before boundary classification so symlinked dependency entries cannot expose server modules to the client bundle. The focused regression proves the bypass and the compiler file passes 20/20.
* fixup! feat(plugins): phase 1 split runtime entries after green gate
Allow canonical paths only within a matching linked package root while preserving runtime and containment checks for imports that leave it. The linked-dependency regression fails before the fix and compiler tests pass 21/21 afterward.
* fixup! feat(plugins): phase 1 split runtime entries after green gate
Reject matching package manifests that contain the plugin or live inside it, so linked-dependency roots cannot exempt plugin or workspace files. The ancestor-manifest regression fails before the fix and compiler tests pass 22/22 afterward.
* fixup! feat(plugins): phase 1 split runtime entries after green gate
Validate plugin-local lexical boundaries before canonical linked-root exemptions and require remembered-root imports to originate inside that root. The linked-root bypass regression fails before the fix and compiler tests pass 23/23 afterward.
* feat(app): customize top-level sidebar items
Let users reorder and hide built-in and plugin sidebar rows from Appearance settings while keeping the preference device-local. Add Search as a first-class row and standardize section explanations as header info tooltips.
* fix(app): preserve consecutive sidebar preference edits
Derive each sidebar change from the latest cached settings and retain unavailable plugin slots while editing the visible list. Keep E2E interaction selectors tied to accessible control names.
* test(app): isolate provider settings unit boundary
Keep the legacy provider-section test focused on provider behavior now that its shared section shell can render the settings info control.
* fix(ci): eliminate recent cross-platform flakes
Synchronize tests on owned state instead of elapsed time or transient identities. Preserve file rename collision safety when platform file IDs are unavailable.
* fix(ci): close follow-up synchronization gaps
Keep fetches in flight through buffered-event classification, scope mock agents to navigation tests, and wait for live workspace hydration before opening agent routes.
* fix(ci): synchronize browser lifecycle boundaries
The editor was trapped below the resident webview's body-level paint plane in split layouts. Render it through the shared overlay root while tracking the owning pane's bounds.
* fix(desktop): keep element selectors available on loaded pages
Annotate element and Screenshot element returned early when a cached load signal said the guest was not ready, even if the current document was complete and executable. Let executeJavaScript own the readiness boundary and keep selector cleanup available in the same stale-signal state.
Extend the real Electron browser regression to reproduce the complete-document/stale-signal mismatch through both toolbar actions.
* test(desktop): await browser selector injection
Poll the guest selector state through the browser bridge instead of assuming injection completes within 250 ms. This keeps the Electron regression deterministic on slower CI hosts.
* Harden browser selector session lifecycle
* Keep selector E2E fixtures independent
* fix(desktop): harden selector and annotation lifecycle
* fix(desktop): keep selector PR focused
* refactor(desktop): own element selector lifecycle
---------
Co-authored-by: Daniel G. Kang <180234654+dgk-dev@users.noreply.github.com>
Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
* feat(app): add AMOLED and all four Catppuccin themes
Add an AMOLED theme (pure black background) and the four official
Catppuccin flavors (Latte light, Frappé/Macchiato/Mocha dark) to the
appearance picker. Generalize the dark-theme builder to support a light
surface variant, register the new themes with Unistyles, and patch all
registered theme keys when applying font/syntax appearance settings.
* fix(app): localize Catppuccin + AMOLED theme labels across language packs
The initial theme commit pasted the English brand/flavor labels into every
locale. Localize them following each pack's convention: transliterate
Catppuccin and the coffee-flavor names into Arabic/Russian scripts, use
katakana/hanzi equivalents in ja/zh-CN, and standard loanwords in
fr/es/pt-BR. AMOLED is a universal acronym and stays as-is except where
the pack transliterates (Arabic).
* fix(app): make Latte terminal ANSI colors readable
* test(app): cover appearance theme picker options
* refactor(app): scope theme PR to AMOLED
* refactor(app): rename AMOLED theme to Pure Black
* fix(app): refine Pure black appearance
* test(app): wait for sidebar toggle icon
* test(app): remove hover timing race
---------
Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
* fix(desktop): preserve browser tabs across focus changes
Electron can replace a guest WebContents when a webview is reparented, which reloads the page and can race automation against a destroyed target. Keep each browser guest on one permanent paintable surface and make user and agent resizing share one canonical viewport.
* fix(desktop): recover browser surfaces after lifecycle changes
* fix(desktop): preserve resident browser lifecycle state
* fix(desktop): seed inactive browser viewport
* fix(ci): skip unrelated required checks cleanly
Matrix jobs had to start no-op runners to preserve interpolated required-check names. Static named jobs let GitHub report genuine skipped conclusions while keeping those names stable.
* fix(ci): gate changes to install patching script
* fix(ci): route cross-package test contracts narrowly
* fix(ci): keep routed contracts merge-blocking
* fix(server): exclude nested test utilities from builds
* fix(ci): cover app-owned native and browser domains
* refactor(ci): align tests with runtime domains
Own browser specs, desktop specs, and Electron-only app code by stable directories so PR routing does not depend on filename conventions. Keep desktop integration coverage inside the required desktop check.
* fix(ci): keep routing and desktop suites isolated
The routing regression must run before dependency installation, and desktop Vitest must not collect Playwright-owned specs.
* fix(ci): isolate desktop e2e runtime
* perf(test): isolate Playwright workers
* perf(test): parallelize Playwright within specs
* fix(test): keep Playwright file scheduling
* fix(test): share dynamic Metro fixture
* fix(test): preserve own-host restart fixtures
* fix(ci): preserve routed contracts after rebase
* Stabilize Playwright wheel-scroll assertions