Files
headquarter/apps/web/package.json
T
alex 6c8cfe9157 feat: responsive web terminal with auto-reconnect, heartbeat, and local echo
Implements a resilient, responsive web terminal that survives network blips,
provides instant typing feedback, and restores scrollback on reconnect.

Backend changes:
- Add heartbeat tracking (15s ping interval, 60s idle timeout)
- Add message batching (16ms flush window) for efficient I/O
- Add termios echo detection and set_echo_state control messages
- Add graceful session_ended notification before close
- Add ping/pong protocol support

Frontend changes:
- Rewrite TerminalComponent with status bar, connection indicator,
  session-ended overlay, reconnect banner, and ResizeObserver
- Add useTerminalConnection hook with:
  - Exponential backoff auto-reconnect (1s → 30s max, 10 attempts)
  - Heartbeat/ping-pong with latency tracking
  - Local echo for printable ASCII with server deduplication
  - Resize debounce (200ms) + throttle (500ms)
  - Scrollback serialization via xterm-addon-serialize
  - Ctrl+Shift+R manual reconnect shortcut
- Add WebSocket protocol types and encoding utilities
- Add xterm-addon-serialize dependency

Tests:
- 16 backend unit tests (TerminalSession + TerminalManager)
- 13 frontend hook tests (connection lifecycle, reconnect, resize,
  scrollback, callbacks)

Quality gates:
- Frontend typecheck: clean
- Frontend lint: clean
- Frontend tests: 48 passed
- Backend unit tests: 101 passed
- Backend ruff: clean

SDD artifacts: openspec/changes/responsive-terminal/
2026-05-27 21:27:49 +02:00

45 lines
1.2 KiB
JSON

{
"name": "headquarter-web",
"version": "0.1.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
"typecheck": "tsc --noEmit",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"test": "vitest run"
},
"dependencies": {
"@phosphor-icons/react": "^2.1.10",
"@types/prismjs": "^1.26.6",
"axios": "^1.6.0",
"prismjs": "^1.30.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.20.0",
"react-simple-code-editor": "^0.14.1",
"tailwindcss": "^3.3.0",
"xterm": "^5.3.0",
"xterm-addon-fit": "^0.8.0",
"xterm-addon-serialize": "^0.11.0",
"xterm-addon-web-links": "^0.9.0"
},
"devDependencies": {
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"@typescript-eslint/eslint-plugin": "^6.14.0",
"@typescript-eslint/parser": "^6.14.0",
"@vitejs/plugin-react": "^4.2.0",
"autoprefixer": "^10.4.16",
"eslint": "^8.55.0",
"jsdom": "^29.1.1",
"postcss": "^8.4.32",
"typescript": "^5.3.0",
"vite": "^5.0.0",
"vitest": "^4.1.6"
}
}