Restore host directories instantly before reconnect (#3259)
* 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
This commit is contained in:
+16
-7
@@ -69,6 +69,7 @@ not retain non-Git directories.
|
||||
| `server/bootstrap.ts` | Daemon initialization: HTTP server, WS server, agent manager, storage, relay |
|
||||
| `server/websocket-server.ts` | WebSocket connection management, hello handshake, binary frame routing |
|
||||
| `server/session.ts` | Per-client session state, timeline subscriptions, terminal operations |
|
||||
| `server/directory-sync/` | Daemon-global latest-state sequences for projects, workspaces, and agents |
|
||||
| `server/agent/agent-manager.ts` | Agent lifecycle state machine, timeline tracking, subscriber management |
|
||||
| `server/agent/agent-storage.ts` | File-backed JSON persistence at `$PASEO_HOME/agents/` |
|
||||
| `server/agent/tools/` | Transport-neutral catalog for workspaces, agents, permissions, and automation |
|
||||
@@ -97,19 +98,27 @@ Cross-platform React Native app that connects to one or more daemons.
|
||||
|
||||
- Expo Router navigation (`/h/[serverId]/workspace/[workspaceId]`, `/h/[serverId]/agent/[agentId]`, etc.). The `workspaceId` URL segment is an opaque workspace id, not a directly meaningful filesystem path.
|
||||
- `HostRuntimeController` manages saved host connections, reconnection, and per-host runtime state
|
||||
- `runtime/replica-cache` keeps a non-authoritative per-host display replica in AsyncStorage: only the last focused agent, its workspace, and a short timeline tail. It restores before navigation becomes ready, leaves remote hydration flags false, and is atomically replaced by the normal snapshot-plus-delta synchronization path.
|
||||
- `runtime/replica-cache` keeps the complete project, workspace, and active-agent directory plus one short focused timeline tail in AsyncStorage. It restores before navigation becomes ready and leaves remote hydration flags false.
|
||||
- `runtime/directory-sync` owns directory reconciliation. On reconnect it passes the persisted per-entity cursor through `project.list`, `fetch_workspaces`, and `fetch_agents`; the daemon returns each entity's latest projection when its sequence is newer, plus tombstones.
|
||||
- `SessionContext` wraps the daemon client for the active session
|
||||
- Composer UI and submit/draft behavior live in `packages/app/src/composer/`; screens and panels should integrate it from there instead of dropping composer internals into `components/`, `hooks/`, or `screens/workspace/`
|
||||
- Timeline reducers in `timeline/session-stream-reducers.ts` handle compaction, gap detection, sequence-based deduplication
|
||||
- Timeline sync correctness is documented in [docs/timeline-sync.md](timeline-sync.md): live streams are for immediacy, `fetch_agent_timeline_request` is authoritative, and catch-up is paged but complete.
|
||||
- Voice features: dictation (STT) and voice agent (realtime)
|
||||
|
||||
The replica cache exists only to paint stale data immediately while the host connects. It does not
|
||||
own mutations, infer deletions, or replace daemon reconciliation. Pending permission requests are
|
||||
not restored from it. AsyncStorage is not encrypted, so the cached timeline tail may contain source
|
||||
code, prompts, and tool output; encrypted-at-rest storage is a separate product/security decision.
|
||||
Its serialized payload has a 1 MiB byte budget and evicts whole host snapshots in least-recently-
|
||||
written order; a single oversized host is omitted rather than partially restored.
|
||||
The replica cache paints stale data immediately while the host connects. Directory cursors are
|
||||
reconciliation checkpoints; cached entities remain non-authoritative until the daemon answers.
|
||||
Pending permission requests are not restored from it. AsyncStorage is not encrypted, so the cached
|
||||
timeline tail may contain source code, prompts, and tool output; encrypted-at-rest storage is a
|
||||
separate product/security decision. Its serialized payload has a 32 MiB byte budget and evicts whole
|
||||
host snapshots in least-recently-written order; a single oversized host is omitted rather than
|
||||
partially restored. Browser and Electron builds store it in IndexedDB. Native builds use
|
||||
AsyncStorage, and Android reserves 64 MiB for that database.
|
||||
|
||||
The three directory entity types have independent monotonic sequences and share one daemon
|
||||
generation. The daemon retains only the latest projection per entity and bounded tombstones, not an
|
||||
event log. A missing, expired, or previous-generation cursor receives a full snapshot. Projects are
|
||||
independent records; a project with no workspaces does not need a workspace placeholder.
|
||||
|
||||
### `packages/cli` — Command-line client
|
||||
|
||||
|
||||
Reference in New Issue
Block a user