UNPKG

@vibeship/devtools

Version:

Comprehensive markdown-based project management system with AI capabilities for Next.js applications

1,453 lines (1,430 loc) 698 kB
"use client"; #!/usr/bin/env node "use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __esm = (fn, res) => function __init() { return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; }; var __commonJS = (cb, mod) => function __require() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; var __export = (target, all) => { for (var name14 in all) __defProp(target, name14, { get: all[name14], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/contexts/VibeshipContext.tsx var import_react, import_jsx_runtime, VibeshipContext; var init_VibeshipContext = __esm({ "src/contexts/VibeshipContext.tsx"() { "use strict"; "use client"; import_react = require("react"); import_jsx_runtime = require("react/jsx-runtime"); VibeshipContext = (0, import_react.createContext)(void 0); } }); // src/providers/ErrorBoundary.tsx function withErrorBoundary(Component4, errorBoundaryProps) { const WrappedComponent = (props) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ErrorBoundary, { ...errorBoundaryProps, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Component4, { ...props }) }); WrappedComponent.displayName = `withErrorBoundary(${Component4.displayName || Component4.name})`; return WrappedComponent; } var import_react2, import_jsx_runtime2, ErrorBoundary; var init_ErrorBoundary = __esm({ "src/providers/ErrorBoundary.tsx"() { "use strict"; "use client"; import_react2 = require("react"); import_jsx_runtime2 = require("react/jsx-runtime"); ErrorBoundary = class extends import_react2.Component { constructor(props) { super(props); this.reset = () => { this.setState({ hasError: false, error: null, errorInfo: null }); }; this.state = { hasError: false, error: null, errorInfo: null }; } static getDerivedStateFromError(error) { return { hasError: true, error }; } componentDidCatch(error, errorInfo) { if (true) { console.error(`[Vibecode ErrorBoundary${this.props.name ? ` - ${this.props.name}` : ""}]:`, error, errorInfo); } this.props.onError?.(error, errorInfo); this.setState({ errorInfo }); } render() { if (this.state.hasError && this.state.error && this.state.errorInfo) { if (this.props.fallback) { return this.props.fallback(this.state.error, this.state.errorInfo, this.reset); } return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "vibecode-error-boundary p-4 border border-red-500 rounded-lg bg-red-50 dark:bg-red-950", children: [ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { className: "text-lg font-semibold text-red-700 dark:text-red-300 mb-2", children: "Something went wrong" }), /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("details", { className: "text-sm text-red-600 dark:text-red-400", children: [ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("summary", { className: "cursor-pointer mb-2", children: "Error details" }), /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("pre", { className: "whitespace-pre-wrap overflow-auto p-2 bg-red-100 dark:bg-red-900 rounded", children: [ this.state.error.toString(), this.state.errorInfo.componentStack ] }) ] }), /* @__PURE__ */ (0, import_jsx_runtime2.jsx)( "button", { onClick: this.reset, className: "mt-4 px-4 py-2 bg-red-600 text-white rounded hover:bg-red-700 transition-colors", children: "Try again" } ) ] }); } return this.props.children; } }; } }); // src/providers/LoadingSpinner.tsx function LoadingSpinner() { return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "vibecode-loading-spinner fixed bottom-4 right-4 p-3 bg-white dark:bg-gray-800 rounded-lg shadow-lg", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex items-center space-x-2", children: [ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "animate-spin rounded-full h-4 w-4 border-b-2 border-primary" }), /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-sm text-gray-600 dark:text-gray-400", children: "Loading Vibecode DevTools..." }) ] }) }); } var import_jsx_runtime3; var init_LoadingSpinner = __esm({ "src/providers/LoadingSpinner.tsx"() { "use strict"; "use client"; import_jsx_runtime3 = require("react/jsx-runtime"); } }); // src/services/security/encryption-service.ts var EncryptionService; var init_encryption_service = __esm({ "src/services/security/encryption-service.ts"() { "use strict"; EncryptionService = class { constructor() { this.algorithm = "AES-GCM"; this.keyLength = 256; this.saltLength = 16; this.ivLength = 12; this.tagLength = 128; this.iterations = 1e5; } /** * Derives a key from a password using PBKDF2 */ async deriveKey(password, salt) { const encoder = new TextEncoder(); const passwordBuffer = encoder.encode(password); const importedKey = await crypto.subtle.importKey( "raw", passwordBuffer, "PBKDF2", false, ["deriveBits", "deriveKey"] ); return crypto.subtle.deriveKey( { name: "PBKDF2", salt, iterations: this.iterations, hash: "SHA-256" }, importedKey, { name: this.algorithm, length: this.keyLength }, false, ["encrypt", "decrypt"] ); } /** * Gets or generates the encryption password */ async getPassword() { if (typeof window === "undefined") { return process.env.ENCRYPTION_KEY || "default-dev-key-change-in-production"; } const storageKey = "vibecode-encryption-id"; let password = localStorage.getItem(storageKey); if (!password) { password = this.generatePassword(); localStorage.setItem(storageKey, password); } return password; } /** * Generates a secure random password */ generatePassword() { const array = new Uint8Array(32); crypto.getRandomValues(array); return Array.from(array, (byte) => byte.toString(16).padStart(2, "0")).join(""); } /** * Encrypts a string */ async encrypt(plaintext) { const encoder = new TextEncoder(); const data = encoder.encode(plaintext); const salt = crypto.getRandomValues(new Uint8Array(this.saltLength)); const iv = crypto.getRandomValues(new Uint8Array(this.ivLength)); const password = await this.getPassword(); const key = await this.deriveKey(password, salt); const encrypted = await crypto.subtle.encrypt( { name: this.algorithm, iv, tagLength: this.tagLength }, key, data ); const combined = new Uint8Array( salt.length + iv.length + encrypted.byteLength ); combined.set(salt, 0); combined.set(iv, salt.length); combined.set(new Uint8Array(encrypted), salt.length + iv.length); return btoa(String.fromCharCode.apply(null, Array.from(combined))); } /** * Decrypts a string */ async decrypt(ciphertext) { const combined = Uint8Array.from(atob(ciphertext), (c) => c.charCodeAt(0)); const salt = combined.slice(0, this.saltLength); const iv = combined.slice(this.saltLength, this.saltLength + this.ivLength); const encrypted = combined.slice(this.saltLength + this.ivLength); const password = await this.getPassword(); const key = await this.deriveKey(password, salt); const decrypted = await crypto.subtle.decrypt( { name: this.algorithm, iv, tagLength: this.tagLength }, key, encrypted ); const decoder = new TextDecoder(); return decoder.decode(decrypted); } /** * Checks if Web Crypto API is available */ isAvailable() { return typeof crypto !== "undefined" && crypto.subtle !== void 0; } }; } }); // src/services/security/api-key-manager.ts var BrowserSecureStorage, SecureAPIKeyManager; var init_api_key_manager = __esm({ "src/services/security/api-key-manager.ts"() { "use strict"; init_encryption_service(); BrowserSecureStorage = class { constructor() { this.prefix = "vibecode-secure-"; } async get(key) { if (typeof window === "undefined") return null; return localStorage.getItem(this.prefix + key); } async set(key, value) { if (typeof window === "undefined") return; localStorage.setItem(this.prefix + key, value); } async remove(key) { if (typeof window === "undefined") return; localStorage.removeItem(this.prefix + key); } async list() { if (typeof window === "undefined") return []; const keys = []; for (let i = 0; i < localStorage.length; i++) { const key = localStorage.key(i); if (key?.startsWith(this.prefix)) { keys.push(key.substring(this.prefix.length)); } } return keys; } }; SecureAPIKeyManager = class { // 5 minutes constructor(encryption, storage) { this.keyPrefix = "api-key-"; this.validationCache = /* @__PURE__ */ new Map(); this.cacheTimeout = 5 * 60 * 1e3; this.encryption = encryption || new EncryptionService(); this.storage = storage || new BrowserSecureStorage(); } async store(provider, key) { if (!key || !provider) { throw new Error("Provider and key are required"); } this.validateKeyFormat(provider, key); let encrypted; try { if (typeof window !== "undefined" && this.encryption.isAvailable()) { encrypted = await this.encryption.encrypt(key); } else { encrypted = Buffer.from(key).toString("base64"); } } catch (error) { console.warn("Encryption failed, using base64:", error); encrypted = Buffer.from(key).toString("base64"); } await this.storage.set(this.keyPrefix + provider, encrypted); this.validationCache.delete(provider); } async retrieve(provider) { console.log(`[APIKeyManager] Retrieving key for ${provider}`); const encrypted = await this.storage.get(this.keyPrefix + provider); if (!encrypted) { console.log(`[APIKeyManager] No encrypted key found for ${provider}`); return null; } console.log(`[APIKeyManager] Found encrypted key for ${provider}, attempting to decrypt...`); try { if (typeof window === "undefined") { const decoded = Buffer.from(encrypted, "base64").toString("utf-8"); console.log(`[APIKeyManager] Successfully decoded key for ${provider} (server-side)`); return decoded; } const decrypted = await this.encryption.decrypt(encrypted); console.log(`[APIKeyManager] Successfully decrypted key for ${provider} (client-side)`); return decrypted; } catch (error) { console.error("Failed to decrypt API key:", error); try { const decoded = Buffer.from(encrypted, "base64").toString("utf-8"); console.log(`[APIKeyManager] Used fallback base64 decode for ${provider}`); return decoded; } catch { console.error(`[APIKeyManager] Failed to decode key for ${provider} even with fallback`); return null; } } } async remove(provider) { await this.storage.remove(this.keyPrefix + provider); this.validationCache.delete(provider); } async validate(provider, key) { const cached = this.validationCache.get(provider); if (cached && Date.now() - cached.timestamp < this.cacheTimeout) { return cached.valid; } let valid = false; try { switch (provider) { case "openai": valid = await this.validateOpenAIKey(key); break; case "anthropic": valid = await this.validateAnthropicKey(key); break; case "xai": valid = await this.validateXAIKey(key); break; default: valid = this.isValidKeyFormat(key); } } catch (error) { console.error("Key validation error:", error); valid = false; } this.validationCache.set(provider, { valid, timestamp: Date.now() }); return valid; } async rotate(provider) { const newKey = this.generateMockKey(provider); await this.store(provider, newKey); return newKey; } async listProviders() { const keys = await this.storage.list(); return keys.filter((key) => key.startsWith(this.keyPrefix)).map((key) => key.substring(this.keyPrefix.length)); } async hasKey(provider) { const key = await this.retrieve(provider); return key !== null; } // Private validation methods validateKeyFormat(provider, key) { if (!this.isValidKeyFormat(key)) { throw new Error(`Invalid key format for provider: ${provider}`); } switch (provider) { case "openai": if (!key.startsWith("sk-") && !key.startsWith("sk-proj-")) { throw new Error('OpenAI keys must start with "sk-" or "sk-proj-"'); } break; case "anthropic": if (!key.startsWith("sk-ant-")) { throw new Error('Anthropic keys must start with "sk-ant-"'); } break; } } isValidKeyFormat(key) { return /^[a-zA-Z0-9\-_]{20,}$/.test(key); } async validateOpenAIKey(key) { try { const response = await fetch("https://api.openai.com/v1/models", { headers: { "Authorization": `Bearer ${key}` } }); return response.status === 200; } catch { return false; } } async validateAnthropicKey(key) { if (typeof window !== "undefined") { console.log("[APIKeyManager] Skipping Anthropic key validation on client side (CORS)"); return key.startsWith("sk-ant-") && key.length > 40; } try { const response = await fetch("https://api.anthropic.com/v1/messages", { method: "POST", headers: { "x-api-key": key, "anthropic-version": "2023-06-01", "content-type": "application/json" }, body: JSON.stringify({ model: "claude-3-opus-20240229", messages: [{ role: "user", content: "test" }], max_tokens: 1 }) }); return response.status !== 401; } catch { return false; } } async validateXAIKey(key) { return this.isValidKeyFormat(key); } generateMockKey(provider) { const prefix = { openai: "sk-proj-", anthropic: "sk-ant-", xai: "xai-" }[provider] || "key-"; const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; let key = prefix; for (let i = 0; i < 48; i++) { key += chars.charAt(Math.floor(Math.random() * chars.length)); } return key; } }; } }); // src/services/settings/ai-settings-store.ts var DEFAULT_SETTINGS, LocalStorageAISettingsStore; var init_ai_settings_store = __esm({ "src/services/settings/ai-settings-store.ts"() { "use strict"; init_api_key_manager(); DEFAULT_SETTINGS = { provider: "openai", model: "gpt-4-turbo-preview", apiKeys: {}, temperature: 0.7, maxTokens: 4096, streaming: true, advanced: { timeout: 3e4, retries: 3, cache: true, responseFormat: "text" }, mcp: { enabled: false, transport: "http" } }; LocalStorageAISettingsStore = class { constructor(keyManager) { this.storageKey = "vibecode-ai-settings"; this.versionKey = "vibecode-ai-settings-version"; this.currentVersion = "1.0.0"; this.keyManager = keyManager || new SecureAPIKeyManager(); } async load() { if (typeof window === "undefined") { return DEFAULT_SETTINGS; } try { const stored = localStorage.getItem(this.storageKey); if (!stored) { return DEFAULT_SETTINGS; } const settings = JSON.parse(stored); const version = localStorage.getItem(this.versionKey); if (version !== this.currentVersion) { await this.migrate(version || "0.0.0"); } const providers = await this.keyManager.listProviders(); const apiKeys = {}; for (const provider of providers) { const key = await this.keyManager.retrieve(provider); if (key) { apiKeys[provider] = key; } } return { ...DEFAULT_SETTINGS, ...settings, apiKeys }; } catch (error) { console.error("Failed to load AI settings:", error); return DEFAULT_SETTINGS; } } async save(settings) { if (typeof window === "undefined") { return; } try { for (const [provider, key] of Object.entries(settings.apiKeys)) { if (key) { await this.keyManager.store(provider, key); } else { await this.keyManager.remove(provider); } } const { apiKeys, ...settingsWithoutKeys } = settings; localStorage.setItem(this.storageKey, JSON.stringify(settingsWithoutKeys)); localStorage.setItem(this.versionKey, this.currentVersion); } catch (error) { console.error("Failed to save AI settings:", error); throw error; } } async migrate(oldVersion) { console.log(`Migrating AI settings from version ${oldVersion} to ${this.currentVersion}`); if (oldVersion < "1.0.0") { const oldSettings = localStorage.getItem("ai-settings"); if (oldSettings) { try { const parsed = JSON.parse(oldSettings); await this.save({ ...DEFAULT_SETTINGS, ...parsed }); localStorage.removeItem("ai-settings"); } catch (error) { console.error("Migration failed:", error); } } } } async export() { const settings = await this.load(); const exportData = { version: this.currentVersion, timestamp: (/* @__PURE__ */ new Date()).toISOString(), settings: { ...settings, // Mask API keys for security apiKeys: Object.keys(settings.apiKeys).reduce((acc, key) => { acc[key] = "***MASKED***"; return acc; }, {}) } }; return JSON.stringify(exportData, null, 2); } async import(data) { try { const parsed = JSON.parse(data); if (!parsed.version || !parsed.settings) { throw new Error("Invalid import data format"); } const { apiKeys, ...settingsWithoutKeys } = parsed.settings; await this.save({ ...DEFAULT_SETTINGS, ...settingsWithoutKeys, apiKeys: {} // Keep existing keys }); } catch (error) { console.error("Failed to import AI settings:", error); throw new Error("Failed to import settings: Invalid format"); } } async reset() { if (typeof window === "undefined") { return; } const providers = await this.keyManager.listProviders(); for (const provider of providers) { await this.keyManager.remove(provider); } localStorage.removeItem(this.storageKey); localStorage.removeItem(this.versionKey); } }; } }); // src/contexts/AISettingsContext.tsx function AISettingsProvider({ children, aiService }) { const [settings, setSettings] = (0, import_react3.useState)(null); const [providers, setProviders] = (0, import_react3.useState)(PROVIDER_INFO); const [isLoading, setIsLoading] = (0, import_react3.useState)(true); const [hasUnsavedChanges, setHasUnsavedChanges] = (0, import_react3.useState)(false); const settingsStore = typeof window !== "undefined" ? new LocalStorageAISettingsStore() : null; const keyManager = typeof window !== "undefined" ? new SecureAPIKeyManager() : null; (0, import_react3.useEffect)(() => { if (typeof window !== "undefined") { loadSettings(); } }, [aiService]); const loadSettings = async () => { if (!settingsStore) return; try { setIsLoading(true); const loadedSettings = await settingsStore.load(); setSettings(loadedSettings); await updateProviderStatuses(loadedSettings); if (aiService && keyManager) { const apiKeys = {}; if (await keyManager.hasKey("openai")) { const key = await keyManager.retrieve("openai"); if (key) apiKeys.openai = { apiKey: key }; } if (await keyManager.hasKey("anthropic")) { const key = await keyManager.retrieve("anthropic"); if (key) apiKeys.anthropic = { apiKey: key }; } if (await keyManager.hasKey("xai")) { const key = await keyManager.retrieve("xai"); if (key) apiKeys.xai = { apiKey: key }; } if (Object.keys(apiKeys).length > 0) { aiService.configure({ providers: apiKeys, defaultProvider: loadedSettings.provider, defaultModel: loadedSettings.model }); } } } catch (error) { console.error("Failed to load AI settings:", error); } finally { setIsLoading(false); } }; const updateProviderStatuses = async (currentSettings) => { const updatedProviders = await Promise.all( providers.map(async (provider) => { const hasKey = keyManager ? await keyManager.hasKey(provider.id) : false; return { ...provider, status: hasKey ? "connected" : "disconnected" }; }) ); setProviders(updatedProviders); }; const updateSettings = (0, import_react3.useCallback)((updates) => { if (!settings) return; setSettings((prev) => prev ? { ...prev, ...updates } : null); setHasUnsavedChanges(true); }, [settings]); const saveSettings = async () => { if (!settings || !settingsStore) return; try { await settingsStore.save(settings); setHasUnsavedChanges(false); await updateProviderStatuses(settings); if (aiService && keyManager) { const apiKeys = {}; if (await keyManager.hasKey("openai")) { const key = await keyManager.retrieve("openai"); if (key) apiKeys.openai = { apiKey: key }; } if (await keyManager.hasKey("anthropic")) { const key = await keyManager.retrieve("anthropic"); if (key) apiKeys.anthropic = { apiKey: key }; } if (await keyManager.hasKey("xai")) { const key = await keyManager.retrieve("xai"); if (key) apiKeys.xai = { apiKey: key }; } aiService.configure({ providers: apiKeys, defaultProvider: settings.provider, defaultModel: settings.model }); } } catch (error) { console.error("Failed to save settings:", error); throw error; } }; const resetSettings = async () => { if (!settingsStore) return; try { await settingsStore.reset(); await loadSettings(); setHasUnsavedChanges(false); } catch (error) { console.error("Failed to reset settings:", error); throw error; } }; const exportSettings = async () => { if (!settingsStore) throw new Error("Settings store not available"); return settingsStore.export(); }; const importSettings = async (data) => { if (!settingsStore) throw new Error("Settings store not available"); try { await settingsStore.import(data); await loadSettings(); setHasUnsavedChanges(false); } catch (error) { console.error("Failed to import settings:", error); throw error; } }; const updateApiKey = async (provider, key) => { if (!settings || !keyManager) return; try { await keyManager.store(provider, key); setSettings((prev) => prev ? { ...prev, apiKeys: { ...prev.apiKeys, [provider]: key } } : null); setHasUnsavedChanges(true); setProviders((prev) => prev.map( (p) => p.id === provider ? { ...p, status: "connected" } : p )); } catch (error) { console.error("Failed to update API key:", error); throw error; } }; const removeApiKey = async (provider) => { if (!settings || !keyManager) return; try { await keyManager.remove(provider); const { [provider]: _, ...remainingKeys } = settings.apiKeys; setSettings((prev) => prev ? { ...prev, apiKeys: remainingKeys } : null); setHasUnsavedChanges(true); setProviders((prev) => prev.map( (p) => p.id === provider ? { ...p, status: "disconnected" } : p )); } catch (error) { console.error("Failed to remove API key:", error); throw error; } }; const validateApiKey = async (provider, key) => { if (!keyManager) return false; return keyManager.validate(provider, key); }; const testConnection = async (provider) => { try { setProviders((prev) => prev.map( (p) => p.id === provider ? { ...p, status: "checking" } : p )); const startTime = Date.now(); const isValid = await validateApiKey(provider, settings?.apiKeys[provider] || ""); const latency = Date.now() - startTime; const result = { success: isValid, latency, error: isValid ? void 0 : "Invalid API key" }; setProviders((prev) => prev.map( (p) => p.id === provider ? { ...p, status: isValid ? "connected" : "error", error: result.error } : p )); return result; } catch (error) { const result = { success: false, error: error instanceof Error ? error.message : "Connection test failed" }; setProviders((prev) => prev.map( (p) => p.id === provider ? { ...p, status: "error", error: result.error } : p )); return result; } }; const switchProvider = (providerId) => { if (!settings) return; const provider = providers.find((p) => p.id === providerId); if (!provider) return; const firstModel = provider.models[0]; updateSettings({ provider: providerId, model: firstModel?.id || "" }); if (aiService) { aiService.switchProvider(providerId); if (firstModel) { aiService.switchModel(firstModel.id); } } }; const switchModel = (modelId) => { if (!settings) return; updateSettings({ model: modelId }); if (aiService) { aiService.switchModel(modelId); } }; const estimateCost = (inputTokens, outputTokens) => { if (!settings) return null; const provider = providers.find((p) => p.id === settings.provider); const model = provider?.models.find((m) => m.id === settings.model); if (!model?.pricing) return null; const inputCost = inputTokens / 1e3 * model.pricing.input; const outputCost = outputTokens / 1e3 * model.pricing.output; return { provider: settings.provider, model: settings.model, inputTokens, outputTokens, inputCost, outputCost, totalCost: inputCost + outputCost, currency: model.pricing.currency }; }; if (!settings) { return null; } return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)( AISettingsContext.Provider, { value: { settings, providers, isLoading, hasUnsavedChanges, updateSettings, saveSettings, resetSettings, exportSettings, importSettings, updateApiKey, removeApiKey, validateApiKey, testConnection, switchProvider, switchModel, estimateCost }, children } ); } function useAISettings() { const context = (0, import_react3.useContext)(AISettingsContext); if (context === void 0) { throw new Error("useAISettings must be used within an AISettingsProvider"); } return context; } var import_react3, import_jsx_runtime4, AISettingsContext, PROVIDER_INFO; var init_AISettingsContext = __esm({ "src/contexts/AISettingsContext.tsx"() { "use strict"; "use client"; import_react3 = require("react"); init_ai_settings_store(); init_api_key_manager(); import_jsx_runtime4 = require("react/jsx-runtime"); AISettingsContext = (0, import_react3.createContext)(void 0); PROVIDER_INFO = [ { id: "openai", name: "OpenAI", icon: "\u{1F916}", description: "GPT-4, GPT-3.5, and DALL-E models", website: "https://openai.com", requiresApiKey: true, customizable: false, status: "disconnected", models: [ { id: "gpt-4-turbo-preview", name: "GPT-4 Turbo", description: "Most capable model with 128k context", contextWindow: 128e3, maxTokens: 4096, supports: { chat: true, completion: true, functionCalling: true, vision: true, streaming: true, jsonMode: true }, pricing: { currency: "USD", input: 0.01, output: 0.03 } }, { id: "gpt-4", name: "GPT-4", description: "Advanced reasoning capabilities", contextWindow: 8192, maxTokens: 4096, supports: { chat: true, completion: true, functionCalling: true, vision: false, streaming: true, jsonMode: true }, pricing: { currency: "USD", input: 0.03, output: 0.06 } }, { id: "gpt-3.5-turbo", name: "GPT-3.5 Turbo", description: "Fast and cost-effective", contextWindow: 16384, maxTokens: 4096, supports: { chat: true, completion: true, functionCalling: true, vision: false, streaming: true, jsonMode: true }, pricing: { currency: "USD", input: 5e-4, output: 15e-4 } } ] }, { id: "anthropic", name: "Anthropic", icon: "\u{1F9E0}", description: "Claude 3 family of models", website: "https://anthropic.com", requiresApiKey: true, customizable: false, status: "disconnected", models: [ { id: "claude-3-opus-20240229", name: "Claude 3 Opus", description: "Most powerful model for complex tasks", contextWindow: 2e5, maxTokens: 4096, supports: { chat: true, completion: true, functionCalling: true, vision: true, streaming: true, jsonMode: false }, pricing: { currency: "USD", input: 0.015, output: 0.075 } }, { id: "claude-3-5-sonnet-20241022", name: "Claude 3.5 Sonnet", description: "Latest Sonnet - balanced performance and cost", contextWindow: 2e5, maxTokens: 8192, supports: { chat: true, completion: true, functionCalling: true, vision: true, streaming: true, jsonMode: false }, pricing: { currency: "USD", input: 3e-3, output: 0.015 } }, { id: "claude-3-5-haiku-20241022", name: "Claude 3.5 Haiku", description: "Latest Haiku - fast and affordable", contextWindow: 2e5, maxTokens: 8192, supports: { chat: true, completion: true, functionCalling: true, vision: true, streaming: true, jsonMode: false }, pricing: { currency: "USD", input: 1e-3, output: 5e-3 } } ] }, { id: "xai", name: "xAI", icon: "\u{1F680}", description: "Grok models from xAI", website: "https://x.ai", requiresApiKey: true, customizable: false, status: "disconnected", models: [ { id: "grok-beta", name: "Grok Beta", description: "Advanced reasoning with real-time knowledge", contextWindow: 8192, maxTokens: 4096, supports: { chat: true, completion: true, functionCalling: false, vision: false, streaming: true, jsonMode: false } } ] } ]; } }); // ../../node_modules/framer-motion/dist/es/context/LayoutGroupContext.mjs var import_react4, LayoutGroupContext; var init_LayoutGroupContext = __esm({ "../../node_modules/framer-motion/dist/es/context/LayoutGroupContext.mjs"() { "use strict"; "use client"; import_react4 = require("react"); LayoutGroupContext = (0, import_react4.createContext)({}); } }); // ../../node_modules/framer-motion/dist/es/utils/use-constant.mjs function useConstant(init) { const ref = (0, import_react5.useRef)(null); if (ref.current === null) { ref.current = init(); } return ref.current; } var import_react5; var init_use_constant = __esm({ "../../node_modules/framer-motion/dist/es/utils/use-constant.mjs"() { "use strict"; import_react5 = require("react"); } }); // ../../node_modules/framer-motion/dist/es/context/PresenceContext.mjs var import_react6, PresenceContext; var init_PresenceContext = __esm({ "../../node_modules/framer-motion/dist/es/context/PresenceContext.mjs"() { "use strict"; "use client"; import_react6 = require("react"); PresenceContext = (0, import_react6.createContext)(null); } }); // ../../node_modules/framer-motion/dist/es/context/MotionConfigContext.mjs var import_react7, MotionConfigContext; var init_MotionConfigContext = __esm({ "../../node_modules/framer-motion/dist/es/context/MotionConfigContext.mjs"() { "use strict"; "use client"; import_react7 = require("react"); MotionConfigContext = (0, import_react7.createContext)({ transformPagePoint: (p) => p, isStatic: false, reducedMotion: "never" }); } }); // ../../node_modules/framer-motion/dist/es/components/AnimatePresence/PopChild.mjs function PopChild({ children, isPresent }) { const id3 = (0, import_react8.useId)(); const ref = (0, import_react8.useRef)(null); const size = (0, import_react8.useRef)({ width: 0, height: 0, top: 0, left: 0 }); const { nonce } = (0, import_react8.useContext)(MotionConfigContext); (0, import_react8.useInsertionEffect)(() => { const { width, height, top, left } = size.current; if (isPresent || !ref.current || !width || !height) return; ref.current.dataset.motionPopId = id3; const style = document.createElement("style"); if (nonce) style.nonce = nonce; document.head.appendChild(style); if (style.sheet) { style.sheet.insertRule(` [data-motion-pop-id="${id3}"] { position: absolute !important; width: ${width}px !important; height: ${height}px !important; top: ${top}px !important; left: ${left}px !important; } `); } return () => { document.head.removeChild(style); }; }, [isPresent]); return (0, import_jsx_runtime5.jsx)(PopChildMeasure, { isPresent, childRef: ref, sizeRef: size, children: React4.cloneElement(children, { ref }) }); } var import_jsx_runtime5, React4, import_react8, PopChildMeasure; var init_PopChild = __esm({ "../../node_modules/framer-motion/dist/es/components/AnimatePresence/PopChild.mjs"() { "use strict"; "use client"; import_jsx_runtime5 = require("react/jsx-runtime"); React4 = __toESM(require("react"), 1); import_react8 = require("react"); init_MotionConfigContext(); PopChildMeasure = class extends React4.Component { getSnapshotBeforeUpdate(prevProps) { const element = this.props.childRef.current; if (element && prevProps.isPresent && !this.props.isPresent) { const size = this.props.sizeRef.current; size.height = element.offsetHeight || 0; size.width = element.offsetWidth || 0; size.top = element.offsetTop; size.left = element.offsetLeft; } return null; } /** * Required with getSnapshotBeforeUpdate to stop React complaining. */ componentDidUpdate() { } render() { return this.props.children; } }; } }); // ../../node_modules/framer-motion/dist/es/components/AnimatePresence/PresenceChild.mjs function newChildrenMap() { return /* @__PURE__ */ new Map(); } var import_jsx_runtime6, React5, import_react9, PresenceChild; var init_PresenceChild = __esm({ "../../node_modules/framer-motion/dist/es/components/AnimatePresence/PresenceChild.mjs"() { "use strict"; "use client"; import_jsx_runtime6 = require("react/jsx-runtime"); React5 = __toESM(require("react"), 1); import_react9 = require("react"); init_PresenceContext(); init_use_constant(); init_PopChild(); PresenceChild = ({ children, initial, isPresent, onExitComplete, custom, presenceAffectsLayout, mode }) => { const presenceChildren = useConstant(newChildrenMap); const id3 = (0, import_react9.useId)(); const memoizedOnExitComplete = (0, import_react9.useCallback)((childId) => { presenceChildren.set(childId, true); for (const isComplete of presenceChildren.values()) { if (!isComplete) return; } onExitComplete && onExitComplete(); }, [presenceChildren, onExitComplete]); const context = (0, import_react9.useMemo)( () => ({ id: id3, initial, isPresent, custom, onExitComplete: memoizedOnExitComplete, register: (childId) => { presenceChildren.set(childId, false); return () => presenceChildren.delete(childId); } }), /** * If the presence of a child affects the layout of the components around it, * we want to make a new context value to ensure they get re-rendered * so they can detect that layout change. */ presenceAffectsLayout ? [Math.random(), memoizedOnExitComplete] : [isPresent, memoizedOnExitComplete] ); (0, import_react9.useMemo)(() => { presenceChildren.forEach((_, key) => presenceChildren.set(key, false)); }, [isPresent]); React5.useEffect(() => { !isPresent && !presenceChildren.size && onExitComplete && onExitComplete(); }, [isPresent]); if (mode === "popLayout") { children = (0, import_jsx_runtime6.jsx)(PopChild, { isPresent, children }); } return (0, import_jsx_runtime6.jsx)(PresenceContext.Provider, { value: context, children }); }; } }); // ../../node_modules/framer-motion/dist/es/components/AnimatePresence/use-presence.mjs function usePresence(subscribe = true) { const context = (0, import_react10.useContext)(PresenceContext); if (context === null) return [true, null]; const { isPresent, onExitComplete, register } = context; const id3 = (0, import_react10.useId)(); (0, import_react10.useEffect)(() => { if (subscribe) register(id3); }, [subscribe]); const safeToRemove = (0, import_react10.useCallback)(() => subscribe && onExitComplete && onExitComplete(id3), [id3, onExitComplete, subscribe]); return !isPresent && onExitComplete ? [false, safeToRemove] : [true]; } var import_react10; var init_use_presence = __esm({ "../../node_modules/framer-motion/dist/es/components/AnimatePresence/use-presence.mjs"() { "use strict"; import_react10 = require("react"); init_PresenceContext(); } }); // ../../node_modules/framer-motion/dist/es/components/AnimatePresence/utils.mjs function onlyElements(children) { const filtered = []; import_react11.Children.forEach(children, (child) => { if ((0, import_react11.isValidElement)(child)) filtered.push(child); }); return filtered; } var import_react11, getChildKey; var init_utils = __esm({ "../../node_modules/framer-motion/dist/es/components/AnimatePresence/utils.mjs"() { "use strict"; import_react11 = require("react"); getChildKey = (child) => child.key || ""; } }); // ../../node_modules/framer-motion/dist/es/utils/is-browser.mjs var isBrowser; var init_is_browser = __esm({ "../../node_modules/framer-motion/dist/es/utils/is-browser.mjs"() { "use strict"; isBrowser = typeof window !== "undefined"; } }); // ../../node_modules/framer-motion/dist/es/utils/use-isomorphic-effect.mjs var import_react12, useIsomorphicLayoutEffect; var init_use_isomorphic_effect = __esm({ "../../node_modules/framer-motion/dist/es/utils/use-isomorphic-effect.mjs"() { "use strict"; import_react12 = require("react"); init_is_browser(); useIsomorphicLayoutEffect = isBrowser ? import_react12.useLayoutEffect : import_react12.useEffect; } }); // ../../node_modules/framer-motion/dist/es/components/AnimatePresence/index.mjs var import_jsx_runtime7, import_react13, AnimatePresence; var init_AnimatePresence = __esm({ "../../node_modules/framer-motion/dist/es/components/AnimatePresence/index.mjs"() { "use strict"; "use client"; import_jsx_runtime7 = require("react/jsx-runtime"); import_react13 = require("react"); init_LayoutGroupContext(); init_use_constant(); init_PresenceChild(); init_use_presence(); init_utils(); init_use_isomorphic_effect(); AnimatePresence = ({ children, custom, initial = true, onExitComplete, presenceAffectsLayout = true, mode = "sync", propagate = false }) => { const [isParentPresent, safeToRemove] = usePresence(propagate); const presentChildren = (0, import_react13.useMemo)(() => onlyElements(children), [children]); const presentKeys = propagate && !isParentPresent ? [] : presentChildren.map(getChildKey); const isInitialRender = (0, import_react13.useRef)(true); const pendingPresentChildren = (0, import_react13.useRef)(presentChildren); const exitComplete = useConstant(() => /* @__PURE__ */ new Map()); const [diffedChildren, setDiffedChildren] = (0, import_react13.useState)(presentChildren); const [renderedChildren, setRenderedChildren] = (0, import_react13.useState)(presentChildren); useIsomorphicLayoutEffect(() => { isInitialRender.current = false; pendingPresentChildren.current = presentChildren; for (let i = 0; i < renderedChildren.length; i++) { const key = getChildKey(renderedChildren[i]); if (!presentKeys.includes(key)) { if (exitComplete.get(key) !== true) { exitComplete.set(key, false); } } else { exitComplete.delete(key); } } }, [renderedChildren, presentKeys.length, presentKeys.join("-")]); const exitingChildren = []; if (presentChildren !== diffedChildren) { let nextChildren = [...presentChildren]; for (let i = 0; i < renderedChildren.length; i++) { const child = renderedChildren[i]; const key = getChildKey(child); if (!presentKeys.includes(key)) { nextChildren.splice(i, 0, child); exitingChildren.push(child); } } if (mode === "wait" && exitingChildren.length) { nextChildren = exitingChildren; } setRenderedChildren(onlyElements(nextChildren)); setDiffedChildren(presentChildren); return; } if (mode === "wait" && renderedChildren.length > 1) { console.warn(`You're attempting to animate multiple children within AnimatePresence, but its mode is set to "wait". This will lead to odd visual behaviour.`); } const { forceRender } = (0, import_react13.useContext)(LayoutGroupContext); return (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children: renderedChildren.map((child) => { const key = getChildKey(child); const isPresent = propagate && !isParentPresent ? false : presentChildren === renderedChildren || presentKeys.includes(key); const onExit = () => { if (exitComplete.has(key)) { exitComplete.set(key, true); } else { return; } let isEveryExitComplete = true; exitComplete.forEach((isExitComplete) => { if (!isExitComplete) isEveryExitComplete = false; }); if (isEveryExitComplete) { forceRender === null || forceRender === void 0 ? void 0 : forceRender(); setRenderedChildren(pendingPresentChildren.current); propagate && (safeToRemove === null || safeToRemove === void 0 ? void 0 : safeToRemove()); onExitComplete && onExitComplete(); } }; return (0, import_jsx_runtime7.jsx)(PresenceChild, { isPresent, initial: !isInitialRender.current || initial ? void 0 : false, custom: isPresent ? void 0 : custom, presenceAffectsLayout, mode, onExitComplete: isPresent ? void 0 : onExit, children: child }, key); }) }); }; } }); // ../../node_modules/motion-utils/dist/es/noop.mjs var noop; var init_noop = __esm({ "../../node_modules/motion-utils/dist/es/noop.mjs"() { "use strict"; noop = /* @__NO_SIDE_EFFECTS__ */ (any) => any; } }); // ../../node_modules/motion-utils/dist/es/errors.mjs var warning, invariant; var init_errors = __esm({ "../../node_modules/motion-utils/dist/es/errors.mjs"() { "use strict"; init_noop(); warning = noop; invariant = noop; if (true) { warning = (check, message) => { if (!check && typeof console !== "undefined") { console.warn(message); } }; invariant = (check, message) => { if (!check) { throw new Error(message); } }; } } }); // ../../node_modules/motion-utils/dist/es/memo.mjs // @__NO_SIDE_EFFECTS__ function memo(callback) { let result; return () => { if (result === void 0)