Development Guide

Setup

Prerequisites

  • macOS 14.0+
  • Xcode 16.0+
  • Node.js 18+
  • Bun 1.0+

Clone & Build

# 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
// mac/VibeTunnel/Core/Services/ServerManager.swift
@MainActor
@Observable
class ServerManager {
    private(set) var isRunning = false
    private(set) var error: Error?
}
Protocol-Oriented Design
// mac/VibeTunnel/Core/Protocols/VibeTunnelServer.swift
@MainActor
protocol VibeTunnelServer: AnyObject {
    var isRunning: Bool { get }
    func start() async throws
    func stop() async
}
Error Handling
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
// 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
// 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
# Terminal 1: Run dev server
cd web && pnpm dev

# Terminal 2: Enable in Mac app
# Settings → Debug → Use Development Server
Swift Development with Poltergeist
# Install Poltergeist if available
poltergeist

# Auto-rebuilds on file changes
# Check menu bar for build status

Testing

Unit Tests
# macOS
cd mac && xcodebuild test

# iOS  
cd ios && ./scripts/test-with-coverage.sh

# Web
cd web && pnpm test
E2E Tests
cd web && pnpm test:e2e

Debugging

View Logs
./scripts/vtlog.sh -n 100    # Last 100 lines
./scripts/vtlog.sh -e         # Errors only
./scripts/vtlog.sh -c Server # Component filter
Debug Server
# 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

cd mac
./scripts/build.sh                    # Release build
./scripts/build.sh --configuration Debug
./scripts/build.sh --sign             # With signing

Web Build

cd web
pnpm build                            # Production build
pnpm build:server                     # Server only
pnpm build:client                     # Client only

Release Build

./scripts/release.sh 1.0.0           # Full release

Code Quality

Linting

# Swift
cd mac && ./scripts/lint.sh

# TypeScript
cd web && pnpm lint
cd web && pnpm check:fix

Formatting

# Swift (SwiftFormat)
swiftformat mac/ ios/

# TypeScript (Prettier)
cd web && pnpm format

Performance

Profiling

# 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

IssueSolution
Port in uselsof -i :4020 then kill process
Build failsClean: rm -rf node_modules dist
Tests failCheck Node/Bun version
Hot reload brokenRestart 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