@tongil_kim/clautunnel 1.7.2 → 1.7.3

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/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../packages/shared/dist/types/message.js","../../../packages/shared/dist/types/session.js","../../../packages/shared/dist/types/machine.js","../../../packages/shared/dist/types/presence.js","../../../packages/shared/src/types/index.ts","../../../packages/shared/src/constants/events.ts","../../../packages/shared/src/constants/message-types.ts","../../../packages/shared/src/constants/index.ts","../../../packages/shared/src/utils/permission-mode.ts","../../../packages/shared/src/utils/index.ts","../../../packages/shared/src/index.ts","../src/index.ts","../src/utils/config.ts","../src/utils/logger.ts","../src/realtime/client.ts","../src/realtime/utils.ts","../src/daemon/session.ts","../src/daemon/machine.ts","../src/daemon/daemon.ts","../src/daemon/sdk-session.ts","../src/daemon/config-manager.ts","../src/commands/start.ts","../src/realtime/machine-client.ts","../src/utils/spinner.ts","../src/utils/supabase.ts","../src/utils/sleep-prevention.ts","../src/mobile/mobile-server.ts","../src/utils/pid.ts","../src/utils/claude-auth.ts","../src/commands/stop.ts","../src/commands/status.ts","../src/commands/login.ts","../src/utils/prompt.ts","../src/commands/logout.ts","../src/commands/signup.ts","../src/commands/setup.ts","../src/commands/mobile-setup.ts","../src/commands/reset.ts"],"sourcesContent":["\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\n//# sourceMappingURL=message.js.map","\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\n//# sourceMappingURL=session.js.map","\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\n//# sourceMappingURL=machine.js.map","\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\n//# sourceMappingURL=presence.js.map","export * from './message.js';\nexport * from './session.js';\nexport * from './machine.js';\nexport * from './presence.js';\n","export const REALTIME_CHANNELS = {\n sessionOutput: (sessionId: string) => `session:${sessionId}:output`,\n sessionInput: (sessionId: string) => `session:${sessionId}:input`,\n sessionPresence: (sessionId: string) => `session:${sessionId}:presence`,\n machinePresence: (machineId: string) => `machine:${machineId}:presence`,\n machineInput: (machineId: string) => `machine:${machineId}:input`,\n machineOutput: (machineId: string) => `machine:${machineId}:output`,\n} as const;\n","// Source of truth for message types.\n// TypeScript types are derived from these arrays via (typeof X)[number].\n// Tests import these arrays directly — no manual duplication needed.\n\nexport const REALTIME_MESSAGE_TYPES = [\n 'output',\n 'input',\n 'error',\n 'system',\n 'mode',\n 'mode-change',\n 'commands',\n 'commands-request',\n 'model',\n 'model-change',\n 'models',\n 'models-request',\n 'mobile-disconnect',\n 'interactive-request',\n 'interactive-response',\n 'interactive-apply',\n 'interactive-confirm',\n 'cancel-request',\n 'clear-request',\n 'resume-request',\n 'resume-history',\n 'user-question',\n 'user-answer',\n 'permission-request',\n 'permission-response',\n 'request-queued',\n 'status-request',\n 'status-response',\n 'session-title',\n 'tool-use',\n 'complete',\n] as const;\n\nexport const MESSAGE_TYPES = [\n 'output',\n 'input',\n 'error',\n 'system',\n 'tool-use',\n] as const;\n","export * from './events.js';\nexport * from './message-types.js';\n","import type { PermissionMode } from '../types/message.js';\n\nconst VALID_PERMISSION_MODES: PermissionMode[] = [\n 'default',\n 'acceptEdits',\n 'plan',\n 'bypassPermissions',\n 'delegate',\n 'dontAsk',\n];\n\nexport function isPermissionMode(value: unknown): value is PermissionMode {\n return typeof value === 'string' && VALID_PERMISSION_MODES.includes(value as PermissionMode);\n}\n","export * from './permission-mode.js';\n","// Types\nexport * from './types/index.js';\n\n// Constants\nexport * from './constants/index.js';\n\n// Runtime utilities\nexport * from './utils/index.js';\n","#!/usr/bin/env node\n\nimport { config } from 'dotenv';\nimport { resolve, dirname } from 'path';\nimport { readFileSync } from 'fs';\nimport { fileURLToPath } from 'url';\n\n// ESM equivalent of __dirname\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n// Load .env from CLI package root (quiet mode to suppress dotenvx tips)\nconfig({ path: resolve(__dirname, '../.env'), quiet: true });\n\n// Read version from package.json\nconst packageJson = JSON.parse(\n readFileSync(resolve(__dirname, '../package.json'), 'utf-8')\n);\nconst version = packageJson.version || '0.0.0';\n\n// Library exports\nexport { Config, getConfig } from './utils/config.js';\nexport { Logger, getLogger } from './utils/logger.js';\nexport { RealtimeClient } from './realtime/client.js';\nexport { SessionManager } from './daemon/session.js';\nexport { MachineManager } from './daemon/machine.js';\nexport { Daemon } from './daemon/daemon.js';\n\n// CLI entry point\nimport { Command } from 'commander';\nimport { createStartCommand } from './commands/start.js';\nimport { createStopCommand } from './commands/stop.js';\nimport { createStatusCommand } from './commands/status.js';\nimport { createLoginCommand } from './commands/login.js';\nimport { createLogoutCommand } from './commands/logout.js';\nimport { createSignupCommand } from './commands/signup.js';\nimport { createSetupCommand } from './commands/setup.js';\nimport { createMobileSetupCommand } from './commands/mobile-setup.js';\nimport { createResetCommand } from './commands/reset.js';\n\nconst program = new Command();\n\nprogram\n .name('clautunnel')\n .description('Remote control for Claude Code CLI')\n .version(version);\n\nprogram.addCommand(createSetupCommand());\nprogram.addCommand(createStartCommand());\nprogram.addCommand(createStopCommand());\nprogram.addCommand(createStatusCommand());\nprogram.addCommand(createLoginCommand());\nprogram.addCommand(createLogoutCommand());\nprogram.addCommand(createSignupCommand());\nprogram.addCommand(createMobileSetupCommand());\nprogram.addCommand(createResetCommand());\n\n// Only parse when run directly (not when imported as library)\nif (process.argv[1]?.includes('clautunnel') || process.argv[1]?.endsWith('/index.js') || process.argv[1]?.endsWith('/index.ts')) {\n program.parse();\n}\n","import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'fs';\nimport { join } from 'path';\nimport { homedir } from 'os';\n\nexport class ConfigurationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ConfigurationError';\n }\n}\n\ninterface ConfigData {\n machineId?: string;\n sessionTokens?: {\n accessToken: string;\n refreshToken: string;\n };\n supabaseUrl?: string;\n supabaseAnonKey?: string;\n mobileProjectPath?: string;\n}\n\nexport class Config {\n private configDir: string;\n private configFile: string;\n private data: ConfigData;\n\n constructor(configDir?: string) {\n this.configDir = configDir ?? join(homedir(), '.clautunnel');\n this.configFile = join(this.configDir, 'config.json');\n if (!configDir) {\n this.migrateFromLegacy();\n }\n this.data = this.loadConfig();\n }\n\n private migrateFromLegacy(): void {\n const legacyDir = join(homedir(), '.termbridge');\n if (existsSync(legacyDir) && !existsSync(this.configDir)) {\n renameSync(legacyDir, this.configDir);\n console.log(`Migrated config from ~/.termbridge to ~/.clautunnel`);\n }\n }\n\n private loadConfig(): ConfigData {\n if (existsSync(this.configFile)) {\n try {\n return JSON.parse(readFileSync(this.configFile, 'utf-8'));\n } catch {\n return {};\n }\n }\n return {};\n }\n\n private saveConfig(): void {\n if (!existsSync(this.configDir)) {\n mkdirSync(this.configDir, { recursive: true });\n }\n writeFileSync(this.configFile, JSON.stringify(this.data, null, 2));\n }\n\n getSupabaseUrl(): string {\n // Prefer env var over config file\n const url = process.env['SUPABASE_URL'] || this.data.supabaseUrl;\n if (!url) {\n throw new Error('SUPABASE_URL environment variable is not set');\n }\n\n // Validate URL format\n try {\n new URL(url);\n } catch {\n throw new Error('SUPABASE_URL must be a valid URL');\n }\n\n return url;\n }\n\n getSupabaseAnonKey(): string {\n // Prefer env var over config file\n const key = process.env['SUPABASE_ANON_KEY'] || this.data.supabaseAnonKey;\n if (!key) {\n throw new Error('SUPABASE_ANON_KEY environment variable is not set');\n }\n return key;\n }\n\n setSupabaseCredentials(credentials: { url: string; anonKey: string }): void {\n this.data.supabaseUrl = credentials.url;\n this.data.supabaseAnonKey = credentials.anonKey;\n this.saveConfig();\n }\n\n isConfigured(): boolean {\n const hasEnvVars = !!(process.env['SUPABASE_URL'] && process.env['SUPABASE_ANON_KEY']);\n const hasConfigFile = !!(this.data.supabaseUrl && this.data.supabaseAnonKey);\n return hasEnvVars || hasConfigFile;\n }\n\n requireConfiguration(): void {\n if (!this.isConfigured()) {\n throw new ConfigurationError(\n 'ClauTunnel is not configured.\\n\\n' +\n 'Run \"clautunnel setup\" to configure your Supabase credentials.\\n\\n' +\n 'Or set environment variables in your shell profile (~/.zshrc or ~/.bashrc):\\n' +\n ' export SUPABASE_URL=https://<project-id>.supabase.co\\n' +\n ' export SUPABASE_ANON_KEY=<your-anon-key>'\n );\n }\n }\n\n getMachineId(): string | undefined {\n return this.data.machineId;\n }\n\n setMachineId(machineId: string): void {\n this.data.machineId = machineId;\n this.saveConfig();\n }\n\n clearMachineId(): void {\n delete this.data.machineId;\n this.saveConfig();\n }\n\n getSessionTokens(): ConfigData['sessionTokens'] | undefined {\n return this.data.sessionTokens;\n }\n\n setSessionTokens(tokens: ConfigData['sessionTokens']): void {\n this.data.sessionTokens = tokens;\n this.saveConfig();\n }\n\n // Alias for setSessionTokens\n setSession(tokens: { accessToken: string; refreshToken: string }): void {\n this.setSessionTokens(tokens);\n }\n\n clearSessionTokens(): void {\n delete this.data.sessionTokens;\n this.saveConfig();\n }\n\n getMobileProjectPath(): string | undefined {\n return this.data.mobileProjectPath;\n }\n\n setMobileProjectPath(path: string): void {\n this.data.mobileProjectPath = path;\n this.saveConfig();\n }\n}\n\n// Default singleton instance\nlet defaultConfig: Config | null = null;\n\nexport function getConfig(): Config {\n if (!defaultConfig) {\n defaultConfig = new Config();\n }\n return defaultConfig;\n}\n","type LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\nexport class Logger {\n private silent: boolean;\n private debugEnabled: boolean;\n\n constructor() {\n this.silent = process.env['SILENT'] === 'true';\n this.debugEnabled = process.env['DEBUG'] === 'true';\n }\n\n private formatTimestamp(): string {\n const now = new Date();\n return now.toTimeString().split(' ')[0] ?? now.toISOString();\n }\n\n private formatMessage(level: LogLevel, message: string, data?: object): string {\n const timestamp = this.formatTimestamp();\n const levelStr = level.toUpperCase().padEnd(5);\n let formatted = `[${timestamp}] [${levelStr}] ${message}`;\n\n if (data) {\n formatted += ` ${JSON.stringify(data)}`;\n }\n\n return formatted;\n }\n\n debug(message: string, data?: object): void {\n if (this.silent || !this.debugEnabled) return;\n console.log(this.formatMessage('debug', message, data));\n }\n\n info(message: string, data?: object): void {\n if (this.silent) return;\n console.log(this.formatMessage('info', message, data));\n }\n\n warn(message: string, data?: object): void {\n if (this.silent) return;\n console.warn(this.formatMessage('warn', message, data));\n }\n\n error(message: string, data?: object): void {\n if (this.silent) return;\n console.error(this.formatMessage('error', message, data));\n }\n}\n\n// Default singleton instance\nlet defaultLogger: Logger | null = null;\n\nexport function getLogger(): Logger {\n if (!defaultLogger) {\n defaultLogger = new Logger();\n }\n return defaultLogger;\n}\n","import { EventEmitter } from 'events';\nimport type { SupabaseClient, RealtimeChannel } from '@supabase/supabase-js';\nimport type {\n RealtimeMessage,\n ModelInfo,\n PermissionMode,\n SlashCommand,\n InteractiveCommandData,\n InteractiveCommandType,\n InteractiveResult,\n PresencePayload,\n UserQuestionData,\n PermissionRequestData,\n ToolUseData,\n} from 'clautunnel-shared';\nimport { REALTIME_CHANNELS } from 'clautunnel-shared';\nimport { subscribeWithTimeout } from './utils.js';\n\nexport interface RealtimeClientOptions {\n supabase: SupabaseClient;\n sessionId: string;\n}\n\nexport class RealtimeClient extends EventEmitter {\n private supabase: SupabaseClient;\n private sessionId: string;\n private outputChannel: RealtimeChannel | null = null;\n private inputChannel: RealtimeChannel | null = null;\n private presenceChannel: RealtimeChannel | null = null;\n private seq: number = 0;\n private realtimeEnabled: boolean = false;\n\n constructor(options: RealtimeClientOptions) {\n super();\n this.supabase = options.supabase;\n this.sessionId = options.sessionId;\n }\n\n async connect(): Promise<void> {\n const privateConfig = { config: { private: true } };\n\n // Subscribe to output channel (CLI broadcasts to mobile)\n const outputChannelName = REALTIME_CHANNELS.sessionOutput(this.sessionId);\n this.outputChannel = this.supabase.channel(outputChannelName, privateConfig);\n\n // Subscribe to input channel (mobile sends to CLI)\n const inputChannelName = REALTIME_CHANNELS.sessionInput(this.sessionId);\n this.inputChannel = this.supabase.channel(inputChannelName, privateConfig);\n\n this.inputChannel.on('broadcast', { event: 'input' }, (payload) => {\n this.emit('input', payload.payload as RealtimeMessage);\n });\n\n const results = await Promise.all([\n subscribeWithTimeout(this.outputChannel, 'output'),\n subscribeWithTimeout(this.inputChannel, 'input'),\n ]);\n\n // Only enable realtime if both channels subscribed successfully\n this.realtimeEnabled = results.every((success) => success);\n\n // Set up presence channel to track CLI online status\n if (this.realtimeEnabled) {\n const presenceChannelName = REALTIME_CHANNELS.sessionPresence(this.sessionId);\n this.presenceChannel = this.supabase.channel(presenceChannelName, privateConfig);\n\n // Subscribe and track presence - re-track on every SUBSCRIBED (handles reconnection)\n this.presenceChannel.subscribe(async (status, err) => {\n if (status === 'SUBSCRIBED' && this.presenceChannel) {\n try {\n const payload: PresencePayload = {\n type: 'cli',\n online_at: new Date().toISOString(),\n };\n await this.presenceChannel.track(payload);\n } catch (trackError) {\n // Presence tracking is non-critical - log and continue\n console.warn('[WARN] Failed to track presence:', trackError);\n }\n } else if (status === 'CHANNEL_ERROR') {\n // Presence is non-critical - log and continue\n console.warn('[WARN] Presence channel error:', err?.message || 'Unknown error');\n }\n });\n }\n\n this.emit('connected');\n }\n\n async disconnect(): Promise<void> {\n // Untrack presence before disconnecting\n if (this.presenceChannel) {\n await this.presenceChannel.untrack();\n await this.supabase.removeChannel(this.presenceChannel);\n this.presenceChannel = null;\n }\n\n if (this.outputChannel) {\n await this.supabase.removeChannel(this.outputChannel);\n this.outputChannel = null;\n }\n\n if (this.inputChannel) {\n await this.supabase.removeChannel(this.inputChannel);\n this.inputChannel = null;\n }\n\n this.emit('disconnected');\n }\n\n async broadcast(content: string): Promise<void> {\n if (!this.outputChannel) {\n throw new Error('Not connected');\n }\n\n const message: RealtimeMessage = {\n type: 'output',\n content,\n timestamp: Date.now(),\n seq: ++this.seq,\n };\n\n // Persist message to database for history\n try {\n const { error } = await this.supabase.from('messages').insert({\n session_id: this.sessionId,\n type: message.type,\n content: message.content,\n seq: message.seq,\n });\n if (error) {\n console.warn('[WARN] Failed to persist message:', error.message);\n }\n } catch (error) {\n // Log but don't fail - message persistence is secondary to realtime\n console.warn('[WARN] Failed to persist message:', error);\n }\n\n // Skip realtime broadcasting if not enabled\n if (!this.realtimeEnabled) {\n return;\n }\n\n try {\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'output',\n payload: message,\n });\n } catch (error) {\n throw error;\n }\n\n this.emit('broadcast', message);\n }\n\n async broadcastMode(mode: PermissionMode): Promise<void> {\n if (!this.outputChannel) {\n throw new Error('Not connected');\n }\n\n // Skip broadcasting if realtime is not enabled\n if (!this.realtimeEnabled) {\n return;\n }\n\n const message: RealtimeMessage = {\n type: 'mode',\n permissionMode: mode,\n timestamp: Date.now(),\n seq: ++this.seq,\n };\n\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'output',\n payload: message,\n });\n\n this.emit('broadcast', message);\n }\n\n async broadcastCommands(commands: SlashCommand[]): Promise<void> {\n if (!this.outputChannel) {\n throw new Error('Not connected');\n }\n\n // Skip broadcasting if realtime is not enabled\n if (!this.realtimeEnabled) {\n return;\n }\n\n const message: RealtimeMessage = {\n type: 'commands',\n commands,\n timestamp: Date.now(),\n seq: ++this.seq,\n };\n\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'output',\n payload: message,\n });\n\n this.emit('broadcast', message);\n }\n\n async broadcastModel(model: string): Promise<void> {\n if (!this.outputChannel) {\n throw new Error('Not connected');\n }\n\n // Skip broadcasting if realtime is not enabled\n if (!this.realtimeEnabled) {\n return;\n }\n\n const message: RealtimeMessage = {\n type: 'model',\n model,\n timestamp: Date.now(),\n seq: ++this.seq,\n };\n\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'output',\n payload: message,\n });\n\n this.emit('broadcast', message);\n }\n\n async broadcastModels(models: ModelInfo[]): Promise<void> {\n if (!this.outputChannel) {\n throw new Error('Not connected');\n }\n\n // Skip broadcasting if realtime is not enabled\n if (!this.realtimeEnabled) {\n return;\n }\n\n const message: RealtimeMessage = {\n type: 'models',\n availableModels: models,\n timestamp: Date.now(),\n seq: ++this.seq,\n };\n\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'output',\n payload: message,\n });\n\n this.emit('broadcast', message);\n }\n\n async broadcastSystem(content: string): Promise<void> {\n if (!this.outputChannel) {\n throw new Error('Not connected');\n }\n\n const message: RealtimeMessage = {\n type: 'system',\n content,\n timestamp: Date.now(),\n seq: ++this.seq,\n };\n\n // Persist message to database for history\n try {\n const { error } = await this.supabase.from('messages').insert({\n session_id: this.sessionId,\n type: message.type,\n content: message.content,\n seq: message.seq,\n });\n if (error) {\n console.warn('[WARN] Failed to persist system message:', error.message);\n }\n } catch (error) {\n console.warn('[WARN] Failed to persist system message:', error);\n }\n\n // Skip realtime broadcasting if not enabled\n if (!this.realtimeEnabled) {\n return;\n }\n\n try {\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'output',\n payload: message,\n });\n } catch (error) {\n throw error;\n }\n\n this.emit('broadcast', message);\n }\n\n async broadcastInteractiveResponse(data: InteractiveCommandData): Promise<void> {\n if (!this.outputChannel) {\n throw new Error('Not connected');\n }\n\n // Skip broadcasting if realtime is not enabled\n if (!this.realtimeEnabled) {\n return;\n }\n\n const message: RealtimeMessage = {\n type: 'interactive-response',\n interactiveData: data,\n timestamp: Date.now(),\n seq: ++this.seq,\n };\n\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'output',\n payload: message,\n });\n\n this.emit('broadcast', message);\n }\n\n async broadcastInteractiveConfirm(\n command: InteractiveCommandType,\n result: InteractiveResult\n ): Promise<void> {\n if (!this.outputChannel) {\n throw new Error('Not connected');\n }\n\n // Skip broadcasting if realtime is not enabled\n if (!this.realtimeEnabled) {\n return;\n }\n\n const message: RealtimeMessage = {\n type: 'interactive-confirm',\n interactiveCommand: command,\n interactiveResult: result,\n timestamp: Date.now(),\n seq: ++this.seq,\n };\n\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'output',\n payload: message,\n });\n\n this.emit('broadcast', message);\n }\n\n async broadcastResumeHistory(historySessionId: string): Promise<void> {\n if (!this.outputChannel) {\n throw new Error('Not connected');\n }\n\n // Skip broadcasting if realtime is not enabled\n if (!this.realtimeEnabled) {\n return;\n }\n\n const message: RealtimeMessage = {\n type: 'resume-history',\n historySessionId,\n timestamp: Date.now(),\n seq: ++this.seq,\n };\n\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'output',\n payload: message,\n });\n\n this.emit('broadcast', message);\n }\n\n async broadcastUserQuestion(questionData: UserQuestionData): Promise<void> {\n if (!this.outputChannel) {\n throw new Error('Not connected');\n }\n\n // Skip broadcasting if realtime is not enabled\n if (!this.realtimeEnabled) {\n return;\n }\n\n const message: RealtimeMessage = {\n type: 'user-question',\n userQuestion: questionData,\n timestamp: Date.now(),\n seq: ++this.seq,\n };\n\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'output',\n payload: message,\n });\n\n this.emit('broadcast', message);\n }\n\n async broadcastPermissionRequest(requestData: PermissionRequestData): Promise<void> {\n if (!this.outputChannel) {\n throw new Error('Not connected');\n }\n\n // Skip broadcasting if realtime is not enabled\n if (!this.realtimeEnabled) {\n return;\n }\n\n const message: RealtimeMessage = {\n type: 'permission-request',\n permissionRequest: requestData,\n timestamp: Date.now(),\n seq: ++this.seq,\n };\n\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'output',\n payload: message,\n });\n\n this.emit('broadcast', message);\n }\n\n async broadcastToolUse(toolUseData: ToolUseData): Promise<void> {\n if (!this.outputChannel) {\n throw new Error('Not connected');\n }\n\n const message: RealtimeMessage = {\n type: 'tool-use',\n toolUseData,\n content: JSON.stringify(toolUseData),\n timestamp: Date.now(),\n seq: ++this.seq,\n };\n\n // Persist to database for history\n try {\n const { error } = await this.supabase.from('messages').insert({\n session_id: this.sessionId,\n type: message.type,\n content: message.content,\n seq: message.seq,\n });\n if (error) {\n console.warn('[WARN] Failed to persist tool-use message:', error.message);\n }\n } catch (error) {\n console.warn('[WARN] Failed to persist tool-use message:', error);\n }\n\n // Skip realtime broadcasting if not enabled\n if (!this.realtimeEnabled) {\n return;\n }\n\n try {\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'output',\n payload: message,\n });\n } catch (error) {\n throw error;\n }\n\n this.emit('broadcast', message);\n }\n\n async broadcastStatusResponse(\n isProcessing: boolean,\n isMessageQueued: boolean,\n permissionMode?: PermissionMode,\n ): Promise<void> {\n if (!this.outputChannel) {\n throw new Error('Not connected');\n }\n\n if (!this.realtimeEnabled) {\n return;\n }\n\n const message: RealtimeMessage = {\n type: 'status-response',\n isProcessing,\n isMessageQueued,\n permissionMode,\n timestamp: Date.now(),\n seq: ++this.seq,\n };\n\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'output',\n payload: message,\n });\n\n this.emit('broadcast', message);\n }\n\n async broadcastComplete(): Promise<void> {\n if (!this.outputChannel) {\n throw new Error('Not connected');\n }\n\n // Skip broadcasting if realtime is not enabled\n if (!this.realtimeEnabled) {\n return;\n }\n\n const message: RealtimeMessage = {\n type: 'complete',\n timestamp: Date.now(),\n seq: ++this.seq,\n };\n\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'output',\n payload: message,\n });\n\n this.emit('broadcast', message);\n }\n\n async broadcastSessionTitle(title: string): Promise<void> {\n if (!this.outputChannel) {\n throw new Error('Not connected');\n }\n\n // Skip broadcasting if realtime is not enabled\n if (!this.realtimeEnabled) {\n return;\n }\n\n const message: RealtimeMessage = {\n type: 'session-title',\n sessionTitle: title,\n timestamp: Date.now(),\n seq: ++this.seq,\n };\n\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'output',\n payload: message,\n });\n\n this.emit('broadcast', message);\n }\n\n async broadcastQueued(): Promise<void> {\n if (!this.outputChannel) {\n throw new Error('Not connected');\n }\n\n if (!this.realtimeEnabled) {\n return;\n }\n\n const message: RealtimeMessage = {\n type: 'request-queued',\n timestamp: Date.now(),\n seq: ++this.seq,\n };\n\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'output',\n payload: message,\n });\n\n this.emit('broadcast', message);\n }\n\n async broadcastError(errorMessage: string, errorCode?: string): Promise<void> {\n if (!this.outputChannel) {\n throw new Error('Not connected');\n }\n\n // Skip broadcasting if realtime is not enabled\n if (!this.realtimeEnabled) {\n return;\n }\n\n const message: RealtimeMessage = {\n type: 'error',\n content: errorMessage,\n errorCode: errorCode || 'unknown',\n timestamp: Date.now(),\n seq: ++this.seq,\n };\n\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'output',\n payload: message,\n });\n\n this.emit('broadcast', message);\n }\n\n getSeq(): number {\n return this.seq;\n }\n\n isConnected(): boolean {\n return this.outputChannel !== null && this.inputChannel !== null;\n }\n\n isRealtimeEnabled(): boolean {\n return this.realtimeEnabled;\n }\n}\n","import type { RealtimeChannel } from '@supabase/supabase-js';\n\nconst DEFAULT_TIMEOUT = 10000;\n\nexport function subscribeWithTimeout(\n channel: RealtimeChannel,\n channelName: string,\n timeout: number = DEFAULT_TIMEOUT\n): Promise<boolean> {\n return new Promise<boolean>((resolve) => {\n let lastStatus = 'unknown';\n\n const timer = setTimeout(() => {\n console.warn(\n `[WARN] Realtime subscription timeout for ${channelName} (last status: ${lastStatus}).`\n );\n resolve(false);\n }, timeout);\n\n channel.subscribe((status, err) => {\n lastStatus = status;\n\n if (status === 'SUBSCRIBED') {\n clearTimeout(timer);\n resolve(true);\n } else if (\n status === 'CHANNEL_ERROR' ||\n status === 'CLOSED' ||\n status === 'TIMED_OUT'\n ) {\n clearTimeout(timer);\n console.warn(\n `[WARN] Channel ${channelName} ${status.toLowerCase()}.`\n );\n if (err) {\n console.warn(`[WARN] Error details: ${err.message || err}`);\n }\n resolve(false);\n }\n });\n });\n}\n","import type { SupabaseClient } from '@supabase/supabase-js';\nimport type { Session, SessionStatus } from 'clautunnel-shared';\n\nexport interface SessionManagerOptions {\n supabase: SupabaseClient;\n}\n\nexport class SessionManager {\n private supabase: SupabaseClient;\n\n constructor(options: SessionManagerOptions) {\n this.supabase = options.supabase;\n }\n\n async createSession(\n machineId: string,\n workingDirectory?: string\n ): Promise<Session> {\n const { data, error } = await this.supabase\n .from('sessions')\n .insert({\n machine_id: machineId,\n status: 'active' as SessionStatus,\n working_directory: workingDirectory,\n started_at: new Date().toISOString(),\n })\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to create session: ${error.message}`);\n }\n\n return data as Session;\n }\n\n async endSession(sessionId: string): Promise<void> {\n const { error } = await this.supabase\n .from('sessions')\n .update({\n status: 'ended' as SessionStatus,\n ended_at: new Date().toISOString(),\n })\n .eq('id', sessionId);\n\n if (error) {\n throw new Error(`Failed to end session: ${error.message}`);\n }\n }\n\n async getSession(sessionId: string): Promise<Session | null> {\n const { data, error } = await this.supabase\n .from('sessions')\n .select()\n .eq('id', sessionId)\n .single();\n\n if (error) {\n if (error.code === 'PGRST116') {\n // Not found\n return null;\n }\n throw new Error(`Failed to get session: ${error.message}`);\n }\n\n return data as Session;\n }\n\n async updateSessionStatus(\n sessionId: string,\n status: SessionStatus\n ): Promise<void> {\n const updates: Partial<Session> = { status };\n\n if (status === 'ended') {\n updates.ended_at = new Date().toISOString();\n }\n\n const { error } = await this.supabase\n .from('sessions')\n .update(updates)\n .eq('id', sessionId);\n\n if (error) {\n throw new Error(`Failed to update session status: ${error.message}`);\n }\n }\n\n async updateSessionModel(\n sessionId: string,\n model: string\n ): Promise<void> {\n const { error } = await this.supabase\n .from('sessions')\n .update({ model })\n .eq('id', sessionId);\n\n if (error) {\n throw new Error(`Failed to update session model: ${error.message}`);\n }\n }\n\n async updateSdkSessionId(\n sessionId: string,\n sdkSessionId: string\n ): Promise<void> {\n const { error } = await this.supabase\n .from('sessions')\n .update({ sdk_session_id: sdkSessionId })\n .eq('id', sessionId);\n\n if (error) {\n throw new Error(`Failed to update SDK session ID: ${error.message}`);\n }\n }\n\n async updateSessionTitle(\n sessionId: string,\n title: string\n ): Promise<void> {\n const { error } = await this.supabase\n .from('sessions')\n .update({ title })\n .eq('id', sessionId);\n\n if (error) {\n throw new Error(`Failed to update session title: ${error.message}`);\n }\n }\n}\n","import type { SupabaseClient } from '@supabase/supabase-js';\nimport type { Machine, MachineStatus } from 'clautunnel-shared';\nimport * as os from 'os';\n\nexport interface MachineManagerOptions {\n supabase: SupabaseClient;\n}\n\nexport class MachineManager {\n private supabase: SupabaseClient;\n\n constructor(options: MachineManagerOptions) {\n this.supabase = options.supabase;\n }\n\n async registerMachine(\n userId: string,\n name?: string,\n machineId?: string\n ): Promise<Machine> {\n const hostname = os.hostname();\n const machineName = name || hostname;\n\n // If machineId provided, try to update existing machine\n if (machineId) {\n const existing = await this.getMachine(machineId);\n if (existing) {\n await this.updateMachineStatus(machineId, 'online');\n return existing;\n }\n }\n\n // Check if machine with same user_id and hostname already exists\n const { data: existingByHostname } = await this.supabase\n .from('machines')\n .select()\n .eq('user_id', userId)\n .eq('hostname', hostname)\n .single();\n\n if (existingByHostname) {\n // Update existing machine and return it\n await this.updateMachineStatus(existingByHostname.id, 'online');\n return existingByHostname as Machine;\n }\n\n // Create new machine\n const { data, error } = await this.supabase\n .from('machines')\n .insert({\n user_id: userId,\n name: machineName,\n hostname,\n status: 'online' as MachineStatus,\n last_seen_at: new Date().toISOString(),\n })\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to register machine: ${error.message}`);\n }\n\n return data as Machine;\n }\n\n async getMachine(machineId: string): Promise<Machine | null> {\n const { data, error } = await this.supabase\n .from('machines')\n .select()\n .eq('id', machineId)\n .single();\n\n if (error) {\n if (error.code === 'PGRST116') {\n // Not found\n return null;\n }\n throw new Error(`Failed to get machine: ${error.message}`);\n }\n\n return data as Machine;\n }\n\n async updateMachineStatus(\n machineId: string,\n status: MachineStatus\n ): Promise<void> {\n const { error } = await this.supabase\n .from('machines')\n .update({\n status,\n last_seen_at: new Date().toISOString(),\n })\n .eq('id', machineId);\n\n if (error) {\n throw new Error(`Failed to update machine status: ${error.message}`);\n }\n }\n\n async heartbeat(machineId: string): Promise<void> {\n const { error } = await this.supabase\n .from('machines')\n .update({\n last_seen_at: new Date().toISOString(),\n })\n .eq('id', machineId);\n\n if (error) {\n throw new Error(`Failed to update heartbeat: ${error.message}`);\n }\n }\n\n async listMachines(userId: string): Promise<Machine[]> {\n const { data, error } = await this.supabase\n .from('machines')\n .select()\n .eq('user_id', userId)\n .order('last_seen_at', { ascending: false });\n\n if (error) {\n throw new Error(`Failed to list machines: ${error.message}`);\n }\n\n return data as Machine[];\n }\n}\n","import { EventEmitter } from 'events';\nimport type { SupabaseClient } from '@supabase/supabase-js';\nimport { SdkSession } from './sdk-session.js';\nimport { SessionManager } from './session.js';\nimport { MachineManager } from './machine.js';\nimport { ConfigManager } from './config-manager.js';\nimport { RealtimeClient } from '../realtime/client.js';\nimport { isPermissionMode } from 'clautunnel-shared';\nimport type { Session, Machine, RealtimeMessage, ImageAttachment, PermissionMode, UserQuestionData, PermissionRequestData, ToolUseData } from 'clautunnel-shared';\n\nexport interface DaemonOptions {\n supabase: SupabaseClient;\n userId: string;\n machineId?: string;\n machineName?: string;\n cwd: string;\n hybrid?: boolean;\n}\n\nexport class Daemon extends EventEmitter {\n private options: DaemonOptions;\n private sdkSession: SdkSession;\n private sessionManager: SessionManager;\n private machineManager: MachineManager;\n private configManager: ConfigManager;\n private realtimeClient: RealtimeClient | null = null;\n private machine: Machine | null = null;\n private session: Session | null = null;\n private running: boolean = false;\n private commandsBroadcast: boolean = false;\n private sdkCommandsBroadcast: boolean = false;\n private titleSet: boolean = false;\n\n constructor(options: DaemonOptions) {\n super();\n this.options = options;\n\n this.configManager = new ConfigManager({\n cwd: options.cwd,\n });\n\n this.sdkSession = new SdkSession({\n cwd: options.cwd,\n permissionMode: this.configManager.getPermissionMode(),\n });\n\n this.sessionManager = new SessionManager({\n supabase: options.supabase,\n });\n\n this.machineManager = new MachineManager({\n supabase: options.supabase,\n });\n\n // Initialize thinking mode from settings\n const thinkingEnabled = this.configManager.getThinkingMode();\n if (thinkingEnabled) {\n this.sdkSession.setThinkingMode(true);\n }\n }\n\n async start(): Promise<void> {\n if (this.running) {\n throw new Error('Daemon is already running');\n }\n\n // Register machine\n this.machine = await this.machineManager.registerMachine(\n this.options.userId,\n this.options.machineName,\n this.options.machineId\n );\n\n // Create session\n this.session = await this.sessionManager.createSession(\n this.machine.id,\n this.options.cwd\n );\n\n // Initialize realtime client\n this.realtimeClient = new RealtimeClient({\n supabase: this.options.supabase,\n sessionId: this.session.id,\n });\n\n // Wire up SDK session output to broadcast\n this.sdkSession.on('output', async (data: string) => {\n // Hybrid mode: output to local stdout\n if (this.options.hybrid !== false) {\n process.stdout.write(data);\n }\n\n // Emit for external listeners (e.g., start command logging)\n this.emit('mobile-output', data);\n\n // Broadcast to mobile\n if (this.realtimeClient) {\n try {\n await this.realtimeClient.broadcast(data);\n } catch {\n // Silently handle broadcast errors\n }\n }\n });\n\n this.sdkSession.on('error', (error: Error) => {\n this.emit('error', error);\n });\n\n // Wire up auth/API errors (authentication_failed, billing_error, rate_limit, etc.)\n this.sdkSession.on('auth-error', async (errorInfo: { errorCode: string; message: string }) => {\n const errorMessages: Record<string, string> = {\n 'authentication_failed': 'Claude CLI authentication expired. Please run \"claude login\" on the host machine.',\n 'billing_error': 'Billing error. Please check your Anthropic account billing status.',\n 'rate_limit': 'Rate limit reached. Please wait a moment and try again.',\n 'server_error': 'Anthropic API server error. Please try again later.',\n };\n\n const displayMessage = errorMessages[errorInfo.errorCode] || `API error: ${errorInfo.message}`;\n\n if (this.options.hybrid !== false) {\n process.stdout.write(`\\n[Error] ${displayMessage}\\n`);\n }\n\n this.emit('error', new Error(displayMessage));\n\n if (this.realtimeClient) {\n try {\n await this.realtimeClient.broadcastError(displayMessage, errorInfo.errorCode);\n await this.realtimeClient.broadcastComplete();\n } catch {\n // Silently handle broadcast errors\n }\n }\n });\n\n // Broadcast commands when they're updated from init message (includes plugins/skills)\n this.sdkSession.on('commands-updated', async () => {\n await this.broadcastCommands();\n });\n\n // Resume failed — notify mobile that we're falling back to a new session\n this.sdkSession.on('resume-failed', async () => {\n const msg = '[Could not resume previous session. Starting a new session instead.]';\n if (this.options.hybrid !== false) {\n process.stdout.write(`\\n${msg}\\n`);\n }\n if (this.realtimeClient) {\n try {\n await this.realtimeClient.broadcastSystem(msg);\n } catch {\n // Silently handle broadcast errors\n }\n }\n });\n\n // Save SDK session ID to Supabase for resume functionality\n this.sdkSession.on('session-started', async (sdkSessionId: string) => {\n if (!this.session) return;\n try {\n await this.sessionManager.updateSdkSessionId(this.session.id, sdkSessionId);\n } catch {\n // Silently handle - non-critical for basic functionality\n }\n });\n\n this.sdkSession.on('complete', async () => {\n // Session query completed, ready for next input\n if (this.options.hybrid !== false) {\n process.stdout.write('\\n> ');\n }\n\n // Broadcast completion to mobile so it knows Claude is done\n if (this.realtimeClient) {\n try {\n await this.realtimeClient.broadcastComplete();\n } catch {\n // Silently handle broadcast errors\n }\n }\n\n // Broadcast real SDK commands (including custom skills) after first query completion\n // This updates the fallback commands with the full list from the SDK\n if (!this.sdkCommandsBroadcast && this.realtimeClient) {\n this.sdkCommandsBroadcast = true;\n await this.broadcastCommands();\n }\n });\n\n // Wire up permission mode changes to broadcast\n this.sdkSession.on('permission-mode', async (mode: PermissionMode) => {\n if (this.realtimeClient) {\n try {\n await this.realtimeClient.broadcastMode(mode);\n } catch {\n // Silently handle broadcast errors\n }\n }\n });\n\n // Wire up user questions to broadcast to mobile\n this.sdkSession.on('user-question', async (questionData: UserQuestionData) => {\n if (this.realtimeClient) {\n try {\n await this.realtimeClient.broadcastUserQuestion(questionData);\n } catch {\n // Silently handle broadcast errors\n }\n }\n });\n\n // Wire up request queuing to broadcast to mobile\n this.sdkSession.on('request-queued', async () => {\n if (this.realtimeClient) {\n try {\n await this.realtimeClient.broadcastQueued();\n } catch {\n // Silently handle broadcast errors\n }\n }\n });\n\n // Wire up permission requests to broadcast to mobile\n this.sdkSession.on('permission-request', async (requestData: PermissionRequestData) => {\n if (this.realtimeClient) {\n try {\n await this.realtimeClient.broadcastPermissionRequest(requestData);\n } catch {\n // Silently handle broadcast errors\n }\n }\n });\n\n // Wire up tool use data to broadcast to mobile (for code diffs)\n this.sdkSession.on('tool-use', async (toolUseData: ToolUseData) => {\n if (this.realtimeClient) {\n try {\n await this.realtimeClient.broadcastToolUse(toolUseData);\n } catch (err) {\n console.warn('[Daemon] Failed to broadcast tool-use:', err);\n }\n }\n });\n\n // Wire up model changes to broadcast and persist\n this.sdkSession.on('model', async (model: string) => {\n // Persist model to database for this session\n if (this.session) {\n try {\n await this.sessionManager.updateSessionModel(this.session.id, model);\n } catch {\n // Silently handle persistence errors\n }\n }\n\n // Broadcast to mobile\n if (this.realtimeClient) {\n try {\n await this.realtimeClient.broadcastModel(model);\n } catch {\n // Silently handle broadcast errors\n }\n }\n });\n\n // Wire up input from mobile\n this.realtimeClient.on('input', async (message: RealtimeMessage) => {\n // Broadcast commands on first message from mobile if not already done\n if (!this.commandsBroadcast) {\n this.commandsBroadcast = true;\n await this.broadcastCommands();\n }\n\n // Handle mode change requests\n if (message.type === 'mode-change' && message.permissionMode) {\n this.sdkSession.setPermissionMode(message.permissionMode);\n // Broadcast the new mode back to confirm\n if (this.realtimeClient) {\n try {\n await this.realtimeClient.broadcastMode(message.permissionMode);\n } catch {\n // Silently handle broadcast errors\n }\n }\n return;\n }\n\n // Handle commands request\n if (message.type === 'commands-request') {\n await this.broadcastCommands();\n return;\n }\n\n // Handle model change requests\n if (message.type === 'model-change' && message.model) {\n const previousModel = this.sdkSession.getModel();\n await this.sdkSession.setModel(message.model);\n\n // Output confirmation message if model actually changed\n if (previousModel !== message.model) {\n const modelNames: Record<string, string> = {\n 'default': 'Opus 4.6',\n 'sonnet': 'Sonnet 4.6',\n 'opus': 'Opus 4.6',\n 'haiku': 'Haiku 3.5',\n };\n const displayName = modelNames[message.model] || message.model;\n const confirmationMsg = `[Model switched to ${displayName}]`;\n\n // Output to local terminal\n if (this.options.hybrid !== false) {\n process.stdout.write(`\\n${confirmationMsg}\\n`);\n }\n\n // Broadcast to mobile as system message (appears as separate bubble)\n if (this.realtimeClient) {\n try {\n await this.realtimeClient.broadcastSystem(confirmationMsg);\n } catch {\n // Silently handle broadcast errors\n }\n }\n } else {\n // Model didn't change — still broadcast current model so mobile clears loading state\n try {\n await this.realtimeClient?.broadcastModel(this.sdkSession.getModel());\n } catch {\n // Silently handle broadcast errors\n }\n }\n return;\n }\n\n // Handle models request - send both available models and current model\n if (message.type === 'models-request') {\n await this.broadcastModels();\n // Also broadcast the current model so UI shows the correct selection\n try {\n await this.realtimeClient?.broadcastModel(this.sdkSession.getModel());\n } catch {\n // Silently handle broadcast errors\n }\n return;\n }\n\n // Handle status request - re-broadcast any pending question or permission,\n // then report current processing state so mobile can restore isTyping\n if (message.type === 'status-request') {\n if (this.realtimeClient) {\n try {\n const pendingQuestion = this.sdkSession.getPendingQuestionData();\n if (pendingQuestion) {\n await this.realtimeClient.broadcastUserQuestion(pendingQuestion);\n }\n const pendingPermission = this.sdkSession.getPendingPermissionData();\n if (pendingPermission) {\n await this.realtimeClient.broadcastPermissionRequest(pendingPermission);\n }\n\n // Broadcast processing state last so it doesn't flash typing indicator\n // before a pending question/permission modal appears\n const isProcessing = this.sdkSession.isActive();\n const isActivelyWorking = isProcessing && !pendingQuestion && !pendingPermission;\n const isMessageQueued = this.sdkSession.hasPendingPrompt();\n await this.realtimeClient.broadcastStatusResponse(\n isActivelyWorking,\n isMessageQueued,\n this.sdkSession.getPermissionMode(),\n );\n } catch {\n // Silently handle broadcast errors\n }\n }\n return;\n }\n\n // Handle mobile disconnect notification\n if (message.type === 'mobile-disconnect') {\n if (this.options.hybrid !== false) {\n process.stdout.write('\\n[ClauTunnel] Mobile client disconnected.\\n');\n }\n this.emit('mobile-disconnected');\n return;\n }\n\n // Handle interactive command request\n if (message.type === 'interactive-request' && message.interactiveCommand) {\n const data = this.configManager.getInteractiveData(message.interactiveCommand);\n if (this.realtimeClient) {\n try {\n await this.realtimeClient.broadcastInteractiveResponse(data);\n } catch {\n // Silently handle broadcast errors\n }\n }\n return;\n }\n\n // Handle interactive apply\n if (message.type === 'interactive-apply' && message.interactivePayload) {\n const result = this.configManager.applyChange(message.interactivePayload);\n\n // If permission mode was changed, update runtime SDK mode too\n if (\n result.success &&\n message.interactivePayload.command === 'permissions' &&\n isPermissionMode(message.interactivePayload.value)\n ) {\n this.sdkSession.setPermissionMode(message.interactivePayload.value);\n }\n\n // If thinking mode was changed, also update the running SDK session\n if (\n message.interactivePayload.command === 'config' &&\n message.interactivePayload.key === 'alwaysThinkingEnabled'\n ) {\n const enabled = Boolean(message.interactivePayload.value);\n await this.sdkSession.setThinkingMode(enabled);\n }\n\n if (this.realtimeClient) {\n try {\n await this.realtimeClient.broadcastInteractiveConfirm(\n message.interactivePayload.command,\n result\n );\n // Also broadcast a system message for confirmation\n const statusText = result.success\n ? `✓ ${result.message}`\n : `✗ ${result.message}`;\n await this.realtimeClient.broadcastSystem(statusText);\n } catch {\n // Silently handle broadcast errors\n }\n }\n return;\n }\n\n // Handle cancel request from mobile - stop Claude mid-processing\n if (message.type === 'cancel-request') {\n this.sdkSession.cancel();\n if (this.options.hybrid !== false) {\n process.stdout.write('\\n[Cancelled]\\n> ');\n }\n if (this.realtimeClient) {\n try {\n await this.realtimeClient.broadcastSystem('[Cancelled]');\n await this.realtimeClient.broadcastComplete();\n } catch (error) {\n console.warn('[Daemon] Failed to broadcast cancel:', error);\n }\n }\n return;\n }\n\n // Handle clear request from mobile (doesn't appear in chat)\n if (message.type === 'clear-request') {\n this.sdkSession.clearHistory();\n if (this.options.hybrid !== false) {\n process.stdout.write('\\n[Conversation cleared]\\n> ');\n }\n return;\n }\n\n // Handle user answer (response to AskUserQuestion)\n // Use provideAnswer() to stream into the existing query instead of\n // sendPrompt() which would be rejected since isProcessing is true\n if (message.type === 'user-answer' && message.userAnswer) {\n const answerText = Object.values(message.userAnswer.answers).join('\\n');\n this.emit('mobile-input', `(answer) ${answerText}`);\n await this.sdkSession.provideAnswer(answerText, message.userAnswer.answers);\n return;\n }\n\n // Handle permission response from mobile\n if (message.type === 'permission-response' && message.permissionResponse) {\n this.sdkSession.handlePermissionResponse(message.permissionResponse);\n return;\n }\n\n // Handle resume request from mobile (doesn't appear in chat)\n if (message.type === 'resume-request' && message.resumeSessionId) {\n const targetSdkSessionId = message.resumeSessionId;\n this.sdkSession.resumeSession(targetSdkSessionId);\n\n const confirmationMsg = `[Resuming session: ${targetSdkSessionId.slice(0, 8)}...]`;\n if (this.options.hybrid !== false) {\n process.stdout.write(`\\n${confirmationMsg}\\n`);\n }\n\n if (this.realtimeClient) {\n try {\n // Find the Supabase session with this SDK session ID to load its messages\n const { data: sessionData } = await this.options.supabase\n .from('sessions')\n .select('id')\n .eq('sdk_session_id', targetSdkSessionId)\n .single();\n\n if (sessionData) {\n // Tell mobile to load messages from this session\n await this.realtimeClient.broadcastResumeHistory(sessionData.id);\n }\n\n await this.realtimeClient.broadcastSystem(confirmationMsg);\n } catch {\n // Silently handle broadcast errors\n }\n }\n\n // Send a prompt to trigger the resumed session\n await this.sdkSession.sendPrompt('Continue from where we left off.');\n return;\n }\n\n // Remove trailing newline/carriage return for SDK\n const prompt = message.content?.replace(/[\\r\\n]+$/, '') || '';\n const attachments = message.attachments;\n\n // Send if there's text or attachments\n if (prompt.trim() || (attachments && attachments.length > 0)) {\n const trimmedPrompt = prompt.trim();\n\n // Emit mobile input event for logging\n this.emit('mobile-input', trimmedPrompt, attachments);\n\n // Handle /clear typed in chat (legacy support)\n if (trimmedPrompt === '/clear') {\n this.sdkSession.clearHistory();\n if (this.realtimeClient) {\n try {\n await this.realtimeClient.broadcastSystem('Conversation cleared');\n } catch {\n // Silently handle broadcast errors\n }\n }\n if (this.options.hybrid !== false) {\n process.stdout.write('\\n[Conversation cleared]\\n> ');\n }\n return;\n }\n\n // Auto-set session title from the first user message\n if (!this.titleSet && this.session) {\n this.titleSet = true;\n const title = trimmedPrompt.length > 50\n ? trimmedPrompt.slice(0, 50) + '...'\n : trimmedPrompt;\n this.sessionManager.updateSessionTitle(this.session.id, title).catch(() => {\n // Non-critical - silently handle\n });\n if (this.realtimeClient) {\n this.realtimeClient.broadcastSessionTitle(title).catch(() => {\n // Non-critical - silently handle\n });\n }\n }\n\n await this.sdkSession.sendPrompt(prompt, attachments);\n }\n });\n\n // Connect to realtime\n await this.realtimeClient.connect();\n\n // Broadcast initial permission mode\n try {\n await this.realtimeClient.broadcastMode(this.sdkSession.getPermissionMode());\n } catch {\n // Silently handle broadcast errors\n }\n\n // Broadcast available commands immediately\n await this.broadcastCommands();\n\n // Broadcast available models immediately\n await this.broadcastModels();\n\n // Broadcast current model\n try {\n await this.realtimeClient.broadcastModel(this.sdkSession.getModel());\n } catch {\n // Silently handle broadcast errors\n }\n\n this.running = true;\n this.emit('started', {\n machine: this.machine,\n session: this.session,\n mobileSyncEnabled: this.realtimeClient?.isRealtimeEnabled() ?? false,\n });\n\n // Show initial prompt\n if (this.options.hybrid !== false) {\n process.stdout.write('\\n[ClauTunnel] Ready for input.\\n> ');\n }\n }\n\n async stop(): Promise<void> {\n if (!this.running) {\n return;\n }\n\n this.running = false;\n\n // Cancel any ongoing SDK operation\n this.sdkSession.cancel();\n\n // End session\n if (this.session) {\n await this.sessionManager.endSession(this.session.id);\n }\n\n // Note: We don't set machine status to 'offline' here because other\n // sessions may still be running on the same machine. The machine\n // status is set to 'online' when any session starts.\n\n // Disconnect realtime\n if (this.realtimeClient) {\n await this.realtimeClient.disconnect();\n }\n\n this.emit('stopped');\n }\n\n async sendPrompt(prompt: string, attachments?: ImageAttachment[]): Promise<void> {\n await this.sdkSession.sendPrompt(prompt, attachments);\n }\n\n isRunning(): boolean {\n return this.running;\n }\n\n getSession(): Session | null {\n return this.session;\n }\n\n getMachine(): Machine | null {\n return this.machine;\n }\n\n private async broadcastCommands(): Promise<void> {\n if (!this.realtimeClient) {\n return;\n }\n\n try {\n const commands = await this.sdkSession.getSupportedCommands();\n await this.realtimeClient.broadcastCommands(commands);\n } catch {\n // Silently handle broadcast errors\n }\n }\n\n private async broadcastModels(): Promise<void> {\n if (!this.realtimeClient) {\n return;\n }\n\n try {\n const models = await this.sdkSession.getSupportedModels();\n await this.realtimeClient.broadcastModels(models);\n } catch {\n // Silently handle broadcast errors\n }\n }\n}\n","import { EventEmitter } from 'events';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\nimport { unstable_v2_createSession, unstable_v2_resumeSession } from '@anthropic-ai/claude-agent-sdk';\nimport type { SDKSession as V2Session, SDKSessionOptions, SDKMessage, SlashCommand as SDKSlashCommand, CanUseTool, PermissionResult, PermissionUpdate as SDKPermissionUpdate, SDKUserMessage } from '@anthropic-ai/claude-agent-sdk';\nimport type { ImageAttachment, ModelInfo, PermissionMode, SlashCommand, UserQuestionData, UserQuestion, PermissionRequestData, PermissionResponseData, PermissionUpdate, ToolUseData } from 'clautunnel-shared';\nimport { v4 as uuidv4 } from 'uuid';\n\n/** Maximum characters to capture from tool use content */\nconst MAX_TOOL_CONTENT = 10000;\n/** Grace period to wait for a result after compact lifecycle events */\nconst COMPACT_FALLBACK_GRACE_MS = 40;\n/** Delay before dispatching queued prompt after compact fallback */\nconst COMPACT_QUEUED_DISPATCH_DELAY_MS = 40;\n/** Guard window to ignore a stale compact result during immediate next-turn handoff */\nconst COMPACT_STALE_RESULT_GUARD_MS = COMPACT_FALLBACK_GRACE_MS + COMPACT_QUEUED_DISPATCH_DELAY_MS;\n\n/** Commands unsupported in remote/mobile context */\nconst UNSUPPORTED_COMMANDS = new Set([\n 'keybindings-help', 'help', 'context', 'cost', 'release-notes',\n 'vim', 'mcp', 'agents', 'hooks', 'status',\n]);\n\nexport interface SdkSessionOptions {\n cwd: string;\n allowedTools?: string[];\n permissionMode?: PermissionMode;\n model?: string;\n}\n\ninterface ConversationMessage {\n role: 'user' | 'assistant';\n content: string;\n}\n\n// Pending permission request with resolver\ninterface PendingPermissionRequest {\n resolve: (result: PermissionResult) => void;\n reject: (error: Error) => void;\n signal: AbortSignal;\n toolInput: Record<string, unknown>;\n}\n\ninterface PendingAnswerRequest {\n resolve: (answers: Record<string, string>) => void;\n reject: (error: Error) => void;\n}\n\nexport class SdkSession extends EventEmitter {\n private options: SdkSessionOptions;\n private sessionId: string | null = null;\n private isProcessing: boolean = false;\n private currentPermissionMode: PermissionMode;\n private v2Session: V2Session | null = null;\n private streamLoopRunning: boolean = false;\n private cachedCommands: SlashCommand[] | null = null;\n private cachedModels: ModelInfo[] | null = null;\n private currentModel: string = 'opus';\n private conversationHistory: ConversationMessage[] = [];\n private pendingContextTransfer: boolean = false;\n private thinkingEnabled: boolean = false;\n private pendingPermissionRequests: Map<string, PendingPermissionRequest> = new Map();\n // Pending AskUserQuestion answer promise\n private pendingAnswerRequest: PendingAnswerRequest | null = null;\n // Track pending question/permission data for re-broadcast on status-request\n private pendingQuestionData: UserQuestionData | null = null;\n private pendingPermissionData: PermissionRequestData | null = null;\n // Track current assistant response text for conversation history\n private currentAssistantResponse: string = '';\n // Queued prompt to send after current processing completes (last-one-wins)\n private pendingPrompt: { prompt: string; attachments?: ImageAttachment[] } | null = null;\n // Tracks prompt during a resume attempt — used to auto-retry with a fresh session on failure\n private resumeAttemptPrompt: { prompt: string; attachments?: ImageAttachment[] } | null = null;\n // Tracks whether the current in-flight prompt is a manual /compact command.\n private awaitingCompactCompletionFallback: boolean = false;\n // Monotonic counter for turn ordering.\n private turnGeneration: number = 0;\n // Generation of the current in-flight turn.\n private activeTurnGeneration: number = 0;\n // Timestamp when the current in-flight turn started.\n private activeTurnStartedAtMs: number = 0;\n // Generation whose late result should be ignored after compact fallback.\n private compactLateResultSuppressedGeneration: number | null = null;\n // Timer used to defer compact completion fallback in case result arrives.\n private compactCompletionFallbackTimer: ReturnType<typeof setTimeout> | null = null;\n // Timer used to dispatch queued prompt shortly after compact fallback.\n private deferredQueuedPromptTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor(options: SdkSessionOptions) {\n super();\n this.options = options;\n this.currentPermissionMode = options.permissionMode || 'default';\n this.currentModel = options.model || 'opus';\n }\n\n /**\n * Handle permission response from mobile\n */\n handlePermissionResponse(response: PermissionResponseData): void {\n const pending = this.pendingPermissionRequests.get(response.requestId);\n if (!pending) {\n console.warn(`[WARN] No pending permission request found for ID: ${response.requestId}`);\n return;\n }\n\n this.pendingPermissionRequests.delete(response.requestId);\n this.pendingPermissionData = null;\n\n if (response.behavior === 'allow') {\n const result: PermissionResult = {\n behavior: 'allow',\n // updatedInput is required by the SDK's Zod schema — if omitted,\n // JSON.stringify drops the key and subprocess validation fails.\n // Fall back to the original tool input to keep it valid.\n updatedInput: response.updatedInput ?? pending.toolInput,\n updatedPermissions: response.updatedPermissions as SDKPermissionUpdate[] | undefined,\n };\n pending.resolve(result);\n } else {\n const result: PermissionResult = {\n behavior: 'deny',\n message: response.message || 'Permission denied by user',\n };\n pending.resolve(result);\n }\n }\n\n /**\n * Create canUseTool callback for SDK\n *\n * AskUserQuestion goes through this path: the subprocess sends a\n * control_request with subtype \"can_use_tool\" and blocks until a\n * control_response is returned. For AskUserQuestion we emit a\n * user-question event, wait for provideAnswer() to resolve the pending\n * promise, and return {behavior:'allow', updatedInput:{questions, answers}}\n * so the subprocess can produce the tool_result and continue.\n */\n private createCanUseTool(): CanUseTool {\n return async (\n toolName: string,\n input: Record<string, unknown>,\n options: {\n signal: AbortSignal;\n suggestions?: SDKPermissionUpdate[];\n blockedPath?: string;\n decisionReason?: string;\n toolUseID: string;\n agentID?: string;\n }\n ): Promise<PermissionResult> => {\n\n // --- AskUserQuestion: route through user-question event -----------\n if (toolName === 'AskUserQuestion') {\n const questionInput = input as {\n questions?: Array<{\n question: string;\n header: string;\n options: Array<{ label: string; description: string }>;\n multiSelect?: boolean;\n }>;\n };\n\n if (questionInput.questions && Array.isArray(questionInput.questions)) {\n const questions: UserQuestion[] = questionInput.questions.map(q => ({\n question: q.question,\n header: q.header,\n options: (q.options || []).map(o => ({\n label: o.label,\n description: o.description,\n })),\n multiSelect: q.multiSelect,\n }));\n\n const questionData: UserQuestionData = {\n toolUseId: options.toolUseID,\n questions,\n };\n\n // Store and broadcast to mobile\n this.pendingQuestionData = questionData;\n this.emit('user-question', questionData);\n\n // Wait for provideAnswer() to supply the answers\n const answers = await new Promise<Record<string, string>>(\n (resolve, reject) => {\n const pendingRequest: PendingAnswerRequest = { resolve, reject };\n this.pendingAnswerRequest = pendingRequest;\n\n // Clean up if the request is aborted (e.g. session cancelled)\n options.signal.addEventListener('abort', () => {\n if (this.pendingAnswerRequest === pendingRequest) {\n this.pendingAnswerRequest = null;\n this.pendingQuestionData = null;\n }\n reject(new Error('Question aborted'));\n });\n }\n );\n\n this.pendingAnswerRequest = null;\n this.pendingQuestionData = null;\n\n // Return updatedInput so the subprocess can build the tool_result\n return {\n behavior: 'allow' as const,\n updatedInput: {\n questions: questionInput.questions,\n answers,\n },\n };\n }\n }\n\n // --- Regular permission request: broadcast to mobile and wait -----\n const requestId = uuidv4();\n\n // Convert SDK permission updates to our type\n const suggestions = options.suggestions?.map((s): PermissionUpdate => {\n // Handle different permission update types\n if (s.type === 'addRules' || s.type === 'replaceRules' || s.type === 'removeRules') {\n return {\n type: s.type,\n rules: s.rules,\n behavior: s.behavior,\n destination: s.destination,\n };\n } else if (s.type === 'setMode') {\n return {\n type: 'setMode',\n mode: s.mode as PermissionMode,\n destination: s.destination,\n };\n } else if (s.type === 'addDirectories' || s.type === 'removeDirectories') {\n return {\n type: s.type,\n directories: s.directories,\n destination: s.destination,\n };\n }\n // Fallback - should never reach here\n return s as PermissionUpdate;\n });\n\n const requestData: PermissionRequestData = {\n requestId,\n toolName,\n toolInput: input,\n toolUseId: options.toolUseID,\n suggestions,\n blockedPath: options.blockedPath,\n decisionReason: options.decisionReason,\n agentId: options.agentID,\n };\n\n // Store and emit event for daemon to broadcast to mobile\n this.pendingPermissionData = requestData;\n this.emit('permission-request', requestData);\n\n // Create promise that will be resolved when mobile responds\n return new Promise<PermissionResult>((resolve, reject) => {\n this.pendingPermissionRequests.set(requestId, {\n resolve,\n reject,\n signal: options.signal,\n toolInput: input,\n });\n\n // Handle abort\n options.signal.addEventListener('abort', () => {\n this.pendingPermissionRequests.delete(requestId);\n this.pendingPermissionData = null;\n reject(new Error('Permission request aborted'));\n });\n });\n };\n }\n\n setPermissionMode(mode: PermissionMode): void {\n const modeChanged = this.currentPermissionMode !== mode;\n this.currentPermissionMode = mode;\n\n // Permission mode is set at session creation time in V2.\n // Recreate session so the next prompt uses the new mode.\n if (modeChanged) {\n this.clearPendingInteractionState('Session reconfigured');\n this.clearCompactCompletionFallbackTimer();\n this.clearDeferredQueuedPromptTimer();\n this.awaitingCompactCompletionFallback = false;\n this.clearCompactLateResultSuppression();\n if (this.v2Session) {\n this.v2Session.close();\n this.v2Session = null;\n this.streamLoopRunning = false;\n this.sessionId = null;\n this.isProcessing = false;\n this.pendingPrompt = null;\n this.pendingContextTransfer = true;\n } else if (this.sessionId) {\n this.sessionId = null;\n this.pendingContextTransfer = true;\n }\n }\n\n this.emit('permission-mode', mode);\n }\n\n getPermissionMode(): PermissionMode {\n return this.currentPermissionMode;\n }\n\n async setThinkingMode(enabled: boolean): Promise<void> {\n this.thinkingEnabled = enabled;\n this.emit('thinking-mode', enabled);\n }\n\n getThinkingMode(): boolean {\n return this.thinkingEnabled;\n }\n\n /**\n * Build V2 session options from current state\n */\n private buildSessionOptions(): SDKSessionOptions {\n const opts: SDKSessionOptions = {\n // SDK accepts shorthand model names: 'opus' | 'sonnet' | 'haiku'\n // Full model IDs (e.g. 'claude-opus-4-6') are also valid but shorthand is preferred\n model: this.currentModel,\n allowedTools: this.options.allowedTools || ['Read', 'Edit', 'Write', 'Bash', 'Glob', 'Grep'],\n canUseTool: this.createCanUseTool(),\n permissionMode: this.currentPermissionMode,\n };\n return opts;\n }\n\n /**\n * Ensure a V2 session exists, creating one if needed\n */\n private ensureSession(): V2Session {\n if (!this.v2Session) {\n const opts = this.buildSessionOptions();\n\n if (this.sessionId) {\n // Resume existing session\n this.v2Session = unstable_v2_resumeSession(this.sessionId, opts);\n } else {\n // Create new session\n this.v2Session = unstable_v2_createSession(opts);\n }\n\n // Start the background message processing loop\n this.startStreamLoop();\n }\n return this.v2Session;\n }\n\n /**\n * Clear session state and retry the saved resume prompt with a fresh session.\n * Returns the saved prompt if a retry should happen, or null if not applicable.\n */\n private consumeResumeAttempt(): { prompt: string; attachments?: ImageAttachment[] } | null {\n const savedPrompt = this.resumeAttemptPrompt;\n if (!savedPrompt) return null;\n\n this.resumeAttemptPrompt = null;\n this.v2Session = null;\n this.sessionId = null;\n this.streamLoopRunning = false;\n this.isProcessing = false;\n\n // Remove the duplicate user history entry pushed by sendPrompt\n if (this.conversationHistory.length > 0 && this.conversationHistory[this.conversationHistory.length - 1].role === 'user') {\n this.conversationHistory.pop();\n }\n\n this.emit('resume-failed');\n return savedPrompt;\n }\n\n /**\n * Background loop that processes messages from the V2 session stream.\n * Runs continuously for the lifetime of the session.\n */\n private async startStreamLoop(): Promise<void> {\n if (this.streamLoopRunning || !this.v2Session) return;\n this.streamLoopRunning = true;\n\n let retrying = false;\n try {\n // The V2 stream() returns after each 'result' message.\n // For multi-turn sessions, we need to call stream() again after each result.\n while (this.v2Session && !this.v2Session['closed']) {\n for await (const message of this.v2Session.stream()) {\n this.processMessage(message);\n }\n }\n } catch (error) {\n if ((error as Error).name !== 'AbortError') {\n const savedPrompt = this.consumeResumeAttempt();\n if (savedPrompt) {\n retrying = true;\n this.sendPrompt(savedPrompt.prompt, savedPrompt.attachments).catch((retryErr) => {\n this.emit('error', retryErr);\n });\n } else {\n this.emit('error', error);\n }\n }\n } finally {\n this.streamLoopRunning = false;\n // If the stream loop exits without a 'result' message (e.g. unexpected\n // disconnect or error), ensure isProcessing is reset so subsequent\n // requests are not permanently blocked.\n // Skip cleanup if we're retrying with a fresh session.\n if (this.isProcessing && !retrying) {\n this.isProcessing = false;\n this.pendingPrompt = null;\n this.emit('complete');\n }\n }\n }\n\n /**\n * Process a single SDK message from the stream\n */\n private processMessage(message: SDKMessage): void {\n // Handle different message types\n if (message.type === 'system' && 'subtype' in message && message.subtype === 'init') {\n // Resume succeeded — clear the tracking flag\n this.resumeAttemptPrompt = null;\n\n // Capture session ID for resuming\n this.sessionId = message.session_id;\n this.emit('session-started', this.sessionId);\n\n // Emit permission mode if present\n if ('permissionMode' in message) {\n this.emit('permission-mode', message.permissionMode);\n }\n\n // Capture slash commands from init message (includes plugins/skills)\n if ('slash_commands' in message && Array.isArray(message.slash_commands)) {\n this.cachedCommands = message.slash_commands.map((cmd: unknown) => {\n if (typeof cmd === 'string') {\n return { name: cmd, description: '', argumentHint: '' };\n } else if (typeof cmd === 'object' && cmd !== null) {\n const cmdObj = cmd as SDKSlashCommand;\n return {\n name: cmdObj.name || '',\n description: cmdObj.description || '',\n argumentHint: cmdObj.argumentHint || '',\n };\n }\n return { name: String(cmd), description: '', argumentHint: '' };\n });\n this.emit('commands-updated', this.cachedCommands);\n }\n } else if (\n message.type === 'system' &&\n 'subtype' in message &&\n message.subtype === 'status' &&\n 'status' in message &&\n message.status === null &&\n this.awaitingCompactCompletionFallback &&\n this.isProcessing\n ) {\n // /compact can complete with status reset (compacting -> null) and no result message.\n this.scheduleCompactCompletionFallback();\n } else if (\n message.type === 'system' &&\n 'subtype' in message &&\n message.subtype === 'compact_boundary' &&\n this.awaitingCompactCompletionFallback &&\n this.isProcessing\n ) {\n // /compact can also complete with compact_boundary and no result message.\n this.scheduleCompactCompletionFallback();\n } else if (message.type === 'auth_status') {\n // Authentication status change from SDK\n const authMsg = message as { type: 'auth_status'; isAuthenticating: boolean; error?: string; output?: string[] };\n if (authMsg.error) {\n this.emit('auth-error', {\n errorCode: 'authentication_failed',\n message: authMsg.error,\n });\n }\n } else if (message.type === 'assistant') {\n // Check for API-level errors (auth failure, billing, rate limit, etc.)\n const assistantError = (message as any).error as string | undefined;\n if (assistantError) {\n this.emit('auth-error', {\n errorCode: assistantError,\n message: assistantError,\n });\n }\n // Assistant text output and tool use\n if (message.message?.content) {\n for (const block of message.message.content) {\n if ('type' in block && block.type === 'text' && 'text' in block) {\n this.emit('output', block.text);\n this.currentAssistantResponse += block.text;\n } else if ('type' in block && block.type === 'tool_use' && 'name' in block) {\n // AskUserQuestion tool_use blocks are handled via the canUseTool\n // callback (which emits 'user-question' and waits for the answer).\n const toolName = (block as any).name as string;\n if (toolName !== 'AskUserQuestion') {\n const input = (block as any).input || {};\n let toolUseData: ToolUseData;\n\n if (toolName === 'Edit' && input.file_path && input.old_string !== undefined) {\n toolUseData = {\n action: 'Edit',\n filePath: input.file_path,\n oldString: String(input.old_string).slice(0, MAX_TOOL_CONTENT),\n newString: String(input.new_string || '').slice(0, MAX_TOOL_CONTENT),\n };\n } else if (toolName === 'Write' && input.file_path) {\n toolUseData = {\n action: 'Write',\n filePath: input.file_path,\n content: String(input.content || '').slice(0, MAX_TOOL_CONTENT),\n };\n } else {\n toolUseData = {\n action: toolName,\n toolName,\n input,\n };\n }\n\n this.emit('tool-use', toolUseData);\n }\n }\n }\n }\n } else if (message.type === 'result') {\n this.clearCompactCompletionFallbackTimer();\n if (this.shouldIgnoreLateCompactResult()) {\n return;\n }\n\n // Emit result text if no assistant output was captured (e.g. slash commands like /context)\n if (!this.currentAssistantResponse.trim() && 'result' in message && message.result) {\n const resultText = String(message.result);\n this.emit('output', resultText);\n this.currentAssistantResponse = resultText;\n }\n // Final result - track assistant response in history\n if (this.currentAssistantResponse.trim()) {\n this.conversationHistory.push({ role: 'assistant', content: this.currentAssistantResponse.trim() });\n }\n\n this.currentAssistantResponse = '';\n this.awaitingCompactCompletionFallback = false;\n this.completeCurrentTurn();\n } else if (message.type === 'tool_progress') {\n // Tool progress (tool being used)\n if ('tool_name' in message) {\n this.emit('output', `\\n[Using tool: ${message.tool_name}]\\n`);\n }\n } else if (message.type === 'tool_use_summary') {\n // Tool use summary\n if ('tool_name' in message) {\n this.emit('output', `[Tool ${message.tool_name} completed]\\n`);\n }\n }\n }\n\n async sendPrompt(prompt: string, attachments?: ImageAttachment[]): Promise<void> {\n if (this.isProcessing) {\n // Queue the message instead of rejecting — last one wins\n this.pendingPrompt = { prompt, attachments };\n this.emit('request-queued');\n return;\n }\n\n this.clearCompactCompletionFallbackTimer();\n this.clearDeferredQueuedPromptTimer();\n this.awaitingCompactCompletionFallback = /^\\/compact(?:\\s|$)/.test(prompt.trim());\n this.activeTurnGeneration = ++this.turnGeneration;\n this.activeTurnStartedAtMs = Date.now();\n if (\n this.compactLateResultSuppressedGeneration !== null &&\n this.activeTurnGeneration > this.compactLateResultSuppressedGeneration + 1\n ) {\n this.clearCompactLateResultSuppression();\n }\n this.isProcessing = true;\n this.currentAssistantResponse = '';\n\n // Track user message in conversation history\n if (prompt.trim()) {\n this.conversationHistory.push({ role: 'user', content: prompt });\n }\n\n try {\n // Track resume attempt: if sessionId is set but no live session, we're about to resume\n if (this.sessionId && !this.v2Session) {\n this.resumeAttemptPrompt = { prompt, attachments };\n }\n\n // Build the prompt text, including context if transferring to new session\n let finalPrompt = prompt;\n if (this.pendingContextTransfer && this.conversationHistory.length > 1) {\n // Build context from previous conversation (excluding current message)\n const previousHistory = this.conversationHistory.slice(0, -1);\n const contextLines = previousHistory.map(msg =>\n `${msg.role === 'user' ? 'User' : 'Assistant'}: ${msg.content}`\n );\n const contextPrefix = `[Previous conversation context - you switched to a new model]\\n${contextLines.join('\\n')}\\n\\n[Continue with new message]\\n`;\n finalPrompt = contextPrefix + prompt;\n this.pendingContextTransfer = false;\n }\n\n // Ensure we have a V2 session\n const session = this.ensureSession();\n\n // Build message content\n const contentBlocks: Array<{ type: string; text?: string; source?: { type: string; media_type: string; data: string } }> = [];\n\n // Add images if present\n if (attachments && attachments.length > 0) {\n for (const attachment of attachments) {\n contentBlocks.push({\n type: 'image',\n source: {\n type: 'base64',\n media_type: attachment.mediaType,\n data: attachment.data,\n },\n });\n }\n }\n\n // Add text\n if (finalPrompt.trim()) {\n contentBlocks.push({\n type: 'text',\n text: finalPrompt,\n });\n }\n\n // Build and send the user message via V2 session.send()\n const userMessage: SDKUserMessage = {\n type: 'user' as const,\n message: {\n role: 'user' as const,\n content: contentBlocks.length > 0 ? contentBlocks : [{ type: 'text' as const, text: finalPrompt }],\n },\n parent_tool_use_id: null,\n session_id: this.sessionId || '',\n };\n\n await session.send(userMessage);\n } catch (error) {\n if ((error as Error).name !== 'AbortError') {\n const savedPrompt = this.consumeResumeAttempt();\n if (savedPrompt) {\n await this.sendPrompt(savedPrompt.prompt, savedPrompt.attachments);\n return;\n }\n }\n\n if ((error as Error).name === 'AbortError') {\n this.emit('output', '\\n[Cancelled]\\n');\n } else {\n this.emit('error', error);\n this.emit('output', `\\n[Error: ${(error as Error).message}]\\n`);\n }\n this.isProcessing = false;\n this.clearCompactCompletionFallbackTimer();\n this.clearDeferredQueuedPromptTimer();\n this.awaitingCompactCompletionFallback = false;\n }\n }\n\n /**\n * Provide an answer to a pending AskUserQuestion.\n *\n * AskUserQuestion flows through the canUseTool callback which blocks\n * waiting for a Promise to resolve. This method resolves that Promise\n * with the user's answers, which causes canUseTool to return\n * {behavior:'allow', updatedInput:{questions, answers}} → the SDK\n * sends the control_response back to the subprocess → it unblocks and\n * builds the tool_result for the Claude API.\n */\n async provideAnswer(answerText: string, answers?: Record<string, string>): Promise<void> {\n // Track in conversation history\n if (answerText.trim()) {\n this.conversationHistory.push({ role: 'user', content: answerText });\n }\n\n if (this.pendingAnswerRequest) {\n // Resolve the pending canUseTool callback with the answers\n const resolvedAnswers = answers || { result: answerText };\n const pendingRequest = this.pendingAnswerRequest;\n this.pendingAnswerRequest = null;\n pendingRequest.resolve(resolvedAnswers);\n return;\n }\n\n // No pending question - fall back to sendPrompt\n await this.sendPrompt(answerText);\n }\n\n cancel(): void {\n this.clearPendingInteractionState('Session cancelled');\n this.clearCompactCompletionFallbackTimer();\n this.clearDeferredQueuedPromptTimer();\n if (this.v2Session) {\n this.v2Session.close();\n this.v2Session = null;\n this.streamLoopRunning = false;\n }\n this.isProcessing = false;\n this.pendingPrompt = null;\n this.awaitingCompactCompletionFallback = false;\n this.clearCompactLateResultSuppression();\n }\n\n getSessionId(): string | null {\n return this.sessionId;\n }\n\n /**\n * Resume a different session by setting its ID.\n * The next sendPrompt call will use this session ID.\n */\n resumeSession(sessionId: string): void {\n // Close existing session if any\n if (this.v2Session) {\n this.v2Session.close();\n this.v2Session = null;\n this.streamLoopRunning = false;\n }\n this.sessionId = sessionId;\n this.isProcessing = false;\n this.pendingPrompt = null;\n this.clearCompactCompletionFallbackTimer();\n this.clearDeferredQueuedPromptTimer();\n this.awaitingCompactCompletionFallback = false;\n this.clearCompactLateResultSuppression();\n this.conversationHistory = []; // Clear local history since we're resuming a different session\n this.emit('session-resumed', sessionId);\n }\n\n isActive(): boolean {\n return this.isProcessing;\n }\n\n getPendingQuestionData(): UserQuestionData | null {\n return this.pendingQuestionData;\n }\n\n getPendingPermissionData(): PermissionRequestData | null {\n return this.pendingPermissionData;\n }\n\n hasPendingPrompt(): boolean {\n return this.pendingPrompt !== null;\n }\n\n async setModel(model: string): Promise<void> {\n if (model === this.currentModel) return;\n\n this.currentModel = model;\n this.clearPendingInteractionState('Session reconfigured');\n this.clearCompactCompletionFallbackTimer();\n this.clearDeferredQueuedPromptTimer();\n\n // Close existing session - a new one will be created with the new model on next sendPrompt()\n if (this.v2Session) {\n this.v2Session.close();\n this.v2Session = null;\n this.streamLoopRunning = false;\n this.sessionId = null;\n this.isProcessing = false;\n this.pendingPrompt = null;\n this.awaitingCompactCompletionFallback = false;\n this.clearCompactLateResultSuppression();\n this.pendingContextTransfer = true;\n } else if (this.sessionId) {\n this.sessionId = null;\n this.awaitingCompactCompletionFallback = false;\n this.clearCompactLateResultSuppression();\n this.pendingContextTransfer = true;\n }\n\n this.emit('model', model);\n }\n\n getModel(): string {\n return this.currentModel;\n }\n\n getConversationHistory(): ConversationMessage[] {\n return [...this.conversationHistory];\n }\n\n clearHistory(): void {\n this.conversationHistory = [];\n this.clearCompactCompletionFallbackTimer();\n this.clearDeferredQueuedPromptTimer();\n // Close existing session and force a fresh one on next prompt\n if (this.v2Session) {\n this.v2Session.close();\n this.v2Session = null;\n this.streamLoopRunning = false;\n }\n this.sessionId = null;\n this.isProcessing = false;\n this.pendingPrompt = null;\n this.awaitingCompactCompletionFallback = false;\n this.clearCompactLateResultSuppression();\n }\n\n private completeCompactCommandFallback(): void {\n this.clearCompactCompletionFallbackTimer();\n this.awaitingCompactCompletionFallback = false;\n this.compactLateResultSuppressedGeneration = this.activeTurnGeneration;\n this.currentAssistantResponse = '';\n this.completeCurrentTurn(COMPACT_QUEUED_DISPATCH_DELAY_MS);\n }\n\n private scheduleCompactCompletionFallback(): void {\n if (this.compactCompletionFallbackTimer) return;\n this.compactCompletionFallbackTimer = setTimeout(() => {\n this.compactCompletionFallbackTimer = null;\n if (this.awaitingCompactCompletionFallback && this.isProcessing) {\n this.completeCompactCommandFallback();\n }\n }, COMPACT_FALLBACK_GRACE_MS);\n }\n\n private clearCompactCompletionFallbackTimer(): void {\n if (this.compactCompletionFallbackTimer) {\n clearTimeout(this.compactCompletionFallbackTimer);\n this.compactCompletionFallbackTimer = null;\n }\n }\n\n private clearDeferredQueuedPromptTimer(): void {\n if (this.deferredQueuedPromptTimer) {\n clearTimeout(this.deferredQueuedPromptTimer);\n this.deferredQueuedPromptTimer = null;\n }\n }\n\n private clearCompactLateResultSuppression(): void {\n this.compactLateResultSuppressedGeneration = null;\n }\n\n private shouldIgnoreLateCompactResult(): boolean {\n const suppressedGeneration = this.compactLateResultSuppressedGeneration;\n if (suppressedGeneration === null) return false;\n\n this.clearCompactLateResultSuppression();\n\n if (this.activeTurnGeneration === suppressedGeneration) return true;\n\n if (this.activeTurnGeneration === suppressedGeneration + 1) {\n const elapsedSinceTurnStart = Date.now() - this.activeTurnStartedAtMs;\n return elapsedSinceTurnStart <= COMPACT_STALE_RESULT_GUARD_MS;\n }\n\n return false;\n }\n\n private completeCurrentTurn(deferQueuedDispatchMs: number = 0): void {\n if (!this.isProcessing) return;\n\n this.isProcessing = false;\n\n // Auto-send queued message if one is pending.\n if (!this.pendingPrompt) {\n this.emit('complete');\n return;\n }\n\n if (deferQueuedDispatchMs > 0) {\n this.clearDeferredQueuedPromptTimer();\n this.deferredQueuedPromptTimer = setTimeout(() => {\n this.deferredQueuedPromptTimer = null;\n const deferred = this.pendingPrompt;\n if (!deferred || this.isProcessing) return;\n this.pendingPrompt = null;\n // Don't emit 'complete' — mobile isTyping stays true seamlessly\n this.sendPrompt(deferred.prompt, deferred.attachments);\n }, deferQueuedDispatchMs);\n return;\n }\n\n const queued = this.pendingPrompt;\n this.pendingPrompt = null;\n // Don't emit 'complete' — mobile isTyping stays true seamlessly\n this.sendPrompt(queued.prompt, queued.attachments);\n }\n\n private clearPendingInteractionState(reason: string): void {\n if (this.pendingAnswerRequest) {\n this.pendingAnswerRequest.reject(new Error(reason));\n this.pendingAnswerRequest = null;\n }\n this.pendingQuestionData = null;\n this.pendingPermissionData = null;\n\n for (const pending of this.pendingPermissionRequests.values()) {\n pending.reject(new Error(reason));\n }\n this.pendingPermissionRequests.clear();\n }\n\n async getSupportedModels(): Promise<ModelInfo[]> {\n // Fallback models matching SDK response format\n const coreModels: ModelInfo[] = [\n { value: 'opus', displayName: 'Opus 4.6', description: 'Opus 4.6 · Most capable for complex work' },\n { value: 'haiku', displayName: 'Haiku 4.5', description: 'Haiku 4.5 · Fastest for quick answers' },\n { value: 'sonnet', displayName: 'Sonnet 4.6', description: 'Sonnet 4.6 · Best for everyday tasks' },\n ];\n\n // Return cached SDK models if available\n if (this.cachedModels) {\n return this.cachedModels;\n }\n\n return coreModels;\n }\n\n /**\n * Scan file system for custom commands/skills\n * Commands are in ~/.claude/commands/ and .claude/commands/\n * Subdirectories create namespaced commands (e.g., gsd/add-phase.md -> gsd:add-phase)\n */\n private scanCustomCommands(): SlashCommand[] {\n const commands: SlashCommand[] = [];\n const homeDir = os.homedir();\n\n // Directories to scan\n const dirs = [\n path.join(homeDir, '.claude', 'commands'), // Personal commands\n path.join(this.options.cwd, '.claude', 'commands'), // Project commands\n ];\n\n for (const dir of dirs) {\n if (!fs.existsSync(dir)) continue;\n\n try {\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n if (entry.isDirectory()) {\n // Namespaced commands (e.g., gsd/)\n const namespace = entry.name;\n const subDir = path.join(dir, namespace);\n const subEntries = fs.readdirSync(subDir);\n\n for (const file of subEntries) {\n if (file.endsWith('.md')) {\n const name = `${namespace}:${file.replace('.md', '')}`;\n const description = this.extractDescription(path.join(subDir, file));\n commands.push({ name, description, argumentHint: '' });\n }\n }\n } else if (entry.isFile() && entry.name.endsWith('.md')) {\n // Top-level commands\n const name = entry.name.replace('.md', '');\n const description = this.extractDescription(path.join(dir, entry.name));\n commands.push({ name, description, argumentHint: '' });\n }\n }\n } catch {\n // Ignore errors scanning directories\n }\n }\n\n return commands;\n }\n\n /**\n * Extract description from markdown file (first line or frontmatter)\n */\n private extractDescription(filePath: string): string {\n try {\n const content = fs.readFileSync(filePath, 'utf-8');\n const lines = content.split('\\n');\n\n // Check for frontmatter description\n if (lines[0] === '---') {\n for (let i = 1; i < lines.length; i++) {\n const line = lines[i];\n if (!line) continue;\n if (line === '---') break;\n if (line.startsWith('description:')) {\n return line.replace('description:', '').trim().replace(/^[\"']|[\"']$/g, '');\n }\n }\n }\n\n // Use first heading or first line as description\n for (const line of lines) {\n const trimmed = line.trim();\n if (trimmed.startsWith('# ')) {\n return trimmed.replace('# ', '');\n }\n if (trimmed && !trimmed.startsWith('---')) {\n return trimmed.slice(0, 100);\n }\n }\n } catch {\n // Ignore errors\n }\n return '';\n }\n\n async getSupportedCommands(): Promise<SlashCommand[]> {\n // Fallback commands - known Claude Code built-in commands\n const fallbackCommands: SlashCommand[] = [\n // Session management\n { name: 'help', description: 'Show all commands and custom slash commands', argumentHint: '' },\n { name: 'clear', description: 'Clear the conversation history', argumentHint: '' },\n { name: 'compact', description: 'Compress conversation by summarizing older messages', argumentHint: '' },\n { name: 'resume', description: 'Resume a previous conversation', argumentHint: '<session-id>' },\n { name: 'rewind', description: 'Go back to a previous message in the session', argumentHint: '' },\n { name: 'context', description: 'Check context and excluded skills', argumentHint: '' },\n // Configuration\n { name: 'config', description: 'Configure Claude Code settings interactively', argumentHint: '' },\n { name: 'permissions', description: 'View or update tool permissions', argumentHint: '' },\n { name: 'allowed-tools', description: 'Configure tool permissions interactively', argumentHint: '' },\n { name: 'model', description: 'Change the AI model', argumentHint: '' },\n { name: 'vim', description: 'Enable vim-style editing mode', argumentHint: '' },\n // Integrations\n { name: 'hooks', description: 'Configure hooks', argumentHint: '' },\n { name: 'mcp', description: 'Manage MCP servers', argumentHint: '' },\n { name: 'agents', description: 'Manage subagents (create, edit, list)', argumentHint: '' },\n { name: 'terminal-setup', description: 'Install terminal shortcuts for iTerm2/VS Code', argumentHint: '' },\n { name: 'install-github-app', description: 'Set up GitHub Actions integration', argumentHint: '' },\n { name: 'ide', description: 'Open in IDE or configure IDE integration', argumentHint: '' },\n // Project\n { name: 'init', description: 'Initialize Claude Code and generate CLAUDE.md', argumentHint: '' },\n { name: 'memory', description: 'Edit CLAUDE.md memory file', argumentHint: '' },\n { name: 'add-dir', description: 'Add a directory to the context', argumentHint: '<path>' },\n // Git & Code Review\n { name: 'commit', description: 'Commit changes to git with a generated message', argumentHint: '' },\n { name: 'review', description: 'Review code changes', argumentHint: '' },\n { name: 'review-pr', description: 'Review a GitHub pull request', argumentHint: '<pr-url>' },\n { name: 'pr-comments', description: 'Get comments from a GitHub pull request', argumentHint: '' },\n { name: 'release-notes', description: 'Generate release notes', argumentHint: '' },\n { name: 'security-review', description: 'Perform a security review', argumentHint: '' },\n // Account & System\n { name: 'login', description: 'Log in to your Anthropic account', argumentHint: '' },\n { name: 'logout', description: 'Log out of your Anthropic account', argumentHint: '' },\n { name: 'doctor', description: 'Check Claude Code health and configuration', argumentHint: '' },\n { name: 'bug', description: 'Report a bug to Anthropic', argumentHint: '' },\n { name: 'cost', description: 'Show token usage and cost', argumentHint: '' },\n { name: 'status', description: 'Show current session status', argumentHint: '' },\n ];\n\n // Get custom commands from file system (includes gsd:* etc.)\n const customCommands = this.scanCustomCommands();\n\n // Start with all commands\n let allCommands: SlashCommand[] = [...customCommands];\n\n // Add cached commands from init message\n if (this.cachedCommands && this.cachedCommands.length > 0) {\n const existingNames = new Set(allCommands.map(c => c.name));\n const newCached = this.cachedCommands.filter(c => !existingNames.has(c.name));\n allCommands = [...allCommands, ...newCached];\n }\n\n // Add fallback commands\n const existingNames = new Set(allCommands.map(c => c.name));\n const uniqueFallbacks = fallbackCommands.filter(c => !existingNames.has(c.name));\n allCommands = [...allCommands, ...uniqueFallbacks];\n\n allCommands = allCommands.filter(c => !UNSUPPORTED_COMMANDS.has(c.name));\n\n return allCommands;\n }\n}\n","import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';\nimport { join, dirname } from 'path';\nimport { homedir } from 'os';\nimport { isPermissionMode } from 'clautunnel-shared';\nimport type {\n InteractiveCommandType,\n InteractiveCommandData,\n InteractiveApplyPayload,\n InteractiveResult,\n InteractiveOption,\n PermissionMode,\n} from 'clautunnel-shared';\n\ninterface ClaudeSettings {\n preferences?: {\n verboseMode?: boolean;\n theme?: string;\n autoCompact?: boolean;\n };\n permissions?: {\n mode?: string;\n allowedTools?: string[];\n allow?: string[];\n };\n vim?: boolean;\n alwaysThinkingEnabled?: boolean;\n}\n\nexport interface ConfigManagerOptions {\n cwd?: string;\n homeDir?: string;\n}\n\nexport class ConfigManager {\n private claudeDir: string;\n private cwd: string;\n\n constructor(options: ConfigManagerOptions = {}) {\n const home = options.homeDir || homedir();\n this.claudeDir = join(home, '.claude');\n this.cwd = options.cwd || process.cwd();\n }\n\n private getGlobalSettingsPath(): string {\n return join(this.claudeDir, 'settings.json');\n }\n\n private getLocalSettingsPath(): string {\n return join(this.claudeDir, 'settings.local.json');\n }\n\n private getProjectSettingsPath(): string {\n return join(this.cwd, '.claude', 'settings.json');\n }\n\n private readSettingsFile(path: string): ClaudeSettings | null {\n try {\n if (existsSync(path)) {\n const content = readFileSync(path, 'utf-8');\n return JSON.parse(content);\n }\n } catch {\n // Silently ignore read errors\n }\n return null;\n }\n\n private writeSettingsFile(path: string, settings: ClaudeSettings): boolean {\n try {\n const dir = dirname(path);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n writeFileSync(path, JSON.stringify(settings, null, 2));\n return true;\n } catch {\n return false;\n }\n }\n\n private getMergedSettings(): ClaudeSettings {\n const global = this.readSettingsFile(this.getGlobalSettingsPath()) || {};\n const local = this.readSettingsFile(this.getLocalSettingsPath()) || {};\n const project = this.readSettingsFile(this.getProjectSettingsPath()) || {};\n\n // Merge settings with project > local > global precedence\n return {\n ...global,\n ...local,\n ...project,\n preferences: {\n ...global.preferences,\n ...local.preferences,\n ...project.preferences,\n },\n permissions: {\n ...global.permissions,\n ...local.permissions,\n ...project.permissions,\n },\n };\n }\n\n /**\n * Get the current thinking mode setting from merged settings\n */\n getThinkingMode(): boolean {\n const settings = this.getMergedSettings();\n return settings.alwaysThinkingEnabled ?? false;\n }\n\n /**\n * Get the current permission mode setting from merged settings\n */\n getPermissionMode(): PermissionMode {\n const settings = this.getMergedSettings();\n const mode = settings.permissions?.mode;\n return isPermissionMode(mode) ? mode : 'default';\n }\n\n getInteractiveData(command: InteractiveCommandType): InteractiveCommandData {\n const settings = this.getMergedSettings();\n\n switch (command) {\n case 'config':\n return this.getConfigData(settings);\n case 'permissions':\n return this.getPermissionsData(settings);\n case 'vim':\n return this.getVimData(settings);\n case 'allowed-tools':\n return this.getAllowedToolsData(settings);\n default:\n return {\n command,\n uiType: 'select',\n title: `${command} Settings`,\n description: 'This command is not yet supported in mobile.',\n options: [],\n };\n }\n }\n\n private getConfigData(settings: ClaudeSettings): InteractiveCommandData {\n const options: InteractiveOption[] = [\n {\n id: 'alwaysThinkingEnabled',\n label: 'Thinking Mode',\n description: 'Enable extended thinking for complex tasks',\n value: settings.alwaysThinkingEnabled || false,\n selected: settings.alwaysThinkingEnabled || false,\n },\n {\n id: 'autoCompact',\n label: 'Auto-Compact',\n description: 'Automatically compact conversation when context is full',\n value: settings.preferences?.autoCompact ?? true,\n selected: settings.preferences?.autoCompact ?? true,\n },\n ];\n\n return {\n command: 'config',\n uiType: 'nested',\n title: 'Configuration',\n description: 'Claude Code preferences and settings',\n options,\n };\n }\n\n private getPermissionsData(settings: ClaudeSettings): InteractiveCommandData {\n const currentMode = settings.permissions?.mode || 'default';\n const options: InteractiveOption[] = [\n {\n id: 'default',\n label: 'Default',\n description: 'Ask before making changes to files',\n value: 'default',\n selected: currentMode === 'default',\n },\n {\n id: 'acceptEdits',\n label: 'Auto-approve Edits',\n description: 'Automatically approve file edits',\n value: 'acceptEdits',\n selected: currentMode === 'acceptEdits',\n },\n {\n id: 'plan',\n label: 'Plan Mode',\n description: 'Only plan changes without executing',\n value: 'plan',\n selected: currentMode === 'plan',\n },\n {\n id: 'bypassPermissions',\n label: 'Yolo Mode',\n description: 'Bypass all permission prompts',\n value: 'bypassPermissions',\n selected: currentMode === 'bypassPermissions',\n },\n ];\n\n return {\n command: 'permissions',\n uiType: 'select',\n title: 'Permission Mode',\n description: 'Select how Claude handles file edits',\n options,\n currentValue: currentMode,\n };\n }\n\n private getVimData(settings: ClaudeSettings): InteractiveCommandData {\n const enabled = settings.vim ?? false;\n\n return {\n command: 'vim',\n uiType: 'toggle',\n title: 'Vim Mode',\n description: 'Enable vim keybindings in the editor',\n options: [\n {\n id: 'vim-enabled',\n label: 'Vim Mode',\n description: enabled ? 'Currently enabled' : 'Currently disabled',\n value: enabled,\n selected: enabled,\n },\n ],\n currentValue: enabled,\n };\n }\n\n private getAllowedToolsData(settings: ClaudeSettings): InteractiveCommandData {\n const allowedTools = settings.permissions?.allowedTools || [];\n const allTools = [\n { id: 'Bash', label: 'Bash', description: 'Execute shell commands' },\n { id: 'Read', label: 'Read', description: 'Read file contents' },\n { id: 'Write', label: 'Write', description: 'Write to files' },\n { id: 'Edit', label: 'Edit', description: 'Edit file contents' },\n { id: 'Glob', label: 'Glob', description: 'Search for files' },\n { id: 'Grep', label: 'Grep', description: 'Search file contents' },\n { id: 'WebFetch', label: 'WebFetch', description: 'Fetch web content' },\n { id: 'WebSearch', label: 'WebSearch', description: 'Search the web' },\n ];\n\n const options: InteractiveOption[] = allTools.map((tool) => ({\n ...tool,\n value: tool.id,\n selected: allowedTools.includes(tool.id),\n }));\n\n return {\n command: 'allowed-tools',\n uiType: 'multi-select',\n title: 'Allowed Tools',\n description: 'Select which tools Claude can use',\n options,\n currentValue: allowedTools,\n };\n }\n\n applyChange(payload: InteractiveApplyPayload): InteractiveResult {\n const globalPath = this.getGlobalSettingsPath();\n const settings = this.readSettingsFile(globalPath) || {};\n\n try {\n switch (payload.command) {\n case 'config':\n return this.applyConfigChange(settings, globalPath, payload);\n case 'permissions':\n return this.applyPermissionsChange(settings, globalPath, payload);\n case 'vim':\n return this.applyVimChange(settings, globalPath, payload);\n case 'allowed-tools':\n return this.applyAllowedToolsChange(settings, globalPath, payload);\n default:\n return {\n success: false,\n message: `Unknown command: ${payload.command}`,\n };\n }\n } catch (error) {\n return {\n success: false,\n message: error instanceof Error ? error.message : 'Unknown error',\n };\n }\n }\n\n private applyConfigChange(\n settings: ClaudeSettings,\n path: string,\n payload: InteractiveApplyPayload\n ): InteractiveResult {\n if (!settings.preferences) {\n settings.preferences = {};\n }\n\n switch (payload.key) {\n case 'theme':\n settings.preferences.theme = payload.value as string;\n break;\n case 'alwaysThinkingEnabled':\n // alwaysThinkingEnabled is at root level, not in preferences\n settings.alwaysThinkingEnabled = payload.value as boolean;\n break;\n case 'autoCompact':\n settings.preferences.autoCompact = payload.value as boolean;\n break;\n case 'verbose':\n settings.preferences.verboseMode = payload.value as boolean;\n break;\n default:\n return { success: false, message: `Unknown config key: ${payload.key}` };\n }\n\n if (this.writeSettingsFile(path, settings)) {\n return { success: true, message: `Config ${payload.key} updated` };\n }\n return { success: false, message: 'Failed to write settings file' };\n }\n\n private applyPermissionsChange(\n settings: ClaudeSettings,\n path: string,\n payload: InteractiveApplyPayload\n ): InteractiveResult {\n if (!settings.permissions) {\n settings.permissions = {};\n }\n\n settings.permissions.mode = payload.value as string;\n\n if (this.writeSettingsFile(path, settings)) {\n return { success: true, message: `Permission mode set to ${payload.value}` };\n }\n return { success: false, message: 'Failed to write settings file' };\n }\n\n private applyVimChange(\n settings: ClaudeSettings,\n path: string,\n payload: InteractiveApplyPayload\n ): InteractiveResult {\n if (payload.action === 'toggle') {\n settings.vim = !settings.vim;\n } else {\n settings.vim = payload.value as boolean;\n }\n\n if (this.writeSettingsFile(path, settings)) {\n return { success: true, message: `Vim mode ${settings.vim ? 'enabled' : 'disabled'}` };\n }\n return { success: false, message: 'Failed to write settings file' };\n }\n\n private applyAllowedToolsChange(\n settings: ClaudeSettings,\n path: string,\n payload: InteractiveApplyPayload\n ): InteractiveResult {\n if (!settings.permissions) {\n settings.permissions = {};\n }\n if (!settings.permissions.allowedTools) {\n settings.permissions.allowedTools = [];\n }\n\n const toolId = payload.value as string;\n\n switch (payload.action) {\n case 'add':\n if (!settings.permissions.allowedTools.includes(toolId)) {\n settings.permissions.allowedTools.push(toolId);\n }\n break;\n case 'remove':\n settings.permissions.allowedTools = settings.permissions.allowedTools.filter(\n (t) => t !== toolId\n );\n break;\n case 'set':\n settings.permissions.allowedTools = payload.value as string[];\n break;\n case 'toggle':\n if (settings.permissions.allowedTools.includes(toolId)) {\n settings.permissions.allowedTools = settings.permissions.allowedTools.filter(\n (t) => t !== toolId\n );\n } else {\n settings.permissions.allowedTools.push(toolId);\n }\n break;\n }\n\n if (this.writeSettingsFile(path, settings)) {\n return { success: true, message: 'Allowed tools updated' };\n }\n return { success: false, message: 'Failed to write settings file' };\n }\n}\n","import { Command } from 'commander';\nimport WebSocket from 'ws';\nimport { Daemon } from '../daemon/daemon.js';\nimport { MachineManager } from '../daemon/machine.js';\nimport { MachineRealtimeClient } from '../realtime/machine-client.js';\nimport { Config, ConfigurationError } from '../utils/config.js';\nimport { Logger } from '../utils/logger.js';\nimport { Spinner } from '../utils/spinner.js';\nimport { createSupabaseClient, restoreSession } from '../utils/supabase.js';\nimport {\n promptYesNo,\n enableSleepPrevention,\n startCaffeinate,\n cleanup as cleanupSleep,\n isMacOS,\n checkFullDiskAccess,\n getFullDiskAccessStatus,\n getTerminalAppName,\n openFullDiskAccessSettings,\n type SleepPreventionState,\n type FullDiskAccessStatus,\n} from '../utils/sleep-prevention.js';\nimport { MobileServerManager } from '../mobile/mobile-server.js';\nimport { acquirePidFile, removePidFile } from '../utils/pid.js';\nimport { checkClaudeCliAuth } from '../utils/claude-auth.js';\nimport type { MachineCommand } from 'clautunnel-shared';\n\n// Polyfill WebSocket for Node.js (Supabase Realtime needs this)\nif (typeof globalThis.WebSocket === 'undefined') {\n // @ts-expect-error WebSocket polyfill for Node.js\n globalThis.WebSocket = WebSocket;\n}\n\nexport interface StartOptions {\n name?: string;\n preventSleep?: boolean;\n mobile?: boolean;\n}\n\nexport function createStartCommand(): Command {\n const command = new Command('start');\n\n command\n .description('Start ClauTunnel and listen for session requests from mobile app')\n .option('-n, --name <name>', 'Machine name')\n .option('--prevent-sleep', 'Auto-enable sleep prevention (skip prompt)')\n .option('--no-mobile', 'Skip mobile server startup')\n .action(async (options: StartOptions) => {\n const config = new Config();\n const logger = new Logger();\n const spinner = new Spinner('Starting ClauTunnel...');\n\n const daemons: Map<string, Daemon> = new Map(); // sessionId -> Daemon\n let machineClient: MachineRealtimeClient | null = null;\n\n try {\n // Enforce single process per machine (atomic check + acquire)\n const existingPid = acquirePidFile();\n if (existingPid !== null) {\n logger.error(`Another clautunnel process is already running (PID: ${existingPid})`);\n logger.error('Run \"clautunnel stop\" first, or kill the existing process.');\n process.exit(1);\n }\n\n config.requireConfiguration();\n\n spinner.start();\n\n const supabase = createSupabaseClient(\n config.getSupabaseUrl(),\n config.getSupabaseAnonKey(),\n { realtime: true }\n );\n\n // Restore session from stored tokens\n spinner.update('Authenticating...');\n\n const session = await restoreSession(supabase, config);\n if (!session) {\n spinner.fail('Not authenticated');\n logger.error(\n 'Run \"clautunnel login\" or \"clautunnel signup\" first.'\n );\n removePidFile();\n process.exit(1);\n }\n\n const { user } = session;\n\n // Persist tokens when Supabase auto-refreshes during long-running sessions\n const {\n data: { subscription: authSubscription },\n } = supabase.auth.onAuthStateChange((event, authSession) => {\n if (event === 'TOKEN_REFRESHED' && authSession) {\n config.setSessionTokens({\n accessToken: authSession.access_token,\n refreshToken: authSession.refresh_token,\n });\n }\n });\n\n spinner.update(`Authenticated as ${user.email}...`);\n\n // Check Claude CLI authentication (Anthropic API)\n spinner.update('Checking Claude CLI auth...');\n const claudeAuth = checkClaudeCliAuth();\n if (!claudeAuth.loggedIn) {\n switch (claudeAuth.failure) {\n case 'cli_not_found':\n spinner.fail('Claude CLI not found');\n logger.error('Claude Code CLI is not installed or not in PATH.');\n logger.error('Install it first: https://docs.anthropic.com/en/docs/claude-code');\n removePidFile();\n process.exit(1);\n break;\n case 'subcommand_not_supported':\n // Older CLI version that doesn't have `auth status` — skip the check\n spinner.update('Claude CLI auth check skipped (CLI version does not support \"auth status\")');\n logger.warn('Could not verify Claude CLI auth — your CLI version may not support \"claude auth status\".');\n logger.warn('If sessions fail to start, try updating Claude Code and running \"claude login\".');\n break;\n case 'not_logged_in':\n spinner.fail('Claude CLI is not logged in');\n logger.error('Claude Code requires authentication to use the Anthropic API.');\n logger.error('Run \"claude login\" first, then try \"clautunnel start\" again.');\n removePidFile();\n process.exit(1);\n break;\n default:\n // Unknown error — warn but don't block\n spinner.update('Claude CLI auth check inconclusive');\n logger.warn('Could not verify Claude CLI authentication (unexpected error).');\n logger.warn('If sessions fail to start, run \"claude login\" and try again.');\n break;\n }\n }\n\n // Check Full Disk Access (macOS only)\n let fdaStatus: FullDiskAccessStatus | null = null;\n\n if (isMacOS()) {\n spinner.stop();\n\n const terminalApp = getTerminalAppName();\n let fdaEnabled = checkFullDiskAccess();\n fdaStatus = getFullDiskAccessStatus(fdaEnabled, terminalApp);\n\n if (fdaStatus.enabled) {\n logger.info(`✓ Full Disk Access: ${fdaStatus.label}`);\n } else {\n logger.warn(`⚠ Full Disk Access: ${fdaStatus.label}`);\n logger.warn('');\n for (const line of fdaStatus.warning!.split('\\n')) {\n logger.warn(` ${line}`);\n }\n logger.warn('');\n\n const openSettings = await promptYesNo(\n 'Open Full Disk Access settings? [Y/n]: '\n );\n\n if (openSettings) {\n openFullDiskAccessSettings();\n logger.info('');\n await promptYesNo(\n 'Press Enter after enabling Full Disk Access (or Enter to skip): '\n );\n\n // Recheck FDA status\n fdaEnabled = checkFullDiskAccess();\n fdaStatus = getFullDiskAccessStatus(fdaEnabled, terminalApp);\n\n if (fdaStatus.enabled) {\n logger.info('✓ Full Disk Access: Enabled');\n } else {\n logger.warn('Full Disk Access still not enabled. Continuing without it.');\n }\n }\n\n logger.info('');\n }\n\n spinner.start();\n }\n\n // Handle sleep prevention (macOS only)\n const sleepState: SleepPreventionState = {\n caffeinateProcess: null,\n pmsetEnabled: false,\n };\n\n if (isMacOS()) {\n spinner.stop();\n\n // Auto-enable if --prevent-sleep flag is used, otherwise ask\n const enableSleep =\n options.preventSleep ||\n (await promptYesNo(\n 'Prevent sleep when lid is closed? (keeps clautunnel running) [y/N]: '\n ));\n\n if (enableSleep) {\n logger.info('');\n logger.info('Enabling sleep prevention...');\n if (!options.preventSleep) {\n logger.info('This requires sudo password (auto-restored on exit)');\n logger.info('');\n }\n\n sleepState.pmsetEnabled = enableSleepPrevention();\n if (sleepState.pmsetEnabled) {\n logger.info('✓ Lid-closed mode enabled');\n } else {\n logger.warn('Failed to enable lid-closed mode. Using basic mode.');\n }\n\n // Start caffeinate to prevent idle sleep\n sleepState.caffeinateProcess = startCaffeinate();\n\n sleepState.caffeinateProcess.on('error', () => {\n logger.warn('Failed to start caffeinate');\n });\n\n logger.info('');\n }\n\n spinner.start();\n }\n\n // Mobile server\n let mobileServer: MobileServerManager | null = null;\n\n if (options.mobile !== false) {\n // Create a pairing code via Edge Function (service role insert, not direct RLS).\n // supabase.functions is a getter that creates a new FunctionsClient each time\n // and doesn't inherit the refreshed session token, so we pass it explicitly.\n const { data: { session: currentSession } } = await supabase.auth.getSession();\n const { data: pairingData, error: pairingError } = await supabase\n .functions.invoke('create-mobile-pairing', {\n headers: { Authorization: `Bearer ${currentSession?.access_token}` },\n });\n\n if (pairingError || !pairingData?.code) {\n spinner.fail('Failed to create mobile pairing code');\n logger.error(pairingError?.message ?? 'No pairing code returned');\n removePidFile();\n process.exit(1);\n }\n\n const pairingCode = pairingData.code;\n\n const mobileProjectPath = config.getMobileProjectPath();\n mobileServer = new MobileServerManager({\n mobileProjectPath,\n supabaseUrl: config.getSupabaseUrl(),\n supabaseAnonKey: config.getSupabaseAnonKey(),\n pairingCode,\n onProgress: (msg) => spinner.update(msg),\n });\n\n const result = await mobileServer.start();\n spinner.stop();\n\n if (result.started) {\n logger.info('');\n logger.info(` Tunnel: ${result.tunnelUrl}`);\n logger.info('');\n } else {\n logger.error(`Mobile server failed: ${result.error}`);\n removePidFile();\n process.exit(1);\n }\n\n spinner.start();\n }\n\n // Cleanup helper\n const cleanup = async () => {\n removePidFile();\n if (mobileServer) {\n try {\n await mobileServer.stop();\n } catch {\n // Best-effort cleanup\n }\n }\n if (sleepState.pmsetEnabled) {\n console.log('Restoring sleep settings...');\n }\n cleanupSleep(sleepState);\n };\n\n spinner.update('Registering machine...');\n\n // Register machine\n const machineManager = new MachineManager({ supabase });\n const machine = await machineManager.registerMachine(\n user.id,\n options.name,\n config.getMachineId()\n );\n\n // Save machine ID for future use\n config.setMachineId(machine.id);\n\n // Handle process signals — registered after machine is available\n // so gracefulShutdown can reliably set offline status\n let isShuttingDown = false;\n\n const gracefulShutdown = async (signal: string) => {\n if (isShuttingDown) {\n console.log('\\nForce exiting...');\n process.exit(1);\n }\n isShuttingDown = true;\n console.log(`\\n[${signal}] Shutting down gracefully...`);\n try {\n for (const [sessionId, d] of daemons) {\n try {\n await d.stop();\n } catch {\n // Continue stopping other daemons\n }\n daemons.delete(sessionId);\n }\n // Set machine status to offline now that all sessions are stopped\n try {\n await machineManager.updateMachineStatus(machine.id, 'offline');\n } catch {\n // Best-effort - don't block shutdown\n }\n if (machineClient) {\n await machineClient.disconnect();\n machineClient = null;\n }\n authSubscription.unsubscribe();\n console.log('[Cleanup] All sessions ended in database');\n await cleanup();\n } catch (error) {\n console.error('[Cleanup] Error during shutdown:', error);\n }\n process.exit(0);\n };\n\n process.on('SIGINT', () => {\n gracefulShutdown('SIGINT').catch(console.error);\n });\n\n process.on('SIGTERM', () => {\n gracefulShutdown('SIGTERM').catch(console.error);\n });\n\n spinner.update('Connecting to realtime...');\n\n // Create machine-level realtime client\n machineClient = new MachineRealtimeClient({\n supabase,\n machineId: machine.id,\n });\n\n const connected = await machineClient.connect();\n\n spinner.stop();\n\n if (!connected) {\n logger.error('Failed to connect to Supabase Realtime.');\n logger.error('');\n logger.error('This may be a temporary issue. Try the following:');\n logger.error(' 1. Open a new terminal and run \"clautunnel start\" again');\n logger.error(' 2. Check your network connection');\n logger.error(' 3. Try \"clautunnel login\" to refresh your session');\n removePidFile();\n process.exit(1);\n }\n\n logger.info('');\n logger.info('✓ ClauTunnel is ready!');\n logger.info(` Machine: ${machine.name}`);\n if (fdaStatus) {\n if (fdaStatus.enabled) {\n logger.info(` Full Disk Access: ${fdaStatus.label}`);\n } else {\n logger.warn(` Full Disk Access: ${fdaStatus.label}`);\n }\n }\n if (sleepState.caffeinateProcess) {\n logger.info(\n ` Sleep prevention: ${sleepState.pmsetEnabled ? 'Lid-closed mode' : 'Basic mode'}`\n );\n }\n if (mobileServer) {\n logger.info(' Mobile server: Running');\n }\n logger.info('');\n logger.info('Open the mobile app to start a session.');\n logger.info('Press Ctrl+C to stop.');\n logger.info('');\n\n // Handle incoming commands from mobile\n machineClient.on('command', async (cmd: MachineCommand) => {\n if (cmd.type === 'start-session') {\n logger.info('Starting session (requested from mobile)...');\n\n try {\n const newDaemon = new Daemon({\n supabase,\n userId: user.id,\n machineId: machine.id,\n machineName: options.name,\n cwd: process.cwd(),\n hybrid: false,\n });\n\n newDaemon.on('started', async ({ session }) => {\n daemons.set(session.id, newDaemon);\n\n logger.info(` Session: ${session.id.slice(0, 8)}...`);\n logger.info(' Mobile sync: Enabled');\n logger.info(` Active sessions: ${daemons.size}`);\n logger.info('');\n\n await machineClient?.broadcastSessionStarted(\n session.id,\n process.cwd()\n );\n });\n\n newDaemon.on('error', (error: Error) => {\n logger.error(`Session error: ${error.message}`);\n });\n\n newDaemon.on('mobile-input', (prompt: string, attachments?: unknown[]) => {\n const hasImages = attachments && attachments.length > 0;\n const imageInfo = hasImages ? ` [+${attachments.length} image${attachments.length > 1 ? 's' : ''}]` : '';\n logger.info(`[Mobile] ${prompt}${imageInfo}`);\n });\n\n newDaemon.on('mobile-output', (data: string) => {\n const trimmed = data.trim();\n if (trimmed) {\n logger.info(`[Claude] ${trimmed}`);\n }\n });\n\n newDaemon.on('mobile-disconnected', async () => {\n logger.info('Mobile disconnected. Ending session...');\n try {\n await newDaemon.stop();\n } catch {\n // Silently handle stop errors - stopped handler handles the rest\n }\n });\n\n newDaemon.on('stopped', async () => {\n const sessionId = newDaemon.getSession()?.id;\n if (sessionId) {\n daemons.delete(sessionId);\n await machineClient?.broadcastSessionEnded(sessionId);\n }\n\n logger.info('Session ended.');\n logger.info(` Active sessions: ${daemons.size}`);\n logger.info('');\n if (daemons.size === 0) {\n logger.info('Waiting for next session request...');\n logger.info('');\n }\n });\n\n await newDaemon.start();\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n logger.error(`Failed to start session: ${errorMessage}`);\n await machineClient?.broadcastError(errorMessage);\n }\n }\n\n if (cmd.type === 'stop-session' && cmd.sessionId) {\n const targetDaemon = daemons.get(cmd.sessionId);\n if (targetDaemon) {\n logger.info(`Stopping session ${cmd.sessionId.slice(0, 8)}... (requested from mobile)`);\n try {\n await targetDaemon.stop();\n } catch {\n // Silently handle stop errors\n }\n }\n }\n });\n } catch (error) {\n removePidFile();\n if (error instanceof ConfigurationError) {\n spinner.stop();\n logger.error(error.message);\n process.exit(1);\n }\n spinner.fail('Failed to start');\n logger.error(\n `${error instanceof Error ? error.message : 'Unknown error'}`\n );\n process.exit(1);\n }\n });\n\n return command;\n}\n","import { EventEmitter } from 'events';\nimport type { SupabaseClient, RealtimeChannel } from '@supabase/supabase-js';\nimport type { MachineCommand, PresencePayload } from 'clautunnel-shared';\nimport { REALTIME_CHANNELS } from 'clautunnel-shared';\nimport { subscribeWithTimeout } from './utils.js';\n\nexport interface MachineRealtimeClientOptions {\n supabase: SupabaseClient;\n machineId: string;\n}\n\nexport class MachineRealtimeClient extends EventEmitter {\n private supabase: SupabaseClient;\n private machineId: string;\n private inputChannel: RealtimeChannel | null = null;\n private outputChannel: RealtimeChannel | null = null;\n private presenceChannel: RealtimeChannel | null = null;\n\n constructor(options: MachineRealtimeClientOptions) {\n super();\n this.supabase = options.supabase;\n this.machineId = options.machineId;\n }\n\n async connect(): Promise<boolean> {\n const privateConfig = { config: { private: true } };\n\n // Subscribe to input channel (receives commands from mobile)\n const inputChannelName = REALTIME_CHANNELS.machineInput(this.machineId);\n this.inputChannel = this.supabase.channel(inputChannelName, privateConfig);\n\n this.inputChannel.on('broadcast', { event: 'machine-command' }, (payload) => {\n this.emit('command', payload.payload as MachineCommand);\n });\n\n // Subscribe to output channel (sends responses to mobile)\n const outputChannelName = REALTIME_CHANNELS.machineOutput(this.machineId);\n this.outputChannel = this.supabase.channel(outputChannelName, privateConfig);\n\n const results = await Promise.all([\n subscribeWithTimeout(this.inputChannel, 'machine-input'),\n subscribeWithTimeout(this.outputChannel, 'machine-output'),\n ]);\n\n const connected = results.every((success) => success);\n\n // Set up presence channel to track listener online status\n if (connected) {\n const presenceChannelName = REALTIME_CHANNELS.machinePresence(this.machineId);\n this.presenceChannel = this.supabase.channel(presenceChannelName, privateConfig);\n\n this.presenceChannel.subscribe(async (status) => {\n if (status === 'SUBSCRIBED' && this.presenceChannel) {\n try {\n const payload: PresencePayload = {\n type: 'cli',\n online_at: new Date().toISOString(),\n };\n await this.presenceChannel.track(payload);\n } catch (trackError) {\n console.warn('[WARN] Failed to track machine presence:', trackError);\n }\n }\n });\n }\n\n return connected;\n }\n\n async broadcastSessionStarted(sessionId: string, workingDirectory: string): Promise<void> {\n if (!this.outputChannel) return;\n\n const command: MachineCommand = {\n type: 'session-started',\n sessionId,\n workingDirectory,\n timestamp: Date.now(),\n };\n\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'machine-command',\n payload: command,\n });\n }\n\n async broadcastSessionEnded(sessionId: string): Promise<void> {\n if (!this.outputChannel) return;\n\n const command: MachineCommand = {\n type: 'session-ended',\n sessionId,\n timestamp: Date.now(),\n };\n\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'machine-command',\n payload: command,\n });\n }\n\n async broadcastError(error: string): Promise<void> {\n if (!this.outputChannel) return;\n\n const command: MachineCommand = {\n type: 'start-session-error',\n error,\n timestamp: Date.now(),\n };\n\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'machine-command',\n payload: command,\n });\n }\n\n async disconnect(): Promise<void> {\n if (this.presenceChannel) {\n await this.presenceChannel.untrack();\n await this.supabase.removeChannel(this.presenceChannel);\n this.presenceChannel = null;\n }\n\n if (this.inputChannel) {\n await this.supabase.removeChannel(this.inputChannel);\n this.inputChannel = null;\n }\n\n if (this.outputChannel) {\n await this.supabase.removeChannel(this.outputChannel);\n this.outputChannel = null;\n }\n\n this.emit('disconnected');\n }\n}\n","export class Spinner {\n private frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];\n private currentFrame = 0;\n private interval: NodeJS.Timeout | null = null;\n private message: string;\n private stream: NodeJS.WriteStream;\n\n constructor(message: string, stream: NodeJS.WriteStream = process.stdout) {\n this.message = message;\n this.stream = stream;\n }\n\n start(): void {\n if (this.interval) {\n return;\n }\n\n // Hide cursor\n this.stream.write('\\x1B[?25l');\n\n this.interval = setInterval(() => {\n const frame = this.frames[this.currentFrame];\n this.stream.write(`\\r${frame} ${this.message}`);\n this.currentFrame = (this.currentFrame + 1) % this.frames.length;\n }, 80);\n }\n\n update(message: string): void {\n this.message = message;\n }\n\n stop(): void {\n if (this.interval) {\n clearInterval(this.interval);\n this.interval = null;\n }\n\n // Clear the line and show cursor\n this.stream.write('\\r\\x1B[K');\n this.stream.write('\\x1B[?25h');\n }\n\n succeed(message: string): void {\n this.stop();\n this.stream.write(`\\r✓ ${message}\\n`);\n }\n\n fail(message: string): void {\n this.stop();\n this.stream.write(`\\r✗ ${message}\\n`);\n }\n}\n","import { createClient, type SupabaseClient } from '@supabase/supabase-js';\n\nexport interface CreateSupabaseClientOptions {\n realtime?: boolean;\n}\n\nexport function createSupabaseClient(\n url: string,\n anonKey: string,\n options?: CreateSupabaseClientOptions\n): SupabaseClient {\n const clientOptions = options?.realtime\n ? {\n realtime: {\n params: { eventsPerSecond: 10 },\n timeout: 30000,\n },\n }\n : undefined;\n\n return createClient(url, anonKey, clientOptions);\n}\n\nexport interface SessionTokenStore {\n getSessionTokens(): { accessToken: string; refreshToken: string } | null;\n setSessionTokens(tokens: { accessToken: string; refreshToken: string }): void;\n clearSessionTokens(): void;\n}\n\nexport async function restoreSession(\n supabase: SupabaseClient,\n config: SessionTokenStore\n): Promise<{ user: any } | null> {\n const sessionTokens = config.getSessionTokens();\n if (!sessionTokens) {\n return null;\n }\n\n const { data: sessionData, error: sessionError } =\n await supabase.auth.setSession({\n access_token: sessionTokens.accessToken,\n refresh_token: sessionTokens.refreshToken,\n });\n\n if (sessionError) {\n config.clearSessionTokens();\n return null;\n }\n\n // Persist refreshed tokens if Supabase rotated them\n if (sessionData?.session) {\n const newAccess = sessionData.session.access_token;\n const newRefresh = sessionData.session.refresh_token;\n if (\n newAccess !== sessionTokens.accessToken ||\n newRefresh !== sessionTokens.refreshToken\n ) {\n config.setSessionTokens({\n accessToken: newAccess,\n refreshToken: newRefresh,\n });\n }\n }\n\n const {\n data: { user },\n error: authError,\n } = await supabase.auth.getUser();\n\n if (authError || !user) {\n return null;\n }\n\n return { user };\n}\n","import { spawn, execSync, type ChildProcess } from 'child_process';\nimport * as readline from 'readline';\nimport { readdirSync } from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\n\nexport interface SleepPreventionState {\n caffeinateProcess: ChildProcess | null;\n pmsetEnabled: boolean;\n}\n\nexport async function promptYesNo(question: string): Promise<boolean> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');\n });\n });\n}\n\nexport function enableSleepPrevention(): boolean {\n try {\n execSync('sudo pmset -a disablesleep 1', { stdio: 'inherit' });\n return true;\n } catch {\n return false;\n }\n}\n\nexport function disableSleepPrevention(): void {\n try {\n execSync('sudo pmset -a disablesleep 0', { stdio: 'inherit' });\n } catch {\n // Ignore errors on cleanup\n }\n}\n\nexport function startCaffeinate(): ChildProcess {\n const process = spawn('caffeinate', ['-i', '-s'], {\n stdio: 'ignore',\n detached: false,\n });\n\n return process;\n}\n\nexport function stopCaffeinate(process: ChildProcess | null): void {\n if (process) {\n process.kill();\n }\n}\n\nexport function cleanup(state: SleepPreventionState): void {\n stopCaffeinate(state.caffeinateProcess);\n if (state.pmsetEnabled) {\n disableSleepPrevention();\n }\n}\n\nexport function isMacOS(): boolean {\n return process.platform === 'darwin';\n}\n\nexport interface FullDiskAccessStatus {\n enabled: boolean;\n label: string;\n warning?: string;\n}\n\n/**\n * Checks if Full Disk Access is granted on macOS by attempting to read\n * a TCC-protected directory. Returns true on non-macOS platforms.\n */\nexport function checkFullDiskAccess(): boolean {\n if (!isMacOS()) return true;\n\n try {\n const safariDir = path.join(os.homedir(), 'Library', 'Safari');\n readdirSync(safariDir);\n return true;\n } catch {\n return false;\n }\n}\n\nconst TERM_PROGRAM_MAP: Record<string, string> = {\n vscode: 'Visual Studio Code',\n Apple_Terminal: 'Terminal',\n 'iTerm.app': 'iTerm2',\n WarpTerminal: 'Warp',\n Hyper: 'Hyper',\n};\n\n/**\n * Detects the terminal application name from the TERM_PROGRAM environment variable.\n */\nexport function getTerminalAppName(): string {\n const termProgram = process.env.TERM_PROGRAM;\n if (termProgram && TERM_PROGRAM_MAP[termProgram]) {\n return TERM_PROGRAM_MAP[termProgram];\n }\n return 'your terminal app';\n}\n\n/**\n * Opens macOS System Settings to the Full Disk Access pane.\n * Returns true on success, false on failure or non-macOS platforms.\n */\nexport function openFullDiskAccessSettings(): boolean {\n if (!isMacOS()) return false;\n\n try {\n execSync(\n 'open \"x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles\"'\n );\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Returns a structured status object with label and optional warning message\n * describing the Full Disk Access state and its implications for remote usage.\n */\nexport function getFullDiskAccessStatus(enabled: boolean, terminalApp?: string): FullDiskAccessStatus {\n if (enabled) {\n return {\n enabled: true,\n label: 'Enabled',\n };\n }\n\n const appName = terminalApp || 'your terminal app';\n\n return {\n enabled: false,\n label: 'Not enabled',\n warning: [\n 'Without Full Disk Access, macOS may show permission dialogs',\n 'when Claude tries to access certain files or directories.',\n 'These dialogs are only visible on this machine\\'s screen —',\n 'you won\\'t be able to see or approve them from the mobile app,',\n 'which will cause Claude\\'s operations to silently hang.',\n '',\n 'To enable:',\n ` 1. Open System Settings → Privacy & Security → Full Disk Access`,\n ` 2. Toggle ON \"${appName}\" in the list`,\n ' 3. Restart your terminal and run \"clautunnel start\" again',\n ].join('\\n'),\n };\n}\n","import { spawn, execSync, type ChildProcess } from 'child_process';\nimport {\n existsSync,\n mkdirSync,\n writeFileSync,\n createWriteStream,\n type WriteStream,\n} from 'fs';\nimport { join } from 'path';\nimport { homedir } from 'os';\nimport { get } from 'http';\nimport qrcode from 'qrcode-terminal';\n\nconst REPO_URL = 'https://github.com/TongilKim/ClauTunnel.git';\nconst DEFAULT_MOBILE_DIR = join(homedir(), '.clautunnel', 'mobile');\n\nexport interface MobileServerOptions {\n mobileProjectPath?: string;\n supabaseUrl: string;\n supabaseAnonKey: string;\n pairingCode?: string;\n expoPort?: number;\n logDir?: string;\n onProgress?: (message: string) => void;\n}\n\nexport interface MobileServerResult {\n started: boolean;\n tunnelUrl?: string;\n error?: string;\n}\n\ninterface PrerequisiteResult {\n ready: boolean;\n issues: string[];\n needsInstall: boolean;\n}\n\nexport class MobileServerManager {\n private options: MobileServerOptions;\n private mobileProjectPath: string;\n private logDir: string;\n private expoPort: number;\n private ngrokProcess: ChildProcess | null = null;\n private expoProcess: ChildProcess | null = null;\n private ngrokLogStream: WriteStream | null = null;\n private expoLogStream: WriteStream | null = null;\n private tunnelUrl: string | null = null;\n private onProgress: (message: string) => void;\n private hasCustomPath: boolean;\n\n constructor(options: MobileServerOptions) {\n this.options = options;\n this.hasCustomPath = options.mobileProjectPath !== undefined;\n this.mobileProjectPath = options.mobileProjectPath ?? DEFAULT_MOBILE_DIR;\n this.expoPort = options.expoPort ?? 8081;\n this.logDir = options.logDir ?? join(homedir(), '.clautunnel', 'logs');\n this.onProgress = options.onProgress ?? (() => {});\n }\n\n getMobileProjectPath(): string {\n return this.mobileProjectPath;\n }\n\n checkPrerequisites(): PrerequisiteResult {\n const issues: string[] = [];\n let needsInstall = false;\n\n // Path check is skipped here — ensureMobileProject handles it\n\n // Check ngrok installation and authtoken\n try {\n execSync('which ngrok', { stdio: 'pipe' });\n\n // ngrok is installed — verify authtoken is configured\n try {\n const configOutput = execSync('ngrok config check', {\n stdio: 'pipe',\n timeout: 5000,\n }).toString();\n // \"Valid configuration file\" means authtoken is set\n if (!configOutput.toLowerCase().includes('valid')) {\n issues.push(\n 'ngrok authtoken is not configured.\\n' +\n ' 1. Sign up at https://ngrok.com\\n' +\n ' 2. Copy your authtoken from https://dashboard.ngrok.com/get-started/your-authtoken\\n' +\n ' 3. Run: ngrok config add-authtoken <your-token>'\n );\n }\n } catch {\n // ngrok config check failed — likely no authtoken\n issues.push(\n 'ngrok authtoken is not configured.\\n' +\n ' 1. Sign up at https://ngrok.com\\n' +\n ' 2. Copy your authtoken from https://dashboard.ngrok.com/get-started/your-authtoken\\n' +\n ' 3. Run: ngrok config add-authtoken <your-token>'\n );\n }\n } catch {\n issues.push(\n 'ngrok is not installed.\\n' +\n ' Install: brew install ngrok\\n' +\n ' Then configure your account:\\n' +\n ' 1. Sign up at https://ngrok.com\\n' +\n ' 2. Copy your authtoken from https://dashboard.ngrok.com/get-started/your-authtoken\\n' +\n ' 3. Run: ngrok config add-authtoken <your-token>'\n );\n }\n\n // Check node_modules\n const nodeModulesPath = join(this.mobileProjectPath, 'node_modules');\n if (!existsSync(nodeModulesPath)) {\n needsInstall = true;\n }\n\n return { ready: issues.length === 0, issues, needsInstall };\n }\n\n ensureMobileProject(): { ready: boolean; cloned: boolean; error?: string } {\n // Check if apps/mobile subdir exists (handles both custom path and cloned repo)\n const packageJson = join(this.mobileProjectPath, 'package.json');\n if (existsSync(packageJson)) {\n return { ready: true, cloned: false };\n }\n\n // If custom path was provided and doesn't exist, don't auto-clone\n if (this.hasCustomPath) {\n return {\n ready: false,\n cloned: false,\n error: `Mobile project path not found: ${this.mobileProjectPath}`,\n };\n }\n\n // Auto-clone to default location\n try {\n // Check git is installed\n execSync('which git', { stdio: 'pipe' });\n } catch {\n return {\n ready: false,\n cloned: false,\n error: 'git is required to download the mobile app.\\n' +\n ' Install: https://git-scm.com/downloads\\n' +\n ' macOS: xcode-select --install',\n };\n }\n\n try {\n // Clone only the apps/mobile directory using sparse checkout\n const clautunnelDir = join(homedir(), '.clautunnel');\n if (!existsSync(clautunnelDir)) {\n mkdirSync(clautunnelDir, { recursive: true });\n }\n\n // Clone with depth 1 and sparse checkout for apps/mobile only\n const repoDir = join(clautunnelDir, 'repo');\n if (existsSync(repoDir)) {\n // Reset any local changes (e.g. pnpm-lock.yaml modified by install) before pulling\n execSync('git checkout -- .', {\n cwd: repoDir,\n stdio: 'pipe',\n timeout: 10000,\n });\n // Pull latest\n execSync('git pull --ff-only', {\n cwd: repoDir,\n stdio: 'pipe',\n timeout: 60000,\n });\n } else {\n execSync(\n `git clone --depth 1 --filter=blob:none --sparse \"${REPO_URL}\" repo`,\n {\n cwd: clautunnelDir,\n stdio: 'pipe',\n timeout: 60000,\n }\n );\n execSync('git sparse-checkout set apps/mobile packages/shared', {\n cwd: repoDir,\n stdio: 'pipe',\n timeout: 30000,\n });\n }\n\n // Point mobileProjectPath to the cloned apps/mobile\n this.mobileProjectPath = join(repoDir, 'apps', 'mobile');\n\n if (!existsSync(join(this.mobileProjectPath, 'package.json'))) {\n return { ready: false, cloned: false, error: 'Clone succeeded but apps/mobile not found' };\n }\n\n return { ready: true, cloned: true };\n } catch (error) {\n return {\n ready: false,\n cloned: false,\n error: `Failed to clone mobile project: ${error instanceof Error ? error.message : 'Unknown error'}`,\n };\n }\n }\n\n ensureEnvFile(): void {\n const envPath = join(this.mobileProjectPath, '.env');\n const lines = [\n `EXPO_PUBLIC_SUPABASE_URL=${this.options.supabaseUrl}`,\n `EXPO_PUBLIC_SUPABASE_ANON_KEY=${this.options.supabaseAnonKey}`,\n '',\n ];\n writeFileSync(envPath, lines.join('\\n'));\n }\n\n installDependencies(): boolean {\n const nodeModulesPath = join(this.mobileProjectPath, 'node_modules');\n const repoRoot = join(this.mobileProjectPath, '..', '..');\n const sharedDistPath = join(repoRoot, 'packages', 'shared', 'dist', 'index.js');\n\n if (existsSync(nodeModulesPath) && existsSync(sharedDistPath)) return true;\n\n // Run pnpm install from repo root so workspace links resolve correctly\n try {\n execSync('pnpm install', {\n cwd: repoRoot,\n stdio: 'pipe',\n timeout: 120000, // 2 minute timeout\n });\n\n // Build shared package so dist/index.js exists for Metro\n const sharedDir = join(repoRoot, 'packages', 'shared');\n if (existsSync(join(sharedDir, 'tsconfig.json'))) {\n execSync('pnpm build', {\n cwd: sharedDir,\n stdio: 'pipe',\n timeout: 30000,\n });\n }\n\n return true;\n } catch {\n return false;\n }\n }\n\n async startNgrok(): Promise<string | null> {\n // Kill any leftover ngrok processes to avoid ERR_NGROK_334\n try {\n execSync('killall ngrok', { stdio: 'pipe' });\n await this.sleep(500);\n } catch {\n // No existing ngrok process — expected\n }\n\n this.ensureLogDir();\n\n this.ngrokLogStream = createWriteStream(join(this.logDir, 'ngrok.log'));\n\n // Capture stderr for error diagnostics\n let stderrData = '';\n\n this.ngrokProcess = spawn('ngrok', ['http', String(this.expoPort)], {\n stdio: ['ignore', 'pipe', 'pipe'],\n detached: false,\n });\n\n // Redirect stdout to log file\n this.ngrokProcess.stdout?.pipe(this.ngrokLogStream);\n\n // Capture stderr while also writing to log\n this.ngrokProcess.stderr?.on('data', (chunk: Buffer) => {\n stderrData += chunk.toString();\n this.ngrokLogStream?.write(chunk);\n });\n\n this.ngrokProcess.on('error', () => {\n // Silently handle spawn errors\n });\n\n // Poll for tunnel URL\n for (let i = 0; i < 10; i++) {\n await this.sleep(1000);\n\n // Check if ngrok exited early (auth error, etc.)\n if (this.ngrokProcess.exitCode !== null) {\n break;\n }\n\n const url = await this.getNgrokTunnelUrl();\n if (url) {\n this.tunnelUrl = url;\n return url;\n }\n }\n\n // Failed — set diagnostic error message\n this.ngrokError = this.diagnoseNgrokFailure(stderrData);\n\n this.killProcessTree(this.ngrokProcess);\n this.ngrokProcess = null;\n return null;\n }\n\n /** Last ngrok error diagnosis (available after startNgrok fails) */\n ngrokError: string | null = null;\n\n private diagnoseNgrokFailure(stderr: string): string {\n const lower = stderr.toLowerCase();\n\n if (lower.includes('authtoken') || lower.includes('err_ngrok_105') || lower.includes('authentication')) {\n return 'ngrok authentication failed.\\n' +\n ' Your authtoken may be invalid or expired.\\n' +\n ' 1. Get a new token at https://dashboard.ngrok.com/get-started/your-authtoken\\n' +\n ' 2. Run: ngrok config add-authtoken <your-token>';\n }\n\n if (lower.includes('tunnel session limit') || lower.includes('err_ngrok_108')) {\n return 'ngrok free plan session limit reached.\\n' +\n ' Free accounts allow 1 tunnel at a time.\\n' +\n ' Close other ngrok tunnels or upgrade your plan at https://ngrok.com/pricing';\n }\n\n if (lower.includes('tcp dial') || lower.includes('connection refused')) {\n return `ngrok could not connect to localhost:${this.expoPort}.\\n` +\n ' This is usually a timing issue — the tunnel started before Expo was ready.';\n }\n\n // Generic fallback with log path hint\n return 'ngrok tunnel failed to start.\\n' +\n ` Check logs for details: ${join(this.logDir, 'ngrok.log')}`;\n }\n\n async startExpo(tunnelUrl: string): Promise<boolean> {\n this.ensureLogDir();\n\n // Kill any process occupying the expo port to avoid\n // \"Port X is running this app in another window\" interactive prompt\n // which hangs in non-interactive mode\n this.killProcessOnPort(this.expoPort);\n\n this.expoLogStream = createWriteStream(join(this.logDir, 'expo.log'));\n\n this.expoProcess = spawn('npx', ['expo', 'start', '--clear', '--port', String(this.expoPort)], {\n cwd: this.mobileProjectPath,\n env: {\n ...process.env,\n EXPO_PACKAGER_PROXY_URL: tunnelUrl,\n EXPO_PUBLIC_TUNNEL_URL: tunnelUrl,\n },\n stdio: ['ignore', 'pipe', 'pipe'],\n detached: false,\n });\n\n this.expoProcess.on('error', () => {\n // Silently handle spawn errors\n });\n\n // Wait for Expo to be ready, print QR code if available\n return new Promise<boolean>((resolve) => {\n let ready = false;\n let resolved = false;\n let qrActive = false;\n\n const timeout = setTimeout(() => {\n if (!resolved) {\n resolved = true;\n this.expoProcess?.stdout?.pipe(this.expoLogStream!);\n this.expoProcess?.stderr?.pipe(this.expoLogStream!);\n resolve(false);\n }\n }, 60000); // 60 second timeout\n\n this.expoProcess?.stdout?.on('data', (data: Buffer) => {\n const text = data.toString();\n const lines = text.split('\\n');\n\n for (const line of lines) {\n if (ready) {\n this.expoLogStream?.write(line + '\\n');\n continue;\n }\n\n // Print QR code lines to terminal\n if (this.isQrCodeLine(line)) {\n qrActive = true;\n process.stdout.write(line + '\\n');\n } else if (qrActive && !this.isExpoReadyLine(line) && line.trim()) {\n // Lines between QR code blocks (spacing, URL info)\n process.stdout.write(line + '\\n');\n } else if (this.isExpoReadyLine(line)) {\n // Expo is ready — this is our success signal\n process.stdout.write(line + '\\n');\n ready = true;\n\n if (!resolved) {\n resolved = true;\n clearTimeout(timeout);\n // Redirect remaining output to log\n this.expoProcess?.stdout?.pipe(this.expoLogStream!);\n this.expoProcess?.stderr?.pipe(this.expoLogStream!);\n resolve(true);\n }\n } else {\n // Pre-ready output goes to log\n this.expoLogStream?.write(line + '\\n');\n }\n }\n });\n\n this.expoProcess?.stderr?.pipe(this.expoLogStream!);\n\n this.expoProcess?.on('exit', () => {\n if (!resolved) {\n resolved = true;\n clearTimeout(timeout);\n resolve(false);\n }\n });\n });\n }\n\n async start(): Promise<MobileServerResult> {\n // Step 1: Ensure mobile project exists (auto-clone if needed)\n this.onProgress('Checking mobile project...');\n const projectResult = this.ensureMobileProject();\n if (!projectResult.ready) {\n return { started: false, error: projectResult.error };\n }\n if (projectResult.cloned) {\n this.onProgress('Mobile project cloned to ~/.clautunnel/repo/apps/mobile');\n }\n\n // Step 2: Check prerequisites (ngrok, etc.)\n this.onProgress('Checking prerequisites...');\n const prereqs = this.checkPrerequisites();\n if (!prereqs.ready) {\n return { started: false, error: prereqs.issues.join('; ') };\n }\n\n // Step 3: Install dependencies if needed\n if (prereqs.needsInstall) {\n this.onProgress('Installing dependencies (this may take a minute)...');\n const installed = this.installDependencies();\n if (!installed) {\n return { started: false, error: 'Failed to install mobile dependencies' };\n }\n }\n\n // Step 4: Start ngrok tunnel (before .env so we have the tunnel URL)\n this.onProgress('Starting ngrok tunnel...');\n const tunnelUrl = await this.startNgrok();\n if (!tunnelUrl) {\n return { started: false, error: this.ngrokError ?? 'Failed to start ngrok tunnel' };\n }\n\n // Step 5: Sync .env file\n this.onProgress('Syncing credentials...');\n this.ensureEnvFile();\n\n // Step 6: Start Expo server (pass tunnel URL so mobile app can fetch tokens at runtime)\n this.onProgress('Starting Expo server...');\n const expoStarted = await this.startExpo(tunnelUrl);\n if (!expoStarted) {\n // Expo failed, kill ngrok too\n await this.stop();\n return { started: false, error: 'Failed to start Expo server' };\n }\n\n // Step 7: Show QR code for Expo Go\n // Convert https://xxx.ngrok-free.app → exp://xxx.ngrok-free.app:443/--/pair?code=UUID\n const host = tunnelUrl.replace(/^https?:\\/\\//, '');\n const pairingParam = this.options.pairingCode ? `/--/pair?code=${this.options.pairingCode}` : '';\n const expoUrl = `exp://${host}:443${pairingParam}`;\n console.log('');\n console.log(' Scan with Expo Go:');\n qrcode.generate(expoUrl, { small: true }, (code: string) => {\n // Indent each line for alignment\n for (const line of code.split('\\n')) {\n console.log(` ${line}`);\n }\n });\n console.log(` ${expoUrl}`);\n console.log('');\n console.log(' ┌─────────────────────────────────────────────────┐');\n console.log(' │ Expo Go is required to open this QR code. │');\n console.log(' │ iOS: https://apps.apple.com/app/id982107779│');\n console.log(' │ Android: https://play.google.com/store/apps/ │');\n console.log(' │ details?id=host.exp.exponent │');\n console.log(' └─────────────────────────────────────────────────┘');\n console.log('');\n\n return { started: true, tunnelUrl };\n }\n\n async stop(): Promise<void> {\n if (this.expoProcess) {\n this.killProcessTree(this.expoProcess);\n this.expoProcess = null;\n }\n\n if (this.ngrokProcess) {\n this.killProcessTree(this.ngrokProcess);\n this.ngrokProcess = null;\n }\n\n // Also force-free the expo port in case child processes survived\n this.killProcessOnPort(this.expoPort);\n\n if (this.expoLogStream) {\n this.expoLogStream.end();\n this.expoLogStream = null;\n }\n\n if (this.ngrokLogStream) {\n this.ngrokLogStream.end();\n this.ngrokLogStream = null;\n }\n\n this.tunnelUrl = null;\n }\n\n getTunnelUrl(): string | null {\n return this.tunnelUrl;\n }\n\n private isQrCodeLine(line: string): boolean {\n return line.includes('\\u2588') || line.includes('\\u2584') || line.includes('\\u2580');\n }\n\n private isExpoReadyLine(line: string): boolean {\n return line.includes('Metro waiting on') || line.includes('Logs for your project');\n }\n\n private getNgrokTunnelUrl(): Promise<string | null> {\n return new Promise((resolve) => {\n const req = get('http://localhost:4040/api/tunnels', (res) => {\n let data = '';\n res.on('data', (chunk) => (data += chunk));\n res.on('end', () => {\n try {\n const tunnels = JSON.parse(data).tunnels;\n const httpsTunnel = tunnels?.find(\n (t: { proto: string }) => t.proto === 'https'\n );\n resolve(httpsTunnel?.public_url ?? null);\n } catch {\n resolve(null);\n }\n });\n });\n\n req.on('error', () => resolve(null));\n req.setTimeout(2000, () => {\n req.destroy();\n resolve(null);\n });\n });\n }\n\n private killProcessTree(proc: ChildProcess): void {\n const pid = proc.pid;\n if (!pid) return;\n\n // Kill the parent process\n try {\n proc.kill('SIGTERM');\n } catch {\n // Already dead\n }\n\n // Also kill child processes (e.g., Metro bundler spawned by Expo)\n // Parent SIGTERM alone may not propagate to all children\n try {\n const children = execSync(`pgrep -P ${pid}`, { stdio: 'pipe' }).toString().trim();\n for (const childPid of children.split('\\n').filter(Boolean)) {\n try {\n process.kill(parseInt(childPid, 10), 'SIGTERM');\n } catch { /* already gone */ }\n }\n } catch {\n // No children or pgrep not available\n }\n }\n\n private ensureLogDir(): void {\n if (!existsSync(this.logDir)) {\n mkdirSync(this.logDir, { recursive: true });\n }\n }\n\n private killProcessOnPort(port: number): void {\n try {\n const output = execSync(`lsof -ti tcp:${port}`, { stdio: 'pipe' }).toString().trim();\n if (output) {\n for (const pid of output.split('\\n')) {\n try {\n process.kill(parseInt(pid, 10), 'SIGTERM');\n } catch {\n // Process already gone\n }\n }\n }\n } catch {\n // No process on port — expected\n }\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\n\nexport const PID_FILE = path.join(os.homedir(), '.clautunnel', 'daemon.pid');\n\n/**\n * PID file format: \"pid:timestamp\"\n * The timestamp is Date.now() at process start.\n * Used by removePidFile() to only remove files written by this process,\n * preventing one instance from deleting another's lock.\n *\n * Known limitation — PID reuse:\n * acquirePidFile() and stop both rely on kill(pid, 0) to check process\n * liveness, which cannot distinguish our daemon from an unrelated process\n * that was assigned the same PID after the daemon crashed. Pure Node.js\n * has no cross-platform way to verify process identity (start time, command\n * line, etc.) without shelling out to platform tools like `ps`.\n *\n * In practice this requires: daemon crash (no PID file cleanup) → OS\n * reassigns the exact same PID → user runs `clautunnel stop` or `start`\n * before noticing. The probability is extremely low given typical PID space\n * sizes (32768–99999+). If it does occur:\n * - `stop` may SIGTERM an unrelated process\n * - `start` may falsely report \"already running\"\n * In either case, manually deleting ~/.clautunnel/daemon.pid resolves it.\n */\n\nconst startTimestamp = Date.now();\n\n/**\n * Atomically acquire the PID file lock.\n * Uses O_EXCL to prevent race conditions between concurrent start commands.\n * If the file already exists, checks whether the owning process is still alive.\n *\n * Returns the PID of an existing running process, or null if\n * the lock was successfully acquired.\n */\nexport function acquirePidFile(pidFile: string = PID_FILE): number | null {\n const dir = path.dirname(pidFile);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n\n const content = `${process.pid}:${startTimestamp}`;\n\n try {\n // O_WRONLY | O_CREAT | O_EXCL — fails if file already exists\n const fd = fs.openSync(pidFile, 'wx');\n fs.writeSync(fd, content);\n fs.closeSync(fd);\n return null; // Lock acquired\n } catch (err: any) {\n if (err.code !== 'EEXIST') {\n throw err;\n }\n }\n\n // File exists — check if the owning process is still alive\n const existing = parsePidFile(pidFile);\n if (existing === null) {\n // Invalid/empty file — remove and retry\n removePidFileUnchecked(pidFile);\n return acquirePidFile(pidFile);\n }\n\n if (isProcessAlive(existing.pid)) {\n return existing.pid; // Process is still running\n }\n\n // Process is dead — stale PID file\n removePidFileUnchecked(pidFile);\n return acquirePidFile(pidFile);\n}\n\n/**\n * Remove the PID file only if it was written by this process\n * (matching both PID and timestamp).\n * Prevents accidentally removing another instance's lock.\n */\nexport function removePidFile(pidFile: string = PID_FILE): void {\n const existing = parsePidFile(pidFile);\n if (existing && existing.pid === process.pid && existing.timestamp === startTimestamp) {\n removePidFileUnchecked(pidFile);\n }\n}\n\n/**\n * Read the PID from the PID file (ignoring the timestamp).\n * Used by stop command to find the daemon PID.\n */\nexport function readPidFile(pidFile: string = PID_FILE): number | null {\n const existing = parsePidFile(pidFile);\n return existing?.pid ?? null;\n}\n\n/**\n * Check if a process with the given PID is still alive.\n */\nexport function isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Check if the PID file still exists (i.e., has not been cleaned up\n * by its owning process's graceful shutdown).\n */\nexport function pidFileExists(pidFile: string = PID_FILE): boolean {\n return fs.existsSync(pidFile);\n}\n\nfunction parsePidFile(pidFile: string): { pid: number; timestamp: number } | null {\n try {\n const content = fs.readFileSync(pidFile, 'utf-8').trim();\n // Support both \"pid:timestamp\" and legacy \"pid\" format\n const parts = content.split(':');\n const pid = parseInt(parts[0], 10);\n const timestamp = parts.length > 1 ? parseInt(parts[1], 10) : 0;\n if (isNaN(pid)) return null;\n return { pid, timestamp: isNaN(timestamp) ? 0 : timestamp };\n } catch {\n return null;\n }\n}\n\nfunction removePidFileUnchecked(pidFile: string): void {\n try {\n fs.unlinkSync(pidFile);\n } catch {\n // File may already be gone\n }\n}\n","import { execSync } from 'child_process';\n\nexport type AuthCheckFailure =\n | 'cli_not_found'\n | 'subcommand_not_supported'\n | 'not_logged_in'\n | 'unknown';\n\nexport interface ClaudeAuthStatus {\n loggedIn: boolean;\n authMethod?: string;\n apiProvider?: string;\n failure?: AuthCheckFailure;\n}\n\n/**\n * Check if the Claude CLI is authenticated by running `claude auth status --json`.\n * Distinguishes between CLI not found, subcommand not supported, and not logged in.\n */\nexport function checkClaudeCliAuth(): ClaudeAuthStatus {\n try {\n const output = execSync('claude auth status --json', {\n encoding: 'utf-8',\n timeout: 10000,\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n\n const status = JSON.parse(output.trim());\n if (status.loggedIn === true) {\n return {\n loggedIn: true,\n authMethod: status.authMethod,\n apiProvider: status.apiProvider,\n };\n }\n return { loggedIn: false, failure: 'not_logged_in' };\n } catch (error: unknown) {\n // execSync throws on non-zero exit codes. The CLI may still write\n // valid JSON to stdout (e.g. exit 1 + {\"loggedIn\": false, ...}).\n const execError = error as { stdout?: string | Buffer; message?: string };\n\n // Try to parse stdout from the thrown error first\n if (execError.stdout) {\n try {\n const stdout =\n typeof execError.stdout === 'string'\n ? execError.stdout\n : execError.stdout.toString('utf-8');\n const status = JSON.parse(stdout.trim());\n if (status.loggedIn === true) {\n return {\n loggedIn: true,\n authMethod: status.authMethod,\n apiProvider: status.apiProvider,\n };\n }\n return { loggedIn: false, failure: 'not_logged_in' };\n } catch {\n // stdout wasn't valid JSON — fall through to message-based detection\n }\n }\n\n const message = execError.message ?? String(error);\n\n // CLI binary not found\n if (\n message.includes('command not found') ||\n message.includes('ENOENT') ||\n message.includes('not recognized')\n ) {\n return { loggedIn: false, failure: 'cli_not_found' };\n }\n\n // Subcommand not supported (older CLI version)\n if (\n message.includes('Unknown command') ||\n message.includes('unknown command') ||\n message.includes('Invalid subcommand') ||\n message.includes('invalid subcommand')\n ) {\n return { loggedIn: false, failure: 'subcommand_not_supported' };\n }\n\n return { loggedIn: false, failure: 'unknown' };\n }\n}\n","import { Command } from 'commander';\nimport * as fs from 'fs';\nimport { Logger } from '../utils/logger.js';\nimport { PID_FILE, readPidFile, isProcessAlive, pidFileExists } from '../utils/pid.js';\n\nexport function createStopCommand(): Command {\n const command = new Command('stop');\n\n command.description('Stop the running daemon').action(async () => {\n const logger = new Logger();\n\n try {\n const pid = readPidFile();\n\n if (pid === null) {\n logger.info('No daemon is running');\n return;\n }\n\n if (!isProcessAlive(pid)) {\n logger.info('Daemon process not found (already stopped)');\n try { fs.unlinkSync(PID_FILE); } catch { /* already gone */ }\n return;\n }\n\n try {\n // Note: We cannot verify that the process at this PID is actually\n // clautunnel (see PID reuse limitation in pid.ts). We rely on:\n // 1. The PID file existing (written only by clautunnel start)\n // 2. The process being alive at that PID\n // 3. Post-SIGTERM: PID file removal by gracefulShutdown as confirmation\n //\n // Send SIGTERM — the daemon's gracefulShutdown handler will:\n // 1. Stop all sessions, set machine offline\n // 2. Call removePidFile() to clean up\n // 3. Exit the process\n process.kill(pid, 'SIGTERM');\n logger.info(`Sent stop signal to daemon (PID: ${pid})`);\n\n // Wait for process to exit.\n // We watch for PID file removal as confirmation that our process\n // handled the signal (not an unrelated process with a reused PID).\n let attempts = 0;\n let pidFileRemoved = false;\n while (attempts < 10) {\n await new Promise((resolve) => setTimeout(resolve, 500));\n\n if (!pidFileExists()) {\n // PID file was cleaned up by gracefulShutdown — confirmed our process\n pidFileRemoved = true;\n break;\n }\n\n if (!isProcessAlive(pid)) {\n // Process exited but didn't clean up PID file (crash during shutdown)\n break;\n }\n\n attempts++;\n }\n\n if (attempts >= 10 && !pidFileRemoved) {\n // Process didn't exit after 5 seconds.\n // Only SIGKILL if the PID file still has the original PID,\n // confirming the process hasn't been replaced.\n const currentPid = readPidFile();\n if (currentPid === pid && isProcessAlive(pid)) {\n logger.warn('Daemon did not stop gracefully, sending SIGKILL');\n process.kill(pid, 'SIGKILL');\n }\n }\n\n logger.info('Daemon stopped');\n } catch (err: any) {\n if (err.code === 'ESRCH') {\n logger.info('Daemon process not found (already stopped)');\n } else {\n throw err;\n }\n }\n\n // Clean up PID file if still present (crash during shutdown).\n // Only remove if it still contains the PID we were stopping.\n const currentPid = readPidFile();\n if (currentPid === pid) {\n try { fs.unlinkSync(PID_FILE); } catch { /* already gone */ }\n }\n } catch (error) {\n logger.error(\n `Failed to stop daemon: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n process.exit(1);\n }\n });\n\n return command;\n}\n","import { Command } from 'commander';\nimport { Config } from '../utils/config.js';\nimport { Logger } from '../utils/logger.js';\nimport { MachineManager } from '../daemon/machine.js';\nimport { createSupabaseClient, restoreSession } from '../utils/supabase.js';\n\nexport function createStatusCommand(): Command {\n const command = new Command('status');\n\n command\n .description('Show connection status')\n .action(async () => {\n const config = new Config();\n const logger = new Logger();\n\n try {\n const supabase = createSupabaseClient(\n config.getSupabaseUrl(),\n config.getSupabaseAnonKey()\n );\n\n // Restore session from stored tokens\n const session = await restoreSession(supabase, config);\n if (!session) {\n logger.info('Status: Not authenticated');\n logger.info('Run \"clautunnel login\" to authenticate');\n return;\n }\n\n const { user } = session;\n\n logger.info(`User: ${user.email}`);\n\n const machineId = config.getMachineId();\n if (!machineId) {\n logger.info('Machine: Not registered');\n logger.info('Run \"clautunnel start\" to register this machine');\n return;\n }\n\n const machineManager = new MachineManager({ supabase });\n const machine = await machineManager.getMachine(machineId);\n\n if (!machine) {\n logger.info(`Machine ID: ${machineId} (not found)`);\n return;\n }\n\n logger.info(`Machine: ${machine.name} (${machine.id})`);\n logger.info(`Status: ${machine.status}`);\n logger.info(`Last seen: ${machine.last_seen_at}`);\n } catch (error) {\n logger.error(\n `Failed to get status: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n process.exit(1);\n }\n });\n\n return command;\n}\n","import { Command } from 'commander';\nimport { Config, ConfigurationError } from '../utils/config.js';\nimport { Logger } from '../utils/logger.js';\nimport { prompt, promptHidden } from '../utils/prompt.js';\nimport { createSupabaseClient } from '../utils/supabase.js';\n\nexport function createLoginCommand(): Command {\n const command = new Command('login');\n\n command.description('Authenticate with ClauTunnel').action(async () => {\n const config = new Config();\n const logger = new Logger();\n\n try {\n config.requireConfiguration();\n\n const supabase = createSupabaseClient(\n config.getSupabaseUrl(),\n config.getSupabaseAnonKey()\n );\n\n const email = await prompt('Email: ');\n const password = await promptHidden('Password: ');\n\n if (!email || !password) {\n logger.error('Email and password are required');\n process.exit(1);\n }\n\n const { data, error } = await supabase.auth.signInWithPassword({\n email,\n password,\n });\n\n if (error) {\n logger.error(`Login failed: ${error.message}`);\n process.exit(1);\n }\n\n if (data.user) {\n logger.info(`Logged in as ${data.user.email}`);\n\n // Store session tokens securely\n if (data.session) {\n config.setSession({\n accessToken: data.session.access_token,\n refreshToken: data.session.refresh_token,\n });\n logger.info('Session saved');\n }\n\n logger.info('');\n logger.info('Next steps:');\n logger.info(' 1. Run \"clautunnel start\" to begin a session');\n logger.info(' 2. Set up the mobile app:');\n logger.info(' https://github.com/TongilKim/ClauTunnel#mobile-app-setup');\n }\n } catch (error) {\n if (error instanceof ConfigurationError) {\n logger.error(error.message);\n process.exit(1);\n }\n logger.error(\n `Login failed: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n process.exit(1);\n }\n });\n\n return command;\n}\n","import * as readline from 'readline';\n\nexport function prompt(question: string): Promise<string> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer);\n });\n });\n}\n\nexport function promptHidden(question: string): Promise<string> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n return new Promise((resolve) => {\n process.stdout.write(question);\n\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(true);\n }\n\n let password = '';\n\n const onData = (char: Buffer) => {\n const c = char.toString();\n\n if (c === '\\n' || c === '\\r') {\n process.stdin.removeListener('data', onData);\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(false);\n }\n process.stdout.write('\\n');\n rl.close();\n resolve(password);\n } else if (c === '\\u0003') {\n // Ctrl+C\n process.exit(0);\n } else if (c === '\\u007F' || c === '\\b') {\n // Backspace\n if (password.length > 0) {\n password = password.slice(0, -1);\n }\n } else {\n password += c;\n }\n };\n\n process.stdin.on('data', onData);\n process.stdin.resume();\n });\n}\n","import { Command } from 'commander';\nimport { Config } from '../utils/config.js';\nimport { Logger } from '../utils/logger.js';\nimport { createSupabaseClient, restoreSession } from '../utils/supabase.js';\n\nexport function createLogoutCommand(): Command {\n const command = new Command('logout');\n\n command.description('Log out of ClauTunnel and revoke all device sessions').action(async () => {\n const config = new Config();\n const logger = new Logger();\n\n const session = config.getSessionTokens();\n if (!session) {\n logger.info('Not currently logged in.');\n return;\n }\n\n // Revoke all sessions (CLI + paired mobile devices)\n // This invalidates all refresh tokens. Access tokens remain valid until\n // they expire (default 1hr), but no new tokens can be issued.\n try {\n const supabase = createSupabaseClient(\n config.getSupabaseUrl(),\n config.getSupabaseAnonKey()\n );\n\n const restored = await restoreSession(supabase, config);\n if (restored) {\n const { error } = await supabase.auth.signOut({ scope: 'global' });\n if (error) {\n logger.warn(`Warning: failed to revoke remote sessions: ${error.message}`);\n logger.warn('Local credentials cleared, but mobile devices may remain active until their tokens expire.');\n } else {\n logger.info('All device sessions revoked.');\n }\n }\n } catch {\n // Best-effort — still clear local tokens even if revocation fails\n logger.warn('Warning: could not reach server to revoke sessions.');\n }\n\n config.clearSessionTokens();\n config.clearMachineId();\n logger.info('Logged out successfully.');\n });\n\n return command;\n}\n","import { Command } from 'commander';\nimport { Config, ConfigurationError } from '../utils/config.js';\nimport { Logger } from '../utils/logger.js';\nimport { prompt, promptHidden } from '../utils/prompt.js';\nimport { createSupabaseClient } from '../utils/supabase.js';\n\nexport function createSignupCommand(): Command {\n const command = new Command('signup');\n\n command.description('Create a new ClauTunnel account').action(async () => {\n const config = new Config();\n const logger = new Logger();\n\n try {\n config.requireConfiguration();\n\n const supabase = createSupabaseClient(\n config.getSupabaseUrl(),\n config.getSupabaseAnonKey()\n );\n\n logger.info('Create a new ClauTunnel account');\n logger.info('');\n\n const email = await prompt('Email: ');\n if (!email) {\n logger.error('Email is required');\n process.exit(1);\n }\n\n const password = await promptHidden('Password: ');\n if (!password) {\n logger.error('Password is required');\n process.exit(1);\n }\n\n if (password.length < 6) {\n logger.error('Password must be at least 6 characters');\n process.exit(1);\n }\n\n const confirmPassword = await promptHidden('Confirm Password: ');\n if (password !== confirmPassword) {\n logger.error('Passwords do not match');\n process.exit(1);\n }\n\n const { data, error } = await supabase.auth.signUp({\n email,\n password,\n });\n\n if (error) {\n logger.error(`Signup failed: ${error.message}`);\n process.exit(1);\n }\n\n if (data.user) {\n logger.info('');\n logger.info(`Account created for ${data.user.email}`);\n\n if (data.session) {\n config.setSession({\n accessToken: data.session.access_token,\n refreshToken: data.session.refresh_token,\n });\n logger.info('Logged in automatically');\n }\n\n logger.info('');\n logger.info('Next steps:');\n logger.info(' 1. Run \"clautunnel start\" to begin a session');\n logger.info(' 2. Set up the mobile app:');\n logger.info(' https://github.com/TongilKim/ClauTunnel#mobile-app-setup');\n }\n } catch (error) {\n if (error instanceof ConfigurationError) {\n logger.error(error.message);\n process.exit(1);\n }\n logger.error(\n `Signup failed: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n process.exit(1);\n }\n });\n\n return command;\n}\n","import { Command } from 'commander';\nimport { Config } from '../utils/config.js';\nimport { Logger } from '../utils/logger.js';\nimport { prompt } from '../utils/prompt.js';\n\nexport function createSetupCommand(): Command {\n const command = new Command('setup');\n\n command\n .description('Configure ClauTunnel with Supabase credentials')\n .action(async () => {\n const config = new Config();\n const logger = new Logger();\n\n try {\n logger.info('ClauTunnel Setup');\n logger.info('================');\n logger.info('');\n\n // Step 1: Project ID\n logger.info('[Step 1/2] Supabase Project ID');\n logger.info('');\n logger.info(' 1. Go to your Supabase project dashboard');\n logger.info(' 2. Settings > General > Copy \"Project ID\"');\n logger.info('');\n\n const projectId = await prompt('Project ID: ');\n if (!projectId) {\n logger.error('Supabase Project ID is required');\n process.exit(1);\n }\n\n // Check if user accidentally pasted a full URL\n if (projectId.includes('supabase.co') || projectId.startsWith('http')) {\n logger.error('');\n logger.error('Please enter only the Project ID, not the full URL.');\n logger.error('');\n logger.error('Example: abcdefghijklmnop');\n logger.error('NOT: https://abcdefghijklmnop.supabase.co');\n process.exit(1);\n }\n\n // Validate Project ID format (alphanumeric, no spaces/special chars)\n if (!/^[a-zA-Z0-9-]+$/.test(projectId)) {\n logger.error('');\n logger.error('Invalid Project ID format.');\n logger.error('The Project ID should only contain letters, numbers, and hyphens.');\n logger.error('');\n logger.error('You can find it at: Settings > General > Project ID');\n process.exit(1);\n }\n\n const url = `https://${projectId}.supabase.co`;\n logger.info('✓ Project ID saved');\n logger.info('');\n\n // Step 2: Anon Key\n logger.info('[Step 2/2] Supabase Anon Key');\n logger.info('');\n logger.info(' 1. Go to your Supabase project dashboard');\n logger.info(' 2. Settings > API Keys > Legacy anon Tab > Copy anon key');\n logger.info('');\n\n const anonKey = await prompt('Anon Key: ');\n if (!anonKey) {\n logger.error('Supabase Anon Key is required');\n process.exit(1);\n }\n\n config.setSupabaseCredentials({ url, anonKey });\n\n logger.info('');\n logger.info('✓ Configuration saved successfully!');\n logger.info('');\n logger.info('Next steps:');\n logger.info(' - New user? Run \"clautunnel signup\" to create an account');\n logger.info(' - Have account? Run \"clautunnel login\" to authenticate');\n } catch (error) {\n logger.error(\n `Setup failed: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n process.exit(1);\n }\n });\n\n return command;\n}\n","import { Command } from 'commander';\nimport { Config, ConfigurationError } from '../utils/config.js';\nimport { Logger } from '../utils/logger.js';\nimport { existsSync, writeFileSync } from 'fs';\nimport { join, resolve } from 'path';\n\nexport function createMobileSetupCommand(): Command {\n const command = new Command('mobile-setup');\n\n command\n .description('Generate mobile app .env file from CLI credentials')\n .action(async () => {\n const config = new Config();\n const logger = new Logger();\n\n try {\n config.requireConfiguration();\n\n const supabaseUrl = config.getSupabaseUrl();\n const supabaseAnonKey = config.getSupabaseAnonKey();\n\n // Look for apps/mobile directory relative to cwd\n const mobileDir = resolve(process.cwd(), 'apps', 'mobile');\n if (!existsSync(mobileDir)) {\n logger.error('Could not find apps/mobile directory.');\n logger.error('');\n logger.error('Make sure you run this command from the ClauTunnel project root:');\n logger.error(' cd clautunnel');\n logger.error(' clautunnel mobile-setup');\n process.exit(1);\n }\n\n const envPath = join(mobileDir, '.env');\n\n // Warn if .env already exists\n if (existsSync(envPath)) {\n logger.warn('apps/mobile/.env already exists and will be overwritten.');\n }\n\n const envContent = [\n `EXPO_PUBLIC_SUPABASE_URL=${supabaseUrl}`,\n `EXPO_PUBLIC_SUPABASE_ANON_KEY=${supabaseAnonKey}`,\n '',\n ].join('\\n');\n\n writeFileSync(envPath, envContent);\n\n // Save mobile project path to config for clautunnel start\n config.setMobileProjectPath(mobileDir);\n\n logger.info('');\n logger.info('Mobile app configured successfully!');\n logger.info(` Project: ${mobileDir}`);\n logger.info(` .env: ${envPath}`);\n logger.info('');\n logger.info('The mobile server will start automatically with \"clautunnel start\".');\n logger.info('Use \"clautunnel start --no-mobile\" to skip mobile server.');\n } catch (error) {\n if (error instanceof ConfigurationError) {\n logger.error(error.message);\n process.exit(1);\n }\n logger.error(\n `Mobile setup failed: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n process.exit(1);\n }\n });\n\n return command;\n}\n","import { Command } from 'commander';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\nimport { execSync } from 'child_process';\nimport { Logger } from '../utils/logger.js';\nimport { PID_FILE, readPidFile, isProcessAlive } from '../utils/pid.js';\nimport { createSupabaseClient } from '../utils/supabase.js';\nimport { isMacOS } from '../utils/sleep-prevention.js';\nimport { promptYesNo } from '../utils/sleep-prevention.js';\n\ninterface ResetOptions {\n skipDb?: boolean;\n skipNgrok?: boolean;\n yes?: boolean;\n}\n\nexport function createResetCommand(): Command {\n const command = new Command('reset');\n\n command\n .description('Reset to fresh user state (uninstall CLI, clean config & DB)')\n .option('--skip-db', 'Skip Supabase DB cleanup')\n .option('--skip-ngrok', 'Keep ngrok installed and configured')\n .option('-y, --yes', 'Skip confirmation prompt')\n .action(async (options: ResetOptions) => {\n const logger = new Logger();\n\n if (!options.yes) {\n logger.info('This will:');\n logger.info(' - Stop any running clautunnel processes');\n logger.info(' - Restore macOS sleep settings');\n if (!options.skipDb) {\n logger.info(' - Delete all your data from Supabase (machines, sessions, messages)');\n }\n if (!options.skipNgrok) {\n logger.info(' - Uninstall ngrok and remove its config');\n }\n logger.info(' - Delete ~/.clautunnel/ config directory');\n logger.info(' - Uninstall clautunnel (npm & Homebrew)');\n logger.info('');\n\n const confirmed = await promptYesNo('Are you sure? [y/N]: ');\n if (!confirmed) {\n logger.info('Aborted.');\n return;\n }\n logger.info('');\n }\n\n // ─── Step 1: Stop running processes ────────────────────────────\n logger.info('[1/7] Stopping running processes...');\n\n const pid = readPidFile();\n if (pid !== null && isProcessAlive(pid)) {\n try {\n process.kill(pid, 'SIGTERM');\n logger.info(` - clautunnel daemon stopped (PID ${pid})`);\n // Give it a moment to clean up child processes\n await new Promise((resolve) => setTimeout(resolve, 1000));\n } catch {\n logger.info(' - could not stop daemon');\n }\n } else {\n logger.info(' - no running daemon');\n }\n // Clean up PID file regardless\n try { fs.unlinkSync(PID_FILE); } catch { /* already gone */ }\n\n // Kill orphaned ngrok/expo processes\n try {\n execSync('pkill -f \"ngrok.*tunnel\" 2>/dev/null', { stdio: 'ignore' });\n logger.info(' - ngrok tunnel process killed');\n } catch { /* not running */ }\n\n try {\n execSync('pkill -f \"expo start\" 2>/dev/null', { stdio: 'ignore' });\n logger.info(' - expo process killed');\n } catch { /* not running */ }\n\n // Kill anything on the default Expo port (8081)\n try {\n const pids = execSync('lsof -ti tcp:8081', { stdio: 'pipe' }).toString().trim();\n if (pids) {\n for (const pid of pids.split('\\n')) {\n try { process.kill(parseInt(pid, 10), 'SIGTERM'); } catch { /* already gone */ }\n }\n logger.info(' - port 8081 freed');\n }\n } catch { /* port already free */ }\n\n // ─── Step 2: Restore macOS sleep settings ──────────────────────\n logger.info('[2/7] Restoring macOS sleep settings...');\n\n if (isMacOS()) {\n try {\n const pmsetOutput = execSync('sudo pmset -g 2>/dev/null', { encoding: 'utf-8' });\n if (pmsetOutput.includes('disablesleep') && pmsetOutput.includes('1')) {\n execSync('sudo pmset -a disablesleep 0', { stdio: 'inherit' });\n logger.info(' - lid-close sleep restored');\n } else {\n logger.info(' - already normal');\n }\n } catch {\n logger.info(' - already normal');\n }\n\n // Kill leftover caffeinate\n try {\n execSync('pkill -f caffeinate 2>/dev/null', { stdio: 'ignore' });\n logger.info(' - caffeinate stopped');\n } catch { /* not running */ }\n } else {\n logger.info(' - not macOS, skipped');\n }\n\n // ─── Step 3: Clean Supabase DB ────────────────────────────────\n if (options.skipDb) {\n logger.info('[3/7] Skipping DB cleanup (--skip-db)');\n } else {\n await cleanSupabaseDb(logger);\n }\n\n // ─── Step 4: Uninstall ngrok ──────────────────────────────────\n if (options.skipNgrok) {\n logger.info('[4/7] Skipping ngrok cleanup (--skip-ngrok)');\n } else {\n logger.info('[4/7] Uninstalling ngrok...');\n try {\n execSync('brew list ngrok', { stdio: 'ignore' });\n execSync('brew uninstall ngrok', { stdio: 'inherit' });\n logger.info(' - ngrok removed');\n } catch {\n try {\n execSync('which ngrok', { stdio: 'ignore' });\n logger.info(' - ngrok found but not installed via Homebrew, remove manually');\n } catch {\n logger.info(' - not installed, skipped');\n }\n }\n\n // Remove ngrok config directories\n const ngrokConfigDir = path.join(os.homedir(), '.config', 'ngrok');\n const ngrokLegacyDir = path.join(os.homedir(), '.ngrok2');\n\n if (fs.existsSync(ngrokConfigDir)) {\n fs.rmSync(ngrokConfigDir, { recursive: true, force: true });\n logger.info(' - ngrok config removed (~/.config/ngrok)');\n }\n if (fs.existsSync(ngrokLegacyDir)) {\n fs.rmSync(ngrokLegacyDir, { recursive: true, force: true });\n logger.info(' - ngrok legacy config removed (~/.ngrok2)');\n }\n }\n\n // ─── Step 5: Remove local data ────────────────────────────────\n logger.info('[5/7] Removing local data...');\n\n const configDir = path.join(os.homedir(), '.clautunnel');\n const legacyDir = path.join(os.homedir(), '.termbridge');\n\n if (fs.existsSync(configDir)) {\n fs.rmSync(configDir, { recursive: true, force: true });\n logger.info(' - ~/.clautunnel removed (config, logs, repo)');\n } else {\n logger.info(' - ~/.clautunnel already clean');\n }\n\n if (fs.existsSync(legacyDir)) {\n fs.rmSync(legacyDir, { recursive: true, force: true });\n logger.info(' - ~/.termbridge removed (legacy)');\n }\n\n // ─── Step 6: Uninstall CLI (npm) ──────────────────────────────\n // Runs after config removal so if it fails, re-running the command\n // still works (the binary is still available).\n logger.info('[6/7] Uninstalling CLI (npm)...');\n try {\n execSync('npm list -g @tongil_kim/clautunnel', { stdio: 'ignore' });\n execSync('npm uninstall -g @tongil_kim/clautunnel', { stdio: 'inherit' });\n logger.info(' - npm package removed');\n } catch {\n logger.info(' - not installed via npm, skipped');\n }\n\n // ─── Step 7: Uninstall CLI (Homebrew) ─────────────────────────\n logger.info('[7/7] Uninstalling CLI (Homebrew)...');\n try {\n execSync('brew list clautunnel', { stdio: 'ignore' });\n execSync('brew uninstall clautunnel', { stdio: 'inherit' });\n logger.info(' - Homebrew package removed');\n } catch {\n logger.info(' - not installed via Homebrew, skipped');\n }\n\n logger.info('');\n logger.info('Done! Fresh user state restored.');\n logger.info('');\n logger.info('Next steps:');\n logger.info(' 1. npm install -g @tongil_kim/clautunnel');\n logger.info(' 2. clautunnel setup');\n logger.info(' 3. clautunnel login');\n logger.info(' 4. clautunnel start');\n });\n\n return command;\n}\n\nasync function cleanSupabaseDb(logger: Logger): Promise<void> {\n const configDir = path.join(os.homedir(), '.clautunnel');\n const configFile = path.join(configDir, 'config.json');\n\n if (!fs.existsSync(configFile)) {\n logger.info('[3/7] Skipping DB cleanup (no config file found)');\n return;\n }\n\n let configData: any;\n try {\n configData = JSON.parse(fs.readFileSync(configFile, 'utf-8'));\n } catch {\n logger.info('[3/7] Skipping DB cleanup (invalid config file)');\n return;\n }\n\n const supabaseUrl = configData.supabaseUrl;\n const anonKey = configData.supabaseAnonKey;\n const accessToken = configData.sessionTokens?.accessToken;\n const refreshToken = configData.sessionTokens?.refreshToken;\n\n if (!supabaseUrl || !anonKey || !accessToken) {\n logger.info('[3/7] Skipping DB cleanup (missing credentials)');\n return;\n }\n\n logger.info('[3/7] Cleaning Supabase DB data...');\n\n // Refresh token in case it's expired\n const supabase = createSupabaseClient(supabaseUrl, anonKey);\n\n let token = accessToken;\n if (refreshToken) {\n const { data } = await supabase.auth.setSession({\n access_token: accessToken,\n refresh_token: refreshToken,\n });\n if (data?.session) {\n token = data.session.access_token;\n }\n }\n\n // Delete push_tokens (no cascade from machines)\n const headers = {\n apikey: anonKey,\n Authorization: `Bearer ${token}`,\n Prefer: 'return=minimal',\n };\n\n try {\n const res = await fetch(`${supabaseUrl}/rest/v1/push_tokens?select=*`, {\n method: 'DELETE',\n headers,\n });\n logger.info(res.ok ? ' - push_tokens cleared' : ' - push_tokens: skipped');\n } catch {\n logger.info(' - push_tokens: skipped');\n }\n\n // Delete machines (cascades to sessions -> messages)\n try {\n const res = await fetch(`${supabaseUrl}/rest/v1/machines?select=*`, {\n method: 'DELETE',\n headers,\n });\n logger.info(res.ok ? ' - machines cleared (sessions + messages cascade)' : ' - machines: skipped');\n } catch {\n logger.info(' - machines: skipped');\n }\n\n // Delete mobile_pairings\n try {\n const res = await fetch(`${supabaseUrl}/rest/v1/mobile_pairings?select=*`, {\n method: 'DELETE',\n headers,\n });\n logger.info(res.ok ? ' - mobile_pairings cleared' : ' - mobile_pairings: skipped');\n } catch {\n logger.info(' - mobile_pairings: skipped');\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AACA,WAAO,eAAe,SAAS,cAAc,EAAE,OAAO,KAAK,CAAC;AAAA;AAAA;;;ACD5D;AAAA;AAAA;AACA,WAAO,eAAe,SAAS,cAAc,EAAE,OAAO,KAAK,CAAC;AAAA;AAAA;;;ACD5D;AAAA;AAAA;AACA,WAAO,eAAe,SAAS,cAAc,EAAE,OAAO,KAAK,CAAC;AAAA;AAAA;;;ACD5D;AAAA;AAAA;AACA,WAAO,eAAe,SAAS,cAAc,EAAE,OAAO,KAAK,CAAC;AAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;ACD5D,iBAAA,mBAAA,OAAA;AACA,iBAAA,mBAAA,OAAA;AACA,iBAAA,mBAAA,OAAA;AACA,iBAAA,oBAAA,OAAA;;;;;;;;;;ACHa,YAAA,oBAAoB;MAC/B,eAAe,CAAC,cAAsB,WAAW,SAAS;MAC1D,cAAc,CAAC,cAAsB,WAAW,SAAS;MACzD,iBAAiB,CAAC,cAAsB,WAAW,SAAS;MAC5D,iBAAiB,CAAC,cAAsB,WAAW,SAAS;MAC5D,cAAc,CAAC,cAAsB,WAAW,SAAS;MACzD,eAAe,CAAC,cAAsB,WAAW,SAAS;;;;;;;;;;;ACF/C,YAAA,yBAAyB;MACpC;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA;;AAGW,YAAA,gBAAgB;MAC3B;MACA;MACA;MACA;MACA;;;;;;;;;;;;;;;;;;;;;;;;;;AC3CF,iBAAA,kBAAA,OAAA;AACA,iBAAA,yBAAA,OAAA;;;;;;;;;ACUA,YAAA,mBAAAA;AATA,QAAM,yBAA2C;MAC/C;MACA;MACA;MACA;MACA;MACA;;AAGF,aAAgBA,kBAAiB,OAAc;AAC7C,aAAO,OAAO,UAAU,YAAY,uBAAuB,SAAS,KAAuB;IAC7F;;;;;;;;;;;;;;;;;;;;;;;;;ACbA,iBAAA,2BAAA,OAAA;;;;;;;;;;;;;;;;;;;;;;;;;ACCA,iBAAA,iBAAA,OAAA;AAGA,iBAAA,qBAAA,OAAA;AAGA,iBAAA,iBAAA,OAAA;;;;;ACLA,SAAS,cAAc;AACvB,SAAS,WAAAC,UAAS,WAAAC,gBAAe;AACjC,SAAS,gBAAAC,qBAAoB;AAC7B,SAAS,qBAAqB;;;ACL9B,SAAS,YAAY,WAAW,cAAc,YAAY,qBAAqB;AAC/E,SAAS,YAAY;AACrB,SAAS,eAAe;AAEjB,IAAM,qBAAN,cAAiC,MAAM;AAAA,EAC5C,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAaO,IAAM,SAAN,MAAa;AAAA,EACV;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,WAAoB;AAC9B,SAAK,YAAY,aAAa,KAAK,QAAQ,GAAG,aAAa;AAC3D,SAAK,aAAa,KAAK,KAAK,WAAW,aAAa;AACpD,QAAI,CAAC,WAAW;AACd,WAAK,kBAAkB;AAAA,IACzB;AACA,SAAK,OAAO,KAAK,WAAW;AAAA,EAC9B;AAAA,EAEQ,oBAA0B;AAChC,UAAM,YAAY,KAAK,QAAQ,GAAG,aAAa;AAC/C,QAAI,WAAW,SAAS,KAAK,CAAC,WAAW,KAAK,SAAS,GAAG;AACxD,iBAAW,WAAW,KAAK,SAAS;AACpC,cAAQ,IAAI,qDAAqD;AAAA,IACnE;AAAA,EACF;AAAA,EAEQ,aAAyB;AAC/B,QAAI,WAAW,KAAK,UAAU,GAAG;AAC/B,UAAI;AACF,eAAO,KAAK,MAAM,aAAa,KAAK,YAAY,OAAO,CAAC;AAAA,MAC1D,QAAQ;AACN,eAAO,CAAC;AAAA,MACV;AAAA,IACF;AACA,WAAO,CAAC;AAAA,EACV;AAAA,EAEQ,aAAmB;AACzB,QAAI,CAAC,WAAW,KAAK,SAAS,GAAG;AAC/B,gBAAU,KAAK,WAAW,EAAE,WAAW,KAAK,CAAC;AAAA,IAC/C;AACA,kBAAc,KAAK,YAAY,KAAK,UAAU,KAAK,MAAM,MAAM,CAAC,CAAC;AAAA,EACnE;AAAA,EAEA,iBAAyB;AAEvB,UAAM,MAAM,QAAQ,IAAI,cAAc,KAAK,KAAK,KAAK;AACrD,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,8CAA8C;AAAA,IAChE;AAGA,QAAI;AACF,UAAI,IAAI,GAAG;AAAA,IACb,QAAQ;AACN,YAAM,IAAI,MAAM,kCAAkC;AAAA,IACpD;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,qBAA6B;AAE3B,UAAM,MAAM,QAAQ,IAAI,mBAAmB,KAAK,KAAK,KAAK;AAC1D,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,mDAAmD;AAAA,IACrE;AACA,WAAO;AAAA,EACT;AAAA,EAEA,uBAAuB,aAAqD;AAC1E,SAAK,KAAK,cAAc,YAAY;AACpC,SAAK,KAAK,kBAAkB,YAAY;AACxC,SAAK,WAAW;AAAA,EAClB;AAAA,EAEA,eAAwB;AACtB,UAAM,aAAa,CAAC,EAAE,QAAQ,IAAI,cAAc,KAAK,QAAQ,IAAI,mBAAmB;AACpF,UAAM,gBAAgB,CAAC,EAAE,KAAK,KAAK,eAAe,KAAK,KAAK;AAC5D,WAAO,cAAc;AAAA,EACvB;AAAA,EAEA,uBAA6B;AAC3B,QAAI,CAAC,KAAK,aAAa,GAAG;AACxB,YAAM,IAAI;AAAA,QACR;AAAA,MAKF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,eAAmC;AACjC,WAAO,KAAK,KAAK;AAAA,EACnB;AAAA,EAEA,aAAa,WAAyB;AACpC,SAAK,KAAK,YAAY;AACtB,SAAK,WAAW;AAAA,EAClB;AAAA,EAEA,iBAAuB;AACrB,WAAO,KAAK,KAAK;AACjB,SAAK,WAAW;AAAA,EAClB;AAAA,EAEA,mBAA4D;AAC1D,WAAO,KAAK,KAAK;AAAA,EACnB;AAAA,EAEA,iBAAiB,QAA2C;AAC1D,SAAK,KAAK,gBAAgB;AAC1B,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA,EAGA,WAAW,QAA6D;AACtE,SAAK,iBAAiB,MAAM;AAAA,EAC9B;AAAA,EAEA,qBAA2B;AACzB,WAAO,KAAK,KAAK;AACjB,SAAK,WAAW;AAAA,EAClB;AAAA,EAEA,uBAA2C;AACzC,WAAO,KAAK,KAAK;AAAA,EACnB;AAAA,EAEA,qBAAqBC,OAAoB;AACvC,SAAK,KAAK,oBAAoBA;AAC9B,SAAK,WAAW;AAAA,EAClB;AACF;AAGA,IAAI,gBAA+B;AAE5B,SAAS,YAAoB;AAClC,MAAI,CAAC,eAAe;AAClB,oBAAgB,IAAI,OAAO;AAAA,EAC7B;AACA,SAAO;AACT;;;ACjKO,IAAM,SAAN,MAAa;AAAA,EACV;AAAA,EACA;AAAA,EAER,cAAc;AACZ,SAAK,SAAS,QAAQ,IAAI,QAAQ,MAAM;AACxC,SAAK,eAAe,QAAQ,IAAI,OAAO,MAAM;AAAA,EAC/C;AAAA,EAEQ,kBAA0B;AAChC,UAAM,MAAM,oBAAI,KAAK;AACrB,WAAO,IAAI,aAAa,EAAE,MAAM,GAAG,EAAE,CAAC,KAAK,IAAI,YAAY;AAAA,EAC7D;AAAA,EAEQ,cAAc,OAAiB,SAAiB,MAAuB;AAC7E,UAAM,YAAY,KAAK,gBAAgB;AACvC,UAAM,WAAW,MAAM,YAAY,EAAE,OAAO,CAAC;AAC7C,QAAI,YAAY,IAAI,SAAS,MAAM,QAAQ,KAAK,OAAO;AAEvD,QAAI,MAAM;AACR,mBAAa,IAAI,KAAK,UAAU,IAAI,CAAC;AAAA,IACvC;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,SAAiB,MAAqB;AAC1C,QAAI,KAAK,UAAU,CAAC,KAAK,aAAc;AACvC,YAAQ,IAAI,KAAK,cAAc,SAAS,SAAS,IAAI,CAAC;AAAA,EACxD;AAAA,EAEA,KAAK,SAAiB,MAAqB;AACzC,QAAI,KAAK,OAAQ;AACjB,YAAQ,IAAI,KAAK,cAAc,QAAQ,SAAS,IAAI,CAAC;AAAA,EACvD;AAAA,EAEA,KAAK,SAAiB,MAAqB;AACzC,QAAI,KAAK,OAAQ;AACjB,YAAQ,KAAK,KAAK,cAAc,QAAQ,SAAS,IAAI,CAAC;AAAA,EACxD;AAAA,EAEA,MAAM,SAAiB,MAAqB;AAC1C,QAAI,KAAK,OAAQ;AACjB,YAAQ,MAAM,KAAK,cAAc,SAAS,SAAS,IAAI,CAAC;AAAA,EAC1D;AACF;AAGA,IAAI,gBAA+B;AAE5B,SAAS,YAAoB;AAClC,MAAI,CAAC,eAAe;AAClB,oBAAgB,IAAI,OAAO;AAAA,EAC7B;AACA,SAAO;AACT;;;AC1CA,+BAAkC;AAflC,SAAS,oBAAoB;;;ACE7B,IAAM,kBAAkB;AAEjB,SAAS,qBACd,SACA,aACA,UAAkB,iBACA;AAClB,SAAO,IAAI,QAAiB,CAACC,aAAY;AACvC,QAAI,aAAa;AAEjB,UAAM,QAAQ,WAAW,MAAM;AAC7B,cAAQ;AAAA,QACN,4CAA4C,WAAW,kBAAkB,UAAU;AAAA,MACrF;AACA,MAAAA,SAAQ,KAAK;AAAA,IACf,GAAG,OAAO;AAEV,YAAQ,UAAU,CAAC,QAAQ,QAAQ;AACjC,mBAAa;AAEb,UAAI,WAAW,cAAc;AAC3B,qBAAa,KAAK;AAClB,QAAAA,SAAQ,IAAI;AAAA,MACd,WACE,WAAW,mBACX,WAAW,YACX,WAAW,aACX;AACA,qBAAa,KAAK;AAClB,gBAAQ;AAAA,UACN,kBAAkB,WAAW,IAAI,OAAO,YAAY,CAAC;AAAA,QACvD;AACA,YAAI,KAAK;AACP,kBAAQ,KAAK,yBAAyB,IAAI,WAAW,GAAG,EAAE;AAAA,QAC5D;AACA,QAAAA,SAAQ,KAAK;AAAA,MACf;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AACH;;;ADlBO,IAAM,iBAAN,cAA6B,aAAa;AAAA,EACvC;AAAA,EACA;AAAA,EACA,gBAAwC;AAAA,EACxC,eAAuC;AAAA,EACvC,kBAA0C;AAAA,EAC1C,MAAc;AAAA,EACd,kBAA2B;AAAA,EAEnC,YAAY,SAAgC;AAC1C,UAAM;AACN,SAAK,WAAW,QAAQ;AACxB,SAAK,YAAY,QAAQ;AAAA,EAC3B;AAAA,EAEA,MAAM,UAAyB;AAC7B,UAAM,gBAAgB,EAAE,QAAQ,EAAE,SAAS,KAAK,EAAE;AAGlD,UAAM,oBAAoB,2CAAkB,cAAc,KAAK,SAAS;AACxE,SAAK,gBAAgB,KAAK,SAAS,QAAQ,mBAAmB,aAAa;AAG3E,UAAM,mBAAmB,2CAAkB,aAAa,KAAK,SAAS;AACtE,SAAK,eAAe,KAAK,SAAS,QAAQ,kBAAkB,aAAa;AAEzE,SAAK,aAAa,GAAG,aAAa,EAAE,OAAO,QAAQ,GAAG,CAAC,YAAY;AACjE,WAAK,KAAK,SAAS,QAAQ,OAA0B;AAAA,IACvD,CAAC;AAED,UAAM,UAAU,MAAM,QAAQ,IAAI;AAAA,MAChC,qBAAqB,KAAK,eAAe,QAAQ;AAAA,MACjD,qBAAqB,KAAK,cAAc,OAAO;AAAA,IACjD,CAAC;AAGD,SAAK,kBAAkB,QAAQ,MAAM,CAAC,YAAY,OAAO;AAGzD,QAAI,KAAK,iBAAiB;AACxB,YAAM,sBAAsB,2CAAkB,gBAAgB,KAAK,SAAS;AAC5E,WAAK,kBAAkB,KAAK,SAAS,QAAQ,qBAAqB,aAAa;AAG/E,WAAK,gBAAgB,UAAU,OAAO,QAAQ,QAAQ;AACpD,YAAI,WAAW,gBAAgB,KAAK,iBAAiB;AACnD,cAAI;AACF,kBAAM,UAA2B;AAAA,cAC/B,MAAM;AAAA,cACN,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,YACpC;AACA,kBAAM,KAAK,gBAAgB,MAAM,OAAO;AAAA,UAC1C,SAAS,YAAY;AAEnB,oBAAQ,KAAK,oCAAoC,UAAU;AAAA,UAC7D;AAAA,QACF,WAAW,WAAW,iBAAiB;AAErC,kBAAQ,KAAK,kCAAkC,KAAK,WAAW,eAAe;AAAA,QAChF;AAAA,MACF,CAAC;AAAA,IACH;AAEA,SAAK,KAAK,WAAW;AAAA,EACvB;AAAA,EAEA,MAAM,aAA4B;AAEhC,QAAI,KAAK,iBAAiB;AACxB,YAAM,KAAK,gBAAgB,QAAQ;AACnC,YAAM,KAAK,SAAS,cAAc,KAAK,eAAe;AACtD,WAAK,kBAAkB;AAAA,IACzB;AAEA,QAAI,KAAK,eAAe;AACtB,YAAM,KAAK,SAAS,cAAc,KAAK,aAAa;AACpD,WAAK,gBAAgB;AAAA,IACvB;AAEA,QAAI,KAAK,cAAc;AACrB,YAAM,KAAK,SAAS,cAAc,KAAK,YAAY;AACnD,WAAK,eAAe;AAAA,IACtB;AAEA,SAAK,KAAK,cAAc;AAAA,EAC1B;AAAA,EAEA,MAAM,UAAU,SAAgC;AAC9C,QAAI,CAAC,KAAK,eAAe;AACvB,YAAM,IAAI,MAAM,eAAe;AAAA,IACjC;AAEA,UAAM,UAA2B;AAAA,MAC/B,MAAM;AAAA,MACN;AAAA,MACA,WAAW,KAAK,IAAI;AAAA,MACpB,KAAK,EAAE,KAAK;AAAA,IACd;AAGA,QAAI;AACF,YAAM,EAAE,MAAM,IAAI,MAAM,KAAK,SAAS,KAAK,UAAU,EAAE,OAAO;AAAA,QAC5D,YAAY,KAAK;AAAA,QACjB,MAAM,QAAQ;AAAA,QACd,SAAS,QAAQ;AAAA,QACjB,KAAK,QAAQ;AAAA,MACf,CAAC;AACD,UAAI,OAAO;AACT,gBAAQ,KAAK,qCAAqC,MAAM,OAAO;AAAA,MACjE;AAAA,IACF,SAAS,OAAO;AAEd,cAAQ,KAAK,qCAAqC,KAAK;AAAA,IACzD;AAGA,QAAI,CAAC,KAAK,iBAAiB;AACzB;AAAA,IACF;AAEA,QAAI;AACF,YAAM,KAAK,cAAc,KAAK;AAAA,QAC5B,MAAM;AAAA,QACN,OAAO;AAAA,QACP,SAAS;AAAA,MACX,CAAC;AAAA,IACH,SAAS,OAAO;AACd,YAAM;AAAA,IACR;AAEA,SAAK,KAAK,aAAa,OAAO;AAAA,EAChC;AAAA,EAEA,MAAM,cAAc,MAAqC;AACvD,QAAI,CAAC,KAAK,eAAe;AACvB,YAAM,IAAI,MAAM,eAAe;AAAA,IACjC;AAGA,QAAI,CAAC,KAAK,iBAAiB;AACzB;AAAA,IACF;AAEA,UAAM,UAA2B;AAAA,MAC/B,MAAM;AAAA,MACN,gBAAgB;AAAA,MAChB,WAAW,KAAK,IAAI;AAAA,MACpB,KAAK,EAAE,KAAK;AAAA,IACd;AAEA,UAAM,KAAK,cAAc,KAAK;AAAA,MAC5B,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAED,SAAK,KAAK,aAAa,OAAO;AAAA,EAChC;AAAA,EAEA,MAAM,kBAAkB,UAAyC;AAC/D,QAAI,CAAC,KAAK,eAAe;AACvB,YAAM,IAAI,MAAM,eAAe;AAAA,IACjC;AAGA,QAAI,CAAC,KAAK,iBAAiB;AACzB;AAAA,IACF;AAEA,UAAM,UAA2B;AAAA,MAC/B,MAAM;AAAA,MACN;AAAA,MACA,WAAW,KAAK,IAAI;AAAA,MACpB,KAAK,EAAE,KAAK;AAAA,IACd;AAEA,UAAM,KAAK,cAAc,KAAK;AAAA,MAC5B,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAED,SAAK,KAAK,aAAa,OAAO;AAAA,EAChC;AAAA,EAEA,MAAM,eAAe,OAA8B;AACjD,QAAI,CAAC,KAAK,eAAe;AACvB,YAAM,IAAI,MAAM,eAAe;AAAA,IACjC;AAGA,QAAI,CAAC,KAAK,iBAAiB;AACzB;AAAA,IACF;AAEA,UAAM,UAA2B;AAAA,MAC/B,MAAM;AAAA,MACN;AAAA,MACA,WAAW,KAAK,IAAI;AAAA,MACpB,KAAK,EAAE,KAAK;AAAA,IACd;AAEA,UAAM,KAAK,cAAc,KAAK;AAAA,MAC5B,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAED,SAAK,KAAK,aAAa,OAAO;AAAA,EAChC;AAAA,EAEA,MAAM,gBAAgB,QAAoC;AACxD,QAAI,CAAC,KAAK,eAAe;AACvB,YAAM,IAAI,MAAM,eAAe;AAAA,IACjC;AAGA,QAAI,CAAC,KAAK,iBAAiB;AACzB;AAAA,IACF;AAEA,UAAM,UAA2B;AAAA,MAC/B,MAAM;AAAA,MACN,iBAAiB;AAAA,MACjB,WAAW,KAAK,IAAI;AAAA,MACpB,KAAK,EAAE,KAAK;AAAA,IACd;AAEA,UAAM,KAAK,cAAc,KAAK;AAAA,MAC5B,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAED,SAAK,KAAK,aAAa,OAAO;AAAA,EAChC;AAAA,EAEA,MAAM,gBAAgB,SAAgC;AACpD,QAAI,CAAC,KAAK,eAAe;AACvB,YAAM,IAAI,MAAM,eAAe;AAAA,IACjC;AAEA,UAAM,UAA2B;AAAA,MAC/B,MAAM;AAAA,MACN;AAAA,MACA,WAAW,KAAK,IAAI;AAAA,MACpB,KAAK,EAAE,KAAK;AAAA,IACd;AAGA,QAAI;AACF,YAAM,EAAE,MAAM,IAAI,MAAM,KAAK,SAAS,KAAK,UAAU,EAAE,OAAO;AAAA,QAC5D,YAAY,KAAK;AAAA,QACjB,MAAM,QAAQ;AAAA,QACd,SAAS,QAAQ;AAAA,QACjB,KAAK,QAAQ;AAAA,MACf,CAAC;AACD,UAAI,OAAO;AACT,gBAAQ,KAAK,4CAA4C,MAAM,OAAO;AAAA,MACxE;AAAA,IACF,SAAS,OAAO;AACd,cAAQ,KAAK,4CAA4C,KAAK;AAAA,IAChE;AAGA,QAAI,CAAC,KAAK,iBAAiB;AACzB;AAAA,IACF;AAEA,QAAI;AACF,YAAM,KAAK,cAAc,KAAK;AAAA,QAC5B,MAAM;AAAA,QACN,OAAO;AAAA,QACP,SAAS;AAAA,MACX,CAAC;AAAA,IACH,SAAS,OAAO;AACd,YAAM;AAAA,IACR;AAEA,SAAK,KAAK,aAAa,OAAO;AAAA,EAChC;AAAA,EAEA,MAAM,6BAA6B,MAA6C;AAC9E,QAAI,CAAC,KAAK,eAAe;AACvB,YAAM,IAAI,MAAM,eAAe;AAAA,IACjC;AAGA,QAAI,CAAC,KAAK,iBAAiB;AACzB;AAAA,IACF;AAEA,UAAM,UAA2B;AAAA,MAC/B,MAAM;AAAA,MACN,iBAAiB;AAAA,MACjB,WAAW,KAAK,IAAI;AAAA,MACpB,KAAK,EAAE,KAAK;AAAA,IACd;AAEA,UAAM,KAAK,cAAc,KAAK;AAAA,MAC5B,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAED,SAAK,KAAK,aAAa,OAAO;AAAA,EAChC;AAAA,EAEA,MAAM,4BACJ,SACA,QACe;AACf,QAAI,CAAC,KAAK,eAAe;AACvB,YAAM,IAAI,MAAM,eAAe;AAAA,IACjC;AAGA,QAAI,CAAC,KAAK,iBAAiB;AACzB;AAAA,IACF;AAEA,UAAM,UAA2B;AAAA,MAC/B,MAAM;AAAA,MACN,oBAAoB;AAAA,MACpB,mBAAmB;AAAA,MACnB,WAAW,KAAK,IAAI;AAAA,MACpB,KAAK,EAAE,KAAK;AAAA,IACd;AAEA,UAAM,KAAK,cAAc,KAAK;AAAA,MAC5B,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAED,SAAK,KAAK,aAAa,OAAO;AAAA,EAChC;AAAA,EAEA,MAAM,uBAAuB,kBAAyC;AACpE,QAAI,CAAC,KAAK,eAAe;AACvB,YAAM,IAAI,MAAM,eAAe;AAAA,IACjC;AAGA,QAAI,CAAC,KAAK,iBAAiB;AACzB;AAAA,IACF;AAEA,UAAM,UAA2B;AAAA,MAC/B,MAAM;AAAA,MACN;AAAA,MACA,WAAW,KAAK,IAAI;AAAA,MACpB,KAAK,EAAE,KAAK;AAAA,IACd;AAEA,UAAM,KAAK,cAAc,KAAK;AAAA,MAC5B,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAED,SAAK,KAAK,aAAa,OAAO;AAAA,EAChC;AAAA,EAEA,MAAM,sBAAsB,cAA+C;AACzE,QAAI,CAAC,KAAK,eAAe;AACvB,YAAM,IAAI,MAAM,eAAe;AAAA,IACjC;AAGA,QAAI,CAAC,KAAK,iBAAiB;AACzB;AAAA,IACF;AAEA,UAAM,UAA2B;AAAA,MAC/B,MAAM;AAAA,MACN,cAAc;AAAA,MACd,WAAW,KAAK,IAAI;AAAA,MACpB,KAAK,EAAE,KAAK;AAAA,IACd;AAEA,UAAM,KAAK,cAAc,KAAK;AAAA,MAC5B,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAED,SAAK,KAAK,aAAa,OAAO;AAAA,EAChC;AAAA,EAEA,MAAM,2BAA2B,aAAmD;AAClF,QAAI,CAAC,KAAK,eAAe;AACvB,YAAM,IAAI,MAAM,eAAe;AAAA,IACjC;AAGA,QAAI,CAAC,KAAK,iBAAiB;AACzB;AAAA,IACF;AAEA,UAAM,UAA2B;AAAA,MAC/B,MAAM;AAAA,MACN,mBAAmB;AAAA,MACnB,WAAW,KAAK,IAAI;AAAA,MACpB,KAAK,EAAE,KAAK;AAAA,IACd;AAEA,UAAM,KAAK,cAAc,KAAK;AAAA,MAC5B,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAED,SAAK,KAAK,aAAa,OAAO;AAAA,EAChC;AAAA,EAEA,MAAM,iBAAiB,aAAyC;AAC9D,QAAI,CAAC,KAAK,eAAe;AACvB,YAAM,IAAI,MAAM,eAAe;AAAA,IACjC;AAEA,UAAM,UAA2B;AAAA,MAC/B,MAAM;AAAA,MACN;AAAA,MACA,SAAS,KAAK,UAAU,WAAW;AAAA,MACnC,WAAW,KAAK,IAAI;AAAA,MACpB,KAAK,EAAE,KAAK;AAAA,IACd;AAGA,QAAI;AACF,YAAM,EAAE,MAAM,IAAI,MAAM,KAAK,SAAS,KAAK,UAAU,EAAE,OAAO;AAAA,QAC5D,YAAY,KAAK;AAAA,QACjB,MAAM,QAAQ;AAAA,QACd,SAAS,QAAQ;AAAA,QACjB,KAAK,QAAQ;AAAA,MACf,CAAC;AACD,UAAI,OAAO;AACT,gBAAQ,KAAK,8CAA8C,MAAM,OAAO;AAAA,MAC1E;AAAA,IACF,SAAS,OAAO;AACd,cAAQ,KAAK,8CAA8C,KAAK;AAAA,IAClE;AAGA,QAAI,CAAC,KAAK,iBAAiB;AACzB;AAAA,IACF;AAEA,QAAI;AACF,YAAM,KAAK,cAAc,KAAK;AAAA,QAC5B,MAAM;AAAA,QACN,OAAO;AAAA,QACP,SAAS;AAAA,MACX,CAAC;AAAA,IACH,SAAS,OAAO;AACd,YAAM;AAAA,IACR;AAEA,SAAK,KAAK,aAAa,OAAO;AAAA,EAChC;AAAA,EAEA,MAAM,wBACJ,cACA,iBACA,gBACe;AACf,QAAI,CAAC,KAAK,eAAe;AACvB,YAAM,IAAI,MAAM,eAAe;AAAA,IACjC;AAEA,QAAI,CAAC,KAAK,iBAAiB;AACzB;AAAA,IACF;AAEA,UAAM,UAA2B;AAAA,MAC/B,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW,KAAK,IAAI;AAAA,MACpB,KAAK,EAAE,KAAK;AAAA,IACd;AAEA,UAAM,KAAK,cAAc,KAAK;AAAA,MAC5B,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAED,SAAK,KAAK,aAAa,OAAO;AAAA,EAChC;AAAA,EAEA,MAAM,oBAAmC;AACvC,QAAI,CAAC,KAAK,eAAe;AACvB,YAAM,IAAI,MAAM,eAAe;AAAA,IACjC;AAGA,QAAI,CAAC,KAAK,iBAAiB;AACzB;AAAA,IACF;AAEA,UAAM,UAA2B;AAAA,MAC/B,MAAM;AAAA,MACN,WAAW,KAAK,IAAI;AAAA,MACpB,KAAK,EAAE,KAAK;AAAA,IACd;AAEA,UAAM,KAAK,cAAc,KAAK;AAAA,MAC5B,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAED,SAAK,KAAK,aAAa,OAAO;AAAA,EAChC;AAAA,EAEA,MAAM,sBAAsB,OAA8B;AACxD,QAAI,CAAC,KAAK,eAAe;AACvB,YAAM,IAAI,MAAM,eAAe;AAAA,IACjC;AAGA,QAAI,CAAC,KAAK,iBAAiB;AACzB;AAAA,IACF;AAEA,UAAM,UAA2B;AAAA,MAC/B,MAAM;AAAA,MACN,cAAc;AAAA,MACd,WAAW,KAAK,IAAI;AAAA,MACpB,KAAK,EAAE,KAAK;AAAA,IACd;AAEA,UAAM,KAAK,cAAc,KAAK;AAAA,MAC5B,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAED,SAAK,KAAK,aAAa,OAAO;AAAA,EAChC;AAAA,EAEA,MAAM,kBAAiC;AACrC,QAAI,CAAC,KAAK,eAAe;AACvB,YAAM,IAAI,MAAM,eAAe;AAAA,IACjC;AAEA,QAAI,CAAC,KAAK,iBAAiB;AACzB;AAAA,IACF;AAEA,UAAM,UAA2B;AAAA,MAC/B,MAAM;AAAA,MACN,WAAW,KAAK,IAAI;AAAA,MACpB,KAAK,EAAE,KAAK;AAAA,IACd;AAEA,UAAM,KAAK,cAAc,KAAK;AAAA,MAC5B,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAED,SAAK,KAAK,aAAa,OAAO;AAAA,EAChC;AAAA,EAEA,MAAM,eAAe,cAAsB,WAAmC;AAC5E,QAAI,CAAC,KAAK,eAAe;AACvB,YAAM,IAAI,MAAM,eAAe;AAAA,IACjC;AAGA,QAAI,CAAC,KAAK,iBAAiB;AACzB;AAAA,IACF;AAEA,UAAM,UAA2B;AAAA,MAC/B,MAAM;AAAA,MACN,SAAS;AAAA,MACT,WAAW,aAAa;AAAA,MACxB,WAAW,KAAK,IAAI;AAAA,MACpB,KAAK,EAAE,KAAK;AAAA,IACd;AAEA,UAAM,KAAK,cAAc,KAAK;AAAA,MAC5B,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAED,SAAK,KAAK,aAAa,OAAO;AAAA,EAChC;AAAA,EAEA,SAAiB;AACf,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,cAAuB;AACrB,WAAO,KAAK,kBAAkB,QAAQ,KAAK,iBAAiB;AAAA,EAC9D;AAAA,EAEA,oBAA6B;AAC3B,WAAO,KAAK;AAAA,EACd;AACF;;;AE9mBO,IAAM,iBAAN,MAAqB;AAAA,EAClB;AAAA,EAER,YAAY,SAAgC;AAC1C,SAAK,WAAW,QAAQ;AAAA,EAC1B;AAAA,EAEA,MAAM,cACJ,WACA,kBACkB;AAClB,UAAM,EAAE,MAAM,MAAM,IAAI,MAAM,KAAK,SAChC,KAAK,UAAU,EACf,OAAO;AAAA,MACN,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,mBAAmB;AAAA,MACnB,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,IACrC,CAAC,EACA,OAAO,EACP,OAAO;AAEV,QAAI,OAAO;AACT,YAAM,IAAI,MAAM,6BAA6B,MAAM,OAAO,EAAE;AAAA,IAC9D;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,WAAW,WAAkC;AACjD,UAAM,EAAE,MAAM,IAAI,MAAM,KAAK,SAC1B,KAAK,UAAU,EACf,OAAO;AAAA,MACN,QAAQ;AAAA,MACR,WAAU,oBAAI,KAAK,GAAE,YAAY;AAAA,IACnC,CAAC,EACA,GAAG,MAAM,SAAS;AAErB,QAAI,OAAO;AACT,YAAM,IAAI,MAAM,0BAA0B,MAAM,OAAO,EAAE;AAAA,IAC3D;AAAA,EACF;AAAA,EAEA,MAAM,WAAW,WAA4C;AAC3D,UAAM,EAAE,MAAM,MAAM,IAAI,MAAM,KAAK,SAChC,KAAK,UAAU,EACf,OAAO,EACP,GAAG,MAAM,SAAS,EAClB,OAAO;AAEV,QAAI,OAAO;AACT,UAAI,MAAM,SAAS,YAAY;AAE7B,eAAO;AAAA,MACT;AACA,YAAM,IAAI,MAAM,0BAA0B,MAAM,OAAO,EAAE;AAAA,IAC3D;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,oBACJ,WACA,QACe;AACf,UAAM,UAA4B,EAAE,OAAO;AAE3C,QAAI,WAAW,SAAS;AACtB,cAAQ,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAC5C;AAEA,UAAM,EAAE,MAAM,IAAI,MAAM,KAAK,SAC1B,KAAK,UAAU,EACf,OAAO,OAAO,EACd,GAAG,MAAM,SAAS;AAErB,QAAI,OAAO;AACT,YAAM,IAAI,MAAM,oCAAoC,MAAM,OAAO,EAAE;AAAA,IACrE;AAAA,EACF;AAAA,EAEA,MAAM,mBACJ,WACA,OACe;AACf,UAAM,EAAE,MAAM,IAAI,MAAM,KAAK,SAC1B,KAAK,UAAU,EACf,OAAO,EAAE,MAAM,CAAC,EAChB,GAAG,MAAM,SAAS;AAErB,QAAI,OAAO;AACT,YAAM,IAAI,MAAM,mCAAmC,MAAM,OAAO,EAAE;AAAA,IACpE;AAAA,EACF;AAAA,EAEA,MAAM,mBACJ,WACA,cACe;AACf,UAAM,EAAE,MAAM,IAAI,MAAM,KAAK,SAC1B,KAAK,UAAU,EACf,OAAO,EAAE,gBAAgB,aAAa,CAAC,EACvC,GAAG,MAAM,SAAS;AAErB,QAAI,OAAO;AACT,YAAM,IAAI,MAAM,oCAAoC,MAAM,OAAO,EAAE;AAAA,IACrE;AAAA,EACF;AAAA,EAEA,MAAM,mBACJ,WACA,OACe;AACf,UAAM,EAAE,MAAM,IAAI,MAAM,KAAK,SAC1B,KAAK,UAAU,EACf,OAAO,EAAE,MAAM,CAAC,EAChB,GAAG,MAAM,SAAS;AAErB,QAAI,OAAO;AACT,YAAM,IAAI,MAAM,mCAAmC,MAAM,OAAO,EAAE;AAAA,IACpE;AAAA,EACF;AACF;;;AC/HA,YAAY,QAAQ;AAMb,IAAM,iBAAN,MAAqB;AAAA,EAClB;AAAA,EAER,YAAY,SAAgC;AAC1C,SAAK,WAAW,QAAQ;AAAA,EAC1B;AAAA,EAEA,MAAM,gBACJ,QACA,MACA,WACkB;AAClB,UAAMC,YAAc,YAAS;AAC7B,UAAM,cAAc,QAAQA;AAG5B,QAAI,WAAW;AACb,YAAM,WAAW,MAAM,KAAK,WAAW,SAAS;AAChD,UAAI,UAAU;AACZ,cAAM,KAAK,oBAAoB,WAAW,QAAQ;AAClD,eAAO;AAAA,MACT;AAAA,IACF;AAGA,UAAM,EAAE,MAAM,mBAAmB,IAAI,MAAM,KAAK,SAC7C,KAAK,UAAU,EACf,OAAO,EACP,GAAG,WAAW,MAAM,EACpB,GAAG,YAAYA,SAAQ,EACvB,OAAO;AAEV,QAAI,oBAAoB;AAEtB,YAAM,KAAK,oBAAoB,mBAAmB,IAAI,QAAQ;AAC9D,aAAO;AAAA,IACT;AAGA,UAAM,EAAE,MAAM,MAAM,IAAI,MAAM,KAAK,SAChC,KAAK,UAAU,EACf,OAAO;AAAA,MACN,SAAS;AAAA,MACT,MAAM;AAAA,MACN,UAAAA;AAAA,MACA,QAAQ;AAAA,MACR,eAAc,oBAAI,KAAK,GAAE,YAAY;AAAA,IACvC,CAAC,EACA,OAAO,EACP,OAAO;AAEV,QAAI,OAAO;AACT,YAAM,IAAI,MAAM,+BAA+B,MAAM,OAAO,EAAE;AAAA,IAChE;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,WAAW,WAA4C;AAC3D,UAAM,EAAE,MAAM,MAAM,IAAI,MAAM,KAAK,SAChC,KAAK,UAAU,EACf,OAAO,EACP,GAAG,MAAM,SAAS,EAClB,OAAO;AAEV,QAAI,OAAO;AACT,UAAI,MAAM,SAAS,YAAY;AAE7B,eAAO;AAAA,MACT;AACA,YAAM,IAAI,MAAM,0BAA0B,MAAM,OAAO,EAAE;AAAA,IAC3D;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,oBACJ,WACA,QACe;AACf,UAAM,EAAE,MAAM,IAAI,MAAM,KAAK,SAC1B,KAAK,UAAU,EACf,OAAO;AAAA,MACN;AAAA,MACA,eAAc,oBAAI,KAAK,GAAE,YAAY;AAAA,IACvC,CAAC,EACA,GAAG,MAAM,SAAS;AAErB,QAAI,OAAO;AACT,YAAM,IAAI,MAAM,oCAAoC,MAAM,OAAO,EAAE;AAAA,IACrE;AAAA,EACF;AAAA,EAEA,MAAM,UAAU,WAAkC;AAChD,UAAM,EAAE,MAAM,IAAI,MAAM,KAAK,SAC1B,KAAK,UAAU,EACf,OAAO;AAAA,MACN,eAAc,oBAAI,KAAK,GAAE,YAAY;AAAA,IACvC,CAAC,EACA,GAAG,MAAM,SAAS;AAErB,QAAI,OAAO;AACT,YAAM,IAAI,MAAM,+BAA+B,MAAM,OAAO,EAAE;AAAA,IAChE;AAAA,EACF;AAAA,EAEA,MAAM,aAAa,QAAoC;AACrD,UAAM,EAAE,MAAM,MAAM,IAAI,MAAM,KAAK,SAChC,KAAK,UAAU,EACf,OAAO,EACP,GAAG,WAAW,MAAM,EACpB,MAAM,gBAAgB,EAAE,WAAW,MAAM,CAAC;AAE7C,QAAI,OAAO;AACT,YAAM,IAAI,MAAM,4BAA4B,MAAM,OAAO,EAAE;AAAA,IAC7D;AAEA,WAAO;AAAA,EACT;AACF;;;AC/HA,SAAS,gBAAAC,qBAAoB;;;ACA7B,SAAS,gBAAAC,qBAAoB;AAC7B,YAAY,QAAQ;AACpB,YAAY,UAAU;AACtB,YAAYC,SAAQ;AACpB,SAAS,2BAA2B,iCAAiC;AAGrE,SAAS,MAAM,cAAc;AAG7B,IAAM,mBAAmB;AAEzB,IAAM,4BAA4B;AAElC,IAAM,mCAAmC;AAEzC,IAAM,gCAAgC,4BAA4B;AAGlE,IAAM,uBAAuB,oBAAI,IAAI;AAAA,EACnC;AAAA,EAAoB;AAAA,EAAQ;AAAA,EAAW;AAAA,EAAQ;AAAA,EAC/C;AAAA,EAAO;AAAA,EAAO;AAAA,EAAU;AAAA,EAAS;AACnC,CAAC;AA2BM,IAAM,aAAN,cAAyBD,cAAa;AAAA,EACnC;AAAA,EACA,YAA2B;AAAA,EAC3B,eAAwB;AAAA,EACxB;AAAA,EACA,YAA8B;AAAA,EAC9B,oBAA6B;AAAA,EAC7B,iBAAwC;AAAA,EACxC,eAAmC;AAAA,EACnC,eAAuB;AAAA,EACvB,sBAA6C,CAAC;AAAA,EAC9C,yBAAkC;AAAA,EAClC,kBAA2B;AAAA,EAC3B,4BAAmE,oBAAI,IAAI;AAAA;AAAA,EAE3E,uBAAoD;AAAA;AAAA,EAEpD,sBAA+C;AAAA,EAC/C,wBAAsD;AAAA;AAAA,EAEtD,2BAAmC;AAAA;AAAA,EAEnC,gBAA4E;AAAA;AAAA,EAE5E,sBAAkF;AAAA;AAAA,EAElF,oCAA6C;AAAA;AAAA,EAE7C,iBAAyB;AAAA;AAAA,EAEzB,uBAA+B;AAAA;AAAA,EAE/B,wBAAgC;AAAA;AAAA,EAEhC,wCAAuD;AAAA;AAAA,EAEvD,iCAAuE;AAAA;AAAA,EAEvE,4BAAkE;AAAA,EAE1E,YAAY,SAA4B;AACtC,UAAM;AACN,SAAK,UAAU;AACf,SAAK,wBAAwB,QAAQ,kBAAkB;AACvD,SAAK,eAAe,QAAQ,SAAS;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA,EAKA,yBAAyB,UAAwC;AAC/D,UAAM,UAAU,KAAK,0BAA0B,IAAI,SAAS,SAAS;AACrE,QAAI,CAAC,SAAS;AACZ,cAAQ,KAAK,sDAAsD,SAAS,SAAS,EAAE;AACvF;AAAA,IACF;AAEA,SAAK,0BAA0B,OAAO,SAAS,SAAS;AACxD,SAAK,wBAAwB;AAE7B,QAAI,SAAS,aAAa,SAAS;AACjC,YAAM,SAA2B;AAAA,QAC/B,UAAU;AAAA;AAAA;AAAA;AAAA,QAIV,cAAc,SAAS,gBAAgB,QAAQ;AAAA,QAC/C,oBAAoB,SAAS;AAAA,MAC/B;AACA,cAAQ,QAAQ,MAAM;AAAA,IACxB,OAAO;AACL,YAAM,SAA2B;AAAA,QAC/B,UAAU;AAAA,QACV,SAAS,SAAS,WAAW;AAAA,MAC/B;AACA,cAAQ,QAAQ,MAAM;AAAA,IACxB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYQ,mBAA+B;AACrC,WAAO,OACL,UACA,OACA,YAQ8B;AAG9B,UAAI,aAAa,mBAAmB;AAClC,cAAM,gBAAgB;AAStB,YAAI,cAAc,aAAa,MAAM,QAAQ,cAAc,SAAS,GAAG;AACrE,gBAAM,YAA4B,cAAc,UAAU,IAAI,QAAM;AAAA,YAClE,UAAU,EAAE;AAAA,YACZ,QAAQ,EAAE;AAAA,YACV,UAAU,EAAE,WAAW,CAAC,GAAG,IAAI,QAAM;AAAA,cACnC,OAAO,EAAE;AAAA,cACT,aAAa,EAAE;AAAA,YACjB,EAAE;AAAA,YACF,aAAa,EAAE;AAAA,UACjB,EAAE;AAEF,gBAAM,eAAiC;AAAA,YACrC,WAAW,QAAQ;AAAA,YACnB;AAAA,UACF;AAGA,eAAK,sBAAsB;AAC3B,eAAK,KAAK,iBAAiB,YAAY;AAGvC,gBAAM,UAAU,MAAM,IAAI;AAAA,YACxB,CAACE,UAAS,WAAW;AACnB,oBAAM,iBAAuC,EAAE,SAAAA,UAAS,OAAO;AAC/D,mBAAK,uBAAuB;AAG5B,sBAAQ,OAAO,iBAAiB,SAAS,MAAM;AAC7C,oBAAI,KAAK,yBAAyB,gBAAgB;AAChD,uBAAK,uBAAuB;AAC5B,uBAAK,sBAAsB;AAAA,gBAC7B;AACA,uBAAO,IAAI,MAAM,kBAAkB,CAAC;AAAA,cACtC,CAAC;AAAA,YACH;AAAA,UACF;AAEA,eAAK,uBAAuB;AAC5B,eAAK,sBAAsB;AAG3B,iBAAO;AAAA,YACL,UAAU;AAAA,YACV,cAAc;AAAA,cACZ,WAAW,cAAc;AAAA,cACzB;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAGA,YAAM,YAAY,OAAO;AAGzB,YAAM,cAAc,QAAQ,aAAa,IAAI,CAAC,MAAwB;AAEpE,YAAI,EAAE,SAAS,cAAc,EAAE,SAAS,kBAAkB,EAAE,SAAS,eAAe;AAClF,iBAAO;AAAA,YACL,MAAM,EAAE;AAAA,YACR,OAAO,EAAE;AAAA,YACT,UAAU,EAAE;AAAA,YACZ,aAAa,EAAE;AAAA,UACjB;AAAA,QACF,WAAW,EAAE,SAAS,WAAW;AAC/B,iBAAO;AAAA,YACL,MAAM;AAAA,YACN,MAAM,EAAE;AAAA,YACR,aAAa,EAAE;AAAA,UACjB;AAAA,QACF,WAAW,EAAE,SAAS,oBAAoB,EAAE,SAAS,qBAAqB;AACxE,iBAAO;AAAA,YACL,MAAM,EAAE;AAAA,YACR,aAAa,EAAE;AAAA,YACf,aAAa,EAAE;AAAA,UACjB;AAAA,QACF;AAEA,eAAO;AAAA,MACT,CAAC;AAED,YAAM,cAAqC;AAAA,QACzC;AAAA,QACA;AAAA,QACA,WAAW;AAAA,QACX,WAAW,QAAQ;AAAA,QACnB;AAAA,QACA,aAAa,QAAQ;AAAA,QACrB,gBAAgB,QAAQ;AAAA,QACxB,SAAS,QAAQ;AAAA,MACnB;AAGA,WAAK,wBAAwB;AAC7B,WAAK,KAAK,sBAAsB,WAAW;AAG3C,aAAO,IAAI,QAA0B,CAACA,UAAS,WAAW;AACxD,aAAK,0BAA0B,IAAI,WAAW;AAAA,UAC5C,SAAAA;AAAA,UACA;AAAA,UACA,QAAQ,QAAQ;AAAA,UAChB,WAAW;AAAA,QACb,CAAC;AAGD,gBAAQ,OAAO,iBAAiB,SAAS,MAAM;AAC7C,eAAK,0BAA0B,OAAO,SAAS;AAC/C,eAAK,wBAAwB;AAC7B,iBAAO,IAAI,MAAM,4BAA4B,CAAC;AAAA,QAChD,CAAC;AAAA,MACH,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,kBAAkB,MAA4B;AAC5C,UAAM,cAAc,KAAK,0BAA0B;AACnD,SAAK,wBAAwB;AAI7B,QAAI,aAAa;AACf,WAAK,6BAA6B,sBAAsB;AACxD,WAAK,oCAAoC;AACzC,WAAK,+BAA+B;AACpC,WAAK,oCAAoC;AACzC,WAAK,kCAAkC;AACvC,UAAI,KAAK,WAAW;AAClB,aAAK,UAAU,MAAM;AACrB,aAAK,YAAY;AACjB,aAAK,oBAAoB;AACzB,aAAK,YAAY;AACjB,aAAK,eAAe;AACpB,aAAK,gBAAgB;AACrB,aAAK,yBAAyB;AAAA,MAChC,WAAW,KAAK,WAAW;AACzB,aAAK,YAAY;AACjB,aAAK,yBAAyB;AAAA,MAChC;AAAA,IACF;AAEA,SAAK,KAAK,mBAAmB,IAAI;AAAA,EACnC;AAAA,EAEA,oBAAoC;AAClC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,gBAAgB,SAAiC;AACrD,SAAK,kBAAkB;AACvB,SAAK,KAAK,iBAAiB,OAAO;AAAA,EACpC;AAAA,EAEA,kBAA2B;AACzB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKQ,sBAAyC;AAC/C,UAAM,OAA0B;AAAA;AAAA;AAAA,MAG9B,OAAO,KAAK;AAAA,MACZ,cAAc,KAAK,QAAQ,gBAAgB,CAAC,QAAQ,QAAQ,SAAS,QAAQ,QAAQ,MAAM;AAAA,MAC3F,YAAY,KAAK,iBAAiB;AAAA,MAClC,gBAAgB,KAAK;AAAA,IACvB;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,gBAA2B;AACjC,QAAI,CAAC,KAAK,WAAW;AACnB,YAAM,OAAO,KAAK,oBAAoB;AAEtC,UAAI,KAAK,WAAW;AAElB,aAAK,YAAY,0BAA0B,KAAK,WAAW,IAAI;AAAA,MACjE,OAAO;AAEL,aAAK,YAAY,0BAA0B,IAAI;AAAA,MACjD;AAGA,WAAK,gBAAgB;AAAA,IACvB;AACA,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,uBAAmF;AACzF,UAAM,cAAc,KAAK;AACzB,QAAI,CAAC,YAAa,QAAO;AAEzB,SAAK,sBAAsB;AAC3B,SAAK,YAAY;AACjB,SAAK,YAAY;AACjB,SAAK,oBAAoB;AACzB,SAAK,eAAe;AAGpB,QAAI,KAAK,oBAAoB,SAAS,KAAK,KAAK,oBAAoB,KAAK,oBAAoB,SAAS,CAAC,EAAE,SAAS,QAAQ;AACxH,WAAK,oBAAoB,IAAI;AAAA,IAC/B;AAEA,SAAK,KAAK,eAAe;AACzB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,kBAAiC;AAC7C,QAAI,KAAK,qBAAqB,CAAC,KAAK,UAAW;AAC/C,SAAK,oBAAoB;AAEzB,QAAI,WAAW;AACf,QAAI;AAGF,aAAO,KAAK,aAAa,CAAC,KAAK,UAAU,QAAQ,GAAG;AAClD,yBAAiB,WAAW,KAAK,UAAU,OAAO,GAAG;AACnD,eAAK,eAAe,OAAO;AAAA,QAC7B;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,UAAK,MAAgB,SAAS,cAAc;AAC1C,cAAM,cAAc,KAAK,qBAAqB;AAC9C,YAAI,aAAa;AACf,qBAAW;AACX,eAAK,WAAW,YAAY,QAAQ,YAAY,WAAW,EAAE,MAAM,CAAC,aAAa;AAC/E,iBAAK,KAAK,SAAS,QAAQ;AAAA,UAC7B,CAAC;AAAA,QACH,OAAO;AACL,eAAK,KAAK,SAAS,KAAK;AAAA,QAC1B;AAAA,MACF;AAAA,IACF,UAAE;AACA,WAAK,oBAAoB;AAKzB,UAAI,KAAK,gBAAgB,CAAC,UAAU;AAClC,aAAK,eAAe;AACpB,aAAK,gBAAgB;AACrB,aAAK,KAAK,UAAU;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,eAAe,SAA2B;AAEhD,QAAI,QAAQ,SAAS,YAAY,aAAa,WAAW,QAAQ,YAAY,QAAQ;AAEnF,WAAK,sBAAsB;AAG3B,WAAK,YAAY,QAAQ;AACzB,WAAK,KAAK,mBAAmB,KAAK,SAAS;AAG3C,UAAI,oBAAoB,SAAS;AAC/B,aAAK,KAAK,mBAAmB,QAAQ,cAAc;AAAA,MACrD;AAGA,UAAI,oBAAoB,WAAW,MAAM,QAAQ,QAAQ,cAAc,GAAG;AACxE,aAAK,iBAAiB,QAAQ,eAAe,IAAI,CAAC,QAAiB;AACjE,cAAI,OAAO,QAAQ,UAAU;AAC3B,mBAAO,EAAE,MAAM,KAAK,aAAa,IAAI,cAAc,GAAG;AAAA,UACxD,WAAW,OAAO,QAAQ,YAAY,QAAQ,MAAM;AAClD,kBAAM,SAAS;AACf,mBAAO;AAAA,cACL,MAAM,OAAO,QAAQ;AAAA,cACrB,aAAa,OAAO,eAAe;AAAA,cACnC,cAAc,OAAO,gBAAgB;AAAA,YACvC;AAAA,UACF;AACA,iBAAO,EAAE,MAAM,OAAO,GAAG,GAAG,aAAa,IAAI,cAAc,GAAG;AAAA,QAChE,CAAC;AACD,aAAK,KAAK,oBAAoB,KAAK,cAAc;AAAA,MACnD;AAAA,IACF,WACE,QAAQ,SAAS,YACjB,aAAa,WACb,QAAQ,YAAY,YACpB,YAAY,WACZ,QAAQ,WAAW,QACnB,KAAK,qCACL,KAAK,cACL;AAEA,WAAK,kCAAkC;AAAA,IACzC,WACE,QAAQ,SAAS,YACjB,aAAa,WACb,QAAQ,YAAY,sBACpB,KAAK,qCACL,KAAK,cACL;AAEA,WAAK,kCAAkC;AAAA,IACzC,WAAW,QAAQ,SAAS,eAAe;AAEzC,YAAM,UAAU;AAChB,UAAI,QAAQ,OAAO;AACjB,aAAK,KAAK,cAAc;AAAA,UACtB,WAAW;AAAA,UACX,SAAS,QAAQ;AAAA,QACnB,CAAC;AAAA,MACH;AAAA,IACF,WAAW,QAAQ,SAAS,aAAa;AAEvC,YAAM,iBAAkB,QAAgB;AACxC,UAAI,gBAAgB;AAClB,aAAK,KAAK,cAAc;AAAA,UACtB,WAAW;AAAA,UACX,SAAS;AAAA,QACX,CAAC;AAAA,MACH;AAEA,UAAI,QAAQ,SAAS,SAAS;AAC5B,mBAAW,SAAS,QAAQ,QAAQ,SAAS;AAC3C,cAAI,UAAU,SAAS,MAAM,SAAS,UAAU,UAAU,OAAO;AAC/D,iBAAK,KAAK,UAAU,MAAM,IAAI;AAC9B,iBAAK,4BAA4B,MAAM;AAAA,UACzC,WAAW,UAAU,SAAS,MAAM,SAAS,cAAc,UAAU,OAAO;AAG1E,kBAAM,WAAY,MAAc;AAChC,gBAAI,aAAa,mBAAmB;AAClC,oBAAM,QAAS,MAAc,SAAS,CAAC;AACvC,kBAAI;AAEJ,kBAAI,aAAa,UAAU,MAAM,aAAa,MAAM,eAAe,QAAW;AAC5E,8BAAc;AAAA,kBACZ,QAAQ;AAAA,kBACR,UAAU,MAAM;AAAA,kBAChB,WAAW,OAAO,MAAM,UAAU,EAAE,MAAM,GAAG,gBAAgB;AAAA,kBAC7D,WAAW,OAAO,MAAM,cAAc,EAAE,EAAE,MAAM,GAAG,gBAAgB;AAAA,gBACrE;AAAA,cACF,WAAW,aAAa,WAAW,MAAM,WAAW;AAClD,8BAAc;AAAA,kBACZ,QAAQ;AAAA,kBACR,UAAU,MAAM;AAAA,kBAChB,SAAS,OAAO,MAAM,WAAW,EAAE,EAAE,MAAM,GAAG,gBAAgB;AAAA,gBAChE;AAAA,cACF,OAAO;AACL,8BAAc;AAAA,kBACZ,QAAQ;AAAA,kBACR;AAAA,kBACA;AAAA,gBACF;AAAA,cACF;AAEA,mBAAK,KAAK,YAAY,WAAW;AAAA,YACnC;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF,WAAW,QAAQ,SAAS,UAAU;AACpC,WAAK,oCAAoC;AACzC,UAAI,KAAK,8BAA8B,GAAG;AACxC;AAAA,MACF;AAGA,UAAI,CAAC,KAAK,yBAAyB,KAAK,KAAK,YAAY,WAAW,QAAQ,QAAQ;AAClF,cAAM,aAAa,OAAO,QAAQ,MAAM;AACxC,aAAK,KAAK,UAAU,UAAU;AAC9B,aAAK,2BAA2B;AAAA,MAClC;AAEA,UAAI,KAAK,yBAAyB,KAAK,GAAG;AACxC,aAAK,oBAAoB,KAAK,EAAE,MAAM,aAAa,SAAS,KAAK,yBAAyB,KAAK,EAAE,CAAC;AAAA,MACpG;AAEA,WAAK,2BAA2B;AAChC,WAAK,oCAAoC;AACzC,WAAK,oBAAoB;AAAA,IAC3B,WAAW,QAAQ,SAAS,iBAAiB;AAE3C,UAAI,eAAe,SAAS;AAC1B,aAAK,KAAK,UAAU;AAAA,eAAkB,QAAQ,SAAS;AAAA,CAAK;AAAA,MAC9D;AAAA,IACF,WAAW,QAAQ,SAAS,oBAAoB;AAE9C,UAAI,eAAe,SAAS;AAC1B,aAAK,KAAK,UAAU,SAAS,QAAQ,SAAS;AAAA,CAAe;AAAA,MAC/D;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,WAAWC,SAAgB,aAAgD;AAC/E,QAAI,KAAK,cAAc;AAErB,WAAK,gBAAgB,EAAE,QAAAA,SAAQ,YAAY;AAC3C,WAAK,KAAK,gBAAgB;AAC1B;AAAA,IACF;AAEA,SAAK,oCAAoC;AACzC,SAAK,+BAA+B;AACpC,SAAK,oCAAoC,qBAAqB,KAAKA,QAAO,KAAK,CAAC;AAChF,SAAK,uBAAuB,EAAE,KAAK;AACnC,SAAK,wBAAwB,KAAK,IAAI;AACtC,QACE,KAAK,0CAA0C,QAC/C,KAAK,uBAAuB,KAAK,wCAAwC,GACzE;AACA,WAAK,kCAAkC;AAAA,IACzC;AACA,SAAK,eAAe;AACpB,SAAK,2BAA2B;AAGhC,QAAIA,QAAO,KAAK,GAAG;AACjB,WAAK,oBAAoB,KAAK,EAAE,MAAM,QAAQ,SAASA,QAAO,CAAC;AAAA,IACjE;AAEA,QAAI;AAEF,UAAI,KAAK,aAAa,CAAC,KAAK,WAAW;AACrC,aAAK,sBAAsB,EAAE,QAAAA,SAAQ,YAAY;AAAA,MACnD;AAGA,UAAI,cAAcA;AAClB,UAAI,KAAK,0BAA0B,KAAK,oBAAoB,SAAS,GAAG;AAEtE,cAAM,kBAAkB,KAAK,oBAAoB,MAAM,GAAG,EAAE;AAC5D,cAAM,eAAe,gBAAgB;AAAA,UAAI,SACvC,GAAG,IAAI,SAAS,SAAS,SAAS,WAAW,KAAK,IAAI,OAAO;AAAA,QAC/D;AACA,cAAM,gBAAgB;AAAA,EAAkE,aAAa,KAAK,IAAI,CAAC;AAAA;AAAA;AAAA;AAC/G,sBAAc,gBAAgBA;AAC9B,aAAK,yBAAyB;AAAA,MAChC;AAGA,YAAM,UAAU,KAAK,cAAc;AAGnC,YAAM,gBAAqH,CAAC;AAG5H,UAAI,eAAe,YAAY,SAAS,GAAG;AACzC,mBAAW,cAAc,aAAa;AACpC,wBAAc,KAAK;AAAA,YACjB,MAAM;AAAA,YACN,QAAQ;AAAA,cACN,MAAM;AAAA,cACN,YAAY,WAAW;AAAA,cACvB,MAAM,WAAW;AAAA,YACnB;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAGA,UAAI,YAAY,KAAK,GAAG;AACtB,sBAAc,KAAK;AAAA,UACjB,MAAM;AAAA,UACN,MAAM;AAAA,QACR,CAAC;AAAA,MACH;AAGA,YAAM,cAA8B;AAAA,QAClC,MAAM;AAAA,QACN,SAAS;AAAA,UACP,MAAM;AAAA,UACN,SAAS,cAAc,SAAS,IAAI,gBAAgB,CAAC,EAAE,MAAM,QAAiB,MAAM,YAAY,CAAC;AAAA,QACnG;AAAA,QACA,oBAAoB;AAAA,QACpB,YAAY,KAAK,aAAa;AAAA,MAChC;AAEA,YAAM,QAAQ,KAAK,WAAW;AAAA,IAChC,SAAS,OAAO;AACd,UAAK,MAAgB,SAAS,cAAc;AAC1C,cAAM,cAAc,KAAK,qBAAqB;AAC9C,YAAI,aAAa;AACf,gBAAM,KAAK,WAAW,YAAY,QAAQ,YAAY,WAAW;AACjE;AAAA,QACF;AAAA,MACF;AAEA,UAAK,MAAgB,SAAS,cAAc;AAC1C,aAAK,KAAK,UAAU,iBAAiB;AAAA,MACvC,OAAO;AACL,aAAK,KAAK,SAAS,KAAK;AACxB,aAAK,KAAK,UAAU;AAAA,UAAc,MAAgB,OAAO;AAAA,CAAK;AAAA,MAChE;AACA,WAAK,eAAe;AACpB,WAAK,oCAAoC;AACzC,WAAK,+BAA+B;AACpC,WAAK,oCAAoC;AAAA,IAC3C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,cAAc,YAAoB,SAAiD;AAEvF,QAAI,WAAW,KAAK,GAAG;AACrB,WAAK,oBAAoB,KAAK,EAAE,MAAM,QAAQ,SAAS,WAAW,CAAC;AAAA,IACrE;AAEA,QAAI,KAAK,sBAAsB;AAE7B,YAAM,kBAAkB,WAAW,EAAE,QAAQ,WAAW;AACxD,YAAM,iBAAiB,KAAK;AAC5B,WAAK,uBAAuB;AAC5B,qBAAe,QAAQ,eAAe;AACtC;AAAA,IACF;AAGA,UAAM,KAAK,WAAW,UAAU;AAAA,EAClC;AAAA,EAEA,SAAe;AACb,SAAK,6BAA6B,mBAAmB;AACrD,SAAK,oCAAoC;AACzC,SAAK,+BAA+B;AACpC,QAAI,KAAK,WAAW;AAClB,WAAK,UAAU,MAAM;AACrB,WAAK,YAAY;AACjB,WAAK,oBAAoB;AAAA,IAC3B;AACA,SAAK,eAAe;AACpB,SAAK,gBAAgB;AACrB,SAAK,oCAAoC;AACzC,SAAK,kCAAkC;AAAA,EACzC;AAAA,EAEA,eAA8B;AAC5B,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,cAAc,WAAyB;AAErC,QAAI,KAAK,WAAW;AAClB,WAAK,UAAU,MAAM;AACrB,WAAK,YAAY;AACjB,WAAK,oBAAoB;AAAA,IAC3B;AACA,SAAK,YAAY;AACjB,SAAK,eAAe;AACpB,SAAK,gBAAgB;AACrB,SAAK,oCAAoC;AACzC,SAAK,+BAA+B;AACpC,SAAK,oCAAoC;AACzC,SAAK,kCAAkC;AACvC,SAAK,sBAAsB,CAAC;AAC5B,SAAK,KAAK,mBAAmB,SAAS;AAAA,EACxC;AAAA,EAEA,WAAoB;AAClB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,yBAAkD;AAChD,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,2BAAyD;AACvD,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,mBAA4B;AAC1B,WAAO,KAAK,kBAAkB;AAAA,EAChC;AAAA,EAEA,MAAM,SAAS,OAA8B;AAC3C,QAAI,UAAU,KAAK,aAAc;AAEjC,SAAK,eAAe;AACpB,SAAK,6BAA6B,sBAAsB;AACxD,SAAK,oCAAoC;AACzC,SAAK,+BAA+B;AAGpC,QAAI,KAAK,WAAW;AAClB,WAAK,UAAU,MAAM;AACrB,WAAK,YAAY;AACjB,WAAK,oBAAoB;AACzB,WAAK,YAAY;AACjB,WAAK,eAAe;AACpB,WAAK,gBAAgB;AACrB,WAAK,oCAAoC;AACzC,WAAK,kCAAkC;AACvC,WAAK,yBAAyB;AAAA,IAChC,WAAW,KAAK,WAAW;AACzB,WAAK,YAAY;AACjB,WAAK,oCAAoC;AACzC,WAAK,kCAAkC;AACvC,WAAK,yBAAyB;AAAA,IAChC;AAEA,SAAK,KAAK,SAAS,KAAK;AAAA,EAC1B;AAAA,EAEA,WAAmB;AACjB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,yBAAgD;AAC9C,WAAO,CAAC,GAAG,KAAK,mBAAmB;AAAA,EACrC;AAAA,EAEA,eAAqB;AACnB,SAAK,sBAAsB,CAAC;AAC5B,SAAK,oCAAoC;AACzC,SAAK,+BAA+B;AAEpC,QAAI,KAAK,WAAW;AAClB,WAAK,UAAU,MAAM;AACrB,WAAK,YAAY;AACjB,WAAK,oBAAoB;AAAA,IAC3B;AACA,SAAK,YAAY;AACjB,SAAK,eAAe;AACpB,SAAK,gBAAgB;AACrB,SAAK,oCAAoC;AACzC,SAAK,kCAAkC;AAAA,EACzC;AAAA,EAEQ,iCAAuC;AAC7C,SAAK,oCAAoC;AACzC,SAAK,oCAAoC;AACzC,SAAK,wCAAwC,KAAK;AAClD,SAAK,2BAA2B;AAChC,SAAK,oBAAoB,gCAAgC;AAAA,EAC3D;AAAA,EAEQ,oCAA0C;AAChD,QAAI,KAAK,+BAAgC;AACzC,SAAK,iCAAiC,WAAW,MAAM;AACrD,WAAK,iCAAiC;AACtC,UAAI,KAAK,qCAAqC,KAAK,cAAc;AAC/D,aAAK,+BAA+B;AAAA,MACtC;AAAA,IACF,GAAG,yBAAyB;AAAA,EAC9B;AAAA,EAEQ,sCAA4C;AAClD,QAAI,KAAK,gCAAgC;AACvC,mBAAa,KAAK,8BAA8B;AAChD,WAAK,iCAAiC;AAAA,IACxC;AAAA,EACF;AAAA,EAEQ,iCAAuC;AAC7C,QAAI,KAAK,2BAA2B;AAClC,mBAAa,KAAK,yBAAyB;AAC3C,WAAK,4BAA4B;AAAA,IACnC;AAAA,EACF;AAAA,EAEQ,oCAA0C;AAChD,SAAK,wCAAwC;AAAA,EAC/C;AAAA,EAEQ,gCAAyC;AAC/C,UAAM,uBAAuB,KAAK;AAClC,QAAI,yBAAyB,KAAM,QAAO;AAE1C,SAAK,kCAAkC;AAEvC,QAAI,KAAK,yBAAyB,qBAAsB,QAAO;AAE/D,QAAI,KAAK,yBAAyB,uBAAuB,GAAG;AAC1D,YAAM,wBAAwB,KAAK,IAAI,IAAI,KAAK;AAChD,aAAO,yBAAyB;AAAA,IAClC;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,oBAAoB,wBAAgC,GAAS;AACnE,QAAI,CAAC,KAAK,aAAc;AAExB,SAAK,eAAe;AAGpB,QAAI,CAAC,KAAK,eAAe;AACvB,WAAK,KAAK,UAAU;AACpB;AAAA,IACF;AAEA,QAAI,wBAAwB,GAAG;AAC7B,WAAK,+BAA+B;AACpC,WAAK,4BAA4B,WAAW,MAAM;AAChD,aAAK,4BAA4B;AACjC,cAAM,WAAW,KAAK;AACtB,YAAI,CAAC,YAAY,KAAK,aAAc;AACpC,aAAK,gBAAgB;AAErB,aAAK,WAAW,SAAS,QAAQ,SAAS,WAAW;AAAA,MACvD,GAAG,qBAAqB;AACxB;AAAA,IACF;AAEA,UAAM,SAAS,KAAK;AACpB,SAAK,gBAAgB;AAErB,SAAK,WAAW,OAAO,QAAQ,OAAO,WAAW;AAAA,EACnD;AAAA,EAEQ,6BAA6B,QAAsB;AACzD,QAAI,KAAK,sBAAsB;AAC7B,WAAK,qBAAqB,OAAO,IAAI,MAAM,MAAM,CAAC;AAClD,WAAK,uBAAuB;AAAA,IAC9B;AACA,SAAK,sBAAsB;AAC3B,SAAK,wBAAwB;AAE7B,eAAW,WAAW,KAAK,0BAA0B,OAAO,GAAG;AAC7D,cAAQ,OAAO,IAAI,MAAM,MAAM,CAAC;AAAA,IAClC;AACA,SAAK,0BAA0B,MAAM;AAAA,EACvC;AAAA,EAEA,MAAM,qBAA2C;AAE/C,UAAM,aAA0B;AAAA,MAC9B,EAAE,OAAO,QAAQ,aAAa,YAAY,aAAa,8CAA2C;AAAA,MAClG,EAAE,OAAO,SAAS,aAAa,aAAa,aAAa,2CAAwC;AAAA,MACjG,EAAE,OAAO,UAAU,aAAa,cAAc,aAAa,0CAAuC;AAAA,IACpG;AAGA,QAAI,KAAK,cAAc;AACrB,aAAO,KAAK;AAAA,IACd;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,qBAAqC;AAC3C,UAAM,WAA2B,CAAC;AAClC,UAAM,UAAa,YAAQ;AAG3B,UAAM,OAAO;AAAA,MACN,UAAK,SAAS,WAAW,UAAU;AAAA;AAAA,MACnC,UAAK,KAAK,QAAQ,KAAK,WAAW,UAAU;AAAA;AAAA,IACnD;AAEA,eAAW,OAAO,MAAM;AACtB,UAAI,CAAI,cAAW,GAAG,EAAG;AAEzB,UAAI;AACF,cAAM,UAAa,eAAY,KAAK,EAAE,eAAe,KAAK,CAAC;AAE3D,mBAAW,SAAS,SAAS;AAC3B,cAAI,MAAM,YAAY,GAAG;AAEvB,kBAAM,YAAY,MAAM;AACxB,kBAAM,SAAc,UAAK,KAAK,SAAS;AACvC,kBAAM,aAAgB,eAAY,MAAM;AAExC,uBAAW,QAAQ,YAAY;AAC7B,kBAAI,KAAK,SAAS,KAAK,GAAG;AACxB,sBAAM,OAAO,GAAG,SAAS,IAAI,KAAK,QAAQ,OAAO,EAAE,CAAC;AACpD,sBAAM,cAAc,KAAK,mBAAwB,UAAK,QAAQ,IAAI,CAAC;AACnE,yBAAS,KAAK,EAAE,MAAM,aAAa,cAAc,GAAG,CAAC;AAAA,cACvD;AAAA,YACF;AAAA,UACF,WAAW,MAAM,OAAO,KAAK,MAAM,KAAK,SAAS,KAAK,GAAG;AAEvD,kBAAM,OAAO,MAAM,KAAK,QAAQ,OAAO,EAAE;AACzC,kBAAM,cAAc,KAAK,mBAAwB,UAAK,KAAK,MAAM,IAAI,CAAC;AACtE,qBAAS,KAAK,EAAE,MAAM,aAAa,cAAc,GAAG,CAAC;AAAA,UACvD;AAAA,QACF;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,mBAAmB,UAA0B;AACnD,QAAI;AACF,YAAM,UAAa,gBAAa,UAAU,OAAO;AACjD,YAAM,QAAQ,QAAQ,MAAM,IAAI;AAGhC,UAAI,MAAM,CAAC,MAAM,OAAO;AACtB,iBAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,gBAAM,OAAO,MAAM,CAAC;AACpB,cAAI,CAAC,KAAM;AACX,cAAI,SAAS,MAAO;AACpB,cAAI,KAAK,WAAW,cAAc,GAAG;AACnC,mBAAO,KAAK,QAAQ,gBAAgB,EAAE,EAAE,KAAK,EAAE,QAAQ,gBAAgB,EAAE;AAAA,UAC3E;AAAA,QACF;AAAA,MACF;AAGA,iBAAW,QAAQ,OAAO;AACxB,cAAM,UAAU,KAAK,KAAK;AAC1B,YAAI,QAAQ,WAAW,IAAI,GAAG;AAC5B,iBAAO,QAAQ,QAAQ,MAAM,EAAE;AAAA,QACjC;AACA,YAAI,WAAW,CAAC,QAAQ,WAAW,KAAK,GAAG;AACzC,iBAAO,QAAQ,MAAM,GAAG,GAAG;AAAA,QAC7B;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,uBAAgD;AAEpD,UAAM,mBAAmC;AAAA;AAAA,MAEvC,EAAE,MAAM,QAAQ,aAAa,+CAA+C,cAAc,GAAG;AAAA,MAC7F,EAAE,MAAM,SAAS,aAAa,kCAAkC,cAAc,GAAG;AAAA,MACjF,EAAE,MAAM,WAAW,aAAa,uDAAuD,cAAc,GAAG;AAAA,MACxG,EAAE,MAAM,UAAU,aAAa,kCAAkC,cAAc,eAAe;AAAA,MAC9F,EAAE,MAAM,UAAU,aAAa,gDAAgD,cAAc,GAAG;AAAA,MAChG,EAAE,MAAM,WAAW,aAAa,qCAAqC,cAAc,GAAG;AAAA;AAAA,MAEtF,EAAE,MAAM,UAAU,aAAa,gDAAgD,cAAc,GAAG;AAAA,MAChG,EAAE,MAAM,eAAe,aAAa,mCAAmC,cAAc,GAAG;AAAA,MACxF,EAAE,MAAM,iBAAiB,aAAa,4CAA4C,cAAc,GAAG;AAAA,MACnG,EAAE,MAAM,SAAS,aAAa,uBAAuB,cAAc,GAAG;AAAA,MACtE,EAAE,MAAM,OAAO,aAAa,iCAAiC,cAAc,GAAG;AAAA;AAAA,MAE9E,EAAE,MAAM,SAAS,aAAa,mBAAmB,cAAc,GAAG;AAAA,MAClE,EAAE,MAAM,OAAO,aAAa,sBAAsB,cAAc,GAAG;AAAA,MACnE,EAAE,MAAM,UAAU,aAAa,yCAAyC,cAAc,GAAG;AAAA,MACzF,EAAE,MAAM,kBAAkB,aAAa,iDAAiD,cAAc,GAAG;AAAA,MACzG,EAAE,MAAM,sBAAsB,aAAa,qCAAqC,cAAc,GAAG;AAAA,MACjG,EAAE,MAAM,OAAO,aAAa,4CAA4C,cAAc,GAAG;AAAA;AAAA,MAEzF,EAAE,MAAM,QAAQ,aAAa,iDAAiD,cAAc,GAAG;AAAA,MAC/F,EAAE,MAAM,UAAU,aAAa,8BAA8B,cAAc,GAAG;AAAA,MAC9E,EAAE,MAAM,WAAW,aAAa,kCAAkC,cAAc,SAAS;AAAA;AAAA,MAEzF,EAAE,MAAM,UAAU,aAAa,kDAAkD,cAAc,GAAG;AAAA,MAClG,EAAE,MAAM,UAAU,aAAa,uBAAuB,cAAc,GAAG;AAAA,MACvE,EAAE,MAAM,aAAa,aAAa,gCAAgC,cAAc,WAAW;AAAA,MAC3F,EAAE,MAAM,eAAe,aAAa,2CAA2C,cAAc,GAAG;AAAA,MAChG,EAAE,MAAM,iBAAiB,aAAa,0BAA0B,cAAc,GAAG;AAAA,MACjF,EAAE,MAAM,mBAAmB,aAAa,6BAA6B,cAAc,GAAG;AAAA;AAAA,MAEtF,EAAE,MAAM,SAAS,aAAa,oCAAoC,cAAc,GAAG;AAAA,MACnF,EAAE,MAAM,UAAU,aAAa,qCAAqC,cAAc,GAAG;AAAA,MACrF,EAAE,MAAM,UAAU,aAAa,8CAA8C,cAAc,GAAG;AAAA,MAC9F,EAAE,MAAM,OAAO,aAAa,6BAA6B,cAAc,GAAG;AAAA,MAC1E,EAAE,MAAM,QAAQ,aAAa,6BAA6B,cAAc,GAAG;AAAA,MAC3E,EAAE,MAAM,UAAU,aAAa,+BAA+B,cAAc,GAAG;AAAA,IACjF;AAGA,UAAM,iBAAiB,KAAK,mBAAmB;AAG/C,QAAI,cAA8B,CAAC,GAAG,cAAc;AAGpD,QAAI,KAAK,kBAAkB,KAAK,eAAe,SAAS,GAAG;AACzD,YAAMC,iBAAgB,IAAI,IAAI,YAAY,IAAI,OAAK,EAAE,IAAI,CAAC;AAC1D,YAAM,YAAY,KAAK,eAAe,OAAO,OAAK,CAACA,eAAc,IAAI,EAAE,IAAI,CAAC;AAC5E,oBAAc,CAAC,GAAG,aAAa,GAAG,SAAS;AAAA,IAC7C;AAGA,UAAM,gBAAgB,IAAI,IAAI,YAAY,IAAI,OAAK,EAAE,IAAI,CAAC;AAC1D,UAAM,kBAAkB,iBAAiB,OAAO,OAAK,CAAC,cAAc,IAAI,EAAE,IAAI,CAAC;AAC/E,kBAAc,CAAC,GAAG,aAAa,GAAG,eAAe;AAEjD,kBAAc,YAAY,OAAO,OAAK,CAAC,qBAAqB,IAAI,EAAE,IAAI,CAAC;AAEvE,WAAO;AAAA,EACT;AACF;;;ACpjCA,IAAAC,4BAAiC;AAHjC,SAAS,cAAAC,aAAY,gBAAAC,eAAc,iBAAAC,gBAAe,aAAAC,kBAAiB;AACnE,SAAS,QAAAC,OAAM,eAAe;AAC9B,SAAS,WAAAC,gBAAe;AA+BjB,IAAM,gBAAN,MAAoB;AAAA,EACjB;AAAA,EACA;AAAA,EAER,YAAY,UAAgC,CAAC,GAAG;AAC9C,UAAM,OAAO,QAAQ,WAAWA,SAAQ;AACxC,SAAK,YAAYD,MAAK,MAAM,SAAS;AACrC,SAAK,MAAM,QAAQ,OAAO,QAAQ,IAAI;AAAA,EACxC;AAAA,EAEQ,wBAAgC;AACtC,WAAOA,MAAK,KAAK,WAAW,eAAe;AAAA,EAC7C;AAAA,EAEQ,uBAA+B;AACrC,WAAOA,MAAK,KAAK,WAAW,qBAAqB;AAAA,EACnD;AAAA,EAEQ,yBAAiC;AACvC,WAAOA,MAAK,KAAK,KAAK,WAAW,eAAe;AAAA,EAClD;AAAA,EAEQ,iBAAiBE,OAAqC;AAC5D,QAAI;AACF,UAAIN,YAAWM,KAAI,GAAG;AACpB,cAAM,UAAUL,cAAaK,OAAM,OAAO;AAC1C,eAAO,KAAK,MAAM,OAAO;AAAA,MAC3B;AAAA,IACF,QAAQ;AAAA,IAER;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,kBAAkBA,OAAc,UAAmC;AACzE,QAAI;AACF,YAAM,MAAM,QAAQA,KAAI;AACxB,UAAI,CAACN,YAAW,GAAG,GAAG;AACpB,QAAAG,WAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAAA,MACpC;AACA,MAAAD,eAAcI,OAAM,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AACrD,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEQ,oBAAoC;AAC1C,UAAM,SAAS,KAAK,iBAAiB,KAAK,sBAAsB,CAAC,KAAK,CAAC;AACvE,UAAM,QAAQ,KAAK,iBAAiB,KAAK,qBAAqB,CAAC,KAAK,CAAC;AACrE,UAAM,UAAU,KAAK,iBAAiB,KAAK,uBAAuB,CAAC,KAAK,CAAC;AAGzE,WAAO;AAAA,MACL,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,aAAa;AAAA,QACX,GAAG,OAAO;AAAA,QACV,GAAG,MAAM;AAAA,QACT,GAAG,QAAQ;AAAA,MACb;AAAA,MACA,aAAa;AAAA,QACX,GAAG,OAAO;AAAA,QACV,GAAG,MAAM;AAAA,QACT,GAAG,QAAQ;AAAA,MACb;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,kBAA2B;AACzB,UAAM,WAAW,KAAK,kBAAkB;AACxC,WAAO,SAAS,yBAAyB;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA,EAKA,oBAAoC;AAClC,UAAM,WAAW,KAAK,kBAAkB;AACxC,UAAM,OAAO,SAAS,aAAa;AACnC,eAAO,4CAAiB,IAAI,IAAI,OAAO;AAAA,EACzC;AAAA,EAEA,mBAAmB,SAAyD;AAC1E,UAAM,WAAW,KAAK,kBAAkB;AAExC,YAAQ,SAAS;AAAA,MACf,KAAK;AACH,eAAO,KAAK,cAAc,QAAQ;AAAA,MACpC,KAAK;AACH,eAAO,KAAK,mBAAmB,QAAQ;AAAA,MACzC,KAAK;AACH,eAAO,KAAK,WAAW,QAAQ;AAAA,MACjC,KAAK;AACH,eAAO,KAAK,oBAAoB,QAAQ;AAAA,MAC1C;AACE,eAAO;AAAA,UACL;AAAA,UACA,QAAQ;AAAA,UACR,OAAO,GAAG,OAAO;AAAA,UACjB,aAAa;AAAA,UACb,SAAS,CAAC;AAAA,QACZ;AAAA,IACJ;AAAA,EACF;AAAA,EAEQ,cAAc,UAAkD;AACtE,UAAM,UAA+B;AAAA,MACnC;AAAA,QACE,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,aAAa;AAAA,QACb,OAAO,SAAS,yBAAyB;AAAA,QACzC,UAAU,SAAS,yBAAyB;AAAA,MAC9C;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,aAAa;AAAA,QACb,OAAO,SAAS,aAAa,eAAe;AAAA,QAC5C,UAAU,SAAS,aAAa,eAAe;AAAA,MACjD;AAAA,IACF;AAEA,WAAO;AAAA,MACL,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,aAAa;AAAA,MACb;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,mBAAmB,UAAkD;AAC3E,UAAM,cAAc,SAAS,aAAa,QAAQ;AAClD,UAAM,UAA+B;AAAA,MACnC;AAAA,QACE,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,aAAa;AAAA,QACb,OAAO;AAAA,QACP,UAAU,gBAAgB;AAAA,MAC5B;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,aAAa;AAAA,QACb,OAAO;AAAA,QACP,UAAU,gBAAgB;AAAA,MAC5B;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,aAAa;AAAA,QACb,OAAO;AAAA,QACP,UAAU,gBAAgB;AAAA,MAC5B;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,aAAa;AAAA,QACb,OAAO;AAAA,QACP,UAAU,gBAAgB;AAAA,MAC5B;AAAA,IACF;AAEA,WAAO;AAAA,MACL,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,aAAa;AAAA,MACb;AAAA,MACA,cAAc;AAAA,IAChB;AAAA,EACF;AAAA,EAEQ,WAAW,UAAkD;AACnE,UAAM,UAAU,SAAS,OAAO;AAEhC,WAAO;AAAA,MACL,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,aAAa;AAAA,MACb,SAAS;AAAA,QACP;AAAA,UACE,IAAI;AAAA,UACJ,OAAO;AAAA,UACP,aAAa,UAAU,sBAAsB;AAAA,UAC7C,OAAO;AAAA,UACP,UAAU;AAAA,QACZ;AAAA,MACF;AAAA,MACA,cAAc;AAAA,IAChB;AAAA,EACF;AAAA,EAEQ,oBAAoB,UAAkD;AAC5E,UAAM,eAAe,SAAS,aAAa,gBAAgB,CAAC;AAC5D,UAAM,WAAW;AAAA,MACf,EAAE,IAAI,QAAQ,OAAO,QAAQ,aAAa,yBAAyB;AAAA,MACnE,EAAE,IAAI,QAAQ,OAAO,QAAQ,aAAa,qBAAqB;AAAA,MAC/D,EAAE,IAAI,SAAS,OAAO,SAAS,aAAa,iBAAiB;AAAA,MAC7D,EAAE,IAAI,QAAQ,OAAO,QAAQ,aAAa,qBAAqB;AAAA,MAC/D,EAAE,IAAI,QAAQ,OAAO,QAAQ,aAAa,mBAAmB;AAAA,MAC7D,EAAE,IAAI,QAAQ,OAAO,QAAQ,aAAa,uBAAuB;AAAA,MACjE,EAAE,IAAI,YAAY,OAAO,YAAY,aAAa,oBAAoB;AAAA,MACtE,EAAE,IAAI,aAAa,OAAO,aAAa,aAAa,iBAAiB;AAAA,IACvE;AAEA,UAAM,UAA+B,SAAS,IAAI,CAAC,UAAU;AAAA,MAC3D,GAAG;AAAA,MACH,OAAO,KAAK;AAAA,MACZ,UAAU,aAAa,SAAS,KAAK,EAAE;AAAA,IACzC,EAAE;AAEF,WAAO;AAAA,MACL,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,aAAa;AAAA,MACb;AAAA,MACA,cAAc;AAAA,IAChB;AAAA,EACF;AAAA,EAEA,YAAY,SAAqD;AAC/D,UAAM,aAAa,KAAK,sBAAsB;AAC9C,UAAM,WAAW,KAAK,iBAAiB,UAAU,KAAK,CAAC;AAEvD,QAAI;AACF,cAAQ,QAAQ,SAAS;AAAA,QACvB,KAAK;AACH,iBAAO,KAAK,kBAAkB,UAAU,YAAY,OAAO;AAAA,QAC7D,KAAK;AACH,iBAAO,KAAK,uBAAuB,UAAU,YAAY,OAAO;AAAA,QAClE,KAAK;AACH,iBAAO,KAAK,eAAe,UAAU,YAAY,OAAO;AAAA,QAC1D,KAAK;AACH,iBAAO,KAAK,wBAAwB,UAAU,YAAY,OAAO;AAAA,QACnE;AACE,iBAAO;AAAA,YACL,SAAS;AAAA,YACT,SAAS,oBAAoB,QAAQ,OAAO;AAAA,UAC9C;AAAA,MACJ;AAAA,IACF,SAAS,OAAO;AACd,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS,iBAAiB,QAAQ,MAAM,UAAU;AAAA,MACpD;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,kBACN,UACAA,OACA,SACmB;AACnB,QAAI,CAAC,SAAS,aAAa;AACzB,eAAS,cAAc,CAAC;AAAA,IAC1B;AAEA,YAAQ,QAAQ,KAAK;AAAA,MACnB,KAAK;AACH,iBAAS,YAAY,QAAQ,QAAQ;AACrC;AAAA,MACF,KAAK;AAEH,iBAAS,wBAAwB,QAAQ;AACzC;AAAA,MACF,KAAK;AACH,iBAAS,YAAY,cAAc,QAAQ;AAC3C;AAAA,MACF,KAAK;AACH,iBAAS,YAAY,cAAc,QAAQ;AAC3C;AAAA,MACF;AACE,eAAO,EAAE,SAAS,OAAO,SAAS,uBAAuB,QAAQ,GAAG,GAAG;AAAA,IAC3E;AAEA,QAAI,KAAK,kBAAkBA,OAAM,QAAQ,GAAG;AAC1C,aAAO,EAAE,SAAS,MAAM,SAAS,UAAU,QAAQ,GAAG,WAAW;AAAA,IACnE;AACA,WAAO,EAAE,SAAS,OAAO,SAAS,gCAAgC;AAAA,EACpE;AAAA,EAEQ,uBACN,UACAA,OACA,SACmB;AACnB,QAAI,CAAC,SAAS,aAAa;AACzB,eAAS,cAAc,CAAC;AAAA,IAC1B;AAEA,aAAS,YAAY,OAAO,QAAQ;AAEpC,QAAI,KAAK,kBAAkBA,OAAM,QAAQ,GAAG;AAC1C,aAAO,EAAE,SAAS,MAAM,SAAS,0BAA0B,QAAQ,KAAK,GAAG;AAAA,IAC7E;AACA,WAAO,EAAE,SAAS,OAAO,SAAS,gCAAgC;AAAA,EACpE;AAAA,EAEQ,eACN,UACAA,OACA,SACmB;AACnB,QAAI,QAAQ,WAAW,UAAU;AAC/B,eAAS,MAAM,CAAC,SAAS;AAAA,IAC3B,OAAO;AACL,eAAS,MAAM,QAAQ;AAAA,IACzB;AAEA,QAAI,KAAK,kBAAkBA,OAAM,QAAQ,GAAG;AAC1C,aAAO,EAAE,SAAS,MAAM,SAAS,YAAY,SAAS,MAAM,YAAY,UAAU,GAAG;AAAA,IACvF;AACA,WAAO,EAAE,SAAS,OAAO,SAAS,gCAAgC;AAAA,EACpE;AAAA,EAEQ,wBACN,UACAA,OACA,SACmB;AACnB,QAAI,CAAC,SAAS,aAAa;AACzB,eAAS,cAAc,CAAC;AAAA,IAC1B;AACA,QAAI,CAAC,SAAS,YAAY,cAAc;AACtC,eAAS,YAAY,eAAe,CAAC;AAAA,IACvC;AAEA,UAAM,SAAS,QAAQ;AAEvB,YAAQ,QAAQ,QAAQ;AAAA,MACtB,KAAK;AACH,YAAI,CAAC,SAAS,YAAY,aAAa,SAAS,MAAM,GAAG;AACvD,mBAAS,YAAY,aAAa,KAAK,MAAM;AAAA,QAC/C;AACA;AAAA,MACF,KAAK;AACH,iBAAS,YAAY,eAAe,SAAS,YAAY,aAAa;AAAA,UACpE,CAAC,MAAM,MAAM;AAAA,QACf;AACA;AAAA,MACF,KAAK;AACH,iBAAS,YAAY,eAAe,QAAQ;AAC5C;AAAA,MACF,KAAK;AACH,YAAI,SAAS,YAAY,aAAa,SAAS,MAAM,GAAG;AACtD,mBAAS,YAAY,eAAe,SAAS,YAAY,aAAa;AAAA,YACpE,CAAC,MAAM,MAAM;AAAA,UACf;AAAA,QACF,OAAO;AACL,mBAAS,YAAY,aAAa,KAAK,MAAM;AAAA,QAC/C;AACA;AAAA,IACJ;AAEA,QAAI,KAAK,kBAAkBA,OAAM,QAAQ,GAAG;AAC1C,aAAO,EAAE,SAAS,MAAM,SAAS,wBAAwB;AAAA,IAC3D;AACA,WAAO,EAAE,SAAS,OAAO,SAAS,gCAAgC;AAAA,EACpE;AACF;;;AF3YA,IAAAC,4BAAiC;AAY1B,IAAM,SAAN,cAAqBC,cAAa;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,iBAAwC;AAAA,EACxC,UAA0B;AAAA,EAC1B,UAA0B;AAAA,EAC1B,UAAmB;AAAA,EACnB,oBAA6B;AAAA,EAC7B,uBAAgC;AAAA,EAChC,WAAoB;AAAA,EAE5B,YAAY,SAAwB;AAClC,UAAM;AACN,SAAK,UAAU;AAEf,SAAK,gBAAgB,IAAI,cAAc;AAAA,MACrC,KAAK,QAAQ;AAAA,IACf,CAAC;AAED,SAAK,aAAa,IAAI,WAAW;AAAA,MAC/B,KAAK,QAAQ;AAAA,MACb,gBAAgB,KAAK,cAAc,kBAAkB;AAAA,IACvD,CAAC;AAED,SAAK,iBAAiB,IAAI,eAAe;AAAA,MACvC,UAAU,QAAQ;AAAA,IACpB,CAAC;AAED,SAAK,iBAAiB,IAAI,eAAe;AAAA,MACvC,UAAU,QAAQ;AAAA,IACpB,CAAC;AAGD,UAAM,kBAAkB,KAAK,cAAc,gBAAgB;AAC3D,QAAI,iBAAiB;AACnB,WAAK,WAAW,gBAAgB,IAAI;AAAA,IACtC;AAAA,EACF;AAAA,EAEA,MAAM,QAAuB;AAC3B,QAAI,KAAK,SAAS;AAChB,YAAM,IAAI,MAAM,2BAA2B;AAAA,IAC7C;AAGA,SAAK,UAAU,MAAM,KAAK,eAAe;AAAA,MACvC,KAAK,QAAQ;AAAA,MACb,KAAK,QAAQ;AAAA,MACb,KAAK,QAAQ;AAAA,IACf;AAGA,SAAK,UAAU,MAAM,KAAK,eAAe;AAAA,MACvC,KAAK,QAAQ;AAAA,MACb,KAAK,QAAQ;AAAA,IACf;AAGA,SAAK,iBAAiB,IAAI,eAAe;AAAA,MACvC,UAAU,KAAK,QAAQ;AAAA,MACvB,WAAW,KAAK,QAAQ;AAAA,IAC1B,CAAC;AAGD,SAAK,WAAW,GAAG,UAAU,OAAO,SAAiB;AAEnD,UAAI,KAAK,QAAQ,WAAW,OAAO;AACjC,gBAAQ,OAAO,MAAM,IAAI;AAAA,MAC3B;AAGA,WAAK,KAAK,iBAAiB,IAAI;AAG/B,UAAI,KAAK,gBAAgB;AACvB,YAAI;AACF,gBAAM,KAAK,eAAe,UAAU,IAAI;AAAA,QAC1C,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF,CAAC;AAED,SAAK,WAAW,GAAG,SAAS,CAAC,UAAiB;AAC5C,WAAK,KAAK,SAAS,KAAK;AAAA,IAC1B,CAAC;AAGD,SAAK,WAAW,GAAG,cAAc,OAAO,cAAsD;AAC5F,YAAM,gBAAwC;AAAA,QAC5C,yBAAyB;AAAA,QACzB,iBAAiB;AAAA,QACjB,cAAc;AAAA,QACd,gBAAgB;AAAA,MAClB;AAEA,YAAM,iBAAiB,cAAc,UAAU,SAAS,KAAK,cAAc,UAAU,OAAO;AAE5F,UAAI,KAAK,QAAQ,WAAW,OAAO;AACjC,gBAAQ,OAAO,MAAM;AAAA,UAAa,cAAc;AAAA,CAAI;AAAA,MACtD;AAEA,WAAK,KAAK,SAAS,IAAI,MAAM,cAAc,CAAC;AAE5C,UAAI,KAAK,gBAAgB;AACvB,YAAI;AACF,gBAAM,KAAK,eAAe,eAAe,gBAAgB,UAAU,SAAS;AAC5E,gBAAM,KAAK,eAAe,kBAAkB;AAAA,QAC9C,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF,CAAC;AAGD,SAAK,WAAW,GAAG,oBAAoB,YAAY;AACjD,YAAM,KAAK,kBAAkB;AAAA,IAC/B,CAAC;AAGD,SAAK,WAAW,GAAG,iBAAiB,YAAY;AAC9C,YAAM,MAAM;AACZ,UAAI,KAAK,QAAQ,WAAW,OAAO;AACjC,gBAAQ,OAAO,MAAM;AAAA,EAAK,GAAG;AAAA,CAAI;AAAA,MACnC;AACA,UAAI,KAAK,gBAAgB;AACvB,YAAI;AACF,gBAAM,KAAK,eAAe,gBAAgB,GAAG;AAAA,QAC/C,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF,CAAC;AAGD,SAAK,WAAW,GAAG,mBAAmB,OAAO,iBAAyB;AACpE,UAAI,CAAC,KAAK,QAAS;AACnB,UAAI;AACF,cAAM,KAAK,eAAe,mBAAmB,KAAK,QAAQ,IAAI,YAAY;AAAA,MAC5E,QAAQ;AAAA,MAER;AAAA,IACF,CAAC;AAED,SAAK,WAAW,GAAG,YAAY,YAAY;AAEzC,UAAI,KAAK,QAAQ,WAAW,OAAO;AACjC,gBAAQ,OAAO,MAAM,MAAM;AAAA,MAC7B;AAGA,UAAI,KAAK,gBAAgB;AACvB,YAAI;AACF,gBAAM,KAAK,eAAe,kBAAkB;AAAA,QAC9C,QAAQ;AAAA,QAER;AAAA,MACF;AAIA,UAAI,CAAC,KAAK,wBAAwB,KAAK,gBAAgB;AACrD,aAAK,uBAAuB;AAC5B,cAAM,KAAK,kBAAkB;AAAA,MAC/B;AAAA,IACF,CAAC;AAGD,SAAK,WAAW,GAAG,mBAAmB,OAAO,SAAyB;AACpE,UAAI,KAAK,gBAAgB;AACvB,YAAI;AACF,gBAAM,KAAK,eAAe,cAAc,IAAI;AAAA,QAC9C,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF,CAAC;AAGD,SAAK,WAAW,GAAG,iBAAiB,OAAO,iBAAmC;AAC5E,UAAI,KAAK,gBAAgB;AACvB,YAAI;AACF,gBAAM,KAAK,eAAe,sBAAsB,YAAY;AAAA,QAC9D,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF,CAAC;AAGD,SAAK,WAAW,GAAG,kBAAkB,YAAY;AAC/C,UAAI,KAAK,gBAAgB;AACvB,YAAI;AACF,gBAAM,KAAK,eAAe,gBAAgB;AAAA,QAC5C,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF,CAAC;AAGD,SAAK,WAAW,GAAG,sBAAsB,OAAO,gBAAuC;AACrF,UAAI,KAAK,gBAAgB;AACvB,YAAI;AACF,gBAAM,KAAK,eAAe,2BAA2B,WAAW;AAAA,QAClE,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF,CAAC;AAGD,SAAK,WAAW,GAAG,YAAY,OAAO,gBAA6B;AACjE,UAAI,KAAK,gBAAgB;AACvB,YAAI;AACF,gBAAM,KAAK,eAAe,iBAAiB,WAAW;AAAA,QACxD,SAAS,KAAK;AACZ,kBAAQ,KAAK,0CAA0C,GAAG;AAAA,QAC5D;AAAA,MACF;AAAA,IACF,CAAC;AAGD,SAAK,WAAW,GAAG,SAAS,OAAO,UAAkB;AAEnD,UAAI,KAAK,SAAS;AAChB,YAAI;AACF,gBAAM,KAAK,eAAe,mBAAmB,KAAK,QAAQ,IAAI,KAAK;AAAA,QACrE,QAAQ;AAAA,QAER;AAAA,MACF;AAGA,UAAI,KAAK,gBAAgB;AACvB,YAAI;AACF,gBAAM,KAAK,eAAe,eAAe,KAAK;AAAA,QAChD,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF,CAAC;AAGD,SAAK,eAAe,GAAG,SAAS,OAAO,YAA6B;AAElE,UAAI,CAAC,KAAK,mBAAmB;AAC3B,aAAK,oBAAoB;AACzB,cAAM,KAAK,kBAAkB;AAAA,MAC/B;AAGA,UAAI,QAAQ,SAAS,iBAAiB,QAAQ,gBAAgB;AAC5D,aAAK,WAAW,kBAAkB,QAAQ,cAAc;AAExD,YAAI,KAAK,gBAAgB;AACvB,cAAI;AACF,kBAAM,KAAK,eAAe,cAAc,QAAQ,cAAc;AAAA,UAChE,QAAQ;AAAA,UAER;AAAA,QACF;AACA;AAAA,MACF;AAGA,UAAI,QAAQ,SAAS,oBAAoB;AACvC,cAAM,KAAK,kBAAkB;AAC7B;AAAA,MACF;AAGA,UAAI,QAAQ,SAAS,kBAAkB,QAAQ,OAAO;AACpD,cAAM,gBAAgB,KAAK,WAAW,SAAS;AAC/C,cAAM,KAAK,WAAW,SAAS,QAAQ,KAAK;AAG5C,YAAI,kBAAkB,QAAQ,OAAO;AACnC,gBAAM,aAAqC;AAAA,YACzC,WAAW;AAAA,YACX,UAAU;AAAA,YACV,QAAQ;AAAA,YACR,SAAS;AAAA,UACX;AACA,gBAAM,cAAc,WAAW,QAAQ,KAAK,KAAK,QAAQ;AACzD,gBAAM,kBAAkB,sBAAsB,WAAW;AAGzD,cAAI,KAAK,QAAQ,WAAW,OAAO;AACjC,oBAAQ,OAAO,MAAM;AAAA,EAAK,eAAe;AAAA,CAAI;AAAA,UAC/C;AAGA,cAAI,KAAK,gBAAgB;AACvB,gBAAI;AACF,oBAAM,KAAK,eAAe,gBAAgB,eAAe;AAAA,YAC3D,QAAQ;AAAA,YAER;AAAA,UACF;AAAA,QACF,OAAO;AAEL,cAAI;AACF,kBAAM,KAAK,gBAAgB,eAAe,KAAK,WAAW,SAAS,CAAC;AAAA,UACtE,QAAQ;AAAA,UAER;AAAA,QACF;AACA;AAAA,MACF;AAGA,UAAI,QAAQ,SAAS,kBAAkB;AACrC,cAAM,KAAK,gBAAgB;AAE3B,YAAI;AACF,gBAAM,KAAK,gBAAgB,eAAe,KAAK,WAAW,SAAS,CAAC;AAAA,QACtE,QAAQ;AAAA,QAER;AACA;AAAA,MACF;AAIA,UAAI,QAAQ,SAAS,kBAAkB;AACrC,YAAI,KAAK,gBAAgB;AACvB,cAAI;AACF,kBAAM,kBAAkB,KAAK,WAAW,uBAAuB;AAC/D,gBAAI,iBAAiB;AACnB,oBAAM,KAAK,eAAe,sBAAsB,eAAe;AAAA,YACjE;AACA,kBAAM,oBAAoB,KAAK,WAAW,yBAAyB;AACnE,gBAAI,mBAAmB;AACrB,oBAAM,KAAK,eAAe,2BAA2B,iBAAiB;AAAA,YACxE;AAIA,kBAAM,eAAe,KAAK,WAAW,SAAS;AAC9C,kBAAM,oBAAoB,gBAAgB,CAAC,mBAAmB,CAAC;AAC/D,kBAAM,kBAAkB,KAAK,WAAW,iBAAiB;AACzD,kBAAM,KAAK,eAAe;AAAA,cACxB;AAAA,cACA;AAAA,cACA,KAAK,WAAW,kBAAkB;AAAA,YACpC;AAAA,UACF,QAAQ;AAAA,UAER;AAAA,QACF;AACA;AAAA,MACF;AAGA,UAAI,QAAQ,SAAS,qBAAqB;AACxC,YAAI,KAAK,QAAQ,WAAW,OAAO;AACjC,kBAAQ,OAAO,MAAM,8CAA8C;AAAA,QACrE;AACA,aAAK,KAAK,qBAAqB;AAC/B;AAAA,MACF;AAGA,UAAI,QAAQ,SAAS,yBAAyB,QAAQ,oBAAoB;AACxE,cAAM,OAAO,KAAK,cAAc,mBAAmB,QAAQ,kBAAkB;AAC7E,YAAI,KAAK,gBAAgB;AACvB,cAAI;AACF,kBAAM,KAAK,eAAe,6BAA6B,IAAI;AAAA,UAC7D,QAAQ;AAAA,UAER;AAAA,QACF;AACA;AAAA,MACF;AAGA,UAAI,QAAQ,SAAS,uBAAuB,QAAQ,oBAAoB;AACtE,cAAM,SAAS,KAAK,cAAc,YAAY,QAAQ,kBAAkB;AAGxE,YACE,OAAO,WACP,QAAQ,mBAAmB,YAAY,qBACvC,4CAAiB,QAAQ,mBAAmB,KAAK,GACjD;AACA,eAAK,WAAW,kBAAkB,QAAQ,mBAAmB,KAAK;AAAA,QACpE;AAGA,YACE,QAAQ,mBAAmB,YAAY,YACvC,QAAQ,mBAAmB,QAAQ,yBACnC;AACA,gBAAM,UAAU,QAAQ,QAAQ,mBAAmB,KAAK;AACxD,gBAAM,KAAK,WAAW,gBAAgB,OAAO;AAAA,QAC/C;AAEA,YAAI,KAAK,gBAAgB;AACvB,cAAI;AACF,kBAAM,KAAK,eAAe;AAAA,cACxB,QAAQ,mBAAmB;AAAA,cAC3B;AAAA,YACF;AAEA,kBAAM,aAAa,OAAO,UACtB,UAAK,OAAO,OAAO,KACnB,UAAK,OAAO,OAAO;AACvB,kBAAM,KAAK,eAAe,gBAAgB,UAAU;AAAA,UACtD,QAAQ;AAAA,UAER;AAAA,QACF;AACA;AAAA,MACF;AAGA,UAAI,QAAQ,SAAS,kBAAkB;AACrC,aAAK,WAAW,OAAO;AACvB,YAAI,KAAK,QAAQ,WAAW,OAAO;AACjC,kBAAQ,OAAO,MAAM,mBAAmB;AAAA,QAC1C;AACA,YAAI,KAAK,gBAAgB;AACvB,cAAI;AACF,kBAAM,KAAK,eAAe,gBAAgB,aAAa;AACvD,kBAAM,KAAK,eAAe,kBAAkB;AAAA,UAC9C,SAAS,OAAO;AACd,oBAAQ,KAAK,wCAAwC,KAAK;AAAA,UAC5D;AAAA,QACF;AACA;AAAA,MACF;AAGA,UAAI,QAAQ,SAAS,iBAAiB;AACpC,aAAK,WAAW,aAAa;AAC7B,YAAI,KAAK,QAAQ,WAAW,OAAO;AACjC,kBAAQ,OAAO,MAAM,8BAA8B;AAAA,QACrD;AACA;AAAA,MACF;AAKA,UAAI,QAAQ,SAAS,iBAAiB,QAAQ,YAAY;AACxD,cAAM,aAAa,OAAO,OAAO,QAAQ,WAAW,OAAO,EAAE,KAAK,IAAI;AACtE,aAAK,KAAK,gBAAgB,YAAY,UAAU,EAAE;AAClD,cAAM,KAAK,WAAW,cAAc,YAAY,QAAQ,WAAW,OAAO;AAC1E;AAAA,MACF;AAGA,UAAI,QAAQ,SAAS,yBAAyB,QAAQ,oBAAoB;AACxE,aAAK,WAAW,yBAAyB,QAAQ,kBAAkB;AACnE;AAAA,MACF;AAGA,UAAI,QAAQ,SAAS,oBAAoB,QAAQ,iBAAiB;AAChE,cAAM,qBAAqB,QAAQ;AACnC,aAAK,WAAW,cAAc,kBAAkB;AAEhD,cAAM,kBAAkB,sBAAsB,mBAAmB,MAAM,GAAG,CAAC,CAAC;AAC5E,YAAI,KAAK,QAAQ,WAAW,OAAO;AACjC,kBAAQ,OAAO,MAAM;AAAA,EAAK,eAAe;AAAA,CAAI;AAAA,QAC/C;AAEA,YAAI,KAAK,gBAAgB;AACvB,cAAI;AAEF,kBAAM,EAAE,MAAM,YAAY,IAAI,MAAM,KAAK,QAAQ,SAC9C,KAAK,UAAU,EACf,OAAO,IAAI,EACX,GAAG,kBAAkB,kBAAkB,EACvC,OAAO;AAEV,gBAAI,aAAa;AAEf,oBAAM,KAAK,eAAe,uBAAuB,YAAY,EAAE;AAAA,YACjE;AAEA,kBAAM,KAAK,eAAe,gBAAgB,eAAe;AAAA,UAC3D,QAAQ;AAAA,UAER;AAAA,QACF;AAGA,cAAM,KAAK,WAAW,WAAW,kCAAkC;AACnE;AAAA,MACF;AAGA,YAAMC,UAAS,QAAQ,SAAS,QAAQ,YAAY,EAAE,KAAK;AAC3D,YAAM,cAAc,QAAQ;AAG5B,UAAIA,QAAO,KAAK,KAAM,eAAe,YAAY,SAAS,GAAI;AAC5D,cAAM,gBAAgBA,QAAO,KAAK;AAGlC,aAAK,KAAK,gBAAgB,eAAe,WAAW;AAGpD,YAAI,kBAAkB,UAAU;AAC9B,eAAK,WAAW,aAAa;AAC7B,cAAI,KAAK,gBAAgB;AACvB,gBAAI;AACF,oBAAM,KAAK,eAAe,gBAAgB,sBAAsB;AAAA,YAClE,QAAQ;AAAA,YAER;AAAA,UACF;AACA,cAAI,KAAK,QAAQ,WAAW,OAAO;AACjC,oBAAQ,OAAO,MAAM,8BAA8B;AAAA,UACrD;AACA;AAAA,QACF;AAGA,YAAI,CAAC,KAAK,YAAY,KAAK,SAAS;AAClC,eAAK,WAAW;AAChB,gBAAM,QAAQ,cAAc,SAAS,KACjC,cAAc,MAAM,GAAG,EAAE,IAAI,QAC7B;AACJ,eAAK,eAAe,mBAAmB,KAAK,QAAQ,IAAI,KAAK,EAAE,MAAM,MAAM;AAAA,UAE3E,CAAC;AACD,cAAI,KAAK,gBAAgB;AACvB,iBAAK,eAAe,sBAAsB,KAAK,EAAE,MAAM,MAAM;AAAA,YAE7D,CAAC;AAAA,UACH;AAAA,QACF;AAEA,cAAM,KAAK,WAAW,WAAWA,SAAQ,WAAW;AAAA,MACtD;AAAA,IACF,CAAC;AAGD,UAAM,KAAK,eAAe,QAAQ;AAGlC,QAAI;AACF,YAAM,KAAK,eAAe,cAAc,KAAK,WAAW,kBAAkB,CAAC;AAAA,IAC7E,QAAQ;AAAA,IAER;AAGA,UAAM,KAAK,kBAAkB;AAG7B,UAAM,KAAK,gBAAgB;AAG3B,QAAI;AACF,YAAM,KAAK,eAAe,eAAe,KAAK,WAAW,SAAS,CAAC;AAAA,IACrE,QAAQ;AAAA,IAER;AAEA,SAAK,UAAU;AACf,SAAK,KAAK,WAAW;AAAA,MACnB,SAAS,KAAK;AAAA,MACd,SAAS,KAAK;AAAA,MACd,mBAAmB,KAAK,gBAAgB,kBAAkB,KAAK;AAAA,IACjE,CAAC;AAGD,QAAI,KAAK,QAAQ,WAAW,OAAO;AACjC,cAAQ,OAAO,MAAM,qCAAqC;AAAA,IAC5D;AAAA,EACF;AAAA,EAEA,MAAM,OAAsB;AAC1B,QAAI,CAAC,KAAK,SAAS;AACjB;AAAA,IACF;AAEA,SAAK,UAAU;AAGf,SAAK,WAAW,OAAO;AAGvB,QAAI,KAAK,SAAS;AAChB,YAAM,KAAK,eAAe,WAAW,KAAK,QAAQ,EAAE;AAAA,IACtD;AAOA,QAAI,KAAK,gBAAgB;AACvB,YAAM,KAAK,eAAe,WAAW;AAAA,IACvC;AAEA,SAAK,KAAK,SAAS;AAAA,EACrB;AAAA,EAEA,MAAM,WAAWA,SAAgB,aAAgD;AAC/E,UAAM,KAAK,WAAW,WAAWA,SAAQ,WAAW;AAAA,EACtD;AAAA,EAEA,YAAqB;AACnB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,aAA6B;AAC3B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,aAA6B;AAC3B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAc,oBAAmC;AAC/C,QAAI,CAAC,KAAK,gBAAgB;AACxB;AAAA,IACF;AAEA,QAAI;AACF,YAAM,WAAW,MAAM,KAAK,WAAW,qBAAqB;AAC5D,YAAM,KAAK,eAAe,kBAAkB,QAAQ;AAAA,IACtD,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEA,MAAc,kBAAiC;AAC7C,QAAI,CAAC,KAAK,gBAAgB;AACxB;AAAA,IACF;AAEA,QAAI;AACF,YAAM,SAAS,MAAM,KAAK,WAAW,mBAAmB;AACxD,YAAM,KAAK,eAAe,gBAAgB,MAAM;AAAA,IAClD,QAAQ;AAAA,IAER;AAAA,EACF;AACF;;;AP7nBA,SAAS,WAAAC,iBAAe;;;AU7BxB,SAAS,eAAe;AACxB,OAAO,eAAe;;;ACEtB,IAAAC,4BAAkC;AAHlC,SAAS,gBAAAC,qBAAoB;AAWtB,IAAM,wBAAN,cAAoCC,cAAa;AAAA,EAC9C;AAAA,EACA;AAAA,EACA,eAAuC;AAAA,EACvC,gBAAwC;AAAA,EACxC,kBAA0C;AAAA,EAElD,YAAY,SAAuC;AACjD,UAAM;AACN,SAAK,WAAW,QAAQ;AACxB,SAAK,YAAY,QAAQ;AAAA,EAC3B;AAAA,EAEA,MAAM,UAA4B;AAChC,UAAM,gBAAgB,EAAE,QAAQ,EAAE,SAAS,KAAK,EAAE;AAGlD,UAAM,mBAAmB,4CAAkB,aAAa,KAAK,SAAS;AACtE,SAAK,eAAe,KAAK,SAAS,QAAQ,kBAAkB,aAAa;AAEzE,SAAK,aAAa,GAAG,aAAa,EAAE,OAAO,kBAAkB,GAAG,CAAC,YAAY;AAC3E,WAAK,KAAK,WAAW,QAAQ,OAAyB;AAAA,IACxD,CAAC;AAGD,UAAM,oBAAoB,4CAAkB,cAAc,KAAK,SAAS;AACxE,SAAK,gBAAgB,KAAK,SAAS,QAAQ,mBAAmB,aAAa;AAE3E,UAAM,UAAU,MAAM,QAAQ,IAAI;AAAA,MAChC,qBAAqB,KAAK,cAAc,eAAe;AAAA,MACvD,qBAAqB,KAAK,eAAe,gBAAgB;AAAA,IAC3D,CAAC;AAED,UAAM,YAAY,QAAQ,MAAM,CAAC,YAAY,OAAO;AAGpD,QAAI,WAAW;AACb,YAAM,sBAAsB,4CAAkB,gBAAgB,KAAK,SAAS;AAC5E,WAAK,kBAAkB,KAAK,SAAS,QAAQ,qBAAqB,aAAa;AAE/E,WAAK,gBAAgB,UAAU,OAAO,WAAW;AAC/C,YAAI,WAAW,gBAAgB,KAAK,iBAAiB;AACnD,cAAI;AACF,kBAAM,UAA2B;AAAA,cAC/B,MAAM;AAAA,cACN,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,YACpC;AACA,kBAAM,KAAK,gBAAgB,MAAM,OAAO;AAAA,UAC1C,SAAS,YAAY;AACnB,oBAAQ,KAAK,4CAA4C,UAAU;AAAA,UACrE;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,wBAAwB,WAAmB,kBAAyC;AACxF,QAAI,CAAC,KAAK,cAAe;AAEzB,UAAM,UAA0B;AAAA,MAC9B,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA,WAAW,KAAK,IAAI;AAAA,IACtB;AAEA,UAAM,KAAK,cAAc,KAAK;AAAA,MAC5B,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,sBAAsB,WAAkC;AAC5D,QAAI,CAAC,KAAK,cAAe;AAEzB,UAAM,UAA0B;AAAA,MAC9B,MAAM;AAAA,MACN;AAAA,MACA,WAAW,KAAK,IAAI;AAAA,IACtB;AAEA,UAAM,KAAK,cAAc,KAAK;AAAA,MAC5B,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,eAAe,OAA8B;AACjD,QAAI,CAAC,KAAK,cAAe;AAEzB,UAAM,UAA0B;AAAA,MAC9B,MAAM;AAAA,MACN;AAAA,MACA,WAAW,KAAK,IAAI;AAAA,IACtB;AAEA,UAAM,KAAK,cAAc,KAAK;AAAA,MAC5B,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,aAA4B;AAChC,QAAI,KAAK,iBAAiB;AACxB,YAAM,KAAK,gBAAgB,QAAQ;AACnC,YAAM,KAAK,SAAS,cAAc,KAAK,eAAe;AACtD,WAAK,kBAAkB;AAAA,IACzB;AAEA,QAAI,KAAK,cAAc;AACrB,YAAM,KAAK,SAAS,cAAc,KAAK,YAAY;AACnD,WAAK,eAAe;AAAA,IACtB;AAEA,QAAI,KAAK,eAAe;AACtB,YAAM,KAAK,SAAS,cAAc,KAAK,aAAa;AACpD,WAAK,gBAAgB;AAAA,IACvB;AAEA,SAAK,KAAK,cAAc;AAAA,EAC1B;AACF;;;ACzIO,IAAM,UAAN,MAAc;AAAA,EACX,SAAS,CAAC,UAAK,UAAK,UAAK,UAAK,UAAK,UAAK,UAAK,UAAK,UAAK,QAAG;AAAA,EAC1D,eAAe;AAAA,EACf,WAAkC;AAAA,EAClC;AAAA,EACA;AAAA,EAER,YAAY,SAAiB,SAA6B,QAAQ,QAAQ;AACxE,SAAK,UAAU;AACf,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,QAAc;AACZ,QAAI,KAAK,UAAU;AACjB;AAAA,IACF;AAGA,SAAK,OAAO,MAAM,WAAW;AAE7B,SAAK,WAAW,YAAY,MAAM;AAChC,YAAM,QAAQ,KAAK,OAAO,KAAK,YAAY;AAC3C,WAAK,OAAO,MAAM,KAAK,KAAK,IAAI,KAAK,OAAO,EAAE;AAC9C,WAAK,gBAAgB,KAAK,eAAe,KAAK,KAAK,OAAO;AAAA,IAC5D,GAAG,EAAE;AAAA,EACP;AAAA,EAEA,OAAO,SAAuB;AAC5B,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,OAAa;AACX,QAAI,KAAK,UAAU;AACjB,oBAAc,KAAK,QAAQ;AAC3B,WAAK,WAAW;AAAA,IAClB;AAGA,SAAK,OAAO,MAAM,UAAU;AAC5B,SAAK,OAAO,MAAM,WAAW;AAAA,EAC/B;AAAA,EAEA,QAAQ,SAAuB;AAC7B,SAAK,KAAK;AACV,SAAK,OAAO,MAAM,YAAO,OAAO;AAAA,CAAI;AAAA,EACtC;AAAA,EAEA,KAAK,SAAuB;AAC1B,SAAK,KAAK;AACV,SAAK,OAAO,MAAM,YAAO,OAAO;AAAA,CAAI;AAAA,EACtC;AACF;;;ACnDA,SAAS,oBAAyC;AAM3C,SAAS,qBACd,KACA,SACA,SACgB;AAChB,QAAM,gBAAgB,SAAS,WAC3B;AAAA,IACE,UAAU;AAAA,MACR,QAAQ,EAAE,iBAAiB,GAAG;AAAA,MAC9B,SAAS;AAAA,IACX;AAAA,EACF,IACA;AAEJ,SAAO,aAAa,KAAK,SAAS,aAAa;AACjD;AAQA,eAAsB,eACpB,UACAC,SAC+B;AAC/B,QAAM,gBAAgBA,QAAO,iBAAiB;AAC9C,MAAI,CAAC,eAAe;AAClB,WAAO;AAAA,EACT;AAEA,QAAM,EAAE,MAAM,aAAa,OAAO,aAAa,IAC7C,MAAM,SAAS,KAAK,WAAW;AAAA,IAC7B,cAAc,cAAc;AAAA,IAC5B,eAAe,cAAc;AAAA,EAC/B,CAAC;AAEH,MAAI,cAAc;AAChB,IAAAA,QAAO,mBAAmB;AAC1B,WAAO;AAAA,EACT;AAGA,MAAI,aAAa,SAAS;AACxB,UAAM,YAAY,YAAY,QAAQ;AACtC,UAAM,aAAa,YAAY,QAAQ;AACvC,QACE,cAAc,cAAc,eAC5B,eAAe,cAAc,cAC7B;AACA,MAAAA,QAAO,iBAAiB;AAAA,QACtB,aAAa;AAAA,QACb,cAAc;AAAA,MAChB,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAM;AAAA,IACJ,MAAM,EAAE,KAAK;AAAA,IACb,OAAO;AAAA,EACT,IAAI,MAAM,SAAS,KAAK,QAAQ;AAEhC,MAAI,aAAa,CAAC,MAAM;AACtB,WAAO;AAAA,EACT;AAEA,SAAO,EAAE,KAAK;AAChB;;;AC1EA,SAAS,OAAO,gBAAmC;AACnD,YAAY,cAAc;AAC1B,SAAS,eAAAC,oBAAmB;AAC5B,YAAYC,WAAU;AACtB,YAAYC,SAAQ;AAOpB,eAAsB,YAAY,UAAoC;AACpE,QAAM,KAAc,yBAAgB;AAAA,IAClC,OAAO,QAAQ;AAAA,IACf,QAAQ,QAAQ;AAAA,EAClB,CAAC;AAED,SAAO,IAAI,QAAQ,CAACC,aAAY;AAC9B,OAAG,SAAS,UAAU,CAAC,WAAW;AAChC,SAAG,MAAM;AACT,MAAAA,SAAQ,OAAO,YAAY,MAAM,OAAO,OAAO,YAAY,MAAM,KAAK;AAAA,IACxE,CAAC;AAAA,EACH,CAAC;AACH;AAEO,SAAS,wBAAiC;AAC/C,MAAI;AACF,aAAS,gCAAgC,EAAE,OAAO,UAAU,CAAC;AAC7D,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,yBAA+B;AAC7C,MAAI;AACF,aAAS,gCAAgC,EAAE,OAAO,UAAU,CAAC;AAAA,EAC/D,QAAQ;AAAA,EAER;AACF;AAEO,SAAS,kBAAgC;AAC9C,QAAMC,WAAU,MAAM,cAAc,CAAC,MAAM,IAAI,GAAG;AAAA,IAChD,OAAO;AAAA,IACP,UAAU;AAAA,EACZ,CAAC;AAED,SAAOA;AACT;AAEO,SAAS,eAAeA,UAAoC;AACjE,MAAIA,UAAS;AACX,IAAAA,SAAQ,KAAK;AAAA,EACf;AACF;AAEO,SAAS,QAAQ,OAAmC;AACzD,iBAAe,MAAM,iBAAiB;AACtC,MAAI,MAAM,cAAc;AACtB,2BAAuB;AAAA,EACzB;AACF;AAEO,SAAS,UAAmB;AACjC,SAAO,QAAQ,aAAa;AAC9B;AAYO,SAAS,sBAA+B;AAC7C,MAAI,CAAC,QAAQ,EAAG,QAAO;AAEvB,MAAI;AACF,UAAM,YAAiB,WAAQ,YAAQ,GAAG,WAAW,QAAQ;AAC7D,IAAAJ,aAAY,SAAS;AACrB,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,IAAM,mBAA2C;AAAA,EAC/C,QAAQ;AAAA,EACR,gBAAgB;AAAA,EAChB,aAAa;AAAA,EACb,cAAc;AAAA,EACd,OAAO;AACT;AAKO,SAAS,qBAA6B;AAC3C,QAAM,cAAc,QAAQ,IAAI;AAChC,MAAI,eAAe,iBAAiB,WAAW,GAAG;AAChD,WAAO,iBAAiB,WAAW;AAAA,EACrC;AACA,SAAO;AACT;AAMO,SAAS,6BAAsC;AACpD,MAAI,CAAC,QAAQ,EAAG,QAAO;AAEvB,MAAI;AACF;AAAA,MACE;AAAA,IACF;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAMO,SAAS,wBAAwB,SAAkB,aAA4C;AACpG,MAAI,SAAS;AACX,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO;AAAA,IACT;AAAA,EACF;AAEA,QAAM,UAAU,eAAe;AAE/B,SAAO;AAAA,IACL,SAAS;AAAA,IACT,OAAO;AAAA,IACP,SAAS;AAAA,MACP;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,mBAAmB,OAAO;AAAA,MAC1B;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,EACb;AACF;;;AC5JA,SAAS,SAAAK,QAAO,YAAAC,iBAAmC;AACnD;AAAA,EACE,cAAAC;AAAA,EACA,aAAAC;AAAA,EACA,iBAAAC;AAAA,EACA;AAAA,OAEK;AACP,SAAS,QAAAC,aAAY;AACrB,SAAS,WAAAC,gBAAe;AACxB,SAAS,WAAW;AACpB,OAAO,YAAY;AAEnB,IAAM,WAAW;AACjB,IAAM,qBAAqBD,MAAKC,SAAQ,GAAG,eAAe,QAAQ;AAwB3D,IAAM,sBAAN,MAA0B;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAoC;AAAA,EACpC,cAAmC;AAAA,EACnC,iBAAqC;AAAA,EACrC,gBAAoC;AAAA,EACpC,YAA2B;AAAA,EAC3B;AAAA,EACA;AAAA,EAER,YAAY,SAA8B;AACxC,SAAK,UAAU;AACf,SAAK,gBAAgB,QAAQ,sBAAsB;AACnD,SAAK,oBAAoB,QAAQ,qBAAqB;AACtD,SAAK,WAAW,QAAQ,YAAY;AACpC,SAAK,SAAS,QAAQ,UAAUD,MAAKC,SAAQ,GAAG,eAAe,MAAM;AACrE,SAAK,aAAa,QAAQ,eAAe,MAAM;AAAA,IAAC;AAAA,EAClD;AAAA,EAEA,uBAA+B;AAC7B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,qBAAyC;AACvC,UAAM,SAAmB,CAAC;AAC1B,QAAI,eAAe;AAKnB,QAAI;AACF,MAAAL,UAAS,eAAe,EAAE,OAAO,OAAO,CAAC;AAGzC,UAAI;AACF,cAAM,eAAeA,UAAS,sBAAsB;AAAA,UAClD,OAAO;AAAA,UACP,SAAS;AAAA,QACX,CAAC,EAAE,SAAS;AAEZ,YAAI,CAAC,aAAa,YAAY,EAAE,SAAS,OAAO,GAAG;AACjD,iBAAO;AAAA,YACL;AAAA,UAIF;AAAA,QACF;AAAA,MACF,QAAQ;AAEN,eAAO;AAAA,UACL;AAAA,QAIF;AAAA,MACF;AAAA,IACF,QAAQ;AACN,aAAO;AAAA,QACL;AAAA,MAMF;AAAA,IACF;AAGA,UAAM,kBAAkBI,MAAK,KAAK,mBAAmB,cAAc;AACnE,QAAI,CAACH,YAAW,eAAe,GAAG;AAChC,qBAAe;AAAA,IACjB;AAEA,WAAO,EAAE,OAAO,OAAO,WAAW,GAAG,QAAQ,aAAa;AAAA,EAC5D;AAAA,EAEA,sBAA2E;AAEzE,UAAMK,eAAcF,MAAK,KAAK,mBAAmB,cAAc;AAC/D,QAAIH,YAAWK,YAAW,GAAG;AAC3B,aAAO,EAAE,OAAO,MAAM,QAAQ,MAAM;AAAA,IACtC;AAGA,QAAI,KAAK,eAAe;AACtB,aAAO;AAAA,QACL,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,OAAO,kCAAkC,KAAK,iBAAiB;AAAA,MACjE;AAAA,IACF;AAGA,QAAI;AAEF,MAAAN,UAAS,aAAa,EAAE,OAAO,OAAO,CAAC;AAAA,IACzC,QAAQ;AACN,aAAO;AAAA,QACL,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,OAAO;AAAA,MAGT;AAAA,IACF;AAEA,QAAI;AAEF,YAAM,gBAAgBI,MAAKC,SAAQ,GAAG,aAAa;AACnD,UAAI,CAACJ,YAAW,aAAa,GAAG;AAC9B,QAAAC,WAAU,eAAe,EAAE,WAAW,KAAK,CAAC;AAAA,MAC9C;AAGA,YAAM,UAAUE,MAAK,eAAe,MAAM;AAC1C,UAAIH,YAAW,OAAO,GAAG;AAEvB,QAAAD,UAAS,qBAAqB;AAAA,UAC5B,KAAK;AAAA,UACL,OAAO;AAAA,UACP,SAAS;AAAA,QACX,CAAC;AAED,QAAAA,UAAS,sBAAsB;AAAA,UAC7B,KAAK;AAAA,UACL,OAAO;AAAA,UACP,SAAS;AAAA,QACX,CAAC;AAAA,MACH,OAAO;AACL,QAAAA;AAAA,UACE,oDAAoD,QAAQ;AAAA,UAC5D;AAAA,YACE,KAAK;AAAA,YACL,OAAO;AAAA,YACP,SAAS;AAAA,UACX;AAAA,QACF;AACA,QAAAA,UAAS,uDAAuD;AAAA,UAC9D,KAAK;AAAA,UACL,OAAO;AAAA,UACP,SAAS;AAAA,QACX,CAAC;AAAA,MACH;AAGA,WAAK,oBAAoBI,MAAK,SAAS,QAAQ,QAAQ;AAEvD,UAAI,CAACH,YAAWG,MAAK,KAAK,mBAAmB,cAAc,CAAC,GAAG;AAC7D,eAAO,EAAE,OAAO,OAAO,QAAQ,OAAO,OAAO,4CAA4C;AAAA,MAC3F;AAEA,aAAO,EAAE,OAAO,MAAM,QAAQ,KAAK;AAAA,IACrC,SAAS,OAAO;AACd,aAAO;AAAA,QACL,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,OAAO,mCAAmC,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,MACpG;AAAA,IACF;AAAA,EACF;AAAA,EAEA,gBAAsB;AACpB,UAAM,UAAUA,MAAK,KAAK,mBAAmB,MAAM;AACnD,UAAM,QAAQ;AAAA,MACZ,4BAA4B,KAAK,QAAQ,WAAW;AAAA,MACpD,iCAAiC,KAAK,QAAQ,eAAe;AAAA,MAC7D;AAAA,IACF;AACA,IAAAD,eAAc,SAAS,MAAM,KAAK,IAAI,CAAC;AAAA,EACzC;AAAA,EAEA,sBAA+B;AAC7B,UAAM,kBAAkBC,MAAK,KAAK,mBAAmB,cAAc;AACnE,UAAM,WAAWA,MAAK,KAAK,mBAAmB,MAAM,IAAI;AACxD,UAAM,iBAAiBA,MAAK,UAAU,YAAY,UAAU,QAAQ,UAAU;AAE9E,QAAIH,YAAW,eAAe,KAAKA,YAAW,cAAc,EAAG,QAAO;AAGtE,QAAI;AACF,MAAAD,UAAS,gBAAgB;AAAA,QACvB,KAAK;AAAA,QACL,OAAO;AAAA,QACP,SAAS;AAAA;AAAA,MACX,CAAC;AAGD,YAAM,YAAYI,MAAK,UAAU,YAAY,QAAQ;AACrD,UAAIH,YAAWG,MAAK,WAAW,eAAe,CAAC,GAAG;AAChD,QAAAJ,UAAS,cAAc;AAAA,UACrB,KAAK;AAAA,UACL,OAAO;AAAA,UACP,SAAS;AAAA,QACX,CAAC;AAAA,MACH;AAEA,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,aAAqC;AAEzC,QAAI;AACF,MAAAA,UAAS,iBAAiB,EAAE,OAAO,OAAO,CAAC;AAC3C,YAAM,KAAK,MAAM,GAAG;AAAA,IACtB,QAAQ;AAAA,IAER;AAEA,SAAK,aAAa;AAElB,SAAK,iBAAiB,kBAAkBI,MAAK,KAAK,QAAQ,WAAW,CAAC;AAGtE,QAAI,aAAa;AAEjB,SAAK,eAAeL,OAAM,SAAS,CAAC,QAAQ,OAAO,KAAK,QAAQ,CAAC,GAAG;AAAA,MAClE,OAAO,CAAC,UAAU,QAAQ,MAAM;AAAA,MAChC,UAAU;AAAA,IACZ,CAAC;AAGD,SAAK,aAAa,QAAQ,KAAK,KAAK,cAAc;AAGlD,SAAK,aAAa,QAAQ,GAAG,QAAQ,CAAC,UAAkB;AACtD,oBAAc,MAAM,SAAS;AAC7B,WAAK,gBAAgB,MAAM,KAAK;AAAA,IAClC,CAAC;AAED,SAAK,aAAa,GAAG,SAAS,MAAM;AAAA,IAEpC,CAAC;AAGD,aAAS,IAAI,GAAG,IAAI,IAAI,KAAK;AAC3B,YAAM,KAAK,MAAM,GAAI;AAGrB,UAAI,KAAK,aAAa,aAAa,MAAM;AACvC;AAAA,MACF;AAEA,YAAM,MAAM,MAAM,KAAK,kBAAkB;AACzC,UAAI,KAAK;AACP,aAAK,YAAY;AACjB,eAAO;AAAA,MACT;AAAA,IACF;AAGA,SAAK,aAAa,KAAK,qBAAqB,UAAU;AAEtD,SAAK,gBAAgB,KAAK,YAAY;AACtC,SAAK,eAAe;AACpB,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,aAA4B;AAAA,EAEpB,qBAAqB,QAAwB;AACnD,UAAM,QAAQ,OAAO,YAAY;AAEjC,QAAI,MAAM,SAAS,WAAW,KAAK,MAAM,SAAS,eAAe,KAAK,MAAM,SAAS,gBAAgB,GAAG;AACtG,aAAO;AAAA,IAIT;AAEA,QAAI,MAAM,SAAS,sBAAsB,KAAK,MAAM,SAAS,eAAe,GAAG;AAC7E,aAAO;AAAA,IAGT;AAEA,QAAI,MAAM,SAAS,UAAU,KAAK,MAAM,SAAS,oBAAoB,GAAG;AACtE,aAAO,wCAAwC,KAAK,QAAQ;AAAA;AAAA,IAE9D;AAGA,WAAO;AAAA,4BACwBK,MAAK,KAAK,QAAQ,WAAW,CAAC;AAAA,EAC/D;AAAA,EAEA,MAAM,UAAU,WAAqC;AACnD,SAAK,aAAa;AAKlB,SAAK,kBAAkB,KAAK,QAAQ;AAEpC,SAAK,gBAAgB,kBAAkBA,MAAK,KAAK,QAAQ,UAAU,CAAC;AAEpE,SAAK,cAAcL,OAAM,OAAO,CAAC,QAAQ,SAAS,WAAW,UAAU,OAAO,KAAK,QAAQ,CAAC,GAAG;AAAA,MAC7F,KAAK,KAAK;AAAA,MACV,KAAK;AAAA,QACH,GAAG,QAAQ;AAAA,QACX,yBAAyB;AAAA,QACzB,wBAAwB;AAAA,MAC1B;AAAA,MACA,OAAO,CAAC,UAAU,QAAQ,MAAM;AAAA,MAChC,UAAU;AAAA,IACZ,CAAC;AAED,SAAK,YAAY,GAAG,SAAS,MAAM;AAAA,IAEnC,CAAC;AAGD,WAAO,IAAI,QAAiB,CAACQ,aAAY;AACvC,UAAI,QAAQ;AACZ,UAAI,WAAW;AACf,UAAI,WAAW;AAEf,YAAM,UAAU,WAAW,MAAM;AAC/B,YAAI,CAAC,UAAU;AACb,qBAAW;AACX,eAAK,aAAa,QAAQ,KAAK,KAAK,aAAc;AAClD,eAAK,aAAa,QAAQ,KAAK,KAAK,aAAc;AAClD,UAAAA,SAAQ,KAAK;AAAA,QACf;AAAA,MACF,GAAG,GAAK;AAER,WAAK,aAAa,QAAQ,GAAG,QAAQ,CAAC,SAAiB;AACrD,cAAM,OAAO,KAAK,SAAS;AAC3B,cAAM,QAAQ,KAAK,MAAM,IAAI;AAE7B,mBAAW,QAAQ,OAAO;AACxB,cAAI,OAAO;AACT,iBAAK,eAAe,MAAM,OAAO,IAAI;AACrC;AAAA,UACF;AAGA,cAAI,KAAK,aAAa,IAAI,GAAG;AAC3B,uBAAW;AACX,oBAAQ,OAAO,MAAM,OAAO,IAAI;AAAA,UAClC,WAAW,YAAY,CAAC,KAAK,gBAAgB,IAAI,KAAK,KAAK,KAAK,GAAG;AAEjE,oBAAQ,OAAO,MAAM,OAAO,IAAI;AAAA,UAClC,WAAW,KAAK,gBAAgB,IAAI,GAAG;AAErC,oBAAQ,OAAO,MAAM,OAAO,IAAI;AAChC,oBAAQ;AAER,gBAAI,CAAC,UAAU;AACb,yBAAW;AACX,2BAAa,OAAO;AAEpB,mBAAK,aAAa,QAAQ,KAAK,KAAK,aAAc;AAClD,mBAAK,aAAa,QAAQ,KAAK,KAAK,aAAc;AAClD,cAAAA,SAAQ,IAAI;AAAA,YACd;AAAA,UACF,OAAO;AAEL,iBAAK,eAAe,MAAM,OAAO,IAAI;AAAA,UACvC;AAAA,QACF;AAAA,MACF,CAAC;AAED,WAAK,aAAa,QAAQ,KAAK,KAAK,aAAc;AAElD,WAAK,aAAa,GAAG,QAAQ,MAAM;AACjC,YAAI,CAAC,UAAU;AACb,qBAAW;AACX,uBAAa,OAAO;AACpB,UAAAA,SAAQ,KAAK;AAAA,QACf;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,QAAqC;AAEzC,SAAK,WAAW,4BAA4B;AAC5C,UAAM,gBAAgB,KAAK,oBAAoB;AAC/C,QAAI,CAAC,cAAc,OAAO;AACxB,aAAO,EAAE,SAAS,OAAO,OAAO,cAAc,MAAM;AAAA,IACtD;AACA,QAAI,cAAc,QAAQ;AACxB,WAAK,WAAW,yDAAyD;AAAA,IAC3E;AAGA,SAAK,WAAW,2BAA2B;AAC3C,UAAM,UAAU,KAAK,mBAAmB;AACxC,QAAI,CAAC,QAAQ,OAAO;AAClB,aAAO,EAAE,SAAS,OAAO,OAAO,QAAQ,OAAO,KAAK,IAAI,EAAE;AAAA,IAC5D;AAGA,QAAI,QAAQ,cAAc;AACxB,WAAK,WAAW,qDAAqD;AACrE,YAAM,YAAY,KAAK,oBAAoB;AAC3C,UAAI,CAAC,WAAW;AACd,eAAO,EAAE,SAAS,OAAO,OAAO,wCAAwC;AAAA,MAC1E;AAAA,IACF;AAGA,SAAK,WAAW,0BAA0B;AAC1C,UAAM,YAAY,MAAM,KAAK,WAAW;AACxC,QAAI,CAAC,WAAW;AACd,aAAO,EAAE,SAAS,OAAO,OAAO,KAAK,cAAc,+BAA+B;AAAA,IACpF;AAGA,SAAK,WAAW,wBAAwB;AACxC,SAAK,cAAc;AAGnB,SAAK,WAAW,yBAAyB;AACzC,UAAM,cAAc,MAAM,KAAK,UAAU,SAAS;AAClD,QAAI,CAAC,aAAa;AAEhB,YAAM,KAAK,KAAK;AAChB,aAAO,EAAE,SAAS,OAAO,OAAO,8BAA8B;AAAA,IAChE;AAIA,UAAM,OAAO,UAAU,QAAQ,gBAAgB,EAAE;AACjD,UAAM,eAAe,KAAK,QAAQ,cAAc,iBAAiB,KAAK,QAAQ,WAAW,KAAK;AAC9F,UAAM,UAAU,SAAS,IAAI,OAAO,YAAY;AAChD,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,sBAAsB;AAClC,WAAO,SAAS,SAAS,EAAE,OAAO,KAAK,GAAG,CAAC,SAAiB;AAE1D,iBAAW,QAAQ,KAAK,MAAM,IAAI,GAAG;AACnC,gBAAQ,IAAI,KAAK,IAAI,EAAE;AAAA,MACzB;AAAA,IACF,CAAC;AACD,YAAQ,IAAI,KAAK,OAAO,EAAE;AAC1B,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,sTAAuD;AACnE,YAAQ,IAAI,iEAAuD;AACnE,YAAQ,IAAI,iEAAuD;AACnE,YAAQ,IAAI,iEAAuD;AACnE,YAAQ,IAAI,iEAAuD;AACnE,YAAQ,IAAI,sTAAuD;AACnE,YAAQ,IAAI,EAAE;AAEd,WAAO,EAAE,SAAS,MAAM,UAAU;AAAA,EACpC;AAAA,EAEA,MAAM,OAAsB;AAC1B,QAAI,KAAK,aAAa;AACpB,WAAK,gBAAgB,KAAK,WAAW;AACrC,WAAK,cAAc;AAAA,IACrB;AAEA,QAAI,KAAK,cAAc;AACrB,WAAK,gBAAgB,KAAK,YAAY;AACtC,WAAK,eAAe;AAAA,IACtB;AAGA,SAAK,kBAAkB,KAAK,QAAQ;AAEpC,QAAI,KAAK,eAAe;AACtB,WAAK,cAAc,IAAI;AACvB,WAAK,gBAAgB;AAAA,IACvB;AAEA,QAAI,KAAK,gBAAgB;AACvB,WAAK,eAAe,IAAI;AACxB,WAAK,iBAAiB;AAAA,IACxB;AAEA,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,eAA8B;AAC5B,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,aAAa,MAAuB;AAC1C,WAAO,KAAK,SAAS,QAAQ,KAAK,KAAK,SAAS,QAAQ,KAAK,KAAK,SAAS,QAAQ;AAAA,EACrF;AAAA,EAEQ,gBAAgB,MAAuB;AAC7C,WAAO,KAAK,SAAS,kBAAkB,KAAK,KAAK,SAAS,uBAAuB;AAAA,EACnF;AAAA,EAEQ,oBAA4C;AAClD,WAAO,IAAI,QAAQ,CAACA,aAAY;AAC9B,YAAM,MAAM,IAAI,qCAAqC,CAAC,QAAQ;AAC5D,YAAI,OAAO;AACX,YAAI,GAAG,QAAQ,CAAC,UAAW,QAAQ,KAAM;AACzC,YAAI,GAAG,OAAO,MAAM;AAClB,cAAI;AACF,kBAAM,UAAU,KAAK,MAAM,IAAI,EAAE;AACjC,kBAAM,cAAc,SAAS;AAAA,cAC3B,CAAC,MAAyB,EAAE,UAAU;AAAA,YACxC;AACA,YAAAA,SAAQ,aAAa,cAAc,IAAI;AAAA,UACzC,QAAQ;AACN,YAAAA,SAAQ,IAAI;AAAA,UACd;AAAA,QACF,CAAC;AAAA,MACH,CAAC;AAED,UAAI,GAAG,SAAS,MAAMA,SAAQ,IAAI,CAAC;AACnC,UAAI,WAAW,KAAM,MAAM;AACzB,YAAI,QAAQ;AACZ,QAAAA,SAAQ,IAAI;AAAA,MACd,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEQ,gBAAgB,MAA0B;AAChD,UAAM,MAAM,KAAK;AACjB,QAAI,CAAC,IAAK;AAGV,QAAI;AACF,WAAK,KAAK,SAAS;AAAA,IACrB,QAAQ;AAAA,IAER;AAIA,QAAI;AACF,YAAM,WAAWP,UAAS,YAAY,GAAG,IAAI,EAAE,OAAO,OAAO,CAAC,EAAE,SAAS,EAAE,KAAK;AAChF,iBAAW,YAAY,SAAS,MAAM,IAAI,EAAE,OAAO,OAAO,GAAG;AAC3D,YAAI;AACF,kBAAQ,KAAK,SAAS,UAAU,EAAE,GAAG,SAAS;AAAA,QAChD,QAAQ;AAAA,QAAqB;AAAA,MAC/B;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEQ,eAAqB;AAC3B,QAAI,CAACC,YAAW,KAAK,MAAM,GAAG;AAC5B,MAAAC,WAAU,KAAK,QAAQ,EAAE,WAAW,KAAK,CAAC;AAAA,IAC5C;AAAA,EACF;AAAA,EAEQ,kBAAkB,MAAoB;AAC5C,QAAI;AACF,YAAM,SAASF,UAAS,gBAAgB,IAAI,IAAI,EAAE,OAAO,OAAO,CAAC,EAAE,SAAS,EAAE,KAAK;AACnF,UAAI,QAAQ;AACV,mBAAW,OAAO,OAAO,MAAM,IAAI,GAAG;AACpC,cAAI;AACF,oBAAQ,KAAK,SAAS,KAAK,EAAE,GAAG,SAAS;AAAA,UAC3C,QAAQ;AAAA,UAER;AAAA,QACF;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEQ,MAAM,IAA2B;AACvC,WAAO,IAAI,QAAQ,CAACO,aAAY,WAAWA,UAAS,EAAE,CAAC;AAAA,EACzD;AACF;;;ACjmBA,YAAYC,SAAQ;AACpB,YAAYC,WAAU;AACtB,YAAYC,SAAQ;AAEb,IAAM,WAAgB,WAAQ,YAAQ,GAAG,eAAe,YAAY;AAwB3E,IAAM,iBAAiB,KAAK,IAAI;AAUzB,SAAS,eAAe,UAAkB,UAAyB;AACxE,QAAM,MAAW,cAAQ,OAAO;AAChC,MAAI,CAAI,eAAW,GAAG,GAAG;AACvB,IAAG,cAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAAA,EACvC;AAEA,QAAM,UAAU,GAAG,QAAQ,GAAG,IAAI,cAAc;AAEhD,MAAI;AAEF,UAAM,KAAQ,aAAS,SAAS,IAAI;AACpC,IAAG,cAAU,IAAI,OAAO;AACxB,IAAG,cAAU,EAAE;AACf,WAAO;AAAA,EACT,SAAS,KAAU;AACjB,QAAI,IAAI,SAAS,UAAU;AACzB,YAAM;AAAA,IACR;AAAA,EACF;AAGA,QAAM,WAAW,aAAa,OAAO;AACrC,MAAI,aAAa,MAAM;AAErB,2BAAuB,OAAO;AAC9B,WAAO,eAAe,OAAO;AAAA,EAC/B;AAEA,MAAI,eAAe,SAAS,GAAG,GAAG;AAChC,WAAO,SAAS;AAAA,EAClB;AAGA,yBAAuB,OAAO;AAC9B,SAAO,eAAe,OAAO;AAC/B;AAOO,SAAS,cAAc,UAAkB,UAAgB;AAC9D,QAAM,WAAW,aAAa,OAAO;AACrC,MAAI,YAAY,SAAS,QAAQ,QAAQ,OAAO,SAAS,cAAc,gBAAgB;AACrF,2BAAuB,OAAO;AAAA,EAChC;AACF;AAMO,SAAS,YAAY,UAAkB,UAAyB;AACrE,QAAM,WAAW,aAAa,OAAO;AACrC,SAAO,UAAU,OAAO;AAC1B;AAKO,SAAS,eAAe,KAAsB;AACnD,MAAI;AACF,YAAQ,KAAK,KAAK,CAAC;AACnB,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAMO,SAAS,cAAc,UAAkB,UAAmB;AACjE,SAAU,eAAW,OAAO;AAC9B;AAEA,SAAS,aAAa,SAA4D;AAChF,MAAI;AACF,UAAM,UAAa,iBAAa,SAAS,OAAO,EAAE,KAAK;AAEvD,UAAM,QAAQ,QAAQ,MAAM,GAAG;AAC/B,UAAM,MAAM,SAAS,MAAM,CAAC,GAAG,EAAE;AACjC,UAAM,YAAY,MAAM,SAAS,IAAI,SAAS,MAAM,CAAC,GAAG,EAAE,IAAI;AAC9D,QAAI,MAAM,GAAG,EAAG,QAAO;AACvB,WAAO,EAAE,KAAK,WAAW,MAAM,SAAS,IAAI,IAAI,UAAU;AAAA,EAC5D,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,uBAAuB,SAAuB;AACrD,MAAI;AACF,IAAG,eAAW,OAAO;AAAA,EACvB,QAAQ;AAAA,EAER;AACF;;;ACxIA,SAAS,YAAAC,iBAAgB;AAmBlB,SAAS,qBAAuC;AACrD,MAAI;AACF,UAAM,SAASA,UAAS,6BAA6B;AAAA,MACnD,UAAU;AAAA,MACV,SAAS;AAAA,MACT,OAAO,CAAC,QAAQ,QAAQ,MAAM;AAAA,IAChC,CAAC;AAED,UAAM,SAAS,KAAK,MAAM,OAAO,KAAK,CAAC;AACvC,QAAI,OAAO,aAAa,MAAM;AAC5B,aAAO;AAAA,QACL,UAAU;AAAA,QACV,YAAY,OAAO;AAAA,QACnB,aAAa,OAAO;AAAA,MACtB;AAAA,IACF;AACA,WAAO,EAAE,UAAU,OAAO,SAAS,gBAAgB;AAAA,EACrD,SAAS,OAAgB;AAGvB,UAAM,YAAY;AAGlB,QAAI,UAAU,QAAQ;AACpB,UAAI;AACF,cAAM,SACJ,OAAO,UAAU,WAAW,WACxB,UAAU,SACV,UAAU,OAAO,SAAS,OAAO;AACvC,cAAM,SAAS,KAAK,MAAM,OAAO,KAAK,CAAC;AACvC,YAAI,OAAO,aAAa,MAAM;AAC5B,iBAAO;AAAA,YACL,UAAU;AAAA,YACV,YAAY,OAAO;AAAA,YACnB,aAAa,OAAO;AAAA,UACtB;AAAA,QACF;AACA,eAAO,EAAE,UAAU,OAAO,SAAS,gBAAgB;AAAA,MACrD,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,UAAM,UAAU,UAAU,WAAW,OAAO,KAAK;AAGjD,QACE,QAAQ,SAAS,mBAAmB,KACpC,QAAQ,SAAS,QAAQ,KACzB,QAAQ,SAAS,gBAAgB,GACjC;AACA,aAAO,EAAE,UAAU,OAAO,SAAS,gBAAgB;AAAA,IACrD;AAGA,QACE,QAAQ,SAAS,iBAAiB,KAClC,QAAQ,SAAS,iBAAiB,KAClC,QAAQ,SAAS,oBAAoB,KACrC,QAAQ,SAAS,oBAAoB,GACrC;AACA,aAAO,EAAE,UAAU,OAAO,SAAS,2BAA2B;AAAA,IAChE;AAEA,WAAO,EAAE,UAAU,OAAO,SAAS,UAAU;AAAA,EAC/C;AACF;;;APzDA,IAAI,OAAO,WAAW,cAAc,aAAa;AAE/C,aAAW,YAAY;AACzB;AAQO,SAAS,qBAA8B;AAC5C,QAAM,UAAU,IAAI,QAAQ,OAAO;AAEnC,UACG,YAAY,kEAAkE,EAC9E,OAAO,qBAAqB,cAAc,EAC1C,OAAO,mBAAmB,4CAA4C,EACtE,OAAO,eAAe,4BAA4B,EAClD,OAAO,OAAO,YAA0B;AACvC,UAAMC,UAAS,IAAI,OAAO;AAC1B,UAAM,SAAS,IAAI,OAAO;AAC1B,UAAM,UAAU,IAAI,QAAQ,wBAAwB;AAEpD,UAAM,UAA+B,oBAAI,IAAI;AAC7C,QAAI,gBAA8C;AAElD,QAAI;AAEF,YAAM,cAAc,eAAe;AACnC,UAAI,gBAAgB,MAAM;AACxB,eAAO,MAAM,uDAAuD,WAAW,GAAG;AAClF,eAAO,MAAM,4DAA4D;AACzE,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,MAAAA,QAAO,qBAAqB;AAE5B,cAAQ,MAAM;AAEd,YAAM,WAAW;AAAA,QACfA,QAAO,eAAe;AAAA,QACtBA,QAAO,mBAAmB;AAAA,QAC1B,EAAE,UAAU,KAAK;AAAA,MACnB;AAGA,cAAQ,OAAO,mBAAmB;AAElC,YAAM,UAAU,MAAM,eAAe,UAAUA,OAAM;AACrD,UAAI,CAAC,SAAS;AACZ,gBAAQ,KAAK,mBAAmB;AAChC,eAAO;AAAA,UACL;AAAA,QACF;AACA,sBAAc;AACd,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,YAAM,EAAE,KAAK,IAAI;AAGjB,YAAM;AAAA,QACJ,MAAM,EAAE,cAAc,iBAAiB;AAAA,MACzC,IAAI,SAAS,KAAK,kBAAkB,CAAC,OAAO,gBAAgB;AAC1D,YAAI,UAAU,qBAAqB,aAAa;AAC9C,UAAAA,QAAO,iBAAiB;AAAA,YACtB,aAAa,YAAY;AAAA,YACzB,cAAc,YAAY;AAAA,UAC5B,CAAC;AAAA,QACH;AAAA,MACF,CAAC;AAED,cAAQ,OAAO,oBAAoB,KAAK,KAAK,KAAK;AAGlD,cAAQ,OAAO,6BAA6B;AAC5C,YAAM,aAAa,mBAAmB;AACtC,UAAI,CAAC,WAAW,UAAU;AACxB,gBAAQ,WAAW,SAAS;AAAA,UAC1B,KAAK;AACH,oBAAQ,KAAK,sBAAsB;AACnC,mBAAO,MAAM,kDAAkD;AAC/D,mBAAO,MAAM,kEAAkE;AAC/E,0BAAc;AACd,oBAAQ,KAAK,CAAC;AACd;AAAA,UACF,KAAK;AAEH,oBAAQ,OAAO,4EAA4E;AAC3F,mBAAO,KAAK,gGAA2F;AACvG,mBAAO,KAAK,iFAAiF;AAC7F;AAAA,UACF,KAAK;AACH,oBAAQ,KAAK,6BAA6B;AAC1C,mBAAO,MAAM,+DAA+D;AAC5E,mBAAO,MAAM,8DAA8D;AAC3E,0BAAc;AACd,oBAAQ,KAAK,CAAC;AACd;AAAA,UACF;AAEE,oBAAQ,OAAO,oCAAoC;AACnD,mBAAO,KAAK,gEAAgE;AAC5E,mBAAO,KAAK,8DAA8D;AAC1E;AAAA,QACJ;AAAA,MACF;AAGA,UAAI,YAAyC;AAE7C,UAAI,QAAQ,GAAG;AACb,gBAAQ,KAAK;AAEb,cAAM,cAAc,mBAAmB;AACvC,YAAI,aAAa,oBAAoB;AACrC,oBAAY,wBAAwB,YAAY,WAAW;AAE3D,YAAI,UAAU,SAAS;AACrB,iBAAO,KAAK,4BAAuB,UAAU,KAAK,EAAE;AAAA,QACtD,OAAO;AACL,iBAAO,KAAK,4BAAuB,UAAU,KAAK,EAAE;AACpD,iBAAO,KAAK,EAAE;AACd,qBAAW,QAAQ,UAAU,QAAS,MAAM,IAAI,GAAG;AACjD,mBAAO,KAAK,KAAK,IAAI,EAAE;AAAA,UACzB;AACA,iBAAO,KAAK,EAAE;AAEd,gBAAM,eAAe,MAAM;AAAA,YACzB;AAAA,UACF;AAEA,cAAI,cAAc;AAChB,uCAA2B;AAC3B,mBAAO,KAAK,EAAE;AACd,kBAAM;AAAA,cACJ;AAAA,YACF;AAGA,yBAAa,oBAAoB;AACjC,wBAAY,wBAAwB,YAAY,WAAW;AAE3D,gBAAI,UAAU,SAAS;AACrB,qBAAO,KAAK,kCAA6B;AAAA,YAC3C,OAAO;AACL,qBAAO,KAAK,4DAA4D;AAAA,YAC1E;AAAA,UACF;AAEA,iBAAO,KAAK,EAAE;AAAA,QAChB;AAEA,gBAAQ,MAAM;AAAA,MAChB;AAGA,YAAM,aAAmC;AAAA,QACvC,mBAAmB;AAAA,QACnB,cAAc;AAAA,MAChB;AAEA,UAAI,QAAQ,GAAG;AACb,gBAAQ,KAAK;AAGb,cAAM,cACJ,QAAQ,gBACP,MAAM;AAAA,UACL;AAAA,QACF;AAEF,YAAI,aAAa;AACf,iBAAO,KAAK,EAAE;AACd,iBAAO,KAAK,8BAA8B;AAC1C,cAAI,CAAC,QAAQ,cAAc;AACzB,mBAAO,KAAK,qDAAqD;AACjE,mBAAO,KAAK,EAAE;AAAA,UAChB;AAEA,qBAAW,eAAe,sBAAsB;AAChD,cAAI,WAAW,cAAc;AAC3B,mBAAO,KAAK,gCAA2B;AAAA,UACzC,OAAO;AACL,mBAAO,KAAK,qDAAqD;AAAA,UACnE;AAGA,qBAAW,oBAAoB,gBAAgB;AAE/C,qBAAW,kBAAkB,GAAG,SAAS,MAAM;AAC7C,mBAAO,KAAK,4BAA4B;AAAA,UAC1C,CAAC;AAED,iBAAO,KAAK,EAAE;AAAA,QAChB;AAEA,gBAAQ,MAAM;AAAA,MAChB;AAGA,UAAI,eAA2C;AAE/C,UAAI,QAAQ,WAAW,OAAO;AAI5B,cAAM,EAAE,MAAM,EAAE,SAAS,eAAe,EAAE,IAAI,MAAM,SAAS,KAAK,WAAW;AAC7E,cAAM,EAAE,MAAM,aAAa,OAAO,aAAa,IAAI,MAAM,SACtD,UAAU,OAAO,yBAAyB;AAAA,UACzC,SAAS,EAAE,eAAe,UAAU,gBAAgB,YAAY,GAAG;AAAA,QACrE,CAAC;AAEH,YAAI,gBAAgB,CAAC,aAAa,MAAM;AACtC,kBAAQ,KAAK,sCAAsC;AACnD,iBAAO,MAAM,cAAc,WAAW,0BAA0B;AAChE,wBAAc;AACd,kBAAQ,KAAK,CAAC;AAAA,QAChB;AAEA,cAAM,cAAc,YAAY;AAEhC,cAAM,oBAAoBA,QAAO,qBAAqB;AACtD,uBAAe,IAAI,oBAAoB;AAAA,UACrC;AAAA,UACA,aAAaA,QAAO,eAAe;AAAA,UACnC,iBAAiBA,QAAO,mBAAmB;AAAA,UAC3C;AAAA,UACA,YAAY,CAAC,QAAQ,QAAQ,OAAO,GAAG;AAAA,QACzC,CAAC;AAED,cAAM,SAAS,MAAM,aAAa,MAAM;AACxC,gBAAQ,KAAK;AAEb,YAAI,OAAO,SAAS;AAClB,iBAAO,KAAK,EAAE;AACd,iBAAO,KAAK,aAAa,OAAO,SAAS,EAAE;AAC3C,iBAAO,KAAK,EAAE;AAAA,QAChB,OAAO;AACL,iBAAO,MAAM,yBAAyB,OAAO,KAAK,EAAE;AACpD,wBAAc;AACd,kBAAQ,KAAK,CAAC;AAAA,QAChB;AAEA,gBAAQ,MAAM;AAAA,MAChB;AAGA,YAAMC,WAAU,YAAY;AAC1B,sBAAc;AACd,YAAI,cAAc;AAChB,cAAI;AACF,kBAAM,aAAa,KAAK;AAAA,UAC1B,QAAQ;AAAA,UAER;AAAA,QACF;AACA,YAAI,WAAW,cAAc;AAC3B,kBAAQ,IAAI,6BAA6B;AAAA,QAC3C;AACA,gBAAa,UAAU;AAAA,MACzB;AAEA,cAAQ,OAAO,wBAAwB;AAGvC,YAAM,iBAAiB,IAAI,eAAe,EAAE,SAAS,CAAC;AACtD,YAAM,UAAU,MAAM,eAAe;AAAA,QACnC,KAAK;AAAA,QACL,QAAQ;AAAA,QACRD,QAAO,aAAa;AAAA,MACtB;AAGA,MAAAA,QAAO,aAAa,QAAQ,EAAE;AAI9B,UAAI,iBAAiB;AAErB,YAAM,mBAAmB,OAAO,WAAmB;AACjD,YAAI,gBAAgB;AAClB,kBAAQ,IAAI,oBAAoB;AAChC,kBAAQ,KAAK,CAAC;AAAA,QAChB;AACA,yBAAiB;AACjB,gBAAQ,IAAI;AAAA,GAAM,MAAM,+BAA+B;AACvD,YAAI;AACF,qBAAW,CAAC,WAAW,CAAC,KAAK,SAAS;AACpC,gBAAI;AACF,oBAAM,EAAE,KAAK;AAAA,YACf,QAAQ;AAAA,YAER;AACA,oBAAQ,OAAO,SAAS;AAAA,UAC1B;AAEA,cAAI;AACF,kBAAM,eAAe,oBAAoB,QAAQ,IAAI,SAAS;AAAA,UAChE,QAAQ;AAAA,UAER;AACA,cAAI,eAAe;AACjB,kBAAM,cAAc,WAAW;AAC/B,4BAAgB;AAAA,UAClB;AACA,2BAAiB,YAAY;AAC7B,kBAAQ,IAAI,0CAA0C;AACtD,gBAAMC,SAAQ;AAAA,QAChB,SAAS,OAAO;AACd,kBAAQ,MAAM,oCAAoC,KAAK;AAAA,QACzD;AACA,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,cAAQ,GAAG,UAAU,MAAM;AACzB,yBAAiB,QAAQ,EAAE,MAAM,QAAQ,KAAK;AAAA,MAChD,CAAC;AAED,cAAQ,GAAG,WAAW,MAAM;AAC1B,yBAAiB,SAAS,EAAE,MAAM,QAAQ,KAAK;AAAA,MACjD,CAAC;AAED,cAAQ,OAAO,2BAA2B;AAG1C,sBAAgB,IAAI,sBAAsB;AAAA,QACxC;AAAA,QACA,WAAW,QAAQ;AAAA,MACrB,CAAC;AAED,YAAM,YAAY,MAAM,cAAc,QAAQ;AAE9C,cAAQ,KAAK;AAEb,UAAI,CAAC,WAAW;AACd,eAAO,MAAM,yCAAyC;AACtD,eAAO,MAAM,EAAE;AACf,eAAO,MAAM,mDAAmD;AAChE,eAAO,MAAM,2DAA2D;AACxE,eAAO,MAAM,oCAAoC;AACjD,eAAO,MAAM,qDAAqD;AAClE,sBAAc;AACd,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,aAAO,KAAK,EAAE;AACd,aAAO,KAAK,6BAAwB;AACpC,aAAO,KAAK,cAAc,QAAQ,IAAI,EAAE;AACxC,UAAI,WAAW;AACb,YAAI,UAAU,SAAS;AACrB,iBAAO,KAAK,uBAAuB,UAAU,KAAK,EAAE;AAAA,QACtD,OAAO;AACL,iBAAO,KAAK,uBAAuB,UAAU,KAAK,EAAE;AAAA,QACtD;AAAA,MACF;AACA,UAAI,WAAW,mBAAmB;AAChC,eAAO;AAAA,UACL,uBAAuB,WAAW,eAAe,oBAAoB,YAAY;AAAA,QACnF;AAAA,MACF;AACA,UAAI,cAAc;AAChB,eAAO,KAAK,0BAA0B;AAAA,MACxC;AACA,aAAO,KAAK,EAAE;AACd,aAAO,KAAK,yCAAyC;AACrD,aAAO,KAAK,uBAAuB;AACnC,aAAO,KAAK,EAAE;AAGd,oBAAc,GAAG,WAAW,OAAO,QAAwB;AACzD,YAAI,IAAI,SAAS,iBAAiB;AAChC,iBAAO,KAAK,6CAA6C;AAEzD,cAAI;AACF,kBAAM,YAAY,IAAI,OAAO;AAAA,cAC3B;AAAA,cACA,QAAQ,KAAK;AAAA,cACb,WAAW,QAAQ;AAAA,cACnB,aAAa,QAAQ;AAAA,cACrB,KAAK,QAAQ,IAAI;AAAA,cACjB,QAAQ;AAAA,YACV,CAAC;AAED,sBAAU,GAAG,WAAW,OAAO,EAAE,SAAAC,SAAQ,MAAM;AAC7C,sBAAQ,IAAIA,SAAQ,IAAI,SAAS;AAEjC,qBAAO,KAAK,cAAcA,SAAQ,GAAG,MAAM,GAAG,CAAC,CAAC,KAAK;AACrD,qBAAO,KAAK,wBAAwB;AACpC,qBAAO,KAAK,sBAAsB,QAAQ,IAAI,EAAE;AAChD,qBAAO,KAAK,EAAE;AAEd,oBAAM,eAAe;AAAA,gBACnBA,SAAQ;AAAA,gBACR,QAAQ,IAAI;AAAA,cACd;AAAA,YACF,CAAC;AAED,sBAAU,GAAG,SAAS,CAAC,UAAiB;AACtC,qBAAO,MAAM,kBAAkB,MAAM,OAAO,EAAE;AAAA,YAChD,CAAC;AAED,sBAAU,GAAG,gBAAgB,CAACC,SAAgB,gBAA4B;AACxE,oBAAM,YAAY,eAAe,YAAY,SAAS;AACtD,oBAAM,YAAY,YAAY,MAAM,YAAY,MAAM,SAAS,YAAY,SAAS,IAAI,MAAM,EAAE,MAAM;AACtG,qBAAO,KAAK,YAAYA,OAAM,GAAG,SAAS,EAAE;AAAA,YAC9C,CAAC;AAED,sBAAU,GAAG,iBAAiB,CAAC,SAAiB;AAC9C,oBAAM,UAAU,KAAK,KAAK;AAC1B,kBAAI,SAAS;AACX,uBAAO,KAAK,YAAY,OAAO,EAAE;AAAA,cACnC;AAAA,YACF,CAAC;AAED,sBAAU,GAAG,uBAAuB,YAAY;AAC9C,qBAAO,KAAK,wCAAwC;AACpD,kBAAI;AACF,sBAAM,UAAU,KAAK;AAAA,cACvB,QAAQ;AAAA,cAER;AAAA,YACF,CAAC;AAED,sBAAU,GAAG,WAAW,YAAY;AAClC,oBAAM,YAAY,UAAU,WAAW,GAAG;AAC1C,kBAAI,WAAW;AACb,wBAAQ,OAAO,SAAS;AACxB,sBAAM,eAAe,sBAAsB,SAAS;AAAA,cACtD;AAEA,qBAAO,KAAK,gBAAgB;AAC5B,qBAAO,KAAK,sBAAsB,QAAQ,IAAI,EAAE;AAChD,qBAAO,KAAK,EAAE;AACd,kBAAI,QAAQ,SAAS,GAAG;AACtB,uBAAO,KAAK,qCAAqC;AACjD,uBAAO,KAAK,EAAE;AAAA,cAChB;AAAA,YACF,CAAC;AAED,kBAAM,UAAU,MAAM;AAAA,UACxB,SAAS,OAAO;AACd,kBAAM,eACJ,iBAAiB,QAAQ,MAAM,UAAU;AAC3C,mBAAO,MAAM,4BAA4B,YAAY,EAAE;AACvD,kBAAM,eAAe,eAAe,YAAY;AAAA,UAClD;AAAA,QACF;AAEA,YAAI,IAAI,SAAS,kBAAkB,IAAI,WAAW;AAChD,gBAAM,eAAe,QAAQ,IAAI,IAAI,SAAS;AAC9C,cAAI,cAAc;AAChB,mBAAO,KAAK,oBAAoB,IAAI,UAAU,MAAM,GAAG,CAAC,CAAC,6BAA6B;AACtF,gBAAI;AACF,oBAAM,aAAa,KAAK;AAAA,YAC1B,QAAQ;AAAA,YAER;AAAA,UACF;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH,SAAS,OAAO;AACd,oBAAc;AACd,UAAI,iBAAiB,oBAAoB;AACvC,gBAAQ,KAAK;AACb,eAAO,MAAM,MAAM,OAAO;AAC1B,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,cAAQ,KAAK,iBAAiB;AAC9B,aAAO;AAAA,QACL,GAAG,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,MAC7D;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAEH,SAAO;AACT;;;AQ1fA,SAAS,WAAAC,gBAAe;AACxB,YAAYC,SAAQ;AAIb,SAAS,oBAA6B;AAC3C,QAAM,UAAU,IAAIC,SAAQ,MAAM;AAElC,UAAQ,YAAY,yBAAyB,EAAE,OAAO,YAAY;AAChE,UAAM,SAAS,IAAI,OAAO;AAE1B,QAAI;AACF,YAAM,MAAM,YAAY;AAExB,UAAI,QAAQ,MAAM;AAChB,eAAO,KAAK,sBAAsB;AAClC;AAAA,MACF;AAEA,UAAI,CAAC,eAAe,GAAG,GAAG;AACxB,eAAO,KAAK,4CAA4C;AACxD,YAAI;AAAE,UAAG,eAAW,QAAQ;AAAA,QAAG,QAAQ;AAAA,QAAqB;AAC5D;AAAA,MACF;AAEA,UAAI;AAWF,gBAAQ,KAAK,KAAK,SAAS;AAC3B,eAAO,KAAK,oCAAoC,GAAG,GAAG;AAKtD,YAAI,WAAW;AACf,YAAI,iBAAiB;AACrB,eAAO,WAAW,IAAI;AACpB,gBAAM,IAAI,QAAQ,CAACC,aAAY,WAAWA,UAAS,GAAG,CAAC;AAEvD,cAAI,CAAC,cAAc,GAAG;AAEpB,6BAAiB;AACjB;AAAA,UACF;AAEA,cAAI,CAAC,eAAe,GAAG,GAAG;AAExB;AAAA,UACF;AAEA;AAAA,QACF;AAEA,YAAI,YAAY,MAAM,CAAC,gBAAgB;AAIrC,gBAAMC,cAAa,YAAY;AAC/B,cAAIA,gBAAe,OAAO,eAAe,GAAG,GAAG;AAC7C,mBAAO,KAAK,iDAAiD;AAC7D,oBAAQ,KAAK,KAAK,SAAS;AAAA,UAC7B;AAAA,QACF;AAEA,eAAO,KAAK,gBAAgB;AAAA,MAC9B,SAAS,KAAU;AACjB,YAAI,IAAI,SAAS,SAAS;AACxB,iBAAO,KAAK,4CAA4C;AAAA,QAC1D,OAAO;AACL,gBAAM;AAAA,QACR;AAAA,MACF;AAIA,YAAM,aAAa,YAAY;AAC/B,UAAI,eAAe,KAAK;AACtB,YAAI;AAAE,UAAG,eAAW,QAAQ;AAAA,QAAG,QAAQ;AAAA,QAAqB;AAAA,MAC9D;AAAA,IACF,SAAS,OAAO;AACd,aAAO;AAAA,QACL,0BAA0B,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,MACpF;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAED,SAAO;AACT;;;AChGA,SAAS,WAAAC,gBAAe;AAMjB,SAAS,sBAA+B;AAC7C,QAAM,UAAU,IAAIC,SAAQ,QAAQ;AAEpC,UACG,YAAY,wBAAwB,EACpC,OAAO,YAAY;AAClB,UAAMC,UAAS,IAAI,OAAO;AAC1B,UAAM,SAAS,IAAI,OAAO;AAE1B,QAAI;AACF,YAAM,WAAW;AAAA,QACfA,QAAO,eAAe;AAAA,QACtBA,QAAO,mBAAmB;AAAA,MAC5B;AAGA,YAAM,UAAU,MAAM,eAAe,UAAUA,OAAM;AACrD,UAAI,CAAC,SAAS;AACZ,eAAO,KAAK,2BAA2B;AACvC,eAAO,KAAK,wCAAwC;AACpD;AAAA,MACF;AAEA,YAAM,EAAE,KAAK,IAAI;AAEjB,aAAO,KAAK,SAAS,KAAK,KAAK,EAAE;AAEjC,YAAM,YAAYA,QAAO,aAAa;AACtC,UAAI,CAAC,WAAW;AACd,eAAO,KAAK,yBAAyB;AACrC,eAAO,KAAK,iDAAiD;AAC7D;AAAA,MACF;AAEA,YAAM,iBAAiB,IAAI,eAAe,EAAE,SAAS,CAAC;AACtD,YAAM,UAAU,MAAM,eAAe,WAAW,SAAS;AAEzD,UAAI,CAAC,SAAS;AACZ,eAAO,KAAK,eAAe,SAAS,cAAc;AAClD;AAAA,MACF;AAEA,aAAO,KAAK,YAAY,QAAQ,IAAI,KAAK,QAAQ,EAAE,GAAG;AACtD,aAAO,KAAK,WAAW,QAAQ,MAAM,EAAE;AACvC,aAAO,KAAK,cAAc,QAAQ,YAAY,EAAE;AAAA,IAClD,SAAS,OAAO;AACd,aAAO;AAAA,QACL,yBAAyB,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,MACnF;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAEH,SAAO;AACT;;;AC5DA,SAAS,WAAAC,gBAAe;;;ACAxB,YAAYC,eAAc;AAEnB,SAAS,OAAO,UAAmC;AACxD,QAAM,KAAc,0BAAgB;AAAA,IAClC,OAAO,QAAQ;AAAA,IACf,QAAQ,QAAQ;AAAA,EAClB,CAAC;AAED,SAAO,IAAI,QAAQ,CAACC,aAAY;AAC9B,OAAG,SAAS,UAAU,CAAC,WAAW;AAChC,SAAG,MAAM;AACT,MAAAA,SAAQ,MAAM;AAAA,IAChB,CAAC;AAAA,EACH,CAAC;AACH;AAEO,SAAS,aAAa,UAAmC;AAC9D,QAAM,KAAc,0BAAgB;AAAA,IAClC,OAAO,QAAQ;AAAA,IACf,QAAQ,QAAQ;AAAA,EAClB,CAAC;AAED,SAAO,IAAI,QAAQ,CAACA,aAAY;AAC9B,YAAQ,OAAO,MAAM,QAAQ;AAE7B,QAAI,QAAQ,MAAM,OAAO;AACvB,cAAQ,MAAM,WAAW,IAAI;AAAA,IAC/B;AAEA,QAAI,WAAW;AAEf,UAAM,SAAS,CAAC,SAAiB;AAC/B,YAAM,IAAI,KAAK,SAAS;AAExB,UAAI,MAAM,QAAQ,MAAM,MAAM;AAC5B,gBAAQ,MAAM,eAAe,QAAQ,MAAM;AAC3C,YAAI,QAAQ,MAAM,OAAO;AACvB,kBAAQ,MAAM,WAAW,KAAK;AAAA,QAChC;AACA,gBAAQ,OAAO,MAAM,IAAI;AACzB,WAAG,MAAM;AACT,QAAAA,SAAQ,QAAQ;AAAA,MAClB,WAAW,MAAM,KAAU;AAEzB,gBAAQ,KAAK,CAAC;AAAA,MAChB,WAAW,MAAM,UAAY,MAAM,MAAM;AAEvC,YAAI,SAAS,SAAS,GAAG;AACvB,qBAAW,SAAS,MAAM,GAAG,EAAE;AAAA,QACjC;AAAA,MACF,OAAO;AACL,oBAAY;AAAA,MACd;AAAA,IACF;AAEA,YAAQ,MAAM,GAAG,QAAQ,MAAM;AAC/B,YAAQ,MAAM,OAAO;AAAA,EACvB,CAAC;AACH;;;ADpDO,SAAS,qBAA8B;AAC5C,QAAM,UAAU,IAAIC,SAAQ,OAAO;AAEnC,UAAQ,YAAY,8BAA8B,EAAE,OAAO,YAAY;AACrE,UAAMC,UAAS,IAAI,OAAO;AAC1B,UAAM,SAAS,IAAI,OAAO;AAE1B,QAAI;AACF,MAAAA,QAAO,qBAAqB;AAE5B,YAAM,WAAW;AAAA,QACfA,QAAO,eAAe;AAAA,QACtBA,QAAO,mBAAmB;AAAA,MAC5B;AAEA,YAAM,QAAQ,MAAM,OAAO,SAAS;AACpC,YAAM,WAAW,MAAM,aAAa,YAAY;AAEhD,UAAI,CAAC,SAAS,CAAC,UAAU;AACvB,eAAO,MAAM,iCAAiC;AAC9C,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,SAAS,KAAK,mBAAmB;AAAA,QAC7D;AAAA,QACA;AAAA,MACF,CAAC;AAED,UAAI,OAAO;AACT,eAAO,MAAM,iBAAiB,MAAM,OAAO,EAAE;AAC7C,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,UAAI,KAAK,MAAM;AACb,eAAO,KAAK,gBAAgB,KAAK,KAAK,KAAK,EAAE;AAG7C,YAAI,KAAK,SAAS;AAChB,UAAAA,QAAO,WAAW;AAAA,YAChB,aAAa,KAAK,QAAQ;AAAA,YAC1B,cAAc,KAAK,QAAQ;AAAA,UAC7B,CAAC;AACD,iBAAO,KAAK,eAAe;AAAA,QAC7B;AAEA,eAAO,KAAK,EAAE;AACd,eAAO,KAAK,aAAa;AACzB,eAAO,KAAK,gDAAgD;AAC5D,eAAO,KAAK,6BAA6B;AACzC,eAAO,KAAK,+DAA+D;AAAA,MAC7E;AAAA,IACF,SAAS,OAAO;AACd,UAAI,iBAAiB,oBAAoB;AACvC,eAAO,MAAM,MAAM,OAAO;AAC1B,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,aAAO;AAAA,QACL,iBAAiB,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,MAC3E;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAED,SAAO;AACT;;;AEtEA,SAAS,WAAAC,gBAAe;AAKjB,SAAS,sBAA+B;AAC7C,QAAM,UAAU,IAAIC,SAAQ,QAAQ;AAEpC,UAAQ,YAAY,sDAAsD,EAAE,OAAO,YAAY;AAC7F,UAAMC,UAAS,IAAI,OAAO;AAC1B,UAAM,SAAS,IAAI,OAAO;AAE1B,UAAM,UAAUA,QAAO,iBAAiB;AACxC,QAAI,CAAC,SAAS;AACZ,aAAO,KAAK,0BAA0B;AACtC;AAAA,IACF;AAKA,QAAI;AACF,YAAM,WAAW;AAAA,QACfA,QAAO,eAAe;AAAA,QACtBA,QAAO,mBAAmB;AAAA,MAC5B;AAEA,YAAM,WAAW,MAAM,eAAe,UAAUA,OAAM;AACtD,UAAI,UAAU;AACZ,cAAM,EAAE,MAAM,IAAI,MAAM,SAAS,KAAK,QAAQ,EAAE,OAAO,SAAS,CAAC;AACjE,YAAI,OAAO;AACT,iBAAO,KAAK,8CAA8C,MAAM,OAAO,EAAE;AACzE,iBAAO,KAAK,4FAA4F;AAAA,QAC1G,OAAO;AACL,iBAAO,KAAK,8BAA8B;AAAA,QAC5C;AAAA,MACF;AAAA,IACF,QAAQ;AAEN,aAAO,KAAK,qDAAqD;AAAA,IACnE;AAEA,IAAAA,QAAO,mBAAmB;AAC1B,IAAAA,QAAO,eAAe;AACtB,WAAO,KAAK,0BAA0B;AAAA,EACxC,CAAC;AAED,SAAO;AACT;;;AChDA,SAAS,WAAAC,gBAAe;AAMjB,SAAS,sBAA+B;AAC7C,QAAM,UAAU,IAAIC,SAAQ,QAAQ;AAEpC,UAAQ,YAAY,iCAAiC,EAAE,OAAO,YAAY;AACxE,UAAMC,UAAS,IAAI,OAAO;AAC1B,UAAM,SAAS,IAAI,OAAO;AAE1B,QAAI;AACF,MAAAA,QAAO,qBAAqB;AAE5B,YAAM,WAAW;AAAA,QACfA,QAAO,eAAe;AAAA,QACtBA,QAAO,mBAAmB;AAAA,MAC5B;AAEA,aAAO,KAAK,iCAAiC;AAC7C,aAAO,KAAK,EAAE;AAEd,YAAM,QAAQ,MAAM,OAAO,SAAS;AACpC,UAAI,CAAC,OAAO;AACV,eAAO,MAAM,mBAAmB;AAChC,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,YAAM,WAAW,MAAM,aAAa,YAAY;AAChD,UAAI,CAAC,UAAU;AACb,eAAO,MAAM,sBAAsB;AACnC,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,UAAI,SAAS,SAAS,GAAG;AACvB,eAAO,MAAM,wCAAwC;AACrD,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,YAAM,kBAAkB,MAAM,aAAa,oBAAoB;AAC/D,UAAI,aAAa,iBAAiB;AAChC,eAAO,MAAM,wBAAwB;AACrC,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,SAAS,KAAK,OAAO;AAAA,QACjD;AAAA,QACA;AAAA,MACF,CAAC;AAED,UAAI,OAAO;AACT,eAAO,MAAM,kBAAkB,MAAM,OAAO,EAAE;AAC9C,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,UAAI,KAAK,MAAM;AACb,eAAO,KAAK,EAAE;AACd,eAAO,KAAK,uBAAuB,KAAK,KAAK,KAAK,EAAE;AAEpD,YAAI,KAAK,SAAS;AAChB,UAAAA,QAAO,WAAW;AAAA,YAChB,aAAa,KAAK,QAAQ;AAAA,YAC1B,cAAc,KAAK,QAAQ;AAAA,UAC7B,CAAC;AACD,iBAAO,KAAK,yBAAyB;AAAA,QACvC;AAEA,eAAO,KAAK,EAAE;AACd,eAAO,KAAK,aAAa;AACzB,eAAO,KAAK,gDAAgD;AAC5D,eAAO,KAAK,6BAA6B;AACzC,eAAO,KAAK,+DAA+D;AAAA,MAC7E;AAAA,IACF,SAAS,OAAO;AACd,UAAI,iBAAiB,oBAAoB;AACvC,eAAO,MAAM,MAAM,OAAO;AAC1B,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,aAAO;AAAA,QACL,kBAAkB,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,MAC5E;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAED,SAAO;AACT;;;ACxFA,SAAS,WAAAC,gBAAe;AAKjB,SAAS,qBAA8B;AAC5C,QAAM,UAAU,IAAIC,SAAQ,OAAO;AAEnC,UACG,YAAY,gDAAgD,EAC5D,OAAO,YAAY;AAClB,UAAMC,UAAS,IAAI,OAAO;AAC1B,UAAM,SAAS,IAAI,OAAO;AAE1B,QAAI;AACF,aAAO,KAAK,kBAAkB;AAC9B,aAAO,KAAK,kBAAkB;AAC9B,aAAO,KAAK,EAAE;AAGd,aAAO,KAAK,gCAAgC;AAC5C,aAAO,KAAK,EAAE;AACd,aAAO,KAAK,4CAA4C;AACxD,aAAO,KAAK,6CAA6C;AACzD,aAAO,KAAK,EAAE;AAEd,YAAM,YAAY,MAAM,OAAO,cAAc;AAC7C,UAAI,CAAC,WAAW;AACd,eAAO,MAAM,iCAAiC;AAC9C,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAGA,UAAI,UAAU,SAAS,aAAa,KAAK,UAAU,WAAW,MAAM,GAAG;AACrE,eAAO,MAAM,EAAE;AACf,eAAO,MAAM,qDAAqD;AAClE,eAAO,MAAM,EAAE;AACf,eAAO,MAAM,2BAA2B;AACxC,eAAO,MAAM,2CAA2C;AACxD,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAGA,UAAI,CAAC,kBAAkB,KAAK,SAAS,GAAG;AACtC,eAAO,MAAM,EAAE;AACf,eAAO,MAAM,4BAA4B;AACzC,eAAO,MAAM,mEAAmE;AAChF,eAAO,MAAM,EAAE;AACf,eAAO,MAAM,qDAAqD;AAClE,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,YAAM,MAAM,WAAW,SAAS;AAChC,aAAO,KAAK,yBAAoB;AAChC,aAAO,KAAK,EAAE;AAGd,aAAO,KAAK,8BAA8B;AAC1C,aAAO,KAAK,EAAE;AACd,aAAO,KAAK,4CAA4C;AACxD,aAAO,KAAK,4DAA4D;AACxE,aAAO,KAAK,EAAE;AAEd,YAAM,UAAU,MAAM,OAAO,YAAY;AACzC,UAAI,CAAC,SAAS;AACZ,eAAO,MAAM,+BAA+B;AAC5C,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,MAAAA,QAAO,uBAAuB,EAAE,KAAK,QAAQ,CAAC;AAE9C,aAAO,KAAK,EAAE;AACd,aAAO,KAAK,0CAAqC;AACjD,aAAO,KAAK,EAAE;AACd,aAAO,KAAK,aAAa;AACzB,aAAO,KAAK,iEAAiE;AAC7E,aAAO,KAAK,2DAA2D;AAAA,IACzE,SAAS,OAAO;AACd,aAAO;AAAA,QACL,iBAAiB,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,MAC3E;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAEH,SAAO;AACT;;;ACtFA,SAAS,WAAAC,gBAAe;AAGxB,SAAS,cAAAC,aAAY,iBAAAC,sBAAqB;AAC1C,SAAS,QAAAC,OAAM,eAAe;AAEvB,SAAS,2BAAoC;AAClD,QAAM,UAAU,IAAIC,SAAQ,cAAc;AAE1C,UACG,YAAY,oDAAoD,EAChE,OAAO,YAAY;AAClB,UAAMC,UAAS,IAAI,OAAO;AAC1B,UAAM,SAAS,IAAI,OAAO;AAE1B,QAAI;AACF,MAAAA,QAAO,qBAAqB;AAE5B,YAAM,cAAcA,QAAO,eAAe;AAC1C,YAAM,kBAAkBA,QAAO,mBAAmB;AAGlD,YAAM,YAAY,QAAQ,QAAQ,IAAI,GAAG,QAAQ,QAAQ;AACzD,UAAI,CAACJ,YAAW,SAAS,GAAG;AAC1B,eAAO,MAAM,uCAAuC;AACpD,eAAO,MAAM,EAAE;AACf,eAAO,MAAM,kEAAkE;AAC/E,eAAO,MAAM,iBAAiB;AAC9B,eAAO,MAAM,2BAA2B;AACxC,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,YAAM,UAAUE,MAAK,WAAW,MAAM;AAGtC,UAAIF,YAAW,OAAO,GAAG;AACvB,eAAO,KAAK,0DAA0D;AAAA,MACxE;AAEA,YAAM,aAAa;AAAA,QACjB,4BAA4B,WAAW;AAAA,QACvC,iCAAiC,eAAe;AAAA,QAChD;AAAA,MACF,EAAE,KAAK,IAAI;AAEX,MAAAC,eAAc,SAAS,UAAU;AAGjC,MAAAG,QAAO,qBAAqB,SAAS;AAErC,aAAO,KAAK,EAAE;AACd,aAAO,KAAK,qCAAqC;AACjD,aAAO,KAAK,cAAc,SAAS,EAAE;AACrC,aAAO,KAAK,WAAW,OAAO,EAAE;AAChC,aAAO,KAAK,EAAE;AACd,aAAO,KAAK,qEAAqE;AACjF,aAAO,KAAK,2DAA2D;AAAA,IACzE,SAAS,OAAO;AACd,UAAI,iBAAiB,oBAAoB;AACvC,eAAO,MAAM,MAAM,OAAO;AAC1B,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,aAAO;AAAA,QACL,wBAAwB,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,MAClF;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF,CAAC;AAEH,SAAO;AACT;;;ACtEA,SAAS,WAAAC,gBAAe;AACxB,YAAYC,SAAQ;AACpB,YAAYC,WAAU;AACtB,YAAYC,SAAQ;AACpB,SAAS,YAAAC,iBAAgB;AAalB,SAAS,qBAA8B;AAC5C,QAAM,UAAU,IAAIC,SAAQ,OAAO;AAEnC,UACG,YAAY,8DAA8D,EAC1E,OAAO,aAAa,0BAA0B,EAC9C,OAAO,gBAAgB,qCAAqC,EAC5D,OAAO,aAAa,0BAA0B,EAC9C,OAAO,OAAO,YAA0B;AACvC,UAAM,SAAS,IAAI,OAAO;AAE1B,QAAI,CAAC,QAAQ,KAAK;AAChB,aAAO,KAAK,YAAY;AACxB,aAAO,KAAK,2CAA2C;AACvD,aAAO,KAAK,kCAAkC;AAC9C,UAAI,CAAC,QAAQ,QAAQ;AACnB,eAAO,KAAK,uEAAuE;AAAA,MACrF;AACA,UAAI,CAAC,QAAQ,WAAW;AACtB,eAAO,KAAK,2CAA2C;AAAA,MACzD;AACA,aAAO,KAAK,4CAA4C;AACxD,aAAO,KAAK,2CAA2C;AACvD,aAAO,KAAK,EAAE;AAEd,YAAM,YAAY,MAAM,YAAY,uBAAuB;AAC3D,UAAI,CAAC,WAAW;AACd,eAAO,KAAK,UAAU;AACtB;AAAA,MACF;AACA,aAAO,KAAK,EAAE;AAAA,IAChB;AAGA,WAAO,KAAK,qCAAqC;AAEjD,UAAM,MAAM,YAAY;AACxB,QAAI,QAAQ,QAAQ,eAAe,GAAG,GAAG;AACvC,UAAI;AACF,gBAAQ,KAAK,KAAK,SAAS;AAC3B,eAAO,KAAK,sCAAsC,GAAG,GAAG;AAExD,cAAM,IAAI,QAAQ,CAACC,aAAY,WAAWA,UAAS,GAAI,CAAC;AAAA,MAC1D,QAAQ;AACN,eAAO,KAAK,2BAA2B;AAAA,MACzC;AAAA,IACF,OAAO;AACL,aAAO,KAAK,uBAAuB;AAAA,IACrC;AAEA,QAAI;AAAE,MAAG,eAAW,QAAQ;AAAA,IAAG,QAAQ;AAAA,IAAqB;AAG5D,QAAI;AACF,MAAAC,UAAS,wCAAwC,EAAE,OAAO,SAAS,CAAC;AACpE,aAAO,KAAK,iCAAiC;AAAA,IAC/C,QAAQ;AAAA,IAAoB;AAE5B,QAAI;AACF,MAAAA,UAAS,qCAAqC,EAAE,OAAO,SAAS,CAAC;AACjE,aAAO,KAAK,yBAAyB;AAAA,IACvC,QAAQ;AAAA,IAAoB;AAG5B,QAAI;AACF,YAAM,OAAOA,UAAS,qBAAqB,EAAE,OAAO,OAAO,CAAC,EAAE,SAAS,EAAE,KAAK;AAC9E,UAAI,MAAM;AACR,mBAAWC,QAAO,KAAK,MAAM,IAAI,GAAG;AAClC,cAAI;AAAE,oBAAQ,KAAK,SAASA,MAAK,EAAE,GAAG,SAAS;AAAA,UAAG,QAAQ;AAAA,UAAqB;AAAA,QACjF;AACA,eAAO,KAAK,qBAAqB;AAAA,MACnC;AAAA,IACF,QAAQ;AAAA,IAA0B;AAGlC,WAAO,KAAK,yCAAyC;AAErD,QAAI,QAAQ,GAAG;AACb,UAAI;AACF,cAAM,cAAcD,UAAS,6BAA6B,EAAE,UAAU,QAAQ,CAAC;AAC/E,YAAI,YAAY,SAAS,cAAc,KAAK,YAAY,SAAS,GAAG,GAAG;AACrE,UAAAA,UAAS,gCAAgC,EAAE,OAAO,UAAU,CAAC;AAC7D,iBAAO,KAAK,8BAA8B;AAAA,QAC5C,OAAO;AACL,iBAAO,KAAK,oBAAoB;AAAA,QAClC;AAAA,MACF,QAAQ;AACN,eAAO,KAAK,oBAAoB;AAAA,MAClC;AAGA,UAAI;AACF,QAAAA,UAAS,mCAAmC,EAAE,OAAO,SAAS,CAAC;AAC/D,eAAO,KAAK,wBAAwB;AAAA,MACtC,QAAQ;AAAA,MAAoB;AAAA,IAC9B,OAAO;AACL,aAAO,KAAK,wBAAwB;AAAA,IACtC;AAGA,QAAI,QAAQ,QAAQ;AAClB,aAAO,KAAK,uCAAuC;AAAA,IACrD,OAAO;AACL,YAAM,gBAAgB,MAAM;AAAA,IAC9B;AAGA,QAAI,QAAQ,WAAW;AACrB,aAAO,KAAK,6CAA6C;AAAA,IAC3D,OAAO;AACL,aAAO,KAAK,6BAA6B;AACzC,UAAI;AACF,QAAAA,UAAS,mBAAmB,EAAE,OAAO,SAAS,CAAC;AAC/C,QAAAA,UAAS,wBAAwB,EAAE,OAAO,UAAU,CAAC;AACrD,eAAO,KAAK,mBAAmB;AAAA,MACjC,QAAQ;AACN,YAAI;AACF,UAAAA,UAAS,eAAe,EAAE,OAAO,SAAS,CAAC;AAC3C,iBAAO,KAAK,iEAAiE;AAAA,QAC/E,QAAQ;AACN,iBAAO,KAAK,4BAA4B;AAAA,QAC1C;AAAA,MACF;AAGA,YAAM,iBAAsB,WAAQ,YAAQ,GAAG,WAAW,OAAO;AACjE,YAAM,iBAAsB,WAAQ,YAAQ,GAAG,SAAS;AAExD,UAAO,eAAW,cAAc,GAAG;AACjC,QAAG,WAAO,gBAAgB,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAC1D,eAAO,KAAK,4CAA4C;AAAA,MAC1D;AACA,UAAO,eAAW,cAAc,GAAG;AACjC,QAAG,WAAO,gBAAgB,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAC1D,eAAO,KAAK,6CAA6C;AAAA,MAC3D;AAAA,IACF;AAGA,WAAO,KAAK,8BAA8B;AAE1C,UAAM,YAAiB,WAAQ,YAAQ,GAAG,aAAa;AACvD,UAAM,YAAiB,WAAQ,YAAQ,GAAG,aAAa;AAEvD,QAAO,eAAW,SAAS,GAAG;AAC5B,MAAG,WAAO,WAAW,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AACrD,aAAO,KAAK,gDAAgD;AAAA,IAC9D,OAAO;AACL,aAAO,KAAK,iCAAiC;AAAA,IAC/C;AAEA,QAAO,eAAW,SAAS,GAAG;AAC5B,MAAG,WAAO,WAAW,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AACrD,aAAO,KAAK,oCAAoC;AAAA,IAClD;AAKA,WAAO,KAAK,iCAAiC;AAC7C,QAAI;AACF,MAAAA,UAAS,sCAAsC,EAAE,OAAO,SAAS,CAAC;AAClE,MAAAA,UAAS,2CAA2C,EAAE,OAAO,UAAU,CAAC;AACxE,aAAO,KAAK,yBAAyB;AAAA,IACvC,QAAQ;AACN,aAAO,KAAK,oCAAoC;AAAA,IAClD;AAGA,WAAO,KAAK,sCAAsC;AAClD,QAAI;AACF,MAAAA,UAAS,wBAAwB,EAAE,OAAO,SAAS,CAAC;AACpD,MAAAA,UAAS,6BAA6B,EAAE,OAAO,UAAU,CAAC;AAC1D,aAAO,KAAK,8BAA8B;AAAA,IAC5C,QAAQ;AACN,aAAO,KAAK,yCAAyC;AAAA,IACvD;AAEA,WAAO,KAAK,EAAE;AACd,WAAO,KAAK,kCAAkC;AAC9C,WAAO,KAAK,EAAE;AACd,WAAO,KAAK,aAAa;AACzB,WAAO,KAAK,4CAA4C;AACxD,WAAO,KAAK,uBAAuB;AACnC,WAAO,KAAK,uBAAuB;AACnC,WAAO,KAAK,uBAAuB;AAAA,EACrC,CAAC;AAEH,SAAO;AACT;AAEA,eAAe,gBAAgB,QAA+B;AAC5D,QAAM,YAAiB,WAAQ,YAAQ,GAAG,aAAa;AACvD,QAAM,aAAkB,WAAK,WAAW,aAAa;AAErD,MAAI,CAAI,eAAW,UAAU,GAAG;AAC9B,WAAO,KAAK,kDAAkD;AAC9D;AAAA,EACF;AAEA,MAAI;AACJ,MAAI;AACF,iBAAa,KAAK,MAAS,iBAAa,YAAY,OAAO,CAAC;AAAA,EAC9D,QAAQ;AACN,WAAO,KAAK,iDAAiD;AAC7D;AAAA,EACF;AAEA,QAAM,cAAc,WAAW;AAC/B,QAAM,UAAU,WAAW;AAC3B,QAAM,cAAc,WAAW,eAAe;AAC9C,QAAM,eAAe,WAAW,eAAe;AAE/C,MAAI,CAAC,eAAe,CAAC,WAAW,CAAC,aAAa;AAC5C,WAAO,KAAK,iDAAiD;AAC7D;AAAA,EACF;AAEA,SAAO,KAAK,oCAAoC;AAGhD,QAAM,WAAW,qBAAqB,aAAa,OAAO;AAE1D,MAAI,QAAQ;AACZ,MAAI,cAAc;AAChB,UAAM,EAAE,KAAK,IAAI,MAAM,SAAS,KAAK,WAAW;AAAA,MAC9C,cAAc;AAAA,MACd,eAAe;AAAA,IACjB,CAAC;AACD,QAAI,MAAM,SAAS;AACjB,cAAQ,KAAK,QAAQ;AAAA,IACvB;AAAA,EACF;AAGA,QAAM,UAAU;AAAA,IACd,QAAQ;AAAA,IACR,eAAe,UAAU,KAAK;AAAA,IAC9B,QAAQ;AAAA,EACV;AAEA,MAAI;AACF,UAAM,MAAM,MAAM,MAAM,GAAG,WAAW,iCAAiC;AAAA,MACrE,QAAQ;AAAA,MACR;AAAA,IACF,CAAC;AACD,WAAO,KAAK,IAAI,KAAK,4BAA4B,0BAA0B;AAAA,EAC7E,QAAQ;AACN,WAAO,KAAK,0BAA0B;AAAA,EACxC;AAGA,MAAI;AACF,UAAM,MAAM,MAAM,MAAM,GAAG,WAAW,8BAA8B;AAAA,MAClE,QAAQ;AAAA,MACR;AAAA,IACF,CAAC;AACD,WAAO,KAAK,IAAI,KAAK,uDAAuD,uBAAuB;AAAA,EACrG,QAAQ;AACN,WAAO,KAAK,uBAAuB;AAAA,EACrC;AAGA,MAAI;AACF,UAAM,MAAM,MAAM,MAAM,GAAG,WAAW,qCAAqC;AAAA,MACzE,QAAQ;AAAA,MACR;AAAA,IACF,CAAC;AACD,WAAO,KAAK,IAAI,KAAK,gCAAgC,8BAA8B;AAAA,EACrF,QAAQ;AACN,WAAO,KAAK,8BAA8B;AAAA,EAC5C;AACF;;;A1BzRA,IAAM,aAAa,cAAc,YAAY,GAAG;AAChD,IAAM,YAAYE,SAAQ,UAAU;AAGpC,OAAO,EAAE,MAAMC,SAAQ,WAAW,SAAS,GAAG,OAAO,KAAK,CAAC;AAG3D,IAAM,cAAc,KAAK;AAAA,EACvBC,cAAaD,SAAQ,WAAW,iBAAiB,GAAG,OAAO;AAC7D;AACA,IAAM,UAAU,YAAY,WAAW;AAsBvC,IAAM,UAAU,IAAIE,UAAQ;AAE5B,QACG,KAAK,YAAY,EACjB,YAAY,oCAAoC,EAChD,QAAQ,OAAO;AAElB,QAAQ,WAAW,mBAAmB,CAAC;AACvC,QAAQ,WAAW,mBAAmB,CAAC;AACvC,QAAQ,WAAW,kBAAkB,CAAC;AACtC,QAAQ,WAAW,oBAAoB,CAAC;AACxC,QAAQ,WAAW,mBAAmB,CAAC;AACvC,QAAQ,WAAW,oBAAoB,CAAC;AACxC,QAAQ,WAAW,oBAAoB,CAAC;AACxC,QAAQ,WAAW,yBAAyB,CAAC;AAC7C,QAAQ,WAAW,mBAAmB,CAAC;AAGvC,IAAI,QAAQ,KAAK,CAAC,GAAG,SAAS,YAAY,KAAK,QAAQ,KAAK,CAAC,GAAG,SAAS,WAAW,KAAK,QAAQ,KAAK,CAAC,GAAG,SAAS,WAAW,GAAG;AAC/H,UAAQ,MAAM;AAChB;","names":["isPermissionMode","resolve","dirname","readFileSync","path","resolve","hostname","EventEmitter","EventEmitter","os","resolve","prompt","existingNames","import_clautunnel_shared","existsSync","readFileSync","writeFileSync","mkdirSync","join","homedir","path","import_clautunnel_shared","EventEmitter","prompt","Command","import_clautunnel_shared","EventEmitter","EventEmitter","config","readdirSync","path","os","resolve","process","spawn","execSync","existsSync","mkdirSync","writeFileSync","join","homedir","packageJson","resolve","fs","path","os","execSync","config","cleanup","session","prompt","Command","fs","Command","resolve","currentPid","Command","Command","config","Command","readline","resolve","Command","config","Command","Command","config","Command","Command","config","Command","Command","config","Command","existsSync","writeFileSync","join","Command","config","Command","fs","path","os","execSync","Command","resolve","execSync","pid","dirname","resolve","readFileSync","Command"]}
1
+ {"version":3,"sources":["../../../packages/shared/dist/types/message.js","../../../packages/shared/dist/types/session.js","../../../packages/shared/dist/types/machine.js","../../../packages/shared/dist/types/presence.js","../../../packages/shared/src/types/index.ts","../../../packages/shared/src/constants/events.ts","../../../packages/shared/src/constants/message-types.ts","../../../packages/shared/src/constants/index.ts","../../../packages/shared/src/utils/permission-mode.ts","../../../packages/shared/src/utils/index.ts","../../../packages/shared/src/index.ts","../src/index.ts","../src/utils/config.ts","../src/utils/logger.ts","../src/realtime/client.ts","../src/realtime/utils.ts","../src/daemon/session.ts","../src/daemon/machine.ts","../src/daemon/daemon.ts","../src/daemon/sdk-session.ts","../src/daemon/config-manager.ts","../src/commands/start.ts","../src/realtime/machine-client.ts","../src/utils/spinner.ts","../src/utils/supabase.ts","../src/utils/sleep-prevention.ts","../src/mobile/mobile-server.ts","../src/utils/pid.ts","../src/utils/claude-auth.ts","../src/commands/stop.ts","../src/commands/status.ts","../src/commands/login.ts","../src/utils/prompt.ts","../src/commands/logout.ts","../src/commands/signup.ts","../src/commands/setup.ts","../src/commands/mobile-setup.ts","../src/commands/reset.ts"],"sourcesContent":["\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\n//# sourceMappingURL=message.js.map","\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\n//# sourceMappingURL=session.js.map","\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\n//# sourceMappingURL=machine.js.map","\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\n//# sourceMappingURL=presence.js.map","export * from './message.js';\nexport * from './session.js';\nexport * from './machine.js';\nexport * from './presence.js';\n","export const REALTIME_CHANNELS = {\n sessionOutput: (sessionId: string) => `session:${sessionId}:output`,\n sessionInput: (sessionId: string) => `session:${sessionId}:input`,\n sessionPresence: (sessionId: string) => `session:${sessionId}:presence`,\n machinePresence: (machineId: string) => `machine:${machineId}:presence`,\n machineInput: (machineId: string) => `machine:${machineId}:input`,\n machineOutput: (machineId: string) => `machine:${machineId}:output`,\n} as const;\n","// Source of truth for message types.\n// TypeScript types are derived from these arrays via (typeof X)[number].\n// Tests import these arrays directly — no manual duplication needed.\n\nexport const REALTIME_MESSAGE_TYPES = [\n 'output',\n 'input',\n 'error',\n 'system',\n 'mode',\n 'mode-change',\n 'commands',\n 'commands-request',\n 'model',\n 'model-change',\n 'models',\n 'models-request',\n 'mobile-disconnect',\n 'interactive-request',\n 'interactive-response',\n 'interactive-apply',\n 'interactive-confirm',\n 'cancel-request',\n 'clear-request',\n 'resume-request',\n 'resume-history',\n 'user-question',\n 'user-answer',\n 'permission-request',\n 'permission-response',\n 'request-queued',\n 'status-request',\n 'status-response',\n 'session-title',\n 'tool-use',\n 'complete',\n] as const;\n\nexport const MESSAGE_TYPES = [\n 'output',\n 'input',\n 'error',\n 'system',\n 'tool-use',\n] as const;\n","export * from './events.js';\nexport * from './message-types.js';\n","import type { PermissionMode } from '../types/message.js';\n\nconst VALID_PERMISSION_MODES: PermissionMode[] = [\n 'default',\n 'acceptEdits',\n 'plan',\n 'bypassPermissions',\n 'delegate',\n 'dontAsk',\n];\n\nexport function isPermissionMode(value: unknown): value is PermissionMode {\n return typeof value === 'string' && VALID_PERMISSION_MODES.includes(value as PermissionMode);\n}\n","export * from './permission-mode.js';\n","// Types\nexport * from './types/index.js';\n\n// Constants\nexport * from './constants/index.js';\n\n// Runtime utilities\nexport * from './utils/index.js';\n","#!/usr/bin/env node\n\nimport { config } from 'dotenv';\nimport { resolve, dirname } from 'path';\nimport { readFileSync } from 'fs';\nimport { fileURLToPath } from 'url';\n\n// ESM equivalent of __dirname\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n// Load .env from CLI package root (quiet mode to suppress dotenvx tips)\nconfig({ path: resolve(__dirname, '../.env'), quiet: true });\n\n// Read version from package.json\nconst packageJson = JSON.parse(\n readFileSync(resolve(__dirname, '../package.json'), 'utf-8')\n);\nconst version = packageJson.version || '0.0.0';\n\n// Library exports\nexport { Config, getConfig } from './utils/config.js';\nexport { Logger, getLogger } from './utils/logger.js';\nexport { RealtimeClient } from './realtime/client.js';\nexport { SessionManager } from './daemon/session.js';\nexport { MachineManager } from './daemon/machine.js';\nexport { Daemon } from './daemon/daemon.js';\n\n// CLI entry point\nimport { Command } from 'commander';\nimport { createStartCommand } from './commands/start.js';\nimport { createStopCommand } from './commands/stop.js';\nimport { createStatusCommand } from './commands/status.js';\nimport { createLoginCommand } from './commands/login.js';\nimport { createLogoutCommand } from './commands/logout.js';\nimport { createSignupCommand } from './commands/signup.js';\nimport { createSetupCommand } from './commands/setup.js';\nimport { createMobileSetupCommand } from './commands/mobile-setup.js';\nimport { createResetCommand } from './commands/reset.js';\n\nconst program = new Command();\n\nprogram\n .name('clautunnel')\n .description('Remote control for Claude Code CLI')\n .version(version);\n\nprogram.addCommand(createSetupCommand());\nprogram.addCommand(createStartCommand());\nprogram.addCommand(createStopCommand());\nprogram.addCommand(createStatusCommand());\nprogram.addCommand(createLoginCommand());\nprogram.addCommand(createLogoutCommand());\nprogram.addCommand(createSignupCommand());\nprogram.addCommand(createMobileSetupCommand());\nprogram.addCommand(createResetCommand());\n\n// Only parse when run directly (not when imported as library)\nif (process.argv[1]?.includes('clautunnel') || process.argv[1]?.endsWith('/index.js') || process.argv[1]?.endsWith('/index.ts')) {\n program.parse();\n}\n","import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'fs';\nimport { join } from 'path';\nimport { homedir } from 'os';\n\nexport class ConfigurationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ConfigurationError';\n }\n}\n\ninterface ConfigData {\n machineId?: string;\n sessionTokens?: {\n accessToken: string;\n refreshToken: string;\n };\n supabaseUrl?: string;\n supabaseAnonKey?: string;\n mobileProjectPath?: string;\n}\n\nexport class Config {\n private configDir: string;\n private configFile: string;\n private data: ConfigData;\n\n constructor(configDir?: string) {\n this.configDir = configDir ?? join(homedir(), '.clautunnel');\n this.configFile = join(this.configDir, 'config.json');\n if (!configDir) {\n this.migrateFromLegacy();\n }\n this.data = this.loadConfig();\n }\n\n private migrateFromLegacy(): void {\n const legacyDir = join(homedir(), '.termbridge');\n if (existsSync(legacyDir) && !existsSync(this.configDir)) {\n renameSync(legacyDir, this.configDir);\n console.log(`Migrated config from ~/.termbridge to ~/.clautunnel`);\n }\n }\n\n private loadConfig(): ConfigData {\n if (existsSync(this.configFile)) {\n try {\n return JSON.parse(readFileSync(this.configFile, 'utf-8'));\n } catch {\n return {};\n }\n }\n return {};\n }\n\n private saveConfig(): void {\n if (!existsSync(this.configDir)) {\n mkdirSync(this.configDir, { recursive: true });\n }\n writeFileSync(this.configFile, JSON.stringify(this.data, null, 2));\n }\n\n getSupabaseUrl(): string {\n // Prefer env var over config file\n const url = process.env['SUPABASE_URL'] || this.data.supabaseUrl;\n if (!url) {\n throw new Error('SUPABASE_URL environment variable is not set');\n }\n\n // Validate URL format\n try {\n new URL(url);\n } catch {\n throw new Error('SUPABASE_URL must be a valid URL');\n }\n\n return url;\n }\n\n getSupabaseAnonKey(): string {\n // Prefer env var over config file\n const key = process.env['SUPABASE_ANON_KEY'] || this.data.supabaseAnonKey;\n if (!key) {\n throw new Error('SUPABASE_ANON_KEY environment variable is not set');\n }\n return key;\n }\n\n setSupabaseCredentials(credentials: { url: string; anonKey: string }): void {\n this.data.supabaseUrl = credentials.url;\n this.data.supabaseAnonKey = credentials.anonKey;\n this.saveConfig();\n }\n\n isConfigured(): boolean {\n const hasEnvVars = !!(process.env['SUPABASE_URL'] && process.env['SUPABASE_ANON_KEY']);\n const hasConfigFile = !!(this.data.supabaseUrl && this.data.supabaseAnonKey);\n return hasEnvVars || hasConfigFile;\n }\n\n requireConfiguration(): void {\n if (!this.isConfigured()) {\n throw new ConfigurationError(\n 'ClauTunnel is not configured.\\n\\n' +\n 'Run \"clautunnel setup\" to configure your Supabase credentials.\\n\\n' +\n 'Or set environment variables in your shell profile (~/.zshrc or ~/.bashrc):\\n' +\n ' export SUPABASE_URL=https://<project-id>.supabase.co\\n' +\n ' export SUPABASE_ANON_KEY=<your-anon-key>'\n );\n }\n }\n\n getMachineId(): string | undefined {\n return this.data.machineId;\n }\n\n setMachineId(machineId: string): void {\n this.data.machineId = machineId;\n this.saveConfig();\n }\n\n clearMachineId(): void {\n delete this.data.machineId;\n this.saveConfig();\n }\n\n getSessionTokens(): ConfigData['sessionTokens'] | undefined {\n return this.data.sessionTokens;\n }\n\n setSessionTokens(tokens: ConfigData['sessionTokens']): void {\n this.data.sessionTokens = tokens;\n this.saveConfig();\n }\n\n // Alias for setSessionTokens\n setSession(tokens: { accessToken: string; refreshToken: string }): void {\n this.setSessionTokens(tokens);\n }\n\n clearSessionTokens(): void {\n delete this.data.sessionTokens;\n this.saveConfig();\n }\n\n getMobileProjectPath(): string | undefined {\n return this.data.mobileProjectPath;\n }\n\n setMobileProjectPath(path: string): void {\n this.data.mobileProjectPath = path;\n this.saveConfig();\n }\n}\n\n// Default singleton instance\nlet defaultConfig: Config | null = null;\n\nexport function getConfig(): Config {\n if (!defaultConfig) {\n defaultConfig = new Config();\n }\n return defaultConfig;\n}\n","type LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\nexport class Logger {\n private silent: boolean;\n private debugEnabled: boolean;\n\n constructor() {\n this.silent = process.env['SILENT'] === 'true';\n this.debugEnabled = process.env['DEBUG'] === 'true';\n }\n\n private formatTimestamp(): string {\n const now = new Date();\n return now.toTimeString().split(' ')[0] ?? now.toISOString();\n }\n\n private formatMessage(level: LogLevel, message: string, data?: object): string {\n const timestamp = this.formatTimestamp();\n const levelStr = level.toUpperCase().padEnd(5);\n let formatted = `[${timestamp}] [${levelStr}] ${message}`;\n\n if (data) {\n formatted += ` ${JSON.stringify(data)}`;\n }\n\n return formatted;\n }\n\n debug(message: string, data?: object): void {\n if (this.silent || !this.debugEnabled) return;\n console.log(this.formatMessage('debug', message, data));\n }\n\n info(message: string, data?: object): void {\n if (this.silent) return;\n console.log(this.formatMessage('info', message, data));\n }\n\n warn(message: string, data?: object): void {\n if (this.silent) return;\n console.warn(this.formatMessage('warn', message, data));\n }\n\n error(message: string, data?: object): void {\n if (this.silent) return;\n console.error(this.formatMessage('error', message, data));\n }\n}\n\n// Default singleton instance\nlet defaultLogger: Logger | null = null;\n\nexport function getLogger(): Logger {\n if (!defaultLogger) {\n defaultLogger = new Logger();\n }\n return defaultLogger;\n}\n","import { EventEmitter } from 'events';\nimport type { SupabaseClient, RealtimeChannel } from '@supabase/supabase-js';\nimport type {\n RealtimeMessage,\n ModelInfo,\n PermissionMode,\n SlashCommand,\n InteractiveCommandData,\n InteractiveCommandType,\n InteractiveResult,\n PresencePayload,\n UserQuestionData,\n PermissionRequestData,\n ToolUseData,\n} from 'clautunnel-shared';\nimport { REALTIME_CHANNELS } from 'clautunnel-shared';\nimport { subscribeWithTimeout } from './utils.js';\n\nexport interface RealtimeClientOptions {\n supabase: SupabaseClient;\n sessionId: string;\n}\n\nexport class RealtimeClient extends EventEmitter {\n private supabase: SupabaseClient;\n private sessionId: string;\n private outputChannel: RealtimeChannel | null = null;\n private inputChannel: RealtimeChannel | null = null;\n private presenceChannel: RealtimeChannel | null = null;\n private seq: number = 0;\n private realtimeEnabled: boolean = false;\n\n constructor(options: RealtimeClientOptions) {\n super();\n this.supabase = options.supabase;\n this.sessionId = options.sessionId;\n }\n\n async connect(): Promise<void> {\n const privateConfig = { config: { private: true } };\n\n // Subscribe to output channel (CLI broadcasts to mobile)\n const outputChannelName = REALTIME_CHANNELS.sessionOutput(this.sessionId);\n this.outputChannel = this.supabase.channel(outputChannelName, privateConfig);\n\n // Subscribe to input channel (mobile sends to CLI)\n const inputChannelName = REALTIME_CHANNELS.sessionInput(this.sessionId);\n this.inputChannel = this.supabase.channel(inputChannelName, privateConfig);\n\n this.inputChannel.on('broadcast', { event: 'input' }, (payload) => {\n this.emit('input', payload.payload as RealtimeMessage);\n });\n\n const results = await Promise.all([\n subscribeWithTimeout(this.outputChannel, 'output'),\n subscribeWithTimeout(this.inputChannel, 'input'),\n ]);\n\n // Only enable realtime if both channels subscribed successfully\n this.realtimeEnabled = results.every((success) => success);\n\n // Set up presence channel to track CLI online status\n if (this.realtimeEnabled) {\n const presenceChannelName = REALTIME_CHANNELS.sessionPresence(this.sessionId);\n this.presenceChannel = this.supabase.channel(presenceChannelName, privateConfig);\n\n // Subscribe and track presence - re-track on every SUBSCRIBED (handles reconnection)\n this.presenceChannel.subscribe(async (status, err) => {\n if (status === 'SUBSCRIBED' && this.presenceChannel) {\n try {\n const payload: PresencePayload = {\n type: 'cli',\n online_at: new Date().toISOString(),\n };\n await this.presenceChannel.track(payload);\n } catch (trackError) {\n // Presence tracking is non-critical - log and continue\n console.warn('[WARN] Failed to track presence:', trackError);\n }\n } else if (status === 'CHANNEL_ERROR') {\n // Presence is non-critical - log and continue\n console.warn('[WARN] Presence channel error:', err?.message || 'Unknown error');\n }\n });\n }\n\n this.emit('connected');\n }\n\n async disconnect(): Promise<void> {\n // Untrack presence before disconnecting\n if (this.presenceChannel) {\n await this.presenceChannel.untrack();\n await this.supabase.removeChannel(this.presenceChannel);\n this.presenceChannel = null;\n }\n\n if (this.outputChannel) {\n await this.supabase.removeChannel(this.outputChannel);\n this.outputChannel = null;\n }\n\n if (this.inputChannel) {\n await this.supabase.removeChannel(this.inputChannel);\n this.inputChannel = null;\n }\n\n this.emit('disconnected');\n }\n\n async broadcast(content: string): Promise<void> {\n if (!this.outputChannel) {\n throw new Error('Not connected');\n }\n\n const message: RealtimeMessage = {\n type: 'output',\n content,\n timestamp: Date.now(),\n seq: ++this.seq,\n };\n\n // Persist message to database for history\n try {\n const { error } = await this.supabase.from('messages').insert({\n session_id: this.sessionId,\n type: message.type,\n content: message.content,\n seq: message.seq,\n });\n if (error) {\n console.warn('[WARN] Failed to persist message:', error.message);\n }\n } catch (error) {\n // Log but don't fail - message persistence is secondary to realtime\n console.warn('[WARN] Failed to persist message:', error);\n }\n\n // Skip realtime broadcasting if not enabled\n if (!this.realtimeEnabled) {\n return;\n }\n\n try {\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'output',\n payload: message,\n });\n } catch (error) {\n throw error;\n }\n\n this.emit('broadcast', message);\n }\n\n async broadcastMode(mode: PermissionMode): Promise<void> {\n if (!this.outputChannel) {\n throw new Error('Not connected');\n }\n\n // Skip broadcasting if realtime is not enabled\n if (!this.realtimeEnabled) {\n return;\n }\n\n const message: RealtimeMessage = {\n type: 'mode',\n permissionMode: mode,\n timestamp: Date.now(),\n seq: ++this.seq,\n };\n\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'output',\n payload: message,\n });\n\n this.emit('broadcast', message);\n }\n\n async broadcastCommands(commands: SlashCommand[]): Promise<void> {\n if (!this.outputChannel) {\n throw new Error('Not connected');\n }\n\n // Skip broadcasting if realtime is not enabled\n if (!this.realtimeEnabled) {\n return;\n }\n\n const message: RealtimeMessage = {\n type: 'commands',\n commands,\n timestamp: Date.now(),\n seq: ++this.seq,\n };\n\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'output',\n payload: message,\n });\n\n this.emit('broadcast', message);\n }\n\n async broadcastModel(model: string): Promise<void> {\n if (!this.outputChannel) {\n throw new Error('Not connected');\n }\n\n // Skip broadcasting if realtime is not enabled\n if (!this.realtimeEnabled) {\n return;\n }\n\n const message: RealtimeMessage = {\n type: 'model',\n model,\n timestamp: Date.now(),\n seq: ++this.seq,\n };\n\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'output',\n payload: message,\n });\n\n this.emit('broadcast', message);\n }\n\n async broadcastModels(models: ModelInfo[]): Promise<void> {\n if (!this.outputChannel) {\n throw new Error('Not connected');\n }\n\n // Skip broadcasting if realtime is not enabled\n if (!this.realtimeEnabled) {\n return;\n }\n\n const message: RealtimeMessage = {\n type: 'models',\n availableModels: models,\n timestamp: Date.now(),\n seq: ++this.seq,\n };\n\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'output',\n payload: message,\n });\n\n this.emit('broadcast', message);\n }\n\n async broadcastSystem(content: string): Promise<void> {\n if (!this.outputChannel) {\n throw new Error('Not connected');\n }\n\n const message: RealtimeMessage = {\n type: 'system',\n content,\n timestamp: Date.now(),\n seq: ++this.seq,\n };\n\n // Persist message to database for history\n try {\n const { error } = await this.supabase.from('messages').insert({\n session_id: this.sessionId,\n type: message.type,\n content: message.content,\n seq: message.seq,\n });\n if (error) {\n console.warn('[WARN] Failed to persist system message:', error.message);\n }\n } catch (error) {\n console.warn('[WARN] Failed to persist system message:', error);\n }\n\n // Skip realtime broadcasting if not enabled\n if (!this.realtimeEnabled) {\n return;\n }\n\n try {\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'output',\n payload: message,\n });\n } catch (error) {\n throw error;\n }\n\n this.emit('broadcast', message);\n }\n\n async broadcastInteractiveResponse(data: InteractiveCommandData): Promise<void> {\n if (!this.outputChannel) {\n throw new Error('Not connected');\n }\n\n // Skip broadcasting if realtime is not enabled\n if (!this.realtimeEnabled) {\n return;\n }\n\n const message: RealtimeMessage = {\n type: 'interactive-response',\n interactiveData: data,\n timestamp: Date.now(),\n seq: ++this.seq,\n };\n\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'output',\n payload: message,\n });\n\n this.emit('broadcast', message);\n }\n\n async broadcastInteractiveConfirm(\n command: InteractiveCommandType,\n result: InteractiveResult\n ): Promise<void> {\n if (!this.outputChannel) {\n throw new Error('Not connected');\n }\n\n // Skip broadcasting if realtime is not enabled\n if (!this.realtimeEnabled) {\n return;\n }\n\n const message: RealtimeMessage = {\n type: 'interactive-confirm',\n interactiveCommand: command,\n interactiveResult: result,\n timestamp: Date.now(),\n seq: ++this.seq,\n };\n\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'output',\n payload: message,\n });\n\n this.emit('broadcast', message);\n }\n\n async broadcastResumeHistory(historySessionId: string): Promise<void> {\n if (!this.outputChannel) {\n throw new Error('Not connected');\n }\n\n // Skip broadcasting if realtime is not enabled\n if (!this.realtimeEnabled) {\n return;\n }\n\n const message: RealtimeMessage = {\n type: 'resume-history',\n historySessionId,\n timestamp: Date.now(),\n seq: ++this.seq,\n };\n\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'output',\n payload: message,\n });\n\n this.emit('broadcast', message);\n }\n\n async broadcastUserQuestion(questionData: UserQuestionData): Promise<void> {\n if (!this.outputChannel) {\n throw new Error('Not connected');\n }\n\n // Skip broadcasting if realtime is not enabled\n if (!this.realtimeEnabled) {\n return;\n }\n\n const message: RealtimeMessage = {\n type: 'user-question',\n userQuestion: questionData,\n timestamp: Date.now(),\n seq: ++this.seq,\n };\n\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'output',\n payload: message,\n });\n\n this.emit('broadcast', message);\n }\n\n async broadcastPermissionRequest(requestData: PermissionRequestData): Promise<void> {\n if (!this.outputChannel) {\n throw new Error('Not connected');\n }\n\n // Skip broadcasting if realtime is not enabled\n if (!this.realtimeEnabled) {\n return;\n }\n\n const message: RealtimeMessage = {\n type: 'permission-request',\n permissionRequest: requestData,\n timestamp: Date.now(),\n seq: ++this.seq,\n };\n\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'output',\n payload: message,\n });\n\n this.emit('broadcast', message);\n }\n\n async broadcastToolUse(toolUseData: ToolUseData): Promise<void> {\n if (!this.outputChannel) {\n throw new Error('Not connected');\n }\n\n const message: RealtimeMessage = {\n type: 'tool-use',\n toolUseData,\n content: JSON.stringify(toolUseData),\n timestamp: Date.now(),\n seq: ++this.seq,\n };\n\n // Persist to database for history\n try {\n const { error } = await this.supabase.from('messages').insert({\n session_id: this.sessionId,\n type: message.type,\n content: message.content,\n seq: message.seq,\n });\n if (error) {\n console.warn('[WARN] Failed to persist tool-use message:', error.message);\n }\n } catch (error) {\n console.warn('[WARN] Failed to persist tool-use message:', error);\n }\n\n // Skip realtime broadcasting if not enabled\n if (!this.realtimeEnabled) {\n return;\n }\n\n try {\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'output',\n payload: message,\n });\n } catch (error) {\n throw error;\n }\n\n this.emit('broadcast', message);\n }\n\n async broadcastStatusResponse(\n isProcessing: boolean,\n isMessageQueued: boolean,\n permissionMode?: PermissionMode,\n ): Promise<void> {\n if (!this.outputChannel) {\n throw new Error('Not connected');\n }\n\n if (!this.realtimeEnabled) {\n return;\n }\n\n const message: RealtimeMessage = {\n type: 'status-response',\n isProcessing,\n isMessageQueued,\n permissionMode,\n timestamp: Date.now(),\n seq: ++this.seq,\n };\n\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'output',\n payload: message,\n });\n\n this.emit('broadcast', message);\n }\n\n async broadcastComplete(): Promise<void> {\n if (!this.outputChannel) {\n throw new Error('Not connected');\n }\n\n // Skip broadcasting if realtime is not enabled\n if (!this.realtimeEnabled) {\n return;\n }\n\n const message: RealtimeMessage = {\n type: 'complete',\n timestamp: Date.now(),\n seq: ++this.seq,\n };\n\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'output',\n payload: message,\n });\n\n this.emit('broadcast', message);\n }\n\n async broadcastSessionTitle(title: string): Promise<void> {\n if (!this.outputChannel) {\n throw new Error('Not connected');\n }\n\n // Skip broadcasting if realtime is not enabled\n if (!this.realtimeEnabled) {\n return;\n }\n\n const message: RealtimeMessage = {\n type: 'session-title',\n sessionTitle: title,\n timestamp: Date.now(),\n seq: ++this.seq,\n };\n\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'output',\n payload: message,\n });\n\n this.emit('broadcast', message);\n }\n\n async broadcastQueued(): Promise<void> {\n if (!this.outputChannel) {\n throw new Error('Not connected');\n }\n\n if (!this.realtimeEnabled) {\n return;\n }\n\n const message: RealtimeMessage = {\n type: 'request-queued',\n timestamp: Date.now(),\n seq: ++this.seq,\n };\n\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'output',\n payload: message,\n });\n\n this.emit('broadcast', message);\n }\n\n async broadcastError(errorMessage: string, errorCode?: string): Promise<void> {\n if (!this.outputChannel) {\n throw new Error('Not connected');\n }\n\n // Skip broadcasting if realtime is not enabled\n if (!this.realtimeEnabled) {\n return;\n }\n\n const message: RealtimeMessage = {\n type: 'error',\n content: errorMessage,\n errorCode: errorCode || 'unknown',\n timestamp: Date.now(),\n seq: ++this.seq,\n };\n\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'output',\n payload: message,\n });\n\n this.emit('broadcast', message);\n }\n\n getSeq(): number {\n return this.seq;\n }\n\n isConnected(): boolean {\n return this.outputChannel !== null && this.inputChannel !== null;\n }\n\n isRealtimeEnabled(): boolean {\n return this.realtimeEnabled;\n }\n}\n","import type { RealtimeChannel } from '@supabase/supabase-js';\n\nconst DEFAULT_TIMEOUT = 10000;\n\nexport function subscribeWithTimeout(\n channel: RealtimeChannel,\n channelName: string,\n timeout: number = DEFAULT_TIMEOUT\n): Promise<boolean> {\n return new Promise<boolean>((resolve) => {\n let lastStatus = 'unknown';\n\n const timer = setTimeout(() => {\n console.warn(\n `[WARN] Realtime subscription timeout for ${channelName} (last status: ${lastStatus}).`\n );\n resolve(false);\n }, timeout);\n\n channel.subscribe((status, err) => {\n lastStatus = status;\n\n if (status === 'SUBSCRIBED') {\n clearTimeout(timer);\n resolve(true);\n } else if (\n status === 'CHANNEL_ERROR' ||\n status === 'CLOSED' ||\n status === 'TIMED_OUT'\n ) {\n clearTimeout(timer);\n console.warn(\n `[WARN] Channel ${channelName} ${status.toLowerCase()}.`\n );\n if (err) {\n console.warn(`[WARN] Error details: ${err.message || err}`);\n }\n resolve(false);\n }\n });\n });\n}\n","import type { SupabaseClient } from '@supabase/supabase-js';\nimport type { Session, SessionStatus } from 'clautunnel-shared';\n\nexport interface SessionManagerOptions {\n supabase: SupabaseClient;\n}\n\nexport class SessionManager {\n private supabase: SupabaseClient;\n\n constructor(options: SessionManagerOptions) {\n this.supabase = options.supabase;\n }\n\n async createSession(\n machineId: string,\n workingDirectory?: string\n ): Promise<Session> {\n const { data, error } = await this.supabase\n .from('sessions')\n .insert({\n machine_id: machineId,\n status: 'active' as SessionStatus,\n working_directory: workingDirectory,\n started_at: new Date().toISOString(),\n })\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to create session: ${error.message}`);\n }\n\n return data as Session;\n }\n\n async endSession(sessionId: string): Promise<void> {\n const { error } = await this.supabase\n .from('sessions')\n .update({\n status: 'ended' as SessionStatus,\n ended_at: new Date().toISOString(),\n })\n .eq('id', sessionId);\n\n if (error) {\n throw new Error(`Failed to end session: ${error.message}`);\n }\n }\n\n async getSession(sessionId: string): Promise<Session | null> {\n const { data, error } = await this.supabase\n .from('sessions')\n .select()\n .eq('id', sessionId)\n .single();\n\n if (error) {\n if (error.code === 'PGRST116') {\n // Not found\n return null;\n }\n throw new Error(`Failed to get session: ${error.message}`);\n }\n\n return data as Session;\n }\n\n async updateSessionStatus(\n sessionId: string,\n status: SessionStatus\n ): Promise<void> {\n const updates: Partial<Session> = { status };\n\n if (status === 'ended') {\n updates.ended_at = new Date().toISOString();\n }\n\n const { error } = await this.supabase\n .from('sessions')\n .update(updates)\n .eq('id', sessionId);\n\n if (error) {\n throw new Error(`Failed to update session status: ${error.message}`);\n }\n }\n\n async updateSessionModel(\n sessionId: string,\n model: string\n ): Promise<void> {\n const { error } = await this.supabase\n .from('sessions')\n .update({ model })\n .eq('id', sessionId);\n\n if (error) {\n throw new Error(`Failed to update session model: ${error.message}`);\n }\n }\n\n async updateSdkSessionId(\n sessionId: string,\n sdkSessionId: string\n ): Promise<void> {\n const { error } = await this.supabase\n .from('sessions')\n .update({ sdk_session_id: sdkSessionId })\n .eq('id', sessionId);\n\n if (error) {\n throw new Error(`Failed to update SDK session ID: ${error.message}`);\n }\n }\n\n async updateSessionTitle(\n sessionId: string,\n title: string\n ): Promise<void> {\n const { error } = await this.supabase\n .from('sessions')\n .update({ title })\n .eq('id', sessionId);\n\n if (error) {\n throw new Error(`Failed to update session title: ${error.message}`);\n }\n }\n}\n","import type { SupabaseClient } from '@supabase/supabase-js';\nimport type { Machine, MachineStatus } from 'clautunnel-shared';\nimport * as os from 'os';\n\nexport interface MachineManagerOptions {\n supabase: SupabaseClient;\n}\n\nexport class MachineManager {\n private supabase: SupabaseClient;\n\n constructor(options: MachineManagerOptions) {\n this.supabase = options.supabase;\n }\n\n async registerMachine(\n userId: string,\n name?: string,\n machineId?: string\n ): Promise<Machine> {\n const hostname = os.hostname();\n const machineName = name || hostname;\n\n // If machineId provided, try to update existing machine\n if (machineId) {\n const existing = await this.getMachine(machineId);\n if (existing) {\n await this.updateMachineStatus(machineId, 'online');\n return existing;\n }\n }\n\n // Check if machine with same user_id and hostname already exists\n const { data: existingByHostname } = await this.supabase\n .from('machines')\n .select()\n .eq('user_id', userId)\n .eq('hostname', hostname)\n .single();\n\n if (existingByHostname) {\n // Update existing machine and return it\n await this.updateMachineStatus(existingByHostname.id, 'online');\n return existingByHostname as Machine;\n }\n\n // Create new machine\n const { data, error } = await this.supabase\n .from('machines')\n .insert({\n user_id: userId,\n name: machineName,\n hostname,\n status: 'online' as MachineStatus,\n last_seen_at: new Date().toISOString(),\n })\n .select()\n .single();\n\n if (error) {\n throw new Error(`Failed to register machine: ${error.message}`);\n }\n\n return data as Machine;\n }\n\n async getMachine(machineId: string): Promise<Machine | null> {\n const { data, error } = await this.supabase\n .from('machines')\n .select()\n .eq('id', machineId)\n .single();\n\n if (error) {\n if (error.code === 'PGRST116') {\n // Not found\n return null;\n }\n throw new Error(`Failed to get machine: ${error.message}`);\n }\n\n return data as Machine;\n }\n\n async updateMachineStatus(\n machineId: string,\n status: MachineStatus\n ): Promise<void> {\n const { error } = await this.supabase\n .from('machines')\n .update({\n status,\n last_seen_at: new Date().toISOString(),\n })\n .eq('id', machineId);\n\n if (error) {\n throw new Error(`Failed to update machine status: ${error.message}`);\n }\n }\n\n async heartbeat(machineId: string): Promise<void> {\n const { error } = await this.supabase\n .from('machines')\n .update({\n last_seen_at: new Date().toISOString(),\n })\n .eq('id', machineId);\n\n if (error) {\n throw new Error(`Failed to update heartbeat: ${error.message}`);\n }\n }\n\n async listMachines(userId: string): Promise<Machine[]> {\n const { data, error } = await this.supabase\n .from('machines')\n .select()\n .eq('user_id', userId)\n .order('last_seen_at', { ascending: false });\n\n if (error) {\n throw new Error(`Failed to list machines: ${error.message}`);\n }\n\n return data as Machine[];\n }\n}\n","import { EventEmitter } from 'events';\nimport type { SupabaseClient } from '@supabase/supabase-js';\nimport { SdkSession } from './sdk-session.js';\nimport { SessionManager } from './session.js';\nimport { MachineManager } from './machine.js';\nimport { ConfigManager } from './config-manager.js';\nimport { RealtimeClient } from '../realtime/client.js';\nimport { isPermissionMode } from 'clautunnel-shared';\nimport type { Session, Machine, RealtimeMessage, ImageAttachment, PermissionMode, UserQuestionData, PermissionRequestData, ToolUseData } from 'clautunnel-shared';\n\nexport interface DaemonOptions {\n supabase: SupabaseClient;\n userId: string;\n machineId?: string;\n machineName?: string;\n cwd: string;\n hybrid?: boolean;\n}\n\nexport class Daemon extends EventEmitter {\n private options: DaemonOptions;\n private sdkSession: SdkSession;\n private sessionManager: SessionManager;\n private machineManager: MachineManager;\n private configManager: ConfigManager;\n private realtimeClient: RealtimeClient | null = null;\n private machine: Machine | null = null;\n private session: Session | null = null;\n private running: boolean = false;\n private commandsBroadcast: boolean = false;\n private sdkCommandsBroadcast: boolean = false;\n private titleSet: boolean = false;\n\n constructor(options: DaemonOptions) {\n super();\n this.options = options;\n\n this.configManager = new ConfigManager({\n cwd: options.cwd,\n });\n\n this.sdkSession = new SdkSession({\n cwd: options.cwd,\n permissionMode: this.configManager.getPermissionMode(),\n });\n\n this.sessionManager = new SessionManager({\n supabase: options.supabase,\n });\n\n this.machineManager = new MachineManager({\n supabase: options.supabase,\n });\n\n // Initialize thinking mode from settings\n const thinkingEnabled = this.configManager.getThinkingMode();\n if (thinkingEnabled) {\n this.sdkSession.setThinkingMode(true);\n }\n }\n\n async start(): Promise<void> {\n if (this.running) {\n throw new Error('Daemon is already running');\n }\n\n // Register machine\n this.machine = await this.machineManager.registerMachine(\n this.options.userId,\n this.options.machineName,\n this.options.machineId\n );\n\n // Create session\n this.session = await this.sessionManager.createSession(\n this.machine.id,\n this.options.cwd\n );\n\n // Initialize realtime client\n this.realtimeClient = new RealtimeClient({\n supabase: this.options.supabase,\n sessionId: this.session.id,\n });\n\n // Wire up SDK session output to broadcast\n this.sdkSession.on('output', async (data: string) => {\n // Hybrid mode: output to local stdout\n if (this.options.hybrid !== false) {\n process.stdout.write(data);\n }\n\n // Emit for external listeners (e.g., start command logging)\n this.emit('mobile-output', data);\n\n // Broadcast to mobile\n if (this.realtimeClient) {\n try {\n await this.realtimeClient.broadcast(data);\n } catch {\n // Silently handle broadcast errors\n }\n }\n });\n\n this.sdkSession.on('error', (error: Error) => {\n this.emit('error', error);\n });\n\n // Wire up auth/API errors (authentication_failed, billing_error, rate_limit, etc.)\n this.sdkSession.on('auth-error', async (errorInfo: { errorCode: string; message: string }) => {\n const errorMessages: Record<string, string> = {\n 'authentication_failed': 'Claude CLI authentication expired. Please run \"claude login\" on the host machine.',\n 'billing_error': 'Billing error. Please check your Anthropic account billing status.',\n 'rate_limit': 'Rate limit reached. Please wait a moment and try again.',\n 'server_error': 'Anthropic API server error. Please try again later.',\n };\n\n const displayMessage = errorMessages[errorInfo.errorCode] || `API error: ${errorInfo.message}`;\n\n if (this.options.hybrid !== false) {\n process.stdout.write(`\\n[Error] ${displayMessage}\\n`);\n }\n\n this.emit('error', new Error(displayMessage));\n\n if (this.realtimeClient) {\n try {\n await this.realtimeClient.broadcastError(displayMessage, errorInfo.errorCode);\n await this.realtimeClient.broadcastComplete();\n } catch {\n // Silently handle broadcast errors\n }\n }\n });\n\n // Broadcast commands when they're updated from init message (includes plugins/skills)\n this.sdkSession.on('commands-updated', async () => {\n await this.broadcastCommands();\n });\n\n // Resume failed — notify mobile that we're falling back to a new session\n this.sdkSession.on('resume-failed', async () => {\n const msg = '[Could not resume previous session. Starting a new session instead.]';\n if (this.options.hybrid !== false) {\n process.stdout.write(`\\n${msg}\\n`);\n }\n if (this.realtimeClient) {\n try {\n await this.realtimeClient.broadcastSystem(msg);\n } catch {\n // Silently handle broadcast errors\n }\n }\n });\n\n // Save SDK session ID to Supabase for resume functionality\n this.sdkSession.on('session-started', async (sdkSessionId: string) => {\n if (!this.session) return;\n try {\n await this.sessionManager.updateSdkSessionId(this.session.id, sdkSessionId);\n } catch {\n // Silently handle - non-critical for basic functionality\n }\n });\n\n this.sdkSession.on('complete', async () => {\n // Session query completed, ready for next input\n if (this.options.hybrid !== false) {\n process.stdout.write('\\n> ');\n }\n\n // Broadcast completion to mobile so it knows Claude is done\n if (this.realtimeClient) {\n try {\n await this.realtimeClient.broadcastComplete();\n } catch {\n // Silently handle broadcast errors\n }\n }\n\n // Broadcast real SDK commands (including custom skills) after first query completion\n // This updates the fallback commands with the full list from the SDK\n if (!this.sdkCommandsBroadcast && this.realtimeClient) {\n this.sdkCommandsBroadcast = true;\n await this.broadcastCommands();\n }\n });\n\n // Wire up permission mode changes to broadcast\n this.sdkSession.on('permission-mode', async (mode: PermissionMode) => {\n if (this.realtimeClient) {\n try {\n await this.realtimeClient.broadcastMode(mode);\n } catch {\n // Silently handle broadcast errors\n }\n }\n });\n\n // Wire up user questions to broadcast to mobile\n this.sdkSession.on('user-question', async (questionData: UserQuestionData) => {\n if (this.realtimeClient) {\n try {\n await this.realtimeClient.broadcastUserQuestion(questionData);\n } catch {\n // Silently handle broadcast errors\n }\n }\n });\n\n // Wire up request queuing to broadcast to mobile\n this.sdkSession.on('request-queued', async () => {\n if (this.realtimeClient) {\n try {\n await this.realtimeClient.broadcastQueued();\n } catch {\n // Silently handle broadcast errors\n }\n }\n });\n\n // Wire up permission requests to broadcast to mobile\n this.sdkSession.on('permission-request', async (requestData: PermissionRequestData) => {\n if (this.realtimeClient) {\n try {\n await this.realtimeClient.broadcastPermissionRequest(requestData);\n } catch {\n // Silently handle broadcast errors\n }\n }\n });\n\n // Wire up tool use data to broadcast to mobile (for code diffs)\n this.sdkSession.on('tool-use', async (toolUseData: ToolUseData) => {\n if (this.realtimeClient) {\n try {\n await this.realtimeClient.broadcastToolUse(toolUseData);\n } catch (err) {\n console.warn('[Daemon] Failed to broadcast tool-use:', err);\n }\n }\n });\n\n // Wire up model changes to broadcast and persist\n this.sdkSession.on('model', async (model: string) => {\n // Persist model to database for this session\n if (this.session) {\n try {\n await this.sessionManager.updateSessionModel(this.session.id, model);\n } catch {\n // Silently handle persistence errors\n }\n }\n\n // Broadcast to mobile\n if (this.realtimeClient) {\n try {\n await this.realtimeClient.broadcastModel(model);\n } catch {\n // Silently handle broadcast errors\n }\n }\n });\n\n // Wire up input from mobile\n this.realtimeClient.on('input', async (message: RealtimeMessage) => {\n // Broadcast commands on first message from mobile if not already done\n if (!this.commandsBroadcast) {\n this.commandsBroadcast = true;\n await this.broadcastCommands();\n }\n\n // Handle mode change requests\n if (message.type === 'mode-change' && message.permissionMode) {\n this.sdkSession.setPermissionMode(message.permissionMode);\n // Broadcast the new mode back to confirm\n if (this.realtimeClient) {\n try {\n await this.realtimeClient.broadcastMode(message.permissionMode);\n } catch {\n // Silently handle broadcast errors\n }\n }\n return;\n }\n\n // Handle commands request\n if (message.type === 'commands-request') {\n await this.broadcastCommands();\n return;\n }\n\n // Handle model change requests\n if (message.type === 'model-change' && message.model) {\n const previousModel = this.sdkSession.getModel();\n await this.sdkSession.setModel(message.model);\n\n // Output confirmation message if model actually changed\n if (previousModel !== message.model) {\n const modelNames: Record<string, string> = {\n 'default': 'Opus 4.6',\n 'sonnet': 'Sonnet 4.6',\n 'opus': 'Opus 4.6',\n 'haiku': 'Haiku 3.5',\n };\n const displayName = modelNames[message.model] || message.model;\n const confirmationMsg = `[Model switched to ${displayName}]`;\n\n // Output to local terminal\n if (this.options.hybrid !== false) {\n process.stdout.write(`\\n${confirmationMsg}\\n`);\n }\n\n // Broadcast to mobile as system message (appears as separate bubble)\n if (this.realtimeClient) {\n try {\n await this.realtimeClient.broadcastSystem(confirmationMsg);\n } catch {\n // Silently handle broadcast errors\n }\n }\n } else {\n // Model didn't change — still broadcast current model so mobile clears loading state\n try {\n await this.realtimeClient?.broadcastModel(this.sdkSession.getModel());\n } catch {\n // Silently handle broadcast errors\n }\n }\n return;\n }\n\n // Handle models request - send both available models and current model\n if (message.type === 'models-request') {\n await this.broadcastModels();\n // Also broadcast the current model so UI shows the correct selection\n try {\n await this.realtimeClient?.broadcastModel(this.sdkSession.getModel());\n } catch {\n // Silently handle broadcast errors\n }\n return;\n }\n\n // Handle status request - re-broadcast any pending question or permission,\n // then report current processing state so mobile can restore isTyping\n if (message.type === 'status-request') {\n if (this.realtimeClient) {\n try {\n const pendingQuestion = this.sdkSession.getPendingQuestionData();\n if (pendingQuestion) {\n await this.realtimeClient.broadcastUserQuestion(pendingQuestion);\n }\n const pendingPermission = this.sdkSession.getPendingPermissionData();\n if (pendingPermission) {\n await this.realtimeClient.broadcastPermissionRequest(pendingPermission);\n }\n\n // Broadcast processing state last so it doesn't flash typing indicator\n // before a pending question/permission modal appears\n const isProcessing = this.sdkSession.isActive();\n const isActivelyWorking = isProcessing && !pendingQuestion && !pendingPermission;\n const isMessageQueued = this.sdkSession.hasPendingPrompt();\n await this.realtimeClient.broadcastStatusResponse(\n isActivelyWorking,\n isMessageQueued,\n this.sdkSession.getPermissionMode(),\n );\n } catch {\n // Silently handle broadcast errors\n }\n }\n return;\n }\n\n // Handle mobile disconnect notification\n if (message.type === 'mobile-disconnect') {\n if (this.options.hybrid !== false) {\n process.stdout.write('\\n[ClauTunnel] Mobile client disconnected.\\n');\n }\n this.emit('mobile-disconnected');\n return;\n }\n\n // Handle interactive command request\n if (message.type === 'interactive-request' && message.interactiveCommand) {\n const data = this.configManager.getInteractiveData(message.interactiveCommand);\n if (this.realtimeClient) {\n try {\n await this.realtimeClient.broadcastInteractiveResponse(data);\n } catch {\n // Silently handle broadcast errors\n }\n }\n return;\n }\n\n // Handle interactive apply\n if (message.type === 'interactive-apply' && message.interactivePayload) {\n const result = this.configManager.applyChange(message.interactivePayload);\n\n // If permission mode was changed, update runtime SDK mode too\n if (\n result.success &&\n message.interactivePayload.command === 'permissions' &&\n isPermissionMode(message.interactivePayload.value)\n ) {\n this.sdkSession.setPermissionMode(message.interactivePayload.value);\n }\n\n // If thinking mode was changed, also update the running SDK session\n if (\n message.interactivePayload.command === 'config' &&\n message.interactivePayload.key === 'alwaysThinkingEnabled'\n ) {\n const enabled = Boolean(message.interactivePayload.value);\n await this.sdkSession.setThinkingMode(enabled);\n }\n\n if (this.realtimeClient) {\n try {\n await this.realtimeClient.broadcastInteractiveConfirm(\n message.interactivePayload.command,\n result\n );\n // Also broadcast a system message for confirmation\n const statusText = result.success\n ? `✓ ${result.message}`\n : `✗ ${result.message}`;\n await this.realtimeClient.broadcastSystem(statusText);\n } catch {\n // Silently handle broadcast errors\n }\n }\n return;\n }\n\n // Handle cancel request from mobile - stop Claude mid-processing\n if (message.type === 'cancel-request') {\n this.sdkSession.cancel();\n if (this.options.hybrid !== false) {\n process.stdout.write('\\n[Cancelled]\\n> ');\n }\n if (this.realtimeClient) {\n try {\n await this.realtimeClient.broadcastSystem('[Cancelled]');\n await this.realtimeClient.broadcastComplete();\n } catch (error) {\n console.warn('[Daemon] Failed to broadcast cancel:', error);\n }\n }\n return;\n }\n\n // Handle clear request from mobile (doesn't appear in chat)\n if (message.type === 'clear-request') {\n this.sdkSession.clearHistory();\n if (this.options.hybrid !== false) {\n process.stdout.write('\\n[Conversation cleared]\\n> ');\n }\n return;\n }\n\n // Handle user answer (response to AskUserQuestion)\n // Use provideAnswer() to stream into the existing query instead of\n // sendPrompt() which would be rejected since isProcessing is true\n if (message.type === 'user-answer' && message.userAnswer) {\n const answerText = Object.values(message.userAnswer.answers).join('\\n');\n this.emit('mobile-input', `(answer) ${answerText}`);\n await this.sdkSession.provideAnswer(answerText, message.userAnswer.answers);\n return;\n }\n\n // Handle permission response from mobile\n if (message.type === 'permission-response' && message.permissionResponse) {\n this.sdkSession.handlePermissionResponse(message.permissionResponse);\n return;\n }\n\n // Handle resume request from mobile (doesn't appear in chat)\n if (message.type === 'resume-request' && message.resumeSessionId) {\n const targetSdkSessionId = message.resumeSessionId;\n this.sdkSession.resumeSession(targetSdkSessionId);\n\n const confirmationMsg = `[Resuming session: ${targetSdkSessionId.slice(0, 8)}...]`;\n if (this.options.hybrid !== false) {\n process.stdout.write(`\\n${confirmationMsg}\\n`);\n }\n\n if (this.realtimeClient) {\n try {\n // Find the Supabase session with this SDK session ID to load its messages\n const { data: sessionData } = await this.options.supabase\n .from('sessions')\n .select('id')\n .eq('sdk_session_id', targetSdkSessionId)\n .single();\n\n if (sessionData) {\n // Tell mobile to load messages from this session\n await this.realtimeClient.broadcastResumeHistory(sessionData.id);\n }\n\n await this.realtimeClient.broadcastSystem(confirmationMsg);\n } catch {\n // Silently handle broadcast errors\n }\n }\n\n // Send a prompt to trigger the resumed session\n await this.sdkSession.sendPrompt('Continue from where we left off.');\n return;\n }\n\n // Remove trailing newline/carriage return for SDK\n const prompt = message.content?.replace(/[\\r\\n]+$/, '') || '';\n const attachments = message.attachments;\n\n // Send if there's text or attachments\n if (prompt.trim() || (attachments && attachments.length > 0)) {\n const trimmedPrompt = prompt.trim();\n\n // Emit mobile input event for logging\n this.emit('mobile-input', trimmedPrompt, attachments);\n\n // Handle /clear typed in chat (legacy support)\n if (trimmedPrompt === '/clear') {\n this.sdkSession.clearHistory();\n if (this.realtimeClient) {\n try {\n await this.realtimeClient.broadcastSystem('Conversation cleared');\n } catch {\n // Silently handle broadcast errors\n }\n }\n if (this.options.hybrid !== false) {\n process.stdout.write('\\n[Conversation cleared]\\n> ');\n }\n return;\n }\n\n // Auto-set session title from the first user message\n if (!this.titleSet && this.session) {\n this.titleSet = true;\n const title = trimmedPrompt.length > 50\n ? trimmedPrompt.slice(0, 50) + '...'\n : trimmedPrompt;\n this.sessionManager.updateSessionTitle(this.session.id, title).catch(() => {\n // Non-critical - silently handle\n });\n if (this.realtimeClient) {\n this.realtimeClient.broadcastSessionTitle(title).catch(() => {\n // Non-critical - silently handle\n });\n }\n }\n\n await this.sdkSession.sendPrompt(prompt, attachments);\n }\n });\n\n // Connect to realtime\n await this.realtimeClient.connect();\n\n // Broadcast initial permission mode\n try {\n await this.realtimeClient.broadcastMode(this.sdkSession.getPermissionMode());\n } catch {\n // Silently handle broadcast errors\n }\n\n // Broadcast available commands immediately\n await this.broadcastCommands();\n\n // Broadcast available models immediately\n await this.broadcastModels();\n\n // Broadcast current model\n try {\n await this.realtimeClient.broadcastModel(this.sdkSession.getModel());\n } catch {\n // Silently handle broadcast errors\n }\n\n this.running = true;\n this.emit('started', {\n machine: this.machine,\n session: this.session,\n mobileSyncEnabled: this.realtimeClient?.isRealtimeEnabled() ?? false,\n });\n\n // Show initial prompt\n if (this.options.hybrid !== false) {\n process.stdout.write('\\n[ClauTunnel] Ready for input.\\n> ');\n }\n }\n\n async stop(): Promise<void> {\n if (!this.running) {\n return;\n }\n\n this.running = false;\n\n // Cancel any ongoing SDK operation\n this.sdkSession.cancel();\n\n // End session\n if (this.session) {\n await this.sessionManager.endSession(this.session.id);\n }\n\n // Note: We don't set machine status to 'offline' here because other\n // sessions may still be running on the same machine. The machine\n // status is set to 'online' when any session starts.\n\n // Disconnect realtime\n if (this.realtimeClient) {\n await this.realtimeClient.disconnect();\n }\n\n this.emit('stopped');\n }\n\n async sendPrompt(prompt: string, attachments?: ImageAttachment[]): Promise<void> {\n await this.sdkSession.sendPrompt(prompt, attachments);\n }\n\n isRunning(): boolean {\n return this.running;\n }\n\n getSession(): Session | null {\n return this.session;\n }\n\n getMachine(): Machine | null {\n return this.machine;\n }\n\n private async broadcastCommands(): Promise<void> {\n if (!this.realtimeClient) {\n return;\n }\n\n try {\n const commands = await this.sdkSession.getSupportedCommands();\n await this.realtimeClient.broadcastCommands(commands);\n } catch {\n // Silently handle broadcast errors\n }\n }\n\n private async broadcastModels(): Promise<void> {\n if (!this.realtimeClient) {\n return;\n }\n\n try {\n const models = await this.sdkSession.getSupportedModels();\n await this.realtimeClient.broadcastModels(models);\n } catch {\n // Silently handle broadcast errors\n }\n }\n}\n","import { EventEmitter } from 'events';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\nimport { unstable_v2_createSession, unstable_v2_resumeSession } from '@anthropic-ai/claude-agent-sdk';\nimport type { SDKSession as V2Session, SDKSessionOptions, SDKMessage, SlashCommand as SDKSlashCommand, CanUseTool, PermissionResult, PermissionUpdate as SDKPermissionUpdate, SDKUserMessage } from '@anthropic-ai/claude-agent-sdk';\nimport type { ImageAttachment, ModelInfo, PermissionMode, SlashCommand, UserQuestionData, UserQuestion, PermissionRequestData, PermissionResponseData, PermissionUpdate, ToolUseData } from 'clautunnel-shared';\nimport { v4 as uuidv4 } from 'uuid';\n\n/** Maximum characters to capture from tool use content */\nconst MAX_TOOL_CONTENT = 10000;\n/** Grace period to wait for a result after compact lifecycle events */\nconst COMPACT_FALLBACK_GRACE_MS = 40;\n/** Delay before dispatching queued prompt after compact fallback */\nconst COMPACT_QUEUED_DISPATCH_DELAY_MS = 40;\n/** Guard window to ignore a stale compact result during immediate next-turn handoff */\nconst COMPACT_STALE_RESULT_GUARD_MS = COMPACT_FALLBACK_GRACE_MS + COMPACT_QUEUED_DISPATCH_DELAY_MS;\n\n/** Commands unsupported in remote/mobile context */\nconst UNSUPPORTED_COMMANDS = new Set([\n 'keybindings-help', 'help', 'context', 'cost', 'release-notes',\n 'vim', 'mcp', 'agents', 'hooks', 'status',\n]);\n\nexport interface SdkSessionOptions {\n cwd: string;\n allowedTools?: string[];\n permissionMode?: PermissionMode;\n model?: string;\n}\n\ninterface ConversationMessage {\n role: 'user' | 'assistant';\n content: string;\n}\n\n// Pending permission request with resolver\ninterface PendingPermissionRequest {\n resolve: (result: PermissionResult) => void;\n reject: (error: Error) => void;\n signal: AbortSignal;\n toolInput: Record<string, unknown>;\n}\n\ninterface PendingAnswerRequest {\n resolve: (answers: Record<string, string>) => void;\n reject: (error: Error) => void;\n}\n\nexport class SdkSession extends EventEmitter {\n private options: SdkSessionOptions;\n private sessionId: string | null = null;\n private isProcessing: boolean = false;\n private currentPermissionMode: PermissionMode;\n private v2Session: V2Session | null = null;\n private streamLoopRunning: boolean = false;\n private cachedCommands: SlashCommand[] | null = null;\n private cachedModels: ModelInfo[] | null = null;\n private currentModel: string = 'opus';\n private conversationHistory: ConversationMessage[] = [];\n private pendingContextTransfer: boolean = false;\n private thinkingEnabled: boolean = false;\n private pendingPermissionRequests: Map<string, PendingPermissionRequest> = new Map();\n // Pending AskUserQuestion answer promise\n private pendingAnswerRequest: PendingAnswerRequest | null = null;\n // Track pending question/permission data for re-broadcast on status-request\n private pendingQuestionData: UserQuestionData | null = null;\n private pendingPermissionData: PermissionRequestData | null = null;\n // Track current assistant response text for conversation history\n private currentAssistantResponse: string = '';\n // Queued prompt to send after current processing completes (last-one-wins)\n private pendingPrompt: { prompt: string; attachments?: ImageAttachment[] } | null = null;\n // Tracks prompt during a resume attempt — used to auto-retry with a fresh session on failure\n private resumeAttemptPrompt: { prompt: string; attachments?: ImageAttachment[] } | null = null;\n // Tracks whether the current in-flight prompt is a manual /compact command.\n private awaitingCompactCompletionFallback: boolean = false;\n // Monotonic counter for turn ordering.\n private turnGeneration: number = 0;\n // Generation of the current in-flight turn.\n private activeTurnGeneration: number = 0;\n // Timestamp when the current in-flight turn started.\n private activeTurnStartedAtMs: number = 0;\n // Generation whose late result should be ignored after compact fallback.\n private compactLateResultSuppressedGeneration: number | null = null;\n // Timer used to defer compact completion fallback in case result arrives.\n private compactCompletionFallbackTimer: ReturnType<typeof setTimeout> | null = null;\n // Timer used to dispatch queued prompt shortly after compact fallback.\n private deferredQueuedPromptTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor(options: SdkSessionOptions) {\n super();\n this.options = options;\n this.currentPermissionMode = options.permissionMode || 'default';\n this.currentModel = options.model || 'opus';\n }\n\n /**\n * Handle permission response from mobile\n */\n handlePermissionResponse(response: PermissionResponseData): void {\n const pending = this.pendingPermissionRequests.get(response.requestId);\n if (!pending) {\n console.warn(`[WARN] No pending permission request found for ID: ${response.requestId}`);\n return;\n }\n\n this.pendingPermissionRequests.delete(response.requestId);\n this.pendingPermissionData = null;\n\n if (response.behavior === 'allow') {\n const result: PermissionResult = {\n behavior: 'allow',\n // updatedInput is required by the SDK's Zod schema — if omitted,\n // JSON.stringify drops the key and subprocess validation fails.\n // Fall back to the original tool input to keep it valid.\n updatedInput: response.updatedInput ?? pending.toolInput,\n updatedPermissions: response.updatedPermissions as SDKPermissionUpdate[] | undefined,\n };\n pending.resolve(result);\n } else {\n const result: PermissionResult = {\n behavior: 'deny',\n message: response.message || 'Permission denied by user',\n };\n pending.resolve(result);\n }\n }\n\n /**\n * Create canUseTool callback for SDK\n *\n * AskUserQuestion goes through this path: the subprocess sends a\n * control_request with subtype \"can_use_tool\" and blocks until a\n * control_response is returned. For AskUserQuestion we emit a\n * user-question event, wait for provideAnswer() to resolve the pending\n * promise, and return {behavior:'allow', updatedInput:{questions, answers}}\n * so the subprocess can produce the tool_result and continue.\n */\n private createCanUseTool(): CanUseTool {\n return async (\n toolName: string,\n input: Record<string, unknown>,\n options: {\n signal: AbortSignal;\n suggestions?: SDKPermissionUpdate[];\n blockedPath?: string;\n decisionReason?: string;\n toolUseID: string;\n agentID?: string;\n }\n ): Promise<PermissionResult> => {\n\n // --- AskUserQuestion: route through user-question event -----------\n if (toolName === 'AskUserQuestion') {\n const questionInput = input as {\n questions?: Array<{\n question: string;\n header: string;\n options: Array<{ label: string; description: string }>;\n multiSelect?: boolean;\n }>;\n };\n\n if (questionInput.questions && Array.isArray(questionInput.questions)) {\n const questions: UserQuestion[] = questionInput.questions.map(q => ({\n question: q.question,\n header: q.header,\n options: (q.options || []).map(o => ({\n label: o.label,\n description: o.description,\n })),\n multiSelect: q.multiSelect,\n }));\n\n const questionData: UserQuestionData = {\n toolUseId: options.toolUseID,\n questions,\n };\n\n // Store and broadcast to mobile\n this.pendingQuestionData = questionData;\n this.emit('user-question', questionData);\n\n // Wait for provideAnswer() to supply the answers\n const answers = await new Promise<Record<string, string>>(\n (resolve, reject) => {\n const pendingRequest: PendingAnswerRequest = { resolve, reject };\n this.pendingAnswerRequest = pendingRequest;\n\n // Clean up if the request is aborted (e.g. session cancelled)\n options.signal.addEventListener('abort', () => {\n if (this.pendingAnswerRequest === pendingRequest) {\n this.pendingAnswerRequest = null;\n this.pendingQuestionData = null;\n }\n reject(new Error('Question aborted'));\n });\n }\n );\n\n this.pendingAnswerRequest = null;\n this.pendingQuestionData = null;\n\n // Return updatedInput so the subprocess can build the tool_result\n return {\n behavior: 'allow' as const,\n updatedInput: {\n questions: questionInput.questions,\n answers,\n },\n };\n }\n }\n\n // --- Regular permission request: broadcast to mobile and wait -----\n const requestId = uuidv4();\n\n // Convert SDK permission updates to our type\n const suggestions = options.suggestions?.map((s): PermissionUpdate => {\n // Handle different permission update types\n if (s.type === 'addRules' || s.type === 'replaceRules' || s.type === 'removeRules') {\n return {\n type: s.type,\n rules: s.rules,\n behavior: s.behavior,\n destination: s.destination,\n };\n } else if (s.type === 'setMode') {\n return {\n type: 'setMode',\n mode: s.mode as PermissionMode,\n destination: s.destination,\n };\n } else if (s.type === 'addDirectories' || s.type === 'removeDirectories') {\n return {\n type: s.type,\n directories: s.directories,\n destination: s.destination,\n };\n }\n // Fallback - should never reach here\n return s as PermissionUpdate;\n });\n\n const requestData: PermissionRequestData = {\n requestId,\n toolName,\n toolInput: input,\n toolUseId: options.toolUseID,\n suggestions,\n blockedPath: options.blockedPath,\n decisionReason: options.decisionReason,\n agentId: options.agentID,\n };\n\n // Store and emit event for daemon to broadcast to mobile\n this.pendingPermissionData = requestData;\n this.emit('permission-request', requestData);\n\n // Create promise that will be resolved when mobile responds\n return new Promise<PermissionResult>((resolve, reject) => {\n this.pendingPermissionRequests.set(requestId, {\n resolve,\n reject,\n signal: options.signal,\n toolInput: input,\n });\n\n // Handle abort\n options.signal.addEventListener('abort', () => {\n this.pendingPermissionRequests.delete(requestId);\n this.pendingPermissionData = null;\n reject(new Error('Permission request aborted'));\n });\n });\n };\n }\n\n setPermissionMode(mode: PermissionMode): void {\n const modeChanged = this.currentPermissionMode !== mode;\n this.currentPermissionMode = mode;\n\n // Permission mode is set at session creation time in V2.\n // Recreate session so the next prompt uses the new mode.\n if (modeChanged) {\n this.clearPendingInteractionState('Session reconfigured');\n this.clearCompactCompletionFallbackTimer();\n this.clearDeferredQueuedPromptTimer();\n this.awaitingCompactCompletionFallback = false;\n this.clearCompactLateResultSuppression();\n if (this.v2Session) {\n this.v2Session.close();\n this.v2Session = null;\n this.streamLoopRunning = false;\n this.sessionId = null;\n this.isProcessing = false;\n this.pendingPrompt = null;\n this.pendingContextTransfer = true;\n } else if (this.sessionId) {\n this.sessionId = null;\n this.pendingContextTransfer = true;\n }\n }\n\n this.emit('permission-mode', mode);\n }\n\n getPermissionMode(): PermissionMode {\n return this.currentPermissionMode;\n }\n\n async setThinkingMode(enabled: boolean): Promise<void> {\n this.thinkingEnabled = enabled;\n this.emit('thinking-mode', enabled);\n }\n\n getThinkingMode(): boolean {\n return this.thinkingEnabled;\n }\n\n /**\n * Build V2 session options from current state\n */\n private buildSessionOptions(): SDKSessionOptions {\n const opts: SDKSessionOptions = {\n // SDK accepts shorthand model names: 'opus' | 'sonnet' | 'haiku'\n // Full model IDs (e.g. 'claude-opus-4-6') are also valid but shorthand is preferred\n model: this.currentModel,\n allowedTools: this.options.allowedTools || ['Read', 'Edit', 'Write', 'Bash', 'Glob', 'Grep'],\n canUseTool: this.createCanUseTool(),\n permissionMode: this.currentPermissionMode,\n };\n return opts;\n }\n\n /**\n * Ensure a V2 session exists, creating one if needed\n */\n private ensureSession(): V2Session {\n if (!this.v2Session) {\n const opts = this.buildSessionOptions();\n\n if (this.sessionId) {\n // Resume existing session\n this.v2Session = unstable_v2_resumeSession(this.sessionId, opts);\n } else {\n // Create new session\n this.v2Session = unstable_v2_createSession(opts);\n }\n\n // Start the background message processing loop\n this.startStreamLoop();\n }\n return this.v2Session;\n }\n\n /**\n * Clear session state and retry the saved resume prompt with a fresh session.\n * Returns the saved prompt if a retry should happen, or null if not applicable.\n */\n private consumeResumeAttempt(): { prompt: string; attachments?: ImageAttachment[] } | null {\n const savedPrompt = this.resumeAttemptPrompt;\n if (!savedPrompt) return null;\n\n this.resumeAttemptPrompt = null;\n this.v2Session = null;\n this.sessionId = null;\n this.streamLoopRunning = false;\n this.isProcessing = false;\n\n // Remove the duplicate user history entry pushed by sendPrompt\n if (this.conversationHistory.length > 0 && this.conversationHistory[this.conversationHistory.length - 1].role === 'user') {\n this.conversationHistory.pop();\n }\n\n this.emit('resume-failed');\n return savedPrompt;\n }\n\n /**\n * Background loop that processes messages from the V2 session stream.\n * Runs continuously for the lifetime of the session.\n */\n private async startStreamLoop(): Promise<void> {\n if (this.streamLoopRunning || !this.v2Session) return;\n this.streamLoopRunning = true;\n\n let retrying = false;\n try {\n // The V2 stream() returns after each 'result' message.\n // For multi-turn sessions, we need to call stream() again after each result.\n while (this.v2Session && !this.v2Session['closed']) {\n for await (const message of this.v2Session.stream()) {\n this.processMessage(message);\n }\n }\n } catch (error) {\n if ((error as Error).name !== 'AbortError') {\n const savedPrompt = this.consumeResumeAttempt();\n if (savedPrompt) {\n retrying = true;\n this.sendPrompt(savedPrompt.prompt, savedPrompt.attachments).catch((retryErr) => {\n this.emit('error', retryErr);\n });\n } else {\n this.emit('error', error);\n }\n }\n } finally {\n this.streamLoopRunning = false;\n // If the stream loop exits without a 'result' message (e.g. unexpected\n // disconnect or error), ensure isProcessing is reset so subsequent\n // requests are not permanently blocked.\n // Skip cleanup if we're retrying with a fresh session.\n if (this.isProcessing && !retrying) {\n this.isProcessing = false;\n this.pendingPrompt = null;\n this.emit('complete');\n }\n }\n }\n\n /**\n * Process a single SDK message from the stream\n */\n private processMessage(message: SDKMessage): void {\n // Handle different message types\n if (message.type === 'system' && 'subtype' in message && message.subtype === 'init') {\n // Resume succeeded — clear the tracking flag\n this.resumeAttemptPrompt = null;\n\n // Capture session ID for resuming\n this.sessionId = message.session_id;\n this.emit('session-started', this.sessionId);\n\n // Emit permission mode if present\n if ('permissionMode' in message) {\n this.emit('permission-mode', message.permissionMode);\n }\n\n // Capture slash commands from init message (includes plugins/skills)\n if ('slash_commands' in message && Array.isArray(message.slash_commands)) {\n this.cachedCommands = message.slash_commands.map((cmd: unknown) => {\n if (typeof cmd === 'string') {\n return { name: cmd, description: '', argumentHint: '' };\n } else if (typeof cmd === 'object' && cmd !== null) {\n const cmdObj = cmd as SDKSlashCommand;\n return {\n name: cmdObj.name || '',\n description: cmdObj.description || '',\n argumentHint: cmdObj.argumentHint || '',\n };\n }\n return { name: String(cmd), description: '', argumentHint: '' };\n });\n this.emit('commands-updated', this.cachedCommands);\n }\n } else if (\n message.type === 'system' &&\n 'subtype' in message &&\n message.subtype === 'status' &&\n 'status' in message &&\n message.status === null &&\n this.awaitingCompactCompletionFallback &&\n this.isProcessing\n ) {\n // /compact can complete with status reset (compacting -> null) and no result message.\n this.scheduleCompactCompletionFallback();\n } else if (\n message.type === 'system' &&\n 'subtype' in message &&\n message.subtype === 'compact_boundary' &&\n this.awaitingCompactCompletionFallback &&\n this.isProcessing\n ) {\n // /compact can also complete with compact_boundary and no result message.\n this.scheduleCompactCompletionFallback();\n } else if (message.type === 'auth_status') {\n // Authentication status change from SDK\n const authMsg = message as { type: 'auth_status'; isAuthenticating: boolean; error?: string; output?: string[] };\n if (authMsg.error) {\n this.emit('auth-error', {\n errorCode: 'authentication_failed',\n message: authMsg.error,\n });\n }\n } else if (message.type === 'assistant') {\n // Check for API-level errors (auth failure, billing, rate limit, etc.)\n const assistantError = (message as any).error as string | undefined;\n if (assistantError) {\n this.emit('auth-error', {\n errorCode: assistantError,\n message: assistantError,\n });\n }\n // Assistant text output and tool use\n if (message.message?.content) {\n for (const block of message.message.content) {\n if ('type' in block && block.type === 'text' && 'text' in block) {\n this.emit('output', block.text);\n this.currentAssistantResponse += block.text;\n } else if ('type' in block && block.type === 'tool_use' && 'name' in block) {\n // AskUserQuestion tool_use blocks are handled via the canUseTool\n // callback (which emits 'user-question' and waits for the answer).\n const toolName = (block as any).name as string;\n if (toolName !== 'AskUserQuestion') {\n const input = (block as any).input || {};\n let toolUseData: ToolUseData;\n\n if (toolName === 'Edit' && input.file_path && input.old_string !== undefined) {\n toolUseData = {\n action: 'Edit',\n filePath: input.file_path,\n oldString: String(input.old_string).slice(0, MAX_TOOL_CONTENT),\n newString: String(input.new_string || '').slice(0, MAX_TOOL_CONTENT),\n };\n } else if (toolName === 'Write' && input.file_path) {\n toolUseData = {\n action: 'Write',\n filePath: input.file_path,\n content: String(input.content || '').slice(0, MAX_TOOL_CONTENT),\n };\n } else {\n toolUseData = {\n action: toolName,\n toolName,\n input,\n };\n }\n\n this.emit('tool-use', toolUseData);\n }\n }\n }\n }\n } else if (message.type === 'result') {\n this.clearCompactCompletionFallbackTimer();\n if (this.shouldIgnoreLateCompactResult()) {\n return;\n }\n\n // Emit result text if no assistant output was captured (e.g. slash commands like /context)\n if (!this.currentAssistantResponse.trim() && 'result' in message && message.result) {\n const resultText = String(message.result);\n this.emit('output', resultText);\n this.currentAssistantResponse = resultText;\n }\n // Final result - track assistant response in history\n if (this.currentAssistantResponse.trim()) {\n this.conversationHistory.push({ role: 'assistant', content: this.currentAssistantResponse.trim() });\n }\n\n this.currentAssistantResponse = '';\n this.awaitingCompactCompletionFallback = false;\n this.completeCurrentTurn();\n } else if (message.type === 'tool_progress') {\n // Tool progress (tool being used)\n if ('tool_name' in message) {\n this.emit('output', `\\n[Using tool: ${message.tool_name}]\\n`);\n }\n } else if (message.type === 'tool_use_summary') {\n // Tool use summary\n if ('tool_name' in message) {\n this.emit('output', `[Tool ${message.tool_name} completed]\\n`);\n }\n }\n }\n\n async sendPrompt(prompt: string, attachments?: ImageAttachment[]): Promise<void> {\n if (this.isProcessing) {\n // Queue the message instead of rejecting — last one wins\n this.pendingPrompt = { prompt, attachments };\n this.emit('request-queued');\n return;\n }\n\n this.clearCompactCompletionFallbackTimer();\n this.clearDeferredQueuedPromptTimer();\n this.awaitingCompactCompletionFallback = /^\\/compact(?:\\s|$)/.test(prompt.trim());\n this.activeTurnGeneration = ++this.turnGeneration;\n this.activeTurnStartedAtMs = Date.now();\n if (\n this.compactLateResultSuppressedGeneration !== null &&\n this.activeTurnGeneration > this.compactLateResultSuppressedGeneration + 1\n ) {\n this.clearCompactLateResultSuppression();\n }\n this.isProcessing = true;\n this.currentAssistantResponse = '';\n\n // Track user message in conversation history\n if (prompt.trim()) {\n this.conversationHistory.push({ role: 'user', content: prompt });\n }\n\n try {\n // Track resume attempt: if sessionId is set but no live session, we're about to resume\n if (this.sessionId && !this.v2Session) {\n this.resumeAttemptPrompt = { prompt, attachments };\n }\n\n // Build the prompt text, including context if transferring to new session\n let finalPrompt = prompt;\n if (this.pendingContextTransfer && this.conversationHistory.length > 1) {\n // Build context from previous conversation (excluding current message)\n const previousHistory = this.conversationHistory.slice(0, -1);\n const contextLines = previousHistory.map(msg =>\n `${msg.role === 'user' ? 'User' : 'Assistant'}: ${msg.content}`\n );\n const contextPrefix = `[Previous conversation context - you switched to a new model]\\n${contextLines.join('\\n')}\\n\\n[Continue with new message]\\n`;\n finalPrompt = contextPrefix + prompt;\n this.pendingContextTransfer = false;\n }\n\n // Ensure we have a V2 session\n const session = this.ensureSession();\n\n // Build message content\n const contentBlocks: Array<{ type: string; text?: string; source?: { type: string; media_type: string; data: string } }> = [];\n\n // Add images if present\n if (attachments && attachments.length > 0) {\n for (const attachment of attachments) {\n contentBlocks.push({\n type: 'image',\n source: {\n type: 'base64',\n media_type: attachment.mediaType,\n data: attachment.data,\n },\n });\n }\n }\n\n // Add text\n if (finalPrompt.trim()) {\n contentBlocks.push({\n type: 'text',\n text: finalPrompt,\n });\n }\n\n // Build and send the user message via V2 session.send()\n const userMessage: SDKUserMessage = {\n type: 'user' as const,\n message: {\n role: 'user' as const,\n content: contentBlocks.length > 0 ? contentBlocks : [{ type: 'text' as const, text: finalPrompt }],\n },\n parent_tool_use_id: null,\n session_id: this.sessionId || '',\n };\n\n await session.send(userMessage);\n } catch (error) {\n if ((error as Error).name !== 'AbortError') {\n const savedPrompt = this.consumeResumeAttempt();\n if (savedPrompt) {\n await this.sendPrompt(savedPrompt.prompt, savedPrompt.attachments);\n return;\n }\n }\n\n if ((error as Error).name === 'AbortError') {\n this.emit('output', '\\n[Cancelled]\\n');\n } else {\n this.emit('error', error);\n this.emit('output', `\\n[Error: ${(error as Error).message}]\\n`);\n }\n this.isProcessing = false;\n this.clearCompactCompletionFallbackTimer();\n this.clearDeferredQueuedPromptTimer();\n this.awaitingCompactCompletionFallback = false;\n }\n }\n\n /**\n * Provide an answer to a pending AskUserQuestion.\n *\n * AskUserQuestion flows through the canUseTool callback which blocks\n * waiting for a Promise to resolve. This method resolves that Promise\n * with the user's answers, which causes canUseTool to return\n * {behavior:'allow', updatedInput:{questions, answers}} → the SDK\n * sends the control_response back to the subprocess → it unblocks and\n * builds the tool_result for the Claude API.\n */\n async provideAnswer(answerText: string, answers?: Record<string, string>): Promise<void> {\n // Track in conversation history\n if (answerText.trim()) {\n this.conversationHistory.push({ role: 'user', content: answerText });\n }\n\n if (this.pendingAnswerRequest) {\n // Resolve the pending canUseTool callback with the answers\n const resolvedAnswers = answers || { result: answerText };\n const pendingRequest = this.pendingAnswerRequest;\n this.pendingAnswerRequest = null;\n pendingRequest.resolve(resolvedAnswers);\n return;\n }\n\n // No pending question - fall back to sendPrompt\n await this.sendPrompt(answerText);\n }\n\n cancel(): void {\n this.clearPendingInteractionState('Session cancelled');\n this.clearCompactCompletionFallbackTimer();\n this.clearDeferredQueuedPromptTimer();\n if (this.v2Session) {\n this.v2Session.close();\n this.v2Session = null;\n this.streamLoopRunning = false;\n }\n this.isProcessing = false;\n this.pendingPrompt = null;\n this.awaitingCompactCompletionFallback = false;\n this.clearCompactLateResultSuppression();\n }\n\n getSessionId(): string | null {\n return this.sessionId;\n }\n\n /**\n * Resume a different session by setting its ID.\n * The next sendPrompt call will use this session ID.\n */\n resumeSession(sessionId: string): void {\n // Close existing session if any\n if (this.v2Session) {\n this.v2Session.close();\n this.v2Session = null;\n this.streamLoopRunning = false;\n }\n this.sessionId = sessionId;\n this.isProcessing = false;\n this.pendingPrompt = null;\n this.clearCompactCompletionFallbackTimer();\n this.clearDeferredQueuedPromptTimer();\n this.awaitingCompactCompletionFallback = false;\n this.clearCompactLateResultSuppression();\n this.conversationHistory = []; // Clear local history since we're resuming a different session\n this.emit('session-resumed', sessionId);\n }\n\n isActive(): boolean {\n return this.isProcessing;\n }\n\n getPendingQuestionData(): UserQuestionData | null {\n return this.pendingQuestionData;\n }\n\n getPendingPermissionData(): PermissionRequestData | null {\n return this.pendingPermissionData;\n }\n\n hasPendingPrompt(): boolean {\n return this.pendingPrompt !== null;\n }\n\n async setModel(model: string): Promise<void> {\n if (model === this.currentModel) return;\n\n this.currentModel = model;\n this.clearPendingInteractionState('Session reconfigured');\n this.clearCompactCompletionFallbackTimer();\n this.clearDeferredQueuedPromptTimer();\n\n // Close existing session - a new one will be created with the new model on next sendPrompt()\n if (this.v2Session) {\n this.v2Session.close();\n this.v2Session = null;\n this.streamLoopRunning = false;\n this.sessionId = null;\n this.isProcessing = false;\n this.pendingPrompt = null;\n this.awaitingCompactCompletionFallback = false;\n this.clearCompactLateResultSuppression();\n this.pendingContextTransfer = true;\n } else if (this.sessionId) {\n this.sessionId = null;\n this.awaitingCompactCompletionFallback = false;\n this.clearCompactLateResultSuppression();\n this.pendingContextTransfer = true;\n }\n\n this.emit('model', model);\n }\n\n getModel(): string {\n return this.currentModel;\n }\n\n getConversationHistory(): ConversationMessage[] {\n return [...this.conversationHistory];\n }\n\n clearHistory(): void {\n this.conversationHistory = [];\n this.clearCompactCompletionFallbackTimer();\n this.clearDeferredQueuedPromptTimer();\n // Close existing session and force a fresh one on next prompt\n if (this.v2Session) {\n this.v2Session.close();\n this.v2Session = null;\n this.streamLoopRunning = false;\n }\n this.sessionId = null;\n this.isProcessing = false;\n this.pendingPrompt = null;\n this.awaitingCompactCompletionFallback = false;\n this.clearCompactLateResultSuppression();\n }\n\n private completeCompactCommandFallback(): void {\n this.clearCompactCompletionFallbackTimer();\n this.awaitingCompactCompletionFallback = false;\n this.compactLateResultSuppressedGeneration = this.activeTurnGeneration;\n this.currentAssistantResponse = '';\n this.completeCurrentTurn(COMPACT_QUEUED_DISPATCH_DELAY_MS);\n }\n\n private scheduleCompactCompletionFallback(): void {\n if (this.compactCompletionFallbackTimer) return;\n this.compactCompletionFallbackTimer = setTimeout(() => {\n this.compactCompletionFallbackTimer = null;\n if (this.awaitingCompactCompletionFallback && this.isProcessing) {\n this.completeCompactCommandFallback();\n }\n }, COMPACT_FALLBACK_GRACE_MS);\n }\n\n private clearCompactCompletionFallbackTimer(): void {\n if (this.compactCompletionFallbackTimer) {\n clearTimeout(this.compactCompletionFallbackTimer);\n this.compactCompletionFallbackTimer = null;\n }\n }\n\n private clearDeferredQueuedPromptTimer(): void {\n if (this.deferredQueuedPromptTimer) {\n clearTimeout(this.deferredQueuedPromptTimer);\n this.deferredQueuedPromptTimer = null;\n }\n }\n\n private clearCompactLateResultSuppression(): void {\n this.compactLateResultSuppressedGeneration = null;\n }\n\n private shouldIgnoreLateCompactResult(): boolean {\n const suppressedGeneration = this.compactLateResultSuppressedGeneration;\n if (suppressedGeneration === null) return false;\n\n this.clearCompactLateResultSuppression();\n\n if (this.activeTurnGeneration === suppressedGeneration) return true;\n\n if (this.activeTurnGeneration === suppressedGeneration + 1) {\n const elapsedSinceTurnStart = Date.now() - this.activeTurnStartedAtMs;\n return elapsedSinceTurnStart <= COMPACT_STALE_RESULT_GUARD_MS;\n }\n\n return false;\n }\n\n private completeCurrentTurn(deferQueuedDispatchMs: number = 0): void {\n if (!this.isProcessing) return;\n\n this.isProcessing = false;\n\n // Auto-send queued message if one is pending.\n if (!this.pendingPrompt) {\n this.emit('complete');\n return;\n }\n\n if (deferQueuedDispatchMs > 0) {\n this.clearDeferredQueuedPromptTimer();\n this.deferredQueuedPromptTimer = setTimeout(() => {\n this.deferredQueuedPromptTimer = null;\n const deferred = this.pendingPrompt;\n if (!deferred || this.isProcessing) return;\n this.pendingPrompt = null;\n // Don't emit 'complete' — mobile isTyping stays true seamlessly\n this.sendPrompt(deferred.prompt, deferred.attachments);\n }, deferQueuedDispatchMs);\n return;\n }\n\n const queued = this.pendingPrompt;\n this.pendingPrompt = null;\n // Don't emit 'complete' — mobile isTyping stays true seamlessly\n this.sendPrompt(queued.prompt, queued.attachments);\n }\n\n private clearPendingInteractionState(reason: string): void {\n if (this.pendingAnswerRequest) {\n this.pendingAnswerRequest.reject(new Error(reason));\n this.pendingAnswerRequest = null;\n }\n this.pendingQuestionData = null;\n this.pendingPermissionData = null;\n\n for (const pending of this.pendingPermissionRequests.values()) {\n pending.reject(new Error(reason));\n }\n this.pendingPermissionRequests.clear();\n }\n\n async getSupportedModels(): Promise<ModelInfo[]> {\n // Fallback models matching SDK response format\n const coreModels: ModelInfo[] = [\n { value: 'opus', displayName: 'Opus 4.6', description: 'Opus 4.6 · Most capable for complex work' },\n { value: 'haiku', displayName: 'Haiku 4.5', description: 'Haiku 4.5 · Fastest for quick answers' },\n { value: 'sonnet', displayName: 'Sonnet 4.6', description: 'Sonnet 4.6 · Best for everyday tasks' },\n ];\n\n // Return cached SDK models if available\n if (this.cachedModels) {\n return this.cachedModels;\n }\n\n return coreModels;\n }\n\n /**\n * Scan file system for custom commands/skills\n * Commands are in ~/.claude/commands/ and .claude/commands/\n * Subdirectories create namespaced commands (e.g., gsd/add-phase.md -> gsd:add-phase)\n */\n private scanCustomCommands(): SlashCommand[] {\n const commands: SlashCommand[] = [];\n const homeDir = os.homedir();\n\n // Directories to scan\n const dirs = [\n path.join(homeDir, '.claude', 'commands'), // Personal commands\n path.join(this.options.cwd, '.claude', 'commands'), // Project commands\n ];\n\n for (const dir of dirs) {\n if (!fs.existsSync(dir)) continue;\n\n try {\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n if (entry.isDirectory()) {\n // Namespaced commands (e.g., gsd/)\n const namespace = entry.name;\n const subDir = path.join(dir, namespace);\n const subEntries = fs.readdirSync(subDir);\n\n for (const file of subEntries) {\n if (file.endsWith('.md')) {\n const name = `${namespace}:${file.replace('.md', '')}`;\n const description = this.extractDescription(path.join(subDir, file));\n commands.push({ name, description, argumentHint: '' });\n }\n }\n } else if (entry.isFile() && entry.name.endsWith('.md')) {\n // Top-level commands\n const name = entry.name.replace('.md', '');\n const description = this.extractDescription(path.join(dir, entry.name));\n commands.push({ name, description, argumentHint: '' });\n }\n }\n } catch {\n // Ignore errors scanning directories\n }\n }\n\n return commands;\n }\n\n /**\n * Extract description from markdown file (first line or frontmatter)\n */\n private extractDescription(filePath: string): string {\n try {\n const content = fs.readFileSync(filePath, 'utf-8');\n const lines = content.split('\\n');\n\n // Check for frontmatter description\n if (lines[0] === '---') {\n for (let i = 1; i < lines.length; i++) {\n const line = lines[i];\n if (!line) continue;\n if (line === '---') break;\n if (line.startsWith('description:')) {\n return line.replace('description:', '').trim().replace(/^[\"']|[\"']$/g, '');\n }\n }\n }\n\n // Use first heading or first line as description\n for (const line of lines) {\n const trimmed = line.trim();\n if (trimmed.startsWith('# ')) {\n return trimmed.replace('# ', '');\n }\n if (trimmed && !trimmed.startsWith('---')) {\n return trimmed.slice(0, 100);\n }\n }\n } catch {\n // Ignore errors\n }\n return '';\n }\n\n async getSupportedCommands(): Promise<SlashCommand[]> {\n // Fallback commands - known Claude Code built-in commands\n const fallbackCommands: SlashCommand[] = [\n // Session management\n { name: 'help', description: 'Show all commands and custom slash commands', argumentHint: '' },\n { name: 'clear', description: 'Clear the conversation history', argumentHint: '' },\n { name: 'compact', description: 'Compress conversation by summarizing older messages', argumentHint: '' },\n { name: 'resume', description: 'Resume a previous conversation', argumentHint: '<session-id>' },\n { name: 'rewind', description: 'Go back to a previous message in the session', argumentHint: '' },\n { name: 'context', description: 'Check context and excluded skills', argumentHint: '' },\n // Configuration\n { name: 'config', description: 'Configure Claude Code settings interactively', argumentHint: '' },\n { name: 'permissions', description: 'View or update tool permissions', argumentHint: '' },\n { name: 'allowed-tools', description: 'Configure tool permissions interactively', argumentHint: '' },\n { name: 'model', description: 'Change the AI model', argumentHint: '' },\n { name: 'vim', description: 'Enable vim-style editing mode', argumentHint: '' },\n // Integrations\n { name: 'hooks', description: 'Configure hooks', argumentHint: '' },\n { name: 'mcp', description: 'Manage MCP servers', argumentHint: '' },\n { name: 'agents', description: 'Manage subagents (create, edit, list)', argumentHint: '' },\n { name: 'terminal-setup', description: 'Install terminal shortcuts for iTerm2/VS Code', argumentHint: '' },\n { name: 'install-github-app', description: 'Set up GitHub Actions integration', argumentHint: '' },\n { name: 'ide', description: 'Open in IDE or configure IDE integration', argumentHint: '' },\n // Project\n { name: 'init', description: 'Initialize Claude Code and generate CLAUDE.md', argumentHint: '' },\n { name: 'memory', description: 'Edit CLAUDE.md memory file', argumentHint: '' },\n { name: 'add-dir', description: 'Add a directory to the context', argumentHint: '<path>' },\n // Git & Code Review\n { name: 'commit', description: 'Commit changes to git with a generated message', argumentHint: '' },\n { name: 'review', description: 'Review code changes', argumentHint: '' },\n { name: 'review-pr', description: 'Review a GitHub pull request', argumentHint: '<pr-url>' },\n { name: 'pr-comments', description: 'Get comments from a GitHub pull request', argumentHint: '' },\n { name: 'release-notes', description: 'Generate release notes', argumentHint: '' },\n { name: 'security-review', description: 'Perform a security review', argumentHint: '' },\n // Account & System\n { name: 'login', description: 'Log in to your Anthropic account', argumentHint: '' },\n { name: 'logout', description: 'Log out of your Anthropic account', argumentHint: '' },\n { name: 'doctor', description: 'Check Claude Code health and configuration', argumentHint: '' },\n { name: 'bug', description: 'Report a bug to Anthropic', argumentHint: '' },\n { name: 'cost', description: 'Show token usage and cost', argumentHint: '' },\n { name: 'status', description: 'Show current session status', argumentHint: '' },\n ];\n\n // Get custom commands from file system (includes gsd:* etc.)\n const customCommands = this.scanCustomCommands();\n\n // Start with all commands\n let allCommands: SlashCommand[] = [...customCommands];\n\n // Add cached commands from init message\n if (this.cachedCommands && this.cachedCommands.length > 0) {\n const existingNames = new Set(allCommands.map(c => c.name));\n const newCached = this.cachedCommands.filter(c => !existingNames.has(c.name));\n allCommands = [...allCommands, ...newCached];\n }\n\n // Add fallback commands\n const existingNames = new Set(allCommands.map(c => c.name));\n const uniqueFallbacks = fallbackCommands.filter(c => !existingNames.has(c.name));\n allCommands = [...allCommands, ...uniqueFallbacks];\n\n allCommands = allCommands.filter(c => !UNSUPPORTED_COMMANDS.has(c.name));\n\n return allCommands;\n }\n}\n","import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';\nimport { join, dirname } from 'path';\nimport { homedir } from 'os';\nimport { isPermissionMode } from 'clautunnel-shared';\nimport type {\n InteractiveCommandType,\n InteractiveCommandData,\n InteractiveApplyPayload,\n InteractiveResult,\n InteractiveOption,\n PermissionMode,\n} from 'clautunnel-shared';\n\ninterface ClaudeSettings {\n preferences?: {\n verboseMode?: boolean;\n theme?: string;\n autoCompact?: boolean;\n };\n permissions?: {\n mode?: string;\n allowedTools?: string[];\n allow?: string[];\n };\n vim?: boolean;\n alwaysThinkingEnabled?: boolean;\n}\n\nexport interface ConfigManagerOptions {\n cwd?: string;\n homeDir?: string;\n}\n\nexport class ConfigManager {\n private claudeDir: string;\n private cwd: string;\n\n constructor(options: ConfigManagerOptions = {}) {\n const home = options.homeDir || homedir();\n this.claudeDir = join(home, '.claude');\n this.cwd = options.cwd || process.cwd();\n }\n\n private getGlobalSettingsPath(): string {\n return join(this.claudeDir, 'settings.json');\n }\n\n private getLocalSettingsPath(): string {\n return join(this.claudeDir, 'settings.local.json');\n }\n\n private getProjectSettingsPath(): string {\n return join(this.cwd, '.claude', 'settings.json');\n }\n\n private readSettingsFile(path: string): ClaudeSettings | null {\n try {\n if (existsSync(path)) {\n const content = readFileSync(path, 'utf-8');\n return JSON.parse(content);\n }\n } catch {\n // Silently ignore read errors\n }\n return null;\n }\n\n private writeSettingsFile(path: string, settings: ClaudeSettings): boolean {\n try {\n const dir = dirname(path);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n writeFileSync(path, JSON.stringify(settings, null, 2));\n return true;\n } catch {\n return false;\n }\n }\n\n private getMergedSettings(): ClaudeSettings {\n const global = this.readSettingsFile(this.getGlobalSettingsPath()) || {};\n const local = this.readSettingsFile(this.getLocalSettingsPath()) || {};\n const project = this.readSettingsFile(this.getProjectSettingsPath()) || {};\n\n // Merge settings with project > local > global precedence\n return {\n ...global,\n ...local,\n ...project,\n preferences: {\n ...global.preferences,\n ...local.preferences,\n ...project.preferences,\n },\n permissions: {\n ...global.permissions,\n ...local.permissions,\n ...project.permissions,\n },\n };\n }\n\n /**\n * Get the current thinking mode setting from merged settings\n */\n getThinkingMode(): boolean {\n const settings = this.getMergedSettings();\n return settings.alwaysThinkingEnabled ?? false;\n }\n\n /**\n * Get the current permission mode setting from merged settings\n */\n getPermissionMode(): PermissionMode {\n const settings = this.getMergedSettings();\n const mode = settings.permissions?.mode;\n return isPermissionMode(mode) ? mode : 'default';\n }\n\n getInteractiveData(command: InteractiveCommandType): InteractiveCommandData {\n const settings = this.getMergedSettings();\n\n switch (command) {\n case 'config':\n return this.getConfigData(settings);\n case 'permissions':\n return this.getPermissionsData(settings);\n case 'vim':\n return this.getVimData(settings);\n case 'allowed-tools':\n return this.getAllowedToolsData(settings);\n default:\n return {\n command,\n uiType: 'select',\n title: `${command} Settings`,\n description: 'This command is not yet supported in mobile.',\n options: [],\n };\n }\n }\n\n private getConfigData(settings: ClaudeSettings): InteractiveCommandData {\n const options: InteractiveOption[] = [\n {\n id: 'alwaysThinkingEnabled',\n label: 'Thinking Mode',\n description: 'Enable extended thinking for complex tasks',\n value: settings.alwaysThinkingEnabled || false,\n selected: settings.alwaysThinkingEnabled || false,\n },\n {\n id: 'autoCompact',\n label: 'Auto-Compact',\n description: 'Automatically compact conversation when context is full',\n value: settings.preferences?.autoCompact ?? true,\n selected: settings.preferences?.autoCompact ?? true,\n },\n ];\n\n return {\n command: 'config',\n uiType: 'nested',\n title: 'Configuration',\n description: 'Claude Code preferences and settings',\n options,\n };\n }\n\n private getPermissionsData(settings: ClaudeSettings): InteractiveCommandData {\n const currentMode = settings.permissions?.mode || 'default';\n const options: InteractiveOption[] = [\n {\n id: 'default',\n label: 'Default',\n description: 'Ask before making changes to files',\n value: 'default',\n selected: currentMode === 'default',\n },\n {\n id: 'acceptEdits',\n label: 'Auto-approve Edits',\n description: 'Automatically approve file edits',\n value: 'acceptEdits',\n selected: currentMode === 'acceptEdits',\n },\n {\n id: 'plan',\n label: 'Plan Mode',\n description: 'Only plan changes without executing',\n value: 'plan',\n selected: currentMode === 'plan',\n },\n {\n id: 'bypassPermissions',\n label: 'Yolo Mode',\n description: 'Bypass all permission prompts',\n value: 'bypassPermissions',\n selected: currentMode === 'bypassPermissions',\n },\n ];\n\n return {\n command: 'permissions',\n uiType: 'select',\n title: 'Permission Mode',\n description: 'Select how Claude handles file edits',\n options,\n currentValue: currentMode,\n };\n }\n\n private getVimData(settings: ClaudeSettings): InteractiveCommandData {\n const enabled = settings.vim ?? false;\n\n return {\n command: 'vim',\n uiType: 'toggle',\n title: 'Vim Mode',\n description: 'Enable vim keybindings in the editor',\n options: [\n {\n id: 'vim-enabled',\n label: 'Vim Mode',\n description: enabled ? 'Currently enabled' : 'Currently disabled',\n value: enabled,\n selected: enabled,\n },\n ],\n currentValue: enabled,\n };\n }\n\n private getAllowedToolsData(settings: ClaudeSettings): InteractiveCommandData {\n const allowedTools = settings.permissions?.allowedTools || [];\n const allTools = [\n { id: 'Bash', label: 'Bash', description: 'Execute shell commands' },\n { id: 'Read', label: 'Read', description: 'Read file contents' },\n { id: 'Write', label: 'Write', description: 'Write to files' },\n { id: 'Edit', label: 'Edit', description: 'Edit file contents' },\n { id: 'Glob', label: 'Glob', description: 'Search for files' },\n { id: 'Grep', label: 'Grep', description: 'Search file contents' },\n { id: 'WebFetch', label: 'WebFetch', description: 'Fetch web content' },\n { id: 'WebSearch', label: 'WebSearch', description: 'Search the web' },\n ];\n\n const options: InteractiveOption[] = allTools.map((tool) => ({\n ...tool,\n value: tool.id,\n selected: allowedTools.includes(tool.id),\n }));\n\n return {\n command: 'allowed-tools',\n uiType: 'multi-select',\n title: 'Allowed Tools',\n description: 'Select which tools Claude can use',\n options,\n currentValue: allowedTools,\n };\n }\n\n applyChange(payload: InteractiveApplyPayload): InteractiveResult {\n const globalPath = this.getGlobalSettingsPath();\n const settings = this.readSettingsFile(globalPath) || {};\n\n try {\n switch (payload.command) {\n case 'config':\n return this.applyConfigChange(settings, globalPath, payload);\n case 'permissions':\n return this.applyPermissionsChange(settings, globalPath, payload);\n case 'vim':\n return this.applyVimChange(settings, globalPath, payload);\n case 'allowed-tools':\n return this.applyAllowedToolsChange(settings, globalPath, payload);\n default:\n return {\n success: false,\n message: `Unknown command: ${payload.command}`,\n };\n }\n } catch (error) {\n return {\n success: false,\n message: error instanceof Error ? error.message : 'Unknown error',\n };\n }\n }\n\n private applyConfigChange(\n settings: ClaudeSettings,\n path: string,\n payload: InteractiveApplyPayload\n ): InteractiveResult {\n if (!settings.preferences) {\n settings.preferences = {};\n }\n\n switch (payload.key) {\n case 'theme':\n settings.preferences.theme = payload.value as string;\n break;\n case 'alwaysThinkingEnabled':\n // alwaysThinkingEnabled is at root level, not in preferences\n settings.alwaysThinkingEnabled = payload.value as boolean;\n break;\n case 'autoCompact':\n settings.preferences.autoCompact = payload.value as boolean;\n break;\n case 'verbose':\n settings.preferences.verboseMode = payload.value as boolean;\n break;\n default:\n return { success: false, message: `Unknown config key: ${payload.key}` };\n }\n\n if (this.writeSettingsFile(path, settings)) {\n return { success: true, message: `Config ${payload.key} updated` };\n }\n return { success: false, message: 'Failed to write settings file' };\n }\n\n private applyPermissionsChange(\n settings: ClaudeSettings,\n path: string,\n payload: InteractiveApplyPayload\n ): InteractiveResult {\n if (!settings.permissions) {\n settings.permissions = {};\n }\n\n settings.permissions.mode = payload.value as string;\n\n if (this.writeSettingsFile(path, settings)) {\n return { success: true, message: `Permission mode set to ${payload.value}` };\n }\n return { success: false, message: 'Failed to write settings file' };\n }\n\n private applyVimChange(\n settings: ClaudeSettings,\n path: string,\n payload: InteractiveApplyPayload\n ): InteractiveResult {\n if (payload.action === 'toggle') {\n settings.vim = !settings.vim;\n } else {\n settings.vim = payload.value as boolean;\n }\n\n if (this.writeSettingsFile(path, settings)) {\n return { success: true, message: `Vim mode ${settings.vim ? 'enabled' : 'disabled'}` };\n }\n return { success: false, message: 'Failed to write settings file' };\n }\n\n private applyAllowedToolsChange(\n settings: ClaudeSettings,\n path: string,\n payload: InteractiveApplyPayload\n ): InteractiveResult {\n if (!settings.permissions) {\n settings.permissions = {};\n }\n if (!settings.permissions.allowedTools) {\n settings.permissions.allowedTools = [];\n }\n\n const toolId = payload.value as string;\n\n switch (payload.action) {\n case 'add':\n if (!settings.permissions.allowedTools.includes(toolId)) {\n settings.permissions.allowedTools.push(toolId);\n }\n break;\n case 'remove':\n settings.permissions.allowedTools = settings.permissions.allowedTools.filter(\n (t) => t !== toolId\n );\n break;\n case 'set':\n settings.permissions.allowedTools = payload.value as string[];\n break;\n case 'toggle':\n if (settings.permissions.allowedTools.includes(toolId)) {\n settings.permissions.allowedTools = settings.permissions.allowedTools.filter(\n (t) => t !== toolId\n );\n } else {\n settings.permissions.allowedTools.push(toolId);\n }\n break;\n }\n\n if (this.writeSettingsFile(path, settings)) {\n return { success: true, message: 'Allowed tools updated' };\n }\n return { success: false, message: 'Failed to write settings file' };\n }\n}\n","import { Command } from 'commander';\nimport WebSocket from 'ws';\nimport { Daemon } from '../daemon/daemon.js';\nimport { MachineManager } from '../daemon/machine.js';\nimport { MachineRealtimeClient } from '../realtime/machine-client.js';\nimport { Config, ConfigurationError } from '../utils/config.js';\nimport { Logger } from '../utils/logger.js';\nimport { Spinner } from '../utils/spinner.js';\nimport { createSupabaseClient, restoreSession } from '../utils/supabase.js';\nimport {\n promptYesNo,\n enableSleepPrevention,\n startCaffeinate,\n cleanup as cleanupSleep,\n isMacOS,\n checkFullDiskAccess,\n getFullDiskAccessStatus,\n getTerminalAppName,\n openFullDiskAccessSettings,\n type SleepPreventionState,\n type FullDiskAccessStatus,\n} from '../utils/sleep-prevention.js';\nimport { existsSync } from 'fs';\nimport { join, resolve } from 'path';\nimport { MobileServerManager } from '../mobile/mobile-server.js';\nimport { acquirePidFile, removePidFile } from '../utils/pid.js';\nimport { checkClaudeCliAuth } from '../utils/claude-auth.js';\nimport type { MachineCommand } from 'clautunnel-shared';\n\n// Polyfill WebSocket for Node.js (Supabase Realtime needs this)\nif (typeof globalThis.WebSocket === 'undefined') {\n // @ts-expect-error WebSocket polyfill for Node.js\n globalThis.WebSocket = WebSocket;\n}\n\nexport interface StartOptions {\n name?: string;\n preventSleep?: boolean;\n mobile?: boolean;\n}\n\nexport function createStartCommand(): Command {\n const command = new Command('start');\n\n command\n .description('Start ClauTunnel and listen for session requests from mobile app')\n .option('-n, --name <name>', 'Machine name')\n .option('--prevent-sleep', 'Auto-enable sleep prevention (skip prompt)')\n .option('--no-mobile', 'Skip mobile server startup')\n .action(async (options: StartOptions) => {\n const config = new Config();\n const logger = new Logger();\n const spinner = new Spinner('Starting ClauTunnel...');\n\n const daemons: Map<string, Daemon> = new Map(); // sessionId -> Daemon\n let machineClient: MachineRealtimeClient | null = null;\n\n try {\n // Enforce single process per machine (atomic check + acquire)\n const existingPid = acquirePidFile();\n if (existingPid !== null) {\n logger.error(`Another clautunnel process is already running (PID: ${existingPid})`);\n logger.error('Run \"clautunnel stop\" first, or kill the existing process.');\n process.exit(1);\n }\n\n config.requireConfiguration();\n\n spinner.start();\n\n const supabase = createSupabaseClient(\n config.getSupabaseUrl(),\n config.getSupabaseAnonKey(),\n { realtime: true }\n );\n\n // Restore session from stored tokens\n spinner.update('Authenticating...');\n\n const session = await restoreSession(supabase, config);\n if (!session) {\n spinner.fail('Not authenticated');\n logger.error(\n 'Run \"clautunnel login\" or \"clautunnel signup\" first.'\n );\n removePidFile();\n process.exit(1);\n }\n\n const { user } = session;\n\n // Persist tokens when Supabase auto-refreshes during long-running sessions\n const {\n data: { subscription: authSubscription },\n } = supabase.auth.onAuthStateChange((event, authSession) => {\n if (event === 'TOKEN_REFRESHED' && authSession) {\n config.setSessionTokens({\n accessToken: authSession.access_token,\n refreshToken: authSession.refresh_token,\n });\n }\n });\n\n spinner.update(`Authenticated as ${user.email}...`);\n\n // Check Claude CLI authentication (Anthropic API)\n spinner.update('Checking Claude CLI auth...');\n const claudeAuth = checkClaudeCliAuth();\n if (!claudeAuth.loggedIn) {\n switch (claudeAuth.failure) {\n case 'cli_not_found':\n spinner.fail('Claude CLI not found');\n logger.error('Claude Code CLI is not installed or not in PATH.');\n logger.error('Install it first: https://docs.anthropic.com/en/docs/claude-code');\n removePidFile();\n process.exit(1);\n break;\n case 'subcommand_not_supported':\n // Older CLI version that doesn't have `auth status` — skip the check\n spinner.update('Claude CLI auth check skipped (CLI version does not support \"auth status\")');\n logger.warn('Could not verify Claude CLI auth — your CLI version may not support \"claude auth status\".');\n logger.warn('If sessions fail to start, try updating Claude Code and running \"claude login\".');\n break;\n case 'not_logged_in':\n spinner.fail('Claude CLI is not logged in');\n logger.error('Claude Code requires authentication to use the Anthropic API.');\n logger.error('Run \"claude login\" first, then try \"clautunnel start\" again.');\n removePidFile();\n process.exit(1);\n break;\n default:\n // Unknown error — warn but don't block\n spinner.update('Claude CLI auth check inconclusive');\n logger.warn('Could not verify Claude CLI authentication (unexpected error).');\n logger.warn('If sessions fail to start, run \"claude login\" and try again.');\n break;\n }\n }\n\n // Check Full Disk Access (macOS only)\n let fdaStatus: FullDiskAccessStatus | null = null;\n\n if (isMacOS()) {\n spinner.stop();\n\n const terminalApp = getTerminalAppName();\n let fdaEnabled = checkFullDiskAccess();\n fdaStatus = getFullDiskAccessStatus(fdaEnabled, terminalApp);\n\n if (fdaStatus.enabled) {\n logger.info(`✓ Full Disk Access: ${fdaStatus.label}`);\n } else {\n logger.warn(`⚠ Full Disk Access: ${fdaStatus.label}`);\n logger.warn('');\n for (const line of fdaStatus.warning!.split('\\n')) {\n logger.warn(` ${line}`);\n }\n logger.warn('');\n\n const openSettings = await promptYesNo(\n 'Open Full Disk Access settings? [Y/n]: '\n );\n\n if (openSettings) {\n openFullDiskAccessSettings();\n logger.info('');\n await promptYesNo(\n 'Press Enter after enabling Full Disk Access (or Enter to skip): '\n );\n\n // Recheck FDA status\n fdaEnabled = checkFullDiskAccess();\n fdaStatus = getFullDiskAccessStatus(fdaEnabled, terminalApp);\n\n if (fdaStatus.enabled) {\n logger.info('✓ Full Disk Access: Enabled');\n } else {\n logger.warn('Full Disk Access still not enabled. Continuing without it.');\n }\n }\n\n logger.info('');\n }\n\n spinner.start();\n }\n\n // Handle sleep prevention (macOS only)\n const sleepState: SleepPreventionState = {\n caffeinateProcess: null,\n pmsetEnabled: false,\n };\n\n if (isMacOS()) {\n spinner.stop();\n\n // Auto-enable if --prevent-sleep flag is used, otherwise ask\n const enableSleep =\n options.preventSleep ||\n (await promptYesNo(\n 'Prevent sleep when lid is closed? (keeps clautunnel running) [y/N]: '\n ));\n\n if (enableSleep) {\n logger.info('');\n logger.info('Enabling sleep prevention...');\n if (!options.preventSleep) {\n logger.info('This requires sudo password (auto-restored on exit)');\n logger.info('');\n }\n\n sleepState.pmsetEnabled = enableSleepPrevention();\n if (sleepState.pmsetEnabled) {\n logger.info('✓ Lid-closed mode enabled');\n } else {\n logger.warn('Failed to enable lid-closed mode. Using basic mode.');\n }\n\n // Start caffeinate to prevent idle sleep\n sleepState.caffeinateProcess = startCaffeinate();\n\n sleepState.caffeinateProcess.on('error', () => {\n logger.warn('Failed to start caffeinate');\n });\n\n logger.info('');\n }\n\n spinner.start();\n }\n\n // Mobile server\n let mobileServer: MobileServerManager | null = null;\n\n if (options.mobile !== false) {\n // Create a pairing code via Edge Function (service role insert, not direct RLS).\n // supabase.functions is a getter that creates a new FunctionsClient each time\n // and doesn't inherit the refreshed session token, so we pass it explicitly.\n const { data: { session: currentSession } } = await supabase.auth.getSession();\n const { data: pairingData, error: pairingError } = await supabase\n .functions.invoke('create-mobile-pairing', {\n headers: { Authorization: `Bearer ${currentSession?.access_token}` },\n });\n\n if (pairingError || !pairingData?.code) {\n spinner.fail('Failed to create mobile pairing code');\n logger.error(pairingError?.message ?? 'No pairing code returned');\n removePidFile();\n process.exit(1);\n }\n\n const pairingCode = pairingData.code;\n\n let mobileProjectPath = config.getMobileProjectPath();\n\n // Auto-detect local mobile project when running from within the monorepo\n if (!mobileProjectPath) {\n const siblingMobile = resolve(process.cwd(), '..', 'mobile');\n if (existsSync(join(siblingMobile, 'package.json'))) {\n mobileProjectPath = siblingMobile;\n }\n }\n\n mobileServer = new MobileServerManager({\n mobileProjectPath,\n supabaseUrl: config.getSupabaseUrl(),\n supabaseAnonKey: config.getSupabaseAnonKey(),\n pairingCode,\n onProgress: (msg) => spinner.update(msg),\n });\n\n const result = await mobileServer.start();\n spinner.stop();\n\n if (result.started) {\n logger.info('');\n logger.info(` Tunnel: ${result.tunnelUrl}`);\n logger.info('');\n } else {\n logger.error(`Mobile server failed: ${result.error}`);\n removePidFile();\n process.exit(1);\n }\n\n spinner.start();\n }\n\n // Cleanup helper\n const cleanup = async () => {\n removePidFile();\n if (mobileServer) {\n try {\n await mobileServer.stop();\n } catch {\n // Best-effort cleanup\n }\n }\n if (sleepState.pmsetEnabled) {\n console.log('Restoring sleep settings...');\n }\n cleanupSleep(sleepState);\n };\n\n spinner.update('Registering machine...');\n\n // Register machine\n const machineManager = new MachineManager({ supabase });\n const machine = await machineManager.registerMachine(\n user.id,\n options.name,\n config.getMachineId()\n );\n\n // Save machine ID for future use\n config.setMachineId(machine.id);\n\n // Handle process signals — registered after machine is available\n // so gracefulShutdown can reliably set offline status\n let isShuttingDown = false;\n\n const gracefulShutdown = async (signal: string) => {\n if (isShuttingDown) {\n console.log('\\nForce exiting...');\n process.exit(1);\n }\n isShuttingDown = true;\n console.log(`\\n[${signal}] Shutting down gracefully...`);\n try {\n for (const [sessionId, d] of daemons) {\n try {\n await d.stop();\n } catch {\n // Continue stopping other daemons\n }\n daemons.delete(sessionId);\n }\n // Set machine status to offline now that all sessions are stopped\n try {\n await machineManager.updateMachineStatus(machine.id, 'offline');\n } catch {\n // Best-effort - don't block shutdown\n }\n if (machineClient) {\n await machineClient.disconnect();\n machineClient = null;\n }\n authSubscription.unsubscribe();\n console.log('[Cleanup] All sessions ended in database');\n await cleanup();\n } catch (error) {\n console.error('[Cleanup] Error during shutdown:', error);\n }\n process.exit(0);\n };\n\n process.on('SIGINT', () => {\n gracefulShutdown('SIGINT').catch(console.error);\n });\n\n process.on('SIGTERM', () => {\n gracefulShutdown('SIGTERM').catch(console.error);\n });\n\n spinner.update('Connecting to realtime...');\n\n // Create machine-level realtime client\n machineClient = new MachineRealtimeClient({\n supabase,\n machineId: machine.id,\n });\n\n const connected = await machineClient.connect();\n\n spinner.stop();\n\n if (!connected) {\n logger.error('Failed to connect to Supabase Realtime.');\n logger.error('');\n logger.error('This may be a temporary issue. Try the following:');\n logger.error(' 1. Open a new terminal and run \"clautunnel start\" again');\n logger.error(' 2. Check your network connection');\n logger.error(' 3. Try \"clautunnel login\" to refresh your session');\n removePidFile();\n process.exit(1);\n }\n\n logger.info('');\n logger.info('✓ ClauTunnel is ready!');\n logger.info(` Machine: ${machine.name}`);\n if (fdaStatus) {\n if (fdaStatus.enabled) {\n logger.info(` Full Disk Access: ${fdaStatus.label}`);\n } else {\n logger.warn(` Full Disk Access: ${fdaStatus.label}`);\n }\n }\n if (sleepState.caffeinateProcess) {\n logger.info(\n ` Sleep prevention: ${sleepState.pmsetEnabled ? 'Lid-closed mode' : 'Basic mode'}`\n );\n }\n if (mobileServer) {\n logger.info(' Mobile server: Running');\n }\n logger.info('');\n logger.info('Open the mobile app to start a session.');\n logger.info('Press Ctrl+C to stop.');\n logger.info('');\n\n // Handle incoming commands from mobile\n machineClient.on('command', async (cmd: MachineCommand) => {\n if (cmd.type === 'start-session') {\n logger.info('Starting session (requested from mobile)...');\n\n try {\n const newDaemon = new Daemon({\n supabase,\n userId: user.id,\n machineId: machine.id,\n machineName: options.name,\n cwd: process.cwd(),\n hybrid: false,\n });\n\n newDaemon.on('started', async ({ session }) => {\n daemons.set(session.id, newDaemon);\n\n logger.info(` Session: ${session.id.slice(0, 8)}...`);\n logger.info(' Mobile sync: Enabled');\n logger.info(` Active sessions: ${daemons.size}`);\n logger.info('');\n\n await machineClient?.broadcastSessionStarted(\n session.id,\n process.cwd()\n );\n });\n\n newDaemon.on('error', (error: Error) => {\n logger.error(`Session error: ${error.message}`);\n });\n\n newDaemon.on('mobile-input', (prompt: string, attachments?: unknown[]) => {\n const hasImages = attachments && attachments.length > 0;\n const imageInfo = hasImages ? ` [+${attachments.length} image${attachments.length > 1 ? 's' : ''}]` : '';\n logger.info(`[Mobile] ${prompt}${imageInfo}`);\n });\n\n newDaemon.on('mobile-output', (data: string) => {\n const trimmed = data.trim();\n if (trimmed) {\n logger.info(`[Claude] ${trimmed}`);\n }\n });\n\n newDaemon.on('mobile-disconnected', async () => {\n logger.info('Mobile disconnected. Ending session...');\n try {\n await newDaemon.stop();\n } catch {\n // Silently handle stop errors - stopped handler handles the rest\n }\n });\n\n newDaemon.on('stopped', async () => {\n const sessionId = newDaemon.getSession()?.id;\n if (sessionId) {\n daemons.delete(sessionId);\n await machineClient?.broadcastSessionEnded(sessionId);\n }\n\n logger.info('Session ended.');\n logger.info(` Active sessions: ${daemons.size}`);\n logger.info('');\n if (daemons.size === 0) {\n logger.info('Waiting for next session request...');\n logger.info('');\n }\n });\n\n await newDaemon.start();\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : 'Unknown error';\n logger.error(`Failed to start session: ${errorMessage}`);\n await machineClient?.broadcastError(errorMessage);\n }\n }\n\n if (cmd.type === 'stop-session' && cmd.sessionId) {\n const targetDaemon = daemons.get(cmd.sessionId);\n if (targetDaemon) {\n logger.info(`Stopping session ${cmd.sessionId.slice(0, 8)}... (requested from mobile)`);\n try {\n await targetDaemon.stop();\n } catch {\n // Silently handle stop errors\n }\n }\n }\n });\n } catch (error) {\n removePidFile();\n if (error instanceof ConfigurationError) {\n spinner.stop();\n logger.error(error.message);\n process.exit(1);\n }\n spinner.fail('Failed to start');\n logger.error(\n `${error instanceof Error ? error.message : 'Unknown error'}`\n );\n process.exit(1);\n }\n });\n\n return command;\n}\n","import { EventEmitter } from 'events';\nimport type { SupabaseClient, RealtimeChannel } from '@supabase/supabase-js';\nimport type { MachineCommand, PresencePayload } from 'clautunnel-shared';\nimport { REALTIME_CHANNELS } from 'clautunnel-shared';\nimport { subscribeWithTimeout } from './utils.js';\n\nexport interface MachineRealtimeClientOptions {\n supabase: SupabaseClient;\n machineId: string;\n}\n\nexport class MachineRealtimeClient extends EventEmitter {\n private supabase: SupabaseClient;\n private machineId: string;\n private inputChannel: RealtimeChannel | null = null;\n private outputChannel: RealtimeChannel | null = null;\n private presenceChannel: RealtimeChannel | null = null;\n\n constructor(options: MachineRealtimeClientOptions) {\n super();\n this.supabase = options.supabase;\n this.machineId = options.machineId;\n }\n\n async connect(): Promise<boolean> {\n const privateConfig = { config: { private: true } };\n\n // Subscribe to input channel (receives commands from mobile)\n const inputChannelName = REALTIME_CHANNELS.machineInput(this.machineId);\n this.inputChannel = this.supabase.channel(inputChannelName, privateConfig);\n\n this.inputChannel.on('broadcast', { event: 'machine-command' }, (payload) => {\n this.emit('command', payload.payload as MachineCommand);\n });\n\n // Subscribe to output channel (sends responses to mobile)\n const outputChannelName = REALTIME_CHANNELS.machineOutput(this.machineId);\n this.outputChannel = this.supabase.channel(outputChannelName, privateConfig);\n\n const results = await Promise.all([\n subscribeWithTimeout(this.inputChannel, 'machine-input'),\n subscribeWithTimeout(this.outputChannel, 'machine-output'),\n ]);\n\n const connected = results.every((success) => success);\n\n // Set up presence channel to track listener online status\n if (connected) {\n const presenceChannelName = REALTIME_CHANNELS.machinePresence(this.machineId);\n this.presenceChannel = this.supabase.channel(presenceChannelName, privateConfig);\n\n this.presenceChannel.subscribe(async (status) => {\n if (status === 'SUBSCRIBED' && this.presenceChannel) {\n try {\n const payload: PresencePayload = {\n type: 'cli',\n online_at: new Date().toISOString(),\n };\n await this.presenceChannel.track(payload);\n } catch (trackError) {\n console.warn('[WARN] Failed to track machine presence:', trackError);\n }\n }\n });\n }\n\n return connected;\n }\n\n async broadcastSessionStarted(sessionId: string, workingDirectory: string): Promise<void> {\n if (!this.outputChannel) return;\n\n const command: MachineCommand = {\n type: 'session-started',\n sessionId,\n workingDirectory,\n timestamp: Date.now(),\n };\n\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'machine-command',\n payload: command,\n });\n }\n\n async broadcastSessionEnded(sessionId: string): Promise<void> {\n if (!this.outputChannel) return;\n\n const command: MachineCommand = {\n type: 'session-ended',\n sessionId,\n timestamp: Date.now(),\n };\n\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'machine-command',\n payload: command,\n });\n }\n\n async broadcastError(error: string): Promise<void> {\n if (!this.outputChannel) return;\n\n const command: MachineCommand = {\n type: 'start-session-error',\n error,\n timestamp: Date.now(),\n };\n\n await this.outputChannel.send({\n type: 'broadcast',\n event: 'machine-command',\n payload: command,\n });\n }\n\n async disconnect(): Promise<void> {\n if (this.presenceChannel) {\n await this.presenceChannel.untrack();\n await this.supabase.removeChannel(this.presenceChannel);\n this.presenceChannel = null;\n }\n\n if (this.inputChannel) {\n await this.supabase.removeChannel(this.inputChannel);\n this.inputChannel = null;\n }\n\n if (this.outputChannel) {\n await this.supabase.removeChannel(this.outputChannel);\n this.outputChannel = null;\n }\n\n this.emit('disconnected');\n }\n}\n","export class Spinner {\n private frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];\n private currentFrame = 0;\n private interval: NodeJS.Timeout | null = null;\n private message: string;\n private stream: NodeJS.WriteStream;\n\n constructor(message: string, stream: NodeJS.WriteStream = process.stdout) {\n this.message = message;\n this.stream = stream;\n }\n\n start(): void {\n if (this.interval) {\n return;\n }\n\n // Hide cursor\n this.stream.write('\\x1B[?25l');\n\n this.interval = setInterval(() => {\n const frame = this.frames[this.currentFrame];\n this.stream.write(`\\r${frame} ${this.message}`);\n this.currentFrame = (this.currentFrame + 1) % this.frames.length;\n }, 80);\n }\n\n update(message: string): void {\n this.message = message;\n }\n\n stop(): void {\n if (this.interval) {\n clearInterval(this.interval);\n this.interval = null;\n }\n\n // Clear the line and show cursor\n this.stream.write('\\r\\x1B[K');\n this.stream.write('\\x1B[?25h');\n }\n\n succeed(message: string): void {\n this.stop();\n this.stream.write(`\\r✓ ${message}\\n`);\n }\n\n fail(message: string): void {\n this.stop();\n this.stream.write(`\\r✗ ${message}\\n`);\n }\n}\n","import { createClient, type SupabaseClient } from '@supabase/supabase-js';\n\nexport interface CreateSupabaseClientOptions {\n realtime?: boolean;\n}\n\nexport function createSupabaseClient(\n url: string,\n anonKey: string,\n options?: CreateSupabaseClientOptions\n): SupabaseClient {\n const clientOptions = options?.realtime\n ? {\n realtime: {\n params: { eventsPerSecond: 10 },\n timeout: 30000,\n },\n }\n : undefined;\n\n return createClient(url, anonKey, clientOptions);\n}\n\nexport interface SessionTokenStore {\n getSessionTokens(): { accessToken: string; refreshToken: string } | null;\n setSessionTokens(tokens: { accessToken: string; refreshToken: string }): void;\n clearSessionTokens(): void;\n}\n\nexport async function restoreSession(\n supabase: SupabaseClient,\n config: SessionTokenStore\n): Promise<{ user: any } | null> {\n const sessionTokens = config.getSessionTokens();\n if (!sessionTokens) {\n return null;\n }\n\n const { data: sessionData, error: sessionError } =\n await supabase.auth.setSession({\n access_token: sessionTokens.accessToken,\n refresh_token: sessionTokens.refreshToken,\n });\n\n if (sessionError) {\n config.clearSessionTokens();\n return null;\n }\n\n // Persist refreshed tokens if Supabase rotated them\n if (sessionData?.session) {\n const newAccess = sessionData.session.access_token;\n const newRefresh = sessionData.session.refresh_token;\n if (\n newAccess !== sessionTokens.accessToken ||\n newRefresh !== sessionTokens.refreshToken\n ) {\n config.setSessionTokens({\n accessToken: newAccess,\n refreshToken: newRefresh,\n });\n }\n }\n\n const {\n data: { user },\n error: authError,\n } = await supabase.auth.getUser();\n\n if (authError || !user) {\n return null;\n }\n\n return { user };\n}\n","import { spawn, execSync, type ChildProcess } from 'child_process';\nimport * as readline from 'readline';\nimport { readdirSync } from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\n\nexport interface SleepPreventionState {\n caffeinateProcess: ChildProcess | null;\n pmsetEnabled: boolean;\n}\n\nexport async function promptYesNo(question: string): Promise<boolean> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');\n });\n });\n}\n\nexport function enableSleepPrevention(): boolean {\n try {\n execSync('sudo pmset -a disablesleep 1', { stdio: 'inherit' });\n return true;\n } catch {\n return false;\n }\n}\n\nexport function disableSleepPrevention(): void {\n try {\n execSync('sudo pmset -a disablesleep 0', { stdio: 'inherit' });\n } catch {\n // Ignore errors on cleanup\n }\n}\n\nexport function startCaffeinate(): ChildProcess {\n const process = spawn('caffeinate', ['-i', '-s'], {\n stdio: 'ignore',\n detached: false,\n });\n\n return process;\n}\n\nexport function stopCaffeinate(process: ChildProcess | null): void {\n if (process) {\n process.kill();\n }\n}\n\nexport function cleanup(state: SleepPreventionState): void {\n stopCaffeinate(state.caffeinateProcess);\n if (state.pmsetEnabled) {\n disableSleepPrevention();\n }\n}\n\nexport function isMacOS(): boolean {\n return process.platform === 'darwin';\n}\n\nexport interface FullDiskAccessStatus {\n enabled: boolean;\n label: string;\n warning?: string;\n}\n\n/**\n * Checks if Full Disk Access is granted on macOS by attempting to read\n * a TCC-protected directory. Returns true on non-macOS platforms.\n */\nexport function checkFullDiskAccess(): boolean {\n if (!isMacOS()) return true;\n\n try {\n const safariDir = path.join(os.homedir(), 'Library', 'Safari');\n readdirSync(safariDir);\n return true;\n } catch {\n return false;\n }\n}\n\nconst TERM_PROGRAM_MAP: Record<string, string> = {\n vscode: 'Visual Studio Code',\n Apple_Terminal: 'Terminal',\n 'iTerm.app': 'iTerm2',\n WarpTerminal: 'Warp',\n Hyper: 'Hyper',\n};\n\n/**\n * Detects the terminal application name from the TERM_PROGRAM environment variable.\n */\nexport function getTerminalAppName(): string {\n const termProgram = process.env.TERM_PROGRAM;\n if (termProgram && TERM_PROGRAM_MAP[termProgram]) {\n return TERM_PROGRAM_MAP[termProgram];\n }\n return 'your terminal app';\n}\n\n/**\n * Opens macOS System Settings to the Full Disk Access pane.\n * Returns true on success, false on failure or non-macOS platforms.\n */\nexport function openFullDiskAccessSettings(): boolean {\n if (!isMacOS()) return false;\n\n try {\n execSync(\n 'open \"x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles\"'\n );\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Returns a structured status object with label and optional warning message\n * describing the Full Disk Access state and its implications for remote usage.\n */\nexport function getFullDiskAccessStatus(enabled: boolean, terminalApp?: string): FullDiskAccessStatus {\n if (enabled) {\n return {\n enabled: true,\n label: 'Enabled',\n };\n }\n\n const appName = terminalApp || 'your terminal app';\n\n return {\n enabled: false,\n label: 'Not enabled',\n warning: [\n 'Without Full Disk Access, macOS may show permission dialogs',\n 'when Claude tries to access certain files or directories.',\n 'These dialogs are only visible on this machine\\'s screen —',\n 'you won\\'t be able to see or approve them from the mobile app,',\n 'which will cause Claude\\'s operations to silently hang.',\n '',\n 'To enable:',\n ` 1. Open System Settings → Privacy & Security → Full Disk Access`,\n ` 2. Toggle ON \"${appName}\" in the list`,\n ' 3. Restart your terminal and run \"clautunnel start\" again',\n ].join('\\n'),\n };\n}\n","import { spawn, execSync, type ChildProcess } from 'child_process';\nimport {\n existsSync,\n mkdirSync,\n writeFileSync,\n createWriteStream,\n type WriteStream,\n} from 'fs';\nimport { join } from 'path';\nimport { homedir } from 'os';\nimport { get } from 'http';\nimport qrcode from 'qrcode-terminal';\n\nconst REPO_URL = 'https://github.com/TongilKim/ClauTunnel.git';\nconst DEFAULT_MOBILE_DIR = join(homedir(), '.clautunnel', 'mobile');\n\nexport interface MobileServerOptions {\n mobileProjectPath?: string;\n supabaseUrl: string;\n supabaseAnonKey: string;\n pairingCode?: string;\n expoPort?: number;\n logDir?: string;\n onProgress?: (message: string) => void;\n}\n\nexport interface MobileServerResult {\n started: boolean;\n tunnelUrl?: string;\n error?: string;\n}\n\ninterface PrerequisiteResult {\n ready: boolean;\n issues: string[];\n needsInstall: boolean;\n}\n\nexport class MobileServerManager {\n private options: MobileServerOptions;\n private mobileProjectPath: string;\n private logDir: string;\n private expoPort: number;\n private ngrokProcess: ChildProcess | null = null;\n private expoProcess: ChildProcess | null = null;\n private ngrokLogStream: WriteStream | null = null;\n private expoLogStream: WriteStream | null = null;\n private tunnelUrl: string | null = null;\n private onProgress: (message: string) => void;\n private hasCustomPath: boolean;\n\n constructor(options: MobileServerOptions) {\n this.options = options;\n this.hasCustomPath = options.mobileProjectPath !== undefined;\n this.mobileProjectPath = options.mobileProjectPath ?? DEFAULT_MOBILE_DIR;\n this.expoPort = options.expoPort ?? 8081;\n this.logDir = options.logDir ?? join(homedir(), '.clautunnel', 'logs');\n this.onProgress = options.onProgress ?? (() => {});\n }\n\n getMobileProjectPath(): string {\n return this.mobileProjectPath;\n }\n\n checkPrerequisites(): PrerequisiteResult {\n const issues: string[] = [];\n let needsInstall = false;\n\n // Path check is skipped here — ensureMobileProject handles it\n\n // Check ngrok installation and authtoken\n try {\n execSync('which ngrok', { stdio: 'pipe' });\n\n // ngrok is installed — verify authtoken is configured\n try {\n const configOutput = execSync('ngrok config check', {\n stdio: 'pipe',\n timeout: 5000,\n }).toString();\n // \"Valid configuration file\" means authtoken is set\n if (!configOutput.toLowerCase().includes('valid')) {\n issues.push(\n 'ngrok authtoken is not configured.\\n' +\n ' 1. Sign up at https://ngrok.com\\n' +\n ' 2. Copy your authtoken from https://dashboard.ngrok.com/get-started/your-authtoken\\n' +\n ' 3. Run: ngrok config add-authtoken <your-token>'\n );\n }\n } catch {\n // ngrok config check failed — likely no authtoken\n issues.push(\n 'ngrok authtoken is not configured.\\n' +\n ' 1. Sign up at https://ngrok.com\\n' +\n ' 2. Copy your authtoken from https://dashboard.ngrok.com/get-started/your-authtoken\\n' +\n ' 3. Run: ngrok config add-authtoken <your-token>'\n );\n }\n } catch {\n issues.push(\n 'ngrok is not installed.\\n' +\n ' Install: brew install ngrok\\n' +\n ' Then configure your account:\\n' +\n ' 1. Sign up at https://ngrok.com\\n' +\n ' 2. Copy your authtoken from https://dashboard.ngrok.com/get-started/your-authtoken\\n' +\n ' 3. Run: ngrok config add-authtoken <your-token>'\n );\n }\n\n // Check node_modules\n const nodeModulesPath = join(this.mobileProjectPath, 'node_modules');\n if (!existsSync(nodeModulesPath)) {\n needsInstall = true;\n }\n\n return { ready: issues.length === 0, issues, needsInstall };\n }\n\n ensureMobileProject(): { ready: boolean; cloned: boolean; error?: string } {\n // Check if apps/mobile subdir exists (handles both custom path and cloned repo)\n const packageJson = join(this.mobileProjectPath, 'package.json');\n if (existsSync(packageJson)) {\n return { ready: true, cloned: false };\n }\n\n // If custom path was provided and doesn't exist, don't auto-clone\n if (this.hasCustomPath) {\n return {\n ready: false,\n cloned: false,\n error: `Mobile project path not found: ${this.mobileProjectPath}`,\n };\n }\n\n // Auto-clone to default location\n try {\n // Check git is installed\n execSync('which git', { stdio: 'pipe' });\n } catch {\n return {\n ready: false,\n cloned: false,\n error: 'git is required to download the mobile app.\\n' +\n ' Install: https://git-scm.com/downloads\\n' +\n ' macOS: xcode-select --install',\n };\n }\n\n try {\n // Clone only the apps/mobile directory using sparse checkout\n const clautunnelDir = join(homedir(), '.clautunnel');\n if (!existsSync(clautunnelDir)) {\n mkdirSync(clautunnelDir, { recursive: true });\n }\n\n // Clone with depth 1 and sparse checkout for apps/mobile only\n const repoDir = join(clautunnelDir, 'repo');\n if (existsSync(repoDir)) {\n // Reset any local changes (e.g. pnpm-lock.yaml modified by install) before pulling\n execSync('git checkout -- .', {\n cwd: repoDir,\n stdio: 'pipe',\n timeout: 10000,\n });\n // Pull latest\n execSync('git pull --ff-only', {\n cwd: repoDir,\n stdio: 'pipe',\n timeout: 60000,\n });\n } else {\n execSync(\n `git clone --depth 1 --filter=blob:none --sparse \"${REPO_URL}\" repo`,\n {\n cwd: clautunnelDir,\n stdio: 'pipe',\n timeout: 60000,\n }\n );\n execSync('git sparse-checkout set apps/mobile packages/shared', {\n cwd: repoDir,\n stdio: 'pipe',\n timeout: 30000,\n });\n }\n\n // Point mobileProjectPath to the cloned apps/mobile\n this.mobileProjectPath = join(repoDir, 'apps', 'mobile');\n\n if (!existsSync(join(this.mobileProjectPath, 'package.json'))) {\n return { ready: false, cloned: false, error: 'Clone succeeded but apps/mobile not found' };\n }\n\n return { ready: true, cloned: true };\n } catch (error) {\n return {\n ready: false,\n cloned: false,\n error: `Failed to clone mobile project: ${error instanceof Error ? error.message : 'Unknown error'}`,\n };\n }\n }\n\n ensureEnvFile(): void {\n const envPath = join(this.mobileProjectPath, '.env');\n const lines = [\n `EXPO_PUBLIC_SUPABASE_URL=${this.options.supabaseUrl}`,\n `EXPO_PUBLIC_SUPABASE_ANON_KEY=${this.options.supabaseAnonKey}`,\n '',\n ];\n writeFileSync(envPath, lines.join('\\n'));\n }\n\n installDependencies(): boolean {\n const nodeModulesPath = join(this.mobileProjectPath, 'node_modules');\n const repoRoot = join(this.mobileProjectPath, '..', '..');\n const sharedDistPath = join(repoRoot, 'packages', 'shared', 'dist', 'index.js');\n\n if (existsSync(nodeModulesPath) && existsSync(sharedDistPath)) return true;\n\n // Run pnpm install from repo root so workspace links resolve correctly\n try {\n execSync('pnpm install', {\n cwd: repoRoot,\n stdio: 'pipe',\n timeout: 120000, // 2 minute timeout\n });\n\n // Build shared package so dist/index.js exists for Metro\n const sharedDir = join(repoRoot, 'packages', 'shared');\n if (existsSync(join(sharedDir, 'tsconfig.json'))) {\n execSync('pnpm build', {\n cwd: sharedDir,\n stdio: 'pipe',\n timeout: 30000,\n });\n }\n\n return true;\n } catch {\n return false;\n }\n }\n\n async startNgrok(): Promise<string | null> {\n // Kill any leftover ngrok processes to avoid ERR_NGROK_334\n try {\n execSync('killall ngrok', { stdio: 'pipe' });\n await this.sleep(500);\n } catch {\n // No existing ngrok process — expected\n }\n\n this.ensureLogDir();\n\n this.ngrokLogStream = createWriteStream(join(this.logDir, 'ngrok.log'));\n\n // Capture stderr for error diagnostics\n let stderrData = '';\n\n this.ngrokProcess = spawn('ngrok', ['http', String(this.expoPort)], {\n stdio: ['ignore', 'pipe', 'pipe'],\n detached: false,\n });\n\n // Redirect stdout to log file\n this.ngrokProcess.stdout?.pipe(this.ngrokLogStream);\n\n // Capture stderr while also writing to log\n this.ngrokProcess.stderr?.on('data', (chunk: Buffer) => {\n stderrData += chunk.toString();\n this.ngrokLogStream?.write(chunk);\n });\n\n this.ngrokProcess.on('error', () => {\n // Silently handle spawn errors\n });\n\n // Poll for tunnel URL\n for (let i = 0; i < 10; i++) {\n await this.sleep(1000);\n\n // Check if ngrok exited early (auth error, etc.)\n if (this.ngrokProcess.exitCode !== null) {\n break;\n }\n\n const url = await this.getNgrokTunnelUrl();\n if (url) {\n this.tunnelUrl = url;\n return url;\n }\n }\n\n // Failed — set diagnostic error message\n this.ngrokError = this.diagnoseNgrokFailure(stderrData);\n\n this.killProcessTree(this.ngrokProcess);\n this.ngrokProcess = null;\n return null;\n }\n\n /** Last ngrok error diagnosis (available after startNgrok fails) */\n ngrokError: string | null = null;\n\n private diagnoseNgrokFailure(stderr: string): string {\n const lower = stderr.toLowerCase();\n\n if (lower.includes('authtoken') || lower.includes('err_ngrok_105') || lower.includes('authentication')) {\n return 'ngrok authentication failed.\\n' +\n ' Your authtoken may be invalid or expired.\\n' +\n ' 1. Get a new token at https://dashboard.ngrok.com/get-started/your-authtoken\\n' +\n ' 2. Run: ngrok config add-authtoken <your-token>';\n }\n\n if (lower.includes('tunnel session limit') || lower.includes('err_ngrok_108')) {\n return 'ngrok free plan session limit reached.\\n' +\n ' Free accounts allow 1 tunnel at a time.\\n' +\n ' Close other ngrok tunnels or upgrade your plan at https://ngrok.com/pricing';\n }\n\n if (lower.includes('tcp dial') || lower.includes('connection refused')) {\n return `ngrok could not connect to localhost:${this.expoPort}.\\n` +\n ' This is usually a timing issue — the tunnel started before Expo was ready.';\n }\n\n // Generic fallback with log path hint\n return 'ngrok tunnel failed to start.\\n' +\n ` Check logs for details: ${join(this.logDir, 'ngrok.log')}`;\n }\n\n async startExpo(tunnelUrl: string): Promise<boolean> {\n this.ensureLogDir();\n\n // Kill any process occupying the expo port to avoid\n // \"Port X is running this app in another window\" interactive prompt\n // which hangs in non-interactive mode\n this.killProcessOnPort(this.expoPort);\n\n this.expoLogStream = createWriteStream(join(this.logDir, 'expo.log'));\n\n this.expoProcess = spawn('npx', ['expo', 'start', '--clear', '--port', String(this.expoPort)], {\n cwd: this.mobileProjectPath,\n env: {\n ...process.env,\n EXPO_PACKAGER_PROXY_URL: tunnelUrl,\n EXPO_PUBLIC_TUNNEL_URL: tunnelUrl,\n },\n stdio: ['ignore', 'pipe', 'pipe'],\n detached: false,\n });\n\n this.expoProcess.on('error', () => {\n // Silently handle spawn errors\n });\n\n // Wait for Expo to be ready, print QR code if available\n return new Promise<boolean>((resolve) => {\n let ready = false;\n let resolved = false;\n let qrActive = false;\n\n const timeout = setTimeout(() => {\n if (!resolved) {\n resolved = true;\n this.expoProcess?.stdout?.pipe(this.expoLogStream!);\n this.expoProcess?.stderr?.pipe(this.expoLogStream!);\n resolve(false);\n }\n }, 60000); // 60 second timeout\n\n this.expoProcess?.stdout?.on('data', (data: Buffer) => {\n const text = data.toString();\n const lines = text.split('\\n');\n\n for (const line of lines) {\n if (ready) {\n this.expoLogStream?.write(line + '\\n');\n continue;\n }\n\n // Print QR code lines to terminal\n if (this.isQrCodeLine(line)) {\n qrActive = true;\n process.stdout.write(line + '\\n');\n } else if (qrActive && !this.isExpoReadyLine(line) && line.trim()) {\n // Lines between QR code blocks (spacing, URL info)\n process.stdout.write(line + '\\n');\n } else if (this.isExpoReadyLine(line)) {\n // Expo is ready — this is our success signal\n process.stdout.write(line + '\\n');\n ready = true;\n\n if (!resolved) {\n resolved = true;\n clearTimeout(timeout);\n // Redirect remaining output to log\n this.expoProcess?.stdout?.pipe(this.expoLogStream!);\n this.expoProcess?.stderr?.pipe(this.expoLogStream!);\n resolve(true);\n }\n } else {\n // Pre-ready output goes to log\n this.expoLogStream?.write(line + '\\n');\n }\n }\n });\n\n this.expoProcess?.stderr?.pipe(this.expoLogStream!);\n\n this.expoProcess?.on('exit', () => {\n if (!resolved) {\n resolved = true;\n clearTimeout(timeout);\n resolve(false);\n }\n });\n });\n }\n\n async start(): Promise<MobileServerResult> {\n // Step 1: Ensure mobile project exists (auto-clone if needed)\n this.onProgress('Checking mobile project...');\n const projectResult = this.ensureMobileProject();\n if (!projectResult.ready) {\n return { started: false, error: projectResult.error };\n }\n if (projectResult.cloned) {\n this.onProgress('Mobile project cloned to ~/.clautunnel/repo/apps/mobile');\n }\n\n // Step 2: Check prerequisites (ngrok, etc.)\n this.onProgress('Checking prerequisites...');\n const prereqs = this.checkPrerequisites();\n if (!prereqs.ready) {\n return { started: false, error: prereqs.issues.join('; ') };\n }\n\n // Step 3: Install dependencies if needed\n if (prereqs.needsInstall) {\n this.onProgress('Installing dependencies (this may take a minute)...');\n const installed = this.installDependencies();\n if (!installed) {\n return { started: false, error: 'Failed to install mobile dependencies' };\n }\n }\n\n // Step 4: Start ngrok tunnel (before .env so we have the tunnel URL)\n this.onProgress('Starting ngrok tunnel...');\n const tunnelUrl = await this.startNgrok();\n if (!tunnelUrl) {\n return { started: false, error: this.ngrokError ?? 'Failed to start ngrok tunnel' };\n }\n\n // Step 5: Sync .env file\n this.onProgress('Syncing credentials...');\n this.ensureEnvFile();\n\n // Step 6: Start Expo server (pass tunnel URL so mobile app can fetch tokens at runtime)\n this.onProgress('Starting Expo server...');\n const expoStarted = await this.startExpo(tunnelUrl);\n if (!expoStarted) {\n // Expo failed, kill ngrok too\n await this.stop();\n return { started: false, error: 'Failed to start Expo server' };\n }\n\n // Step 7: Show QR code for Expo Go\n // Convert https://xxx.ngrok-free.app → exp://xxx.ngrok-free.app:443/--/pair?code=UUID\n const host = tunnelUrl.replace(/^https?:\\/\\//, '');\n const pairingParam = this.options.pairingCode ? `/--/pair?code=${this.options.pairingCode}` : '';\n const expoUrl = `exp://${host}:443${pairingParam}`;\n console.log('');\n console.log(' Scan with Expo Go:');\n qrcode.generate(expoUrl, { small: true }, (code: string) => {\n // Indent each line for alignment\n for (const line of code.split('\\n')) {\n console.log(` ${line}`);\n }\n });\n console.log(` ${expoUrl}`);\n console.log('');\n console.log(' ┌─────────────────────────────────────────────────┐');\n console.log(' │ Expo Go is required to open this QR code. │');\n console.log(' │ iOS: https://apps.apple.com/app/id982107779│');\n console.log(' │ Android: https://play.google.com/store/apps/ │');\n console.log(' │ details?id=host.exp.exponent │');\n console.log(' └─────────────────────────────────────────────────┘');\n console.log('');\n\n return { started: true, tunnelUrl };\n }\n\n async stop(): Promise<void> {\n if (this.expoProcess) {\n this.killProcessTree(this.expoProcess);\n this.expoProcess = null;\n }\n\n if (this.ngrokProcess) {\n this.killProcessTree(this.ngrokProcess);\n this.ngrokProcess = null;\n }\n\n // Also force-free the expo port in case child processes survived\n this.killProcessOnPort(this.expoPort);\n\n if (this.expoLogStream) {\n this.expoLogStream.end();\n this.expoLogStream = null;\n }\n\n if (this.ngrokLogStream) {\n this.ngrokLogStream.end();\n this.ngrokLogStream = null;\n }\n\n this.tunnelUrl = null;\n }\n\n getTunnelUrl(): string | null {\n return this.tunnelUrl;\n }\n\n private isQrCodeLine(line: string): boolean {\n return line.includes('\\u2588') || line.includes('\\u2584') || line.includes('\\u2580');\n }\n\n private isExpoReadyLine(line: string): boolean {\n return line.includes('Metro waiting on') || line.includes('Logs for your project');\n }\n\n private getNgrokTunnelUrl(): Promise<string | null> {\n return new Promise((resolve) => {\n const req = get('http://localhost:4040/api/tunnels', (res) => {\n let data = '';\n res.on('data', (chunk) => (data += chunk));\n res.on('end', () => {\n try {\n const tunnels = JSON.parse(data).tunnels;\n const httpsTunnel = tunnels?.find(\n (t: { proto: string }) => t.proto === 'https'\n );\n resolve(httpsTunnel?.public_url ?? null);\n } catch {\n resolve(null);\n }\n });\n });\n\n req.on('error', () => resolve(null));\n req.setTimeout(2000, () => {\n req.destroy();\n resolve(null);\n });\n });\n }\n\n private killProcessTree(proc: ChildProcess): void {\n const pid = proc.pid;\n if (!pid) return;\n\n // Kill the parent process\n try {\n proc.kill('SIGTERM');\n } catch {\n // Already dead\n }\n\n // Also kill child processes (e.g., Metro bundler spawned by Expo)\n // Parent SIGTERM alone may not propagate to all children\n try {\n const children = execSync(`pgrep -P ${pid}`, { stdio: 'pipe' }).toString().trim();\n for (const childPid of children.split('\\n').filter(Boolean)) {\n try {\n process.kill(parseInt(childPid, 10), 'SIGTERM');\n } catch { /* already gone */ }\n }\n } catch {\n // No children or pgrep not available\n }\n }\n\n private ensureLogDir(): void {\n if (!existsSync(this.logDir)) {\n mkdirSync(this.logDir, { recursive: true });\n }\n }\n\n private killProcessOnPort(port: number): void {\n try {\n const output = execSync(`lsof -ti tcp:${port}`, { stdio: 'pipe' }).toString().trim();\n if (output) {\n for (const pid of output.split('\\n')) {\n try {\n process.kill(parseInt(pid, 10), 'SIGTERM');\n } catch {\n // Process already gone\n }\n }\n }\n } catch {\n // No process on port — expected\n }\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\n\nexport const PID_FILE = path.join(os.homedir(), '.clautunnel', 'daemon.pid');\n\n/**\n * PID file format: \"pid:timestamp\"\n * The timestamp is Date.now() at process start.\n * Used by removePidFile() to only remove files written by this process,\n * preventing one instance from deleting another's lock.\n *\n * Known limitation — PID reuse:\n * acquirePidFile() and stop both rely on kill(pid, 0) to check process\n * liveness, which cannot distinguish our daemon from an unrelated process\n * that was assigned the same PID after the daemon crashed. Pure Node.js\n * has no cross-platform way to verify process identity (start time, command\n * line, etc.) without shelling out to platform tools like `ps`.\n *\n * In practice this requires: daemon crash (no PID file cleanup) → OS\n * reassigns the exact same PID → user runs `clautunnel stop` or `start`\n * before noticing. The probability is extremely low given typical PID space\n * sizes (32768–99999+). If it does occur:\n * - `stop` may SIGTERM an unrelated process\n * - `start` may falsely report \"already running\"\n * In either case, manually deleting ~/.clautunnel/daemon.pid resolves it.\n */\n\nconst startTimestamp = Date.now();\n\n/**\n * Atomically acquire the PID file lock.\n * Uses O_EXCL to prevent race conditions between concurrent start commands.\n * If the file already exists, checks whether the owning process is still alive.\n *\n * Returns the PID of an existing running process, or null if\n * the lock was successfully acquired.\n */\nexport function acquirePidFile(pidFile: string = PID_FILE): number | null {\n const dir = path.dirname(pidFile);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n\n const content = `${process.pid}:${startTimestamp}`;\n\n try {\n // O_WRONLY | O_CREAT | O_EXCL — fails if file already exists\n const fd = fs.openSync(pidFile, 'wx');\n fs.writeSync(fd, content);\n fs.closeSync(fd);\n return null; // Lock acquired\n } catch (err: any) {\n if (err.code !== 'EEXIST') {\n throw err;\n }\n }\n\n // File exists — check if the owning process is still alive\n const existing = parsePidFile(pidFile);\n if (existing === null) {\n // Invalid/empty file — remove and retry\n removePidFileUnchecked(pidFile);\n return acquirePidFile(pidFile);\n }\n\n if (isProcessAlive(existing.pid)) {\n return existing.pid; // Process is still running\n }\n\n // Process is dead — stale PID file\n removePidFileUnchecked(pidFile);\n return acquirePidFile(pidFile);\n}\n\n/**\n * Remove the PID file only if it was written by this process\n * (matching both PID and timestamp).\n * Prevents accidentally removing another instance's lock.\n */\nexport function removePidFile(pidFile: string = PID_FILE): void {\n const existing = parsePidFile(pidFile);\n if (existing && existing.pid === process.pid && existing.timestamp === startTimestamp) {\n removePidFileUnchecked(pidFile);\n }\n}\n\n/**\n * Read the PID from the PID file (ignoring the timestamp).\n * Used by stop command to find the daemon PID.\n */\nexport function readPidFile(pidFile: string = PID_FILE): number | null {\n const existing = parsePidFile(pidFile);\n return existing?.pid ?? null;\n}\n\n/**\n * Check if a process with the given PID is still alive.\n */\nexport function isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Check if the PID file still exists (i.e., has not been cleaned up\n * by its owning process's graceful shutdown).\n */\nexport function pidFileExists(pidFile: string = PID_FILE): boolean {\n return fs.existsSync(pidFile);\n}\n\nfunction parsePidFile(pidFile: string): { pid: number; timestamp: number } | null {\n try {\n const content = fs.readFileSync(pidFile, 'utf-8').trim();\n // Support both \"pid:timestamp\" and legacy \"pid\" format\n const parts = content.split(':');\n const pid = parseInt(parts[0], 10);\n const timestamp = parts.length > 1 ? parseInt(parts[1], 10) : 0;\n if (isNaN(pid)) return null;\n return { pid, timestamp: isNaN(timestamp) ? 0 : timestamp };\n } catch {\n return null;\n }\n}\n\nfunction removePidFileUnchecked(pidFile: string): void {\n try {\n fs.unlinkSync(pidFile);\n } catch {\n // File may already be gone\n }\n}\n","import { execSync } from 'child_process';\n\nexport type AuthCheckFailure =\n | 'cli_not_found'\n | 'subcommand_not_supported'\n | 'not_logged_in'\n | 'unknown';\n\nexport interface ClaudeAuthStatus {\n loggedIn: boolean;\n authMethod?: string;\n apiProvider?: string;\n failure?: AuthCheckFailure;\n}\n\n/**\n * Check if the Claude CLI is authenticated by running `claude auth status --json`.\n * Distinguishes between CLI not found, subcommand not supported, and not logged in.\n */\nexport function checkClaudeCliAuth(): ClaudeAuthStatus {\n try {\n const output = execSync('claude auth status --json', {\n encoding: 'utf-8',\n timeout: 10000,\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n\n const status = JSON.parse(output.trim());\n if (status.loggedIn === true) {\n return {\n loggedIn: true,\n authMethod: status.authMethod,\n apiProvider: status.apiProvider,\n };\n }\n return { loggedIn: false, failure: 'not_logged_in' };\n } catch (error: unknown) {\n // execSync throws on non-zero exit codes. The CLI may still write\n // valid JSON to stdout (e.g. exit 1 + {\"loggedIn\": false, ...}).\n const execError = error as { stdout?: string | Buffer; message?: string };\n\n // Try to parse stdout from the thrown error first\n if (execError.stdout) {\n try {\n const stdout =\n typeof execError.stdout === 'string'\n ? execError.stdout\n : execError.stdout.toString('utf-8');\n const status = JSON.parse(stdout.trim());\n if (status.loggedIn === true) {\n return {\n loggedIn: true,\n authMethod: status.authMethod,\n apiProvider: status.apiProvider,\n };\n }\n return { loggedIn: false, failure: 'not_logged_in' };\n } catch {\n // stdout wasn't valid JSON — fall through to message-based detection\n }\n }\n\n const message = execError.message ?? String(error);\n\n // CLI binary not found\n if (\n message.includes('command not found') ||\n message.includes('ENOENT') ||\n message.includes('not recognized')\n ) {\n return { loggedIn: false, failure: 'cli_not_found' };\n }\n\n // Subcommand not supported (older CLI version)\n if (\n message.includes('Unknown command') ||\n message.includes('unknown command') ||\n message.includes('Invalid subcommand') ||\n message.includes('invalid subcommand')\n ) {\n return { loggedIn: false, failure: 'subcommand_not_supported' };\n }\n\n return { loggedIn: false, failure: 'unknown' };\n }\n}\n","import { Command } from 'commander';\nimport * as fs from 'fs';\nimport { Logger } from '../utils/logger.js';\nimport { PID_FILE, readPidFile, isProcessAlive, pidFileExists } from '../utils/pid.js';\n\nexport function createStopCommand(): Command {\n const command = new Command('stop');\n\n command.description('Stop the running daemon').action(async () => {\n const logger = new Logger();\n\n try {\n const pid = readPidFile();\n\n if (pid === null) {\n logger.info('No daemon is running');\n return;\n }\n\n if (!isProcessAlive(pid)) {\n logger.info('Daemon process not found (already stopped)');\n try { fs.unlinkSync(PID_FILE); } catch { /* already gone */ }\n return;\n }\n\n try {\n // Note: We cannot verify that the process at this PID is actually\n // clautunnel (see PID reuse limitation in pid.ts). We rely on:\n // 1. The PID file existing (written only by clautunnel start)\n // 2. The process being alive at that PID\n // 3. Post-SIGTERM: PID file removal by gracefulShutdown as confirmation\n //\n // Send SIGTERM — the daemon's gracefulShutdown handler will:\n // 1. Stop all sessions, set machine offline\n // 2. Call removePidFile() to clean up\n // 3. Exit the process\n process.kill(pid, 'SIGTERM');\n logger.info(`Sent stop signal to daemon (PID: ${pid})`);\n\n // Wait for process to exit.\n // We watch for PID file removal as confirmation that our process\n // handled the signal (not an unrelated process with a reused PID).\n let attempts = 0;\n let pidFileRemoved = false;\n while (attempts < 10) {\n await new Promise((resolve) => setTimeout(resolve, 500));\n\n if (!pidFileExists()) {\n // PID file was cleaned up by gracefulShutdown — confirmed our process\n pidFileRemoved = true;\n break;\n }\n\n if (!isProcessAlive(pid)) {\n // Process exited but didn't clean up PID file (crash during shutdown)\n break;\n }\n\n attempts++;\n }\n\n if (attempts >= 10 && !pidFileRemoved) {\n // Process didn't exit after 5 seconds.\n // Only SIGKILL if the PID file still has the original PID,\n // confirming the process hasn't been replaced.\n const currentPid = readPidFile();\n if (currentPid === pid && isProcessAlive(pid)) {\n logger.warn('Daemon did not stop gracefully, sending SIGKILL');\n process.kill(pid, 'SIGKILL');\n }\n }\n\n logger.info('Daemon stopped');\n } catch (err: any) {\n if (err.code === 'ESRCH') {\n logger.info('Daemon process not found (already stopped)');\n } else {\n throw err;\n }\n }\n\n // Clean up PID file if still present (crash during shutdown).\n // Only remove if it still contains the PID we were stopping.\n const currentPid = readPidFile();\n if (currentPid === pid) {\n try { fs.unlinkSync(PID_FILE); } catch { /* already gone */ }\n }\n } catch (error) {\n logger.error(\n `Failed to stop daemon: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n process.exit(1);\n }\n });\n\n return command;\n}\n","import { Command } from 'commander';\nimport { Config } from '../utils/config.js';\nimport { Logger } from '../utils/logger.js';\nimport { MachineManager } from '../daemon/machine.js';\nimport { createSupabaseClient, restoreSession } from '../utils/supabase.js';\n\nexport function createStatusCommand(): Command {\n const command = new Command('status');\n\n command\n .description('Show connection status')\n .action(async () => {\n const config = new Config();\n const logger = new Logger();\n\n try {\n const supabase = createSupabaseClient(\n config.getSupabaseUrl(),\n config.getSupabaseAnonKey()\n );\n\n // Restore session from stored tokens\n const session = await restoreSession(supabase, config);\n if (!session) {\n logger.info('Status: Not authenticated');\n logger.info('Run \"clautunnel login\" to authenticate');\n return;\n }\n\n const { user } = session;\n\n logger.info(`User: ${user.email}`);\n\n const machineId = config.getMachineId();\n if (!machineId) {\n logger.info('Machine: Not registered');\n logger.info('Run \"clautunnel start\" to register this machine');\n return;\n }\n\n const machineManager = new MachineManager({ supabase });\n const machine = await machineManager.getMachine(machineId);\n\n if (!machine) {\n logger.info(`Machine ID: ${machineId} (not found)`);\n return;\n }\n\n logger.info(`Machine: ${machine.name} (${machine.id})`);\n logger.info(`Status: ${machine.status}`);\n logger.info(`Last seen: ${machine.last_seen_at}`);\n } catch (error) {\n logger.error(\n `Failed to get status: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n process.exit(1);\n }\n });\n\n return command;\n}\n","import { Command } from 'commander';\nimport { Config, ConfigurationError } from '../utils/config.js';\nimport { Logger } from '../utils/logger.js';\nimport { prompt, promptHidden } from '../utils/prompt.js';\nimport { createSupabaseClient } from '../utils/supabase.js';\n\nexport function createLoginCommand(): Command {\n const command = new Command('login');\n\n command.description('Authenticate with ClauTunnel').action(async () => {\n const config = new Config();\n const logger = new Logger();\n\n try {\n config.requireConfiguration();\n\n const supabase = createSupabaseClient(\n config.getSupabaseUrl(),\n config.getSupabaseAnonKey()\n );\n\n const email = await prompt('Email: ');\n const password = await promptHidden('Password: ');\n\n if (!email || !password) {\n logger.error('Email and password are required');\n process.exit(1);\n }\n\n const { data, error } = await supabase.auth.signInWithPassword({\n email,\n password,\n });\n\n if (error) {\n logger.error(`Login failed: ${error.message}`);\n process.exit(1);\n }\n\n if (data.user) {\n logger.info(`Logged in as ${data.user.email}`);\n\n // Store session tokens securely\n if (data.session) {\n config.setSession({\n accessToken: data.session.access_token,\n refreshToken: data.session.refresh_token,\n });\n logger.info('Session saved');\n }\n\n logger.info('');\n logger.info('Next steps:');\n logger.info(' 1. Run \"clautunnel start\" to begin a session');\n logger.info(' 2. Set up the mobile app:');\n logger.info(' https://github.com/TongilKim/ClauTunnel#mobile-app-setup');\n }\n } catch (error) {\n if (error instanceof ConfigurationError) {\n logger.error(error.message);\n process.exit(1);\n }\n logger.error(\n `Login failed: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n process.exit(1);\n }\n });\n\n return command;\n}\n","import * as readline from 'readline';\n\nexport function prompt(question: string): Promise<string> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer);\n });\n });\n}\n\nexport function promptHidden(question: string): Promise<string> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n return new Promise((resolve) => {\n process.stdout.write(question);\n\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(true);\n }\n\n let password = '';\n\n const onData = (char: Buffer) => {\n const c = char.toString();\n\n if (c === '\\n' || c === '\\r') {\n process.stdin.removeListener('data', onData);\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(false);\n }\n process.stdout.write('\\n');\n rl.close();\n resolve(password);\n } else if (c === '\\u0003') {\n // Ctrl+C\n process.exit(0);\n } else if (c === '\\u007F' || c === '\\b') {\n // Backspace\n if (password.length > 0) {\n password = password.slice(0, -1);\n }\n } else {\n password += c;\n }\n };\n\n process.stdin.on('data', onData);\n process.stdin.resume();\n });\n}\n","import { Command } from 'commander';\nimport { Config } from '../utils/config.js';\nimport { Logger } from '../utils/logger.js';\nimport { createSupabaseClient, restoreSession } from '../utils/supabase.js';\n\nexport function createLogoutCommand(): Command {\n const command = new Command('logout');\n\n command.description('Log out of ClauTunnel and revoke all device sessions').action(async () => {\n const config = new Config();\n const logger = new Logger();\n\n const session = config.getSessionTokens();\n if (!session) {\n logger.info('Not currently logged in.');\n return;\n }\n\n // Revoke all sessions (CLI + paired mobile devices)\n // This invalidates all refresh tokens. Access tokens remain valid until\n // they expire (default 1hr), but no new tokens can be issued.\n try {\n const supabase = createSupabaseClient(\n config.getSupabaseUrl(),\n config.getSupabaseAnonKey()\n );\n\n const restored = await restoreSession(supabase, config);\n if (restored) {\n const { error } = await supabase.auth.signOut({ scope: 'global' });\n if (error) {\n logger.warn(`Warning: failed to revoke remote sessions: ${error.message}`);\n logger.warn('Local credentials cleared, but mobile devices may remain active until their tokens expire.');\n } else {\n logger.info('All device sessions revoked.');\n }\n }\n } catch {\n // Best-effort — still clear local tokens even if revocation fails\n logger.warn('Warning: could not reach server to revoke sessions.');\n }\n\n config.clearSessionTokens();\n config.clearMachineId();\n logger.info('Logged out successfully.');\n });\n\n return command;\n}\n","import { Command } from 'commander';\nimport { Config, ConfigurationError } from '../utils/config.js';\nimport { Logger } from '../utils/logger.js';\nimport { prompt, promptHidden } from '../utils/prompt.js';\nimport { createSupabaseClient } from '../utils/supabase.js';\n\nexport function createSignupCommand(): Command {\n const command = new Command('signup');\n\n command.description('Create a new ClauTunnel account').action(async () => {\n const config = new Config();\n const logger = new Logger();\n\n try {\n config.requireConfiguration();\n\n const supabase = createSupabaseClient(\n config.getSupabaseUrl(),\n config.getSupabaseAnonKey()\n );\n\n logger.info('Create a new ClauTunnel account');\n logger.info('');\n\n const email = await prompt('Email: ');\n if (!email) {\n logger.error('Email is required');\n process.exit(1);\n }\n\n const password = await promptHidden('Password: ');\n if (!password) {\n logger.error('Password is required');\n process.exit(1);\n }\n\n if (password.length < 6) {\n logger.error('Password must be at least 6 characters');\n process.exit(1);\n }\n\n const confirmPassword = await promptHidden('Confirm Password: ');\n if (password !== confirmPassword) {\n logger.error('Passwords do not match');\n process.exit(1);\n }\n\n const { data, error } = await supabase.auth.signUp({\n email,\n password,\n });\n\n if (error) {\n logger.error(`Signup failed: ${error.message}`);\n process.exit(1);\n }\n\n if (data.user) {\n logger.info('');\n logger.info(`Account created for ${data.user.email}`);\n\n if (data.session) {\n config.setSession({\n accessToken: data.session.access_token,\n refreshToken: data.session.refresh_token,\n });\n logger.info('Logged in automatically');\n }\n\n logger.info('');\n logger.info('Next steps:');\n logger.info(' 1. Run \"clautunnel start\" to begin a session');\n logger.info(' 2. Set up the mobile app:');\n logger.info(' https://github.com/TongilKim/ClauTunnel#mobile-app-setup');\n }\n } catch (error) {\n if (error instanceof ConfigurationError) {\n logger.error(error.message);\n process.exit(1);\n }\n logger.error(\n `Signup failed: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n process.exit(1);\n }\n });\n\n return command;\n}\n","import { Command } from 'commander';\nimport { Config } from '../utils/config.js';\nimport { Logger } from '../utils/logger.js';\nimport { prompt } from '../utils/prompt.js';\n\nexport function createSetupCommand(): Command {\n const command = new Command('setup');\n\n command\n .description('Configure ClauTunnel with Supabase credentials')\n .action(async () => {\n const config = new Config();\n const logger = new Logger();\n\n try {\n logger.info('ClauTunnel Setup');\n logger.info('================');\n logger.info('');\n\n // Step 1: Project ID\n logger.info('[Step 1/2] Supabase Project ID');\n logger.info('');\n logger.info(' 1. Go to your Supabase project dashboard');\n logger.info(' 2. Settings > General > Copy \"Project ID\"');\n logger.info('');\n\n const projectId = await prompt('Project ID: ');\n if (!projectId) {\n logger.error('Supabase Project ID is required');\n process.exit(1);\n }\n\n // Check if user accidentally pasted a full URL\n if (projectId.includes('supabase.co') || projectId.startsWith('http')) {\n logger.error('');\n logger.error('Please enter only the Project ID, not the full URL.');\n logger.error('');\n logger.error('Example: abcdefghijklmnop');\n logger.error('NOT: https://abcdefghijklmnop.supabase.co');\n process.exit(1);\n }\n\n // Validate Project ID format (alphanumeric, no spaces/special chars)\n if (!/^[a-zA-Z0-9-]+$/.test(projectId)) {\n logger.error('');\n logger.error('Invalid Project ID format.');\n logger.error('The Project ID should only contain letters, numbers, and hyphens.');\n logger.error('');\n logger.error('You can find it at: Settings > General > Project ID');\n process.exit(1);\n }\n\n const url = `https://${projectId}.supabase.co`;\n logger.info('✓ Project ID saved');\n logger.info('');\n\n // Step 2: Anon Key\n logger.info('[Step 2/2] Supabase Anon Key');\n logger.info('');\n logger.info(' 1. Go to your Supabase project dashboard');\n logger.info(' 2. Settings > API Keys > Legacy anon Tab > Copy anon key');\n logger.info('');\n\n const anonKey = await prompt('Anon Key: ');\n if (!anonKey) {\n logger.error('Supabase Anon Key is required');\n process.exit(1);\n }\n\n config.setSupabaseCredentials({ url, anonKey });\n\n logger.info('');\n logger.info('✓ Configuration saved successfully!');\n logger.info('');\n logger.info('Next steps:');\n logger.info(' - New user? Run \"clautunnel signup\" to create an account');\n logger.info(' - Have account? Run \"clautunnel login\" to authenticate');\n } catch (error) {\n logger.error(\n `Setup failed: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n process.exit(1);\n }\n });\n\n return command;\n}\n","import { Command } from 'commander';\nimport { Config, ConfigurationError } from '../utils/config.js';\nimport { Logger } from '../utils/logger.js';\nimport { existsSync, writeFileSync } from 'fs';\nimport { join, resolve } from 'path';\n\nexport function createMobileSetupCommand(): Command {\n const command = new Command('mobile-setup');\n\n command\n .description('Generate mobile app .env file from CLI credentials')\n .action(async () => {\n const config = new Config();\n const logger = new Logger();\n\n try {\n config.requireConfiguration();\n\n const supabaseUrl = config.getSupabaseUrl();\n const supabaseAnonKey = config.getSupabaseAnonKey();\n\n // Look for apps/mobile directory relative to cwd\n const mobileDir = resolve(process.cwd(), 'apps', 'mobile');\n if (!existsSync(mobileDir)) {\n logger.error('Could not find apps/mobile directory.');\n logger.error('');\n logger.error('Make sure you run this command from the ClauTunnel project root:');\n logger.error(' cd clautunnel');\n logger.error(' clautunnel mobile-setup');\n process.exit(1);\n }\n\n const envPath = join(mobileDir, '.env');\n\n // Warn if .env already exists\n if (existsSync(envPath)) {\n logger.warn('apps/mobile/.env already exists and will be overwritten.');\n }\n\n const envContent = [\n `EXPO_PUBLIC_SUPABASE_URL=${supabaseUrl}`,\n `EXPO_PUBLIC_SUPABASE_ANON_KEY=${supabaseAnonKey}`,\n '',\n ].join('\\n');\n\n writeFileSync(envPath, envContent);\n\n // Save mobile project path to config for clautunnel start\n config.setMobileProjectPath(mobileDir);\n\n logger.info('');\n logger.info('Mobile app configured successfully!');\n logger.info(` Project: ${mobileDir}`);\n logger.info(` .env: ${envPath}`);\n logger.info('');\n logger.info('The mobile server will start automatically with \"clautunnel start\".');\n logger.info('Use \"clautunnel start --no-mobile\" to skip mobile server.');\n } catch (error) {\n if (error instanceof ConfigurationError) {\n logger.error(error.message);\n process.exit(1);\n }\n logger.error(\n `Mobile setup failed: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n process.exit(1);\n }\n });\n\n return command;\n}\n","import { Command } from 'commander';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\nimport { execSync } from 'child_process';\nimport { Logger } from '../utils/logger.js';\nimport { PID_FILE, readPidFile, isProcessAlive } from '../utils/pid.js';\nimport { createSupabaseClient } from '../utils/supabase.js';\nimport { isMacOS } from '../utils/sleep-prevention.js';\nimport { promptYesNo } from '../utils/sleep-prevention.js';\n\ninterface ResetOptions {\n skipDb?: boolean;\n skipNgrok?: boolean;\n yes?: boolean;\n}\n\nexport function createResetCommand(): Command {\n const command = new Command('reset');\n\n command\n .description('Reset to fresh user state (uninstall CLI, clean config & DB)')\n .option('--skip-db', 'Skip Supabase DB cleanup')\n .option('--skip-ngrok', 'Keep ngrok installed and configured')\n .option('-y, --yes', 'Skip confirmation prompt')\n .action(async (options: ResetOptions) => {\n const logger = new Logger();\n\n if (!options.yes) {\n logger.info('This will:');\n logger.info(' - Stop any running clautunnel processes');\n logger.info(' - Restore macOS sleep settings');\n if (!options.skipDb) {\n logger.info(' - Delete all your data from Supabase (machines, sessions, messages)');\n }\n if (!options.skipNgrok) {\n logger.info(' - Uninstall ngrok and remove its config');\n }\n logger.info(' - Delete ~/.clautunnel/ config directory');\n logger.info(' - Uninstall clautunnel (npm & Homebrew)');\n logger.info('');\n\n const confirmed = await promptYesNo('Are you sure? [y/N]: ');\n if (!confirmed) {\n logger.info('Aborted.');\n return;\n }\n logger.info('');\n }\n\n // ─── Step 1: Stop running processes ────────────────────────────\n logger.info('[1/7] Stopping running processes...');\n\n const pid = readPidFile();\n if (pid !== null && isProcessAlive(pid)) {\n try {\n process.kill(pid, 'SIGTERM');\n logger.info(` - clautunnel daemon stopped (PID ${pid})`);\n // Give it a moment to clean up child processes\n await new Promise((resolve) => setTimeout(resolve, 1000));\n } catch {\n logger.info(' - could not stop daemon');\n }\n } else {\n logger.info(' - no running daemon');\n }\n // Clean up PID file regardless\n try { fs.unlinkSync(PID_FILE); } catch { /* already gone */ }\n\n // Kill orphaned ngrok/expo processes\n try {\n execSync('pkill -f \"ngrok.*tunnel\" 2>/dev/null', { stdio: 'ignore' });\n logger.info(' - ngrok tunnel process killed');\n } catch { /* not running */ }\n\n try {\n execSync('pkill -f \"expo start\" 2>/dev/null', { stdio: 'ignore' });\n logger.info(' - expo process killed');\n } catch { /* not running */ }\n\n // Kill anything on the default Expo port (8081)\n try {\n const pids = execSync('lsof -ti tcp:8081', { stdio: 'pipe' }).toString().trim();\n if (pids) {\n for (const pid of pids.split('\\n')) {\n try { process.kill(parseInt(pid, 10), 'SIGTERM'); } catch { /* already gone */ }\n }\n logger.info(' - port 8081 freed');\n }\n } catch { /* port already free */ }\n\n // ─── Step 2: Restore macOS sleep settings ──────────────────────\n logger.info('[2/7] Restoring macOS sleep settings...');\n\n if (isMacOS()) {\n try {\n const pmsetOutput = execSync('sudo pmset -g 2>/dev/null', { encoding: 'utf-8' });\n if (pmsetOutput.includes('disablesleep') && pmsetOutput.includes('1')) {\n execSync('sudo pmset -a disablesleep 0', { stdio: 'inherit' });\n logger.info(' - lid-close sleep restored');\n } else {\n logger.info(' - already normal');\n }\n } catch {\n logger.info(' - already normal');\n }\n\n // Kill leftover caffeinate\n try {\n execSync('pkill -f caffeinate 2>/dev/null', { stdio: 'ignore' });\n logger.info(' - caffeinate stopped');\n } catch { /* not running */ }\n } else {\n logger.info(' - not macOS, skipped');\n }\n\n // ─── Step 3: Clean Supabase DB ────────────────────────────────\n if (options.skipDb) {\n logger.info('[3/7] Skipping DB cleanup (--skip-db)');\n } else {\n await cleanSupabaseDb(logger);\n }\n\n // ─── Step 4: Uninstall ngrok ──────────────────────────────────\n if (options.skipNgrok) {\n logger.info('[4/7] Skipping ngrok cleanup (--skip-ngrok)');\n } else {\n logger.info('[4/7] Uninstalling ngrok...');\n try {\n execSync('brew list ngrok', { stdio: 'ignore' });\n execSync('brew uninstall ngrok', { stdio: 'inherit' });\n logger.info(' - ngrok removed');\n } catch {\n try {\n execSync('which ngrok', { stdio: 'ignore' });\n logger.info(' - ngrok found but not installed via Homebrew, remove manually');\n } catch {\n logger.info(' - not installed, skipped');\n }\n }\n\n // Remove ngrok config directories\n const ngrokConfigDir = path.join(os.homedir(), '.config', 'ngrok');\n const ngrokLegacyDir = path.join(os.homedir(), '.ngrok2');\n\n if (fs.existsSync(ngrokConfigDir)) {\n fs.rmSync(ngrokConfigDir, { recursive: true, force: true });\n logger.info(' - ngrok config removed (~/.config/ngrok)');\n }\n if (fs.existsSync(ngrokLegacyDir)) {\n fs.rmSync(ngrokLegacyDir, { recursive: true, force: true });\n logger.info(' - ngrok legacy config removed (~/.ngrok2)');\n }\n }\n\n // ─── Step 5: Remove local data ────────────────────────────────\n logger.info('[5/7] Removing local data...');\n\n const configDir = path.join(os.homedir(), '.clautunnel');\n const legacyDir = path.join(os.homedir(), '.termbridge');\n\n if (fs.existsSync(configDir)) {\n fs.rmSync(configDir, { recursive: true, force: true });\n logger.info(' - ~/.clautunnel removed (config, logs, repo)');\n } else {\n logger.info(' - ~/.clautunnel already clean');\n }\n\n if (fs.existsSync(legacyDir)) {\n fs.rmSync(legacyDir, { recursive: true, force: true });\n logger.info(' - ~/.termbridge removed (legacy)');\n }\n\n // ─── Step 6: Uninstall CLI (npm) ──────────────────────────────\n // Runs after config removal so if it fails, re-running the command\n // still works (the binary is still available).\n logger.info('[6/7] Uninstalling CLI (npm)...');\n try {\n execSync('npm list -g @tongil_kim/clautunnel', { stdio: 'ignore' });\n execSync('npm uninstall -g @tongil_kim/clautunnel', { stdio: 'inherit' });\n logger.info(' - npm package removed');\n } catch {\n logger.info(' - not installed via npm, skipped');\n }\n\n // ─── Step 7: Uninstall CLI (Homebrew) ─────────────────────────\n logger.info('[7/7] Uninstalling CLI (Homebrew)...');\n try {\n execSync('brew list clautunnel', { stdio: 'ignore' });\n execSync('brew uninstall clautunnel', { stdio: 'inherit' });\n logger.info(' - Homebrew package removed');\n } catch {\n logger.info(' - not installed via Homebrew, skipped');\n }\n\n logger.info('');\n logger.info('Done! Fresh user state restored.');\n logger.info('');\n logger.info('Next steps:');\n logger.info(' 1. npm install -g @tongil_kim/clautunnel');\n logger.info(' 2. clautunnel setup');\n logger.info(' 3. clautunnel login');\n logger.info(' 4. clautunnel start');\n });\n\n return command;\n}\n\nasync function cleanSupabaseDb(logger: Logger): Promise<void> {\n const configDir = path.join(os.homedir(), '.clautunnel');\n const configFile = path.join(configDir, 'config.json');\n\n if (!fs.existsSync(configFile)) {\n logger.info('[3/7] Skipping DB cleanup (no config file found)');\n return;\n }\n\n let configData: any;\n try {\n configData = JSON.parse(fs.readFileSync(configFile, 'utf-8'));\n } catch {\n logger.info('[3/7] Skipping DB cleanup (invalid config file)');\n return;\n }\n\n const supabaseUrl = configData.supabaseUrl;\n const anonKey = configData.supabaseAnonKey;\n const accessToken = configData.sessionTokens?.accessToken;\n const refreshToken = configData.sessionTokens?.refreshToken;\n\n if (!supabaseUrl || !anonKey || !accessToken) {\n logger.info('[3/7] Skipping DB cleanup (missing credentials)');\n return;\n }\n\n logger.info('[3/7] Cleaning Supabase DB data...');\n\n // Refresh token in case it's expired\n const supabase = createSupabaseClient(supabaseUrl, anonKey);\n\n let token = accessToken;\n if (refreshToken) {\n const { data } = await supabase.auth.setSession({\n access_token: accessToken,\n refresh_token: refreshToken,\n });\n if (data?.session) {\n token = data.session.access_token;\n }\n }\n\n // Delete push_tokens (no cascade from machines)\n const headers = {\n apikey: anonKey,\n Authorization: `Bearer ${token}`,\n Prefer: 'return=minimal',\n };\n\n try {\n const res = await fetch(`${supabaseUrl}/rest/v1/push_tokens?select=*`, {\n method: 'DELETE',\n headers,\n });\n logger.info(res.ok ? ' - push_tokens cleared' : ' - push_tokens: skipped');\n } catch {\n logger.info(' - push_tokens: skipped');\n }\n\n // Delete machines (cascades to sessions -> messages)\n try {\n const res = await fetch(`${supabaseUrl}/rest/v1/machines?select=*`, {\n method: 'DELETE',\n headers,\n });\n logger.info(res.ok ? ' - machines cleared (sessions + messages cascade)' : ' - machines: skipped');\n } catch {\n logger.info(' - machines: skipped');\n }\n\n // Delete mobile_pairings\n try {\n const res = await fetch(`${supabaseUrl}/rest/v1/mobile_pairings?select=*`, {\n method: 'DELETE',\n headers,\n });\n logger.info(res.ok ? ' - mobile_pairings cleared' : ' - mobile_pairings: skipped');\n } catch {\n logger.info(' - mobile_pairings: skipped');\n }\n}\n"],"mappings":"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","names":["isPermissionMode","resolve","dirname","readFileSync","path","resolve","hostname","EventEmitter","EventEmitter","os","resolve","prompt","existingNames","import_clautunnel_shared","existsSync","readFileSync","writeFileSync","mkdirSync","join","homedir","path","import_clautunnel_shared","EventEmitter","prompt","Command","import_clautunnel_shared","EventEmitter","EventEmitter","config","readdirSync","path","os","resolve","process","existsSync","join","spawn","execSync","existsSync","mkdirSync","writeFileSync","join","homedir","packageJson","resolve","fs","path","os","execSync","config","existsSync","join","cleanup","session","prompt","Command","fs","Command","resolve","currentPid","Command","Command","config","Command","readline","resolve","Command","config","Command","Command","config","Command","Command","config","Command","Command","config","Command","existsSync","writeFileSync","join","resolve","Command","config","Command","fs","path","os","execSync","Command","resolve","execSync","pid","dirname","resolve","readFileSync","Command"]}