@willjackson/claude-code-bridge 0.2.4 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -146
- package/dist/{chunk-5HWFDZKH.js → chunk-LUL3SX2F.js} +1 -355
- package/dist/chunk-LUL3SX2F.js.map +1 -0
- package/dist/cli.d.ts +1 -2
- package/dist/cli.js +38 -154
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +35 -290
- package/dist/index.js +1 -81
- package/dist/index.js.map +1 -1
- package/package.json +4 -6
- package/dist/chunk-5HWFDZKH.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/logger.ts","../src/bridge/protocol.ts","../src/transport/interface.ts","../src/transport/websocket.ts","../src/bridge/messages.ts","../src/bridge/core.ts","../src/utils/config.ts"],"sourcesContent":["import pino from 'pino';\n\n/**\n * Log levels supported by the logger\n */\nexport type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal';\n\n/**\n * Logger interface (subset of pino.Logger for public API)\n */\nexport type Logger = pino.Logger;\n\n/**\n * Determines if we're in a development environment\n */\nfunction isDevelopment(): boolean {\n return process.env.NODE_ENV !== 'production';\n}\n\n/**\n * Gets the default log level from environment or falls back to 'info'\n */\nfunction getDefaultLevel(): LogLevel {\n const envLevel = process.env.LOG_LEVEL?.toLowerCase() as LogLevel | undefined;\n const validLevels: LogLevel[] = ['trace', 'debug', 'info', 'warn', 'error', 'fatal'];\n if (envLevel && validLevels.includes(envLevel)) {\n return envLevel;\n }\n return 'info';\n}\n\n/**\n * Creates a logger instance with the given component name\n *\n * @param name - Component name to include in log output\n * @param level - Optional log level override (defaults to LOG_LEVEL env var or 'info')\n * @returns A pino logger instance configured for the component\n *\n * @example\n * ```typescript\n * const logger = createLogger('bridge');\n * logger.info('Bridge started');\n * logger.error({ err }, 'Connection failed');\n * ```\n */\nexport function createLogger(name: string, level?: LogLevel): Logger {\n const logLevel = level ?? getDefaultLevel();\n\n const options: pino.LoggerOptions = {\n name,\n level: logLevel,\n };\n\n // Use pretty printing in development for better readability\n if (isDevelopment()) {\n options.transport = {\n target: 'pino-pretty',\n options: {\n colorize: true,\n translateTime: 'SYS:standard',\n ignore: 'pid,hostname',\n },\n };\n }\n\n return pino(options);\n}\n\n/**\n * Creates a child logger from an existing logger with additional context\n *\n * @param parent - Parent logger instance\n * @param bindings - Additional context to include in all log messages\n * @returns A child logger instance\n */\nexport function createChildLogger(parent: Logger, bindings: Record<string, unknown>): Logger {\n return parent.child(bindings);\n}\n","/**\n * Protocol definitions for Claude Code Bridge\n * Defines message types, schemas, and serialization utilities\n */\n\nimport { z } from 'zod';\nimport { v4 as uuidv4 } from 'uuid';\n\n// ============================================================================\n// Message Type Enum\n// ============================================================================\n\nexport const MessageType = z.enum([\n 'request',\n 'response',\n 'context_sync',\n 'task_delegate',\n 'notification',\n]);\n\nexport type MessageType = z.infer<typeof MessageType>;\n\n// ============================================================================\n// File and Directory Schemas\n// ============================================================================\n\nexport const FileChunkSchema = z.object({\n path: z.string(),\n content: z.string(),\n startLine: z.number().optional(),\n endLine: z.number().optional(),\n language: z.string().optional(),\n});\n\nexport type FileChunk = z.infer<typeof FileChunkSchema>;\n\nexport const DirectoryTreeSchema: z.ZodType<DirectoryTree> = z.lazy(() =>\n z.object({\n name: z.string(),\n type: z.enum(['file', 'directory']),\n children: z.array(DirectoryTreeSchema).optional(),\n })\n);\n\nexport interface DirectoryTree {\n name: string;\n type: 'file' | 'directory';\n children?: DirectoryTree[];\n}\n\n// ============================================================================\n// Artifact Schema\n// ============================================================================\n\nexport const ArtifactSchema = z.object({\n path: z.string(),\n action: z.enum(['created', 'modified', 'deleted']),\n diff: z.string().optional(),\n});\n\nexport type Artifact = z.infer<typeof ArtifactSchema>;\n\n// ============================================================================\n// Context Schema\n// ============================================================================\n\nexport const ContextSchema = z.object({\n files: z.array(FileChunkSchema).optional(),\n tree: DirectoryTreeSchema.optional(),\n summary: z.string().optional(),\n variables: z.record(z.any()).optional(),\n});\n\nexport type Context = z.infer<typeof ContextSchema>;\n\n// ============================================================================\n// Task Request Schema\n// ============================================================================\n\nexport const TaskRequestSchema = z.object({\n id: z.string(),\n description: z.string(),\n scope: z.enum(['execute', 'analyze', 'suggest']),\n constraints: z.array(z.string()).optional(),\n returnFormat: z.enum(['full', 'summary', 'diff']).optional(),\n timeout: z.number().optional(),\n data: z.record(z.unknown()).optional(),\n});\n\nexport type TaskRequest = z.infer<typeof TaskRequestSchema>;\n\n// ============================================================================\n// Task Result Schema\n// ============================================================================\n\nexport const TaskResultSchema = z.object({\n taskId: z.string().optional(),\n success: z.boolean(),\n data: z.any(),\n artifacts: z.array(ArtifactSchema).optional(),\n followUp: z.string().optional(),\n error: z.string().optional(),\n});\n\nexport type TaskResult = z.infer<typeof TaskResultSchema>;\n\n// ============================================================================\n// Bridge Message Schema\n// ============================================================================\n\nexport const BridgeMessageSchema = z.object({\n id: z.string().uuid(),\n type: MessageType,\n source: z.string(),\n timestamp: z.number(),\n context: ContextSchema.optional(),\n task: TaskRequestSchema.optional(),\n result: TaskResultSchema.optional(),\n});\n\nexport type BridgeMessage = z.infer<typeof BridgeMessageSchema>;\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Creates a base message with auto-generated UUID and timestamp\n * @param type The message type\n * @param source The source instance identifier\n * @returns A partial BridgeMessage with id, type, source, and timestamp\n */\nexport function createMessage(\n type: MessageType,\n source: string\n): BridgeMessage {\n return {\n id: uuidv4(),\n type,\n source,\n timestamp: Date.now(),\n };\n}\n\n/**\n * Validates a message against the BridgeMessage schema\n * @param data The data to validate\n * @returns The validated BridgeMessage or throws if invalid\n */\nexport function validateMessage(data: unknown): BridgeMessage {\n return BridgeMessageSchema.parse(data);\n}\n\n/**\n * Safe validation that returns a result object instead of throwing\n * @param data The data to validate\n * @returns A Zod SafeParseReturnType with success/error information\n */\nexport function safeValidateMessage(data: unknown) {\n return BridgeMessageSchema.safeParse(data);\n}\n\n/**\n * Serializes a BridgeMessage to JSON string\n * @param message The message to serialize\n * @returns JSON string representation\n */\nexport function serializeMessage(message: BridgeMessage): string {\n return JSON.stringify(message);\n}\n\n/**\n * Deserializes a JSON string to a validated BridgeMessage\n * @param json The JSON string to deserialize\n * @returns The validated BridgeMessage\n * @throws Error if JSON is invalid or message doesn't match schema\n */\nexport function deserializeMessage(json: string): BridgeMessage {\n let parsed: unknown;\n try {\n parsed = JSON.parse(json);\n } catch {\n throw new Error('Invalid JSON');\n }\n return validateMessage(parsed);\n}\n\n/**\n * Safe deserialization that returns a result object instead of throwing\n * @param json The JSON string to deserialize\n * @returns A Zod SafeParseReturnType with success/error information\n */\nexport function safeDeserializeMessage(json: string) {\n let parsed: unknown;\n try {\n parsed = JSON.parse(json);\n } catch {\n return {\n success: false as const,\n error: new z.ZodError([\n {\n code: 'custom',\n message: 'Invalid JSON',\n path: [],\n },\n ]),\n };\n }\n return BridgeMessageSchema.safeParse(parsed);\n}\n","/**\n * Transport layer interface and types for Claude Code Bridge\n * Defines the abstract transport interface for communication between bridge instances\n */\n\nimport type { BridgeMessage } from '../bridge/protocol.js';\n\n// ============================================================================\n// Connection State Enum\n// ============================================================================\n\n/**\n * Represents the current state of a transport connection\n */\nexport enum ConnectionState {\n /** Not connected to any peer */\n DISCONNECTED = 'DISCONNECTED',\n /** Currently attempting to establish connection */\n CONNECTING = 'CONNECTING',\n /** Successfully connected and ready for communication */\n CONNECTED = 'CONNECTED',\n /** Connection lost, attempting to reconnect */\n RECONNECTING = 'RECONNECTING',\n}\n\n// ============================================================================\n// Connection Configuration\n// ============================================================================\n\n/**\n * Authentication configuration for transport connections\n */\nexport interface AuthConfig {\n /** Authentication type */\n type: 'token' | 'none';\n /** Authentication token (required if type is 'token') */\n token?: string;\n}\n\n/**\n * Configuration for establishing a transport connection\n */\nexport interface ConnectionConfig {\n /** Full WebSocket URL (e.g., ws://localhost:8765) */\n url?: string;\n /** Host to connect to (used if url is not provided) */\n host?: string;\n /** Port to connect to (used if url is not provided) */\n port?: number;\n /** Enable automatic reconnection on disconnect */\n reconnect?: boolean;\n /** Interval between reconnection attempts in milliseconds */\n reconnectInterval?: number;\n /** Maximum number of reconnection attempts before giving up */\n maxReconnectAttempts?: number;\n /** Authentication configuration */\n auth?: AuthConfig;\n}\n\n// ============================================================================\n// Event Handler Types\n// ============================================================================\n\n/**\n * Handler for incoming messages\n */\nexport type MessageHandler = (message: BridgeMessage) => void;\n\n/**\n * Handler for disconnect events\n */\nexport type DisconnectHandler = () => void;\n\n/**\n * Handler for error events\n */\nexport type ErrorHandler = (error: Error) => void;\n\n// ============================================================================\n// Transport Interface\n// ============================================================================\n\n/**\n * Abstract transport interface for bridge communication\n * Implementations handle the actual network protocol (WebSocket, TCP, etc.)\n */\nexport interface Transport {\n /**\n * Establish connection to a remote peer\n * @param config Connection configuration\n * @returns Promise that resolves when connection is established\n * @throws Error if connection fails\n */\n connect(config: ConnectionConfig): Promise<void>;\n\n /**\n * Cleanly close the current connection\n * @returns Promise that resolves when disconnection is complete\n */\n disconnect(): Promise<void>;\n\n /**\n * Send a message to the connected peer\n * @param message The message to send\n * @returns Promise that resolves when message is sent\n * @throws Error if not connected and message cannot be queued\n */\n send(message: BridgeMessage): Promise<void>;\n\n /**\n * Register a handler for incoming messages\n * @param handler Function to call when a message is received\n */\n onMessage(handler: MessageHandler): void;\n\n /**\n * Register a handler for disconnect events\n * @param handler Function to call when connection is lost\n */\n onDisconnect(handler: DisconnectHandler): void;\n\n /**\n * Register a handler for error events\n * @param handler Function to call when an error occurs\n */\n onError(handler: ErrorHandler): void;\n\n /**\n * Check if the transport is currently connected\n * @returns true if connected, false otherwise\n */\n isConnected(): boolean;\n\n /**\n * Get the current connection state\n * @returns The current ConnectionState\n */\n getState(): ConnectionState;\n}\n\n// ============================================================================\n// Transport Events (for EventEmitter pattern)\n// ============================================================================\n\n/**\n * Transport event types for EventEmitter-based implementations\n */\nexport interface TransportEvents {\n /** Emitted when a message is received */\n message: BridgeMessage;\n /** Emitted when connection is established */\n connect: void;\n /** Emitted when connection is closed */\n disconnect: void;\n /** Emitted when an error occurs */\n error: Error;\n /** Emitted when reconnection is attempted */\n reconnecting: { attempt: number; maxAttempts: number };\n}\n","/**\n * WebSocket Transport implementation for Claude Code Bridge\n * Provides WebSocket-based communication between bridge instances\n */\n\nimport WebSocket from 'ws';\nimport type { BridgeMessage } from '../bridge/protocol.js';\nimport { serializeMessage, safeDeserializeMessage } from '../bridge/protocol.js';\nimport {\n ConnectionState,\n type ConnectionConfig,\n type Transport,\n type MessageHandler,\n type DisconnectHandler,\n type ErrorHandler,\n} from './interface.js';\nimport { createLogger } from '../utils/logger.js';\n\nconst logger = createLogger('websocket-transport');\n\n/** Default reconnection interval in milliseconds */\nconst DEFAULT_RECONNECT_INTERVAL = 1000;\n\n/** Default maximum reconnection attempts */\nconst DEFAULT_MAX_RECONNECT_ATTEMPTS = 10;\n\n/** Default heartbeat interval in milliseconds */\nconst DEFAULT_HEARTBEAT_INTERVAL = 30000;\n\n/** Heartbeat timeout - how long to wait for pong response */\nconst HEARTBEAT_TIMEOUT = 10000;\n\n/**\n * WebSocket-based transport implementation\n * Handles connection lifecycle, message sending/receiving, and event handling\n * Supports auto-reconnection, message queuing, and heartbeat monitoring\n */\nexport class WebSocketTransport implements Transport {\n private ws: WebSocket | null = null;\n private state: ConnectionState = ConnectionState.DISCONNECTED;\n private config: ConnectionConfig | null = null;\n\n // Reconnection state\n private reconnectAttempts: number = 0;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private intentionalDisconnect: boolean = false;\n\n // Message queue for offline messages\n private messageQueue: BridgeMessage[] = [];\n\n // Heartbeat state\n private heartbeatInterval: ReturnType<typeof setInterval> | null = null;\n private heartbeatTimeout: ReturnType<typeof setTimeout> | null = null;\n private awaitingPong: boolean = false;\n\n // Event handlers\n private messageHandlers: MessageHandler[] = [];\n private disconnectHandlers: DisconnectHandler[] = [];\n private errorHandlers: ErrorHandler[] = [];\n private reconnectingHandlers: Array<(attempt: number, maxAttempts: number) => void> = [];\n\n /**\n * Build the WebSocket URL from the connection configuration\n */\n private buildUrl(config: ConnectionConfig): string {\n if (config.url) {\n return config.url;\n }\n\n const host = config.host ?? 'localhost';\n const port = config.port ?? 8765;\n return `ws://${host}:${port}`;\n }\n\n /**\n * Establish connection to a remote peer\n */\n async connect(config: ConnectionConfig): Promise<void> {\n if (this.state === ConnectionState.CONNECTED) {\n throw new Error('Already connected');\n }\n\n this.config = config;\n this.intentionalDisconnect = false;\n this.reconnectAttempts = 0;\n\n return this.establishConnection();\n }\n\n /**\n * Internal method to establish WebSocket connection\n * Used for both initial connection and reconnection attempts\n */\n private async establishConnection(): Promise<void> {\n if (!this.config) {\n throw new Error('No configuration set');\n }\n\n this.state = ConnectionState.CONNECTING;\n\n const url = this.buildUrl(this.config);\n logger.debug({ url, attempt: this.reconnectAttempts }, 'Connecting to WebSocket server');\n\n return new Promise<void>((resolve, reject) => {\n try {\n this.ws = new WebSocket(url);\n\n // Handle connection open\n this.ws.on('open', () => {\n this.state = ConnectionState.CONNECTED;\n this.reconnectAttempts = 0;\n logger.info({ url }, 'WebSocket connection established');\n\n // Start heartbeat monitoring\n this.startHeartbeat();\n\n // Flush queued messages\n this.flushMessageQueue();\n\n resolve();\n });\n\n // Handle incoming messages\n this.ws.on('message', (data: WebSocket.RawData) => {\n this.handleIncomingMessage(data);\n });\n\n // Handle pong responses for heartbeat\n this.ws.on('pong', () => {\n this.handlePong();\n });\n\n // Handle connection close\n this.ws.on('close', (code, reason) => {\n const wasConnected = this.state === ConnectionState.CONNECTED;\n const wasReconnecting = this.state === ConnectionState.RECONNECTING;\n\n // Stop heartbeat\n this.stopHeartbeat();\n\n logger.info({ code, reason: reason.toString() }, 'WebSocket connection closed');\n\n // Notify disconnect handlers only if we were previously connected\n if (wasConnected) {\n this.notifyDisconnect();\n }\n\n // Attempt reconnection if enabled and not intentional disconnect\n if (!this.intentionalDisconnect && this.shouldReconnect()) {\n this.scheduleReconnect();\n } else if (!wasReconnecting) {\n this.state = ConnectionState.DISCONNECTED;\n }\n });\n\n // Handle errors\n this.ws.on('error', (error: Error) => {\n logger.error({ error: error.message }, 'WebSocket error');\n\n // If we're still connecting (initial connection), reject the promise\n if (this.state === ConnectionState.CONNECTING && this.reconnectAttempts === 0) {\n this.state = ConnectionState.DISCONNECTED;\n reject(error);\n return;\n }\n\n // Notify error handlers\n this.notifyError(error);\n });\n } catch (error) {\n this.state = ConnectionState.DISCONNECTED;\n reject(error);\n }\n });\n }\n\n /**\n * Cleanly close the current connection\n */\n async disconnect(): Promise<void> {\n // Mark as intentional to prevent reconnection\n this.intentionalDisconnect = true;\n\n // Clear any pending reconnection timer\n this.clearReconnectTimer();\n\n // Stop heartbeat\n this.stopHeartbeat();\n\n // Clear message queue on intentional disconnect\n this.messageQueue = [];\n\n if (!this.ws || this.state === ConnectionState.DISCONNECTED) {\n this.state = ConnectionState.DISCONNECTED;\n return;\n }\n\n logger.debug('Disconnecting WebSocket');\n\n return new Promise<void>((resolve) => {\n if (!this.ws) {\n this.state = ConnectionState.DISCONNECTED;\n resolve();\n return;\n }\n\n // Set up close handler before closing\n const onClose = () => {\n this.state = ConnectionState.DISCONNECTED;\n this.ws = null;\n resolve();\n };\n\n // If already closed, resolve immediately\n if (this.ws.readyState === WebSocket.CLOSED) {\n onClose();\n return;\n }\n\n // Set up timeout in case close doesn't happen\n const timeout = setTimeout(() => {\n this.state = ConnectionState.DISCONNECTED;\n this.ws = null;\n resolve();\n }, 5000);\n\n this.ws.once('close', () => {\n clearTimeout(timeout);\n onClose();\n });\n\n // Initiate close\n this.ws.close(1000, 'Disconnect requested');\n });\n }\n\n /**\n * Send a message to the connected peer\n * If disconnected and reconnection is enabled, queues the message for later delivery\n */\n async send(message: BridgeMessage): Promise<void> {\n // If connected, send immediately\n if (this.ws && this.state === ConnectionState.CONNECTED) {\n return this.sendImmediate(message);\n }\n\n // If reconnecting and reconnection is enabled, queue the message\n if (this.shouldReconnect() && (this.state === ConnectionState.RECONNECTING || this.state === ConnectionState.DISCONNECTED)) {\n this.queueMessage(message);\n return;\n }\n\n throw new Error('Not connected');\n }\n\n /**\n * Immediately send a message over the WebSocket\n */\n private async sendImmediate(message: BridgeMessage): Promise<void> {\n if (!this.ws || this.state !== ConnectionState.CONNECTED) {\n throw new Error('Not connected');\n }\n\n const serialized = serializeMessage(message);\n logger.debug({ messageId: message.id, type: message.type }, 'Sending message');\n\n return new Promise<void>((resolve, reject) => {\n this.ws!.send(serialized, (error) => {\n if (error) {\n logger.error({ error: error.message, messageId: message.id }, 'Failed to send message');\n reject(error);\n } else {\n resolve();\n }\n });\n });\n }\n\n /**\n * Queue a message for later delivery when reconnected\n */\n private queueMessage(message: BridgeMessage): void {\n this.messageQueue.push(message);\n logger.debug({ messageId: message.id, queueLength: this.messageQueue.length }, 'Message queued for delivery');\n }\n\n /**\n * Flush all queued messages after reconnection\n */\n private async flushMessageQueue(): Promise<void> {\n if (this.messageQueue.length === 0) {\n return;\n }\n\n logger.info({ queueLength: this.messageQueue.length }, 'Flushing message queue');\n\n const messages = [...this.messageQueue];\n this.messageQueue = [];\n\n for (const message of messages) {\n try {\n await this.sendImmediate(message);\n } catch (error) {\n logger.error({ error: (error as Error).message, messageId: message.id }, 'Failed to send queued message');\n // Re-queue the failed message\n this.messageQueue.unshift(message);\n break;\n }\n }\n }\n\n /**\n * Register a handler for incoming messages\n */\n onMessage(handler: MessageHandler): void {\n this.messageHandlers.push(handler);\n }\n\n /**\n * Register a handler for disconnect events\n */\n onDisconnect(handler: DisconnectHandler): void {\n this.disconnectHandlers.push(handler);\n }\n\n /**\n * Register a handler for error events\n */\n onError(handler: ErrorHandler): void {\n this.errorHandlers.push(handler);\n }\n\n /**\n * Register a handler for reconnecting events\n */\n onReconnecting(handler: (attempt: number, maxAttempts: number) => void): void {\n this.reconnectingHandlers.push(handler);\n }\n\n /**\n * Check if the transport is currently connected\n */\n isConnected(): boolean {\n return this.state === ConnectionState.CONNECTED;\n }\n\n /**\n * Get the current connection state\n */\n getState(): ConnectionState {\n return this.state;\n }\n\n /**\n * Handle incoming WebSocket messages\n */\n private handleIncomingMessage(data: WebSocket.RawData): void {\n const messageString = data.toString();\n logger.debug({ dataLength: messageString.length }, 'Received message');\n\n const result = safeDeserializeMessage(messageString);\n\n if (!result.success) {\n logger.warn({ error: result.error.message }, 'Failed to parse incoming message');\n this.notifyError(new Error(`Invalid message format: ${result.error.message}`));\n return;\n }\n\n const message = result.data;\n logger.debug({ messageId: message.id, type: message.type }, 'Parsed message');\n\n // Notify all message handlers\n for (const handler of this.messageHandlers) {\n try {\n handler(message);\n } catch (error) {\n logger.error({ error: (error as Error).message }, 'Message handler threw error');\n }\n }\n }\n\n /**\n * Notify all disconnect handlers\n */\n private notifyDisconnect(): void {\n for (const handler of this.disconnectHandlers) {\n try {\n handler();\n } catch (error) {\n logger.error({ error: (error as Error).message }, 'Disconnect handler threw error');\n }\n }\n }\n\n /**\n * Notify all error handlers\n */\n private notifyError(error: Error): void {\n for (const handler of this.errorHandlers) {\n try {\n handler(error);\n } catch (handlerError) {\n logger.error({ error: (handlerError as Error).message }, 'Error handler threw error');\n }\n }\n }\n\n /**\n * Notify all reconnecting handlers\n */\n private notifyReconnecting(attempt: number, maxAttempts: number): void {\n for (const handler of this.reconnectingHandlers) {\n try {\n handler(attempt, maxAttempts);\n } catch (error) {\n logger.error({ error: (error as Error).message }, 'Reconnecting handler threw error');\n }\n }\n }\n\n // ============================================================================\n // Reconnection Methods\n // ============================================================================\n\n /**\n * Check if reconnection should be attempted\n */\n private shouldReconnect(): boolean {\n if (!this.config?.reconnect) {\n return false;\n }\n\n const maxAttempts = this.config.maxReconnectAttempts ?? DEFAULT_MAX_RECONNECT_ATTEMPTS;\n return this.reconnectAttempts < maxAttempts;\n }\n\n /**\n * Schedule a reconnection attempt\n */\n private scheduleReconnect(): void {\n if (this.reconnectTimer) {\n return; // Already scheduled\n }\n\n this.state = ConnectionState.RECONNECTING;\n this.reconnectAttempts++;\n\n const maxAttempts = this.config?.maxReconnectAttempts ?? DEFAULT_MAX_RECONNECT_ATTEMPTS;\n const interval = this.config?.reconnectInterval ?? DEFAULT_RECONNECT_INTERVAL;\n\n logger.info(\n { attempt: this.reconnectAttempts, maxAttempts, interval },\n 'Scheduling reconnection attempt'\n );\n\n // Notify reconnecting handlers\n this.notifyReconnecting(this.reconnectAttempts, maxAttempts);\n\n this.reconnectTimer = setTimeout(async () => {\n this.reconnectTimer = null;\n\n try {\n await this.establishConnection();\n logger.info({ attempts: this.reconnectAttempts }, 'Reconnection successful');\n } catch (error) {\n logger.warn({ error: (error as Error).message }, 'Reconnection attempt failed');\n\n // Schedule another attempt if we haven't reached the limit\n if (this.shouldReconnect()) {\n this.scheduleReconnect();\n } else {\n logger.error({ maxAttempts }, 'Max reconnection attempts reached, giving up');\n this.state = ConnectionState.DISCONNECTED;\n this.notifyError(new Error(`Failed to reconnect after ${maxAttempts} attempts`));\n }\n }\n }, interval);\n }\n\n /**\n * Clear any pending reconnection timer\n */\n private clearReconnectTimer(): void {\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n }\n\n // ============================================================================\n // Heartbeat Methods\n // ============================================================================\n\n /**\n * Start the heartbeat monitoring\n */\n private startHeartbeat(): void {\n this.stopHeartbeat(); // Clear any existing heartbeat\n\n this.heartbeatInterval = setInterval(() => {\n this.sendPing();\n }, DEFAULT_HEARTBEAT_INTERVAL);\n\n logger.debug({ interval: DEFAULT_HEARTBEAT_INTERVAL }, 'Heartbeat monitoring started');\n }\n\n /**\n * Stop the heartbeat monitoring\n */\n private stopHeartbeat(): void {\n if (this.heartbeatInterval) {\n clearInterval(this.heartbeatInterval);\n this.heartbeatInterval = null;\n }\n\n if (this.heartbeatTimeout) {\n clearTimeout(this.heartbeatTimeout);\n this.heartbeatTimeout = null;\n }\n\n this.awaitingPong = false;\n }\n\n /**\n * Send a ping to the peer\n */\n private sendPing(): void {\n if (!this.ws || this.state !== ConnectionState.CONNECTED) {\n return;\n }\n\n if (this.awaitingPong) {\n // We didn't receive a pong for the previous ping - connection may be dead\n logger.warn('No pong received, connection may be dead');\n this.handleHeartbeatTimeout();\n return;\n }\n\n this.awaitingPong = true;\n this.ws.ping();\n\n // Set timeout for pong response\n this.heartbeatTimeout = setTimeout(() => {\n if (this.awaitingPong) {\n this.handleHeartbeatTimeout();\n }\n }, HEARTBEAT_TIMEOUT);\n\n logger.debug('Ping sent');\n }\n\n /**\n * Handle pong response from peer\n */\n private handlePong(): void {\n this.awaitingPong = false;\n\n if (this.heartbeatTimeout) {\n clearTimeout(this.heartbeatTimeout);\n this.heartbeatTimeout = null;\n }\n\n logger.debug('Pong received');\n }\n\n /**\n * Handle heartbeat timeout (no pong received)\n */\n private handleHeartbeatTimeout(): void {\n logger.warn('Heartbeat timeout - closing connection');\n this.awaitingPong = false;\n\n if (this.heartbeatTimeout) {\n clearTimeout(this.heartbeatTimeout);\n this.heartbeatTimeout = null;\n }\n\n // Close the connection to trigger reconnection if enabled\n if (this.ws) {\n this.ws.terminate();\n }\n }\n\n // ============================================================================\n // Getters for testing/debugging\n // ============================================================================\n\n /**\n * Get the current message queue length (for testing)\n */\n getQueueLength(): number {\n return this.messageQueue.length;\n }\n\n /**\n * Get the number of reconnection attempts (for testing)\n */\n getReconnectAttempts(): number {\n return this.reconnectAttempts;\n }\n}\n","/**\n * Message builder factory functions for Claude Code Bridge\n * Provides convenient functions to create specific message types\n */\n\nimport { createMessage, type BridgeMessage, type Context, type TaskRequest, type TaskResult } from './protocol.js';\n\n/**\n * Notification data structure for notification messages\n */\nexport interface NotificationData {\n type: string;\n message: string;\n data?: Record<string, unknown>;\n}\n\n/**\n * Creates a context synchronization message\n * Used to share context (files, tree, summary) with a peer\n * @param source The source instance identifier\n * @param context The context to synchronize\n * @returns A BridgeMessage with type 'context_sync'\n */\nexport function createContextSyncMessage(\n source: string,\n context: Context\n): BridgeMessage {\n const message = createMessage('context_sync', source);\n return {\n ...message,\n context,\n };\n}\n\n/**\n * Creates a task delegation message\n * Used to delegate a task to a peer instance\n * @param source The source instance identifier\n * @param task The task to delegate\n * @returns A BridgeMessage with type 'task_delegate'\n */\nexport function createTaskDelegateMessage(\n source: string,\n task: TaskRequest\n): BridgeMessage {\n const message = createMessage('task_delegate', source);\n return {\n ...message,\n task,\n };\n}\n\n/**\n * Creates a task response message\n * Used to respond to a delegated task\n * @param source The source instance identifier\n * @param taskId The ID of the task being responded to\n * @param result The result of the task execution\n * @returns A BridgeMessage with type 'response'\n */\nexport function createTaskResponseMessage(\n source: string,\n taskId: string,\n result: Omit<TaskResult, 'taskId'>\n): BridgeMessage {\n const message = createMessage('response', source);\n return {\n ...message,\n result: {\n ...result,\n taskId,\n },\n };\n}\n\n/**\n * Creates a context request message\n * Used to request specific context from a peer\n * @param source The source instance identifier\n * @param query A description of what context is being requested\n * @returns A BridgeMessage with type 'request'\n */\nexport function createContextRequestMessage(\n source: string,\n query: string\n): BridgeMessage {\n const message = createMessage('request', source);\n return {\n ...message,\n context: {\n summary: query,\n },\n };\n}\n\n/**\n * Creates a notification message\n * Used to send notifications to peers (events, status updates, etc.)\n * @param source The source instance identifier\n * @param notification The notification data\n * @returns A BridgeMessage with type 'notification'\n */\nexport function createNotificationMessage(\n source: string,\n notification: NotificationData\n): BridgeMessage {\n const message = createMessage('notification', source);\n return {\n ...message,\n context: {\n summary: notification.message,\n variables: {\n notificationType: notification.type,\n ...notification.data,\n },\n },\n };\n}\n","/**\n * Bridge Core - Main orchestration class for Claude Code Bridge\n * Handles peer connections, message routing, and lifecycle management\n */\n\nimport { WebSocketServer, WebSocket as WsWebSocket } from 'ws';\nimport { v4 as uuidv4 } from 'uuid';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\nimport { createLogger } from '../utils/logger.js';\nimport { WebSocketTransport } from '../transport/websocket.js';\nimport { ConnectionState, type Transport } from '../transport/interface.js';\nimport {\n type BridgeMessage,\n type TaskRequest,\n type TaskResult,\n type Context,\n type FileChunk,\n safeDeserializeMessage,\n serializeMessage,\n} from './protocol.js';\nimport {\n createTaskDelegateMessage,\n createTaskResponseMessage,\n createContextSyncMessage,\n createContextRequestMessage,\n} from './messages.js';\n\nconst logger = createLogger('bridge');\n\n// ============================================================================\n// Type Definitions\n// ============================================================================\n\n/**\n * Bridge operation mode\n * - 'host': Listen for incoming connections only\n * - 'client': Connect to a remote bridge only\n * - 'peer': Both listen and connect (bidirectional)\n */\nexport type BridgeMode = 'host' | 'client' | 'peer';\n\n/**\n * Configuration for the bridge's listening server\n */\nexport interface BridgeListenConfig {\n /** Port to listen on */\n port: number;\n /** Host to bind to (default: 0.0.0.0) */\n host?: string;\n}\n\n/**\n * Configuration for connecting to a remote bridge\n */\nexport interface BridgeConnectConfig {\n /** Full WebSocket URL (e.g., ws://localhost:8765) */\n url?: string;\n /** Use host.docker.internal for container-to-host connection */\n hostGateway?: boolean;\n /** Port to connect to (used if url is not provided) */\n port?: number;\n}\n\n/**\n * Context sharing configuration\n */\nexport interface ContextSharingConfig {\n /** Enable automatic context synchronization */\n autoSync?: boolean;\n /** Interval in milliseconds for auto-sync (default: 5000) */\n syncInterval?: number;\n}\n\n/**\n * Full configuration for Bridge initialization\n */\nexport interface BridgeConfig {\n /** Operation mode: 'host', 'client', or 'peer' */\n mode: BridgeMode;\n /** Unique identifier for this bridge instance */\n instanceName: string;\n /** Server configuration (required for 'host' and 'peer' modes) */\n listen?: BridgeListenConfig;\n /** Connection configuration (required for 'client' and 'peer' modes) */\n connect?: BridgeConnectConfig;\n /** Task timeout in milliseconds (default: 300000 / 5 minutes) */\n taskTimeout?: number;\n /** Context sharing configuration */\n contextSharing?: ContextSharingConfig;\n}\n\n/**\n * Information about a connected peer\n */\nexport interface PeerInfo {\n /** Unique identifier for the peer connection */\n id: string;\n /** Name of the peer instance */\n name: string;\n /** Environment type of the peer */\n environment?: string;\n /** Timestamp when the peer connected */\n connectedAt: number;\n /** Timestamp of last activity from the peer */\n lastActivity: number;\n}\n\n/**\n * Internal peer connection tracking\n */\ninterface PeerConnection {\n /** Peer information */\n info: PeerInfo;\n /** WebSocket connection (for server-side connections) */\n ws?: WsWebSocket;\n /** Transport instance (for client-side connections) */\n transport?: Transport;\n}\n\n/**\n * Handler for peer connection events\n */\nexport type PeerConnectedHandler = (peer: PeerInfo) => void;\n\n/**\n * Handler for peer disconnection events\n */\nexport type PeerDisconnectedHandler = (peer: PeerInfo) => void;\n\n/**\n * Handler for incoming messages from peers\n */\nexport type MessageReceivedHandler = (message: BridgeMessage, peerId: string) => void;\n\n/**\n * Handler for incoming task delegation requests\n * Returns a TaskResult or Promise<TaskResult>\n */\nexport type TaskReceivedHandler = (task: TaskRequest, peerId: string) => TaskResult | Promise<TaskResult>;\n\n/**\n * Handler for incoming context synchronization\n */\nexport type ContextReceivedHandler = (context: Context, peerId: string) => void;\n\n/**\n * Handler for incoming context requests\n * Returns FileChunk[] or Promise<FileChunk[]>\n */\nexport type ContextRequestedHandler = (query: string, peerId: string) => FileChunk[] | Promise<FileChunk[]>;\n\n/**\n * Pending task tracking for response correlation\n */\ninterface PendingTask {\n taskId: string;\n peerId: string;\n resolve: (result: TaskResult) => void;\n reject: (error: Error) => void;\n timeoutId: ReturnType<typeof setTimeout>;\n}\n\n/**\n * Pending context request tracking for response correlation\n */\ninterface PendingContextRequest {\n requestId: string;\n peerId: string;\n resolve: (chunks: FileChunk[]) => void;\n reject: (error: Error) => void;\n timeoutId: ReturnType<typeof setTimeout>;\n}\n\n// ============================================================================\n// Bridge Class\n// ============================================================================\n\n/**\n * Main Bridge class for managing peer-to-peer communication\n * Supports three modes of operation:\n * - 'host': Acts as a server, accepting incoming connections\n * - 'client': Acts as a client, connecting to a remote server\n * - 'peer': Both listens for connections and connects to a remote peer\n */\nexport class Bridge {\n private config: BridgeConfig;\n private server: WebSocketServer | null = null;\n private clientTransport: WebSocketTransport | null = null;\n private peers: Map<string, PeerConnection> = new Map();\n private started: boolean = false;\n\n // Event handlers\n private peerConnectedHandlers: PeerConnectedHandler[] = [];\n private peerDisconnectedHandlers: PeerDisconnectedHandler[] = [];\n private messageReceivedHandlers: MessageReceivedHandler[] = [];\n private taskReceivedHandler: TaskReceivedHandler | null = null;\n private contextReceivedHandlers: ContextReceivedHandler[] = [];\n private contextRequestedHandler: ContextRequestedHandler | null = null;\n\n // Task correlation\n private pendingTasks: Map<string, PendingTask> = new Map();\n\n // Context request correlation\n private pendingContextRequests: Map<string, PendingContextRequest> = new Map();\n\n // Auto-sync interval timer\n private autoSyncIntervalId: ReturnType<typeof setInterval> | null = null;\n\n /**\n * Create a new Bridge instance\n * @param config Bridge configuration\n */\n constructor(config: BridgeConfig) {\n this.config = config;\n this.validateConfig();\n logger.info({ instanceName: config.instanceName, mode: config.mode }, 'Bridge instance created');\n }\n\n /**\n * Validate the configuration based on mode requirements\n */\n private validateConfig(): void {\n const { mode, listen, connect } = this.config;\n\n if (mode === 'host' && !listen) {\n throw new Error(\"'host' mode requires 'listen' configuration\");\n }\n\n if (mode === 'client' && !connect) {\n throw new Error(\"'client' mode requires 'connect' configuration\");\n }\n\n if (mode === 'peer' && !listen && !connect) {\n throw new Error(\"'peer' mode requires either 'listen' or 'connect' configuration (or both)\");\n }\n }\n\n /**\n * Start the bridge based on configured mode\n * - 'host': Starts WebSocket server\n * - 'client': Connects to remote bridge\n * - 'peer': Both starts server and connects to remote\n */\n async start(): Promise<void> {\n if (this.started) {\n throw new Error('Bridge is already started');\n }\n\n const { mode } = this.config;\n logger.info({ mode }, 'Starting bridge');\n\n try {\n // Start server if in host or peer mode\n if ((mode === 'host' || mode === 'peer') && this.config.listen) {\n await this.startServer();\n }\n\n // Connect to remote if in client or peer mode\n if ((mode === 'client' || mode === 'peer') && this.config.connect) {\n await this.connectToRemote();\n }\n\n this.started = true;\n this.writeStatusFile();\n logger.info({ mode, instanceName: this.config.instanceName }, 'Bridge started successfully');\n } catch (error) {\n // Cleanup on failure\n await this.cleanup();\n throw error;\n }\n }\n\n /**\n * Stop the bridge and close all connections\n */\n async stop(): Promise<void> {\n if (!this.started) {\n return;\n }\n\n logger.info('Stopping bridge');\n await this.cleanup();\n this.started = false;\n logger.info('Bridge stopped');\n }\n\n /**\n * Get list of connected peers\n */\n getPeers(): PeerInfo[] {\n return Array.from(this.peers.values()).map(p => p.info);\n }\n\n /**\n * Connect to a remote bridge\n * @param url WebSocket URL to connect to\n */\n async connectToPeer(url: string): Promise<void> {\n const transport = new WebSocketTransport();\n\n // Set up message handler\n transport.onMessage((message) => {\n this.handleMessage(message, transport);\n });\n\n // Set up disconnect handler\n transport.onDisconnect(() => {\n this.handleClientDisconnect(transport);\n });\n\n try {\n await transport.connect({\n url,\n reconnect: true,\n reconnectInterval: 1000,\n maxReconnectAttempts: 10,\n });\n\n // Create peer info for the connected remote\n const peerId = uuidv4();\n const peerInfo: PeerInfo = {\n id: peerId,\n name: 'remote', // Will be updated when we receive peer info\n connectedAt: Date.now(),\n lastActivity: Date.now(),\n };\n\n this.peers.set(peerId, {\n info: peerInfo,\n transport,\n });\n\n // Store peerId on transport for lookup\n (transport as WebSocketTransport & { _peerId?: string })._peerId = peerId;\n\n this.notifyPeerConnected(peerInfo);\n logger.info({ peerId, url }, 'Connected to remote peer');\n } catch (error) {\n logger.error({ error: (error as Error).message, url }, 'Failed to connect to remote peer');\n throw error;\n }\n }\n\n /**\n * Disconnect from a specific peer\n * @param peerId ID of the peer to disconnect from\n */\n async disconnectFromPeer(peerId: string): Promise<void> {\n const peer = this.peers.get(peerId);\n if (!peer) {\n throw new Error(`Peer not found: ${peerId}`);\n }\n\n if (peer.transport) {\n await peer.transport.disconnect();\n }\n\n if (peer.ws) {\n peer.ws.close(1000, 'Disconnect requested');\n }\n\n this.peers.delete(peerId);\n this.notifyPeerDisconnected(peer.info);\n logger.info({ peerId }, 'Disconnected from peer');\n }\n\n /**\n * Send a message to a specific peer\n * @param peerId ID of the peer to send to\n * @param message Message to send\n */\n async sendToPeer(peerId: string, message: BridgeMessage): Promise<void> {\n const peer = this.peers.get(peerId);\n if (!peer) {\n throw new Error(`Peer not found: ${peerId}`);\n }\n\n if (peer.transport) {\n await peer.transport.send(message);\n } else if (peer.ws) {\n const serialized = serializeMessage(message);\n await new Promise<void>((resolve, reject) => {\n peer.ws!.send(serialized, (error) => {\n if (error) {\n reject(error);\n } else {\n resolve();\n }\n });\n });\n } else {\n throw new Error('No transport available for peer');\n }\n\n logger.debug({ peerId, messageId: message.id, type: message.type }, 'Sent message to peer');\n }\n\n /**\n * Broadcast a message to all connected peers\n * @param message Message to broadcast\n */\n async broadcast(message: BridgeMessage): Promise<void> {\n const sendPromises = Array.from(this.peers.keys()).map(peerId =>\n this.sendToPeer(peerId, message).catch(error => {\n logger.error({ error: (error as Error).message, peerId }, 'Failed to send to peer');\n })\n );\n\n await Promise.all(sendPromises);\n logger.debug({ messageId: message.id, peerCount: this.peers.size }, 'Broadcast message sent');\n }\n\n // ============================================================================\n // Event Registration\n // ============================================================================\n\n /**\n * Register a handler for peer connection events\n */\n onPeerConnected(handler: PeerConnectedHandler): void {\n this.peerConnectedHandlers.push(handler);\n }\n\n /**\n * Register a handler for peer disconnection events\n */\n onPeerDisconnected(handler: PeerDisconnectedHandler): void {\n this.peerDisconnectedHandlers.push(handler);\n }\n\n /**\n * Register a handler for incoming messages\n */\n onMessage(handler: MessageReceivedHandler): void {\n this.messageReceivedHandlers.push(handler);\n }\n\n /**\n * Register a handler for incoming task delegation requests\n * Only one handler can be registered at a time\n * @param handler Function that receives a TaskRequest and returns a TaskResult\n */\n onTaskReceived(handler: TaskReceivedHandler): void {\n this.taskReceivedHandler = handler;\n }\n\n /**\n * Register a handler for incoming context synchronization\n * Multiple handlers can be registered\n * @param handler Function that receives context and peerId\n */\n onContextReceived(handler: ContextReceivedHandler): void {\n this.contextReceivedHandlers.push(handler);\n }\n\n /**\n * Register a handler for incoming context requests\n * Only one handler can be registered at a time\n * @param handler Function that receives a query and returns FileChunk[]\n */\n onContextRequested(handler: ContextRequestedHandler): void {\n this.contextRequestedHandler = handler;\n }\n\n // ============================================================================\n // Task Delegation\n // ============================================================================\n\n /**\n * Delegate a task to a peer and wait for the result\n * @param task The task request to delegate\n * @param peerId Optional peer ID to send to (defaults to first peer)\n * @returns Promise that resolves with the task result\n * @throws Error if no peers are connected or task times out\n */\n async delegateTask(task: TaskRequest, peerId?: string): Promise<TaskResult> {\n // Get target peer\n if (!peerId) {\n const peers = this.getPeers();\n if (peers.length === 0) {\n throw new Error('No peers connected to delegate task to');\n }\n peerId = peers[0].id;\n }\n\n // Validate peer exists\n if (!this.peers.has(peerId)) {\n throw new Error(`Peer not found: ${peerId}`);\n }\n\n // Determine timeout\n const timeout = task.timeout ?? this.config.taskTimeout ?? 300000; // Default 5 minutes\n\n // Create promise to track task completion\n return new Promise<TaskResult>((resolve, reject) => {\n // Create the task delegate message\n const message = createTaskDelegateMessage(this.config.instanceName, task);\n\n // Set up timeout\n const timeoutId = setTimeout(() => {\n const pending = this.pendingTasks.get(task.id);\n if (pending) {\n this.pendingTasks.delete(task.id);\n reject(new Error(`Task '${task.id}' timed out after ${timeout}ms`));\n }\n }, timeout);\n\n // Store pending task for correlation\n this.pendingTasks.set(task.id, {\n taskId: task.id,\n peerId,\n resolve,\n reject,\n timeoutId,\n });\n\n // Send the task\n this.sendToPeer(peerId, message).catch((error) => {\n // Clean up on send error\n clearTimeout(timeoutId);\n this.pendingTasks.delete(task.id);\n reject(error);\n });\n\n logger.debug({ taskId: task.id, peerId, timeout }, 'Task delegated');\n });\n }\n\n // ============================================================================\n // Context Synchronization\n // ============================================================================\n\n /**\n * Synchronize context with connected peers\n * @param context Optional context to sync. If not provided, broadcasts to all peers\n * @param peerId Optional peer ID to send to (defaults to all peers)\n */\n async syncContext(context?: Context, peerId?: string): Promise<void> {\n // Use empty context if not provided\n const contextToSync = context ?? {};\n\n // Create the context sync message\n const message = createContextSyncMessage(this.config.instanceName, contextToSync);\n\n if (peerId) {\n // Send to specific peer\n await this.sendToPeer(peerId, message);\n logger.debug({ peerId, messageId: message.id }, 'Context synced to peer');\n } else {\n // Broadcast to all peers\n await this.broadcast(message);\n logger.debug({ peerCount: this.peers.size, messageId: message.id }, 'Context synced to all peers');\n }\n }\n\n /**\n * Request context from a peer based on a query\n * @param query Description of what context is being requested\n * @param peerId Optional peer ID to request from (defaults to first peer)\n * @param timeout Optional timeout in milliseconds (default: 30000)\n * @returns Promise that resolves with FileChunk[] from the peer\n * @throws Error if no peers are connected or request times out\n */\n async requestContext(query: string, peerId?: string, timeout: number = 30000): Promise<FileChunk[]> {\n // Get target peer\n if (!peerId) {\n const peers = this.getPeers();\n if (peers.length === 0) {\n throw new Error('No peers connected to request context from');\n }\n peerId = peers[0].id;\n }\n\n // Validate peer exists\n if (!this.peers.has(peerId)) {\n throw new Error(`Peer not found: ${peerId}`);\n }\n\n // Create promise to track request completion\n return new Promise<FileChunk[]>((resolve, reject) => {\n // Create the context request message\n const message = createContextRequestMessage(this.config.instanceName, query);\n\n // Set up timeout\n const timeoutId = setTimeout(() => {\n const pending = this.pendingContextRequests.get(message.id);\n if (pending) {\n this.pendingContextRequests.delete(message.id);\n reject(new Error(`Context request timed out after ${timeout}ms`));\n }\n }, timeout);\n\n // Store pending request for correlation\n this.pendingContextRequests.set(message.id, {\n requestId: message.id,\n peerId,\n resolve,\n reject,\n timeoutId,\n });\n\n // Send the request\n this.sendToPeer(peerId, message).catch((error) => {\n // Clean up on send error\n clearTimeout(timeoutId);\n this.pendingContextRequests.delete(message.id);\n reject(error);\n });\n\n logger.debug({ requestId: message.id, peerId, query }, 'Context requested');\n });\n }\n\n /**\n * Start automatic context synchronization\n * Uses interval from config.contextSharing.syncInterval (default: 5000ms)\n * @param contextProvider Optional function that returns context to sync\n */\n startAutoSync(contextProvider?: () => Context | Promise<Context>): void {\n // Stop any existing auto-sync\n this.stopAutoSync();\n\n const interval = this.config.contextSharing?.syncInterval ?? 5000;\n\n this.autoSyncIntervalId = setInterval(async () => {\n try {\n // Get context from provider if available\n const context = contextProvider ? await contextProvider() : undefined;\n await this.syncContext(context);\n } catch (error) {\n logger.error({ error: (error as Error).message }, 'Auto-sync error');\n }\n }, interval);\n\n logger.info({ interval }, 'Auto-sync started');\n }\n\n /**\n * Stop automatic context synchronization\n */\n stopAutoSync(): void {\n if (this.autoSyncIntervalId) {\n clearInterval(this.autoSyncIntervalId);\n this.autoSyncIntervalId = null;\n logger.info('Auto-sync stopped');\n }\n }\n\n // ============================================================================\n // Private Methods - Server\n // ============================================================================\n\n /**\n * Start the WebSocket server\n */\n private async startServer(): Promise<void> {\n const { listen } = this.config;\n if (!listen) {\n throw new Error('Listen configuration is required');\n }\n\n return new Promise<void>((resolve, reject) => {\n const host = listen.host ?? '0.0.0.0';\n const port = listen.port;\n\n logger.debug({ host, port }, 'Starting WebSocket server');\n\n this.server = new WebSocketServer({ host, port });\n\n this.server.on('listening', () => {\n logger.info({ host, port }, 'WebSocket server listening');\n resolve();\n });\n\n this.server.on('error', (error) => {\n logger.error({ error: (error as Error).message }, 'WebSocket server error');\n reject(error);\n });\n\n this.server.on('connection', (ws, request) => {\n this.handleNewConnection(ws, request);\n });\n });\n }\n\n /**\n * Handle a new incoming connection\n */\n private handleNewConnection(ws: WsWebSocket, request: { url?: string }): void {\n const peerId = uuidv4();\n const peerInfo: PeerInfo = {\n id: peerId,\n name: 'client', // Will be updated when we receive peer info\n connectedAt: Date.now(),\n lastActivity: Date.now(),\n };\n\n this.peers.set(peerId, {\n info: peerInfo,\n ws,\n });\n\n logger.info({ peerId, url: request.url }, 'New peer connected');\n\n // Set up message handler\n ws.on('message', (data) => {\n const messageString = data.toString();\n const result = safeDeserializeMessage(messageString);\n\n if (result.success) {\n peerInfo.lastActivity = Date.now();\n this.handleMessage(result.data, ws, peerId);\n } else {\n logger.warn({ peerId, error: result.error.message }, 'Invalid message received');\n }\n });\n\n // Set up close handler\n ws.on('close', (code, reason) => {\n logger.info({ peerId, code, reason: reason.toString() }, 'Peer disconnected');\n this.peers.delete(peerId);\n this.notifyPeerDisconnected(peerInfo);\n });\n\n // Set up error handler\n ws.on('error', (error) => {\n logger.error({ peerId, error: (error as Error).message }, 'Peer connection error');\n });\n\n // Notify peer connected handlers\n this.notifyPeerConnected(peerInfo);\n }\n\n // ============================================================================\n // Private Methods - Client\n // ============================================================================\n\n /**\n * Connect to a remote bridge as a client\n */\n private async connectToRemote(): Promise<void> {\n const { connect } = this.config;\n if (!connect) {\n throw new Error('Connect configuration is required');\n }\n\n // Build URL from config\n let url = connect.url;\n if (!url) {\n const host = connect.hostGateway ? 'host.docker.internal' : 'localhost';\n const port = connect.port ?? 8765;\n url = `ws://${host}:${port}`;\n }\n\n this.clientTransport = new WebSocketTransport();\n\n // Set up message handler\n this.clientTransport.onMessage((message) => {\n this.handleMessage(message, this.clientTransport!);\n });\n\n // Set up disconnect handler\n this.clientTransport.onDisconnect(() => {\n this.handleClientDisconnect(this.clientTransport!);\n });\n\n try {\n await this.clientTransport.connect({\n url,\n reconnect: true,\n reconnectInterval: 1000,\n maxReconnectAttempts: 10,\n });\n\n // Create peer info for the connected server\n const peerId = uuidv4();\n const peerInfo: PeerInfo = {\n id: peerId,\n name: 'server',\n connectedAt: Date.now(),\n lastActivity: Date.now(),\n };\n\n this.peers.set(peerId, {\n info: peerInfo,\n transport: this.clientTransport,\n });\n\n // Store peerId on transport for lookup\n (this.clientTransport as WebSocketTransport & { _peerId?: string })._peerId = peerId;\n\n this.notifyPeerConnected(peerInfo);\n logger.info({ peerId, url }, 'Connected to remote bridge');\n } catch (error) {\n logger.error({ error: (error as Error).message }, 'Failed to connect to remote bridge');\n this.clientTransport = null;\n throw error;\n }\n }\n\n /**\n * Handle client transport disconnect\n */\n private handleClientDisconnect(transport: Transport): void {\n // Find peer by transport\n const typedTransport = transport as WebSocketTransport & { _peerId?: string };\n const peerId = typedTransport._peerId;\n\n if (peerId) {\n const peer = this.peers.get(peerId);\n if (peer) {\n this.peers.delete(peerId);\n this.notifyPeerDisconnected(peer.info);\n logger.info({ peerId }, 'Client transport disconnected');\n }\n }\n }\n\n // ============================================================================\n // Private Methods - Message Handling\n // ============================================================================\n\n /**\n * Handle an incoming message\n */\n private handleMessage(\n message: BridgeMessage,\n source: WsWebSocket | Transport,\n peerId?: string\n ): void {\n // Find peerId if not provided\n if (!peerId) {\n const typedSource = source as WebSocketTransport & { _peerId?: string };\n peerId = typedSource._peerId;\n }\n\n if (!peerId) {\n // Try to find by ws reference\n for (const [id, peer] of this.peers) {\n if (peer.ws === source || peer.transport === source) {\n peerId = id;\n break;\n }\n }\n }\n\n if (!peerId) {\n logger.warn({ messageId: message.id }, 'Received message from unknown peer');\n return;\n }\n\n // Update last activity\n const peer = this.peers.get(peerId);\n if (peer) {\n peer.info.lastActivity = Date.now();\n }\n\n logger.debug({ peerId, messageId: message.id, type: message.type }, 'Received message');\n\n // Handle task delegation messages\n if (message.type === 'task_delegate' && message.task) {\n this.handleTaskDelegate(message, peerId);\n return;\n }\n\n // Handle task response messages\n if (message.type === 'response' && message.result?.taskId) {\n this.handleTaskResponse(message);\n return;\n }\n\n // Handle context sync messages\n if (message.type === 'context_sync' && message.context) {\n this.handleContextSync(message, peerId);\n return;\n }\n\n // Handle context request messages\n if (message.type === 'request' && message.context?.summary) {\n this.handleContextRequest(message, peerId);\n return;\n }\n\n // Handle context response messages (responses to context requests)\n if (message.type === 'response' && message.context?.files !== undefined) {\n this.handleContextResponse(message);\n return;\n }\n\n // Notify message handlers for other message types\n this.notifyMessageReceived(message, peerId);\n }\n\n /**\n * Handle incoming task delegation request\n */\n private async handleTaskDelegate(message: BridgeMessage, peerId: string): Promise<void> {\n const task = message.task!;\n logger.debug({ taskId: task.id, peerId }, 'Received task delegation');\n\n // If no handler registered, try to forward to another peer\n if (!this.taskReceivedHandler) {\n // Find another peer to forward to (not the sender)\n const otherPeers = Array.from(this.peers.keys()).filter(id => id !== peerId);\n\n if (otherPeers.length > 0) {\n // Forward to the first available peer\n const targetPeerId = otherPeers[0];\n logger.info({ taskId: task.id, targetPeerId }, 'Forwarding task to another peer');\n\n try {\n // Forward the original message\n await this.sendToPeer(targetPeerId, message);\n\n // Set up response forwarding - store the original sender\n const forwardKey = `forward:${task.id}`;\n (this as unknown as Record<string, string>)[forwardKey] = peerId;\n\n return;\n } catch (err) {\n logger.error({ error: (err as Error).message, taskId: task.id }, 'Failed to forward task');\n }\n }\n\n logger.warn({ taskId: task.id }, 'No task handler registered and no peers to forward to');\n const response = createTaskResponseMessage(\n this.config.instanceName,\n task.id,\n {\n success: false,\n data: null,\n error: 'No task handler registered on peer',\n }\n );\n await this.sendToPeer(peerId, response).catch((err) => {\n logger.error({ error: (err as Error).message, taskId: task.id }, 'Failed to send error response');\n });\n return;\n }\n\n try {\n // Execute the task handler\n const result = await this.taskReceivedHandler(task, peerId);\n\n // Send successful response\n const response = createTaskResponseMessage(\n this.config.instanceName,\n task.id,\n result\n );\n await this.sendToPeer(peerId, response);\n logger.debug({ taskId: task.id, success: result.success }, 'Task response sent');\n } catch (error) {\n // Send error response\n const response = createTaskResponseMessage(\n this.config.instanceName,\n task.id,\n {\n success: false,\n data: null,\n error: (error as Error).message,\n }\n );\n await this.sendToPeer(peerId, response).catch((err) => {\n logger.error({ error: (err as Error).message, taskId: task.id }, 'Failed to send error response');\n });\n logger.error({ taskId: task.id, error: (error as Error).message }, 'Task handler error');\n }\n }\n\n /**\n * Handle task response message (correlate with pending task)\n */\n private async handleTaskResponse(message: BridgeMessage): Promise<void> {\n const taskId = message.result!.taskId!;\n\n // Check if this is a forwarded response that needs to go back to original sender\n const forwardKey = `forward:${taskId}`;\n const originalSender = (this as unknown as Record<string, string>)[forwardKey];\n if (originalSender) {\n delete (this as unknown as Record<string, string>)[forwardKey];\n logger.info({ taskId, originalSender }, 'Forwarding task response to original sender');\n await this.sendToPeer(originalSender, message).catch((err) => {\n logger.error({ error: (err as Error).message, taskId }, 'Failed to forward response');\n });\n return;\n }\n\n const pending = this.pendingTasks.get(taskId);\n\n if (!pending) {\n logger.warn({ taskId }, 'Received response for unknown task');\n return;\n }\n\n // Clear timeout and remove from pending\n clearTimeout(pending.timeoutId);\n this.pendingTasks.delete(taskId);\n\n // Resolve the promise with the result\n const result: TaskResult = {\n taskId: message.result!.taskId,\n success: message.result!.success,\n data: message.result!.data,\n artifacts: message.result!.artifacts,\n followUp: message.result!.followUp,\n error: message.result!.error,\n };\n\n logger.debug({ taskId, success: result.success }, 'Task result received');\n pending.resolve(result);\n }\n\n /**\n * Handle incoming context sync message\n */\n private handleContextSync(message: BridgeMessage, peerId: string): void {\n const context = message.context!;\n logger.debug({ peerId, messageId: message.id }, 'Received context sync');\n\n // Notify all context received handlers\n this.notifyContextReceived(context, peerId);\n }\n\n /**\n * Handle incoming context request message\n */\n private async handleContextRequest(message: BridgeMessage, peerId: string): Promise<void> {\n const query = message.context!.summary!;\n logger.debug({ peerId, messageId: message.id, query }, 'Received context request');\n\n // If no handler registered, try to forward to another peer\n if (!this.contextRequestedHandler) {\n // Find another peer to forward to (not the sender)\n const otherPeers = Array.from(this.peers.keys()).filter(id => id !== peerId);\n\n if (otherPeers.length > 0) {\n // Forward to the first available peer\n const targetPeerId = otherPeers[0];\n logger.info({ messageId: message.id, targetPeerId }, 'Forwarding context request to another peer');\n\n try {\n // Forward the original message\n await this.sendToPeer(targetPeerId, message);\n\n // Set up response forwarding - store the original sender\n const forwardKey = `ctxfwd:${message.id}`;\n (this as unknown as Record<string, string>)[forwardKey] = peerId;\n\n return;\n } catch (err) {\n logger.error({ error: (err as Error).message, messageId: message.id }, 'Failed to forward context request');\n }\n }\n\n logger.warn({ messageId: message.id }, 'No context request handler registered and no peers to forward to');\n const response = createContextSyncMessage(this.config.instanceName, { files: [] });\n // Change type to response and add request ID for correlation\n const responseMessage: BridgeMessage = {\n ...response,\n type: 'response',\n context: {\n ...response.context,\n variables: { requestId: message.id },\n },\n };\n await this.sendToPeer(peerId, responseMessage).catch((err) => {\n logger.error({ error: (err as Error).message, messageId: message.id }, 'Failed to send empty context response');\n });\n return;\n }\n\n try {\n // Execute the context request handler\n const files = await this.contextRequestedHandler(query, peerId);\n\n // Create and send response\n const response = createContextSyncMessage(this.config.instanceName, { files });\n const responseMessage: BridgeMessage = {\n ...response,\n type: 'response',\n context: {\n ...response.context,\n variables: { requestId: message.id },\n },\n };\n await this.sendToPeer(peerId, responseMessage);\n logger.debug({ messageId: message.id, fileCount: files.length }, 'Context response sent');\n } catch (error) {\n // Send error response with empty files\n const response = createContextSyncMessage(this.config.instanceName, {\n files: [],\n summary: (error as Error).message,\n });\n const responseMessage: BridgeMessage = {\n ...response,\n type: 'response',\n context: {\n ...response.context,\n variables: { requestId: message.id, error: (error as Error).message },\n },\n };\n await this.sendToPeer(peerId, responseMessage).catch((err) => {\n logger.error({ error: (err as Error).message, messageId: message.id }, 'Failed to send error context response');\n });\n logger.error({ messageId: message.id, error: (error as Error).message }, 'Context request handler error');\n }\n }\n\n /**\n * Handle context response message (correlate with pending context request)\n */\n private async handleContextResponse(message: BridgeMessage): Promise<void> {\n const requestId = message.context?.variables?.requestId as string;\n if (!requestId) {\n logger.warn({ messageId: message.id }, 'Context response without requestId');\n return;\n }\n\n // Check if this is a forwarded response that needs to go back to original sender\n const forwardKey = `ctxfwd:${requestId}`;\n const originalSender = (this as unknown as Record<string, string>)[forwardKey];\n if (originalSender) {\n delete (this as unknown as Record<string, string>)[forwardKey];\n logger.info({ requestId, originalSender }, 'Forwarding context response to original sender');\n await this.sendToPeer(originalSender, message).catch((err) => {\n logger.error({ error: (err as Error).message, requestId }, 'Failed to forward context response');\n });\n return;\n }\n\n const pending = this.pendingContextRequests.get(requestId);\n if (!pending) {\n logger.warn({ requestId }, 'Received response for unknown context request');\n return;\n }\n\n // Clear timeout and remove from pending\n clearTimeout(pending.timeoutId);\n this.pendingContextRequests.delete(requestId);\n\n // Check for error\n const error = message.context?.variables?.error as string | undefined;\n if (error) {\n pending.reject(new Error(error));\n return;\n }\n\n // Resolve the promise with the files\n const files = message.context?.files ?? [];\n logger.debug({ requestId, fileCount: files.length }, 'Context response received');\n pending.resolve(files);\n }\n\n // ============================================================================\n // Private Methods - Event Notification\n // ============================================================================\n\n private notifyPeerConnected(peer: PeerInfo): void {\n // Update status file with new peer\n this.writeStatusFile();\n\n for (const handler of this.peerConnectedHandlers) {\n try {\n handler(peer);\n } catch (error) {\n logger.error({ error: (error as Error).message }, 'Peer connected handler error');\n }\n }\n }\n\n private notifyPeerDisconnected(peer: PeerInfo): void {\n // Reject any pending tasks for this peer\n for (const [taskId, pending] of this.pendingTasks) {\n if (pending.peerId === peer.id) {\n clearTimeout(pending.timeoutId);\n this.pendingTasks.delete(taskId);\n pending.reject(new Error(`Peer '${peer.id}' disconnected while task '${taskId}' was pending`));\n }\n }\n\n // Reject any pending context requests for this peer\n for (const [requestId, pending] of this.pendingContextRequests) {\n if (pending.peerId === peer.id) {\n clearTimeout(pending.timeoutId);\n this.pendingContextRequests.delete(requestId);\n pending.reject(new Error(`Peer '${peer.id}' disconnected while context request '${requestId}' was pending`));\n }\n }\n\n for (const handler of this.peerDisconnectedHandlers) {\n try {\n handler(peer);\n } catch (error) {\n logger.error({ error: (error as Error).message }, 'Peer disconnected handler error');\n }\n }\n\n // Update status file after peer removed\n this.writeStatusFile();\n }\n\n private notifyMessageReceived(message: BridgeMessage, peerId: string): void {\n for (const handler of this.messageReceivedHandlers) {\n try {\n handler(message, peerId);\n } catch (error) {\n logger.error({ error: (error as Error).message }, 'Message received handler error');\n }\n }\n }\n\n private notifyContextReceived(context: Context, peerId: string): void {\n for (const handler of this.contextReceivedHandlers) {\n try {\n handler(context, peerId);\n } catch (error) {\n logger.error({ error: (error as Error).message }, 'Context received handler error');\n }\n }\n }\n\n // ============================================================================\n // Private Methods - Cleanup\n // ============================================================================\n\n /**\n * Clean up all resources\n */\n private async cleanup(): Promise<void> {\n logger.debug('Starting cleanup');\n\n // Stop auto-sync\n this.stopAutoSync();\n logger.debug('Auto-sync stopped');\n\n // Reject all pending tasks\n const pendingTaskCount = this.pendingTasks.size;\n for (const [taskId, pending] of this.pendingTasks) {\n clearTimeout(pending.timeoutId);\n pending.reject(new Error('Bridge is shutting down'));\n }\n this.pendingTasks.clear();\n if (pendingTaskCount > 0) {\n logger.debug({ count: pendingTaskCount }, 'Pending tasks cancelled');\n }\n\n // Reject all pending context requests\n const pendingContextCount = this.pendingContextRequests.size;\n for (const [requestId, pending] of this.pendingContextRequests) {\n clearTimeout(pending.timeoutId);\n pending.reject(new Error('Bridge is shutting down'));\n }\n this.pendingContextRequests.clear();\n if (pendingContextCount > 0) {\n logger.debug({ count: pendingContextCount }, 'Pending context requests cancelled');\n }\n\n // Disconnect client transport\n if (this.clientTransport) {\n logger.debug('Disconnecting client transport');\n try {\n await this.clientTransport.disconnect();\n logger.debug('Client transport disconnected');\n } catch {\n // Ignore disconnect errors during cleanup\n }\n this.clientTransport = null;\n }\n\n // Close all peer WebSocket connections\n const peerCount = this.peers.size;\n if (peerCount > 0) {\n logger.debug({ count: peerCount }, 'Closing peer connections');\n }\n for (const [peerId, peer] of this.peers) {\n if (peer.ws) {\n try {\n peer.ws.close(1000, 'Bridge stopping');\n } catch {\n // Ignore close errors during cleanup\n }\n }\n if (peer.transport) {\n try {\n await peer.transport.disconnect();\n } catch {\n // Ignore disconnect errors during cleanup\n }\n }\n logger.debug({ peerId }, 'Peer disconnected');\n }\n this.peers.clear();\n\n // Close server\n if (this.server) {\n logger.debug('Closing WebSocket server');\n await new Promise<void>((resolve) => {\n this.server!.close(() => {\n resolve();\n });\n });\n this.server = null;\n logger.debug('WebSocket server closed');\n }\n\n // Remove status file\n this.removeStatusFile();\n\n logger.debug('Cleanup complete');\n }\n\n // ============================================================================\n // Status File Management\n // ============================================================================\n\n /**\n * Get the status file path\n */\n private getStatusFilePath(): string {\n const bridgeDir = path.join(os.homedir(), '.claude-bridge');\n return path.join(bridgeDir, 'status.json');\n }\n\n /**\n * Ensure the .claude-bridge directory exists\n */\n private ensureBridgeDir(): void {\n const bridgeDir = path.join(os.homedir(), '.claude-bridge');\n if (!fs.existsSync(bridgeDir)) {\n fs.mkdirSync(bridgeDir, { recursive: true });\n }\n }\n\n /**\n * Write current status to status file\n */\n private writeStatusFile(): void {\n try {\n this.ensureBridgeDir();\n const statusFile = this.getStatusFilePath();\n const status = {\n port: this.config.listen?.port,\n instanceName: this.config.instanceName,\n mode: this.config.mode,\n peers: this.getPeers().map(p => ({\n id: p.id,\n name: p.name,\n connectedAt: new Date(p.connectedAt).toISOString(),\n lastActivity: new Date(p.lastActivity).toISOString(),\n })),\n };\n fs.writeFileSync(statusFile, JSON.stringify(status, null, 2), 'utf-8');\n logger.debug({ statusFile }, 'Status file updated');\n } catch (error) {\n logger.error({ error: (error as Error).message }, 'Failed to write status file');\n }\n }\n\n /**\n * Remove the status file\n */\n private removeStatusFile(): void {\n try {\n const statusFile = this.getStatusFilePath();\n if (fs.existsSync(statusFile)) {\n fs.unlinkSync(statusFile);\n logger.debug({ statusFile }, 'Status file removed');\n }\n } catch (error) {\n logger.error({ error: (error as Error).message }, 'Failed to remove status file');\n }\n }\n\n // ============================================================================\n // Getters for State Inspection\n // ============================================================================\n\n /**\n * Check if the bridge is started\n */\n isStarted(): boolean {\n return this.started;\n }\n\n /**\n * Get the instance name\n */\n getInstanceName(): string {\n return this.config.instanceName;\n }\n\n /**\n * Get the operation mode\n */\n getMode(): BridgeMode {\n return this.config.mode;\n }\n\n /**\n * Get the number of connected peers\n */\n getPeerCount(): number {\n return this.peers.size;\n }\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\nimport { parse as parseYaml } from 'yaml';\n\n/**\n * Configuration for the bridge's listening socket\n */\nexport interface ListenConfig {\n port: number;\n host: string;\n}\n\n/**\n * Configuration for connecting to a remote bridge\n */\nexport interface ConnectConfig {\n url?: string;\n hostGateway?: boolean;\n port?: number;\n}\n\n/**\n * Configuration for context sharing behavior\n */\nexport interface ContextSharingConfig {\n autoSync: boolean;\n syncInterval: number;\n maxChunkTokens: number;\n includePatterns: string[];\n excludePatterns: string[];\n}\n\n/**\n * Configuration for interaction behavior\n */\nexport interface InteractionConfig {\n requireConfirmation: boolean;\n notifyOnActivity: boolean;\n taskTimeout: number;\n}\n\n/**\n * Full bridge configuration\n */\nexport interface BridgeConfig {\n instanceName?: string;\n mode?: 'host' | 'client' | 'peer';\n listen: ListenConfig;\n connect?: ConnectConfig;\n contextSharing: ContextSharingConfig;\n interaction: InteractionConfig;\n}\n\n/**\n * Default configuration values\n */\nexport const DEFAULT_CONFIG: BridgeConfig = {\n listen: {\n port: 8765,\n host: '0.0.0.0',\n },\n contextSharing: {\n autoSync: true,\n syncInterval: 5000,\n maxChunkTokens: 4000,\n includePatterns: ['src/**/*.ts', 'src/**/*.tsx', '*.json'],\n excludePatterns: ['node_modules/**', 'dist/**', '.git/**'],\n },\n interaction: {\n requireConfirmation: false,\n notifyOnActivity: true,\n taskTimeout: 300000, // 5 minutes\n },\n};\n\n/**\n * Deep merges a partial config with the default config\n *\n * @param partial - Partial configuration to merge\n * @returns Complete configuration with defaults for missing values\n */\nexport function mergeConfig(partial: Partial<BridgeConfig>): BridgeConfig {\n return {\n ...DEFAULT_CONFIG,\n ...partial,\n listen: {\n ...DEFAULT_CONFIG.listen,\n ...(partial.listen ?? {}),\n },\n connect: partial.connect\n ? {\n ...partial.connect,\n }\n : undefined,\n contextSharing: {\n ...DEFAULT_CONFIG.contextSharing,\n ...(partial.contextSharing ?? {}),\n },\n interaction: {\n ...DEFAULT_CONFIG.interaction,\n ...(partial.interaction ?? {}),\n },\n };\n}\n\n/**\n * Attempts to read and parse a YAML config file\n *\n * @param filePath - Path to the config file\n * @returns Parsed config or null if file doesn't exist\n */\nfunction readConfigFile(filePath: string): Partial<BridgeConfig> | null {\n try {\n if (!fs.existsSync(filePath)) {\n return null;\n }\n const content = fs.readFileSync(filePath, 'utf-8');\n const parsed = parseYaml(content);\n return parsed as Partial<BridgeConfig>;\n } catch {\n // Return null if file can't be read or parsed\n return null;\n }\n}\n\n/**\n * Gets the default config file paths to search\n *\n * @returns Array of config file paths in priority order\n */\nfunction getDefaultConfigPaths(): string[] {\n const homeDir = os.homedir();\n const cwd = process.cwd();\n\n return [\n // Project-local config takes priority\n path.join(cwd, '.claude-bridge.yml'),\n path.join(cwd, '.claude-bridge.yaml'),\n // User home config as fallback\n path.join(homeDir, '.claude-bridge', 'config.yml'),\n path.join(homeDir, '.claude-bridge', 'config.yaml'),\n ];\n}\n\n/**\n * Loads configuration from file(s) and merges with defaults\n *\n * Searches for config files in the following order:\n * 1. Explicit path (if provided)\n * 2. .claude-bridge.yml in current working directory\n * 3. ~/.claude-bridge/config.yml\n *\n * @param configPath - Optional explicit path to config file\n * @returns Complete configuration with defaults for missing values\n *\n * @example\n * ```typescript\n * // Load from default locations\n * const config = await loadConfig();\n *\n * // Load from specific path\n * const config = await loadConfig('/path/to/config.yml');\n * ```\n */\nexport async function loadConfig(configPath?: string): Promise<BridgeConfig> {\n // If explicit path provided, try to load it\n if (configPath) {\n const parsed = readConfigFile(configPath);\n if (parsed) {\n return mergeConfig(parsed);\n }\n // If explicit path doesn't exist, return defaults\n return { ...DEFAULT_CONFIG };\n }\n\n // Search default paths\n const searchPaths = getDefaultConfigPaths();\n\n for (const searchPath of searchPaths) {\n const parsed = readConfigFile(searchPath);\n if (parsed) {\n return mergeConfig(parsed);\n }\n }\n\n // No config file found, return defaults\n return { ...DEFAULT_CONFIG };\n}\n\n/**\n * Synchronous version of loadConfig for simpler usage patterns\n *\n * @param configPath - Optional explicit path to config file\n * @returns Complete configuration with defaults for missing values\n */\nexport function loadConfigSync(configPath?: string): BridgeConfig {\n // If explicit path provided, try to load it\n if (configPath) {\n const parsed = readConfigFile(configPath);\n if (parsed) {\n return mergeConfig(parsed);\n }\n // If explicit path doesn't exist, return defaults\n return { ...DEFAULT_CONFIG };\n }\n\n // Search default paths\n const searchPaths = getDefaultConfigPaths();\n\n for (const searchPath of searchPaths) {\n const parsed = readConfigFile(searchPath);\n if (parsed) {\n return mergeConfig(parsed);\n }\n }\n\n // No config file found, return defaults\n return { ...DEFAULT_CONFIG };\n}\n"],"mappings":"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","names":["ConnectionState","uuidv4","logger","uuidv4","peer","fs","path","os"]}
|
package/dist/cli.d.ts
CHANGED
|
@@ -9,8 +9,7 @@ import { Command } from 'commander';
|
|
|
9
9
|
* stop Stop the running bridge
|
|
10
10
|
* status Show bridge status and connected peers
|
|
11
11
|
* connect Connect to a remote bridge
|
|
12
|
-
*
|
|
13
|
-
* info Show environment and configuration info
|
|
12
|
+
* info Show system and configuration info
|
|
14
13
|
*
|
|
15
14
|
* Global options:
|
|
16
15
|
* --verbose, -v Enable verbose logging
|
package/dist/cli.js
CHANGED
|
@@ -4,18 +4,11 @@ import {
|
|
|
4
4
|
ConnectionState,
|
|
5
5
|
WebSocketTransport,
|
|
6
6
|
createLogger,
|
|
7
|
-
detectEnvironment,
|
|
8
|
-
discoverDdevProjects,
|
|
9
|
-
discoverDockerPeers,
|
|
10
|
-
discoverDocksalProjects,
|
|
11
|
-
discoverLandoProjects,
|
|
12
|
-
getDefaultConfig,
|
|
13
|
-
getHostGateway,
|
|
14
7
|
loadConfigSync
|
|
15
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-LUL3SX2F.js";
|
|
16
9
|
|
|
17
10
|
// src/cli/index.ts
|
|
18
|
-
import { Command as
|
|
11
|
+
import { Command as Command6 } from "commander";
|
|
19
12
|
|
|
20
13
|
// src/cli/commands/start.ts
|
|
21
14
|
import { Command } from "commander";
|
|
@@ -79,10 +72,10 @@ Received ${signal}, shutting down gracefully...`);
|
|
|
79
72
|
};
|
|
80
73
|
}
|
|
81
74
|
function handleUnhandledRejections(options = {}) {
|
|
82
|
-
const { exit = false, logger:
|
|
75
|
+
const { exit = false, logger: logger7 = console.error } = options;
|
|
83
76
|
process.on("unhandledRejection", (reason, promise) => {
|
|
84
77
|
const error = reason instanceof Error ? reason : new Error(String(reason));
|
|
85
|
-
|
|
78
|
+
logger7("Unhandled promise rejection:", error);
|
|
86
79
|
if (exit) {
|
|
87
80
|
process.exit(1);
|
|
88
81
|
}
|
|
@@ -366,18 +359,6 @@ function registerHandlers(bridge, config) {
|
|
|
366
359
|
}
|
|
367
360
|
function buildBridgeConfig(options, globalOptions) {
|
|
368
361
|
const fileConfig = loadConfigSync(globalOptions.config);
|
|
369
|
-
let envConfig = {};
|
|
370
|
-
if (options.auto) {
|
|
371
|
-
const env = detectEnvironment();
|
|
372
|
-
const defaultEnvConfig = getDefaultConfig(env);
|
|
373
|
-
logger.info({ environment: env.type, isContainer: env.isContainer }, "Auto-detected environment");
|
|
374
|
-
envConfig = {
|
|
375
|
-
mode: defaultEnvConfig.mode,
|
|
376
|
-
instanceName: defaultEnvConfig.instanceName,
|
|
377
|
-
listen: defaultEnvConfig.listen,
|
|
378
|
-
connect: defaultEnvConfig.connect
|
|
379
|
-
};
|
|
380
|
-
}
|
|
381
362
|
const cliConfig = {};
|
|
382
363
|
if (options.port) {
|
|
383
364
|
cliConfig.listen = {
|
|
@@ -398,19 +379,19 @@ function buildBridgeConfig(options, globalOptions) {
|
|
|
398
379
|
};
|
|
399
380
|
}
|
|
400
381
|
let mode = "peer";
|
|
401
|
-
const hasListen = cliConfig.listen ||
|
|
402
|
-
const hasConnect = cliConfig.connect ||
|
|
382
|
+
const hasListen = cliConfig.listen || fileConfig.listen;
|
|
383
|
+
const hasConnect = cliConfig.connect || fileConfig.connect;
|
|
403
384
|
if (hasListen && !hasConnect) {
|
|
404
385
|
mode = "host";
|
|
405
386
|
} else if (hasConnect && !hasListen) {
|
|
406
387
|
mode = "client";
|
|
407
388
|
}
|
|
408
389
|
const finalConfig = {
|
|
409
|
-
mode: cliConfig.mode ??
|
|
410
|
-
instanceName: cliConfig.instanceName ??
|
|
390
|
+
mode: cliConfig.mode ?? fileConfig.mode ?? mode,
|
|
391
|
+
instanceName: cliConfig.instanceName ?? fileConfig.instanceName ?? `bridge-${process.pid}`,
|
|
411
392
|
listen: {
|
|
412
|
-
port: cliConfig.listen?.port ??
|
|
413
|
-
host: cliConfig.listen?.host ??
|
|
393
|
+
port: cliConfig.listen?.port ?? fileConfig.listen.port,
|
|
394
|
+
host: cliConfig.listen?.host ?? fileConfig.listen.host
|
|
414
395
|
},
|
|
415
396
|
taskTimeout: fileConfig.interaction.taskTimeout,
|
|
416
397
|
contextSharing: {
|
|
@@ -418,7 +399,7 @@ function buildBridgeConfig(options, globalOptions) {
|
|
|
418
399
|
syncInterval: fileConfig.contextSharing.syncInterval
|
|
419
400
|
}
|
|
420
401
|
};
|
|
421
|
-
const connectUrl = cliConfig.connect?.url ??
|
|
402
|
+
const connectUrl = cliConfig.connect?.url ?? fileConfig.connect?.url;
|
|
422
403
|
if (connectUrl) {
|
|
423
404
|
finalConfig.connect = {
|
|
424
405
|
url: connectUrl
|
|
@@ -494,7 +475,7 @@ To connect from another bridge:`);
|
|
|
494
475
|
}
|
|
495
476
|
function createStartCommand() {
|
|
496
477
|
const command = new Command("start");
|
|
497
|
-
command.description("Start the bridge server").option("-p, --port <port>", "Port to listen on (default: 8765
|
|
478
|
+
command.description("Start the bridge server").option("-p, --port <port>", "Port to listen on (default: 8765)").option("-h, --host <host>", "Host to bind to (default: 0.0.0.0)").option("-c, --connect <url>", "URL to connect to on startup (e.g., ws://localhost:8765)").option("-d, --daemon", "Run in background").option("--with-handlers", "Enable file reading and task handling capabilities").action(async (options) => {
|
|
498
479
|
const globalOptions = command.parent?.opts();
|
|
499
480
|
await startBridge(options, globalOptions);
|
|
500
481
|
});
|
|
@@ -841,76 +822,12 @@ function createConnectCommand() {
|
|
|
841
822
|
return command;
|
|
842
823
|
}
|
|
843
824
|
|
|
844
|
-
// src/cli/commands/discover.ts
|
|
845
|
-
import { Command as Command5 } from "commander";
|
|
846
|
-
var logger5 = createLogger("cli:discover");
|
|
847
|
-
function printPeersTable(peers) {
|
|
848
|
-
if (peers.length === 0) {
|
|
849
|
-
console.log("No bridges found.");
|
|
850
|
-
console.log("");
|
|
851
|
-
console.log("Suggestions:");
|
|
852
|
-
console.log(" - Start a bridge: claude-bridge start");
|
|
853
|
-
console.log(" - Add bridge labels to Docker containers");
|
|
854
|
-
console.log(" - Install bridge addon in your Docksal/DDEV project");
|
|
855
|
-
return;
|
|
856
|
-
}
|
|
857
|
-
const cols = {
|
|
858
|
-
name: { title: "Name", width: 25 },
|
|
859
|
-
source: { title: "Source", width: 12 },
|
|
860
|
-
url: { title: "URL", width: 35 },
|
|
861
|
-
status: { title: "Status", width: 12 }
|
|
862
|
-
};
|
|
863
|
-
console.log(
|
|
864
|
-
cols.name.title.padEnd(cols.name.width) + cols.source.title.padEnd(cols.source.width) + cols.url.title.padEnd(cols.url.width) + cols.status.title.padEnd(cols.status.width)
|
|
865
|
-
);
|
|
866
|
-
console.log(
|
|
867
|
-
"-".repeat(cols.name.width - 1) + " " + "-".repeat(cols.source.width - 1) + " " + "-".repeat(cols.url.width - 1) + " " + "-".repeat(cols.status.width - 1)
|
|
868
|
-
);
|
|
869
|
-
for (const peer of peers) {
|
|
870
|
-
const row = peer.name.slice(0, cols.name.width - 1).padEnd(cols.name.width) + peer.source.padEnd(cols.source.width) + peer.url.slice(0, cols.url.width - 1).padEnd(cols.url.width) + (peer.status || "unknown").padEnd(cols.status.width);
|
|
871
|
-
console.log(row);
|
|
872
|
-
}
|
|
873
|
-
console.log("");
|
|
874
|
-
console.log("To connect to a bridge:");
|
|
875
|
-
console.log(" claude-bridge connect <url>");
|
|
876
|
-
}
|
|
877
|
-
async function discoverBridges() {
|
|
878
|
-
console.log("Discovering bridges on local network...\n");
|
|
879
|
-
const allPeers = [];
|
|
880
|
-
const dockerPeers = discoverDockerPeers();
|
|
881
|
-
allPeers.push(...dockerPeers);
|
|
882
|
-
logger5.debug({ count: dockerPeers.length }, "Docker peers discovered");
|
|
883
|
-
const docksalPeers = discoverDocksalProjects();
|
|
884
|
-
allPeers.push(...docksalPeers);
|
|
885
|
-
logger5.debug({ count: docksalPeers.length }, "Docksal peers discovered");
|
|
886
|
-
const ddevPeers = discoverDdevProjects();
|
|
887
|
-
allPeers.push(...ddevPeers);
|
|
888
|
-
logger5.debug({ count: ddevPeers.length }, "DDEV peers discovered");
|
|
889
|
-
const landoPeers = discoverLandoProjects();
|
|
890
|
-
allPeers.push(...landoPeers);
|
|
891
|
-
logger5.debug({ count: landoPeers.length }, "Lando peers discovered");
|
|
892
|
-
printPeersTable(allPeers);
|
|
893
|
-
}
|
|
894
|
-
function createDiscoverCommand() {
|
|
895
|
-
const command = new Command5("discover");
|
|
896
|
-
command.description("Discover bridges on local network").action(async () => {
|
|
897
|
-
try {
|
|
898
|
-
await discoverBridges();
|
|
899
|
-
} catch (error) {
|
|
900
|
-
logger5.error({ error: error.message }, "Discover command failed");
|
|
901
|
-
console.error(`Error: ${error.message}`);
|
|
902
|
-
process.exit(1);
|
|
903
|
-
}
|
|
904
|
-
});
|
|
905
|
-
return command;
|
|
906
|
-
}
|
|
907
|
-
|
|
908
825
|
// src/cli/commands/info.ts
|
|
909
|
-
import { Command as
|
|
826
|
+
import { Command as Command5 } from "commander";
|
|
910
827
|
import * as fs4 from "fs";
|
|
911
828
|
import * as path4 from "path";
|
|
912
829
|
import * as os4 from "os";
|
|
913
|
-
var
|
|
830
|
+
var logger5 = createLogger("cli:info");
|
|
914
831
|
function getConfigFilePath() {
|
|
915
832
|
const localConfig = path4.join(process.cwd(), ".claude-bridge.yml");
|
|
916
833
|
if (fs4.existsSync(localConfig)) {
|
|
@@ -944,30 +861,25 @@ function printKeyValue(key, value, indent = 0) {
|
|
|
944
861
|
console.log(`${prefix}${key}: ${formatValue(value)}`);
|
|
945
862
|
}
|
|
946
863
|
function showInfo(globalOptions) {
|
|
947
|
-
console.log("Claude Code Bridge -
|
|
948
|
-
console.log("=".repeat(
|
|
949
|
-
printSection("
|
|
950
|
-
|
|
951
|
-
printKeyValue("
|
|
952
|
-
printKeyValue("Platform",
|
|
953
|
-
printKeyValue("
|
|
954
|
-
printKeyValue("
|
|
955
|
-
printKeyValue("
|
|
864
|
+
console.log("Claude Code Bridge - System Information");
|
|
865
|
+
console.log("=".repeat(40));
|
|
866
|
+
printSection("System");
|
|
867
|
+
printKeyValue("Node Version", process.version);
|
|
868
|
+
printKeyValue("OS", `${os4.type()} ${os4.release()}`);
|
|
869
|
+
printKeyValue("Platform", process.platform);
|
|
870
|
+
printKeyValue("Arch", os4.arch());
|
|
871
|
+
printKeyValue("Home Directory", os4.homedir());
|
|
872
|
+
printKeyValue("Working Directory", process.cwd());
|
|
956
873
|
printSection("Network");
|
|
957
|
-
const
|
|
958
|
-
const
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
console.log(" Note: To connect from host machine:");
|
|
967
|
-
console.log(` ws://localhost:${listenPort}`);
|
|
968
|
-
console.log("");
|
|
969
|
-
console.log(" To connect to host from this container:");
|
|
970
|
-
console.log(` ws://${hostGateway}:8766`);
|
|
874
|
+
const interfaces = os4.networkInterfaces();
|
|
875
|
+
for (const [name, addrs] of Object.entries(interfaces)) {
|
|
876
|
+
if (addrs) {
|
|
877
|
+
for (const addr of addrs) {
|
|
878
|
+
if (addr.family === "IPv4" && !addr.internal) {
|
|
879
|
+
printKeyValue(name, addr.address);
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
}
|
|
971
883
|
}
|
|
972
884
|
printSection("Configuration");
|
|
973
885
|
const configPath = globalOptions.config || getConfigFilePath();
|
|
@@ -1006,43 +918,16 @@ function showInfo(globalOptions) {
|
|
|
1006
918
|
printKeyValue("Require Confirmation", config.interaction.requireConfirmation, 2);
|
|
1007
919
|
printKeyValue("Notify On Activity", config.interaction.notifyOnActivity, 2);
|
|
1008
920
|
printKeyValue("Task Timeout", `${config.interaction.taskTimeout}ms`, 2);
|
|
1009
|
-
printSection("System");
|
|
1010
|
-
printKeyValue("Node Version", process.version);
|
|
1011
|
-
printKeyValue("OS", `${os4.type()} ${os4.release()}`);
|
|
1012
|
-
printKeyValue("Arch", os4.arch());
|
|
1013
|
-
printKeyValue("Home Directory", os4.homedir());
|
|
1014
|
-
printKeyValue("Working Directory", process.cwd());
|
|
1015
|
-
printSection("Environment Variables");
|
|
1016
|
-
const relevantEnvVars = [
|
|
1017
|
-
"DOCKSAL_STACK",
|
|
1018
|
-
"DOCKSAL_PROJECT",
|
|
1019
|
-
"IS_DDEV_PROJECT",
|
|
1020
|
-
"DDEV_PROJECT",
|
|
1021
|
-
"LANDO",
|
|
1022
|
-
"LANDO_APP_NAME",
|
|
1023
|
-
"LOG_LEVEL"
|
|
1024
|
-
];
|
|
1025
|
-
let hasEnvVars = false;
|
|
1026
|
-
for (const varName of relevantEnvVars) {
|
|
1027
|
-
const value = process.env[varName];
|
|
1028
|
-
if (value !== void 0) {
|
|
1029
|
-
printKeyValue(varName, value);
|
|
1030
|
-
hasEnvVars = true;
|
|
1031
|
-
}
|
|
1032
|
-
}
|
|
1033
|
-
if (!hasEnvVars) {
|
|
1034
|
-
console.log(" (no relevant environment variables set)");
|
|
1035
|
-
}
|
|
1036
921
|
console.log("");
|
|
1037
922
|
}
|
|
1038
923
|
function createInfoCommand() {
|
|
1039
|
-
const command = new
|
|
1040
|
-
command.description("Show
|
|
924
|
+
const command = new Command5("info");
|
|
925
|
+
command.description("Show system and configuration info").action(() => {
|
|
1041
926
|
try {
|
|
1042
927
|
const globalOptions = command.parent?.opts() ?? {};
|
|
1043
928
|
showInfo(globalOptions);
|
|
1044
929
|
} catch (error) {
|
|
1045
|
-
|
|
930
|
+
logger5.error({ error: error.message }, "Info command failed");
|
|
1046
931
|
console.error(`Error: ${error.message}`);
|
|
1047
932
|
process.exit(1);
|
|
1048
933
|
}
|
|
@@ -1052,9 +937,9 @@ function createInfoCommand() {
|
|
|
1052
937
|
|
|
1053
938
|
// src/cli/index.ts
|
|
1054
939
|
var VERSION = "0.1.0";
|
|
1055
|
-
var
|
|
940
|
+
var logger6 = createLogger("cli");
|
|
1056
941
|
function createProgram() {
|
|
1057
|
-
const program = new
|
|
942
|
+
const program = new Command6();
|
|
1058
943
|
program.name("claude-bridge").description("Bidirectional communication system for Claude Code instances across environments").version(VERSION, "-V, --version", "Output the version number").option("-v, --verbose", "Enable verbose logging").option("--config <path>", "Path to config file");
|
|
1059
944
|
program.hook("preAction", (thisCommand) => {
|
|
1060
945
|
const opts = thisCommand.opts();
|
|
@@ -1073,12 +958,11 @@ async function main() {
|
|
|
1073
958
|
program.addCommand(createStopCommand());
|
|
1074
959
|
program.addCommand(createStatusCommand());
|
|
1075
960
|
program.addCommand(createConnectCommand());
|
|
1076
|
-
program.addCommand(createDiscoverCommand());
|
|
1077
961
|
program.addCommand(createInfoCommand());
|
|
1078
962
|
await program.parseAsync(process.argv);
|
|
1079
963
|
}
|
|
1080
964
|
main().catch((error) => {
|
|
1081
|
-
|
|
965
|
+
logger6.error({ err: error }, "CLI error");
|
|
1082
966
|
process.exit(1);
|
|
1083
967
|
});
|
|
1084
968
|
export {
|