feat: background-task tracking and task-progress parity across claude/opencode/hermes/pi - #6
Open
hydra-z[bot] wants to merge 431 commits into
Open
feat: background-task tracking and task-progress parity across claude/opencode/hermes/pi#6hydra-z[bot] wants to merge 431 commits into
hydra-z[bot] wants to merge 431 commits into
Conversation
* feat(app): expand command center actions Keep command center navigation stable by revealing only clipped rows without smooth centering. Prioritize a concise default list while making workspace, Git, pane, and creation actions searchable through the existing contribution and action-policy paths. * test(app): search for query-only command action Add project is intentionally absent from the unfiltered command center. Exercise the overlay flow through search before selecting it.
Generated titles optimized for topical brevity and could omit the requested operation or the identifier that distinguished the task. Preserve the operation, target, and strongest anchor so sidebar titles remain actionable.
* feat(app): preview HTML files in the file pane Renders .html/.htm files as a page in the file pane, with the same Preview/Source toggle Markdown already has. The main use is reading richer visual plans an agent wrote as a self-contained HTML page. A preview is a viewer, not a browser. Each document is prefixed with a doctype and a strict policy, so the policy is always the first element and always lands in the parser-created head: inline script and style run, and remote subresources, fetch, XHR, WebSocket, beacon, and form posts are refused. The frame has an opaque origin, so it cannot reach the app's DOM and storage and cookie APIs throw inside it. One gap is left on web and cannot be closed there: a sandboxed document may navigate itself, and no CSP directive in current browsers prevents it -- navigate-to was dropped from CSP3 and is unenforced, and meta refresh needs no script (both verified against the Chromium the app ships against). The opaque origin bounds it to the page's own contents, and SECURITY.md documents it. Native narrows it further by refusing navigation after the initial document, with the caveat that the decision runs in app JS. Self-contained pages only -- a page that pulls a CDN script renders unstyled, and Source still shows everything. * fix(app): harden HTML preview behavior and tests --------- Co-authored-by: Nicholas Salgueiro <nicholas.salgueiro@britecore.com> Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
…o#2638) * feat(app): fork an agent session mid-run from the tab menu Forking already existed, but only on the footer of a *completed* assistant turn. While an agent is running, the in-flight turn renders RunningTurnFooter with no fork menu, so exploring another path meant scrolling back to hunt for an older turn's footer — or waiting for the run to finish. Add two entries to the agent tab context menu ("Fork chat in a new tab", "Fork chat in a new workspace"), reachable regardless of run state. They omit the fork boundary, and selectForkContextRows projects the whole timeline when no boundary is given, so a mid-run fork carries everything up to now — including the partially streamed in-flight turn. Fork logic moves out of agent-stream/view.tsx into a shared useForkAgent hook so the turn footer and the tab menu share one code path; the per-turn behavior is unchanged (it still pins a boundary to its turn). No server, protocol, or capability changes — this reuses the existing agent.fork_context RPC and agentForkContext host feature. The daemon handler is already a pure in-memory timeline read, so it was safe mid-turn before this change. * fix(app): resolve missing agent records before failing a fork handleForkAgent read the agent record from the session store and gave up if it was absent from both agents and agentDetails. A persisted agent tab can outlive its record — restored on startup before hydration — so both fork entries failed with a generic toast even though the agent exists on the daemon and is perfectly forkable. Fall back to client.fetchAgent and store the result before failing, mirroring the resolution path agent-panel.tsx already uses. Only report forkFailed when the agent genuinely cannot be resolved; a disconnected host now says so instead. The resolution logic lands in resolveForkAgentSource with injected dependencies, since workspace-screen.tsx has no handler-level test harness and a sibling testable module is the pattern in this directory. storeFetchedAgentDetail moves out of panels/agent-panel.tsx into utils/agent-detail-store.ts so the workspace screen doesn't import a panel module — and into its own file rather than agent-directory-sync.ts, which would close an import cycle through legacy-daemon-workspaces. * feat(app): fork from the in-flight turn instead of the tab menu Move the mid-run fork affordance to where the fork button already lives: the assistant turn footer, beside the progress loader. RunningTurnFooter previously showed only a spinner and elapsed timer, so the fork button vanished for the whole duration of a run. It now renders AssistantForkMenu alongside them, reachable the moment a run starts. The in-flight fork passes no boundary, so selectForkContextRows projects the whole timeline and the fork captures the response being streamed. A fork button sitting next to a live response that silently dropped that response would be worse than no button. Completed turns still pin their own boundary, enforced by a separate handler type that keeps boundary required. layout.ts is untouched — the affordance is added to the running footer component rather than by lifting the footer suppression, so no copy or duration affordance leaks onto an incomplete turn. Reverts the workspace tab context menu approach, along with the agent resolution helper and store-writer extraction that existed only to serve it. The footer path already holds the agent record. * test(app): cover the in-flight turn fork with a Playwright spec Extends the existing assistant fork menu spec rather than adding a sibling file, so the completed-turn and in-flight cases sit side by side. The new test pins the behavior that defines the feature: the in-flight fork omits the boundary fields entirely, while the completed-turn fork sends one. Both assertions read the actual agent.fork_context frames off the WebSocket, using the read-only page.on("websocket") idiom from helpers/timeline-delivery.ts so the observer cannot perturb the flow it measures. Note the request omits the fields rather than nulling them — daemon-client spreads them conditionally — so absence is what's asserted there, and null only on the response. Also asserts the fork trigger is scoped inside turn-working-indicator, that no copy or duration affordance leaks onto the incomplete turn, that the attachment carries the streamed text, and that the source agent keeps streaming afterwards. * test(app): cover the in-flight fork call site, gate, and teardown Three behaviors this PR introduced had no coverage below the Playwright spec. A copy-paste of resolveAssistantTurnForkBoundary into handleForkInFlightTurn would have left every unit test green. view-fork-in-flight.test.tsx mounts the real AgentStreamView with the render strategy stubbed to the live-auxiliary slot, so handleForkInFlightTurn, useStableEvent and the readOnly expression all stay real. It asserts the fork request has no boundary KEY — matching the wire contract, where the field is absent rather than null — for both targets, and that the read-only gate withholds the trigger, with positive controls either side so an empty tree cannot pass for a working gate. turn-footer.test.tsx covers the race this PR created: the fork menu now mounts only while a run is in flight, so a fork can be pending when the subtree is torn down. The behavior is benign — React 18 makes the orphaned setState a no-op — so the test asserts the observable outcome and leaves a tripwire for unhandled rejections, since AssistantForkMenu's finally has no catch. Each test was verified by mutation: adding boundary: undefined, dropping the readOnly gate, and keeping the running subtree alive each fail the matching test. Scoped to what this PR changed. The relocated hook's error paths, draft setup construction, and attachment metadata predate it and stay untested here. * test(app): replace mocked fork coverage with Playwright --------- Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
* feat(acp): auto-accept shared permission requests Some ACP agents expose permission requests without a native mode that can bypass them. Keep the opt-in at the shared adapter boundary so every ACP implementation gets the same per-session behavior. * test(acp): include the shared feature in provider expectations * fix(acp): honor unattended auto-accept intent * fix(agent): list client features without a model
* Add automatic plus branch maintenance workflow * Build plus artifacts for desktop and CLI/server * Document and summarize plus artifact workflow * Document Apple signing and pin plus workflow actions * Disable Linux plus desktop artifact * Publish plus CLI packages to GitHub Packages * Fix GitHub Packages publish paths * Fix plus mise install summary package name * Disable macOS x64 plus desktop artifact * Tag plus npm packages as latest for mise * fix(worktrees): respect selected local base ref * chore(ci): remove fork-only plus workflow * fix(worktrees): preserve exact branch picker refs --------- Co-authored-by: Matt Cowger <1929548+mcowger@users.noreply.github.com>
* Add collapsed-project status badge to the sidebar Collapsed project rows now surface the most urgent hidden workspace's status as a corner badge on the project icon, instead of giving no signal at all: a loader for running, an alert for needs_input, a dot for attention/failed, nothing for done. Priority order (needs_input > failed > running > attention > done) means a working project keeps its loader even if another workspace is also awaiting review. Every surfaced status shares one badge shell (size, ring, offset) so the loader, alert, and dot never draw a differently-sized circle - previously the loader/alert used a 12pt ring while the dot used a 7-9pt one with a different corner offset. The running loader is also nudged half a point left so its visual center lands on the circle's center rather than reading as shifted right. Adds an e2e capture spec (run on demand, not part of CI) that seeds every state and edge case through the mock provider and dumps DOM geometry, for re-verifying the badge shell stays uniform. * Add PR review gallery images for the status badge PR Temporary evidence assets for pull request review, embedded via blob URLs in the PR description. Safe to delete after merge. * Swap misleading before/after PR images for clean per-state stills This feature never shipped on main, so there is no real "before" to compare against for a reviewer — the earlier before/after images were an artifact of local dev iteration, not a regression fix. Replaced with one clean still per status. * Fatten needs-input alert and dot to fill the shared badge shell Lucide's circle-alert only paints ~83% of its nominal size, so the prior 10pt glyph read as smaller than the loader inside the same 14pt shell. Sized both up so all three glyphs draw the same visual footprint against the shared ring. * Address review: extract pure badge-content selection, drop JSDOM tests Greptile flagged getStatusDotColorStyle's needs_input/running cases as dead (unreachable — shouldRenderSyncedStatusLoader and an explicit check already intercept those buckets earlier). Extracting the selection logic into a plain-TS descriptor function (getProjectStatusBadgeContent) makes that structural: the "dot" variant is typed to failed|attention only, so there's no switch left with unreachable branches. That extraction also resolves the JSDOM component test Greptile flagged (project-leading-visual.test.tsx used vi.hoisted/vi.mock/ createRoot mounting, all banned by docs/testing.md's two test categories) — the pure selector is now tested directly with a plain vitest file, no mounting needed. Dropped that test file and use-sidebar-project-status-bucket.test.tsx (same banned pattern); the real coverage was already redundant with sidebar-workspaces-view-model .test.ts's existing priority-order assertions and the e2e capture spec's real-app gating checks. Also split a conditional branch in the e2e capture spec's assertion loop into two deterministic loops (badge-expected vs no-badge cases) per Greptile's third note. * Size status-badge glyphs even so they center in the shell The badge shell's interior is 12pt (14pt minus the 1pt ring on each side). A centered glyph of size N sits at a (12 - N) / 2 offset, which is fractional for odd N and gets snapped to a device-pixel boundary, rendering visibly off-center (~1.5 device px at 3x). Drop the dot to 8pt and the alert to 10pt so both divide the interior into whole pixels and land dead center; Lucide's circle-alert paints ~83% of nominal, so 10pt draws a ~8.3pt disc that matches the 8pt dot. Also extends the on-demand capture spec to cover the failed bucket, the priority aggregation cases, dark mode, hover, a compact viewport, and a recorded running-to-expand transition, dumping DOM geometry that proves every shell shares one size/offset and every even glyph centers at 0px. * Refresh status-badge PR assets for the even-glyph sizing Recaptures every state at the approved 8pt-dot / 10pt-alert sizing, adds the failed bucket to the per-status set, a crosshair sizing/ centering proof, dark-mode and compact-form-factor shots, and replaces the soft upscaled spinner GIF with a crisp one assembled from native 3x-scale frames. Drops the stale pre-sizing images. * Add capture spec proving workspace statuses roll up to the project badge Seeds three collapsed projects, each with several same-directory workspaces in different buckets, so each resolves to a different highest-priority winner (needs_input / failed / running). Films the collapse and expand so the aggregation is provable as motion, not a single frame. * Add propagation recording showing statuses resolving to the project badge * Add higher-quality mp4 of the status propagation recording * Refactor project status badge coverage --------- Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
) * 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
* fix(server): preserve provider subagent messages The provider SDK defaults to forwarding only child tool activity, which leaves the nested timeline without the child response. Request the full nested transcript so provider subagent panes retain both sides of the conversation. * fix(app): correct project status badge test imports
* fix(server): fail agents when provider process exits The transport previously closed pending RPCs without terminating the active manager run, leaving the agent stuck in running state. Propagate unexpected process termination as a one-shot turn failure while suppressing it during intentional session close. * fix(server): keep idle provider exits recoverable A process death with no active foreground turn is not a failed turn and must not trigger turn-based lifecycle actions. Leave the session disconnected so the next prompt reconnects without publishing a false terminal event. * fix(server): preserve provider exit recovery Connection cleanup after a failed reconnect must not close the durable session boundary or discard AgentManager subscribers. Treat both foreground and autonomous root turns as active when propagating process death. * test(server): make process exit harness portable * fix(server): clear permissions after provider exit * fix(server): preserve plan approval after provider exit * fix(server): serialize provider reconnects * fix(server): stop reconnects after session close
Move the project status badge Playwright spec into the browser-owned directory so the changes contract passes and the test is collected.
* fix(acp): preserve permission choices ACP question bridges encode answers as repeated permission options. Preserve each option through the UI and return the exact selected ID, while keeping auto-accept from choosing on the user's behalf. * fix(acp): validate selected permission behavior Reject inconsistent action IDs instead of allowing the action ID to override the response behavior. Move the misplaced browser spec so the current base CI contract can run. * fix(acp): preserve invalid permission requests Validate selected ACP actions before consuming the pending request so inconsistent client responses can be corrected and retried. * test(acp): verify real permission questions * fix(acp): reject empty permission action ids * test(e2e): scope Kimi config to ACP spec
* fix(server): include native subagents in workspace activity Provider-native children live outside managed agent snapshots, so background work could outlive an idle parent without keeping the workspace running. Aggregate running child descriptors into the owning workspace and publish workspace updates on child lifecycle changes. * fix(server): serialize workspace status updates Queue overlapping descriptor rebuilds per workspace so older activity snapshots cannot overwrite newer lifecycle state. Preserve batched registry reads for multi-workspace updates. * test(server): update workspace status fixtures Provide the native subagent activity dependency in the shared session fixture and wait on observable git-watch output across the serialized update boundary. * fix(server): drop queued workspace updates on subscription swap --------- Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com> Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
* fix(server): make Git observation cross-platform Platform-specific watchers and forced full refreshes amplified Git processes and could miss nested changes. Share checkout and repository observation internally, scope final-state refreshes, and bound degraded polling so streamed summaries and diffs stay correct under bursts. * fix(server): refresh Git worktree state on metadata changes * fix(server): keep Git watcher runtime inputs current * fix(server): normalize watcher runtime boundaries * fix(server): reconcile Git observer topology * test(server): report Git watcher event batches * fix(server): close Git observation gaps * chore(ci): remove temporary Git observation jobs
…#2789) * fix(app): keep timeline pagination duplicate-free Older daemons page projected history by canonical sequence ranges, so one projected block can appear in adjacent responses. Accept each block on the page containing its projection anchor while still advancing across empty projected pages.\n\nProjected siblings can share a provider message ID, so render identity also includes the timeline cursor instead of collapsing distinct blocks onto one layout row. * fix(e2e): preserve isolated daemon launch contract Keep the source-daemon spawn path recognizable to the repository launch-contract check while selecting the built supervisor only for published package fixtures. * fix(app): preserve stable timeline item identity
* perf(app): retain inactive workspace screens App-wide routes cleared the active workspace selection, which removed the retained workspace deck from the React tree and made returning rebuild every panel. Keep mounted deck entries inactive across those routes and suspend inactive panel subscriptions so state is preserved without background work. * perf(app): suspend remaining inactive queries Retained composers and commit diff panels still subscribed through query hooks that did not receive panel activity. Propagate the existing activity gate so app-wide routes leave those hidden surfaces dormant. * refactor(app): separate panel activity from connectivity A hidden retained panel is still connected to its host. Keep connectivity truthful, pause work inside query and stream owners, and preserve terminal emulator identity while its stream is detached. * test(app): target active retained controls * fix(app): retain compact and terminal route content * fix(app): hide inactive workspace overlays
Native composers had no path from the device clipboard into image attachments. Route clipboard data URLs through the existing attachment persistence flow and expose the action only in the native attachment sheet.
* feat(app): add chat outline navigation Long agent sessions need prompt navigation without coupling viewport movement to disposable server windows. Keep fetched timeline pages in client state so repeated jumps stay local, and settle prompt jumps against virtualized row measurement changes. * fix(app): preserve chat outline timeline coverage * fix(app): reconcile outline window submissions * fix(app): harden outline timeline navigation
* fix(app): align turn footer actions Keep running-turn actions in the same position as completed-turn actions and use the shared small icon size for both copy and fork controls. * feat(app): improve sidebar workspace identity Make dense sidebar workspace rows easier to scan and let each device control how connected hosts are identified. * fix(app): keep host badges readable Use a compact display menu and keep identity color on the host icon so translated controls fit and badge text retains standard contrast. * fix(app): announce selected sidebar badge mode * fix(app): retain icon-only host names for screen readers * fix(app): name hoisted workspace rows * fix(app): retain host identity in workspace labels * fix(app): retain workspace status in row labels * fix(app): defer host appearance until identity resolves * fix(app): serialize host appearance writes * fix(app): serialize host registry writes * fix(app): bound sidebar host badge labels * test(app): match workspace status labels * fix(app): consolidate sidebar identity behavior * test(app): assert status grouping behavior * fix(app): keep sidebar row actions accessible * fix(app): stabilize optimistic message layout
* fix(composer): keep background context out of loading state Pull request link resolution can block a new workspace until its checkout target is known, but it is not submission work. Keep that safety gate while reserving the send-button spinner and drop lockout for actual submission or upload progress. * test(composer): cover link resolution at browser boundary Exercise the real new-workspace composer while pull request context resolves, including the submit presentation and file-drop path. Keep the two presentation booleans local to their only caller instead of exporting policy solely for an internal-state unit test. * fix(composer): preserve background lookup ownership Composer edits could release the resolving gate while a pull request lookup still owned the request, briefly allowing workspace creation from the wrong branch. Track logical candidates independently of unrelated draft changes and settle each reference independently so only invalid work releases early. * fix(composer): preserve pasted PR selection order * fix(composer): renew re-added PR lookups * fix(composer): track pasted PR source order * fix(composer): preserve resolved attachment order * fix(composer): coordinate active lookup order
* perf(server): bound Git process starts Git refresh bursts could keep creating short-lived processes at the concurrency ceiling, causing sustained process churn on constrained hosts. Apply one daemon-global start-rate and concurrency policy to every Git command while preserving the legacy concurrency environment variable. * build(nix): update npm dependency hash * fix(server): hold Git slots until process exit * fix(server): enforce Git limits across process lifetime * fix(server): align Git metrics with process exit * Fix Git limiter test deadlocks * Tune default Git process rate
* Fix Darwin Nix desktop app icon * Refresh Darwin Nix bundle identity
* fix(nix): identify desktop app for icon matching * fix(desktop): ignore wrapper class in CLI passthrough * fix(nix): give the Electron launcher a real app root The Wayland app_id — what a bar or taskbar uses to find the .desktop entry, and therefore the icon — is fixed during Electron startup, so neither `--class=` nor main.ts's `app.setName()` reaches it on current Electron. Launching `electron path/to/main.js` gives Electron no package.json to read a name from, so the window published the default "electron" app_id and shells drew the generic Electron icon. Launch a one-file app root named "paseo-desktop" instead, matching the installed desktop entry and hicolor icon. Older Electron (38) derives the app_id from the runtime app name "Paseo", so also ship a NoDisplay alias entry under that name; the icon resolves either way and the launcher list still shows a single Paseo. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* feat: add DeepWiki MCP server at project level * feat(omp): poll context window usage during active turns OMP agents previously reported context window usage only at turn completion, unlike Claude and Codex which stream live updates. Add a periodic poll (3s interval) of getSessionStats() that emits usage_updated events while a turn is active, so the client context window meter updates in real-time. * clear context usage poll timer before scheduling next interval * chore: remove .omp/ directory * fix(omp): make live usage polling lifecycle-safe OMP exposes live usage through a stats request rather than stream events. Keep polling scoped to active turns, suppress unchanged snapshots, and invalidate stale completion reads across interrupts, new turns, and session shutdown. --------- Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
* Improve mobile terminal typing and selection * Address mobile terminal review feedback * Remove dead native terminal input branch * Replay bracketed paste in terminal preamble * Stop per-key terminal resize claims * Stabilize terminal resize browser test * Use tracked terminal mode for native paste * Restore terminal toolbar focus handling * Adapt native terminal to active visibility state * Stabilize native mobile terminal interactions * Add native terminal fallback boundary * test(app): expect explicit terminal resize reclaim * fix(app): stabilize terminal buffer coordinates * fix(app): restrict terminal resize ownership * fix(terminal): gate restored input modes * fix(app): recover stalled terminal WebViews * chore(app): remove obsolete terminal harnesses * fix(app): make terminal resize claims explicit * test(app): stabilize native terminal device flows * test(app): track absolute scrollback coordinates * fix(app): isolate terminal WebView streams * fix(terminal): arbitrate size ownership across clients The daemon now distinguishes explicit ownership claims from passive geometry updates. This keeps the active client authoritative while allowing its split, viewport, and keyboard changes to resize the PTY without idle clients stealing it. * test(server): make worker resize assertion portable Query the worker's authoritative terminal snapshot instead of invoking a Unix-only shell command, so the resize regression exercises the same boundary on Windows and Unix.
* fix(app): preserve formatting when copying assistant selections Browser selection serialized React Native Web layout nodes instead of the assistant message semantics. Recover semantic markup from renderer-owned metadata and reuse the rich clipboard generator used by Copy turn. * fix(app): preserve assistant copy semantics Carry source-only Markdown metadata through the selection copy boundary, unwrap generated code links, and cover ordered starts, hard breaks, and fence languages in Playwright. Refresh the Nix dependency hash for the added clipboard dependency. * fix(app): preserve partial selection context Wrap selected fragments with their shared semantic ancestor chain and enable GFM table and strikethrough conversion. Cover partial nested selections and GFM output through the browser clipboard. * fix(app): preserve copied list and autolink text Adjust partial ordered-list starts for omitted siblings, strip parser-generated anchors before Markdown reconstruction, and refresh the Nix dependency hash computed by CI. * fix(app): normalize partial selection context Normalize cloned ordered lists across block boundaries, degrade incomplete table fragments to selected text, and preserve table alignment provenance through Markdown reconstruction. * fix(app): escape copied table delimiters Rendered table cells no longer retain source escape characters. Escape literal pipes during DOM-to-Markdown conversion so copied tables preserve their column structure. * fix(app): preserve authored link semantics The rendered link boundary conflated parser-generated links with authored autolinks and discarded authored titles. Carry title semantics into the anchor and unwrap only links with explicit generated provenance. * fix(app): preserve nested copy structure Blank-line splitting separated loose nested lists before Markdown rendering, leaving no nesting for clipboard serialization to preserve. Derive protected separators from the Markdown block structure and keep copy metadata independent from monospace surface styling. * fix(app): preserve selected file links Assistant messages and rich clipboard HTML must apply the same link validation policy. A shared parser keeps file links semantic in both MIME representations while retaining markdown-it's unsafe-scheme rejection. * fix(app): preserve partial table content A selected body row wider than its retained header cannot be represented as GFM and is truncated when rich HTML is regenerated. Treat only those over-wide fragments, plus headerless fragments, as incomplete while preserving valid short rows.
* feat(hub): pass execution MCP servers to agents Hub-owned execution capabilities need to reach provider sessions without becoming part of outward agent snapshots. Keep the configuration daemon-private so provider recovery continues to work. * fix(hub): protect daemon MCP namespace Hub execution MCP configuration must not replace the daemon-owned Paseo server. Validate only after owned-record lookup so idempotent replay remains stable while new launches fail before provider or durable state creation. * fix(agent): reject unsupported MCP launches * fix(agent): scope MCP support guard * fix(agent): redact MCP metadata from wire payloads * fix(agent): validate MCP support on restored sessions * fix(session): rehydrate MCP config on resume * fix(session): resume newest matching agent record * fix(session): restore archive state after failed resume
Keep host badges visible under row pressure and apply the selected host color consistently to the icon, label, and tinted background.
The Cloud page pitched a hosted multi-user product and collected emails through a signup form. The Hub is a self-hosted service in private beta and the only way in is a Discord DM, so the signup server function and its webhook are deleted rather than repointed. /cloud now 301s to /hub from the worker entry, which already owns the site's permanent path redirects, so old links and search results keep working. The homepage also drops split panels, service proxy, voice, and keyboard shortcuts. They had turned the page into a feature list; it should show what Paseo enables at a high level. Brand and provider icons move into shared modules so the Hub page, the site header, and the landing page each use one copy instead of three.
* fix(app): stabilize native terminal keyboard input Terminal focus requests blurred and remounted the hidden input even when the software keyboard was already visible, causing visible IME cycles and leaving clipboard commits coupled to stale native text. Keep focus requests idempotent while resetting only the native input buffer. * test(app): remove misleading keyboard device scenario Agent Device cannot durably assert software-keyboard continuity or commit a keyboard clipboard suggestion, so the scenario overstated coverage already owned by focused input-policy tests. * fix(app): derive terminal keyboard focus from visibility Use the keyboard-controller inset as the source of truth so a system-dismissed keyboard cannot leave focus activation suppressed. Avoid a duplicate focus request while explicitly showing the keyboard. * fix(app): track terminal keyboard visibility across layouts Keep keyboard visibility independent from compact-only terminal padding so tablet taps remain idempotent while the software keyboard is open.
* fix(subagents): preserve opened children on parent archive Opening a managed child represents user ownership only while that client's tab remains open. Track that intent per client, detach surviving children during parent archive, and keep single and bulk tab-close behavior consistent. * fix(subagents): mark generic tab openings Centralize managed child tab ownership in agent navigation so list, command-center, deep-link, notification, and subagent-track openings all mark ownership before creating the tab. Use stable localized errors for lifecycle failures. * fix(subagents): classify cold tab openings Fetch uncached agents before deciding whether tab ownership must be recorded, so notification, desktop, and cold-route openings cannot bypass parent archive protection. * fix(app): translate navigation fallback errors * fix(navigation): allow offline workspace intents * refactor(app): derive subagent ownership from open tabs * fix(server): serialize subagent lifecycle ownership
Todo timeline entries gained required activity metadata in beta.1 while the persisted cache format remained unchanged. Reject version 3 snapshots so upgrades hydrate authoritative state instead of rendering legacy rows.
…#3311) * fix(worktrees): preserve selected base config New worktrees were overwriting the selected ref's paseo.json with source-checkout bytes, which could create an accidental revert in an otherwise fresh workspace. Keep committed base config authoritative and warn when locally saved setup changes still need to be committed. * fix(worktrees): seed config exclusively * fix(projects): refresh config status on focus
* fix(app): validate persisted client state Persisted replica data could satisfy TypeScript through an assertion while missing fields required by renderers. Treat every AsyncStorage value as untrusted input, clear values that fail strict schemas, and version the replica DTO so incompatible caches cannot hydrate. * fix(app): preserve validated legacy state * fix(app): preserve validated preferences Preserve supported legacy location fields and every shipped theme while keeping unknown persisted fields rejected. Align browser test seeds with the current preference shape so strict validation exercises the intended provider. * fix(app): migrate legacy agent preferences Released clients stored host/location fields and per-provider thinkingOptionId together. Migrate those exact strict bytes into current preferences without admitting unknown fields. * fix(app): preserve drafts with legacy reviews Accept the exact strict shape released for workspace review attachments so migration can discard that obsolete attachment without clearing every persisted draft.
* fix(claude): preserve native MCP timeouts Paseo forced Claude MCP startup and tool waits to ten minutes, turning unavailable servers into long silent first turns. Let Claude apply its own defaults while preserving explicit user environment overrides. * test(claude): isolate MCP timeout regression Exercise timeout precedence through the existing provider runtime environment input without mutating process-wide test state. * test(workspace-git): await refresh boundaries Synchronize fetch observation tests with initial snapshot and fetch completion before advancing fake timers.
* fix(hub): make daemon disconnect unilateral Local relationship removal must not depend on reaching the Hub. Fence execution authority, make one bounded courtesy revocation attempt, then clear local state so status and reconnect eligibility agree immediately. * fix(hub): preserve disconnect intent across crashes Persist the terminal disconnect marker only while the bounded Hub notification is in flight. Startup removes that marker, so a crash cannot restore the old relationship or create a revocation retry loop.
* fix(providers): make catalog refresh deadlines configurable Provider startup can legitimately exceed a fixed short timeout when catalog discovery has substantial initialization work. Give each provider refresh one configurable deadline covering availability and the complete catalog probe, and cancel named child operations before allowing retries so timed-out work cannot accumulate in the background. * fix(opencode): abort catalog server acquisition A provider refresh could expire while the helper server was still starting because acquisition only tracked the activity without observing its abort signal. Reject acquisition before transferring a server reference, while leaving the manager-owned startup reusable by the next caller. * test(file-observer): allow native burst recovery
…aseo#3323) * fix(server): trust healthy workspace git watchers Quiet observed workspaces were periodically scheduling full Git refreshes, saturating the daemon-wide process pool as workspace count grew. Keep only cheap observation re-ensure work, refresh ignore paths from watcher events, and detect silent metadata watchers with a one-shot canary before accepting the subscription. * fix(server): refresh watcher ignores from git metadata Repository exclude and Git configuration changes also affect the standard ignore set. Route those metadata events back to linked working-tree observations so their excluded directory lists stay current without periodic Git polling. * test(server): drive ignore updates through watcher events The integration contract now exercises the production event-driven ignore refresh instead of waiting for the removed periodic audit. * fix(server): normalize git metadata paths on windows File observation returns platform-native relative separators. Normalize those paths before matching Git metadata names so repository exclusion changes refresh working-tree ignores on Windows too. * fix(server): trail concurrent ignore refreshes Remember ignore-source events that arrive during an in-flight Git query and recompute once more before considering the working-tree observer current.
* feat(cli): add Hub init wizard Reuse the existing login, daemon enrollment, project listing, and deploy paths so onboarding stays compatible with current Hub servers. Generated triggers require an explicit sender allowlist and existing bundles are never modified. * fix(cli): stop Hub init until daemon is ready A durable Hub relationship can be reconnecting without being ready to execute workflows. Keep enrollment skipped, but stop the wizard until daemon status reports connected. * fix(cli): wait for Hub daemon readiness Both fresh enrollment and reconnect paths can expose a durable relationship before the execution socket is connected. Poll the existing status RPC with a bounded wait before resolving projects or deploying. * fix(cli): make hub init detect resolvable resources
* fix(app): keep profile modes scoped to providers Applying a profile through sequential field setters allowed a provider change to race mode persistence, poisoning modeless provider preferences with another provider's mode. Apply profiles as one form transition and heal invalid provider-scoped mode preferences when profiles are used. * test(app): cover profile features across providers
Use one task-row presentation across message and composer lists so running, pending, and completed states keep the same hierarchy and status language.
Provider catalog discovery can exceed one minute during cold startup. Increase the default deadline while preserving explicit config and environment overrides.
Project icon discovery could select an ICO that native clients cannot decode even when a renderable SVG or PNG was available. Keep ICO as the final fallback and recognize common sized icon names.
Running chats expose one provider, so an intermediate provider screen and back action are redundant. Restore the direct model-list entry behavior while preserving the multi-provider picker.
* test(cli): stabilize live relay status coverage The regression fixture deleted the supervisor's active PID lock to model a reachable daemon without local process state. Under CI load, worker readiness could race that deletion and make the supervisor tear down the daemon while status and pairing were probing it.\n\nLaunch the real worker directly so the no-PID state exists naturally, then wait on the CLI-visible live relay state before asserting behavior. * test(cli): wait for complete relay probe state Status readiness alone does not guarantee the next pairing RPC or the foreign-home identity probe will finish inside the CLI's per-call timeout under CI contention. Retry each exact observable outcome within the fixture deadline and resolve the real worker entry through the server package. * test(cli): name retry mechanics once Keep the relay scenarios expressed as CLI probes and exact outcomes while one file-local helper owns the shared deadline, worker-liveness check, and retry cadence.
* feat(sync): restore host directories before reconnect Persist complete project, workspace, and active-agent replicas so every registered host can paint immediately, including offline hosts. Reconcile those replicas through monotonic per-entity cursors on the existing directory RPCs without retaining an event journal. * fix(sync): preserve active turn identity during catch-up Own Agent-to-wire projection beside the existing snapshot normalizer so replica persistence does not reach through directory-sync internals. This also keeps identified active turns intact when unchanged agents are folded into an incremental directory response. * test(e2e): inspect the real IndexedDB replica Keep cache setup, reload, and hydration coverage on the production browser storage backend after the replica moved off localStorage. Measure writes at the actual IndexedDB put boundary as well. * fix warm reconnect cache paths * feat(sync): persist project icons and deepen directory sync * fix(sync): preserve project update order * fix(cache): preserve validated replica persistence * fix(sync): retain cached agents during catch-up
Reuse the existing workspace drag interaction for pinned rows and persist their local order across grouping modes. Keep pressed and dragged row scrims aligned with the active backdrop, and preserve memoized row rendering on web.
Pull upstream's workspace-git refresh-throttling (getpaseo#3323) and the 0.4.0 release. Adopt upstream's workspace-git service and drop the fork's activity-gated watcher feature (workspace-watch-activity-service, touchWorkspaceWatch idle-poll demotion): getpaseo#3323 achieves the same goal (reduce needless refresh work) at the right layer, and the merged fs.watch observer makes per-watcher cost marginal. Reconcile config.ts sessionIdleTimeoutMs with upstream's resolveProfileLists/agentProfiles.
…/opencode/hermes/pi - Add background_task snapshot timeline item (protocol + wire schema) - Claude: consume SDK background_tasks_changed/task_started/task_progress/task_notification - PI: mirror OMP todo-mapper for todoPhases + todo tool results - Add dedicated hermes ACP provider - App: backgroundTasksSnapshot reducer + agentBackgroundTasks store + BackgroundTasksTrack UI - Add injectHeartbeat to AgentSession
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Background-task support and task-progress parity across all four supported agents, delivered as a clean feature branch off the current
watcher-improveHEAD (no force-push againstfeat/background-tasks-ui).What's included
Task-progress parity (
todotimeline)pi/todo-mapper.ts): readstodoPhasesfrom session state +todotool results, mirroring the OMP mapper; wired intostreamHistory,handleToolExecutionEnd, and a dedupemitTodoItem. Claude/opencode/hermes already fed the#3227task-progress card; PI was the gap.Background-task tracking (
background_tasktimeline item)agent-types.ts,messages.ts): additiveAgentBackgroundTaskDescriptor+background_tasksnapshot timeline item.claude/background-task-state.ts): consumes the SDK'sbackground_tasks_changedlevel signal plustask_started/task_progress/task_notificationedges, emits dedupedbackground_tasksnapshots live + on history replay.session-stream-reducers.ts,session-store.ts,composer/background-tasks/index.tsx):backgroundTasksSnapshotextraction (sequencing-gated),agentBackgroundTasksstore, and a collapsibleBackgroundTasksTrackabove the composer.injectHeartbeatonAgentSession(agent-sdk-types.ts): full-turn completion heartbeat for providers that cannot self-deliver (opencode/PI/hermes/ACP). claude and OMP self-deliver and omit it.hermes provider
hermes-acp-agent.ts): defaulthermes acp,HERMES_ACP_SKIP_CONFIGURED_MCP=1(host value wins), waits for asyncavailable_commands_update. Registered in the manifest, registry, builtin-ID literals, and icon names.Verification
typecheck,lint,formatclean.pi/todo-mapper.test.ts,claude/background-task-state.test.ts,hermes-acp-agent.test.ts,provider-registry.test.ts, app reducer + store snapshot tests. 63 tests across the touched suites pass.Known limits
background_taskemission is limited to what the harness surfaces (opencode/PI: none yet; hermes: none over ACP). Claude is the full emitter. TheinjectHeartbeatseam is in place for the completion-detection work (bg-bash job watcher, hermes SQLite poll) documented indocs/background-tasks-design.md.