Documentation Index
Fetch the complete documentation index at: https://docs.vibetunnel.sh/llms.txt
Use this file to discover all available pages before exploring further.
Push Notification Implementation Plan
This document outlines the comprehensive plan for improving VibeTunnel’s notification system through two major initiatives:
- Creating a dedicated Notifications tab in macOS settings
- Migrating SessionMonitor from the Mac app to the server for unified notifications
Overview
Currently, VibeTunnel has inconsistent notification implementations between the Mac and web clients. The Mac app has its own SessionMonitor while the web relies on server events. This leads to:
- Different notification behaviors between platforms
- Missing features (e.g., notification settings parity between platforms)
- Duplicate code and maintenance burden
- Inconsistent descriptions and thresholds
Part 1: macOS Settings Redesign
Current State
- Notification settings are cramped in the General tab
- No room for descriptive text explaining each notification type
- Settings are already at 710px height (quite tall)
- Missing helpful context that exists in the web UI
Proposed Solution: Dedicated Notifications Tab
1. Add Notifications Tab to SettingsTab enum
// SettingsTab.swift
enum SettingsTab: String, CaseIterable {
case general
case notifications // NEW
case quickStart
case dashboard
// ... rest of tabs
}
// Add display name and icon
var displayName: String {
switch self {
case .notifications: "Notifications"
// ... rest
}
}
var icon: String {
switch self {
case .notifications: "bell.badge"
// ... rest
}
}
2. Create NotificationSettingsView.swift
struct NotificationSettingsView: View {
@ObservedObject private var configManager = ConfigManager.shared
@ObservedObject private var notificationService = NotificationService.shared
var body: some View {
Form {
// Master toggle section
Section {
VStack(alignment: .leading, spacing: 8) {
Toggle("Show Session Notifications", isOn: $showNotifications)
Text("Display native macOS notifications for session and command events")
.font(.caption)
.foregroundStyle(.secondary)
}
}
// Notification types section
Section {
NotificationToggleRow(
title: "Session starts",
description: "When a new session starts (useful for shared terminals)",
isOn: $configManager.notificationSessionStart,
helpText: NotificationHelp.sessionStart
)
NotificationToggleRow(
title: "Session ends",
description: "When a session terminates or crashes (shows exit code)",
isOn: $configManager.notificationSessionExit,
helpText: NotificationHelp.sessionExit
)
// ... other notification types
} header: {
Text("Notification Types")
}
// Behavior section
Section {
Toggle("Play sound", isOn: $configManager.notificationSoundEnabled)
Toggle("Show in Notification Center", isOn: $configManager.showInNotificationCenter)
} header: {
Text("Notification Behavior")
}
// Test section
Section {
Button("Test Notification") {
notificationService.sendTestNotification()
}
}
}
}
}
3. Create Reusable NotificationToggleRow Component
struct NotificationToggleRow: View {
let title: String
let description: String
@Binding var isOn: Bool
let helpText: String
var body: some View {
HStack(alignment: .top, spacing: 12) {
VStack(alignment: .leading, spacing: 4) {
HStack {
Toggle(title, isOn: $isOn)
.toggleStyle(.checkbox)
HelpTooltip(text: helpText)
}
Text(description)
.font(.caption)
.foregroundStyle(.secondary)
}
}
.padding(.vertical, 4)
}
}
4. Update SettingsView.swift
// Add the new tab
NotificationSettingsView()
.tabItem {
Label(SettingsTab.notifications.displayName,
systemImage: SettingsTab.notifications.icon)
}
.tag(SettingsTab.notifications)
5. Update GeneralSettingsView.swift
Remove all notification-related settings to free up space.
Standardized Notification Descriptions
Use these descriptions consistently across Mac and web:
| Type | Title | Description |
|---|
| Session Start | Session starts | When a new session starts (useful for shared terminals) |
| Session Exit | Session ends | When a session terminates or crashes (shows exit code) |
| Command Error | Commands fail | When commands fail with non-zero exit codes |
| Command Completion | Commands complete (> 3 seconds) | When commands taking >3 seconds finish (builds, tests, etc.) |
| Terminal Bell | Terminal bell (🔔) | Terminal bell (^G) from vim, IRC mentions, completion sounds |
Part 2: Server-Side SessionMonitor Migration
Current Architecture
Mac App:
SessionMonitor (Swift) → NotificationService → macOS notifications
Server:
PtyManager → Basic events → WS v3 → Web notifications
Proposed Architecture
Server:
PtyManager → SessionMonitor (TypeScript) → Enhanced events → WS v3
↓
Mac & Web clients
Implementation Steps
1. Create Server-Side SessionMonitor
// web/src/server/services/session-monitor.ts
export interface SessionState {
id: string;
name: string;
command: string[];
isRunning: boolean;
commandStartTime?: Date;
lastCommand?: string;
}
export class SessionMonitor {
private sessions = new Map<string, SessionState>();
private commandThresholdMs = 3000; // 3 seconds
constructor(
private ptyManager: PtyManager,
private eventBus: EventEmitter
) {
this.setupEventListeners();
}
// ... other monitoring methods
}
2. Enhance Event Types
// web/src/shared/types.ts
export enum ServerEventType {
SessionStart = 'session-start',
SessionExit = 'session-exit',
CommandFinished = 'command-finished',
CommandError = 'command-error', // NEW - separate from finished
Bell = 'bell', // NEW
Connected = 'connected'
}
export interface ServerEvent {
type: ServerEventType;
timestamp: string;
sessionId: string;
sessionName?: string;
// Event-specific data
exitCode?: number;
command?: string;
duration?: number;
message?: string;
}
3. Integrate with PtyManager
// web/src/server/pty/pty-manager.ts
class PtyManager {
private sessionMonitor: SessionMonitor;
constructor() {
this.sessionMonitor = new SessionMonitor(this, serverEventBus);
}
// Feed data to SessionMonitor
private handlePtyData(sessionId: string, data: string) {
// Existing data handling...
// Detect bell character
if (data.includes('\x07')) {
serverEventBus.emit('notification', {
type: ServerEventType.Bell,
sessionId,
sessionName: this.sessions.get(sessionId)?.name
});
}
}
}
4. Update Server WS v3 Hub
// web/src/server/services/ws-v3-hub.ts
// SessionMonitor emits ServerEvent objects.
// WsV3Hub broadcasts EVENT frames to clients that SUBSCRIBE with:
// sessionId == "" and flags include WsV3SubscribeFlags.Events
5. Update Mac NotificationService
// NotificationService.swift
class NotificationService {
// Remove local SessionMonitor dependency
// Subscribe to server WS v3 events instead
private func connectToServerEvents() {
// WS v3: connect `/ws`, send SUBSCRIBE(sessionId:"", flags: Events)
}
private func handleServerEvent(_ event: ServerEvent) {
// Map server events to notifications
switch event.type {
case .sessionStart:
if preferences.sessionStart {
sendNotification(for: event)
}
// ... handle other event types
}
}
}
6. Update Web Notification Service
// web/src/client/services/push-notification-service.ts
private handleServerEvent(event: ServerEvent) {
if (!this.preferences[this.mapEventTypeToPreference(event.type)]) {
return;
}
// Send browser notification
this.showNotification(event);
}
private mapEventTypeToPreference(type: ServerEventType): keyof NotificationPreferences {
const mapping = {
[ServerEventType.SessionStart]: 'sessionStart',
[ServerEventType.SessionExit]: 'sessionExit',
[ServerEventType.CommandFinished]: 'commandCompletion',
[ServerEventType.CommandError]: 'commandError',
[ServerEventType.Bell]: 'bell'
};
return mapping[type];
}
Migration Strategy
Phase 1: Preparation (Non-breaking)
- Implement server-side SessionMonitor alongside existing system
- Add new event types to shared types
Phase 2: Server Enhancement (Non-breaking)
- Deploy enhanced server with SessionMonitor
- Server emits both old and new event formats
- Test with web client to ensure compatibility
Phase 3: Mac App Migration
- Update Mac app to consume server events
- Keep fallback to local monitoring if server unavailable
- Remove local SessionMonitor once stable
Phase 4: Cleanup
- Remove old event formats from server
- Remove local SessionMonitor code from Mac
- Document new architecture
Testing Plan
Unit Tests
- Event threshold calculations
- Activity state transitions
Integration Tests
- Server events reach both Mac and web clients
- Notification preferences are respected
- Bell character detection
Manual Testing
- Test each notification type on both platforms
- Verify descriptions match
- Test with multiple clients connected
- Test offline Mac app behavior
Success Metrics
- Consistency: Same notifications appear on Mac and web for same events
- Performance: No noticeable lag in notifications
- Reliability: No missed notifications
- Maintainability: Single codebase for monitoring logic
Timeline Estimate
- Week 1: Implement macOS Notifications tab
- Week 2: Create server-side SessionMonitor
- Week 3: Integrate and test with web client
- Week 4: Migrate Mac app and testing
- Week 5: Polish, documentation, and deployment
Risks and Mitigations
| Risk | Impact | Mitigation |
|---|
| Breaking existing notifications | High | Phased rollout, maintain backwards compatibility |
| Performance impact on server | Medium | Efficient event handling, consider debouncing |
| Mac app offline mode | Medium | Keep local fallback for critical notifications |
| Complex migration | Medium | Detailed testing plan, feature flags |
Conclusion
This two-part implementation will:
- Provide a better UI for notification settings on macOS
- Create a unified notification system across all platforms
- Reduce code duplication and maintenance burden
- Ensure consistent behavior for all users
The migration is designed to be non-breaking with careful phases to minimize risk.