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.
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.
Provider catalog discovery can exceed one minute during cold startup. Increase the default deadline while preserving explicit config and environment overrides.
* 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
* 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(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.
* 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
* 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(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(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(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
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.
* 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
* fix(providers): restore implicit model variant selection
Provider catalogs list only explicit overrides, so treating the first override as the default made base model behavior unreachable. Represent the base choice in the catalog and translate it back to an omitted variant at the provider boundary.
* test(providers): exercise variant catalog boundary
The regression concerns the model catalog callers receive, so verify normalization through fetchCatalog instead of coupling the test to its internal builder.
Keep trailing edit controls from changing section heading rhythm, and center each profile's icon with its own text block so one-line and noted rows share the same visual alignment.
Restore the established tree rails while retaining file actions. Keep Escape local to generic editable fields so cancelling a file draft cannot interrupt an agent.
The subagent track used a custom hover path that left its label and chevron muted. Reuse the ghost button interaction so track headers promote their content consistently.
Workspace terminal shutdown only signaled an npm wrapper, leaving Electron alive with broken output pipes. Make the signal-handling runner the terminal-owned process and route external Electron termination through the existing quit lifecycle.
* fix(usage): read Cursor token from modern state.vscdb key via node:sqlite
Settings → Usage showed Cursor as unavailable for a normal Cursor desktop
login. The quota fetcher read the access token from the legacy `cursorAuthStatus`
key, but current Cursor builds store a plain JWT under `cursorAuth/accessToken`
with no such legacy row, so the lookup returned null.
Read the token with built-in node:sqlite instead of shelling out to a `sqlite3`
CLI (absent by default on Windows) — a second, independent cause of the same
"token not found → unavailable" failure. Prefer the modern key, fall back to the
legacy `cursorAuthStatus` blob for older builds, and log read failures at debug
so an unavailable card stays diagnosable.
Fixes#2586
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(usage): cover Cursor sqlite text and blob auth
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
* docs(hub): document per-execution worktree branch names
Hub now materializes `${{ paseo.execution.id }}` inside a daemon
environment's `worktree.newBranch` before it persists or dispatches the
launch, so a reusable branch-off environment can get a stable branch per
execution instead of every trigger contending for one literal name.
The reference states the constraint precisely because it is the part the
YAML cannot show: `newBranch` accepts that one execution-scoped path and
nothing else, and any other expression fails bundle activation with the
authored file and field in the error. Literal branch names stay valid.
* docs(hub): reshape the per-execution worktree branch docs
Split the two pages by the job each reader is doing. The daemon page is a
task guide, so it now carries the worktree YAML and only the two facts
that reader needs to choose a branch name, then links out. The reference
owns the exhaustive contract at the `newBranch` field: a table contrasting
a literal with the template, then the accepted expression scope and what
activation rejects.
Dropped the render-before-dispatch ordering. Readers cannot act on where
Hub materializes the value; the reachable behavior is that a retried or
recovered execution keeps its branch, which is what the table says.
* docs(hub): make the per-execution worktree branch the only guidance
A branch-off Hub environment that aims every execution at one branch name
is not a configuration worth teaching, so the docs no longer present it as
an alternative. Both pages now show `newBranch: trigger-${{ paseo.execution.id }}`
and say what it does, with no literal-branch example and no comparison.
The reference keeps the field's type as a bare syntax fact, along with the
accepted expression, what activation rejects, and the authored field the
failure names.
Stop treating heartbeat silence as proof that a live daemon worker should be destroyed. Crash recovery, explicit lifecycle requests, and supervisor-loss cleanup remain unchanged.
* feat(skills): add Paseo help and provider diagnostics
Give support agents a topology-aware troubleshooting entry point backed by the deployed documentation index, and expose the daemon provider diagnostic through the CLI so agents can inspect the affected host directly. Agent-launching skills now use configured profiles instead of the removed orchestration preferences.
* test(cli): keep provider diagnostics on real boundaries
Remove the internal client mock and preserve its normalization and host-targeting assertions through the existing isolated-daemon coverage.
Hermes in the production Android app does not provide Array.prototype.toSorted. Multi-host project selection and provider cache eviction could therefore crash when they reached deterministic sorting paths.
* feat(app): improve markdown file previews
Keep rendered documents on the chat reading rail, surface YAML front matter as readable metadata, and make shared Markdown links retain the chat accent and hover treatment.
* fix(app): preserve unsafe frontmatter source
* test(app): cover markdown link behavior
Android AsyncStorage's 6 MiB SQLite ceiling was exhausted by per-workspace provider snapshots with no eviction. Raise the native cap to 10 MiB and bound snapshots to 4 MiB with indexed eviction, clearing legacy unindexed data without scanning payloads on every save.
The worker watchdog treated wall-clock time spent in host sleep as evidence that the worker was unresponsive. Count consecutive observed heartbeat misses instead so sleep does not destroy live terminal sessions while genuinely stalled workers still restart after the same active observation window.
* fix(worktrees): honor saved setup configuration
Project Settings writes paseo.json in the source checkout, but existing committed copies in new worktrees previously won silently. Copy the saved project config before lifecycle setup so the command shown to users is the command that runs.
* fix(worktrees): replace config symlinks safely
A selected ref can place a symlink at paseo.json, so copying over that path may overwrite a file outside the worktree. Materialize the saved source config with atomic rename semantics to replace the path entry without following it.
* perf(app): skip transient replica cache writes
The replica cache subscribed to the entire session store, so live stream-head updates forced repeated JSON serialization and browser storage writes even though the head is not persisted. Select the cache's persisted inputs once and schedule writes only when that projection changes.
* test(app): move perf cleanup into fixture
Keep the replica-cache performance scenario as a direct setup, stream, measure, and assert flow while the spec-local Playwright fixture owns deterministic mock-agent cleanup.
* perf(app): remove unused session message state
The legacy message accumulator had no readers but copied its full array for each activity and updated Zustand for every assistant chunk. Keep only the live voice-abort notification and voice transcription behavior.
* test(app): use live session action in task subscription test
* fix(omp): negotiate RPC protocol v2 so large responses don't overflow
OMP caps protocol-v1 single-line RPC frames at 1 MiB. get_available_models
returns the full effective model catalog (hundreds of models), which exceeds
that cap, so OMP replies with an overflow error ("RPC response exceeded the
transport limit") and the OMP provider fails to start sessions.
Negotiate RPC protocol v2 after OMP's startup `ready` frame when it is
supported: v2 lifts the single-frame ceiling to 64 MiB by chunking oversized
frames. Add rpc_chunk reassembly to the shared JSONL transport so chunked
responses are reconstructed before routing, and gate the negotiation on the
ready frame so it is in place before the first request.
Protocol v2 is negotiated only when the peer advertises support in its ready
frame; peers that stay on v1 (e.g. Pi's --mode rpc) are unaffected.
* fix(omp): make protocol startup atomic
---------
Co-authored-by: pi3123 <pi3123@users.noreply.github.com>
Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
* feat(cli): add workspace rename command
`paseo workspace rename <workspace-id> <title>` sets a workspace's
user-visible title through the existing workspace.title.set RPC, and
`--reset` clears the override so the name reverts to the branch or
directory. The command reads the descriptor back so the output shows
what a reset reverted to.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(cli): harden workspace rename against read-back and arg failures
Review findings on the rename command:
- A failed workspace list sweep after a successful title change reported
the whole command as failed. The read-back is display-only, so it now
runs outside the mutation's error path and degrades to a null name.
- Only --reset needs the descriptor read back; a set title is already the
resolved display name, so the common path no longer pages the list.
- Dropped the `"code" in error` rethrow. Nothing in that block throws a
CommandError, but DaemonRpcError always carries a `code` property even
when it is undefined, so the guard let those through to render as
UNKNOWN_ERROR with a stack instead of WORKSPACE_RENAME_FAILED.
- Commander 12 allows excess positionals, so an unquoted multi-word title
renamed to its first word and dropped the rest. The command now rejects
excess arguments.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* refactor(cli): report the rename RPC response instead of reading back
Reading the descriptor back to show what --reset reverted to was the only
reason rename needed a paged workspace sweep, and that sweep dragged in
everything around it: a failure path that could report an applied rename
as failed, a nullable name, and a bespoke warning sink to tell the two
null cases apart.
Sibling commands don't do this. `workspace archive`, `agent mode`, and
`schedule update` all report what the RPC returned and stop; the one
command that reads back is `agent update`, which has the same "applied
but reported as failed" bug. So rename now mirrors `workspace archive`.
`--reset` reports `title: null` rather than naming what it reverted to;
`paseo workspace ls` shows the resolved name. This also reverts the
`collectWorkspaces` extraction, whose only second caller was rename.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>