@vibe-kit/dagger
Version:
Local sandbox provider for Vibekit using Dagger
1 lines • 65.4 kB
Source Map (JSON)
{"version":3,"sources":["../src/index.ts","../src/dagger/vibekit-dagger.ts","../src/dagger/registry-integration.ts","../src/setup/installer.ts","../src/storage/environment-store.ts"],"sourcesContent":["/**\n * @vibe-kit/dagger - Local Sandbox Provider\n *\n * Main entry point for the local provider package.\n * Exports all public APIs for Dagger integration and setup utilities.\n */\n\n// Environment type for compatibility with other packages\nexport interface Environment {\n id: string;\n name: string;\n status: \"running\" | \"stopped\" | \"pending\" | \"error\";\n agentType?: string;\n createdAt?: Date;\n lastUsed?: Date;\n branch?: string;\n environment?: {\n VIBEKIT_AGENT_TYPE?: string;\n AGENT_TYPE?: string;\n [key: string]: string | undefined;\n };\n}\n\n// Dagger integration - matching other providers' interface pattern\nexport {\n LocalSandboxProvider,\n createLocalProvider,\n prebuildAgentImages,\n // Docker registry setup functions\n setupUserDockerRegistry,\n checkDockerLogin,\n uploadImagesToUserAccount,\n getVibeKitConfig,\n saveVibeKitConfig,\n type LocalConfig,\n type AgentType,\n type SandboxInstance,\n type SandboxProvider,\n type SandboxCommands,\n type SandboxExecutionResult,\n type SandboxCommandOptions,\n // Docker registry types\n type DockerLoginInfo,\n type VibeKitConfig,\n} from \"./dagger/vibekit-dagger\";\n\n// Alias for backwards compatibility - keep the old Dagger names available\nexport { LocalSandboxProvider as LocalDaggerSandboxProvider } from \"./dagger/vibekit-dagger\";\nexport type { LocalConfig as LocalDaggerConfig } from \"./dagger/vibekit-dagger\";\n\n// Setup and installation utilities\nexport {\n setupLocalProvider,\n prebuildSpecificAgents,\n validateDependencies,\n checkSetupStatus,\n cleanupPreBuiltImages,\n type SetupOptions,\n type SetupResult,\n} from \"./setup/installer\";\n\n// Environment storage\nexport {\n EnvironmentStore,\n type EnvironmentRecord,\n} from \"./storage/environment-store\";\n","/**\n * VibeKit Dagger Local Sandbox Provider\n *\n * Implements the sandbox provider interface using Dagger for local containerized\n * development environments with ARM64 agent images.\n */\n\nimport { connect } from \"@dagger.io/dagger\";\nimport type { Client, Directory } from \"@dagger.io/dagger\";\nimport { exec } from \"child_process\";\nimport { promisify } from \"util\";\nimport { readFile } from \"fs/promises\";\nimport { existsSync } from \"fs\";\nimport { join } from \"path\";\nimport { EventEmitter } from \"events\";\nimport { homedir } from \"os\";\n\nconst execAsync = promisify(exec);\n\n// Logger interface for structured logging\ninterface Logger {\n debug(message: string, meta?: any): void;\n info(message: string, meta?: any): void;\n warn(message: string, meta?: any): void;\n error(message: string, error?: Error | any, meta?: any): void;\n}\n\n// Default console logger implementation\nclass ConsoleLogger implements Logger {\n private context: string;\n \n constructor(context: string = \"VibeKitDagger\") {\n this.context = context;\n }\n\n private log(level: string, message: string, meta?: any): void {\n const timestamp = new Date().toISOString();\n const logMessage = `[${timestamp}] [${level}] [${this.context}] ${message}`;\n \n if (meta) {\n console.log(logMessage, meta);\n } else {\n console.log(logMessage);\n }\n }\n\n debug(message: string, meta?: any): void {\n if (process.env.VIBEKIT_LOG_LEVEL === \"debug\") {\n this.log(\"DEBUG\", message, meta);\n }\n }\n\n info(message: string, meta?: any): void {\n this.log(\"INFO\", message, meta);\n }\n\n warn(message: string, meta?: any): void {\n this.log(\"WARN\", message, meta);\n }\n\n error(message: string, error?: Error | any, meta?: any): void {\n const errorMeta = error instanceof Error ? {\n ...meta,\n error: {\n message: error.message,\n stack: error.stack,\n name: error.name\n }\n } : meta;\n \n this.log(\"ERROR\", message, errorMeta);\n }\n}\n\n// Custom error types for specific failure scenarios\nexport class VibeKitError extends Error {\n constructor(message: string, public code: string, public cause?: Error) {\n super(message);\n this.name = \"VibeKitError\";\n }\n}\n\nexport class ContainerExecutionError extends VibeKitError {\n constructor(message: string, public exitCode: number, cause?: Error) {\n super(message, \"CONTAINER_EXECUTION_ERROR\", cause);\n this.name = \"ContainerExecutionError\";\n }\n}\n\n// Environment interface for provider methods\ninterface Environment {\n id: string;\n name: string;\n status: \"running\" | \"stopped\" | \"pending\" | \"error\";\n agentType?: string;\n createdAt?: Date;\n lastUsed?: Date;\n branch?: string;\n environment?: {\n VIBEKIT_AGENT_TYPE?: string;\n AGENT_TYPE?: string;\n [key: string]: string | undefined;\n };\n}\n\n// Interface definitions matching E2B/Northflank patterns\nexport interface SandboxExecutionResult {\n exitCode: number;\n stdout: string;\n stderr: string;\n}\n\nexport interface SandboxCommandOptions {\n timeoutMs?: number;\n background?: boolean;\n onStdout?: (data: string) => void;\n onStderr?: (data: string) => void;\n}\n\nexport interface SandboxCommands {\n run(\n command: string,\n options?: SandboxCommandOptions\n ): Promise<SandboxExecutionResult>;\n}\n\nexport interface SandboxInstance {\n sandboxId: string;\n commands: SandboxCommands;\n kill(): Promise<void>;\n pause(): Promise<void>;\n getHost(port: number): Promise<string>;\n // EventEmitter methods for VibeKit streaming compatibility\n on(event: string, listener: (...args: any[]) => void): this;\n emit(event: string, ...args: any[]): boolean;\n}\n\nexport interface SandboxProvider {\n create(\n envs?: Record<string, string>,\n agentType?: \"codex\" | \"claude\" | \"opencode\" | \"gemini\" | \"grok\",\n workingDirectory?: string\n ): Promise<SandboxInstance>;\n resume(sandboxId: string): Promise<SandboxInstance>;\n}\n\nexport type AgentType = \"codex\" | \"claude\" | \"opencode\" | \"gemini\" | \"grok\";\n\nexport interface LocalConfig {\n preferRegistryImages?: boolean;\n dockerHubUser?: string; // Deprecated - use registryUser\n registryUser?: string; // Universal registry username\n registryName?: string; // Registry type: 'dockerhub', 'ghcr', 'ecr', etc.\n pushImages?: boolean;\n privateRegistry?: string;\n autoInstall?: boolean;\n logger?: Logger;\n retryAttempts?: number;\n retryDelayMs?: number;\n connectionTimeout?: number;\n configPath?: string;\n}\n\n// Configuration with environment variable support\nexport class Configuration {\n private static instance: Configuration;\n private config: LocalConfig;\n private logger: Logger;\n\n private constructor(config: LocalConfig = {}) {\n // Support both registryUser and dockerHubUser for backward compatibility\n const registryUser = process.env.VIBEKIT_REGISTRY_USER || config.registryUser || \n process.env.VIBEKIT_DOCKER_USER || config.dockerHubUser;\n \n this.config = {\n preferRegistryImages: this.getEnvBoolean(\"VIBEKIT_PREFER_REGISTRY\", config.preferRegistryImages ?? true),\n dockerHubUser: registryUser, // Keep for backward compatibility\n registryUser: registryUser,\n registryName: process.env.VIBEKIT_REGISTRY_NAME || config.registryName || \"dockerhub\",\n pushImages: this.getEnvBoolean(\"VIBEKIT_PUSH_IMAGES\", config.pushImages ?? true),\n privateRegistry: process.env.VIBEKIT_REGISTRY || config.privateRegistry,\n autoInstall: this.getEnvBoolean(\"VIBEKIT_AUTO_INSTALL\", config.autoInstall ?? false),\n retryAttempts: this.getEnvNumber(\"VIBEKIT_RETRY_ATTEMPTS\", config.retryAttempts ?? 3),\n retryDelayMs: this.getEnvNumber(\"VIBEKIT_RETRY_DELAY\", config.retryDelayMs ?? 1000),\n connectionTimeout: this.getEnvNumber(\"VIBEKIT_CONNECTION_TIMEOUT\", config.connectionTimeout ?? 30000),\n configPath: process.env.VIBEKIT_CONFIG_PATH || config.configPath || join(homedir(), \".vibekit\"),\n logger: config.logger || new ConsoleLogger()\n };\n this.logger = this.config.logger!;\n }\n\n static getInstance(config?: LocalConfig): Configuration {\n if (!Configuration.instance) {\n Configuration.instance = new Configuration(config);\n }\n return Configuration.instance;\n }\n\n private getEnvBoolean(key: string, defaultValue: boolean): boolean {\n const value = process.env[key];\n if (value === undefined) return defaultValue;\n return value.toLowerCase() === \"true\";\n }\n\n private getEnvNumber(key: string, defaultValue: number): number {\n const value = process.env[key];\n if (value === undefined) return defaultValue;\n const num = parseInt(value, 10);\n return isNaN(num) ? defaultValue : num;\n }\n\n get(): LocalConfig {\n return this.config;\n }\n\n getLogger(): Logger {\n return this.logger;\n }\n}\n\n// Validates and sanitizes command input to prevent injection\nfunction sanitizeCommand(command: string): string {\n // For Dagger, we're already running in an isolated container\n // and using sh -c, so we can be less restrictive\n // Still prevent some obvious injection patterns\n \n // Check for obvious command injection attempts\n const veryDangerous = [\n \"rm -rf /\",\n \"rm -rf /*\",\n \":(){ :|:& };:\", // Fork bomb\n \"dd if=/dev/zero\", // Disk fill\n ];\n \n for (const pattern of veryDangerous) {\n if (command.includes(pattern)) {\n throw new Error(`Command contains dangerous pattern: ${pattern}`);\n }\n }\n \n // Allow common shell operators since we're in a sandboxed environment\n // The container isolation provides the security boundary\n return command;\n}\n\n// Registry factory - creates appropriate registry based on config\nasync function createRegistryManager(config: LocalConfig, logger: any): Promise<any> {\n const modulePath = '@vibe-kit/sdk/registry';\n const registryModule = await import(modulePath).catch(() => null);\n \n if (!registryModule) {\n logger.warn(\"Registry module not available\");\n return null;\n }\n \n const { RegistryManager, DockerHubRegistry, GitHubContainerRegistry, AWSECRRegistry } = registryModule;\n const registryName = config.registryName || 'dockerhub';\n \n const registryManager = new RegistryManager({\n defaultRegistry: registryName,\n logger,\n });\n \n // Register the appropriate registry based on configuration\n switch (registryName) {\n case 'ghcr':\n const ghcrRegistry = new GitHubContainerRegistry({ \n logger,\n githubToken: process.env.GITHUB_TOKEN,\n });\n registryManager.registerRegistry('ghcr', ghcrRegistry);\n break;\n \n case 'ecr':\n const ecrRegistry = new AWSECRRegistry({ \n logger,\n awsRegion: process.env.AWS_REGION,\n awsAccountId: process.env.AWS_ACCOUNT_ID,\n });\n registryManager.registerRegistry('ecr', ecrRegistry);\n break;\n \n case 'dockerhub':\n default:\n const dockerHubRegistry = new DockerHubRegistry({ logger });\n registryManager.registerRegistry('dockerhub', dockerHubRegistry);\n break;\n }\n \n return registryManager;\n}\n\n// Image resolution using shared infrastructure\nclass ImageResolver {\n private sharedResolver: any;\n private config: LocalConfig;\n\n constructor(config: LocalConfig, logger: Logger) {\n this.config = config;\n // Support both registryUser and dockerHubUser for backward compatibility\n const registryUser = config.registryUser || config.dockerHubUser;\n \n // Import and use the shared ImageResolver\n const sharedConfig = {\n preferRegistryImages: config.preferRegistryImages,\n pushImages: config.pushImages,\n privateRegistry: config.privateRegistry,\n dockerHubUser: registryUser, // For backward compatibility\n registryUser: registryUser,\n registryName: config.registryName,\n retryAttempts: config.retryAttempts,\n retryDelayMs: config.retryDelayMs,\n logger,\n };\n\n // Use dynamic import to avoid circular dependencies\n this.initializeSharedResolver(sharedConfig);\n }\n\n private async initializeSharedResolver(config: any) {\n try {\n const modulePath = '@vibe-kit/sdk/registry';\n const registryModule = await import(modulePath).catch(() => null);\n if (!registryModule) {\n config.logger.warn(\"Registry module not available, using fallback image resolution\");\n return;\n }\n \n const { ImageResolver: SharedImageResolver } = registryModule;\n \n // Use the factory to create registry manager with appropriate registry\n const registryManager = await createRegistryManager(this.config, config.logger);\n if (!registryManager) {\n config.logger.warn(\"Failed to create registry manager, using fallback\");\n return;\n }\n\n this.sharedResolver = new SharedImageResolver(config, registryManager);\n } catch (error) {\n config.logger.warn(\"Failed to initialize shared resolver:\", error);\n }\n }\n\n async resolveImage(agentType?: AgentType): Promise<string> {\n if (!this.sharedResolver) {\n // Fallback if shared resolver not initialized yet\n const registryUser = this.config.registryUser || this.config.dockerHubUser;\n if (agentType && registryUser) {\n return `${registryUser}/vibekit-${agentType}:latest`;\n }\n return agentType ? `vibekit-${agentType}:latest` : \"ubuntu:24.04\";\n }\n \n return await this.sharedResolver.resolveImage(agentType);\n }\n}\n\n// Local Dagger sandbox instance implementation\nclass LocalSandboxInstance extends EventEmitter implements SandboxInstance {\n private isRunning = true;\n private workspaceDirectory: Directory | null = null;\n private logger: Logger;\n private imageResolver: ImageResolver;\n private config: LocalConfig;\n\n constructor(\n public sandboxId: string,\n private envs?: Record<string, string>,\n private workDir?: string,\n private agentType?: AgentType,\n config?: LocalConfig\n ) {\n super();\n this.config = Configuration.getInstance(config).get();\n this.logger = Configuration.getInstance().getLogger();\n this.imageResolver = new ImageResolver(this.config, this.logger);\n }\n\n get commands(): SandboxCommands {\n return {\n run: async (\n command: string,\n options?: SandboxCommandOptions\n ): Promise<SandboxExecutionResult> => {\n if (!this.isRunning) {\n throw new ContainerExecutionError(\"Sandbox instance is not running\", -1);\n }\n\n // Validate and sanitize command\n let sanitizedCommand: string;\n try {\n sanitizedCommand = sanitizeCommand(command);\n } catch (error) {\n throw new ContainerExecutionError(\n `Invalid command: ${error instanceof Error ? error.message : String(error)}`,\n -1\n );\n }\n\n // Emit start event\n this.emit(\"update\", JSON.stringify({\n type: \"start\",\n command: sanitizedCommand,\n timestamp: Date.now(),\n }));\n\n try {\n return await this.executeCommand(sanitizedCommand, options);\n } catch (error) {\n // Emit error event\n const errorMessage = error instanceof Error ? error.message : String(error);\n this.emit(\"error\", errorMessage);\n \n if (error instanceof ContainerExecutionError) {\n throw error;\n }\n \n throw new ContainerExecutionError(\n `Command execution failed: ${errorMessage}`,\n -1,\n error instanceof Error ? error : undefined\n );\n } finally {\n // Emit end event\n this.emit(\"update\", JSON.stringify({\n type: \"end\",\n command: sanitizedCommand,\n timestamp: Date.now(),\n }));\n }\n },\n };\n }\n\n private async executeCommand(\n command: string,\n options?: SandboxCommandOptions\n ): Promise<SandboxExecutionResult> {\n // Use direct connect instead of connection pool to avoid GraphQL sync issues\n let result: SandboxExecutionResult | null = null;\n \n await connect(async (client) => {\n // Resolve the image\n const image = await this.imageResolver.resolveImage(this.agentType);\n \n // Create container\n let container = client.container()\n .from(image)\n .withWorkdir(this.workDir || \"/vibe0\");\n\n // Add environment variables\n if (this.envs) {\n for (const [key, value] of Object.entries(this.envs)) {\n container = container.withEnvVariable(key, value);\n }\n }\n\n // Restore workspace if exists\n if (this.workspaceDirectory) {\n container = container.withDirectory(\n this.workDir || \"/vibe0\",\n this.workspaceDirectory\n );\n }\n\n // Execute command\n if (options?.background) {\n // Background execution\n container = container.withExec([\"sh\", \"-c\", command], {\n experimentalPrivilegedNesting: true,\n });\n\n // Save workspace state - await the directory call\n this.workspaceDirectory = await container.directory(this.workDir || \"/vibe0\");\n\n result = {\n exitCode: 0,\n stdout: `Background process started: ${command}`,\n stderr: \"\",\n };\n } else {\n // Foreground execution with timeout\n const timeout = options?.timeoutMs || 120000; // 2 minutes default\n const execContainer = container.withExec([\"sh\", \"-c\", command]);\n\n try {\n const [stdout, stderr, exitCode] = await Promise.race([\n Promise.all([\n execContainer.stdout(),\n execContainer.stderr(),\n execContainer.exitCode()\n ]),\n new Promise<never>((_, reject) => \n setTimeout(() => reject(new Error(\"Command execution timeout\")), timeout)\n )\n ]);\n\n // Save workspace state - await the directory call\n this.workspaceDirectory = await execContainer.directory(this.workDir || \"/vibe0\");\n\n // Handle output callbacks\n if (stdout && options?.onStdout) {\n this.emitOutput(\"stdout\", stdout, options.onStdout);\n }\n if (stderr && options?.onStderr) {\n this.emitOutput(\"stderr\", stderr, options.onStderr);\n }\n\n result = { exitCode, stdout, stderr };\n } catch (error) {\n if (error instanceof Error && error.message === \"Command execution timeout\") {\n throw new ContainerExecutionError(\"Command execution timeout\", -1, error);\n }\n throw error;\n }\n }\n });\n\n if (!result) {\n throw new ContainerExecutionError(\"Command execution failed - no result returned\", -1);\n }\n \n return result;\n }\n\n private emitOutput(\n type: \"stdout\" | \"stderr\",\n output: string,\n callback?: (data: string) => void\n ): void {\n const lines = output.split(\"\\n\").filter(line => line.trim());\n for (const line of lines) {\n this.emit(\"update\", `${type.toUpperCase()}: ${line}`);\n if (callback) callback(line);\n }\n }\n\n async kill(): Promise<void> {\n this.isRunning = false;\n this.workspaceDirectory = null;\n this.logger.debug(`Killed sandbox instance: ${this.sandboxId}`);\n }\n\n async pause(): Promise<void> {\n // Not applicable for Dagger containers\n this.logger.debug(`Pause requested for sandbox: ${this.sandboxId} (no-op)`);\n }\n\n async getHost(_port: number): Promise<string> {\n return \"localhost\";\n }\n}\n\nexport class LocalSandboxProvider implements SandboxProvider {\n private logger: Logger;\n private config: LocalConfig;\n\n constructor(config: LocalConfig = {}) {\n this.config = Configuration.getInstance(config).get();\n this.logger = Configuration.getInstance().getLogger();\n }\n\n async create(\n envs?: Record<string, string>,\n agentType?: AgentType,\n workingDirectory?: string\n ): Promise<SandboxInstance> {\n // Generate unique ID with timestamp + random suffix to avoid collisions\n const timestamp = Date.now().toString(36);\n const randomSuffix = Math.random().toString(36).substring(2, 8);\n const sandboxId = `dagger-${agentType || \"default\"}-${timestamp}-${randomSuffix}`;\n const workDir = workingDirectory || \"/vibe0\";\n\n this.logger.info(`Creating sandbox instance`, { sandboxId, agentType, workDir });\n\n const instance = new LocalSandboxInstance(\n sandboxId,\n envs,\n workDir,\n agentType,\n this.config\n );\n\n return instance;\n }\n\n async resume(sandboxId: string): Promise<SandboxInstance> {\n this.logger.info(`Resuming sandbox instance: ${sandboxId}`);\n return await this.create();\n }\n\n async listEnvironments(): Promise<Environment[]> {\n return [];\n }\n}\n\nexport function createLocalProvider(\n config: LocalConfig = {}\n): LocalSandboxProvider {\n return new LocalSandboxProvider(config);\n}\n\n// Pre-cache agent images for faster startup\nexport async function prebuildAgentImages(\n selectedAgents?: AgentType[]\n): Promise<{\n success: boolean;\n results: Array<{\n agentType: AgentType;\n success: boolean;\n error?: string;\n source: \"registry\" | \"dockerfile\" | \"cached\";\n }>;\n}> {\n const config = Configuration.getInstance().get();\n const logger = Configuration.getInstance().getLogger();\n \n // Try to use shared ImageResolver for pre-building\n try {\n const modulePath = '@vibe-kit/sdk/registry';\n const registryModule = await import(modulePath).catch(() => null);\n if (registryModule) {\n const { ImageResolver: SharedImageResolver } = registryModule;\n \n // Use the factory to create registry manager with appropriate registry\n const registryManager = await createRegistryManager(config, logger);\n if (registryManager) {\n const registryUser = config.registryUser || config.dockerHubUser;\n \n const imageResolver = new SharedImageResolver({\n preferRegistryImages: config.preferRegistryImages,\n pushImages: config.pushImages,\n privateRegistry: config.privateRegistry,\n dockerHubUser: registryUser, // For backward compatibility\n registryUser: registryUser,\n registryName: config.registryName,\n retryAttempts: config.retryAttempts,\n retryDelayMs: config.retryDelayMs,\n logger,\n }, registryManager);\n\n return await imageResolver.prebuildImages(selectedAgents);\n }\n }\n } catch (error) {\n logger.warn(\"Failed to use shared image resolver, falling back to basic prebuilding:\", error);\n }\n\n // Fallback to basic image resolution\n const allAgentTypes: AgentType[] = [\"claude\", \"codex\", \"opencode\", \"gemini\", \"grok\"];\n const agentTypes = selectedAgents?.length ? selectedAgents : allAgentTypes;\n const results: Array<{\n agentType: AgentType;\n success: boolean;\n error?: string;\n source: \"registry\" | \"dockerfile\" | \"cached\";\n }> = [];\n\n logger.info(\"Pre-caching agent images for faster startup (fallback mode)\");\n\n for (const agentType of agentTypes) {\n try {\n const imageResolver = new ImageResolver(config, logger);\n await imageResolver.resolveImage(agentType);\n results.push({ agentType, success: true, source: \"cached\" });\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n logger.error(`Failed to cache image for ${agentType}`, error);\n results.push({ agentType, success: false, error: errorMessage, source: \"dockerfile\" });\n }\n }\n\n const successCount = results.filter(r => r.success).length;\n logger.info(`Pre-cache complete: ${successCount}/${agentTypes.length} images ready`);\n\n return {\n success: successCount > 0,\n results,\n };\n}\n\n// Re-export types for backward compatibility\nexport type DockerLoginInfo = {\n isLoggedIn: boolean;\n username?: string | null;\n registry?: string;\n};\n\nexport type VibeKitConfig = {\n dockerHubUser?: string;\n lastImageBuild?: string;\n registryImages?: Partial<Record<AgentType, string>>;\n privateRegistry?: string;\n preferRegistryImages?: boolean;\n pushImages?: boolean;\n [key: string]: any;\n};\n\n// Re-export functions for backward compatibility\nexport { checkDockerLogin } from \"./registry-integration\";\nexport { getVibeKitConfig, saveVibeKitConfig } from \"./registry-integration\"; \nexport { uploadImagesToUserAccount, setupUserDockerRegistry } from \"./registry-integration\";","/**\n * Registry Integration Bridge\n * \n * Provides backward compatibility by bridging Dagger package functions\n * to the new shared registry infrastructure.\n */\n\nimport { Configuration } from \"./vibekit-dagger\";\n\n// Import types and classes dynamically to avoid circular dependencies\ntype DockerLoginInfo = {\n isLoggedIn: boolean;\n username?: string | null;\n registry?: string;\n};\n\ntype VibeKitConfig = {\n dockerHubUser?: string;\n lastImageBuild?: string;\n registryImages?: Partial<Record<AgentType, string>>;\n privateRegistry?: string;\n preferRegistryImages?: boolean;\n pushImages?: boolean;\n [key: string]: any;\n};\n\ntype AgentType = \"codex\" | \"claude\" | \"opencode\" | \"gemini\" | \"grok\";\n\n// Dynamic imports to avoid circular dependencies\nlet DockerClient: any = null;\nlet ConfigManager: any = null;\nlet DockerHubRegistry: any = null;\nlet RegistryManager: any = null;\n\nasync function getDockerClient() {\n if (!DockerClient) {\n // Import from services module\n const servicesPath = '@vibe-kit/sdk/services';\n const servicesModule = await import(servicesPath).catch(() => null);\n if (servicesModule) {\n DockerClient = servicesModule.DockerClient;\n }\n }\n \n if (!DockerClient) {\n throw new Error(\"DockerClient not available. Please ensure @vibe-kit/sdk is properly installed.\");\n }\n \n const config = Configuration.getInstance().get();\n const logger = Configuration.getInstance().getLogger();\n \n return new DockerClient({\n retryAttempts: config.retryAttempts,\n retryDelayMs: config.retryDelayMs,\n logger,\n });\n}\n\nasync function getConfigManager() {\n if (!ConfigManager) {\n // Import from services module\n const servicesPath = '@vibe-kit/sdk/services';\n const servicesModule = await import(servicesPath).catch(() => null);\n if (servicesModule) {\n ConfigManager = servicesModule.ConfigManager;\n }\n }\n \n if (!ConfigManager) {\n throw new Error(\"ConfigManager not available. Please ensure @vibe-kit/sdk is properly installed.\");\n }\n \n const config = Configuration.getInstance().get();\n const logger = Configuration.getInstance().getLogger();\n \n return new ConfigManager({\n configPath: config.configPath,\n logger,\n });\n}\n\nasync function getRegistryManager() {\n if (!DockerHubRegistry || !RegistryManager) {\n const registryPath = '@vibe-kit/sdk/registry';\n const registryModule = await import(registryPath).catch(() => null);\n if (registryModule) {\n DockerHubRegistry = registryModule.DockerHubRegistry;\n RegistryManager = registryModule.RegistryManager;\n }\n }\n \n if (!DockerHubRegistry || !RegistryManager) {\n throw new Error(\"Registry modules not available. Please ensure @vibe-kit/sdk is properly installed.\");\n }\n \n const logger = Configuration.getInstance().getLogger();\n const dockerHubRegistry = new DockerHubRegistry({ logger });\n \n const registryManager = new RegistryManager({\n defaultRegistry: 'dockerhub',\n logger,\n });\n \n registryManager.registerRegistry('dockerhub', dockerHubRegistry);\n return registryManager;\n}\n\n/**\n * Check if user is logged into Docker Hub\n */\nexport async function checkDockerLogin(): Promise<DockerLoginInfo> {\n const dockerClient = await getDockerClient();\n return await dockerClient.checkDockerLogin();\n}\n\n/**\n * Get or create VibeKit configuration\n */\nexport async function getVibeKitConfig(): Promise<VibeKitConfig> {\n const configManager = await getConfigManager();\n return await configManager.getConfig();\n}\n\n/**\n * Save VibeKit configuration\n */\nexport async function saveVibeKitConfig(config: VibeKitConfig): Promise<void> {\n const configManager = await getConfigManager();\n await configManager.saveConfig(config);\n}\n\n/**\n * Upload images to user's Docker Hub account\n */\nexport async function uploadImagesToUserAccount(\n dockerHubUser: string,\n selectedAgents?: AgentType[]\n): Promise<{\n success: boolean;\n results: Array<{\n agentType: AgentType;\n success: boolean;\n error?: string;\n imageUrl?: string;\n }>;\n}> {\n const registryManager = await getRegistryManager();\n return await registryManager.uploadImages(dockerHubUser, selectedAgents, 'dockerhub');\n}\n\n/**\n * Docker registry setup utilities\n */\nexport async function setupUserDockerRegistry(\n selectedAgents?: AgentType[]\n): Promise<{\n success: boolean;\n config?: VibeKitConfig;\n error?: string;\n}> {\n const registryManager = await getRegistryManager();\n return await registryManager.setupRegistry(selectedAgents, 'dockerhub');\n}","/**\n * Local Provider Setup and Installation\n * \n * Handles setup and pre-building of agent images for the local provider.\n * This includes validating dependencies, installing tools, and caching\n * Docker images for faster startup times.\n */\n\nimport { exec } from 'child_process';\nimport { promisify } from 'util';\nimport { prebuildAgentImages, type AgentType } from '../dagger/vibekit-dagger';\n\nconst execAsync = promisify(exec);\n\nexport interface SetupOptions {\n skipPreBuild?: boolean;\n selectedAgents?: AgentType[];\n verbose?: boolean;\n}\n\nexport interface SetupResult {\n success: boolean;\n message: string;\n preBuildResults?: Array<{ agentType: AgentType; success: boolean; error?: string }>;\n warnings?: string[];\n}\n\n/**\n * Validate system dependencies for local provider\n */\nexport async function validateDependencies(): Promise<{ valid: boolean; issues: string[] }> {\n const issues: string[] = [];\n\n try {\n // Check Docker\n await execAsync('docker --version');\n try {\n await execAsync('docker info');\n } catch (error) {\n issues.push('Docker is installed but not running. Please start Docker.');\n }\n } catch (error) {\n issues.push('Docker is not installed. Please install Docker from https://docs.docker.com/get-docker/');\n }\n\n try {\n // Check Dagger CLI\n await execAsync('dagger version');\n } catch (error) {\n issues.push('Dagger CLI is not installed. Please install from https://docs.dagger.io/install/');\n }\n\n try {\n // Check Node.js version (for MCP server functionality)\n const { stdout } = await execAsync('node --version');\n const version = stdout.trim();\n const majorVersion = parseInt(version.substring(1).split('.')[0]);\n if (majorVersion < 18) {\n issues.push(`Node.js ${version} detected. Node.js 18+ is recommended for optimal performance.`);\n }\n } catch (error) {\n issues.push('Node.js is not available. This may affect MCP server functionality.');\n }\n\n return {\n valid: issues.length === 0,\n issues\n };\n}\n\n/**\n * Setup the local provider with optional pre-building\n */\nexport async function setupLocalProvider(options: SetupOptions = {}): Promise<SetupResult> {\n const { skipPreBuild = false, selectedAgents, verbose = false } = options;\n const warnings: string[] = [];\n\n try {\n if (verbose) {\n console.log('🔍 Validating system dependencies...');\n }\n\n // Step 1: Validate dependencies\n const validation = await validateDependencies();\n if (!validation.valid) {\n return {\n success: false,\n message: `Setup failed due to missing dependencies:\\n${validation.issues.map(issue => ` ❌ ${issue}`).join('\\n')}`,\n warnings\n };\n }\n\n if (verbose) {\n console.log('✅ System dependencies validated');\n }\n\n // Step 2: Test Dagger connectivity\n if (verbose) {\n console.log('🔗 Testing Dagger engine connectivity...');\n }\n\n try {\n await execAsync('dagger query --help', { timeout: 10000 });\n if (verbose) {\n console.log('✅ Dagger engine connectivity verified');\n }\n } catch (error) {\n warnings.push('Dagger engine test skipped (may start on first use)');\n if (verbose) {\n console.log('⚠️ Dagger engine will start automatically on first use');\n }\n }\n\n let preBuildResults;\n\n // Step 3: Pre-build agent images (optional)\n if (!skipPreBuild) {\n if (verbose) {\n console.log('🏗️ Pre-building agent images for faster startup...');\n }\n\n try {\n const buildResult = await prebuildAgentImages(selectedAgents);\n preBuildResults = buildResult.results;\n\n if (buildResult.success) {\n const successCount = buildResult.results.filter(r => r.success).length;\n if (verbose) {\n console.log(`✅ Pre-build completed: ${successCount}/${buildResult.results.length} images ready`);\n }\n } else {\n warnings.push('Some agent images failed to pre-build but can be built on first use');\n }\n } catch (error) {\n warnings.push(`Pre-building failed: ${error instanceof Error ? error.message : String(error)}`);\n if (verbose) {\n console.log('⚠️ Agent images will be built on first use instead');\n }\n }\n } else if (verbose) {\n console.log('⏭️ Skipping pre-build as requested');\n }\n\n // Step 4: Setup completion\n const successMessage = [\n 'Local provider setup completed successfully!',\n '',\n '📋 What\\'s available:',\n ' • Create sandboxes with agent-specific environments',\n ' • Automatic Docker image caching for fast startup',\n ' • Local development with containerized isolation',\n ' • Git operations and PR creation support',\n '',\n '🚀 Quick start:',\n ' const provider = createLocalProvider();',\n ' const sandbox = await provider.create({}, \"claude\");',\n '',\n ];\n\n if (preBuildResults) {\n const successfulBuilds = preBuildResults.filter(r => r.success).map(r => r.agentType);\n if (successfulBuilds.length > 0) {\n successMessage.push(`🎯 Pre-built agents: ${successfulBuilds.join(', ')}`);\n }\n }\n\n if (warnings.length > 0) {\n successMessage.push('');\n successMessage.push('⚠️ Warnings:');\n warnings.forEach(warning => successMessage.push(` • ${warning}`));\n }\n\n return {\n success: true,\n message: successMessage.join('\\n'),\n preBuildResults,\n warnings\n };\n\n } catch (error) {\n return {\n success: false,\n message: `Setup failed: ${error instanceof Error ? error.message : String(error)}`,\n warnings\n };\n }\n}\n\n/**\n * Pre-build specific agent images\n */\nexport async function prebuildSpecificAgents(agentTypes: AgentType[]): Promise<SetupResult> {\n try {\n console.log(`🏗️ Pre-building images for: ${agentTypes.join(', ')}`);\n \n const buildResult = await prebuildAgentImages();\n const requestedResults = buildResult.results.filter(r => agentTypes.includes(r.agentType));\n \n const successCount = requestedResults.filter(r => r.success).length;\n const failedAgents = requestedResults.filter(r => !r.success).map(r => `${r.agentType}: ${r.error}`);\n \n let message = `Pre-build completed: ${successCount}/${agentTypes.length} requested images ready`;\n \n if (failedAgents.length > 0) {\n message += `\\n\\nFailed builds:\\n${failedAgents.map(f => ` ❌ ${f}`).join('\\n')}`;\n }\n\n return {\n success: successCount > 0,\n message,\n preBuildResults: requestedResults\n };\n } catch (error) {\n return {\n success: false,\n message: `Pre-build failed: ${error instanceof Error ? error.message : String(error)}`\n };\n }\n}\n\n/**\n * Check if local provider is properly set up\n */\nexport async function checkSetupStatus(): Promise<{ isSetup: boolean; issues: string[]; recommendations: string[] }> {\n const issues: string[] = [];\n const recommendations: string[] = [];\n\n // Check dependencies\n const validation = await validateDependencies();\n issues.push(...validation.issues);\n\n // Check if any agent images are pre-built\n try {\n const agentTypes: AgentType[] = [\"claude\", \"codex\", \"opencode\", \"gemini\"];\n let hasPreBuiltImages = false;\n\n for (const agentType of agentTypes) {\n try {\n const { stdout } = await execAsync(`docker images -q vibekit-${agentType}:latest`);\n if (stdout.trim()) {\n hasPreBuiltImages = true;\n break;\n }\n } catch (error) {\n // Ignore individual image check errors\n }\n }\n\n if (!hasPreBuiltImages) {\n recommendations.push('Consider pre-building agent images for faster startup: prebuildAgentImages()');\n }\n } catch (error) {\n recommendations.push('Unable to check pre-built images status');\n }\n\n return {\n isSetup: issues.length === 0,\n issues,\n recommendations\n };\n}\n\n/**\n * Clean up pre-built images (for maintenance)\n */\nexport async function cleanupPreBuiltImages(): Promise<{ success: boolean; removed: string[]; errors: string[] }> {\n const removed: string[] = [];\n const errors: string[] = [];\n const agentTypes: AgentType[] = [\"claude\", \"codex\", \"opencode\", \"gemini\"];\n\n for (const agentType of agentTypes) {\n const imageTag = `vibekit-${agentType}:latest`;\n try {\n const { stdout } = await execAsync(`docker images -q ${imageTag}`);\n if (stdout.trim()) {\n await execAsync(`docker rmi ${imageTag}`);\n removed.push(imageTag);\n }\n } catch (error) {\n errors.push(`Failed to remove ${imageTag}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n\n return {\n success: errors.length === 0,\n removed,\n errors\n };\n} ","/**\n * Environment Storage System\n * \n * Provides persistent storage for sandbox environment metadata\n * to track environments across CLI sessions.\n */\n\nimport { readFile, writeFile, mkdir } from 'fs/promises';\nimport { existsSync } from 'fs';\nimport { join, dirname } from 'path';\nimport { homedir } from 'os';\nimport type { AgentType } from '../dagger/vibekit-dagger';\n\nexport interface EnvironmentRecord {\n id: string;\n name: string;\n status: 'running' | 'stopped' | 'paused' | 'error';\n agentType?: AgentType;\n branch?: string;\n created: Date;\n lastUsed: Date;\n sandboxId: string;\n workingDirectory: string;\n envVars: Record<string, string>;\n dockerImage?: string;\n pid?: number; // For tracking background processes\n githubToken?: string;\n model?: string;\n apiKey?: string;\n}\n\nexport class EnvironmentStore {\n private storePath: string;\n private lockPath: string;\n\n constructor(customPath?: string) {\n const basePath = customPath || join(homedir(), '.vibekit');\n this.storePath = join(basePath, 'environments.json');\n this.lockPath = join(basePath, 'environments.lock');\n }\n\n /**\n * Ensure storage directory exists\n */\n private async ensureStorageDir(): Promise<void> {\n const dir = dirname(this.storePath);\n if (!existsSync(dir)) {\n await mkdir(dir, { recursive: true });\n }\n }\n\n /**\n * Simple file-based locking for concurrent access\n */\n private async acquireLock(): Promise<void> {\n await this.ensureStorageDir();\n let attempts = 0;\n const maxAttempts = 50; // 5 seconds with 100ms intervals\n \n while (attempts < maxAttempts) {\n try {\n if (!existsSync(this.lockPath)) {\n await writeFile(this.lockPath, process.pid.toString());\n return;\n }\n await new Promise(resolve => setTimeout(resolve, 100));\n attempts++;\n } catch (error) {\n // File might have been deleted between check and write, try again\n attempts++;\n }\n }\n \n throw new Error('Could not acquire lock for environment storage');\n }\n\n /**\n * Release the file lock\n */\n private async releaseLock(): Promise<void> {\n try {\n if (existsSync(this.lockPath)) {\n const lockContent = await readFile(this.lockPath, 'utf-8');\n if (lockContent.trim() === process.pid.toString()) {\n await writeFile(this.lockPath, ''); // Clear lock file\n }\n }\n } catch (error) {\n // Lock file might have been removed by another process\n }\n }\n\n /**\n * Load all environments from storage\n */\n async load(): Promise<EnvironmentRecord[]> {\n await this.acquireLock();\n \n try {\n await this.ensureStorageDir();\n \n if (!existsSync(this.storePath)) {\n return [];\n }\n\n const content = await readFile(this.storePath, 'utf-8');\n const data = JSON.parse(content);\n \n // Convert date strings back to Date objects\n return data.map((env: any) => ({\n ...env,\n created: new Date(env.created),\n lastUsed: new Date(env.lastUsed)\n }));\n } catch (error) {\n if (error instanceof SyntaxError) {\n // Corrupted JSON, start fresh\n return [];\n }\n throw error;\n } finally {\n await this.releaseLock();\n }\n }\n\n /**\n * Save all environments to storage\n */\n private async saveAll(environments: EnvironmentRecord[]): Promise<void> {\n await this.ensureStorageDir();\n await writeFile(this.storePath, JSON.stringify(environments, null, 2));\n }\n\n /**\n * Save a new environment\n */\n async save(env: EnvironmentRecord): Promise<void> {\n await this.acquireLock();\n \n try {\n const environments = await this.load();\n \n // Check for duplicate names\n const existing = environments.find(e => e.name === env.name);\n if (existing) {\n throw new Error(`Environment with name '${env.name}' already exists`);\n }\n \n environments.push(env);\n await this.saveAll(environments);\n } finally {\n await this.releaseLock();\n }\n }\n\n /**\n * Update an existing environment\n */\n async update(id: string, updates: Partial<EnvironmentRecord>): Promise<void> {\n await this.acquireLock();\n \n try {\n const environments = await this.load();\n const index = environments.findIndex(env => env.id === id);\n \n if (index === -1) {\n throw new Error(`Environment with id '${id}' not found`);\n }\n \n environments[index] = { ...environments[index], ...updates };\n await this.saveAll(environments);\n } finally {\n await this.releaseLock();\n }\n }\n\n /**\n * Delete an environment by ID\n */\n async delete(id: string): Promise<void> {\n await this.acquireLock();\n \n try {\n const environments = await this.load();\n const filteredEnvironments = environments.filter(env => env.id !== id);\n \n if (filteredEnvironments.length === environments.length) {\n throw new Error(`Environment with id '${id}' not found`);\n }\n \n await this.saveAll(filteredEnvironments);\n } finally {\n await this.releaseLock();\n }\n }\n\n /**\n * Find environment by ID\n */\n async findById(id: string): Promise<EnvironmentRecord | null> {\n const environments = await this.load();\n return environments.find(env => env.id === id) || null;\n }\n\n /**\n * Find environment by name\n */\n async findByName(name: string): Promise<EnvironmentRecord | null> {\n const environments = await this.load();\n return environments.find(env => env.name === name) || null;\n }\n\n /**\n * Get environments filtered by status\n */\n async getByStatus(status: EnvironmentRecord['status']): Promise<EnvironmentRecord[]> {\n const environments = await this.load();\n return environments.filter(env => env.status === status);\n }\n\n /**\n * Get environments filtered by agent type\n */\n async getByAgentType(agentType: AgentType): Promise<EnvironmentRecord[]> {\n const environments = await this.load();\n return environments.filter(env => env.agentType === agentType);\n }\n\n /**\n * Clean up old environments (older than specified days)\n */\n async cleanup(olderThanDays: number = 30): Promise<string[]> {\n await this.acquireLock();\n \n try {\n const environments = await this.load();\n const cutoffDate = new Date();\n cutoffDate.setDate(cutoffDate.getDate() - olderThanDays);\n \n const toRemove = environments.filter(env => \n env.lastUsed < cutoffDate && env.status !== 'running'\n );\n \n const remaining = environments.filter(env => \n env.lastUsed >= cutoffDate || env.status === 'running'\n );\n \n await this.saveAll(remaining);\n \n return toRemove.map(env => env.name);\n } finally {\n await this.releaseLock();\n }\n }\n} "],"mappings":"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