Home

mweinbach / agent-coworker

publicmweinbach/agent-coworker
Overview Code History Branches Pull requestsIssuesInsights
main
HomeOverview Code PRsIssues

Fix draft thread persistence and canonicalize desktop session recovery (#51)

7 months ago

900bfb0
Authored
Max Weinbach3/20/2026, 7:18:40 AM
* feat(server): add harness session snapshot projections

* refactor(desktop): hydrate threads from harness snapshots

* test(desktop): align snapshot restore regressions

* fix: workspace path parity for sessions, legacy lastEventSeq, desktop snapshot skip

- Add canonicalWorkspacePath/sameWorkspacePath and use for get_session_snapshot
  permission checks and SQLite listSessions filtering (in-memory after fetch)
- listPersistedSessionSnapshots accepts optional workingDirectory filter; legacy
  summaries use LEGACY_JSON_SESSION_LIST_LAST_EVENT_SEQ (0); document in protocol
- Desktop selectThread: skip get_session_snapshot when feed loaded and cache
  fingerprint matches
- Tests: session-store filter + sentinel, session-db path normalization,
  server snapshot alias path, desktop warm-cache regression

Made-with: Cursor

* Prevent saving empty draft threads in desktop app

* Extract desktop test JSDOM harness

* Fix Windows workspace path comparisons

* Fix session snapshot prompt state tracking

* Fix desktop thread reconnect snapshot waiter handling

* Fix desktop snapshot cleanup and timeout waiter leaks

* fix(desktop): scrub removed thread cache and preserve drafts

Prevent deleted thread data from lingering in cached desktop snapshots, preserve draft threads during session reconciliation, and drop outdated build verification guidance from AGENTS.md.

Made-with: Cursor

* fix(desktop): validate and prune cached session snapshots

Prevent malformed or deleted session snapshot cache entries from surviving desktop bootstrap or workspace session refreshes.

Made-with: Cursor

* fix: recover from dropped selections and bad resumes

Keep desktop thread selection valid after session refreshes remove the active thread, and fall back to synthesized snapshots when persisted resume projections are malformed.

Made-with: Cursor

* fix: thread migration and session snapshot edge cases

Fix 5 issues identified in code review:

1. bootstrap.ts: Fix legacyTranscriptId calculation to capture original
   thread.id whenever it differs from computed id, ensuring proper tracking
   during migration scenarios when sessionId changes from null

2. thread.ts: Fix race condition by only applying cached snapshot when
   skipHarnessSnapshotFetch is true. Add fallback to apply cached snapshot
   when harness fetch fails instead of leaving thread in transcript-only mode

3. thread.ts: Fix silent error handling in readTranscriptEvents() to
   propagate errors when all transcript reads fail, preventing empty arrays
   from being misinterpreted as valid empty transcripts

4. threadEventReducer.ts: Preserve legacyTranscriptId when filtering out
   duplicate threads during migration. Copy legacyTranscriptId from filtered
   thread to replacement thread if replacement lacks one

5. runtimeState.ts: Remove threadSelectionRequests from rekeyThreadRuntimeMaps
   to prevent stale selection request entries after thread ID migration.
   Selection requests stay with original thread ID and are cleared by selectThread()

* fix(desktop): address PR review issues for thread selection

- Add selection currency check after cached snapshot application to prevent stale state during async operations
- Add debug logging for session snapshot fingerprint mismatches
- Document draft threadephemerality in persistence helpers
- Document thread identity migration flow in websocket-protocol.md

* fix: handle stale snapshots and parse errors in session hydration

- Validate snapshot freshness in loadInitialSessionSnapshot by comparing
  lastEventSeq against persisted record. Falls back to legacy snapshot
  when DB snapshot is stale, preventing silent turn loss after unclean
  shutdown.

- Wrap getSessionSnapshot in try/catch in SessionAdminManager to catch
  parse errors from malformed/schema-mismatched JSON. Gracefully falls
  back to legacy snapshot instead of returning internal_error.

Parent1987b68

61 files changed
  • AGENTS.md+0−6
  • apps/desktop/electron/services/persistence.ts+2−0
  • apps/desktop/src/app/localStateCache.ts+1−1
  • apps/desktop/src/app/store.actions/bootstrap.ts+71−14
  • apps/desktop/src/app/store.actions/thread.ts+339−49
  • apps/desktop/src/app/store.actions/workspace.ts+4−0
  • apps/desktop/src/app/store.helpers.ts+4−2
  • apps/desktop/src/app/store.helpers/controlSocket.ts
+317
−2
  • apps/desktop/src/app/store.helpers/persistence.ts+27−3
  • apps/desktop/src/app/store.helpers/runtimeState.ts+34−1
  • apps/desktop/src/app/store.helpers/threadEventReducer.ts+82−9
  • apps/desktop/src/app/store.helpers/transcriptBuffer.ts+2−0
  • apps/desktop/src/app/types.ts+12−15
  • apps/desktop/src/lib/desktopSchemas.ts+5−0
  • apps/desktop/test/app-topbar.test.tsx+1−40
  • apps/desktop/test/backup-page.test.ts+1−42
  • apps/desktop/test/bootstrap-cache.test.ts+156−6
  • apps/desktop/test/chat-view.stability.test.tsx+20−59
  • apps/desktop/test/context-sidebar.test.tsx+1−40
  • apps/desktop/test/control-socket.test.ts+269−0
  • apps/desktop/test/developer-page.test.tsx+1−45
  • apps/desktop/test/jsdomHarness.ts+125−0
  • apps/desktop/test/memory-page.test.ts+1−45
  • apps/desktop/test/onboarding-ui.test.tsx+26−67
  • apps/desktop/test/protocol-v2-events.test.ts+395−79
  • apps/desktop/test/providers-page.test.ts+1−45
  • apps/desktop/test/settings-nav.test.ts+20−3
  • apps/desktop/test/thread-reconnect.test.ts+616−27
  • apps/desktop/test/workspace-mcp-editor.test.ts+3−3
  • apps/desktop/test/workspace-settings-sync.test.ts+94−17
  • apps/desktop/test/workspaces-page.test.ts+9−60
  • docs/websocket-protocol.md+154−8
  • src/server/protocol.ts+12−2
  • src/server/protocolEventParser.ts+23−1
  • src/server/protocolParser.ts+12−1
  • src/server/session/AgentSession.ts+125−4
  • src/server/session/InteractionManager.ts+7−5
  • src/server/session/PersistenceManager.ts+9−1
  • src/server/session/SessionAdminManager.ts+57−3
  • src/server/session/SessionContext.ts+3−0
  • src/server/session/SessionSnapshotProjector.ts+1104−0
  • src/server/session/TurnExecutionManager.ts+4−4
  • src/server/sessionDb.ts+11−2
  • src/server/sessionDb/mappers.ts+10−0
  • src/server/sessionDb/migrations.ts+7−0
  • src/server/sessionDb/repository.ts+96−10
  • src/server/sessionStore.ts+20−1
  • src/server/startServer.ts+21−1
  • src/server/startServer/dispatchClientMessage.ts+3−1
  • src/shared/sessionSnapshot.ts+224−0
  • src/utils/workspacePath.ts+19−0
  • tasks/lessons.md+4−0
  • tasks/todo.md+0−84
  • test/protocol.test.ts+90−0
  • test/server.test.ts+435−0
  • test/session-db-mappers.test.ts+10−0
  • test/session-db.test.ts+165−0
  • test/session-store.test.ts+31−0
  • test/session.test.ts+44−0
  • test/sessionSnapshotProjector.test.ts+167−0
  • test/workspace-path.test.ts+19−0