caadd59441
Move the following audited-and-implemented changes into openspec/changes/archive/2026-06-12-completed-changes-archive/: - backend-frontend-refactoring - config-profile-git-mounts - config-profile-includes-ui - config-profile-multi-repo-mounts - container-monitoring-notifications - git-mount-url-validation - home-path-expansion - mobile-terminal-ux - mount-specificity-ordering - notification-center - persistent-terminal-sessions - session-list-overhaul - ssh-key-mounting - terminal-fullscreen-unified-header - tool-session-progress-and-updates Also regenerated .pi-map*.md files for openspec/changes so the remaining active changes (multi-session-terminal-ux, reorganize-long-files, working-copies, workspace-first-ui) reflect the new layout.
74 lines
3.8 KiB
Markdown
74 lines
3.8 KiB
Markdown
## Context
|
|
|
|
Currently, terminal sessions are ephemeral. Each WebSocket connection to `/ws/tool-instances/{instance_id}/terminal` spawns a new `docker exec` process via `TerminalManager.create_session()`. When the WebSocket disconnects, the session is cleaned up and the `docker exec` process is killed. This means users lose their shell state, running processes, and command history every time they disconnect.
|
|
|
|
The current architecture:
|
|
- `TerminalManager` tracks sessions by `session_id` (UUID) in a dictionary
|
|
- Each session creates a new PTY and `docker exec` process
|
|
- WebSocket I/O loops are tied to the session lifecycle
|
|
- No concept of reconnection or session persistence
|
|
|
|
## Goals / Non-Goals
|
|
|
|
**Goals:**
|
|
- Terminal sessions persist across WebSocket disconnections/reconnections
|
|
- Users reconnect to the same shell process, maintaining state and history
|
|
- Add explicit "Reset Terminal" functionality to kill and restart the session
|
|
- Graceful handling of idle timeouts to clean up abandoned sessions
|
|
- Buffer recent output for replay on reconnect
|
|
|
|
**Non-Goals:**
|
|
- Multi-user shared terminal sessions (one session per instance, but only one active WebSocket at a time)
|
|
- Session persistence across container restarts or instance stops
|
|
- Full terminal scrollback history persistence (only recent buffer)
|
|
- Automatic session restoration after instance restart
|
|
|
|
## Decisions
|
|
|
|
**1. Session tracking by instance_id**
|
|
- Rationale: One persistent session per tool instance is the simplest model
|
|
- Alternative: Track by user_id + instance_id — rejected because it's overkill; users don't need multiple terminals to the same container
|
|
- Trade-off: Only one user can have an active terminal at a time per instance
|
|
|
|
**2. Detach WebSocket from session on disconnect**
|
|
- Rationale: Keep the `docker exec` process alive, just remove the WebSocket reference
|
|
- Implementation: Session stores a list of WebSocket connections (initially just one)
|
|
- On disconnect: remove WebSocket from session, don't kill process
|
|
- On reconnect: attach new WebSocket to existing session
|
|
|
|
**3. Circular buffer for output replay**
|
|
- Rationale: Users should see what happened while disconnected
|
|
- Size: 10KB buffer (configurable) — enough for ~100 lines of typical output
|
|
- Implementation: Buffer stores raw bytes, replayed on WebSocket attach
|
|
|
|
**4. Reset terminal via WebSocket message**
|
|
- Rationale: Users need a way to kill a stuck or corrupted session
|
|
- Implementation: JSON control message `{"type": "reset"}` kills process and starts fresh
|
|
- Alternative: HTTP endpoint — rejected because it's more complex and less intuitive
|
|
|
|
**5. Idle timeout cleanup**
|
|
- Rationale: Prevent resource leaks from abandoned sessions
|
|
- Timeout: 30 minutes of no WebSocket connections
|
|
- Implementation: Background task checks last_activity timestamp
|
|
|
|
## Risks / Trade-offs
|
|
|
|
- **[Risk] Zombie sessions**: Users disconnect and never reconnect, leaving `docker exec` processes running
|
|
- Mitigation: Idle timeout of 30 minutes cleans up abandoned sessions
|
|
- **[Risk] Session corruption**: If the shell process crashes, the session is dead but still tracked
|
|
- Mitigation: Health check on `docker exec` process; auto-reset on next connect if dead
|
|
- **[Risk] Concurrent connections**: Multiple tabs trying to connect to the same instance
|
|
- Mitigation: Only allow one active WebSocket per session; new connection closes old one with a message
|
|
|
|
## Migration Plan
|
|
|
|
1. Deploy updated backend services (TerminalManager, TerminalSession, terminal endpoint)
|
|
2. Deploy frontend changes (reset button, reconnection handling)
|
|
3. No database migration needed
|
|
4. Rollback: Revert to previous code; existing sessions will be killed on disconnect as before
|
|
|
|
## Open Questions
|
|
|
|
- Should we show a "session resumed" indicator in the UI?
|
|
- Should we persist the last N commands for command history?
|