om-memory-system 3.6.0-next.43 → 3.6.0-next.45

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/config.d.ts CHANGED
@@ -52,6 +52,8 @@ interface OmmsConfig {
52
52
  from: string;
53
53
  to: string;
54
54
  }>;
55
+ /** Claude Code's folder (its transcripts are in `<folder>/projects`). Empty means `CLAUDE_CONFIG_DIR`, then `~/.claude`. Global config only. */
56
+ claudeConfigDir?: string;
55
57
  webServerAutoStart?: boolean;
56
58
  webServerEnabled?: boolean;
57
59
  webServerPort?: number;
@@ -100,7 +102,7 @@ interface OmmsConfig {
100
102
  injectOn?: "first" | "always";
101
103
  };
102
104
  }
103
- export declare const CONFIG_TEMPLATE = "{\n // ============================================\n // omms (Opinionated Modular Memory System) Configuration\n // ============================================\n \n // Storage location for the vector database. Leave unset to use the\n // default ~/.omms/data (a legacy ~/.opencode-mem/data store is migrated\n // there automatically on first start; see docs/omms-migration.md).\n // \"storagePath\": \"~/.omms/data\",\n\n \"userEmailOverride\": \"\",\n \"userNameOverride\": \"\",\n \n // ============================================\n // Embedding Model (for similarity search)\n // ============================================\n // Local = Hugging Face / ONNX via @huggingface/transformers (not Apple MLX).\n // Remote = set BOTH embeddingApiUrl and embeddingApiKey (OpenAI-compatible /embeddings).\n \n // Default: Nomic Embed v1 (768 dimensions, 8192 context, multilingual)\n \"embeddingModel\": \"Xenova/nomic-embed-text-v1\",\n\n // Opt-in Nomic task prefixes (search_document: / search_query:). After enabling,\n // re-index existing memories so store and query vectors stay aligned.\n // \"embeddingUseTaskPrefixes\": true,\n \n // Auto-detected dimensions (no need to set manually)\n // \"embeddingDimensions\": 768,\n \n // Other recommended local models:\n // \"embeddingModel\": \"Xenova/jina-embeddings-v2-base-en\", // 768 dims, English-only, 8192 context\n // \"embeddingModel\": \"Xenova/jina-embeddings-v2-small-en\", // 512 dims, faster, 8192 context\n // \"embeddingModel\": \"Xenova/all-MiniLM-L6-v2\", // 384 dims, very fast, 512 context\n // \"embeddingModel\": \"Xenova/all-mpnet-base-v2\", // 768 dims, good quality, 512 context\n \n // Optional: OpenAI-compatible API for embeddings (both URL and key required)\n // \"embeddingApiUrl\": \"https://api.openai.com/v1\",\n // \"embeddingApiKey\": \"env://OPENAI_API_KEY\", // or \"sk-...\" / \"file:///path/to/key\"\n // \"embeddingModel\": \"text-embedding-3-small\", // 1536 dims, auto-detected\n \n // ============================================\n // Web Server Settings\n // ============================================\n \n // Start a background import of past chats on each host's next start.\n \"autoBackfill\": true,\n // \"piBackfillModel\": \"inherit\", // or \"external\", or \"provider/model\"\n // \"opencodeBackfillModel\": \"inherit\", // or \"external\", or \"provider/model\"\n // Directory maps for history recorded in moved or deleted directories.\n // \"importPathMaps\": [{ \"from\": \"~/code/app-feat-x\", \"to\": \"~/code/app\" }],\n\n // Register the web app to start when you log in.\n \"webServerAutoStart\": true,\n // Enable web UI for managing memories (accessible at http://localhost:4747)\n \"webServerEnabled\": true,\n \n // Port for web UI server\n \"webServerPort\": 4747,\n \n // Host address for web UI (use 127.0.0.1 for local only, 0.0.0.0 for network access)\n \"webServerHost\": \"127.0.0.1\",\n\n // Optional HTTP Basic Auth for the web UI. Accepts literal, env://, or file:// secrets.\n // \"webServerAuthPassword\": \"\",\n // \"webServerAuthUsername\": \"\",\n\n // Required when webServerHost is not loopback. Protects /api/* with Bearer / X-Omms-Token (legacy X-Opencode-Mem-Token still works).\n // \"webServerApiToken\": \"env://OMMS_WEB_TOKEN\",\n \n // ============================================\n // Database Settings\n // ============================================\n \n // Maximum vectors per database shard (auto-creates new shard when limit reached)\n \"maxVectorsPerShard\": 50000,\n \n // Automatically delete old memories based on retention period\n \"autoCleanupEnabled\": true,\n \n // Days to keep memories before auto-cleanup (only if autoCleanupEnabled is true)\n \"autoCleanupRetentionDays\": 30,\n \n // Automatically detect and remove duplicate memories\n \"deduplicationEnabled\": true,\n \n // Similarity threshold (0-1) for detecting duplicates (higher = stricter)\n \"deduplicationSimilarityThreshold\": 0.90,\n \n // ============================================\n // Memory Scope Settings\n // ============================================\n\n // Default scope for memory list/search queries\n // \"project\" keeps queries within the current project, \"all-projects\" searches across all project shards\n \"memory\": {\n \"defaultScope\": \"project\"\n },\n\n // ============================================\n // Model for auto-capture and profile learning (same rule in OpenCode and Pi)\n // ============================================\n\n // Which model summarises your work, in this order:\n // 1. The host model below: opencodeProvider/opencodeModel in OpenCode,\n // piProvider/piModel in Pi. Set the model to \"inherit\" to follow\n // whatever model the session is using, or to \"external\" to send\n // every call to the external API below.\n // 2. If no host model is set: the external API (memoryModel/memoryApiUrl/\n // memoryApiKey further down).\n // 3. If neither is set: the session's own model.\n // If the host model fails and the external API is configured, the external\n // API is used instead.\n //\n // Host models go through OpenCode's or Pi's own sign-in (OAuth like Claude\n // Pro/Max, GitHub Copilot, ChatGPT, or your own key there), so no separate API\n // key is needed here.\n //\n // Examples (OpenCode names from 'opencode providers list'; Pi names from its model list):\n // \"opencodeProvider\": \"anthropic\", \"opencodeModel\": \"claude-haiku-4-5-20251001\"\n // \"opencodeProvider\": \"openai\", \"opencodeModel\": \"inherit\"\n // \"piProvider\": \"openai-codex\", \"piModel\": \"gpt-5.6-luna\"\n //\n // \"opencodeProvider\": \"anthropic\",\n // \"opencodeModel\": \"claude-haiku-4-5-20251001\",\n // \"piProvider\": \"openai-codex\",\n // \"piModel\": \"gpt-5.6-luna\",\n\n // ============================================\n // Auto-Capture Settings\n // ============================================\n \n // Auto-capture runs in the background without blocking your main session.\n // Note: Ollama may not support tool calling. Use OpenAI, Anthropic, or Groq for best results.\n \n \"autoCaptureEnabled\": true,\n \n // Provider type: \"openai-chat\" | \"openai-responses\" | \"anthropic\" | \"minimax\" | \"orcarouter\" | \"google-gemini\"\n // Note: \"openai-chat\" is a generic OpenAI API-compatible mode.\n // Any service that follows the OpenAI Chat Completions API can use it via custom \"memoryApiUrl\".\n \"memoryProvider\": \"openai-chat\",\n \n // External API (step 2 above, and the fallback when a host model fails).\n // Uncomment all 3 lines and replace memoryApiKey before use:\n // \"memoryModel\": \"gpt-4o-mini\",\n // \"memoryApiUrl\": \"https://api.openai.com/v1\",\n // \"memoryApiKey\": \"sk-...\",\n\n // API Key Formats:\n // Direct value: \"sk-...\"\n // From file: \"file://~/.config/litellm-key.txt\"\n // From env variable: \"env://LITELLM_API_KEY\"\n \n // Examples for different providers:\n // Any OpenAI-compatible endpoint can use the \"openai-chat\" provider pattern below.\n // Common examples: DeepSeek, Qwen (via Alibaba Cloud ModelStudio),\n // Zhipu GLM (BigModel platform), and Kimi (Moonshot AI platform).\n\n // OpenAI Chat Completion (default, backward compatible):\n // \"memoryProvider\": \"openai-chat\"\n // \"memoryModel\": \"gpt-4o-mini\"\n // \"memoryApiUrl\": \"https://api.openai.com/v1\"\n // \"memoryApiKey\": \"sk-...\"\n\n // DeepSeek (OpenAI-compatible example):\n // \"memoryProvider\": \"openai-chat\"\n // \"memoryModel\": \"deepseek-chat\"\n // \"memoryApiUrl\": \"https://api.deepseek.com/v1\"\n // \"memoryApiKey\": \"sk-...\"\n \n // OpenAI Responses API (recommended, with session support):\n // \"memoryProvider\": \"openai-responses\"\n // \"memoryModel\": \"gpt-4o\"\n // \"memoryApiUrl\": \"https://api.openai.com/v1\"\n // \"memoryApiKey\": \"sk-...\"\n \n // Anthropic (with session support):\n // \"memoryProvider\": \"anthropic\"\n // \"memoryModel\": \"claude-3-5-haiku-20241022\"\n // \"memoryApiUrl\": \"https://api.anthropic.com/v1\"\n // \"memoryApiKey\": \"sk-ant-...\"\n\n // MiniMax (Anthropic Messages-compatible endpoint, with session support):\n // \"memoryProvider\": \"minimax\"\n // \"memoryModel\": \"MiniMax-M3\"\n // \"memoryApiUrl\": \"https://api.minimax.io\" // global endpoint\n // \"memoryApiKey\": \"<MiniMax API key>\"\n // // China endpoint: \"memoryApiUrl\": \"https://api.minimaxi.com\"\n // // Optional adaptive thinking for MiniMax-M3:\n // \"memoryExtraParams\": { \"thinking\": { \"type\": \"adaptive\" } }\n\n // OrcaRouter (OpenAI-compatible gateway, namespaced model IDs, with session support):\n // \"memoryProvider\": \"orcarouter\"\n // \"memoryApiKey\": \"<OrcaRouter API key>\"\n // // memoryApiUrl and memoryModel are optional \u2014 they default to\n // // https://api.orcarouter.ai/v1 and \"orcarouter/auto\" (a routing alias).\n // // OrcaRouter rejects bare model names, so if you set memoryModel, use a\n // // namespaced ID such as \"openai/gpt-5.5\" or \"deepseek/deepseek-v4-flash\".\n // \"memoryModel\": \"openai/gpt-5.5\"\n\n // Groq (OpenAI-compatible, use openai-chat provider):\n // \"memoryProvider\": \"openai-chat\"\n // \"memoryModel\": \"llama-3.3-70b-versatile\"\n // \"memoryApiUrl\": \"https://api.groq.com/openai/v1\"\n // \"memoryApiKey\": \"gsk_...\"\n \n // Maximum iterations for multi-turn AI analysis (for openai-responses, anthropic, and minimax)\n \"autoCaptureMaxIterations\": 5,\n \n // Timeout per iteration in milliseconds (30 seconds default)\n \"autoCaptureIterationTimeout\": 30000,\n\n // Tries for one turn's capture, on Pi and OpenCode, 2 and 4 seconds apart. After the\n // last one fails, a turn the model could not reach goes to the capture retry queue.\n \"autoCaptureMaxRetries\": 3,\n\n // Maximum UTF-8 bytes for the auto-capture markdown context sent to the summary model.\n // Prevents HTTP 400 context overflows on models with ~131K token windows (e.g. Groq Llama).\n // Rough guide: tokens \u2248 bytes / 4 for mixed code/prose.\n \"autoCaptureMaxContextBytes\": 131072,\n \n // Days to keep AI session history before cleanup\n \"aiSessionRetentionDays\": 7,\n\n // Capture diagnostics: every capture attempt always writes one metadata line\n // (model, stop reason, sizes, outcome) to ~/.omms/omms.log, with no\n // conversation text. Set captureTrace to true to also write each attempt's\n // prompt and raw reply to ~/.omms/traces/ for debugging. Traces can contain\n // conversation content: <private> text and common API key formats are\n // redacted, files are readable only by you, and they are deleted after\n // captureTraceRetentionDays. Only this global file can turn tracing on.\n // \"captureTrace\": false,\n // \"captureTraceRetentionDays\": 7,\n // \"captureAttemptRetentionDays\": 30,\n\n // Capture retry queue: when a live capture fails because the model cannot be\n // reached (network error, timeout, HTTP 408, 429 or 5xx), OMMS keeps a copy of\n // the turn in ~/.omms/data and tries it again later. The copy has <private>\n // text and common API key formats removed. Turns are deleted when the retry\n // ends or after captureRetryRetentionHours (0 to 720). 0 turns the queue off.\n // Only this global file can set it.\n // \"captureRetryRetentionHours\": 72,\n\n // Temperature for AI API requests (set to false to omit parameter for models that don't support it)\n // Some reasoning models (like o1, o3, gpt-5) don't support temperature parameter\n // Set to false and add \"memoryTemperature\": false in config when using such models\n \"memoryTemperature\": 0.3,\n\n // Extra parameters to include in API request body\n // Useful for local inference servers (e.g. llama-server with --jinja) that support\n // additional parameters like disabling thinking/reasoning mode\n // Example for Qwen3 models: { \"enable_thinking\": false }\n // \"memoryExtraParams\": {},\n\n // Language for auto-capture summaries (default: \"auto\" for auto-detection)\n // Options: \"auto\", \"en\", \"id\", \"zh\", \"ja\", \"es\", \"fr\", \"de\", \"ru\", \"pt\", \"ar\", \"ko\"\n // \"autoCaptureLanguage\": \"auto\",\n\n // ============================================\n // Toast Notifications\n // ============================================\n\n // Show toast when memory is auto-captured\n \"showAutoCaptureToasts\": true,\n\n // Show toast when user profile is updated\n \"showUserProfileToasts\": true,\n\n // Show toast for error messages\n \"showErrorToasts\": true,\n\n // ============================================\n // User Profile System\n // ============================================\n\n // Analyze user prompts every N prompts to build/update your user profile\n // When N uncaptured prompts accumulate, AI will analyze them to identify:\n // - User preferences (code style, communication style, tool preferences)\n // - User patterns (recurring topics, problem domains, technical interests)\n // - User workflows (development habits, sequences, learning style)\n // - Skill level (overall and per-domain assessment)\n \"userProfileAnalysisInterval\": 10,\n\n // Days before inactive items (all types) are eligible for removal\n \"userProfileStaleDays\": 2,\n\n // Number of preferences shown in UI\n \"userProfileDisplayPreferences\": 20,\n \n // Number of patterns shown in UI\n \"userProfileDisplayPatterns\": 15,\n \n // Number of workflows shown in UI\n \"userProfileDisplayWorkflows\": 10,\n \n // Number of preferences injected into LLM conversation context\n // Keep this small \u2014 the strongest signals are enough; more dilute LLM attention\n \"userProfileInjectPreferences\": 5,\n \n // Number of patterns injected into LLM conversation context\n \"userProfileInjectPatterns\": 5,\n \n // Number of workflows injected into LLM conversation context\n \"userProfileInjectWorkflows\": 3,\n \n // Days before preference confidence starts to decay (if not reinforced)\n // Preferences that aren't seen again will gradually lose confidence and be removed\n \"userProfileConfidenceDecayDays\": 30,\n \n // Number of profile versions to keep in changelog (for rollback/debugging)\n // Older versions are automatically cleaned up\n \"userProfileChangelogRetentionCount\": 5,\n\n // Minimum evidence count for a preference/pattern to survive confidence decay\n // Items confirmed fewer times are more likely to be pruned when confidence decays\n \"userProfileMinEvidenceForRetention\": 3,\n\n // Periodically merge duplicate or irrelevant profile items with the configured AI provider\n \"userProfileAutoCleanupEnabled\": true,\n // Number of analyzed user prompts between automatic AI cleanup runs\n \"userProfileAutoCleanupInterval\": 100,\n\n // Enable LLM validation of existing preferences against recent behavior.\n // When enabled, each analysis round checks if top-5 preferences still match recent prompts.\n // Experimental \u2014 disabled by default.\n \"userProfileValidationEnabled\": false,\n\n // ============================================\n // Search Settings\n // ============================================\n \n // Minimum similarity score (0-1) for memory search results\n \"similarityThreshold\": 0.6,\n\n // Maximum number of memories to return in search results\n \"maxMemories\": 10,\n\n // ============================================\n // Advanced Settings\n // ============================================\n \n // Inject user profile into AI context (preferences, patterns, workflows)\n \"injectProfile\": true\n}\n";
105
+ export declare const CONFIG_TEMPLATE = "{\n // ============================================\n // omms (Opinionated Modular Memory System) Configuration\n // ============================================\n \n // Storage location for the vector database. Leave unset to use the\n // default ~/.omms/data (a legacy ~/.opencode-mem/data store is migrated\n // there automatically on first start; see docs/omms-migration.md).\n // \"storagePath\": \"~/.omms/data\",\n\n \"userEmailOverride\": \"\",\n \"userNameOverride\": \"\",\n \n // ============================================\n // Embedding Model (for similarity search)\n // ============================================\n // Local = Hugging Face / ONNX via @huggingface/transformers (not Apple MLX).\n // Remote = set BOTH embeddingApiUrl and embeddingApiKey (OpenAI-compatible /embeddings).\n \n // Default: Nomic Embed v1 (768 dimensions, 8192 context, multilingual)\n \"embeddingModel\": \"Xenova/nomic-embed-text-v1\",\n\n // Opt-in Nomic task prefixes (search_document: / search_query:). After enabling,\n // re-index existing memories so store and query vectors stay aligned.\n // \"embeddingUseTaskPrefixes\": true,\n \n // Auto-detected dimensions (no need to set manually)\n // \"embeddingDimensions\": 768,\n \n // Other recommended local models:\n // \"embeddingModel\": \"Xenova/jina-embeddings-v2-base-en\", // 768 dims, English-only, 8192 context\n // \"embeddingModel\": \"Xenova/jina-embeddings-v2-small-en\", // 512 dims, faster, 8192 context\n // \"embeddingModel\": \"Xenova/all-MiniLM-L6-v2\", // 384 dims, very fast, 512 context\n // \"embeddingModel\": \"Xenova/all-mpnet-base-v2\", // 768 dims, good quality, 512 context\n \n // Optional: OpenAI-compatible API for embeddings (both URL and key required)\n // \"embeddingApiUrl\": \"https://api.openai.com/v1\",\n // \"embeddingApiKey\": \"env://OPENAI_API_KEY\", // or \"sk-...\" / \"file:///path/to/key\"\n // \"embeddingModel\": \"text-embedding-3-small\", // 1536 dims, auto-detected\n \n // ============================================\n // Web Server Settings\n // ============================================\n \n // Start a background import of past chats on each host's next start.\n \"autoBackfill\": true,\n // \"piBackfillModel\": \"inherit\", // or \"external\", or \"provider/model\"\n // \"opencodeBackfillModel\": \"inherit\", // or \"external\", or \"provider/model\"\n // Directory maps for history recorded in moved or deleted directories.\n // \"importPathMaps\": [{ \"from\": \"~/code/app-feat-x\", \"to\": \"~/code/app\" }],\n // Claude Code's folder, when it is not ~/.claude (like CLAUDE_CONFIG_DIR).\n // \"claudeConfigDir\": \"~/.claude-work\",\n\n // Register the web app to start when you log in.\n \"webServerAutoStart\": true,\n // Enable web UI for managing memories (accessible at http://localhost:4747)\n \"webServerEnabled\": true,\n \n // Port for web UI server\n \"webServerPort\": 4747,\n \n // Host address for web UI (use 127.0.0.1 for local only, 0.0.0.0 for network access)\n \"webServerHost\": \"127.0.0.1\",\n\n // Optional HTTP Basic Auth for the web UI. Accepts literal, env://, or file:// secrets.\n // \"webServerAuthPassword\": \"\",\n // \"webServerAuthUsername\": \"\",\n\n // Required when webServerHost is not loopback. Protects /api/* with Bearer / X-Omms-Token (legacy X-Opencode-Mem-Token still works).\n // \"webServerApiToken\": \"env://OMMS_WEB_TOKEN\",\n \n // ============================================\n // Database Settings\n // ============================================\n \n // Maximum vectors per database shard (auto-creates new shard when limit reached)\n \"maxVectorsPerShard\": 50000,\n \n // Automatically delete old memories based on retention period\n \"autoCleanupEnabled\": true,\n \n // Days to keep memories before auto-cleanup (only if autoCleanupEnabled is true)\n \"autoCleanupRetentionDays\": 30,\n \n // Automatically detect and remove duplicate memories\n \"deduplicationEnabled\": true,\n \n // Similarity threshold (0-1) for detecting duplicates (higher = stricter)\n \"deduplicationSimilarityThreshold\": 0.90,\n \n // ============================================\n // Memory Scope Settings\n // ============================================\n\n // Default scope for memory list/search queries\n // \"project\" keeps queries within the current project, \"all-projects\" searches across all project shards\n \"memory\": {\n \"defaultScope\": \"project\"\n },\n\n // ============================================\n // Model for auto-capture and profile learning (same rule in OpenCode and Pi)\n // ============================================\n\n // Which model summarises your work, in this order:\n // 1. The host model below: opencodeProvider/opencodeModel in OpenCode,\n // piProvider/piModel in Pi. Set the model to \"inherit\" to follow\n // whatever model the session is using, or to \"external\" to send\n // every call to the external API below.\n // 2. If no host model is set: the external API (memoryModel/memoryApiUrl/\n // memoryApiKey further down).\n // 3. If neither is set: the session's own model.\n // If the host model fails and the external API is configured, the external\n // API is used instead.\n //\n // Host models go through OpenCode's or Pi's own sign-in (OAuth like Claude\n // Pro/Max, GitHub Copilot, ChatGPT, or your own key there), so no separate API\n // key is needed here.\n //\n // Examples (OpenCode names from 'opencode providers list'; Pi names from its model list):\n // \"opencodeProvider\": \"anthropic\", \"opencodeModel\": \"claude-haiku-4-5-20251001\"\n // \"opencodeProvider\": \"openai\", \"opencodeModel\": \"inherit\"\n // \"piProvider\": \"openai-codex\", \"piModel\": \"gpt-5.6-luna\"\n //\n // \"opencodeProvider\": \"anthropic\",\n // \"opencodeModel\": \"claude-haiku-4-5-20251001\",\n // \"piProvider\": \"openai-codex\",\n // \"piModel\": \"gpt-5.6-luna\",\n\n // ============================================\n // Auto-Capture Settings\n // ============================================\n \n // Auto-capture runs in the background without blocking your main session.\n // Note: Ollama may not support tool calling. Use OpenAI, Anthropic, or Groq for best results.\n \n \"autoCaptureEnabled\": true,\n \n // Provider type: \"openai-chat\" | \"openai-responses\" | \"anthropic\" | \"minimax\" | \"orcarouter\" | \"google-gemini\"\n // Note: \"openai-chat\" is a generic OpenAI API-compatible mode.\n // Any service that follows the OpenAI Chat Completions API can use it via custom \"memoryApiUrl\".\n \"memoryProvider\": \"openai-chat\",\n \n // External API (step 2 above, and the fallback when a host model fails).\n // Uncomment all 3 lines and replace memoryApiKey before use:\n // \"memoryModel\": \"gpt-4o-mini\",\n // \"memoryApiUrl\": \"https://api.openai.com/v1\",\n // \"memoryApiKey\": \"sk-...\",\n\n // API Key Formats:\n // Direct value: \"sk-...\"\n // From file: \"file://~/.config/litellm-key.txt\"\n // From env variable: \"env://LITELLM_API_KEY\"\n \n // Examples for different providers:\n // Any OpenAI-compatible endpoint can use the \"openai-chat\" provider pattern below.\n // Common examples: DeepSeek, Qwen (via Alibaba Cloud ModelStudio),\n // Zhipu GLM (BigModel platform), and Kimi (Moonshot AI platform).\n\n // OpenAI Chat Completion (default, backward compatible):\n // \"memoryProvider\": \"openai-chat\"\n // \"memoryModel\": \"gpt-4o-mini\"\n // \"memoryApiUrl\": \"https://api.openai.com/v1\"\n // \"memoryApiKey\": \"sk-...\"\n\n // DeepSeek (OpenAI-compatible example):\n // \"memoryProvider\": \"openai-chat\"\n // \"memoryModel\": \"deepseek-chat\"\n // \"memoryApiUrl\": \"https://api.deepseek.com/v1\"\n // \"memoryApiKey\": \"sk-...\"\n \n // OpenAI Responses API (recommended, with session support):\n // \"memoryProvider\": \"openai-responses\"\n // \"memoryModel\": \"gpt-4o\"\n // \"memoryApiUrl\": \"https://api.openai.com/v1\"\n // \"memoryApiKey\": \"sk-...\"\n \n // Anthropic (with session support):\n // \"memoryProvider\": \"anthropic\"\n // \"memoryModel\": \"claude-3-5-haiku-20241022\"\n // \"memoryApiUrl\": \"https://api.anthropic.com/v1\"\n // \"memoryApiKey\": \"sk-ant-...\"\n\n // MiniMax (Anthropic Messages-compatible endpoint, with session support):\n // \"memoryProvider\": \"minimax\"\n // \"memoryModel\": \"MiniMax-M3\"\n // \"memoryApiUrl\": \"https://api.minimax.io\" // global endpoint\n // \"memoryApiKey\": \"<MiniMax API key>\"\n // // China endpoint: \"memoryApiUrl\": \"https://api.minimaxi.com\"\n // // Optional adaptive thinking for MiniMax-M3:\n // \"memoryExtraParams\": { \"thinking\": { \"type\": \"adaptive\" } }\n\n // OrcaRouter (OpenAI-compatible gateway, namespaced model IDs, with session support):\n // \"memoryProvider\": \"orcarouter\"\n // \"memoryApiKey\": \"<OrcaRouter API key>\"\n // // memoryApiUrl and memoryModel are optional \u2014 they default to\n // // https://api.orcarouter.ai/v1 and \"orcarouter/auto\" (a routing alias).\n // // OrcaRouter rejects bare model names, so if you set memoryModel, use a\n // // namespaced ID such as \"openai/gpt-5.5\" or \"deepseek/deepseek-v4-flash\".\n // \"memoryModel\": \"openai/gpt-5.5\"\n\n // Groq (OpenAI-compatible, use openai-chat provider):\n // \"memoryProvider\": \"openai-chat\"\n // \"memoryModel\": \"llama-3.3-70b-versatile\"\n // \"memoryApiUrl\": \"https://api.groq.com/openai/v1\"\n // \"memoryApiKey\": \"gsk_...\"\n \n // Maximum iterations for multi-turn AI analysis (for openai-responses, anthropic, and minimax)\n \"autoCaptureMaxIterations\": 5,\n \n // Timeout per iteration in milliseconds (30 seconds default)\n \"autoCaptureIterationTimeout\": 30000,\n\n // Tries for one turn's capture, on Pi and OpenCode, 2 and 4 seconds apart. After the\n // last one fails, a turn the model could not reach goes to the capture retry queue.\n \"autoCaptureMaxRetries\": 3,\n\n // Maximum UTF-8 bytes for the auto-capture markdown context sent to the summary model.\n // Prevents HTTP 400 context overflows on models with ~131K token windows (e.g. Groq Llama).\n // Rough guide: tokens \u2248 bytes / 4 for mixed code/prose.\n \"autoCaptureMaxContextBytes\": 131072,\n \n // Days to keep AI session history before cleanup\n \"aiSessionRetentionDays\": 7,\n\n // Capture diagnostics: every capture attempt always writes one metadata line\n // (model, stop reason, sizes, outcome) to ~/.omms/omms.log, with no\n // conversation text. Set captureTrace to true to also write each attempt's\n // prompt and raw reply to ~/.omms/traces/ for debugging. Traces can contain\n // conversation content: <private> text and common API key formats are\n // redacted, files are readable only by you, and they are deleted after\n // captureTraceRetentionDays. Only this global file can turn tracing on.\n // \"captureTrace\": false,\n // \"captureTraceRetentionDays\": 7,\n // \"captureAttemptRetentionDays\": 30,\n\n // Capture retry queue: when a live capture fails because the model cannot be\n // reached (network error, timeout, HTTP 408, 429 or 5xx), OMMS keeps a copy of\n // the turn in ~/.omms/data and tries it again later. The copy has <private>\n // text and common API key formats removed. Turns are deleted when the retry\n // ends or after captureRetryRetentionHours (0 to 720). 0 turns the queue off.\n // Only this global file can set it.\n // \"captureRetryRetentionHours\": 72,\n\n // Temperature for AI API requests (set to false to omit parameter for models that don't support it)\n // Some reasoning models (like o1, o3, gpt-5) don't support temperature parameter\n // Set to false and add \"memoryTemperature\": false in config when using such models\n \"memoryTemperature\": 0.3,\n\n // Extra parameters to include in API request body\n // Useful for local inference servers (e.g. llama-server with --jinja) that support\n // additional parameters like disabling thinking/reasoning mode\n // Example for Qwen3 models: { \"enable_thinking\": false }\n // \"memoryExtraParams\": {},\n\n // Language for auto-capture summaries (default: \"auto\" for auto-detection)\n // Options: \"auto\", \"en\", \"id\", \"zh\", \"ja\", \"es\", \"fr\", \"de\", \"ru\", \"pt\", \"ar\", \"ko\"\n // \"autoCaptureLanguage\": \"auto\",\n\n // ============================================\n // Toast Notifications\n // ============================================\n\n // Show toast when memory is auto-captured\n \"showAutoCaptureToasts\": true,\n\n // Show toast when user profile is updated\n \"showUserProfileToasts\": true,\n\n // Show toast for error messages\n \"showErrorToasts\": true,\n\n // ============================================\n // User Profile System\n // ============================================\n\n // Analyze user prompts every N prompts to build/update your user profile\n // When N uncaptured prompts accumulate, AI will analyze them to identify:\n // - User preferences (code style, communication style, tool preferences)\n // - User patterns (recurring topics, problem domains, technical interests)\n // - User workflows (development habits, sequences, learning style)\n // - Skill level (overall and per-domain assessment)\n \"userProfileAnalysisInterval\": 10,\n\n // Days before inactive items (all types) are eligible for removal\n \"userProfileStaleDays\": 2,\n\n // Number of preferences shown in UI\n \"userProfileDisplayPreferences\": 20,\n \n // Number of patterns shown in UI\n \"userProfileDisplayPatterns\": 15,\n \n // Number of workflows shown in UI\n \"userProfileDisplayWorkflows\": 10,\n \n // Number of preferences injected into LLM conversation context\n // Keep this small \u2014 the strongest signals are enough; more dilute LLM attention\n \"userProfileInjectPreferences\": 5,\n \n // Number of patterns injected into LLM conversation context\n \"userProfileInjectPatterns\": 5,\n \n // Number of workflows injected into LLM conversation context\n \"userProfileInjectWorkflows\": 3,\n \n // Days before preference confidence starts to decay (if not reinforced)\n // Preferences that aren't seen again will gradually lose confidence and be removed\n \"userProfileConfidenceDecayDays\": 30,\n \n // Number of profile versions to keep in changelog (for rollback/debugging)\n // Older versions are automatically cleaned up\n \"userProfileChangelogRetentionCount\": 5,\n\n // Minimum evidence count for a preference/pattern to survive confidence decay\n // Items confirmed fewer times are more likely to be pruned when confidence decays\n \"userProfileMinEvidenceForRetention\": 3,\n\n // Periodically merge duplicate or irrelevant profile items with the configured AI provider\n \"userProfileAutoCleanupEnabled\": true,\n // Number of analyzed user prompts between automatic AI cleanup runs\n \"userProfileAutoCleanupInterval\": 100,\n\n // Enable LLM validation of existing preferences against recent behavior.\n // When enabled, each analysis round checks if top-5 preferences still match recent prompts.\n // Experimental \u2014 disabled by default.\n \"userProfileValidationEnabled\": false,\n\n // ============================================\n // Search Settings\n // ============================================\n \n // Minimum similarity score (0-1) for memory search results\n \"similarityThreshold\": 0.6,\n\n // Maximum number of memories to return in search results\n \"maxMemories\": 10,\n\n // ============================================\n // Advanced Settings\n // ============================================\n \n // Inject user profile into AI context (preferences, patterns, workflows)\n \"injectProfile\": true\n}\n";
104
106
  export declare function normalizeAutoCaptureMaxContextBytes(value: number): number;
105
107
  /** Whole hours from 0 to 720. A value that is not a number gives the default. */
106
108
  export declare function normalizeCaptureRetryRetentionHours(value: unknown): number;
@@ -145,6 +147,7 @@ declare function buildConfig(fileConfig: OmmsConfig): {
145
147
  opencodeBackfillModel: string;
146
148
  piBackfillModel: string;
147
149
  importPathMaps: import("./importer/importer.js").ImportPathMap[];
150
+ claudeConfigDir: string;
148
151
  webServerAutoStart: boolean;
149
152
  webServerEnabled: boolean;
150
153
  webServerPort: number;
@@ -239,6 +242,7 @@ export declare let CONFIG: {
239
242
  opencodeBackfillModel: string;
240
243
  piBackfillModel: string;
241
244
  importPathMaps: import("./importer/importer.js").ImportPathMap[];
245
+ claudeConfigDir: string;
242
246
  webServerAutoStart: boolean;
243
247
  webServerEnabled: boolean;
244
248
  webServerPort: number;
package/dist/config.js CHANGED
@@ -2,6 +2,7 @@ import { existsSync, readFileSync, mkdirSync, writeFileSync, statSync } from "no
2
2
  import { join } from "node:path";
3
3
  import { homedir } from "node:os";
4
4
  import { stripJsoncComments } from "./services/jsonc.js";
5
+ import { isValidClaudeConfigDir } from "./services/claude-folder.js";
5
6
  import { log } from "./services/logger.js";
6
7
  import { resolveSecretValue } from "./services/secret-resolver.js";
7
8
  import { isPlaceholderApiKey } from "./services/ai/api-key-placeholder.js";
@@ -58,6 +59,7 @@ const DEFAULTS = {
58
59
  opencodeBackfillModel: "inherit",
59
60
  piBackfillModel: "inherit",
60
61
  importPathMaps: [],
62
+ claudeConfigDir: "",
61
63
  webServerAutoStart: true,
62
64
  webServerEnabled: true,
63
65
  webServerPort: 4747,
@@ -205,6 +207,8 @@ export const CONFIG_TEMPLATE = `{
205
207
  // "opencodeBackfillModel": "inherit", // or "external", or "provider/model"
206
208
  // Directory maps for history recorded in moved or deleted directories.
207
209
  // "importPathMaps": [{ "from": "~/code/app-feat-x", "to": "~/code/app" }],
210
+ // Claude Code's folder, when it is not ~/.claude (like CLAUDE_CONFIG_DIR).
211
+ // "claudeConfigDir": "~/.claude-work",
208
212
 
209
213
  // Register the web app to start when you log in.
210
214
  "webServerAutoStart": true,
@@ -599,6 +603,10 @@ function buildConfig(fileConfig) {
599
603
  parseBackfillModel(fileConfig, "pi");
600
604
  parseBackfillModel(fileConfig, "opencode");
601
605
  const importPathMaps = parseImportPathMaps(fileConfig.importPathMaps);
606
+ if (fileConfig.claudeConfigDir !== undefined &&
607
+ !isValidClaudeConfigDir(fileConfig.claudeConfigDir)) {
608
+ throw new Error("Invalid claudeConfigDir config");
609
+ }
602
610
  for (const key of ["autoBackfill", "webServerAutoStart"]) {
603
611
  if (fileConfig[key] !== undefined && typeof fileConfig[key] !== "boolean") {
604
612
  throw new Error(`Invalid ${key} config`);
@@ -663,6 +671,7 @@ function buildConfig(fileConfig) {
663
671
  opencodeBackfillModel: fileConfig.opencodeBackfillModel ?? DEFAULTS.opencodeBackfillModel,
664
672
  piBackfillModel: fileConfig.piBackfillModel ?? DEFAULTS.piBackfillModel,
665
673
  importPathMaps,
674
+ claudeConfigDir: expandPath(fileConfig.claudeConfigDir?.trim() ?? DEFAULTS.claudeConfigDir),
666
675
  webServerAutoStart: fileConfig.webServerAutoStart ?? DEFAULTS.webServerAutoStart,
667
676
  webServerEnabled: fileConfig.webServerEnabled ?? DEFAULTS.webServerEnabled,
668
677
  webServerPort: fileConfig.webServerPort ?? DEFAULTS.webServerPort,
@@ -820,6 +829,8 @@ export function initConfig(directory, options = {}) {
820
829
  delete projectOverrides.opencodeBackfillModel;
821
830
  delete projectOverrides.piBackfillModel;
822
831
  delete projectOverrides.importPathMaps;
832
+ // A checked-in project file must not point the web app at another folder.
833
+ delete projectOverrides.claudeConfigDir;
823
834
  delete projectOverrides.webServerAutoStart;
824
835
  delete projectOverrides.webServerEnabled;
825
836
  const merged = { ...globalConfig, ...projectOverrides };
@@ -92,7 +92,7 @@ function checkedTranscriptPath(transcriptPath, sessionId) {
92
92
  if (basename(transcriptPath) !== fileName || basename(real) !== fileName) {
93
93
  throw new ClaudeHookRequestError("transcript_path must be named <session_id>.jsonl");
94
94
  }
95
- const root = realPathOrResolved(defaultClaudeProjectsRoot());
95
+ const root = realPathOrResolved(defaultClaudeProjectsRoot(CONFIG.claudeConfigDir));
96
96
  if (!real.startsWith(root + sep)) {
97
97
  throw new ClaudeHookRequestError("transcript_path must be under the Claude projects folder");
98
98
  }
@@ -107,6 +107,8 @@ function parseCaptureRequest(body) {
107
107
  throw new ClaudeHookRequestError("transcript_path must be an absolute .jsonl path");
108
108
  }
109
109
  const { sessionId, cwd } = sessionAndCwd(input);
110
+ // The path check uses `claudeConfigDir`, which the Settings page may just have changed.
111
+ refreshConfigIfChanged(cwd);
110
112
  return {
111
113
  sessionId,
112
114
  cwd,
@@ -16,8 +16,8 @@ import { type ImportPathMap, type ImportProjectReport, type LazyImportSource } f
16
16
  * time.
17
17
  */
18
18
  export declare const CLAUDE_HEADER_READ_LIMIT: number;
19
- /** `$CLAUDE_CONFIG_DIR/projects` when the variable is set, else `~/.claude/projects`. */
20
- export declare function defaultClaudeProjectsRoot(): string;
19
+ /** The Claude projects folder; `claudeConfigDir` is `CONFIG.claudeConfigDir`. */
20
+ export declare function defaultClaudeProjectsRoot(claudeConfigDir?: string): string;
21
21
  export interface DiscoveredClaudeSession {
22
22
  file: string;
23
23
  /** Path relative to the root, with `/` separators; the file name for a file root. */
@@ -1,7 +1,8 @@
1
1
  import { closeSync, existsSync, openSync, readFileSync, readSync, readdirSync, statSync, } from "node:fs";
2
- import { homedir } from "node:os";
3
2
  import { basename, join } from "node:path";
4
3
  import { StringDecoder } from "node:string_decoder";
4
+ import { CONFIG } from "../config.js";
5
+ import { claudeProjectsRoot } from "../services/claude-folder.js";
5
6
  import { extractScopeFromContainerTag } from "../services/memory-scope.js";
6
7
  import { getTags } from "../services/tags.js";
7
8
  import { extractClaudeConversationWindows, parseClaudeTranscript, parseClaudeTranscriptLine, } from "./claude-conversation.js";
@@ -23,10 +24,9 @@ import { countImportableUnits, projectFilterTag, selectImportWindows, } from "./
23
24
  */
24
25
  export const CLAUDE_HEADER_READ_LIMIT = 1024 * 1024;
25
26
  const READ_CHUNK = 64 * 1024;
26
- /** `$CLAUDE_CONFIG_DIR/projects` when the variable is set, else `~/.claude/projects`. */
27
- export function defaultClaudeProjectsRoot() {
28
- const configDir = process.env.CLAUDE_CONFIG_DIR?.trim();
29
- return join(configDir || join(homedir(), ".claude"), "projects");
27
+ /** The Claude projects folder; `claudeConfigDir` is `CONFIG.claudeConfigDir`. */
28
+ export function defaultClaudeProjectsRoot(claudeConfigDir) {
29
+ return claudeProjectsRoot(claudeConfigDir);
30
30
  }
31
31
  /** A missing folder is an empty history. Any other read error is reported, not hidden. */
32
32
  function readEntries(dir, unreadable) {
@@ -128,7 +128,7 @@ function isFile(path) {
128
128
  }
129
129
  }
130
130
  export function discoverClaudeSessions(options = {}) {
131
- const root = options.root ?? defaultClaudeProjectsRoot();
131
+ const root = options.root ?? defaultClaudeProjectsRoot(CONFIG.claudeConfigDir);
132
132
  const sessions = [];
133
133
  const unrecognized = [];
134
134
  if (!existsSync(root))
@@ -37,7 +37,7 @@ export async function importReadiness(deps = {}) {
37
37
  external: { state, provider: CONFIG.memoryProvider, model: CONFIG.memoryModel ?? null },
38
38
  opencode: { available: opencode.available, models: opencode.models ?? [] },
39
39
  piReader,
40
- claudeCode: claudeReadiness(deps.claudeRoot?.() ?? defaultClaudeSourcePath()),
40
+ claudeCode: claudeReadiness(deps.claudeRoot?.() ?? defaultClaudeSourcePath(CONFIG.claudeConfigDir)),
41
41
  };
42
42
  }
43
43
  function claudeReadiness(defaultRoot) {
@@ -136,7 +136,7 @@ export function validateSessionListRequest(value) {
136
136
  /** One page of session metadata; no prompts, replies, or tool data. */
137
137
  export async function listImportSessions(request, options) {
138
138
  const source = request.sourceToken === undefined
139
- ? validateImportSource(options.host, defaultImportSourcePath(options.host))
139
+ ? validateImportSource(options.host, defaultImportSourcePath(options.host, (await import("../config.js")).CONFIG.claudeConfigDir))
140
140
  : null;
141
141
  const token = source?.sourceToken ?? request.sourceToken;
142
142
  const identity = readImportSourceToken(token, options.host);
@@ -22,13 +22,9 @@ export declare function readImportSourceToken(token: unknown, host: ImportHost):
22
22
  export declare function importSourceKey(identity: ImportSourceIdentity): string;
23
23
  /** Refuse a source whose path now names another file, such as a swapped-in symlink. */
24
24
  export declare function assertImportSourceUnchanged(identity: ImportSourceIdentity): void;
25
- /**
26
- * Same folder as `defaultClaudeProjectsRoot()` in `claude-reader.ts`. That
27
- * module loads the storage engine, so this light module keeps its own copy;
28
- * `tests/import-sources.test.ts` checks that the two agree.
29
- */
30
- export declare function defaultClaudeSourcePath(): string;
31
- export declare function defaultImportSourcePath(host: ImportHost): string;
25
+ /** The Claude projects folder; `claudeConfigDir` is `CONFIG.claudeConfigDir`. */
26
+ export declare function defaultClaudeSourcePath(claudeConfigDir?: string): string;
27
+ export declare function defaultImportSourcePath(host: ImportHost, claudeConfigDir?: string): string;
32
28
  export interface ValidatedImportSource {
33
29
  kind: ImportSourceKind;
34
30
  displayPath: string;
@@ -45,7 +41,7 @@ export interface BrowseEntry {
45
41
  * One folder at a time, with no recursion: subfolders and files the host can
46
42
  * import. A Claude Code source is always a folder, so it lists folders only. Symlinked entries are hidden. Only offered on loopback binds.
47
43
  */
48
- export declare function browseImportSources(host: ImportHost, path?: unknown): {
44
+ export declare function browseImportSources(host: ImportHost, path?: unknown, claudeConfigDir?: string): {
49
45
  path: string;
50
46
  parent: string | null;
51
47
  entries: BrowseEntry[];
@@ -2,6 +2,7 @@ import { createHmac, randomBytes, timingSafeEqual } from "node:crypto";
2
2
  import { closeSync, existsSync, openSync, readdirSync, readSync, realpathSync, statSync, } from "node:fs";
3
3
  import { homedir } from "node:os";
4
4
  import { dirname, isAbsolute, join } from "node:path";
5
+ import { claudeProjectsRoot } from "../services/claude-folder.js";
5
6
  import { DEFAULT_PI_SESSION_ROOT, readPiSessionHeader } from "./discovery.js";
6
7
  import { DEFAULT_OPENCODE_DB } from "./opencode-reader.js";
7
8
  export class ImportSourceError extends Error {
@@ -79,19 +80,15 @@ function isSqliteFile(path) {
79
80
  closeSync(fd);
80
81
  }
81
82
  }
82
- /**
83
- * Same folder as `defaultClaudeProjectsRoot()` in `claude-reader.ts`. That
84
- * module loads the storage engine, so this light module keeps its own copy;
85
- * `tests/import-sources.test.ts` checks that the two agree.
86
- */
87
- export function defaultClaudeSourcePath() {
88
- return join(homedir(), ".claude", "projects");
83
+ /** The Claude projects folder; `claudeConfigDir` is `CONFIG.claudeConfigDir`. */
84
+ export function defaultClaudeSourcePath(claudeConfigDir) {
85
+ return claudeProjectsRoot(claudeConfigDir);
89
86
  }
90
- export function defaultImportSourcePath(host) {
87
+ export function defaultImportSourcePath(host, claudeConfigDir) {
91
88
  if (host === "pi")
92
89
  return DEFAULT_PI_SESSION_ROOT;
93
90
  if (host === "claude-code")
94
- return defaultClaudeSourcePath();
91
+ return defaultClaudeSourcePath(claudeConfigDir);
95
92
  return DEFAULT_OPENCODE_DB;
96
93
  }
97
94
  /** Check an absolute path's kind and format; never returns file contents. */
@@ -130,10 +127,12 @@ const BROWSE_LIMIT = 500;
130
127
  * One folder at a time, with no recursion: subfolders and files the host can
131
128
  * import. A Claude Code source is always a folder, so it lists folders only. Symlinked entries are hidden. Only offered on loopback binds.
132
129
  */
133
- export function browseImportSources(host, path) {
130
+ export function browseImportSources(host, path, claudeConfigDir) {
134
131
  let start = path;
135
132
  if (start === undefined || start === null || start === "") {
136
- const preferred = host === "opencode" ? dirname(DEFAULT_OPENCODE_DB) : defaultImportSourcePath(host);
133
+ const preferred = host === "opencode"
134
+ ? dirname(DEFAULT_OPENCODE_DB)
135
+ : defaultImportSourcePath(host, claudeConfigDir);
137
136
  start = existsSync(preferred) ? preferred : homedir();
138
137
  }
139
138
  const folder = checkedPath(start);
@@ -150,7 +150,17 @@ async function runUntracked(host, args, run) {
150
150
  };
151
151
  if (host === "claude-code") {
152
152
  const { importClaudeHistory } = await import("./claude-import.js");
153
- return importClaudeHistory(deps, filters);
153
+ if (args.source)
154
+ return importClaudeHistory(deps, filters);
155
+ // Without --root, read the folder live capture uses.
156
+ const [{ CONFIG }, { claudeProjectsRoot }] = await Promise.all([
157
+ import("../config.js"),
158
+ import("../services/claude-folder.js"),
159
+ ]);
160
+ return importClaudeHistory(deps, {
161
+ ...filters,
162
+ root: claudeProjectsRoot(CONFIG.claudeConfigDir),
163
+ });
154
164
  }
155
165
  const { importPiHistory } = await import("./importer.js");
156
166
  const { loadPiSessionForImport } = await import("./session-loader.js");
@@ -0,0 +1,16 @@
1
+ /**
2
+ * The Claude Code folder, in one place for every caller: the `claudeConfigDir`
3
+ * setting, then `CLAUDE_CONFIG_DIR`, then `~/.claude`. Pure on purpose: callers
4
+ * pass `CONFIG.claudeConfigDir`, because many tests stub `src/config.js`.
5
+ * It sits in services so the settings snapshot can use it too.
6
+ */
7
+ export type ClaudeFolderSource = "setting" | "env" | "default";
8
+ export interface ClaudeFolder {
9
+ folder: string;
10
+ source: ClaudeFolderSource;
11
+ }
12
+ /** Empty, an absolute path, or `~/...`. A relative path would depend on the web app's working directory. */
13
+ export declare function isValidClaudeConfigDir(value: unknown): value is string;
14
+ export declare function resolveClaudeFolder(configured: string | undefined, env?: string | undefined, home?: string): ClaudeFolder;
15
+ /** `<Claude folder>/projects`, where Claude Code writes its transcripts. */
16
+ export declare function claudeProjectsRoot(configured: string | undefined, env?: string, home?: string): string;
@@ -0,0 +1,24 @@
1
+ import { homedir } from "node:os";
2
+ import { isAbsolute, join } from "node:path";
3
+ /** Empty, an absolute path, or `~/...`. A relative path would depend on the web app's working directory. */
4
+ export function isValidClaudeConfigDir(value) {
5
+ if (typeof value !== "string")
6
+ return false;
7
+ const trimmed = value.trim();
8
+ return trimmed === "" || trimmed.startsWith("~/") || isAbsolute(trimmed);
9
+ }
10
+ export function resolveClaudeFolder(configured, env = process.env.CLAUDE_CONFIG_DIR, home = homedir()) {
11
+ const expand = (path) => (path.startsWith("~/") ? join(home, path.slice(2)) : path);
12
+ const setting = configured?.trim();
13
+ if (setting)
14
+ return { folder: expand(setting), source: "setting" };
15
+ // A variable set without shell expansion can still hold a literal `~/`.
16
+ const fromEnv = env?.trim();
17
+ if (fromEnv)
18
+ return { folder: expand(fromEnv), source: "env" };
19
+ return { folder: join(home, ".claude"), source: "default" };
20
+ }
21
+ /** `<Claude folder>/projects`, where Claude Code writes its transcripts. */
22
+ export function claudeProjectsRoot(configured, env, home) {
23
+ return join(resolveClaudeFolder(configured, env, home).folder, "projects");
24
+ }
@@ -3,6 +3,7 @@ import { promises as fs, readFileSync, statSync } from "node:fs";
3
3
  import { dirname, join } from "node:path";
4
4
  import { applyEdits, modify, parse } from "jsonc-parser";
5
5
  import { CONFIG_TEMPLATE, getGlobalConfigSourcePath, getGlobalConfigWritePath, validateGlobalConfig, } from "../config.js";
6
+ import { isValidClaudeConfigDir } from "./claude-folder.js";
6
7
  const keys = new Set([
7
8
  "opencodeProvider",
8
9
  "opencodeModel",
@@ -21,6 +22,7 @@ const keys = new Set([
21
22
  "memoryModel",
22
23
  "memoryApiKey",
23
24
  "importPathMaps",
25
+ "claudeConfigDir",
24
26
  ]);
25
27
  const MEMORY_PROVIDERS = [
26
28
  "openai-chat",
@@ -50,6 +52,9 @@ function isValidEdit(key, value) {
50
52
  // Entries are checked by the startup validation below.
51
53
  if (key === "importPathMaps")
52
54
  return Array.isArray(value);
55
+ // An empty value clears the field.
56
+ if (key === "claudeConfigDir")
57
+ return isValidClaudeConfigDir(value);
53
58
  return typeof value === "string" && value.trim().length > 0;
54
59
  }
55
60
  export class ConfigConflictError extends Error {
@@ -29,6 +29,11 @@ export declare function getSettingsSnapshot(directory: string): {
29
29
  pi: import("./ai/live-model-choice.js").PiLiveModelChoice;
30
30
  "claude-code": import("./ai/live-model-choice.js").AutoCaptureProviderStatus;
31
31
  };
32
+ claudeFolder: {
33
+ root: string;
34
+ source: import("./claude-folder.js").ClaudeFolderSource;
35
+ exists: boolean;
36
+ };
32
37
  };
33
38
  /**
34
39
  * Where `memoryApiKey` comes from and whether it resolves in this web
@@ -2,6 +2,7 @@ import { existsSync, readFileSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
  import { parse } from "jsonc-parser";
4
4
  import { CONFIG, getGlobalConfigSourcePath } from "../config.js";
5
+ import { resolveClaudeFolder } from "./claude-folder.js";
5
6
  import { readGlobalConfigRevision } from "./global-config-writer.js";
6
7
  import { getAutoCaptureProviderStatus, isExternalModelReady, resolveClaudeCodeLiveModel, resolvePiLiveModel, } from "./ai/live-model-choice.js";
7
8
  const editable = [
@@ -21,6 +22,7 @@ const editable = [
21
22
  "memoryApiUrl",
22
23
  "memoryModel",
23
24
  "importPathMaps",
25
+ "claudeConfigDir",
24
26
  ];
25
27
  /** Keys a project config cannot override, so the page always shows the global value. */
26
28
  const globalOnly = [
@@ -32,6 +34,7 @@ const globalOnly = [
32
34
  "memoryProvider",
33
35
  "memoryApiUrl",
34
36
  "importPathMaps",
37
+ "claudeConfigDir",
35
38
  ];
36
39
  function readSettingsFile(path) {
37
40
  if (!path)
@@ -83,6 +86,9 @@ export function getSettingsSnapshot(directory) {
83
86
  },
84
87
  ];
85
88
  }));
89
+ const claudeSetting = global.claudeConfigDir ?? CONFIG.claudeConfigDir;
90
+ const claude = resolveClaudeFolder(typeof claudeSetting === "string" ? claudeSetting : "");
91
+ const claudeRoot = join(claude.folder, "projects");
86
92
  return {
87
93
  revision: readGlobalConfigRevision(),
88
94
  settings,
@@ -95,6 +101,8 @@ export function getSettingsSnapshot(directory) {
95
101
  // Claude Code capture uses the external API only; `issues` names each missing setting.
96
102
  "claude-code": resolveClaudeCodeLiveModel(CONFIG),
97
103
  },
104
+ // The folder Claude Code capture and import read; the check never reads transcripts.
105
+ claudeFolder: { root: claudeRoot, source: claude.source, exists: existsSync(claudeRoot) },
98
106
  };
99
107
  }
100
108
  /**
@@ -793,8 +793,11 @@ export class WebServer {
793
793
  if (body?.host !== "pi" && body?.host !== "opencode" && body?.host !== "claude-code") {
794
794
  return this.jsonResponse({ error: "Choose Pi, OpenCode, or Claude Code" }, 400);
795
795
  }
796
- const { browseImportSources } = await import("../importer/web-import-api.js");
797
- return this.importResponse(() => browseImportSources(body.host, body.path));
796
+ const [{ browseImportSources }, { CONFIG }] = await Promise.all([
797
+ import("../importer/web-import-api.js"),
798
+ import("../config.js"),
799
+ ]);
800
+ return this.importResponse(() => browseImportSources(body.host, body.path, CONFIG.claudeConfigDir));
798
801
  }
799
802
  if (path === "/api/settings/imports/sources/validate" && method === "POST") {
800
803
  const body = (await req.json());
@@ -119,6 +119,6 @@ ${e}</tr>
119
119
  `}tablecell(e){let t=this.parser.parseInline(e.tokens),n=e.header?`th`:`td`;return(e.align?`<${n} align="${e.align}">`:`<${n}>`)+t+`</${n}>
120
120
  `}strong({tokens:e}){return`<strong>${this.parser.parseInline(e)}</strong>`}em({tokens:e}){return`<em>${this.parser.parseInline(e)}</em>`}codespan({text:e}){return`<code>${Nf(e,!0)}</code>`}br(e){return`<br>`}del({tokens:e}){return`<del>${this.parser.parseInline(e)}</del>`}link({href:e,title:t,tokens:n}){let r=this.parser.parseInline(n),i=Pf(e);if(i===null)return r;e=i;let a=`<a href="`+e+`"`;return t&&(a+=` title="`+Nf(t)+`"`),a+=`>`+r+`</a>`,a}image({href:e,title:t,text:n,tokens:r}){r&&(n=this.parser.parseInline(r,this.parser.textRenderer));let i=Pf(e);if(i===null)return Nf(n);e=i;let a=`<img src="${e}" alt="${Nf(n)}"`;return t&&(a+=` title="${Nf(t)}"`),a+=`>`,a}text(e){return`tokens`in e&&e.tokens?this.parser.parseInline(e.tokens):`escaped`in e&&e.escaped?e.text:Nf(e.text)}},Gf=class{strong({text:e}){return e}em({text:e}){return e}codespan({text:e}){return e}del({text:e}){return e}html({text:e}){return e}text({text:e}){return e}link({text:e}){return``+e}image({text:e}){return``+e}br(){return``}checkbox({raw:e}){return e}},Kf=class e{options;renderer;textRenderer;constructor(e){this.options=e||md,this.options.renderer=this.options.renderer||new Wf,this.renderer=this.options.renderer,this.renderer.options=this.options,this.renderer.parser=this,this.textRenderer=new Gf}static parse(t,n){return new e(n).parse(t)}static parseInline(t,n){return new e(n).parseInline(t)}parse(e){this.renderer.parser=this;let t=``;for(let n=0;n<e.length;n++){let r=e[n];if(this.options.extensions?.renderers?.[r.type]){let e=r,n=this.options.extensions.renderers[e.type].call({parser:this},e);if(n!==!1||![`space`,`hr`,`heading`,`code`,`table`,`blockquote`,`list`,`checkbox`,`html`,`def`,`paragraph`,`text`].includes(e.type)){t+=n||``;continue}}let i=r;switch(i.type){case`space`:t+=this.renderer.space(i);break;case`hr`:t+=this.renderer.hr(i);break;case`heading`:t+=this.renderer.heading(i);break;case`code`:t+=this.renderer.code(i);break;case`table`:t+=this.renderer.table(i);break;case`blockquote`:t+=this.renderer.blockquote(i);break;case`list`:t+=this.renderer.list(i);break;case`checkbox`:t+=this.renderer.checkbox(i);break;case`html`:t+=this.renderer.html(i);break;case`def`:t+=this.renderer.def(i);break;case`paragraph`:t+=this.renderer.paragraph(i);break;case`text`:t+=this.renderer.text(i);break;default:{let e=`Token with "`+i.type+`" type was not found.`;if(this.options.silent)return console.error(e),``;throw Error(e)}}}return t}parseInline(e,t=this.renderer){this.renderer.parser=this;let n=``;for(let r=0;r<e.length;r++){let i=e[r];if(this.options.extensions?.renderers?.[i.type]){let e=this.options.extensions.renderers[i.type].call({parser:this},i);if(e!==!1||![`escape`,`html`,`link`,`image`,`checkbox`,`strong`,`em`,`codespan`,`br`,`del`,`text`].includes(i.type)){n+=e||``;continue}}let a=i;switch(a.type){case`escape`:n+=t.text(a);break;case`html`:n+=t.html(a);break;case`link`:n+=t.link(a);break;case`image`:n+=t.image(a);break;case`checkbox`:n+=t.checkbox(a);break;case`strong`:n+=t.strong(a);break;case`em`:n+=t.em(a);break;case`codespan`:n+=t.codespan(a);break;case`br`:n+=t.br(a);break;case`del`:n+=t.del(a);break;case`text`:n+=t.text(a);break;default:{let e=`Token with "`+a.type+`" type was not found.`;if(this.options.silent)return console.error(e),``;throw Error(e)}}}return n}},qf=class{options;block;constructor(e){this.options=e||md}static passThroughHooks=new Set([`preprocess`,`postprocess`,`processAllTokens`,`emStrongMask`]);static passThroughHooksRespectAsync=new Set([`preprocess`,`postprocess`,`processAllTokens`]);preprocess(e){return e}postprocess(e){return e}processAllTokens(e){return e}emStrongMask(e){return e}provideLexer(e=this.block){return e?Uf.lex:Uf.lexInline}provideParser(e=this.block){return e?Kf.parse:Kf.parseInline}},Jf=new class{defaults=pd();options=this.setOptions;parse=this.parseMarkdown(!0);parseInline=this.parseMarkdown(!1);Parser=Kf;Renderer=Wf;TextRenderer=Gf;Lexer=Uf;Tokenizer=Hf;Hooks=qf;constructor(...e){this.use(...e)}walkTokens(e,t){let n=[];for(let r of e)switch(n=n.concat(t.call(this,r)),r.type){case`table`:{let e=r;for(let r of e.header)n=n.concat(this.walkTokens(r.tokens,t));for(let r of e.rows)for(let e of r)n=n.concat(this.walkTokens(e.tokens,t));break}case`list`:{let e=r;n=n.concat(this.walkTokens(e.items,t));break}default:{let e=r;this.defaults.extensions?.childTokens?.[e.type]?this.defaults.extensions.childTokens[e.type].forEach(r=>{let i=e[r].flat(1/0);n=n.concat(this.walkTokens(i,t))}):e.tokens&&(n=n.concat(this.walkTokens(e.tokens,t)))}}return n}use(...e){let t=this.defaults.extensions||{renderers:{},childTokens:{}};return e.forEach(e=>{let n={...e};if(n.async=this.defaults.async||n.async||!1,e.extensions&&(e.extensions.forEach(e=>{if(!e.name)throw Error(`extension name required`);if(`renderer`in e){let n=t.renderers[e.name];n?t.renderers[e.name]=function(...t){let r=e.renderer.apply(this,t);return r===!1&&(r=n.apply(this,t)),r}:t.renderers[e.name]=e.renderer}if(`tokenizer`in e){if(!e.level||e.level!==`block`&&e.level!==`inline`)throw Error(`extension level must be 'block' or 'inline'`);let n=t[e.level];n?n.unshift(e.tokenizer):t[e.level]=[e.tokenizer],e.start&&(e.level===`block`?t.startBlock?t.startBlock.push(e.start):t.startBlock=[e.start]:e.level===`inline`&&(t.startInline?t.startInline.push(e.start):t.startInline=[e.start]))}`childTokens`in e&&e.childTokens&&(t.childTokens[e.name]=e.childTokens)}),n.extensions=t),e.renderer){let t=this.defaults.renderer||new Wf(this.defaults);for(let n in e.renderer){if(!(n in t))throw Error(`renderer '${n}' does not exist`);if([`options`,`parser`].includes(n))continue;let r=n,i=e.renderer[r],a=t[r];t[r]=(...e)=>{let n=i.apply(t,e);return n===!1&&(n=a.apply(t,e)),n||``}}n.renderer=t}if(e.tokenizer){let t=this.defaults.tokenizer||new Hf(this.defaults);for(let n in e.tokenizer){if(!(n in t))throw Error(`tokenizer '${n}' does not exist`);if([`options`,`rules`,`lexer`].includes(n))continue;let r=n,i=e.tokenizer[r],a=t[r];t[r]=(...e)=>{let n=i.apply(t,e);return n===!1&&(n=a.apply(t,e)),n}}n.tokenizer=t}if(e.hooks){let t=this.defaults.hooks||new qf;for(let n in e.hooks){if(!(n in t))throw Error(`hook '${n}' does not exist`);if([`options`,`block`].includes(n))continue;let r=n,i=e.hooks[r],a=t[r];t[r]=qf.passThroughHooks.has(n)?e=>{if(this.defaults.async&&qf.passThroughHooksRespectAsync.has(n))return(async()=>{let n=await i.call(t,e);return a.call(t,n)})();let r=i.call(t,e);return a.call(t,r)}:(...e)=>{if(this.defaults.async)return(async()=>{let n=await i.apply(t,e);return n===!1&&(n=await a.apply(t,e)),n})();let n=i.apply(t,e);return n===!1&&(n=a.apply(t,e)),n}}n.hooks=t}if(e.walkTokens){let t=this.defaults.walkTokens,r=e.walkTokens;n.walkTokens=function(e){let n=[];return n.push(r.call(this,e)),t&&(n=n.concat(t.call(this,e))),n}}this.defaults={...this.defaults,...n}}),this}setOptions(e){return this.defaults={...this.defaults,...e},this}lexer(e,t){return Uf.lex(e,t??this.defaults)}parser(e,t){return Kf.parse(e,t??this.defaults)}parseMarkdown(e){return(t,n)=>{let r={...n},i={...this.defaults,...r},a=this.onError(!!i.silent,!!i.async);if(this.defaults.async===!0&&r.async===!1)return a(Error(`marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise.`));if(typeof t>`u`||t===null)return a(Error(`marked(): input parameter is undefined or null`));if(typeof t!=`string`)return a(Error(`marked(): input parameter is of type `+Object.prototype.toString.call(t)+`, string expected`));if(i.hooks&&(i.hooks.options=i,i.hooks.block=e),i.async)return(async()=>{let n=i.hooks?await i.hooks.preprocess(t):t,r=await(i.hooks?await i.hooks.provideLexer(e):e?Uf.lex:Uf.lexInline)(n,i),a=i.hooks?await i.hooks.processAllTokens(r):r;i.walkTokens&&await Promise.all(this.walkTokens(a,i.walkTokens));let o=await(i.hooks?await i.hooks.provideParser(e):e?Kf.parse:Kf.parseInline)(a,i);return i.hooks?await i.hooks.postprocess(o):o})().catch(a);try{i.hooks&&(t=i.hooks.preprocess(t));let n=(i.hooks?i.hooks.provideLexer(e):e?Uf.lex:Uf.lexInline)(t,i);i.hooks&&(n=i.hooks.processAllTokens(n)),i.walkTokens&&this.walkTokens(n,i.walkTokens);let r=(i.hooks?i.hooks.provideParser(e):e?Kf.parse:Kf.parseInline)(n,i);return i.hooks&&(r=i.hooks.postprocess(r)),r}catch(e){return a(e)}}}onError(e,t){return n=>{if(n.message+=`
121
121
  Please report this to https://github.com/markedjs/marked.`,e){let e=`<p>An error occurred:</p><pre>`+Nf(n.message+``,!0)+`</pre>`;return t?Promise.resolve(e):e}if(t)return Promise.reject(n);throw n}}};function Yf(e,t){return Jf.parse(e,t)}Yf.options=Yf.setOptions=function(e){return Jf.setOptions(e),Yf.defaults=Jf.defaults,hd(Yf.defaults),Yf},Yf.getDefaults=pd,Yf.defaults=md;function Xf(...e){return Jf.use(...e),Yf.defaults=Jf.defaults,hd(Yf.defaults),Yf}Yf.use=Xf,Yf.walkTokens=function(e,t){return Jf.walkTokens(e,t)},Yf.parseInline=Jf.parseInline,Yf.Parser=Kf,Yf.parser=Kf.parse,Yf.Renderer=Wf,Yf.TextRenderer=Gf,Yf.Lexer=Uf,Yf.lexer=Uf.lex,Yf.Tokenizer=Hf,Yf.Hooks=qf,Yf.parse=Yf,Yf.options,Yf.setOptions,Yf.walkTokens,Yf.parseInline,Kf.parse,Uf.lex,Yf.setOptions({gfm:!0,breaks:!0});function Zf(e){let t=Yf.parse(e,{async:!1});return fd.sanitize(t)}function Qf(e){if(e.projectPath){let t=e.projectPath.replace(/\\/g,`/`).split(`/`).filter(e=>e);return t[t.length-1]||e.projectPath}return e.displayName||e.id}function $f(e){return{createdDate:Y(e.createdAt),updatedDate:e.updatedAt&&e.updatedAt!==e.createdAt?Y(e.updatedAt):null}}function ep(e,t){return e.similarity===void 0?null:t?`${Math.round(e.similarity*100)}%`:`${e.similarity}%`}function tp({variant:e,item:t,memory:n,prompt:r,selected:i=!1,onSelect:a,onPin:o,onUnpin:s,onEdit:c,onDeleteMemory:l,onDeletePrompt:u,activeKeyword:d,onKeywordClick:f}){let{t:p}=lr();if(e===`pair`&&n&&r){let e=n.isPinned||!1,t=$f(n),u=ep(n,!0);return(0,V.jsxs)(`div`,{className:`rounded-xl border border-border bg-card/60 p-3 space-y-3 ${i?`ring-1 ring-primary/50`:``} ${e?`border-primary/40`:``}`,"data-id":n.id,children:[(0,V.jsxs)(`div`,{className:`space-y-2 rounded-lg bg-muted/40 p-3`,children:[(0,V.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,V.jsx)(J,{variant:`secondary`,children:p(`badge-prompt`)}),(0,V.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:Y(r.createdAt)})]}),(0,V.jsx)(`p`,{className:`text-sm whitespace-pre-wrap break-words`,children:r.content})]}),(0,V.jsx)(`div`,{className:`flex justify-center text-muted-foreground`,children:(0,V.jsx)(te,{className:`size-4`})}),(0,V.jsxs)(`div`,{className:`space-y-2`,children:[(0,V.jsxs)(`div`,{className:`flex flex-wrap items-start justify-between gap-2`,children:[(0,V.jsxs)(`div`,{className:`flex flex-wrap items-center gap-1.5 min-w-0`,children:[(0,V.jsx)(Ui,{checked:i,onCheckedChange:e=>a?.(n.id,e===!0)}),(0,V.jsx)(J,{children:p(`badge-memory`)}),n.memoryType?(0,V.jsx)(J,{variant:`outline`,children:n.memoryType}):null,u?(0,V.jsx)(`span`,{className:`text-xs text-primary`,children:u}):null,e?(0,V.jsx)(J,{variant:`secondary`,children:p(`badge-pinned`)}):null,(0,V.jsx)(`span`,{className:`text-xs text-muted-foreground truncate`,children:n.displayName||n.id})]}),(0,V.jsxs)(`div`,{className:`flex items-center gap-1 shrink-0`,children:[e?(0,V.jsx)(W,{variant:`ghost`,size:`icon-xs`,title:`Unpin`,onClick:()=>s?.(n.id),children:(0,V.jsx)(_e,{className:`size-3.5 fill-current`})}):(0,V.jsx)(W,{variant:`ghost`,size:`icon-xs`,title:`Pin`,onClick:()=>o?.(n.id),children:(0,V.jsx)(_e,{className:`size-3.5`})}),(0,V.jsx)(W,{variant:`ghost`,size:`icon-xs`,onClick:()=>c?.(n.id),children:(0,V.jsx)(he,{className:`size-3.5`})}),(0,V.jsx)(zl,{content:p(`tooltip-delete-pair`),children:(0,V.jsx)(W,{variant:`destructive`,size:`icon-xs`,"aria-label":p(`btn-delete-pair`),onClick:()=>l?.(n.id,!0),children:(0,V.jsx)(Oe,{className:`size-3.5`})})})]})]}),n.tags?.length?(0,V.jsx)(`div`,{className:`flex flex-wrap gap-1`,children:n.tags.map(e=>(0,V.jsx)(Ll,{keyword:e,active:d?.toLowerCase()===e.toLowerCase(),title:p(`tooltip-filter-keyword`),onClick:f},e))}):null,(0,V.jsx)(`div`,{className:`markdown-content text-sm prose-invert max-w-none`,dangerouslySetInnerHTML:{__html:Zf(n.content)}}),(0,V.jsxs)(`div`,{className:`flex flex-wrap gap-3 text-xs text-muted-foreground`,children:[(0,V.jsxs)(`span`,{children:[p(`date-created`),` `,t.createdDate]}),t.updatedDate?(0,V.jsxs)(`span`,{children:[p(`date-updated`),` `,t.updatedDate]}):null,(0,V.jsxs)(`span`,{children:[`ID: `,n.id]})]})]})]})}if(e===`prompt`&&t){let e=!!t.linkedMemoryId;return(0,V.jsxs)(`div`,{className:`rounded-xl border border-border bg-card/60 p-3 space-y-2 ${i?`ring-1 ring-primary/50`:``}`,"data-id":t.id,children:[(0,V.jsxs)(`div`,{className:`flex flex-wrap items-start justify-between gap-2`,children:[(0,V.jsxs)(`div`,{className:`flex flex-wrap items-center gap-1.5`,children:[(0,V.jsx)(Ui,{checked:i,onCheckedChange:e=>a?.(t.id,e===!0)}),(0,V.jsx)(de,{className:`size-3.5 text-muted-foreground`}),(0,V.jsx)(J,{variant:`secondary`,children:p(`badge-prompt`)}),e?(0,V.jsxs)(J,{variant:`outline`,children:[(0,V.jsx)(F,{className:`size-3`}),p(`badge-linked`)]}):null,(0,V.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:Y(t.createdAt)})]}),e?(0,V.jsx)(zl,{content:p(`tooltip-delete-prompt-pair`),children:(0,V.jsx)(W,{variant:`destructive`,size:`icon-xs`,"aria-label":p(e?`btn-delete-pair`:`btn-delete`),onClick:()=>u?.(t.id,e),children:(0,V.jsx)(Oe,{className:`size-3.5`})})}):(0,V.jsx)(W,{variant:`destructive`,size:`icon-xs`,"aria-label":p(e?`btn-delete-pair`:`btn-delete`),title:p(`btn-delete`),onClick:()=>u?.(t.id,e),children:(0,V.jsx)(Oe,{className:`size-3.5`})})]}),(0,V.jsx)(`p`,{className:`text-sm whitespace-pre-wrap break-words`,children:t.content}),e?(0,V.jsxs)(`div`,{className:`flex items-center gap-1 text-xs text-muted-foreground`,children:[(0,V.jsx)(te,{className:`size-3`}),p(`text-generated-above`),(0,V.jsx)(re,{className:`size-3`})]}):null]})}if(e===`memory`&&t){let e=t.isPinned||!1,n=!!t.linkedPromptId,r=$f(t),u=ep(t,!1);return(0,V.jsxs)(`div`,{className:`rounded-xl border border-border bg-card/60 p-3 space-y-2 ${i?`ring-1 ring-primary/50`:``} ${e?`border-primary/40`:``}`,"data-id":t.id,children:[(0,V.jsxs)(`div`,{className:`flex flex-wrap items-start justify-between gap-2`,children:[(0,V.jsxs)(`div`,{className:`flex flex-wrap items-center gap-1.5 min-w-0`,children:[(0,V.jsx)(Ui,{checked:i,onCheckedChange:e=>a?.(t.id,e===!0)}),t.memoryType?(0,V.jsx)(J,{variant:`outline`,children:t.memoryType}):null,n?(0,V.jsxs)(J,{variant:`outline`,children:[(0,V.jsx)(F,{className:`size-3`}),p(`badge-linked`)]}):null,u?(0,V.jsx)(`span`,{className:`text-xs text-primary`,children:u}):null,e?(0,V.jsx)(J,{variant:`secondary`,children:p(`badge-pinned`)}):null,(0,V.jsx)(`span`,{className:`text-xs text-muted-foreground truncate`,children:Qf(t)}),t.projectPath?(0,V.jsx)(`span`,{className:`text-xs text-muted-foreground/70 truncate w-full`,children:t.projectPath}):null]}),(0,V.jsxs)(`div`,{className:`flex items-center gap-1 shrink-0`,children:[e?(0,V.jsx)(W,{variant:`ghost`,size:`icon-xs`,title:`Unpin`,onClick:()=>s?.(t.id),children:(0,V.jsx)(_e,{className:`size-3.5 fill-current`})}):(0,V.jsx)(W,{variant:`ghost`,size:`icon-xs`,title:`Pin`,onClick:()=>o?.(t.id),children:(0,V.jsx)(_e,{className:`size-3.5`})}),(0,V.jsx)(W,{variant:`ghost`,size:`icon-xs`,onClick:()=>c?.(t.id),children:(0,V.jsx)(he,{className:`size-3.5`})}),n?(0,V.jsx)(zl,{content:p(`tooltip-delete-pair`),children:(0,V.jsx)(W,{variant:`destructive`,size:`icon-xs`,"aria-label":p(n?`btn-delete-pair`:`btn-delete`),onClick:()=>l?.(t.id,n),children:(0,V.jsx)(Oe,{className:`size-3.5`})})}):(0,V.jsx)(W,{variant:`destructive`,size:`icon-xs`,"aria-label":p(n?`btn-delete-pair`:`btn-delete`),title:p(`btn-delete`),onClick:()=>l?.(t.id,n),children:(0,V.jsx)(Oe,{className:`size-3.5`})})]})]}),t.tags?.length?(0,V.jsx)(`div`,{className:`flex flex-wrap gap-1`,children:t.tags.map(e=>(0,V.jsx)(Ll,{keyword:e,active:d?.toLowerCase()===e.toLowerCase(),title:p(`tooltip-filter-keyword`),onClick:f},e))}):null,(0,V.jsx)(`div`,{className:`markdown-content text-sm prose-invert max-w-none`,dangerouslySetInnerHTML:{__html:Zf(t.content)}}),n?(0,V.jsxs)(`div`,{className:`flex items-center gap-1 text-xs text-muted-foreground`,children:[(0,V.jsx)(re,{className:`size-3`}),p(`text-from-below`),(0,V.jsx)(te,{className:`size-3`})]}):null,(0,V.jsxs)(`div`,{className:`flex flex-wrap gap-3 text-xs text-muted-foreground`,children:[(0,V.jsxs)(`span`,{children:[p(`date-created`),` `,r.createdDate]}),r.updatedDate?(0,V.jsxs)(`span`,{children:[p(`date-updated`),` `,r.updatedDate]}):null,(0,V.jsxs)(`span`,{children:[`ID: `,t.id]})]})]})}return null}function np(e){let t=new Map(e.map(e=>[e.id,e])),n=[],r=new Set;for(let i of e)if(!r.has(i.id)){if(i.type===`memory`&&i.linkedPromptId&&t.has(i.linkedPromptId)){let e=t.get(i.linkedPromptId);n.push({isPair:!0,memory:i,prompt:e}),r.add(i.id),r.add(e.id)}else if(i.type===`prompt`&&i.linkedMemoryId&&t.has(i.linkedMemoryId)){let e=t.get(i.linkedMemoryId);n.push({isPair:!0,memory:e,prompt:i}),r.add(i.id),r.add(e.id)}else n.push({isPair:!1,type:i.type,item:i}),r.add(i.id)}return n.sort((e,t)=>{let n=e.isPair?e.memory.createdAt:e.item.createdAt,r=t.isPair?t.memory.createdAt:t.item.createdAt;return new Date(r).getTime()-new Date(n).getTime()})}function rp({memories:e,selectedIds:t,currentPage:n,totalPages:r,loading:i=!1,error:a=null,onSelect:o,onPageChange:s,onPin:c,onUnpin:l,onEdit:u,onDeleteMemory:d,onDeletePrompt:f,activeKeyword:p,onKeywordClick:m}){let{t:h}=lr(),g=(0,_.useMemo)(()=>np(e),[e]),v=h(`text-page`,{current:n,total:r}),y=(0,V.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,V.jsx)(W,{variant:`outline`,size:`icon-xs`,disabled:!(n>1),onClick:()=>s(-1),children:(0,V.jsx)(ae,{className:`size-3.5`})}),(0,V.jsx)(`span`,{className:`text-xs text-muted-foreground tabular-nums`,children:v}),(0,V.jsx)(W,{variant:`outline`,size:`icon-xs`,disabled:!(n<r),onClick:()=>s(1),children:(0,V.jsx)(A,{className:`size-3.5`})})]});return(0,V.jsxs)(`div`,{className:`space-y-3`,children:[(0,V.jsx)(`div`,{className:`grid min-h-32 items-start gap-3 lg:grid-cols-2`,children:i&&e.length===0?(0,V.jsx)(`div`,{className:`text-sm text-muted-foreground py-8 text-center`,children:h(`loading-init`)}):a?(0,V.jsxs)(`div`,{className:`text-sm text-destructive py-8 text-center`,children:[`Error: `,a]}):g.length===0?(0,V.jsx)(`div`,{className:`text-sm text-muted-foreground py-8 text-center`,children:h(`empty-memories`)}):g.map(e=>e.isPair?(0,V.jsx)(tp,{variant:`pair`,memory:e.memory,prompt:e.prompt,selected:t.has(e.memory.id),onSelect:o,onPin:c,onUnpin:l,onEdit:u,onDeleteMemory:d,onDeletePrompt:f,activeKeyword:p,onKeywordClick:m},e.memory.id):e.type===`prompt`?(0,V.jsx)(tp,{variant:`prompt`,item:e.item,selected:t.has(e.item.id),onSelect:o,onPin:c,onUnpin:l,onEdit:u,onDeleteMemory:d,onDeletePrompt:f,activeKeyword:p,onKeywordClick:m},e.item.id):(0,V.jsx)(tp,{variant:`memory`,item:e.item,selected:t.has(e.item.id),onSelect:o,onPin:c,onUnpin:l,onEdit:u,onDeleteMemory:d,onDeletePrompt:f,activeKeyword:p,onKeywordClick:m},e.item.id))}),(0,V.jsx)(`div`,{className:`flex justify-end`,children:y})]})}var ip=Object.defineProperty,ap=(e,t)=>ip(e,`name`,{value:t,configurable:!0}),op=_.createContext(void 0);function sp(e){let t=_.useContext(op);return e||t||`ltr`}ap(sp,`useDirection`);var cp=Object.defineProperty,lp=(e,t)=>cp(e,`name`,{value:t,configurable:!0});function up(e,[t,n]){return Math.min(n,Math.max(t,e))}lp(up,`clamp`);var dp=Object.defineProperty,Q=(e,t)=>dp(e,`name`,{value:t,configurable:!0});function fp(e,t){return _.useReducer((e,n)=>t[e][n]??e,e)}Q(fp,`useStateMachine`);var pp=`ScrollArea`,[mp,hp]=Br(pp),[gp,_p]=mp(pp),vp=_.forwardRef(Q(function(e,t){let{__scopeScrollArea:n,type:r=`hover`,dir:i,scrollHideDelay:a=600,...o}=e,[s,c]=_.useState(null),[l,u]=_.useState(null),[d,f]=_.useState(null),[p,m]=_.useState(null),[h,g]=_.useState(null),[v,y]=_.useState(0),[b,x]=_.useState(0),[S,C]=_.useState(!1),[w,T]=_.useState(!1),E=gr(t,c),D=sp(i);return(0,V.jsx)(gp,{scope:n,type:r,dir:D,scrollHideDelay:a,scrollArea:s,viewport:l,onViewportChange:u,content:d,onContentChange:f,scrollbarX:p,onScrollbarXChange:m,scrollbarXEnabled:S,onScrollbarXEnabledChange:C,scrollbarY:h,onScrollbarYChange:g,scrollbarYEnabled:w,onScrollbarYEnabledChange:T,onCornerWidthChange:y,onCornerHeightChange:x,children:(0,V.jsx)(wi.div,{dir:D,...o,ref:E,style:{position:`relative`,"--radix-scroll-area-corner-width":v+`px`,"--radix-scroll-area-corner-height":b+`px`,...e.style}})})},`ScrollArea`)),yp=`ScrollAreaViewport`,bp=_.forwardRef(Q(function(e,t){let{__scopeScrollArea:n,children:r,nonce:i,...a}=e,o=_p(yp,n),s=gr(t,_.useRef(null),o.onViewportChange);return(0,V.jsxs)(V.Fragment,{children:[(0,V.jsx)(xp,{nonce:i}),(0,V.jsx)(wi.div,{"data-radix-scroll-area-viewport":``,...a,ref:s,style:{overflowX:o.scrollbarXEnabled?`scroll`:`hidden`,overflowY:o.scrollbarYEnabled?`scroll`:`hidden`,...e.style},children:(0,V.jsx)(`div`,{ref:o.onContentChange,style:{minWidth:`100%`,display:`table`},children:r})})]})},`ScrollAreaViewport`)),xp=_.memo(Q(function({nonce:e}){return(0,V.jsx)(`style`,{dangerouslySetInnerHTML:{__html:`[data-radix-scroll-area-viewport]{scrollbar-width:none;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;}[data-radix-scroll-area-viewport]::-webkit-scrollbar{display:none}`},nonce:e})},`ScrollAreaViewportStyle`),(e,t)=>e.nonce===t.nonce),Sp=`ScrollAreaScrollbar`,Cp=_.forwardRef(Q(function(e,t){let{forceMount:n,...r}=e,i=_p(Sp,e.__scopeScrollArea),{onScrollbarXEnabledChange:a,onScrollbarYEnabledChange:o}=i,s=e.orientation===`horizontal`;return _.useEffect(()=>(s?a(!0):o(!0),()=>{s?a(!1):o(!1)}),[s,a,o]),i.type===`hover`?(0,V.jsx)(wp,{...r,ref:t,forceMount:n}):i.type===`scroll`?(0,V.jsx)(Tp,{...r,ref:t,forceMount:n}):i.type===`auto`?(0,V.jsx)(Ep,{...r,ref:t,forceMount:n}):i.type===`always`?(0,V.jsx)(Dp,{...r,ref:t,"data-state":`visible`}):null},`ScrollAreaScrollbar`)),wp=_.forwardRef(Q(function(e,t){let{forceMount:n,...r}=e,i=_p(Sp,e.__scopeScrollArea),[a,o]=_.useState(!1);return _.useEffect(()=>{let e=i.scrollArea,t=0;if(e){let n=Q(()=>{window.clearTimeout(t),o(!0)},`handlePointerEnter`),r=Q(()=>{t=window.setTimeout(()=>o(!1),i.scrollHideDelay)},`handlePointerLeave`);return e.addEventListener(`pointerenter`,n),e.addEventListener(`pointerleave`,r),()=>{window.clearTimeout(t),e.removeEventListener(`pointerenter`,n),e.removeEventListener(`pointerleave`,r)}}},[i.scrollArea,i.scrollHideDelay]),(0,V.jsx)(gi,{present:n||a,children:(0,V.jsx)(Ep,{"data-state":a?`visible`:`hidden`,...r,ref:t})})},`ScrollAreaScrollbarHover`)),Tp=_.forwardRef(Q(function(e,t){let{forceMount:n,...r}=e,i=_p(Sp,e.__scopeScrollArea),a=e.orientation===`horizontal`,o=qp(()=>c(`SCROLL_END`),100),[s,c]=fp(`hidden`,{hidden:{SCROLL:`scrolling`},scrolling:{SCROLL_END:`idle`,POINTER_ENTER:`interacting`},interacting:{SCROLL:`interacting`,POINTER_LEAVE:`idle`},idle:{HIDE:`hidden`,SCROLL:`scrolling`,POINTER_ENTER:`interacting`}});return _.useEffect(()=>{if(s===`idle`){let e=window.setTimeout(()=>c(`HIDE`),i.scrollHideDelay);return()=>window.clearTimeout(e)}},[s,i.scrollHideDelay,c]),_.useEffect(()=>{let e=i.viewport,t=a?`scrollLeft`:`scrollTop`;if(e){let n=e[t],r=Q(()=>{let r=e[t];n!==r&&(c(`SCROLL`),o()),n=r},`handleScroll`);return e.addEventListener(`scroll`,r),()=>e.removeEventListener(`scroll`,r)}},[i.viewport,a,c,o]),(0,V.jsx)(gi,{present:n||s!==`hidden`,children:(0,V.jsx)(Dp,{"data-state":s===`hidden`?`hidden`:`visible`,...r,ref:t,onPointerEnter:Gr(e.onPointerEnter,()=>c(`POINTER_ENTER`)),onPointerLeave:Gr(e.onPointerLeave,()=>c(`POINTER_LEAVE`))})})},`ScrollAreaScrollbarScroll`)),Ep=_.forwardRef(Q(function(e,t){let n=_p(Sp,e.__scopeScrollArea),{forceMount:r,...i}=e,[a,o]=_.useState(!1),s=e.orientation===`horizontal`,c=qp(()=>{if(n.viewport){let e=n.viewport.offsetWidth<n.viewport.scrollWidth,t=n.viewport.offsetHeight<n.viewport.scrollHeight;o(s?e:t)}},10);return Jp(n.viewport,c),Jp(n.content,c),(0,V.jsx)(gi,{present:r||a,children:(0,V.jsx)(Dp,{"data-state":a?`visible`:`hidden`,...i,ref:t})})},`ScrollAreaScrollbarAuto`)),Dp=_.forwardRef(Q(function(e,t){let{orientation:n=`vertical`,...r}=e,i=_p(Sp,e.__scopeScrollArea),a=_.useRef(null),o=_.useRef(0),[s,c]=_.useState({content:0,viewport:0,scrollbar:{size:0,paddingStart:0,paddingEnd:0}}),l=Bp(s.viewport,s.content),u={...r,sizes:s,onSizesChange:c,hasThumb:l>0&&l<1,onThumbChange:Q(e=>a.current=e,`onThumbChange`),onThumbPointerUp:Q(()=>o.current=0,`onThumbPointerUp`),onThumbPointerDown:Q(e=>o.current=e,`onThumbPointerDown`)};function d(e,t){return Hp(e,o.current,s,t)}return Q(d,`getScrollPosition`),n===`horizontal`?(0,V.jsx)(Op,{...u,ref:t,onThumbPositionChange:()=>{if(i.viewport&&a.current){let e=i.viewport.scrollLeft,t=Up(e,s,i.dir);a.current.style.transform=`translate3d(${t}px, 0, 0)`}},onWheelScroll:e=>{i.viewport&&(i.viewport.scrollLeft=e)},onDragScroll:e=>{i.viewport&&(i.viewport.scrollLeft=d(e,i.dir))}}):n===`vertical`?(0,V.jsx)(kp,{...u,ref:t,onThumbPositionChange:()=>{if(i.viewport&&a.current){let e=i.viewport.scrollTop,t=Up(e,s);a.current.style.transform=`translate3d(0, ${t}px, 0)`}},onWheelScroll:e=>{i.viewport&&(i.viewport.scrollTop=e)},onDragScroll:e=>{i.viewport&&(i.viewport.scrollTop=d(e))}}):null},`ScrollAreaScrollbarVisible`)),Op=_.forwardRef(Q(function(e,t){let{sizes:n,onSizesChange:r,...i}=e,a=_p(Sp,e.__scopeScrollArea),[o,s]=_.useState(),c=_.useRef(null),l=gr(t,c,a.onScrollbarXChange);return _.useEffect(()=>{c.current&&s(getComputedStyle(c.current))},[c]),(0,V.jsx)(Mp,{"data-orientation":`horizontal`,...i,ref:l,sizes:n,style:{bottom:0,left:a.dir===`rtl`?`var(--radix-scroll-area-corner-width)`:0,right:a.dir===`ltr`?`var(--radix-scroll-area-corner-width)`:0,"--radix-scroll-area-thumb-width":Vp(n)+`px`,...e.style},onThumbPointerDown:t=>e.onThumbPointerDown(t.x),onDragScroll:t=>e.onDragScroll(t.x),onWheelScroll:(t,n)=>{if(a.viewport){let r=a.viewport.scrollLeft+t.deltaX;e.onWheelScroll(r),Gp(r,n)&&t.preventDefault()}},onResize:()=>{c.current&&a.viewport&&o&&r({content:a.viewport.scrollWidth,viewport:a.viewport.offsetWidth,scrollbar:{size:c.current.clientWidth,paddingStart:zp(o.paddingLeft),paddingEnd:zp(o.paddingRight)}})}})},`ScrollAreaScrollbarX`)),kp=_.forwardRef(Q(function(e,t){let{sizes:n,onSizesChange:r,...i}=e,a=_p(Sp,e.__scopeScrollArea),[o,s]=_.useState(),c=_.useRef(null),l=gr(t,c,a.onScrollbarYChange);return _.useEffect(()=>{c.current&&s(getComputedStyle(c.current))},[c]),(0,V.jsx)(Mp,{"data-orientation":`vertical`,...i,ref:l,sizes:n,style:{top:0,right:a.dir===`ltr`?0:void 0,left:a.dir===`rtl`?0:void 0,bottom:`var(--radix-scroll-area-corner-height)`,"--radix-scroll-area-thumb-height":Vp(n)+`px`,...e.style},onThumbPointerDown:t=>e.onThumbPointerDown(t.y),onDragScroll:t=>e.onDragScroll(t.y),onWheelScroll:(t,n)=>{if(a.viewport){let r=a.viewport.scrollTop+t.deltaY;e.onWheelScroll(r),Gp(r,n)&&t.preventDefault()}},onResize:()=>{c.current&&a.viewport&&o&&r({content:a.viewport.scrollHeight,viewport:a.viewport.offsetHeight,scrollbar:{size:c.current.clientHeight,paddingStart:zp(o.paddingTop),paddingEnd:zp(o.paddingBottom)}})}})},`ScrollAreaScrollbarY`)),[Ap,jp]=mp(Sp),Mp=_.forwardRef(Q(function(e,t){let{__scopeScrollArea:n,sizes:r,hasThumb:i,onThumbChange:a,onThumbPointerUp:o,onThumbPointerDown:s,onThumbPositionChange:c,onDragScroll:l,onWheelScroll:u,onResize:d,...f}=e,p=_p(Sp,n),[m,h]=_.useState(null),g=gr(t,h),v=_.useRef(null),y=_.useRef(``),b=p.viewport,x=r.content-r.viewport,S=Zi(u),C=Zi(c),w=qp(d,10);function T(e){if(v.current){let t=e.clientX-v.current.left,n=e.clientY-v.current.top;l({x:t,y:n})}}return Q(T,`handleDragScroll`),_.useEffect(()=>{let e=Q(e=>{let t=e.target;m?.contains(t)&&S(e,x)},`handleWheel`);return document.addEventListener(`wheel`,e,{passive:!1}),()=>document.removeEventListener(`wheel`,e,{passive:!1})},[b,m,x,S]),_.useEffect(C,[r,C]),Jp(m,w),Jp(p.content,w),(0,V.jsx)(Ap,{scope:n,scrollbar:m,hasThumb:i,onThumbChange:Zi(a),onThumbPointerUp:Zi(o),onThumbPositionChange:C,onThumbPointerDown:Zi(s),children:(0,V.jsx)(wi.div,{...f,ref:g,style:{position:`absolute`,...f.style},onPointerDown:Gr(e.onPointerDown,e=>{e.button===0&&(e.target.setPointerCapture(e.pointerId),v.current=m.getBoundingClientRect(),y.current=document.body.style.webkitUserSelect,document.body.style.webkitUserSelect=`none`,p.viewport&&(p.viewport.style.scrollBehavior=`auto`),T(e))}),onPointerMove:Gr(e.onPointerMove,T),onPointerUp:Gr(e.onPointerUp,e=>{let t=e.target;t.hasPointerCapture(e.pointerId)&&t.releasePointerCapture(e.pointerId),document.body.style.webkitUserSelect=y.current,p.viewport&&(p.viewport.style.scrollBehavior=``),v.current=null})})})},`ScrollAreaScrollbarImpl`)),Np=`ScrollAreaThumb`,Pp=_.forwardRef(Q(function(e,t){let{forceMount:n,...r}=e,i=jp(Np,e.__scopeScrollArea);return(0,V.jsx)(gi,{present:n||i.hasThumb,children:(0,V.jsx)(Fp,{ref:t,...r})})},`ScrollAreaThumb`)),Fp=_.forwardRef(Q(function(e,t){let{__scopeScrollArea:n,style:r,...i}=e,a=_p(Np,n),o=jp(Np,n),{onThumbPositionChange:s}=o,c=gr(t,o.onThumbChange),l=_.useRef(void 0),u=qp(()=>{l.current&&=(l.current(),void 0)},100);return _.useEffect(()=>{let e=a.viewport;if(e){let t=Q(()=>{if(u(),!l.current){let t=Kp(e,s);l.current=t,s()}},`handleScroll`);return s(),e.addEventListener(`scroll`,t),()=>e.removeEventListener(`scroll`,t)}},[a.viewport,u,s]),(0,V.jsx)(wi.div,{"data-state":o.hasThumb?`visible`:`hidden`,...i,ref:c,style:{width:`var(--radix-scroll-area-thumb-width)`,height:`var(--radix-scroll-area-thumb-height)`,...r},onPointerDownCapture:Gr(e.onPointerDownCapture,e=>{let t=e.target.getBoundingClientRect(),n=e.clientX-t.left,r=e.clientY-t.top;o.onThumbPointerDown({x:n,y:r})}),onPointerUp:Gr(e.onPointerUp,o.onThumbPointerUp)})},`ScrollAreaThumbImpl`)),Ip=`ScrollAreaCorner`,Lp=_.forwardRef(Q(function(e,t){let n=_p(Ip,e.__scopeScrollArea),r=!!(n.scrollbarX&&n.scrollbarY);return n.type!==`scroll`&&r?(0,V.jsx)(Rp,{...e,ref:t}):null},`ScrollAreaCorner`)),Rp=_.forwardRef(Q(function(e,t){let{__scopeScrollArea:n,...r}=e,i=_p(Ip,n),[a,o]=_.useState(0),[s,c]=_.useState(0),l=!!(a&&s),{onCornerWidthChange:u,onCornerHeightChange:d}=i;return Jp(i.scrollbarX,()=>{let e=i.scrollbarX?.offsetHeight||0;i.onCornerHeightChange(e),c(e)}),Jp(i.scrollbarY,()=>{let e=i.scrollbarY?.offsetWidth||0;i.onCornerWidthChange(e),o(e)}),_.useEffect(()=>()=>{u(0),d(0)},[u,d]),l?(0,V.jsx)(wi.div,{...r,ref:t,style:{width:a,height:s,position:`absolute`,right:i.dir===`ltr`?0:void 0,left:i.dir===`rtl`?0:void 0,bottom:0,...e.style}}):null},`ScrollAreaCornerImpl`));function zp(e){return e?parseInt(e,10):0}Q(zp,`toInt`);function Bp(e,t){let n=e/t;return isNaN(n)?0:n}Q(Bp,`getThumbRatio`);function Vp(e){let t=Bp(e.viewport,e.content),n=e.scrollbar.paddingStart+e.scrollbar.paddingEnd,r=(e.scrollbar.size-n)*t;return Math.max(r,18)}Q(Vp,`getThumbSize`);function Hp(e,t,n,r=`ltr`){let i=Vp(n),a=i/2,o=t||a,s=i-o,c=n.scrollbar.paddingStart+o,l=n.scrollbar.size-n.scrollbar.paddingEnd-s,u=n.content-n.viewport,d=r===`ltr`?[0,u]:[u*-1,0];return Wp([c,l],d)(e)}Q(Hp,`getScrollPositionFromPointer`);function Up(e,t,n=`ltr`){let r=Vp(t),i=t.scrollbar.paddingStart+t.scrollbar.paddingEnd,a=t.scrollbar.size-i,o=t.content-t.viewport,s=a-r,c=up(e,n===`ltr`?[0,o]:[o*-1,0]);return Wp([0,o],[0,s])(c)}Q(Up,`getThumbOffsetFromScroll`);function Wp(e,t){return n=>{if(e[0]===e[1]||t[0]===t[1])return t[0];let r=(t[1]-t[0])/(e[1]-e[0]);return t[0]+r*(n-e[0])}}Q(Wp,`linearScale`);function Gp(e,t){return e>0&&e<t}Q(Gp,`isScrollingWithinScrollbarBounds`);var Kp=Q((e,t=()=>{})=>{let n={left:e.scrollLeft,top:e.scrollTop},r=0;return Q((function i(){let a={left:e.scrollLeft,top:e.scrollTop},o=n.left!==a.left,s=n.top!==a.top;(o||s)&&t(),n=a,r=window.requestAnimationFrame(i)}),`loop`)(),()=>window.cancelAnimationFrame(r)},`addUnlinkedScrollListener`);function qp(e,t){let n=Zi(e),r=_.useRef(0);return _.useEffect(()=>()=>window.clearTimeout(r.current),[]),_.useCallback(()=>{window.clearTimeout(r.current),r.current=window.setTimeout(n,t)},[n,t])}Q(qp,`useDebounceCallback`);function Jp(e,t){let n=Zi(t);Xr(()=>{let t=0;if(e){let r=new ResizeObserver(()=>{cancelAnimationFrame(t),t=window.requestAnimationFrame(n)});return r.observe(e),()=>{window.cancelAnimationFrame(t),r.unobserve(e)}}},[e,n])}Q(Jp,`useResizeObserver`);var Yp=vp,Xp=bp,Zp=Lp;function Qp({className:e,children:t,...n}){return(0,V.jsxs)(Yp,{"data-slot":`scroll-area`,className:B(`relative`,e),...n,children:[(0,V.jsx)(Xp,{"data-slot":`scroll-area-viewport`,className:`focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1`,children:t}),(0,V.jsx)($p,{}),(0,V.jsx)(Zp,{})]})}function $p({className:e,orientation:t=`vertical`,...n}){return(0,V.jsx)(Cp,{"data-slot":`scroll-area-scrollbar`,orientation:t,className:B(`flex touch-none p-px transition-colors select-none`,t===`vertical`&&`h-full w-2.5 border-l border-l-transparent`,t===`horizontal`&&`h-2.5 flex-col border-t border-t-transparent`,e),...n,children:(0,V.jsx)(Pp,{"data-slot":`scroll-area-thumb`,className:`bg-border relative flex-1 rounded-full`})})}function em({open:e=!1,profileId:t=``,onOpenChange:n}){let{t:r}=lr(),[i,a]=(0,_.useState)(!1),[o,s]=(0,_.useState)([]);(0,_.useEffect)(()=>{e&&t&&c(t)},[e,t]);async function c(e){a(!0),s([]);let t=await Wn(`/api/user-profile/changelog?profileId=${encodeURIComponent(e)}&limit=10`);a(!1),t.success&&t.data?s(t.data):s([])}return(0,V.jsx)(Os,{open:e,onOpenChange:n,children:(0,V.jsxs)(js,{className:`sm:max-w-lg`,children:[(0,V.jsx)(Ms,{children:(0,V.jsx)(Ps,{children:r(`modal-changelog-title`)})}),(0,V.jsx)(Qp,{className:`max-h-80`,children:i?(0,V.jsx)(`div`,{className:`text-sm text-muted-foreground py-6 text-center`,children:r(`loading-changelog`)}):o.length===0?(0,V.jsx)(`div`,{className:`text-sm text-muted-foreground py-6 text-center`,children:r(`empty-changelog`)}):(0,V.jsx)(`div`,{className:`space-y-3 pr-3`,children:o.map((e,t)=>(0,V.jsxs)(`div`,{className:`rounded-lg border border-border p-3 space-y-1`,children:[(0,V.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2 text-xs`,children:[(0,V.jsxs)(`span`,{className:`font-medium`,children:[`v`,e.version]}),(0,V.jsx)(`span`,{className:`text-muted-foreground`,children:e.changeType}),(0,V.jsx)(`span`,{className:`text-muted-foreground ml-auto`,children:Y(e.createdAt)})]}),(0,V.jsx)(`p`,{className:`text-sm`,children:e.changeSummary})]},`${e.version}-${t}`))})})]})})}function tm({className:e,type:t,...n}){return(0,V.jsx)(`input`,{type:t,"data-slot":`input`,className:B(`border-input file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 flex h-8 w-full min-w-0 rounded-lg border bg-transparent px-2.5 py-1 text-sm shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50`,`focus-visible:border-ring focus-visible:ring-ring/30 focus-visible:ring-3`,`aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive`,e),...n})}function nm({open:e=!1,type:t=null,index:n=0,action:r=`edit`,item:i=null,onOpenChange:a,onSaved:o}){let{t:s}=lr(),[c,l]=(0,_.useState)(``),[u,d]=(0,_.useState)(``),[f,p]=(0,_.useState)([``]),[m,h]=(0,_.useState)(`1`),[g,v]=(0,_.useState)(!1),y=r===`edit`,b=t===`workflows`;(0,_.useEffect)(()=>{e&&i&&(l(i.category||``),d(i.description||``),p(i.steps?.length?[...i.steps]:[``]),h(`1`))},[e,i]);let x=y?s(`btn-edit`)||`Edit Item`:m===`2`?s(`confirm-delete-title`)||`Confirm Delete`:s(`confirm-delete`)||`Delete Item?`;function S(e){a?.(e)}function C(){p(e=>[...e,``])}function w(e){p(t=>{let n=t.filter((t,n)=>n!==e);return n.length===0?[``]:n})}function T(e,t){p(n=>n.map((n,r)=>r===e?t:n))}async function E(e){if(e.preventDefault(),!t)return;if(r===`delete`){if(m===`1`){h(`2`);return}v(!0);let e=await Wn(`/api/user-profile/item`,{method:`PATCH`,headers:{"Content-Type":`application/json`},body:JSON.stringify({type:t,index:n,action:`delete`})});v(!1),e.success?(H.success(s(`toast-delete-success`)||`Item deleted`),S(!1),o?.()):H.error(e.error||s(`toast-delete-failed`)||`Delete failed`);return}v(!0);let i={type:t,index:n,action:`edit`,category:b?void 0:c,description:u};t===`workflows`&&(i.steps=f.map(e=>e.trim()).filter(Boolean));let a=await Wn(`/api/user-profile/item`,{method:`PATCH`,headers:{"Content-Type":`application/json`},body:JSON.stringify(i)});v(!1),a.success?(H.success(s(`toast-update-success`)||`Item updated`),S(!1),o?.()):H.error(a.error||s(`toast-update-failed`)||`Update failed`)}return(0,V.jsx)(Os,{open:e,onOpenChange:S,children:(0,V.jsxs)(js,{className:`sm:max-w-lg`,children:[(0,V.jsx)(Ms,{children:(0,V.jsx)(Ps,{children:x})}),(0,V.jsxs)(`form`,{className:`space-y-4`,onSubmit:E,children:[y||m===`1`?(0,V.jsxs)(V.Fragment,{children:[b?null:(0,V.jsxs)(`div`,{className:`space-y-2`,children:[(0,V.jsx)(Nl,{htmlFor:`profile-item-category`,children:s(`label-category`)}),(0,V.jsx)(tm,{id:`profile-item-category`,value:c,onChange:e=>l(e.target.value),disabled:!y})]}),(0,V.jsxs)(`div`,{className:`space-y-2`,children:[(0,V.jsx)(Nl,{htmlFor:`profile-item-description`,children:s(`label-description`)}),(0,V.jsx)(Pl,{id:`profile-item-description`,rows:4,value:u,onChange:e=>d(e.target.value),disabled:!y})]}),b&&y?(0,V.jsxs)(`div`,{className:`space-y-2`,children:[(0,V.jsx)(Nl,{children:s(`label-steps`)}),(0,V.jsx)(`div`,{className:`space-y-2`,children:f.map((e,t)=>(0,V.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,V.jsx)(`span`,{className:`text-xs text-muted-foreground w-5 tabular-nums`,children:t+1}),(0,V.jsx)(tm,{value:e,placeholder:`Step ${t+1}...`,onChange:e=>T(t,e.target.value)}),(0,V.jsx)(W,{type:`button`,variant:`ghost`,size:`icon-xs`,onClick:()=>w(t),children:`×`})]},t))}),(0,V.jsx)(W,{type:`button`,variant:`secondary`,size:`sm`,onClick:C,children:s(`btn-add-step`)})]}):null]}):null,(0,V.jsxs)(Ns,{children:[(0,V.jsx)(W,{type:`button`,variant:`secondary`,onClick:()=>S(!1),children:s(`btn-cancel`)}),(0,V.jsx)(W,{type:`submit`,variant:y?`default`:`destructive`,disabled:g,children:y?s(`btn-save`)||`Save`:s(`btn-delete`)||`Delete`})]})]})]})})}var rm=20;function im(e,t){let n=e.length,r=Math.max(1,Math.ceil(n/rm)),i=Math.min(t,r),a=(i-1)*rm;return{items:e.slice(a,a+rm),total:n,totalPages:r,page:i,start:a}}function am(e){return Math.round((e.confidence||0)*1e3)/10}function om(e){return e.evidence?Array.isArray(e.evidence)?e.evidence.join(`
122
- `):e.evidence:``}function sm(e){return e.evidence?Array.isArray(e.evidence)?e.evidence.length:1:0}function cm({profile:e,loading:t=!1,onRefresh:n,onCleanup:r}){let{t:i}=lr(),[a,o]=(0,_.useState)({pref:1,pat:1,wf:1}),[s,c]=(0,_.useState)(!1),[l,u]=(0,_.useState)(!1),[d,f]=(0,_.useState)(null),[p,m]=(0,_.useState)(0),[h,g]=(0,_.useState)(`edit`),[v,y]=(0,_.useState)(null),b=(0,_.useMemo)(()=>{if(!e?.exists||!e.profileData)return null;let t=e.profileData;if(typeof t==`string`)try{t=JSON.parse(t)}catch{return null}return t},[e]),x=(0,_.useMemo)(()=>Oc(b?.preferences),[b]),S=(0,_.useMemo)(()=>Oc(b?.patterns),[b]),C=(0,_.useMemo)(()=>Oc(b?.workflows),[b]),w=(0,_.useMemo)(()=>C.map((e,t)=>({item:e,index:t})).sort((e,t)=>(t.item.frequency||0)-(e.item.frequency||0)),[C]),T=im(x,a.pref),E=im(S,a.pat),D=im(w,a.wf),O=C.length;function te(e,t,n){let r=(e===`preferences`?x:e===`patterns`?S:C)[t];r&&(f(e),m(t),g(n),y(r),u(!0))}function re(e,t){return e.indexOf(t)}function ie({page:e,pageKey:t}){return e.total<=rm?null:(0,V.jsxs)(`div`,{className:`flex flex-wrap items-center gap-1.5 pt-2`,children:[(0,V.jsxs)(`span`,{className:`text-xs text-muted-foreground mr-2`,children:[e.start+1,`-`,Math.min(e.start+rm,e.total),` / `,e.total]}),Array.from({length:e.totalPages},(e,t)=>t+1).map(n=>(0,V.jsx)(W,{size:`xs`,variant:n===e.page?`default`:`outline`,onClick:()=>o(e=>({...e,[t]:n})),children:n},n))]})}function k({item:e,type:t,fullList:n}){let r=re(n,e),a=am(e);return(0,V.jsxs)(`div`,{className:`rounded-xl border border-border bg-card/50 p-3 space-y-2`,children:[(0,V.jsxs)(`div`,{className:`flex items-start gap-2`,children:[(0,V.jsx)(J,{variant:`outline`,children:e.category||`General`}),(0,V.jsxs)(`div`,{className:`flex items-center gap-0.5 ml-auto`,children:[(0,V.jsx)(W,{variant:`ghost`,size:`icon-xs`,title:i(`btn-edit`)||`Edit`,onClick:()=>te(t,r,`edit`),children:(0,V.jsx)(ge,{className:`size-3`})}),(0,V.jsx)(W,{variant:`ghost`,size:`icon-xs`,title:i(`btn-delete`)||`Delete`,onClick:()=>te(t,r,`delete`),children:(0,V.jsx)(Oe,{className:`size-3`})})]}),(0,V.jsxs)(`div`,{className:`size-9 rounded-full border border-border grid place-items-center text-[10px] tabular-nums shrink-0`,title:`${a}%`,children:[a,`%`]})]}),(0,V.jsx)(`p`,{className:`text-sm`,children:e.description||``}),e.evidence||e.frequency?(0,V.jsxs)(`div`,{className:`flex items-center gap-1.5 text-xs text-muted-foreground`,children:[(0,V.jsxs)(`span`,{className:`inline-flex items-center gap-1`,title:i(`label-evidence-tooltip`,{count:e.frequency||1}),children:[(0,V.jsx)(De,{className:`size-3`}),e.frequency||1]}),sm(e)>0?(0,V.jsxs)(V.Fragment,{children:[(0,V.jsx)(`span`,{children:`·`}),(0,V.jsxs)(`span`,{className:`inline-flex items-center gap-1`,title:om(e),children:[(0,V.jsx)(P,{className:`size-3`}),sm(e),` evidence`]})]}):null]}):null]})}return t&&!e?(0,V.jsx)(`div`,{className:`text-sm text-muted-foreground py-8 text-center`,children:i(`loading-profile`)}):e?.exists?b?(0,V.jsxs)(V.Fragment,{children:[(0,V.jsxs)(`div`,{className:`space-y-6`,children:[(0,V.jsxs)(`div`,{className:`space-y-2`,children:[(0,V.jsx)(`h3`,{className:`text-base font-medium`,children:e.displayName||e.userId}),(0,V.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,V.jsxs)(`span`,{className:`rounded-full bg-muted px-2.5 py-1 text-xs`,children:[(0,V.jsx)(`span`,{className:`text-muted-foreground`,children:i(`profile-version`)}),(0,V.jsx)(`span`,{className:`ml-1`,children:e.version})]}),(0,V.jsxs)(`span`,{className:`rounded-full bg-muted px-2.5 py-1 text-xs`,children:[(0,V.jsx)(`span`,{className:`text-muted-foreground`,children:i(`profile-prompts`)}),(0,V.jsx)(`span`,{className:`ml-1`,children:e.totalPromptsAnalyzed})]}),(0,V.jsxs)(`span`,{className:`rounded-full bg-muted px-2.5 py-1 text-xs`,children:[(0,V.jsx)(`span`,{className:`text-muted-foreground`,children:i(`profile-updated`)}),(0,V.jsx)(`span`,{className:`ml-1`,children:e.lastAnalyzedAt?Y(e.lastAnalyzedAt):`—`})]}),(0,V.jsxs)(`div`,{className:`ms-auto flex flex-wrap items-center gap-1.5`,children:[(0,V.jsxs)(W,{variant:`outline`,size:`sm`,onClick:()=>r?.(),children:[(0,V.jsx)(Te,{className:`size-3.5`}),i(`btn-ai-cleanup`)]}),(0,V.jsxs)(W,{variant:`secondary`,size:`sm`,onClick:()=>n?.(),children:[(0,V.jsx)(xe,{className:`size-3.5`}),i(`btn-refresh`)]}),(0,V.jsxs)(W,{variant:`secondary`,size:`sm`,onClick:()=>c(!0),children:[(0,V.jsx)(Se,{className:`size-3.5`}),`History`]})]})]})]}),(0,V.jsxs)(`div`,{className:`grid gap-6`,children:[(0,V.jsxs)(`section`,{id:`profile-preferences`,className:`scroll-mt-4 space-y-3`,children:[(0,V.jsxs)(`h4`,{className:`flex items-center gap-2 text-sm font-medium`,children:[(0,V.jsx)(N,{className:`size-4`}),i(`profile-preferences`),(0,V.jsx)(`span`,{className:`text-muted-foreground`,children:x.length})]}),x.length===0?(0,V.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:i(`empty-preferences`)}):(0,V.jsxs)(V.Fragment,{children:[(0,V.jsx)(`div`,{className:`grid gap-2 sm:grid-cols-2 lg:grid-cols-3`,children:T.items.map(e=>(0,V.jsx)(k,{item:e,type:`preferences`,fullList:x},re(x,e)))}),(0,V.jsx)(ie,{page:T,pageKey:`pref`})]})]}),(0,V.jsxs)(`section`,{id:`profile-patterns`,className:`scroll-mt-4 space-y-3`,children:[(0,V.jsxs)(`h4`,{className:`flex items-center gap-2 text-sm font-medium`,children:[(0,V.jsx)(ee,{className:`size-4`}),i(`profile-patterns`),(0,V.jsx)(`span`,{className:`text-muted-foreground`,children:S.length})]}),S.length===0?(0,V.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:i(`empty-patterns`)}):(0,V.jsxs)(V.Fragment,{children:[(0,V.jsx)(`div`,{className:`grid gap-2 sm:grid-cols-2 lg:grid-cols-3`,children:E.items.map(e=>(0,V.jsx)(k,{item:e,type:`patterns`,fullList:S},re(S,e)))}),(0,V.jsx)(ie,{page:E,pageKey:`pat`})]})]}),(0,V.jsxs)(`section`,{id:`profile-workflows`,className:`scroll-mt-4 space-y-3`,children:[(0,V.jsxs)(`h4`,{className:`flex items-center gap-2 text-sm font-medium`,children:[(0,V.jsx)(Ne,{className:`size-4`}),i(`profile-workflows`),(0,V.jsx)(`span`,{className:`text-muted-foreground`,children:O})]}),O===0?(0,V.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:i(`empty-workflows`)}):(0,V.jsxs)(V.Fragment,{children:[(0,V.jsx)(`div`,{className:`space-y-2`,children:D.items.map(e=>{let t=e.item,n=e.index,r=am(t);return(0,V.jsxs)(`div`,{className:`rounded-xl border border-border bg-card/50 p-3 space-y-2`,children:[(0,V.jsxs)(`div`,{className:`flex items-start gap-2`,children:[(0,V.jsx)(`div`,{className:`text-sm font-medium flex-1`,children:t.description||``}),(0,V.jsxs)(`div`,{className:`flex items-center gap-0.5`,children:[(0,V.jsx)(W,{variant:`ghost`,size:`icon-xs`,onClick:()=>te(`workflows`,n,`edit`),children:(0,V.jsx)(ge,{className:`size-3`})}),(0,V.jsx)(W,{variant:`ghost`,size:`icon-xs`,onClick:()=>te(`workflows`,n,`delete`),children:(0,V.jsx)(Oe,{className:`size-3`})})]}),(0,V.jsxs)(`div`,{className:`size-9 rounded-full border border-border grid place-items-center text-[10px] tabular-nums shrink-0`,children:[r,`%`]})]}),t.steps?.length?(0,V.jsx)(`div`,{className:`flex flex-wrap items-center gap-1.5`,children:t.steps.map((e,n)=>(0,V.jsxs)(`div`,{className:`contents`,children:[(0,V.jsxs)(`div`,{className:`inline-flex items-center gap-1.5 rounded-lg bg-muted px-2 py-1 text-xs`,children:[(0,V.jsx)(`span`,{className:`text-muted-foreground tabular-nums`,children:n+1}),(0,V.jsx)(`span`,{children:e})]}),n<(t.steps?.length||0)-1?(0,V.jsx)(ne,{className:`size-3 text-muted-foreground`}):null]},n))}):null,(0,V.jsxs)(`div`,{className:`flex items-center gap-1.5 text-xs text-muted-foreground`,children:[(0,V.jsxs)(`span`,{className:`inline-flex items-center gap-1`,title:i(`label-evidence-tooltip`,{count:t.frequency||1}),children:[(0,V.jsx)(De,{className:`size-3`}),t.frequency||1]}),sm(t)>0?(0,V.jsxs)(V.Fragment,{children:[(0,V.jsx)(`span`,{children:`·`}),(0,V.jsxs)(`span`,{className:`inline-flex items-center gap-1`,title:om(t),children:[(0,V.jsx)(P,{className:`size-3`}),sm(t),` evidence`]})]}):null]})]},e.index)})}),(0,V.jsx)(ie,{page:D,pageKey:`wf`})]})]})]})]}),(0,V.jsx)(em,{open:s,onOpenChange:c,profileId:e?.id||``}),(0,V.jsx)(nm,{open:l,onOpenChange:u,type:d,index:p,action:h,item:v,onSaved:n})]}):null:(0,V.jsxs)(`div`,{className:`flex flex-col items-center gap-2 py-10 text-muted-foreground`,children:[(0,V.jsx)(je,{className:`size-8`}),(0,V.jsx)(`p`,{className:`text-sm`,children:e?.message||i(`empty-preferences`)})]})}function lm({open:e=!1,count:t=0,onOpenChange:n,onComplete:r}){let{t:i}=lr(),[a,o]=(0,_.useState)(!1),[s,c]=(0,_.useState)(``),[l,u]=(0,_.useState)(0);(0,_.useEffect)(()=>{e&&!a&&(c(i(`migration-found-tags`,{count:t})),u(0))},[e,a,t,i]);function d(e){a&&!e||n?.(e)}async function f(){o(!0),c(i(`status-migration-init`)),u(0);let e=!0,t=0,n=1e3;for(;e&&t<n;){t++;let n=await Wn(`/api/migration/tags/run-batch`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({batchSize:3})});if(!n.success||!n.data){c(i(`toast-migration-failed`)+`: `+(n.error||``)),o(!1);return}let r=n.data.processed;e=n.data.hasMore;let a=n.data.total;u(a>0?Math.round(r/a*100):0),c(i(`status-migration-progress`,{current:r,total:a})),e&&await new Promise(e=>setTimeout(e,100))}if(t>=n){c(i(`migration-stopped`)),o(!1);return}u(100),c(i(`toast-migration-success`)),H.success(i(`toast-migration-success`)),setTimeout(()=>{o(!1),d(!1),r?.()},2e3)}return(0,V.jsx)(Os,{open:e,onOpenChange:d,children:(0,V.jsxs)(js,{className:`sm:max-w-md`,showCloseButton:!a,children:[(0,V.jsx)(Ms,{children:(0,V.jsx)(Ps,{children:i(`modal-migration-title`)})}),(0,V.jsxs)(`div`,{className:`space-y-3`,children:[(0,V.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:s}),(0,V.jsx)(`div`,{className:`h-2 rounded-full bg-muted overflow-hidden`,children:(0,V.jsx)(`div`,{className:`h-full bg-primary transition-all duration-200`,style:{width:`${l}%`}})}),(0,V.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:i(`migration-note`)})]}),a?null:(0,V.jsx)(Ns,{children:(0,V.jsxs)(W,{onClick:f,children:[(0,V.jsx)(ve,{className:`size-3.5`}),i(`btn-start-migration`)]})})]})})}async function $(e,t={}){let n=(t.method??`GET`).toUpperCase(),r=n!==`GET`&&n!==`HEAD`,i=await fetch(e,{...t,headers:{"x-omms-token":window.__OMMS_TOKEN__??``,...r||t.body?{"Content-Type":`application/json`}:{},...t.headers}}),a=await i.json();if(!i.ok)throw Error(a.error??`Request failed (${i.status})`);return a}var um=new Set,dm=0;function fm(e){dm++;for(let t of um)t(e)}function pm(){let e=dm;return{isCurrent:()=>dm===e}}async function mm(){try{let e=await $(`/api/settings`);return fm(e),e}catch{return null}}function hm(e){return um.add(e),()=>{um.delete(e)}}function gm(e,t){return`${e.replace(/\.+$/,``)}. ${t}`}var _m={Models:[`模型`,`النماذج`],"External API fallback":[`外部 API 备用模型`,`النموذج الاحتياطي عبر واجهة API الخارجية`],none:[`无`,`لا يوجد`],ready:[`就绪`,`جاهز`],"not ready":[`未就绪`,`غير جاهز`],"Credentials (values hidden)":[`凭据(不显示内容)`,`بيانات الاعتماد (القيم مخفية)`],set:[`已设置`,`مضبوط`],"not set":[`未设置`,`غير مضبوط`],"Effective model":[`当前使用模型`,`النموذج المستخدم`],session:[`会话`,`الجلسة`],"external API":[`外部 API`,`واجهة API الخارجية`],unavailable:[`不可用`,`غير متاح`],"Project override is active. Changes to the global file may not take effect here.":[`项目设置优先。全局文件的更改可能不会在此生效。`,`إعدادات المشروع لها الأولوية. قد لا تسري تغييرات الملف العام هنا.`],"Model choice":[`模型选择`,`اختيار النموذج`],"Session model":[`会话模型`,`نموذج الجلسة`],"Manual model":[`手动选择模型`,`اختيار النموذج يدوياً`],"Manual provider/model":[`手动输入提供商/模型`,`إدخال المزوّد/النموذج يدوياً`],"Model list unavailable. Enter provider/model manually.":[`模型列表不可用。请手动输入提供商/模型。`,`قائمة النماذج غير متاحة. أدخل المزوّد/النموذج يدوياً.`],"OpenCode model list unavailable":[`OpenCode 模型列表不可用`,`قائمة نماذج OpenCode غير متاحة`],"OMMS could not find OpenCode on this computer, so it cannot list OpenCode's models here. Type the model as provider/model, for example zai-coding-plan/glm-5.3. If OpenCode is installed, open an OpenCode session and reload this page.":[`OMMS 在这台电脑上找不到 OpenCode,因此无法在此列出 OpenCode 的模型。请按 提供商/模型 格式输入模型,例如 zai-coding-plan/glm-5.3。如果已安装 OpenCode,请打开一个 OpenCode 会话,然后重新加载此页面。`,`لم يعثر OMMS على OpenCode في هذا الحاسوب، لذا لا يمكنه عرض نماذج OpenCode هنا. أدخل النموذج بصيغة المزوّد/النموذج، مثل zai-coding-plan/glm-5.3. إذا كان OpenCode مثبتاً، فافتح جلسة OpenCode ثم أعد تحميل هذه الصفحة.`],"OpenCode took too long to send its model list. Reload this page to try again, or type the model as provider/model.":[`OpenCode 发送模型列表的时间过长。请重新加载此页面重试,或按 提供商/模型 格式输入模型。`,`استغرق OpenCode وقتاً طويلاً لإرسال قائمة نماذجه. أعد تحميل هذه الصفحة للمحاولة مرة أخرى، أو أدخل النموذج بصيغة المزوّد/النموذج.`],"OpenCode has no signed-in models. Run `opencode auth login`, then reload this page.":["OpenCode 没有已登录的模型。请运行 `opencode auth login`,然后重新加载此页面。","لا توجد في OpenCode نماذج مسجَّل الدخول إليها. شغّل `opencode auth login` ثم أعد تحميل هذه الصفحة."],"This OpenCode version sent a model list OMMS cannot read. Type the model as provider/model. Update OMMS if this continues.":[`此版本的 OpenCode 发送的模型列表 OMMS 无法读取。请按 提供商/模型 格式输入模型。如果问题持续,请更新 OMMS。`,`أرسل هذا الإصدار من OpenCode قائمة نماذج لا يستطيع OMMS قراءتها. أدخل النموذج بصيغة المزوّد/النموذج. حدّث OMMS إذا استمرت المشكلة.`],"OMMS could not read Pi's model list. Type the model as provider/model.":[`OMMS 无法读取 Pi 的模型列表。请按 提供商/模型 格式输入模型。`,`تعذّر على OMMS قراءة قائمة نماذج Pi. أدخل النموذج بصيغة المزوّد/النموذج.`],"Pi has no signed-in models. Sign in to a provider in Pi, then reload this page.":[`Pi 没有已登录的模型。请在 Pi 中登录一个提供商,然后重新加载此页面。`,`لا توجد في Pi نماذج مسجَّل الدخول إليها. سجّل الدخول إلى مزوّد في Pi ثم أعد تحميل هذه الصفحة.`],"Save model":[`保存模型`,`حفظ النموذج`],"Enter a model as provider/model.":[`按 提供商/模型 格式输入。`,`أدخل النموذج بصيغة المزوّد/النموذج.`],"Saved. New capture and profile work uses these settings.":[`已保存。下一次捕获和用户画像将使用这些设置。`,`تم الحفظ. ستستخدم عمليات الالتقاط والملف الشخصي الجديدة هذه الإعدادات.`],"Saved. OMMS now reads ~/.config/omms/omms.jsonc. The legacy config was kept.":[`已保存。OMMS 现在读取 ~/.config/omms/omms.jsonc,旧配置保留。`,`تم الحفظ. يقرأ OMMS الآن الملف ~/.config/omms/omms.jsonc مع الاحتفاظ بالإعدادات القديمة.`],"Current settings were reloaded; check the values and save again.":[`已重新加载当前设置;检查数值后再次保存。`,`أُعيد تحميل الإعدادات الحالية. راجع القيم ثم احفظ مجدداً.`],"Capture diagnostics":[`捕获诊断`,`تشخيص الالتقاط`],"Time range":[`时间范围`,`الفترة الزمنية`],"24 hours":[`24 小时`,`24 ساعة`],"7 days":[`7 天`,`7 أيام`],"30 days":[`30 天`,`30 يوماً`],"90 days":[`90 天`,`90 يوماً`],"Outcomes by model":[`各模型结果`,`النتائج حسب النموذج`],"Host / model":[`主机 / 模型`,`المضيف / النموذج`],Saved:[`已保存`,`محفوظ`],Skipped:[`已跳过`,`متجاوز`],Failed:[`失败`,`فشل`],Total:[`总数`,`المجموع`],"Failure reasons":[`失败原因`,`أسباب الفشل`],"Recent attempts":[`最近尝试`,`المحاولات الأخيرة`],Time:[`时间`,`الوقت`],Host:[`主机`,`المضيف`],Source:[`来源`,`المصدر`],Session:[`会话`,`الجلسة`],Path:[`路径`,`المسار`],Model:[`模型`,`النموذج`],Stop:[`结束原因`,`سبب التوقف`],Blocks:[`区块`,`الكتل`],Prompt:[`提示词长度`,`طول الطلب`],Reply:[`回复长度`,`طول الرد`],Duration:[`耗时`,`المدة`],Outcome:[`结果`,`النتيجة`],Reason:[`原因`,`السبب`],"Save capture traces":[`保存捕获追踪`,`حفظ تتبعات الالتقاط`],"Traces can contain conversation content after redaction. Keep tracing off unless you need it for debugging.":[`追踪文件在脱敏后仍可能包含对话内容。仅在调试时开启。`,`قد تحتوي التتبعات على محتوى المحادثة بعد التنقيح. فعّلها عند التصحيح فقط.`],"This project turns tracing off. The global switch cannot turn it on here.":[`此项目已关闭追踪。全局开关无法在此开启。`,`أوقف هذا المشروع التتبع. لا يمكن للمفتاح العام تفعيله هنا.`],"Trace retention (days)":[`追踪保留天数`,`مدة حفظ التتبعات (بالأيام)`],"Attempt retention (days)":[`尝试记录保留天数`,`مدة حفظ المحاولات (بالأيام)`],"Retry retention (hours)":[`重试保留小时数`,`مدة حفظ إعادة المحاولة (بالساعات)`],"When the capture model cannot be reached, OMMS keeps the turn and tries again later. Queued turns can hold conversation content after redaction. 0 turns the queue off and deletes waiting turns.":[`捕获模型无法访问时,OMMS 会保留该轮对话并稍后重试。排队的对话在脱敏后仍可能包含对话内容。设为 0 会关闭队列并删除等待中的对话。`,`عندما يتعذر الوصول إلى نموذج الالتقاط، يحتفظ OMMS بالجولة ويعيد المحاولة لاحقاً. قد تحتوي الجولات المنتظرة على محتوى المحادثة بعد التنقيح. القيمة 0 توقف قائمة الانتظار وتحذف الجولات المنتظرة.`],"Turns waiting for retry":[`等待重试的对话`,`الجولات المنتظرة لإعادة المحاولة`],"Retry now":[`立即重试`,`أعد المحاولة الآن`],"Retrying now.":[`正在重试。`,`تجري إعادة المحاولة الآن.`],"A retry is already running.":[`重试已在运行。`,`إعادة المحاولة قيد التشغيل بالفعل.`],"These turns retry at the next Pi session start.":[`这些对话将在下次启动 Pi 会话时重试。`,`ستُعاد محاولة هذه الجولات عند بدء جلسة Pi التالية.`],"These turns retry at the next OpenCode session start.":[`这些对话将在下次启动 OpenCode 会话时重试。`,`ستُعاد محاولة هذه الجولات عند بدء جلسة OpenCode التالية.`],"These turns retry at the next Claude Code session start.":[`这些对话将在下次启动 Claude Code 会话时重试。`,`ستُعاد محاولة هذه الجولات عند بدء جلسة Claude Code التالية.`],"Claude Code capture uses the external API.":[`Claude Code 捕获使用外部 API。`,`يستخدم التقاط Claude Code واجهة API الخارجية.`],"Claude Code capture is off. Complete the external API settings.":[`Claude Code 捕获已关闭。请完成外部 API 设置。`,`التقاط Claude Code متوقف. أكمل إعدادات واجهة API الخارجية.`],"Missing settings":[`缺少的设置`,`الإعدادات الناقصة`],"memoryModel is not configured":[`未配置 memoryModel`,`لم يُضبط memoryModel`],"memoryApiUrl is not configured":[`未配置 memoryApiUrl`,`لم يُضبط memoryApiUrl`],"memoryApiKey is not configured":[`未配置 memoryApiKey`,`لم يُضبط memoryApiKey`],"memoryApiKey contains a placeholder value":[`memoryApiKey 包含占位值`,`يحتوي memoryApiKey على قيمة نائبة`],"Claude Code backfill always uses the external API. It has no backfill model setting.":[`Claude Code 回填始终使用外部 API,没有回填模型设置。`,`يستخدم استيراد Claude Code دائماً واجهة API الخارجية، ولا يوجد له إعداد لنموذج الاستيراد.`],"Claude Code transcripts folder":[`Claude Code 对话记录文件夹`,`مجلد سجلات محادثات Claude Code`],"Claude Code transcripts":[`Claude Code 对话记录`,`سجلات محادثات Claude Code`],found:[`已找到`,`موجود`],"not found":[`未找到`,`غير موجود`],"Claude Code imports always use the external API.":[`Claude Code 导入始终使用外部 API。`,`يستخدم استيراد Claude Code دائماً واجهة API الخارجية.`],"Claude Code imports use the external API. Complete the external API settings.":[`Claude Code 导入使用外部 API。请完成外部 API 设置。`,`يستخدم استيراد Claude Code واجهة API الخارجية. أكمل إعدادات واجهة API الخارجية.`],"Trace files":[`追踪文件`,`ملفات التتبع`],View:[`查看`,`عرض`],Delete:[`删除`,`حذف`],Health:[`健康检查`,`فحص الحالة`],"Config files":[`配置文件`,`ملفات الإعدادات`],"Memory store":[`记忆存储`,`مخزن الذاكرة`],Embedding:[`嵌入模型`,`نموذج التضمين`],"Web binding":[`网页服务绑定`,`ربط خادم الويب`],"OpenCode model":[`OpenCode 模型`,`نموذج OpenCode`],"Pi model":[`Pi 模型`,`نموذج Pi`],"Capture failures (24 hours)":[`捕获失败(24 小时)`,`فشل الالتقاط (24 ساعة)`],"OpenCode model test":[`OpenCode 模型测试`,`اختبار نموذج OpenCode`],"Pi model test":[`Pi 模型测试`,`اختبار نموذج Pi`],"Run checks":[`运行检查`,`تشغيل الفحوصات`],"Run checks and test models":[`运行检查并测试模型`,`تشغيل الفحوصات واختبار النماذج`],"Checking…":[`正在检查…`,`جارٍ الفحص…`],pass:[`通过`,`نجاح`],warn:[`警告`,`تحذير`],fail:[`失败`,`فشل`],"Import and backfill":[`导入和回填`,`الاستيراد والاستكمال`],"Automatic import":[`自动导入`,`الاستيراد التلقائي`],"Automatic import makes model calls. Changes apply at the next host start. Turning it off stops a running import after the current exchange.":[`自动导入会调用模型。更改在下次启动主机时生效。关闭后,正在运行的导入将在当前轮次结束后停止。`,`يستدعي الاستيراد التلقائي النموذج. تسري التغييرات عند بدء المضيف التالي. يوقف التعطيل الاستيراد بعد التبادل الحالي.`],"Import past chats automatically":[`自动导入过去的对话`,`استيراد المحادثات السابقة تلقائياً`],"Backfill model":[`历史导入模型`,`نموذج استيراد السجل`],"Same as live capture":[`与实时捕获相同`,`مثل الالتقاط المباشر`],"Saved. Changes apply at the next host start.":[`已保存。更改在下次启动主机时生效。`,`تم الحفظ. تسري التغييرات عند بدء المضيف التالي.`],State:[`状态`,`الحالة`],"not started":[`尚未开始`,`لم يبدأ`],"not-started":[`尚未开始`,`لم يبدأ`],Imported:[`已导入`,`مستورَد`],Pending:[`待处理`,`معلّق`],"Unresolved sessions":[`目录未解析的会话`,`جلسات بمجلدات غير محددة`],Cutoff:[`截止时间`,`وقت القطع`],stopped:[`已停止`,`توقف`],"Web app":[`网页应用`,`تطبيق الويب`],"Start web app at login":[`登录时启动网页应用`,`بدء تطبيق الويب عند تسجيل الدخول`],"Login item":[`登录启动项`,`عنصر بدء تسجيل الدخول`],"not installed":[`未安装`,`غير مثبّت`],"not-installed":[`未安装`,`غير مثبّت`],installed:[`已安装`,`مثبّت`],unsupported:[`不受支持`,`غير مدعوم`],"no-runtime":[`缺少运行环境`,`بيئة التشغيل غير متاحة`],"no-package":[`缺少软件包`,`الحزمة غير متاحة`],"Login items are unsupported on this platform.":[`此平台不支持登录启动项。`,`عناصر بدء تسجيل الدخول غير مدعومة على هذا النظام.`],"Install Node or Bun to start the web app at login.":[`安装 Node 或 Bun 后,网页应用才能在登录时启动。`,`ثبّت Node أو Bun لبدء تطبيق الويب عند تسجيل الدخول.`],"Use these commands to apply the change now:":[`使用以下命令立即应用更改:`,`استخدم هذه الأوامر لتطبيق التغيير الآن:`],"Saved. The login item changes at the next Pi or OpenCode start.":[`已保存。登录启动项将在下次启动 Pi 或 OpenCode 时更新。`,`تم الحفظ. يتغير عنصر بدء التشغيل عند بدء Pi أو OpenCode التالي.`],"History host":[`历史记录主机`,`مضيف السجل`],Scope:[`范围`,`النطاق`],"Current project":[`当前项目`,`المشروع الحالي`],"All projects":[`所有项目`,`كل المشاريع`],"Project directory":[`项目目录`,`مجلد المشروع`],"Current directory":[`当前目录`,`المجلد الحالي`],"Profile batch size":[`用户画像批量大小`,`حجم دفعة الملف الشخصي`],"Directory maps (old=new, one per line)":[`目录映射(旧=新,每行一条)`,`تعيين المجلدات (قديم=جديد، واحد في كل سطر)`],"Force reimport":[`强制重新导入`,`فرض إعادة الاستيراد`],"Skip memories":[`跳过记忆`,`تجاوز الذكريات`],"Skip profile":[`跳过用户画像`,`تجاوز الملف الشخصي`],"Import model":[`导入模型`,`نموذج الاستيراد`],"Saved external API":[`已保存的外部 API`,`واجهة API الخارجية المحفوظة`],"Preview (dry run)":[`预览(不写入)`,`معاينة (تشغيل تجريبي)`],"Start import":[`开始导入`,`بدء الاستيراد`],"Cancel after current unit":[`完成当前单元后取消`,`الإلغاء بعد الوحدة الحالية`],"Directory maps must be old=new, one per line":[`目录映射须为 旧=新,每行一条`,`يجب أن يكون تعيين المجلدات بصيغة قديم=جديد، واحد في كل سطر`],running:[`运行中`,`جارٍ التشغيل`],cancelling:[`正在取消`,`جارٍ الإلغاء`],cancelled:[`已取消`,`أُلغي`],done:[`已完成`,`اكتمل`],failed:[`失败`,`فشل`],units:[`单元`,`وحدات`],"List sessions":[`列出会话`,`عرض الجلسات`],"Refresh list":[`刷新列表`,`تحديث القائمة`],"Advanced options":[`高级选项`,`خيارات متقدمة`],"Hide advanced options":[`隐藏高级选项`,`إخفاء الخيارات المتقدمة`],"default location":[`默认位置`,`الموقع الافتراضي`],"Prompt date from":[`提示日期起`,`تاريخ الطلب من`],"Prompt date to":[`提示日期止`,`تاريخ الطلب إلى`],"Prompt dates are inclusive, use your time zone, and filter the turns inside each session, not the list. Empty dates include every turn.":[`提示日期包含首尾两天,按你所在时区计算,只筛选每个会话中的对话轮次,不筛选列表。留空则包含所有轮次。`,`تواريخ الطلب شاملة لليومين، وتُحسب بمنطقتك الزمنية، وتُصفّي الأدوار داخل كل جلسة لا القائمة. تركها فارغة يشمل كل الأدوار.`],"Sessions with directories that no longer exist":[`目录已不存在的会话`,`جلسات لم تعد مجلداتها موجودة`],"Show them and add a directory map":[`显示它们并添加目录映射`,`اعرضها وأضف تعيين مجلد`],Selected:[`已选择`,`المحدد`],"Select all matching":[`选择所有匹配项`,`تحديد كل المطابق`],"Clear selection":[`清除选择`,`مسح التحديد`],Select:[`选择`,`تحديد`],Created:[`创建时间`,`تاريخ الإنشاء`],"Resolved by":[`解析方式`,`طريقة التحديد`],recorded:[`记录的目录`,`المجلد المسجّل`],mapped:[`目录映射`,`تعيين مجلد`],"project root":[`项目根目录`,`جذر المشروع`],missing:[`缺失`,`مفقود`],"No sessions match.":[`没有匹配的会话。`,`لا توجد جلسات مطابقة.`],Previous:[`上一页`,`السابق`],Next:[`下一页`,`التالي`],None:[`无`,`لا شيء`],"Configured, not tested.":[`已配置,未测试。`,`مُعدّ، لم يُختبر.`],"An import with an OpenCode signed-in model runs from the terminal or with /import in OpenCode.":[`使用 OpenCode 已登录模型的导入需在终端运行,或在 OpenCode 中使用 /import。`,`يتم الاستيراد بنموذج OpenCode المسجَّل الدخول من الطرفية أو بالأمر /import داخل OpenCode.`],"The chosen OpenCode model is not connected here. An import with an OpenCode signed-in model runs from the terminal or with /import in OpenCode. Choose the external API for a web import.":[`所选 OpenCode 模型在此处未连接。使用 OpenCode 已登录模型的导入需在终端运行,或在 OpenCode 中使用 /import。网页导入请选择外部 API。`,`نموذج OpenCode المختار غير متصل هنا. يتم الاستيراد بنموذج OpenCode المسجَّل الدخول من الطرفية أو بالأمر /import داخل OpenCode. اختر واجهة API الخارجية للاستيراد من الصفحة.`],"Test models in Health":[`在健康检查中测试模型`,`اختبر النماذج في قسم السلامة`],Import:[`导入`,`استيراد`],sessions:[`个会话`,`جلسات`],"List sessions first.":[`请先列出会话。`,`اعرض الجلسات أولاً.`],"Options changed. Refresh the session list first.":[`选项已更改。请先刷新会话列表。`,`تغيّرت الخيارات. حدّث قائمة الجلسات أولاً.`],"Select at least one session.":[`请至少选择一个会话。`,`حدّد جلسة واحدة على الأقل.`],"Select at most 1000 sessions one by one, or use Select all matching.":[`逐个选择最多 1000 个会话,或使用“选择所有匹配项”。`,`حدّد 1000 جلسة كحد أقصى واحدة تلو الأخرى، أو استخدم «تحديد كل المطابق».`],"Model readiness is unknown. Reload the page.":[`无法确定模型是否就绪。请重新加载页面。`,`حالة جاهزية النموذج غير معروفة. أعد تحميل الصفحة.`],"No import model is ready. Connect a model in OpenCode or complete the external API settings.":[`没有可用的导入模型。请在 OpenCode 中连接模型,或补全外部 API 设置。`,`لا يوجد نموذج استيراد جاهز. اربط نموذجاً في OpenCode أو أكمل إعدادات واجهة API الخارجية.`],"The external API is not ready":[`外部 API 未就绪`,`واجهة API الخارجية غير جاهزة`],"The external API has no memoryModel in the global config":[`全局配置中缺少外部 API 的 memoryModel`,`لا يحتوي الإعداد العام على memoryModel لواجهة API الخارجية`],"The external API has no memoryApiUrl in the global config":[`全局配置中缺少外部 API 的 memoryApiUrl`,`لا يحتوي الإعداد العام على memoryApiUrl لواجهة API الخارجية`],"The external API key is missing in the OpenCode process; check memoryApiKey and its env:// or file:// source":[`OpenCode 进程中缺少外部 API 密钥;请检查 memoryApiKey 及其 env:// 或 file:// 来源`,`مفتاح واجهة API الخارجية غير موجود في عملية OpenCode؛ تحقّق من memoryApiKey ومصدره env:// أو file://`],"The memoryProvider in the global config is not supported for imports":[`全局配置中的 memoryProvider 不支持导入`,`مزوّد memoryProvider في الإعداد العام غير مدعوم للاستيراد`],"Pi sessions folder or one .jsonl session file":[`Pi 会话文件夹或单个 .jsonl 会话文件`,`مجلد جلسات Pi أو ملف جلسة ‎.jsonl واحد`],"OpenCode database file":[`OpenCode 数据库文件`,`ملف قاعدة بيانات OpenCode`],"Absolute path, for example on a mounted volume":[`绝对路径,例如已挂载卷上的路径`,`مسار مطلق، مثلاً على وحدة تخزين مركّبة`],"Use this source":[`使用此来源`,`استخدم هذا المصدر`],Browse:[`浏览`,`استعراض`],"Use the default location":[`使用默认位置`,`استخدم الموقع الافتراضي`],"Chosen source":[`已选来源`,`المصدر المختار`],Choose:[`选择`,`اختيار`],"Only the first 500 entries are shown.":[`仅显示前 500 项。`,`تُعرض أول 500 عنصر فقط.`],"Reload the page before saving again.":[`再次保存前请重新加载页面。`,`أعد تحميل الصفحة قبل الحفظ مرة أخرى.`],"The current settings could not be reloaded. Reload the page.":[`无法重新加载当前设置。请重新加载页面。`,`تعذّر إعادة تحميل الإعدادات الحالية. أعد تحميل الصفحة.`],Log:[`日志`,`السجل`],"Capture attempts only":[`仅显示捕获尝试`,`محاولات الالتقاط فقط`],Refresh:[`刷新`,`تحديث`],"Copy log path":[`复制日志路径`,`نسخ مسار السجل`],"Log lines":[`日志行`,`أسطر السجل`],"No log has been written yet.":[`尚未写入日志。`,`لم يُكتب سجل بعد.`],"Loading log…":[`正在加载日志…`,`جارٍ تحميل السجل…`],"External API":[`外部 API`,`واجهة API الخارجية`],"An OpenAI- or Anthropic-compatible endpoint that either host can use for capture and backfill.":[`兼容 OpenAI 或 Anthropic 的端点,两个宿主都可用于捕获和回填。`,`نقطة نهاية متوافقة مع OpenAI أو Anthropic يمكن لأي مضيف استخدامها للالتقاط والاستيراد.`],Provider:[`提供商`,`المزوّد`],"API URL":[`API 地址`,`عنوان API`],"API key":[`API 密钥`,`مفتاح API`],"Save endpoint":[`保存端点`,`حفظ نقطة النهاية`],"Nothing to save.":[`没有需要保存的内容。`,`لا يوجد ما يُحفظ.`],"Key source":[`密钥来源`,`مصدر المفتاح`],"environment variable":[`环境变量`,`متغير البيئة`],"key file":[`密钥文件`,`ملف المفتاح`],"set in the config file":[`在配置文件中设置`,`مضبوط في ملف الإعدادات`],"resolves in the web app":[`可在网页应用中解析`,`يُقرأ في تطبيق الويب`],"does not resolve in the web app":[`无法在网页应用中解析`,`لا يُقرأ في تطبيق الويب`],"A login web app does not see variables set only in a shell profile; a key file works everywhere.":[`登录时启动的网页应用看不到仅在 shell 配置文件中设置的变量;密钥文件在任何地方都可用。`,`تطبيق الويب الذي يبدأ عند تسجيل الدخول لا يرى المتغيرات المضبوطة في ملف الصدفة فقط؛ ملف المفتاح يعمل في كل مكان.`],"The key does not resolve in this web app. Save it to a key file instead.":[`此网页应用无法解析该密钥。请改为保存到密钥文件。`,`لا يُقرأ المفتاح في تطبيق الويب هذا. احفظه في ملف مفتاح بدلاً من ذلك.`],"Environment variable":[`环境变量`,`متغير البيئة`],"Key file":[`密钥文件`,`ملف المفتاح`],"Save key to a private file":[`将密钥保存到私有文件`,`حفظ المفتاح في ملف خاص`],"Variable name":[`变量名`,`اسم المتغير`],"Key file path":[`密钥文件路径`,`مسار ملف المفتاح`],"Key file name":[`密钥文件名`,`اسم ملف المفتاح`],"The key is written to ~/.config/omms/secrets/ readable only by you. It is never shown again.":[`密钥写入 ~/.config/omms/secrets/,仅你可读,之后不再显示。`,`يُكتب المفتاح في ~/.config/omms/secrets/ ولا يقرؤه غيرك، ولن يُعرض مرة أخرى.`],"Save key source":[`保存密钥来源`,`حفظ مصدر المفتاح`],"Key source saved.":[`密钥来源已保存。`,`تم حفظ مصدر المفتاح.`],"A key file with this name exists. Replace it?":[`已存在同名密钥文件。要替换吗?`,`يوجد ملف مفتاح بهذا الاسم. هل تريد استبداله؟`],"Enter a variable name such as ZAI_API_KEY":[`请输入变量名,例如 ZAI_API_KEY`,`أدخل اسم متغير مثل ZAI_API_KEY`],"Enter the path of a key file":[`请输入密钥文件路径`,`أدخل مسار ملف المفتاح`],"Name the key file with letters, digits, dashes, or underscores":[`密钥文件名只能包含字母、数字、短横线或下划线`,`سمِّ ملف المفتاح بحروف أو أرقام أو شرطات أو شرطات سفلية`],"Paste the key":[`请粘贴密钥`,`الصق المفتاح`],Test:[`测试`,`اختبار`],"Test call succeeded":[`测试调用成功`,`نجح استدعاء الاختبار`],"Test call failed":[`测试调用失败`,`فشل استدعاء الاختبار`],"External API needs":[`外部 API 缺少`,`تحتاج واجهة API الخارجية إلى`],"Automatic import makes model calls. A model change applies at the next run. Turning it off stops a running import after the current exchange.":[`自动导入会调用模型。模型更改在下次运行时生效。关闭后,正在进行的导入会在当前对话完成后停止。`,`يستدعي الاستيراد التلقائي النماذج. يسري تغيير النموذج في التشغيل التالي. إيقافه يوقف الاستيراد الجاري بعد المحادثة الحالية.`],"Saved. Changes apply at the next run.":[`已保存。更改在下次运行时生效。`,`تم الحفظ. تسري التغييرات في التشغيل التالي.`],paused:[`已暂停`,`متوقف مؤقتاً`],"started from auto":[`自动启动`,`بدأ تلقائياً`],"started from web":[`从网页启动`,`بدأ من الويب`],"started from cli":[`从终端启动`,`بدأ من الطرفية`],"started from slash":[`从斜杠命令启动`,`بدأ من أمر الشرطة المائلة`],"Minutes left":[`剩余分钟`,`الدقائق المتبقية`],unknown:[`未知`,`غير معروف`],about:[`约`,`حوالي`],"Run now":[`立即运行`,`تشغيل الآن`],Pause:[`暂停`,`إيقاف مؤقت`],Resume:[`继续`,`استئناف`],"Pausing after the current exchange.":[`将在当前对话完成后暂停。`,`سيتوقف مؤقتاً بعد المحادثة الحالية.`],"Backfill started.":[`回填已开始。`,`بدأ الاستيراد.`],"Directory maps":[`目录映射`,`خرائط المجلدات`],"Map a directory that was moved or deleted to the project it belongs to. A change applies to the next import or backfill run.":[`将已移动或删除的目录映射到其所属项目。更改在下次导入或回填时生效。`,`اربط مجلداً نُقل أو حُذف بالمشروع الذي ينتمي إليه. يسري التغيير في الاستيراد التالي.`],"Saved maps":[`已保存的映射`,`الخرائط المحفوظة`],Keep:[`保留`,`إبقاء`],Remove:[`移除`,`إزالة`],"Unresolved directories":[`无法解析的目录`,`مجلدات غير محلولة`],"No unresolved directories in the latest run.":[`最近一次运行没有无法解析的目录。`,`لا توجد مجلدات غير محلولة في آخر تشغيل.`],"No suggestion found.":[`未找到建议。`,`لم يُعثر على اقتراح.`],"Target directory":[`目标目录`,`المجلد الهدف`],"Use this map":[`使用此映射`,`استخدام هذه الخريطة`],"Save maps":[`保存映射`,`حفظ الخرائط`],"Saved. Maps apply to the next import or backfill run.":[`已保存。映射在下次导入或回填时生效。`,`تم الحفظ. تسري الخرائط في الاستيراد التالي.`],"Running version":[`运行版本`,`الإصدار الجاري`],"Global command":[`全局命令`,`الأمر العام`],"not installed globally":[`未全局安装`,`غير مثبت عمومياً`],"The global command's version differs from the running OMMS. Upgrade it:":[`全局命令的版本与正在运行的 OMMS 不同。请升级:`,`يختلف إصدار الأمر العام عن OMMS الجاري. حدّثه:`],"A global install is optional but recommended: the login item and the terminal commands then run without npx.":[`全局安装是可选的,但建议安装:这样登录项和终端命令无需 npx 即可运行。`,`التثبيت العام اختياري لكنه موصى به: يعمل عنصر تسجيل الدخول وأوامر الطرفية حينها دون npx.`]};function vm(e,t){return t===`en`?e:_m[e]?.[t===`zh`?0:1]??e}function ym(){let{language:e}=lr();return t=>vm(t,e)}function bm(e,t){if(e===`env`){let n=(t.name??``).trim();if(!/^[A-Za-z_][A-Za-z0-9_]*$/.test(n))throw Error(`Enter a variable name such as ZAI_API_KEY`);return{source:e,name:n}}if(e===`file`){let n=(t.path??``).trim();if(!n)throw Error(`Enter the path of a key file`);return{source:e,path:n}}let n=(t.name??``).trim()||`memory-api`;if(!/^[A-Za-z0-9_-]{1,64}$/.test(n))throw Error(`Name the key file with letters, digits, dashes, or underscores`);if(!(t.value??``).trim())throw Error(`Paste the key`);return{source:e,name:n,value:t.value??``,replace:t.replace===!0}}function xm(e){let t=[],n=e.memoryProvider===`orcarouter`;return!n&&!e.memoryModel&&t.push(`memoryModel`),!n&&!e.memoryApiUrl&&t.push(`memoryApiUrl`),e.keySet||t.push(`memoryApiKey`),t}function Sm(e,t){if(t===`inherit`||t===`external`)return{[`${e}Model`]:t};let n=t.indexOf(`/`);if(n<1||n===t.length-1)throw Error(`Enter a model as provider/model.`);return{[`${e}Provider`]:t.slice(0,n),[`${e}Model`]:t.slice(n+1)}}function Cm(e){return e.global===null?{kind:`missing`,command:`npm i -g om-memory-system`}:e.global===e.running?{kind:`same`,command:null}:{kind:`different`,command:`npm i -g om-memory-system@latest`}}function wm(e,t,n){let r=new Map;for(let n of e)t.has(n.from)||r.set(n.from,n);for(let e of n){let t=e.target.trim();e.accepted&&t&&r.set(e.directory,{from:e.directory,to:t})}return[...r.values()]}var Tm={opencode:`OpenCode`,pi:`Pi`,"claude-code":`Claude Code`};function Em(e){return Tm[e]}function Dm({status:e}){let t=ym();return(0,V.jsxs)(`div`,{className:`space-y-1 rounded-lg border border-border p-3`,children:[(0,V.jsx)(`h3`,{className:`font-medium`,children:Em(`claude-code`)}),e?.ready===!0&&(0,V.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:t(`Claude Code capture uses the external API.`)}),e?.ready===!1&&(0,V.jsxs)(`div`,{role:`alert`,className:`space-y-1 text-xs`,children:[(0,V.jsx)(`p`,{className:`text-amber-600`,children:t(`Claude Code capture is off. Complete the external API settings.`)}),(e.issues??[]).length>0&&(0,V.jsxs)(`p`,{children:[t(`Missing settings`),`: `,(e.issues??[]).map(e=>t(e)).join(`; `)]})]})]})}function Om(){let e=ym(),[t,n]=(0,_.useState)(),[r,i]=(0,_.useState)({}),[a,o]=(0,_.useState)(``),[s,c]=(0,_.useState)(!1);(0,_.useEffect)(()=>{let e=!0,t=pm();$(`/api/settings`).then(r=>{e&&t.isCurrent()&&n(r)}).catch(t=>{e&&o(t.message)});for(let t of[`opencode`,`pi`])$(`/api/settings/models?host=${t}`).then(n=>{e&&i(e=>({...e,[t]:n}))}).catch(()=>{e&&i(e=>({...e,[t]:{available:!1}}))});let r=hm(t=>{e&&n(t)});return()=>{e=!1,r()}},[]);async function l(n,r){if(!t)return;let i;try{i=Sm(n,r)}catch(t){o(e(t.message));return}c(!0);let a,s;try{a=await $(`/api/settings`,{method:`PATCH`,body:JSON.stringify({edits:i,revision:t.revision})})}catch(e){s=e}let l=await mm()!==null;if(c(!1),a){let t=e(a.migratedLegacy?`Saved. OMMS now reads ~/.config/omms/omms.jsonc. The legacy config was kept.`:`Saved. New capture and profile work uses these settings.`);o(l?t:`${t} ${e(`Reload the page before saving again.`)}`)}else o(gm(s?.message??``,e(l?`Current settings were reloaded; check the values and save again.`:`The current settings could not be reloaded. Reload the page.`)))}let u=xm({memoryProvider:t?.settings.memoryProvider?.globalValue,memoryModel:t?.settings.memoryModel?.globalValue,memoryApiUrl:t?.settings.memoryApiUrl?.globalValue,keySet:!!t?.secrets.memoryApiKey?.set});return(0,V.jsxs)(`section`,{className:`space-y-3 rounded-xl border border-border bg-card p-4`,"aria-label":e(`Models`),children:[(0,V.jsx)(`h2`,{className:`text-lg font-medium`,children:e(`Models`)}),(0,V.jsxs)(`p`,{className:`text-sm text-muted-foreground`,children:[e(`External API fallback`),`: `,t?.fallback.model??e(`none`),` (`,e(t?.fallback.configured?`ready`:`not ready`),`).`]}),[`opencode`,`pi`].map(e=>(0,V.jsx)(km,{host:e,model:t?.settings[`${e}Model`],provider:t?.settings[`${e}Provider`],effective:e===`pi`?t?.effective.pi.kind:t?.effective.opencode.mode??`unready`,list:r[e],externalMissing:u,busy:s||!t,onSave:t=>l(e,t)},e)),(0,V.jsx)(Dm,{status:t?.effective[`claude-code`]}),(0,V.jsxs)(`div`,{className:`text-xs text-muted-foreground`,children:[e(`Credentials (values hidden)`),`:`,` `,t&&Object.entries(t.secrets).map(([t,n])=>(0,V.jsxs)(`span`,{className:`me-3`,children:[t,`: `,n.set?`${e(`set`)} (${n.source})`:e(`not set`)]},t))]}),a&&(0,V.jsx)(`p`,{role:`status`,className:`text-sm`,children:a})]})}function km({host:e,model:t,provider:n,effective:r,list:i,externalMissing:a,busy:o,onSave:s}){let c=ym(),l=t?.globalValue===`inherit`||!t?.globalValue?`inherit`:t.globalValue===`external`?`external`:`${n?.globalValue??``}/${t.globalValue}`,[u,d]=(0,_.useState)(),[f,p]=(0,_.useState)(),[m,h]=(0,_.useState)(),g=u??(l===`inherit`||l===`external`?l:`manual`),v=i?.models??[],y=l===`inherit`||l===`external`?``:l,b=m||y||(v[0]?`${v[0].provider}/${v[0].model}`:`typed`),x=!v.some(e=>`${e.provider}/${e.model}`===b),S=f??y;return(0,V.jsxs)(`div`,{className:`space-y-2 rounded-lg border border-border p-3`,children:[(0,V.jsx)(`h3`,{className:`font-medium`,children:Em(e)}),(0,V.jsxs)(`p`,{className:`text-xs text-muted-foreground`,children:[c(`Effective model`),`:`,` `,t?.value===`external`&&r===`manual`?c(`external API`):t?.value===`inherit`||r===`session`?c(`session`):r===`manual`?c(`external API`):r===`unready`?c(`unavailable`):`${n?.value??``}/${t?.value??``}`]}),(t?.source===`project`||n?.source===`project`)&&(0,V.jsx)(`p`,{className:`text-xs text-amber-600`,children:c(`Project override is active. Changes to the global file may not take effect here.`)}),(0,V.jsx)(`label`,{className:`block text-sm`,htmlFor:`${e}-model`,children:c(`Model choice`)}),(0,V.jsxs)(dn,{id:`${e}-model`,className:`w-full rounded-lg border border-border bg-background p-2 text-sm`,value:g,onChange:e=>d(e.target.value),children:[(0,V.jsx)(`option`,{value:`inherit`,children:c(`Session model`)}),(0,V.jsx)(`option`,{value:`manual`,children:c(`Manual model`)}),(0,V.jsx)(`option`,{value:`external`,disabled:a.length>0,children:c(`External API`)})]}),a.length>0&&(0,V.jsxs)(`p`,{className:`text-xs text-muted-foreground`,children:[c(`External API needs`),`: `,a.join(`, `)]}),g===`manual`&&i?.available&&v.length>0&&(0,V.jsxs)(dn,{className:`w-full rounded-lg border border-border bg-background p-2 text-sm`,"aria-label":`${Em(e)} ${c(`Model`)}`,value:x?`typed`:b,onChange:e=>h(e.target.value),children:[v.map(e=>(0,V.jsxs)(`option`,{value:`${e.provider}/${e.model}`,children:[e.name,` (`,e.provider,`/`,e.model,`)`]},`${e.provider}/${e.model}`)),(0,V.jsx)(`option`,{value:`typed`,children:c(`Manual provider/model`)})]}),g===`manual`&&x&&(0,V.jsx)(`input`,{className:`w-full rounded-lg border border-border bg-background p-2 text-sm`,"aria-label":`${e} ${c(`Manual provider/model`)}`,placeholder:`provider/model`,value:S,onChange:e=>{p(e.target.value),h(`typed`)}}),g===`manual`&&i&&!i.available&&(0,V.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:i.reason?c(i.reason):c(`Model list unavailable. Enter provider/model manually.`)}),(0,V.jsx)(`button`,{type:`button`,className:`rounded-lg border border-border px-3 py-1.5 text-sm`,disabled:o,onClick:()=>s(g===`manual`?x?S.trim():b:g),children:c(`Save model`)})]})}var Am=[`openai-chat`,`openai-responses`,`anthropic`,`minimax`,`orcarouter`,`google-gemini`];function jm(){let e=ym(),[t,n]=(0,_.useState)(),[r,i]=(0,_.useState)({}),[a,o]=(0,_.useState)(`file`),[s,c]=(0,_.useState)({name:``,path:``,value:``}),[l,u]=(0,_.useState)(``),[d,f]=(0,_.useState)(!1);(0,_.useEffect)(()=>{let e=!0,t=pm();$(`/api/settings`).then(r=>{e&&t.isCurrent()&&n(r)}).catch(t=>{e&&u(t.message)});let r=hm(t=>{e&&n(t)});return()=>{e=!1,r()}},[]);let p=e=>String(t?.settings[e]?.globalValue??``),m=e=>r[e]??p(e);async function h(){if(!t)return;let n={};for(let e of[`memoryProvider`,`memoryApiUrl`,`memoryModel`]){let t=m(e).trim();t&&t!==p(e)&&(n[e]=t)}if(!Object.keys(n).length){u(e(`Nothing to save.`));return}f(!0);try{await $(`/api/settings`,{method:`PATCH`,body:JSON.stringify({edits:n,revision:t.revision})}),i({}),u(e(`Saved. New capture and profile work uses these settings.`))}catch(e){u(e.message)}await mm(),f(!1)}async function g(n=!1){if(!t)return;let r;try{r=bm(a,{...s,replace:n})}catch(t){u(e(t.message));return}f(!0);try{await $(`/api/settings/external-api/key`,{method:`POST`,body:JSON.stringify({...r,revision:t.revision})}),c(e=>({...e,value:``})),u(e(`Key source saved.`))}catch(t){let r=t.message;if(a===`paste`&&!n&&r.includes(`Confirm to replace`)){f(!1),window.confirm(e(`A key file with this name exists. Replace it?`))&&await g(!0);return}u(r)}await mm(),f(!1)}async function v(){f(!0);try{let t=await $(`/api/settings/external-api/test`,{method:`POST`,body:`{}`});u(t.ok?`${e(`Test call succeeded`)}: ${t.model??``}`:`${e(`Test call failed`)}: ${t.error??``}`)}catch(e){u(e.message)}f(!1)}let y=t?.externalKey;return(0,V.jsxs)(`section`,{className:`space-y-3 rounded-xl border border-border bg-card p-4`,"aria-label":e(`External API`),children:[(0,V.jsx)(`h2`,{className:`text-lg font-medium`,children:e(`External API`)}),(0,V.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:e(`An OpenAI- or Anthropic-compatible endpoint that either host can use for capture and backfill.`)}),(0,V.jsxs)(`label`,{className:`block text-sm`,children:[e(`Provider`),(0,V.jsx)(dn,{"aria-label":e(`Provider`),className:`mt-1 block w-full rounded border border-border bg-background p-2`,value:m(`memoryProvider`)||`openai-chat`,onChange:e=>i({...r,memoryProvider:e.target.value}),children:Am.map(e=>(0,V.jsx)(`option`,{value:e,children:e},e))})]}),(0,V.jsxs)(`label`,{className:`block text-sm`,children:[e(`API URL`),(0,V.jsx)(`input`,{className:`mt-1 block w-full rounded border border-border bg-background p-2`,placeholder:`https://api.example.com/v1`,value:m(`memoryApiUrl`),onChange:e=>i({...r,memoryApiUrl:e.target.value})})]}),(0,V.jsxs)(`label`,{className:`block text-sm`,children:[e(`Model`),(0,V.jsx)(`input`,{className:`mt-1 block w-full rounded border border-border bg-background p-2`,placeholder:`glm-5-turbo`,value:m(`memoryModel`),onChange:e=>i({...r,memoryModel:e.target.value})})]}),(0,V.jsx)(`button`,{type:`button`,className:`rounded border border-border px-3 py-1.5 text-sm`,disabled:d||!t,onClick:()=>void h(),children:e(`Save endpoint`)}),(0,V.jsxs)(`fieldset`,{className:`space-y-2 rounded-lg border border-border p-3 text-sm`,children:[(0,V.jsx)(`legend`,{className:`px-1 font-medium`,children:e(`API key`)}),(0,V.jsxs)(`p`,{className:`text-xs text-muted-foreground`,children:[e(`Key source`),`:`,` `,y?.source===`env`?`${e(`environment variable`)} ${y.reference}`:y?.source===`file`?`${e(`key file`)} ${y.reference}`:y?.source===`literal`?e(`set in the config file`):e(`not set`),y?.source&&` · ${e(y.resolvesInWebApp?`resolves in the web app`:`does not resolve in the web app`)}`]}),y?.source===`env`&&(0,V.jsx)(`p`,{className:`text-xs text-amber-600`,children:e(`A login web app does not see variables set only in a shell profile; a key file works everywhere.`)}),y?.source&&!y.resolvesInWebApp&&(0,V.jsx)(`p`,{className:`text-xs text-amber-600`,children:e(`The key does not resolve in this web app. Save it to a key file instead.`)}),[[`env`,`Environment variable`],[`file`,`Key file`],[`paste`,`Save key to a private file`]].map(([t,n])=>(0,V.jsxs)(`label`,{className:`flex items-center gap-2`,children:[(0,V.jsx)(`input`,{type:`radio`,name:`omms-key-source`,checked:a===t,onChange:()=>o(t)}),e(n)]},t)),a===`env`&&(0,V.jsx)(`input`,{"aria-label":e(`Variable name`),className:`w-full rounded border border-border bg-background p-2`,placeholder:`ZAI_API_KEY`,value:s.name,onChange:e=>c({...s,name:e.target.value})}),a===`file`&&(0,V.jsx)(`input`,{"aria-label":e(`Key file path`),className:`w-full rounded border border-border bg-background p-2`,placeholder:`~/.config/omms/secrets/zai.key`,value:s.path,onChange:e=>c({...s,path:e.target.value})}),a===`paste`&&(0,V.jsxs)(V.Fragment,{children:[(0,V.jsx)(`input`,{"aria-label":e(`Key file name`),className:`w-full rounded border border-border bg-background p-2`,placeholder:`memory-api`,value:s.name,onChange:e=>c({...s,name:e.target.value})}),(0,V.jsx)(`input`,{"aria-label":e(`API key`),type:`password`,autoComplete:`off`,className:`w-full rounded border border-border bg-background p-2`,value:s.value,onChange:e=>c({...s,value:e.target.value})}),(0,V.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:e(`The key is written to ~/.config/omms/secrets/ readable only by you. It is never shown again.`)})]}),(0,V.jsx)(`button`,{type:`button`,className:`rounded border border-border px-3 py-1.5`,disabled:d||!t,onClick:()=>void g(),children:e(`Save key source`)})]}),(0,V.jsx)(`button`,{type:`button`,className:`rounded border border-border px-3 py-1.5 text-sm`,disabled:d,onClick:()=>void v(),children:e(`Test`)}),l&&(0,V.jsx)(`p`,{role:`status`,className:`text-sm`,children:l})]})}function Mm(){let e=ym(),[t,n]=(0,_.useState)(),[r,i]=(0,_.useState)(),[a,o]=(0,_.useState)(new Set),[s,c]=(0,_.useState)({}),[l,u]=(0,_.useState)(``),[d,f]=(0,_.useState)(!1),p=()=>$(`/api/settings/import-maps`).then(e=>{i(e),o(new Set),c({})}).catch(e=>u(e.message));(0,_.useEffect)(()=>{let e=!0;$(`/api/settings`).then(t=>{e&&n(t)}).catch(t=>{e&&u(t.message)}),p();let t=hm(t=>{e&&n(t)});return()=>{e=!1,t()}},[]);function m(e,t){c(n=>{let r=n[e.directory]??{directory:e.directory,target:e.suggestion??``,accepted:!1};return{...n,[e.directory]:{...r,...t}}})}async function h(){if(!t||!r)return;let n=wm(r.saved,a,Object.values(s));f(!0);try{await $(`/api/settings`,{method:`PATCH`,body:JSON.stringify({edits:{importPathMaps:n},revision:t.revision})}),u(e(`Saved. Maps apply to the next import or backfill run.`))}catch(e){u(e.message)}await mm(),await p(),f(!1)}return(0,V.jsxs)(`section`,{id:`directory-maps`,className:`space-y-3 rounded-xl border border-border bg-card p-4`,"aria-label":e(`Directory maps`),children:[(0,V.jsx)(`h2`,{className:`text-lg font-medium`,children:e(`Directory maps`)}),(0,V.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:e(`Map a directory that was moved or deleted to the project it belongs to. A change applies to the next import or backfill run.`)}),(0,V.jsx)(`h3`,{className:`font-medium`,children:e(`Saved maps`)}),!r?.saved.length&&(0,V.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:e(`none`)}),(0,V.jsx)(`ul`,{className:`space-y-1 text-sm`,children:r?.saved.map(t=>(0,V.jsxs)(`li`,{className:`flex flex-wrap items-center gap-2`,children:[(0,V.jsxs)(`span`,{className:a.has(t.from)?`line-through`:``,children:[(0,V.jsx)(`code`,{children:t.from}),` → `,(0,V.jsx)(`code`,{children:t.to})]}),(0,V.jsx)(`button`,{type:`button`,className:`rounded border border-border px-2 py-0.5 text-xs`,onClick:()=>o(e=>{let n=new Set(e);return n.has(t.from)?n.delete(t.from):n.add(t.from),n}),children:a.has(t.from)?e(`Keep`):e(`Remove`)})]},t.from))}),[`pi`,`opencode`,`claude-code`].map(t=>(0,V.jsxs)(`div`,{className:`space-y-2`,children:[(0,V.jsxs)(`h3`,{className:`font-medium`,children:[Em(t),`: `,e(`Unresolved directories`)]}),!r?.[t]?.length&&(0,V.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:e(`No unresolved directories in the latest run.`)}),r?.[t]?.map(t=>{let n=s[t.directory],r=n?.target??t.suggestion??``;return(0,V.jsxs)(`div`,{className:`space-y-1 rounded-lg border border-border p-2 text-sm`,children:[(0,V.jsxs)(`p`,{children:[(0,V.jsx)(`code`,{children:t.directory}),` · `,t.sessions,` `,e(`sessions`)]}),!t.suggestion&&(0,V.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:e(`No suggestion found.`)}),(0,V.jsx)(`input`,{"aria-label":`${t.directory} ${e(`Target directory`)}`,className:`w-full rounded border border-border bg-background p-2`,placeholder:e(`Target directory`),value:r,onChange:e=>m(t,{target:e.target.value})}),(0,V.jsxs)(`label`,{className:`flex items-center gap-2`,children:[(0,V.jsx)(`input`,{type:`checkbox`,checked:n?.accepted??!1,onChange:e=>m(t,{accepted:e.target.checked})}),e(`Use this map`)]})]},t.directory)})]},t)),(0,V.jsx)(`button`,{type:`button`,className:`rounded border border-border px-3 py-1.5 text-sm`,disabled:d||!t||!r,onClick:()=>void h(),children:e(`Save maps`)}),l&&(0,V.jsx)(`p`,{role:`status`,className:`text-sm`,children:l})]})}var Nm=`overflow-x-auto rounded-lg border border-border`,Pm=`px-3 py-2 text-start font-medium`,Fm=`bg-muted/50 text-xs text-muted-foreground`,Im=`px-3 py-2 text-start font-medium`,Lm=`border-t border-border transition-colors hover:bg-muted/30`,Rm=`px-3 py-1.5`;function zm(){let e=ym(),[t,n]=(0,_.useState)(7),[r,i]=(0,_.useState)(),[a,o]=(0,_.useState)([]),[s,c]=(0,_.useState)(),[l,u]=(0,_.useState)(``),[d,f]=(0,_.useState)(``),[p,m]=(0,_.useState)(``),h=(0,_.useCallback)(async e=>{let t=pm();try{let[n,r,a]=await Promise.all([$(`/api/settings/diagnostics?days=${e}`),$(`/api/settings/traces`),$(`/api/settings`)]);i(n),o(r.traces),t.isCurrent()&&c(a),f(``)}catch(e){f(e.message)}},[]);(0,_.useEffect)(()=>{h(t)},[t,h]),(0,_.useEffect)(()=>hm(e=>c(e)),[]);async function g(n){if(!s)return;let r;try{await $(`/api/settings`,{method:`PATCH`,body:JSON.stringify({revision:s.revision,edits:n})})}catch(e){r=e}let i=await mm()!==null;if(!r){m(``),await h(t),i||f(e(`Reload the page before saving again.`));return}f(gm(r.message,e(i?`Current settings were reloaded; check the values and save again.`:`The current settings could not be reloaded. Reload the page.`)))}async function v(e){try{let t=await $(`/api/settings/traces/${encodeURIComponent(e)}`);u(t.content)}catch(e){f(e.message)}}async function y(n){if(window.confirm(`${e(`Delete`)} ${n}?`))try{await $(`/api/settings/traces/${encodeURIComponent(n)}`,{method:`DELETE`}),u(``),await h(t)}catch(e){f(e.message)}}async function b(n){try{let{result:r}=await $(`/api/settings/capture-retry/${n}/run`,{method:`POST`,body:`{}`});m(e(r===`scheduled`?n===`pi`?`These turns retry at the next Pi session start.`:n===`claude-code`?`These turns retry at the next Claude Code session start.`:`These turns retry at the next OpenCode session start.`:r===`running`?`A retry is already running.`:`Retrying now.`)),await h(t)}catch(e){f(e.message)}}let x=s?.settings.captureTrace,S=Number(s?.settings.captureRetryRetentionHours?.value??72);return(0,V.jsxs)(`section`,{className:`space-y-4 rounded-xl border border-border bg-card p-4`,"aria-label":e(`Capture diagnostics`),children:[(0,V.jsx)(`h2`,{className:`text-lg font-medium`,children:e(`Capture diagnostics`)}),(0,V.jsxs)(`label`,{className:`flex items-center gap-2 pb-2 text-sm`,children:[e(`Time range`),(0,V.jsxs)(dn,{"aria-label":e(`Time range`),className:`rounded-lg border border-border bg-background px-2 py-1`,value:t,onChange:e=>n(Number(e.target.value)),children:[(0,V.jsx)(`option`,{value:1,children:e(`24 hours`)}),(0,V.jsx)(`option`,{value:7,children:e(`7 days`)}),(0,V.jsx)(`option`,{value:30,children:e(`30 days`)}),(0,V.jsx)(`option`,{value:90,children:e(`90 days`)})]})]}),d&&(0,V.jsx)(`p`,{role:`alert`,children:d}),(0,V.jsx)(`div`,{className:Nm,children:(0,V.jsxs)(`table`,{className:`w-full text-sm`,children:[(0,V.jsx)(`caption`,{className:Pm,children:e(`Outcomes by model`)}),(0,V.jsx)(`thead`,{className:Fm,children:(0,V.jsx)(`tr`,{children:[`Host / model`,`Saved`,`Skipped`,`Failed`,`Total`].map((t,n)=>(0,V.jsx)(`th`,{scope:`col`,className:B(Im,n>0&&`text-end`),children:e(t)},t))})}),(0,V.jsx)(`tbody`,{children:r?.byModel.map((e,t)=>(0,V.jsxs)(`tr`,{className:Lm,children:[(0,V.jsxs)(`td`,{className:Rm,children:[(0,V.jsx)(`span`,{className:`text-muted-foreground`,children:e.host}),` `,(0,V.jsx)(`span`,{className:`font-mono text-xs`,children:e.provider||e.model?`${e.provider??``}/${e.model??``}`:`—`})]}),[e.saved,e.skipped,e.failed].map((t,n)=>(0,V.jsxs)(`td`,{className:B(Rm,`text-end tabular-nums`),children:[t,` `,(0,V.jsxs)(`span`,{className:`text-xs text-muted-foreground`,children:[Math.round(100*t/e.total),`%`]})]},n)),(0,V.jsx)(`td`,{className:B(Rm,`text-end font-medium tabular-nums`),children:e.total})]},`${e.host}-${e.provider}-${e.model}-${t}`))})]})}),(0,V.jsx)(`div`,{className:Nm,children:(0,V.jsxs)(`table`,{className:`w-full text-sm`,children:[(0,V.jsx)(`caption`,{className:Pm,children:e(`Failure reasons`)}),(0,V.jsx)(`thead`,{className:Fm,children:(0,V.jsxs)(`tr`,{children:[(0,V.jsx)(`th`,{scope:`col`,className:Im,children:e(`Host`)}),(0,V.jsx)(`th`,{scope:`col`,className:Im,children:e(`Reason`)}),(0,V.jsx)(`th`,{scope:`col`,className:B(Im,`text-end`),children:e(`Total`)})]})}),(0,V.jsx)(`tbody`,{children:r?.byReason.map((e,t)=>(0,V.jsxs)(`tr`,{className:Lm,children:[(0,V.jsx)(`td`,{className:B(Rm,`text-muted-foreground`),children:e.host}),(0,V.jsx)(`td`,{className:B(Rm,`font-mono text-xs`),children:e.reason}),(0,V.jsx)(`td`,{className:B(Rm,`text-end tabular-nums`),children:e.count})]},`${e.host}-${e.reason}-${t}`))})]})}),(0,V.jsx)(`div`,{className:B(Nm,`max-h-72 overflow-y-auto`),children:(0,V.jsxs)(`table`,{className:`w-full min-w-max text-sm`,children:[(0,V.jsx)(`caption`,{className:Pm,children:e(`Recent attempts`)}),(0,V.jsx)(`thead`,{className:B(Fm,`sticky top-0`),children:(0,V.jsx)(`tr`,{children:[`Time`,`Host`,`Source`,`Session`,`Path`,`Model`,`Stop`,`Blocks`,`Prompt`,`Reply`,`Duration`,`Outcome`,`Reason`].map(t=>(0,V.jsx)(`th`,{scope:`col`,className:Im,children:e(t)},t))})}),(0,V.jsx)(`tbody`,{children:r?.recent.map((e,t)=>(0,V.jsx)(`tr`,{className:Lm,children:[new Date(e.timestamp).toLocaleString(),e.host,e.sourceType,e.sessionId,e.path,`${e.provider??``}/${e.model??``}`,e.stopReason,e.blockTypes?.join(`, `),e.promptChars,e.replyChars,e.durationMs,e.outcome,e.reason].map((e,t)=>(0,V.jsx)(`td`,{className:B(Rm,`whitespace-nowrap`),children:e??``},t))},`${e.timestamp}-${t}`))})]})}),(0,V.jsxs)(`div`,{className:`space-y-2 border-t border-border pt-3 text-sm`,children:[(0,V.jsxs)(`label`,{className:`flex items-center gap-2`,children:[(0,V.jsx)(`input`,{type:`checkbox`,checked:x?.value===!0,disabled:!s,onChange:t=>{t.target.checked&&!window.confirm(e(`Traces can contain conversation content after redaction. Keep tracing off unless you need it for debugging.`))||g({captureTrace:t.target.checked})}}),` `,e(`Save capture traces`)]}),(0,V.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:e(`Traces can contain conversation content after redaction. Keep tracing off unless you need it for debugging.`)}),x?.source===`project`&&(0,V.jsx)(`p`,{className:`text-xs text-amber-600`,children:e(`This project turns tracing off. The global switch cannot turn it on here.`)}),[`captureTraceRetentionDays`,`captureAttemptRetentionDays`].map(t=>(0,V.jsxs)(`label`,{className:`block`,children:[e(t===`captureTraceRetentionDays`?`Trace retention (days)`:`Attempt retention (days)`),` `,(0,V.jsx)(`input`,{type:`number`,min:1,className:`ms-2 w-20 rounded border border-border bg-background p-1`,defaultValue:Number(s?.settings[t]?.value??30),onBlur:e=>{let n=Number(e.target.value);Number.isSafeInteger(n)&&n>0&&n!==s?.settings[t]?.value&&g({[t]:n})}},`${t}-${s?.settings[t]?.value}`)]},t)),(0,V.jsxs)(`label`,{className:`block`,children:[e(`Retry retention (hours)`),` `,(0,V.jsx)(`input`,{type:`number`,min:0,max:720,className:`ms-2 w-20 rounded border border-border bg-background p-1`,defaultValue:S,onBlur:e=>{let t=Number(e.target.value);Number.isSafeInteger(t)&&t>=0&&t<=720&&t!==S&&g({captureRetryRetentionHours:t})}},`captureRetryRetentionHours-${S}`)]}),(0,V.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:e(`When the capture model cannot be reached, OMMS keeps the turn and tries again later. Queued turns can hold conversation content after redaction. 0 turns the queue off and deletes waiting turns.`)}),(0,V.jsx)(`h3`,{className:`font-medium`,children:e(`Turns waiting for retry`)}),[`pi`,`opencode`,`claude-code`].map(t=>{let n=r?.retryQueue?.[t]??0;return(0,V.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,V.jsx)(`span`,{className:`w-24`,children:Em(t)}),(0,V.jsx)(`span`,{className:`tabular-nums`,children:n}),(0,V.jsx)(`button`,{type:`button`,disabled:n===0||S===0,className:`disabled:opacity-50`,onClick:()=>void b(t),children:e(`Retry now`)})]},t)}),p&&(0,V.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:p}),(0,V.jsx)(`h3`,{className:`font-medium`,children:e(`Trace files`)}),a.map(t=>(0,V.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,V.jsxs)(`span`,{children:[t.file,` (`,t.size,` bytes)`]}),(0,V.jsx)(`button`,{type:`button`,onClick:()=>void v(t.file),children:e(`View`)}),(0,V.jsx)(`button`,{type:`button`,onClick:()=>void y(t.file),children:e(`Delete`)})]},t.file)),l&&(0,V.jsx)(`pre`,{className:`max-h-60 overflow-auto whitespace-pre-wrap break-words rounded bg-background p-2 text-xs`,children:l})]})]})}function Bm(){let e=ym(),[t,n]=(0,_.useState)([]),[r,i]=(0,_.useState)(!1),[a,o]=(0,_.useState)(``);async function s(e){i(!0);try{let t=await $(`/api/settings/health`,{method:`POST`,body:JSON.stringify({testModels:e})});n(t.checks),o(``)}catch(e){o(e.message)}finally{i(!1)}}return(0,V.jsxs)(`section`,{id:`settings-health`,className:`space-y-3 rounded-xl border border-border bg-card p-4`,"aria-label":e(`Health`),children:[(0,V.jsx)(`h2`,{className:`text-lg font-medium`,children:e(`Health`)}),(0,V.jsxs)(`div`,{className:`flex gap-2`,children:[(0,V.jsx)(`button`,{className:`rounded-lg border border-border px-3 py-1.5 text-sm`,disabled:r,onClick:()=>void s(!1),children:e(`Run checks`)}),(0,V.jsx)(`button`,{className:`rounded-lg border border-border px-3 py-1.5 text-sm`,disabled:r,onClick:()=>void s(!0),children:e(`Run checks and test models`)})]}),r&&(0,V.jsx)(`p`,{role:`status`,children:e(`Checking…`)}),a&&(0,V.jsx)(`p`,{role:`alert`,children:a}),(0,V.jsx)(`ul`,{className:`space-y-2 text-sm`,children:t.map(t=>(0,V.jsxs)(`li`,{className:`rounded-lg border border-border p-2`,children:[(0,V.jsx)(`strong`,{className:t.status===`fail`?`text-red-600`:t.status===`warn`?`text-amber-600`:`text-green-600`,children:e(t.status).toUpperCase()}),` `,`· `,e(t.check),`: `,t.reason]},t.check))})]})}function Vm(e){let t=/^(\d{4})-(\d{2})-(\d{2})$/.exec(e);return t?[Number(t[1]),Number(t[2])-1,Number(t[3])]:null}function Hm(e){let t=Vm(e);return t?new Date(t[0],t[1],t[2],0,0,0,0).getTime():void 0}function Um(e){let t=Vm(e);return t?new Date(t[0],t[1],t[2],23,59,59,999).getTime():void 0}function Wm(e,t,n){let r=!n&&e!==null&&e.revision===t.revision;return{page:r?{...t,listedAt:e.listedAt}:t,sameListing:r}}function Gm(e){let t=ym(),[n,r]=(0,_.useState)(``),[i,a]=(0,_.useState)(null),[o,s]=(0,_.useState)(null),[c,l]=(0,_.useState)(!1),[u,d]=(0,_.useState)(``),f=`rounded border border-border px-3 py-1.5 text-sm disabled:opacity-50`;async function p(t){try{let n=await $(`/api/settings/imports/sources/validate`,{method:`POST`,body:JSON.stringify({host:e.host,path:t})});a(n),r(n.displayPath),e.onChoose(n),d(``)}catch(e){d(e.message)}}async function m(t){try{let n=await $(`/api/settings/imports/sources/browse`,{method:`POST`,body:JSON.stringify({host:e.host,...t?{path:t}:{}})});s(n),d(``)}catch(e){let t=e.message;/loopback/i.test(t)&&l(!0),d(t)}}function h(){a(null),r(``),s(null),e.onChoose(null)}return(0,V.jsxs)(`div`,{className:`space-y-2 text-sm`,children:[(0,V.jsxs)(`label`,{className:`block`,children:[e.host===`pi`?t(`Pi sessions folder or one .jsonl session file`):e.host===`claude-code`?t(`Claude Code transcripts folder`):t(`OpenCode database file`),(0,V.jsx)(`input`,{className:`mt-1 block w-full rounded border border-border bg-background p-2 font-mono`,value:n,placeholder:t(`Absolute path, for example on a mounted volume`),onChange:e=>r(e.target.value)})]}),(0,V.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,V.jsx)(`button`,{type:`button`,className:f,disabled:!n.trim(),onClick:()=>void p(n.trim()),children:t(`Use this source`)}),!c&&(0,V.jsx)(`button`,{type:`button`,className:f,onClick:()=>void m(o?.path),children:t(`Browse`)}),i&&(0,V.jsx)(`button`,{type:`button`,className:f,onClick:h,children:t(`Use the default location`)})]}),i&&(0,V.jsxs)(`p`,{role:`status`,children:[t(`Chosen source`),`: `,(0,V.jsx)(`span`,{className:`font-mono`,children:i.displayPath})]}),u&&(0,V.jsx)(`p`,{role:`alert`,children:u}),o&&(0,V.jsxs)(`div`,{className:`rounded border border-border p-2`,children:[(0,V.jsx)(`p`,{className:`font-mono text-xs break-all`,children:o.path}),(0,V.jsxs)(`ul`,{className:`max-h-60 overflow-auto`,children:[o.parent&&(0,V.jsx)(`li`,{children:(0,V.jsx)(`button`,{type:`button`,className:`underline`,onClick:()=>void m(o.parent),children:`..`})}),o.entries.map(n=>(0,V.jsxs)(`li`,{className:`flex items-center gap-2`,children:[n.kind===`folder`?(0,V.jsxs)(`button`,{type:`button`,className:`underline`,onClick:()=>void m(n.path),children:[n.name,`/`]}):(0,V.jsx)(`span`,{className:`font-mono text-xs`,children:n.name}),(n.kind!==`folder`||e.host!==`opencode`)&&(0,V.jsx)(`button`,{type:`button`,className:`text-xs underline`,onClick:()=>void p(n.path),children:t(`Choose`)})]},n.path))]}),o.truncated&&(0,V.jsx)(`p`,{className:`text-xs`,children:t(`Only the first 500 entries are shown.`)})]})]})}var Km=50,qm=1e3,Jm={"missing-model":`The external API has no memoryModel in the global config`,"missing-url":`The external API has no memoryApiUrl in the global config`,"missing-key":`The external API key is missing in the OpenCode process; check memoryApiKey and its env:// or file:// source`,"unsupported-provider":`The memoryProvider in the global config is not supported for imports`},Ym=()=>({mode:`ids`,picked:new Map});function Xm(e,t){return e.split(`
123
- `).map(e=>e.trim()).filter(Boolean).map(e=>{let n=e.indexOf(`=`);if(n<1||n===e.length-1)throw Error(t);return{from:e.slice(0,n),to:e.slice(n+1)}})}function Zm(){let e=ym(),[t,n]=(0,_.useState)(`pi`),[r,i]=(0,_.useState)(null),[a,o]=(0,_.useState)(`current-project`),[s,c]=(0,_.useState)(``),[l,u]=(0,_.useState)(``),[d,f]=(0,_.useState)(``),[p,m]=(0,_.useState)(``),[h,g]=(0,_.useState)(``),[v,y]=(0,_.useState)(!1),[b,x]=(0,_.useState)(!1),[S,C]=(0,_.useState)(!1),[w,T]=(0,_.useState)(!1),[E,D]=(0,_.useState)(null),[O,ee]=(0,_.useState)(``),[te,ne]=(0,_.useState)(!1),[re,ie]=(0,_.useState)(!1),[k,ae]=(0,_.useState)(Ym),[A,j]=(0,_.useState)(null),[oe,M]=(0,_.useState)(``),se=t===`claude-code`&&oe!==`external`?``:oe,[N,P]=(0,_.useState)(null),[F,ce]=(0,_.useState)(``);(0,_.useEffect)(()=>{$(`/api/settings/imports/readiness`).then(e=>{j(e);let t=e.opencode.models[0];M(t?`${t.provider}/${t.model}`:e.external.state===`ready`?`external`:``)}).catch(()=>j(null)),$(`/api/settings/imports/current`).then(e=>P(e.job)).catch(()=>{})},[]),(0,_.useEffect)(()=>{if(N?.state!==`running`&&N?.state!==`cancelling`)return;let e=setInterval(()=>{$(`/api/settings/imports/current`).then(e=>P(e.job)).catch(e=>ce(e.message))},1e3);return()=>clearInterval(e)},[N?.state]);let le=JSON.stringify([t,r?.sourceToken,a,s,l]),ue=!!E&&(te||le!==O);function de(){let n=Xm(l,e(`Directory maps must be old=new, one per line`));return{host:t,...r?{source:r.sourceToken}:{},scope:a,...a===`current-project`&&s?{project:s}:{},pathMaps:n}}async function fe(e,t){ie(!0);try{let n=await $(`/api/settings/imports/sessions`,{method:`POST`,body:JSON.stringify({...de(),offset:e,limit:Km,refresh:t})}),r=Wm(E,n,t);r.sameListing||ae(Ym()),D(r.page),ee(le),ne(!1),ce(``)}catch(e){ce(e.message)}finally{ie(!1)}}let I=E?E.total-(a===`all-projects`?E.unresolvedCount:0):0,pe=k.mode===`all`?I-k.excluded.size:k.picked.size,me=e=>k.mode===`all`?!k.excluded.has(e.key):k.picked.has(e.key);function he(e){if(!(!e.selectable||!e.directory)){if(k.mode===`all`){let t=new Set(k.excluded);t.has(e.key)?t.delete(e.key):t.add(e.key),ae({mode:`all`,excluded:t})}else{let t=new Map(k.picked);t.has(e.key)?t.delete(e.key):t.set(e.key,e.directory),ae({mode:`ids`,picked:t})}}}let ge=!b||!S,_e=t===`pi`&&A?.piReader.available===!1,ve=ge?A?se?se===`external`&&A.external.state!==`ready`?e(Jm[A.external.state]??`The external API is not ready`):null:e(t===`claude-code`?`Claude Code imports use the external API. Complete the external API settings.`:`No import model is ready. Connect a model in OpenCode or complete the external API settings.`):e(`Model readiness is unknown. Reload the page.`):null,ye=E?ue?e(`Options changed. Refresh the session list first.`):pe===0?e(`Select at least one session.`):k.mode===`ids`&&k.picked.size>qm?e(`Select at most 1000 sessions one by one, or use Select all matching.`):null:e(`List sessions first.`),be=N?.state===`running`||N?.state===`cancelling`;async function xe(n){if(E)try{let r=d?Hm(d):void 0,i=p?Um(p):void 0,o={host:t,source:E.source.sourceToken,selection:k.mode===`all`?{mode:`all`,excludedKeys:[...k.excluded],revision:E.revision,listedAt:E.listedAt}:{mode:`ids`,sessions:[...k.picked].map(([e,t])=>({key:e,directory:t})),listedAt:E.listedAt},options:{dryRun:n,force:v,skipMemories:b,skipProfile:S,scope:a,...a===`current-project`&&s?{project:s}:{},...r===void 0?{}:{since:r},...i===void 0?{}:{until:i},...h?{profileBatch:Number(h)}:{},pathMaps:Xm(l,e(`Directory maps must be old=new, one per line`))},...se?{modelChoice:se}:{}},c=await $(`/api/settings/imports`,{method:`POST`,body:JSON.stringify(o)});P(c),ce(``)}catch(e){let t=e.message;/out of date|changed|no longer/i.test(t)&&ne(!0),ce(t)}}async function Se(){try{let e=await $(`/api/settings/imports/current/cancel`,{method:`POST`,body:`{}`});P(e.job)}catch(e){ce(e.message)}}function Ce(){o(`all-projects`),T(!0)}let we={recorded:e(`recorded`),mapped:e(`mapped`),worktree:e(`project root`),unresolved:e(`missing`)},Te=`mt-1 block w-full rounded border border-border bg-background p-2`,Ee=`rounded border border-border px-3 py-1.5 text-sm disabled:opacity-50`;return(0,V.jsxs)(`section`,{className:`space-y-3 rounded-xl border border-border bg-card p-4`,"aria-label":e(`Import and backfill`),children:[(0,V.jsx)(`h2`,{className:`text-lg font-medium`,children:e(`Import and backfill`)}),(0,V.jsxs)(`div`,{className:`flex flex-wrap items-end gap-3`,children:[(0,V.jsxs)(`label`,{className:`text-sm`,children:[e(`History host`),(0,V.jsxs)(dn,{"aria-label":e(`History host`),className:Te,value:t,onChange:e=>{let t=e.target.value;n(t),t===`claude-code`&&A?.external.state===`ready`&&M(`external`),i(null),D(null),ae(Ym())},children:[(0,V.jsx)(`option`,{value:`pi`,children:`Pi`}),(0,V.jsx)(`option`,{value:`opencode`,children:`OpenCode`}),(0,V.jsx)(`option`,{value:`claude-code`,children:`Claude Code`})]})]}),(0,V.jsx)(`button`,{type:`button`,className:Ee,disabled:re,onClick:()=>void fe(0,!0),children:e(E?`Refresh list`:`List sessions`)}),(0,V.jsx)(`button`,{type:`button`,className:Ee,onClick:()=>T(!w),children:e(w?`Hide advanced options`:`Advanced options`)})]}),(0,V.jsxs)(`p`,{className:`text-xs text-muted-foreground`,children:[e(`Source`),`: `,r?.displayPath??E?.source.displayPath??e(`default location`),` · `,e(a===`current-project`?`Current project`:`All projects`)]}),_e&&(0,V.jsx)(`p`,{role:`alert`,children:A?.piReader.reason}),t===`claude-code`&&A?.claudeCode&&(0,V.jsxs)(`p`,{className:`text-xs text-muted-foreground`,children:[e(`Claude Code transcripts`),`:`,` `,(0,V.jsx)(`span`,{className:`font-mono break-all`,children:A.claudeCode.defaultRoot}),` (`,A.claudeCode.defaultRootFound?e(`found`):e(`not found`),`).`,` `,e(`Claude Code imports always use the external API.`)]}),w&&(0,V.jsxs)(`div`,{className:`space-y-3 rounded-lg border border-border p-3`,children:[(0,V.jsx)(Gm,{host:t,onChoose:i}),(0,V.jsxs)(`div`,{className:`grid gap-3 sm:grid-cols-2`,children:[(0,V.jsxs)(`label`,{className:`text-sm`,children:[e(`Scope`),(0,V.jsxs)(dn,{"aria-label":e(`Scope`),className:Te,value:a,onChange:e=>o(e.target.value),children:[(0,V.jsx)(`option`,{value:`current-project`,children:e(`Current project`)}),(0,V.jsx)(`option`,{value:`all-projects`,children:e(`All projects`)})]})]}),a===`current-project`&&(0,V.jsxs)(`label`,{className:`text-sm`,children:[e(`Project directory`),(0,V.jsx)(`input`,{className:Te,value:s,onChange:e=>c(e.target.value),placeholder:e(`Current directory`)})]}),(0,V.jsxs)(`label`,{className:`text-sm`,children:[e(`Prompt date from`),(0,V.jsx)(`input`,{type:`date`,className:Te,value:d,onChange:e=>f(e.target.value)})]}),(0,V.jsxs)(`label`,{className:`text-sm`,children:[e(`Prompt date to`),(0,V.jsx)(`input`,{type:`date`,className:Te,value:p,onChange:e=>m(e.target.value)})]}),(0,V.jsxs)(`label`,{className:`text-sm`,children:[e(`Profile batch size`),(0,V.jsx)(`input`,{inputMode:`numeric`,className:Te,value:h,onChange:e=>g(e.target.value)})]})]}),(0,V.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:e(`Prompt dates are inclusive, use your time zone, and filter the turns inside each session, not the list. Empty dates include every turn.`)}),(0,V.jsxs)(`label`,{className:`block text-sm`,children:[e(`Directory maps (old=new, one per line)`),(0,V.jsx)(`textarea`,{className:Te,rows:2,value:l,onChange:e=>u(e.target.value)})]}),(0,V.jsx)(`div`,{className:`flex flex-wrap gap-3 text-sm`,children:[[`Force reimport`,v,y],[`Skip memories`,b,x],[`Skip profile`,S,C]].map(([t,n,r])=>(0,V.jsxs)(`label`,{children:[(0,V.jsx)(`input`,{type:`checkbox`,checked:n,onChange:e=>r(e.target.checked)}),` `,e(t)]},t))})]}),ue&&E&&(0,V.jsx)(`p`,{role:`status`,className:`text-sm text-amber-600`,children:e(`Options changed. Refresh the session list first.`)}),E&&a===`current-project`&&E.unresolvedCount>0&&(0,V.jsxs)(`p`,{className:`text-sm`,children:[e(`Sessions with directories that no longer exist`),`: `,E.unresolvedCount,`.`,` `,(0,V.jsx)(`button`,{type:`button`,className:`underline`,onClick:Ce,children:e(`Show them and add a directory map`)})]}),E&&(0,V.jsxs)(`div`,{className:`space-y-2`,children:[(0,V.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2 text-sm`,children:[(0,V.jsxs)(`span`,{role:`status`,children:[e(`Selected`),`: `,pe,` / `,I]}),(0,V.jsxs)(`button`,{type:`button`,className:Ee,disabled:I===0,onClick:()=>ae({mode:`all`,excluded:new Set}),children:[e(`Select all matching`),` (`,I,`)`]}),(0,V.jsx)(`button`,{type:`button`,className:Ee,onClick:()=>ae(Ym()),children:e(`Clear selection`)})]}),(0,V.jsxs)(`div`,{className:`overflow-x-auto`,children:[(0,V.jsxs)(`table`,{className:`w-full text-left text-sm`,children:[(0,V.jsx)(`thead`,{children:(0,V.jsxs)(`tr`,{className:`text-muted-foreground`,children:[(0,V.jsx)(`th`,{className:`p-1`,children:(0,V.jsx)(`span`,{className:`sr-only`,children:e(`Select`)})}),(0,V.jsx)(`th`,{className:`p-1`,children:e(`Created`)}),(0,V.jsx)(`th`,{className:`p-1`,children:e(`Session`)}),(0,V.jsx)(`th`,{className:`p-1`,children:e(`Project directory`)}),(0,V.jsx)(`th`,{className:`p-1`,children:e(`Resolved by`)})]})}),(0,V.jsx)(`tbody`,{children:E.rows.map(t=>(0,V.jsxs)(`tr`,{className:`border-t border-border`,children:[(0,V.jsx)(`td`,{className:`p-1`,children:(0,V.jsx)(`input`,{type:`checkbox`,"aria-label":`${e(`Select`)} ${t.sessionId??t.key}`,checked:t.selectable&&me(t),disabled:!t.selectable,onChange:()=>he(t)})}),(0,V.jsx)(`td`,{className:`p-1 whitespace-nowrap`,children:t.createdAt?new Date(t.createdAt).toLocaleString():`—`}),(0,V.jsx)(`td`,{className:`p-1 font-mono text-xs`,children:t.sessionId??t.key}),(0,V.jsx)(`td`,{className:`p-1 font-mono text-xs break-all`,children:t.directory??t.recordedDirectory??`—`}),(0,V.jsx)(`td`,{className:`p-1`,children:we[t.via]})]},t.key))})]}),E.total===0&&(0,V.jsx)(`p`,{className:`text-sm`,children:e(`No sessions match.`)})]}),(0,V.jsxs)(`div`,{className:`flex items-center gap-2 text-sm`,children:[(0,V.jsx)(`button`,{type:`button`,className:Ee,disabled:re||E.offset===0,onClick:()=>void fe(Math.max(0,E.offset-Km),!1),children:e(`Previous`)}),(0,V.jsxs)(`span`,{children:[E.total?E.offset+1:0,`–`,Math.min(E.offset+Km,E.total),` /`,` `,E.total]}),(0,V.jsx)(`button`,{type:`button`,className:Ee,disabled:re||E.offset+Km>=E.total,onClick:()=>void fe(E.offset+Km,!1),children:e(`Next`)})]})]}),(0,V.jsxs)(`label`,{className:`block text-sm`,children:[e(`Import model`),(0,V.jsxs)(dn,{"aria-label":e(`Import model`),className:Te,value:se,onChange:e=>M(e.target.value),children:[(0,V.jsx)(`option`,{value:``,children:e(`None`)}),t!==`claude-code`&&A?.opencode.models.map(e=>(0,V.jsxs)(`option`,{value:`${e.provider}/${e.model}`,children:[e.name,` (`,e.provider,`/`,e.model,`)`]},`${e.provider}/${e.model}`)),(0,V.jsxs)(`option`,{value:`external`,children:[e(`Saved external API`),A?.external.model?` (${A.external.model})`:``,A&&A.external.state!==`ready`?` — ${e(`not ready`)}`:``]})]})]}),t!==`claude-code`&&A&&!A.opencode.available&&(0,V.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:e(`An import with an OpenCode signed-in model runs from the terminal or with /import in OpenCode.`)}),(0,V.jsxs)(`p`,{className:`text-xs text-muted-foreground`,children:[e(`Configured, not tested.`),` `,(0,V.jsx)(`button`,{type:`button`,className:`underline`,onClick:()=>document.getElementById(`settings-health`)?.scrollIntoView(),children:e(`Test models in Health`)})]}),(0,V.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,V.jsx)(`button`,{type:`button`,className:Ee,disabled:be||_e||!!ye,onClick:()=>void xe(!0),children:e(`Preview (dry run)`)}),(0,V.jsx)(`button`,{type:`button`,className:Ee,disabled:be||_e||!!ye||!!ve,onClick:()=>void xe(!1),children:e(`Start import`)}),be&&(0,V.jsx)(`button`,{type:`button`,className:Ee,disabled:N?.state===`cancelling`,onClick:()=>void Se(),children:e(`Cancel after current unit`)})]}),(ye||ve)&&!be&&(0,V.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:ye??ve}),F&&(0,V.jsx)(`p`,{role:`alert`,children:F}),N&&(0,V.jsxs)(`div`,{role:`status`,className:`text-sm`,children:[N.host,` · `,N.dryRun?e(`Preview (dry run)`):e(`Import`),` · `,e(N.state),` ·`,` `,N.sessions,` `,e(`sessions`),` · `,N.processed,`/`,N.total,` `,e(`units`),N.error&&(0,V.jsx)(`p`,{role:`alert`,children:N.error}),N.report&&(0,V.jsx)(`pre`,{className:`mt-2 overflow-auto whitespace-pre-wrap rounded bg-background p-3 text-xs`,children:N.report})]})]})}function Qm(e){return Object.values(e).some(e=>e?.state===`running`)}function $m(e){return!e||e.total<=0?null:{percent:e.percent,done:`${e.done.toLocaleString(`en-US`)} / ${e.total.toLocaleString(`en-US`)}`,minutesLeft:e.minutesLeft===null?`unknown`:`about ${e.minutesLeft}`}}function eh(e,t){let n=e?.state===`running`,r=e?.paused===!0;return{runNow:!n&&!r&&!t,pause:n&&!r,resume:r&&!t}}function th(e,t){return e??!t}function nh(e,t){let n=t.indexOf(`/`);if(t!==`inherit`&&t!==`external`&&(n<1||n===t.length-1))throw Error(`Enter a model as provider/model.`);return{[`${e}BackfillModel`]:t}}var rh=[`pi`,`opencode`,`claude-code`];function ih(){let e=ym(),[t,n]=(0,_.useState)(),[r,i]=(0,_.useState)({pi:null,opencode:null,"claude-code":null}),[a,o]=(0,_.useState)(),[s,c]=(0,_.useState)({}),[l,u]=(0,_.useState)({}),[d,f]=(0,_.useState)({}),[p,m]=(0,_.useState)(``),[h,g]=(0,_.useState)(!1),v=Qm(r)||rh.some(e=>a?.[e]?.run?.state===`running`),y=()=>$(`/api/settings/backfill/runs`).then(o).catch(e=>m(e.message));(0,_.useEffect)(()=>{let e=!0;$(`/api/settings`).then(t=>{e&&n(t)}).catch(t=>{e&&m(t.message)}),$(`/api/settings/backfill`).then(t=>{e&&i(t)}).catch(t=>{e&&m(t.message)}),y();for(let t of[`pi`,`opencode`])$(`/api/settings/models?host=${t}`).then(n=>{e&&c(e=>({...e,[t]:n}))}).catch(()=>{e&&c(e=>({...e,[t]:{available:!1}}))});let t=hm(t=>{e&&n(t)});return()=>{e=!1,t()}},[]),(0,_.useEffect)(()=>{if(!v)return;let e=!0,t=setInterval(()=>{$(`/api/settings/backfill`).then(t=>{e&&i(t)}).catch(t=>{e&&m(t.message)}),e&&y()},3e3);return()=>{e=!1,clearInterval(t)}},[v]);async function b(n){if(t){g(!0);try{await $(`/api/settings`,{method:`PATCH`,body:JSON.stringify({edits:n,revision:t.revision})}),m(e(`Saved. Changes apply at the next run.`))}catch(e){m(e.message)}await mm(),g(!1)}}async function x(t,n){g(!0);try{await $(`/api/settings/backfill/${t}/${n}`,{method:`POST`,body:`{}`}),m(e(n===`pause`?`Pausing after the current exchange.`:`Backfill started.`))}catch(e){m(e.message)}await y(),g(!1)}function S(t,n){try{b(nh(t,n.trim()))}catch(t){m(e(t.message))}}return(0,V.jsxs)(`section`,{className:`space-y-3 rounded-xl border border-border bg-card p-4`,"aria-label":e(`Automatic import`),children:[(0,V.jsx)(`h2`,{className:`text-lg font-medium`,children:e(`Automatic import`)}),(0,V.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:e(`Automatic import makes model calls. A model change applies at the next run. Turning it off stops a running import after the current exchange.`)}),(0,V.jsxs)(`label`,{className:`flex items-center gap-2 text-sm`,children:[(0,V.jsx)(`input`,{type:`checkbox`,checked:!!t?.settings.autoBackfill?.globalValue,disabled:h||!t,onChange:e=>void b({autoBackfill:e.target.checked})}),e(`Import past chats automatically`)]}),rh.map(n=>{let i=String(t?.settings[`${n}BackfillModel`]?.globalValue??`inherit`),o=l[n]??i,c=s[n]?.models??[],p=o===`inherit`||o===`external`||c.some(e=>`${e.provider}/${e.model}`===o),m=xm({memoryProvider:t?.settings.memoryProvider?.globalValue,memoryModel:t?.settings.memoryModel?.globalValue,memoryApiUrl:t?.settings.memoryApiUrl?.globalValue,keySet:!!t?.secrets?.memoryApiKey?.set}),g=a?.[n]?.run??null,_=a?.[n]?.runNowUnavailable??null,v=eh(g,_),y=g?.state===`running`?$m(g):null,b=th(d[n],p);return(0,V.jsxs)(`div`,{className:`space-y-2 rounded-lg border border-border p-3 text-sm`,children:[(0,V.jsx)(`h3`,{className:`font-medium`,children:Em(n)}),n===`claude-code`?(0,V.jsx)(`p`,{className:`text-muted-foreground`,children:e(`Claude Code backfill always uses the external API. It has no backfill model setting.`)}):(0,V.jsxs)(V.Fragment,{children:[(0,V.jsxs)(`label`,{className:`block`,children:[e(`Backfill model`),(0,V.jsxs)(dn,{"aria-label":`${Em(n)} ${e(`Backfill model`)}`,className:`mt-1 block w-full rounded border border-border bg-background p-2`,value:b?`typed`:o,onChange:e=>{let t=e.target.value;f(e=>({...e,[n]:t===`typed`})),u(e=>({...e,[n]:t}))},children:[(0,V.jsx)(`option`,{value:`inherit`,children:e(`Same as live capture`)}),(0,V.jsx)(`option`,{value:`external`,disabled:m.length>0,children:e(`External API`)}),c.map(e=>(0,V.jsxs)(`option`,{value:`${e.provider}/${e.model}`,children:[e.name,` (`,e.provider,`/`,e.model,`)`]},`${e.provider}/${e.model}`)),(0,V.jsx)(`option`,{value:`typed`,children:e(`Manual provider/model`)})]})]}),b&&(0,V.jsx)(`input`,{"aria-label":`${n} ${e(`Manual provider/model`)}`,className:`w-full rounded border border-border bg-background p-2`,placeholder:`provider/model`,value:o===`typed`?``:o,onChange:e=>u(t=>({...t,[n]:e.target.value}))}),m.length>0&&(0,V.jsxs)(`p`,{className:`text-xs text-muted-foreground`,children:[e(`External API needs`),`: `,m.join(`, `)]}),s[n]?.available===!1&&(0,V.jsx)(`p`,{children:s[n].reason?e(s[n].reason):e(`Model list unavailable. Enter provider/model manually.`)}),(0,V.jsx)(`button`,{type:`button`,className:`rounded border border-border px-3 py-1.5`,disabled:h||!t,onClick:()=>S(n,o),children:e(`Save model`)})]}),(0,V.jsxs)(`p`,{children:[e(`State`),`:`,` `,g?.paused?e(`paused`):e(g?.state??r[n]?.state??`not started`),g?.state===`running`&&g.surface&&` (${e(`started from ${g.surface}`)})`]}),y&&(0,V.jsxs)(`div`,{className:`space-y-1`,children:[(0,V.jsx)(`div`,{role:`progressbar`,"aria-valuemin":0,"aria-valuemax":100,"aria-valuenow":y.percent,className:`h-2 w-full overflow-hidden rounded bg-muted`,children:(0,V.jsx)(`div`,{className:`h-full bg-primary`,style:{width:`${y.percent}%`}})}),(0,V.jsxs)(`p`,{className:`text-muted-foreground`,children:[y.percent,`% · `,y.done,` · `,e(`Minutes left`),`:`,` `,y.minutesLeft===`unknown`?e(`unknown`):y.minutesLeft.replace(`about`,e(`about`))]})]}),(0,V.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,V.jsx)(`button`,{type:`button`,className:`rounded border border-border px-3 py-1.5`,disabled:h||!v.runNow,onClick:()=>void x(n,`run`),children:e(`Run now`)}),(0,V.jsx)(`button`,{type:`button`,className:`rounded border border-border px-3 py-1.5`,disabled:h||!v.pause,onClick:()=>void x(n,`pause`),children:e(`Pause`)}),(0,V.jsx)(`button`,{type:`button`,className:`rounded border border-border px-3 py-1.5`,disabled:h||!v.resume,onClick:()=>void x(n,`resume`),children:e(`Resume`)})]}),_&&(0,V.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:_}),r[n]&&(0,V.jsxs)(`div`,{className:`space-y-1 text-muted-foreground`,children:[(0,V.jsxs)(`p`,{children:[e(`Imported`),`: `,r[n].counts.imported,` · `,e(`Skipped`),`:`,` `,r[n].counts.skipped,` · `,e(`Failed`),`: `,r[n].counts.failed]}),(0,V.jsxs)(`p`,{children:[e(`Pending`),`: `,r[n].counts.pending,` · `,e(`Unresolved sessions`),`:`,` `,r[n].counts.unresolved,r[n].counts.unresolved>0&&(0,V.jsxs)(V.Fragment,{children:[` `,(0,V.jsx)(`a`,{className:`underline`,href:`#directory-maps`,children:e(`Directory maps`)})]})]}),(0,V.jsxs)(`p`,{children:[e(`Model`),`: `,r[n].model??e(`none`)]}),(0,V.jsxs)(`p`,{children:[e(`Cutoff`),`: `,new Date(r[n].cutoff).toLocaleString()]}),r[n].error&&(0,V.jsx)(`p`,{role:`alert`,children:r[n].error})]})]},n)}),p&&(0,V.jsx)(`p`,{role:`status`,className:`text-sm`,children:p})]})}function ah(){let e=ym(),[t,n]=(0,_.useState)(),[r,i]=(0,_.useState)(),[a,o]=(0,_.useState)(),[s,c]=(0,_.useState)(``),[l,u]=(0,_.useState)(!1);(0,_.useEffect)(()=>{let e=!0;$(`/api/settings`).then(t=>{e&&n(t)}).catch(t=>{e&&c(t.message)}),$(`/api/settings/web-autostart`).then(t=>{e&&i(t)}).catch(t=>{e&&c(t.message)}),$(`/api/settings/version`).then(t=>{e&&o(t)}).catch(()=>{});let t=hm(t=>{e&&n(t)});return()=>{e=!1,t()}},[]);async function d(n){if(t){u(!0);try{await $(`/api/settings`,{method:`PATCH`,body:JSON.stringify({edits:{webServerAutoStart:n},revision:t.revision})}),c(e(`Saved. The login item changes at the next Pi or OpenCode start.`))}catch(e){c(e.message)}await mm(),u(!1)}}return(0,V.jsxs)(`section`,{className:`space-y-3 rounded-xl border border-border bg-card p-4`,"aria-label":e(`Web app`),children:[(0,V.jsx)(`h2`,{className:`text-lg font-medium`,children:e(`Web app`)}),(0,V.jsxs)(`label`,{className:`flex items-center gap-2 text-sm`,children:[(0,V.jsx)(`input`,{type:`checkbox`,checked:!!t?.settings.webServerAutoStart?.globalValue,disabled:l||!t,onChange:e=>void d(e.target.checked)}),e(`Start web app at login`)]}),(0,V.jsxs)(`p`,{className:`text-sm`,children:[e(`Login item`),`: `,e(r?.state??`not installed`)]}),r?.state===`unsupported`&&(0,V.jsx)(`p`,{role:`status`,children:e(`Login items are unsupported on this platform.`)}),r?.state===`no-runtime`&&(0,V.jsx)(`p`,{role:`status`,children:e(`Install Node or Bun to start the web app at login.`)}),a&&(0,V.jsx)(oh,{info:a}),(0,V.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:e(`Use these commands to apply the change now:`)}),(0,V.jsxs)(`div`,{className:`space-y-1 font-mono text-xs`,children:[(0,V.jsx)(`p`,{children:`om-memory-system web`}),(0,V.jsx)(`p`,{children:`om-memory-system web install`}),(0,V.jsx)(`p`,{children:`om-memory-system web uninstall`}),(0,V.jsx)(`p`,{children:`om-memory-system web status`})]}),s&&(0,V.jsx)(`p`,{role:`status`,className:`text-sm`,children:s})]})}function oh({info:e}){let t=ym(),n=Cm(e);return(0,V.jsxs)(`div`,{className:`space-y-1 text-sm`,children:[(0,V.jsxs)(`p`,{children:[t(`Running version`),`: `,e.running,` · `,t(`Global command`),`:`,` `,e.global??t(`not installed globally`)]}),n.kind===`different`&&(0,V.jsx)(`p`,{role:`status`,className:`text-amber-600`,children:t(`The global command's version differs from the running OMMS. Upgrade it:`)}),n.command&&(0,V.jsx)(`p`,{className:`font-mono text-xs`,children:n.command}),(0,V.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:t(`A global install is optional but recommended: the login item and the terminal commands then run without npx.`)})]})}function sh(){let e=ym(),[t,n]=(0,_.useState)(!1),[r,i]=(0,_.useState)(),[a,o]=(0,_.useState)(``);async function s(e){try{i(await $(`/api/settings/log?lines=200${e?`&filter=capture`:``}`)),o(``)}catch(e){o(e.message)}}return(0,_.useEffect)(()=>{s(t)},[t]),(0,V.jsxs)(`section`,{className:`space-y-3 rounded-xl border border-border bg-card p-4`,"aria-label":e(`Log`),children:[(0,V.jsx)(`h2`,{className:`text-lg font-medium`,children:e(`Log`)}),(0,V.jsxs)(`div`,{className:`flex flex-wrap items-center gap-3 text-sm`,children:[(0,V.jsxs)(`label`,{children:[(0,V.jsx)(`input`,{type:`checkbox`,checked:t,onChange:e=>n(e.target.checked)}),` `,e(`Capture attempts only`)]}),(0,V.jsx)(`button`,{type:`button`,className:`rounded-lg border border-border px-3 py-1`,onClick:()=>void s(t),children:e(`Refresh`)}),r&&(0,V.jsx)(`button`,{type:`button`,className:`rounded-lg border border-border px-3 py-1`,onClick:()=>void navigator.clipboard.writeText(r.path),children:e(`Copy log path`)})]}),(0,V.jsx)(`p`,{className:`break-all text-xs text-muted-foreground`,children:r?.path}),a&&(0,V.jsx)(`p`,{role:`alert`,children:a}),(0,V.jsx)(`pre`,{className:`max-h-80 overflow-auto rounded-lg bg-background p-3 text-xs whitespace-pre-wrap break-words`,"aria-label":e(`Log lines`),children:r?r.lines.length?r.lines.join(`
124
- `):e(`No log has been written yet.`):e(`Loading log…`)})]})}function ch(){return(0,V.jsxs)(`div`,{className:`settings-view space-y-6`,children:[(0,V.jsx)(jm,{}),(0,V.jsx)(Om,{}),(0,V.jsx)(zm,{}),(0,V.jsx)(Bm,{}),(0,V.jsx)(Zm,{}),(0,V.jsx)(ih,{}),(0,V.jsx)(Mm,{}),(0,V.jsx)(ah,{}),(0,V.jsx)(sh,{})]})}var lh=Fr(`grid gap-0.5 rounded-2xl border px-4 py-3 text-left text-sm has-data-[slot=alert-action]:relative has-data-[slot=alert-action]:pr-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2.5 *:[svg]:row-span-2 *:[svg]:translate-y-0.5 *:[svg]:text-current *:[svg:not([class*='size-'])]:size-4 group/alert relative w-full`,{variants:{variant:{default:`bg-card text-card-foreground`,destructive:`text-destructive bg-card *:data-[slot=alert-description]:text-destructive/90 *:[svg]:text-current`}},defaultVariants:{variant:`default`}});function uh({className:e,variant:t,...n}){return(0,V.jsx)(`div`,{"data-slot":`alert`,role:`alert`,className:B(lh({variant:t}),e),...n})}function dh({className:e,...t}){return(0,V.jsx)(`div`,{"data-slot":`alert-description`,className:B(`text-muted-foreground text-sm [&_p]:leading-relaxed col-start-2`,e),...t})}function fh({...e}){let t=El();return(0,V.jsx)(Un,{theme:t,className:`toaster group`,style:{"--normal-bg":`var(--color-popover)`,"--normal-text":`var(--color-popover-foreground)`,"--normal-border":`var(--color-border)`},icons:{loading:(0,V.jsx)(ce,{className:`size-4 animate-spin`}),success:(0,V.jsx)(oe,{className:`size-4`}),error:(0,V.jsx)(I,{className:`size-4`}),info:(0,V.jsx)(P,{className:`size-4`}),warning:(0,V.jsx)(Ae,{className:`size-4`})},...e})}function ph(e,t,n){return e?t:n}var mh=[``,`feature`,`bug-fix`,`refactor`,`architecture`,`rule`,`documentation`,`discussion`,`analysis`,`configuration`];function hh(){let{t:e,language:t}=lr(),n=fl(),[r,i]=(0,_.useState)(!1),a=ur(),o=dr();(0,_.useEffect)(()=>{let e=ul();(async()=>{await a.loadTags(),await a.loadMemories(),await a.loadStats(),await a.checkMigrationStatus(),await a.checkAuthWarning()})();let t=setInterval(()=>{a.loadStats(),!a.isSearching&&n===`project`&&a.loadMemories()},3e4);return()=>{e(),clearInterval(t)}},[]);let s=o.loadUserProfile;(0,_.useEffect)(()=>{n===`profile`&&s()},[n,s]);function c(e){e!==t&&(ar(e),a.loadMemories(),a.loadStats(),n===`profile`&&o.loadUserProfile())}function l(e){e.defaultPrevented||e.button!==0||e.metaKey||e.ctrlKey||e.shiftKey||e.altKey||(e.preventDefault(),ll(Qc.home))}return(0,V.jsxs)(V.Fragment,{children:[(0,V.jsx)(fh,{richColors:!0,position:`bottom-right`}),(0,V.jsxs)(`div`,{className:`flex min-h-svh bg-background text-foreground`,children:[(0,V.jsx)(Al,{open:r,onOpenChange:i,currentView:n,brand:e(`brand`),projectLabel:e(`tab-project`),profileLabel:e(`tab-profile`),profileSections:[{id:`profile-preferences`,label:e(`profile-preferences`)},{id:`profile-patterns`,label:e(`profile-patterns`)},{id:`profile-workflows`,label:e(`profile-workflows`)}],langLabel:t.toUpperCase(),languageLabel:e(`nav-language`),themeLabel:e(`nav-theme`),settingsLabel:e(`nav-settings`),closeLabel:e(`nav-close`),collapseLabel:e(`nav-collapse`),expandLabel:e(`nav-expand`),onLanguageSelect:c}),(0,V.jsxs)(`div`,{className:`flex min-w-0 flex-1 flex-col`,children:[(0,V.jsxs)(`div`,{className:`sticky top-0 z-30 flex items-center gap-2 border-b border-border bg-background/95 px-3 py-2 backdrop-blur md:hidden`,children:[(0,V.jsx)(W,{variant:`ghost`,size:`icon-sm`,onClick:()=>i(!0),"aria-label":e(`nav-menu`),children:(0,V.jsx)(ue,{className:`size-4`})}),(0,V.jsx)(`a`,{href:Qc.home,className:`truncate text-sm tracking-wide text-primary`,onClick:l,children:e(`brand`)})]}),(0,V.jsxs)(`div`,{className:`mx-auto w-full max-w-6xl flex-1 space-y-4 p-4 md:p-6`,children:[a.showAuthWarning?(0,V.jsxs)(uh,{variant:`destructive`,children:[(0,V.jsx)(Ae,{}),(0,V.jsx)(dh,{children:e(`auth-warning-text`)})]}):null,(0,V.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-2`,children:[(0,V.jsx)(`h1`,{className:`text-base tracking-wide text-primary`,children:e(n===`project`?`tab-project`:n===`profile`?`tab-profile`:`nav-settings`)}),n===`project`?(0,V.jsxs)(`div`,{className:`flex items-center gap-2 text-xs text-muted-foreground`,children:[(0,V.jsx)(`span`,{children:e(`text-total`,{count:ph(a.isSearching,a.totalItems,a.statsTotal)})}),a.refreshing?(0,V.jsx)(le,{className:`size-3.5 animate-spin`}):null]}):null]}),n===`project`?(0,V.jsxs)(V.Fragment,{children:[(0,V.jsxs)(`div`,{className:`flex flex-wrap items-end gap-3 rounded-xl border border-border bg-card p-3`,children:[(0,V.jsxs)(`div`,{className:`min-w-0 max-w-full space-y-1`,children:[(0,V.jsx)(Nl,{htmlFor:`tag-filter`,children:e(`label-tag`)}),(0,V.jsxs)(dn,{id:`tag-filter`,className:`flex h-8 w-64 max-w-full rounded-lg border border-border bg-background px-2 text-sm`,value:a.selectedTag,onChange:e=>a.onTagFilterChange(e.currentTarget.value),children:[(0,V.jsx)(`option`,{value:``,children:e(`opt-all-tags`)}),a.tags.map(e=>(0,V.jsx)(`option`,{value:e.tag,children:e.displayName||e.tag},e.tag))]})]}),a.selectedKeyword?(0,V.jsxs)(`div`,{className:`space-y-1`,children:[(0,V.jsx)(`span`,{className:`block text-sm font-medium`,children:e(`label-keyword`)}),(0,V.jsxs)(`div`,{className:`flex h-8 items-center gap-1`,children:[(0,V.jsx)(Ll,{keyword:a.selectedKeyword,active:!0}),(0,V.jsx)(W,{variant:`ghost`,size:`icon-xs`,onClick:()=>a.onKeywordFilterChange(``),"aria-label":e(`btn-clear-keyword`),title:e(`btn-clear-keyword`),children:(0,V.jsx)(Pe,{className:`size-3.5`})})]})]}):null,(0,V.jsxs)(`div`,{className:`flex flex-1 items-end gap-1.5 min-w-56`,children:[(0,V.jsxs)(`div`,{className:`flex-1 space-y-1`,children:[(0,V.jsx)(Nl,{htmlFor:`search-input`,className:`sr-only`,children:e(`placeholder-search`)}),(0,V.jsx)(tm,{id:`search-input`,placeholder:e(`placeholder-search`),value:a.searchInput,onChange:e=>a.setSearchInput(e.target.value),onKeyDown:e=>e.key===`Enter`&&a.performSearch()})]}),(0,V.jsx)(W,{variant:`outline`,size:`icon`,onClick:a.performSearch,children:(0,V.jsx)(Ce,{className:`size-4`})}),a.isSearching?(0,V.jsx)(W,{variant:`outline`,size:`icon`,onClick:a.clearSearch,children:(0,V.jsx)(Pe,{className:`size-4`})}):null]}),(0,V.jsxs)(`div`,{className:`flex flex-wrap gap-1.5`,children:[(0,V.jsx)(zl,{content:e(`tooltip-cleanup`),children:(0,V.jsxs)(W,{variant:`outline`,size:`sm`,onClick:a.runCleanup,children:[(0,V.jsx)(ke,{className:`size-3.5`}),e(`btn-cleanup`)]})}),(0,V.jsx)(zl,{content:e(`tooltip-deduplicate`),children:(0,V.jsxs)(W,{variant:`outline`,size:`sm`,onClick:a.runDeduplication,children:[(0,V.jsx)(xe,{className:`size-3.5`}),e(`btn-deduplicate`)]})})]}),a.selectedIds.size>0?(0,V.jsxs)(`div`,{className:`flex w-full flex-wrap items-center gap-2 border-t border-border pt-3`,children:[(0,V.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:e(`text-selected`,{count:a.selectedIds.size})}),(0,V.jsx)(W,{variant:`secondary`,size:`xs`,onClick:a.selectAllCurrentPage,children:e(`btn-select-all`)}),(0,V.jsx)(W,{variant:`destructive`,size:`xs`,onClick:a.bulkDelete,children:e(`btn-delete-selected`)}),(0,V.jsx)(W,{variant:`ghost`,size:`xs`,onClick:a.deselectAll,children:e(`btn-deselect-all`)})]}):null]}),a.migrationNeeded?(0,V.jsxs)(uh,{variant:`destructive`,className:`space-y-3`,children:[(0,V.jsx)(Ae,{}),(0,V.jsxs)(dh,{className:`space-y-3`,children:[(0,V.jsx)(`p`,{children:a.migrationMessage||e(`migration-mismatch`)}),(0,V.jsxs)(`label`,{className:`flex items-start gap-2 text-sm`,children:[(0,V.jsx)(Ui,{checked:a.migrationConfirmed,onCheckedChange:e=>a.setMigrationConfirmed(e===!0),className:`mt-0.5`}),(0,V.jsx)(`span`,{children:e(`migration-understand`)})]}),(0,V.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,V.jsx)(W,{variant:`destructive`,size:`sm`,disabled:!a.migrationConfirmed,onClick:()=>a.runMigration(`fresh-start`),children:e(`btn-fresh-start`)}),(0,V.jsx)(W,{variant:`secondary`,size:`sm`,disabled:!a.migrationConfirmed,onClick:()=>a.runMigration(`re-embed`),children:e(`btn-reembed`)})]})]})]}):null,(0,V.jsx)(rp,{memories:a.memories,selectedIds:a.selectedIds,currentPage:a.currentPage,totalPages:a.totalPages,totalItems:a.totalItems,isSearching:a.isSearching,loading:a.loadingMemories,error:a.memoriesError,onSelect:a.onSelect,onPageChange:e=>{let t=a.currentPage+e;a.setCurrentPage(t),a.loadMemories({page:t})},onPin:a.pinMemory,onUnpin:a.unpinMemory,onEdit:a.openEdit,onDeleteMemory:a.deleteMemory,onDeletePrompt:a.deletePrompt,activeKeyword:a.selectedKeyword,onKeywordClick:e=>a.onKeywordFilterChange(a.selectedKeyword.toLowerCase()===e.toLowerCase()?``:e)}),(0,V.jsxs)(`section`,{className:`rounded-xl border border-border bg-card p-4 space-y-3`,children:[(0,V.jsx)(`h2`,{className:`text-sm text-muted-foreground`,children:e(`section-add`)}),(0,V.jsxs)(`form`,{className:`space-y-3`,onSubmit:a.addMemory,children:[(0,V.jsxs)(`div`,{className:`grid gap-3 md:grid-cols-3`,children:[(0,V.jsxs)(`div`,{className:`space-y-1`,children:[(0,V.jsx)(Nl,{htmlFor:`add-tag`,children:e(`label-tag`)}),(0,V.jsxs)(dn,{id:`add-tag`,required:!0,className:`flex h-8 w-full rounded-lg border border-border bg-background px-2 text-sm`,value:a.addTag,onChange:e=>a.setAddTag(e.target.value),children:[(0,V.jsx)(`option`,{value:``,children:e(`opt-select-tag`)}),a.tags.map(e=>(0,V.jsx)(`option`,{value:e.tag,children:e.displayName||e.tag},e.tag))]})]}),(0,V.jsxs)(`div`,{className:`space-y-1`,children:[(0,V.jsx)(Nl,{htmlFor:`add-type`,children:e(`label-type`)}),(0,V.jsx)(dn,{id:`add-type`,className:`flex h-8 w-full rounded-lg border border-border bg-background px-2 text-sm`,value:a.addType,onChange:e=>a.setAddType(e.target.value),children:mh.map(t=>(0,V.jsx)(`option`,{value:t,children:e(t?`opt-${t}`:`opt-other`)},t||`other`))})]}),(0,V.jsxs)(`div`,{className:`space-y-1`,children:[(0,V.jsx)(Nl,{htmlFor:`add-tags`,children:e(`label-tags`)}),(0,V.jsx)(tm,{id:`add-tags`,placeholder:e(`placeholder-tags`),value:a.addTags,onChange:e=>a.setAddTags(e.target.value)})]})]}),(0,V.jsxs)(`div`,{className:`space-y-1`,children:[(0,V.jsx)(Nl,{htmlFor:`add-content`,children:e(`label-content`)}),(0,V.jsx)(Pl,{id:`add-content`,rows:4,required:!0,placeholder:e(`placeholder-content`),value:a.addContent,onChange:e=>a.setAddContent(e.target.value)})]}),(0,V.jsxs)(W,{type:`submit`,children:[(0,V.jsx)(ye,{className:`size-3.5`}),e(`btn-add-memory`)]})]})]})]}):n===`settings`?(0,V.jsx)(ch,{}):(0,V.jsx)(cm,{profile:o.userProfile,loading:o.loadingProfile,onRefresh:o.refreshProfile,onCleanup:()=>o.setAiCleanupOpen(!0)})]})]})]}),(0,V.jsx)(Fl,{open:a.editOpen,onOpenChange:a.setEditOpen,content:a.editContent,onSave:a.saveEdit}),(0,V.jsx)(lm,{open:a.tagMigrationOpen,onOpenChange:a.setTagMigrationOpen,count:a.tagMigrationCount,onComplete:()=>{a.loadMemories(),a.loadStats()}}),(0,V.jsx)(Mc,{open:o.aiCleanupOpen,onOpenChange:o.setAiCleanupOpen,profile:o.userProfile,onApplied:o.loadUserProfile})]})}Tl();var gh=document.getElementById(`app`);if(!gh)throw Error(`Root element #app not found`);(0,v.createRoot)(gh).render((0,V.jsx)(_.StrictMode,{children:(0,V.jsx)(cr,{children:(0,V.jsx)(hh,{})})}));
122
+ `):e.evidence:``}function sm(e){return e.evidence?Array.isArray(e.evidence)?e.evidence.length:1:0}function cm({profile:e,loading:t=!1,onRefresh:n,onCleanup:r}){let{t:i}=lr(),[a,o]=(0,_.useState)({pref:1,pat:1,wf:1}),[s,c]=(0,_.useState)(!1),[l,u]=(0,_.useState)(!1),[d,f]=(0,_.useState)(null),[p,m]=(0,_.useState)(0),[h,g]=(0,_.useState)(`edit`),[v,y]=(0,_.useState)(null),b=(0,_.useMemo)(()=>{if(!e?.exists||!e.profileData)return null;let t=e.profileData;if(typeof t==`string`)try{t=JSON.parse(t)}catch{return null}return t},[e]),x=(0,_.useMemo)(()=>Oc(b?.preferences),[b]),S=(0,_.useMemo)(()=>Oc(b?.patterns),[b]),C=(0,_.useMemo)(()=>Oc(b?.workflows),[b]),w=(0,_.useMemo)(()=>C.map((e,t)=>({item:e,index:t})).sort((e,t)=>(t.item.frequency||0)-(e.item.frequency||0)),[C]),T=im(x,a.pref),E=im(S,a.pat),D=im(w,a.wf),O=C.length;function te(e,t,n){let r=(e===`preferences`?x:e===`patterns`?S:C)[t];r&&(f(e),m(t),g(n),y(r),u(!0))}function re(e,t){return e.indexOf(t)}function ie({page:e,pageKey:t}){return e.total<=rm?null:(0,V.jsxs)(`div`,{className:`flex flex-wrap items-center gap-1.5 pt-2`,children:[(0,V.jsxs)(`span`,{className:`text-xs text-muted-foreground mr-2`,children:[e.start+1,`-`,Math.min(e.start+rm,e.total),` / `,e.total]}),Array.from({length:e.totalPages},(e,t)=>t+1).map(n=>(0,V.jsx)(W,{size:`xs`,variant:n===e.page?`default`:`outline`,onClick:()=>o(e=>({...e,[t]:n})),children:n},n))]})}function k({item:e,type:t,fullList:n}){let r=re(n,e),a=am(e);return(0,V.jsxs)(`div`,{className:`rounded-xl border border-border bg-card/50 p-3 space-y-2`,children:[(0,V.jsxs)(`div`,{className:`flex items-start gap-2`,children:[(0,V.jsx)(J,{variant:`outline`,children:e.category||`General`}),(0,V.jsxs)(`div`,{className:`flex items-center gap-0.5 ml-auto`,children:[(0,V.jsx)(W,{variant:`ghost`,size:`icon-xs`,title:i(`btn-edit`)||`Edit`,onClick:()=>te(t,r,`edit`),children:(0,V.jsx)(ge,{className:`size-3`})}),(0,V.jsx)(W,{variant:`ghost`,size:`icon-xs`,title:i(`btn-delete`)||`Delete`,onClick:()=>te(t,r,`delete`),children:(0,V.jsx)(Oe,{className:`size-3`})})]}),(0,V.jsxs)(`div`,{className:`size-9 rounded-full border border-border grid place-items-center text-[10px] tabular-nums shrink-0`,title:`${a}%`,children:[a,`%`]})]}),(0,V.jsx)(`p`,{className:`text-sm`,children:e.description||``}),e.evidence||e.frequency?(0,V.jsxs)(`div`,{className:`flex items-center gap-1.5 text-xs text-muted-foreground`,children:[(0,V.jsxs)(`span`,{className:`inline-flex items-center gap-1`,title:i(`label-evidence-tooltip`,{count:e.frequency||1}),children:[(0,V.jsx)(De,{className:`size-3`}),e.frequency||1]}),sm(e)>0?(0,V.jsxs)(V.Fragment,{children:[(0,V.jsx)(`span`,{children:`·`}),(0,V.jsxs)(`span`,{className:`inline-flex items-center gap-1`,title:om(e),children:[(0,V.jsx)(P,{className:`size-3`}),sm(e),` evidence`]})]}):null]}):null]})}return t&&!e?(0,V.jsx)(`div`,{className:`text-sm text-muted-foreground py-8 text-center`,children:i(`loading-profile`)}):e?.exists?b?(0,V.jsxs)(V.Fragment,{children:[(0,V.jsxs)(`div`,{className:`space-y-6`,children:[(0,V.jsxs)(`div`,{className:`space-y-2`,children:[(0,V.jsx)(`h3`,{className:`text-base font-medium`,children:e.displayName||e.userId}),(0,V.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,V.jsxs)(`span`,{className:`rounded-full bg-muted px-2.5 py-1 text-xs`,children:[(0,V.jsx)(`span`,{className:`text-muted-foreground`,children:i(`profile-version`)}),(0,V.jsx)(`span`,{className:`ml-1`,children:e.version})]}),(0,V.jsxs)(`span`,{className:`rounded-full bg-muted px-2.5 py-1 text-xs`,children:[(0,V.jsx)(`span`,{className:`text-muted-foreground`,children:i(`profile-prompts`)}),(0,V.jsx)(`span`,{className:`ml-1`,children:e.totalPromptsAnalyzed})]}),(0,V.jsxs)(`span`,{className:`rounded-full bg-muted px-2.5 py-1 text-xs`,children:[(0,V.jsx)(`span`,{className:`text-muted-foreground`,children:i(`profile-updated`)}),(0,V.jsx)(`span`,{className:`ml-1`,children:e.lastAnalyzedAt?Y(e.lastAnalyzedAt):`—`})]}),(0,V.jsxs)(`div`,{className:`ms-auto flex flex-wrap items-center gap-1.5`,children:[(0,V.jsxs)(W,{variant:`outline`,size:`sm`,onClick:()=>r?.(),children:[(0,V.jsx)(Te,{className:`size-3.5`}),i(`btn-ai-cleanup`)]}),(0,V.jsxs)(W,{variant:`secondary`,size:`sm`,onClick:()=>n?.(),children:[(0,V.jsx)(xe,{className:`size-3.5`}),i(`btn-refresh`)]}),(0,V.jsxs)(W,{variant:`secondary`,size:`sm`,onClick:()=>c(!0),children:[(0,V.jsx)(Se,{className:`size-3.5`}),`History`]})]})]})]}),(0,V.jsxs)(`div`,{className:`grid gap-6`,children:[(0,V.jsxs)(`section`,{id:`profile-preferences`,className:`scroll-mt-4 space-y-3`,children:[(0,V.jsxs)(`h4`,{className:`flex items-center gap-2 text-sm font-medium`,children:[(0,V.jsx)(N,{className:`size-4`}),i(`profile-preferences`),(0,V.jsx)(`span`,{className:`text-muted-foreground`,children:x.length})]}),x.length===0?(0,V.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:i(`empty-preferences`)}):(0,V.jsxs)(V.Fragment,{children:[(0,V.jsx)(`div`,{className:`grid gap-2 sm:grid-cols-2 lg:grid-cols-3`,children:T.items.map(e=>(0,V.jsx)(k,{item:e,type:`preferences`,fullList:x},re(x,e)))}),(0,V.jsx)(ie,{page:T,pageKey:`pref`})]})]}),(0,V.jsxs)(`section`,{id:`profile-patterns`,className:`scroll-mt-4 space-y-3`,children:[(0,V.jsxs)(`h4`,{className:`flex items-center gap-2 text-sm font-medium`,children:[(0,V.jsx)(ee,{className:`size-4`}),i(`profile-patterns`),(0,V.jsx)(`span`,{className:`text-muted-foreground`,children:S.length})]}),S.length===0?(0,V.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:i(`empty-patterns`)}):(0,V.jsxs)(V.Fragment,{children:[(0,V.jsx)(`div`,{className:`grid gap-2 sm:grid-cols-2 lg:grid-cols-3`,children:E.items.map(e=>(0,V.jsx)(k,{item:e,type:`patterns`,fullList:S},re(S,e)))}),(0,V.jsx)(ie,{page:E,pageKey:`pat`})]})]}),(0,V.jsxs)(`section`,{id:`profile-workflows`,className:`scroll-mt-4 space-y-3`,children:[(0,V.jsxs)(`h4`,{className:`flex items-center gap-2 text-sm font-medium`,children:[(0,V.jsx)(Ne,{className:`size-4`}),i(`profile-workflows`),(0,V.jsx)(`span`,{className:`text-muted-foreground`,children:O})]}),O===0?(0,V.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:i(`empty-workflows`)}):(0,V.jsxs)(V.Fragment,{children:[(0,V.jsx)(`div`,{className:`space-y-2`,children:D.items.map(e=>{let t=e.item,n=e.index,r=am(t);return(0,V.jsxs)(`div`,{className:`rounded-xl border border-border bg-card/50 p-3 space-y-2`,children:[(0,V.jsxs)(`div`,{className:`flex items-start gap-2`,children:[(0,V.jsx)(`div`,{className:`text-sm font-medium flex-1`,children:t.description||``}),(0,V.jsxs)(`div`,{className:`flex items-center gap-0.5`,children:[(0,V.jsx)(W,{variant:`ghost`,size:`icon-xs`,onClick:()=>te(`workflows`,n,`edit`),children:(0,V.jsx)(ge,{className:`size-3`})}),(0,V.jsx)(W,{variant:`ghost`,size:`icon-xs`,onClick:()=>te(`workflows`,n,`delete`),children:(0,V.jsx)(Oe,{className:`size-3`})})]}),(0,V.jsxs)(`div`,{className:`size-9 rounded-full border border-border grid place-items-center text-[10px] tabular-nums shrink-0`,children:[r,`%`]})]}),t.steps?.length?(0,V.jsx)(`div`,{className:`flex flex-wrap items-center gap-1.5`,children:t.steps.map((e,n)=>(0,V.jsxs)(`div`,{className:`contents`,children:[(0,V.jsxs)(`div`,{className:`inline-flex items-center gap-1.5 rounded-lg bg-muted px-2 py-1 text-xs`,children:[(0,V.jsx)(`span`,{className:`text-muted-foreground tabular-nums`,children:n+1}),(0,V.jsx)(`span`,{children:e})]}),n<(t.steps?.length||0)-1?(0,V.jsx)(ne,{className:`size-3 text-muted-foreground`}):null]},n))}):null,(0,V.jsxs)(`div`,{className:`flex items-center gap-1.5 text-xs text-muted-foreground`,children:[(0,V.jsxs)(`span`,{className:`inline-flex items-center gap-1`,title:i(`label-evidence-tooltip`,{count:t.frequency||1}),children:[(0,V.jsx)(De,{className:`size-3`}),t.frequency||1]}),sm(t)>0?(0,V.jsxs)(V.Fragment,{children:[(0,V.jsx)(`span`,{children:`·`}),(0,V.jsxs)(`span`,{className:`inline-flex items-center gap-1`,title:om(t),children:[(0,V.jsx)(P,{className:`size-3`}),sm(t),` evidence`]})]}):null]})]},e.index)})}),(0,V.jsx)(ie,{page:D,pageKey:`wf`})]})]})]})]}),(0,V.jsx)(em,{open:s,onOpenChange:c,profileId:e?.id||``}),(0,V.jsx)(nm,{open:l,onOpenChange:u,type:d,index:p,action:h,item:v,onSaved:n})]}):null:(0,V.jsxs)(`div`,{className:`flex flex-col items-center gap-2 py-10 text-muted-foreground`,children:[(0,V.jsx)(je,{className:`size-8`}),(0,V.jsx)(`p`,{className:`text-sm`,children:e?.message||i(`empty-preferences`)})]})}function lm({open:e=!1,count:t=0,onOpenChange:n,onComplete:r}){let{t:i}=lr(),[a,o]=(0,_.useState)(!1),[s,c]=(0,_.useState)(``),[l,u]=(0,_.useState)(0);(0,_.useEffect)(()=>{e&&!a&&(c(i(`migration-found-tags`,{count:t})),u(0))},[e,a,t,i]);function d(e){a&&!e||n?.(e)}async function f(){o(!0),c(i(`status-migration-init`)),u(0);let e=!0,t=0,n=1e3;for(;e&&t<n;){t++;let n=await Wn(`/api/migration/tags/run-batch`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({batchSize:3})});if(!n.success||!n.data){c(i(`toast-migration-failed`)+`: `+(n.error||``)),o(!1);return}let r=n.data.processed;e=n.data.hasMore;let a=n.data.total;u(a>0?Math.round(r/a*100):0),c(i(`status-migration-progress`,{current:r,total:a})),e&&await new Promise(e=>setTimeout(e,100))}if(t>=n){c(i(`migration-stopped`)),o(!1);return}u(100),c(i(`toast-migration-success`)),H.success(i(`toast-migration-success`)),setTimeout(()=>{o(!1),d(!1),r?.()},2e3)}return(0,V.jsx)(Os,{open:e,onOpenChange:d,children:(0,V.jsxs)(js,{className:`sm:max-w-md`,showCloseButton:!a,children:[(0,V.jsx)(Ms,{children:(0,V.jsx)(Ps,{children:i(`modal-migration-title`)})}),(0,V.jsxs)(`div`,{className:`space-y-3`,children:[(0,V.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:s}),(0,V.jsx)(`div`,{className:`h-2 rounded-full bg-muted overflow-hidden`,children:(0,V.jsx)(`div`,{className:`h-full bg-primary transition-all duration-200`,style:{width:`${l}%`}})}),(0,V.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:i(`migration-note`)})]}),a?null:(0,V.jsx)(Ns,{children:(0,V.jsxs)(W,{onClick:f,children:[(0,V.jsx)(ve,{className:`size-3.5`}),i(`btn-start-migration`)]})})]})})}async function $(e,t={}){let n=(t.method??`GET`).toUpperCase(),r=n!==`GET`&&n!==`HEAD`,i=await fetch(e,{...t,headers:{"x-omms-token":window.__OMMS_TOKEN__??``,...r||t.body?{"Content-Type":`application/json`}:{},...t.headers}}),a=await i.json();if(!i.ok)throw Error(a.error??`Request failed (${i.status})`);return a}var um=new Set,dm=0;function fm(e){dm++;for(let t of um)t(e)}function pm(){let e=dm;return{isCurrent:()=>dm===e}}async function mm(){try{let e=await $(`/api/settings`);return fm(e),e}catch{return null}}function hm(e){return um.add(e),()=>{um.delete(e)}}function gm(e,t){return`${e.replace(/\.+$/,``)}. ${t}`}var _m={Models:[`模型`,`النماذج`],"External API fallback":[`外部 API 备用模型`,`النموذج الاحتياطي عبر واجهة API الخارجية`],none:[`无`,`لا يوجد`],ready:[`就绪`,`جاهز`],"not ready":[`未就绪`,`غير جاهز`],"Credentials (values hidden)":[`凭据(不显示内容)`,`بيانات الاعتماد (القيم مخفية)`],set:[`已设置`,`مضبوط`],"not set":[`未设置`,`غير مضبوط`],"Effective model":[`当前使用模型`,`النموذج المستخدم`],session:[`会话`,`الجلسة`],"external API":[`外部 API`,`واجهة API الخارجية`],unavailable:[`不可用`,`غير متاح`],"Project override is active. Changes to the global file may not take effect here.":[`项目设置优先。全局文件的更改可能不会在此生效。`,`إعدادات المشروع لها الأولوية. قد لا تسري تغييرات الملف العام هنا.`],"Model choice":[`模型选择`,`اختيار النموذج`],"Session model":[`会话模型`,`نموذج الجلسة`],"Manual model":[`手动选择模型`,`اختيار النموذج يدوياً`],"Manual provider/model":[`手动输入提供商/模型`,`إدخال المزوّد/النموذج يدوياً`],"Model list unavailable. Enter provider/model manually.":[`模型列表不可用。请手动输入提供商/模型。`,`قائمة النماذج غير متاحة. أدخل المزوّد/النموذج يدوياً.`],"OpenCode model list unavailable":[`OpenCode 模型列表不可用`,`قائمة نماذج OpenCode غير متاحة`],"OMMS could not find OpenCode on this computer, so it cannot list OpenCode's models here. Type the model as provider/model, for example zai-coding-plan/glm-5.3. If OpenCode is installed, open an OpenCode session and reload this page.":[`OMMS 在这台电脑上找不到 OpenCode,因此无法在此列出 OpenCode 的模型。请按 提供商/模型 格式输入模型,例如 zai-coding-plan/glm-5.3。如果已安装 OpenCode,请打开一个 OpenCode 会话,然后重新加载此页面。`,`لم يعثر OMMS على OpenCode في هذا الحاسوب، لذا لا يمكنه عرض نماذج OpenCode هنا. أدخل النموذج بصيغة المزوّد/النموذج، مثل zai-coding-plan/glm-5.3. إذا كان OpenCode مثبتاً، فافتح جلسة OpenCode ثم أعد تحميل هذه الصفحة.`],"OpenCode took too long to send its model list. Reload this page to try again, or type the model as provider/model.":[`OpenCode 发送模型列表的时间过长。请重新加载此页面重试,或按 提供商/模型 格式输入模型。`,`استغرق OpenCode وقتاً طويلاً لإرسال قائمة نماذجه. أعد تحميل هذه الصفحة للمحاولة مرة أخرى، أو أدخل النموذج بصيغة المزوّد/النموذج.`],"OpenCode has no signed-in models. Run `opencode auth login`, then reload this page.":["OpenCode 没有已登录的模型。请运行 `opencode auth login`,然后重新加载此页面。","لا توجد في OpenCode نماذج مسجَّل الدخول إليها. شغّل `opencode auth login` ثم أعد تحميل هذه الصفحة."],"This OpenCode version sent a model list OMMS cannot read. Type the model as provider/model. Update OMMS if this continues.":[`此版本的 OpenCode 发送的模型列表 OMMS 无法读取。请按 提供商/模型 格式输入模型。如果问题持续,请更新 OMMS。`,`أرسل هذا الإصدار من OpenCode قائمة نماذج لا يستطيع OMMS قراءتها. أدخل النموذج بصيغة المزوّد/النموذج. حدّث OMMS إذا استمرت المشكلة.`],"OMMS could not read Pi's model list. Type the model as provider/model.":[`OMMS 无法读取 Pi 的模型列表。请按 提供商/模型 格式输入模型。`,`تعذّر على OMMS قراءة قائمة نماذج Pi. أدخل النموذج بصيغة المزوّد/النموذج.`],"Pi has no signed-in models. Sign in to a provider in Pi, then reload this page.":[`Pi 没有已登录的模型。请在 Pi 中登录一个提供商,然后重新加载此页面。`,`لا توجد في Pi نماذج مسجَّل الدخول إليها. سجّل الدخول إلى مزوّد في Pi ثم أعد تحميل هذه الصفحة.`],"Save model":[`保存模型`,`حفظ النموذج`],"Enter a model as provider/model.":[`按 提供商/模型 格式输入。`,`أدخل النموذج بصيغة المزوّد/النموذج.`],"Saved. New capture and profile work uses these settings.":[`已保存。下一次捕获和用户画像将使用这些设置。`,`تم الحفظ. ستستخدم عمليات الالتقاط والملف الشخصي الجديدة هذه الإعدادات.`],"Saved. OMMS now reads ~/.config/omms/omms.jsonc. The legacy config was kept.":[`已保存。OMMS 现在读取 ~/.config/omms/omms.jsonc,旧配置保留。`,`تم الحفظ. يقرأ OMMS الآن الملف ~/.config/omms/omms.jsonc مع الاحتفاظ بالإعدادات القديمة.`],"Current settings were reloaded; check the values and save again.":[`已重新加载当前设置;检查数值后再次保存。`,`أُعيد تحميل الإعدادات الحالية. راجع القيم ثم احفظ مجدداً.`],"Capture diagnostics":[`捕获诊断`,`تشخيص الالتقاط`],"Time range":[`时间范围`,`الفترة الزمنية`],"24 hours":[`24 小时`,`24 ساعة`],"7 days":[`7 天`,`7 أيام`],"30 days":[`30 天`,`30 يوماً`],"90 days":[`90 天`,`90 يوماً`],"Outcomes by model":[`各模型结果`,`النتائج حسب النموذج`],"Host / model":[`主机 / 模型`,`المضيف / النموذج`],Saved:[`已保存`,`محفوظ`],Skipped:[`已跳过`,`متجاوز`],Failed:[`失败`,`فشل`],Total:[`总数`,`المجموع`],"Failure reasons":[`失败原因`,`أسباب الفشل`],"Recent attempts":[`最近尝试`,`المحاولات الأخيرة`],Time:[`时间`,`الوقت`],Host:[`主机`,`المضيف`],Source:[`来源`,`المصدر`],Session:[`会话`,`الجلسة`],Path:[`路径`,`المسار`],Model:[`模型`,`النموذج`],Stop:[`结束原因`,`سبب التوقف`],Blocks:[`区块`,`الكتل`],Prompt:[`提示词长度`,`طول الطلب`],Reply:[`回复长度`,`طول الرد`],Duration:[`耗时`,`المدة`],Outcome:[`结果`,`النتيجة`],Reason:[`原因`,`السبب`],"Save capture traces":[`保存捕获追踪`,`حفظ تتبعات الالتقاط`],"Traces can contain conversation content after redaction. Keep tracing off unless you need it for debugging.":[`追踪文件在脱敏后仍可能包含对话内容。仅在调试时开启。`,`قد تحتوي التتبعات على محتوى المحادثة بعد التنقيح. فعّلها عند التصحيح فقط.`],"This project turns tracing off. The global switch cannot turn it on here.":[`此项目已关闭追踪。全局开关无法在此开启。`,`أوقف هذا المشروع التتبع. لا يمكن للمفتاح العام تفعيله هنا.`],"Trace retention (days)":[`追踪保留天数`,`مدة حفظ التتبعات (بالأيام)`],"Attempt retention (days)":[`尝试记录保留天数`,`مدة حفظ المحاولات (بالأيام)`],"Retry retention (hours)":[`重试保留小时数`,`مدة حفظ إعادة المحاولة (بالساعات)`],"When the capture model cannot be reached, OMMS keeps the turn and tries again later. Queued turns can hold conversation content after redaction. 0 turns the queue off and deletes waiting turns.":[`捕获模型无法访问时,OMMS 会保留该轮对话并稍后重试。排队的对话在脱敏后仍可能包含对话内容。设为 0 会关闭队列并删除等待中的对话。`,`عندما يتعذر الوصول إلى نموذج الالتقاط، يحتفظ OMMS بالجولة ويعيد المحاولة لاحقاً. قد تحتوي الجولات المنتظرة على محتوى المحادثة بعد التنقيح. القيمة 0 توقف قائمة الانتظار وتحذف الجولات المنتظرة.`],"Turns waiting for retry":[`等待重试的对话`,`الجولات المنتظرة لإعادة المحاولة`],"Retry now":[`立即重试`,`أعد المحاولة الآن`],"Retrying now.":[`正在重试。`,`تجري إعادة المحاولة الآن.`],"A retry is already running.":[`重试已在运行。`,`إعادة المحاولة قيد التشغيل بالفعل.`],"These turns retry at the next Pi session start.":[`这些对话将在下次启动 Pi 会话时重试。`,`ستُعاد محاولة هذه الجولات عند بدء جلسة Pi التالية.`],"These turns retry at the next OpenCode session start.":[`这些对话将在下次启动 OpenCode 会话时重试。`,`ستُعاد محاولة هذه الجولات عند بدء جلسة OpenCode التالية.`],"These turns retry at the next Claude Code session start.":[`这些对话将在下次启动 Claude Code 会话时重试。`,`ستُعاد محاولة هذه الجولات عند بدء جلسة Claude Code التالية.`],"Claude Code capture uses the external API.":[`Claude Code 捕获使用外部 API。`,`يستخدم التقاط Claude Code واجهة API الخارجية.`],"Claude Code capture is off. Complete the external API settings.":[`Claude Code 捕获已关闭。请完成外部 API 设置。`,`التقاط Claude Code متوقف. أكمل إعدادات واجهة API الخارجية.`],"Missing settings":[`缺少的设置`,`الإعدادات الناقصة`],"memoryModel is not configured":[`未配置 memoryModel`,`لم يُضبط memoryModel`],"memoryApiUrl is not configured":[`未配置 memoryApiUrl`,`لم يُضبط memoryApiUrl`],"memoryApiKey is not configured":[`未配置 memoryApiKey`,`لم يُضبط memoryApiKey`],"memoryApiKey contains a placeholder value":[`memoryApiKey 包含占位值`,`يحتوي memoryApiKey على قيمة نائبة`],"Claude Code backfill always uses the external API. It has no backfill model setting.":[`Claude Code 回填始终使用外部 API,没有回填模型设置。`,`يستخدم استيراد Claude Code دائماً واجهة API الخارجية، ولا يوجد له إعداد لنموذج الاستيراد.`],"Claude Code transcripts folder":[`Claude Code 对话记录文件夹`,`مجلد سجلات محادثات Claude Code`],"Claude Code transcripts":[`Claude Code 对话记录`,`سجلات محادثات Claude Code`],found:[`已找到`,`موجود`],"not found":[`未找到`,`غير موجود`],"Claude Code imports always use the external API.":[`Claude Code 导入始终使用外部 API。`,`يستخدم استيراد Claude Code دائماً واجهة API الخارجية.`],"Claude Code imports use the external API. Complete the external API settings.":[`Claude Code 导入使用外部 API。请完成外部 API 设置。`,`يستخدم استيراد Claude Code واجهة API الخارجية. أكمل إعدادات واجهة API الخارجية.`],"Trace files":[`追踪文件`,`ملفات التتبع`],View:[`查看`,`عرض`],Delete:[`删除`,`حذف`],Health:[`健康检查`,`فحص الحالة`],"Config files":[`配置文件`,`ملفات الإعدادات`],"Memory store":[`记忆存储`,`مخزن الذاكرة`],Embedding:[`嵌入模型`,`نموذج التضمين`],"Web binding":[`网页服务绑定`,`ربط خادم الويب`],"OpenCode model":[`OpenCode 模型`,`نموذج OpenCode`],"Pi model":[`Pi 模型`,`نموذج Pi`],"Capture failures (24 hours)":[`捕获失败(24 小时)`,`فشل الالتقاط (24 ساعة)`],"OpenCode model test":[`OpenCode 模型测试`,`اختبار نموذج OpenCode`],"Pi model test":[`Pi 模型测试`,`اختبار نموذج Pi`],"Run checks":[`运行检查`,`تشغيل الفحوصات`],"Run checks and test models":[`运行检查并测试模型`,`تشغيل الفحوصات واختبار النماذج`],"Checking…":[`正在检查…`,`جارٍ الفحص…`],pass:[`通过`,`نجاح`],warn:[`警告`,`تحذير`],fail:[`失败`,`فشل`],"Import and backfill":[`导入和回填`,`الاستيراد والاستكمال`],"Automatic import":[`自动导入`,`الاستيراد التلقائي`],"Automatic import makes model calls. Changes apply at the next host start. Turning it off stops a running import after the current exchange.":[`自动导入会调用模型。更改在下次启动主机时生效。关闭后,正在运行的导入将在当前轮次结束后停止。`,`يستدعي الاستيراد التلقائي النموذج. تسري التغييرات عند بدء المضيف التالي. يوقف التعطيل الاستيراد بعد التبادل الحالي.`],"Import past chats automatically":[`自动导入过去的对话`,`استيراد المحادثات السابقة تلقائياً`],"Backfill model":[`历史导入模型`,`نموذج استيراد السجل`],"Same as live capture":[`与实时捕获相同`,`مثل الالتقاط المباشر`],"Saved. Changes apply at the next host start.":[`已保存。更改在下次启动主机时生效。`,`تم الحفظ. تسري التغييرات عند بدء المضيف التالي.`],State:[`状态`,`الحالة`],"not started":[`尚未开始`,`لم يبدأ`],"not-started":[`尚未开始`,`لم يبدأ`],Imported:[`已导入`,`مستورَد`],Pending:[`待处理`,`معلّق`],"Unresolved sessions":[`目录未解析的会话`,`جلسات بمجلدات غير محددة`],Cutoff:[`截止时间`,`وقت القطع`],stopped:[`已停止`,`توقف`],"Web app":[`网页应用`,`تطبيق الويب`],"Start web app at login":[`登录时启动网页应用`,`بدء تطبيق الويب عند تسجيل الدخول`],"Login item":[`登录启动项`,`عنصر بدء تسجيل الدخول`],"not installed":[`未安装`,`غير مثبّت`],"not-installed":[`未安装`,`غير مثبّت`],installed:[`已安装`,`مثبّت`],unsupported:[`不受支持`,`غير مدعوم`],"no-runtime":[`缺少运行环境`,`بيئة التشغيل غير متاحة`],"no-package":[`缺少软件包`,`الحزمة غير متاحة`],"Login items are unsupported on this platform.":[`此平台不支持登录启动项。`,`عناصر بدء تسجيل الدخول غير مدعومة على هذا النظام.`],"Install Node or Bun to start the web app at login.":[`安装 Node 或 Bun 后,网页应用才能在登录时启动。`,`ثبّت Node أو Bun لبدء تطبيق الويب عند تسجيل الدخول.`],"Use these commands to apply the change now:":[`使用以下命令立即应用更改:`,`استخدم هذه الأوامر لتطبيق التغيير الآن:`],"Saved. The login item changes at the next Pi or OpenCode start.":[`已保存。登录启动项将在下次启动 Pi 或 OpenCode 时更新。`,`تم الحفظ. يتغير عنصر بدء التشغيل عند بدء Pi أو OpenCode التالي.`],"History host":[`历史记录主机`,`مضيف السجل`],Scope:[`范围`,`النطاق`],"Current project":[`当前项目`,`المشروع الحالي`],"All projects":[`所有项目`,`كل المشاريع`],"Project directory":[`项目目录`,`مجلد المشروع`],"Current directory":[`当前目录`,`المجلد الحالي`],"Profile batch size":[`用户画像批量大小`,`حجم دفعة الملف الشخصي`],"Directory maps (old=new, one per line)":[`目录映射(旧=新,每行一条)`,`تعيين المجلدات (قديم=جديد، واحد في كل سطر)`],"Force reimport":[`强制重新导入`,`فرض إعادة الاستيراد`],"Skip memories":[`跳过记忆`,`تجاوز الذكريات`],"Skip profile":[`跳过用户画像`,`تجاوز الملف الشخصي`],"Import model":[`导入模型`,`نموذج الاستيراد`],"Saved external API":[`已保存的外部 API`,`واجهة API الخارجية المحفوظة`],"Preview (dry run)":[`预览(不写入)`,`معاينة (تشغيل تجريبي)`],"Start import":[`开始导入`,`بدء الاستيراد`],"Cancel after current unit":[`完成当前单元后取消`,`الإلغاء بعد الوحدة الحالية`],"Directory maps must be old=new, one per line":[`目录映射须为 旧=新,每行一条`,`يجب أن يكون تعيين المجلدات بصيغة قديم=جديد، واحد في كل سطر`],running:[`运行中`,`جارٍ التشغيل`],cancelling:[`正在取消`,`جارٍ الإلغاء`],cancelled:[`已取消`,`أُلغي`],done:[`已完成`,`اكتمل`],failed:[`失败`,`فشل`],units:[`单元`,`وحدات`],"List sessions":[`列出会话`,`عرض الجلسات`],"Refresh list":[`刷新列表`,`تحديث القائمة`],"Advanced options":[`高级选项`,`خيارات متقدمة`],"Hide advanced options":[`隐藏高级选项`,`إخفاء الخيارات المتقدمة`],"default location":[`默认位置`,`الموقع الافتراضي`],"Prompt date from":[`提示日期起`,`تاريخ الطلب من`],"Prompt date to":[`提示日期止`,`تاريخ الطلب إلى`],"Prompt dates are inclusive, use your time zone, and filter the turns inside each session, not the list. Empty dates include every turn.":[`提示日期包含首尾两天,按你所在时区计算,只筛选每个会话中的对话轮次,不筛选列表。留空则包含所有轮次。`,`تواريخ الطلب شاملة لليومين، وتُحسب بمنطقتك الزمنية، وتُصفّي الأدوار داخل كل جلسة لا القائمة. تركها فارغة يشمل كل الأدوار.`],"Sessions with directories that no longer exist":[`目录已不存在的会话`,`جلسات لم تعد مجلداتها موجودة`],"Show them and add a directory map":[`显示它们并添加目录映射`,`اعرضها وأضف تعيين مجلد`],Selected:[`已选择`,`المحدد`],"Select all matching":[`选择所有匹配项`,`تحديد كل المطابق`],"Clear selection":[`清除选择`,`مسح التحديد`],Select:[`选择`,`تحديد`],Created:[`创建时间`,`تاريخ الإنشاء`],"Resolved by":[`解析方式`,`طريقة التحديد`],recorded:[`记录的目录`,`المجلد المسجّل`],mapped:[`目录映射`,`تعيين مجلد`],"project root":[`项目根目录`,`جذر المشروع`],missing:[`缺失`,`مفقود`],"No sessions match.":[`没有匹配的会话。`,`لا توجد جلسات مطابقة.`],Previous:[`上一页`,`السابق`],Next:[`下一页`,`التالي`],None:[`无`,`لا شيء`],"Configured, not tested.":[`已配置,未测试。`,`مُعدّ، لم يُختبر.`],"An import with an OpenCode signed-in model runs from the terminal or with /import in OpenCode.":[`使用 OpenCode 已登录模型的导入需在终端运行,或在 OpenCode 中使用 /import。`,`يتم الاستيراد بنموذج OpenCode المسجَّل الدخول من الطرفية أو بالأمر /import داخل OpenCode.`],"The chosen OpenCode model is not connected here. An import with an OpenCode signed-in model runs from the terminal or with /import in OpenCode. Choose the external API for a web import.":[`所选 OpenCode 模型在此处未连接。使用 OpenCode 已登录模型的导入需在终端运行,或在 OpenCode 中使用 /import。网页导入请选择外部 API。`,`نموذج OpenCode المختار غير متصل هنا. يتم الاستيراد بنموذج OpenCode المسجَّل الدخول من الطرفية أو بالأمر /import داخل OpenCode. اختر واجهة API الخارجية للاستيراد من الصفحة.`],"Test models in Health":[`在健康检查中测试模型`,`اختبر النماذج في قسم السلامة`],Import:[`导入`,`استيراد`],sessions:[`个会话`,`جلسات`],"List sessions first.":[`请先列出会话。`,`اعرض الجلسات أولاً.`],"Options changed. Refresh the session list first.":[`选项已更改。请先刷新会话列表。`,`تغيّرت الخيارات. حدّث قائمة الجلسات أولاً.`],"Select at least one session.":[`请至少选择一个会话。`,`حدّد جلسة واحدة على الأقل.`],"Select at most 1000 sessions one by one, or use Select all matching.":[`逐个选择最多 1000 个会话,或使用“选择所有匹配项”。`,`حدّد 1000 جلسة كحد أقصى واحدة تلو الأخرى، أو استخدم «تحديد كل المطابق».`],"Model readiness is unknown. Reload the page.":[`无法确定模型是否就绪。请重新加载页面。`,`حالة جاهزية النموذج غير معروفة. أعد تحميل الصفحة.`],"No import model is ready. Connect a model in OpenCode or complete the external API settings.":[`没有可用的导入模型。请在 OpenCode 中连接模型,或补全外部 API 设置。`,`لا يوجد نموذج استيراد جاهز. اربط نموذجاً في OpenCode أو أكمل إعدادات واجهة API الخارجية.`],"The external API is not ready":[`外部 API 未就绪`,`واجهة API الخارجية غير جاهزة`],"The external API has no memoryModel in the global config":[`全局配置中缺少外部 API 的 memoryModel`,`لا يحتوي الإعداد العام على memoryModel لواجهة API الخارجية`],"The external API has no memoryApiUrl in the global config":[`全局配置中缺少外部 API 的 memoryApiUrl`,`لا يحتوي الإعداد العام على memoryApiUrl لواجهة API الخارجية`],"The external API key is missing in the OpenCode process; check memoryApiKey and its env:// or file:// source":[`OpenCode 进程中缺少外部 API 密钥;请检查 memoryApiKey 及其 env:// 或 file:// 来源`,`مفتاح واجهة API الخارجية غير موجود في عملية OpenCode؛ تحقّق من memoryApiKey ومصدره env:// أو file://`],"The memoryProvider in the global config is not supported for imports":[`全局配置中的 memoryProvider 不支持导入`,`مزوّد memoryProvider في الإعداد العام غير مدعوم للاستيراد`],"Pi sessions folder or one .jsonl session file":[`Pi 会话文件夹或单个 .jsonl 会话文件`,`مجلد جلسات Pi أو ملف جلسة ‎.jsonl واحد`],"OpenCode database file":[`OpenCode 数据库文件`,`ملف قاعدة بيانات OpenCode`],"Absolute path, for example on a mounted volume":[`绝对路径,例如已挂载卷上的路径`,`مسار مطلق، مثلاً على وحدة تخزين مركّبة`],"Use this source":[`使用此来源`,`استخدم هذا المصدر`],Browse:[`浏览`,`استعراض`],"Use the default location":[`使用默认位置`,`استخدم الموقع الافتراضي`],"Chosen source":[`已选来源`,`المصدر المختار`],Choose:[`选择`,`اختيار`],"Only the first 500 entries are shown.":[`仅显示前 500 项。`,`تُعرض أول 500 عنصر فقط.`],"Reload the page before saving again.":[`再次保存前请重新加载页面。`,`أعد تحميل الصفحة قبل الحفظ مرة أخرى.`],"The current settings could not be reloaded. Reload the page.":[`无法重新加载当前设置。请重新加载页面。`,`تعذّر إعادة تحميل الإعدادات الحالية. أعد تحميل الصفحة.`],Log:[`日志`,`السجل`],"Capture attempts only":[`仅显示捕获尝试`,`محاولات الالتقاط فقط`],Refresh:[`刷新`,`تحديث`],"Copy log path":[`复制日志路径`,`نسخ مسار السجل`],"Log lines":[`日志行`,`أسطر السجل`],"No log has been written yet.":[`尚未写入日志。`,`لم يُكتب سجل بعد.`],"Loading log…":[`正在加载日志…`,`جارٍ تحميل السجل…`],"External API":[`外部 API`,`واجهة API الخارجية`],"An OpenAI- or Anthropic-compatible endpoint that either host can use for capture and backfill.":[`兼容 OpenAI 或 Anthropic 的端点,两个宿主都可用于捕获和回填。`,`نقطة نهاية متوافقة مع OpenAI أو Anthropic يمكن لأي مضيف استخدامها للالتقاط والاستيراد.`],Provider:[`提供商`,`المزوّد`],"API URL":[`API 地址`,`عنوان API`],"API key":[`API 密钥`,`مفتاح API`],"Save endpoint":[`保存端点`,`حفظ نقطة النهاية`],"Nothing to save.":[`没有需要保存的内容。`,`لا يوجد ما يُحفظ.`],"Key source":[`密钥来源`,`مصدر المفتاح`],"environment variable":[`环境变量`,`متغير البيئة`],"key file":[`密钥文件`,`ملف المفتاح`],"set in the config file":[`在配置文件中设置`,`مضبوط في ملف الإعدادات`],"resolves in the web app":[`可在网页应用中解析`,`يُقرأ في تطبيق الويب`],"does not resolve in the web app":[`无法在网页应用中解析`,`لا يُقرأ في تطبيق الويب`],"A login web app does not see variables set only in a shell profile; a key file works everywhere.":[`登录时启动的网页应用看不到仅在 shell 配置文件中设置的变量;密钥文件在任何地方都可用。`,`تطبيق الويب الذي يبدأ عند تسجيل الدخول لا يرى المتغيرات المضبوطة في ملف الصدفة فقط؛ ملف المفتاح يعمل في كل مكان.`],"The key does not resolve in this web app. Save it to a key file instead.":[`此网页应用无法解析该密钥。请改为保存到密钥文件。`,`لا يُقرأ المفتاح في تطبيق الويب هذا. احفظه في ملف مفتاح بدلاً من ذلك.`],"Environment variable":[`环境变量`,`متغير البيئة`],"Key file":[`密钥文件`,`ملف المفتاح`],"Save key to a private file":[`将密钥保存到私有文件`,`حفظ المفتاح في ملف خاص`],"Variable name":[`变量名`,`اسم المتغير`],"Key file path":[`密钥文件路径`,`مسار ملف المفتاح`],"Key file name":[`密钥文件名`,`اسم ملف المفتاح`],"The key is written to ~/.config/omms/secrets/ readable only by you. It is never shown again.":[`密钥写入 ~/.config/omms/secrets/,仅你可读,之后不再显示。`,`يُكتب المفتاح في ~/.config/omms/secrets/ ولا يقرؤه غيرك، ولن يُعرض مرة أخرى.`],"Save key source":[`保存密钥来源`,`حفظ مصدر المفتاح`],"Key source saved.":[`密钥来源已保存。`,`تم حفظ مصدر المفتاح.`],"A key file with this name exists. Replace it?":[`已存在同名密钥文件。要替换吗?`,`يوجد ملف مفتاح بهذا الاسم. هل تريد استبداله؟`],"Enter a variable name such as ZAI_API_KEY":[`请输入变量名,例如 ZAI_API_KEY`,`أدخل اسم متغير مثل ZAI_API_KEY`],"Enter the path of a key file":[`请输入密钥文件路径`,`أدخل مسار ملف المفتاح`],"Name the key file with letters, digits, dashes, or underscores":[`密钥文件名只能包含字母、数字、短横线或下划线`,`سمِّ ملف المفتاح بحروف أو أرقام أو شرطات أو شرطات سفلية`],"Paste the key":[`请粘贴密钥`,`الصق المفتاح`],Test:[`测试`,`اختبار`],"Test call succeeded":[`测试调用成功`,`نجح استدعاء الاختبار`],"Test call failed":[`测试调用失败`,`فشل استدعاء الاختبار`],"External API needs":[`外部 API 缺少`,`تحتاج واجهة API الخارجية إلى`],"Automatic import makes model calls. A model change applies at the next run. Turning it off stops a running import after the current exchange.":[`自动导入会调用模型。模型更改在下次运行时生效。关闭后,正在进行的导入会在当前对话完成后停止。`,`يستدعي الاستيراد التلقائي النماذج. يسري تغيير النموذج في التشغيل التالي. إيقافه يوقف الاستيراد الجاري بعد المحادثة الحالية.`],"Saved. Changes apply at the next run.":[`已保存。更改在下次运行时生效。`,`تم الحفظ. تسري التغييرات في التشغيل التالي.`],paused:[`已暂停`,`متوقف مؤقتاً`],"started from auto":[`自动启动`,`بدأ تلقائياً`],"started from web":[`从网页启动`,`بدأ من الويب`],"started from cli":[`从终端启动`,`بدأ من الطرفية`],"started from slash":[`从斜杠命令启动`,`بدأ من أمر الشرطة المائلة`],"Minutes left":[`剩余分钟`,`الدقائق المتبقية`],unknown:[`未知`,`غير معروف`],about:[`约`,`حوالي`],"Run now":[`立即运行`,`تشغيل الآن`],Pause:[`暂停`,`إيقاف مؤقت`],Resume:[`继续`,`استئناف`],"Pausing after the current exchange.":[`将在当前对话完成后暂停。`,`سيتوقف مؤقتاً بعد المحادثة الحالية.`],"Backfill started.":[`回填已开始。`,`بدأ الاستيراد.`],"Directory maps":[`目录映射`,`خرائط المجلدات`],"Map a directory that was moved or deleted to the project it belongs to. A change applies to the next import or backfill run.":[`将已移动或删除的目录映射到其所属项目。更改在下次导入或回填时生效。`,`اربط مجلداً نُقل أو حُذف بالمشروع الذي ينتمي إليه. يسري التغيير في الاستيراد التالي.`],"Saved maps":[`已保存的映射`,`الخرائط المحفوظة`],Keep:[`保留`,`إبقاء`],Remove:[`移除`,`إزالة`],"Unresolved directories":[`无法解析的目录`,`مجلدات غير محلولة`],"No unresolved directories in the latest run.":[`最近一次运行没有无法解析的目录。`,`لا توجد مجلدات غير محلولة في آخر تشغيل.`],"No suggestion found.":[`未找到建议。`,`لم يُعثر على اقتراح.`],"Target directory":[`目标目录`,`المجلد الهدف`],"Use this map":[`使用此映射`,`استخدام هذه الخريطة`],"Save maps":[`保存映射`,`حفظ الخرائط`],"Saved. Maps apply to the next import or backfill run.":[`已保存。映射在下次导入或回填时生效。`,`تم الحفظ. تسري الخرائط في الاستيراد التالي.`],"Claude Code folder":[`Claude Code 文件夹`,`مجلد Claude Code`],"Set this when Claude Code does not use ~/.claude, for example when you start it with CLAUDE_CONFIG_DIR. Leave it empty to use the default.":[`当 Claude Code 不使用 ~/.claude 时(例如用 CLAUDE_CONFIG_DIR 启动它),请设置此项。留空则使用默认文件夹。`,`اضبط هذا عندما لا يستخدم Claude Code المجلد ‎~/.claude، مثلاً عند تشغيله مع CLAUDE_CONFIG_DIR. اتركه فارغاً لاستخدام المجلد الافتراضي.`],"Save folder":[`保存文件夹`,`حفظ المجلد`],"Transcripts folder in use":[`正在使用的会话记录文件夹`,`مجلد سجلات الجلسات المستخدم`],From:[`来源`,`المصدر`],"this setting":[`此设置`,`هذا الإعداد`],"the CLAUDE_CONFIG_DIR variable of the web app":[`网页应用的 CLAUDE_CONFIG_DIR 变量`,`متغير CLAUDE_CONFIG_DIR لتطبيق الويب`],"the default folder":[`默认文件夹`,`المجلد الافتراضي`],"This folder does not exist. Claude Code capture and import will not work:":[`此文件夹不存在。Claude Code 的捕获和导入将无法工作:`,`هذا المجلد غير موجود. لن يعمل الالتقاط والاستيراد في Claude Code:`],"Enter a full path, or a path that starts with ~/.":[`请输入完整路径,或以 ~/ 开头的路径。`,`أدخل مساراً كاملاً، أو مساراً يبدأ بـ ‎~/.`],"Saved. Capture and import use this folder now.":[`已保存。捕获和导入现在使用此文件夹。`,`تم الحفظ. يستخدم الالتقاط والاستيراد هذا المجلد الآن.`],"Running version":[`运行版本`,`الإصدار الجاري`],"Global command":[`全局命令`,`الأمر العام`],"not installed globally":[`未全局安装`,`غير مثبت عمومياً`],"The global command's version differs from the running OMMS. Upgrade it:":[`全局命令的版本与正在运行的 OMMS 不同。请升级:`,`يختلف إصدار الأمر العام عن OMMS الجاري. حدّثه:`],"A global install is optional but recommended: the login item and the terminal commands then run without npx.":[`全局安装是可选的,但建议安装:这样登录项和终端命令无需 npx 即可运行。`,`التثبيت العام اختياري لكنه موصى به: يعمل عنصر تسجيل الدخول وأوامر الطرفية حينها دون npx.`]};function vm(e,t){return t===`en`?e:_m[e]?.[t===`zh`?0:1]??e}function ym(){let{language:e}=lr();return t=>vm(t,e)}function bm(e,t){if(e===`env`){let n=(t.name??``).trim();if(!/^[A-Za-z_][A-Za-z0-9_]*$/.test(n))throw Error(`Enter a variable name such as ZAI_API_KEY`);return{source:e,name:n}}if(e===`file`){let n=(t.path??``).trim();if(!n)throw Error(`Enter the path of a key file`);return{source:e,path:n}}let n=(t.name??``).trim()||`memory-api`;if(!/^[A-Za-z0-9_-]{1,64}$/.test(n))throw Error(`Name the key file with letters, digits, dashes, or underscores`);if(!(t.value??``).trim())throw Error(`Paste the key`);return{source:e,name:n,value:t.value??``,replace:t.replace===!0}}function xm(e){let t=[],n=e.memoryProvider===`orcarouter`;return!n&&!e.memoryModel&&t.push(`memoryModel`),!n&&!e.memoryApiUrl&&t.push(`memoryApiUrl`),e.keySet||t.push(`memoryApiKey`),t}function Sm(e,t){if(t===`inherit`||t===`external`)return{[`${e}Model`]:t};let n=t.indexOf(`/`);if(n<1||n===t.length-1)throw Error(`Enter a model as provider/model.`);return{[`${e}Provider`]:t.slice(0,n),[`${e}Model`]:t.slice(n+1)}}function Cm(e){return e.global===null?{kind:`missing`,command:`npm i -g om-memory-system`}:e.global===e.running?{kind:`same`,command:null}:{kind:`different`,command:`npm i -g om-memory-system@latest`}}function wm(e,t,n){let r=new Map;for(let n of e)t.has(n.from)||r.set(n.from,n);for(let e of n){let t=e.target.trim();e.accepted&&t&&r.set(e.directory,{from:e.directory,to:t})}return[...r.values()]}var Tm={opencode:`OpenCode`,pi:`Pi`,"claude-code":`Claude Code`};function Em(e){return Tm[e]}function Dm({status:e}){let t=ym();return(0,V.jsxs)(`div`,{className:`space-y-1 rounded-lg border border-border p-3`,children:[(0,V.jsx)(`h3`,{className:`font-medium`,children:Em(`claude-code`)}),e?.ready===!0&&(0,V.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:t(`Claude Code capture uses the external API.`)}),e?.ready===!1&&(0,V.jsxs)(`div`,{role:`alert`,className:`space-y-1 text-xs`,children:[(0,V.jsx)(`p`,{className:`text-amber-600`,children:t(`Claude Code capture is off. Complete the external API settings.`)}),(e.issues??[]).length>0&&(0,V.jsxs)(`p`,{children:[t(`Missing settings`),`: `,(e.issues??[]).map(e=>t(e)).join(`; `)]})]})]})}function Om(){let e=ym(),[t,n]=(0,_.useState)(),[r,i]=(0,_.useState)({}),[a,o]=(0,_.useState)(``),[s,c]=(0,_.useState)(!1);(0,_.useEffect)(()=>{let e=!0,t=pm();$(`/api/settings`).then(r=>{e&&t.isCurrent()&&n(r)}).catch(t=>{e&&o(t.message)});for(let t of[`opencode`,`pi`])$(`/api/settings/models?host=${t}`).then(n=>{e&&i(e=>({...e,[t]:n}))}).catch(()=>{e&&i(e=>({...e,[t]:{available:!1}}))});let r=hm(t=>{e&&n(t)});return()=>{e=!1,r()}},[]);async function l(n,r){if(!t)return;let i;try{i=Sm(n,r)}catch(t){o(e(t.message));return}c(!0);let a,s;try{a=await $(`/api/settings`,{method:`PATCH`,body:JSON.stringify({edits:i,revision:t.revision})})}catch(e){s=e}let l=await mm()!==null;if(c(!1),a){let t=e(a.migratedLegacy?`Saved. OMMS now reads ~/.config/omms/omms.jsonc. The legacy config was kept.`:`Saved. New capture and profile work uses these settings.`);o(l?t:`${t} ${e(`Reload the page before saving again.`)}`)}else o(gm(s?.message??``,e(l?`Current settings were reloaded; check the values and save again.`:`The current settings could not be reloaded. Reload the page.`)))}let u=xm({memoryProvider:t?.settings.memoryProvider?.globalValue,memoryModel:t?.settings.memoryModel?.globalValue,memoryApiUrl:t?.settings.memoryApiUrl?.globalValue,keySet:!!t?.secrets.memoryApiKey?.set});return(0,V.jsxs)(`section`,{className:`space-y-3 rounded-xl border border-border bg-card p-4`,"aria-label":e(`Models`),children:[(0,V.jsx)(`h2`,{className:`text-lg font-medium`,children:e(`Models`)}),(0,V.jsxs)(`p`,{className:`text-sm text-muted-foreground`,children:[e(`External API fallback`),`: `,t?.fallback.model??e(`none`),` (`,e(t?.fallback.configured?`ready`:`not ready`),`).`]}),[`opencode`,`pi`].map(e=>(0,V.jsx)(km,{host:e,model:t?.settings[`${e}Model`],provider:t?.settings[`${e}Provider`],effective:e===`pi`?t?.effective.pi.kind:t?.effective.opencode.mode??`unready`,list:r[e],externalMissing:u,busy:s||!t,onSave:t=>l(e,t)},e)),(0,V.jsx)(Dm,{status:t?.effective[`claude-code`]}),(0,V.jsxs)(`div`,{className:`text-xs text-muted-foreground`,children:[e(`Credentials (values hidden)`),`:`,` `,t&&Object.entries(t.secrets).map(([t,n])=>(0,V.jsxs)(`span`,{className:`me-3`,children:[t,`: `,n.set?`${e(`set`)} (${n.source})`:e(`not set`)]},t))]}),a&&(0,V.jsx)(`p`,{role:`status`,className:`text-sm`,children:a})]})}function km({host:e,model:t,provider:n,effective:r,list:i,externalMissing:a,busy:o,onSave:s}){let c=ym(),l=t?.globalValue===`inherit`||!t?.globalValue?`inherit`:t.globalValue===`external`?`external`:`${n?.globalValue??``}/${t.globalValue}`,[u,d]=(0,_.useState)(),[f,p]=(0,_.useState)(),[m,h]=(0,_.useState)(),g=u??(l===`inherit`||l===`external`?l:`manual`),v=i?.models??[],y=l===`inherit`||l===`external`?``:l,b=m||y||(v[0]?`${v[0].provider}/${v[0].model}`:`typed`),x=!v.some(e=>`${e.provider}/${e.model}`===b),S=f??y;return(0,V.jsxs)(`div`,{className:`space-y-2 rounded-lg border border-border p-3`,children:[(0,V.jsx)(`h3`,{className:`font-medium`,children:Em(e)}),(0,V.jsxs)(`p`,{className:`text-xs text-muted-foreground`,children:[c(`Effective model`),`:`,` `,t?.value===`external`&&r===`manual`?c(`external API`):t?.value===`inherit`||r===`session`?c(`session`):r===`manual`?c(`external API`):r===`unready`?c(`unavailable`):`${n?.value??``}/${t?.value??``}`]}),(t?.source===`project`||n?.source===`project`)&&(0,V.jsx)(`p`,{className:`text-xs text-amber-600`,children:c(`Project override is active. Changes to the global file may not take effect here.`)}),(0,V.jsx)(`label`,{className:`block text-sm`,htmlFor:`${e}-model`,children:c(`Model choice`)}),(0,V.jsxs)(dn,{id:`${e}-model`,className:`w-full rounded-lg border border-border bg-background p-2 text-sm`,value:g,onChange:e=>d(e.target.value),children:[(0,V.jsx)(`option`,{value:`inherit`,children:c(`Session model`)}),(0,V.jsx)(`option`,{value:`manual`,children:c(`Manual model`)}),(0,V.jsx)(`option`,{value:`external`,disabled:a.length>0,children:c(`External API`)})]}),a.length>0&&(0,V.jsxs)(`p`,{className:`text-xs text-muted-foreground`,children:[c(`External API needs`),`: `,a.join(`, `)]}),g===`manual`&&i?.available&&v.length>0&&(0,V.jsxs)(dn,{className:`w-full rounded-lg border border-border bg-background p-2 text-sm`,"aria-label":`${Em(e)} ${c(`Model`)}`,value:x?`typed`:b,onChange:e=>h(e.target.value),children:[v.map(e=>(0,V.jsxs)(`option`,{value:`${e.provider}/${e.model}`,children:[e.name,` (`,e.provider,`/`,e.model,`)`]},`${e.provider}/${e.model}`)),(0,V.jsx)(`option`,{value:`typed`,children:c(`Manual provider/model`)})]}),g===`manual`&&x&&(0,V.jsx)(`input`,{className:`w-full rounded-lg border border-border bg-background p-2 text-sm`,"aria-label":`${e} ${c(`Manual provider/model`)}`,placeholder:`provider/model`,value:S,onChange:e=>{p(e.target.value),h(`typed`)}}),g===`manual`&&i&&!i.available&&(0,V.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:i.reason?c(i.reason):c(`Model list unavailable. Enter provider/model manually.`)}),(0,V.jsx)(`button`,{type:`button`,className:`rounded-lg border border-border px-3 py-1.5 text-sm`,disabled:o,onClick:()=>s(g===`manual`?x?S.trim():b:g),children:c(`Save model`)})]})}var Am=[`openai-chat`,`openai-responses`,`anthropic`,`minimax`,`orcarouter`,`google-gemini`];function jm(){let e=ym(),[t,n]=(0,_.useState)(),[r,i]=(0,_.useState)({}),[a,o]=(0,_.useState)(`file`),[s,c]=(0,_.useState)({name:``,path:``,value:``}),[l,u]=(0,_.useState)(``),[d,f]=(0,_.useState)(!1);(0,_.useEffect)(()=>{let e=!0,t=pm();$(`/api/settings`).then(r=>{e&&t.isCurrent()&&n(r)}).catch(t=>{e&&u(t.message)});let r=hm(t=>{e&&n(t)});return()=>{e=!1,r()}},[]);let p=e=>String(t?.settings[e]?.globalValue??``),m=e=>r[e]??p(e);async function h(){if(!t)return;let n={};for(let e of[`memoryProvider`,`memoryApiUrl`,`memoryModel`]){let t=m(e).trim();t&&t!==p(e)&&(n[e]=t)}if(!Object.keys(n).length){u(e(`Nothing to save.`));return}f(!0);try{await $(`/api/settings`,{method:`PATCH`,body:JSON.stringify({edits:n,revision:t.revision})}),i({}),u(e(`Saved. New capture and profile work uses these settings.`))}catch(e){u(e.message)}await mm(),f(!1)}async function g(n=!1){if(!t)return;let r;try{r=bm(a,{...s,replace:n})}catch(t){u(e(t.message));return}f(!0);try{await $(`/api/settings/external-api/key`,{method:`POST`,body:JSON.stringify({...r,revision:t.revision})}),c(e=>({...e,value:``})),u(e(`Key source saved.`))}catch(t){let r=t.message;if(a===`paste`&&!n&&r.includes(`Confirm to replace`)){f(!1),window.confirm(e(`A key file with this name exists. Replace it?`))&&await g(!0);return}u(r)}await mm(),f(!1)}async function v(){f(!0);try{let t=await $(`/api/settings/external-api/test`,{method:`POST`,body:`{}`});u(t.ok?`${e(`Test call succeeded`)}: ${t.model??``}`:`${e(`Test call failed`)}: ${t.error??``}`)}catch(e){u(e.message)}f(!1)}let y=t?.externalKey;return(0,V.jsxs)(`section`,{className:`space-y-3 rounded-xl border border-border bg-card p-4`,"aria-label":e(`External API`),children:[(0,V.jsx)(`h2`,{className:`text-lg font-medium`,children:e(`External API`)}),(0,V.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:e(`An OpenAI- or Anthropic-compatible endpoint that either host can use for capture and backfill.`)}),(0,V.jsxs)(`label`,{className:`block text-sm`,children:[e(`Provider`),(0,V.jsx)(dn,{"aria-label":e(`Provider`),className:`mt-1 block w-full rounded border border-border bg-background p-2`,value:m(`memoryProvider`)||`openai-chat`,onChange:e=>i({...r,memoryProvider:e.target.value}),children:Am.map(e=>(0,V.jsx)(`option`,{value:e,children:e},e))})]}),(0,V.jsxs)(`label`,{className:`block text-sm`,children:[e(`API URL`),(0,V.jsx)(`input`,{className:`mt-1 block w-full rounded border border-border bg-background p-2`,placeholder:`https://api.example.com/v1`,value:m(`memoryApiUrl`),onChange:e=>i({...r,memoryApiUrl:e.target.value})})]}),(0,V.jsxs)(`label`,{className:`block text-sm`,children:[e(`Model`),(0,V.jsx)(`input`,{className:`mt-1 block w-full rounded border border-border bg-background p-2`,placeholder:`glm-5-turbo`,value:m(`memoryModel`),onChange:e=>i({...r,memoryModel:e.target.value})})]}),(0,V.jsx)(`button`,{type:`button`,className:`rounded border border-border px-3 py-1.5 text-sm`,disabled:d||!t,onClick:()=>void h(),children:e(`Save endpoint`)}),(0,V.jsxs)(`fieldset`,{className:`space-y-2 rounded-lg border border-border p-3 text-sm`,children:[(0,V.jsx)(`legend`,{className:`px-1 font-medium`,children:e(`API key`)}),(0,V.jsxs)(`p`,{className:`text-xs text-muted-foreground`,children:[e(`Key source`),`:`,` `,y?.source===`env`?`${e(`environment variable`)} ${y.reference}`:y?.source===`file`?`${e(`key file`)} ${y.reference}`:y?.source===`literal`?e(`set in the config file`):e(`not set`),y?.source&&` · ${e(y.resolvesInWebApp?`resolves in the web app`:`does not resolve in the web app`)}`]}),y?.source===`env`&&(0,V.jsx)(`p`,{className:`text-xs text-amber-600`,children:e(`A login web app does not see variables set only in a shell profile; a key file works everywhere.`)}),y?.source&&!y.resolvesInWebApp&&(0,V.jsx)(`p`,{className:`text-xs text-amber-600`,children:e(`The key does not resolve in this web app. Save it to a key file instead.`)}),[[`env`,`Environment variable`],[`file`,`Key file`],[`paste`,`Save key to a private file`]].map(([t,n])=>(0,V.jsxs)(`label`,{className:`flex items-center gap-2`,children:[(0,V.jsx)(`input`,{type:`radio`,name:`omms-key-source`,checked:a===t,onChange:()=>o(t)}),e(n)]},t)),a===`env`&&(0,V.jsx)(`input`,{"aria-label":e(`Variable name`),className:`w-full rounded border border-border bg-background p-2`,placeholder:`ZAI_API_KEY`,value:s.name,onChange:e=>c({...s,name:e.target.value})}),a===`file`&&(0,V.jsx)(`input`,{"aria-label":e(`Key file path`),className:`w-full rounded border border-border bg-background p-2`,placeholder:`~/.config/omms/secrets/zai.key`,value:s.path,onChange:e=>c({...s,path:e.target.value})}),a===`paste`&&(0,V.jsxs)(V.Fragment,{children:[(0,V.jsx)(`input`,{"aria-label":e(`Key file name`),className:`w-full rounded border border-border bg-background p-2`,placeholder:`memory-api`,value:s.name,onChange:e=>c({...s,name:e.target.value})}),(0,V.jsx)(`input`,{"aria-label":e(`API key`),type:`password`,autoComplete:`off`,className:`w-full rounded border border-border bg-background p-2`,value:s.value,onChange:e=>c({...s,value:e.target.value})}),(0,V.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:e(`The key is written to ~/.config/omms/secrets/ readable only by you. It is never shown again.`)})]}),(0,V.jsx)(`button`,{type:`button`,className:`rounded border border-border px-3 py-1.5`,disabled:d||!t,onClick:()=>void g(),children:e(`Save key source`)})]}),(0,V.jsx)(`button`,{type:`button`,className:`rounded border border-border px-3 py-1.5 text-sm`,disabled:d,onClick:()=>void v(),children:e(`Test`)}),l&&(0,V.jsx)(`p`,{role:`status`,className:`text-sm`,children:l})]})}function Mm(){let e=ym(),[t,n]=(0,_.useState)(),[r,i]=(0,_.useState)(),[a,o]=(0,_.useState)(new Set),[s,c]=(0,_.useState)({}),[l,u]=(0,_.useState)(``),[d,f]=(0,_.useState)(!1),p=()=>$(`/api/settings/import-maps`).then(e=>{i(e),o(new Set),c({})}).catch(e=>u(e.message));(0,_.useEffect)(()=>{let e=!0;$(`/api/settings`).then(t=>{e&&n(t)}).catch(t=>{e&&u(t.message)}),p();let t=hm(t=>{e&&n(t)});return()=>{e=!1,t()}},[]);function m(e,t){c(n=>{let r=n[e.directory]??{directory:e.directory,target:e.suggestion??``,accepted:!1};return{...n,[e.directory]:{...r,...t}}})}async function h(){if(!t||!r)return;let n=wm(r.saved,a,Object.values(s));f(!0);try{await $(`/api/settings`,{method:`PATCH`,body:JSON.stringify({edits:{importPathMaps:n},revision:t.revision})}),u(e(`Saved. Maps apply to the next import or backfill run.`))}catch(e){u(e.message)}await mm(),await p(),f(!1)}return(0,V.jsxs)(`section`,{id:`directory-maps`,className:`space-y-3 rounded-xl border border-border bg-card p-4`,"aria-label":e(`Directory maps`),children:[(0,V.jsx)(`h2`,{className:`text-lg font-medium`,children:e(`Directory maps`)}),(0,V.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:e(`Map a directory that was moved or deleted to the project it belongs to. A change applies to the next import or backfill run.`)}),(0,V.jsx)(`h3`,{className:`font-medium`,children:e(`Saved maps`)}),!r?.saved.length&&(0,V.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:e(`none`)}),(0,V.jsx)(`ul`,{className:`space-y-1 text-sm`,children:r?.saved.map(t=>(0,V.jsxs)(`li`,{className:`flex flex-wrap items-center gap-2`,children:[(0,V.jsxs)(`span`,{className:a.has(t.from)?`line-through`:``,children:[(0,V.jsx)(`code`,{children:t.from}),` → `,(0,V.jsx)(`code`,{children:t.to})]}),(0,V.jsx)(`button`,{type:`button`,className:`rounded border border-border px-2 py-0.5 text-xs`,onClick:()=>o(e=>{let n=new Set(e);return n.has(t.from)?n.delete(t.from):n.add(t.from),n}),children:a.has(t.from)?e(`Keep`):e(`Remove`)})]},t.from))}),[`pi`,`opencode`,`claude-code`].map(t=>(0,V.jsxs)(`div`,{className:`space-y-2`,children:[(0,V.jsxs)(`h3`,{className:`font-medium`,children:[Em(t),`: `,e(`Unresolved directories`)]}),!r?.[t]?.length&&(0,V.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:e(`No unresolved directories in the latest run.`)}),r?.[t]?.map(t=>{let n=s[t.directory],r=n?.target??t.suggestion??``;return(0,V.jsxs)(`div`,{className:`space-y-1 rounded-lg border border-border p-2 text-sm`,children:[(0,V.jsxs)(`p`,{children:[(0,V.jsx)(`code`,{children:t.directory}),` · `,t.sessions,` `,e(`sessions`)]}),!t.suggestion&&(0,V.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:e(`No suggestion found.`)}),(0,V.jsx)(`input`,{"aria-label":`${t.directory} ${e(`Target directory`)}`,className:`w-full rounded border border-border bg-background p-2`,placeholder:e(`Target directory`),value:r,onChange:e=>m(t,{target:e.target.value})}),(0,V.jsxs)(`label`,{className:`flex items-center gap-2`,children:[(0,V.jsx)(`input`,{type:`checkbox`,checked:n?.accepted??!1,onChange:e=>m(t,{accepted:e.target.checked})}),e(`Use this map`)]})]},t.directory)})]},t)),(0,V.jsx)(`button`,{type:`button`,className:`rounded border border-border px-3 py-1.5 text-sm`,disabled:d||!t||!r,onClick:()=>void h(),children:e(`Save maps`)}),l&&(0,V.jsx)(`p`,{role:`status`,className:`text-sm`,children:l})]})}var Nm=`overflow-x-auto rounded-lg border border-border`,Pm=`px-3 py-2 text-start font-medium`,Fm=`bg-muted/50 text-xs text-muted-foreground`,Im=`px-3 py-2 text-start font-medium`,Lm=`border-t border-border transition-colors hover:bg-muted/30`,Rm=`px-3 py-1.5`;function zm(){let e=ym(),[t,n]=(0,_.useState)(7),[r,i]=(0,_.useState)(),[a,o]=(0,_.useState)([]),[s,c]=(0,_.useState)(),[l,u]=(0,_.useState)(``),[d,f]=(0,_.useState)(``),[p,m]=(0,_.useState)(``),h=(0,_.useCallback)(async e=>{let t=pm();try{let[n,r,a]=await Promise.all([$(`/api/settings/diagnostics?days=${e}`),$(`/api/settings/traces`),$(`/api/settings`)]);i(n),o(r.traces),t.isCurrent()&&c(a),f(``)}catch(e){f(e.message)}},[]);(0,_.useEffect)(()=>{h(t)},[t,h]),(0,_.useEffect)(()=>hm(e=>c(e)),[]);async function g(n){if(!s)return;let r;try{await $(`/api/settings`,{method:`PATCH`,body:JSON.stringify({revision:s.revision,edits:n})})}catch(e){r=e}let i=await mm()!==null;if(!r){m(``),await h(t),i||f(e(`Reload the page before saving again.`));return}f(gm(r.message,e(i?`Current settings were reloaded; check the values and save again.`:`The current settings could not be reloaded. Reload the page.`)))}async function v(e){try{let t=await $(`/api/settings/traces/${encodeURIComponent(e)}`);u(t.content)}catch(e){f(e.message)}}async function y(n){if(window.confirm(`${e(`Delete`)} ${n}?`))try{await $(`/api/settings/traces/${encodeURIComponent(n)}`,{method:`DELETE`}),u(``),await h(t)}catch(e){f(e.message)}}async function b(n){try{let{result:r}=await $(`/api/settings/capture-retry/${n}/run`,{method:`POST`,body:`{}`});m(e(r===`scheduled`?n===`pi`?`These turns retry at the next Pi session start.`:n===`claude-code`?`These turns retry at the next Claude Code session start.`:`These turns retry at the next OpenCode session start.`:r===`running`?`A retry is already running.`:`Retrying now.`)),await h(t)}catch(e){f(e.message)}}let x=s?.settings.captureTrace,S=Number(s?.settings.captureRetryRetentionHours?.value??72);return(0,V.jsxs)(`section`,{className:`space-y-4 rounded-xl border border-border bg-card p-4`,"aria-label":e(`Capture diagnostics`),children:[(0,V.jsx)(`h2`,{className:`text-lg font-medium`,children:e(`Capture diagnostics`)}),(0,V.jsxs)(`label`,{className:`flex items-center gap-2 pb-2 text-sm`,children:[e(`Time range`),(0,V.jsxs)(dn,{"aria-label":e(`Time range`),className:`rounded-lg border border-border bg-background px-2 py-1`,value:t,onChange:e=>n(Number(e.target.value)),children:[(0,V.jsx)(`option`,{value:1,children:e(`24 hours`)}),(0,V.jsx)(`option`,{value:7,children:e(`7 days`)}),(0,V.jsx)(`option`,{value:30,children:e(`30 days`)}),(0,V.jsx)(`option`,{value:90,children:e(`90 days`)})]})]}),d&&(0,V.jsx)(`p`,{role:`alert`,children:d}),(0,V.jsx)(`div`,{className:Nm,children:(0,V.jsxs)(`table`,{className:`w-full text-sm`,children:[(0,V.jsx)(`caption`,{className:Pm,children:e(`Outcomes by model`)}),(0,V.jsx)(`thead`,{className:Fm,children:(0,V.jsx)(`tr`,{children:[`Host / model`,`Saved`,`Skipped`,`Failed`,`Total`].map((t,n)=>(0,V.jsx)(`th`,{scope:`col`,className:B(Im,n>0&&`text-end`),children:e(t)},t))})}),(0,V.jsx)(`tbody`,{children:r?.byModel.map((e,t)=>(0,V.jsxs)(`tr`,{className:Lm,children:[(0,V.jsxs)(`td`,{className:Rm,children:[(0,V.jsx)(`span`,{className:`text-muted-foreground`,children:e.host}),` `,(0,V.jsx)(`span`,{className:`font-mono text-xs`,children:e.provider||e.model?`${e.provider??``}/${e.model??``}`:`—`})]}),[e.saved,e.skipped,e.failed].map((t,n)=>(0,V.jsxs)(`td`,{className:B(Rm,`text-end tabular-nums`),children:[t,` `,(0,V.jsxs)(`span`,{className:`text-xs text-muted-foreground`,children:[Math.round(100*t/e.total),`%`]})]},n)),(0,V.jsx)(`td`,{className:B(Rm,`text-end font-medium tabular-nums`),children:e.total})]},`${e.host}-${e.provider}-${e.model}-${t}`))})]})}),(0,V.jsx)(`div`,{className:Nm,children:(0,V.jsxs)(`table`,{className:`w-full text-sm`,children:[(0,V.jsx)(`caption`,{className:Pm,children:e(`Failure reasons`)}),(0,V.jsx)(`thead`,{className:Fm,children:(0,V.jsxs)(`tr`,{children:[(0,V.jsx)(`th`,{scope:`col`,className:Im,children:e(`Host`)}),(0,V.jsx)(`th`,{scope:`col`,className:Im,children:e(`Reason`)}),(0,V.jsx)(`th`,{scope:`col`,className:B(Im,`text-end`),children:e(`Total`)})]})}),(0,V.jsx)(`tbody`,{children:r?.byReason.map((e,t)=>(0,V.jsxs)(`tr`,{className:Lm,children:[(0,V.jsx)(`td`,{className:B(Rm,`text-muted-foreground`),children:e.host}),(0,V.jsx)(`td`,{className:B(Rm,`font-mono text-xs`),children:e.reason}),(0,V.jsx)(`td`,{className:B(Rm,`text-end tabular-nums`),children:e.count})]},`${e.host}-${e.reason}-${t}`))})]})}),(0,V.jsx)(`div`,{className:B(Nm,`max-h-72 overflow-y-auto`),children:(0,V.jsxs)(`table`,{className:`w-full min-w-max text-sm`,children:[(0,V.jsx)(`caption`,{className:Pm,children:e(`Recent attempts`)}),(0,V.jsx)(`thead`,{className:B(Fm,`sticky top-0`),children:(0,V.jsx)(`tr`,{children:[`Time`,`Host`,`Source`,`Session`,`Path`,`Model`,`Stop`,`Blocks`,`Prompt`,`Reply`,`Duration`,`Outcome`,`Reason`].map(t=>(0,V.jsx)(`th`,{scope:`col`,className:Im,children:e(t)},t))})}),(0,V.jsx)(`tbody`,{children:r?.recent.map((e,t)=>(0,V.jsx)(`tr`,{className:Lm,children:[new Date(e.timestamp).toLocaleString(),e.host,e.sourceType,e.sessionId,e.path,`${e.provider??``}/${e.model??``}`,e.stopReason,e.blockTypes?.join(`, `),e.promptChars,e.replyChars,e.durationMs,e.outcome,e.reason].map((e,t)=>(0,V.jsx)(`td`,{className:B(Rm,`whitespace-nowrap`),children:e??``},t))},`${e.timestamp}-${t}`))})]})}),(0,V.jsxs)(`div`,{className:`space-y-2 border-t border-border pt-3 text-sm`,children:[(0,V.jsxs)(`label`,{className:`flex items-center gap-2`,children:[(0,V.jsx)(`input`,{type:`checkbox`,checked:x?.value===!0,disabled:!s,onChange:t=>{t.target.checked&&!window.confirm(e(`Traces can contain conversation content after redaction. Keep tracing off unless you need it for debugging.`))||g({captureTrace:t.target.checked})}}),` `,e(`Save capture traces`)]}),(0,V.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:e(`Traces can contain conversation content after redaction. Keep tracing off unless you need it for debugging.`)}),x?.source===`project`&&(0,V.jsx)(`p`,{className:`text-xs text-amber-600`,children:e(`This project turns tracing off. The global switch cannot turn it on here.`)}),[`captureTraceRetentionDays`,`captureAttemptRetentionDays`].map(t=>(0,V.jsxs)(`label`,{className:`block`,children:[e(t===`captureTraceRetentionDays`?`Trace retention (days)`:`Attempt retention (days)`),` `,(0,V.jsx)(`input`,{type:`number`,min:1,className:`ms-2 w-20 rounded border border-border bg-background p-1`,defaultValue:Number(s?.settings[t]?.value??30),onBlur:e=>{let n=Number(e.target.value);Number.isSafeInteger(n)&&n>0&&n!==s?.settings[t]?.value&&g({[t]:n})}},`${t}-${s?.settings[t]?.value}`)]},t)),(0,V.jsxs)(`label`,{className:`block`,children:[e(`Retry retention (hours)`),` `,(0,V.jsx)(`input`,{type:`number`,min:0,max:720,className:`ms-2 w-20 rounded border border-border bg-background p-1`,defaultValue:S,onBlur:e=>{let t=Number(e.target.value);Number.isSafeInteger(t)&&t>=0&&t<=720&&t!==S&&g({captureRetryRetentionHours:t})}},`captureRetryRetentionHours-${S}`)]}),(0,V.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:e(`When the capture model cannot be reached, OMMS keeps the turn and tries again later. Queued turns can hold conversation content after redaction. 0 turns the queue off and deletes waiting turns.`)}),(0,V.jsx)(`h3`,{className:`font-medium`,children:e(`Turns waiting for retry`)}),[`pi`,`opencode`,`claude-code`].map(t=>{let n=r?.retryQueue?.[t]??0;return(0,V.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,V.jsx)(`span`,{className:`w-24`,children:Em(t)}),(0,V.jsx)(`span`,{className:`tabular-nums`,children:n}),(0,V.jsx)(`button`,{type:`button`,disabled:n===0||S===0,className:`disabled:opacity-50`,onClick:()=>void b(t),children:e(`Retry now`)})]},t)}),p&&(0,V.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:p}),(0,V.jsx)(`h3`,{className:`font-medium`,children:e(`Trace files`)}),a.map(t=>(0,V.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,V.jsxs)(`span`,{children:[t.file,` (`,t.size,` bytes)`]}),(0,V.jsx)(`button`,{type:`button`,onClick:()=>void v(t.file),children:e(`View`)}),(0,V.jsx)(`button`,{type:`button`,onClick:()=>void y(t.file),children:e(`Delete`)})]},t.file)),l&&(0,V.jsx)(`pre`,{className:`max-h-60 overflow-auto whitespace-pre-wrap break-words rounded bg-background p-2 text-xs`,children:l})]})]})}function Bm(){let e=ym(),[t,n]=(0,_.useState)([]),[r,i]=(0,_.useState)(!1),[a,o]=(0,_.useState)(``);async function s(e){i(!0);try{let t=await $(`/api/settings/health`,{method:`POST`,body:JSON.stringify({testModels:e})});n(t.checks),o(``)}catch(e){o(e.message)}finally{i(!1)}}return(0,V.jsxs)(`section`,{id:`settings-health`,className:`space-y-3 rounded-xl border border-border bg-card p-4`,"aria-label":e(`Health`),children:[(0,V.jsx)(`h2`,{className:`text-lg font-medium`,children:e(`Health`)}),(0,V.jsxs)(`div`,{className:`flex gap-2`,children:[(0,V.jsx)(`button`,{className:`rounded-lg border border-border px-3 py-1.5 text-sm`,disabled:r,onClick:()=>void s(!1),children:e(`Run checks`)}),(0,V.jsx)(`button`,{className:`rounded-lg border border-border px-3 py-1.5 text-sm`,disabled:r,onClick:()=>void s(!0),children:e(`Run checks and test models`)})]}),r&&(0,V.jsx)(`p`,{role:`status`,children:e(`Checking…`)}),a&&(0,V.jsx)(`p`,{role:`alert`,children:a}),(0,V.jsx)(`ul`,{className:`space-y-2 text-sm`,children:t.map(t=>(0,V.jsxs)(`li`,{className:`rounded-lg border border-border p-2`,children:[(0,V.jsx)(`strong`,{className:t.status===`fail`?`text-red-600`:t.status===`warn`?`text-amber-600`:`text-green-600`,children:e(t.status).toUpperCase()}),` `,`· `,e(t.check),`: `,t.reason]},t.check))})]})}function Vm(e){let t=/^(\d{4})-(\d{2})-(\d{2})$/.exec(e);return t?[Number(t[1]),Number(t[2])-1,Number(t[3])]:null}function Hm(e){let t=Vm(e);return t?new Date(t[0],t[1],t[2],0,0,0,0).getTime():void 0}function Um(e){let t=Vm(e);return t?new Date(t[0],t[1],t[2],23,59,59,999).getTime():void 0}function Wm(e,t,n){let r=!n&&e!==null&&e.revision===t.revision;return{page:r?{...t,listedAt:e.listedAt}:t,sameListing:r}}function Gm(e){let t=ym(),[n,r]=(0,_.useState)(``),[i,a]=(0,_.useState)(null),[o,s]=(0,_.useState)(null),[c,l]=(0,_.useState)(!1),[u,d]=(0,_.useState)(``),f=`rounded border border-border px-3 py-1.5 text-sm disabled:opacity-50`;async function p(t){try{let n=await $(`/api/settings/imports/sources/validate`,{method:`POST`,body:JSON.stringify({host:e.host,path:t})});a(n),r(n.displayPath),e.onChoose(n),d(``)}catch(e){d(e.message)}}async function m(t){try{let n=await $(`/api/settings/imports/sources/browse`,{method:`POST`,body:JSON.stringify({host:e.host,...t?{path:t}:{}})});s(n),d(``)}catch(e){let t=e.message;/loopback/i.test(t)&&l(!0),d(t)}}function h(){a(null),r(``),s(null),e.onChoose(null)}return(0,V.jsxs)(`div`,{className:`space-y-2 text-sm`,children:[(0,V.jsxs)(`label`,{className:`block`,children:[e.host===`pi`?t(`Pi sessions folder or one .jsonl session file`):e.host===`claude-code`?t(`Claude Code transcripts folder`):t(`OpenCode database file`),(0,V.jsx)(`input`,{className:`mt-1 block w-full rounded border border-border bg-background p-2 font-mono`,value:n,placeholder:t(`Absolute path, for example on a mounted volume`),onChange:e=>r(e.target.value)})]}),(0,V.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,V.jsx)(`button`,{type:`button`,className:f,disabled:!n.trim(),onClick:()=>void p(n.trim()),children:t(`Use this source`)}),!c&&(0,V.jsx)(`button`,{type:`button`,className:f,onClick:()=>void m(o?.path),children:t(`Browse`)}),i&&(0,V.jsx)(`button`,{type:`button`,className:f,onClick:h,children:t(`Use the default location`)})]}),i&&(0,V.jsxs)(`p`,{role:`status`,children:[t(`Chosen source`),`: `,(0,V.jsx)(`span`,{className:`font-mono`,children:i.displayPath})]}),u&&(0,V.jsx)(`p`,{role:`alert`,children:u}),o&&(0,V.jsxs)(`div`,{className:`rounded border border-border p-2`,children:[(0,V.jsx)(`p`,{className:`font-mono text-xs break-all`,children:o.path}),(0,V.jsxs)(`ul`,{className:`max-h-60 overflow-auto`,children:[o.parent&&(0,V.jsx)(`li`,{children:(0,V.jsx)(`button`,{type:`button`,className:`underline`,onClick:()=>void m(o.parent),children:`..`})}),o.entries.map(n=>(0,V.jsxs)(`li`,{className:`flex items-center gap-2`,children:[n.kind===`folder`?(0,V.jsxs)(`button`,{type:`button`,className:`underline`,onClick:()=>void m(n.path),children:[n.name,`/`]}):(0,V.jsx)(`span`,{className:`font-mono text-xs`,children:n.name}),(n.kind!==`folder`||e.host!==`opencode`)&&(0,V.jsx)(`button`,{type:`button`,className:`text-xs underline`,onClick:()=>void p(n.path),children:t(`Choose`)})]},n.path))]}),o.truncated&&(0,V.jsx)(`p`,{className:`text-xs`,children:t(`Only the first 500 entries are shown.`)})]})]})}var Km=50,qm=1e3,Jm={"missing-model":`The external API has no memoryModel in the global config`,"missing-url":`The external API has no memoryApiUrl in the global config`,"missing-key":`The external API key is missing in the OpenCode process; check memoryApiKey and its env:// or file:// source`,"unsupported-provider":`The memoryProvider in the global config is not supported for imports`},Ym=()=>({mode:`ids`,picked:new Map});function Xm(e,t){return e.split(`
123
+ `).map(e=>e.trim()).filter(Boolean).map(e=>{let n=e.indexOf(`=`);if(n<1||n===e.length-1)throw Error(t);return{from:e.slice(0,n),to:e.slice(n+1)}})}function Zm(){let e=ym(),[t,n]=(0,_.useState)(`pi`),[r,i]=(0,_.useState)(null),[a,o]=(0,_.useState)(`current-project`),[s,c]=(0,_.useState)(``),[l,u]=(0,_.useState)(``),[d,f]=(0,_.useState)(``),[p,m]=(0,_.useState)(``),[h,g]=(0,_.useState)(``),[v,y]=(0,_.useState)(!1),[b,x]=(0,_.useState)(!1),[S,C]=(0,_.useState)(!1),[w,T]=(0,_.useState)(!1),[E,D]=(0,_.useState)(null),[O,ee]=(0,_.useState)(``),[te,ne]=(0,_.useState)(!1),[re,ie]=(0,_.useState)(!1),[k,ae]=(0,_.useState)(Ym),[A,j]=(0,_.useState)(null),[oe,M]=(0,_.useState)(``),se=t===`claude-code`&&oe!==`external`?``:oe,[N,P]=(0,_.useState)(null),[F,ce]=(0,_.useState)(``);(0,_.useEffect)(()=>{$(`/api/settings/imports/readiness`).then(e=>{j(e);let t=e.opencode.models[0];M(t?`${t.provider}/${t.model}`:e.external.state===`ready`?`external`:``)}).catch(()=>j(null)),$(`/api/settings/imports/current`).then(e=>P(e.job)).catch(()=>{})},[]),(0,_.useEffect)(()=>{if(N?.state!==`running`&&N?.state!==`cancelling`)return;let e=setInterval(()=>{$(`/api/settings/imports/current`).then(e=>P(e.job)).catch(e=>ce(e.message))},1e3);return()=>clearInterval(e)},[N?.state]);let le=JSON.stringify([t,r?.sourceToken,a,s,l]),ue=!!E&&(te||le!==O);function de(){let n=Xm(l,e(`Directory maps must be old=new, one per line`));return{host:t,...r?{source:r.sourceToken}:{},scope:a,...a===`current-project`&&s?{project:s}:{},pathMaps:n}}async function fe(e,t){ie(!0);try{let n=await $(`/api/settings/imports/sessions`,{method:`POST`,body:JSON.stringify({...de(),offset:e,limit:Km,refresh:t})}),r=Wm(E,n,t);r.sameListing||ae(Ym()),D(r.page),ee(le),ne(!1),ce(``)}catch(e){ce(e.message)}finally{ie(!1)}}let I=E?E.total-(a===`all-projects`?E.unresolvedCount:0):0,pe=k.mode===`all`?I-k.excluded.size:k.picked.size,me=e=>k.mode===`all`?!k.excluded.has(e.key):k.picked.has(e.key);function he(e){if(!(!e.selectable||!e.directory)){if(k.mode===`all`){let t=new Set(k.excluded);t.has(e.key)?t.delete(e.key):t.add(e.key),ae({mode:`all`,excluded:t})}else{let t=new Map(k.picked);t.has(e.key)?t.delete(e.key):t.set(e.key,e.directory),ae({mode:`ids`,picked:t})}}}let ge=!b||!S,_e=t===`pi`&&A?.piReader.available===!1,ve=ge?A?se?se===`external`&&A.external.state!==`ready`?e(Jm[A.external.state]??`The external API is not ready`):null:e(t===`claude-code`?`Claude Code imports use the external API. Complete the external API settings.`:`No import model is ready. Connect a model in OpenCode or complete the external API settings.`):e(`Model readiness is unknown. Reload the page.`):null,ye=E?ue?e(`Options changed. Refresh the session list first.`):pe===0?e(`Select at least one session.`):k.mode===`ids`&&k.picked.size>qm?e(`Select at most 1000 sessions one by one, or use Select all matching.`):null:e(`List sessions first.`),be=N?.state===`running`||N?.state===`cancelling`;async function xe(n){if(E)try{let r=d?Hm(d):void 0,i=p?Um(p):void 0,o={host:t,source:E.source.sourceToken,selection:k.mode===`all`?{mode:`all`,excludedKeys:[...k.excluded],revision:E.revision,listedAt:E.listedAt}:{mode:`ids`,sessions:[...k.picked].map(([e,t])=>({key:e,directory:t})),listedAt:E.listedAt},options:{dryRun:n,force:v,skipMemories:b,skipProfile:S,scope:a,...a===`current-project`&&s?{project:s}:{},...r===void 0?{}:{since:r},...i===void 0?{}:{until:i},...h?{profileBatch:Number(h)}:{},pathMaps:Xm(l,e(`Directory maps must be old=new, one per line`))},...se?{modelChoice:se}:{}},c=await $(`/api/settings/imports`,{method:`POST`,body:JSON.stringify(o)});P(c),ce(``)}catch(e){let t=e.message;/out of date|changed|no longer/i.test(t)&&ne(!0),ce(t)}}async function Se(){try{let e=await $(`/api/settings/imports/current/cancel`,{method:`POST`,body:`{}`});P(e.job)}catch(e){ce(e.message)}}function Ce(){o(`all-projects`),T(!0)}let we={recorded:e(`recorded`),mapped:e(`mapped`),worktree:e(`project root`),unresolved:e(`missing`)},Te=`mt-1 block w-full rounded border border-border bg-background p-2`,Ee=`rounded border border-border px-3 py-1.5 text-sm disabled:opacity-50`;return(0,V.jsxs)(`section`,{className:`space-y-3 rounded-xl border border-border bg-card p-4`,"aria-label":e(`Import and backfill`),children:[(0,V.jsx)(`h2`,{className:`text-lg font-medium`,children:e(`Import and backfill`)}),(0,V.jsxs)(`div`,{className:`flex flex-wrap items-end gap-3`,children:[(0,V.jsxs)(`label`,{className:`text-sm`,children:[e(`History host`),(0,V.jsxs)(dn,{"aria-label":e(`History host`),className:Te,value:t,onChange:e=>{let t=e.target.value;n(t),t===`claude-code`&&A?.external.state===`ready`&&M(`external`),i(null),D(null),ae(Ym())},children:[(0,V.jsx)(`option`,{value:`pi`,children:`Pi`}),(0,V.jsx)(`option`,{value:`opencode`,children:`OpenCode`}),(0,V.jsx)(`option`,{value:`claude-code`,children:`Claude Code`})]})]}),(0,V.jsx)(`button`,{type:`button`,className:Ee,disabled:re,onClick:()=>void fe(0,!0),children:e(E?`Refresh list`:`List sessions`)}),(0,V.jsx)(`button`,{type:`button`,className:Ee,onClick:()=>T(!w),children:e(w?`Hide advanced options`:`Advanced options`)})]}),(0,V.jsxs)(`p`,{className:`text-xs text-muted-foreground`,children:[e(`Source`),`: `,r?.displayPath??E?.source.displayPath??e(`default location`),` · `,e(a===`current-project`?`Current project`:`All projects`)]}),_e&&(0,V.jsx)(`p`,{role:`alert`,children:A?.piReader.reason}),t===`claude-code`&&A?.claudeCode&&(0,V.jsxs)(`p`,{className:`text-xs text-muted-foreground`,children:[e(`Claude Code transcripts`),`:`,` `,(0,V.jsx)(`span`,{className:`font-mono break-all`,children:A.claudeCode.defaultRoot}),` (`,A.claudeCode.defaultRootFound?e(`found`):e(`not found`),`).`,` `,e(`Claude Code imports always use the external API.`)]}),w&&(0,V.jsxs)(`div`,{className:`space-y-3 rounded-lg border border-border p-3`,children:[(0,V.jsx)(Gm,{host:t,onChoose:i}),(0,V.jsxs)(`div`,{className:`grid gap-3 sm:grid-cols-2`,children:[(0,V.jsxs)(`label`,{className:`text-sm`,children:[e(`Scope`),(0,V.jsxs)(dn,{"aria-label":e(`Scope`),className:Te,value:a,onChange:e=>o(e.target.value),children:[(0,V.jsx)(`option`,{value:`current-project`,children:e(`Current project`)}),(0,V.jsx)(`option`,{value:`all-projects`,children:e(`All projects`)})]})]}),a===`current-project`&&(0,V.jsxs)(`label`,{className:`text-sm`,children:[e(`Project directory`),(0,V.jsx)(`input`,{className:Te,value:s,onChange:e=>c(e.target.value),placeholder:e(`Current directory`)})]}),(0,V.jsxs)(`label`,{className:`text-sm`,children:[e(`Prompt date from`),(0,V.jsx)(`input`,{type:`date`,className:Te,value:d,onChange:e=>f(e.target.value)})]}),(0,V.jsxs)(`label`,{className:`text-sm`,children:[e(`Prompt date to`),(0,V.jsx)(`input`,{type:`date`,className:Te,value:p,onChange:e=>m(e.target.value)})]}),(0,V.jsxs)(`label`,{className:`text-sm`,children:[e(`Profile batch size`),(0,V.jsx)(`input`,{inputMode:`numeric`,className:Te,value:h,onChange:e=>g(e.target.value)})]})]}),(0,V.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:e(`Prompt dates are inclusive, use your time zone, and filter the turns inside each session, not the list. Empty dates include every turn.`)}),(0,V.jsxs)(`label`,{className:`block text-sm`,children:[e(`Directory maps (old=new, one per line)`),(0,V.jsx)(`textarea`,{className:Te,rows:2,value:l,onChange:e=>u(e.target.value)})]}),(0,V.jsx)(`div`,{className:`flex flex-wrap gap-3 text-sm`,children:[[`Force reimport`,v,y],[`Skip memories`,b,x],[`Skip profile`,S,C]].map(([t,n,r])=>(0,V.jsxs)(`label`,{children:[(0,V.jsx)(`input`,{type:`checkbox`,checked:n,onChange:e=>r(e.target.checked)}),` `,e(t)]},t))})]}),ue&&E&&(0,V.jsx)(`p`,{role:`status`,className:`text-sm text-amber-600`,children:e(`Options changed. Refresh the session list first.`)}),E&&a===`current-project`&&E.unresolvedCount>0&&(0,V.jsxs)(`p`,{className:`text-sm`,children:[e(`Sessions with directories that no longer exist`),`: `,E.unresolvedCount,`.`,` `,(0,V.jsx)(`button`,{type:`button`,className:`underline`,onClick:Ce,children:e(`Show them and add a directory map`)})]}),E&&(0,V.jsxs)(`div`,{className:`space-y-2`,children:[(0,V.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2 text-sm`,children:[(0,V.jsxs)(`span`,{role:`status`,children:[e(`Selected`),`: `,pe,` / `,I]}),(0,V.jsxs)(`button`,{type:`button`,className:Ee,disabled:I===0,onClick:()=>ae({mode:`all`,excluded:new Set}),children:[e(`Select all matching`),` (`,I,`)`]}),(0,V.jsx)(`button`,{type:`button`,className:Ee,onClick:()=>ae(Ym()),children:e(`Clear selection`)})]}),(0,V.jsxs)(`div`,{className:`overflow-x-auto`,children:[(0,V.jsxs)(`table`,{className:`w-full text-left text-sm`,children:[(0,V.jsx)(`thead`,{children:(0,V.jsxs)(`tr`,{className:`text-muted-foreground`,children:[(0,V.jsx)(`th`,{className:`p-1`,children:(0,V.jsx)(`span`,{className:`sr-only`,children:e(`Select`)})}),(0,V.jsx)(`th`,{className:`p-1`,children:e(`Created`)}),(0,V.jsx)(`th`,{className:`p-1`,children:e(`Session`)}),(0,V.jsx)(`th`,{className:`p-1`,children:e(`Project directory`)}),(0,V.jsx)(`th`,{className:`p-1`,children:e(`Resolved by`)})]})}),(0,V.jsx)(`tbody`,{children:E.rows.map(t=>(0,V.jsxs)(`tr`,{className:`border-t border-border`,children:[(0,V.jsx)(`td`,{className:`p-1`,children:(0,V.jsx)(`input`,{type:`checkbox`,"aria-label":`${e(`Select`)} ${t.sessionId??t.key}`,checked:t.selectable&&me(t),disabled:!t.selectable,onChange:()=>he(t)})}),(0,V.jsx)(`td`,{className:`p-1 whitespace-nowrap`,children:t.createdAt?new Date(t.createdAt).toLocaleString():`—`}),(0,V.jsx)(`td`,{className:`p-1 font-mono text-xs`,children:t.sessionId??t.key}),(0,V.jsx)(`td`,{className:`p-1 font-mono text-xs break-all`,children:t.directory??t.recordedDirectory??`—`}),(0,V.jsx)(`td`,{className:`p-1`,children:we[t.via]})]},t.key))})]}),E.total===0&&(0,V.jsx)(`p`,{className:`text-sm`,children:e(`No sessions match.`)})]}),(0,V.jsxs)(`div`,{className:`flex items-center gap-2 text-sm`,children:[(0,V.jsx)(`button`,{type:`button`,className:Ee,disabled:re||E.offset===0,onClick:()=>void fe(Math.max(0,E.offset-Km),!1),children:e(`Previous`)}),(0,V.jsxs)(`span`,{children:[E.total?E.offset+1:0,`–`,Math.min(E.offset+Km,E.total),` /`,` `,E.total]}),(0,V.jsx)(`button`,{type:`button`,className:Ee,disabled:re||E.offset+Km>=E.total,onClick:()=>void fe(E.offset+Km,!1),children:e(`Next`)})]})]}),(0,V.jsxs)(`label`,{className:`block text-sm`,children:[e(`Import model`),(0,V.jsxs)(dn,{"aria-label":e(`Import model`),className:Te,value:se,onChange:e=>M(e.target.value),children:[(0,V.jsx)(`option`,{value:``,children:e(`None`)}),t!==`claude-code`&&A?.opencode.models.map(e=>(0,V.jsxs)(`option`,{value:`${e.provider}/${e.model}`,children:[e.name,` (`,e.provider,`/`,e.model,`)`]},`${e.provider}/${e.model}`)),(0,V.jsxs)(`option`,{value:`external`,children:[e(`Saved external API`),A?.external.model?` (${A.external.model})`:``,A&&A.external.state!==`ready`?` — ${e(`not ready`)}`:``]})]})]}),t!==`claude-code`&&A&&!A.opencode.available&&(0,V.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:e(`An import with an OpenCode signed-in model runs from the terminal or with /import in OpenCode.`)}),(0,V.jsxs)(`p`,{className:`text-xs text-muted-foreground`,children:[e(`Configured, not tested.`),` `,(0,V.jsx)(`button`,{type:`button`,className:`underline`,onClick:()=>document.getElementById(`settings-health`)?.scrollIntoView(),children:e(`Test models in Health`)})]}),(0,V.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,V.jsx)(`button`,{type:`button`,className:Ee,disabled:be||_e||!!ye,onClick:()=>void xe(!0),children:e(`Preview (dry run)`)}),(0,V.jsx)(`button`,{type:`button`,className:Ee,disabled:be||_e||!!ye||!!ve,onClick:()=>void xe(!1),children:e(`Start import`)}),be&&(0,V.jsx)(`button`,{type:`button`,className:Ee,disabled:N?.state===`cancelling`,onClick:()=>void Se(),children:e(`Cancel after current unit`)})]}),(ye||ve)&&!be&&(0,V.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:ye??ve}),F&&(0,V.jsx)(`p`,{role:`alert`,children:F}),N&&(0,V.jsxs)(`div`,{role:`status`,className:`text-sm`,children:[N.host,` · `,N.dryRun?e(`Preview (dry run)`):e(`Import`),` · `,e(N.state),` ·`,` `,N.sessions,` `,e(`sessions`),` · `,N.processed,`/`,N.total,` `,e(`units`),N.error&&(0,V.jsx)(`p`,{role:`alert`,children:N.error}),N.report&&(0,V.jsx)(`pre`,{className:`mt-2 overflow-auto whitespace-pre-wrap rounded bg-background p-3 text-xs`,children:N.report})]})]})}function Qm(e){return Object.values(e).some(e=>e?.state===`running`)}function $m(e){return!e||e.total<=0?null:{percent:e.percent,done:`${e.done.toLocaleString(`en-US`)} / ${e.total.toLocaleString(`en-US`)}`,minutesLeft:e.minutesLeft===null?`unknown`:`about ${e.minutesLeft}`}}function eh(e,t){let n=e?.state===`running`,r=e?.paused===!0;return{runNow:!n&&!r&&!t,pause:n&&!r,resume:r&&!t}}function th(e,t){return e??!t}function nh(e,t){let n=t.indexOf(`/`);if(t!==`inherit`&&t!==`external`&&(n<1||n===t.length-1))throw Error(`Enter a model as provider/model.`);return{[`${e}BackfillModel`]:t}}var rh=[`pi`,`opencode`,`claude-code`];function ih(){let e=ym(),[t,n]=(0,_.useState)(),[r,i]=(0,_.useState)({pi:null,opencode:null,"claude-code":null}),[a,o]=(0,_.useState)(),[s,c]=(0,_.useState)({}),[l,u]=(0,_.useState)({}),[d,f]=(0,_.useState)({}),[p,m]=(0,_.useState)(``),[h,g]=(0,_.useState)(!1),v=Qm(r)||rh.some(e=>a?.[e]?.run?.state===`running`),y=()=>$(`/api/settings/backfill/runs`).then(o).catch(e=>m(e.message));(0,_.useEffect)(()=>{let e=!0;$(`/api/settings`).then(t=>{e&&n(t)}).catch(t=>{e&&m(t.message)}),$(`/api/settings/backfill`).then(t=>{e&&i(t)}).catch(t=>{e&&m(t.message)}),y();for(let t of[`pi`,`opencode`])$(`/api/settings/models?host=${t}`).then(n=>{e&&c(e=>({...e,[t]:n}))}).catch(()=>{e&&c(e=>({...e,[t]:{available:!1}}))});let t=hm(t=>{e&&n(t)});return()=>{e=!1,t()}},[]),(0,_.useEffect)(()=>{if(!v)return;let e=!0,t=setInterval(()=>{$(`/api/settings/backfill`).then(t=>{e&&i(t)}).catch(t=>{e&&m(t.message)}),e&&y()},3e3);return()=>{e=!1,clearInterval(t)}},[v]);async function b(n){if(t){g(!0);try{await $(`/api/settings`,{method:`PATCH`,body:JSON.stringify({edits:n,revision:t.revision})}),m(e(`Saved. Changes apply at the next run.`))}catch(e){m(e.message)}await mm(),g(!1)}}async function x(t,n){g(!0);try{await $(`/api/settings/backfill/${t}/${n}`,{method:`POST`,body:`{}`}),m(e(n===`pause`?`Pausing after the current exchange.`:`Backfill started.`))}catch(e){m(e.message)}await y(),g(!1)}function S(t,n){try{b(nh(t,n.trim()))}catch(t){m(e(t.message))}}return(0,V.jsxs)(`section`,{className:`space-y-3 rounded-xl border border-border bg-card p-4`,"aria-label":e(`Automatic import`),children:[(0,V.jsx)(`h2`,{className:`text-lg font-medium`,children:e(`Automatic import`)}),(0,V.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:e(`Automatic import makes model calls. A model change applies at the next run. Turning it off stops a running import after the current exchange.`)}),(0,V.jsxs)(`label`,{className:`flex items-center gap-2 text-sm`,children:[(0,V.jsx)(`input`,{type:`checkbox`,checked:!!t?.settings.autoBackfill?.globalValue,disabled:h||!t,onChange:e=>void b({autoBackfill:e.target.checked})}),e(`Import past chats automatically`)]}),rh.map(n=>{let i=String(t?.settings[`${n}BackfillModel`]?.globalValue??`inherit`),o=l[n]??i,c=s[n]?.models??[],p=o===`inherit`||o===`external`||c.some(e=>`${e.provider}/${e.model}`===o),m=xm({memoryProvider:t?.settings.memoryProvider?.globalValue,memoryModel:t?.settings.memoryModel?.globalValue,memoryApiUrl:t?.settings.memoryApiUrl?.globalValue,keySet:!!t?.secrets?.memoryApiKey?.set}),g=a?.[n]?.run??null,_=a?.[n]?.runNowUnavailable??null,v=eh(g,_),y=g?.state===`running`?$m(g):null,b=th(d[n],p);return(0,V.jsxs)(`div`,{className:`space-y-2 rounded-lg border border-border p-3 text-sm`,children:[(0,V.jsx)(`h3`,{className:`font-medium`,children:Em(n)}),n===`claude-code`?(0,V.jsx)(`p`,{className:`text-muted-foreground`,children:e(`Claude Code backfill always uses the external API. It has no backfill model setting.`)}):(0,V.jsxs)(V.Fragment,{children:[(0,V.jsxs)(`label`,{className:`block`,children:[e(`Backfill model`),(0,V.jsxs)(dn,{"aria-label":`${Em(n)} ${e(`Backfill model`)}`,className:`mt-1 block w-full rounded border border-border bg-background p-2`,value:b?`typed`:o,onChange:e=>{let t=e.target.value;f(e=>({...e,[n]:t===`typed`})),u(e=>({...e,[n]:t}))},children:[(0,V.jsx)(`option`,{value:`inherit`,children:e(`Same as live capture`)}),(0,V.jsx)(`option`,{value:`external`,disabled:m.length>0,children:e(`External API`)}),c.map(e=>(0,V.jsxs)(`option`,{value:`${e.provider}/${e.model}`,children:[e.name,` (`,e.provider,`/`,e.model,`)`]},`${e.provider}/${e.model}`)),(0,V.jsx)(`option`,{value:`typed`,children:e(`Manual provider/model`)})]})]}),b&&(0,V.jsx)(`input`,{"aria-label":`${n} ${e(`Manual provider/model`)}`,className:`w-full rounded border border-border bg-background p-2`,placeholder:`provider/model`,value:o===`typed`?``:o,onChange:e=>u(t=>({...t,[n]:e.target.value}))}),m.length>0&&(0,V.jsxs)(`p`,{className:`text-xs text-muted-foreground`,children:[e(`External API needs`),`: `,m.join(`, `)]}),s[n]?.available===!1&&(0,V.jsx)(`p`,{children:s[n].reason?e(s[n].reason):e(`Model list unavailable. Enter provider/model manually.`)}),(0,V.jsx)(`button`,{type:`button`,className:`rounded border border-border px-3 py-1.5`,disabled:h||!t,onClick:()=>S(n,o),children:e(`Save model`)})]}),(0,V.jsxs)(`p`,{children:[e(`State`),`:`,` `,g?.paused?e(`paused`):e(g?.state??r[n]?.state??`not started`),g?.state===`running`&&g.surface&&` (${e(`started from ${g.surface}`)})`]}),y&&(0,V.jsxs)(`div`,{className:`space-y-1`,children:[(0,V.jsx)(`div`,{role:`progressbar`,"aria-valuemin":0,"aria-valuemax":100,"aria-valuenow":y.percent,className:`h-2 w-full overflow-hidden rounded bg-muted`,children:(0,V.jsx)(`div`,{className:`h-full bg-primary`,style:{width:`${y.percent}%`}})}),(0,V.jsxs)(`p`,{className:`text-muted-foreground`,children:[y.percent,`% · `,y.done,` · `,e(`Minutes left`),`:`,` `,y.minutesLeft===`unknown`?e(`unknown`):y.minutesLeft.replace(`about`,e(`about`))]})]}),(0,V.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,V.jsx)(`button`,{type:`button`,className:`rounded border border-border px-3 py-1.5`,disabled:h||!v.runNow,onClick:()=>void x(n,`run`),children:e(`Run now`)}),(0,V.jsx)(`button`,{type:`button`,className:`rounded border border-border px-3 py-1.5`,disabled:h||!v.pause,onClick:()=>void x(n,`pause`),children:e(`Pause`)}),(0,V.jsx)(`button`,{type:`button`,className:`rounded border border-border px-3 py-1.5`,disabled:h||!v.resume,onClick:()=>void x(n,`resume`),children:e(`Resume`)})]}),_&&(0,V.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:_}),r[n]&&(0,V.jsxs)(`div`,{className:`space-y-1 text-muted-foreground`,children:[(0,V.jsxs)(`p`,{children:[e(`Imported`),`: `,r[n].counts.imported,` · `,e(`Skipped`),`:`,` `,r[n].counts.skipped,` · `,e(`Failed`),`: `,r[n].counts.failed]}),(0,V.jsxs)(`p`,{children:[e(`Pending`),`: `,r[n].counts.pending,` · `,e(`Unresolved sessions`),`:`,` `,r[n].counts.unresolved,r[n].counts.unresolved>0&&(0,V.jsxs)(V.Fragment,{children:[` `,(0,V.jsx)(`a`,{className:`underline`,href:`#directory-maps`,children:e(`Directory maps`)})]})]}),(0,V.jsxs)(`p`,{children:[e(`Model`),`: `,r[n].model??e(`none`)]}),(0,V.jsxs)(`p`,{children:[e(`Cutoff`),`: `,new Date(r[n].cutoff).toLocaleString()]}),r[n].error&&(0,V.jsx)(`p`,{role:`alert`,children:r[n].error})]})]},n)}),p&&(0,V.jsx)(`p`,{role:`status`,className:`text-sm`,children:p})]})}function ah(){let e=ym(),[t,n]=(0,_.useState)(),[r,i]=(0,_.useState)(),[a,o]=(0,_.useState)(),[s,c]=(0,_.useState)(``),[l,u]=(0,_.useState)(!1);(0,_.useEffect)(()=>{let e=!0;$(`/api/settings`).then(t=>{e&&n(t)}).catch(t=>{e&&c(t.message)}),$(`/api/settings/web-autostart`).then(t=>{e&&i(t)}).catch(t=>{e&&c(t.message)}),$(`/api/settings/version`).then(t=>{e&&o(t)}).catch(()=>{});let t=hm(t=>{e&&n(t)});return()=>{e=!1,t()}},[]);async function d(n){if(t){u(!0);try{await $(`/api/settings`,{method:`PATCH`,body:JSON.stringify({edits:{webServerAutoStart:n},revision:t.revision})}),c(e(`Saved. The login item changes at the next Pi or OpenCode start.`))}catch(e){c(e.message)}await mm(),u(!1)}}return(0,V.jsxs)(`section`,{className:`space-y-3 rounded-xl border border-border bg-card p-4`,"aria-label":e(`Web app`),children:[(0,V.jsx)(`h2`,{className:`text-lg font-medium`,children:e(`Web app`)}),(0,V.jsxs)(`label`,{className:`flex items-center gap-2 text-sm`,children:[(0,V.jsx)(`input`,{type:`checkbox`,checked:!!t?.settings.webServerAutoStart?.globalValue,disabled:l||!t,onChange:e=>void d(e.target.checked)}),e(`Start web app at login`)]}),(0,V.jsxs)(`p`,{className:`text-sm`,children:[e(`Login item`),`: `,e(r?.state??`not installed`)]}),r?.state===`unsupported`&&(0,V.jsx)(`p`,{role:`status`,children:e(`Login items are unsupported on this platform.`)}),r?.state===`no-runtime`&&(0,V.jsx)(`p`,{role:`status`,children:e(`Install Node or Bun to start the web app at login.`)}),a&&(0,V.jsx)(oh,{info:a}),(0,V.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:e(`Use these commands to apply the change now:`)}),(0,V.jsxs)(`div`,{className:`space-y-1 font-mono text-xs`,children:[(0,V.jsx)(`p`,{children:`om-memory-system web`}),(0,V.jsx)(`p`,{children:`om-memory-system web install`}),(0,V.jsx)(`p`,{children:`om-memory-system web uninstall`}),(0,V.jsx)(`p`,{children:`om-memory-system web status`})]}),s&&(0,V.jsx)(`p`,{role:`status`,className:`text-sm`,children:s})]})}function oh({info:e}){let t=ym(),n=Cm(e);return(0,V.jsxs)(`div`,{className:`space-y-1 text-sm`,children:[(0,V.jsxs)(`p`,{children:[t(`Running version`),`: `,e.running,` · `,t(`Global command`),`:`,` `,e.global??t(`not installed globally`)]}),n.kind===`different`&&(0,V.jsx)(`p`,{role:`status`,className:`text-amber-600`,children:t(`The global command's version differs from the running OMMS. Upgrade it:`)}),n.command&&(0,V.jsx)(`p`,{className:`font-mono text-xs`,children:n.command}),(0,V.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:t(`A global install is optional but recommended: the login item and the terminal commands then run without npx.`)})]})}function sh(e){let t=e.trim();return t===``||t.startsWith(`~/`)||t.startsWith(`/`)||/^[A-Za-z]:[\\/]/.test(t)||t.startsWith(`\\\\`)}function ch(e,t,n){return n?t:typeof e==`string`?e:``}function lh(){let e=ym(),[t,n]=(0,_.useState)(),[r,i]=(0,_.useState)(``),[a,o]=(0,_.useState)(``),[s,c]=(0,_.useState)(!1),l=(0,_.useRef)(!1);(0,_.useEffect)(()=>{let e=!0,t=t=>{e&&(n(t),i(e=>ch(t.settings.claudeConfigDir?.globalValue,e,l.current)))},r=pm();$(`/api/settings`).then(e=>{r.isCurrent()&&t(e)}).catch(t=>{e&&o(t.message)});let a=hm(e=>t(e));return()=>{e=!1,a()}},[]);async function u(){if(t){if(!sh(r)){o(e(`Enter a full path, or a path that starts with ~/.`));return}c(!0);try{await $(`/api/settings`,{method:`PATCH`,body:JSON.stringify({edits:{claudeConfigDir:r.trim()},revision:t.revision})}),l.current=!1,o(e(`Saved. Capture and import use this folder now.`))}catch(e){o(e.message)}await mm(),c(!1)}}return(0,V.jsxs)(`section`,{className:`space-y-3 rounded-xl border border-border bg-card p-4`,"aria-label":e(`Claude Code folder`),children:[(0,V.jsx)(`h2`,{className:`text-lg font-medium`,children:e(`Claude Code folder`)}),(0,V.jsx)(`p`,{className:`text-sm text-muted-foreground`,children:e(`Set this when Claude Code does not use ~/.claude, for example when you start it with CLAUDE_CONFIG_DIR. Leave it empty to use the default.`)}),(0,V.jsxs)(`label`,{className:`block space-y-1 text-sm`,children:[(0,V.jsx)(`span`,{children:e(`Claude Code folder`)}),(0,V.jsx)(`input`,{className:`w-full rounded border border-border bg-background p-2 font-mono`,placeholder:`~/.claude`,value:r,disabled:s||!t,onChange:e=>{l.current=!0,i(e.target.value)}})]}),(0,V.jsx)(`button`,{type:`button`,className:`rounded border border-border px-3 py-1.5 text-sm`,disabled:s||!t,onClick:()=>void u(),children:e(`Save folder`)}),(0,V.jsx)(uh,{folder:t?.claudeFolder}),a&&(0,V.jsx)(`p`,{role:`status`,className:`text-sm`,children:a})]})}function uh({folder:e}){let t=ym();if(!e)return null;let n={setting:t(`this setting`),env:t(`the CLAUDE_CONFIG_DIR variable of the web app`),default:t(`the default folder`)};return(0,V.jsxs)(`div`,{className:`space-y-1 text-sm`,children:[(0,V.jsxs)(`p`,{children:[t(`Transcripts folder in use`),`: `,(0,V.jsx)(`span`,{className:`font-mono`,children:e.root})]}),(0,V.jsxs)(`p`,{children:[t(`From`),`: `,n[e.source]]}),!e.exists&&(0,V.jsxs)(`p`,{role:`status`,className:`text-amber-600`,children:[t(`This folder does not exist. Claude Code capture and import will not work:`),` `,(0,V.jsx)(`span`,{className:`font-mono`,children:e.root})]})]})}function dh(){let e=ym(),[t,n]=(0,_.useState)(!1),[r,i]=(0,_.useState)(),[a,o]=(0,_.useState)(``);async function s(e){try{i(await $(`/api/settings/log?lines=200${e?`&filter=capture`:``}`)),o(``)}catch(e){o(e.message)}}return(0,_.useEffect)(()=>{s(t)},[t]),(0,V.jsxs)(`section`,{className:`space-y-3 rounded-xl border border-border bg-card p-4`,"aria-label":e(`Log`),children:[(0,V.jsx)(`h2`,{className:`text-lg font-medium`,children:e(`Log`)}),(0,V.jsxs)(`div`,{className:`flex flex-wrap items-center gap-3 text-sm`,children:[(0,V.jsxs)(`label`,{children:[(0,V.jsx)(`input`,{type:`checkbox`,checked:t,onChange:e=>n(e.target.checked)}),` `,e(`Capture attempts only`)]}),(0,V.jsx)(`button`,{type:`button`,className:`rounded-lg border border-border px-3 py-1`,onClick:()=>void s(t),children:e(`Refresh`)}),r&&(0,V.jsx)(`button`,{type:`button`,className:`rounded-lg border border-border px-3 py-1`,onClick:()=>void navigator.clipboard.writeText(r.path),children:e(`Copy log path`)})]}),(0,V.jsx)(`p`,{className:`break-all text-xs text-muted-foreground`,children:r?.path}),a&&(0,V.jsx)(`p`,{role:`alert`,children:a}),(0,V.jsx)(`pre`,{className:`max-h-80 overflow-auto rounded-lg bg-background p-3 text-xs whitespace-pre-wrap break-words`,"aria-label":e(`Log lines`),children:r?r.lines.length?r.lines.join(`
124
+ `):e(`No log has been written yet.`):e(`Loading log…`)})]})}function fh(){return(0,V.jsxs)(`div`,{className:`settings-view space-y-6`,children:[(0,V.jsx)(jm,{}),(0,V.jsx)(Om,{}),(0,V.jsx)(zm,{}),(0,V.jsx)(Bm,{}),(0,V.jsx)(lh,{}),(0,V.jsx)(Zm,{}),(0,V.jsx)(ih,{}),(0,V.jsx)(Mm,{}),(0,V.jsx)(ah,{}),(0,V.jsx)(dh,{})]})}var ph=Fr(`grid gap-0.5 rounded-2xl border px-4 py-3 text-left text-sm has-data-[slot=alert-action]:relative has-data-[slot=alert-action]:pr-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2.5 *:[svg]:row-span-2 *:[svg]:translate-y-0.5 *:[svg]:text-current *:[svg:not([class*='size-'])]:size-4 group/alert relative w-full`,{variants:{variant:{default:`bg-card text-card-foreground`,destructive:`text-destructive bg-card *:data-[slot=alert-description]:text-destructive/90 *:[svg]:text-current`}},defaultVariants:{variant:`default`}});function mh({className:e,variant:t,...n}){return(0,V.jsx)(`div`,{"data-slot":`alert`,role:`alert`,className:B(ph({variant:t}),e),...n})}function hh({className:e,...t}){return(0,V.jsx)(`div`,{"data-slot":`alert-description`,className:B(`text-muted-foreground text-sm [&_p]:leading-relaxed col-start-2`,e),...t})}function gh({...e}){let t=El();return(0,V.jsx)(Un,{theme:t,className:`toaster group`,style:{"--normal-bg":`var(--color-popover)`,"--normal-text":`var(--color-popover-foreground)`,"--normal-border":`var(--color-border)`},icons:{loading:(0,V.jsx)(ce,{className:`size-4 animate-spin`}),success:(0,V.jsx)(oe,{className:`size-4`}),error:(0,V.jsx)(I,{className:`size-4`}),info:(0,V.jsx)(P,{className:`size-4`}),warning:(0,V.jsx)(Ae,{className:`size-4`})},...e})}function _h(e,t,n){return e?t:n}var vh=[``,`feature`,`bug-fix`,`refactor`,`architecture`,`rule`,`documentation`,`discussion`,`analysis`,`configuration`];function yh(){let{t:e,language:t}=lr(),n=fl(),[r,i]=(0,_.useState)(!1),a=ur(),o=dr();(0,_.useEffect)(()=>{let e=ul();(async()=>{await a.loadTags(),await a.loadMemories(),await a.loadStats(),await a.checkMigrationStatus(),await a.checkAuthWarning()})();let t=setInterval(()=>{a.loadStats(),!a.isSearching&&n===`project`&&a.loadMemories()},3e4);return()=>{e(),clearInterval(t)}},[]);let s=o.loadUserProfile;(0,_.useEffect)(()=>{n===`profile`&&s()},[n,s]);function c(e){e!==t&&(ar(e),a.loadMemories(),a.loadStats(),n===`profile`&&o.loadUserProfile())}function l(e){e.defaultPrevented||e.button!==0||e.metaKey||e.ctrlKey||e.shiftKey||e.altKey||(e.preventDefault(),ll(Qc.home))}return(0,V.jsxs)(V.Fragment,{children:[(0,V.jsx)(gh,{richColors:!0,position:`bottom-right`}),(0,V.jsxs)(`div`,{className:`flex min-h-svh bg-background text-foreground`,children:[(0,V.jsx)(Al,{open:r,onOpenChange:i,currentView:n,brand:e(`brand`),projectLabel:e(`tab-project`),profileLabel:e(`tab-profile`),profileSections:[{id:`profile-preferences`,label:e(`profile-preferences`)},{id:`profile-patterns`,label:e(`profile-patterns`)},{id:`profile-workflows`,label:e(`profile-workflows`)}],langLabel:t.toUpperCase(),languageLabel:e(`nav-language`),themeLabel:e(`nav-theme`),settingsLabel:e(`nav-settings`),closeLabel:e(`nav-close`),collapseLabel:e(`nav-collapse`),expandLabel:e(`nav-expand`),onLanguageSelect:c}),(0,V.jsxs)(`div`,{className:`flex min-w-0 flex-1 flex-col`,children:[(0,V.jsxs)(`div`,{className:`sticky top-0 z-30 flex items-center gap-2 border-b border-border bg-background/95 px-3 py-2 backdrop-blur md:hidden`,children:[(0,V.jsx)(W,{variant:`ghost`,size:`icon-sm`,onClick:()=>i(!0),"aria-label":e(`nav-menu`),children:(0,V.jsx)(ue,{className:`size-4`})}),(0,V.jsx)(`a`,{href:Qc.home,className:`truncate text-sm tracking-wide text-primary`,onClick:l,children:e(`brand`)})]}),(0,V.jsxs)(`div`,{className:`mx-auto w-full max-w-6xl flex-1 space-y-4 p-4 md:p-6`,children:[a.showAuthWarning?(0,V.jsxs)(mh,{variant:`destructive`,children:[(0,V.jsx)(Ae,{}),(0,V.jsx)(hh,{children:e(`auth-warning-text`)})]}):null,(0,V.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-2`,children:[(0,V.jsx)(`h1`,{className:`text-base tracking-wide text-primary`,children:e(n===`project`?`tab-project`:n===`profile`?`tab-profile`:`nav-settings`)}),n===`project`?(0,V.jsxs)(`div`,{className:`flex items-center gap-2 text-xs text-muted-foreground`,children:[(0,V.jsx)(`span`,{children:e(`text-total`,{count:_h(a.isSearching,a.totalItems,a.statsTotal)})}),a.refreshing?(0,V.jsx)(le,{className:`size-3.5 animate-spin`}):null]}):null]}),n===`project`?(0,V.jsxs)(V.Fragment,{children:[(0,V.jsxs)(`div`,{className:`flex flex-wrap items-end gap-3 rounded-xl border border-border bg-card p-3`,children:[(0,V.jsxs)(`div`,{className:`min-w-0 max-w-full space-y-1`,children:[(0,V.jsx)(Nl,{htmlFor:`tag-filter`,children:e(`label-tag`)}),(0,V.jsxs)(dn,{id:`tag-filter`,className:`flex h-8 w-64 max-w-full rounded-lg border border-border bg-background px-2 text-sm`,value:a.selectedTag,onChange:e=>a.onTagFilterChange(e.currentTarget.value),children:[(0,V.jsx)(`option`,{value:``,children:e(`opt-all-tags`)}),a.tags.map(e=>(0,V.jsx)(`option`,{value:e.tag,children:e.displayName||e.tag},e.tag))]})]}),a.selectedKeyword?(0,V.jsxs)(`div`,{className:`space-y-1`,children:[(0,V.jsx)(`span`,{className:`block text-sm font-medium`,children:e(`label-keyword`)}),(0,V.jsxs)(`div`,{className:`flex h-8 items-center gap-1`,children:[(0,V.jsx)(Ll,{keyword:a.selectedKeyword,active:!0}),(0,V.jsx)(W,{variant:`ghost`,size:`icon-xs`,onClick:()=>a.onKeywordFilterChange(``),"aria-label":e(`btn-clear-keyword`),title:e(`btn-clear-keyword`),children:(0,V.jsx)(Pe,{className:`size-3.5`})})]})]}):null,(0,V.jsxs)(`div`,{className:`flex flex-1 items-end gap-1.5 min-w-56`,children:[(0,V.jsxs)(`div`,{className:`flex-1 space-y-1`,children:[(0,V.jsx)(Nl,{htmlFor:`search-input`,className:`sr-only`,children:e(`placeholder-search`)}),(0,V.jsx)(tm,{id:`search-input`,placeholder:e(`placeholder-search`),value:a.searchInput,onChange:e=>a.setSearchInput(e.target.value),onKeyDown:e=>e.key===`Enter`&&a.performSearch()})]}),(0,V.jsx)(W,{variant:`outline`,size:`icon`,onClick:a.performSearch,children:(0,V.jsx)(Ce,{className:`size-4`})}),a.isSearching?(0,V.jsx)(W,{variant:`outline`,size:`icon`,onClick:a.clearSearch,children:(0,V.jsx)(Pe,{className:`size-4`})}):null]}),(0,V.jsxs)(`div`,{className:`flex flex-wrap gap-1.5`,children:[(0,V.jsx)(zl,{content:e(`tooltip-cleanup`),children:(0,V.jsxs)(W,{variant:`outline`,size:`sm`,onClick:a.runCleanup,children:[(0,V.jsx)(ke,{className:`size-3.5`}),e(`btn-cleanup`)]})}),(0,V.jsx)(zl,{content:e(`tooltip-deduplicate`),children:(0,V.jsxs)(W,{variant:`outline`,size:`sm`,onClick:a.runDeduplication,children:[(0,V.jsx)(xe,{className:`size-3.5`}),e(`btn-deduplicate`)]})})]}),a.selectedIds.size>0?(0,V.jsxs)(`div`,{className:`flex w-full flex-wrap items-center gap-2 border-t border-border pt-3`,children:[(0,V.jsx)(`span`,{className:`text-xs text-muted-foreground`,children:e(`text-selected`,{count:a.selectedIds.size})}),(0,V.jsx)(W,{variant:`secondary`,size:`xs`,onClick:a.selectAllCurrentPage,children:e(`btn-select-all`)}),(0,V.jsx)(W,{variant:`destructive`,size:`xs`,onClick:a.bulkDelete,children:e(`btn-delete-selected`)}),(0,V.jsx)(W,{variant:`ghost`,size:`xs`,onClick:a.deselectAll,children:e(`btn-deselect-all`)})]}):null]}),a.migrationNeeded?(0,V.jsxs)(mh,{variant:`destructive`,className:`space-y-3`,children:[(0,V.jsx)(Ae,{}),(0,V.jsxs)(hh,{className:`space-y-3`,children:[(0,V.jsx)(`p`,{children:a.migrationMessage||e(`migration-mismatch`)}),(0,V.jsxs)(`label`,{className:`flex items-start gap-2 text-sm`,children:[(0,V.jsx)(Ui,{checked:a.migrationConfirmed,onCheckedChange:e=>a.setMigrationConfirmed(e===!0),className:`mt-0.5`}),(0,V.jsx)(`span`,{children:e(`migration-understand`)})]}),(0,V.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,V.jsx)(W,{variant:`destructive`,size:`sm`,disabled:!a.migrationConfirmed,onClick:()=>a.runMigration(`fresh-start`),children:e(`btn-fresh-start`)}),(0,V.jsx)(W,{variant:`secondary`,size:`sm`,disabled:!a.migrationConfirmed,onClick:()=>a.runMigration(`re-embed`),children:e(`btn-reembed`)})]})]})]}):null,(0,V.jsx)(rp,{memories:a.memories,selectedIds:a.selectedIds,currentPage:a.currentPage,totalPages:a.totalPages,totalItems:a.totalItems,isSearching:a.isSearching,loading:a.loadingMemories,error:a.memoriesError,onSelect:a.onSelect,onPageChange:e=>{let t=a.currentPage+e;a.setCurrentPage(t),a.loadMemories({page:t})},onPin:a.pinMemory,onUnpin:a.unpinMemory,onEdit:a.openEdit,onDeleteMemory:a.deleteMemory,onDeletePrompt:a.deletePrompt,activeKeyword:a.selectedKeyword,onKeywordClick:e=>a.onKeywordFilterChange(a.selectedKeyword.toLowerCase()===e.toLowerCase()?``:e)}),(0,V.jsxs)(`section`,{className:`rounded-xl border border-border bg-card p-4 space-y-3`,children:[(0,V.jsx)(`h2`,{className:`text-sm text-muted-foreground`,children:e(`section-add`)}),(0,V.jsxs)(`form`,{className:`space-y-3`,onSubmit:a.addMemory,children:[(0,V.jsxs)(`div`,{className:`grid gap-3 md:grid-cols-3`,children:[(0,V.jsxs)(`div`,{className:`space-y-1`,children:[(0,V.jsx)(Nl,{htmlFor:`add-tag`,children:e(`label-tag`)}),(0,V.jsxs)(dn,{id:`add-tag`,required:!0,className:`flex h-8 w-full rounded-lg border border-border bg-background px-2 text-sm`,value:a.addTag,onChange:e=>a.setAddTag(e.target.value),children:[(0,V.jsx)(`option`,{value:``,children:e(`opt-select-tag`)}),a.tags.map(e=>(0,V.jsx)(`option`,{value:e.tag,children:e.displayName||e.tag},e.tag))]})]}),(0,V.jsxs)(`div`,{className:`space-y-1`,children:[(0,V.jsx)(Nl,{htmlFor:`add-type`,children:e(`label-type`)}),(0,V.jsx)(dn,{id:`add-type`,className:`flex h-8 w-full rounded-lg border border-border bg-background px-2 text-sm`,value:a.addType,onChange:e=>a.setAddType(e.target.value),children:vh.map(t=>(0,V.jsx)(`option`,{value:t,children:e(t?`opt-${t}`:`opt-other`)},t||`other`))})]}),(0,V.jsxs)(`div`,{className:`space-y-1`,children:[(0,V.jsx)(Nl,{htmlFor:`add-tags`,children:e(`label-tags`)}),(0,V.jsx)(tm,{id:`add-tags`,placeholder:e(`placeholder-tags`),value:a.addTags,onChange:e=>a.setAddTags(e.target.value)})]})]}),(0,V.jsxs)(`div`,{className:`space-y-1`,children:[(0,V.jsx)(Nl,{htmlFor:`add-content`,children:e(`label-content`)}),(0,V.jsx)(Pl,{id:`add-content`,rows:4,required:!0,placeholder:e(`placeholder-content`),value:a.addContent,onChange:e=>a.setAddContent(e.target.value)})]}),(0,V.jsxs)(W,{type:`submit`,children:[(0,V.jsx)(ye,{className:`size-3.5`}),e(`btn-add-memory`)]})]})]})]}):n===`settings`?(0,V.jsx)(fh,{}):(0,V.jsx)(cm,{profile:o.userProfile,loading:o.loadingProfile,onRefresh:o.refreshProfile,onCleanup:()=>o.setAiCleanupOpen(!0)})]})]})]}),(0,V.jsx)(Fl,{open:a.editOpen,onOpenChange:a.setEditOpen,content:a.editContent,onSave:a.saveEdit}),(0,V.jsx)(lm,{open:a.tagMigrationOpen,onOpenChange:a.setTagMigrationOpen,count:a.tagMigrationCount,onComplete:()=>{a.loadMemories(),a.loadStats()}}),(0,V.jsx)(Mc,{open:o.aiCleanupOpen,onOpenChange:o.setAiCleanupOpen,profile:o.userProfile,onApplied:o.loadUserProfile})]})}Tl();var bh=document.getElementById(`app`);if(!bh)throw Error(`Root element #app not found`);(0,v.createRoot)(bh).render((0,V.jsx)(_.StrictMode,{children:(0,V.jsx)(cr,{children:(0,V.jsx)(yh,{})})}));
@@ -5,7 +5,7 @@
5
5
  <link rel="icon" type="image/x-icon" href="/favicon.ico" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>omms Memory Explorer</title>
8
- <script type="module" crossorigin src="/assets/index-BtJzyEtW.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-Bh5aFNPX.js"></script>
9
9
  <link rel="stylesheet" crossorigin href="/assets/index-DG7RjW5B.css">
10
10
  </head>
11
11
  <body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "om-memory-system",
3
- "version": "3.6.0-next.43",
3
+ "version": "3.6.0-next.45",
4
4
  "description": "Opinionated modular memory system for coding agents (OpenCode + Pi)",
5
5
  "type": "module",
6
6
  "main": "dist/plugin.js",