Skip to content

fix: session stabilization, dedup, and code audit refactor#5

Merged
dimakis merged 4 commits intomainfrom
fix/session-stabilization
Apr 1, 2026
Merged

fix: session stabilization, dedup, and code audit refactor#5
dimakis merged 4 commits intomainfrom
fix/session-stabilization

Conversation

@dimakis
Copy link
Copy Markdown
Owner

@dimakis dimakis commented Apr 1, 2026

Summary

  • Session stabilization: WebSocket disconnects no longer kill the Agent SDK session. Sessions are detached (not aborted) on WS close, and a new WS can reattach within a 2-minute TTL. Critical for mobile use over Tailscale.
  • Session list dedup + cleanup: getSessions() deduplicates by session ID. Swipe-to-dismiss on mobile, "Clear" button in the section header.
  • Code audit refactor: Extracted shared types to types/chat.ts, utilities to lib/, broke up the 234-line startChat god function, removed dead exports from notify.ts, tightened types (anyunknown), guarded JSON.parse in WS handler.

New modules

  • server/session-registry.ts — session lifecycle decoupled from WebSocket lifecycle
  • server/tool-summary.ts — extracted summarizeToolInput (was private in chat.ts)
  • server/content-blocks.ts — deduplicated content block parsing
  • frontend/src/types/chat.ts — shared types (Message, Session, ImageAttachment, etc.)
  • frontend/src/lib/ — groupMessages, formatTime, truncate, resizeImage

Test plan

  • 70 tests passing (was 30 before this branch)
  • tsc --noEmit clean
  • ESLint --quiet clean
  • Pre-commit hooks pass on all commits

Made with Cursor

dimakis added 4 commits April 1, 2026 02:26
TDD: tests written first, then implementation. SessionRegistry decouples
session lifecycle from WebSocket connection lifecycle — sessions survive
brief disconnects via detach/reattach with a configurable TTL.

Made-with: Cursor
WS disconnect now detaches (not aborts) the session. The SDK query keeps
running server-side. On reconnect, the frontend sends a reattach message
with the previous clientId. If the session is still alive, the new WS is
swapped in and streaming resumes. Detached sessions auto-abort after 2
minutes if no reattach arrives.

Made-with: Cursor
getSessions() now deduplicates by session ID (keeping most recent), which
eliminates the repeated entries caused by querying multiple worktree dirs.
Added hide/clear endpoints (DELETE /api/sessions/:id, DELETE /api/sessions).
Frontend: swipe-to-dismiss on individual sessions (mobile touch), "Clear"
button in the section header.

Made-with: Cursor
…ctions

Frontend:
- Extract shared types (Message, Session, ImageAttachment, etc.) to types/chat.ts
- Extract utilities: groupMessages, formatRelativeTime, resizeImage, truncate to lib/
- Components now import from types/ instead of coupling to ChatView page
- Wrap handlePermission in useCallback (stabilizes PermissionBanner timer)
- Guard JSON.parse in WS onmessage with try/catch
- Replace Record<string, any> with Record<string, unknown>
- Remove unused lastPayload ref

Server:
- Extract content-blocks.ts: parseContentBlocks + extractToolResultText (was duplicated
  between streaming loop and getMessages)
- Break up startChat: extract resolveWorktree, stageImages, buildPermissionHandler
- Remove dead buildNotificationHeaders export from notify.ts
- Replace err: any with err: unknown + instanceof checks
- Update chat.test.ts exports check, remove stale comment
- Add content-blocks.test.ts (7 new tests)

Total: 70 tests passing, 0 lint errors, tsc clean.
Made-with: Cursor
@dimakis dimakis merged commit d6ea69a into main Apr 1, 2026
1 check passed
@dimakis dimakis deleted the fix/session-stabilization branch April 1, 2026 06:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant