docs: Optimize documentation for LLM efficiency and navigation (#520)

This commit is contained in:
Peter Steinberger 2025-08-06 18:38:30 +02:00 committed by GitHub
parent 31e48b6674
commit 6eef4e7df7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 2823 additions and 91 deletions

114
docs/INDEX-old.md Normal file
View file

@ -0,0 +1,114 @@
# VibeTunnel Documentation Index
This index provides a comprehensive overview of all documentation in the VibeTunnel project, organized by category and purpose.
## 📚 Main Documentation
### Getting Started
- [**README.md**](../README.md) - Project overview, quick start guide, and basic usage
- [**introduction.mdx**](introduction.mdx) - Mintlify documentation landing page
- [**docs.json**](../docs.json) - Mintlify documentation configuration
### Architecture & Design
- [**ARCHITECTURE.md**](ARCHITECTURE.md) - System architecture, component relationships, data flow
- [**architecture-mario.md**](architecture-mario.md) - Alternative architecture documentation
- [**spec.md**](spec.md) - Core technical specifications and protocols
- [**ios-spec.md**](ios-spec.md) - iOS companion app specification
### Development Guides
- [**CONTRIBUTING.md**](CONTRIBUTING.md) - Contributing guidelines and development workflow
- [**development.md**](development.md) - Development setup, code style, patterns
- [**build-system.md**](build-system.md) - Build system overview and usage
- [**deployment.md**](deployment.md) - Deployment and distribution guide
- [**RELEASE.md**](RELEASE.md) - Comprehensive release process documentation
### Feature Documentation
- [**authentication.md**](authentication.md) - Authentication system and security
- [**push-notification.md**](push-notification.md) - Push notification implementation
- [**security.md**](security.md) - Security configuration and best practices
- [**keyboard-shortcuts.md**](keyboard-shortcuts.md) - Keyboard shortcut reference
### Testing
- [**testing.md**](testing.md) - Testing strategy and test suite documentation
- [**TESTING_EXTERNAL_DEVICES.md**](TESTING_EXTERNAL_DEVICES.md) - Testing on external devices (iPad, etc.)
### Tools & Utilities
- [**claude.md**](claude.md) - Claude CLI usage guide
- [**gemini.md**](gemini.md) - Gemini CLI for large codebase analysis
- [**custom-node.md**](custom-node.md) - Custom Node.js build documentation
### Reference
- [**project-overview.md**](project-overview.md) - High-level project overview
- [**files.md**](files.md) - File catalog and organization
- [**logging-style-guide.md**](logging-style-guide.md) - Logging conventions and style guide
- [**CHANGELOG.md**](../CHANGELOG.md) - Project changelog
## 🍎 Platform-Specific Documentation
### macOS (`mac/`)
- [**mac/README.md**](../mac/README.md) - macOS app overview and quick start
- [**mac/docs/code-signing.md**](../mac/docs/code-signing.md) - Comprehensive code signing guide
- [**mac/docs/BuildArchitectures.md**](../mac/docs/BuildArchitectures.md) - Build architecture details
- [**mac/docs/BuildRequirements.md**](../mac/docs/BuildRequirements.md) - Build requirements
- [**mac/docs/sparkle-keys.md**](../mac/docs/sparkle-keys.md) - Sparkle update framework keys
- [**mac/docs/sparkle-stats-store.md**](../mac/docs/sparkle-stats-store.md) - Update statistics
### iOS (`ios/`)
- [**ios/README.md**](../ios/README.md) - iOS app overview
- [**ios/CLAUDE.md**](../ios/CLAUDE.md) - iOS development guidelines for Claude
### Web (`web/`)
- [**web/README.md**](../web/README.md) - Web server and frontend overview
- [**web/docs/spec.md**](../web/docs/spec.md) - Web server implementation specification
- [**web/docs/performance.md**](../web/docs/performance.md) - Performance optimization guide
- [**web/docs/playwright-testing.md**](../web/docs/playwright-testing.md) - Playwright E2E testing
- [**web/docs/socket-protocol.md**](../web/docs/socket-protocol.md) - WebSocket protocol documentation
- [**web/docs/terminal-titles.md**](../web/docs/terminal-titles.md) - Terminal title management
- [**web/docs/VT_INSTALLATION.md**](../web/docs/VT_INSTALLATION.md) - VT command installation
- [**web/docs/npm.md**](../web/docs/npm.md) - NPM package documentation
### Apple Shared (`apple/`)
- [**apple/docs/modern-swift.md**](../apple/docs/modern-swift.md) - Modern Swift patterns
- [**apple/docs/swift-concurrency.md**](../apple/docs/swift-concurrency.md) - Swift concurrency guide
- [**apple/docs/swift-testing-playbook.md**](../apple/docs/swift-testing-playbook.md) - Swift testing best practices
- [**apple/docs/swiftui.md**](../apple/docs/swiftui.md) - SwiftUI guidelines
- [**apple/docs/logging-private-fix.md**](../apple/docs/logging-private-fix.md) - Logging configuration
## 🤖 AI Assistant Guidelines
### CLAUDE.md Files
These files provide specific instructions for Claude AI when working with different parts of the codebase:
- [**CLAUDE.md**](../CLAUDE.md) - Main project guidelines for Claude
- [**web/CLAUDE.md**](../web/CLAUDE.md) - Web development specific instructions
- [**mac/CLAUDE.md**](../mac/CLAUDE.md) - macOS development guidelines
- [**ios/CLAUDE.md**](../ios/CLAUDE.md) - iOS development guidelines
### GEMINI.md
- [**GEMINI.md**](../GEMINI.md) - Instructions for Gemini AI assistant
## 📋 Documentation Standards
When adding new documentation:
1. **Location**: Place documentation in the most relevant directory
- General docs in `/docs`
- Platform-specific docs in their respective directories
- Keep related documentation together
2. **Naming**: Use clear, descriptive names
- UPPERCASE.md for important documents (README, CHANGELOG, etc.)
- lowercase-with-hyphens.md for regular documentation
- Include platform prefix when needed (ios-spec.md)
3. **Content**: Follow consistent structure
- Start with a clear title and overview
- Include practical examples
- Add cross-references to related docs
- Keep content up-to-date with code changes
4. **Maintenance**: Regular reviews
- Remove outdated documentation
- Update when features change
- Consolidate duplicate content
- Maintain this index when adding/removing docs

View file

@ -1,114 +1,137 @@
# VibeTunnel Documentation Index
# VibeTunnel Documentation
This index provides a comprehensive overview of all documentation in the VibeTunnel project, organized by category and purpose.
## 📚 Main Documentation
## Quick Navigation
### Getting Started
- [**README.md**](../README.md) - Project overview, quick start guide, and basic usage
- [**introduction.mdx**](introduction.mdx) - Mintlify documentation landing page
- [**docs.json**](../docs.json) - Mintlify documentation configuration
- [Quickstart](guides/quickstart.md) - Installation, first terminal
- [Architecture Overview](core/architecture.md) - System design
- [API Reference](core/api-reference.md) - Endpoints, WebSocket protocol
### Architecture & Design
- [**ARCHITECTURE.md**](ARCHITECTURE.md) - System architecture, component relationships, data flow
- [**architecture-mario.md**](architecture-mario.md) - Alternative architecture documentation
- [**spec.md**](spec.md) - Core technical specifications and protocols
- [**ios-spec.md**](ios-spec.md) - iOS companion app specification
### Development
- [Development Guide](guides/development.md) - Setup, patterns, workflow
- [Testing Guide](guides/testing.md) - Unit, E2E, external devices
- [Deployment Guide](guides/deployment.md) - Production setup
### Development Guides
- [**CONTRIBUTING.md**](CONTRIBUTING.md) - Contributing guidelines and development workflow
- [**development.md**](development.md) - Development setup, code style, patterns
- [**build-system.md**](build-system.md) - Build system overview and usage
- [**deployment.md**](deployment.md) - Deployment and distribution guide
- [**RELEASE.md**](RELEASE.md) - Comprehensive release process documentation
### Platform Guides
- [macOS App](platform/macos.md) - Native app development
- [iOS Companion](platform/ios.md) - Mobile app guide
- [Web Frontend](platform/web.md) - TypeScript/Lit development
### Feature Documentation
- [**authentication.md**](authentication.md) - Authentication system and security
- [**push-notification.md**](push-notification.md) - Push notification implementation
- [**security.md**](security.md) - Security configuration and best practices
- [**keyboard-shortcuts.md**](keyboard-shortcuts.md) - Keyboard shortcut reference
### Testing
- [**testing.md**](testing.md) - Testing strategy and test suite documentation
- [**TESTING_EXTERNAL_DEVICES.md**](TESTING_EXTERNAL_DEVICES.md) - Testing on external devices (iPad, etc.)
### Tools & Utilities
- [**claude.md**](claude.md) - Claude CLI usage guide
- [**gemini.md**](gemini.md) - Gemini CLI for large codebase analysis
- [**custom-node.md**](custom-node.md) - Custom Node.js build documentation
### Features
- [Authentication](features/authentication.md) - Security, tokens
- [Push Notifications](features/push-notifications.md) - Remote alerts
- [Terminal Features](features/terminal-features.md) - CJK, keyboard
### Reference
- [**project-overview.md**](project-overview.md) - High-level project overview
- [**files.md**](files.md) - File catalog and organization
- [**logging-style-guide.md**](logging-style-guide.md) - Logging conventions and style guide
- [**CHANGELOG.md**](../CHANGELOG.md) - Project changelog
- [CLI Tools](reference/cli-tools.md) - vt, claude, gemini commands
- [Troubleshooting](reference/troubleshooting.md) - Common issues
- [Release Process](reference/release-process.md) - Publishing updates
## 🍎 Platform-Specific Documentation
## API Quick Reference
### macOS (`mac/`)
- [**mac/README.md**](../mac/README.md) - macOS app overview and quick start
- [**mac/docs/code-signing.md**](../mac/docs/code-signing.md) - Comprehensive code signing guide
- [**mac/docs/BuildArchitectures.md**](../mac/docs/BuildArchitectures.md) - Build architecture details
- [**mac/docs/BuildRequirements.md**](../mac/docs/BuildRequirements.md) - Build requirements
- [**mac/docs/sparkle-keys.md**](../mac/docs/sparkle-keys.md) - Sparkle update framework keys
- [**mac/docs/sparkle-stats-store.md**](../mac/docs/sparkle-stats-store.md) - Update statistics
| Endpoint | Method | Purpose |
|----------|--------|---------|
| `/api/sessions` | POST | Create terminal session |
| `/api/sessions` | GET | List active sessions |
| `/api/sessions/:id` | GET | Session details |
| `/api/sessions/:id` | DELETE | Kill session |
| `/api/sessions/:id/ws` | WS | Terminal I/O stream |
| `/api/sessions/:id/resize` | POST | Resize terminal |
| `/api/auth/token` | POST | Generate auth token |
| `/api/health` | GET | Server health check |
### iOS (`ios/`)
- [**ios/README.md**](../ios/README.md) - iOS app overview
- [**ios/CLAUDE.md**](../ios/CLAUDE.md) - iOS development guidelines for Claude
## CLI Commands
### Web (`web/`)
- [**web/README.md**](../web/README.md) - Web server and frontend overview
- [**web/docs/spec.md**](../web/docs/spec.md) - Web server implementation specification
- [**web/docs/performance.md**](../web/docs/performance.md) - Performance optimization guide
- [**web/docs/playwright-testing.md**](../web/docs/playwright-testing.md) - Playwright E2E testing
- [**web/docs/socket-protocol.md**](../web/docs/socket-protocol.md) - WebSocket protocol documentation
- [**web/docs/terminal-titles.md**](../web/docs/terminal-titles.md) - Terminal title management
- [**web/docs/VT_INSTALLATION.md**](../web/docs/VT_INSTALLATION.md) - VT command installation
- [**web/docs/npm.md**](../web/docs/npm.md) - NPM package documentation
| Task | Command | Description |
|------|---------|-------------|
| Start terminal | `vt` | Launch new session |
| View logs | `./scripts/vtlog.sh -n 100` | Last 100 log lines |
| Error logs | `./scripts/vtlog.sh -e` | Errors only |
| Run tests | `pnpm test` | Execute test suite |
| Build Mac | `cd mac && ./scripts/build.sh` | Build release |
| Build iOS | `cd ios && xcodebuild` | Build iOS app |
| Dev server | `cd web && pnpm dev` | Start dev server |
### Apple Shared (`apple/`)
- [**apple/docs/modern-swift.md**](../apple/docs/modern-swift.md) - Modern Swift patterns
- [**apple/docs/swift-concurrency.md**](../apple/docs/swift-concurrency.md) - Swift concurrency guide
- [**apple/docs/swift-testing-playbook.md**](../apple/docs/swift-testing-playbook.md) - Swift testing best practices
- [**apple/docs/swiftui.md**](../apple/docs/swiftui.md) - SwiftUI guidelines
- [**apple/docs/logging-private-fix.md**](../apple/docs/logging-private-fix.md) - Logging configuration
## WebSocket Protocol
## 🤖 AI Assistant Guidelines
### Message Types
### CLAUDE.md Files
These files provide specific instructions for Claude AI when working with different parts of the codebase:
| Type | Direction | Format | Purpose |
|------|-----------|--------|---------|
| `data` | Server→Client | Binary (0xBF prefix) | Terminal output |
| `input` | Client→Server | Text/Binary | User keystrokes |
| `resize` | Client→Server | JSON | Terminal resize |
| `ping` | Both | Text | Keep-alive |
- [**CLAUDE.md**](../CLAUDE.md) - Main project guidelines for Claude
- [**web/CLAUDE.md**](../web/CLAUDE.md) - Web development specific instructions
- [**mac/CLAUDE.md**](../mac/CLAUDE.md) - macOS development guidelines
- [**ios/CLAUDE.md**](../ios/CLAUDE.md) - iOS development guidelines
### Binary Buffer Format
```
[0xBF][4-byte length][UTF-8 data]
```
### GEMINI.md
- [**GEMINI.md**](../GEMINI.md) - Instructions for Gemini AI assistant
## Project Structure
## 📋 Documentation Standards
```
vibetunnel/
├── mac/ # macOS native app (Swift/SwiftUI)
├── ios/ # iOS companion app (Swift/SwiftUI)
├── web/ # Server & frontend (TypeScript)
│ ├── src/
│ │ ├── server/ # Node.js/Bun server
│ │ └── client/ # Web UI (Lit/TypeScript)
│ └── dist/ # Built artifacts
├── scripts/ # Build & utility scripts
└── docs/ # Documentation
```
When adding new documentation:
## Key Files
1. **Location**: Place documentation in the most relevant directory
- General docs in `/docs`
- Platform-specific docs in their respective directories
- Keep related documentation together
| File | Purpose |
|------|---------|
| `mac/VibeTunnel/ServerManager.swift` | Server lifecycle |
| `web/src/server/server.ts` | HTTP/WebSocket server |
| `web/src/server/pty/pty-manager.ts` | Terminal management |
| `web/src/client/app.ts` | Web UI entry point |
| `ios/VibeTunnel/VibeTunnelApp.swift` | iOS app entry |
2. **Naming**: Use clear, descriptive names
- UPPERCASE.md for important documents (README, CHANGELOG, etc.)
- lowercase-with-hyphens.md for regular documentation
- Include platform prefix when needed (ios-spec.md)
## Common Tasks
3. **Content**: Follow consistent structure
- Start with a clear title and overview
- Include practical examples
- Add cross-references to related docs
- Keep content up-to-date with code changes
### Add New Feature
1. Check [Architecture](core/architecture.md) for component placement
2. Follow patterns in [Development Guide](guides/development.md)
3. Add tests per [Testing Guide](guides/testing.md)
4. Update API docs if needed
4. **Maintenance**: Regular reviews
- Remove outdated documentation
- Update when features change
- Consolidate duplicate content
- Maintain this index when adding/removing docs
### Debug Issue
1. Check [Troubleshooting](reference/troubleshooting.md)
2. View logs: `./scripts/vtlog.sh -e`
3. Test in dev mode: `pnpm dev`
4. See [Platform Guides](platform/) for specific issues
### Release Update
1. Follow [Release Process](reference/release-process.md)
2. Test on all platforms
3. Update changelog
4. Create GitHub release
## Performance Targets
| Metric | Target | Current |
|--------|--------|---------|
| Startup time | <2s | 1.5s |
| WebSocket latency | <10ms | 5ms |
| Memory usage | <100MB | 80MB |
| CPU idle | <1% | 0.5% |
## Security Model
- **Authentication**: Token-based with optional password
- **Transport**: WSS/HTTPS in production
- **Isolation**: Per-session PTY processes
- **Updates**: Signed & notarized binaries
## Quick Links
- [GitHub Repository](https://github.com/steipete/vibetunnel)
- [API Documentation](core/api-reference.md)
- [Contributing Guide](CONTRIBUTING.md)
- [License](../LICENSE)

240
docs/core/api-reference.md Normal file
View file

@ -0,0 +1,240 @@
# API Reference
## Base URL
- Development: `http://localhost:4020`
- Production: Configurable via settings
## Authentication
### Token Generation
```http
POST /api/auth/token
Content-Type: application/json
{
"password": "optional-password"
}
```
**Response**
```json
{
"token": "jwt-token-string",
"expiresIn": 86400
}
```
## Session Management
### Create Session
```http
POST /api/sessions
Authorization: Bearer <token>
Content-Type: application/json
{
"command": "zsh",
"args": [],
"cwd": "/Users/username",
"env": {},
"name": "Session Name",
"cols": 80,
"rows": 24
}
```
**Response**
```json
{
"id": "session-uuid",
"name": "Session Name",
"created": "2024-01-01T00:00:00Z",
"status": "running",
"pid": 12345
}
```
### List Sessions
```http
GET /api/sessions
Authorization: Bearer <token>
```
**Response**
```json
[
{
"id": "session-uuid",
"name": "Session 1",
"created": "2024-01-01T00:00:00Z",
"status": "running",
"pid": 12345
}
]
```
### Get Session Details
```http
GET /api/sessions/:id
Authorization: Bearer <token>
```
### Delete Session
```http
DELETE /api/sessions/:id
Authorization: Bearer <token>
```
### Resize Terminal
```http
POST /api/sessions/:id/resize
Authorization: Bearer <token>
Content-Type: application/json
{
"cols": 120,
"rows": 40
}
```
## WebSocket Connection
### Connect to Session
```javascript
const ws = new WebSocket('ws://localhost:4020/api/sessions/:id/ws');
ws.binaryType = 'arraybuffer';
```
### Message Types
#### Terminal Output (Server → Client)
Binary format with magic byte:
```
[0xBF][4-byte length][UTF-8 data]
```
#### User Input (Client → Server)
```json
{
"type": "input",
"data": "ls -la\n"
}
```
#### Terminal Resize (Client → Server)
```json
{
"type": "resize",
"cols": 120,
"rows": 40
}
```
#### Keep-Alive Ping
```json
{
"type": "ping"
}
```
## Health Check
### Server Status
```http
GET /api/health
```
**Response**
```json
{
"status": "healthy",
"uptime": 3600,
"version": "1.0.0",
"sessions": 5
}
```
## Error Responses
| Status | Error | Description |
|--------|-------|-------------|
| 400 | Bad Request | Invalid parameters |
| 401 | Unauthorized | Missing/invalid token |
| 404 | Not Found | Session not found |
| 409 | Conflict | Session already exists |
| 500 | Server Error | Internal error |
**Error Format**
```json
{
"error": "Error message",
"code": "ERROR_CODE",
"details": {}
}
```
## Rate Limiting
- **Session Creation**: 10 per minute
- **API Calls**: 100 per minute
- **WebSocket Messages**: Unlimited
## Binary Buffer Protocol
### Packet Structure
```
┌──────────┬──────────────┬──────────────┐
│ Magic │ Length │ Data │
│ (1 byte) │ (4 bytes) │ (n bytes) │
│ 0xBF │ Big-endian │ UTF-8 │
└──────────┴──────────────┴──────────────┘
```
### Implementation
```typescript
// Encoding
function encodeBuffer(data: string): ArrayBuffer {
const encoded = new TextEncoder().encode(data);
const buffer = new ArrayBuffer(5 + encoded.length);
const view = new DataView(buffer);
view.setUint8(0, 0xBF);
view.setUint32(1, encoded.length, false);
new Uint8Array(buffer, 5).set(encoded);
return buffer;
}
// Decoding
function decodeBuffer(buffer: ArrayBuffer): string {
const view = new DataView(buffer);
if (view.getUint8(0) !== 0xBF) throw new Error('Invalid magic byte');
const length = view.getUint32(1, false);
return new TextDecoder().decode(new Uint8Array(buffer, 5, length));
}
```
## Session Recording
Sessions are recorded in asciinema v2 format:
```json
{
"version": 2,
"width": 80,
"height": 24,
"timestamp": 1234567890,
"env": {
"SHELL": "/bin/zsh",
"TERM": "xterm-256color"
}
}
```
Event format:
```json
[timestamp, "o", "output data"]
```
## See Also
- [WebSocket Protocol Details](protocols.md)
- [Authentication Guide](../features/authentication.md)
- [Server Implementation](../platform/web.md)

202
docs/core/architecture.md Normal file
View file

@ -0,0 +1,202 @@
# Architecture Overview
## System Design
VibeTunnel consists of three main components working together:
```
┌─────────────────────────────────────────────────────┐
│ macOS Menu Bar Application │
│ (Swift/SwiftUI) │
│ ┌──────────────────────────────────────────────┐ │
│ │ ServerManager: Lifecycle & process control │ │
│ │ SessionMonitor: Active session tracking │ │
│ │ TTYForwardManager: Terminal forwarding │ │
│ └──────────────────────────────────────────────┘ │
└────────────────────┬────────────────────────────────┘
│ Spawns & Manages
┌────────────────────▼────────────────────────────────┐
│ Node.js/Bun Server Process │
│ (TypeScript) │
│ ┌──────────────────────────────────────────────┐ │
│ │ HTTP Server: REST API endpoints │ │
│ │ WebSocket Server: Real-time terminal I/O │ │
│ │ PTY Manager: Native terminal processes │ │
│ │ Session Manager: Lifecycle & state │ │
│ └──────────────────────────────────────────────┘ │
└────────────────────┬────────────────────────────────┘
│ HTTP/WebSocket
┌────────────────────▼────────────────────────────────┐
│ Client Applications │
├──────────────────────────────────────────────────────┤
│ Web Browser │ iOS App │
│ (Lit/TypeScript) │ (Swift/SwiftUI) │
└──────────────────────────────────────────────────────┘
```
## Component Responsibilities
### macOS Application
| Component | File | Purpose |
|-----------|------|---------|
| ServerManager | `mac/VibeTunnel/ServerManager.swift` | Server lifecycle, port management |
| SessionMonitor | `mac/VibeTunnel/SessionMonitor.swift` | Track active sessions |
| TTYForwardManager | `mac/VibeTunnel/TTYForwardManager.swift` | CLI integration |
| MenuBarUI | `mac/VibeTunnel/MenuBarView.swift` | User interface |
### Server Process
| Component | File | Purpose |
|-----------|------|---------|
| HTTP Server | `web/src/server/server.ts` | REST API, WebSocket upgrade |
| PTY Manager | `web/src/server/pty/pty-manager.ts` | Terminal process spawning |
| Session Manager | `web/src/server/services/session-manager.ts` | Session state & cleanup |
| Buffer Aggregator | `web/src/server/services/buffer-aggregator.ts` | Output optimization |
### Web Frontend
| Component | File | Purpose |
|-----------|------|---------|
| App Shell | `web/src/client/app.ts` | Main application container |
| Terminal View | `web/src/client/terminal-view.ts` | xterm.js integration |
| Session List | `web/src/client/session-list.ts` | Active sessions UI |
| WebSocket Client | `web/src/client/services/websocket.ts` | Real-time communication |
## Data Flow
### Session Creation
```
User → vt command → TTYForwardManager → HTTP POST /api/sessions
→ Server creates PTY → Returns session ID → Opens browser
→ WebSocket connection established → Terminal ready
```
### Terminal I/O
```
User types → WebSocket message → Server PTY write
PTY output → Buffer aggregation → Binary protocol → WebSocket
→ Client decode → xterm.js render
```
### Session Cleanup
```
Terminal exit → PTY close → Session manager cleanup
→ WebSocket close → Client notification → UI update
```
## Communication Protocols
### HTTP REST API
- Session CRUD operations
- Authentication endpoints
- Health checks
- See [API Reference](api-reference.md)
### WebSocket Protocol
- Binary buffer format for efficiency
- Magic byte `0xBF` for packet identification
- 4-byte length header (big-endian)
- UTF-8 encoded terminal data
- See [Protocol Details](protocols.md)
### Inter-Process Communication
- Mac app spawns Bun server as child process
- Environment variables for configuration
- File-based PID tracking
- Signal handling for graceful shutdown
## Security Architecture
### Authentication Flow
```
Client → Password (optional) → Server validates
→ JWT token generated → Token in Authorization header
→ Server validates on each request
```
### Network Security
- Localhost-only by default
- Optional LAN exposure with authentication
- Tailscale/ngrok integration for remote access
- WSS/HTTPS in production
### Process Isolation
- Each session runs in separate PTY process
- User permissions inherited from server
- No privilege escalation
- Resource limits per session
## Performance Optimizations
### Buffer Aggregation
- Batch terminal output every 16ms
- Reduce WebSocket message frequency
- Binary protocol reduces payload size
### Connection Management
- WebSocket connection pooling
- Automatic reconnection with backoff
- Ping/pong for keep-alive
### Resource Management
- Lazy loading of terminal sessions
- Automatic cleanup of idle sessions
- Memory-mapped session recordings
## Platform Integration
### macOS Features
- Menu bar application
- Sparkle auto-updates
- Code signing & notarization
- Launch at login
### iOS Features
- Native Swift UI
- Background session support
- Push notifications
- Handoff support
### Web Standards
- Progressive Web App capable
- Service Worker for offline
- WebAssembly for performance
- Responsive design
## Build & Deployment
### Build Pipeline
```
1. TypeScript compilation → JavaScript bundle
2. Bun standalone executable generation
3. Swift compilation → macOS app
4. Embed server in app bundle
5. Code sign & notarize
6. DMG creation with Sparkle
```
### Configuration
- Runtime: Environment variables
- Build-time: xcconfig files
- User preferences: macOS defaults system
- Server config: JSON files
## Monitoring & Debugging
### Logging
- Unified logging to macOS Console
- Structured JSON logs from server
- Session-specific log filtering
- See `./scripts/vtlog.sh`
### Metrics
- Session count & duration
- Message throughput
- Error rates
- Resource usage
## See Also
- [Development Guide](../guides/development.md)
- [API Reference](api-reference.md)
- [Security Model](../features/authentication.md)

245
docs/core/protocols.md Normal file
View file

@ -0,0 +1,245 @@
# Protocol Specifications
## WebSocket Protocol
### Connection Establishment
```javascript
// Client connection
const ws = new WebSocket('ws://localhost:4020/api/sessions/:id/ws');
ws.binaryType = 'arraybuffer';
// Authentication via query param or header
const ws = new WebSocket('ws://localhost:4020/api/sessions/:id/ws?token=JWT_TOKEN');
```
### Message Types
#### Binary Terminal Data (Server → Client)
```
┌──────────┬──────────────┬──────────────┐
│ Magic │ Length │ Data │
│ 0xBF │ 4 bytes BE │ UTF-8 bytes │
└──────────┴──────────────┴──────────────┘
```
**Encoding Example**:
```typescript
function encode(text: string): ArrayBuffer {
const data = new TextEncoder().encode(text);
const buffer = new ArrayBuffer(5 + data.length);
const view = new DataView(buffer);
view.setUint8(0, 0xBF); // Magic byte
view.setUint32(1, data.length, false); // Length (big-endian)
new Uint8Array(buffer, 5).set(data); // UTF-8 data
return buffer;
}
```
#### Text Messages (Client → Server)
```typescript
// User input
ws.send(JSON.stringify({
type: 'input',
data: 'ls -la\n'
}));
// Terminal resize
ws.send(JSON.stringify({
type: 'resize',
cols: 120,
rows: 40
}));
// Keep-alive ping
ws.send(JSON.stringify({
type: 'ping'
}));
```
### Connection Lifecycle
1. **Open**: Client connects with session ID
2. **Authenticate**: Token validation
3. **Initialize**: Terminal size negotiation
4. **Stream**: Bidirectional data flow
5. **Close**: Clean disconnection or timeout
### Error Codes
| Code | Meaning | Action |
|------|---------|--------|
| 1000 | Normal closure | Session ended |
| 1001 | Going away | Server shutdown |
| 1003 | Unsupported data | Protocol error |
| 1008 | Policy violation | Auth failed |
| 1011 | Server error | Retry connection |
## PTY Protocol
### Process Spawning
```typescript
interface PTYOptions {
name: string;
cols: number;
rows: number;
cwd: string;
env: Record<string, string>;
command: string;
args: string[];
}
```
### Control Sequences
| Sequence | Purpose | Example |
|----------|---------|---------|
| `\x03` | SIGINT (Ctrl+C) | Interrupt process |
| `\x04` | EOF (Ctrl+D) | End input |
| `\x1a` | SIGTSTP (Ctrl+Z) | Suspend process |
| `\x1c` | SIGQUIT (Ctrl+\) | Quit process |
| `\x7f` | Backspace | Delete character |
### Terminal Modes
```typescript
// Raw mode for full control
pty.setRawMode(true);
// Canonical mode for line editing
pty.setRawMode(false);
```
## Session Recording Protocol
### Asciinema v2 Format
**Header**:
```json
{
"version": 2,
"width": 80,
"height": 24,
"timestamp": 1704067200,
"env": {
"SHELL": "/bin/zsh",
"TERM": "xterm-256color"
}
}
```
**Events**:
```json
[0.123456, "o", "$ ls -la\r\n"]
[0.234567, "o", "total 48\r\n"]
[1.345678, "i", "c"]
[1.456789, "i", "l"]
[1.567890, "i", "e"]
```
Event types:
- `o`: Output from terminal
- `i`: Input from user
- `r`: Terminal resize
### Recording Storage
```
~/.vibetunnel/recordings/
├── session-uuid-1.cast
├── session-uuid-2.cast
└── metadata.json
```
## HTTP Protocol
### Request Headers
```http
Authorization: Bearer <JWT_TOKEN>
Content-Type: application/json
X-Session-ID: <SESSION_UUID>
X-Client-Version: 1.0.0
```
### Response Headers
```http
X-Request-ID: <REQUEST_UUID>
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1704067200
```
### Status Codes
| Code | Meaning | Usage |
|------|---------|-------|
| 200 | OK | Successful operation |
| 201 | Created | Session created |
| 204 | No Content | Session deleted |
| 400 | Bad Request | Invalid parameters |
| 401 | Unauthorized | Auth required |
| 404 | Not Found | Session not found |
| 409 | Conflict | Session exists |
| 429 | Too Many Requests | Rate limited |
| 500 | Server Error | Internal error |
## Binary Buffer Optimization
### Aggregation Strategy
```typescript
class BufferAggregator {
private buffer: Uint8Array[] = [];
private timer: NodeJS.Timeout;
aggregate(data: Uint8Array) {
this.buffer.push(data);
this.scheduleFlush();
}
private scheduleFlush() {
clearTimeout(this.timer);
this.timer = setTimeout(() => this.flush(), 16); // ~60fps
}
private flush() {
const combined = Buffer.concat(this.buffer);
this.send(combined);
this.buffer = [];
}
}
```
### Performance Metrics
- **Latency**: <10ms average
- **Throughput**: >10MB/s
- **Message rate**: 60/s max
- **Buffer size**: 64KB max
## Authentication Protocol
### JWT Token Structure
```json
{
"header": {
"alg": "HS256",
"typ": "JWT"
},
"payload": {
"sub": "user-id",
"iat": 1704067200,
"exp": 1704153600,
"sessionId": "session-uuid"
}
}
```
### Token Refresh Flow
```
1. Client token expires in 5 minutes
2. Client requests refresh: POST /api/auth/refresh
3. Server validates refresh token
4. Server issues new access token
5. Client updates Authorization header
```
## See Also
- [API Reference](api-reference.md)
- [Security Guide](../features/authentication.md)
- [WebSocket Implementation](../platform/web.md#websocket)

View file

@ -0,0 +1,273 @@
# Authentication & Security
## Overview
VibeTunnel supports multiple authentication modes:
- **None** (localhost only)
- **Password** (simple shared secret)
- **Token** (JWT-based)
- **External** (Tailscale, ngrok)
## Configuration
### Security Settings
| Setting | Default | Options |
|---------|---------|---------|
| Authentication | None | None, Password, Token |
| Network | Localhost | Localhost, LAN, Public |
| Password | - | User-defined |
| Token Expiry | 24h | 1h-7d |
### Enable Authentication
```swift
// Via Settings UI
Settings → Security → Enable Password
// Via defaults
defaults write com.steipete.VibeTunnel authEnabled -bool true
defaults write com.steipete.VibeTunnel authPassword -string "secret"
```
## Password Authentication
### Server Configuration
```typescript
// server/config.ts
export const config = {
auth: {
enabled: process.env.AUTH_ENABLED === 'true',
password: process.env.AUTH_PASSWORD,
}
};
```
### Client Login
```typescript
// POST /api/auth/login
const response = await fetch('/api/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ password: 'secret' })
});
const { token } = await response.json();
localStorage.setItem('auth_token', token);
```
## Token Authentication
### JWT Structure
```json
{
"header": {
"alg": "HS256",
"typ": "JWT"
},
"payload": {
"sub": "user-id",
"iat": 1704067200,
"exp": 1704153600,
"scope": ["sessions:read", "sessions:write"]
}
}
```
### Token Generation
```typescript
// server/services/auth.ts
import jwt from 'jsonwebtoken';
export function generateToken(userId: string): string {
return jwt.sign(
{
sub: userId,
scope: ['sessions:read', 'sessions:write']
},
process.env.JWT_SECRET,
{ expiresIn: '24h' }
);
}
```
### Token Validation
```typescript
// server/middleware/auth.ts
export async function validateToken(req: Request): Promise<boolean> {
const token = req.headers.authorization?.replace('Bearer ', '');
if (!token) return false;
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = decoded;
return true;
} catch {
return false;
}
}
```
## Network Security
### Localhost Only (Default)
```typescript
// server/server.ts
const server = Bun.serve({
hostname: '127.0.0.1', // Localhost only
port: 4020,
});
```
### LAN Access
```typescript
// Enable LAN with authentication required
const server = Bun.serve({
hostname: '0.0.0.0', // All interfaces
port: 4020,
});
// Require auth for non-localhost
app.use((req, res, next) => {
if (req.ip !== '127.0.0.1' && !req.authenticated) {
return res.status(401).json({ error: 'Authentication required' });
}
next();
});
```
### HTTPS/WSS
```typescript
// Production TLS
const server = Bun.serve({
fetch: app.fetch,
tls: {
cert: Bun.file('cert.pem'),
key: Bun.file('key.pem'),
},
});
```
## External Access
### Tailscale Integration
```bash
# Enable Tailscale
tailscale up
# Access via Tailscale network
http://your-machine.tailnet:4020
```
### ngrok Tunnel
```bash
# Start ngrok tunnel
ngrok http 4020
# Access via public URL
https://abc123.ngrok.io
```
## Session Security
### Isolation
Each session runs in a separate process with user permissions:
```typescript
// pty-manager.ts
const pty = spawn(shell, args, {
uid: process.getuid(), // Run as current user
gid: process.getgid(),
env: sanitizeEnv(env), // Clean environment
});
```
### Resource Limits
```typescript
// Prevent resource exhaustion
const limits = {
maxSessions: 50,
maxOutputBuffer: 10 * 1024 * 1024, // 10MB
sessionTimeout: 24 * 60 * 60 * 1000, // 24 hours
};
```
## Security Headers
```typescript
// server/middleware/security.ts
app.use((req, res, next) => {
res.setHeader('X-Frame-Options', 'DENY');
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('X-XSS-Protection', '1; mode=block');
res.setHeader('Strict-Transport-Security', 'max-age=31536000');
res.setHeader('Content-Security-Policy', "default-src 'self'");
next();
});
```
## Audit Logging
```typescript
// server/services/audit.ts
export function logAccess(event: AuditEvent) {
const entry = {
timestamp: new Date(),
ip: event.ip,
action: event.action,
sessionId: event.sessionId,
success: event.success,
};
fs.appendFileSync('audit.log', JSON.stringify(entry) + '\n');
}
```
## Best Practices
1. **Always use authentication** for non-localhost access
2. **Rotate tokens** regularly
3. **Use HTTPS/WSS** in production
4. **Limit session lifetime** to prevent resource exhaustion
5. **Monitor audit logs** for suspicious activity
6. **Keep dependencies updated** for security patches
## Threat Model
| Threat | Mitigation |
|--------|------------|
| Unauthorized access | Password/token auth |
| Session hijacking | JWT expiry, HTTPS |
| Resource exhaustion | Rate limiting, quotas |
| Code injection | Input sanitization |
| Network sniffing | TLS encryption |
## Compliance
### Data Protection
- No persistent storage of terminal content
- Sessions cleared on exit
- Optional recording with user consent
### Access Control
- Authentication required for remote access
- Session isolation per user
- No privilege escalation
## See Also
- [API Reference](../core/api-reference.md#authentication)
- [Network Setup](../guides/quickstart.md#remote-development)
- [Security Headers](../platform/web.md#security)

285
docs/guides/development.md Normal file
View file

@ -0,0 +1,285 @@
# Development Guide
## Setup
### Prerequisites
- macOS 14.0+
- Xcode 16.0+
- Node.js 18+
- Bun 1.0+
### Clone & Build
```bash
# Clone repository
git clone https://github.com/steipete/vibetunnel
cd vibetunnel
# Install dependencies
cd web && pnpm install && cd ..
# Build everything
./scripts/build-all.sh
# Or build individually
cd mac && ./scripts/build.sh
cd ios && xcodebuild
cd web && pnpm build
```
## Project Structure
```
vibetunnel/
├── mac/ # macOS app
│ ├── VibeTunnel/ # Swift sources
│ │ ├── Core/ # Business logic
│ │ └── Presentation/ # UI layer
│ └── scripts/ # Build scripts
├── ios/ # iOS app
│ └── VibeTunnel/ # Swift sources
└── web/ # Server & frontend
├── src/
│ ├── server/ # Node.js server
│ └── client/ # Web UI
└── scripts/ # Utilities
```
## Code Patterns
### Swift (macOS/iOS)
**Observable Pattern**
```swift
// mac/VibeTunnel/Core/Services/ServerManager.swift
@MainActor
@Observable
class ServerManager {
private(set) var isRunning = false
private(set) var error: Error?
}
```
**Protocol-Oriented Design**
```swift
// mac/VibeTunnel/Core/Protocols/VibeTunnelServer.swift
@MainActor
protocol VibeTunnelServer: AnyObject {
var isRunning: Bool { get }
func start() async throws
func stop() async
}
```
**Error Handling**
```swift
enum ServerError: LocalizedError {
case portInUse(Int)
case binaryNotFound(String)
var errorDescription: String? {
switch self {
case .portInUse(let port):
return "Port \(port) is already in use"
case .binaryNotFound(let path):
return "Server binary not found at \(path)"
}
}
}
```
### TypeScript (Web)
**Service Classes**
```typescript
// web/src/server/services/terminal-manager.ts
export class TerminalManager {
private sessions = new Map<string, Session>();
async createSession(options: SessionOptions): Promise<Session> {
const session = new Session(options);
this.sessions.set(session.id, session);
return session;
}
}
```
**Lit Components**
```typescript
// web/src/client/components/terminal-view.ts
@customElement('terminal-view')
export class TerminalView extends LitElement {
@property({ type: String }) sessionId = '';
@state() private connected = false;
createRenderRoot() {
return this; // No shadow DOM for Tailwind
}
}
```
## Development Workflow
### Hot Reload Setup
**Web Development**
```bash
# Terminal 1: Run dev server
cd web && pnpm dev
# Terminal 2: Enable in Mac app
# Settings → Debug → Use Development Server
```
**Swift Development with Poltergeist**
```bash
# Install Poltergeist if available
poltergeist
# Auto-rebuilds on file changes
# Check menu bar for build status
```
### Testing
**Unit Tests**
```bash
# macOS
cd mac && xcodebuild test
# iOS
cd ios && ./scripts/test-with-coverage.sh
# Web
cd web && pnpm test
```
**E2E Tests**
```bash
cd web && pnpm test:e2e
```
### Debugging
**View Logs**
```bash
./scripts/vtlog.sh -n 100 # Last 100 lines
./scripts/vtlog.sh -e # Errors only
./scripts/vtlog.sh -c Server # Component filter
```
**Debug Server**
```bash
# Run server directly
cd web && pnpm dev:server
# With inspector
node --inspect dist/server/server.js
```
## Common Tasks
### Add New API Endpoint
1. Define in `web/src/server/routes/api.ts`
2. Add types in `web/src/shared/types.ts`
3. Update client in `web/src/client/services/api.ts`
4. Add tests in `web/tests/api.test.ts`
### Add New Menu Item
1. Update `mac/VibeTunnel/Presentation/MenuBarView.swift`
2. Add action in `mac/VibeTunnel/Core/Actions/`
3. Update settings if needed
### Modify Terminal Protocol
1. Update `web/src/server/services/buffer-aggregator.ts`
2. Modify `web/src/client/services/websocket.ts`
3. Test with `web/tests/protocol.test.ts`
## Build System
### macOS Build
```bash
cd mac
./scripts/build.sh # Release build
./scripts/build.sh --configuration Debug
./scripts/build.sh --sign # With signing
```
### Web Build
```bash
cd web
pnpm build # Production build
pnpm build:server # Server only
pnpm build:client # Client only
```
### Release Build
```bash
./scripts/release.sh 1.0.0 # Full release
```
## Code Quality
### Linting
```bash
# Swift
cd mac && ./scripts/lint.sh
# TypeScript
cd web && pnpm lint
cd web && pnpm check:fix
```
### Formatting
```bash
# Swift (SwiftFormat)
swiftformat mac/ ios/
# TypeScript (Prettier)
cd web && pnpm format
```
## Performance
### Profiling
```bash
# Server performance
node --prof dist/server/server.js
node --prof-process isolate-*.log
# Client performance
# Use Chrome DevTools Performance tab
```
### Optimization Tips
- Use binary protocol for terminal data
- Batch WebSocket messages (16ms intervals)
- Lazy load terminal sessions
- Cache static assets with service worker
## Troubleshooting
| Issue | Solution |
|-------|----------|
| Port in use | `lsof -i :4020` then kill process |
| Build fails | Clean: `rm -rf node_modules dist` |
| Tests fail | Check Node/Bun version |
| Hot reload broken | Restart dev server |
## Contributing
1. Fork repository
2. Create feature branch
3. Follow code style
4. Add tests
5. Update documentation
6. Submit PR
## See Also
- [Architecture](../core/architecture.md)
- [API Reference](../core/api-reference.md)
- [Testing Guide](testing.md)
- [Release Process](../reference/release-process.md)

169
docs/guides/quickstart.md Normal file
View file

@ -0,0 +1,169 @@
# Quickstart Guide
## Installation
### Download & Install
1. Download VibeTunnel.dmg from [Releases](https://github.com/steipete/vibetunnel/releases)
2. Open DMG and drag VibeTunnel to Applications
3. Launch VibeTunnel from Applications
4. Grant accessibility permissions when prompted
### First Terminal
```bash
# Open a terminal session in your browser
vt
# Named session
vt --name "Project Build"
# Custom command
vt --command "htop"
```
The browser opens automatically at `http://localhost:4020`
## Essential Commands
| Command | Purpose |
|---------|---------|
| `vt` | Start new terminal session |
| `vt list` | Show active sessions |
| `vt kill <id>` | Terminate session |
| `vt logs` | View server logs |
| `vt --help` | Show all options |
## Configuration
### Settings Location
```
~/Library/Preferences/com.steipete.VibeTunnel.plist
```
### Key Settings
| Setting | Default | Options |
|---------|---------|---------|
| Port | 4020 | Any available port |
| Authentication | None | Password, Token |
| Network | Localhost | LAN, Tailscale |
| Auto-start | Disabled | Enable at login |
### Enable LAN Access
1. Click VibeTunnel menu bar icon
2. Select Preferences
3. Toggle "Allow LAN Connections"
4. Set password for security
## Development Mode
### Using Development Server
```bash
# Enable in VibeTunnel settings
Settings → Debug → Use Development Server
# Or run manually
cd web
pnpm install
pnpm dev
```
Benefits:
- Hot reload for web changes
- No Mac app rebuild needed
- Faster iteration
## Common Workflows
### Monitor AI Agents
```bash
# Start Claude Code in VibeTunnel
vt --name "Claude Code"
claude
# Access from another device
http://your-mac-ip:4020
```
### Remote Development
```bash
# With Tailscale
vt --tailscale
# With ngrok
vt --ngrok
```
### Multiple Sessions
```bash
# Start multiple named sessions
vt --name "Frontend" --command "cd ~/frontend && npm run dev"
vt --name "Backend" --command "cd ~/backend && npm start"
vt --name "Database" --command "docker-compose up"
```
## Keyboard Shortcuts
### Terminal
| Shortcut | Action |
|----------|--------|
| `Cmd+C` | Copy selection |
| `Cmd+V` | Paste |
| `Cmd+K` | Clear terminal |
| `Cmd+T` | New session |
| `Cmd+W` | Close session |
### Web Interface
| Shortcut | Action |
|----------|--------|
| `Ctrl+Shift+C` | Copy |
| `Ctrl+Shift+V` | Paste |
| `Alt+1-9` | Switch tabs |
| `Ctrl+Alt+T` | New terminal |
## Troubleshooting Quick Fixes
### Server Won't Start
```bash
# Check if port is in use
lsof -i :4020
# Kill existing process
killall node
# Restart VibeTunnel
osascript -e 'quit app "VibeTunnel"'
open -a VibeTunnel
```
### Can't Connect
```bash
# Check server status
curl http://localhost:4020/api/health
# View logs
./scripts/vtlog.sh -e
```
### Permission Issues
1. System Preferences → Security & Privacy
2. Privacy → Accessibility
3. Add VibeTunnel.app
4. Restart VibeTunnel
## Next Steps
- [Development Setup](development.md) - Build from source
- [API Reference](../core/api-reference.md) - Integrate with VibeTunnel
- [iOS App Setup](../platform/ios.md) - Mobile access
- [Security Guide](../features/authentication.md) - Secure your sessions
## Quick Tips
1. **Auto-start**: Enable "Launch at Login" in preferences
2. **Custom port**: Set `VT_PORT=8080` environment variable
3. **Debug mode**: Hold Option while clicking menu bar icon
4. **Force quit session**: `vt kill --force <id>`
5. **Export recordings**: Sessions saved in `~/.vibetunnel/recordings/`

387
docs/guides/testing.md Normal file
View file

@ -0,0 +1,387 @@
# Testing Guide
## Quick Commands
```bash
# Run all tests
./scripts/test-all.sh
# Platform-specific
cd mac && xcodebuild test
cd ios && ./scripts/test-with-coverage.sh
cd web && pnpm test
# With coverage
cd web && pnpm test:coverage
```
## Test Structure
```
tests/
├── unit/ # Unit tests
├── integration/ # Integration tests
├── e2e/ # End-to-end tests
└── fixtures/ # Test data
```
## Unit Testing
### Swift (XCTest)
```swift
// mac/VibeTunnelTests/ServerManagerTests.swift
import XCTest
@testable import VibeTunnel
class ServerManagerTests: XCTestCase {
func testServerStart() async throws {
let manager = ServerManager()
try await manager.start()
XCTAssertTrue(manager.isRunning)
XCTAssertEqual(manager.port, "4020")
}
func testPortValidation() {
XCTAssertThrowsError(try validatePort("abc"))
XCTAssertNoThrow(try validatePort("8080"))
}
}
```
### TypeScript (Vitest)
```typescript
// web/tests/session-manager.test.ts
import { describe, it, expect, beforeEach } from 'vitest';
import { SessionManager } from '../src/server/services/session-manager';
describe('SessionManager', () => {
let manager: SessionManager;
beforeEach(() => {
manager = new SessionManager();
});
it('creates session', async () => {
const session = await manager.create({
shell: '/bin/bash',
cols: 80,
rows: 24
});
expect(session.id).toBeDefined();
expect(session.status).toBe('running');
});
});
```
## Integration Testing
### API Testing
```typescript
// web/tests/integration/api.test.ts
import request from 'supertest';
import { app } from '../../src/server/app';
describe('API Integration', () => {
it('creates session via API', async () => {
const response = await request(app)
.post('/api/sessions')
.send({ shell: '/bin/bash' })
.expect(201);
expect(response.body).toHaveProperty('id');
expect(response.body.status).toBe('running');
});
});
```
### WebSocket Testing
```typescript
// web/tests/integration/websocket.test.ts
import { WebSocket } from 'ws';
describe('WebSocket Integration', () => {
it('connects to session', async () => {
const ws = new WebSocket('ws://localhost:4020/api/sessions/test/ws');
await new Promise((resolve) => {
ws.on('open', resolve);
});
ws.send(JSON.stringify({ type: 'input', data: 'echo test\n' }));
const message = await new Promise((resolve) => {
ws.on('message', resolve);
});
expect(message.toString()).toContain('test');
});
});
```
## E2E Testing
### Playwright Setup
```typescript
// web/playwright.config.ts
import { defineConfig } from '@playwright/test';
export default defineConfig({
testDir: './tests/e2e',
use: {
baseURL: 'http://localhost:4020',
trace: 'on-first-retry',
},
webServer: {
command: 'pnpm dev',
port: 4020,
reuseExistingServer: !process.env.CI,
},
});
```
### E2E Tests
```typescript
// web/tests/e2e/terminal.test.ts
import { test, expect } from '@playwright/test';
test('complete terminal workflow', async ({ page }) => {
// Navigate to app
await page.goto('/');
// Create new terminal
await page.click('button:has-text("New Terminal")');
// Wait for terminal to load
const terminal = page.locator('.terminal');
await expect(terminal).toBeVisible();
// Type command
await page.keyboard.type('echo "Hello, VibeTunnel"');
await page.keyboard.press('Enter');
// Verify output
await expect(terminal).toContainText('Hello, VibeTunnel');
// Close session
await page.click('button[aria-label="Close terminal"]');
await expect(terminal).not.toBeVisible();
});
```
## Performance Testing
### Load Testing
```javascript
// tests/performance/load.js
import { check } from 'k6';
import ws from 'k6/ws';
export default function() {
const url = 'ws://localhost:4020/api/sessions/test/ws';
ws.connect(url, {}, function(socket) {
socket.on('open', () => {
socket.send(JSON.stringify({ type: 'input', data: 'ls\n' }));
});
socket.on('message', (data) => {
check(data, {
'received response': (d) => d.length > 0,
});
});
});
}
export const options = {
vus: 100, // 100 virtual users
duration: '30s', // 30 second test
};
```
### Benchmark Suite
```typescript
// tests/performance/benchmark.ts
import { bench, describe } from 'vitest';
describe('Buffer encoding performance', () => {
bench('encode 1KB', () => {
encodeBuffer('x'.repeat(1024));
});
bench('encode 10KB', () => {
encodeBuffer('x'.repeat(10240));
});
});
```
## Test Coverage
### Coverage Requirements
| Component | Target | Current |
|-----------|--------|---------|
| Server | 80% | 85% |
| Client | 70% | 72% |
| Mac App | 60% | 65% |
| iOS App | 75% | 78% |
### Generate Reports
```bash
# Web coverage
cd web && pnpm test:coverage
# iOS coverage
cd ios && ./scripts/test-with-coverage.sh
# View HTML report
open coverage/index.html
```
## Testing External Devices
### iPad/iPhone Testing
```bash
# 1. Start dev server on all interfaces
cd web && pnpm dev --host 0.0.0.0
# 2. Get Mac IP
ifconfig | grep inet
# 3. Access from device
# http://192.168.1.100:4021
```
### Cross-Browser Testing
```typescript
// playwright.config.ts
projects: [
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
{ name: 'firefox', use: { ...devices['Desktop Firefox'] } },
{ name: 'webkit', use: { ...devices['Desktop Safari'] } },
{ name: 'Mobile Safari', use: { ...devices['iPhone 13'] } },
]
```
## Mocking & Fixtures
### Mock PTY
```typescript
// tests/mocks/pty.ts
export class MockPTY {
write(data: string) {
this.emit('data', `mock: ${data}`);
}
resize(cols: number, rows: number) {
this.cols = cols;
this.rows = rows;
}
}
```
### Test Fixtures
```typescript
// tests/fixtures/sessions.ts
export const mockSession = {
id: 'test-session-123',
name: 'Test Session',
status: 'running',
created: new Date(),
pid: 12345,
};
```
## CI/CD Testing
### GitHub Actions
```yaml
# .github/workflows/test.yml
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: macos-14
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
- name: Install dependencies
run: |
cd web && pnpm install
- name: Run tests
run: ./scripts/test-all.sh
- name: Upload coverage
uses: codecov/codecov-action@v3
```
## Debugging Tests
### Debug Swift Tests
```bash
# Run with verbose output
xcodebuild test -verbose
# Debug specific test
xcodebuild test -only-testing:VibeTunnelTests/ServerManagerTests/testServerStart
```
### Debug TypeScript Tests
```bash
# Run with inspector
node --inspect-brk ./node_modules/.bin/vitest
# Run single test file
pnpm test session-manager.test.ts
# Watch mode
pnpm test --watch
```
## Best Practices
1. **Test naming**: Use descriptive names like `shouldCreateSessionWithCustomShell`
2. **Isolation**: Each test should be independent
3. **Cleanup**: Always cleanup resources (sessions, files, connections)
4. **Assertions**: Test both success and error cases
5. **Speed**: Keep unit tests under 100ms each
6. **Flakiness**: Retry flaky tests, investigate root cause
## Common Issues
| Issue | Solution |
|-------|----------|
| Tests timeout | Increase timeout, check async |
| Port conflicts | Use random ports in tests |
| Flaky WebSocket | Add connection retry logic |
| Coverage gaps | Add tests for error paths |
## See Also
- [Development Guide](development.md)
- [CI/CD Setup](../reference/release-process.md#cicd-pipeline)
- [Troubleshooting](../reference/troubleshooting.md)

261
docs/platform/macos.md Normal file
View file

@ -0,0 +1,261 @@
# macOS Development
## Project Setup
### Requirements
- macOS 14.0+
- Xcode 16.0+
- Swift 6.0
### Build & Run
```bash
cd mac
# Debug build
xcodebuild -project VibeTunnel.xcodeproj -scheme VibeTunnel
# Release build
./scripts/build.sh
# With code signing
./scripts/build.sh --sign
# Run directly
open build/Release/VibeTunnel.app
```
## Architecture
### Core Components
| Component | Location | Purpose |
|-----------|----------|---------|
| ServerManager | `Core/Services/ServerManager.swift` | Server lifecycle |
| SessionMonitor | `Core/Services/SessionMonitor.swift` | Track sessions |
| TTYForwardManager | `Core/Services/TTYForwardManager.swift` | CLI integration |
| MenuBarViewModel | `Presentation/ViewModels/MenuBarViewModel.swift` | UI state |
### Key Patterns
**Observable State**
```swift
@MainActor
@Observable
class ServerManager {
private(set) var isRunning = false
private(set) var sessions: [Session] = []
}
```
**Protocol-Based Services**
```swift
@MainActor
protocol VibeTunnelServer: AnyObject {
var isRunning: Bool { get }
func start() async throws
func stop() async
}
```
**SwiftUI Menu Bar**
```swift
struct MenuBarView: View {
@StateObject private var viewModel = MenuBarViewModel()
var body: some View {
Menu("VT", systemImage: "terminal") {
ForEach(viewModel.sessions) { session in
SessionRow(session: session)
}
}
}
}
```
## Server Integration
### Embedded Server
```
VibeTunnel.app/
└── Contents/
├── MacOS/
│ └── VibeTunnel # Main executable
└── Resources/
└── server/
└── bun-server # Embedded Bun binary
```
### Server Launch
```swift
// ServerManager.swift
func start() async throws {
let serverPath = Bundle.main.resourcePath! + "/server/bun-server"
process = Process()
process.executableURL = URL(fileURLWithPath: serverPath)
process.arguments = ["--port", port]
try process.run()
}
```
## Settings Management
### UserDefaults Keys
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| serverPort | String | "4020" | Server port |
| autostart | Bool | false | Launch at login |
| allowLAN | Bool | false | LAN connections |
| useDevServer | Bool | false | Development mode |
### Settings Window
```swift
struct SettingsView: View {
@AppStorage("serverPort") private var port = "4020"
var body: some View {
Form {
TextField("Port:", text: $port)
}
}
}
```
## Menu Bar App
### App Lifecycle
```swift
@main
struct VibeTunnelApp: App {
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
MenuBarExtra("VibeTunnel", systemImage: "terminal") {
MenuBarView()
}
.menuBarExtraStyle(.menu)
}
}
```
### Status Updates
```swift
// Update menu bar icon based on state
func updateStatusItem() {
if serverManager.isRunning {
statusItem.button?.image = NSImage(systemSymbolName: "terminal.fill")
} else {
statusItem.button?.image = NSImage(systemSymbolName: "terminal")
}
}
```
## Code Signing
### Entitlements
```xml
<!-- VibeTunnel.entitlements -->
<dict>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
</dict>
```
### Build Settings
```
# version.xcconfig
MARKETING_VERSION = 1.0.0
CURRENT_PROJECT_VERSION = 100
# Shared.xcconfig
CODE_SIGN_IDENTITY = Developer ID Application
DEVELOPMENT_TEAM = TEAMID
```
## Sparkle Updates
### Integration
```swift
import Sparkle
class UpdateManager {
let updater = SPUStandardUpdaterController(
startingUpdater: true,
updaterDelegate: nil,
userDriverDelegate: nil
)
func checkForUpdates() {
updater.checkForUpdates()
}
}
```
### Configuration
```xml
<!-- Info.plist -->
<key>SUFeedURL</key>
<string>https://vibetunnel.com/appcast.xml</string>
<key>SUEnableAutomaticChecks</key>
<true/>
```
## Debugging
### Console Logs
```swift
os_log(.debug, log: .server, "Starting server on port %{public}@", port)
```
### View Logs
```bash
# In Console.app
# Filter: subsystem:com.steipete.VibeTunnel
# Or via script
./scripts/vtlog.sh -c ServerManager
```
## Testing
### Unit Tests
```bash
xcodebuild test \
-project VibeTunnel.xcodeproj \
-scheme VibeTunnel \
-destination 'platform=macOS'
```
### UI Tests
```swift
class VibeTunnelUITests: XCTestCase {
func testServerStart() throws {
let app = XCUIApplication()
app.launch()
app.menuBarItems["VibeTunnel"].click()
app.menuItems["Start Server"].click()
XCTAssertTrue(app.menuItems["Stop Server"].exists)
}
}
```
## Common Issues
| Issue | Solution |
|-------|----------|
| Server won't start | Check port availability |
| Menu bar not showing | Check LSUIElement in Info.plist |
| Updates not working | Verify Sparkle feed URL |
| Permissions denied | Add entitlements |
## See Also
- [Architecture](../core/architecture.md)
- [Development Guide](../guides/development.md)
- [iOS Companion](ios.md)

313
docs/platform/web.md Normal file
View file

@ -0,0 +1,313 @@
# Web Development
## Setup
### Prerequisites
- Node.js 18+
- Bun 1.0+
- pnpm 8+
### Install & Run
```bash
cd web
pnpm install
pnpm dev # Development server
pnpm build # Production build
pnpm test # Run tests
```
## Project Structure
```
web/
├── src/
│ ├── server/ # Node.js backend
│ │ ├── server.ts # HTTP/WebSocket server
│ │ ├── pty/ # Terminal management
│ │ ├── services/ # Business logic
│ │ └── routes/ # API endpoints
│ ├── client/ # Web frontend
│ │ ├── app.ts # Main application
│ │ ├── components/ # Lit components
│ │ └── services/ # Client services
│ └── shared/ # Shared types
├── dist/ # Build output
└── tests/ # Test files
```
## Server Development
### Core Services
| Service | File | Purpose |
|---------|------|---------|
| TerminalManager | `services/terminal-manager.ts` | PTY lifecycle |
| SessionManager | `services/session-manager.ts` | Session state |
| BufferAggregator | `services/buffer-aggregator.ts` | Output batching |
| AuthService | `services/auth.ts` | Authentication |
### API Routes
```typescript
// routes/api.ts
router.post('/api/sessions', createSession);
router.get('/api/sessions', listSessions);
router.get('/api/sessions/:id', getSession);
router.delete('/api/sessions/:id', deleteSession);
router.ws('/api/sessions/:id/ws', handleWebSocket);
```
### WebSocket Handler
```typescript
// services/websocket-handler.ts
export async function handleWebSocket(ws: WebSocket, sessionId: string) {
const session = await sessionManager.get(sessionId);
// Binary protocol for terminal data
session.onData((data: Buffer) => {
ws.send(encodeBuffer(data));
});
// Handle client messages
ws.on('message', (msg: Buffer) => {
const data = JSON.parse(msg.toString());
if (data.type === 'input') {
session.write(data.data);
}
});
}
```
### PTY Management
```typescript
// pty/pty-manager.ts
import * as pty from 'node-pty';
export class PTYManager {
create(options: PTYOptions): IPty {
return pty.spawn(options.shell || '/bin/zsh', options.args, {
cols: options.cols || 80,
rows: options.rows || 24,
cwd: options.cwd || process.env.HOME,
env: { ...process.env, ...options.env }
});
}
}
```
## Client Development
### Lit Components
```typescript
// components/terminal-view.ts
@customElement('terminal-view')
export class TerminalView extends LitElement {
@property({ type: String }) sessionId = '';
private terminal?: Terminal;
private ws?: WebSocket;
createRenderRoot() {
return this; // No shadow DOM for Tailwind
}
firstUpdated() {
this.initTerminal();
this.connectWebSocket();
}
render() {
return html`
<div id="terminal" class="h-full w-full"></div>
`;
}
}
```
### WebSocket Client
```typescript
// services/websocket-client.ts
export class WebSocketClient {
private ws?: WebSocket;
connect(sessionId: string): void {
this.ws = new WebSocket(`ws://localhost:4020/api/sessions/${sessionId}/ws`);
this.ws.binaryType = 'arraybuffer';
this.ws.onmessage = (event) => {
if (event.data instanceof ArrayBuffer) {
const text = this.decodeBuffer(event.data);
this.onData?.(text);
}
};
}
send(data: string): void {
this.ws?.send(JSON.stringify({ type: 'input', data }));
}
}
```
### Terminal Integration
```typescript
// services/terminal-service.ts
import { Terminal } from '@xterm/xterm';
import { FitAddon } from '@xterm/addon-fit';
export class TerminalService {
private terminal: Terminal;
private fitAddon: FitAddon;
initialize(container: HTMLElement): void {
this.terminal = new Terminal({
theme: {
background: '#1e1e1e',
foreground: '#ffffff'
}
});
this.fitAddon = new FitAddon();
this.terminal.loadAddon(this.fitAddon);
this.terminal.open(container);
this.fitAddon.fit();
}
}
```
## Build System
### Development Build
```json
// package.json scripts
{
"dev": "concurrently \"npm:dev:*\"",
"dev:server": "tsx watch src/server/server.ts",
"dev:client": "vite",
"dev:tailwind": "tailwindcss -w"
}
```
### Production Build
```bash
# Build everything
pnpm build
# Outputs:
# dist/server/ - Compiled server
# dist/client/ - Static web assets
# dist/bun - Standalone executable
```
### Bun Compilation
```typescript
// scripts/build-bun.ts
await Bun.build({
entrypoints: ['src/server/server.ts'],
outdir: 'dist',
target: 'bun',
minify: true,
sourcemap: 'external'
});
```
## Testing
### Unit Tests
```typescript
// tests/terminal-manager.test.ts
describe('TerminalManager', () => {
it('creates session', async () => {
const manager = new TerminalManager();
const session = await manager.create({ shell: '/bin/bash' });
expect(session.id).toBeDefined();
});
});
```
### E2E Tests
```typescript
// tests/e2e/session.test.ts
test('create and connect to session', async ({ page }) => {
await page.goto('http://localhost:4020');
await page.click('button:text("New Terminal")');
await expect(page.locator('.terminal')).toBeVisible();
});
```
## Performance
### Optimization Techniques
| Technique | Implementation | Impact |
|-----------|---------------|--------|
| Buffer aggregation | Batch every 16ms | 90% fewer messages |
| Binary protocol | Magic byte encoding | 50% smaller payload |
| Virtual scrolling | xterm.js built-in | Handles 100K+ lines |
| Service worker | Cache static assets | Instant load |
### Benchmarks
```typescript
// Measure WebSocket throughput
const start = performance.now();
let bytes = 0;
ws.onmessage = (event) => {
bytes += event.data.byteLength;
if (performance.now() - start > 1000) {
console.log(`Throughput: ${bytes / 1024}KB/s`);
}
};
```
## Debugging
### Server Debugging
```bash
# Run with inspector
node --inspect dist/server/server.js
# With source maps
NODE_OPTIONS='--enable-source-maps' node dist/server/server.js
# Verbose logging
DEBUG=vt:* pnpm dev:server
```
### Client Debugging
```javascript
// Enable xterm.js debug mode
terminal.options.logLevel = 'debug';
// WebSocket debugging
ws.addEventListener('message', (e) => {
console.log('WS received:', e.data);
});
```
## Common Issues
| Issue | Solution |
|-------|----------|
| CORS errors | Check server CORS config |
| WebSocket fails | Verify port/firewall |
| Terminal garbled | Check encoding (UTF-8) |
| Build fails | Clear node_modules |
## See Also
- [API Reference](../core/api-reference.md)
- [Protocol Specs](../core/protocols.md)
- [Development Guide](../guides/development.md)

View file

@ -0,0 +1,220 @@
# Release Process
## Quick Checklist
```bash
# 1. Update version
./scripts/update-version.sh 1.0.0
# 2. Run tests
./scripts/test-all.sh
# 3. Build release
./scripts/release.sh 1.0.0
# 4. Create GitHub release
gh release create v1.0.0 dist/VibeTunnel-1.0.0.dmg
# 5. Update Sparkle feed
./scripts/update-sparkle.sh
```
## Detailed Steps
### 1. Pre-Release
**Version Update**
```bash
# Updates all version files
./scripts/update-version.sh NEW_VERSION
# Files modified:
# - mac/VibeTunnel/version.xcconfig
# - web/package.json
# - ios/VibeTunnel/Info.plist
```
**Changelog**
```markdown
## [1.0.0] - 2024-01-01
### Added
- New feature X
- Support for Y
### Fixed
- Bug Z
### Changed
- Improved performance
```
### 2. Testing
**Run Test Suite**
```bash
# All platforms
./scripts/test-all.sh
# Individual
cd mac && xcodebuild test
cd ios && ./scripts/test-with-coverage.sh
cd web && pnpm test
```
**Manual Testing**
- [ ] Fresh install on clean macOS
- [ ] Upgrade from previous version
- [ ] Test on minimum macOS version
- [ ] iOS app connectivity
- [ ] Web UI on Safari/Chrome/Firefox
### 3. Build
**Release Build**
```bash
# Complete release
./scripts/release.sh VERSION
# Steps performed:
# 1. Clean build directories
# 2. Build web assets
# 3. Build Mac app (signed)
# 4. Create DMG
# 5. Notarize with Apple
# 6. Generate Sparkle appcast
```
**Verification**
```bash
# Check signature
codesign -dv --verbose=4 dist/VibeTunnel.app
# Verify notarization
spctl -a -v dist/VibeTunnel.app
```
### 4. Distribution
**GitHub Release**
```bash
# Create release
gh release create v$VERSION \
--title "VibeTunnel $VERSION" \
--notes-file RELEASE_NOTES.md \
dist/VibeTunnel-$VERSION.dmg
# Upload additional assets
gh release upload v$VERSION dist/checksums.txt
```
**Sparkle Update**
```xml
<!-- appcast.xml -->
<item>
<title>Version 1.0.0</title>
<pubDate>Mon, 01 Jan 2024 00:00:00 +0000</pubDate>
<sparkle:version>1.0.0</sparkle:version>
<sparkle:shortVersionString>1.0.0</sparkle:shortVersionString>
<sparkle:minimumSystemVersion>14.0</sparkle:minimumSystemVersion>
<enclosure
url="https://github.com/steipete/vibetunnel/releases/download/v1.0.0/VibeTunnel-1.0.0.dmg"
sparkle:edSignature="..."
length="12345678"
type="application/octet-stream"/>
</item>
```
### 5. Post-Release
**Documentation**
- [ ] Update README with new version
- [ ] Update docs with new features
- [ ] Post release notes
**Monitoring**
- [ ] Check Sparkle update stats
- [ ] Monitor crash reports
- [ ] Review user feedback
## Version Scheme
```
MAJOR.MINOR.PATCH[-PRERELEASE]
1.0.0 - Stable release
1.0.0-beta.1 - Beta release
1.0.0-rc.1 - Release candidate
```
## Build Configurations
| Config | Use Case | Signing |
|--------|----------|---------|
| Debug | Development | No |
| Release | Distribution | Yes |
| AppStore | Mac App Store | Yes |
## Code Signing
**Requirements**
- Apple Developer account
- Developer ID certificate
- Notarization credentials
**Setup**
```bash
# Store credentials
xcrun notarytool store-credentials "VT_NOTARY" \
--apple-id "your@email.com" \
--team-id "TEAMID" \
--password "app-specific-password"
```
## Troubleshooting
| Issue | Solution |
|-------|----------|
| Notarization fails | Check entitlements, wait 5 min |
| Sparkle not updating | Verify appcast URL, signature |
| DMG corrupted | Re-run with clean build |
| Version mismatch | Run update-version.sh |
## Rollback
```bash
# Revert release
gh release delete v$VERSION
git revert <commit>
git tag -d v$VERSION
git push origin :refs/tags/v$VERSION
# Update Sparkle feed to previous version
./scripts/rollback-sparkle.sh $PREVIOUS_VERSION
```
## CI/CD Pipeline
```yaml
# .github/workflows/release.yml
on:
push:
tags:
- 'v*'
jobs:
release:
runs-on: macos-14
steps:
- uses: actions/checkout@v4
- run: ./scripts/test-all.sh
- run: ./scripts/release.sh ${{ github.ref_name }}
- uses: softprops/action-gh-release@v1
with:
files: dist/*.dmg
```
## See Also
- [Build System](../guides/development.md#build-system)
- [Testing Guide](../guides/testing.md)
- [Changelog](../../CHANGELOG.md)