The desktop app could time out connecting to the daemon on first launch
because the PID file advertised a listen address before the HTTP server
was actually listening. The supervisor now writes the PID lock with
listen: null and updates it only after the worker sends a paseo:ready
IPC message confirming the server is listening.
- Rename daemon-runner.ts to supervisor-entrypoint.ts
- PID lock acquired with listen: null, updated via paseo:ready IPC
- Worker sends paseo:ready after httpServer.listen() resolves
- Desktop polls until listen is non-null before returning to the app
- Remove PASEO_PID_LOCK_MODE and external lock mode
- Remove unnecessary env overrides (PASEO_HOME, PASEO_CORS_ORIGINS) from
desktop daemon spawn
- Reduce trace log bloat: inbound/outbound WebSocket messages now log
only message type and payload size instead of full payloads
- Supervisor restarts worker on SIGKILL (covers OOM)
Replace the silent daemon bootstrap failure path with a multi-phase
startup screen that shows progress and surfaces errors. Uses Expo
Router Stack.Protected to gate app screens behind bootstrap completion,
keeping the Stack mounted at all times to avoid layout remounts.
- bootstrapDesktop() returns structured result instead of swallowing errors
- addConnectionFromListenAndWaitForOnline() waits for real connection, not just probe
- Startup screen shows stacked progress steps with checkmark transitions
- Error state shows daemon logs, copy button, GitHub issue link, docs link, retry
- External URLs open in system browser via openExternalUrl
Replace three competing event paths (foreground stream, live event pump,
JSONL history poller) with a single push-based subscribe() + startTurn()
contract. This fixes duplicate user messages and stuck running state caused
by timing-based routing between concurrent event sources.
Key changes:
- AgentSession interface: remove stream(), add subscribe() and startTurn()
- All providers (Claude, Codex, OpenCode): single subscribers Set with
notifySubscribers() for push-based event delivery and turnId stamping
- Agent manager: identity-based turn ownership via activeForegroundTurnId
replacing pendingRun async generator
- Delete: dual queues, routeSdkMessageFromPump, startLiveHistoryPolling,
snapHistoryOffsetToEnd, liveEventBacklog, Pushable
- Fix Codex provider not clearing activeForegroundTurnId on turn completion
- Add real-provider integration tests for event stream invariants
useHostRuntimeSession returned the full HostRuntimeSnapshot, causing
every consumer to rerender on any internal state change (probe cycles,
client generation bumps). Replace with targeted hooks that return
primitives/stable references so useSyncExternalStore skips rerenders
when the subscribed value hasn't actually changed.
New hooks: useHostRuntimeClient, useHostRuntimeConnectionStatus,
useHostRuntimeLastError, useHostRuntimeAgentDirectoryStatus,
useHostRuntimeIsDirectoryLoading. Existing useHostRuntimeIsConnected
already followed this pattern.
useHostRuntimeSnapshot kept only for settings-screen where probe
data is legitimately needed.
Replace the multi-step new-agent route flow with a single
create_paseo_worktree endpoint that registers the workspace immediately
and creates the git worktree in the background. The sidebar now calls
this endpoint directly and shows a creating spinner inline.
Also auto-resolves the base branch from origin/HEAD when not explicitly
provided, removes the unused Tauri WebSocket transport layer, and
normalizes loopback endpoints to localhost.
Closes#125
Replace inline data-URL image handling with a persistent attachment storage service, add draft lifecycle states (active/abandoned/sent) with generation tracking, and update fetchAgent to return project placement alongside agent snapshots.