- Model selector is no longer disabled while providers load; opens
immediately and streams available providers as they arrive
- Selecting a non-default provider on mobile now works correctly
- Provider icon added to model trigger in mobile preferences sheet
- Thinking icon (brain) added to thinking trigger in mobile preferences
- Model descriptions for OpenCode/Pi shown inline next to model name
instead of in a tooltip
- Running agents and draft screen share a single provider/model cache,
eliminating duplicate network requests
- Provider data is prefetched when entering a workspace so the model
selector is instant on first open
The mobile preferences modal split CombinedModelSelector's onSelect into
separate onSelectProvider and onSelectModel calls, but onSelectProvider
was never passed from DraftAgentStatusBar — so selecting a non-cloud
provider was silently ignored while only the model ID updated.
Add onSelectProviderAndModel prop to ControlledStatusBar and use it on
the mobile path, matching the web path's atomic behavior.
- Add onDropdownClose callback to AgentStatusBar and wire through ControlledStatusBar
to CombinedModelSelector so running agents focus input after any dropdown closes
- Fix mobile misalignment in model selector by adding marginHorizontal: spacing[1]
to sectionHeading, drillDownRow, backButton, and providerSearchContainer to match
ComboboxItem's mobile margins
- Add CombinedModelSelector with two-level drill-down (providers → models),
favorites section, search, and single-provider auto-drill mode
- Add provider snapshot system (ProviderSnapshotManager) for cached provider/model state
- Add provider diagnostics with resolved binary paths and versions across all providers
- Add StatusBadge shared component for consistent status visual language
- Add ProviderDiagnosticSheet for detailed provider health inspection
- Add desktop auto-focus on input after any status bar interaction (model, mode,
thinking, features) using focusWithRetries
- Fix Combobox flicker on height change by switching to bottom-based CSS positioning
once initial floating-ui position resolves
- Add dynamic dropdown height: Level 1 fits content, Level 2 calculates from model count
- Remove "Other providers" section from model selector (only show available providers)
On macOS, apps launched from Finder/Dock inherit a minimal environment
(PATH is just /usr/bin:/bin:/usr/sbin:/sbin). This caused two problems:
1. Agent binaries like codex were not detected (findExecutable failed)
2. Terminals spawned by Paseo had no access to user-installed tools
(node, bun, direnv — all "command not found")
Fix: at Electron startup, spawn the user's login shell and capture its
full environment via JSON.stringify(process.env) using UUID markers.
This is the same battle-tested approach VS Code uses. The resolved
environment is merged into process.env before the daemon starts, so
all child processes — agents, terminals, git operations — inherit the
correct environment automatically.
This replaces the previous approach of invoking resolveShellEnv() (via
the shell-env npm package) at multiple scattered call sites. Now there
is a single source of truth: process.env is enriched once at startup.
Changes:
- New: packages/desktop/src/login-shell-env.ts (VS Code approach)
- Removed: resolveShellEnv(), shell-env dependency, $SHELL -lic probes
- Simplified: applyProviderEnv() and findExecutable() now trust process.env
When dictating and focused on an agent, pressing Enter now confirms
the dictation and sends the message, matching the behavior of clicking
the submit button.
Remove the "Refreshing" and "Failed to refresh agent" toasts from the
agent panel — they fire frequently but are meaningless since sync
recovers transparently. The "Reconnecting..." toast for host disconnect
is preserved.
Strip debug console.log calls across the app: render tracking in
message/stream views, dependency change tracking in workspace screen,
terminal tab slot logging, and verbose audio engine/voice runtime
bridge stats logging. Legitimate console.error/warn in catch blocks
are kept.
Same fix as the Silero VAD — sherpa-onnx returns Float32Arrays backed
by native memory which Node.js rejects as "External buffers are not
allowed". Copy into JS-managed memory before passing to audio pipeline.
Users connecting multiple daemons (e.g. local + remote via Tailscale) hit
a "belongs to X, not Y" error because the edit-host modal's Add Connection
button scoped new connections to the current host's server ID. Remove that
button and its supporting state so all connections go through the top-level
flow which has no server ID constraint.
The bundled silero_vad.onnx lives inside Electron's app.asar which
native C++ (sherpa-onnx) cannot open via OS file I/O. On first voice
activation, copy the model to ~/.paseo/models/local-speech/silero-vad/
using Node.js fs (asar-aware) and point the native code there.
buildClientConfig in test-daemon-connection.ts never set appVersion, so
probe clients (which become the live client) sent hello without it. The
daemon's version gate then hid Pi/Copilot from all these sessions.
Also update appVersion on the Session when a client reconnects with a
newer version, so stale sessions don't stay gated forever.
worktreeRoot was added as a required field in 9154f8fc, which breaks
old clients parsing new daemon responses and new clients parsing old
daemon responses. Made it .optional() with .transform() fallbacks.
Also added a critical rule to CLAUDE.md: schema changes must always
be backward-compatible in both directions.
- Add classify.ts as the single source of truth for CLI invocation
routing (discriminated union, derives known commands from Commander)
- Remove all hardcoded command lists and duplicate path detection logic
- Simplify shell wrappers to dumb pipes (zero classification)
- Fix hot-start: use `open -n -g -a` (VS Code pattern) so second-instance
event fires when app is already running
- Fix cold-start race: pull-based IPC (getPendingOpenProject) so renderer
fetches the pending path after React mounts, instead of push event that
arrived before the listener existed
- Fix asar read corruption: unpack node-entrypoint-runner.js from asar
(Node.js v24 in Electron 41 can't parse package.json inside asar)
- Strip ELECTRON_RUN_AS_NODE from env when spawning desktop app from CLI
AgentProviderSchema was z.enum() which caused old clients to reject
session messages containing unknown providers (pi, copilot), breaking
the entire session. Changed to z.string() for future clients.
For currently deployed clients (<0.1.45), the daemon now filters out
unknown providers based on the appVersion sent in the WebSocket hello
message. Clients that don't send appVersion only see claude/codex/opencode.
Always specify the model in paseo run examples (e.g. --provider codex/gpt-5.4
instead of --provider codex) to prevent agents from launching with wrong defaults.