Make provider catalogs compact and content-addressed so repeat launches can reuse the persisted snapshot instead of transferring it again. Remove eager global catalog loading and the stopped-agent defensive tail fetch, while keeping sequence-gap and reconnect recovery as the correctness paths. Add an opt-in production-ID Android profiling build for local startup traces.
* feat: make relay opt-in for device pairing
* fix(relay): keep pairing state authoritative
* fix(relay): refresh pairing state across transports
* fix(onboard): honor explicit relay opt-out
* fix(relay): surface transport startup failures
* fix(pairing): gate offers for older daemons
* test(cli): rely on real pairing transport coverage
* fix(cli): report live relay without a pid file
* fix(relay): synchronize config during daemon startup
* fix(relay): preserve mutability for ignored overrides
* fix(cli): use reachable daemon for pairing
* fix(app): redirect invalid pair device routes
* fix(pairing): support remote host device pairing
Keep Pair Device host-relative through the existing settings and daemon RPC flow. Route CLI output through an injected adapter so workflow tests do not mutate process globals.
* fix(pairing): validate pairing destinations
Expose the host-relative Pair Device flow on every supported app platform. Reject a reachable daemon whose identity does not match the requested Paseo home before reading or mutating its pairing state.
* fix(pairing): render QR codes across platforms
Generate SVG text without DOM or canvas and render it through the existing cross-platform SVG stack.
* fix(cli): pair from persisted relay state
Allow explicit relay pairing while the daemon is stopped when relay is already enabled in persisted configuration.
* fix: reject oversized checkout diffs
* fix(diff): keep large previews from disconnecting clients
The physical socket limit is an OOM backstop, not a frame-size contract. Bound structured diff construction incrementally and report oversized previews without closing the client's socket.
* fix(app): preserve oversized diff state
* fix(diff): stay within relay frame limit
---------
Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
* feat(schedules): per-run workspaces, isolation and archive controls
Scheduled agents never appeared in the sidebar: each schedule reused one
stamped workspace and archived the run's agent on completion. Now every run
mints its own workspace — the entity the sidebar shows — with per-schedule
controls for isolation (local or worktree) and whether to archive that
workspace when the run finishes.
The schedule form is rebuilt on a non-React form model (open/commands/close)
to end the flicker, edit-into-create contamination, and multi-host hydration
bugs that came from effect-choreographed shared state. That lands the reusable
foundations it needed: a form kit over a single control-geometry owner, a
data-access taxonomy (replica/snapshot/fetch) with real load-state semantics,
and lint/boundary guardrails so new screens inherit the paved road.
Also fixes desktop combobox popovers truncating options when the trigger is
narrower than the content. New schedule protocol fields are optional on both
create and update, so old and new clients/daemons stay compatible.
* test(app): complete mock themes for control-geometry tokens
switch and terminal-profile-edit-modal now style through
createControlGeometry, which reads theme.borderWidth[1], theme.opacity[50],
and theme.colors.borderAccent. The hand-rolled mock themes in these two
suites lacked those tokens, so the eager StyleSheet.create mock threw at
import (collection error), not on any assertion. Add the missing tokens.
* fix(schedules): address review findings on run cleanup, edit isolation, load error, sheet dismiss, and preference hydration
- Server: archive the run's workspace even when agent creation fails, so a
misconfigured provider no longer orphans a sidebar workspace/worktree.
- Edit form: keep a stored worktree isolation while worktree eligibility is
still resolving, instead of silently downgrading a saved schedule to local.
- Schedules screen: show the load error/retry UI when every host fails, rather
than spinning forever behind the loading branch.
- Form sheet: fire the parent onClose on native gesture/backdrop dismiss so the
sheet closes instead of re-opening.
- Form model: apply late-loading saved preferences to untouched create-mode
fields (never to edited schedules or user-modified fields).
* fix(schedules): review batch — reconnect resubscribe, worktree prune, Android dismiss, cadence and provider edit safety
- Push-router: re-send terminal and checkout-diff subscriptions after a
reconnect; the old per-hook effect resubscribed on isConnected and the
extracted router did not, so daemon restarts silently stopped terminals_changed
pushes (root cause of the terminal-activity e2e failures).
- Server: pass the run's source repo root when archiving worktree runs so the
worktree is unregistered (git worktree remove/prune), not just deleted; also
archive the workspace when agent creation fails even with archive-off (an
agentless workspace has nothing to inspect).
- Sheet: RN Modal onDismiss is iOS-only — notify dismiss once-per-close on the
Android native path too; replace the JSDOM component test with a real
Playwright dismiss spec and inline the trivial dismiss decision.
- Form model: editing an interval schedule no longer rewrites its cadence to
cron unless the cadence UI is touched (90-minute intervals have no cron
equivalent); switching projects clears stale provider/model state and gates
submit until the new host's snapshot resolves.
* chore(lint): drop custom lint wrapper and boundary script, plain oxlint
The import bans stay in .oxlintrc.json (oxlint-native no-restricted-imports).
The receiver-sensitive checks the custom script enforced are not worth a
parallel lint pipeline; if they come back it will be as oxlint rules.
* fix(schedules): crash-safe run cleanup, capability-gated run options, resilient mutations
- Persist the run's workspace/agent ids on the running-run record so a daemon
crash mid-run can be recovered: restart archives the interrupted run's
workspace under the same policy as normal cleanup (agentless always archives,
otherwise archiveOnFinish is respected).
- Hide Archive on finish (and omit archiveOnFinish/isolation from payloads) on
hosts without workspaceMultiplicity — an old daemon ignores the fields, so
offering the switch there would lie.
- Optimistic pause/resume/delete no longer throw when the schedules cache holds
a still-connecting entry alongside loaded data.
- Mode field is gated on provider mode options, not a selected model, so
model-less providers can pick their advertised modes.